All of lore.kernel.org
 help / color / mirror / Atom feed
Search results ordered by [date|relevance]  view[summary|nested|Atom feed]
thread overview below | download mbox.gz: |
* [PATCH 09/19] rust: add `kernel` crate
  @ 2021-12-06 14:03  1% ` Miguel Ojeda
  2021-12-06 14:03  3% ` [PATCH 16/19] samples: add Rust examples Miguel Ojeda
  1 sibling, 0 replies; 77+ results
From: Miguel Ojeda @ 2021-12-06 14:03 UTC (permalink / raw)
  To: Linus Torvalds, Greg Kroah-Hartman
  Cc: rust-for-linux, linux-kbuild, linux-doc, linux-kernel,
	Wedson Almeida Filho, Alex Gaynor, Geoffrey Thomas, Finn Behrens,
	Adam Bratschi-Kaye, Michael Ellerman, Sumera Priyadarsini,
	Sven Van Asbroeck, Gary Guo, Boris-Chengbiao Zhou, Boqun Feng,
	Fox Chen, Dan Robertson, Viktor Garske, Dariusz Sosnowski,
	Léo Lanteri Thauvin, Niklas Mohrin, Gioh Kim,
	Milan Landaverde, Morgan Bartlett, Miguel Ojeda

From: Wedson Almeida Filho <wedsonaf@google.com>

The `kernel` crate currently includes all the abstractions that wrap
kernel features written in C.

These abstractions call the C side of the kernel via the generated
bindings with the `bindgen` tool. Modules developed in Rust should
never call the bindings themselves.

In the future, as the abstractions grow in number, we may need
to split this crate into several, possibly following a similar
subdivision in subsystems as the kernel itself and/or moving
the code to the actual subsystems.

Co-developed-by: Alex Gaynor <alex.gaynor@gmail.com>
Signed-off-by: Alex Gaynor <alex.gaynor@gmail.com>
Co-developed-by: Geoffrey Thomas <geofft@ldpreload.com>
Signed-off-by: Geoffrey Thomas <geofft@ldpreload.com>
Co-developed-by: Finn Behrens <me@kloenk.de>
Signed-off-by: Finn Behrens <me@kloenk.de>
Co-developed-by: Adam Bratschi-Kaye <ark.email@gmail.com>
Signed-off-by: Adam Bratschi-Kaye <ark.email@gmail.com>
Co-developed-by: Michael Ellerman <mpe@ellerman.id.au>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Co-developed-by: Sumera Priyadarsini <sylphrenadin@gmail.com>
Signed-off-by: Sumera Priyadarsini <sylphrenadin@gmail.com>
Co-developed-by: Sven Van Asbroeck <thesven73@gmail.com>
Signed-off-by: Sven Van Asbroeck <thesven73@gmail.com>
Co-developed-by: Gary Guo <gary@garyguo.net>
Signed-off-by: Gary Guo <gary@garyguo.net>
Co-developed-by: Boris-Chengbiao Zhou <bobo1239@web.de>
Signed-off-by: Boris-Chengbiao Zhou <bobo1239@web.de>
Co-developed-by: Boqun Feng <boqun.feng@gmail.com>
Signed-off-by: Boqun Feng <boqun.feng@gmail.com>
Co-developed-by: Fox Chen <foxhlchen@gmail.com>
Signed-off-by: Fox Chen <foxhlchen@gmail.com>
Co-developed-by: Dan Robertson <daniel.robertson@starlab.io>
Signed-off-by: Dan Robertson <daniel.robertson@starlab.io>
Co-developed-by: Viktor Garske <viktor@v-gar.de>
Signed-off-by: Viktor Garske <viktor@v-gar.de>
Co-developed-by: Dariusz Sosnowski <dsosnowski@dsosnowski.pl>
Signed-off-by: Dariusz Sosnowski <dsosnowski@dsosnowski.pl>
Co-developed-by: Léo Lanteri Thauvin <leseulartichaut@gmail.com>
Signed-off-by: Léo Lanteri Thauvin <leseulartichaut@gmail.com>
Co-developed-by: Niklas Mohrin <dev@niklasmohrin.de>
Signed-off-by: Niklas Mohrin <dev@niklasmohrin.de>
Co-developed-by: Gioh Kim <gurugio@gmail.com>
Signed-off-by: Gioh Kim <gurugio@gmail.com>
Co-developed-by: Milan Landaverde <milan@mdaverde.com>
Signed-off-by: Milan Landaverde <milan@mdaverde.com>
Co-developed-by: Morgan Bartlett <mjmouse9999@gmail.com>
Signed-off-by: Morgan Bartlett <mjmouse9999@gmail.com>
Signed-off-by: Wedson Almeida Filho <wedsonaf@google.com>
Co-developed-by: Miguel Ojeda <ojeda@kernel.org>
Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
---
 include/linux/spinlock.h            |  17 +-
 kernel/printk/printk.c              |   5 +-
 rust/kernel/allocator.rs            |  65 +++
 rust/kernel/amba.rs                 | 276 +++++++++++
 rust/kernel/bindings.rs             |  47 ++
 rust/kernel/bindings_helper.h       |  30 ++
 rust/kernel/buffer.rs               |  52 ++
 rust/kernel/build_assert.rs         |  80 +++
 rust/kernel/c_types.rs              | 119 +++++
 rust/kernel/chrdev.rs               | 212 ++++++++
 rust/kernel/cred.rs                 |  73 +++
 rust/kernel/device.rs               | 206 ++++++++
 rust/kernel/driver.rs               | 198 ++++++++
 rust/kernel/error.rs                | 542 +++++++++++++++++++++
 rust/kernel/file.rs                 | 141 ++++++
 rust/kernel/file_operations.rs      | 723 ++++++++++++++++++++++++++++
 rust/kernel/gpio.rs                 | 475 ++++++++++++++++++
 rust/kernel/io_buffer.rs            | 153 ++++++
 rust/kernel/io_mem.rs               | 207 ++++++++
 rust/kernel/iov_iter.rs             |  81 ++++
 rust/kernel/irq.rs                  | 408 ++++++++++++++++
 rust/kernel/lib.rs                  | 256 ++++++++++
 rust/kernel/linked_list.rs          | 247 ++++++++++
 rust/kernel/miscdev.rs              | 166 +++++++
 rust/kernel/module_param.rs         | 497 +++++++++++++++++++
 rust/kernel/of.rs                   | 101 ++++
 rust/kernel/pages.rs                | 162 +++++++
 rust/kernel/platdev.rs              | 152 ++++++
 rust/kernel/power.rs                | 118 +++++
 rust/kernel/prelude.rs              |  33 ++
 rust/kernel/print.rs                | 441 +++++++++++++++++
 rust/kernel/random.rs               |  50 ++
 rust/kernel/raw_list.rs             | 361 ++++++++++++++
 rust/kernel/rbtree.rs               | 562 +++++++++++++++++++++
 rust/kernel/revocable.rs            | 163 +++++++
 rust/kernel/security.rs             |  36 ++
 rust/kernel/static_assert.rs        |  39 ++
 rust/kernel/std_vendor.rs           | 150 ++++++
 rust/kernel/str.rs                  | 375 +++++++++++++++
 rust/kernel/sync/arc.rs             | 500 +++++++++++++++++++
 rust/kernel/sync/condvar.rs         | 137 ++++++
 rust/kernel/sync/guard.rs           | 181 +++++++
 rust/kernel/sync/locked_by.rs       | 112 +++++
 rust/kernel/sync/mod.rs             |  92 ++++
 rust/kernel/sync/mutex.rs           | 111 +++++
 rust/kernel/sync/revocable_mutex.rs | 184 +++++++
 rust/kernel/sync/seqlock.rs         | 201 ++++++++
 rust/kernel/sync/spinlock.rs        | 180 +++++++
 rust/kernel/sysctl.rs               | 197 ++++++++
 rust/kernel/task.rs                 | 182 +++++++
 rust/kernel/types.rs                | 486 +++++++++++++++++++
 rust/kernel/user_ptr.rs             | 175 +++++++
 52 files changed, 10750 insertions(+), 7 deletions(-)
 create mode 100644 rust/kernel/allocator.rs
 create mode 100644 rust/kernel/amba.rs
 create mode 100644 rust/kernel/bindings.rs
 create mode 100644 rust/kernel/bindings_helper.h
 create mode 100644 rust/kernel/buffer.rs
 create mode 100644 rust/kernel/build_assert.rs
 create mode 100644 rust/kernel/c_types.rs
 create mode 100644 rust/kernel/chrdev.rs
 create mode 100644 rust/kernel/cred.rs
 create mode 100644 rust/kernel/device.rs
 create mode 100644 rust/kernel/driver.rs
 create mode 100644 rust/kernel/error.rs
 create mode 100644 rust/kernel/file.rs
 create mode 100644 rust/kernel/file_operations.rs
 create mode 100644 rust/kernel/gpio.rs
 create mode 100644 rust/kernel/io_buffer.rs
 create mode 100644 rust/kernel/io_mem.rs
 create mode 100644 rust/kernel/iov_iter.rs
 create mode 100644 rust/kernel/irq.rs
 create mode 100644 rust/kernel/lib.rs
 create mode 100644 rust/kernel/linked_list.rs
 create mode 100644 rust/kernel/miscdev.rs
 create mode 100644 rust/kernel/module_param.rs
 create mode 100644 rust/kernel/of.rs
 create mode 100644 rust/kernel/pages.rs
 create mode 100644 rust/kernel/platdev.rs
 create mode 100644 rust/kernel/power.rs
 create mode 100644 rust/kernel/prelude.rs
 create mode 100644 rust/kernel/print.rs
 create mode 100644 rust/kernel/random.rs
 create mode 100644 rust/kernel/raw_list.rs
 create mode 100644 rust/kernel/rbtree.rs
 create mode 100644 rust/kernel/revocable.rs
 create mode 100644 rust/kernel/security.rs
 create mode 100644 rust/kernel/static_assert.rs
 create mode 100644 rust/kernel/std_vendor.rs
 create mode 100644 rust/kernel/str.rs
 create mode 100644 rust/kernel/sync/arc.rs
 create mode 100644 rust/kernel/sync/condvar.rs
 create mode 100644 rust/kernel/sync/guard.rs
 create mode 100644 rust/kernel/sync/locked_by.rs
 create mode 100644 rust/kernel/sync/mod.rs
 create mode 100644 rust/kernel/sync/mutex.rs
 create mode 100644 rust/kernel/sync/revocable_mutex.rs
 create mode 100644 rust/kernel/sync/seqlock.rs
 create mode 100644 rust/kernel/sync/spinlock.rs
 create mode 100644 rust/kernel/sysctl.rs
 create mode 100644 rust/kernel/task.rs
 create mode 100644 rust/kernel/types.rs
 create mode 100644 rust/kernel/user_ptr.rs

diff --git a/include/linux/spinlock.h b/include/linux/spinlock.h
index b4e5ca23f840..40e467cdee2d 100644
--- a/include/linux/spinlock.h
+++ b/include/linux/spinlock.h
@@ -326,12 +326,17 @@ static __always_inline raw_spinlock_t *spinlock_check(spinlock_t *lock)
 
 #ifdef CONFIG_DEBUG_SPINLOCK
 
-# define spin_lock_init(lock)					\
-do {								\
-	static struct lock_class_key __key;			\
-								\
-	__raw_spin_lock_init(spinlock_check(lock),		\
-			     #lock, &__key, LD_WAIT_CONFIG);	\
+static inline void __spin_lock_init(spinlock_t *lock, const char *name,
+				    struct lock_class_key *key)
+{
+	__raw_spin_lock_init(spinlock_check(lock), name, key, LD_WAIT_CONFIG);
+}
+
+# define spin_lock_init(lock)			\
+do {						\
+	static struct lock_class_key __key;	\
+						\
+	__spin_lock_init(lock, #lock, &__key);	\
 } while (0)
 
 #else
diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
index 57b132b658e1..cbc35d586afb 100644
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -392,7 +392,10 @@ static struct latched_seq clear_seq = {
 /* the maximum size of a formatted record (i.e. with prefix added per line) */
 #define CONSOLE_LOG_MAX		1024
 
-/* the maximum size allowed to be reserved for a record */
+/*
+ * The maximum size allowed to be reserved for a record.
+ * Keep in sync with rust/kernel/print.rs.
+ */
 #define LOG_LINE_MAX		(CONSOLE_LOG_MAX - PREFIX_MAX)
 
 #define LOG_LEVEL(v)		((v) & 0x07)
diff --git a/rust/kernel/allocator.rs b/rust/kernel/allocator.rs
new file mode 100644
index 000000000000..4c5d2fc6f206
--- /dev/null
+++ b/rust/kernel/allocator.rs
@@ -0,0 +1,65 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Allocator support.
+
+use core::alloc::{GlobalAlloc, Layout};
+use core::ptr;
+
+use crate::bindings;
+use crate::c_types;
+
+struct KernelAllocator;
+
+unsafe impl GlobalAlloc for KernelAllocator {
+    unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
+        // `krealloc()` is used instead of `kmalloc()` because the latter is
+        // an inline function and cannot be bound to as a result.
+        unsafe { bindings::krealloc(ptr::null(), layout.size(), bindings::GFP_KERNEL) as *mut u8 }
+    }
+
+    unsafe fn dealloc(&self, ptr: *mut u8, _layout: Layout) {
+        unsafe {
+            bindings::kfree(ptr as *const c_types::c_void);
+        }
+    }
+}
+
+#[global_allocator]
+static ALLOCATOR: KernelAllocator = KernelAllocator;
+
+// `rustc` only generates these for some crate types. Even then, we would need
+// to extract the object file that has them from the archive. For the moment,
+// let's generate them ourselves instead.
+//
+// Note that `#[no_mangle]` implies exported too, nowadays.
+#[no_mangle]
+fn __rust_alloc(size: usize, _align: usize) -> *mut u8 {
+    unsafe { bindings::krealloc(core::ptr::null(), size, bindings::GFP_KERNEL) as *mut u8 }
+}
+
+#[no_mangle]
+fn __rust_dealloc(ptr: *mut u8, _size: usize, _align: usize) {
+    unsafe { bindings::kfree(ptr as *const c_types::c_void) };
+}
+
+#[no_mangle]
+fn __rust_realloc(ptr: *mut u8, _old_size: usize, _align: usize, new_size: usize) -> *mut u8 {
+    unsafe {
+        bindings::krealloc(
+            ptr as *const c_types::c_void,
+            new_size,
+            bindings::GFP_KERNEL,
+        ) as *mut u8
+    }
+}
+
+#[no_mangle]
+fn __rust_alloc_zeroed(size: usize, _align: usize) -> *mut u8 {
+    unsafe {
+        bindings::krealloc(
+            core::ptr::null(),
+            size,
+            bindings::GFP_KERNEL | bindings::__GFP_ZERO,
+        ) as *mut u8
+    }
+}
diff --git a/rust/kernel/amba.rs b/rust/kernel/amba.rs
new file mode 100644
index 000000000000..689528502ca5
--- /dev/null
+++ b/rust/kernel/amba.rs
@@ -0,0 +1,276 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Amba devices drivers.
+//!
+//! C header: [`include/linux/amba/bus.h`](../../../../include/linux/amba/bus.h)
+
+use crate::{
+    bindings, c_types, device, driver, error::from_kernel_result, io_mem::Resource, power,
+    str::CStr, to_result, types::PointerWrapper, Error, Result,
+};
+use core::{marker::PhantomData, ops::Deref};
+
+/// A registration of an amba driver.
+pub type Registration<T> = driver::Registration<Adapter<T>>;
+
+/// Id of an Amba device.
+pub struct DeviceId<T = ()> {
+    /// Device id.
+    pub id: u32,
+
+    /// Mask that identifies which bits are valid in the device id.
+    pub mask: u32,
+
+    /// Context data to be associated with the device id. This is carried over to [`Driver::probe`]
+    /// so that drivers can encode any information they may need then.
+    pub data: T,
+}
+
+/// An amba driver.
+pub trait Driver
+where
+    <Self::Data as Deref>::Target: driver::DeviceRemoval,
+{
+    /// Data stored on device by driver.
+    type Data: PointerWrapper + Send + Sync + Deref;
+
+    /// The type that implements the power-management operations.
+    ///
+    /// The default is a type that implements no power-management operations. Drivers that do
+    /// implement them need to specify the type (commonly [`Self`]).
+    type PowerOps: power::Operations<Data = Self::Data> = power::NoOperations<Self::Data>;
+
+    /// The type holding information about each device id supported by the driver.
+    type IdInfo: 'static = ();
+
+    /// The table of device ids supported by the drivers.
+    const ID_TABLE: &'static [DeviceId<Self::IdInfo>];
+
+    /// Probes for the device with the given id.
+    fn probe(dev: &mut Device, id: &DeviceId<Self::IdInfo>) -> Result<Self::Data>;
+
+    /// Cleans any resources up that are associated with the device.
+    ///
+    /// This is called when the driver is detached from the device.
+    fn remove(_data: &Self::Data) {}
+}
+
+/// An adapter for the registration of Amba drivers.
+pub struct Adapter<T: Driver>(PhantomData<T>)
+where
+    <T::Data as Deref>::Target: driver::DeviceRemoval;
+
+impl<T: Driver> driver::DriverOps for Adapter<T>
+where
+    <T::Data as Deref>::Target: driver::DeviceRemoval,
+{
+    type RegType = bindings::amba_driver;
+    type RawIdType = bindings::amba_id;
+    type IdType = DeviceId<T::IdInfo>;
+    const ID_TABLE: &'static [Self::IdType] = T::ID_TABLE;
+
+    unsafe fn register(
+        reg: *mut bindings::amba_driver,
+        name: &'static CStr,
+        id_table: *const bindings::amba_id,
+    ) -> Result {
+        // SAFETY: By the safety requirements of this function (defined in the trait defintion),
+        // `reg` is non-null and valid.
+        let amba = unsafe { &mut *reg };
+        amba.drv.name = name.as_char_ptr();
+        amba.id_table = id_table;
+        amba.probe = Some(probe_callback::<T>);
+        amba.remove = Some(remove_callback::<T>);
+        if cfg!(CONFIG_PM) {
+            // SAFETY: `probe_callback` sets the driver data after calling `T::Data::into_pointer`,
+            // and we guarantee that `T::Data` is the same as `T::PowerOps::Data` by a constraint
+            // in the type declaration.
+            amba.drv.pm = unsafe { power::OpsTable::<T::PowerOps>::build() };
+        }
+        // SAFETY: By the safety requirements of this function, `reg` is valid and fully
+        // initialised.
+        to_result(|| unsafe { bindings::amba_driver_register(reg) })
+    }
+
+    unsafe fn unregister(reg: *mut bindings::amba_driver) {
+        // SAFETY: By the safety requirements of this function (defined in the trait definition),
+        // `reg` was passed (and updated) by a previous successful call to `amba_driver_register`.
+        unsafe { bindings::amba_driver_unregister(reg) };
+    }
+
+    fn to_raw_id(index: usize, id: &Self::IdType) -> Self::RawIdType {
+        bindings::amba_id {
+            id: id.id,
+            mask: id.mask,
+            data: index as _,
+        }
+    }
+}
+
+unsafe extern "C" fn probe_callback<T: Driver>(
+    adev: *mut bindings::amba_device,
+    aid: *const bindings::amba_id,
+) -> c_types::c_int
+where
+    <T::Data as Deref>::Target: driver::DeviceRemoval,
+{
+    from_kernel_result! {
+        // SAFETY: `adev` is valid by the contract with the C code. `dev` is alive only for the
+        // duration of this call, so it is guaranteed to remain alive for the lifetime of `dev`.
+        let mut dev = unsafe { Device::from_ptr(adev) };
+        // SAFETY: `aid` is valid by the requirements the contract with the C code.
+        let index = unsafe { (*aid).data } as usize;
+        if index >= T::ID_TABLE.len() {
+            return Err(Error::ENXIO);
+        }
+        let data = T::probe(&mut dev, &T::ID_TABLE[index])?;
+        let ptr = T::Data::into_pointer(data);
+        // SAFETY: `adev` is valid for write by the contract with the C code.
+        unsafe { bindings::amba_set_drvdata(adev, ptr as _) };
+        Ok(0)
+    }
+}
+
+unsafe extern "C" fn remove_callback<T: Driver>(adev: *mut bindings::amba_device)
+where
+    <T::Data as Deref>::Target: driver::DeviceRemoval,
+{
+    // SAFETY: `adev` is valid by the contract with the C code.
+    let ptr = unsafe { bindings::amba_get_drvdata(adev) };
+    // SAFETY: The value returned by `amba_get_drvdata` was stored by a previous call to
+    // `amba_set_drvdata` in `probe_callback` above; the value comes from a call to
+    // `T::Data::into_pointer`.
+    let data = unsafe { T::Data::from_pointer(ptr) };
+    T::remove(&data);
+    <<T::Data as Deref>::Target as driver::DeviceRemoval>::device_remove(data.deref());
+}
+
+/// An Amba device.
+///
+/// # Invariants
+///
+/// The field `ptr` is non-null and valid for the lifetime of the object.
+pub struct Device {
+    ptr: *mut bindings::amba_device,
+    res: Option<Resource>,
+}
+
+impl Device {
+    /// Creates a new device from the given pointer.
+    ///
+    /// # Safety
+    ///
+    /// `ptr` must be non-null and valid. It must remain valid for the lifetime of the returned
+    /// instance.
+    unsafe fn from_ptr(ptr: *mut bindings::amba_device) -> Self {
+        // SAFETY: The safety requirements of the function ensure that `ptr` is valid.
+        let dev = unsafe { &mut *ptr };
+        // INVARIANT: The safety requirements of the function ensure the lifetime invariant.
+        Self {
+            ptr,
+            res: Resource::new(dev.res.start, dev.res.end),
+        }
+    }
+
+    /// Returns the io mem resource associated with the device, if there is one.
+    ///
+    /// Ownership of the resource is transferred to the caller, so subsequent calls to this
+    /// function will return [`None`].
+    pub fn take_resource(&mut self) -> Option<Resource> {
+        self.res.take()
+    }
+
+    /// Returns the index-th irq associated with the device, if one exists.
+    pub fn irq(&self, index: usize) -> Option<u32> {
+        // SAFETY: By the type invariants, `self.ptr` is valid for read.
+        let dev = unsafe { &*self.ptr };
+        if index >= dev.irq.len() || dev.irq[index] == 0 {
+            None
+        } else {
+            Some(dev.irq[index])
+        }
+    }
+}
+
+// SAFETY: The device returned by `raw_device` is the raw Amba device.
+unsafe impl device::RawDevice for Device {
+    fn raw_device(&self) -> *mut bindings::device {
+        // SAFETY: By the type invariants, we know that `self.ptr` is non-null and valid.
+        unsafe { &mut (*self.ptr).dev }
+    }
+}
+
+/// Declares a kernel module that exposes a single amba driver.
+///
+/// # Examples
+///
+/// ```ignore
+/// # use kernel::prelude::*;
+/// # use kernel::{amba, declare_amba_id_table, module_amba_driver};
+/// #
+/// # struct State;
+/// # impl kernel::driver::DeviceRemoval for State {
+/// #   fn device_remove(&self) {}
+/// # }
+/// struct MyDriver;
+/// impl amba::Driver for MyDriver {
+///     // [...]
+/// #   type Data = kernel::sync::Ref<State>;
+/// #   fn probe(dev: &mut amba::Device, id: &amba::DeviceId<Self::IdInfo>) -> Result<Self::Data> {
+/// #     todo!()
+/// #   }
+/// #   declare_amba_id_table! [
+/// #       { id: 0x00041061, mask: 0x000fffff, data: () },
+/// #   ];
+/// }
+///
+/// module_amba_driver! {
+///     type: MyDriver,
+///     name: b"module_name",
+///     author: b"Author name",
+///     license: b"GPL v2",
+/// }
+/// ```
+#[macro_export]
+macro_rules! module_amba_driver {
+    ($($f:tt)*) => {
+        $crate::module_driver!(<T>, $crate::amba::Adapter<T>, { $($f)* });
+    };
+}
+
+/// Declares the id table for amba devices.
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::prelude::*;
+/// # use kernel::{amba, declare_amba_id_table};
+/// #
+/// # struct State;
+/// # impl kernel::driver::DeviceRemoval for State {
+/// #   fn device_remove(&self) {}
+/// # }
+/// # struct Sample;
+/// # impl kernel::amba::Driver for Sample {
+/// #   type Data = kernel::sync::Ref<State>;
+/// #   fn probe(dev: &mut amba::Device, id: &amba::DeviceId<Self::IdInfo>) -> Result<Self::Data> {
+/// #     todo!()
+/// #   }
+///     declare_amba_id_table! [
+///         { id: 0x00041061, mask: 0x000fffff, data: () },
+///     ];
+/// # }
+/// ```
+#[macro_export]
+macro_rules! declare_amba_id_table {
+    ($({$($entry:tt)*},)*) => {
+        const ID_TABLE: &'static [$crate::amba::DeviceId<Self::IdInfo>] = &[
+            $( $crate::amba::DeviceId { $($entry)* },)*
+        ];
+    };
+
+    // Cover case without a trailing comma.
+    ($(($($entry:tt)*)),*) => {
+        $crate::declare_amba_id_table!{ $({$($entry)*},)*}
+    }
+}
diff --git a/rust/kernel/bindings.rs b/rust/kernel/bindings.rs
new file mode 100644
index 000000000000..02678ca589c8
--- /dev/null
+++ b/rust/kernel/bindings.rs
@@ -0,0 +1,47 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Bindings
+//!
+//! Imports the generated bindings by `bindgen`.
+
+// See https://github.com/rust-lang/rust-bindgen/issues/1651.
+#![cfg_attr(test, allow(deref_nullptr))]
+#![cfg_attr(test, allow(unaligned_references))]
+#![cfg_attr(test, allow(unsafe_op_in_unsafe_fn))]
+#![allow(
+    clippy::all,
+    non_camel_case_types,
+    non_upper_case_globals,
+    non_snake_case,
+    improper_ctypes,
+    unreachable_pub,
+    unsafe_op_in_unsafe_fn
+)]
+
+mod bindings_raw {
+    // Use glob import here to expose all helpers.
+    // Symbols defined within the module will take precedence to the glob import.
+    pub use super::bindings_helper::*;
+    use crate::c_types;
+    include!(concat!(env!("OBJTREE"), "/rust/bindings_generated.rs"));
+}
+
+// When both a directly exposed symbol and a helper exists for the same function,
+// the directly exposed symbol is preferred and the helper becomes dead code, so
+// ignore the warning here.
+#[allow(dead_code)]
+mod bindings_helper {
+    // Import the generated bindings for types.
+    use super::bindings_raw::*;
+    use crate::c_types;
+    include!(concat!(
+        env!("OBJTREE"),
+        "/rust/bindings_helpers_generated.rs"
+    ));
+}
+
+pub use bindings_raw::*;
+
+pub const GFP_KERNEL: gfp_t = BINDINGS_GFP_KERNEL;
+pub const __GFP_ZERO: gfp_t = BINDINGS___GFP_ZERO;
+pub const __GFP_HIGHMEM: gfp_t = ___GFP_HIGHMEM;
diff --git a/rust/kernel/bindings_helper.h b/rust/kernel/bindings_helper.h
new file mode 100644
index 000000000000..55c3f25a54eb
--- /dev/null
+++ b/rust/kernel/bindings_helper.h
@@ -0,0 +1,30 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#include <linux/cdev.h>
+#include <linux/errname.h>
+#include <linux/fs.h>
+#include <linux/module.h>
+#include <linux/random.h>
+#include <linux/slab.h>
+#include <linux/sysctl.h>
+#include <linux/uaccess.h>
+#include <linux/uio.h>
+#include <linux/version.h>
+#include <linux/miscdevice.h>
+#include <linux/poll.h>
+#include <linux/mm.h>
+#include <linux/file.h>
+#include <uapi/linux/android/binder.h>
+#include <linux/platform_device.h>
+#include <linux/of_platform.h>
+#include <linux/security.h>
+#include <asm/io.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/irqdomain.h>
+#include <linux/amba/bus.h>
+#include <linux/gpio/driver.h>
+
+// `bindgen` gets confused at certain things
+const gfp_t BINDINGS_GFP_KERNEL = GFP_KERNEL;
+const gfp_t BINDINGS___GFP_ZERO = __GFP_ZERO;
diff --git a/rust/kernel/buffer.rs b/rust/kernel/buffer.rs
new file mode 100644
index 000000000000..48f429065323
--- /dev/null
+++ b/rust/kernel/buffer.rs
@@ -0,0 +1,52 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Struct for writing to a pre-allocated buffer with the [`write!`] macro.
+
+use core::fmt;
+
+/// A pre-allocated buffer that implements [`core::fmt::Write`].
+///
+/// Consecutive writes will append to what has already been written.
+/// Writes that don't fit in the buffer will fail.
+pub struct Buffer<'a> {
+    slice: &'a mut [u8],
+    pos: usize,
+}
+
+impl<'a> Buffer<'a> {
+    /// Creates a new buffer from an existing array.
+    pub fn new(slice: &'a mut [u8]) -> Self {
+        Buffer { slice, pos: 0 }
+    }
+
+    /// Creates a new buffer from a raw pointer.
+    ///
+    /// # Safety
+    ///
+    /// `ptr` must be valid for read and writes, have at least `len` bytes in
+    /// size, and remain valid and not be used by other threads for the lifetime
+    /// of the returned instance.
+    pub unsafe fn from_raw(ptr: *mut u8, len: usize) -> Self {
+        // SAFETY: The safety requirements of the function satisfy those of
+        // `from_raw_parts_mut`.
+        Self::new(unsafe { core::slice::from_raw_parts_mut(ptr, len) })
+    }
+
+    /// Number of bytes that have already been written to the buffer.
+    /// This will always be less than the length of the original array.
+    pub fn bytes_written(&self) -> usize {
+        self.pos
+    }
+}
+
+impl fmt::Write for Buffer<'_> {
+    fn write_str(&mut self, s: &str) -> fmt::Result {
+        if s.len() > self.slice.len() - self.pos {
+            Err(fmt::Error)
+        } else {
+            self.slice[self.pos..self.pos + s.len()].copy_from_slice(s.as_bytes());
+            self.pos += s.len();
+            Ok(())
+        }
+    }
+}
diff --git a/rust/kernel/build_assert.rs b/rust/kernel/build_assert.rs
new file mode 100644
index 000000000000..f726927185c0
--- /dev/null
+++ b/rust/kernel/build_assert.rs
@@ -0,0 +1,80 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Build-time assert.
+
+/// Fails the build if the code path calling `build_error!` can possibly be executed.
+///
+/// If the macro is executed in const context, `build_error!` will panic.
+/// If the compiler or optimizer cannot guarantee that `build_error!` can never
+/// be called, a build error will be triggered.
+///
+/// # Examples
+/// ```
+/// # use kernel::build_error;
+/// #[inline]
+/// fn foo(a: usize) -> usize {
+///     a.checked_add(1).unwrap_or_else(|| build_error!("overflow"))
+/// }
+/// ```
+#[macro_export]
+macro_rules! build_error {
+    () => {{
+        $crate::build_error("")
+    }};
+    ($msg:expr) => {{
+        $crate::build_error($msg)
+    }};
+}
+
+/// Asserts that a boolean expression is `true` at compile time.
+///
+/// If the condition is evaluated to `false` in const context, `build_assert!`
+/// will panic. If the compiler or optimizer cannot guarantee the condition will
+/// be evaluated to `true`, a build error will be triggered.
+///
+/// [`static_assert!`] should be preferred to `build_assert!` whenever possible.
+///
+/// # Examples
+///
+/// These examples show that different types of [`assert!`] will trigger errors
+/// at different stage of compilation. It is preferred to err as early as
+/// possible, so [`static_assert!`] should be used whenever possible.
+/// ```compile_fail
+/// # use kernel::prelude::*;
+/// fn foo() {
+///     static_assert!(1 > 1); // Compile-time error
+///     build_assert!(1 > 1); // Build-time error
+///     assert!(1 > 1); // Run-time error
+/// }
+/// ```
+///
+/// When the condition refers to generic parameters or parameters of an inline function,
+/// [`static_assert!`] cannot be used. Use `build_assert!` in this scenario.
+/// ```no_run
+/// # use kernel::prelude::*;
+/// fn foo<const N: usize>() {
+///     // `static_assert!(N > 1);` is not allowed
+///     build_assert!(N > 1); // Build-time check
+///     assert!(N > 1); // Run-time check
+/// }
+///
+/// #[inline]
+/// fn bar(n: usize) {
+///     // `static_assert!(n > 1);` is not allowed
+///     build_assert!(n > 1); // Build-time check
+///     assert!(n > 1); // Run-time check
+/// }
+/// ```
+#[macro_export]
+macro_rules! build_assert {
+    ($cond:expr $(,)?) => {{
+        if !$cond {
+            $crate::build_error(concat!("assertion failed: ", stringify!($cond)));
+        }
+    }};
+    ($cond:expr, $msg:expr) => {{
+        if !$cond {
+            $crate::build_error($msg);
+        }
+    }};
+}
diff --git a/rust/kernel/c_types.rs b/rust/kernel/c_types.rs
new file mode 100644
index 000000000000..07593a3ba8be
--- /dev/null
+++ b/rust/kernel/c_types.rs
@@ -0,0 +1,119 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! C types for the bindings.
+//!
+//! The bindings generated by `bindgen` use these types to map to the C ones.
+//!
+//! C's standard integer types may differ in width depending on
+//! the architecture, thus we need to conditionally compile those.
+
+#![allow(non_camel_case_types)]
+
+#[cfg(any(target_arch = "arm", target_arch = "x86", target_arch = "riscv32",))]
+mod c {
+    /// C `void` type.
+    pub type c_void = core::ffi::c_void;
+
+    /// C `char` type.
+    pub type c_char = i8;
+
+    /// C `signed char` type.
+    pub type c_schar = i8;
+
+    /// C `unsigned char` type.
+    pub type c_uchar = u8;
+
+    /// C `short` type.
+    pub type c_short = i16;
+
+    /// C `unsigned short` type.
+    pub type c_ushort = u16;
+
+    /// C `int` type.
+    pub type c_int = i32;
+
+    /// C `unsigned int` type.
+    pub type c_uint = u32;
+
+    /// C `long` type.
+    pub type c_long = i32;
+
+    /// C `unsigned long` type.
+    pub type c_ulong = u32;
+
+    /// C `long long` type.
+    pub type c_longlong = i64;
+
+    /// C `unsigned long long` type.
+    pub type c_ulonglong = u64;
+
+    /// C `ssize_t` type (typically defined in `<sys/types.h>` by POSIX).
+    ///
+    /// For some 32-bit architectures like this one, the kernel defines it as
+    /// `int`, i.e. it is an [`i32`].
+    pub type c_ssize_t = isize;
+
+    /// C `size_t` type (typically defined in `<stddef.h>`).
+    ///
+    /// For some 32-bit architectures like this one, the kernel defines it as
+    /// `unsigned int`, i.e. it is an [`u32`].
+    pub type c_size_t = usize;
+}
+
+#[cfg(any(
+    target_arch = "aarch64",
+    target_arch = "x86_64",
+    target_arch = "powerpc64",
+    target_arch = "riscv64",
+))]
+mod c {
+    /// C `void` type.
+    pub type c_void = core::ffi::c_void;
+
+    /// C `char` type.
+    pub type c_char = i8;
+
+    /// C `signed char` type.
+    pub type c_schar = i8;
+
+    /// C `unsigned char` type.
+    pub type c_uchar = u8;
+
+    /// C `short` type.
+    pub type c_short = i16;
+
+    /// C `unsigned short` type.
+    pub type c_ushort = u16;
+
+    /// C `int` type.
+    pub type c_int = i32;
+
+    /// C `unsigned int` type.
+    pub type c_uint = u32;
+
+    /// C `long` type.
+    pub type c_long = i64;
+
+    /// C `unsigned long` type.
+    pub type c_ulong = u64;
+
+    /// C `long long` type.
+    pub type c_longlong = i64;
+
+    /// C `unsigned long long` type.
+    pub type c_ulonglong = u64;
+
+    /// C `ssize_t` type (typically defined in `<sys/types.h>` by POSIX).
+    ///
+    /// For 64-bit architectures like this one, the kernel defines it as
+    /// `long`, i.e. it is an [`i64`].
+    pub type c_ssize_t = isize;
+
+    /// C `size_t` type (typically defined in `<stddef.h>`).
+    ///
+    /// For 64-bit architectures like this one, the kernel defines it as
+    /// `unsigned long`, i.e. it is an [`u64`].
+    pub type c_size_t = usize;
+}
+
+pub use c::*;
diff --git a/rust/kernel/chrdev.rs b/rust/kernel/chrdev.rs
new file mode 100644
index 000000000000..20e93ec05def
--- /dev/null
+++ b/rust/kernel/chrdev.rs
@@ -0,0 +1,212 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Character devices.
+//!
+//! Also called "char devices", `chrdev`, `cdev`.
+//!
+//! C header: [`include/linux/cdev.h`](../../../../include/linux/cdev.h)
+//!
+//! Reference: <https://www.kernel.org/doc/html/latest/core-api/kernel-api.html#char-devices>
+
+use alloc::boxed::Box;
+use core::convert::TryInto;
+use core::marker::PhantomPinned;
+use core::pin::Pin;
+
+use crate::bindings;
+use crate::c_types;
+use crate::error::{Error, Result};
+use crate::file_operations;
+use crate::str::CStr;
+
+/// Character device.
+///
+/// # Invariants
+///
+/// - [`self.0`] is valid and non-null.
+/// - [`(*self.0).ops`] is valid, non-null and has static lifetime.
+/// - [`(*self.0).owner`] is valid and, if non-null, has module lifetime.
+struct Cdev(*mut bindings::cdev);
+
+impl Cdev {
+    fn alloc(
+        fops: &'static bindings::file_operations,
+        module: &'static crate::ThisModule,
+    ) -> Result<Self> {
+        // SAFETY: FFI call.
+        let cdev = unsafe { bindings::cdev_alloc() };
+        if cdev.is_null() {
+            return Err(Error::ENOMEM);
+        }
+        // SAFETY: `cdev` is valid and non-null since `cdev_alloc()`
+        // returned a valid pointer which was null-checked.
+        unsafe {
+            (*cdev).ops = fops;
+            (*cdev).owner = module.0;
+        }
+        // INVARIANTS:
+        // - [`self.0`] is valid and non-null.
+        // - [`(*self.0).ops`] is valid, non-null and has static lifetime,
+        //   because it was coerced from a reference with static lifetime.
+        // - [`(*self.0).owner`] is valid and, if non-null, has module lifetime,
+        //   guaranteed by the [`ThisModule`] invariant.
+        Ok(Self(cdev))
+    }
+
+    fn add(&mut self, dev: bindings::dev_t, count: c_types::c_uint) -> Result {
+        // SAFETY: according to the type invariants:
+        // - [`self.0`] can be safely passed to [`bindings::cdev_add`].
+        // - [`(*self.0).ops`] will live at least as long as [`self.0`].
+        // - [`(*self.0).owner`] will live at least as long as the
+        //   module, which is an implicit requirement.
+        let rc = unsafe { bindings::cdev_add(self.0, dev, count) };
+        if rc != 0 {
+            return Err(Error::from_kernel_errno(rc));
+        }
+        Ok(())
+    }
+}
+
+impl Drop for Cdev {
+    fn drop(&mut self) {
+        // SAFETY: [`self.0`] is valid and non-null by the type invariants.
+        unsafe {
+            bindings::cdev_del(self.0);
+        }
+    }
+}
+
+struct RegistrationInner<const N: usize> {
+    dev: bindings::dev_t,
+    used: usize,
+    cdevs: [Option<Cdev>; N],
+    _pin: PhantomPinned,
+}
+
+/// Character device registration.
+///
+/// May contain up to a fixed number (`N`) of devices. Must be pinned.
+pub struct Registration<const N: usize> {
+    name: &'static CStr,
+    minors_start: u16,
+    this_module: &'static crate::ThisModule,
+    inner: Option<RegistrationInner<N>>,
+}
+
+impl<const N: usize> Registration<{ N }> {
+    /// Creates a [`Registration`] object for a character device.
+    ///
+    /// This does *not* register the device: see [`Self::register()`].
+    ///
+    /// This associated function is intended to be used when you need to avoid
+    /// a memory allocation, e.g. when the [`Registration`] is a member of
+    /// a bigger structure inside your [`crate::KernelModule`] instance. If you
+    /// are going to pin the registration right away, call
+    /// [`Self::new_pinned()`] instead.
+    pub fn new(
+        name: &'static CStr,
+        minors_start: u16,
+        this_module: &'static crate::ThisModule,
+    ) -> Self {
+        Registration {
+            name,
+            minors_start,
+            this_module,
+            inner: None,
+        }
+    }
+
+    /// Creates a pinned [`Registration`] object for a character device.
+    ///
+    /// This does *not* register the device: see [`Self::register()`].
+    pub fn new_pinned(
+        name: &'static CStr,
+        minors_start: u16,
+        this_module: &'static crate::ThisModule,
+    ) -> Result<Pin<Box<Self>>> {
+        Ok(Pin::from(Box::try_new(Self::new(
+            name,
+            minors_start,
+            this_module,
+        ))?))
+    }
+
+    /// Registers a character device.
+    ///
+    /// You may call this once per device type, up to `N` times.
+    pub fn register<T: file_operations::FileOpener<()>>(self: Pin<&mut Self>) -> Result {
+        // SAFETY: We must ensure that we never move out of `this`.
+        let this = unsafe { self.get_unchecked_mut() };
+        if this.inner.is_none() {
+            let mut dev: bindings::dev_t = 0;
+            // SAFETY: Calling unsafe function. `this.name` has `'static`
+            // lifetime.
+            let res = unsafe {
+                bindings::alloc_chrdev_region(
+                    &mut dev,
+                    this.minors_start.into(),
+                    N.try_into()?,
+                    this.name.as_char_ptr(),
+                )
+            };
+            if res != 0 {
+                return Err(Error::from_kernel_errno(res));
+            }
+            const NONE: Option<Cdev> = None;
+            this.inner = Some(RegistrationInner {
+                dev,
+                used: 0,
+                cdevs: [NONE; N],
+                _pin: PhantomPinned,
+            });
+        }
+
+        let mut inner = this.inner.as_mut().unwrap();
+        if inner.used == N {
+            return Err(Error::EINVAL);
+        }
+
+        // SAFETY: The adapter doesn't retrieve any state yet, so it's compatible with any
+        // registration.
+        let fops = unsafe { file_operations::FileOperationsVtable::<Self, T>::build() };
+        let mut cdev = Cdev::alloc(fops, this.this_module)?;
+        cdev.add(inner.dev + inner.used as bindings::dev_t, 1)?;
+        inner.cdevs[inner.used].replace(cdev);
+        inner.used += 1;
+        Ok(())
+    }
+}
+
+impl<const N: usize> file_operations::FileOpenAdapter for Registration<{ N }> {
+    type Arg = ();
+
+    unsafe fn convert(
+        _inode: *mut bindings::inode,
+        _file: *mut bindings::file,
+    ) -> *const Self::Arg {
+        // TODO: Update the SAFETY comment on the call to `FileOperationsVTable::build` above once
+        // this is updated to retrieve state.
+        &()
+    }
+}
+
+// SAFETY: `Registration` does not expose any of its state across threads
+// (it is fine for multiple threads to have a shared reference to it).
+unsafe impl<const N: usize> Sync for Registration<{ N }> {}
+
+impl<const N: usize> Drop for Registration<{ N }> {
+    fn drop(&mut self) {
+        if let Some(inner) = self.inner.as_mut() {
+            // Replicate kernel C behaviour: drop [`Cdev`]s before calling
+            // [`bindings::unregister_chrdev_region`].
+            for i in 0..inner.used {
+                inner.cdevs[i].take();
+            }
+            // SAFETY: [`self.inner`] is Some, so [`inner.dev`] was previously
+            // created using [`bindings::alloc_chrdev_region`].
+            unsafe {
+                bindings::unregister_chrdev_region(inner.dev, N.try_into().unwrap());
+            }
+        }
+    }
+}
diff --git a/rust/kernel/cred.rs b/rust/kernel/cred.rs
new file mode 100644
index 000000000000..1602aa6935ca
--- /dev/null
+++ b/rust/kernel/cred.rs
@@ -0,0 +1,73 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Credentials management.
+//!
+//! C header: [`include/linux/cred.h`](../../../../include/linux/cred.h)
+//!
+//! Reference: <https://www.kernel.org/doc/html/latest/security/credentials.html>
+
+use crate::bindings;
+use core::{marker::PhantomData, mem::ManuallyDrop, ops::Deref};
+
+/// Wraps the kernel's `struct cred`.
+///
+/// # Invariants
+///
+/// The pointer `Credential::ptr` is non-null and valid. Its reference count is also non-zero.
+pub struct Credential {
+    pub(crate) ptr: *const bindings::cred,
+}
+
+impl Clone for Credential {
+    fn clone(&self) -> Self {
+        // SAFETY: The type invariants guarantee that `self.ptr` has a non-zero reference count.
+        let ptr = unsafe { bindings::get_cred(self.ptr) };
+
+        // INVARIANT: We incremented the reference count to account for the new `Credential` being
+        // created.
+        Self { ptr }
+    }
+}
+
+impl Drop for Credential {
+    fn drop(&mut self) {
+        // SAFETY: The type invariants guarantee that `ptr` has a non-zero reference count.
+        unsafe { bindings::put_cred(self.ptr) };
+    }
+}
+
+/// A wrapper for [`Credential`] that doesn't automatically decrement the refcount when dropped.
+///
+/// We need the wrapper because [`ManuallyDrop`] alone would allow callers to call
+/// [`ManuallyDrop::into_inner`]. This would allow an unsafe sequence to be triggered without
+/// `unsafe` blocks because it would trigger an unbalanced call to `put_cred`.
+///
+/// # Invariants
+///
+/// The wrapped [`Credential`] remains valid for the lifetime of the object.
+pub struct CredentialRef<'a> {
+    cred: ManuallyDrop<Credential>,
+    _p: PhantomData<&'a ()>,
+}
+
+impl CredentialRef<'_> {
+    /// Constructs a new [`struct cred`] wrapper that doesn't change its reference count.
+    ///
+    /// # Safety
+    ///
+    /// The pointer `ptr` must be non-null and valid for the lifetime of the object.
+    pub(crate) unsafe fn from_ptr(ptr: *const bindings::cred) -> Self {
+        Self {
+            cred: ManuallyDrop::new(Credential { ptr }),
+            _p: PhantomData,
+        }
+    }
+}
+
+impl Deref for CredentialRef<'_> {
+    type Target = Credential;
+
+    fn deref(&self) -> &Self::Target {
+        self.cred.deref()
+    }
+}
diff --git a/rust/kernel/device.rs b/rust/kernel/device.rs
new file mode 100644
index 000000000000..417ad9d0ce78
--- /dev/null
+++ b/rust/kernel/device.rs
@@ -0,0 +1,206 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Generic devices that are part of the kernel's driver model.
+//!
+//! C header: [`include/linux/device.h`](../../../../include/linux/device.h)
+
+use crate::{
+    bindings,
+    revocable::{Revocable, RevocableGuard},
+    str::CStr,
+    sync::{NeedsLockClass, RevocableMutex, RevocableMutexGuard, UniqueRef},
+    Result,
+};
+use core::{
+    ops::{Deref, DerefMut},
+    pin::Pin,
+};
+
+/// A raw device.
+///
+/// # Safety
+///
+/// Implementers must ensure that the `*mut device` returned by [`RawDevice::raw_device`] is
+/// related to `self`, that is, actions on it will affect `self`. For example, if one calls
+/// `get_device`, then the refcount on the device represented by `self` will be incremented.
+///
+/// Additionally, implementers must ensure that the device is never renamed. Commit a5462516aa994
+/// has details on why `device_rename` should not be used.
+pub unsafe trait RawDevice {
+    /// Returns the raw `struct device` related to `self`.
+    fn raw_device(&self) -> *mut bindings::device;
+
+    /// Returns the name of the device.
+    fn name(&self) -> &CStr {
+        let ptr = self.raw_device();
+
+        // SAFETY: `ptr` is valid because `self` keeps it alive.
+        let name = unsafe { bindings::dev_name(ptr) };
+
+        // SAFETY: The name of the device remains valid while it is alive (because the device is
+        // never renamed, per the safety requirement of this trait). This is guaranteed to be the
+        // case because the reference to `self` outlives the one of the returned `CStr` (enforced
+        // by the compiler because of their lifetimes).
+        unsafe { CStr::from_char_ptr(name) }
+    }
+}
+
+/// A ref-counted device.
+///
+/// # Invariants
+///
+/// `ptr` is valid, non-null, and has a non-zero reference count. One of the references is owned by
+/// `self`, and will be decremented when `self` is dropped.
+pub struct Device {
+    pub(crate) ptr: *mut bindings::device,
+}
+
+impl Device {
+    /// Creates a new device instance.
+    ///
+    /// # Safety
+    ///
+    /// Callers must ensure that `ptr` is valid, non-null, and has a non-zero reference count.
+    pub unsafe fn new(ptr: *mut bindings::device) -> Self {
+        // SAFETY: By the safety requiments, ptr is valid and its refcounted will be incremented.
+        unsafe { bindings::get_device(ptr) };
+        // INVARIANT: The safety requirements satisfy all but one invariant, which is that `self`
+        // owns a reference. This is satisfied by the call to `get_device` above.
+        Self { ptr }
+    }
+
+    /// Creates a new device instance from an existing [`RawDevice`] instance.
+    pub fn from_dev(dev: &dyn RawDevice) -> Self {
+        // SAFETY: The requirements are satisfied by the existence of `RawDevice` and its safety
+        // requirements.
+        unsafe { Self::new(dev.raw_device()) }
+    }
+}
+
+impl Drop for Device {
+    fn drop(&mut self) {
+        // SAFETY: By the type invariants, we know that `self` owns a reference, so it is safe to
+        // relinquish it now.
+        unsafe { bindings::put_device(self.ptr) };
+    }
+}
+
+/// Device data.
+///
+/// When a device is removed (for whatever reason, for example, because the device was unplugged or
+/// because the user decided to unbind the driver), the driver is given a chance to clean its state
+/// up, and all io resources should ideally not be used anymore.
+///
+/// However, the device data is reference-counted because other subsystems hold pointers to it. So
+/// some device state must be freed and not used anymore, while others must remain accessible.
+///
+/// This struct separates the device data into three categories:
+/// 1. Registrations: are destroyed when the device is removed, but before the io resources
+///    become inaccessible.
+/// 2. Io resources: are available until the device is removed.
+/// 3. General data: remain available as long as the ref count is nonzero.
+///
+/// This struct implements the `DeviceRemoval` trait so that it can clean resources up even if not
+/// explicitly called by the device drivers.
+pub struct Data<T, U, V> {
+    registrations: RevocableMutex<T>,
+    resources: Revocable<U>,
+    general: V,
+}
+
+/// Safely creates an new reference-counted instance of [`Data`].
+#[doc(hidden)]
+#[macro_export]
+macro_rules! new_device_data {
+    ($reg:expr, $res:expr, $gen:expr, $name:literal) => {{
+        static mut CLASS1: core::mem::MaybeUninit<$crate::bindings::lock_class_key> =
+            core::mem::MaybeUninit::uninit();
+        static mut CLASS2: core::mem::MaybeUninit<$crate::bindings::lock_class_key> =
+            core::mem::MaybeUninit::uninit();
+        let regs = $reg;
+        let res = $res;
+        let gen = $gen;
+        let name = $crate::c_str!($name);
+        // SAFETY: `CLASS1` and `CLASS2` are never used by Rust code directly; the C portion of the
+        // kernel may change it though.
+        unsafe {
+            $crate::device::Data::try_new(
+                regs,
+                res,
+                gen,
+                name,
+                CLASS1.as_mut_ptr(),
+                CLASS2.as_mut_ptr(),
+            )
+        }
+    }};
+}
+
+impl<T, U, V> Data<T, U, V> {
+    /// Creates a new instance of `Data`.
+    ///
+    /// It is recommended that the [`new_device_data`] macro be used as it automatically creates
+    /// the lock classes.
+    ///
+    /// # Safety
+    ///
+    /// `key1` and `key2` must point to valid memory locations and remain valid until `self` is
+    /// dropped.
+    pub unsafe fn try_new(
+        registrations: T,
+        resources: U,
+        general: V,
+        name: &'static CStr,
+        key1: *mut bindings::lock_class_key,
+        key2: *mut bindings::lock_class_key,
+    ) -> Result<Pin<UniqueRef<Self>>> {
+        let mut ret = Pin::from(UniqueRef::try_new(Self {
+            // SAFETY: We call `RevocableMutex::init` below.
+            registrations: unsafe { RevocableMutex::new(registrations) },
+            resources: Revocable::new(resources),
+            general,
+        })?);
+
+        // SAFETY: `Data::registrations` is pinned when `Data` is.
+        let pinned = unsafe { ret.as_mut().map_unchecked_mut(|d| &mut d.registrations) };
+
+        // SAFETY: The safety requirements of this function satisfy those of `RevocableMutex::init`.
+        unsafe { pinned.init(name, key1, key2) };
+        Ok(ret)
+    }
+
+    /// Returns the resources if they're still available.
+    pub fn resources(&self) -> Option<RevocableGuard<'_, U>> {
+        self.resources.try_access()
+    }
+
+    /// Returns the locked registrations if they're still available.
+    pub fn registrations(&self) -> Option<RevocableMutexGuard<'_, T>> {
+        self.registrations.try_lock()
+    }
+}
+
+impl<T, U, V> crate::driver::DeviceRemoval for Data<T, U, V> {
+    fn device_remove(&self) {
+        // We revoke the registrations first so that resources are still available to them during
+        // unregistration.
+        self.registrations.revoke();
+
+        // Release resources now. General data remains available.
+        self.resources.revoke();
+    }
+}
+
+impl<T, U, V> Deref for Data<T, U, V> {
+    type Target = V;
+
+    fn deref(&self) -> &V {
+        &self.general
+    }
+}
+
+impl<T, U, V> DerefMut for Data<T, U, V> {
+    fn deref_mut(&mut self) -> &mut V {
+        &mut self.general
+    }
+}
diff --git a/rust/kernel/driver.rs b/rust/kernel/driver.rs
new file mode 100644
index 000000000000..d72ada58138c
--- /dev/null
+++ b/rust/kernel/driver.rs
@@ -0,0 +1,198 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Generic support for drivers of different buses (e.g., PCI, Platform, Amba, etc.).
+//!
+//! Each bus/subsystem is expected to implement [`DriverOps`], which allows drivers to register
+//! using the [`Registration`] class.
+
+use crate::{str::CStr, Error, KernelModule, Result, ScopeGuard, ThisModule};
+use alloc::{boxed::Box, vec::Vec};
+use core::{cell::UnsafeCell, mem::MaybeUninit, pin::Pin};
+
+/// A subsystem (e.g., PCI, Platform, Amba, etc.) that allows drivers to be written for it.
+pub trait DriverOps {
+    /// The type that holds information about the registration. This is typically a struct defined
+    /// by the C portion of the kernel.
+    type RegType: Default;
+
+    /// The type that holds identification data for the devices supported by the driver. In
+    /// addition to the information required by the bus, it may also store device-specific data
+    /// using Rust types.
+    type IdType: 'static;
+
+    /// The table of ids containing all supported devices.
+    const ID_TABLE: &'static [Self::IdType];
+
+    /// The raw type that holds identification data for the devices supported by the driver. This
+    /// is typically a struct defined by the C portion of the kernel.
+    ///
+    /// A zero-terminated array of this type is produced and passed to the C portion during
+    /// registration.
+    type RawIdType;
+
+    /// Registers a driver.
+    ///
+    /// # Safety
+    ///
+    /// `reg` must point to valid, initialised, and writable memory. It may be modified by this
+    /// function to hold registration state.
+    ///
+    /// `id_table` must point to a valid for read zero-terminated array of ids.
+    ///
+    /// On success, `reg` and `id_table` must remain pinned and valid until the matching call to
+    /// [`DriverOps::unregister`].
+    unsafe fn register(
+        reg: *mut Self::RegType,
+        name: &'static CStr,
+        id_table: *const Self::RawIdType,
+    ) -> Result;
+
+    /// Unregisters a driver previously registered with [`DriverOps::register`].
+    ///
+    /// # Safety
+    ///
+    /// `reg` must point to valid writable memory, initialised by a previous successful call to
+    /// [`DriverOps::register`].
+    unsafe fn unregister(reg: *mut Self::RegType);
+
+    /// Converts an id into a raw id.
+    ///
+    /// This is used when building a zero-terminated array from the Rust array.
+    fn to_raw_id(index: usize, id: &Self::IdType) -> Self::RawIdType;
+}
+
+/// The registration of a driver.
+pub struct Registration<T: DriverOps> {
+    is_registered: bool,
+    concrete_reg: UnsafeCell<T::RegType>,
+    id_table: Vec<MaybeUninit<T::RawIdType>>,
+}
+
+// SAFETY: `Registration` has no fields or methods accessible via `&Registration`, so it is safe to
+// share references to it with multiple threads as nothing can be done.
+unsafe impl<T: DriverOps> Sync for Registration<T> {}
+
+impl<T: DriverOps> Registration<T> {
+    /// Creates a new instance of the registration object.
+    pub fn new() -> Self {
+        Self {
+            is_registered: false,
+            concrete_reg: UnsafeCell::new(T::RegType::default()),
+            id_table: Vec::new(),
+        }
+    }
+
+    /// Allocates a pinned registration object and registers it.
+    ///
+    /// Returns a pinned heap-allocated representation of the registration.
+    pub fn new_pinned(name: &'static CStr) -> Result<Pin<Box<Self>>> {
+        let mut reg = Pin::from(Box::try_new(Self::new())?);
+        reg.as_mut().register(name)?;
+        Ok(reg)
+    }
+
+    /// Registers a driver with its subsystem.
+    ///
+    /// It must be pinned because the memory block that represents the registration is potentially
+    /// self-referential.
+    pub fn register(self: Pin<&mut Self>, name: &'static CStr) -> Result {
+        // SAFETY: We never move out of `this`.
+        let this = unsafe { self.get_unchecked_mut() };
+        if this.is_registered {
+            // Already registered.
+            return Err(Error::EINVAL);
+        }
+
+        if this.id_table.is_empty() {
+            this.build_table()?;
+        }
+
+        // SAFETY: `concrete_reg` was initialised via its default constructor. `id_table` was just
+        // initialised above with a zero terminating entry. Both are only freed after `Self::drop`
+        // is called, which first calls `T::unregister`.
+        unsafe {
+            T::register(
+                this.concrete_reg.get(),
+                name,
+                &this.id_table[0] as *const _ as *const _,
+            )
+        }?;
+
+        this.is_registered = true;
+        Ok(())
+    }
+
+    /// Builds the zero-terminated raw-type array of supported devices.
+    ///
+    /// This is not ideal because the table is built at runtime. Once Rust fully supports const
+    /// generics, we can build the table at compile time.
+    fn build_table(&mut self) -> Result {
+        // Clear the table on failure, to indicate that the table isn't initialised.
+        let mut table = ScopeGuard::new_with_data(&mut self.id_table, |t| t.clear());
+
+        table.try_reserve_exact(T::ID_TABLE.len() + 1)?;
+        for (i, id) in T::ID_TABLE.iter().enumerate() {
+            table.try_push(MaybeUninit::new(T::to_raw_id(i, id)))?;
+        }
+        table.try_push(MaybeUninit::zeroed())?;
+        table.dismiss();
+        Ok(())
+    }
+}
+
+impl<T: DriverOps> Default for Registration<T> {
+    fn default() -> Self {
+        Self::new()
+    }
+}
+
+impl<T: DriverOps> Drop for Registration<T> {
+    fn drop(&mut self) {
+        if self.is_registered {
+            // SAFETY: This path only runs if a previous call to `T::register` completed
+            // successfully.
+            unsafe { T::unregister(self.concrete_reg.get()) };
+        }
+    }
+}
+
+/// Custom code within device removal.
+pub trait DeviceRemoval {
+    /// Cleans resources up when the device is removed.
+    ///
+    /// This is called when a device is removed and offers implementers the chance to run some code
+    /// that cleans state up.
+    fn device_remove(&self);
+}
+
+/// A kernel module that only registers the given driver on init.
+///
+/// This is a helper struct to make it easier to define single-functionality modules, in this case,
+/// modules that offer a single driver.
+pub struct Module<T: DriverOps> {
+    _driver: Pin<Box<Registration<T>>>,
+}
+
+impl<T: DriverOps> KernelModule for Module<T> {
+    fn init(name: &'static CStr, _module: &'static ThisModule) -> Result<Self> {
+        Ok(Self {
+            _driver: Registration::new_pinned(name)?,
+        })
+    }
+}
+
+/// Declares a kernel module that exposes a single driver.
+///
+/// It is meant to be used as a helper by other subsystems so they can more easily expose their own
+/// macros.
+#[macro_export]
+macro_rules! module_driver {
+    (<$gen_type:ident>, $driver_ops:ty, { type: $type:ty, $($f:tt)* }) => {
+        type Ops<$gen_type> = $driver_ops;
+        type ModuleType = $crate::driver::Module<Ops<$type>>;
+        $crate::prelude::module! {
+            type: ModuleType,
+            $($f)*
+        }
+    }
+}
diff --git a/rust/kernel/error.rs b/rust/kernel/error.rs
new file mode 100644
index 000000000000..93fa35c4df21
--- /dev/null
+++ b/rust/kernel/error.rs
@@ -0,0 +1,542 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Kernel errors.
+//!
+//! C header: [`include/uapi/asm-generic/errno-base.h`](../../../include/uapi/asm-generic/errno-base.h)
+
+use crate::str::CStr;
+use crate::{bindings, c_types};
+use alloc::{
+    alloc::{AllocError, LayoutError},
+    collections::TryReserveError,
+};
+use core::convert::From;
+use core::fmt;
+use core::num::TryFromIntError;
+use core::str::{self, Utf8Error};
+
+macro_rules! declare_err {
+    ($err:tt) => {
+        pub const $err: Self = Error(-(bindings::$err as i32));
+    };
+    ($err:tt, $($doc:expr),+) => {
+        $(
+        #[doc = $doc]
+        )*
+        pub const $err: Self = Error(-(bindings::$err as i32));
+    };
+}
+
+/// Generic integer kernel error.
+///
+/// The kernel defines a set of integer generic error codes based on C and
+/// POSIX ones. These codes may have a more specific meaning in some contexts.
+///
+/// # Invariants
+///
+/// The value is a valid `errno` (i.e. `>= -MAX_ERRNO && < 0`).
+#[derive(Clone, Copy, PartialEq, Eq)]
+pub struct Error(c_types::c_int);
+
+impl Error {
+    declare_err!(EPERM, "Operation not permitted.");
+
+    declare_err!(ENOENT, "No such file or directory.");
+
+    declare_err!(ESRCH, "No such process.");
+
+    declare_err!(EINTR, "Interrupted system call.");
+
+    declare_err!(EIO, "I/O error.");
+
+    declare_err!(ENXIO, "No such device or address.");
+
+    declare_err!(E2BIG, "Argument list too long.");
+
+    declare_err!(ENOEXEC, "Exec format error.");
+
+    declare_err!(EBADF, "Bad file number.");
+
+    declare_err!(ECHILD, "Exec format error.");
+
+    declare_err!(EAGAIN, "Try again.");
+
+    declare_err!(ENOMEM, "Out of memory.");
+
+    declare_err!(EACCES, "Permission denied.");
+
+    declare_err!(EFAULT, "Bad address.");
+
+    declare_err!(ENOTBLK, "Block device required.");
+
+    declare_err!(EBUSY, "Device or resource busy.");
+
+    declare_err!(EEXIST, "File exists.");
+
+    declare_err!(EXDEV, "Cross-device link.");
+
+    declare_err!(ENODEV, "No such device.");
+
+    declare_err!(ENOTDIR, "Not a directory.");
+
+    declare_err!(EISDIR, "Is a directory.");
+
+    declare_err!(EINVAL, "Invalid argument.");
+
+    declare_err!(ENFILE, "File table overflow.");
+
+    declare_err!(EMFILE, "Too many open files.");
+
+    declare_err!(ENOTTY, "Not a typewriter.");
+
+    declare_err!(ETXTBSY, "Text file busy.");
+
+    declare_err!(EFBIG, "File too large.");
+
+    declare_err!(ENOSPC, "No space left on device.");
+
+    declare_err!(ESPIPE, "Illegal seek.");
+
+    declare_err!(EROFS, "Read-only file system.");
+
+    declare_err!(EMLINK, "Too many links.");
+
+    declare_err!(EPIPE, "Broken pipe.");
+
+    declare_err!(EDOM, "Math argument out of domain of func.");
+
+    declare_err!(ERANGE, "Math result not representable.");
+
+    declare_err!(EDEADLK, "Resource deadlock would occur");
+
+    declare_err!(ENAMETOOLONG, "File name too long");
+
+    declare_err!(ENOLCK, "No record locks available");
+
+    declare_err!(
+        ENOSYS,
+        "Invalid system call number.",
+        "",
+        "This error code is special: arch syscall entry code will return",
+        "[`Self::ENOSYS`] if users try to call a syscall that doesn't exist.",
+        "To keep failures of syscalls that really do exist distinguishable from",
+        "failures due to attempts to use a nonexistent syscall, syscall",
+        "implementations should refrain from returning [`Self::ENOSYS`]."
+    );
+
+    declare_err!(ENOTEMPTY, "Directory not empty.");
+
+    declare_err!(ELOOP, "Too many symbolic links encountered.");
+
+    declare_err!(EWOULDBLOCK, "Operation would block.");
+
+    declare_err!(ENOMSG, "No message of desired type.");
+
+    declare_err!(EIDRM, "Identifier removed.");
+
+    declare_err!(ECHRNG, "Channel number out of range.");
+
+    declare_err!(EL2NSYNC, "Level 2 not synchronized.");
+
+    declare_err!(EL3HLT, "Level 3 halted.");
+
+    declare_err!(EL3RST, "Level 3 reset.");
+
+    declare_err!(ELNRNG, "Link number out of range.");
+
+    declare_err!(EUNATCH, "Protocol driver not attached.");
+
+    declare_err!(ENOCSI, "No CSI structure available.");
+
+    declare_err!(EL2HLT, "Level 2 halted.");
+
+    declare_err!(EBADE, "Invalid exchange.");
+
+    declare_err!(EBADR, "Invalid request descriptor.");
+
+    declare_err!(EXFULL, "Exchange full.");
+
+    declare_err!(ENOANO, "No anode.");
+
+    declare_err!(EBADRQC, "Invalid request code.");
+
+    declare_err!(EBADSLT, "Invalid slot.");
+
+    declare_err!(EDEADLOCK, "Resource deadlock would occur.");
+
+    declare_err!(EBFONT, "Bad font file format.");
+
+    declare_err!(ENOSTR, "Device not a stream.");
+
+    declare_err!(ENODATA, "No data available.");
+
+    declare_err!(ETIME, "Timer expired.");
+
+    declare_err!(ENOSR, "Out of streams resources.");
+
+    declare_err!(ENONET, "Machine is not on the network.");
+
+    declare_err!(ENOPKG, "Package not installed.");
+
+    declare_err!(EREMOTE, "Object is remote.");
+
+    declare_err!(ENOLINK, "Link has been severed.");
+
+    declare_err!(EADV, "Advertise error.");
+
+    declare_err!(ESRMNT, "Srmount error.");
+
+    declare_err!(ECOMM, "Communication error on send.");
+
+    declare_err!(EPROTO, "Protocol error.");
+
+    declare_err!(EMULTIHOP, "Multihop attempted.");
+
+    declare_err!(EDOTDOT, "RFS specific error.");
+
+    declare_err!(EBADMSG, "Not a data message.");
+
+    declare_err!(EOVERFLOW, "Value too large for defined data type.");
+
+    declare_err!(ENOTUNIQ, "Name not unique on network.");
+
+    declare_err!(EBADFD, "File descriptor in bad state.");
+
+    declare_err!(EREMCHG, "Remote address changed.");
+
+    declare_err!(ELIBACC, "Can not access a needed shared library.");
+
+    declare_err!(ELIBBAD, "Accessing a corrupted shared library.");
+
+    declare_err!(ELIBSCN, ".lib section in a.out corrupted.");
+
+    declare_err!(ELIBMAX, "Attempting to link in too many shared libraries.");
+
+    declare_err!(ELIBEXEC, "Cannot exec a shared library directly.");
+
+    declare_err!(EILSEQ, "Illegal byte sequence.");
+
+    declare_err!(ERESTART, "Interrupted system call should be restarted.");
+
+    declare_err!(ESTRPIPE, "Streams pipe error.");
+
+    declare_err!(EUSERS, "Too many users.");
+
+    declare_err!(ENOTSOCK, "Socket operation on non-socket.");
+
+    declare_err!(EDESTADDRREQ, "Destination address required.");
+
+    declare_err!(EMSGSIZE, "Message too long.");
+
+    declare_err!(EPROTOTYPE, "Protocol wrong type for socket.");
+
+    declare_err!(ENOPROTOOPT, "Protocol not available.");
+
+    declare_err!(EPROTONOSUPPORT, "Protocol not supported.");
+
+    declare_err!(ESOCKTNOSUPPORT, "Socket type not supported.");
+
+    declare_err!(EOPNOTSUPP, "Operation not supported on transport endpoint.");
+
+    declare_err!(EPFNOSUPPORT, "Protocol family not supported.");
+
+    declare_err!(EAFNOSUPPORT, "Address family not supported by protocol.");
+
+    declare_err!(EADDRINUSE, "Address already in use.");
+
+    declare_err!(EADDRNOTAVAIL, "Cannot assign requested address.");
+
+    declare_err!(ENETDOWN, "Network is down.");
+
+    declare_err!(ENETUNREACH, "Network is unreachable.");
+
+    declare_err!(ENETRESET, "Network dropped connection because of reset.");
+
+    declare_err!(ECONNABORTED, "Software caused connection abort.");
+
+    declare_err!(ECONNRESET, "Connection reset by peer.");
+
+    declare_err!(ENOBUFS, "No buffer space available.");
+
+    declare_err!(EISCONN, "Transport endpoint is already connected.");
+
+    declare_err!(ENOTCONN, "Transport endpoint is not connected.");
+
+    declare_err!(ESHUTDOWN, "Cannot send after transport endpoint shutdown.");
+
+    declare_err!(ETOOMANYREFS, "Too many references: cannot splice.");
+
+    declare_err!(ETIMEDOUT, "Connection timed out.");
+
+    declare_err!(ECONNREFUSED, "Connection refused.");
+
+    declare_err!(EHOSTDOWN, "Host is down.");
+
+    declare_err!(EHOSTUNREACH, "No route to host.");
+
+    declare_err!(EALREADY, "Operation already in progress.");
+
+    declare_err!(EINPROGRESS, "Operation now in progress.");
+
+    declare_err!(ESTALE, "Stale file handle.");
+
+    declare_err!(EUCLEAN, "Structure needs cleaning.");
+
+    declare_err!(ENOTNAM, "Not a XENIX named type file.");
+
+    declare_err!(ENAVAIL, "No XENIX semaphores available.");
+
+    declare_err!(EISNAM, "Is a named type file.");
+
+    declare_err!(EREMOTEIO, "Remote I/O error.");
+
+    declare_err!(EDQUOT, "Quota exceeded.");
+
+    declare_err!(ENOMEDIUM, "No medium found.");
+
+    declare_err!(EMEDIUMTYPE, "Wrong medium type.");
+
+    declare_err!(ECANCELED, "Operation Canceled.");
+
+    declare_err!(ENOKEY, "Required key not available.");
+
+    declare_err!(EKEYEXPIRED, "Key has expired.");
+
+    declare_err!(EKEYREVOKED, "Key has been revoked.");
+
+    declare_err!(EKEYREJECTED, "Key was rejected by service.");
+
+    declare_err!(EOWNERDEAD, "Owner died.", "", "For robust mutexes.");
+
+    declare_err!(ENOTRECOVERABLE, "State not recoverable.");
+
+    declare_err!(ERFKILL, "Operation not possible due to RF-kill.");
+
+    declare_err!(EHWPOISON, "Memory page has hardware error.");
+
+    declare_err!(ERESTARTSYS, "Restart the system call.");
+
+    declare_err!(ENOTSUPP, "Operation is not supported.");
+
+    /// Creates an [`Error`] from a kernel error code.
+    ///
+    /// It is a bug to pass an out-of-range `errno`. `EINVAL` would
+    /// be returned in such a case.
+    pub(crate) fn from_kernel_errno(errno: c_types::c_int) -> Error {
+        if errno < -(bindings::MAX_ERRNO as i32) || errno >= 0 {
+            // TODO: make it a `WARN_ONCE` once available.
+            crate::pr_warn!(
+                "attempted to create `Error` with out of range `errno`: {}",
+                errno
+            );
+            return Error::EINVAL;
+        }
+
+        // INVARIANT: the check above ensures the type invariant
+        // will hold.
+        Error(errno)
+    }
+
+    /// Creates an [`Error`] from a kernel error code.
+    ///
+    /// # Safety
+    ///
+    /// `errno` must be within error code range (i.e. `>= -MAX_ERRNO && < 0`).
+    pub(crate) unsafe fn from_kernel_errno_unchecked(errno: c_types::c_int) -> Error {
+        // INVARIANT: the contract ensures the type invariant
+        // will hold.
+        Error(errno)
+    }
+
+    /// Returns the kernel error code.
+    pub fn to_kernel_errno(self) -> c_types::c_int {
+        self.0
+    }
+}
+
+impl fmt::Debug for Error {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        // SAFETY: FFI call.
+        let name = unsafe { bindings::errname(-self.0) };
+
+        if name.is_null() {
+            // Print out number if no name can be found.
+            return f.debug_tuple("Error").field(&-self.0).finish();
+        }
+
+        // SAFETY: `'static` string from C, and is not NULL.
+        let cstr = unsafe { CStr::from_char_ptr(name) };
+        // SAFETY: These strings are ASCII-only.
+        let str = unsafe { str::from_utf8_unchecked(cstr) };
+        f.debug_tuple(str).finish()
+    }
+}
+
+impl From<TryFromIntError> for Error {
+    fn from(_: TryFromIntError) -> Error {
+        Error::EINVAL
+    }
+}
+
+impl From<Utf8Error> for Error {
+    fn from(_: Utf8Error) -> Error {
+        Error::EINVAL
+    }
+}
+
+impl From<TryReserveError> for Error {
+    fn from(_: TryReserveError) -> Error {
+        Error::ENOMEM
+    }
+}
+
+impl From<LayoutError> for Error {
+    fn from(_: LayoutError) -> Error {
+        Error::ENOMEM
+    }
+}
+
+impl From<core::fmt::Error> for Error {
+    fn from(_: core::fmt::Error) -> Error {
+        Error::EINVAL
+    }
+}
+
+/// A [`Result`] with an [`Error`] error type.
+///
+/// To be used as the return type for functions that may fail.
+///
+/// # Error codes in C and Rust
+///
+/// In C, it is common that functions indicate success or failure through
+/// their return value; modifying or returning extra data through non-`const`
+/// pointer parameters. In particular, in the kernel, functions that may fail
+/// typically return an `int` that represents a generic error code. We model
+/// those as [`Error`].
+///
+/// In Rust, it is idiomatic to model functions that may fail as returning
+/// a [`Result`]. Since in the kernel many functions return an error code,
+/// [`Result`] is a type alias for a [`core::result::Result`] that uses
+/// [`Error`] as its error type.
+///
+/// Note that even if a function does not return anything when it succeeds,
+/// it should still be modeled as returning a `Result` rather than
+/// just an [`Error`].
+pub type Result<T = ()> = core::result::Result<T, Error>;
+
+impl From<AllocError> for Error {
+    fn from(_: AllocError) -> Error {
+        Error::ENOMEM
+    }
+}
+
+// # Invariant: `-bindings::MAX_ERRNO` fits in an `i16`.
+crate::static_assert!(bindings::MAX_ERRNO <= -(i16::MIN as i32) as u32);
+
+pub(crate) fn from_kernel_result_helper<T>(r: Result<T>) -> T
+where
+    T: From<i16>,
+{
+    match r {
+        Ok(v) => v,
+        // NO-OVERFLOW: negative `errno`s are no smaller than `-bindings::MAX_ERRNO`,
+        // `-bindings::MAX_ERRNO` fits in an `i16` as per invariant above,
+        // therefore a negative `errno` always fits in an `i16` and will not overflow.
+        Err(e) => T::from(e.to_kernel_errno() as i16),
+    }
+}
+
+/// Transforms a [`crate::error::Result<T>`] to a kernel C integer result.
+///
+/// This is useful when calling Rust functions that return [`crate::error::Result<T>`]
+/// from inside `extern "C"` functions that need to return an integer
+/// error result.
+///
+/// `T` should be convertible to an `i16` via `From<i16>`.
+///
+/// # Examples
+///
+/// ```ignore
+/// # use kernel::from_kernel_result;
+/// # use kernel::c_types;
+/// # use kernel::bindings;
+/// unsafe extern "C" fn probe_callback(
+///     pdev: *mut bindings::platform_device,
+/// ) -> c_types::c_int {
+///     from_kernel_result! {
+///         let ptr = devm_alloc(pdev)?;
+///         bindings::platform_set_drvdata(pdev, ptr);
+///         Ok(0)
+///     }
+/// }
+/// ```
+macro_rules! from_kernel_result {
+    ($($tt:tt)*) => {{
+        $crate::error::from_kernel_result_helper((|| {
+            $($tt)*
+        })())
+    }};
+}
+
+pub(crate) use from_kernel_result;
+
+/// Transform a kernel "error pointer" to a normal pointer.
+///
+/// Some kernel C API functions return an "error pointer" which optionally
+/// embeds an `errno`. Callers are supposed to check the returned pointer
+/// for errors. This function performs the check and converts the "error pointer"
+/// to a normal pointer in an idiomatic fashion.
+///
+/// # Examples
+///
+/// ```ignore
+/// # use kernel::prelude::*;
+/// # use kernel::from_kernel_err_ptr;
+/// # use kernel::c_types;
+/// # use kernel::bindings;
+/// fn devm_platform_ioremap_resource(
+///     pdev: &mut PlatformDevice,
+///     index: u32,
+/// ) -> Result<*mut c_types::c_void> {
+///     // SAFETY: FFI call.
+///     unsafe {
+///         from_kernel_err_ptr(bindings::devm_platform_ioremap_resource(
+///             pdev.to_ptr(),
+///             index,
+///         ))
+///     }
+/// }
+/// ```
+// TODO: remove `dead_code` marker once an in-kernel client is available.
+#[allow(dead_code)]
+pub(crate) fn from_kernel_err_ptr<T>(ptr: *mut T) -> Result<*mut T> {
+    // CAST: casting a pointer to `*const c_types::c_void` is always valid.
+    let const_ptr: *const c_types::c_void = ptr.cast();
+    // SAFETY: the FFI function does not deref the pointer.
+    if unsafe { bindings::IS_ERR(const_ptr) } {
+        // SAFETY: the FFI function does not deref the pointer.
+        let err = unsafe { bindings::PTR_ERR(const_ptr) };
+        // CAST: if `IS_ERR()` returns `true`,
+        // then `PTR_ERR()` is guaranteed to return a
+        // negative value greater-or-equal to `-bindings::MAX_ERRNO`,
+        // which always fits in an `i16`, as per the invariant above.
+        // And an `i16` always fits in an `i32`. So casting `err` to
+        // an `i32` can never overflow, and is always valid.
+        //
+        // SAFETY: `IS_ERR()` ensures `err` is a
+        // negative value greater-or-equal to `-bindings::MAX_ERRNO`
+        return Err(unsafe { Error::from_kernel_errno_unchecked(err as i32) });
+    }
+    Ok(ptr)
+}
+
+/// Calls a kernel function that returns an integer error code on failure and converts the result
+/// to a [`Result`].
+pub fn to_result(func: impl FnOnce() -> c_types::c_int) -> Result {
+    let err = func();
+    if err < 0 {
+        Err(Error::from_kernel_errno(err))
+    } else {
+        Ok(())
+    }
+}
diff --git a/rust/kernel/file.rs b/rust/kernel/file.rs
new file mode 100644
index 000000000000..d2c0eefc9f68
--- /dev/null
+++ b/rust/kernel/file.rs
@@ -0,0 +1,141 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Files and file descriptors.
+//!
+//! C headers: [`include/linux/fs.h`](../../../../include/linux/fs.h) and
+//! [`include/linux/file.h`](../../../../include/linux/file.h)
+
+use crate::{bindings, cred::CredentialRef, error::Error, Result};
+use core::{mem::ManuallyDrop, ops::Deref};
+
+/// Wraps the kernel's `struct file`.
+///
+/// # Invariants
+///
+/// The pointer `File::ptr` is non-null and valid. Its reference count is also non-zero.
+pub struct File {
+    pub(crate) ptr: *mut bindings::file,
+}
+
+impl File {
+    /// Constructs a new [`struct file`] wrapper from a file descriptor.
+    ///
+    /// The file descriptor belongs to the current process.
+    pub fn from_fd(fd: u32) -> Result<Self> {
+        // SAFETY: FFI call, there are no requirements on `fd`.
+        let ptr = unsafe { bindings::fget(fd) };
+        if ptr.is_null() {
+            return Err(Error::EBADF);
+        }
+
+        // INVARIANTS: We checked that `ptr` is non-null, so it is valid. `fget` increments the ref
+        // count before returning.
+        Ok(Self { ptr })
+    }
+
+    /// Returns the current seek/cursor/pointer position (`struct file::f_pos`).
+    pub fn pos(&self) -> u64 {
+        // SAFETY: `File::ptr` is guaranteed to be valid by the type invariants.
+        unsafe { (*self.ptr).f_pos as u64 }
+    }
+
+    /// Returns whether the file is in blocking mode.
+    pub fn is_blocking(&self) -> bool {
+        // SAFETY: `File::ptr` is guaranteed to be valid by the type invariants.
+        unsafe { (*self.ptr).f_flags & bindings::O_NONBLOCK == 0 }
+    }
+
+    /// Returns the credentials of the task that originally opened the file.
+    pub fn cred(&self) -> CredentialRef<'_> {
+        // SAFETY: `File::ptr` is guaranteed to be valid by the type invariants.
+        let ptr = unsafe { (*self.ptr).f_cred };
+        // SAFETY: The lifetimes of `self` and `CredentialRef` are tied, so it is guaranteed that
+        // the credential pointer remains valid (because the file is still alive, and it doesn't
+        // change over the lifetime of a file).
+        unsafe { CredentialRef::from_ptr(ptr) }
+    }
+}
+
+impl Drop for File {
+    fn drop(&mut self) {
+        // SAFETY: The type invariants guarantee that `File::ptr` has a non-zero reference count.
+        unsafe { bindings::fput(self.ptr) };
+    }
+}
+
+/// A wrapper for [`File`] that doesn't automatically decrement the refcount when dropped.
+///
+/// We need the wrapper because [`ManuallyDrop`] alone would allow callers to call
+/// [`ManuallyDrop::into_inner`]. This would allow an unsafe sequence to be triggered without
+/// `unsafe` blocks because it would trigger an unbalanced call to `fput`.
+///
+/// # Invariants
+///
+/// The wrapped [`File`] remains valid for the lifetime of the object.
+pub(crate) struct FileRef(ManuallyDrop<File>);
+
+impl FileRef {
+    /// Constructs a new [`struct file`] wrapper that doesn't change its reference count.
+    ///
+    /// # Safety
+    ///
+    /// The pointer `ptr` must be non-null and valid for the lifetime of the object.
+    pub(crate) unsafe fn from_ptr(ptr: *mut bindings::file) -> Self {
+        Self(ManuallyDrop::new(File { ptr }))
+    }
+}
+
+impl Deref for FileRef {
+    type Target = File;
+
+    fn deref(&self) -> &Self::Target {
+        self.0.deref()
+    }
+}
+
+/// A file descriptor reservation.
+///
+/// This allows the creation of a file descriptor in two steps: first, we reserve a slot for it,
+/// then we commit or drop the reservation. The first step may fail (e.g., the current process ran
+/// out of available slots), but commit and drop never fail (and are mutually exclusive).
+pub struct FileDescriptorReservation {
+    fd: u32,
+}
+
+impl FileDescriptorReservation {
+    /// Creates a new file descriptor reservation.
+    pub fn new(flags: u32) -> Result<Self> {
+        // SAFETY: FFI call, there are no safety requirements on `flags`.
+        let fd = unsafe { bindings::get_unused_fd_flags(flags) };
+        if fd < 0 {
+            return Err(Error::from_kernel_errno(fd));
+        }
+        Ok(Self { fd: fd as _ })
+    }
+
+    /// Returns the file descriptor number that was reserved.
+    pub fn reserved_fd(&self) -> u32 {
+        self.fd
+    }
+
+    /// Commits the reservation.
+    ///
+    /// The previously reserved file descriptor is bound to `file`.
+    pub fn commit(self, file: File) {
+        // SAFETY: `self.fd` was previously returned by `get_unused_fd_flags`, and `file.ptr` is
+        // guaranteed to have an owned ref count by its type invariants.
+        unsafe { bindings::fd_install(self.fd, file.ptr) };
+
+        // `fd_install` consumes both the file descriptor and the file reference, so we cannot run
+        // the destructors.
+        core::mem::forget(self);
+        core::mem::forget(file);
+    }
+}
+
+impl Drop for FileDescriptorReservation {
+    fn drop(&mut self) {
+        // SAFETY: `self.fd` was returned by a previous call to `get_unused_fd_flags`.
+        unsafe { bindings::put_unused_fd(self.fd) };
+    }
+}
diff --git a/rust/kernel/file_operations.rs b/rust/kernel/file_operations.rs
new file mode 100644
index 000000000000..3d96a32a3764
--- /dev/null
+++ b/rust/kernel/file_operations.rs
@@ -0,0 +1,723 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! File operations.
+//!
+//! C header: [`include/linux/fs.h`](../../../../include/linux/fs.h)
+
+use core::convert::{TryFrom, TryInto};
+use core::{marker, mem, ptr};
+
+use alloc::boxed::Box;
+
+use crate::{
+    bindings, c_types,
+    error::{from_kernel_result, Error, Result},
+    file::{File, FileRef},
+    io_buffer::{IoBufferReader, IoBufferWriter},
+    iov_iter::IovIter,
+    sync::CondVar,
+    types::PointerWrapper,
+    user_ptr::{UserSlicePtr, UserSlicePtrReader, UserSlicePtrWriter},
+};
+
+/// Wraps the kernel's `struct poll_table_struct`.
+///
+/// # Invariants
+///
+/// The pointer `PollTable::ptr` is null or valid.
+pub struct PollTable {
+    ptr: *mut bindings::poll_table_struct,
+}
+
+impl PollTable {
+    /// Constructors a new `struct poll_table_struct` wrapper.
+    ///
+    /// # Safety
+    ///
+    /// The pointer `ptr` must be either null or a valid pointer for the lifetime of the object.
+    unsafe fn from_ptr(ptr: *mut bindings::poll_table_struct) -> Self {
+        Self { ptr }
+    }
+
+    /// Associates the given file and condition variable to this poll table. It means notifying the
+    /// condition variable will notify the poll table as well; additionally, the association
+    /// between the condition variable and the file will automatically be undone by the kernel when
+    /// the file is destructed. To unilaterally remove the association before then, one can call
+    /// [`CondVar::free_waiters`].
+    ///
+    /// # Safety
+    ///
+    /// If the condition variable is destroyed before the file, then [`CondVar::free_waiters`] must
+    /// be called to ensure that all waiters are flushed out.
+    pub unsafe fn register_wait<'a>(&self, file: &'a File, cv: &'a CondVar) {
+        if self.ptr.is_null() {
+            return;
+        }
+
+        // SAFETY: `PollTable::ptr` is guaranteed to be valid by the type invariants and the null
+        // check above.
+        let table = unsafe { &*self.ptr };
+        if let Some(proc) = table._qproc {
+            // SAFETY: All pointers are known to be valid.
+            unsafe { proc(file.ptr as _, cv.wait_list.get(), self.ptr) }
+        }
+    }
+}
+
+/// Equivalent to [`std::io::SeekFrom`].
+///
+/// [`std::io::SeekFrom`]: https://doc.rust-lang.org/std/io/enum.SeekFrom.html
+pub enum SeekFrom {
+    /// Equivalent to C's `SEEK_SET`.
+    Start(u64),
+
+    /// Equivalent to C's `SEEK_END`.
+    End(i64),
+
+    /// Equivalent to C's `SEEK_CUR`.
+    Current(i64),
+}
+
+/// Called by the VFS when an inode should be opened.
+///
+/// Calls `T::open` on the returned value of `A::convert`.
+///
+/// # Safety
+///
+/// The returned value of `A::convert` must be a valid non-null pointer and
+/// `T:open` must return a valid non-null pointer on an `Ok` result.
+unsafe extern "C" fn open_callback<A: FileOpenAdapter, T: FileOpener<A::Arg>>(
+    inode: *mut bindings::inode,
+    file: *mut bindings::file,
+) -> c_types::c_int {
+    from_kernel_result! {
+        // SAFETY: `A::convert` must return a valid non-null pointer that
+        // should point to data in the inode or file that lives longer
+        // than the following use of `T::open`.
+        let arg = unsafe { A::convert(inode, file) };
+        // SAFETY: The C contract guarantees that `file` is valid. Additionally,
+        // `fileref` never outlives this function, so it is guaranteed to be
+        // valid.
+        let fileref = unsafe { FileRef::from_ptr(file) };
+        // SAFETY: `arg` was previously returned by `A::convert` and must
+        // be a valid non-null pointer.
+        let ptr = T::open(unsafe { &*arg }, &fileref)?.into_pointer();
+        // SAFETY: The C contract guarantees that `private_data` is available
+        // for implementers of the file operations (no other C code accesses
+        // it), so we know that there are no concurrent threads/CPUs accessing
+        // it (it's not visible to any other Rust code).
+        unsafe { (*file).private_data = ptr as *mut c_types::c_void };
+        Ok(0)
+    }
+}
+
+unsafe extern "C" fn read_callback<T: FileOperations>(
+    file: *mut bindings::file,
+    buf: *mut c_types::c_char,
+    len: c_types::c_size_t,
+    offset: *mut bindings::loff_t,
+) -> c_types::c_ssize_t {
+    from_kernel_result! {
+        let mut data = unsafe { UserSlicePtr::new(buf as *mut c_types::c_void, len).writer() };
+        // SAFETY: `private_data` was initialised by `open_callback` with a value returned by
+        // `T::Wrapper::into_pointer`. `T::Wrapper::from_pointer` is only called by the `release`
+        // callback, which the C API guarantees that will be called only when all references to
+        // `file` have been released, so we know it can't be called while this function is running.
+        let f = unsafe { T::Wrapper::borrow((*file).private_data) };
+        // No `FMODE_UNSIGNED_OFFSET` support, so `offset` must be in [0, 2^63).
+        // See discussion in https://github.com/fishinabarrel/linux-kernel-module-rust/pull/113
+        let read = T::read(f, unsafe { &FileRef::from_ptr(file) }, &mut data, unsafe { *offset }.try_into()?)?;
+        unsafe { (*offset) += bindings::loff_t::try_from(read).unwrap() };
+        Ok(read as _)
+    }
+}
+
+unsafe extern "C" fn read_iter_callback<T: FileOperations>(
+    iocb: *mut bindings::kiocb,
+    raw_iter: *mut bindings::iov_iter,
+) -> isize {
+    from_kernel_result! {
+        let mut iter = unsafe { IovIter::from_ptr(raw_iter) };
+        let file = unsafe { (*iocb).ki_filp };
+        let offset = unsafe { (*iocb).ki_pos };
+        // SAFETY: `private_data` was initialised by `open_callback` with a value returned by
+        // `T::Wrapper::into_pointer`. `T::Wrapper::from_pointer` is only called by the `release`
+        // callback, which the C API guarantees that will be called only when all references to
+        // `file` have been released, so we know it can't be called while this function is running.
+        let f = unsafe { T::Wrapper::borrow((*file).private_data) };
+        let read = T::read(f, unsafe { &FileRef::from_ptr(file) }, &mut iter, offset.try_into()?)?;
+        unsafe { (*iocb).ki_pos += bindings::loff_t::try_from(read).unwrap() };
+        Ok(read as _)
+    }
+}
+
+unsafe extern "C" fn write_callback<T: FileOperations>(
+    file: *mut bindings::file,
+    buf: *const c_types::c_char,
+    len: c_types::c_size_t,
+    offset: *mut bindings::loff_t,
+) -> c_types::c_ssize_t {
+    from_kernel_result! {
+        let mut data = unsafe { UserSlicePtr::new(buf as *mut c_types::c_void, len).reader() };
+        // SAFETY: `private_data` was initialised by `open_callback` with a value returned by
+        // `T::Wrapper::into_pointer`. `T::Wrapper::from_pointer` is only called by the `release`
+        // callback, which the C API guarantees that will be called only when all references to
+        // `file` have been released, so we know it can't be called while this function is running.
+        let f = unsafe { T::Wrapper::borrow((*file).private_data) };
+        // No `FMODE_UNSIGNED_OFFSET` support, so `offset` must be in [0, 2^63).
+        // See discussion in https://github.com/fishinabarrel/linux-kernel-module-rust/pull/113
+        let written = T::write(f, unsafe { &FileRef::from_ptr(file) }, &mut data, unsafe { *offset }.try_into()?)?;
+        unsafe { (*offset) += bindings::loff_t::try_from(written).unwrap() };
+        Ok(written as _)
+    }
+}
+
+unsafe extern "C" fn write_iter_callback<T: FileOperations>(
+    iocb: *mut bindings::kiocb,
+    raw_iter: *mut bindings::iov_iter,
+) -> isize {
+    from_kernel_result! {
+        let mut iter = unsafe { IovIter::from_ptr(raw_iter) };
+        let file = unsafe { (*iocb).ki_filp };
+        let offset = unsafe { (*iocb).ki_pos };
+        // SAFETY: `private_data` was initialised by `open_callback` with a value returned by
+        // `T::Wrapper::into_pointer`. `T::Wrapper::from_pointer` is only called by the `release`
+        // callback, which the C API guarantees that will be called only when all references to
+        // `file` have been released, so we know it can't be called while this function is running.
+        let f = unsafe { T::Wrapper::borrow((*file).private_data) };
+        let written = T::write(f, unsafe { &FileRef::from_ptr(file) }, &mut iter, offset.try_into()?)?;
+        unsafe { (*iocb).ki_pos += bindings::loff_t::try_from(written).unwrap() };
+        Ok(written as _)
+    }
+}
+
+unsafe extern "C" fn release_callback<T: FileOperations>(
+    _inode: *mut bindings::inode,
+    file: *mut bindings::file,
+) -> c_types::c_int {
+    let ptr = mem::replace(unsafe { &mut (*file).private_data }, ptr::null_mut());
+    T::release(unsafe { T::Wrapper::from_pointer(ptr as _) }, unsafe {
+        &FileRef::from_ptr(file)
+    });
+    0
+}
+
+unsafe extern "C" fn llseek_callback<T: FileOperations>(
+    file: *mut bindings::file,
+    offset: bindings::loff_t,
+    whence: c_types::c_int,
+) -> bindings::loff_t {
+    from_kernel_result! {
+        let off = match whence as u32 {
+            bindings::SEEK_SET => SeekFrom::Start(offset.try_into()?),
+            bindings::SEEK_CUR => SeekFrom::Current(offset),
+            bindings::SEEK_END => SeekFrom::End(offset),
+            _ => return Err(Error::EINVAL),
+        };
+        // SAFETY: `private_data` was initialised by `open_callback` with a value returned by
+        // `T::Wrapper::into_pointer`. `T::Wrapper::from_pointer` is only called by the `release`
+        // callback, which the C API guarantees that will be called only when all references to
+        // `file` have been released, so we know it can't be called while this function is running.
+        let f = unsafe { T::Wrapper::borrow((*file).private_data) };
+        let off = T::seek(f, unsafe { &FileRef::from_ptr(file) }, off)?;
+        Ok(off as bindings::loff_t)
+    }
+}
+
+unsafe extern "C" fn unlocked_ioctl_callback<T: FileOperations>(
+    file: *mut bindings::file,
+    cmd: c_types::c_uint,
+    arg: c_types::c_ulong,
+) -> c_types::c_long {
+    from_kernel_result! {
+        // SAFETY: `private_data` was initialised by `open_callback` with a value returned by
+        // `T::Wrapper::into_pointer`. `T::Wrapper::from_pointer` is only called by the `release`
+        // callback, which the C API guarantees that will be called only when all references to
+        // `file` have been released, so we know it can't be called while this function is running.
+        let f = unsafe { T::Wrapper::borrow((*file).private_data) };
+        let mut cmd = IoctlCommand::new(cmd as _, arg as _);
+        let ret = T::ioctl(f, unsafe { &FileRef::from_ptr(file) }, &mut cmd)?;
+        Ok(ret as _)
+    }
+}
+
+unsafe extern "C" fn compat_ioctl_callback<T: FileOperations>(
+    file: *mut bindings::file,
+    cmd: c_types::c_uint,
+    arg: c_types::c_ulong,
+) -> c_types::c_long {
+    from_kernel_result! {
+        // SAFETY: `private_data` was initialised by `open_callback` with a value returned by
+        // `T::Wrapper::into_pointer`. `T::Wrapper::from_pointer` is only called by the `release`
+        // callback, which the C API guarantees that will be called only when all references to
+        // `file` have been released, so we know it can't be called while this function is running.
+        let f = unsafe { T::Wrapper::borrow((*file).private_data) };
+        let mut cmd = IoctlCommand::new(cmd as _, arg as _);
+        let ret = T::compat_ioctl(f, unsafe { &FileRef::from_ptr(file) }, &mut cmd)?;
+        Ok(ret as _)
+    }
+}
+
+unsafe extern "C" fn mmap_callback<T: FileOperations>(
+    file: *mut bindings::file,
+    vma: *mut bindings::vm_area_struct,
+) -> c_types::c_int {
+    from_kernel_result! {
+        // SAFETY: `private_data` was initialised by `open_callback` with a value returned by
+        // `T::Wrapper::into_pointer`. `T::Wrapper::from_pointer` is only called by the `release`
+        // callback, which the C API guarantees that will be called only when all references to
+        // `file` have been released, so we know it can't be called while this function is running.
+        let f = unsafe { T::Wrapper::borrow((*file).private_data) };
+        T::mmap(f, unsafe { &FileRef::from_ptr(file) }, unsafe { &mut *vma })?;
+        Ok(0)
+    }
+}
+
+unsafe extern "C" fn fsync_callback<T: FileOperations>(
+    file: *mut bindings::file,
+    start: bindings::loff_t,
+    end: bindings::loff_t,
+    datasync: c_types::c_int,
+) -> c_types::c_int {
+    from_kernel_result! {
+        let start = start.try_into()?;
+        let end = end.try_into()?;
+        let datasync = datasync != 0;
+        // SAFETY: `private_data` was initialised by `open_callback` with a value returned by
+        // `T::Wrapper::into_pointer`. `T::Wrapper::from_pointer` is only called by the `release`
+        // callback, which the C API guarantees that will be called only when all references to
+        // `file` have been released, so we know it can't be called while this function is running.
+        let f = unsafe { T::Wrapper::borrow((*file).private_data) };
+        let res = T::fsync(f, unsafe { &FileRef::from_ptr(file) }, start, end, datasync)?;
+        Ok(res.try_into().unwrap())
+    }
+}
+
+unsafe extern "C" fn poll_callback<T: FileOperations>(
+    file: *mut bindings::file,
+    wait: *mut bindings::poll_table_struct,
+) -> bindings::__poll_t {
+    // SAFETY: `private_data` was initialised by `open_callback` with a value returned by
+    // `T::Wrapper::into_pointer`. `T::Wrapper::from_pointer` is only called by the `release`
+    // callback, which the C API guarantees that will be called only when all references to `file`
+    // have been released, so we know it can't be called while this function is running.
+    let f = unsafe { T::Wrapper::borrow((*file).private_data) };
+    match T::poll(f, unsafe { &FileRef::from_ptr(file) }, unsafe {
+        &PollTable::from_ptr(wait)
+    }) {
+        Ok(v) => v,
+        Err(_) => bindings::POLLERR,
+    }
+}
+
+pub(crate) struct FileOperationsVtable<A, T>(marker::PhantomData<A>, marker::PhantomData<T>);
+
+impl<A: FileOpenAdapter, T: FileOpener<A::Arg>> FileOperationsVtable<A, T> {
+    const VTABLE: bindings::file_operations = bindings::file_operations {
+        open: Some(open_callback::<A, T>),
+        release: Some(release_callback::<T>),
+        read: if T::TO_USE.read {
+            Some(read_callback::<T>)
+        } else {
+            None
+        },
+        write: if T::TO_USE.write {
+            Some(write_callback::<T>)
+        } else {
+            None
+        },
+        llseek: if T::TO_USE.seek {
+            Some(llseek_callback::<T>)
+        } else {
+            None
+        },
+
+        check_flags: None,
+        compat_ioctl: if T::TO_USE.compat_ioctl {
+            Some(compat_ioctl_callback::<T>)
+        } else {
+            None
+        },
+        copy_file_range: None,
+        fallocate: None,
+        fadvise: None,
+        fasync: None,
+        flock: None,
+        flush: None,
+        fsync: if T::TO_USE.fsync {
+            Some(fsync_callback::<T>)
+        } else {
+            None
+        },
+        get_unmapped_area: None,
+        iterate: None,
+        iterate_shared: None,
+        iopoll: None,
+        lock: None,
+        mmap: if T::TO_USE.mmap {
+            Some(mmap_callback::<T>)
+        } else {
+            None
+        },
+        mmap_supported_flags: 0,
+        owner: ptr::null_mut(),
+        poll: if T::TO_USE.poll {
+            Some(poll_callback::<T>)
+        } else {
+            None
+        },
+        read_iter: if T::TO_USE.read_iter {
+            Some(read_iter_callback::<T>)
+        } else {
+            None
+        },
+        remap_file_range: None,
+        sendpage: None,
+        setlease: None,
+        show_fdinfo: None,
+        splice_read: None,
+        splice_write: None,
+        unlocked_ioctl: if T::TO_USE.ioctl {
+            Some(unlocked_ioctl_callback::<T>)
+        } else {
+            None
+        },
+        write_iter: if T::TO_USE.write_iter {
+            Some(write_iter_callback::<T>)
+        } else {
+            None
+        },
+    };
+
+    /// Builds an instance of [`struct file_operations`].
+    ///
+    /// # Safety
+    ///
+    /// The caller must ensure that the adapter is compatible with the way the device is registered.
+    pub(crate) const unsafe fn build() -> &'static bindings::file_operations {
+        &Self::VTABLE
+    }
+}
+
+/// Represents which fields of [`struct file_operations`] should be populated with pointers.
+pub struct ToUse {
+    /// The `read` field of [`struct file_operations`].
+    pub read: bool,
+
+    /// The `read_iter` field of [`struct file_operations`].
+    pub read_iter: bool,
+
+    /// The `write` field of [`struct file_operations`].
+    pub write: bool,
+
+    /// The `write_iter` field of [`struct file_operations`].
+    pub write_iter: bool,
+
+    /// The `llseek` field of [`struct file_operations`].
+    pub seek: bool,
+
+    /// The `unlocked_ioctl` field of [`struct file_operations`].
+    pub ioctl: bool,
+
+    /// The `compat_ioctl` field of [`struct file_operations`].
+    pub compat_ioctl: bool,
+
+    /// The `fsync` field of [`struct file_operations`].
+    pub fsync: bool,
+
+    /// The `mmap` field of [`struct file_operations`].
+    pub mmap: bool,
+
+    /// The `poll` field of [`struct file_operations`].
+    pub poll: bool,
+}
+
+/// A constant version where all values are to set to `false`, that is, all supported fields will
+/// be set to null pointers.
+pub const USE_NONE: ToUse = ToUse {
+    read: false,
+    read_iter: false,
+    write: false,
+    write_iter: false,
+    seek: false,
+    ioctl: false,
+    compat_ioctl: false,
+    fsync: false,
+    mmap: false,
+    poll: false,
+};
+
+/// Defines the [`FileOperations::TO_USE`] field based on a list of fields to be populated.
+#[macro_export]
+macro_rules! declare_file_operations {
+    () => {
+        const TO_USE: $crate::file_operations::ToUse = $crate::file_operations::USE_NONE;
+    };
+    ($($i:ident),+) => {
+        const TO_USE: kernel::file_operations::ToUse =
+            $crate::file_operations::ToUse {
+                $($i: true),+ ,
+                ..$crate::file_operations::USE_NONE
+            };
+    };
+}
+
+/// Allows the handling of ioctls defined with the `_IO`, `_IOR`, `_IOW`, and `_IOWR` macros.
+///
+/// For each macro, there is a handler function that takes the appropriate types as arguments.
+pub trait IoctlHandler: Sync {
+    /// The type of the first argument to each associated function.
+    type Target<'a>;
+
+    /// Handles ioctls defined with the `_IO` macro, that is, with no buffer as argument.
+    fn pure(_this: Self::Target<'_>, _file: &File, _cmd: u32, _arg: usize) -> Result<i32> {
+        Err(Error::EINVAL)
+    }
+
+    /// Handles ioctls defined with the `_IOR` macro, that is, with an output buffer provided as
+    /// argument.
+    fn read(
+        _this: Self::Target<'_>,
+        _file: &File,
+        _cmd: u32,
+        _writer: &mut UserSlicePtrWriter,
+    ) -> Result<i32> {
+        Err(Error::EINVAL)
+    }
+
+    /// Handles ioctls defined with the `_IOW` macro, that is, with an input buffer provided as
+    /// argument.
+    fn write(
+        _this: Self::Target<'_>,
+        _file: &File,
+        _cmd: u32,
+        _reader: &mut UserSlicePtrReader,
+    ) -> Result<i32> {
+        Err(Error::EINVAL)
+    }
+
+    /// Handles ioctls defined with the `_IOWR` macro, that is, with a buffer for both input and
+    /// output provided as argument.
+    fn read_write(
+        _this: Self::Target<'_>,
+        _file: &File,
+        _cmd: u32,
+        _data: UserSlicePtr,
+    ) -> Result<i32> {
+        Err(Error::EINVAL)
+    }
+}
+
+/// Represents an ioctl command.
+///
+/// It can use the components of an ioctl command to dispatch ioctls using
+/// [`IoctlCommand::dispatch`].
+pub struct IoctlCommand {
+    cmd: u32,
+    arg: usize,
+    user_slice: Option<UserSlicePtr>,
+}
+
+impl IoctlCommand {
+    /// Constructs a new [`IoctlCommand`].
+    fn new(cmd: u32, arg: usize) -> Self {
+        let size = (cmd >> bindings::_IOC_SIZESHIFT) & bindings::_IOC_SIZEMASK;
+
+        // SAFETY: We only create one instance of the user slice per ioctl call, so TOCTOU issues
+        // are not possible.
+        let user_slice = Some(unsafe { UserSlicePtr::new(arg as _, size as _) });
+        Self {
+            cmd,
+            arg,
+            user_slice,
+        }
+    }
+
+    /// Dispatches the given ioctl to the appropriate handler based on the value of the command. It
+    /// also creates a [`UserSlicePtr`], [`UserSlicePtrReader`], or [`UserSlicePtrWriter`]
+    /// depending on the direction of the buffer of the command.
+    ///
+    /// It is meant to be used in implementations of [`FileOperations::ioctl`] and
+    /// [`FileOperations::compat_ioctl`].
+    pub fn dispatch<T: IoctlHandler>(
+        &mut self,
+        handler: T::Target<'_>,
+        file: &File,
+    ) -> Result<i32> {
+        let dir = (self.cmd >> bindings::_IOC_DIRSHIFT) & bindings::_IOC_DIRMASK;
+        if dir == bindings::_IOC_NONE {
+            return T::pure(handler, file, self.cmd, self.arg);
+        }
+
+        let data = self.user_slice.take().ok_or(Error::EINVAL)?;
+        const READ_WRITE: u32 = bindings::_IOC_READ | bindings::_IOC_WRITE;
+        match dir {
+            bindings::_IOC_WRITE => T::write(handler, file, self.cmd, &mut data.reader()),
+            bindings::_IOC_READ => T::read(handler, file, self.cmd, &mut data.writer()),
+            READ_WRITE => T::read_write(handler, file, self.cmd, data),
+            _ => Err(Error::EINVAL),
+        }
+    }
+
+    /// Returns the raw 32-bit value of the command and the ptr-sized argument.
+    pub fn raw(&self) -> (u32, usize) {
+        (self.cmd, self.arg)
+    }
+}
+
+/// Trait for extracting file open arguments from kernel data structures.
+///
+/// This is meant to be implemented by registration managers.
+pub trait FileOpenAdapter {
+    /// The type of argument this adapter extracts.
+    type Arg;
+
+    /// Converts untyped data stored in [`struct inode`] and [`struct file`] (when [`struct
+    /// file_operations::open`] is called) into the given type. For example, for `miscdev`
+    /// devices, a pointer to the registered [`struct miscdev`] is stored in [`struct
+    /// file::private_data`].
+    ///
+    /// # Safety
+    ///
+    /// This function must be called only when [`struct file_operations::open`] is being called for
+    /// a file that was registered by the implementer. The returned pointer must be valid and
+    /// not-null.
+    unsafe fn convert(_inode: *mut bindings::inode, _file: *mut bindings::file)
+        -> *const Self::Arg;
+}
+
+/// Trait for implementers of kernel files.
+///
+/// In addition to the methods in [`FileOperations`], implementers must also provide
+/// [`FileOpener::open`] with a customised argument. This allows a single implementation of
+/// [`FileOperations`] to be used for different types of registrations, for example, `miscdev` and
+/// `chrdev`.
+pub trait FileOpener<T: ?Sized>: FileOperations {
+    /// Creates a new instance of this file.
+    ///
+    /// Corresponds to the `open` function pointer in `struct file_operations`.
+    fn open(context: &T, file: &File) -> Result<Self::Wrapper>;
+}
+
+impl<T: FileOperations<Wrapper = Box<T>> + Default> FileOpener<()> for T {
+    fn open(_: &(), _file: &File) -> Result<Self::Wrapper> {
+        Ok(Box::try_new(T::default())?)
+    }
+}
+
+/// Corresponds to the kernel's `struct file_operations`.
+///
+/// You implement this trait whenever you would create a `struct file_operations`.
+///
+/// File descriptors may be used from multiple threads/processes concurrently, so your type must be
+/// [`Sync`]. It must also be [`Send`] because [`FileOperations::release`] will be called from the
+/// thread that decrements that associated file's refcount to zero.
+pub trait FileOperations: Send + Sync + Sized + 'static {
+    /// The methods to use to populate [`struct file_operations`].
+    const TO_USE: ToUse;
+
+    /// The pointer type that will be used to hold ourselves.
+    type Wrapper: PointerWrapper = Box<Self>;
+
+    /// Cleans up after the last reference to the file goes away.
+    ///
+    /// Note that the object is moved, so it will be freed automatically unless the implementation
+    /// moves it elsewhere.
+    ///
+    /// Corresponds to the `release` function pointer in `struct file_operations`.
+    fn release(_obj: Self::Wrapper, _file: &File) {}
+
+    /// Reads data from this file to the caller's buffer.
+    ///
+    /// Corresponds to the `read` and `read_iter` function pointers in `struct file_operations`.
+    fn read(
+        _this: <Self::Wrapper as PointerWrapper>::Borrowed<'_>,
+        _file: &File,
+        _data: &mut impl IoBufferWriter,
+        _offset: u64,
+    ) -> Result<usize> {
+        Err(Error::EINVAL)
+    }
+
+    /// Writes data from the caller's buffer to this file.
+    ///
+    /// Corresponds to the `write` and `write_iter` function pointers in `struct file_operations`.
+    fn write(
+        _this: <Self::Wrapper as PointerWrapper>::Borrowed<'_>,
+        _file: &File,
+        _data: &mut impl IoBufferReader,
+        _offset: u64,
+    ) -> Result<usize> {
+        Err(Error::EINVAL)
+    }
+
+    /// Changes the position of the file.
+    ///
+    /// Corresponds to the `llseek` function pointer in `struct file_operations`.
+    fn seek(
+        _this: <Self::Wrapper as PointerWrapper>::Borrowed<'_>,
+        _file: &File,
+        _offset: SeekFrom,
+    ) -> Result<u64> {
+        Err(Error::EINVAL)
+    }
+
+    /// Performs IO control operations that are specific to the file.
+    ///
+    /// Corresponds to the `unlocked_ioctl` function pointer in `struct file_operations`.
+    fn ioctl(
+        _this: <Self::Wrapper as PointerWrapper>::Borrowed<'_>,
+        _file: &File,
+        _cmd: &mut IoctlCommand,
+    ) -> Result<i32> {
+        Err(Error::ENOTTY)
+    }
+
+    /// Performs 32-bit IO control operations on that are specific to the file on 64-bit kernels.
+    ///
+    /// Corresponds to the `compat_ioctl` function pointer in `struct file_operations`.
+    fn compat_ioctl(
+        _this: <Self::Wrapper as PointerWrapper>::Borrowed<'_>,
+        _file: &File,
+        _cmd: &mut IoctlCommand,
+    ) -> Result<i32> {
+        Err(Error::ENOTTY)
+    }
+
+    /// Syncs pending changes to this file.
+    ///
+    /// Corresponds to the `fsync` function pointer in `struct file_operations`.
+    fn fsync(
+        _this: <Self::Wrapper as PointerWrapper>::Borrowed<'_>,
+        _file: &File,
+        _start: u64,
+        _end: u64,
+        _datasync: bool,
+    ) -> Result<u32> {
+        Err(Error::EINVAL)
+    }
+
+    /// Maps areas of the caller's virtual memory with device/file memory.
+    ///
+    /// Corresponds to the `mmap` function pointer in `struct file_operations`.
+    /// TODO: wrap `vm_area_struct` so that we don't have to expose it.
+    fn mmap(
+        _this: <Self::Wrapper as PointerWrapper>::Borrowed<'_>,
+        _file: &File,
+        _vma: &mut bindings::vm_area_struct,
+    ) -> Result {
+        Err(Error::EINVAL)
+    }
+
+    /// Checks the state of the file and optionally registers for notification when the state
+    /// changes.
+    ///
+    /// Corresponds to the `poll` function pointer in `struct file_operations`.
+    fn poll(
+        _this: <Self::Wrapper as PointerWrapper>::Borrowed<'_>,
+        _file: &File,
+        _table: &PollTable,
+    ) -> Result<u32> {
+        Ok(bindings::POLLIN | bindings::POLLOUT | bindings::POLLRDNORM | bindings::POLLWRNORM)
+    }
+}
diff --git a/rust/kernel/gpio.rs b/rust/kernel/gpio.rs
new file mode 100644
index 000000000000..cd11fcfa9836
--- /dev/null
+++ b/rust/kernel/gpio.rs
@@ -0,0 +1,475 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Support for gpio device drivers.
+//!
+//! C header: [`include/linux/gpio/driver.h`](../../../../include/linux/gpio/driver.h)
+
+use crate::{
+    bindings, c_types, device, error::from_kernel_result, types::PointerWrapper, Error, Result,
+};
+use core::{
+    cell::UnsafeCell,
+    marker::{PhantomData, PhantomPinned},
+    pin::Pin,
+};
+
+#[cfg(CONFIG_GPIOLIB_IRQCHIP)]
+pub use irqchip::{ChipWithIrqChip, RegistrationWithIrqChip};
+
+/// The direction of a gpio line.
+pub enum LineDirection {
+    /// Direction is input.
+    In = bindings::GPIO_LINE_DIRECTION_IN as _,
+
+    /// Direction is output.
+    Out = bindings::GPIO_LINE_DIRECTION_OUT as _,
+}
+
+/// A gpio chip.
+pub trait Chip {
+    /// Context data associated with the gpio chip.
+    ///
+    /// It determines the type of the context data passed to each of the methods of the trait.
+    type Data: PointerWrapper + Sync + Send;
+
+    /// The methods to use to populate [`struct gpio_chip`]. This is typically populated with
+    /// [`declare_gpio_chip_operations`].
+    const TO_USE: ToUse;
+
+    /// Returns the direction of the given gpio line.
+    fn get_direction(
+        _data: <Self::Data as PointerWrapper>::Borrowed<'_>,
+        _offset: u32,
+    ) -> Result<LineDirection> {
+        Err(Error::ENOTSUPP)
+    }
+
+    /// Configures the direction as input of the given gpio line.
+    fn direction_input(
+        _data: <Self::Data as PointerWrapper>::Borrowed<'_>,
+        _offset: u32,
+    ) -> Result {
+        Err(Error::EIO)
+    }
+
+    /// Configures the direction as output of the given gpio line.
+    ///
+    /// The value that will be initially output is also specified.
+    fn direction_output(
+        _data: <Self::Data as PointerWrapper>::Borrowed<'_>,
+        _offset: u32,
+        _value: bool,
+    ) -> Result {
+        Err(Error::ENOTSUPP)
+    }
+
+    /// Returns the current value of the given gpio line.
+    fn get(_data: <Self::Data as PointerWrapper>::Borrowed<'_>, _offset: u32) -> Result<bool> {
+        Err(Error::EIO)
+    }
+
+    /// Sets the value of the given gpio line.
+    fn set(_data: <Self::Data as PointerWrapper>::Borrowed<'_>, _offset: u32, _value: bool) {}
+}
+
+/// Represents which fields of [`struct gpio_chip`] should be populated with pointers.
+///
+/// This is typically populated with the [`declare_gpio_chip_operations`] macro.
+pub struct ToUse {
+    /// The `get_direction` field of [`struct gpio_chip`].
+    pub get_direction: bool,
+
+    /// The `direction_input` field of [`struct gpio_chip`].
+    pub direction_input: bool,
+
+    /// The `direction_output` field of [`struct gpio_chip`].
+    pub direction_output: bool,
+
+    /// The `get` field of [`struct gpio_chip`].
+    pub get: bool,
+
+    /// The `set` field of [`struct gpio_chip`].
+    pub set: bool,
+}
+
+/// A constant version where all values are set to `false`, that is, all supported fields will be
+/// set to null pointers.
+pub const USE_NONE: ToUse = ToUse {
+    get_direction: false,
+    direction_input: false,
+    direction_output: false,
+    get: false,
+    set: false,
+};
+
+/// Defines the [`Chip::TO_USE`] field based on a list of fields to be populated.
+#[macro_export]
+macro_rules! declare_gpio_chip_operations {
+    () => {
+        const TO_USE: $crate::gpio::ToUse = $crate::gpio::USE_NONE;
+    };
+    ($($i:ident),+) => {
+        #[allow(clippy::needless_update)]
+        const TO_USE: $crate::gpio::ToUse =
+            $crate::gpio::ToUse {
+                $($i: true),+ ,
+                ..$crate::gpio::USE_NONE
+            };
+    };
+}
+
+/// A registration of a gpio chip.
+pub struct Registration<T: Chip> {
+    gc: UnsafeCell<bindings::gpio_chip>,
+    parent: Option<device::Device>,
+    _p: PhantomData<T>,
+    _pin: PhantomPinned,
+}
+
+impl<T: Chip> Registration<T> {
+    /// Creates a new [`Registration`] but does not register it yet.
+    ///
+    /// It is allowed to move.
+    pub fn new() -> Self {
+        Self {
+            parent: None,
+            gc: UnsafeCell::new(bindings::gpio_chip::default()),
+            _pin: PhantomPinned,
+            _p: PhantomData,
+        }
+    }
+
+    /// Registers a gpio chip with the rest of the kernel.
+    pub fn register(
+        self: Pin<&mut Self>,
+        gpio_count: u16,
+        base: Option<i32>,
+        parent: &dyn device::RawDevice,
+        data: T::Data,
+    ) -> Result {
+        if self.parent.is_some() {
+            // Already registered.
+            return Err(Error::EINVAL);
+        }
+
+        // SAFETY: We never move out of `this`.
+        let this = unsafe { self.get_unchecked_mut() };
+        {
+            let gc = this.gc.get_mut();
+
+            // Set up the callbacks.
+            gc.request = Some(bindings::gpiochip_generic_request);
+            gc.free = Some(bindings::gpiochip_generic_free);
+            if T::TO_USE.get_direction {
+                gc.get_direction = Some(get_direction_callback::<T>);
+            }
+            if T::TO_USE.direction_input {
+                gc.direction_input = Some(direction_input_callback::<T>);
+            }
+            if T::TO_USE.direction_output {
+                gc.direction_output = Some(direction_output_callback::<T>);
+            }
+            if T::TO_USE.get {
+                gc.get = Some(get_callback::<T>);
+            }
+            if T::TO_USE.set {
+                gc.set = Some(set_callback::<T>);
+            }
+
+            // When a base is not explicitly given, use -1 for one to be picked.
+            if let Some(b) = base {
+                gc.base = b;
+            } else {
+                gc.base = -1;
+            }
+
+            gc.ngpio = gpio_count;
+            gc.parent = parent.raw_device();
+            gc.label = parent.name().as_char_ptr();
+
+            // TODO: Define `gc.owner` as well.
+        }
+
+        let data_pointer = <T::Data as PointerWrapper>::into_pointer(data);
+        // SAFETY: `gc` was initilised above, so it is valid.
+        let ret = unsafe {
+            bindings::gpiochip_add_data_with_key(
+                this.gc.get(),
+                data_pointer as _,
+                core::ptr::null_mut(),
+                core::ptr::null_mut(),
+            )
+        };
+        if ret < 0 {
+            // SAFETY: `data_pointer` was returned by `into_pointer` above.
+            unsafe { T::Data::from_pointer(data_pointer) };
+            return Err(Error::from_kernel_errno(ret));
+        }
+
+        this.parent = Some(device::Device::from_dev(parent));
+        Ok(())
+    }
+}
+
+// SAFETY: `Registration` doesn't offer any methods or access to fields when shared between threads
+// or CPUs, so it is safe to share it.
+unsafe impl<T: Chip> Sync for Registration<T> {}
+
+// SAFETY: Registration with and unregistration from the gpio subsystem can happen from any thread.
+// Additionally, `T::Data` (which is dropped during unregistration) is `Send`, so it is ok to move
+// `Registration` to different threads.
+unsafe impl<T: Chip> Send for Registration<T> {}
+
+impl<T: Chip> Default for Registration<T> {
+    fn default() -> Self {
+        Self::new()
+    }
+}
+
+impl<T: Chip> Drop for Registration<T> {
+    /// Removes the registration from the kernel if it has completed successfully before.
+    fn drop(&mut self) {
+        if self.parent.is_some() {
+            // Get a pointer to the data stored in chip before destroying it.
+            // SAFETY: `gc` was during registration, which is guaranteed to have succeeded (because
+            // `parent` is `Some(_)`, so it remains valid.
+            let data_pointer = unsafe { bindings::gpiochip_get_data(self.gc.get()) };
+
+            // SAFETY: By the same argument above, `gc` is still valid.
+            unsafe { bindings::gpiochip_remove(self.gc.get()) };
+
+            // Free data as well.
+            // SAFETY: `data_pointer` was returned by `into_pointer` during registration.
+            unsafe { <T::Data as PointerWrapper>::from_pointer(data_pointer) };
+        }
+    }
+}
+
+unsafe extern "C" fn get_direction_callback<T: Chip>(
+    gc: *mut bindings::gpio_chip,
+    offset: c_types::c_uint,
+) -> c_types::c_int {
+    from_kernel_result! {
+        // SAFETY: The value stored as chip data was returned by `into_pointer` during registration.
+        let data = unsafe { T::Data::borrow(bindings::gpiochip_get_data(gc)) };
+        Ok(T::get_direction(data, offset)? as i32)
+    }
+}
+
+unsafe extern "C" fn direction_input_callback<T: Chip>(
+    gc: *mut bindings::gpio_chip,
+    offset: c_types::c_uint,
+) -> c_types::c_int {
+    from_kernel_result! {
+        // SAFETY: The value stored as chip data was returned by `into_pointer` during registration.
+        let data = unsafe { T::Data::borrow(bindings::gpiochip_get_data(gc)) };
+        T::direction_input(data, offset)?;
+        Ok(0)
+    }
+}
+
+unsafe extern "C" fn direction_output_callback<T: Chip>(
+    gc: *mut bindings::gpio_chip,
+    offset: c_types::c_uint,
+    value: c_types::c_int,
+) -> c_types::c_int {
+    from_kernel_result! {
+        // SAFETY: The value stored as chip data was returned by `into_pointer` during registration.
+        let data = unsafe { T::Data::borrow(bindings::gpiochip_get_data(gc)) };
+        T::direction_output(data, offset, value != 0)?;
+        Ok(0)
+    }
+}
+
+unsafe extern "C" fn get_callback<T: Chip>(
+    gc: *mut bindings::gpio_chip,
+    offset: c_types::c_uint,
+) -> c_types::c_int {
+    from_kernel_result! {
+        // SAFETY: The value stored as chip data was returned by `into_pointer` during registration.
+        let data = unsafe { T::Data::borrow(bindings::gpiochip_get_data(gc)) };
+        let v = T::get(data, offset)?;
+        Ok(v as _)
+    }
+}
+
+unsafe extern "C" fn set_callback<T: Chip>(
+    gc: *mut bindings::gpio_chip,
+    offset: c_types::c_uint,
+    value: c_types::c_int,
+) {
+    // SAFETY: The value stored as chip data was returned by `into_pointer` during registration.
+    let data = unsafe { T::Data::borrow(bindings::gpiochip_get_data(gc)) };
+    T::set(data, offset, value != 0);
+}
+
+#[cfg(CONFIG_GPIOLIB_IRQCHIP)]
+mod irqchip {
+    use super::*;
+    use crate::irq;
+
+    /// A gpio chip that includes an irq chip.
+    pub trait ChipWithIrqChip: Chip {
+        /// Implements the irq flow for the gpio chip.
+        fn handle_irq_flow(
+            _data: <Self::Data as PointerWrapper>::Borrowed<'_>,
+            _desc: &irq::Descriptor,
+            _domain: &irq::Domain,
+        );
+    }
+
+    /// A registration of a gpio chip that includes an irq chip.
+    pub struct RegistrationWithIrqChip<T: ChipWithIrqChip> {
+        reg: Registration<T>,
+        irq_chip: UnsafeCell<bindings::irq_chip>,
+        parent_irq: u32,
+    }
+
+    impl<T: ChipWithIrqChip> RegistrationWithIrqChip<T> {
+        /// Creates a new [`RegistrationWithIrqChip`] but does not register it yet.
+        ///
+        /// It is allowed to move.
+        pub fn new() -> Self {
+            Self {
+                reg: Registration::new(),
+                irq_chip: UnsafeCell::new(bindings::irq_chip::default()),
+                parent_irq: 0,
+            }
+        }
+
+        /// Registers a gpio chip and its irq chip with the rest of the kernel.
+        pub fn register<U: irq::Chip<Data = T::Data>>(
+            mut self: Pin<&mut Self>,
+            gpio_count: u16,
+            base: Option<i32>,
+            parent: &dyn device::RawDevice,
+            data: T::Data,
+            parent_irq: u32,
+        ) -> Result {
+            if self.reg.parent.is_some() {
+                // Already registered.
+                return Err(Error::EINVAL);
+            }
+
+            // SAFETY: We never move out of `this`.
+            let this = unsafe { self.as_mut().get_unchecked_mut() };
+
+            // Initialise the irq_chip.
+            {
+                let irq_chip = this.irq_chip.get_mut();
+                irq_chip.name = parent.name().as_char_ptr();
+
+                // SAFETY: The gpio subsystem configures a pointer to `gpio_chip` as the irq chip
+                // data, so we use `IrqChipAdapter` to convert to the `T::Data`, which is the same
+                // as `irq::Chip::Data` per the bound above.
+                unsafe { irq::init_chip::<IrqChipAdapter<U>>(irq_chip) };
+            }
+
+            // Initialise gc irq state.
+            {
+                let girq = &mut this.reg.gc.get_mut().irq;
+                girq.chip = this.irq_chip.get();
+                // SAFETY: By leaving `parent_handler_data` set to `null`, the gpio subsystem
+                // initialises it to a pointer to the gpio chip, which is what `FlowHandler<T>`
+                // expects.
+                girq.parent_handler = unsafe { irq::new_flow_handler::<FlowHandler<T>>() };
+                girq.num_parents = 1;
+                girq.parents = &mut this.parent_irq;
+                this.parent_irq = parent_irq;
+                girq.default_type = bindings::IRQ_TYPE_NONE;
+                girq.handler = Some(bindings::handle_bad_irq);
+            }
+
+            // SAFETY: `reg` is pinned when `self` is.
+            let pinned = unsafe { self.map_unchecked_mut(|r| &mut r.reg) };
+            pinned.register(gpio_count, base, parent, data)
+        }
+    }
+
+    impl<T: ChipWithIrqChip> Default for RegistrationWithIrqChip<T> {
+        fn default() -> Self {
+            Self::new()
+        }
+    }
+
+    // SAFETY: `RegistrationWithIrqChip` doesn't offer any methods or access to fields when shared
+    // between threads or CPUs, so it is safe to share it.
+    unsafe impl<T: ChipWithIrqChip> Sync for RegistrationWithIrqChip<T> {}
+
+    // SAFETY: Registration with and unregistration from the gpio subsystem (including irq chips for
+    // them) can happen from any thread. Additionally, `T::Data` (which is dropped during
+    // unregistration) is `Send`, so it is ok to move `Registration` to different threads.
+    unsafe impl<T: ChipWithIrqChip> Send for RegistrationWithIrqChip<T> where T::Data: Send {}
+
+    struct FlowHandler<T: ChipWithIrqChip>(PhantomData<T>);
+
+    impl<T: ChipWithIrqChip> irq::FlowHandler for FlowHandler<T> {
+        type Data = *mut bindings::gpio_chip;
+
+        fn handle_irq_flow(gc: *mut bindings::gpio_chip, desc: &irq::Descriptor) {
+            // SAFETY: `FlowHandler` is only used in gpio chips, and it is removed when the gpio is
+            // unregistered, so we know that `gc` must still be valid. We also know that the value
+            // stored as gpio data was returned by `T::Data::into_pointer` again because
+            // `FlowHandler` is a private structure only used in this way.
+            let data = unsafe { T::Data::borrow(bindings::gpiochip_get_data(gc)) };
+
+            // SAFETY: `gc` is valid (see comment above), so we can dereference it.
+            let domain = unsafe { irq::Domain::from_ptr((*gc).irq.domain) };
+
+            T::handle_irq_flow(data, desc, &domain);
+        }
+    }
+
+    /// Adapter from an irq chip with `gpio_chip` pointer as context to one where the gpio chip
+    /// data is passed as context.
+    struct IrqChipAdapter<T: irq::Chip>(PhantomData<T>);
+
+    impl<T: irq::Chip> irq::Chip for IrqChipAdapter<T> {
+        type Data = *mut bindings::gpio_chip;
+        const TO_USE: irq::ToUse = T::TO_USE;
+
+        fn ack(gc: *mut bindings::gpio_chip, irq_data: &irq::IrqData) {
+            // SAFETY: `IrqChipAdapter` is a private struct, only used when the data stored in the
+            // gpio chip is known to come from `T::Data`, and only valid while the gpio chip is
+            // registered, so `gc` is valid.
+            let data = unsafe { T::Data::borrow(bindings::gpiochip_get_data(gc as _)) };
+            T::ack(data, irq_data);
+        }
+
+        fn mask(gc: *mut bindings::gpio_chip, irq_data: &irq::IrqData) {
+            // SAFETY: `IrqChipAdapter` is a private struct, only used when the data stored in the
+            // gpio chip is known to come from `T::Data`, and only valid while the gpio chip is
+            // registered, so `gc` is valid.
+            let data = unsafe { T::Data::borrow(bindings::gpiochip_get_data(gc as _)) };
+            T::mask(data, irq_data);
+        }
+
+        fn unmask(gc: *mut bindings::gpio_chip, irq_data: &irq::IrqData) {
+            // SAFETY: `IrqChipAdapter` is a private struct, only used when the data stored in the
+            // gpio chip is known to come from `T::Data`, and only valid while the gpio chip is
+            // registered, so `gc` is valid.
+            let data = unsafe { T::Data::borrow(bindings::gpiochip_get_data(gc as _)) };
+            T::unmask(data, irq_data);
+        }
+
+        fn set_type(
+            gc: *mut bindings::gpio_chip,
+            irq_data: &mut irq::LockedIrqData,
+            flow_type: u32,
+        ) -> Result<irq::ExtraResult> {
+            // SAFETY: `IrqChipAdapter` is a private struct, only used when the data stored in the
+            // gpio chip is known to come from `T::Data`, and only valid while the gpio chip is
+            // registered, so `gc` is valid.
+            let data = unsafe { T::Data::borrow(bindings::gpiochip_get_data(gc as _)) };
+            T::set_type(data, irq_data, flow_type)
+        }
+
+        fn set_wake(gc: *mut bindings::gpio_chip, irq_data: &irq::IrqData, on: bool) -> Result {
+            // SAFETY: `IrqChipAdapter` is a private struct, only used when the data stored in the
+            // gpio chip is known to come from `T::Data`, and only valid while the gpio chip is
+            // registered, so `gc` is valid.
+            let data = unsafe { T::Data::borrow(bindings::gpiochip_get_data(gc as _)) };
+            T::set_wake(data, irq_data, on)
+        }
+    }
+}
diff --git a/rust/kernel/io_buffer.rs b/rust/kernel/io_buffer.rs
new file mode 100644
index 000000000000..ccecc4763aca
--- /dev/null
+++ b/rust/kernel/io_buffer.rs
@@ -0,0 +1,153 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Buffers used in IO.
+
+use crate::Result;
+use alloc::vec::Vec;
+use core::mem::{size_of, MaybeUninit};
+
+/// Represents a buffer to be read from during IO.
+pub trait IoBufferReader {
+    /// Returns the number of bytes left to be read from the io buffer.
+    ///
+    /// Note that even reading less than this number of bytes may fail.
+    fn len(&self) -> usize;
+
+    /// Returns `true` if no data is available in the io buffer.
+    fn is_empty(&self) -> bool {
+        self.len() == 0
+    }
+
+    /// Reads raw data from the io buffer into a raw kernel buffer.
+    ///
+    /// # Safety
+    ///
+    /// The output buffer must be valid.
+    unsafe fn read_raw(&mut self, out: *mut u8, len: usize) -> Result;
+
+    /// Reads all data remaining in the io buffer.
+    ///
+    /// Returns `EFAULT` if the address does not currently point to mapped, readable memory.
+    fn read_all(&mut self) -> Result<Vec<u8>> {
+        let mut data = Vec::<u8>::new();
+        data.try_resize(self.len(), 0)?;
+
+        // SAFETY: The output buffer is valid as we just allocated it.
+        unsafe { self.read_raw(data.as_mut_ptr(), data.len())? };
+        Ok(data)
+    }
+
+    /// Reads a byte slice from the io buffer.
+    ///
+    /// Returns `EFAULT` if the byte slice is bigger than the remaining size of the user slice or
+    /// if the address does not currently point to mapped, readable memory.
+    fn read_slice(&mut self, data: &mut [u8]) -> Result {
+        // SAFETY: The output buffer is valid as it's coming from a live reference.
+        unsafe { self.read_raw(data.as_mut_ptr(), data.len()) }
+    }
+
+    /// Reads the contents of a plain old data (POD) type from the io buffer.
+    fn read<T: ReadableFromBytes>(&mut self) -> Result<T> {
+        let mut out = MaybeUninit::<T>::uninit();
+        // SAFETY: The buffer is valid as it was just allocated.
+        unsafe { self.read_raw(out.as_mut_ptr() as _, size_of::<T>()) }?;
+        // SAFETY: We just initialised the data.
+        Ok(unsafe { out.assume_init() })
+    }
+}
+
+/// Represents a buffer to be written to during IO.
+pub trait IoBufferWriter {
+    /// Returns the number of bytes left to be written into the io buffer.
+    ///
+    /// Note that even writing less than this number of bytes may fail.
+    fn len(&self) -> usize;
+
+    /// Returns `true` if the io buffer cannot hold any additional data.
+    fn is_empty(&self) -> bool {
+        self.len() == 0
+    }
+
+    /// Writes zeroes to the io buffer.
+    ///
+    /// Differently from the other write functions, `clear` will zero as much as it can and update
+    /// the writer internal state to reflect this. It will, however, return an error if it cannot
+    /// clear `len` bytes.
+    ///
+    /// For example, if a caller requests that 100 bytes be cleared but a segfault happens after
+    /// 20 bytes, then EFAULT is returned and the writer is advanced by 20 bytes.
+    fn clear(&mut self, len: usize) -> Result;
+
+    /// Writes a byte slice into the io buffer.
+    ///
+    /// Returns `EFAULT` if the byte slice is bigger than the remaining size of the io buffer or if
+    /// the address does not currently point to mapped, writable memory.
+    fn write_slice(&mut self, data: &[u8]) -> Result {
+        // SAFETY: The input buffer is valid as it's coming from a live reference.
+        unsafe { self.write_raw(data.as_ptr(), data.len()) }
+    }
+
+    /// Writes raw data to the io buffer from a raw kernel buffer.
+    ///
+    /// # Safety
+    ///
+    /// The input buffer must be valid.
+    unsafe fn write_raw(&mut self, data: *const u8, len: usize) -> Result;
+
+    /// Writes the contents of the given data into the io buffer.
+    fn write<T: WritableToBytes>(&mut self, data: &T) -> Result {
+        // SAFETY: The input buffer is valid as it's coming from a live
+        // reference to a type that implements `WritableToBytes`.
+        unsafe { self.write_raw(data as *const T as _, size_of::<T>()) }
+    }
+}
+
+/// Specifies that a type is safely readable from byte slices.
+///
+/// Not all types can be safely read from byte slices; examples from
+/// <https://doc.rust-lang.org/reference/behavior-considered-undefined.html> include `bool`
+/// that must be either `0` or `1`, and `char` that cannot be a surrogate or above `char::MAX`.
+///
+/// # Safety
+///
+/// Implementers must ensure that the type is made up only of types that can be safely read from
+/// arbitrary byte sequences (e.g., `u32`, `u64`, etc.).
+pub unsafe trait ReadableFromBytes {}
+
+// SAFETY: All bit patterns are acceptable values of the types below.
+unsafe impl ReadableFromBytes for u8 {}
+unsafe impl ReadableFromBytes for u16 {}
+unsafe impl ReadableFromBytes for u32 {}
+unsafe impl ReadableFromBytes for u64 {}
+unsafe impl ReadableFromBytes for usize {}
+unsafe impl ReadableFromBytes for i8 {}
+unsafe impl ReadableFromBytes for i16 {}
+unsafe impl ReadableFromBytes for i32 {}
+unsafe impl ReadableFromBytes for i64 {}
+unsafe impl ReadableFromBytes for isize {}
+
+/// Specifies that a type is safely writable to byte slices.
+///
+/// This means that we don't read undefined values (which leads to UB) in preparation for writing
+/// to the byte slice. It also ensures that no potentially sensitive information is leaked into the
+/// byte slices.
+///
+/// # Safety
+///
+/// A type must not include padding bytes and must be fully initialised to safely implement
+/// [`WritableToBytes`] (i.e., it doesn't contain [`MaybeUninit`] fields). A composition of
+/// writable types in a structure is not necessarily writable because it may result in padding
+/// bytes.
+pub unsafe trait WritableToBytes {}
+
+// SAFETY: Initialised instances of the following types have no uninitialised portions.
+unsafe impl WritableToBytes for u8 {}
+unsafe impl WritableToBytes for u16 {}
+unsafe impl WritableToBytes for u32 {}
+unsafe impl WritableToBytes for u64 {}
+unsafe impl WritableToBytes for usize {}
+unsafe impl WritableToBytes for i8 {}
+unsafe impl WritableToBytes for i16 {}
+unsafe impl WritableToBytes for i32 {}
+unsafe impl WritableToBytes for i64 {}
+unsafe impl WritableToBytes for isize {}
diff --git a/rust/kernel/io_mem.rs b/rust/kernel/io_mem.rs
new file mode 100644
index 000000000000..c6d2ea4abc2c
--- /dev/null
+++ b/rust/kernel/io_mem.rs
@@ -0,0 +1,207 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Memory-mapped IO.
+//!
+//! C header: [`include/asm-generic/io.h`](../../../../include/asm-generic/io.h)
+
+#![allow(dead_code)]
+
+use crate::{bindings, Error, Result};
+use core::convert::TryInto;
+
+/// Represents a memory resource.
+pub struct Resource {
+    offset: bindings::resource_size_t,
+    size: bindings::resource_size_t,
+}
+
+impl Resource {
+    pub(crate) fn new(
+        start: bindings::resource_size_t,
+        end: bindings::resource_size_t,
+    ) -> Option<Self> {
+        if start == 0 {
+            return None;
+        }
+        Some(Self {
+            offset: start,
+            size: end.checked_sub(start)?.checked_add(1)?,
+        })
+    }
+}
+
+/// Represents a memory block of at least `SIZE` bytes.
+///
+/// # Invariants
+///
+/// `ptr` is a non-null and valid address of at least `SIZE` bytes and returned by an `ioremap`
+/// variant. `ptr` is also 8-byte aligned.
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::prelude::*;
+/// use kernel::io_mem::{IoMem, Resource};
+///
+/// fn test(res: Resource) -> Result {
+///     // Create an io mem block of at least 100 bytes.
+///     // SAFETY: No DMA operations are initiated through `mem`.
+///     let mem = unsafe { IoMem::<100>::try_new(res) }?;
+///
+///     // Read one byte from offset 10.
+///     let v = mem.readb(10);
+///
+///     // Write value to offset 20.
+///     mem.writeb(v, 20);
+///
+///     Ok(())
+/// }
+///
+/// ```
+pub struct IoMem<const SIZE: usize> {
+    ptr: usize,
+}
+
+macro_rules! define_read {
+    ($(#[$attr:meta])* $name:ident, $try_name:ident, $type_name:ty) => {
+        /// Reads IO data from the given offset known, at compile time.
+        ///
+        /// If the offset is not known at compile time, the build will fail.
+        $(#[$attr])*
+        pub fn $name(&self, offset: usize) -> $type_name {
+            Self::check_offset::<$type_name>(offset);
+            let ptr = self.ptr.wrapping_add(offset);
+            // SAFETY: The type invariants guarantee that `ptr` is a valid pointer. The check above
+            // guarantees that the code won't build if `offset` makes the read go out of bounds
+            // (including the type size).
+            unsafe { bindings::$name(ptr as _) }
+        }
+
+        /// Reads IO data from the given offset.
+        ///
+        /// It fails if/when the offset (plus the type size) is out of bounds.
+        $(#[$attr])*
+        pub fn $try_name(&self, offset: usize) -> Result<$type_name> {
+            if !Self::offset_ok::<$type_name>(offset) {
+                return Err(Error::EINVAL);
+            }
+            let ptr = self.ptr.wrapping_add(offset);
+            // SAFETY: The type invariants guarantee that `ptr` is a valid pointer. The check above
+            // returns an error if `offset` would make the read go out of bounds (including the
+            // type size).
+            Ok(unsafe { bindings::$name(ptr as _) })
+        }
+    };
+}
+
+macro_rules! define_write {
+    ($(#[$attr:meta])* $name:ident, $try_name:ident, $type_name:ty) => {
+        /// Writes IO data to the given offset, known at compile time.
+        ///
+        /// If the offset is not known at compile time, the build will fail.
+        $(#[$attr])*
+        pub fn $name(&self, value: $type_name, offset: usize) {
+            Self::check_offset::<$type_name>(offset);
+            let ptr = self.ptr.wrapping_add(offset);
+            // SAFETY: The type invariants guarantee that `ptr` is a valid pointer. The check above
+            // guarantees that the code won't link if `offset` makes the write go out of bounds
+            // (including the type size).
+            unsafe { bindings::$name(value, ptr as _) }
+        }
+
+        /// Writes IO data to the given offset.
+        ///
+        /// It fails if/when the offset (plus the type size) is out of bounds.
+        $(#[$attr])*
+        pub fn $try_name(&self, value: $type_name, offset: usize) -> Result {
+            if !Self::offset_ok::<$type_name>(offset) {
+                return Err(Error::EINVAL);
+            }
+            let ptr = self.ptr.wrapping_add(offset);
+            // SAFETY: The type invariants guarantee that `ptr` is a valid pointer. The check above
+            // returns an error if `offset` would make the write go out of bounds (including the
+            // type size).
+            unsafe { bindings::$name(value, ptr as _) };
+            Ok(())
+        }
+    };
+}
+
+impl<const SIZE: usize> IoMem<SIZE> {
+    /// Tries to create a new instance of a memory block.
+    ///
+    /// The resource described by `res` is mapped into the CPU's address space so that it can be
+    /// accessed directly. It is also consumed by this function so that it can't be mapped again
+    /// to a different address.
+    ///
+    /// # Safety
+    ///
+    /// Callers must ensure that either (a) the resulting interface cannot be used to initiate DMA
+    /// operations, or (b) that DMA operations initiated via the returned interface use DMA handles
+    /// allocated through the `dma` module.
+    pub unsafe fn try_new(res: Resource) -> Result<Self> {
+        // Check that the resource has at least `SIZE` bytes in it.
+        if res.size < SIZE.try_into()? {
+            return Err(Error::EINVAL);
+        }
+
+        // To be able to check pointers at compile time based only on offsets, we need to guarantee
+        // that the base pointer is minimally aligned. So we conservatively expect at least 8 bytes.
+        if res.offset % 8 != 0 {
+            crate::pr_err!("Physical address is not 64-bit aligned: {:x}", res.offset);
+            return Err(Error::EDOM);
+        }
+
+        // Try to map the resource.
+        // SAFETY: Just mapping the memory range.
+        let addr = unsafe { bindings::ioremap(res.offset, res.size as _) };
+        if addr.is_null() {
+            Err(Error::ENOMEM)
+        } else {
+            // INVARIANT: `addr` is non-null and was returned by `ioremap`, so it is valid. It is
+            // also 8-byte aligned because we checked it above.
+            Ok(Self { ptr: addr as usize })
+        }
+    }
+
+    const fn offset_ok<T>(offset: usize) -> bool {
+        let type_size = core::mem::size_of::<T>();
+        if let Some(end) = offset.checked_add(type_size) {
+            end <= SIZE && offset % type_size == 0
+        } else {
+            false
+        }
+    }
+
+    const fn check_offset<T>(offset: usize) {
+        crate::build_assert!(Self::offset_ok::<T>(offset), "IoMem offset overflow");
+    }
+
+    define_read!(readb, try_readb, u8);
+    define_read!(readw, try_readw, u16);
+    define_read!(readl, try_readl, u32);
+    define_read!(
+        #[cfg(CONFIG_64BIT)]
+        readq,
+        try_readq,
+        u64
+    );
+
+    define_write!(writeb, try_writeb, u8);
+    define_write!(writew, try_writew, u16);
+    define_write!(writel, try_writel, u32);
+    define_write!(
+        #[cfg(CONFIG_64BIT)]
+        writeq,
+        try_writeq,
+        u64
+    );
+}
+
+impl<const SIZE: usize> Drop for IoMem<SIZE> {
+    fn drop(&mut self) {
+        // SAFETY: By the type invariant, `self.ptr` is a value returned by a previous successful
+        // call to `ioremap`.
+        unsafe { bindings::iounmap(self.ptr as _) };
+    }
+}
diff --git a/rust/kernel/iov_iter.rs b/rust/kernel/iov_iter.rs
new file mode 100644
index 000000000000..fe738c529b84
--- /dev/null
+++ b/rust/kernel/iov_iter.rs
@@ -0,0 +1,81 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! IO vector iterators.
+//!
+//! C header: [`include/linux/uio.h`](../../../../include/linux/uio.h)
+
+use crate::{
+    bindings,
+    error::Error,
+    io_buffer::{IoBufferReader, IoBufferWriter},
+    Result,
+};
+
+/// Wraps the kernel's `struct iov_iter`.
+///
+/// # Invariants
+///
+/// The pointer `IovIter::ptr` is non-null and valid.
+pub struct IovIter {
+    ptr: *mut bindings::iov_iter,
+}
+
+impl IovIter {
+    fn common_len(&self) -> usize {
+        // SAFETY: `IovIter::ptr` is guaranteed to be valid by the type invariants.
+        unsafe { (*self.ptr).count }
+    }
+
+    /// Constructs a new [`struct iov_iter`] wrapper.
+    ///
+    /// # Safety
+    ///
+    /// The pointer `ptr` must be non-null and valid for the lifetime of the object.
+    pub(crate) unsafe fn from_ptr(ptr: *mut bindings::iov_iter) -> Self {
+        // INVARIANTS: the safety contract ensures the type invariant will hold.
+        Self { ptr }
+    }
+}
+
+impl IoBufferWriter for IovIter {
+    fn len(&self) -> usize {
+        self.common_len()
+    }
+
+    fn clear(&mut self, mut len: usize) -> Result {
+        while len > 0 {
+            // SAFETY: `IovIter::ptr` is guaranteed to be valid by the type invariants.
+            let written = unsafe { bindings::iov_iter_zero(len, self.ptr) };
+            if written == 0 {
+                return Err(Error::EFAULT);
+            }
+
+            len -= written;
+        }
+        Ok(())
+    }
+
+    unsafe fn write_raw(&mut self, data: *const u8, len: usize) -> Result {
+        let res = unsafe { bindings::copy_to_iter(data as _, len, self.ptr) };
+        if res != len {
+            Err(Error::EFAULT)
+        } else {
+            Ok(())
+        }
+    }
+}
+
+impl IoBufferReader for IovIter {
+    fn len(&self) -> usize {
+        self.common_len()
+    }
+
+    unsafe fn read_raw(&mut self, out: *mut u8, len: usize) -> Result {
+        let res = unsafe { bindings::copy_from_iter(out as _, len, self.ptr) };
+        if res != len {
+            Err(Error::EFAULT)
+        } else {
+            Ok(())
+        }
+    }
+}
diff --git a/rust/kernel/irq.rs b/rust/kernel/irq.rs
new file mode 100644
index 000000000000..256bbf8b1ea3
--- /dev/null
+++ b/rust/kernel/irq.rs
@@ -0,0 +1,408 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Interrupts and interrupt chips.
+//!
+//! See <https://www.kernel.org/doc/Documentation/core-api/genericirq.rst>.
+//!
+//! C headers: [`include/linux/irq.h`](../../../../include/linux/irq.h) and
+//! [`include/linux/interrupt.h`](../../../../include/linux/interrupt.h).
+
+#![allow(dead_code)]
+
+use crate::{bindings, c_types, error::from_kernel_result, types::PointerWrapper, Error, Result};
+use core::ops::Deref;
+
+type IrqHwNumber = bindings::irq_hw_number_t;
+
+/// Wraps the kernel's `struct irq_data`.
+///
+/// # Invariants
+///
+/// The pointer `IrqData::ptr` is non-null and valid.
+pub struct IrqData {
+    ptr: *mut bindings::irq_data,
+}
+
+impl IrqData {
+    /// Creates a new `IrqData` instance from a raw pointer.
+    ///
+    /// # Safety
+    ///
+    /// Callers must ensure that `ptr` is non-null and valid when the function is called, and that
+    /// it remains valid for the lifetime of the return [`IrqData`] instance.
+    unsafe fn from_ptr(ptr: *mut bindings::irq_data) -> Self {
+        // INVARIANTS: By the safety requirements, the instance we're creating satisfies the type
+        // invariants.
+        Self { ptr }
+    }
+
+    /// Returns the hardware irq number.
+    pub fn hwirq(&self) -> IrqHwNumber {
+        // SAFETY: By the type invariants, it's ok to dereference `ptr`.
+        unsafe { (*self.ptr).hwirq }
+    }
+}
+
+/// Wraps the kernel's `struct irq_data` when it is locked.
+///
+/// Being locked allows additional operations to be performed on the data.
+pub struct LockedIrqData(IrqData);
+
+impl LockedIrqData {
+    /// Sets the high-level irq flow handler to the builtin one for level-triggered irqs.
+    pub fn set_level_handler(&mut self) {
+        // SAFETY: By the type invariants of `self.0`, we know `self.0.ptr` is valid.
+        unsafe { bindings::irq_set_handler_locked(self.0.ptr, Some(bindings::handle_level_irq)) };
+    }
+
+    /// Sets the high-level irq flow handler to the builtin one for edge-triggered irqs.
+    pub fn set_edge_handler(&mut self) {
+        // SAFETY: By the type invariants of `self.0`, we know `self.0.ptr` is valid.
+        unsafe { bindings::irq_set_handler_locked(self.0.ptr, Some(bindings::handle_edge_irq)) };
+    }
+
+    /// Sets the high-level irq flow handler to the builtin one for bad irqs.
+    pub fn set_bad_handler(&mut self) {
+        // SAFETY: By the type invariants of `self.0`, we know `self.0.ptr` is valid.
+        unsafe { bindings::irq_set_handler_locked(self.0.ptr, Some(bindings::handle_bad_irq)) };
+    }
+}
+
+impl Deref for LockedIrqData {
+    type Target = IrqData;
+
+    fn deref(&self) -> &Self::Target {
+        &self.0
+    }
+}
+
+/// Extra information returned by some of the [`Chip`] methods on success.
+pub enum ExtraResult {
+    /// Indicates that the caller (irq core) will update the descriptor state.
+    None = bindings::IRQ_SET_MASK_OK as _,
+
+    /// Indicates that the callee (irq chip implementation) already updated the descriptor state.
+    NoCopy = bindings::IRQ_SET_MASK_OK_NOCOPY as _,
+
+    /// Same as [`ExtraResult::None`] in terms of updating descriptor state. It is used in stacked
+    /// irq chips to indicate that descendant chips should be skipped.
+    Done = bindings::IRQ_SET_MASK_OK_DONE as _,
+}
+
+/// An irq chip.
+///
+/// It is a trait for the functions defined in [`struct irq_chip`].
+///
+/// [`struct irq_chip`]: ../../../include/linux/irq.h
+pub trait Chip: Sized {
+    /// The type of the context data stored in the irq chip and made available on each callback.
+    type Data: PointerWrapper;
+
+    /// The methods to use to populate [`struct irq_chip`]. This is typically populated with
+    /// [`declare_irq_chip_operations`].
+    const TO_USE: ToUse;
+
+    /// Called at the start of a new interrupt.
+    fn ack(data: <Self::Data as PointerWrapper>::Borrowed<'_>, irq_data: &IrqData);
+
+    /// Masks an interrupt source.
+    fn mask(data: <Self::Data as PointerWrapper>::Borrowed<'_>, irq_data: &IrqData);
+
+    /// Unmasks an interrupt source.
+    fn unmask(_data: <Self::Data as PointerWrapper>::Borrowed<'_>, irq_data: &IrqData);
+
+    /// Sets the flow type of an interrupt.
+    ///
+    /// The flow type is a combination of the constants in [`Type`].
+    fn set_type(
+        _data: <Self::Data as PointerWrapper>::Borrowed<'_>,
+        _irq_data: &mut LockedIrqData,
+        _flow_type: u32,
+    ) -> Result<ExtraResult> {
+        Ok(ExtraResult::None)
+    }
+
+    /// Enables or disables power-management wake-on of an interrupt.
+    fn set_wake(
+        _data: <Self::Data as PointerWrapper>::Borrowed<'_>,
+        _irq_data: &IrqData,
+        _on: bool,
+    ) -> Result {
+        Ok(())
+    }
+}
+
+/// Initialises `chip` with the callbacks defined in `T`.
+///
+/// # Safety
+///
+/// The caller must ensure that the value stored in the irq chip data is the result of calling
+/// [`PointerWrapper::into_pointer] for the [`T::Data`] type.
+pub(crate) unsafe fn init_chip<T: Chip>(chip: &mut bindings::irq_chip) {
+    chip.irq_ack = Some(irq_ack_callback::<T>);
+    chip.irq_mask = Some(irq_mask_callback::<T>);
+    chip.irq_unmask = Some(irq_unmask_callback::<T>);
+
+    if T::TO_USE.set_type {
+        chip.irq_set_type = Some(irq_set_type_callback::<T>);
+    }
+
+    if T::TO_USE.set_wake {
+        chip.irq_set_wake = Some(irq_set_wake_callback::<T>);
+    }
+}
+
+/// Represents which fields of [`struct irq_chip`] should be populated with pointers.
+///
+/// This is typically populated with the [`declare_irq_chip_operations`] macro.
+pub struct ToUse {
+    /// The `irq_set_type` field of [`struct irq_chip`].
+    pub set_type: bool,
+
+    /// The `irq_set_wake` field of [`struct irq_chip`].
+    pub set_wake: bool,
+}
+
+/// A constant version where all values are to set to `false`, that is, all supported fields will
+/// be set to null pointers.
+pub const USE_NONE: ToUse = ToUse {
+    set_type: false,
+    set_wake: false,
+};
+
+/// Defines the [`Chip::TO_USE`] field based on a list of fields to be populated.
+#[macro_export]
+macro_rules! declare_irq_chip_operations {
+    () => {
+        const TO_USE: $crate::irq::ToUse = $crate::irq::USE_NONE;
+    };
+    ($($i:ident),+) => {
+        #[allow(clippy::needless_update)]
+        const TO_USE: $crate::irq::ToUse =
+            $crate::irq::ToUse {
+                $($i: true),+ ,
+                ..$crate::irq::USE_NONE
+            };
+    };
+}
+
+/// Enables or disables power-management wake-on for the given irq number.
+pub fn set_wake(irq: u32, on: bool) -> Result {
+    // SAFETY: Just an FFI call, there are no extra requirements for safety.
+    let ret = unsafe { bindings::irq_set_irq_wake(irq, on as _) };
+    if ret < 0 {
+        Err(Error::from_kernel_errno(ret))
+    } else {
+        Ok(())
+    }
+}
+
+unsafe extern "C" fn irq_ack_callback<T: Chip>(irq_data: *mut bindings::irq_data) {
+    // SAFETY: The safety requirements of `init_chip`, which is the only place that uses this
+    // callback, ensure that the value stored as irq chip data comes from a previous call to
+    // `PointerWrapper::into_pointer`.
+    let data = unsafe { T::Data::borrow(bindings::irq_data_get_irq_chip_data(irq_data)) };
+
+    // SAFETY: The value returned by `IrqData` is only valid until the end of this function, and
+    // `irq_data` is guaranteed to be valid until then (by the contract with C code).
+    T::ack(data, unsafe { &IrqData::from_ptr(irq_data) })
+}
+
+unsafe extern "C" fn irq_mask_callback<T: Chip>(irq_data: *mut bindings::irq_data) {
+    // SAFETY: The safety requirements of `init_chip`, which is the only place that uses this
+    // callback, ensure that the value stored as irq chip data comes from a previous call to
+    // `PointerWrapper::into_pointer`.
+    let data = unsafe { T::Data::borrow(bindings::irq_data_get_irq_chip_data(irq_data)) };
+
+    // SAFETY: The value returned by `IrqData` is only valid until the end of this function, and
+    // `irq_data` is guaranteed to be valid until then (by the contract with C code).
+    T::mask(data, unsafe { &IrqData::from_ptr(irq_data) })
+}
+
+unsafe extern "C" fn irq_unmask_callback<T: Chip>(irq_data: *mut bindings::irq_data) {
+    // SAFETY: The safety requirements of `init_chip`, which is the only place that uses this
+    // callback, ensure that the value stored as irq chip data comes from a previous call to
+    // `PointerWrapper::into_pointer`.
+    let data = unsafe { T::Data::borrow(bindings::irq_data_get_irq_chip_data(irq_data)) };
+
+    // SAFETY: The value returned by `IrqData` is only valid until the end of this function, and
+    // `irq_data` is guaranteed to be valid until then (by the contract with C code).
+    T::unmask(data, unsafe { &IrqData::from_ptr(irq_data) })
+}
+
+unsafe extern "C" fn irq_set_type_callback<T: Chip>(
+    irq_data: *mut bindings::irq_data,
+    flow_type: c_types::c_uint,
+) -> c_types::c_int {
+    from_kernel_result! {
+        // SAFETY: The safety requirements of `init_chip`, which is the only place that uses this
+        // callback, ensure that the value stored as irq chip data comes from a previous call to
+        // `PointerWrapper::into_pointer`.
+        let data = unsafe { T::Data::borrow(bindings::irq_data_get_irq_chip_data(irq_data)) };
+
+        // SAFETY: The value returned by `IrqData` is only valid until the end of this function, and
+        // `irq_data` is guaranteed to be valid until then (by the contract with C code).
+        let ret = T::set_type(data, &mut LockedIrqData(unsafe { IrqData::from_ptr(irq_data) }), flow_type)?;
+        Ok(ret as _)
+    }
+}
+
+unsafe extern "C" fn irq_set_wake_callback<T: Chip>(
+    irq_data: *mut bindings::irq_data,
+    on: c_types::c_uint,
+) -> c_types::c_int {
+    from_kernel_result! {
+        // SAFETY: The safety requirements of `init_chip`, which is the only place that uses this
+        // callback, ensure that the value stored as irq chip data comes from a previous call to
+        // `PointerWrapper::into_pointer`.
+        let data = unsafe { T::Data::borrow(bindings::irq_data_get_irq_chip_data(irq_data)) };
+
+        // SAFETY: The value returned by `IrqData` is only valid until the end of this function, and
+        // `irq_data` is guaranteed to be valid until then (by the contract with C code).
+        T::set_wake(data, unsafe { &IrqData::from_ptr(irq_data) }, on != 0)?;
+        Ok(0)
+    }
+}
+
+/// Contains constants that describes how an interrupt can be triggered.
+///
+/// It is tagged with `non_exhaustive` to prevent users from instantiating it.
+#[non_exhaustive]
+pub struct Type;
+
+impl Type {
+    /// The interrupt cannot be triggered.
+    pub const NONE: u32 = bindings::IRQ_TYPE_NONE;
+
+    /// The interrupt is triggered when the signal goes from low to high.
+    pub const EDGE_RISING: u32 = bindings::IRQ_TYPE_EDGE_RISING;
+
+    /// The interrupt is triggered when the signal goes from high to low.
+    pub const EDGE_FALLING: u32 = bindings::IRQ_TYPE_EDGE_FALLING;
+
+    /// The interrupt is triggered when the signal goes from low to high and when it goes to high
+    /// to low.
+    pub const EDGE_BOTH: u32 = bindings::IRQ_TYPE_EDGE_BOTH;
+
+    /// The interrupt is triggered while the signal is held high.
+    pub const LEVEL_HIGH: u32 = bindings::IRQ_TYPE_LEVEL_HIGH;
+
+    /// The interrupt is triggered while the signal is held low.
+    pub const LEVEL_LOW: u32 = bindings::IRQ_TYPE_LEVEL_LOW;
+}
+
+/// Wraps the kernel's `struct irq_desc`.
+///
+/// # Invariants
+///
+/// The pointer `Descriptor::ptr` is non-null and valid.
+pub struct Descriptor {
+    pub(crate) ptr: *mut bindings::irq_desc,
+}
+
+impl Descriptor {
+    /// Constructs a new `struct irq_desc` wrapper.
+    ///
+    /// # Safety
+    ///
+    /// The pointer `ptr` must be non-null and valid for the lifetime of the returned object.
+    unsafe fn from_ptr(ptr: *mut bindings::irq_desc) -> Self {
+        // INVARIANT: The safety requirements ensure the invariant.
+        Self { ptr }
+    }
+
+    /// Calls `chained_irq_enter` and returns a guard that calls `chained_irq_exit` once dropped.
+    ///
+    /// It is meant to be used by chained irq handlers to dispatch irqs to the next handlers.
+    pub fn enter_chained(&self) -> ChainedGuard<'_> {
+        // SAFETY: By the type invariants, `ptr` is always non-null and valid.
+        let irq_chip = unsafe { bindings::irq_desc_get_chip(self.ptr) };
+
+        // SAFETY: By the type invariants, `ptr` is always non-null and valid. `irq_chip` was just
+        // returned from `ptr`, so it is still valid too.
+        unsafe { bindings::chained_irq_enter(irq_chip, self.ptr) };
+        ChainedGuard {
+            desc: self,
+            irq_chip,
+        }
+    }
+}
+
+/// A guard to call `chained_irq_exit` after `chained_irq_enter` was called.
+///
+/// It is also used as evidence that a previous `chained_irq_enter` was called. So there are no
+/// public constructors and it is only created after indeed calling `chained_irq_enter`.
+pub struct ChainedGuard<'a> {
+    desc: &'a Descriptor,
+    irq_chip: *mut bindings::irq_chip,
+}
+
+impl Drop for ChainedGuard<'_> {
+    fn drop(&mut self) {
+        // SAFETY: The lifetime of `ChainedGuard` guarantees that `self.desc` remains valid, so it
+        // also guarantess `irq_chip` (which was returned from it) and `self.desc.ptr` (guaranteed
+        // by the type invariants).
+        unsafe { bindings::chained_irq_exit(self.irq_chip, self.desc.ptr) };
+    }
+}
+
+/// Wraps the kernel's `struct irq_domain`.
+///
+/// # Invariants
+///
+/// The pointer `Domain::ptr` is non-null and valid.
+pub struct Domain {
+    ptr: *mut bindings::irq_domain,
+}
+
+impl Domain {
+    /// Constructs a new `struct irq_domain` wrapper.
+    ///
+    /// # Safety
+    ///
+    /// The pointer `ptr` must be non-null and valid for the lifetime of the returned object.
+    pub(crate) unsafe fn from_ptr(ptr: *mut bindings::irq_domain) -> Self {
+        // INVARIANT: The safety requirements ensure the invariant.
+        Self { ptr }
+    }
+
+    /// Invokes the chained handler of the given hw irq of the given domain.
+    ///
+    /// It requires evidence that `chained_irq_enter` was called, which is done by passing a
+    /// `ChainedGuard` instance.
+    pub fn generic_handle_chained(&self, hwirq: u32, _guard: &ChainedGuard<'_>) {
+        // SAFETY: `ptr` is valid by the type invariants.
+        unsafe { bindings::generic_handle_domain_irq(self.ptr, hwirq) };
+    }
+}
+
+/// A high-level irq flow handler.
+pub trait FlowHandler {
+    /// The data associated with the handler.
+    type Data: PointerWrapper;
+
+    /// Implements the irq flow for the given descriptor.
+    fn handle_irq_flow(data: <Self::Data as PointerWrapper>::Borrowed<'_>, desc: &Descriptor);
+}
+
+/// Returns the raw irq flow handler corresponding to the (high-level) one defined in `T`.
+///
+/// # Safety
+///
+/// The caller must ensure that the value stored in the irq handler data (as returned by
+/// `irq_desc_get_handler_data`) is the result of calling [`PointerWrapper::into_pointer] for the
+/// [`T::Data`] type.
+pub(crate) unsafe fn new_flow_handler<T: FlowHandler>() -> bindings::irq_flow_handler_t {
+    Some(irq_flow_handler::<T>)
+}
+
+unsafe extern "C" fn irq_flow_handler<T: FlowHandler>(desc: *mut bindings::irq_desc) {
+    // SAFETY: By the safety requirements of `new_flow_handler`, we know that the value returned by
+    // `irq_desc_get_handler_data` comes from calling `T::Data::into_pointer`. `desc` is valid by
+    // the C API contract.
+    let data = unsafe { T::Data::borrow(bindings::irq_desc_get_handler_data(desc)) };
+
+    // SAFETY: The C API guarantees that `desc` is valid for the duration of this call, which
+    // outlives the lifetime returned by `from_desc`.
+    T::handle_irq_flow(data, &unsafe { Descriptor::from_ptr(desc) });
+}
diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs
new file mode 100644
index 000000000000..5917b7d789c4
--- /dev/null
+++ b/rust/kernel/lib.rs
@@ -0,0 +1,256 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! The `kernel` crate.
+//!
+//! This crate contains the kernel APIs that have been ported or wrapped for
+//! usage by Rust code in the kernel and is shared by all of them.
+//!
+//! In other words, all the rest of the Rust code in the kernel (e.g. kernel
+//! modules written in Rust) depends on [`core`], [`alloc`] and this crate.
+//!
+//! If you need a kernel C API that is not ported or wrapped yet here, then
+//! do so first instead of bypassing this crate.
+
+#![no_std]
+#![feature(
+    allocator_api,
+    associated_type_defaults,
+    concat_idents,
+    const_fn_trait_bound,
+    const_mut_refs,
+    doc_cfg,
+    generic_associated_types,
+    ptr_metadata,
+    receiver_trait,
+    coerce_unsized,
+    dispatch_from_dyn,
+    unsize
+)]
+
+// Ensure conditional compilation based on the kernel configuration works;
+// otherwise we may silently break things like initcall handling.
+#[cfg(not(CONFIG_RUST))]
+compile_error!("Missing kernel configuration for conditional compilation");
+
+#[cfg(not(test))]
+#[cfg(not(testlib))]
+mod allocator;
+
+#[doc(hidden)]
+pub mod bindings;
+
+#[cfg(CONFIG_ARM_AMBA)]
+pub mod amba;
+pub mod buffer;
+pub mod c_types;
+pub mod chrdev;
+pub mod cred;
+pub mod device;
+pub mod driver;
+mod error;
+pub mod file;
+pub mod file_operations;
+pub mod gpio;
+pub mod irq;
+pub mod miscdev;
+pub mod pages;
+pub mod power;
+pub mod revocable;
+pub mod security;
+pub mod str;
+pub mod task;
+
+pub mod linked_list;
+mod raw_list;
+pub mod rbtree;
+
+#[doc(hidden)]
+pub mod module_param;
+
+mod build_assert;
+pub mod prelude;
+pub mod print;
+pub mod random;
+mod static_assert;
+#[doc(hidden)]
+pub mod std_vendor;
+pub mod sync;
+
+#[cfg(any(CONFIG_SYSCTL, doc))]
+#[doc(cfg(CONFIG_SYSCTL))]
+pub mod sysctl;
+
+pub mod io_buffer;
+pub mod io_mem;
+pub mod iov_iter;
+pub mod of;
+pub mod platdev;
+mod types;
+pub mod user_ptr;
+
+#[doc(hidden)]
+pub use build_error::build_error;
+
+pub use crate::error::{to_result, Error, Result};
+pub use crate::types::{bit, bits_iter, Mode, Opaque, ScopeGuard};
+
+use core::marker::PhantomData;
+
+/// Page size defined in terms of the `PAGE_SHIFT` macro from C.
+///
+/// [`PAGE_SHIFT`]: ../../../include/asm-generic/page.h
+pub const PAGE_SIZE: usize = 1 << bindings::PAGE_SHIFT;
+
+/// Prefix to appear before log messages printed from within the kernel crate.
+const __LOG_PREFIX: &[u8] = b"rust_kernel\0";
+
+/// The top level entrypoint to implementing a kernel module.
+///
+/// For any teardown or cleanup operations, your type may implement [`Drop`].
+pub trait KernelModule: Sized + Sync {
+    /// Called at module initialization time.
+    ///
+    /// Use this method to perform whatever setup or registration your module
+    /// should do.
+    ///
+    /// Equivalent to the `module_init` macro in the C API.
+    fn init(name: &'static str::CStr, module: &'static ThisModule) -> Result<Self>;
+}
+
+/// Equivalent to `THIS_MODULE` in the C API.
+///
+/// C header: `include/linux/export.h`
+pub struct ThisModule(*mut bindings::module);
+
+// SAFETY: `THIS_MODULE` may be used from all threads within a module.
+unsafe impl Sync for ThisModule {}
+
+impl ThisModule {
+    /// Creates a [`ThisModule`] given the `THIS_MODULE` pointer.
+    ///
+    /// # Safety
+    ///
+    /// The pointer must be equal to the right `THIS_MODULE`.
+    pub const unsafe fn from_ptr(ptr: *mut bindings::module) -> ThisModule {
+        ThisModule(ptr)
+    }
+
+    /// Locks the module parameters to access them.
+    ///
+    /// Returns a [`KParamGuard`] that will release the lock when dropped.
+    pub fn kernel_param_lock(&self) -> KParamGuard<'_> {
+        // SAFETY: `kernel_param_lock` will check if the pointer is null and
+        // use the built-in mutex in that case.
+        #[cfg(CONFIG_SYSFS)]
+        unsafe {
+            bindings::kernel_param_lock(self.0)
+        }
+
+        KParamGuard {
+            #[cfg(CONFIG_SYSFS)]
+            this_module: self,
+            phantom: PhantomData,
+        }
+    }
+}
+
+/// Scoped lock on the kernel parameters of [`ThisModule`].
+///
+/// Lock will be released when this struct is dropped.
+pub struct KParamGuard<'a> {
+    #[cfg(CONFIG_SYSFS)]
+    this_module: &'a ThisModule,
+    phantom: PhantomData<&'a ()>,
+}
+
+#[cfg(CONFIG_SYSFS)]
+impl<'a> Drop for KParamGuard<'a> {
+    fn drop(&mut self) {
+        // SAFETY: `kernel_param_lock` will check if the pointer is null and
+        // use the built-in mutex in that case. The existance of `self`
+        // guarantees that the lock is held.
+        unsafe { bindings::kernel_param_unlock(self.this_module.0) }
+    }
+}
+
+/// Calculates the offset of a field from the beginning of the struct it belongs to.
+///
+/// # Example
+///
+/// ```
+/// # use kernel::prelude::*;
+/// # use kernel::offset_of;
+/// struct Test {
+///     a: u64,
+///     b: u32,
+/// }
+///
+/// fn test() {
+///     // This prints `8`.
+///     pr_info!("{}\n", offset_of!(Test, b));
+/// }
+/// ```
+#[macro_export]
+macro_rules! offset_of {
+    ($type:ty, $($f:tt)*) => {{
+        let tmp = core::mem::MaybeUninit::<$type>::uninit();
+        let outer = tmp.as_ptr();
+        // To avoid warnings when nesting `unsafe` blocks.
+        #[allow(unused_unsafe)]
+        // SAFETY: The pointer is valid and aligned, just not initialised; `addr_of` ensures that
+        // we don't actually read from `outer` (which would be UB) nor create an intermediate
+        // reference.
+        let inner = unsafe { core::ptr::addr_of!((*outer).$($f)*) } as *const u8;
+        // To avoid warnings when nesting `unsafe` blocks.
+        #[allow(unused_unsafe)]
+        // SAFETY: The two pointers are within the same allocation block.
+        unsafe { inner.offset_from(outer as *const u8) }
+    }}
+}
+
+/// Produces a pointer to an object from a pointer to one of its fields.
+///
+/// # Safety
+///
+/// Callers must ensure that the pointer to the field is in fact a pointer to the specified field,
+/// as opposed to a pointer to another object of the same type. If this condition is not met,
+/// any dereference of the resulting pointer is UB.
+///
+/// # Example
+///
+/// ```
+/// # use kernel::prelude::*;
+/// # use kernel::container_of;
+/// struct Test {
+///     a: u64,
+///     b: u32,
+/// }
+///
+/// fn test() {
+///     let test = Test { a: 10, b: 20 };
+///     let b_ptr = &test.b;
+///     let test_alias = container_of!(b_ptr, Test, b);
+///     // This prints `true`.
+///     pr_info!("{}\n", core::ptr::eq(&test, test_alias));
+/// }
+/// ```
+#[macro_export]
+macro_rules! container_of {
+    ($ptr:expr, $type:ty, $($f:tt)*) => {{
+        let ptr = $ptr as *const _ as *const u8;
+        let offset = $crate::offset_of!($type, $($f)*);
+        ptr.wrapping_offset(-offset) as *const $type
+    }}
+}
+
+#[cfg(not(any(testlib, test)))]
+#[panic_handler]
+fn panic(info: &core::panic::PanicInfo<'_>) -> ! {
+    pr_emerg!("{}\n", info);
+    // SAFETY: FFI call.
+    unsafe { bindings::BUG() };
+    // Bindgen currently does not recognize `__noreturn` so `BUG` returns `()`
+    // instead of `!`.
+    // https://github.com/rust-lang/rust-bindgen/issues/2094
+    loop {}
+}
diff --git a/rust/kernel/linked_list.rs b/rust/kernel/linked_list.rs
new file mode 100644
index 000000000000..3330edcc7ca8
--- /dev/null
+++ b/rust/kernel/linked_list.rs
@@ -0,0 +1,247 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Linked lists.
+//!
+//! TODO: This module is a work in progress.
+
+use alloc::boxed::Box;
+use core::ptr::NonNull;
+
+pub use crate::raw_list::{Cursor, GetLinks, Links};
+use crate::{raw_list, raw_list::RawList, sync::Ref};
+
+// TODO: Use the one from `kernel::file_operations::PointerWrapper` instead.
+/// Wraps an object to be inserted in a linked list.
+pub trait Wrapper<T: ?Sized> {
+    /// Converts the wrapped object into a pointer that represents it.
+    fn into_pointer(self) -> NonNull<T>;
+
+    /// Converts the object back from the pointer representation.
+    ///
+    /// # Safety
+    ///
+    /// The passed pointer must come from a previous call to [`Wrapper::into_pointer()`].
+    unsafe fn from_pointer(ptr: NonNull<T>) -> Self;
+
+    /// Returns a reference to the wrapped object.
+    fn as_ref(&self) -> &T;
+}
+
+impl<T: ?Sized> Wrapper<T> for Box<T> {
+    fn into_pointer(self) -> NonNull<T> {
+        NonNull::new(Box::into_raw(self)).unwrap()
+    }
+
+    unsafe fn from_pointer(ptr: NonNull<T>) -> Self {
+        unsafe { Box::from_raw(ptr.as_ptr()) }
+    }
+
+    fn as_ref(&self) -> &T {
+        AsRef::as_ref(self)
+    }
+}
+
+impl<T: ?Sized> Wrapper<T> for Ref<T> {
+    fn into_pointer(self) -> NonNull<T> {
+        NonNull::new(Ref::into_raw(self) as _).unwrap()
+    }
+
+    unsafe fn from_pointer(ptr: NonNull<T>) -> Self {
+        // SAFETY: The safety requirements of `from_pointer` satisfy the ones from `Ref::from_raw`.
+        unsafe { Ref::from_raw(ptr.as_ptr() as _) }
+    }
+
+    fn as_ref(&self) -> &T {
+        AsRef::as_ref(self)
+    }
+}
+
+impl<T: ?Sized> Wrapper<T> for &T {
+    fn into_pointer(self) -> NonNull<T> {
+        NonNull::from(self)
+    }
+
+    unsafe fn from_pointer(ptr: NonNull<T>) -> Self {
+        unsafe { &*ptr.as_ptr() }
+    }
+
+    fn as_ref(&self) -> &T {
+        self
+    }
+}
+
+/// A descriptor of wrapped list elements.
+pub trait GetLinksWrapped: GetLinks {
+    /// Specifies which wrapper (e.g., `Box` and `Arc`) wraps the list entries.
+    type Wrapped: Wrapper<Self::EntryType>;
+}
+
+impl<T: ?Sized> GetLinksWrapped for Box<T>
+where
+    Box<T>: GetLinks,
+{
+    type Wrapped = Box<<Box<T> as GetLinks>::EntryType>;
+}
+
+impl<T: GetLinks + ?Sized> GetLinks for Box<T> {
+    type EntryType = T::EntryType;
+    fn get_links(data: &Self::EntryType) -> &Links<Self::EntryType> {
+        <T as GetLinks>::get_links(data)
+    }
+}
+
+impl<T: ?Sized> GetLinksWrapped for Ref<T>
+where
+    Ref<T>: GetLinks,
+{
+    type Wrapped = Ref<<Ref<T> as GetLinks>::EntryType>;
+}
+
+impl<T: GetLinks + ?Sized> GetLinks for Ref<T> {
+    type EntryType = T::EntryType;
+
+    fn get_links(data: &Self::EntryType) -> &Links<Self::EntryType> {
+        <T as GetLinks>::get_links(data)
+    }
+}
+
+/// A linked list.
+///
+/// Elements in the list are wrapped and ownership is transferred to the list while the element is
+/// in the list.
+pub struct List<G: GetLinksWrapped> {
+    list: RawList<G>,
+}
+
+impl<G: GetLinksWrapped> List<G> {
+    /// Constructs a new empty linked list.
+    pub fn new() -> Self {
+        Self {
+            list: RawList::new(),
+        }
+    }
+
+    /// Returns whether the list is empty.
+    pub fn is_empty(&self) -> bool {
+        self.list.is_empty()
+    }
+
+    /// Adds the given object to the end (back) of the list.
+    ///
+    /// It is dropped if it's already on this (or another) list; this can happen for
+    /// reference-counted objects, so dropping means decrementing the reference count.
+    pub fn push_back(&mut self, data: G::Wrapped) {
+        let ptr = data.into_pointer();
+
+        // SAFETY: We took ownership of the entry, so it is safe to insert it.
+        if !unsafe { self.list.push_back(ptr.as_ref()) } {
+            // If insertion failed, rebuild object so that it can be freed.
+            // SAFETY: We just called `into_pointer` above.
+            unsafe { G::Wrapped::from_pointer(ptr) };
+        }
+    }
+
+    /// Inserts the given object after `existing`.
+    ///
+    /// It is dropped if it's already on this (or another) list; this can happen for
+    /// reference-counted objects, so dropping means decrementing the reference count.
+    ///
+    /// # Safety
+    ///
+    /// Callers must ensure that `existing` points to a valid entry that is on the list.
+    pub unsafe fn insert_after(&mut self, existing: NonNull<G::EntryType>, data: G::Wrapped) {
+        let ptr = data.into_pointer();
+        let entry = unsafe { &*existing.as_ptr() };
+        if unsafe { !self.list.insert_after(entry, ptr.as_ref()) } {
+            // If insertion failed, rebuild object so that it can be freed.
+            unsafe { G::Wrapped::from_pointer(ptr) };
+        }
+    }
+
+    /// Removes the given entry.
+    ///
+    /// # Safety
+    ///
+    /// Callers must ensure that `data` is either on this list or in no list. It being on another
+    /// list leads to memory unsafety.
+    pub unsafe fn remove(&mut self, data: &G::Wrapped) -> Option<G::Wrapped> {
+        let entry_ref = Wrapper::as_ref(data);
+        if unsafe { self.list.remove(entry_ref) } {
+            Some(unsafe { G::Wrapped::from_pointer(NonNull::from(entry_ref)) })
+        } else {
+            None
+        }
+    }
+
+    /// Removes the element currently at the front of the list and returns it.
+    ///
+    /// Returns `None` if the list is empty.
+    pub fn pop_front(&mut self) -> Option<G::Wrapped> {
+        let front = self.list.pop_front()?;
+        // SAFETY: Elements on the list were inserted after a call to `into_pointer `.
+        Some(unsafe { G::Wrapped::from_pointer(front) })
+    }
+
+    /// Returns a cursor starting on the first (front) element of the list.
+    pub fn cursor_front(&self) -> Cursor<'_, G> {
+        self.list.cursor_front()
+    }
+
+    /// Returns a mutable cursor starting on the first (front) element of the list.
+    pub fn cursor_front_mut(&mut self) -> CursorMut<'_, G> {
+        CursorMut::new(self.list.cursor_front_mut())
+    }
+}
+
+impl<G: GetLinksWrapped> Default for List<G> {
+    fn default() -> Self {
+        Self::new()
+    }
+}
+
+impl<G: GetLinksWrapped> Drop for List<G> {
+    fn drop(&mut self) {
+        while self.pop_front().is_some() {}
+    }
+}
+
+/// A list cursor that allows traversing a linked list and inspecting & mutating elements.
+pub struct CursorMut<'a, G: GetLinksWrapped> {
+    cursor: raw_list::CursorMut<'a, G>,
+}
+
+impl<'a, G: GetLinksWrapped> CursorMut<'a, G> {
+    fn new(cursor: raw_list::CursorMut<'a, G>) -> Self {
+        Self { cursor }
+    }
+
+    /// Returns the element the cursor is currently positioned on.
+    pub fn current(&mut self) -> Option<&mut G::EntryType> {
+        self.cursor.current()
+    }
+
+    /// Removes the element the cursor is currently positioned on.
+    ///
+    /// After removal, it advances the cursor to the next element.
+    pub fn remove_current(&mut self) -> Option<G::Wrapped> {
+        let ptr = self.cursor.remove_current()?;
+
+        // SAFETY: Elements on the list were inserted after a call to `into_pointer `.
+        Some(unsafe { G::Wrapped::from_pointer(ptr) })
+    }
+
+    /// Returns the element immediately after the one the cursor is positioned on.
+    pub fn peek_next(&mut self) -> Option<&mut G::EntryType> {
+        self.cursor.peek_next()
+    }
+
+    /// Returns the element immediately before the one the cursor is positioned on.
+    pub fn peek_prev(&mut self) -> Option<&mut G::EntryType> {
+        self.cursor.peek_prev()
+    }
+
+    /// Moves the cursor to the next element.
+    pub fn move_next(&mut self) {
+        self.cursor.move_next();
+    }
+}
diff --git a/rust/kernel/miscdev.rs b/rust/kernel/miscdev.rs
new file mode 100644
index 000000000000..b93e423bfb1e
--- /dev/null
+++ b/rust/kernel/miscdev.rs
@@ -0,0 +1,166 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Miscellaneous devices.
+//!
+//! C header: [`include/linux/miscdevice.h`](../../../../include/linux/miscdevice.h)
+//!
+//! Reference: <https://www.kernel.org/doc/html/latest/driver-api/misc_devices.html>
+
+use crate::bindings;
+use crate::error::{Error, Result};
+use crate::file_operations::{FileOpenAdapter, FileOpener, FileOperationsVtable};
+use crate::{str::CStr, KernelModule, ThisModule};
+use alloc::boxed::Box;
+use core::marker::{PhantomData, PhantomPinned};
+use core::pin::Pin;
+
+/// A registration of a miscellaneous device.
+pub struct Registration<T: Sync = ()> {
+    registered: bool,
+    mdev: bindings::miscdevice,
+    _pin: PhantomPinned,
+
+    /// Context initialised on construction and made available to all file instances on
+    /// [`FileOpener::open`].
+    pub context: T,
+}
+
+impl<T: Sync> Registration<T> {
+    /// Creates a new [`Registration`] but does not register it yet.
+    ///
+    /// It is allowed to move.
+    pub fn new(context: T) -> Self {
+        Self {
+            registered: false,
+            mdev: bindings::miscdevice::default(),
+            _pin: PhantomPinned,
+            context,
+        }
+    }
+
+    /// Registers a miscellaneous device.
+    ///
+    /// Returns a pinned heap-allocated representation of the registration.
+    pub fn new_pinned<F: FileOpener<T>>(
+        name: &'static CStr,
+        minor: Option<i32>,
+        context: T,
+    ) -> Result<Pin<Box<Self>>> {
+        let mut r = Pin::from(Box::try_new(Self::new(context))?);
+        r.as_mut().register::<F>(name, minor)?;
+        Ok(r)
+    }
+
+    /// Registers a miscellaneous device with the rest of the kernel.
+    ///
+    /// It must be pinned because the memory block that represents the registration is
+    /// self-referential. If a minor is not given, the kernel allocates a new one if possible.
+    pub fn register<F: FileOpener<T>>(
+        self: Pin<&mut Self>,
+        name: &'static CStr,
+        minor: Option<i32>,
+    ) -> Result {
+        // SAFETY: We must ensure that we never move out of `this`.
+        let this = unsafe { self.get_unchecked_mut() };
+        if this.registered {
+            // Already registered.
+            return Err(Error::EINVAL);
+        }
+
+        // SAFETY: The adapter is compatible with `misc_register`.
+        this.mdev.fops = unsafe { FileOperationsVtable::<Self, F>::build() };
+        this.mdev.name = name.as_char_ptr();
+        this.mdev.minor = minor.unwrap_or(bindings::MISC_DYNAMIC_MINOR as i32);
+
+        let ret = unsafe { bindings::misc_register(&mut this.mdev) };
+        if ret < 0 {
+            return Err(Error::from_kernel_errno(ret));
+        }
+        this.registered = true;
+        Ok(())
+    }
+}
+
+impl<T: Sync> FileOpenAdapter for Registration<T> {
+    type Arg = T;
+
+    unsafe fn convert(_inode: *mut bindings::inode, file: *mut bindings::file) -> *const Self::Arg {
+        // SAFETY: the caller must guarantee that `file` is valid.
+        let reg = crate::container_of!(unsafe { (*file).private_data }, Self, mdev);
+        unsafe { &(*reg).context }
+    }
+}
+
+// SAFETY: The only method is `register()`, which requires a (pinned) mutable `Registration`, so it
+// is safe to pass `&Registration` to multiple threads because it offers no interior mutability,
+// except maybe through `Registration::context`, but it is itself `Sync`.
+unsafe impl<T: Sync> Sync for Registration<T> {}
+
+// SAFETY: All functions work from any thread. So as long as the `Registration::context` is
+// `Send`, so is `Registration<T>`. `T` needs to be `Sync` because it's a requirement of
+// `Registration<T>`.
+unsafe impl<T: Send + Sync> Send for Registration<T> {}
+
+impl<T: Sync> Drop for Registration<T> {
+    /// Removes the registration from the kernel if it has completed successfully before.
+    fn drop(&mut self) {
+        if self.registered {
+            unsafe { bindings::misc_deregister(&mut self.mdev) }
+        }
+    }
+}
+
+/// Kernel module that exposes a single miscdev device implemented by `F`.
+pub struct Module<F: FileOpener<()>> {
+    _dev: Pin<Box<Registration>>,
+    _p: PhantomData<F>,
+}
+
+impl<F: FileOpener<()>> KernelModule for Module<F> {
+    fn init(name: &'static CStr, _module: &'static ThisModule) -> Result<Self> {
+        Ok(Self {
+            _p: PhantomData,
+            _dev: Registration::new_pinned::<F>(name, None, ())?,
+        })
+    }
+}
+
+/// Declares a kernel module that exposes a single misc device.
+///
+/// The `type` argument should be a type which implements the [`FileOpener`] trait. Also accepts
+/// various forms of kernel metadata.
+///
+/// C header: [`include/linux/moduleparam.h`](../../../include/linux/moduleparam.h)
+///
+/// [`FileOpener`]: ../kernel/file_operations/trait.FileOpener.html
+///
+/// # Examples
+///
+/// ```ignore
+/// use kernel::prelude::*;
+///
+/// module_misc_device! {
+///     type: MyFile,
+///     name: b"my_miscdev_kernel_module",
+///     author: b"Rust for Linux Contributors",
+///     description: b"My very own misc device kernel module!",
+///     license: b"GPL v2",
+/// }
+///
+/// #[derive(Default)]
+/// struct MyFile;
+///
+/// impl kernel::file_operations::FileOperations for MyFile {
+///     kernel::declare_file_operations!();
+/// }
+/// ```
+#[macro_export]
+macro_rules! module_misc_device {
+    (type: $type:ty, $($f:tt)*) => {
+        type ModuleType = kernel::miscdev::Module<$type>;
+        module! {
+            type: ModuleType,
+            $($f)*
+        }
+    }
+}
diff --git a/rust/kernel/module_param.rs b/rust/kernel/module_param.rs
new file mode 100644
index 000000000000..a588449c41fa
--- /dev/null
+++ b/rust/kernel/module_param.rs
@@ -0,0 +1,497 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Types for module parameters.
+//!
+//! C header: [`include/linux/moduleparam.h`](../../../include/linux/moduleparam.h)
+
+use crate::str::CStr;
+use core::fmt::Write;
+
+/// Types that can be used for module parameters.
+///
+/// Note that displaying the type in `sysfs` will fail if
+/// [`alloc::string::ToString::to_string`] (as implemented through the
+/// [`core::fmt::Display`] trait) writes more than [`PAGE_SIZE`]
+/// bytes (including an additional null terminator).
+///
+/// [`PAGE_SIZE`]: `crate::PAGE_SIZE`
+pub trait ModuleParam: core::fmt::Display + core::marker::Sized {
+    /// The `ModuleParam` will be used by the kernel module through this type.
+    ///
+    /// This may differ from `Self` if, for example, `Self` needs to track
+    /// ownership without exposing it or allocate extra space for other possible
+    /// parameter values. See [`StringParam`] or [`ArrayParam`] for examples.
+    type Value: ?Sized;
+
+    /// Whether the parameter is allowed to be set without an argument.
+    ///
+    /// Setting this to `true` allows the parameter to be passed without an
+    /// argument (e.g. just `module.param` instead of `module.param=foo`).
+    const NOARG_ALLOWED: bool;
+
+    /// Convert a parameter argument into the parameter value.
+    ///
+    /// `None` should be returned when parsing of the argument fails.
+    /// `arg == None` indicates that the parameter was passed without an
+    /// argument. If `NOARG_ALLOWED` is set to `false` then `arg` is guaranteed
+    /// to always be `Some(_)`.
+    ///
+    /// Parameters passed at boot time will be set before [`kmalloc`] is
+    /// available (even if the module is loaded at a later time). However, in
+    /// this case, the argument buffer will be valid for the entire lifetime of
+    /// the kernel. So implementations of this method which need to allocate
+    /// should first check that the allocator is available (with
+    /// [`crate::bindings::slab_is_available`]) and when it is not available
+    /// provide an alternative implementation which doesn't allocate. In cases
+    /// where the allocator is not available it is safe to save references to
+    /// `arg` in `Self`, but in other cases a copy should be made.
+    ///
+    /// [`kmalloc`]: ../../../include/linux/slab.h
+    fn try_from_param_arg(arg: Option<&'static [u8]>) -> Option<Self>;
+
+    /// Get the current value of the parameter for use in the kernel module.
+    ///
+    /// This function should not be used directly. Instead use the wrapper
+    /// `read` which will be generated by [`macros::module`].
+    fn value(&self) -> &Self::Value;
+
+    /// Set the module parameter from a string.
+    ///
+    /// Used to set the parameter value when loading the module or when set
+    /// through `sysfs`.
+    ///
+    /// # Safety
+    ///
+    /// If `val` is non-null then it must point to a valid null-terminated
+    /// string. The `arg` field of `param` must be an instance of `Self`.
+    unsafe extern "C" fn set_param(
+        val: *const crate::c_types::c_char,
+        param: *const crate::bindings::kernel_param,
+    ) -> crate::c_types::c_int {
+        let arg = if val.is_null() {
+            None
+        } else {
+            Some(unsafe { CStr::from_char_ptr(val).as_bytes() })
+        };
+        match Self::try_from_param_arg(arg) {
+            Some(new_value) => {
+                let old_value = unsafe { (*param).__bindgen_anon_1.arg as *mut Self };
+                let _ = unsafe { core::ptr::replace(old_value, new_value) };
+                0
+            }
+            None => crate::error::Error::EINVAL.to_kernel_errno(),
+        }
+    }
+
+    /// Write a string representation of the current parameter value to `buf`.
+    ///
+    /// Used for displaying the current parameter value in `sysfs`.
+    ///
+    /// # Safety
+    ///
+    /// `buf` must be a buffer of length at least `kernel::PAGE_SIZE` that is
+    /// writeable. The `arg` field of `param` must be an instance of `Self`.
+    unsafe extern "C" fn get_param(
+        buf: *mut crate::c_types::c_char,
+        param: *const crate::bindings::kernel_param,
+    ) -> crate::c_types::c_int {
+        let slice = unsafe { core::slice::from_raw_parts_mut(buf as *mut u8, crate::PAGE_SIZE) };
+        let mut buf = crate::buffer::Buffer::new(slice);
+        match unsafe { write!(buf, "{}\0", *((*param).__bindgen_anon_1.arg as *mut Self)) } {
+            Err(_) => crate::error::Error::EINVAL.to_kernel_errno(),
+            Ok(()) => buf.bytes_written() as crate::c_types::c_int,
+        }
+    }
+
+    /// Drop the parameter.
+    ///
+    /// Called when unloading a module.
+    ///
+    /// # Safety
+    ///
+    /// The `arg` field of `param` must be an instance of `Self`.
+    unsafe extern "C" fn free(arg: *mut crate::c_types::c_void) {
+        unsafe { core::ptr::drop_in_place(arg as *mut Self) };
+    }
+}
+
+/// Trait for parsing integers.
+///
+/// Strings begining with `0x`, `0o`, or `0b` are parsed as hex, octal, or
+/// binary respectively. Strings beginning with `0` otherwise are parsed as
+/// octal. Anything else is parsed as decimal. A leading `+` or `-` is also
+/// permitted. Any string parsed by [`kstrtol()`] or [`kstrtoul()`] will be
+/// successfully parsed.
+///
+/// [`kstrtol()`]: https://www.kernel.org/doc/html/latest/core-api/kernel-api.html#c.kstrtol
+/// [`kstrtoul()`]: https://www.kernel.org/doc/html/latest/core-api/kernel-api.html#c.kstrtoul
+trait ParseInt: Sized {
+    fn from_str_radix(src: &str, radix: u32) -> Result<Self, core::num::ParseIntError>;
+    fn checked_neg(self) -> Option<Self>;
+
+    fn from_str_unsigned(src: &str) -> Result<Self, core::num::ParseIntError> {
+        let (radix, digits) = if let Some(n) = src.strip_prefix("0x") {
+            (16, n)
+        } else if let Some(n) = src.strip_prefix("0X") {
+            (16, n)
+        } else if let Some(n) = src.strip_prefix("0o") {
+            (8, n)
+        } else if let Some(n) = src.strip_prefix("0O") {
+            (8, n)
+        } else if let Some(n) = src.strip_prefix("0b") {
+            (2, n)
+        } else if let Some(n) = src.strip_prefix("0B") {
+            (2, n)
+        } else if src.starts_with('0') {
+            (8, src)
+        } else {
+            (10, src)
+        };
+        Self::from_str_radix(digits, radix)
+    }
+
+    fn from_str(src: &str) -> Option<Self> {
+        match src.bytes().next() {
+            None => None,
+            Some(b'-') => Self::from_str_unsigned(&src[1..]).ok()?.checked_neg(),
+            Some(b'+') => Some(Self::from_str_unsigned(&src[1..]).ok()?),
+            Some(_) => Some(Self::from_str_unsigned(src).ok()?),
+        }
+    }
+}
+
+macro_rules! impl_parse_int {
+    ($ty:ident) => {
+        impl ParseInt for $ty {
+            fn from_str_radix(src: &str, radix: u32) -> Result<Self, core::num::ParseIntError> {
+                $ty::from_str_radix(src, radix)
+            }
+
+            fn checked_neg(self) -> Option<Self> {
+                self.checked_neg()
+            }
+        }
+    };
+}
+
+impl_parse_int!(i8);
+impl_parse_int!(u8);
+impl_parse_int!(i16);
+impl_parse_int!(u16);
+impl_parse_int!(i32);
+impl_parse_int!(u32);
+impl_parse_int!(i64);
+impl_parse_int!(u64);
+impl_parse_int!(isize);
+impl_parse_int!(usize);
+
+macro_rules! impl_module_param {
+    ($ty:ident) => {
+        impl ModuleParam for $ty {
+            type Value = $ty;
+
+            const NOARG_ALLOWED: bool = false;
+
+            fn try_from_param_arg(arg: Option<&'static [u8]>) -> Option<Self> {
+                let bytes = arg?;
+                let utf8 = core::str::from_utf8(bytes).ok()?;
+                <$ty as crate::module_param::ParseInt>::from_str(utf8)
+            }
+
+            fn value(&self) -> &Self::Value {
+                self
+            }
+        }
+    };
+}
+
+#[doc(hidden)]
+#[macro_export]
+/// Generate a static [`kernel_param_ops`](../../../include/linux/moduleparam.h) struct.
+///
+/// # Example
+/// ```ignore
+/// make_param_ops!(
+///     /// Documentation for new param ops.
+///     PARAM_OPS_MYTYPE, // Name for the static.
+///     MyType // A type which implements [`ModuleParam`].
+/// );
+/// ```
+macro_rules! make_param_ops {
+    ($ops:ident, $ty:ty) => {
+        $crate::make_param_ops!(
+            #[doc=""]
+            $ops,
+            $ty
+        );
+    };
+    ($(#[$meta:meta])* $ops:ident, $ty:ty) => {
+        $(#[$meta])*
+        ///
+        /// Static [`kernel_param_ops`](../../../include/linux/moduleparam.h)
+        /// struct generated by [`make_param_ops`].
+        pub static $ops: $crate::bindings::kernel_param_ops = $crate::bindings::kernel_param_ops {
+            flags: if <$ty as $crate::module_param::ModuleParam>::NOARG_ALLOWED {
+                $crate::bindings::KERNEL_PARAM_OPS_FL_NOARG
+            } else {
+                0
+            },
+            set: Some(<$ty as $crate::module_param::ModuleParam>::set_param),
+            get: Some(<$ty as $crate::module_param::ModuleParam>::get_param),
+            free: Some(<$ty as $crate::module_param::ModuleParam>::free),
+        };
+    };
+}
+
+impl_module_param!(i8);
+impl_module_param!(u8);
+impl_module_param!(i16);
+impl_module_param!(u16);
+impl_module_param!(i32);
+impl_module_param!(u32);
+impl_module_param!(i64);
+impl_module_param!(u64);
+impl_module_param!(isize);
+impl_module_param!(usize);
+
+make_param_ops!(
+    /// Rust implementation of [`kernel_param_ops`](../../../include/linux/moduleparam.h)
+    /// for [`i8`].
+    PARAM_OPS_I8,
+    i8
+);
+make_param_ops!(
+    /// Rust implementation of [`kernel_param_ops`](../../../include/linux/moduleparam.h)
+    /// for [`u8`].
+    PARAM_OPS_U8,
+    u8
+);
+make_param_ops!(
+    /// Rust implementation of [`kernel_param_ops`](../../../include/linux/moduleparam.h)
+    /// for [`i16`].
+    PARAM_OPS_I16,
+    i16
+);
+make_param_ops!(
+    /// Rust implementation of [`kernel_param_ops`](../../../include/linux/moduleparam.h)
+    /// for [`u16`].
+    PARAM_OPS_U16,
+    u16
+);
+make_param_ops!(
+    /// Rust implementation of [`kernel_param_ops`](../../../include/linux/moduleparam.h)
+    /// for [`i32`].
+    PARAM_OPS_I32,
+    i32
+);
+make_param_ops!(
+    /// Rust implementation of [`kernel_param_ops`](../../../include/linux/moduleparam.h)
+    /// for [`u32`].
+    PARAM_OPS_U32,
+    u32
+);
+make_param_ops!(
+    /// Rust implementation of [`kernel_param_ops`](../../../include/linux/moduleparam.h)
+    /// for [`i64`].
+    PARAM_OPS_I64,
+    i64
+);
+make_param_ops!(
+    /// Rust implementation of [`kernel_param_ops`](../../../include/linux/moduleparam.h)
+    /// for [`u64`].
+    PARAM_OPS_U64,
+    u64
+);
+make_param_ops!(
+    /// Rust implementation of [`kernel_param_ops`](../../../include/linux/moduleparam.h)
+    /// for [`isize`].
+    PARAM_OPS_ISIZE,
+    isize
+);
+make_param_ops!(
+    /// Rust implementation of [`kernel_param_ops`](../../../include/linux/moduleparam.h)
+    /// for [`usize`].
+    PARAM_OPS_USIZE,
+    usize
+);
+
+impl ModuleParam for bool {
+    type Value = bool;
+
+    const NOARG_ALLOWED: bool = true;
+
+    fn try_from_param_arg(arg: Option<&'static [u8]>) -> Option<Self> {
+        match arg {
+            None => Some(true),
+            Some(b"y") | Some(b"Y") | Some(b"1") | Some(b"true") => Some(true),
+            Some(b"n") | Some(b"N") | Some(b"0") | Some(b"false") => Some(false),
+            _ => None,
+        }
+    }
+
+    fn value(&self) -> &Self::Value {
+        self
+    }
+}
+
+make_param_ops!(
+    /// Rust implementation of [`kernel_param_ops`](../../../include/linux/moduleparam.h)
+    /// for [`bool`].
+    PARAM_OPS_BOOL,
+    bool
+);
+
+/// An array of at __most__ `N` values.
+///
+/// # Invariant
+///
+/// The first `self.used` elements of `self.values` are initialized.
+pub struct ArrayParam<T, const N: usize> {
+    values: [core::mem::MaybeUninit<T>; N],
+    used: usize,
+}
+
+impl<T, const N: usize> ArrayParam<T, { N }> {
+    fn values(&self) -> &[T] {
+        // SAFETY: The invariant maintained by `ArrayParam` allows us to cast
+        // the first `self.used` elements to `T`.
+        unsafe {
+            &*(&self.values[0..self.used] as *const [core::mem::MaybeUninit<T>] as *const [T])
+        }
+    }
+}
+
+impl<T: Copy, const N: usize> ArrayParam<T, { N }> {
+    const fn new() -> Self {
+        // INVARIANT: The first `self.used` elements of `self.values` are
+        // initialized.
+        ArrayParam {
+            values: [core::mem::MaybeUninit::uninit(); N],
+            used: 0,
+        }
+    }
+
+    const fn push(&mut self, val: T) {
+        if self.used < N {
+            // INVARIANT: The first `self.used` elements of `self.values` are
+            // initialized.
+            self.values[self.used] = core::mem::MaybeUninit::new(val);
+            self.used += 1;
+        }
+    }
+
+    /// Create an instance of `ArrayParam` initialized with `vals`.
+    ///
+    /// This function is only meant to be used in the [`module::module`] macro.
+    pub const fn create(vals: &[T]) -> Self {
+        let mut result = ArrayParam::new();
+        let mut i = 0;
+        while i < vals.len() {
+            result.push(vals[i]);
+            i += 1;
+        }
+        result
+    }
+}
+
+impl<T: core::fmt::Display, const N: usize> core::fmt::Display for ArrayParam<T, { N }> {
+    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
+        for val in self.values() {
+            write!(f, "{},", val)?;
+        }
+        Ok(())
+    }
+}
+
+impl<T: Copy + core::fmt::Display + ModuleParam, const N: usize> ModuleParam
+    for ArrayParam<T, { N }>
+{
+    type Value = [T];
+
+    const NOARG_ALLOWED: bool = false;
+
+    fn try_from_param_arg(arg: Option<&'static [u8]>) -> Option<Self> {
+        arg.and_then(|args| {
+            let mut result = Self::new();
+            for arg in args.split(|b| *b == b',') {
+                result.push(T::try_from_param_arg(Some(arg))?);
+            }
+            Some(result)
+        })
+    }
+
+    fn value(&self) -> &Self::Value {
+        self.values()
+    }
+}
+
+/// A C-style string parameter.
+///
+/// The Rust version of the [`charp`] parameter. This type is meant to be
+/// used by the [`macros::module`] macro, not handled directly. Instead use the
+/// `read` method generated by that macro.
+///
+/// [`charp`]: ../../../include/linux/moduleparam.h
+pub enum StringParam {
+    /// A borrowed parameter value.
+    ///
+    /// Either the default value (which is static in the module) or borrowed
+    /// from the original argument buffer used to set the value.
+    Ref(&'static [u8]),
+
+    /// A value that was allocated when the parameter was set.
+    ///
+    /// The value needs to be freed when the parameter is reset or the module is
+    /// unloaded.
+    Owned(alloc::vec::Vec<u8>),
+}
+
+impl StringParam {
+    fn bytes(&self) -> &[u8] {
+        match self {
+            StringParam::Ref(bytes) => *bytes,
+            StringParam::Owned(vec) => &vec[..],
+        }
+    }
+}
+
+impl core::fmt::Display for StringParam {
+    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
+        let bytes = self.bytes();
+        match core::str::from_utf8(bytes) {
+            Ok(utf8) => write!(f, "{}", utf8),
+            Err(_) => write!(f, "{:?}", bytes),
+        }
+    }
+}
+
+impl ModuleParam for StringParam {
+    type Value = [u8];
+
+    const NOARG_ALLOWED: bool = false;
+
+    fn try_from_param_arg(arg: Option<&'static [u8]>) -> Option<Self> {
+        // SAFETY: It is always safe to call [`slab_is_available`](../../../include/linux/slab.h).
+        let slab_available = unsafe { crate::bindings::slab_is_available() };
+        arg.and_then(|arg| {
+            if slab_available {
+                let mut vec = alloc::vec::Vec::new();
+                vec.try_extend_from_slice(arg).ok()?;
+                Some(StringParam::Owned(vec))
+            } else {
+                Some(StringParam::Ref(arg))
+            }
+        })
+    }
+
+    fn value(&self) -> &Self::Value {
+        self.bytes()
+    }
+}
+
+make_param_ops!(
+    /// Rust implementation of [`kernel_param_ops`](../../../include/linux/moduleparam.h)
+    /// for [`StringParam`].
+    PARAM_OPS_STR,
+    StringParam
+);
diff --git a/rust/kernel/of.rs b/rust/kernel/of.rs
new file mode 100644
index 000000000000..78aa5956f03f
--- /dev/null
+++ b/rust/kernel/of.rs
@@ -0,0 +1,101 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Devicetree and Open Firmware abstractions.
+//!
+//! C header: [`include/linux/of_*.h`](../../../../include/linux/of_*.h)
+
+use crate::{bindings, c_types, str::CStr};
+
+use core::ops::Deref;
+use core::ptr;
+
+/// A kernel Open Firmware / devicetree match table.
+///
+/// Can only exist as an `&OfMatchTable` reference (akin to `&str` or
+/// `&Path` in Rust std).
+///
+/// # Invariants
+///
+/// The inner reference points to a sentinel-terminated C array.
+#[repr(transparent)]
+pub struct OfMatchTable(bindings::of_device_id);
+
+impl OfMatchTable {
+    /// Returns the table as a reference to a static lifetime, sentinel-terminated C array.
+    ///
+    /// This is suitable to be coerced into the kernel's `of_match_table` field.
+    pub fn as_ptr(&'static self) -> &'static bindings::of_device_id {
+        // The inner reference points to a sentinel-terminated C array, as per
+        // the type invariant.
+        &self.0
+    }
+}
+
+/// An Open Firmware Match Table that can be constructed at build time.
+///
+/// # Invariants
+///
+/// `sentinel` always contains zeroes.
+#[repr(C)]
+pub struct ConstOfMatchTable<const N: usize> {
+    table: [bindings::of_device_id; N],
+    sentinel: bindings::of_device_id,
+}
+
+impl<const N: usize> ConstOfMatchTable<N> {
+    /// Creates a new Open Firmware Match Table from a list of compatible strings.
+    pub const fn new_const(compatibles: [&'static CStr; N]) -> Self {
+        let mut table = [Self::zeroed_of_device_id(); N];
+        let mut i = 0;
+        while i < N {
+            table[i] = Self::new_of_device_id(compatibles[i]);
+            i += 1;
+        }
+        Self {
+            table,
+            // INVARIANTS: we zero the sentinel here, and never change it
+            // anywhere. Therefore it always contains zeroes.
+            sentinel: Self::zeroed_of_device_id(),
+        }
+    }
+
+    const fn zeroed_of_device_id() -> bindings::of_device_id {
+        bindings::of_device_id {
+            name: [0; 32],
+            type_: [0; 32],
+            compatible: [0; 128],
+            data: ptr::null(),
+        }
+    }
+
+    const fn new_of_device_id(compatible: &'static CStr) -> bindings::of_device_id {
+        let mut id = Self::zeroed_of_device_id();
+        let compatible = compatible.as_bytes_with_nul();
+        let mut i = 0;
+        while i < compatible.len() {
+            // If `compatible` does not fit in `id.compatible`, an
+            // "index out of bounds" build time error will be triggered.
+            id.compatible[i] = compatible[i] as c_types::c_char;
+            i += 1;
+        }
+        id
+    }
+}
+
+impl<const N: usize> Deref for ConstOfMatchTable<N> {
+    type Target = OfMatchTable;
+
+    fn deref(&self) -> &OfMatchTable {
+        // INVARIANTS: `head` points to a sentinel-terminated C array,
+        // as per the `ConstOfMatchTable` type invariant, therefore
+        // `&OfMatchTable`'s inner reference will point to a sentinel-terminated C array.
+        let head = &self.table[0] as *const bindings::of_device_id as *const OfMatchTable;
+
+        // SAFETY: The returned reference must remain valid for the lifetime of `self`.
+        // The raw pointer `head` points to memory inside `self`. So the reference created
+        // from this raw pointer has the same lifetime as `self`.
+        // Therefore this reference remains valid for the lifetime of `self`, and
+        // is safe to return.
+        unsafe { &*head }
+    }
+}
diff --git a/rust/kernel/pages.rs b/rust/kernel/pages.rs
new file mode 100644
index 000000000000..de8358629fdd
--- /dev/null
+++ b/rust/kernel/pages.rs
@@ -0,0 +1,162 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Kernel page allocation and management.
+//!
+//! TODO: This module is a work in progress.
+
+use crate::{
+    bindings, c_types, io_buffer::IoBufferReader, user_ptr::UserSlicePtrReader, Error, Result,
+    PAGE_SIZE,
+};
+use core::{marker::PhantomData, ptr};
+
+/// A set of physical pages.
+///
+/// `Pages` holds a reference to a set of pages of order `ORDER`. Having the order as a generic
+/// const allows the struct to have the same size as a pointer.
+///
+/// # Invariants
+///
+/// The pointer `Pages::pages` is valid and points to 2^ORDER pages.
+pub struct Pages<const ORDER: u32> {
+    pages: *mut bindings::page,
+}
+
+impl<const ORDER: u32> Pages<ORDER> {
+    /// Allocates a new set of contiguous pages.
+    pub fn new() -> Result<Self> {
+        // TODO: Consider whether we want to allow callers to specify flags.
+        // SAFETY: This only allocates pages. We check that it succeeds in the next statement.
+        let pages = unsafe {
+            bindings::alloc_pages(
+                bindings::GFP_KERNEL | bindings::__GFP_ZERO | bindings::__GFP_HIGHMEM,
+                ORDER,
+            )
+        };
+        if pages.is_null() {
+            return Err(Error::ENOMEM);
+        }
+        // INVARIANTS: We checked that the allocation above succeeded>
+        Ok(Self { pages })
+    }
+
+    /// Maps a single page at the given address in the given VM area.
+    ///
+    /// This is only meant to be used by pages of order 0.
+    pub fn insert_page(&self, vma: &mut bindings::vm_area_struct, address: usize) -> Result {
+        if ORDER != 0 {
+            return Err(Error::EINVAL);
+        }
+
+        // SAFETY: We check above that the allocation is of order 0. The range of `address` is
+        // already checked by `vm_insert_page`.
+        let ret = unsafe { bindings::vm_insert_page(vma, address as _, self.pages) };
+        if ret != 0 {
+            Err(Error::from_kernel_errno(ret))
+        } else {
+            Ok(())
+        }
+    }
+
+    /// Copies data from the given [`UserSlicePtrReader`] into the pages.
+    pub fn copy_into_page(
+        &self,
+        reader: &mut UserSlicePtrReader,
+        offset: usize,
+        len: usize,
+    ) -> Result {
+        // TODO: For now this only works on the first page.
+        let end = offset.checked_add(len).ok_or(Error::EINVAL)?;
+        if end > PAGE_SIZE {
+            return Err(Error::EINVAL);
+        }
+
+        let mapping = self.kmap(0).ok_or(Error::EINVAL)?;
+
+        // SAFETY: We ensured that the buffer was valid with the check above.
+        unsafe { reader.read_raw((mapping.ptr as usize + offset) as _, len) }?;
+        Ok(())
+    }
+
+    /// Maps the pages and reads from them into the given buffer.
+    ///
+    /// # Safety
+    ///
+    /// Callers must ensure that the destination buffer is valid for the given length.
+    /// Additionally, if the raw buffer is intended to be recast, they must ensure that the data
+    /// can be safely cast; [`crate::io_buffer::ReadableFromBytes`] has more details about it.
+    pub unsafe fn read(&self, dest: *mut u8, offset: usize, len: usize) -> Result {
+        // TODO: For now this only works on the first page.
+        let end = offset.checked_add(len).ok_or(Error::EINVAL)?;
+        if end > PAGE_SIZE {
+            return Err(Error::EINVAL);
+        }
+
+        let mapping = self.kmap(0).ok_or(Error::EINVAL)?;
+        unsafe { ptr::copy((mapping.ptr as *mut u8).add(offset), dest, len) };
+        Ok(())
+    }
+
+    /// Maps the pages and writes into them from the given bufer.
+    ///
+    /// # Safety
+    ///
+    /// Callers must ensure that the buffer is valid for the given length. Additionally, if the
+    /// page is (or will be) mapped by userspace, they must ensure that no kernel data is leaked
+    /// through padding if it was cast from another type; [`crate::io_buffer::WritableToBytes`] has
+    /// more details about it.
+    pub unsafe fn write(&self, src: *const u8, offset: usize, len: usize) -> Result {
+        // TODO: For now this only works on the first page.
+        let end = offset.checked_add(len).ok_or(Error::EINVAL)?;
+        if end > PAGE_SIZE {
+            return Err(Error::EINVAL);
+        }
+
+        let mapping = self.kmap(0).ok_or(Error::EINVAL)?;
+        unsafe { ptr::copy(src, (mapping.ptr as *mut u8).add(offset), len) };
+        Ok(())
+    }
+
+    /// Maps the page at index `index`.
+    fn kmap(&self, index: usize) -> Option<PageMapping<'_>> {
+        if index >= 1usize << ORDER {
+            return None;
+        }
+
+        // SAFETY: We checked above that `index` is within range.
+        let page = unsafe { self.pages.add(index) };
+
+        // SAFETY: `page` is valid based on the checks above.
+        let ptr = unsafe { bindings::kmap(page) };
+        if ptr.is_null() {
+            return None;
+        }
+
+        Some(PageMapping {
+            page,
+            ptr,
+            _phantom: PhantomData,
+        })
+    }
+}
+
+impl<const ORDER: u32> Drop for Pages<ORDER> {
+    fn drop(&mut self) {
+        // SAFETY: By the type invariants, we know the pages are allocated with the given order.
+        unsafe { bindings::__free_pages(self.pages, ORDER) };
+    }
+}
+
+struct PageMapping<'a> {
+    page: *mut bindings::page,
+    ptr: *mut c_types::c_void,
+    _phantom: PhantomData<&'a i32>,
+}
+
+impl Drop for PageMapping<'_> {
+    fn drop(&mut self) {
+        // SAFETY: An instance of `PageMapping` is created only when `kmap` succeeded for the given
+        // page, so it is safe to unmap it here.
+        unsafe { bindings::kunmap(self.page) };
+    }
+}
diff --git a/rust/kernel/platdev.rs b/rust/kernel/platdev.rs
new file mode 100644
index 000000000000..852607dfe7f8
--- /dev/null
+++ b/rust/kernel/platdev.rs
@@ -0,0 +1,152 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Platform devices.
+//!
+//! Also called `platdev`, `pdev`.
+//!
+//! C header: [`include/linux/platform_device.h`](../../../../include/linux/platform_device.h)
+
+use crate::{
+    bindings, c_types,
+    error::{from_kernel_result, Error, Result},
+    of::OfMatchTable,
+    str::CStr,
+    types::PointerWrapper,
+};
+use alloc::boxed::Box;
+use core::{marker::PhantomPinned, pin::Pin};
+
+/// A registration of a platform device.
+#[derive(Default)]
+pub struct Registration {
+    registered: bool,
+    pdrv: bindings::platform_driver,
+    _pin: PhantomPinned,
+}
+
+// SAFETY: `Registration` does not expose any of its state across threads
+// (it is fine for multiple threads to have a shared reference to it).
+unsafe impl Sync for Registration {}
+
+extern "C" fn probe_callback<P: PlatformDriver>(
+    pdev: *mut bindings::platform_device,
+) -> c_types::c_int {
+    from_kernel_result! {
+        // SAFETY: `pdev` is guaranteed to be a valid, non-null pointer.
+        let device_id = unsafe { (*pdev).id };
+        let drv_data = P::probe(device_id)?;
+        let drv_data = drv_data.into_pointer() as *mut c_types::c_void;
+        // SAFETY: `pdev` is guaranteed to be a valid, non-null pointer.
+        unsafe {
+            bindings::platform_set_drvdata(pdev, drv_data);
+        }
+        Ok(0)
+    }
+}
+
+extern "C" fn remove_callback<P: PlatformDriver>(
+    pdev: *mut bindings::platform_device,
+) -> c_types::c_int {
+    from_kernel_result! {
+        // SAFETY: `pdev` is guaranteed to be a valid, non-null pointer.
+        let device_id = unsafe { (*pdev).id };
+        // SAFETY: `pdev` is guaranteed to be a valid, non-null pointer.
+        let ptr = unsafe { bindings::platform_get_drvdata(pdev) };
+        // SAFETY:
+        //   - we allocated this pointer using `P::DrvData::into_pointer`,
+        //     so it is safe to turn back into a `P::DrvData`.
+        //   - the allocation happened in `probe`, no-one freed the memory,
+        //     `remove` is the canonical kernel location to free driver data. so OK
+        //     to convert the pointer back to a Rust structure here.
+        let drv_data = unsafe { P::DrvData::from_pointer(ptr) };
+        P::remove(device_id, drv_data)?;
+        Ok(0)
+    }
+}
+
+impl Registration {
+    fn register<P: PlatformDriver>(
+        self: Pin<&mut Self>,
+        name: &'static CStr,
+        of_match_table: Option<&'static OfMatchTable>,
+        module: &'static crate::ThisModule,
+    ) -> Result {
+        // SAFETY: We must ensure that we never move out of `this`.
+        let this = unsafe { self.get_unchecked_mut() };
+        if this.registered {
+            // Already registered.
+            return Err(Error::EINVAL);
+        }
+        this.pdrv.driver.name = name.as_char_ptr();
+        if let Some(tbl) = of_match_table {
+            this.pdrv.driver.of_match_table = tbl.as_ptr();
+        }
+        this.pdrv.probe = Some(probe_callback::<P>);
+        this.pdrv.remove = Some(remove_callback::<P>);
+        // SAFETY:
+        //   - `this.pdrv` lives at least until the call to `platform_driver_unregister()` returns.
+        //   - `name` pointer has static lifetime.
+        //   - `module.0` lives at least as long as the module.
+        //   - `probe()` and `remove()` are static functions.
+        //   - `of_match_table` is either a raw pointer with static lifetime,
+        //      as guaranteed by the [`of::OfMatchTable::as_ptr()`] return type,
+        //      or null.
+        let ret = unsafe { bindings::__platform_driver_register(&mut this.pdrv, module.0) };
+        if ret < 0 {
+            return Err(Error::from_kernel_errno(ret));
+        }
+        this.registered = true;
+        Ok(())
+    }
+
+    /// Registers a platform device.
+    ///
+    /// Returns a pinned heap-allocated representation of the registration.
+    pub fn new_pinned<P: PlatformDriver>(
+        name: &'static CStr,
+        of_match_tbl: Option<&'static OfMatchTable>,
+        module: &'static crate::ThisModule,
+    ) -> Result<Pin<Box<Self>>> {
+        let mut r = Pin::from(Box::try_new(Self::default())?);
+        r.as_mut().register::<P>(name, of_match_tbl, module)?;
+        Ok(r)
+    }
+}
+
+impl Drop for Registration {
+    fn drop(&mut self) {
+        if self.registered {
+            // SAFETY: if `registered` is true, then `self.pdev` was registered
+            // previously, which means `platform_driver_unregister` is always
+            // safe to call.
+            unsafe { bindings::platform_driver_unregister(&mut self.pdrv) }
+        }
+    }
+}
+
+/// Trait for implementers of platform drivers.
+///
+/// Implement this trait whenever you create a platform driver.
+pub trait PlatformDriver {
+    /// Device driver data.
+    ///
+    /// Corresponds to the data set or retrieved via the kernel's
+    /// `platform_{set,get}_drvdata()` functions.
+    ///
+    /// Require that `DrvData` implements `PointerWrapper`. We guarantee to
+    /// never move the underlying wrapped data structure. This allows
+    /// driver writers to use pinned or self-referential data structures.
+    type DrvData: PointerWrapper;
+
+    /// Platform driver probe.
+    ///
+    /// Called when a new platform device is added or discovered.
+    /// Implementers should attempt to initialize the device here.
+    fn probe(device_id: i32) -> Result<Self::DrvData>;
+
+    /// Platform driver remove.
+    ///
+    /// Called when a platform device is removed.
+    /// Implementers should prepare the device for complete removal here.
+    fn remove(device_id: i32, drv_data: Self::DrvData) -> Result;
+}
diff --git a/rust/kernel/power.rs b/rust/kernel/power.rs
new file mode 100644
index 000000000000..e318b5d9f0c0
--- /dev/null
+++ b/rust/kernel/power.rs
@@ -0,0 +1,118 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Power management interfaces.
+//!
+//! C header: [`include/linux/pm.h`](../../../../include/linux/pm.h)
+
+#![allow(dead_code)]
+
+use crate::{bindings, c_types, error::from_kernel_result, types::PointerWrapper, Result};
+use core::marker::PhantomData;
+
+/// Corresponds to the kernel's `struct dev_pm_ops`.
+///
+/// It is meant to be implemented by drivers that support power-management operations.
+pub trait Operations {
+    /// The type of the context data stored by the driver on each device.
+    type Data: PointerWrapper + Sync + Send;
+
+    /// Called before the system goes into a sleep state.
+    fn suspend(_data: <Self::Data as PointerWrapper>::Borrowed<'_>) -> Result {
+        Ok(())
+    }
+
+    /// Called after the system comes back from a sleep state.
+    fn resume(_data: <Self::Data as PointerWrapper>::Borrowed<'_>) -> Result {
+        Ok(())
+    }
+
+    /// Called before creating a hibernation image.
+    fn freeze(_data: <Self::Data as PointerWrapper>::Borrowed<'_>) -> Result {
+        Ok(())
+    }
+
+    /// Called after the system is restored from a hibernation image.
+    fn restore(_data: <Self::Data as PointerWrapper>::Borrowed<'_>) -> Result {
+        Ok(())
+    }
+}
+
+macro_rules! pm_callback {
+    ($callback:ident, $method:ident) => {
+        unsafe extern "C" fn $callback<T: Operations>(
+            dev: *mut bindings::device,
+        ) -> c_types::c_int {
+            from_kernel_result! {
+                // SAFETY: `dev` is valid as it was passed in by the C portion.
+                let ptr = unsafe { bindings::dev_get_drvdata(dev) };
+                // SAFETY: By the safety requirements of `OpsTable::build`, we know that `ptr` came
+                // from a previous call to `T::Data::into_pointer`.
+                let data = unsafe { T::Data::borrow(ptr) };
+                T::$method(data)?;
+                Ok(0)
+            }
+        }
+    };
+}
+
+pm_callback!(suspend_callback, suspend);
+pm_callback!(resume_callback, resume);
+pm_callback!(freeze_callback, freeze);
+pm_callback!(restore_callback, restore);
+
+pub(crate) struct OpsTable<T: Operations>(PhantomData<*const T>);
+
+impl<T: Operations> OpsTable<T> {
+    const VTABLE: bindings::dev_pm_ops = bindings::dev_pm_ops {
+        prepare: None,
+        complete: None,
+        suspend: Some(suspend_callback::<T>),
+        resume: Some(resume_callback::<T>),
+        freeze: Some(freeze_callback::<T>),
+        thaw: None,
+        poweroff: None,
+        restore: Some(restore_callback::<T>),
+        suspend_late: None,
+        resume_early: None,
+        freeze_late: None,
+        thaw_early: None,
+        poweroff_late: None,
+        restore_early: None,
+        suspend_noirq: None,
+        resume_noirq: None,
+        freeze_noirq: None,
+        thaw_noirq: None,
+        poweroff_noirq: None,
+        restore_noirq: None,
+        runtime_suspend: None,
+        runtime_resume: None,
+        runtime_idle: None,
+    };
+
+    /// Builds an instance of `struct dev_pm_ops`.
+    ///
+    /// # Safety
+    ///
+    /// The caller must ensure that `dev_get_drvdata` will result in a value returned by
+    /// [`T::Data::into_pointer`].
+    pub(crate) const unsafe fn build() -> &'static bindings::dev_pm_ops {
+        &Self::VTABLE
+    }
+}
+
+/// Implements the [`Operations`] trait as no-ops.
+///
+/// This is useful when one doesn't want to provide the implementation of any power-manager related
+/// operation.
+pub struct NoOperations<T: PointerWrapper>(PhantomData<T>);
+
+impl<T: PointerWrapper + Send + Sync> Operations for NoOperations<T> {
+    type Data = T;
+}
+
+// SAFETY: `NoOperation` provides no functionality, it is safe to send a reference to it to
+// different threads.
+unsafe impl<T: PointerWrapper> Sync for NoOperations<T> {}
+
+// SAFETY: `NoOperation` provides no functionality, it is safe to send it to different threads.
+unsafe impl<T: PointerWrapper> Send for NoOperations<T> {}
diff --git a/rust/kernel/prelude.rs b/rust/kernel/prelude.rs
new file mode 100644
index 000000000000..b602fc6db761
--- /dev/null
+++ b/rust/kernel/prelude.rs
@@ -0,0 +1,33 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! The `kernel` prelude.
+//!
+//! These are the most common items used by Rust code in the kernel,
+//! intended to be imported by all Rust code, for convenience.
+//!
+//! # Examples
+//!
+//! ```
+//! use kernel::prelude::*;
+//! ```
+
+pub use core::pin::Pin;
+
+pub use alloc::{boxed::Box, string::String, vec::Vec};
+
+pub use macros::module;
+
+pub use super::build_assert;
+
+pub use super::{dbg, pr_alert, pr_crit, pr_debug, pr_emerg, pr_err, pr_info, pr_notice, pr_warn};
+
+pub use super::module_misc_device;
+
+#[cfg(CONFIG_ARM_AMBA)]
+pub use super::module_amba_driver;
+
+pub use super::static_assert;
+
+pub use super::{Error, KernelModule, Result};
+
+pub use super::{str::CStr, ThisModule};
diff --git a/rust/kernel/print.rs b/rust/kernel/print.rs
new file mode 100644
index 000000000000..328d893f87aa
--- /dev/null
+++ b/rust/kernel/print.rs
@@ -0,0 +1,441 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Printing facilities.
+//!
+//! C header: [`include/linux/printk.h`](../../../../include/linux/printk.h)
+//!
+//! Reference: <https://www.kernel.org/doc/html/latest/core-api/printk-basics.html>
+
+use core::cmp;
+use core::fmt;
+
+use crate::bindings;
+use crate::c_types::{c_char, c_void};
+
+// Called from `vsprintf` with format specifier `%pA`.
+#[no_mangle]
+unsafe fn rust_fmt_argument(buf: *mut c_char, end: *mut c_char, ptr: *const c_void) -> *mut c_char {
+    use fmt::Write;
+
+    // Use `usize` to use `saturating_*` functions.
+    struct Writer {
+        buf: usize,
+        end: usize,
+    }
+
+    impl Write for Writer {
+        fn write_str(&mut self, s: &str) -> fmt::Result {
+            // `buf` value after writing `len` bytes. This does not have to be bounded
+            // by `end`, but we don't want it to wrap around to 0.
+            let buf_new = self.buf.saturating_add(s.len());
+
+            // Amount that we can copy. `saturating_sub` ensures we get 0 if
+            // `buf` goes past `end`.
+            let len_to_copy = cmp::min(buf_new, self.end).saturating_sub(self.buf);
+
+            // SAFETY: In any case, `buf` is non-null and properly aligned.
+            // If `len_to_copy` is non-zero, then we know `buf` has not past
+            // `end` yet and so is valid.
+            unsafe {
+                core::ptr::copy_nonoverlapping(
+                    s.as_bytes().as_ptr(),
+                    self.buf as *mut u8,
+                    len_to_copy,
+                )
+            };
+
+            self.buf = buf_new;
+            Ok(())
+        }
+    }
+
+    let mut w = Writer {
+        buf: buf as _,
+        end: end as _,
+    };
+    let _ = w.write_fmt(unsafe { *(ptr as *const fmt::Arguments<'_>) });
+    w.buf as _
+}
+
+/// Format strings.
+///
+/// Public but hidden since it should only be used from public macros.
+#[doc(hidden)]
+pub mod format_strings {
+    use crate::bindings;
+
+    /// The length we copy from the `KERN_*` kernel prefixes.
+    const LENGTH_PREFIX: usize = 2;
+
+    /// The length of the fixed format strings.
+    pub const LENGTH: usize = 10;
+
+    /// Generates a fixed format string for the kernel's [`_printk`].
+    ///
+    /// The format string is always the same for a given level, i.e. for a
+    /// given `prefix`, which are the kernel's `KERN_*` constants.
+    ///
+    /// [`_printk`]: ../../../../include/linux/printk.h
+    const fn generate(is_cont: bool, prefix: &[u8; 3]) -> [u8; LENGTH] {
+        // Ensure the `KERN_*` macros are what we expect.
+        assert!(prefix[0] == b'\x01');
+        if is_cont {
+            assert!(prefix[1] == b'c');
+        } else {
+            assert!(prefix[1] >= b'0' && prefix[1] <= b'7');
+        }
+        assert!(prefix[2] == b'\x00');
+
+        let suffix: &[u8; LENGTH - LENGTH_PREFIX] = if is_cont {
+            b"%pA\0\0\0\0\0"
+        } else {
+            b"%s: %pA\0"
+        };
+
+        [
+            prefix[0], prefix[1], suffix[0], suffix[1], suffix[2], suffix[3], suffix[4], suffix[5],
+            suffix[6], suffix[7],
+        ]
+    }
+
+    // Generate the format strings at compile-time.
+    //
+    // This avoids the compiler generating the contents on the fly in the stack.
+    //
+    // Furthermore, `static` instead of `const` is used to share the strings
+    // for all the kernel.
+    pub static EMERG: [u8; LENGTH] = generate(false, bindings::KERN_EMERG);
+    pub static ALERT: [u8; LENGTH] = generate(false, bindings::KERN_ALERT);
+    pub static CRIT: [u8; LENGTH] = generate(false, bindings::KERN_CRIT);
+    pub static ERR: [u8; LENGTH] = generate(false, bindings::KERN_ERR);
+    pub static WARNING: [u8; LENGTH] = generate(false, bindings::KERN_WARNING);
+    pub static NOTICE: [u8; LENGTH] = generate(false, bindings::KERN_NOTICE);
+    pub static INFO: [u8; LENGTH] = generate(false, bindings::KERN_INFO);
+    pub static DEBUG: [u8; LENGTH] = generate(false, bindings::KERN_DEBUG);
+    pub static CONT: [u8; LENGTH] = generate(true, bindings::KERN_CONT);
+}
+
+/// Prints a message via the kernel's [`_printk`].
+///
+/// Public but hidden since it should only be used from public macros.
+///
+/// # Safety
+///
+/// The format string must be one of the ones in [`format_strings`], and
+/// the module name must be null-terminated.
+///
+/// [`_printk`]: ../../../../include/linux/_printk.h
+#[doc(hidden)]
+pub unsafe fn call_printk(
+    format_string: &[u8; format_strings::LENGTH],
+    module_name: &[u8],
+    args: fmt::Arguments<'_>,
+) {
+    // `_printk` does not seem to fail in any path.
+    unsafe {
+        bindings::_printk(
+            format_string.as_ptr() as _,
+            module_name.as_ptr(),
+            &args as *const _ as *const c_void,
+        );
+    }
+}
+
+/// Prints a message via the kernel's [`_printk`] for the `CONT` level.
+///
+/// Public but hidden since it should only be used from public macros.
+///
+/// [`_printk`]: ../../../../include/linux/printk.h
+#[doc(hidden)]
+pub fn call_printk_cont(args: fmt::Arguments<'_>) {
+    // `_printk` does not seem to fail in any path.
+    //
+    // SAFETY: The format string is fixed.
+    unsafe {
+        bindings::_printk(
+            format_strings::CONT.as_ptr() as _,
+            &args as *const _ as *const c_void,
+        );
+    }
+}
+
+/// Performs formatting and forwards the string to [`call_printk`].
+///
+/// Public but hidden since it should only be used from public macros.
+#[doc(hidden)]
+#[cfg(not(testlib))]
+#[macro_export]
+macro_rules! print_macro (
+    // The non-continuation cases (most of them, e.g. `INFO`).
+    ($format_string:path, false, $($arg:tt)+) => (
+        // SAFETY: This hidden macro should only be called by the documented
+        // printing macros which ensure the format string is one of the fixed
+        // ones. All `__LOG_PREFIX`s are null-terminated as they are generated
+        // by the `module!` proc macro or fixed values defined in a kernel
+        // crate.
+        unsafe {
+            $crate::print::call_printk(
+                &$format_string,
+                crate::__LOG_PREFIX,
+                format_args!($($arg)+),
+            );
+        }
+    );
+
+    // The `CONT` case.
+    ($format_string:path, true, $($arg:tt)+) => (
+        $crate::print::call_printk_cont(
+            format_args!($($arg)+),
+        );
+    );
+);
+
+/// Stub for doctests
+#[cfg(testlib)]
+#[macro_export]
+macro_rules! print_macro (
+    ($format_string:path, $e:expr, $($arg:tt)+) => (
+        ()
+    );
+);
+
+// We could use a macro to generate these macros. However, doing so ends
+// up being a bit ugly: it requires the dollar token trick to escape `$` as
+// well as playing with the `doc` attribute. Furthermore, they cannot be easily
+// imported in the prelude due to [1]. So, for the moment, we just write them
+// manually, like in the C side; while keeping most of the logic in another
+// macro, i.e. [`print_macro`].
+//
+// [1]: https://github.com/rust-lang/rust/issues/52234
+
+/// Prints an emergency-level message (level 0).
+///
+/// Use this level if the system is unusable.
+///
+/// Equivalent to the kernel's [`pr_emerg`] macro.
+///
+/// Mimics the interface of [`std::print!`]. See [`core::fmt`] and
+/// [`alloc::format!`] for information about the formatting syntax.
+///
+/// [`pr_emerg`]: https://www.kernel.org/doc/html/latest/core-api/printk-basics.html#c.pr_emerg
+/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::prelude::*;
+/// pr_emerg!("hello {}\n", "there");
+/// ```
+#[macro_export]
+macro_rules! pr_emerg (
+    ($($arg:tt)*) => (
+        $crate::print_macro!($crate::print::format_strings::EMERG, false, $($arg)*)
+    )
+);
+
+/// Prints an alert-level message (level 1).
+///
+/// Use this level if action must be taken immediately.
+///
+/// Equivalent to the kernel's [`pr_alert`] macro.
+///
+/// Mimics the interface of [`std::print!`]. See [`core::fmt`] and
+/// [`alloc::format!`] for information about the formatting syntax.
+///
+/// [`pr_alert`]: https://www.kernel.org/doc/html/latest/core-api/printk-basics.html#c.pr_alert
+/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::prelude::*;
+/// pr_alert!("hello {}\n", "there");
+/// ```
+#[macro_export]
+macro_rules! pr_alert (
+    ($($arg:tt)*) => (
+        $crate::print_macro!($crate::print::format_strings::ALERT, false, $($arg)*)
+    )
+);
+
+/// Prints a critical-level message (level 2).
+///
+/// Use this level for critical conditions.
+///
+/// Equivalent to the kernel's [`pr_crit`] macro.
+///
+/// Mimics the interface of [`std::print!`]. See [`core::fmt`] and
+/// [`alloc::format!`] for information about the formatting syntax.
+///
+/// [`pr_crit`]: https://www.kernel.org/doc/html/latest/core-api/printk-basics.html#c.pr_crit
+/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::prelude::*;
+/// pr_crit!("hello {}\n", "there");
+/// ```
+#[macro_export]
+macro_rules! pr_crit (
+    ($($arg:tt)*) => (
+        $crate::print_macro!($crate::print::format_strings::CRIT, false, $($arg)*)
+    )
+);
+
+/// Prints an error-level message (level 3).
+///
+/// Use this level for error conditions.
+///
+/// Equivalent to the kernel's [`pr_err`] macro.
+///
+/// Mimics the interface of [`std::print!`]. See [`core::fmt`] and
+/// [`alloc::format!`] for information about the formatting syntax.
+///
+/// [`pr_err`]: https://www.kernel.org/doc/html/latest/core-api/printk-basics.html#c.pr_err
+/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::prelude::*;
+/// pr_err!("hello {}\n", "there");
+/// ```
+#[macro_export]
+macro_rules! pr_err (
+    ($($arg:tt)*) => (
+        $crate::print_macro!($crate::print::format_strings::ERR, false, $($arg)*)
+    )
+);
+
+/// Prints a warning-level message (level 4).
+///
+/// Use this level for warning conditions.
+///
+/// Equivalent to the kernel's [`pr_warn`] macro.
+///
+/// Mimics the interface of [`std::print!`]. See [`core::fmt`] and
+/// [`alloc::format!`] for information about the formatting syntax.
+///
+/// [`pr_warn`]: https://www.kernel.org/doc/html/latest/core-api/printk-basics.html#c.pr_warn
+/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::prelude::*;
+/// pr_warn!("hello {}\n", "there");
+/// ```
+#[macro_export]
+macro_rules! pr_warn (
+    ($($arg:tt)*) => (
+        $crate::print_macro!($crate::print::format_strings::WARNING, false, $($arg)*)
+    )
+);
+
+/// Prints a notice-level message (level 5).
+///
+/// Use this level for normal but significant conditions.
+///
+/// Equivalent to the kernel's [`pr_notice`] macro.
+///
+/// Mimics the interface of [`std::print!`]. See [`core::fmt`] and
+/// [`alloc::format!`] for information about the formatting syntax.
+///
+/// [`pr_notice`]: https://www.kernel.org/doc/html/latest/core-api/printk-basics.html#c.pr_notice
+/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::prelude::*;
+/// pr_notice!("hello {}\n", "there");
+/// ```
+#[macro_export]
+macro_rules! pr_notice (
+    ($($arg:tt)*) => (
+        $crate::print_macro!($crate::print::format_strings::NOTICE, false, $($arg)*)
+    )
+);
+
+/// Prints an info-level message (level 6).
+///
+/// Use this level for informational messages.
+///
+/// Equivalent to the kernel's [`pr_info`] macro.
+///
+/// Mimics the interface of [`std::print!`]. See [`core::fmt`] and
+/// [`alloc::format!`] for information about the formatting syntax.
+///
+/// [`pr_info`]: https://www.kernel.org/doc/html/latest/core-api/printk-basics.html#c.pr_info
+/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::prelude::*;
+/// pr_info!("hello {}\n", "there");
+/// ```
+#[macro_export]
+#[doc(alias = "print")]
+macro_rules! pr_info (
+    ($($arg:tt)*) => (
+        $crate::print_macro!($crate::print::format_strings::INFO, false, $($arg)*)
+    )
+);
+
+/// Prints a debug-level message (level 7).
+///
+/// Use this level for debug messages.
+///
+/// Equivalent to the kernel's [`pr_debug`] macro, except that it doesn't support dynamic debug
+/// yet.
+///
+/// Mimics the interface of [`std::print!`]. See [`core::fmt`] and
+/// [`alloc::format!`] for information about the formatting syntax.
+///
+/// [`pr_debug`]: https://www.kernel.org/doc/html/latest/core-api/printk-basics.html#c.pr_debug
+/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::prelude::*;
+/// pr_debug!("hello {}\n", "there");
+/// ```
+#[macro_export]
+#[doc(alias = "print")]
+macro_rules! pr_debug (
+    ($($arg:tt)*) => (
+        if cfg!(debug_assertions) {
+            $crate::print_macro!($crate::print::format_strings::DEBUG, false, $($arg)*)
+        }
+    )
+);
+
+/// Continues a previous log message in the same line.
+///
+/// Use only when continuing a previous `pr_*!` macro (e.g. [`pr_info!`]).
+///
+/// Equivalent to the kernel's [`pr_cont`] macro.
+///
+/// Mimics the interface of [`std::print!`]. See [`core::fmt`] and
+/// [`alloc::format!`] for information about the formatting syntax.
+///
+/// [`pr_cont`]: https://www.kernel.org/doc/html/latest/core-api/printk-basics.html#c.pr_cont
+/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::prelude::*;
+/// # use kernel::pr_cont;
+/// pr_info!("hello");
+/// pr_cont!(" {}\n", "there");
+/// ```
+#[macro_export]
+macro_rules! pr_cont (
+    ($($arg:tt)*) => (
+        $crate::print_macro!($crate::print::format_strings::CONT, true, $($arg)*)
+    )
+);
diff --git a/rust/kernel/random.rs b/rust/kernel/random.rs
new file mode 100644
index 000000000000..723a89829f66
--- /dev/null
+++ b/rust/kernel/random.rs
@@ -0,0 +1,50 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Random numbers.
+//!
+//! C header: [`include/linux/random.h`](../../../../include/linux/random.h)
+
+use core::convert::TryInto;
+
+use crate::{bindings, c_types, error};
+
+/// Fills a byte slice with random bytes generated from the kernel's CSPRNG.
+///
+/// Ensures that the CSPRNG has been seeded before generating any random bytes,
+/// and will block until it is ready.
+pub fn getrandom(dest: &mut [u8]) -> error::Result {
+    let res = unsafe { bindings::wait_for_random_bytes() };
+    if res != 0 {
+        return Err(error::Error::from_kernel_errno(res));
+    }
+
+    unsafe {
+        bindings::get_random_bytes(
+            dest.as_mut_ptr() as *mut c_types::c_void,
+            dest.len().try_into()?,
+        );
+    }
+    Ok(())
+}
+
+/// Fills a byte slice with random bytes generated from the kernel's CSPRNG.
+///
+/// If the CSPRNG is not yet seeded, returns an `Err(EAGAIN)` immediately.
+pub fn getrandom_nonblock(dest: &mut [u8]) -> error::Result {
+    if !unsafe { bindings::rng_is_initialized() } {
+        return Err(error::Error::EAGAIN);
+    }
+    getrandom(dest)
+}
+
+/// Contributes the contents of a byte slice to the kernel's entropy pool.
+///
+/// Does *not* credit the kernel entropy counter though.
+pub fn add_randomness(data: &[u8]) {
+    unsafe {
+        bindings::add_device_randomness(
+            data.as_ptr() as *const c_types::c_void,
+            data.len().try_into().unwrap(),
+        );
+    }
+}
diff --git a/rust/kernel/raw_list.rs b/rust/kernel/raw_list.rs
new file mode 100644
index 000000000000..4bc4f4a24ad5
--- /dev/null
+++ b/rust/kernel/raw_list.rs
@@ -0,0 +1,361 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Raw lists.
+//!
+//! TODO: This module is a work in progress.
+
+use core::{
+    cell::UnsafeCell,
+    ptr,
+    ptr::NonNull,
+    sync::atomic::{AtomicBool, Ordering},
+};
+
+/// A descriptor of list elements.
+///
+/// It describes the type of list elements and provides a function to determine how to get the
+/// links to be used on a list.
+///
+/// A type that may be in multiple lists simultaneously neneds to implement one of these for each
+/// simultaneous list.
+pub trait GetLinks {
+    /// The type of the entries in the list.
+    type EntryType: ?Sized;
+
+    /// Returns the links to be used when linking an entry within a list.
+    fn get_links(data: &Self::EntryType) -> &Links<Self::EntryType>;
+}
+
+/// The links used to link an object on a linked list.
+///
+/// Instances of this type are usually embedded in structures and returned in calls to
+/// [`GetLinks::get_links`].
+pub struct Links<T: ?Sized> {
+    inserted: AtomicBool,
+    entry: UnsafeCell<ListEntry<T>>,
+}
+
+impl<T: ?Sized> Links<T> {
+    /// Constructs a new [`Links`] instance that isn't inserted on any lists yet.
+    pub fn new() -> Self {
+        Self {
+            inserted: AtomicBool::new(false),
+            entry: UnsafeCell::new(ListEntry::new()),
+        }
+    }
+
+    fn acquire_for_insertion(&self) -> bool {
+        self.inserted
+            .compare_exchange(false, true, Ordering::Acquire, Ordering::Relaxed)
+            .is_ok()
+    }
+
+    fn release_after_removal(&self) {
+        self.inserted.store(false, Ordering::Release);
+    }
+}
+
+impl<T: ?Sized> Default for Links<T> {
+    fn default() -> Self {
+        Self::new()
+    }
+}
+
+struct ListEntry<T: ?Sized> {
+    next: Option<NonNull<T>>,
+    prev: Option<NonNull<T>>,
+}
+
+impl<T: ?Sized> ListEntry<T> {
+    fn new() -> Self {
+        Self {
+            next: None,
+            prev: None,
+        }
+    }
+}
+
+/// A linked list.
+///
+/// # Invariants
+///
+/// The links of objects added to a list are owned by the list.
+pub(crate) struct RawList<G: GetLinks> {
+    head: Option<NonNull<G::EntryType>>,
+}
+
+impl<G: GetLinks> RawList<G> {
+    pub(crate) fn new() -> Self {
+        Self { head: None }
+    }
+
+    pub(crate) fn is_empty(&self) -> bool {
+        self.head.is_none()
+    }
+
+    fn insert_after_priv(
+        &mut self,
+        existing: &G::EntryType,
+        new_entry: &mut ListEntry<G::EntryType>,
+        new_ptr: Option<NonNull<G::EntryType>>,
+    ) {
+        {
+            // SAFETY: It's safe to get the previous entry of `existing` because the list cannot
+            // change.
+            let existing_links = unsafe { &mut *G::get_links(existing).entry.get() };
+            new_entry.next = existing_links.next;
+            existing_links.next = new_ptr;
+        }
+
+        new_entry.prev = Some(NonNull::from(existing));
+
+        // SAFETY: It's safe to get the next entry of `existing` because the list cannot change.
+        let next_links =
+            unsafe { &mut *G::get_links(new_entry.next.unwrap().as_ref()).entry.get() };
+        next_links.prev = new_ptr;
+    }
+
+    /// Inserts the given object after `existing`.
+    ///
+    /// # Safety
+    ///
+    /// Callers must ensure that `existing` points to a valid entry that is on the list.
+    pub(crate) unsafe fn insert_after(
+        &mut self,
+        existing: &G::EntryType,
+        new: &G::EntryType,
+    ) -> bool {
+        let links = G::get_links(new);
+        if !links.acquire_for_insertion() {
+            // Nothing to do if already inserted.
+            return false;
+        }
+
+        // SAFETY: The links are now owned by the list, so it is safe to get a mutable reference.
+        let new_entry = unsafe { &mut *links.entry.get() };
+        self.insert_after_priv(existing, new_entry, Some(NonNull::from(new)));
+        true
+    }
+
+    fn push_back_internal(&mut self, new: &G::EntryType) -> bool {
+        let links = G::get_links(new);
+        if !links.acquire_for_insertion() {
+            // Nothing to do if already inserted.
+            return false;
+        }
+
+        // SAFETY: The links are now owned by the list, so it is safe to get a mutable reference.
+        let new_entry = unsafe { &mut *links.entry.get() };
+        let new_ptr = Some(NonNull::from(new));
+        match self.back() {
+            // SAFETY: `back` is valid as the list cannot change.
+            Some(back) => self.insert_after_priv(unsafe { back.as_ref() }, new_entry, new_ptr),
+            None => {
+                self.head = new_ptr;
+                new_entry.next = new_ptr;
+                new_entry.prev = new_ptr;
+            }
+        }
+        true
+    }
+
+    pub(crate) unsafe fn push_back(&mut self, new: &G::EntryType) -> bool {
+        self.push_back_internal(new)
+    }
+
+    fn remove_internal(&mut self, data: &G::EntryType) -> bool {
+        let links = G::get_links(data);
+
+        // SAFETY: The links are now owned by the list, so it is safe to get a mutable reference.
+        let entry = unsafe { &mut *links.entry.get() };
+        let next = if let Some(next) = entry.next {
+            next
+        } else {
+            // Nothing to do if the entry is not on the list.
+            return false;
+        };
+
+        if ptr::eq(data, next.as_ptr()) {
+            // We're removing the only element.
+            self.head = None
+        } else {
+            // Update the head if we're removing it.
+            if let Some(raw_head) = self.head {
+                if ptr::eq(data, raw_head.as_ptr()) {
+                    self.head = Some(next);
+                }
+            }
+
+            // SAFETY: It's safe to get the previous entry because the list cannot change.
+            unsafe { &mut *G::get_links(entry.prev.unwrap().as_ref()).entry.get() }.next =
+                entry.next;
+
+            // SAFETY: It's safe to get the next entry because the list cannot change.
+            unsafe { &mut *G::get_links(next.as_ref()).entry.get() }.prev = entry.prev;
+        }
+
+        // Reset the links of the element we're removing so that we know it's not on any list.
+        entry.next = None;
+        entry.prev = None;
+        links.release_after_removal();
+        true
+    }
+
+    /// Removes the given entry.
+    ///
+    /// # Safety
+    ///
+    /// Callers must ensure that `data` is either on this list or in no list. It being on another
+    /// list leads to memory unsafety.
+    pub(crate) unsafe fn remove(&mut self, data: &G::EntryType) -> bool {
+        self.remove_internal(data)
+    }
+
+    fn pop_front_internal(&mut self) -> Option<NonNull<G::EntryType>> {
+        let head = self.head?;
+        // SAFETY: The head is on the list as we just got it from there and it cannot change.
+        unsafe { self.remove(head.as_ref()) };
+        Some(head)
+    }
+
+    pub(crate) fn pop_front(&mut self) -> Option<NonNull<G::EntryType>> {
+        self.pop_front_internal()
+    }
+
+    pub(crate) fn front(&self) -> Option<NonNull<G::EntryType>> {
+        self.head
+    }
+
+    pub(crate) fn back(&self) -> Option<NonNull<G::EntryType>> {
+        // SAFETY: The links of head are owned by the list, so it is safe to get a reference.
+        unsafe { &*G::get_links(self.head?.as_ref()).entry.get() }.prev
+    }
+
+    pub(crate) fn cursor_front(&self) -> Cursor<'_, G> {
+        Cursor::new(self, self.front())
+    }
+
+    pub(crate) fn cursor_front_mut(&mut self) -> CursorMut<'_, G> {
+        CursorMut::new(self, self.front())
+    }
+}
+
+struct CommonCursor<G: GetLinks> {
+    cur: Option<NonNull<G::EntryType>>,
+}
+
+impl<G: GetLinks> CommonCursor<G> {
+    fn new(cur: Option<NonNull<G::EntryType>>) -> Self {
+        Self { cur }
+    }
+
+    fn move_next(&mut self, list: &RawList<G>) {
+        match self.cur.take() {
+            None => self.cur = list.head,
+            Some(cur) => {
+                if let Some(head) = list.head {
+                    // SAFETY: We have a shared ref to the linked list, so the links can't change.
+                    let links = unsafe { &*G::get_links(cur.as_ref()).entry.get() };
+                    if links.next.unwrap() != head {
+                        self.cur = links.next;
+                    }
+                }
+            }
+        }
+    }
+
+    fn move_prev(&mut self, list: &RawList<G>) {
+        match list.head {
+            None => self.cur = None,
+            Some(head) => {
+                let next = match self.cur.take() {
+                    None => head,
+                    Some(cur) => {
+                        if cur == head {
+                            return;
+                        }
+                        cur
+                    }
+                };
+                // SAFETY: There's a shared ref to the list, so the links can't change.
+                let links = unsafe { &*G::get_links(next.as_ref()).entry.get() };
+                self.cur = links.prev;
+            }
+        }
+    }
+}
+
+/// A list cursor that allows traversing a linked list and inspecting elements.
+pub struct Cursor<'a, G: GetLinks> {
+    cursor: CommonCursor<G>,
+    list: &'a RawList<G>,
+}
+
+impl<'a, G: GetLinks> Cursor<'a, G> {
+    fn new(list: &'a RawList<G>, cur: Option<NonNull<G::EntryType>>) -> Self {
+        Self {
+            list,
+            cursor: CommonCursor::new(cur),
+        }
+    }
+
+    /// Returns the element the cursor is currently positioned on.
+    pub fn current(&self) -> Option<&'a G::EntryType> {
+        let cur = self.cursor.cur?;
+        // SAFETY: Objects must be kept alive while on the list.
+        Some(unsafe { &*cur.as_ptr() })
+    }
+
+    /// Moves the cursor to the next element.
+    pub fn move_next(&mut self) {
+        self.cursor.move_next(self.list);
+    }
+}
+
+pub(crate) struct CursorMut<'a, G: GetLinks> {
+    cursor: CommonCursor<G>,
+    list: &'a mut RawList<G>,
+}
+
+impl<'a, G: GetLinks> CursorMut<'a, G> {
+    fn new(list: &'a mut RawList<G>, cur: Option<NonNull<G::EntryType>>) -> Self {
+        Self {
+            list,
+            cursor: CommonCursor::new(cur),
+        }
+    }
+
+    pub(crate) fn current(&mut self) -> Option<&mut G::EntryType> {
+        let cur = self.cursor.cur?;
+        // SAFETY: Objects must be kept alive while on the list.
+        Some(unsafe { &mut *cur.as_ptr() })
+    }
+
+    /// Removes the entry the cursor is pointing to and advances the cursor to the next entry. It
+    /// returns a raw pointer to the removed element (if one is removed).
+    pub(crate) fn remove_current(&mut self) -> Option<NonNull<G::EntryType>> {
+        let entry = self.cursor.cur?;
+        self.cursor.move_next(self.list);
+        // SAFETY: The entry is on the list as we just got it from there and it cannot change.
+        unsafe { self.list.remove(entry.as_ref()) };
+        Some(entry)
+    }
+
+    pub(crate) fn peek_next(&mut self) -> Option<&mut G::EntryType> {
+        let mut new = CommonCursor::new(self.cursor.cur);
+        new.move_next(self.list);
+        // SAFETY: Objects must be kept alive while on the list.
+        Some(unsafe { &mut *new.cur?.as_ptr() })
+    }
+
+    pub(crate) fn peek_prev(&mut self) -> Option<&mut G::EntryType> {
+        let mut new = CommonCursor::new(self.cursor.cur);
+        new.move_prev(self.list);
+        // SAFETY: Objects must be kept alive while on the list.
+        Some(unsafe { &mut *new.cur?.as_ptr() })
+    }
+
+    pub(crate) fn move_next(&mut self) {
+        self.cursor.move_next(self.list);
+    }
+}
diff --git a/rust/kernel/rbtree.rs b/rust/kernel/rbtree.rs
new file mode 100644
index 000000000000..880252e9cde7
--- /dev/null
+++ b/rust/kernel/rbtree.rs
@@ -0,0 +1,562 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Red-black trees.
+//!
+//! C header: [`include/linux/rbtree.h`](../../../../include/linux/rbtree.h)
+//!
+//! Reference: <https://www.kernel.org/doc/html/latest/core-api/rbtree.html>
+
+use crate::{bindings, Result};
+use alloc::boxed::Box;
+use core::{
+    cmp::{Ord, Ordering},
+    iter::{IntoIterator, Iterator},
+    marker::PhantomData,
+    mem::MaybeUninit,
+    ptr::{addr_of_mut, NonNull},
+};
+
+struct Node<K, V> {
+    links: bindings::rb_node,
+    key: K,
+    value: V,
+}
+
+/// A red-black tree with owned nodes.
+///
+/// It is backed by the kernel C red-black trees.
+///
+/// # Invariants
+///
+/// Non-null parent/children pointers stored in instances of the `rb_node` C struct are always
+/// valid, and pointing to a field of our internal representation of a node.
+///
+/// # Examples
+///
+/// In the example below we do several operations on a tree. We note that insertions may fail if
+/// the system is out of memory.
+///
+/// ```
+/// # use kernel::prelude::*;
+/// use kernel::rbtree::RBTree;
+///
+/// fn rbtest() -> Result {
+///     // Create a new tree.
+///     let mut tree = RBTree::new();
+///
+///     // Insert three elements.
+///     tree.try_insert(20, 200)?;
+///     tree.try_insert(10, 100)?;
+///     tree.try_insert(30, 300)?;
+///
+///     // Check the nodes we just inserted.
+///     {
+///         let mut iter = tree.iter();
+///         assert_eq!(iter.next().unwrap(), (&10, &100));
+///         assert_eq!(iter.next().unwrap(), (&20, &200));
+///         assert_eq!(iter.next().unwrap(), (&30, &300));
+///         assert!(iter.next().is_none());
+///     }
+///
+///     // Print all elements.
+///     for (key, value) in &tree {
+///         pr_info!("{} = {}\n", key, value);
+///     }
+///
+///     // Replace one of the elements.
+///     tree.try_insert(10, 1000)?;
+///
+///     // Check that the tree reflects the replacement.
+///     {
+///         let mut iter = tree.iter();
+///         assert_eq!(iter.next().unwrap(), (&10, &1000));
+///         assert_eq!(iter.next().unwrap(), (&20, &200));
+///         assert_eq!(iter.next().unwrap(), (&30, &300));
+///         assert!(iter.next().is_none());
+///     }
+///
+///     // Change the value of one of the elements.
+///     *tree.get_mut(&30).unwrap() = 3000;
+///
+///     // Check that the tree reflects the update.
+///     {
+///         let mut iter = tree.iter();
+///         assert_eq!(iter.next().unwrap(), (&10, &1000));
+///         assert_eq!(iter.next().unwrap(), (&20, &200));
+///         assert_eq!(iter.next().unwrap(), (&30, &3000));
+///         assert!(iter.next().is_none());
+///     }
+///
+///     // Remove an element.
+///     tree.remove(&10);
+///
+///     // Check that the tree reflects the removal.
+///     {
+///         let mut iter = tree.iter();
+///         assert_eq!(iter.next().unwrap(), (&20, &200));
+///         assert_eq!(iter.next().unwrap(), (&30, &3000));
+///         assert!(iter.next().is_none());
+///     }
+///
+///     // Update all values.
+///     for value in tree.values_mut() {
+///         *value *= 10;
+///     }
+///
+///     // Check that the tree reflects the changes to values.
+///     {
+///         let mut iter = tree.iter();
+///         assert_eq!(iter.next().unwrap(), (&20, &2000));
+///         assert_eq!(iter.next().unwrap(), (&30, &30000));
+///         assert!(iter.next().is_none());
+///     }
+///
+///     Ok(())
+/// }
+/// ```
+///
+/// In the example below, we first allocate a node, acquire a spinlock, then insert the node into
+/// the tree. This is useful when the insertion context does not allow sleeping, for example, when
+/// holding a spinlock.
+///
+/// ```
+/// # use kernel::prelude::*;
+/// use kernel::{rbtree::RBTree, sync::SpinLock};
+///
+/// fn insert_test(tree: &SpinLock<RBTree<u32, u32>>) -> Result {
+///     // Pre-allocate node. This may fail (as it allocates memory).
+///     let node = RBTree::try_allocate_node(10, 100)?;
+///
+///     // Insert node while holding the lock. It is guaranteed to succeed with no allocation
+///     // attempts.
+///     let mut guard = tree.lock();
+///     guard.insert(node);
+///     Ok(())
+/// }
+/// ```
+///
+/// In the example below, we reuse an existing node allocation from an element we removed.
+///
+/// ```
+/// # use kernel::prelude::*;
+/// use kernel::rbtree::RBTree;
+///
+/// fn reuse_test() -> Result {
+///     // Create a new tree.
+///     let mut tree = RBTree::new();
+///
+///     // Insert three elements.
+///     tree.try_insert(20, 200)?;
+///     tree.try_insert(10, 100)?;
+///     tree.try_insert(30, 300)?;
+///
+///     // Check the nodes we just inserted.
+///     {
+///         let mut iter = tree.iter();
+///         assert_eq!(iter.next().unwrap(), (&10, &100));
+///         assert_eq!(iter.next().unwrap(), (&20, &200));
+///         assert_eq!(iter.next().unwrap(), (&30, &300));
+///         assert!(iter.next().is_none());
+///     }
+///
+///     // Remove a node, getting back ownership of it.
+///     let existing = tree.remove_node(&30).unwrap();
+///
+///     // Check that the tree reflects the removal.
+///     {
+///         let mut iter = tree.iter();
+///         assert_eq!(iter.next().unwrap(), (&10, &100));
+///         assert_eq!(iter.next().unwrap(), (&20, &200));
+///         assert!(iter.next().is_none());
+///     }
+///
+///     // Turn the node into a reservation so that we can reuse it with a different key/value.
+///     let reservation = existing.into_reservation();
+///
+///     // Insert a new node into the tree, reusing the previous allocation. This is guaranteed to
+///     // succeed (no memory allocations).
+///     tree.insert(reservation.into_node(15, 150));
+///
+///     // Check that the tree reflect the new insertion.
+///     {
+///         let mut iter = tree.iter();
+///         assert_eq!(iter.next().unwrap(), (&10, &100));
+///         assert_eq!(iter.next().unwrap(), (&15, &150));
+///         assert_eq!(iter.next().unwrap(), (&20, &200));
+///         assert!(iter.next().is_none());
+///     }
+///
+///     Ok(())
+/// }
+/// ```
+pub struct RBTree<K, V> {
+    root: bindings::rb_root,
+    _p: PhantomData<Node<K, V>>,
+}
+
+impl<K, V> RBTree<K, V> {
+    /// Creates a new and empty tree.
+    pub fn new() -> Self {
+        Self {
+            // INVARIANT: There are no nodes in the tree, so the invariant holds vacuously.
+            root: bindings::rb_root::default(),
+            _p: PhantomData,
+        }
+    }
+
+    /// Tries to insert a new value into the tree.
+    ///
+    /// It overwrites a node if one already exists with the same key and returns it (containing the
+    /// key/value pair). Returns [`None`] if a node with the same key didn't already exist.
+    ///
+    /// Returns an error if it cannot allocate memory for the new node.
+    pub fn try_insert(&mut self, key: K, value: V) -> Result<Option<RBTreeNode<K, V>>>
+    where
+        K: Ord,
+    {
+        Ok(self.insert(Self::try_allocate_node(key, value)?))
+    }
+
+    /// Allocates memory for a node to be eventually initialised and inserted into the tree via a
+    /// call to [`RBTree::insert`].
+    pub fn try_reserve_node() -> Result<RBTreeNodeReservation<K, V>> {
+        Ok(RBTreeNodeReservation {
+            node: Box::try_new(MaybeUninit::uninit())?,
+        })
+    }
+
+    /// Allocates and initialiases a node that can be inserted into the tree via
+    /// [`RBTree::insert`].
+    pub fn try_allocate_node(key: K, value: V) -> Result<RBTreeNode<K, V>> {
+        Ok(Self::try_reserve_node()?.into_node(key, value))
+    }
+
+    /// Inserts a new node into the tree.
+    ///
+    /// It overwrites a node if one already exists with the same key and returns it (containing the
+    /// key/value pair). Returns [`None`] if a node with the same key didn't already exist.
+    ///
+    /// This function always succeeds.
+    pub fn insert(&mut self, node: RBTreeNode<K, V>) -> Option<RBTreeNode<K, V>>
+    where
+        K: Ord,
+    {
+        let RBTreeNode { node } = node;
+        let node = Box::into_raw(node);
+        // SAFETY: `node` is valid at least until we call `Box::from_raw`, which only happens when
+        // the node is removed or replaced.
+        let node_links = unsafe { addr_of_mut!((*node).links) };
+        let mut new_link: &mut *mut bindings::rb_node = &mut self.root.rb_node;
+        let mut parent = core::ptr::null_mut();
+        while !new_link.is_null() {
+            let this = crate::container_of!(*new_link, Node<K, V>, links);
+
+            parent = *new_link;
+
+            // SAFETY: `this` is a non-null node so it is valid by the type invariants. `node` is
+            // valid until the node is removed.
+            match unsafe { (*node).key.cmp(&(*this).key) } {
+                // SAFETY: `parent` is a non-null node so it is valid by the type invariants.
+                Ordering::Less => new_link = unsafe { &mut (*parent).rb_left },
+                // SAFETY: `parent` is a non-null node so it is valid by the type invariants.
+                Ordering::Greater => new_link = unsafe { &mut (*parent).rb_right },
+                Ordering::Equal => {
+                    // INVARIANT: We are replacing an existing node with a new one, which is valid.
+                    // It remains valid because we "forgot" it with `Box::into_raw`.
+                    // SAFETY: All pointers are non-null and valid (parent, despite the name, really
+                    // is the node we're replacing).
+                    unsafe { bindings::rb_replace_node(parent, node_links, &mut self.root) };
+
+                    // INVARIANT: The node is being returned and the caller may free it, however,
+                    // it was removed from the tree. So the invariants still hold.
+                    return Some(RBTreeNode {
+                        // SAFETY: `this` was a node in the tree, so it is valid.
+                        node: unsafe { Box::from_raw(this as _) },
+                    });
+                }
+            }
+        }
+
+        // INVARIANT: We are linking in a new node, which is valid. It remains valid because we
+        // "forgot" it with `Box::into_raw`.
+        // SAFETY: All pointers are non-null and valid (`*new_link` is null, but `new_link` is a
+        // mutable reference).
+        unsafe { bindings::rb_link_node(node_links, parent, new_link) };
+
+        // SAFETY: All pointers are valid. `node` has just been inserted into the tree.
+        unsafe { bindings::rb_insert_color(node_links, &mut self.root) };
+        None
+    }
+
+    /// Returns a node with the given key, if one exists.
+    fn find(&self, key: &K) -> Option<NonNull<Node<K, V>>>
+    where
+        K: Ord,
+    {
+        let mut node = self.root.rb_node;
+        while !node.is_null() {
+            let this = crate::container_of!(node, Node<K, V>, links);
+            // SAFETY: `this` is a non-null node so it is valid by the type invariants.
+            node = match key.cmp(unsafe { &(*this).key }) {
+                // SAFETY: `node` is a non-null node so it is valid by the type invariants.
+                Ordering::Less => unsafe { (*node).rb_left },
+                // SAFETY: `node` is a non-null node so it is valid by the type invariants.
+                Ordering::Greater => unsafe { (*node).rb_right },
+                Ordering::Equal => return NonNull::new(this as _),
+            }
+        }
+        None
+    }
+
+    /// Returns a reference to the value corresponding to the key.
+    pub fn get(&self, key: &K) -> Option<&V>
+    where
+        K: Ord,
+    {
+        // SAFETY: The `find` return value is a node in the tree, so it is valid.
+        self.find(key).map(|node| unsafe { &node.as_ref().value })
+    }
+
+    /// Returns a mutable reference to the value corresponding to the key.
+    pub fn get_mut(&mut self, key: &K) -> Option<&mut V>
+    where
+        K: Ord,
+    {
+        // SAFETY: the `find` return value is a node in the tree, so it is valid.
+        self.find(key)
+            .map(|mut node| unsafe { &mut node.as_mut().value })
+    }
+
+    /// Removes the node with the given key from the tree.
+    ///
+    /// It returns the node that was removed if one exists, or [`None`] otherwise.
+    pub fn remove_node(&mut self, key: &K) -> Option<RBTreeNode<K, V>>
+    where
+        K: Ord,
+    {
+        let mut node = self.find(key)?;
+
+        // SAFETY: the `find` return value is a node in the tree, so it is valid.
+        unsafe { bindings::rb_erase(&mut node.as_mut().links, &mut self.root) };
+
+        // INVARIANT: The node is being returned and the caller may free it, however, it was
+        // removed from the tree. So the invariants still hold.
+        Some(RBTreeNode {
+            // SAFETY: the `find` return value was a node in the tree, so it is valid.
+            node: unsafe { Box::from_raw(node.as_ptr()) },
+        })
+    }
+
+    /// Removes the node with the given key from the tree.
+    ///
+    /// It returns the value that was removed if one exists, or [`None`] otherwise.
+    pub fn remove(&mut self, key: &K) -> Option<V>
+    where
+        K: Ord,
+    {
+        let node = self.remove_node(key)?;
+        let RBTreeNode { node } = node;
+        let Node {
+            links: _,
+            key: _,
+            value,
+        } = *node;
+        Some(value)
+    }
+
+    /// Returns an iterator over the tree nodes, sorted by key.
+    pub fn iter(&self) -> RBTreeIterator<'_, K, V> {
+        RBTreeIterator {
+            _tree: PhantomData,
+            // SAFETY: `root` is valid as it's embedded in `self` and we have a valid `self`.
+            next: unsafe { bindings::rb_first(&self.root) },
+        }
+    }
+
+    /// Returns a mutable iterator over the tree nodes, sorted by key.
+    pub fn iter_mut(&mut self) -> RBTreeIteratorMut<'_, K, V> {
+        RBTreeIteratorMut {
+            _tree: PhantomData,
+            // SAFETY: `root` is valid as it's embedded in `self` and we have a valid `self`.
+            next: unsafe { bindings::rb_first(&self.root) },
+        }
+    }
+
+    /// Returns an iterator over the keys of the nodes in the tree, in sorted order.
+    pub fn keys(&self) -> impl Iterator<Item = &'_ K> {
+        self.iter().map(|(k, _)| k)
+    }
+
+    /// Returns an iterator over the values of the nodes in the tree, sorted by key.
+    pub fn values(&self) -> impl Iterator<Item = &'_ V> {
+        self.iter().map(|(_, v)| v)
+    }
+
+    /// Returns a mutable iterator over the values of the nodes in the tree, sorted by key.
+    pub fn values_mut(&mut self) -> impl Iterator<Item = &'_ mut V> {
+        self.iter_mut().map(|(_, v)| v)
+    }
+}
+
+impl<K, V> Default for RBTree<K, V> {
+    fn default() -> Self {
+        Self::new()
+    }
+}
+
+impl<K, V> Drop for RBTree<K, V> {
+    fn drop(&mut self) {
+        // SAFETY: `root` is valid as it's embedded in `self` and we have a valid `self`.
+        let mut next = unsafe { bindings::rb_first_postorder(&self.root) };
+
+        // INVARIANT: The loop invariant is that all tree nodes from `next` in postorder are valid.
+        while !next.is_null() {
+            let this = crate::container_of!(next, Node<K, V>, links);
+
+            // Find out what the next node is before disposing of the current one.
+            // SAFETY: `next` and all nodes in postorder are still valid.
+            next = unsafe { bindings::rb_next_postorder(next) };
+
+            // INVARIANT: This is the destructor, so we break the type invariant during clean-up,
+            // but it is not observable. The loop invariant is still maintained.
+            // SAFETY: `this` is valid per the loop invariant.
+            unsafe { Box::from_raw(this as *mut Node<K, V>) };
+        }
+    }
+}
+
+impl<'a, K, V> IntoIterator for &'a RBTree<K, V> {
+    type Item = (&'a K, &'a V);
+    type IntoIter = RBTreeIterator<'a, K, V>;
+
+    fn into_iter(self) -> Self::IntoIter {
+        self.iter()
+    }
+}
+
+/// An iterator over the nodes of a [`RBTree`].
+///
+/// Instances are created by calling [`RBTree::iter`].
+pub struct RBTreeIterator<'a, K, V> {
+    _tree: PhantomData<&'a RBTree<K, V>>,
+    next: *mut bindings::rb_node,
+}
+
+impl<'a, K, V> Iterator for RBTreeIterator<'a, K, V> {
+    type Item = (&'a K, &'a V);
+
+    fn next(&mut self) -> Option<Self::Item> {
+        if self.next.is_null() {
+            return None;
+        }
+
+        let cur = crate::container_of!(self.next, Node<K, V>, links);
+
+        // SAFETY: The reference to the tree used to create the iterator outlives the iterator, so
+        // the tree cannot change. By the tree invariant, all nodes are valid.
+        self.next = unsafe { bindings::rb_next(self.next) };
+
+        // SAFETY: By the same reasoning above, it is safe to dereference the node. Additionally,
+        // it is ok to return a reference to members because the iterator must outlive it.
+        Some(unsafe { (&(*cur).key, &(*cur).value) })
+    }
+}
+
+impl<'a, K, V> IntoIterator for &'a mut RBTree<K, V> {
+    type Item = (&'a K, &'a mut V);
+    type IntoIter = RBTreeIteratorMut<'a, K, V>;
+
+    fn into_iter(self) -> Self::IntoIter {
+        self.iter_mut()
+    }
+}
+
+/// A mutable iterator over the nodes of a [`RBTree`].
+///
+/// Instances are created by calling [`RBTree::iter_mut`].
+pub struct RBTreeIteratorMut<'a, K, V> {
+    _tree: PhantomData<&'a RBTree<K, V>>,
+    next: *mut bindings::rb_node,
+}
+
+impl<'a, K, V> Iterator for RBTreeIteratorMut<'a, K, V> {
+    type Item = (&'a K, &'a mut V);
+
+    fn next(&mut self) -> Option<Self::Item> {
+        if self.next.is_null() {
+            return None;
+        }
+
+        let cur = crate::container_of!(self.next, Node<K, V>, links) as *mut Node<K, V>;
+
+        // SAFETY: The reference to the tree used to create the iterator outlives the iterator, so
+        // the tree cannot change (except for the value of previous nodes, but those don't affect
+        // the iteration process). By the tree invariant, all nodes are valid.
+        self.next = unsafe { bindings::rb_next(self.next) };
+
+        // SAFETY: By the same reasoning above, it is safe to dereference the node. Additionally,
+        // it is ok to return a reference to members because the iterator must outlive it.
+        Some(unsafe { (&(*cur).key, &mut (*cur).value) })
+    }
+}
+
+/// A memory reservation for a red-black tree node.
+///
+/// It contains the memory needed to hold a node that can be inserted into a red-black tree. One
+/// can be obtained by directly allocating it ([`RBTree::try_reserve_node`]) or by "uninitialising"
+/// ([`RBTreeNode::into_reservation`]) an actual node (usually returned by some operation like
+/// removal from a tree).
+pub struct RBTreeNodeReservation<K, V> {
+    node: Box<MaybeUninit<Node<K, V>>>,
+}
+
+impl<K, V> RBTreeNodeReservation<K, V> {
+    /// Initialises a node reservation.
+    ///
+    /// It then becomes an [`RBTreeNode`] that can be inserted into a tree.
+    pub fn into_node(mut self, key: K, value: V) -> RBTreeNode<K, V> {
+        let node_ptr = self.node.as_mut_ptr();
+        // SAFETY: `node_ptr` is valid, and so are its fields.
+        unsafe { addr_of_mut!((*node_ptr).links).write(bindings::rb_node::default()) };
+        // SAFETY: `node_ptr` is valid, and so are its fields.
+        unsafe { addr_of_mut!((*node_ptr).key).write(key) };
+        // SAFETY: `node_ptr` is valid, and so are its fields.
+        unsafe { addr_of_mut!((*node_ptr).value).write(value) };
+        let raw = Box::into_raw(self.node);
+        RBTreeNode {
+            // SAFETY: The pointer came from a `MaybeUninit<Node>` whose fields have all been
+            // initialised. Additionally, it has the same layout as `Node`.
+            node: unsafe { Box::from_raw(raw as _) },
+        }
+    }
+}
+
+/// A red-black tree node.
+///
+/// The node is fully initialised (with key and value) and can be inserted into a tree without any
+/// extra allocations or failure paths.
+pub struct RBTreeNode<K, V> {
+    node: Box<Node<K, V>>,
+}
+
+impl<K, V> RBTreeNode<K, V> {
+    /// "Uninitialises" a node.
+    ///
+    /// It then becomes a reservation that can be re-initialised into a different node (i.e., with
+    /// a different key and/or value).
+    ///
+    /// The existing key and value are dropped in-place as part of this operation, that is, memory
+    /// may be freed (but only for the key/value; memory for the node itself is kept for reuse).
+    pub fn into_reservation(self) -> RBTreeNodeReservation<K, V> {
+        let raw = Box::into_raw(self.node);
+        let mut ret = RBTreeNodeReservation {
+            // SAFETY: The pointer came from a valid `Node`, which has the same layout as
+            // `MaybeUninit<Node>`.
+            node: unsafe { Box::from_raw(raw as _) },
+        };
+        // SAFETY: Although the type is `MaybeUninit<Node>`, we know it has been initialised
+        // because it came from a `Node`. So it is safe to drop it.
+        unsafe { core::ptr::drop_in_place(ret.node.as_mut_ptr()) };
+        ret
+    }
+}
diff --git a/rust/kernel/revocable.rs b/rust/kernel/revocable.rs
new file mode 100644
index 000000000000..9cc65ca3a1b6
--- /dev/null
+++ b/rust/kernel/revocable.rs
@@ -0,0 +1,163 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Revocable objects.
+//!
+//! The [`Revocable`] type wraps other types and allows access to them to be revoked. The existence
+//! of a [`RevocableGuard`] ensures that objects remain valid.
+
+use crate::bindings;
+use core::{
+    cell::UnsafeCell,
+    marker::PhantomData,
+    mem::ManuallyDrop,
+    ops::Deref,
+    ptr::drop_in_place,
+    sync::atomic::{AtomicBool, Ordering},
+};
+
+/// An object that can become inaccessible at runtime.
+///
+/// Once access is revoked and all concurrent users complete (i.e., all existing instances of
+/// [`RevocableGuard`] are dropped), the wrapped object is also dropped.
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::revocable::Revocable;
+///
+/// struct Example {
+///     a: u32,
+///     b: u32,
+/// }
+///
+/// fn add_two(v: &Revocable<Example>) -> Option<u32> {
+///     let guard = v.try_access()?;
+///     Some(guard.a + guard.b)
+/// }
+///
+/// fn example() {
+///     let v = Revocable::new(Example { a: 10, b: 20 });
+///     assert_eq!(add_two(&v), Some(30));
+///     v.revoke();
+///     assert_eq!(add_two(&v), None);
+/// }
+/// ```
+pub struct Revocable<T: ?Sized> {
+    is_available: AtomicBool,
+    data: ManuallyDrop<UnsafeCell<T>>,
+}
+
+// SAFETY: `Revocable` is `Send` if the wrapped object is also `Send`. This is because while the
+// functionality exposed by `Revocable` can be accessed from any thread/CPU, it is possible that
+// this isn't supported by the wrapped object.
+unsafe impl<T: ?Sized + Send> Send for Revocable<T> {}
+
+// SAFETY: `Revocable` is `Sync` if the wrapped object is both `Send` and `Sync`. We require `Send`
+// from the wrapped object as well because  of `Revocable::revoke`, which can trigger the `Drop`
+// implementation of the wrapped object from an arbitrary thread.
+unsafe impl<T: ?Sized + Sync + Send> Sync for Revocable<T> {}
+
+impl<T> Revocable<T> {
+    /// Creates a new revocable instance of the given data.
+    pub fn new(data: T) -> Self {
+        Self {
+            is_available: AtomicBool::new(true),
+            data: ManuallyDrop::new(UnsafeCell::new(data)),
+        }
+    }
+}
+
+impl<T: ?Sized> Revocable<T> {
+    /// Tries to access the \[revocable\] wrapped object.
+    ///
+    /// Returns `None` if the object has been revoked and is therefore no longer accessible.
+    ///
+    /// Returns a guard that gives access to the object otherwise; the object is guaranteed to
+    /// remain accessible while the guard is alive. In such cases, callers are not allowed to sleep
+    /// because another CPU may be waiting to complete the revocation of this object.
+    pub fn try_access(&self) -> Option<RevocableGuard<'_, T>> {
+        let guard = RevocableGuard::new(self.data.get());
+        if self.is_available.load(Ordering::Relaxed) {
+            Some(guard)
+        } else {
+            None
+        }
+    }
+
+    /// Revokes access to and drops the wrapped object.
+    ///
+    /// Access to the object is revoked immediately to new callers of [`Revocable::try_access`]. If
+    /// there are concurrent users of the object (i.e., ones that called [`Revocable::try_access`]
+    /// beforehand and still haven't dropped the returned guard), this function waits for the
+    /// concurrent access to complete before dropping the wrapped object.
+    pub fn revoke(&self) {
+        if self
+            .is_available
+            .compare_exchange(true, false, Ordering::Relaxed, Ordering::Relaxed)
+            .is_ok()
+        {
+            // SAFETY: Just an FFI call, there are no further requirements.
+            unsafe { bindings::synchronize_rcu() };
+
+            // SAFETY: We know `self.data` is valid because only one CPU can succeed the
+            // `compare_exchange` above that takes `is_available` from `true` to `false`.
+            unsafe { drop_in_place(self.data.get()) };
+        }
+    }
+}
+
+impl<T: ?Sized> Drop for Revocable<T> {
+    fn drop(&mut self) {
+        // Drop only if the data hasn't been revoked yet (in which case it has already been
+        // dropped).
+        if *self.is_available.get_mut() {
+            // SAFETY: We know `self.data` is valid because no other CPU has changed
+            // `is_available` to `false` yet, and no other CPU can do it anymore because this CPU
+            // holds the only reference (mutable) to `self` now.
+            unsafe { drop_in_place(self.data.get()) };
+        }
+    }
+}
+
+/// A guard that allows access to a revocable object and keeps it alive.
+///
+/// CPUs may not sleep while holding on to [`RevocableGuard`] because it's in atomic context
+/// holding the RCU read-side lock.
+///
+/// # Invariants
+///
+/// The RCU read-side lock is held while the guard is alive.
+pub struct RevocableGuard<'a, T: ?Sized> {
+    data_ref: *const T,
+    _p: PhantomData<&'a ()>,
+}
+
+impl<T: ?Sized> RevocableGuard<'_, T> {
+    fn new(data_ref: *const T) -> Self {
+        // SAFETY: Just an FFI call, there are no further requirements.
+        unsafe { bindings::rcu_read_lock() };
+
+        // INVARIANTS: The RCU read-side lock was just acquired.
+        Self {
+            data_ref,
+            _p: PhantomData,
+        }
+    }
+}
+
+impl<T: ?Sized> Drop for RevocableGuard<'_, T> {
+    fn drop(&mut self) {
+        // SAFETY: By the type invariants, we know that we hold the RCU read-side lock.
+        unsafe { bindings::rcu_read_unlock() };
+    }
+}
+
+impl<T: ?Sized> Deref for RevocableGuard<'_, T> {
+    type Target = T;
+
+    fn deref(&self) -> &Self::Target {
+        // SAFETY: By the type invariants, we hold the rcu read-side lock, so the object is
+        // guaranteed to remain valid.
+        unsafe { &*self.data_ref }
+    }
+}
diff --git a/rust/kernel/security.rs b/rust/kernel/security.rs
new file mode 100644
index 000000000000..2004d01233f4
--- /dev/null
+++ b/rust/kernel/security.rs
@@ -0,0 +1,36 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Linux Security Modules (LSM).
+//!
+//! C header: [`include/linux/security.h`](../../../../include/linux/security.h).
+
+use crate::{bindings, cred::Credential, file::File, to_result, Result};
+
+/// Calls the security modules to determine if the given task can become the manager of a binder
+/// context.
+pub fn binder_set_context_mgr(mgr: &Credential) -> Result {
+    // SAFETY: By the `Credential` invariants, `mgr.ptr` is valid.
+    to_result(|| unsafe { bindings::security_binder_set_context_mgr(mgr.ptr) })
+}
+
+/// Calls the security modules to determine if binder transactions are allowed from task `from` to
+/// task `to`.
+pub fn binder_transaction(from: &Credential, to: &Credential) -> Result {
+    // SAFETY: By the `Credential` invariants, `from.ptr` and `to.ptr` are valid.
+    to_result(|| unsafe { bindings::security_binder_transaction(from.ptr, to.ptr) })
+}
+
+/// Calls the security modules to determine if task `from` is allowed to send binder objects
+/// (owned by itself or other processes) to task `to` through a binder transaction.
+pub fn binder_transfer_binder(from: &Credential, to: &Credential) -> Result {
+    // SAFETY: By the `Credential` invariants, `from.ptr` and `to.ptr` are valid.
+    to_result(|| unsafe { bindings::security_binder_transfer_binder(from.ptr, to.ptr) })
+}
+
+/// Calls the security modules to determine if task `from` is allowed to send the given file to
+/// task `to` (which would get its own file descriptor) through a binder transaction.
+pub fn binder_transfer_file(from: &Credential, to: &Credential, file: &File) -> Result {
+    // SAFETY: By the `Credential` invariants, `from.ptr` and `to.ptr` are valid. Similarly, by the
+    // `File` invariants, `file.ptr` is also valid.
+    to_result(|| unsafe { bindings::security_binder_transfer_file(from.ptr, to.ptr, file.ptr) })
+}
diff --git a/rust/kernel/static_assert.rs b/rust/kernel/static_assert.rs
new file mode 100644
index 000000000000..a80d8ab57564
--- /dev/null
+++ b/rust/kernel/static_assert.rs
@@ -0,0 +1,39 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Static assert.
+
+/// Static assert (i.e. compile-time assert).
+///
+/// Similar to C11 [`_Static_assert`] and C++11 [`static_assert`].
+///
+/// The feature may be added to Rust in the future: see [RFC 2790].
+///
+/// [`_Static_assert`]: https://en.cppreference.com/w/c/language/_Static_assert
+/// [`static_assert`]: https://en.cppreference.com/w/cpp/language/static_assert
+/// [RFC 2790]: https://github.com/rust-lang/rfcs/issues/2790
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::prelude::*;
+/// static_assert!(42 > 24);
+/// static_assert!(core::mem::size_of::<u8>() == 1);
+///
+/// const X: &[u8] = b"bar";
+/// static_assert!(X[1] == 'a' as u8);
+///
+/// const fn f(x: i32) -> i32 {
+///     x + 2
+/// }
+/// static_assert!(f(40) == 42);
+/// ```
+#[macro_export]
+macro_rules! static_assert {
+    ($condition:expr) => {
+        // Based on the latest one in `rustc`'s one before it was [removed].
+        //
+        // [removed]: https://github.com/rust-lang/rust/commit/c2dad1c6b9f9636198d7c561b47a2974f5103f6d
+        #[allow(dead_code)]
+        const _: () = [()][!($condition) as usize];
+    };
+}
diff --git a/rust/kernel/std_vendor.rs b/rust/kernel/std_vendor.rs
new file mode 100644
index 000000000000..492388d7ce10
--- /dev/null
+++ b/rust/kernel/std_vendor.rs
@@ -0,0 +1,150 @@
+// SPDX-License-Identifier: Apache-2.0 OR MIT
+
+//! The contents of this file come from the Rust standard library, hosted in the
+//! <https://github.com/rust-lang/rust> repository. For copyright details, see
+//! <https://github.com/rust-lang/rust/blob/master/COPYRIGHT>.
+
+/// [`std::dbg`], but using [`pr_info`] instead of [`eprintln`].
+///
+/// Prints and returns the value of a given expression for quick and dirty
+/// debugging.
+///
+/// An example:
+///
+/// ```rust
+/// let a = 2;
+/// let b = dbg!(a * 2) + 1;
+/// //      ^-- prints: [src/main.rs:2] a * 2 = 4
+/// assert_eq!(b, 5);
+/// ```
+///
+/// The macro works by using the `Debug` implementation of the type of
+/// the given expression to print the value with [`printk`] along with the
+/// source location of the macro invocation as well as the source code
+/// of the expression.
+///
+/// Invoking the macro on an expression moves and takes ownership of it
+/// before returning the evaluated expression unchanged. If the type
+/// of the expression does not implement `Copy` and you don't want
+/// to give up ownership, you can instead borrow with `dbg!(&expr)`
+/// for some expression `expr`.
+///
+/// The `dbg!` macro works exactly the same in release builds.
+/// This is useful when debugging issues that only occur in release
+/// builds or when debugging in release mode is significantly faster.
+///
+/// Note that the macro is intended as a debugging tool and therefore you
+/// should avoid having uses of it in version control for long periods
+/// (other than in tests and similar).
+///
+/// # Stability
+///
+/// The exact output printed by this macro should not be relied upon
+/// and is subject to future changes.
+///
+/// # Further examples
+///
+/// With a method call:
+///
+/// ```rust
+/// fn foo(n: usize) {
+///     if let Some(_) = dbg!(n.checked_sub(4)) {
+///         // ...
+///     }
+/// }
+///
+/// foo(3)
+/// ```
+///
+/// This prints to the kernel log:
+///
+/// ```text,ignore
+/// [src/main.rs:4] n.checked_sub(4) = None
+/// ```
+///
+/// Naive factorial implementation:
+///
+/// ```rust
+/// fn factorial(n: u32) -> u32 {
+///     if dbg!(n <= 1) {
+///         dbg!(1)
+///     } else {
+///         dbg!(n * factorial(n - 1))
+///     }
+/// }
+///
+/// dbg!(factorial(4));
+/// ```
+///
+/// This prints to the kernel log:
+///
+/// ```text,ignore
+/// [src/main.rs:3] n <= 1 = false
+/// [src/main.rs:3] n <= 1 = false
+/// [src/main.rs:3] n <= 1 = false
+/// [src/main.rs:3] n <= 1 = true
+/// [src/main.rs:4] 1 = 1
+/// [src/main.rs:5] n * factorial(n - 1) = 2
+/// [src/main.rs:5] n * factorial(n - 1) = 6
+/// [src/main.rs:5] n * factorial(n - 1) = 24
+/// [src/main.rs:11] factorial(4) = 24
+/// ```
+///
+/// The `dbg!(..)` macro moves the input:
+///
+/// ```compile_fail
+/// /// A wrapper around `usize` which importantly is not Copyable.
+/// #[derive(Debug)]
+/// struct NoCopy(usize);
+///
+/// let a = NoCopy(42);
+/// let _ = dbg!(a); // <-- `a` is moved here.
+/// let _ = dbg!(a); // <-- `a` is moved again; error!
+/// ```
+///
+/// You can also use `dbg!()` without a value to just print the
+/// file and line whenever it's reached.
+///
+/// Finally, if you want to `dbg!(..)` multiple values, it will treat them as
+/// a tuple (and return it, too):
+///
+/// ```
+/// assert_eq!(dbg!(1usize, 2u32), (1, 2));
+/// ```
+///
+/// However, a single argument with a trailing comma will still not be treated
+/// as a tuple, following the convention of ignoring trailing commas in macro
+/// invocations. You can use a 1-tuple directly if you need one:
+///
+/// ```
+/// assert_eq!(1, dbg!(1u32,)); // trailing comma ignored
+/// assert_eq!((1,), dbg!((1u32,))); // 1-tuple
+/// ```
+///
+/// [`std::dbg`]: https://doc.rust-lang.org/std/macro.dbg.html
+/// [`eprintln`]: https://doc.rust-lang.org/std/macro.eprintln.html
+/// [`printk`]: https://www.kernel.org/doc/html/latest/core-api/printk-basics.html
+#[macro_export]
+macro_rules! dbg {
+    // NOTE: We cannot use `concat!` to make a static string as a format argument
+    // of `pr_info!` because `file!` could contain a `{` or
+    // `$val` expression could be a block (`{ .. }`), in which case the `pr_info!`
+    // will be malformed.
+    () => {
+        $crate::pr_info!("[{}:{}]\n", ::core::file!(), ::core::line!())
+    };
+    ($val:expr $(,)?) => {
+        // Use of `match` here is intentional because it affects the lifetimes
+        // of temporaries - https://stackoverflow.com/a/48732525/1063961
+        match $val {
+            tmp => {
+                $crate::pr_info!("[{}:{}] {} = {:#?}\n",
+                    ::core::file!(), ::core::line!(), ::core::stringify!($val), &tmp);
+                tmp
+            }
+        }
+    };
+    ($($val:expr),+ $(,)?) => {
+        ($($crate::dbg!($val)),+,)
+    };
+}
diff --git a/rust/kernel/str.rs b/rust/kernel/str.rs
new file mode 100644
index 000000000000..840099f384b3
--- /dev/null
+++ b/rust/kernel/str.rs
@@ -0,0 +1,375 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! String representations.
+
+use core::fmt::{self, Write};
+use core::ops::{self, Deref, Index};
+
+use crate::bindings;
+use crate::c_types;
+
+/// Byte string without UTF-8 validity guarantee.
+///
+/// `BStr` is simply an alias to `[u8]`, but has a more evident semantical meaning.
+pub type BStr = [u8];
+
+/// Creates a new [`BStr`] from a string literal.
+///
+/// `b_str!` converts the supplied string literal to byte string, so non-ASCII
+/// characters can be included.
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::b_str;
+/// # use kernel::str::BStr;
+/// const MY_BSTR: &'static BStr = b_str!("My awesome BStr!");
+/// ```
+#[macro_export]
+macro_rules! b_str {
+    ($str:literal) => {{
+        const S: &'static str = $str;
+        const C: &'static $crate::str::BStr = S.as_bytes();
+        C
+    }};
+}
+
+/// Possible errors when using conversion functions in [`CStr`].
+#[derive(Debug, Clone, Copy)]
+pub enum CStrConvertError {
+    /// Supplied bytes contain an interior `NUL`.
+    InteriorNul,
+
+    /// Supplied bytes are not terminated by `NUL`.
+    NotNulTerminated,
+}
+
+impl From<CStrConvertError> for crate::Error {
+    #[inline]
+    fn from(_: CStrConvertError) -> crate::Error {
+        crate::Error::EINVAL
+    }
+}
+
+/// A string that is guaranteed to have exactly one `NUL` byte, which is at the
+/// end.
+///
+/// Used for interoperability with kernel APIs that take C strings.
+#[repr(transparent)]
+pub struct CStr([u8]);
+
+impl CStr {
+    /// Returns the length of this string excluding `NUL`.
+    #[inline]
+    pub const fn len(&self) -> usize {
+        self.len_with_nul() - 1
+    }
+
+    /// Returns the length of this string with `NUL`.
+    #[inline]
+    pub const fn len_with_nul(&self) -> usize {
+        // SAFETY: This is one of the invariant of `CStr`.
+        // We add a `unreachable_unchecked` here to hint the optimizer that
+        // the value returned from this function is non-zero.
+        if self.0.is_empty() {
+            unsafe { core::hint::unreachable_unchecked() };
+        }
+        self.0.len()
+    }
+
+    /// Returns `true` if the string only includes `NUL`.
+    #[inline]
+    pub const fn is_empty(&self) -> bool {
+        self.len() == 0
+    }
+
+    /// Wraps a raw C string pointer.
+    ///
+    /// # Safety
+    ///
+    /// `ptr` must be a valid pointer to a `NUL`-terminated C string, and it must
+    /// last at least `'a`. When `CStr` is alive, the memory pointed by `ptr`
+    /// must not be mutated.
+    #[inline]
+    pub unsafe fn from_char_ptr<'a>(ptr: *const c_types::c_char) -> &'a Self {
+        // SAFETY: The safety precondition guarantees `ptr` is a valid pointer
+        // to a `NUL`-terminated C string.
+        let len = unsafe { bindings::strlen(ptr) } + 1;
+        // SAFETY: Lifetime guaranteed by the safety precondition.
+        let bytes = unsafe { core::slice::from_raw_parts(ptr as _, len as _) };
+        // SAFETY: As `len` is returned by `strlen`, `bytes` does not contain interior `NUL`.
+        // As we have added 1 to `len`, the last byte is known to be `NUL`.
+        unsafe { Self::from_bytes_with_nul_unchecked(bytes) }
+    }
+
+    /// Creates a [`CStr`] from a `[u8]`.
+    ///
+    /// The provided slice must be `NUL`-terminated, does not contain any
+    /// interior `NUL` bytes.
+    pub const fn from_bytes_with_nul(bytes: &[u8]) -> Result<&Self, CStrConvertError> {
+        if bytes.is_empty() {
+            return Err(CStrConvertError::NotNulTerminated);
+        }
+        if bytes[bytes.len() - 1] != 0 {
+            return Err(CStrConvertError::NotNulTerminated);
+        }
+        let mut i = 0;
+        // `i + 1 < bytes.len()` allows LLVM to optimize away bounds checking,
+        // while it couldn't optimize away bounds checks for `i < bytes.len() - 1`.
+        while i + 1 < bytes.len() {
+            if bytes[i] == 0 {
+                return Err(CStrConvertError::InteriorNul);
+            }
+            i += 1;
+        }
+        // SAFETY: We just checked that all properties hold.
+        Ok(unsafe { Self::from_bytes_with_nul_unchecked(bytes) })
+    }
+
+    /// Creates a [`CStr`] from a `[u8]`, panic if input is not valid.
+    ///
+    /// This function is only meant to be used by `c_str!` macro, so
+    /// crates using `c_str!` macro don't have to enable `const_panic` feature.
+    #[doc(hidden)]
+    pub const fn from_bytes_with_nul_unwrap(bytes: &[u8]) -> &Self {
+        match Self::from_bytes_with_nul(bytes) {
+            Ok(v) => v,
+            Err(_) => panic!("string contains interior NUL"),
+        }
+    }
+
+    /// Creates a [`CStr`] from a `[u8]` without performing any additional
+    /// checks.
+    ///
+    /// # Safety
+    ///
+    /// `bytes` *must* end with a `NUL` byte, and should only have a single
+    /// `NUL` byte (or the string will be truncated).
+    #[inline]
+    pub const unsafe fn from_bytes_with_nul_unchecked(bytes: &[u8]) -> &CStr {
+        // SAFETY: Properties of `bytes` guaranteed by the safety precondition.
+        unsafe { core::mem::transmute(bytes) }
+    }
+
+    /// Returns a C pointer to the string.
+    #[inline]
+    pub const fn as_char_ptr(&self) -> *const c_types::c_char {
+        self.0.as_ptr() as _
+    }
+
+    /// Convert the string to a byte slice without the trailing 0 byte.
+    #[inline]
+    pub fn as_bytes(&self) -> &[u8] {
+        &self.0[..self.len()]
+    }
+
+    /// Convert the string to a byte slice containing the trailing 0 byte.
+    #[inline]
+    pub const fn as_bytes_with_nul(&self) -> &[u8] {
+        &self.0
+    }
+
+    /// Yields a [`&str`] slice if the [`CStr`] contains valid UTF-8.
+    ///
+    /// If the contents of the [`CStr`] are valid UTF-8 data, this
+    /// function will return the corresponding [`&str`] slice. Otherwise,
+    /// it will return an error with details of where UTF-8 validation failed.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # use kernel::str::CStr;
+    /// let cstr = CStr::from_bytes_with_nul(b"foo\0").unwrap();
+    /// assert_eq!(cstr.to_str(), Ok("foo"));
+    /// ```
+    #[inline]
+    pub fn to_str(&self) -> Result<&str, core::str::Utf8Error> {
+        core::str::from_utf8(self.as_bytes())
+    }
+
+    /// Unsafely convert this [`CStr`] into a [`&str`], without checking for
+    /// valid UTF-8.
+    ///
+    /// # Safety
+    ///
+    /// The contents must be valid UTF-8.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # use kernel::c_str;
+    /// # use kernel::str::CStr;
+    /// // SAFETY: String literals are guaranteed to be valid UTF-8
+    /// // by the Rust compiler.
+    /// let bar = c_str!("ツ");
+    /// assert_eq!(unsafe { bar.as_str_unchecked() }, "ツ");
+    /// ```
+    #[inline]
+    pub unsafe fn as_str_unchecked(&self) -> &str {
+        unsafe { core::str::from_utf8_unchecked(self.as_bytes()) }
+    }
+}
+
+impl fmt::Display for CStr {
+    /// Formats printable ASCII characters, escaping the rest.
+    ///
+    /// ```
+    /// # use kernel::c_str;
+    /// # use kernel::str::CStr;
+    /// let penguin = c_str!("🐧");
+    /// assert_eq!(format!("{}", penguin), "\\xf0\\x9f\\x90\\xa7");
+    ///
+    /// let ascii = c_str!("so \"cool\"");
+    /// assert_eq!(format!("{}", ascii), "so \"cool\"");
+    /// ```
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        for &c in self.as_bytes() {
+            if (0x20..0x7f).contains(&c) {
+                // Printable character
+                f.write_char(c as char)?;
+            } else {
+                write!(f, "\\x{:02x}", c)?;
+            }
+        }
+        Ok(())
+    }
+}
+
+impl fmt::Debug for CStr {
+    /// Formats printable ASCII characters with a double quote on either end, escaping the rest.
+    ///
+    /// ```
+    /// # use kernel::c_str;
+    /// # use kernel::str::CStr;
+    /// let penguin = c_str!("🐧");
+    /// assert_eq!(format!("{:?}", penguin), "\"\\xf0\\x9f\\x90\\xa7\"");
+    ///
+    /// // embedded double quotes are escaped
+    /// let ascii = c_str!("so \"cool\"");
+    /// assert_eq!(format!("{:?}", ascii), "\"so \\\"cool\\\"\"");
+    /// ```
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.write_str("\"")?;
+        for &c in self.as_bytes() {
+            match c {
+                // Printable characters
+                b'\"' => f.write_str("\\\"")?,
+                0x20..=0x7e => f.write_char(c as char)?,
+                _ => write!(f, "\\x{:02x}", c)?,
+            }
+        }
+        f.write_str("\"")
+    }
+}
+
+impl AsRef<BStr> for CStr {
+    #[inline]
+    fn as_ref(&self) -> &BStr {
+        self.as_bytes()
+    }
+}
+
+impl Deref for CStr {
+    type Target = BStr;
+
+    #[inline]
+    fn deref(&self) -> &Self::Target {
+        self.as_bytes()
+    }
+}
+
+impl Index<ops::RangeFrom<usize>> for CStr {
+    type Output = CStr;
+
+    #[inline]
+    fn index(&self, index: ops::RangeFrom<usize>) -> &Self::Output {
+        // Delegate bounds checking to slice.
+        // Assign to _ to mute clippy's unnecessary operation warning.
+        let _ = &self.as_bytes()[index.start..];
+        // SAFETY: We just checked the bounds.
+        unsafe { Self::from_bytes_with_nul_unchecked(&self.0[index.start..]) }
+    }
+}
+
+impl Index<ops::RangeFull> for CStr {
+    type Output = CStr;
+
+    #[inline]
+    fn index(&self, _index: ops::RangeFull) -> &Self::Output {
+        self
+    }
+}
+
+mod private {
+    use core::ops;
+
+    //  Marker trait for index types that can be forward to `BStr`.
+    pub trait CStrIndex {}
+
+    impl CStrIndex for usize {}
+    impl CStrIndex for ops::Range<usize> {}
+    impl CStrIndex for ops::RangeInclusive<usize> {}
+    impl CStrIndex for ops::RangeToInclusive<usize> {}
+}
+
+impl<Idx> Index<Idx> for CStr
+where
+    Idx: private::CStrIndex,
+    BStr: Index<Idx>,
+{
+    type Output = <BStr as Index<Idx>>::Output;
+
+    #[inline]
+    fn index(&self, index: Idx) -> &Self::Output {
+        &self.as_bytes()[index]
+    }
+}
+
+/// Creates a new [`CStr`] from a string literal.
+///
+/// The string literal should not contain any `NUL` bytes.
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::c_str;
+/// # use kernel::str::CStr;
+/// const MY_CSTR: &'static CStr = c_str!("My awesome CStr!");
+/// ```
+#[macro_export]
+macro_rules! c_str {
+    ($str:literal) => {{
+        const S: &str = concat!($str, "\0");
+        const C: &$crate::str::CStr = $crate::str::CStr::from_bytes_with_nul_unwrap(S.as_bytes());
+        C
+    }};
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn test_cstr_to_str() {
+        let good_bytes = b"\xf0\x9f\xa6\x80\0";
+        let checked_cstr = CStr::from_bytes_with_nul(good_bytes).unwrap();
+        let checked_str = checked_cstr.to_str().unwrap();
+        assert_eq!(checked_str, "🦀");
+    }
+
+    #[test]
+    #[should_panic]
+    fn test_cstr_to_str_panic() {
+        let bad_bytes = b"\xc3\x28\0";
+        let checked_cstr = CStr::from_bytes_with_nul(bad_bytes).unwrap();
+        checked_cstr.to_str().unwrap();
+    }
+
+    #[test]
+    fn test_cstr_as_str_unchecked() {
+        let good_bytes = b"\xf0\x9f\x90\xA7\0";
+        let checked_cstr = CStr::from_bytes_with_nul(good_bytes).unwrap();
+        let unchecked_str = unsafe { checked_cstr.as_str_unchecked() };
+        assert_eq!(unchecked_str, "🐧");
+    }
+}
diff --git a/rust/kernel/sync/arc.rs b/rust/kernel/sync/arc.rs
new file mode 100644
index 000000000000..7ca921fb5d1d
--- /dev/null
+++ b/rust/kernel/sync/arc.rs
@@ -0,0 +1,500 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! A reference-counted pointer.
+//!
+//! This module implements a way for users to create reference-counted objects and pointers to
+//! them. Such a pointer automatically increments and decrements the count, and drops the
+//! underlying object when it reaches zero. It is also safe to use concurrently from multiple
+//! threads.
+//!
+//! It is different from the standard library's [`Arc`] in a few ways:
+//! 1. It is backed by the kernel's `refcount_t` type.
+//! 2. It does not support weak references, which allows it to be half the size.
+//! 3. It saturates the reference count instead of aborting when it goes over a threshold.
+//! 4. It does not provide a `get_mut` method, so the ref counted object is pinned.
+//!
+//! [`Arc`]: https://doc.rust-lang.org/std/sync/struct.Arc.html
+
+use crate::{bindings, Error, Opaque, Result};
+use alloc::{
+    alloc::{alloc, dealloc},
+    vec::Vec,
+};
+use core::{
+    alloc::Layout,
+    convert::{AsRef, TryFrom},
+    marker::{PhantomData, Unsize},
+    mem::{ManuallyDrop, MaybeUninit},
+    ops::{Deref, DerefMut},
+    pin::Pin,
+    ptr::{self, NonNull},
+};
+
+/// A reference-counted pointer to an instance of `T`.
+///
+/// The reference count is incremented when new instances of [`Ref`] are created, and decremented
+/// when they are dropped. When the count reaches zero, the underlying `T` is also dropped.
+///
+/// # Invariants
+///
+/// The reference count on an instance of [`Ref`] is always non-zero.
+/// The object pointed to by [`Ref`] is always pinned.
+pub struct Ref<T: ?Sized> {
+    ptr: NonNull<RefInner<T>>,
+    _p: PhantomData<RefInner<T>>,
+}
+
+#[repr(C)]
+struct RefInner<T: ?Sized> {
+    refcount: Opaque<bindings::refcount_t>,
+    data: T,
+}
+
+// This is to allow [`Ref`] (and variants) to be used as the type of `self`.
+impl<T: ?Sized> core::ops::Receiver for Ref<T> {}
+
+// This is to allow [`RefBorrow`] (and variants) to be used as the type of `self`.
+impl<T: ?Sized> core::ops::Receiver for RefBorrow<'_, T> {}
+
+// This is to allow coercion from `Ref<T>` to `Ref<U>` if `T` can be converted to the
+// dynamically-sized type (DST) `U`.
+impl<T: ?Sized + Unsize<U>, U: ?Sized> core::ops::CoerceUnsized<Ref<U>> for Ref<T> {}
+
+// This is to allow `Ref<U>` to be dispatched on when `Ref<T>` can be coerced into `Ref<U>`.
+impl<T: ?Sized + Unsize<U>, U: ?Sized> core::ops::DispatchFromDyn<Ref<U>> for Ref<T> {}
+
+// SAFETY: It is safe to send `Ref<T>` to another thread when the underlying `T` is `Sync` because
+// it effectively means sharing `&T` (which is safe because `T` is `Sync`); additionally, it needs
+// `T` to be `Send` because any thread that has a `Ref<T>` may ultimately access `T` directly, for
+// example, when the reference count reaches zero and `T` is dropped.
+unsafe impl<T: ?Sized + Sync + Send> Send for Ref<T> {}
+
+// SAFETY: It is safe to send `&Ref<T>` to another thread when the underlying `T` is `Sync` for
+// the same reason as above. `T` needs to be `Send` as well because a thread can clone a `&Ref<T>`
+// into a `Ref<T>`, which may lead to `T` being accessed by the same reasoning as above.
+unsafe impl<T: ?Sized + Sync + Send> Sync for Ref<T> {}
+
+impl<T> Ref<T> {
+    /// Constructs a new reference counted instance of `T`.
+    pub fn try_new(contents: T) -> Result<Self> {
+        let layout = Layout::new::<RefInner<T>>();
+        // SAFETY: The layout size is guaranteed to be non-zero because `RefInner` contains the
+        // reference count.
+        let inner = NonNull::new(unsafe { alloc(layout) })
+            .ok_or(Error::ENOMEM)?
+            .cast::<RefInner<T>>();
+
+        // INVARIANT: The refcount is initialised to a non-zero value.
+        let value = RefInner {
+            // SAFETY: Just an FFI call that returns a `refcount_t` initialised to 1.
+            refcount: Opaque::new(unsafe { bindings::REFCOUNT_INIT(1) }),
+            data: contents,
+        };
+        // SAFETY: `inner` is writable and properly aligned.
+        unsafe { inner.as_ptr().write(value) };
+
+        // SAFETY: We just created `inner` with a reference count of 1, which is owned by the new
+        // `Ref` object.
+        Ok(unsafe { Self::from_inner(inner) })
+    }
+
+    /// Deconstructs a [`Ref`] object into a `usize`.
+    ///
+    /// It can be reconstructed once via [`Ref::from_usize`].
+    pub fn into_usize(obj: Self) -> usize {
+        ManuallyDrop::new(obj).ptr.as_ptr() as _
+    }
+
+    /// Borrows a [`Ref`] instance previously deconstructed via [`Ref::into_usize`].
+    ///
+    /// # Safety
+    ///
+    /// `encoded` must have been returned by a previous call to [`Ref::into_usize`]. Additionally,
+    /// [`Ref::from_usize`] can only be called after *all* instances of [`RefBorrow`] have been
+    /// dropped.
+    pub unsafe fn borrow_usize<'a>(encoded: usize) -> RefBorrow<'a, T> {
+        // SAFETY: By the safety requirement of this function, we know that `encoded` came from
+        // a previous call to `Ref::into_usize`.
+        let inner = NonNull::new(encoded as *mut RefInner<T>).unwrap();
+
+        // SAFETY: The safety requirements ensure that the object remains alive for the lifetime of
+        // the returned value. There is no way to create mutable references to the object.
+        unsafe { RefBorrow::new(inner) }
+    }
+
+    /// Recreates a [`Ref`] instance previously deconstructed via [`Ref::into_usize`].
+    ///
+    /// # Safety
+    ///
+    /// `encoded` must have been returned by a previous call to [`Ref::into_usize`]. Additionally,
+    /// it can only be called once for each previous call to [``Ref::into_usize`].
+    pub unsafe fn from_usize(encoded: usize) -> Self {
+        // SAFETY: By the safety invariants we know that `encoded` came from `Ref::into_usize`, so
+        // the reference count held then will be owned by the new `Ref` object.
+        unsafe { Self::from_inner(NonNull::new(encoded as _).unwrap()) }
+    }
+}
+
+impl<T: ?Sized> Ref<T> {
+    /// Constructs a new [`Ref`] from an existing [`RefInner`].
+    ///
+    /// # Safety
+    ///
+    /// The caller must ensure that `inner` points to a valid location and has a non-zero reference
+    /// count, one of which will be owned by the new [`Ref`] instance.
+    unsafe fn from_inner(inner: NonNull<RefInner<T>>) -> Self {
+        // INVARIANT: By the safety requirements, the invariants hold.
+        Ref {
+            ptr: inner,
+            _p: PhantomData,
+        }
+    }
+
+    /// Determines if two reference-counted pointers point to the same underlying instance of `T`.
+    pub fn ptr_eq(a: &Self, b: &Self) -> bool {
+        ptr::eq(a.ptr.as_ptr(), b.ptr.as_ptr())
+    }
+
+    /// Deconstructs a [`Ref`] object into a raw pointer.
+    ///
+    /// It can be reconstructed once via [`Ref::from_raw`].
+    pub fn into_raw(obj: Self) -> *const T {
+        let ret = &*obj as *const T;
+        core::mem::forget(obj);
+        ret
+    }
+
+    /// Recreates a [`Ref`] instance previously deconstructed via [`Ref::into_raw`].
+    ///
+    /// This code relies on the `repr(C)` layout of structs as described in
+    /// <https://doc.rust-lang.org/reference/type-layout.html#reprc-structs>.
+    ///
+    /// # Safety
+    ///
+    /// `ptr` must have been returned by a previous call to [`Ref::into_raw`]. Additionally, it
+    /// can only be called once for each previous call to [``Ref::into_raw`].
+    pub unsafe fn from_raw(ptr: *const T) -> Self {
+        // SAFETY: The safety requirement ensures that the pointer is valid.
+        let align = core::mem::align_of_val(unsafe { &*ptr });
+        let offset = Layout::new::<RefInner<()>>()
+            .align_to(align)
+            .unwrap()
+            .pad_to_align()
+            .size();
+        // SAFETY: The pointer is in bounds because by the safety requirements `ptr` came from
+        // `Ref::into_raw`, so it is a pointer `offset` bytes from the beginning of the allocation.
+        let data = unsafe { (ptr as *const u8).sub(offset) };
+        let metadata = ptr::metadata(ptr as *const RefInner<T>);
+        let ptr = ptr::from_raw_parts_mut(data as _, metadata);
+        // SAFETY: By the safety requirements we know that `ptr` came from `Ref::into_raw`, so the
+        // reference count held then will be owned by the new `Ref` object.
+        unsafe { Self::from_inner(NonNull::new(ptr).unwrap()) }
+    }
+
+    /// Returns a [`RefBorrow`] from the given [`Ref`].
+    ///
+    /// This is useful when the argument of a function call is a [`RefBorrow`] (e.g., in a method
+    /// receiver), but we have a [`Ref`] instead. Getting a [`RefBorrow`] is free when optimised.
+    #[inline]
+    pub fn as_ref_borrow(&self) -> RefBorrow<'_, T> {
+        // SAFETY: The constraint that lifetime of the shared reference must outlive that of
+        // the returned `RefBorrow` ensures that the object remains alive.
+        unsafe { RefBorrow::new(self.ptr) }
+    }
+}
+
+impl<T: ?Sized> Deref for Ref<T> {
+    type Target = T;
+
+    fn deref(&self) -> &Self::Target {
+        // SAFETY: By the type invariant, there is necessarily a reference to the object, so it is
+        // safe to dereference it.
+        unsafe { &self.ptr.as_ref().data }
+    }
+}
+
+impl<T: ?Sized> Clone for Ref<T> {
+    fn clone(&self) -> Self {
+        // INVARIANT: C `refcount_inc` saturates the refcount, so it cannot overflow to zero.
+        // SAFETY: By the type invariant, there is necessarily a reference to the object, so it is
+        // safe to increment the refcount.
+        unsafe { bindings::refcount_inc(self.ptr.as_ref().refcount.get()) };
+
+        // SAFETY: We just incremented the refcount. This increment is now owned by the new `Ref`.
+        unsafe { Self::from_inner(self.ptr) }
+    }
+}
+
+impl<T: ?Sized> AsRef<T> for Ref<T> {
+    fn as_ref(&self) -> &T {
+        // SAFETY: By the type invariant, there is necessarily a reference to the object, so it is
+        // safe to dereference it.
+        unsafe { &self.ptr.as_ref().data }
+    }
+}
+
+impl<T: ?Sized> Drop for Ref<T> {
+    fn drop(&mut self) {
+        // SAFETY: By the type invariant, there is necessarily a reference to the object. We cannot
+        // touch `refcount` after it's decremented to a non-zero value because another thread/CPU
+        // may concurrently decrement it to zero and free it. It is ok to have a raw pointer to
+        // freed/invalid memory as long as it is never dereferenced.
+        let refcount = unsafe { self.ptr.as_ref() }.refcount.get();
+
+        // INVARIANT: If the refcount reaches zero, there are no other instances of `Ref`, and
+        // this instance is being dropped, so the broken invariant is not observable.
+        // SAFETY: Also by the type invariant, we are allowed to decrement the refcount.
+        let is_zero = unsafe { bindings::refcount_dec_and_test(refcount) };
+        if is_zero {
+            // The count reached zero, we must free the memory.
+
+            // SAFETY: This thread holds the only remaining reference to `self`, so it is safe to
+            // get a mutable reference to it.
+            let inner = unsafe { self.ptr.as_mut() };
+            let layout = Layout::for_value(inner);
+            // SAFETY: The value stored in inner is valid.
+            unsafe { core::ptr::drop_in_place(inner) };
+            // SAFETY: The pointer was initialised from the result of a call to `alloc`.
+            unsafe { dealloc(self.ptr.cast().as_ptr(), layout) };
+        }
+    }
+}
+
+impl<T> TryFrom<Vec<T>> for Ref<[T]> {
+    type Error = Error;
+
+    fn try_from(mut v: Vec<T>) -> Result<Self> {
+        let value_layout = Layout::array::<T>(v.len())?;
+        let layout = Layout::new::<RefInner<()>>()
+            .extend(value_layout)?
+            .0
+            .pad_to_align();
+        // SAFETY: The layout size is guaranteed to be non-zero because `RefInner` contains the
+        // reference count.
+        let ptr = NonNull::new(unsafe { alloc(layout) }).ok_or(Error::ENOMEM)?;
+        let inner =
+            core::ptr::slice_from_raw_parts_mut(ptr.as_ptr() as _, v.len()) as *mut RefInner<[T]>;
+
+        // SAFETY: Just an FFI call that returns a `refcount_t` initialised to 1.
+        let count = Opaque::new(unsafe { bindings::REFCOUNT_INIT(1) });
+        // SAFETY: `inner.refcount` is writable and properly aligned.
+        unsafe { core::ptr::addr_of_mut!((*inner).refcount).write(count) };
+        // SAFETY: The contents of `v` as readable and properly aligned; `inner.data` is writable
+        // and properly aligned. There is no overlap between the two because `inner` is a new
+        // allocation.
+        unsafe {
+            core::ptr::copy_nonoverlapping(
+                v.as_ptr(),
+                core::ptr::addr_of_mut!((*inner).data) as *mut [T] as *mut T,
+                v.len(),
+            )
+        };
+        // SAFETY: We're setting the new length to zero, so it is <= to capacity, and old_len..0 is
+        // an empty range (so satisfies vacuously the requirement of being initialised).
+        unsafe { v.set_len(0) };
+        // SAFETY: We just created `inner` with a reference count of 1, which is owned by the new
+        // `Ref` object.
+        Ok(unsafe { Self::from_inner(NonNull::new(inner).unwrap()) })
+    }
+}
+
+impl<T: ?Sized> From<UniqueRef<T>> for Ref<T> {
+    fn from(item: UniqueRef<T>) -> Self {
+        item.inner
+    }
+}
+
+impl<T: ?Sized> From<UniqueRef<T>> for Pin<UniqueRef<T>> {
+    fn from(obj: UniqueRef<T>) -> Self {
+        // SAFETY: It is not possible to move/replace `T` inside a `Pin<UniqueRef<T>>` (unless `T`
+        // is `Unpin`), so it is ok to convert it to `Pin<UniqueRef<T>>`.
+        unsafe { Pin::new_unchecked(obj) }
+    }
+}
+
+impl<T: ?Sized> From<Pin<UniqueRef<T>>> for Ref<T> {
+    fn from(item: Pin<UniqueRef<T>>) -> Self {
+        // SAFETY: The type invariants of `Ref` guarantee that the data is pinned.
+        unsafe { Pin::into_inner_unchecked(item).inner }
+    }
+}
+
+/// A borrowed [`Ref`] with manually-managed lifetime.
+///
+/// # Invariants
+///
+/// There are no mutable references to the underlying [`Ref`], and it remains valid for the lifetime
+/// of the [`RefBorrow`] instance.
+pub struct RefBorrow<'a, T: ?Sized + 'a> {
+    inner: NonNull<RefInner<T>>,
+    _p: PhantomData<&'a ()>,
+}
+
+impl<T: ?Sized> Clone for RefBorrow<'_, T> {
+    fn clone(&self) -> Self {
+        *self
+    }
+}
+
+impl<T: ?Sized> Copy for RefBorrow<'_, T> {}
+
+impl<T: ?Sized> RefBorrow<'_, T> {
+    /// Creates a new [`RefBorrow`] instance.
+    ///
+    /// # Safety
+    ///
+    /// Callers must ensure the following for the lifetime of the returned [`RefBorrow`] instance:
+    /// 1. That `obj` remains valid;
+    /// 2. That no mutable references to `obj` are created.
+    unsafe fn new(inner: NonNull<RefInner<T>>) -> Self {
+        // INVARIANT: The safety requirements guarantee the invariants.
+        Self {
+            inner,
+            _p: PhantomData,
+        }
+    }
+}
+
+impl<T: ?Sized> From<RefBorrow<'_, T>> for Ref<T> {
+    fn from(b: RefBorrow<'_, T>) -> Self {
+        // SAFETY: The existence of `b` guarantees that the refcount is non-zero. `ManuallyDrop`
+        // guarantees that `drop` isn't called, so it's ok that the temporary `Ref` doesn't own the
+        // increment.
+        ManuallyDrop::new(unsafe { Ref::from_inner(b.inner) })
+            .deref()
+            .clone()
+    }
+}
+
+impl<T: ?Sized> Deref for RefBorrow<'_, T> {
+    type Target = T;
+
+    fn deref(&self) -> &Self::Target {
+        // SAFETY: By the type invariant, the underlying object is still alive with no mutable
+        // references to it, so it is safe to create a shared reference.
+        unsafe { &self.inner.as_ref().data }
+    }
+}
+
+/// A refcounted object that is known to have a refcount of 1.
+///
+/// It is mutable and can be converted to a [`Ref`] so that it can be shared.
+///
+/// # Invariants
+///
+/// `inner` always has a reference count of 1.
+///
+/// # Examples
+///
+/// In the following example, we make changes to the inner object before turning it into a
+/// `Ref<Test>` object (after which point, it cannot be mutated directly). Note that `x.into()`
+/// cannot fail.
+///
+/// ```
+/// # use kernel::prelude::*;
+/// use kernel::sync::{Ref, UniqueRef};
+///
+/// struct Example {
+///     a: u32,
+///     b: u32,
+/// }
+///
+/// fn test() -> Result<Ref<Example>> {
+///     let mut x = UniqueRef::try_new(Example { a: 10, b: 20 })?;
+///     x.a += 1;
+///     x.b += 1;
+///     Ok(x.into())
+/// }
+/// ```
+///
+/// In the following example we first allocate memory for a ref-counted `Example` but we don't
+/// initialise it on allocation. We do initialise it later with a call to [`UniqueRef::write`],
+/// followed by a conversion to `Ref<Example>`. This is particularly useful when allocation happens
+/// in one context (e.g., sleepable) and initialisation in another (e.g., atomic):
+///
+/// ```
+/// # use kernel::prelude::*;
+/// use kernel::sync::{Ref, UniqueRef};
+///
+/// struct Example {
+///     a: u32,
+///     b: u32,
+/// }
+///
+/// fn test2() -> Result<Ref<Example>> {
+///     let x = UniqueRef::try_new_uninit()?;
+///     Ok(x.write(Example { a: 10, b: 20 }).into())
+/// }
+/// ```
+///
+/// In the last example below, the caller gets a pinned instance of `Example` while converting to
+/// `Ref<Example>`; this is useful in scenarios where one needs a pinned reference during
+/// initialisation, for example, when initialising fields that are wrapped in locks.
+///
+/// ```
+/// # use kernel::prelude::*;
+/// use kernel::sync::{Ref, UniqueRef};
+///
+/// struct Example {
+///     a: u32,
+///     b: u32,
+/// }
+///
+/// fn test2() -> Result<Ref<Example>> {
+///     let mut pinned = Pin::from(UniqueRef::try_new(Example { a: 10, b: 20 })?);
+///     // We can modify `pinned` because it is `Unpin`.
+///     pinned.as_mut().a += 1;
+///     Ok(pinned.into())
+/// }
+/// ```
+pub struct UniqueRef<T: ?Sized> {
+    inner: Ref<T>,
+}
+
+impl<T> UniqueRef<T> {
+    /// Tries to allocate a new [`UniqueRef`] instance.
+    pub fn try_new(value: T) -> Result<Self> {
+        Ok(Self {
+            // INVARIANT: The newly-created object has a ref-count of 1.
+            inner: Ref::try_new(value)?,
+        })
+    }
+
+    /// Tries to allocate a new [`UniqueRef`] instance whose contents are not initialised yet.
+    pub fn try_new_uninit() -> Result<UniqueRef<MaybeUninit<T>>> {
+        Ok(UniqueRef::<MaybeUninit<T>> {
+            // INVARIANT: The newly-created object has a ref-count of 1.
+            inner: Ref::try_new(MaybeUninit::uninit())?,
+        })
+    }
+}
+
+impl<T> UniqueRef<MaybeUninit<T>> {
+    /// Converts a `UniqueRef<MaybeUninit<T>>` into a `UniqueRef<T>` by writing a value into it.
+    pub fn write(mut self, value: T) -> UniqueRef<T> {
+        self.deref_mut().write(value);
+        let inner = ManuallyDrop::new(self).inner.ptr;
+        UniqueRef {
+            // SAFETY: The new `Ref` is taking over `ptr` from `self.inner` (which won't be
+            // dropped). The types are compatible because `MaybeUninit<T>` is compatible with `T`.
+            inner: unsafe { Ref::from_inner(inner.cast()) },
+        }
+    }
+}
+
+impl<T: ?Sized> Deref for UniqueRef<T> {
+    type Target = T;
+
+    fn deref(&self) -> &Self::Target {
+        self.inner.deref()
+    }
+}
+
+impl<T: ?Sized> DerefMut for UniqueRef<T> {
+    fn deref_mut(&mut self) -> &mut Self::Target {
+        // SAFETY: By the `Ref` type invariant, there is necessarily a reference to the object, so
+        // it is safe to dereference it. Additionally, we know there is only one reference when
+        // it's inside a `UniqueRef`, so it is safe to get a mutable reference.
+        unsafe { &mut self.inner.ptr.as_mut().data }
+    }
+}
diff --git a/rust/kernel/sync/condvar.rs b/rust/kernel/sync/condvar.rs
new file mode 100644
index 000000000000..b60b7e418c73
--- /dev/null
+++ b/rust/kernel/sync/condvar.rs
@@ -0,0 +1,137 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! A condition variable.
+//!
+//! This module allows Rust code to use the kernel's [`struct wait_queue_head`] as a condition
+//! variable.
+
+use super::{GuardMut, Lock, NeedsLockClass};
+use crate::{bindings, str::CStr, task::Task, Opaque};
+use core::{marker::PhantomPinned, pin::Pin};
+
+/// Safely initialises a [`CondVar`] with the given name, generating a new lock class.
+#[macro_export]
+macro_rules! condvar_init {
+    ($condvar:expr, $name:literal) => {
+        $crate::init_with_lockdep!($condvar, $name)
+    };
+}
+
+// TODO: `bindgen` is not generating this constant. Figure out why.
+const POLLFREE: u32 = 0x4000;
+
+/// Exposes the kernel's [`struct wait_queue_head`] as a condition variable. It allows the caller to
+/// atomically release the given lock and go to sleep. It reacquires the lock when it wakes up. And
+/// it wakes up when notified by another thread (via [`CondVar::notify_one`] or
+/// [`CondVar::notify_all`]) or because the thread received a signal.
+///
+/// [`struct wait_queue_head`]: ../../../include/linux/wait.h
+pub struct CondVar {
+    pub(crate) wait_list: Opaque<bindings::wait_queue_head>,
+
+    /// A condvar needs to be pinned because it contains a [`struct list_head`] that is
+    /// self-referential, so it cannot be safely moved once it is initialised.
+    _pin: PhantomPinned,
+}
+
+// SAFETY: `CondVar` only uses a `struct wait_queue_head`, which is safe to use on any thread.
+unsafe impl Send for CondVar {}
+
+// SAFETY: `CondVar` only uses a `struct wait_queue_head`, which is safe to use on multiple threads
+// concurrently.
+unsafe impl Sync for CondVar {}
+
+impl CondVar {
+    /// Constructs a new conditional variable.
+    ///
+    /// # Safety
+    ///
+    /// The caller must call `CondVar::init` before using the conditional variable.
+    pub unsafe fn new() -> Self {
+        Self {
+            wait_list: Opaque::uninit(),
+            _pin: PhantomPinned,
+        }
+    }
+
+    /// Atomically releases the given lock (whose ownership is proven by the guard) and puts the
+    /// thread to sleep. It wakes up when notified by [`CondVar::notify_one`] or
+    /// [`CondVar::notify_all`], or when the thread receives a signal.
+    ///
+    /// Returns whether there is a signal pending.
+    #[must_use = "wait returns if a signal is pending, so the caller must check the return value"]
+    pub fn wait<L: Lock>(&self, guard: &mut GuardMut<'_, L>) -> bool {
+        let lock = guard.guard.lock;
+        let wait = Opaque::<bindings::wait_queue_entry>::uninit();
+
+        // SAFETY: `wait` points to valid memory.
+        unsafe { bindings::init_wait(wait.get()) };
+
+        // SAFETY: Both `wait` and `wait_list` point to valid memory.
+        unsafe {
+            bindings::prepare_to_wait_exclusive(
+                self.wait_list.get(),
+                wait.get(),
+                bindings::TASK_INTERRUPTIBLE as _,
+            )
+        };
+
+        // SAFETY: The guard is evidence that the caller owns the lock.
+        unsafe { lock.unlock(&mut guard.guard.context) };
+
+        // SAFETY: No arguments, switches to another thread.
+        unsafe { bindings::schedule() };
+
+        lock.relock(&mut guard.guard.context);
+
+        // SAFETY: Both `wait` and `wait_list` point to valid memory.
+        unsafe { bindings::finish_wait(self.wait_list.get(), wait.get()) };
+
+        Task::current().signal_pending()
+    }
+
+    /// Calls the kernel function to notify the appropriate number of threads with the given flags.
+    fn notify(&self, count: i32, flags: u32) {
+        // SAFETY: `wait_list` points to valid memory.
+        unsafe {
+            bindings::__wake_up(
+                self.wait_list.get(),
+                bindings::TASK_NORMAL,
+                count,
+                flags as _,
+            )
+        };
+    }
+
+    /// Wakes a single waiter up, if any. This is not 'sticky' in the sense that if no thread is
+    /// waiting, the notification is lost completely (as opposed to automatically waking up the
+    /// next waiter).
+    pub fn notify_one(&self) {
+        self.notify(1, 0);
+    }
+
+    /// Wakes all waiters up, if any. This is not 'sticky' in the sense that if no thread is
+    /// waiting, the notification is lost completely (as opposed to automatically waking up the
+    /// next waiter).
+    pub fn notify_all(&self) {
+        self.notify(0, 0);
+    }
+
+    /// Wakes all waiters up. If they were added by `epoll`, they are also removed from the list of
+    /// waiters. This is useful when cleaning up a condition variable that may be waited on by
+    /// threads that use `epoll`.
+    pub fn free_waiters(&self) {
+        self.notify(1, bindings::POLLHUP | POLLFREE);
+    }
+}
+
+impl NeedsLockClass for CondVar {
+    unsafe fn init(
+        self: Pin<&mut Self>,
+        name: &'static CStr,
+        key: *mut bindings::lock_class_key,
+        _: *mut bindings::lock_class_key,
+    ) {
+        unsafe { bindings::__init_waitqueue_head(self.wait_list.get(), name.as_char_ptr(), key) };
+    }
+}
diff --git a/rust/kernel/sync/guard.rs b/rust/kernel/sync/guard.rs
new file mode 100644
index 000000000000..9b0506a31fe7
--- /dev/null
+++ b/rust/kernel/sync/guard.rs
@@ -0,0 +1,181 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! A generic lock guard and trait.
+//!
+//! This module contains a lock guard that can be used with any locking primitive that implements
+//! the ([`Lock`]) trait. It also contains the definition of the trait, which can be leveraged by
+//! other constructs to work on generic locking primitives.
+
+use super::NeedsLockClass;
+use crate::{bindings, str::CStr};
+use core::pin::Pin;
+
+/// Allows mutual exclusion primitives that implement the [`Lock`] trait to automatically unlock
+/// when a guard goes out of scope. It also provides a safe and convenient way to access the data
+/// protected by the lock.
+#[must_use = "the lock unlocks immediately when the guard is unused"]
+pub struct GuardMut<'a, L: Lock + ?Sized> {
+    pub(crate) guard: Guard<'a, L>,
+}
+
+// SAFETY: `GuardMut` is sync when the data protected by the lock is also sync. This is more
+// conservative than the default compiler implementation; more details can be found on
+// https://github.com/rust-lang/rust/issues/41622 -- it refers to `MutexGuard` from the standard
+// library.
+unsafe impl<L> Sync for GuardMut<'_, L>
+where
+    L: Lock + ?Sized,
+    L::Inner: Sync,
+{
+}
+
+impl<L: Lock + ?Sized> core::ops::Deref for GuardMut<'_, L> {
+    type Target = L::Inner;
+
+    fn deref(&self) -> &Self::Target {
+        self.guard.deref()
+    }
+}
+
+impl<L: Lock + ?Sized> core::ops::DerefMut for GuardMut<'_, L> {
+    fn deref_mut(&mut self) -> &mut L::Inner {
+        // SAFETY: The caller owns the lock, so it is safe to deref the protected data.
+        unsafe { &mut *self.guard.lock.locked_data().get() }
+    }
+}
+
+impl<'a, L: Lock + ?Sized> GuardMut<'a, L> {
+    /// Constructs a new lock guard.
+    ///
+    /// # Safety
+    ///
+    /// The caller must ensure that it owns the lock.
+    pub(crate) unsafe fn new(lock: &'a L, context: L::GuardContext) -> Self {
+        // SAFETY: The safety requirements for this function satisfy the `Guard::new` ones.
+        Self {
+            guard: unsafe { Guard::new(lock, context) },
+        }
+    }
+}
+
+/// Allows mutual exclusion primitives that implement the [`Lock`] trait to automatically unlock
+/// when a guard goes out of scope. It also provides a safe and convenient way to immutably access
+/// the data protected by the lock.
+#[must_use = "the lock unlocks immediately when the guard is unused"]
+pub struct Guard<'a, L: Lock + ?Sized> {
+    pub(crate) lock: &'a L,
+    pub(crate) context: L::GuardContext,
+}
+
+// SAFETY: `Guard` is sync when the data protected by the lock is also sync. This is more
+// conservative than the default compiler implementation; more details can be found on
+// https://github.com/rust-lang/rust/issues/41622 -- it refers to `MutexGuard` from the standard
+// library.
+unsafe impl<L> Sync for Guard<'_, L>
+where
+    L: Lock + ?Sized,
+    L::Inner: Sync,
+{
+}
+
+impl<L: Lock + ?Sized> core::ops::Deref for Guard<'_, L> {
+    type Target = L::Inner;
+
+    fn deref(&self) -> &Self::Target {
+        // SAFETY: The caller owns the lock, so it is safe to deref the protected data.
+        unsafe { &*self.lock.locked_data().get() }
+    }
+}
+
+impl<L: Lock + ?Sized> Drop for Guard<'_, L> {
+    fn drop(&mut self) {
+        // SAFETY: The caller owns the lock, so it is safe to unlock it.
+        unsafe { self.lock.unlock(&mut self.context) };
+    }
+}
+
+impl<'a, L: Lock + ?Sized> Guard<'a, L> {
+    /// Constructs a new immutable lock guard.
+    ///
+    /// # Safety
+    ///
+    /// The caller must ensure that it owns the lock.
+    pub(crate) unsafe fn new(lock: &'a L, context: L::GuardContext) -> Self {
+        Self { lock, context }
+    }
+}
+
+/// A generic mutual exclusion primitive.
+///
+/// [`Guard`] and [`GuardMut`] are written such that any mutual exclusion primitive that can
+/// implement this trait can also benefit from having an automatic way to unlock itself.
+///
+/// # Safety
+///
+/// Implementers of this trait must ensure that only one thread/CPU may access the protected data
+/// once the lock is held, that is, between calls to `lock_noguard` and `unlock`.
+pub unsafe trait Lock {
+    /// The type of the data protected by the lock.
+    type Inner: ?Sized;
+
+    /// The type of context, if any, that needs to be stored in the guard.
+    type GuardContext;
+
+    /// Acquires the lock, making the caller its owner.
+    #[must_use]
+    fn lock_noguard(&self) -> Self::GuardContext;
+
+    /// Reacquires the lock, making the caller its owner.
+    ///
+    /// The guard context before the last unlock is passed in.
+    ///
+    /// Locks that don't require this state on relock can simply use the default implementation
+    /// that calls [`Lock::lock_noguard`].
+    fn relock(&self, ctx: &mut Self::GuardContext) {
+        *ctx = self.lock_noguard();
+    }
+
+    /// Releases the lock, giving up ownership of the lock.
+    ///
+    /// # Safety
+    ///
+    /// It must only be called by the current owner of the lock.
+    unsafe fn unlock(&self, context: &mut Self::GuardContext);
+
+    /// Returns the data protected by the lock.
+    fn locked_data(&self) -> &core::cell::UnsafeCell<Self::Inner>;
+}
+
+/// A generic mutual exclusion primitive that can be instantiated generically.
+pub trait CreatableLock: Lock {
+    /// Constructs a new instance of the lock.
+    ///
+    /// # Safety
+    ///
+    /// The caller must call [`CreatableLock::init_lock`] before using the lock.
+    unsafe fn new_lock(data: Self::Inner) -> Self;
+
+    /// Initialises the lock type instance so that it can be safely used.
+    ///
+    /// # Safety
+    ///
+    /// `key` must point to a valid memory location that will remain valid until the lock is
+    /// dropped.
+    unsafe fn init_lock(
+        self: Pin<&mut Self>,
+        name: &'static CStr,
+        key: *mut bindings::lock_class_key,
+    );
+}
+
+impl<L: CreatableLock> NeedsLockClass for L {
+    unsafe fn init(
+        self: Pin<&mut Self>,
+        name: &'static CStr,
+        key: *mut bindings::lock_class_key,
+        _: *mut bindings::lock_class_key,
+    ) {
+        // SAFETY: The safety requirements of this function satisfy those of `init_lock`.
+        unsafe { self.init_lock(name, key) };
+    }
+}
diff --git a/rust/kernel/sync/locked_by.rs b/rust/kernel/sync/locked_by.rs
new file mode 100644
index 000000000000..e7546e12b8df
--- /dev/null
+++ b/rust/kernel/sync/locked_by.rs
@@ -0,0 +1,112 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! A wrapper for data protected by a lock that does not wrap it.
+
+use super::{GuardMut, Lock};
+use core::{cell::UnsafeCell, ops::Deref, ptr};
+
+/// Allows access to some data to be serialised by a lock that does not wrap it.
+///
+/// In most cases, data protected by a lock is wrapped by the appropriate lock type, e.g.,
+/// [`super::Mutex`] or [`super::SpinLock`]. [`LockedBy`] is meant for cases when this is not
+/// possible. For example, if a container has a lock and some data in the contained elements needs
+/// to be protected by the same lock.
+///
+/// [`LockedBy`] wraps the data in lieu of another locking primitive, and only allows access to it
+/// when the caller shows evidence that 'external' lock is locked.
+///
+/// # Example
+///
+/// The following is an example for illustrative purposes: `InnerDirectory::bytes_used` is an
+/// aggregate of all `InnerFile::bytes_used` and must be kept consistent; so we wrap `InnerFile` in
+/// a `LockedBy` so that it shares a lock with `InnerDirectory`. This allows us to enforce at
+/// compile-time that access to `InnerFile` is only granted when an `InnerDirectory` is also
+/// locked; we enforce at run time that the right `InnerDirectory` is locked.
+///
+/// ```
+/// # use kernel::prelude::*;
+/// use kernel::sync::{LockedBy, Mutex};
+///
+/// struct InnerFile {
+///     bytes_used: u64,
+/// }
+///
+/// struct File {
+///     name: String,
+///     inner: LockedBy<InnerFile, Mutex<InnerDirectory>>,
+/// }
+///
+/// struct InnerDirectory {
+///     /// The sum of the bytes used by all files.
+///     bytes_used: u64,
+///     files: Vec<File>,
+/// }
+///
+/// struct Directory {
+///     name: String,
+///     inner: Mutex<InnerDirectory>,
+/// }
+/// ```
+pub struct LockedBy<T: ?Sized, L: Lock + ?Sized> {
+    owner: *const L::Inner,
+    data: UnsafeCell<T>,
+}
+
+// SAFETY: `LockedBy` can be transferred across thread boundaries iff the data it protects can.
+unsafe impl<T: ?Sized + Send, L: Lock + ?Sized> Send for LockedBy<T, L> {}
+
+// SAFETY: `LockedBy` serialises the interior mutability it provides, so it is `Sync` as long as the
+// data it protects is `Send`.
+unsafe impl<T: ?Sized + Send, L: Lock + ?Sized> Sync for LockedBy<T, L> {}
+
+impl<T, L: Lock + ?Sized> LockedBy<T, L> {
+    /// Constructs a new instance of [`LockedBy`].
+    ///
+    /// It stores a raw pointer to the owner that is never dereferenced. It is only used to ensure
+    /// that the right owner is being used to access the protected data. If the owner is freed, the
+    /// data becomes inaccessible; if another instance of the owner is allocated *on the same
+    /// memory location*, the data becomes accessible again: none of this affects memory safety
+    /// because in any case at most one thread (or CPU) can access the protected data at a time.
+    pub fn new(owner: &L, data: T) -> Self {
+        Self {
+            owner: owner.locked_data().get(),
+            data: UnsafeCell::new(data),
+        }
+    }
+}
+
+impl<T: ?Sized, L: Lock + ?Sized> LockedBy<T, L> {
+    /// Returns a reference to the protected data when the caller provides evidence (via a
+    /// [`GuardMut`]) that the owner is locked.
+    pub fn access<'a>(&'a self, guard: &'a GuardMut<'_, L>) -> &'a T {
+        if !ptr::eq(guard.deref(), self.owner) {
+            panic!("guard does not match owner");
+        }
+
+        // SAFETY: `guard` is evidence that the owner is locked.
+        unsafe { &mut *self.data.get() }
+    }
+
+    /// Returns a mutable reference to the protected data when the caller provides evidence (via a
+    /// mutable [`GuardMut`]) that the owner is locked mutably.
+    pub fn access_mut<'a>(&'a self, guard: &'a mut GuardMut<'_, L>) -> &'a mut T {
+        if !ptr::eq(guard.deref().deref(), self.owner) {
+            panic!("guard does not match owner");
+        }
+
+        // SAFETY: `guard` is evidence that the owner is locked.
+        unsafe { &mut *self.data.get() }
+    }
+
+    /// Returns a mutable reference to the protected data when the caller provides evidence (via a
+    /// mutable owner) that the owner is locked mutably. Showing a mutable reference to the owner
+    /// is sufficient because we know no other references can exist to it.
+    pub fn access_from_mut<'a>(&'a self, owner: &'a mut L::Inner) -> &'a mut T {
+        if !ptr::eq(owner, self.owner) {
+            panic!("mismatched owners");
+        }
+
+        // SAFETY: `owner` is evidence that there is only one reference to the owner.
+        unsafe { &mut *self.data.get() }
+    }
+}
diff --git a/rust/kernel/sync/mod.rs b/rust/kernel/sync/mod.rs
new file mode 100644
index 000000000000..51067fc7b6fc
--- /dev/null
+++ b/rust/kernel/sync/mod.rs
@@ -0,0 +1,92 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Synchronisation primitives.
+//!
+//! This module contains the kernel APIs related to synchronisation that have been ported or
+//! wrapped for usage by Rust code in the kernel and is shared by all of them.
+//!
+//! # Example
+//!
+//! ```no_run
+//! # use kernel::prelude::*;
+//! # use kernel::mutex_init;
+//! # use kernel::sync::Mutex;
+//! # use alloc::boxed::Box;
+//! # use core::pin::Pin;
+//! // SAFETY: `init` is called below.
+//! let mut data = Pin::from(Box::new(unsafe { Mutex::new(0) }));
+//! mutex_init!(data.as_mut(), "test::data");
+//! *data.lock() = 10;
+//! pr_info!("{}\n", *data.lock());
+//! ```
+
+use crate::{bindings, str::CStr};
+use core::pin::Pin;
+
+mod arc;
+mod condvar;
+mod guard;
+mod locked_by;
+mod mutex;
+mod revocable_mutex;
+mod seqlock;
+mod spinlock;
+
+pub use arc::{Ref, RefBorrow, UniqueRef};
+pub use condvar::CondVar;
+pub use guard::{CreatableLock, Guard, GuardMut, Lock};
+pub use locked_by::LockedBy;
+pub use mutex::Mutex;
+pub use revocable_mutex::{RevocableMutex, RevocableMutexGuard};
+pub use seqlock::{SeqLock, SeqLockReadGuard};
+pub use spinlock::SpinLock;
+
+/// Safely initialises an object that has an `init` function that takes a name and a lock class as
+/// arguments, examples of these are [`Mutex`] and [`SpinLock`]. Each of them also provides a more
+/// specialised name that uses this macro.
+#[doc(hidden)]
+#[macro_export]
+macro_rules! init_with_lockdep {
+    ($obj:expr, $name:literal) => {{
+        static mut CLASS1: core::mem::MaybeUninit<$crate::bindings::lock_class_key> =
+            core::mem::MaybeUninit::uninit();
+        static mut CLASS2: core::mem::MaybeUninit<$crate::bindings::lock_class_key> =
+            core::mem::MaybeUninit::uninit();
+        let obj = $obj;
+        let name = $crate::c_str!($name);
+        // SAFETY: `CLASS1` and `CLASS2` are never used by Rust code directly; the C portion of the
+        // kernel may change it though.
+        #[allow(unused_unsafe)]
+        unsafe {
+            $crate::sync::NeedsLockClass::init(obj, name, CLASS1.as_mut_ptr(), CLASS2.as_mut_ptr())
+        };
+    }};
+}
+
+/// A trait for types that need a lock class during initialisation.
+///
+/// Implementers of this trait benefit from the [`init_with_lockdep`] macro that generates a new
+/// class for each initialisation call site.
+pub trait NeedsLockClass {
+    /// Initialises the type instance so that it can be safely used.
+    ///
+    /// Callers are encouraged to use the [`init_with_lockdep`] macro as it automatically creates a
+    /// new lock class on each usage.
+    ///
+    /// # Safety
+    ///
+    /// `key1` and `key2` must point to valid memory locations and remain valid until `self` is
+    /// dropped.
+    unsafe fn init(
+        self: Pin<&mut Self>,
+        name: &'static CStr,
+        key1: *mut bindings::lock_class_key,
+        key2: *mut bindings::lock_class_key,
+    );
+}
+
+/// Reschedules the caller's task if needed.
+pub fn cond_resched() -> bool {
+    // SAFETY: No arguments, reschedules `current` if needed.
+    unsafe { bindings::cond_resched() != 0 }
+}
diff --git a/rust/kernel/sync/mutex.rs b/rust/kernel/sync/mutex.rs
new file mode 100644
index 000000000000..aaaf5bcb87b3
--- /dev/null
+++ b/rust/kernel/sync/mutex.rs
@@ -0,0 +1,111 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! A kernel mutex.
+//!
+//! This module allows Rust code to use the kernel's [`struct mutex`].
+
+use super::{CreatableLock, GuardMut, Lock};
+use crate::{bindings, str::CStr, Opaque};
+use core::{cell::UnsafeCell, marker::PhantomPinned, pin::Pin};
+
+/// Safely initialises a [`Mutex`] with the given name, generating a new lock class.
+#[macro_export]
+macro_rules! mutex_init {
+    ($mutex:expr, $name:literal) => {
+        $crate::init_with_lockdep!($mutex, $name)
+    };
+}
+
+/// Exposes the kernel's [`struct mutex`]. When multiple threads attempt to lock the same mutex,
+/// only one at a time is allowed to progress, the others will block (sleep) until the mutex is
+/// unlocked, at which point another thread will be allowed to wake up and make progress.
+///
+/// A [`Mutex`] must first be initialised with a call to [`Mutex::init_lock`] before it can be
+/// used. The [`mutex_init`] macro is provided to automatically assign a new lock class to a mutex
+/// instance.
+///
+/// Since it may block, [`Mutex`] needs to be used with care in atomic contexts.
+///
+/// [`struct mutex`]: ../../../include/linux/mutex.h
+pub struct Mutex<T: ?Sized> {
+    /// The kernel `struct mutex` object.
+    mutex: Opaque<bindings::mutex>,
+
+    /// A mutex needs to be pinned because it contains a [`struct list_head`] that is
+    /// self-referential, so it cannot be safely moved once it is initialised.
+    _pin: PhantomPinned,
+
+    /// The data protected by the mutex.
+    data: UnsafeCell<T>,
+}
+
+// SAFETY: `Mutex` can be transferred across thread boundaries iff the data it protects can.
+unsafe impl<T: ?Sized + Send> Send for Mutex<T> {}
+
+// SAFETY: `Mutex` serialises the interior mutability it provides, so it is `Sync` as long as the
+// data it protects is `Send`.
+unsafe impl<T: ?Sized + Send> Sync for Mutex<T> {}
+
+impl<T> Mutex<T> {
+    /// Constructs a new mutex.
+    ///
+    /// # Safety
+    ///
+    /// The caller must call [`Mutex::init_lock`] before using the mutex.
+    pub unsafe fn new(t: T) -> Self {
+        Self {
+            mutex: Opaque::uninit(),
+            data: UnsafeCell::new(t),
+            _pin: PhantomPinned,
+        }
+    }
+}
+
+impl<T: ?Sized> Mutex<T> {
+    /// Locks the mutex and gives the caller access to the data protected by it. Only one thread at
+    /// a time is allowed to access the protected data.
+    pub fn lock(&self) -> GuardMut<'_, Self> {
+        let ctx = self.lock_noguard();
+        // SAFETY: The mutex was just acquired.
+        unsafe { GuardMut::new(self, ctx) }
+    }
+}
+
+impl<T> CreatableLock for Mutex<T> {
+    unsafe fn new_lock(data: Self::Inner) -> Self {
+        // SAFETY: The safety requirements of `new_lock` also require that `init_lock` be called.
+        unsafe { Self::new(data) }
+    }
+
+    unsafe fn init_lock(
+        self: Pin<&mut Self>,
+        name: &'static CStr,
+        key: *mut bindings::lock_class_key,
+    ) {
+        unsafe { bindings::__mutex_init(self.mutex.get(), name.as_char_ptr(), key) };
+    }
+}
+
+pub struct EmptyGuardContext;
+
+// SAFETY: The underlying kernel `struct mutex` object ensures mutual exclusion.
+unsafe impl<T: ?Sized> Lock for Mutex<T> {
+    type Inner = T;
+    type GuardContext = EmptyGuardContext;
+
+    fn lock_noguard(&self) -> EmptyGuardContext {
+        // SAFETY: `mutex` points to valid memory.
+        unsafe { bindings::mutex_lock(self.mutex.get()) };
+        EmptyGuardContext
+    }
+
+    unsafe fn unlock(&self, _: &mut EmptyGuardContext) {
+        // SAFETY: The safety requirements of the function ensure that the mutex is owned by the
+        // caller.
+        unsafe { bindings::mutex_unlock(self.mutex.get()) };
+    }
+
+    fn locked_data(&self) -> &UnsafeCell<T> {
+        &self.data
+    }
+}
diff --git a/rust/kernel/sync/revocable_mutex.rs b/rust/kernel/sync/revocable_mutex.rs
new file mode 100644
index 000000000000..2747cd254cb2
--- /dev/null
+++ b/rust/kernel/sync/revocable_mutex.rs
@@ -0,0 +1,184 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! A kernel mutex where acccess to contents can be revoked at runtime.
+
+use crate::{
+    bindings,
+    str::CStr,
+    sync::{GuardMut, Mutex, NeedsLockClass},
+};
+use core::{
+    mem::ManuallyDrop,
+    ops::{Deref, DerefMut},
+    pin::Pin,
+    ptr::drop_in_place,
+};
+
+/// The state within a `RevocableMutex` that is protected by a mutex.
+///
+/// We don't use simply `Option<T>` because we need to drop in-place because the contents are
+/// implicitly pinned.
+struct RevocableMutexInner<T: ?Sized> {
+    is_available: bool,
+    data: ManuallyDrop<T>,
+}
+
+/// A mutex whose contents can become inaccessible at runtime.
+///
+/// Once access is revoked and all concurrent users complete (i.e., all existing instances of
+/// [`RevocableMutexGuard`] are dropped), the wrapped object is also dropped.
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::sync::RevocableMutex;
+/// # use kernel::revocable_mutex_init;
+/// # use core::pin::Pin;
+///
+/// struct Example {
+///     a: u32,
+///     b: u32,
+/// }
+///
+/// fn add_two(v: &RevocableMutex<Example>) -> Option<u32> {
+///     let guard = v.try_lock()?;
+///     Some(guard.a + guard.b)
+/// }
+///
+/// fn example() {
+///     // SAFETY: We call `revocable_mutex_init` immediately below.
+///     let mut v = unsafe { RevocableMutex::new(Example { a: 10, b: 20 }) };
+///     // SAFETY: We never move out of `v`.
+///     let pinned = unsafe { Pin::new_unchecked(&mut v) };
+///     revocable_mutex_init!(pinned, "example::v");
+///     assert_eq!(add_two(&v), Some(30));
+///     v.revoke();
+///     assert_eq!(add_two(&v), None);
+/// }
+/// ```
+pub struct RevocableMutex<T: ?Sized> {
+    inner: Mutex<RevocableMutexInner<T>>,
+}
+
+// SAFETY: `Mutex` can be transferred across thread boundaries iff the data it protects can.
+unsafe impl<T: ?Sized + Send> Send for RevocableMutex<T> {}
+
+// SAFETY: `Mutex` serialises the interior mutability it provides, so it is `Sync` as long as the
+// data it protects is `Send`.
+unsafe impl<T: ?Sized + Send> Sync for RevocableMutex<T> {}
+
+/// Safely initialises a [`RevocableMutex`] with the given name, generating a new lock class.
+#[macro_export]
+macro_rules! revocable_mutex_init {
+    ($mutex:expr, $name:literal) => {
+        $crate::init_with_lockdep!($mutex, $name)
+    };
+}
+
+impl<T> RevocableMutex<T> {
+    /// Creates a new revocable instance of the given data.
+    ///
+    /// # Safety
+    ///
+    /// The caller must call [`RevocableMutex::init`] before using the revocable mutex.
+    pub unsafe fn new(data: T) -> Self {
+        Self {
+            // SAFETY: The safety requirements of this function require that `RevocableMutex::init`
+            // be called before the returned object can be used. Mutex initialisation is called
+            // from `RevocableMutex::init`, so we satisfy the requirement from `Mutex`.
+            inner: unsafe {
+                Mutex::new(RevocableMutexInner {
+                    is_available: true,
+                    data: ManuallyDrop::new(data),
+                })
+            },
+        }
+    }
+}
+
+impl<T> NeedsLockClass for RevocableMutex<T> {
+    unsafe fn init(
+        self: Pin<&mut Self>,
+        name: &'static CStr,
+        key1: *mut bindings::lock_class_key,
+        key2: *mut bindings::lock_class_key,
+    ) {
+        // SAFETY: `inner` is pinned when `self` is.
+        let mutex = unsafe { self.map_unchecked_mut(|r| &mut r.inner) };
+
+        // SAFETY: The safety requirements of this function satisfy the ones for `Mutex::init`
+        // (they're the same).
+        unsafe { mutex.init(name, key1, key2) };
+    }
+}
+
+impl<T: ?Sized> RevocableMutex<T> {
+    /// Tries to lock (and access) the \[revocable\] wrapped object.
+    ///
+    /// Returns `None` if the object has been revoked and is therefore no longer accessible.
+    ///
+    /// Returns a guard that gives access to the object otherwise; the object is guaranteed to
+    /// remain accessible while the guard is alive. Callers are allowed to sleep while holding on
+    /// to the returned guard.
+    pub fn try_lock(&self) -> Option<RevocableMutexGuard<'_, T>> {
+        let inner = self.inner.lock();
+        if !inner.is_available {
+            return None;
+        }
+        Some(RevocableMutexGuard::new(inner))
+    }
+
+    /// Revokes access to and drops the wrapped object.
+    ///
+    /// Revocation and dropping happens after ongoing accessors complete.
+    pub fn revoke(&self) {
+        let mut inner = self.inner.lock();
+        if !inner.is_available {
+            // Already revoked.
+            return;
+        }
+
+        // SAFETY: We know `inner.data` is valid because `is_available` is set to true. We'll drop
+        // it here and set it to false so it isn't dropped again.
+        unsafe { drop_in_place(&mut inner.data) };
+        inner.is_available = false;
+    }
+}
+
+impl<T: ?Sized> Drop for RevocableMutex<T> {
+    fn drop(&mut self) {
+        self.revoke();
+    }
+}
+
+/// A guard that allows access to a revocable object and keeps it alive.
+pub struct RevocableMutexGuard<'a, T: ?Sized> {
+    guard: GuardMut<'a, Mutex<RevocableMutexInner<T>>>,
+}
+
+impl<'a, T: ?Sized> RevocableMutexGuard<'a, T> {
+    fn new(guard: GuardMut<'a, Mutex<RevocableMutexInner<T>>>) -> Self {
+        Self { guard }
+    }
+
+    /// Returns a pinned mutable reference to the wrapped object.
+    pub fn as_pinned_mut(&mut self) -> Pin<&mut T> {
+        // SAFETY: Revocable mutexes must be pinned, so we choose to always project the data as
+        // pinned as well (i.e., we guarantee we never move it).
+        unsafe { Pin::new_unchecked(&mut self.guard.data) }
+    }
+}
+
+impl<T: ?Sized> Deref for RevocableMutexGuard<'_, T> {
+    type Target = T;
+
+    fn deref(&self) -> &Self::Target {
+        &self.guard.data
+    }
+}
+
+impl<T: ?Sized> DerefMut for RevocableMutexGuard<'_, T> {
+    fn deref_mut(&mut self) -> &mut Self::Target {
+        &mut self.guard.data
+    }
+}
diff --git a/rust/kernel/sync/seqlock.rs b/rust/kernel/sync/seqlock.rs
new file mode 100644
index 000000000000..76eb620b6720
--- /dev/null
+++ b/rust/kernel/sync/seqlock.rs
@@ -0,0 +1,201 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! A kernel sequential lock (seqlock).
+//!
+//! This module allows Rust code to use the sequential locks based on the kernel's `seqcount_t` and
+//! any locks implementing the [`CreatableLock`] trait.
+//!
+//! See <https://www.kernel.org/doc/Documentation/locking/seqlock.rst>.
+
+use super::{CreatableLock, Guard, Lock, NeedsLockClass};
+use crate::{bindings, str::CStr, Opaque};
+use core::{cell::UnsafeCell, marker::PhantomPinned, ops::Deref, pin::Pin};
+
+/// Exposes sequential locks backed by the kernel's `seqcount_t`.
+///
+/// The write-side critical section is protected by a lock implementing the `CreatableLock` trait.
+///
+/// # Examples
+///
+///```
+/// # use kernel::prelude::*;
+/// use kernel::sync::{SeqLock, SpinLock};
+/// use core::sync::atomic::{AtomicU32, Ordering};
+///
+/// struct Example {
+///     a: AtomicU32,
+///     b: AtomicU32,
+/// }
+///
+/// fn get_sum(v: &SeqLock<SpinLock<Example>>) -> u32 {
+///     // Use `access` to access the fields of `Example`.
+///     v.access(|e| e.a.load(Ordering::Relaxed) + e.b.load(Ordering::Relaxed))
+/// }
+///
+/// fn get_sum_with_guard(v: &SeqLock<SpinLock<Example>>) -> u32 {
+///     // Use `read` and `need_retry` in a loop to access the fields of `Example`.
+///     loop {
+///         let guard = v.read();
+///         let sum = guard.a.load(Ordering::Relaxed) + guard.b.load(Ordering::Relaxed);
+///         if !guard.need_retry() {
+///             break sum;
+///         }
+///     }
+/// }
+///
+/// fn inc_each(v: &SeqLock<SpinLock<Example>>) {
+///     // Use a write-side guard to access the fields of `Example`.
+///     let guard = v.write();
+///     let a = guard.a.load(Ordering::Relaxed);
+///     guard.a.store(a + 1, Ordering::Relaxed);
+///     let b = guard.b.load(Ordering::Relaxed);
+///     guard.b.store(b + 1, Ordering::Relaxed);
+/// }
+/// ```
+pub struct SeqLock<L: CreatableLock + ?Sized> {
+    _p: PhantomPinned,
+    count: Opaque<bindings::seqcount>,
+    write_lock: L,
+}
+
+// SAFETY: `SeqLock` can be transferred across thread boundaries iff the data it protects and the
+// underlying lock can.
+unsafe impl<L: CreatableLock + Send> Send for SeqLock<L> where L::Inner: Send {}
+
+// SAFETY: `SeqLock` allows concurrent access to the data it protects by both readers and writers,
+// so it requires that the data it protects be `Sync`, as well as the underlying lock.
+unsafe impl<L: CreatableLock + Sync> Sync for SeqLock<L> where L::Inner: Sync {}
+
+impl<L: CreatableLock> SeqLock<L> {
+    /// Constructs a new instance of [`SeqLock`].
+    ///
+    /// # Safety
+    ///
+    /// The caller must call [`SeqLock::init`] before using the seqlock.
+    pub unsafe fn new(data: L::Inner) -> Self
+    where
+        L::Inner: Sized,
+    {
+        Self {
+            _p: PhantomPinned,
+            count: Opaque::uninit(),
+            // SAFETY: `L::init_lock` is called from `SeqLock::init`, which is required to be
+            // called by the function's safety requirements.
+            write_lock: unsafe { L::new_lock(data) },
+        }
+    }
+}
+
+impl<L: CreatableLock + ?Sized> SeqLock<L> {
+    /// Accesses the protected data in read mode.
+    ///
+    /// Readers and writers are allowed to run concurrently, so callers must check if they need to
+    /// refetch the values before they are used (e.g., because a writer changed them concurrently,
+    /// rendering them potentially inconsistent). The check is performed via calls to
+    /// [`SeqLockReadGuard::need_retry`].
+    pub fn read(&self) -> SeqLockReadGuard<'_, L> {
+        SeqLockReadGuard {
+            lock: self,
+            // SAFETY: `count` contains valid memory.
+            start_count: unsafe { bindings::read_seqcount_begin(self.count.get()) },
+        }
+    }
+
+    /// Accesses the protected data in read mode.
+    ///
+    /// The provided closure is called repeatedly if it may have accessed inconsistent data (e.g.,
+    /// because a concurrent writer modified it). This is a wrapper around [`SeqLock::read`] and
+    /// [`SeqLockReadGuard::need_retry`] in a loop.
+    pub fn access<F: Fn(&L::Inner) -> R, R>(&self, cb: F) -> R {
+        loop {
+            let guard = self.read();
+            let ret = cb(&guard);
+            if !guard.need_retry() {
+                return ret;
+            }
+        }
+    }
+
+    /// Locks the underlying lock and returns a guard that allows access to the protected data.
+    ///
+    /// The guard is not mutable though because readers are still allowed to concurrently access
+    /// the data. The protected data structure needs to provide interior mutability itself (e.g.,
+    /// via atomic types) for the individual fields that can be mutated.
+    pub fn write(&self) -> Guard<'_, Self> {
+        let ctx = self.lock_noguard();
+        // SAFETY: The seqlock was just acquired.
+        unsafe { Guard::new(self, ctx) }
+    }
+}
+
+impl<L: CreatableLock + ?Sized> NeedsLockClass for SeqLock<L> {
+    unsafe fn init(
+        mut self: Pin<&mut Self>,
+        name: &'static CStr,
+        key1: *mut bindings::lock_class_key,
+        key2: *mut bindings::lock_class_key,
+    ) {
+        // SAFETY: `write_lock` is pinned when `self` is.
+        let pinned = unsafe { self.as_mut().map_unchecked_mut(|s| &mut s.write_lock) };
+        // SAFETY: `key1` is valid by the safety requirements of this function.
+        unsafe { pinned.init_lock(name, key1) };
+        // SAFETY: `key2` is valid by the safety requirements of this function.
+        unsafe { bindings::__seqcount_init(self.count.get(), name.as_char_ptr(), key2) };
+    }
+}
+
+// SAFETY: The underlying lock ensures mutual exclusion.
+unsafe impl<L: CreatableLock + ?Sized> Lock for SeqLock<L> {
+    type Inner = L::Inner;
+    type GuardContext = L::GuardContext;
+
+    fn lock_noguard(&self) -> L::GuardContext {
+        let ctx = self.write_lock.lock_noguard();
+        // SAFETY: `count` contains valid memory.
+        unsafe { bindings::write_seqcount_begin(self.count.get()) };
+        ctx
+    }
+
+    fn relock(&self, ctx: &mut L::GuardContext) {
+        self.write_lock.relock(ctx);
+        // SAFETY: `count` contains valid memory.
+        unsafe { bindings::write_seqcount_begin(self.count.get()) };
+    }
+
+    unsafe fn unlock(&self, ctx: &mut L::GuardContext) {
+        // SAFETY: The safety requirements of the function ensure that lock is owned by the caller.
+        unsafe { bindings::write_seqcount_end(self.count.get()) };
+        // SAFETY: The safety requirements of the function ensure that lock is owned by the caller.
+        unsafe { self.write_lock.unlock(ctx) };
+    }
+
+    fn locked_data(&self) -> &UnsafeCell<L::Inner> {
+        self.write_lock.locked_data()
+    }
+}
+
+/// Allows read-side access to data protected by a sequential lock.
+pub struct SeqLockReadGuard<'a, L: CreatableLock + ?Sized> {
+    lock: &'a SeqLock<L>,
+    start_count: u32,
+}
+
+impl<L: CreatableLock + ?Sized> SeqLockReadGuard<'_, L> {
+    /// Determine if the callers needs to retry reading values.
+    ///
+    /// It returns `true` when a concurrent writer ran between the guard being created and
+    /// [`Self::need_retry`] being called.
+    pub fn need_retry(&self) -> bool {
+        // SAFETY: `count` is valid because the guard guarantees that the lock remains alive.
+        unsafe { bindings::read_seqcount_retry(self.lock.count.get(), self.start_count) != 0 }
+    }
+}
+
+impl<L: CreatableLock + ?Sized> Deref for SeqLockReadGuard<'_, L> {
+    type Target = L::Inner;
+
+    fn deref(&self) -> &Self::Target {
+        // SAFETY: We only ever allow shared access to the protected data.
+        unsafe { &*self.lock.locked_data().get() }
+    }
+}
diff --git a/rust/kernel/sync/spinlock.rs b/rust/kernel/sync/spinlock.rs
new file mode 100644
index 000000000000..f4bcf57043ca
--- /dev/null
+++ b/rust/kernel/sync/spinlock.rs
@@ -0,0 +1,180 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! A kernel spinlock.
+//!
+//! This module allows Rust code to use the kernel's [`struct spinlock`].
+//!
+//! See <https://www.kernel.org/doc/Documentation/locking/spinlocks.txt>.
+
+use super::{CreatableLock, GuardMut, Lock};
+use crate::{bindings, c_types, str::CStr, Opaque};
+use core::{cell::UnsafeCell, marker::PhantomPinned, pin::Pin};
+
+/// Safely initialises a [`SpinLock`] with the given name, generating a new lock class.
+#[macro_export]
+macro_rules! spinlock_init {
+    ($spinlock:expr, $name:literal) => {
+        $crate::init_with_lockdep!($spinlock, $name)
+    };
+}
+
+/// Exposes the kernel's [`spinlock_t`]. When multiple CPUs attempt to lock the same spinlock, only
+/// one at a time is allowed to progress, the others will block (spinning) until the spinlock is
+/// unlocked, at which point another CPU will be allowed to make progress.
+///
+/// A [`SpinLock`] must first be initialised with a call to [`SpinLock::init_lock`] before it can be
+/// used. The [`spinlock_init`] macro is provided to automatically assign a new lock class to a
+/// spinlock instance.
+///
+/// There are two ways to acquire the lock:
+///  - [`SpinLock::lock`], which doesn't manage interrupt state, so it should be used in only two
+///    cases: (a) when the caller knows that interrupts are disabled, or (b) when callers never use
+///    it in atomic context (e.g., interrupt handlers), in which case it is ok for interrupts to be
+///    enabled.
+///  - [`SpinLock::lock_irqdisable`], which disables interrupts if they are enabled before
+///    acquiring the lock. When the lock is released, the interrupt state is automatically returned
+///    to its value before [`SpinLock::lock_irqdisable`] was called.
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::prelude::*;
+/// # use kernel::sync::SpinLock;
+/// # use core::pin::Pin;
+///
+/// struct Example {
+///     a: u32,
+///     b: u32,
+/// }
+///
+/// // Function that acquires spinlock without changing interrupt state.
+/// fn lock_example(value: &SpinLock<Example>) {
+///     let mut guard = value.lock();
+///     guard.a = 10;
+///     guard.b = 20;
+/// }
+///
+/// // Function that acquires spinlock and disables interrupts while holding it.
+/// fn lock_irqdisable_example(value: &SpinLock<Example>) {
+///     let mut guard = value.lock_irqdisable();
+///     guard.a = 30;
+///     guard.b = 40;
+/// }
+///
+/// // Initialises a spinlock and calls the example functions.
+/// pub fn spinlock_example() {
+///     // SAFETY: `spinlock_init` is called below.
+///     let mut value = unsafe { SpinLock::new(Example { a: 1, b: 2 }) };
+///     // SAFETY: We don't move `value`.
+///     kernel::spinlock_init!(unsafe { Pin::new_unchecked(&mut value) }, "value");
+///     lock_example(&value);
+///     lock_irqdisable_example(&value);
+/// }
+/// ```
+///
+/// [`spinlock_t`]: ../../../include/linux/spinlock.h
+pub struct SpinLock<T: ?Sized> {
+    spin_lock: Opaque<bindings::spinlock>,
+
+    /// Spinlocks are architecture-defined. So we conservatively require them to be pinned in case
+    /// some architecture uses self-references now or in the future.
+    _pin: PhantomPinned,
+
+    data: UnsafeCell<T>,
+}
+
+// SAFETY: `SpinLock` can be transferred across thread boundaries iff the data it protects can.
+unsafe impl<T: ?Sized + Send> Send for SpinLock<T> {}
+
+// SAFETY: `SpinLock` serialises the interior mutability it provides, so it is `Sync` as long as the
+// data it protects is `Send`.
+unsafe impl<T: ?Sized + Send> Sync for SpinLock<T> {}
+
+impl<T> SpinLock<T> {
+    /// Constructs a new spinlock.
+    ///
+    /// # Safety
+    ///
+    /// The caller must call [`SpinLock::init_lock`] before using the spinlock.
+    pub unsafe fn new(t: T) -> Self {
+        Self {
+            spin_lock: Opaque::uninit(),
+            data: UnsafeCell::new(t),
+            _pin: PhantomPinned,
+        }
+    }
+}
+
+impl<T: ?Sized> SpinLock<T> {
+    /// Locks the spinlock and gives the caller access to the data protected by it. Only one thread
+    /// at a time is allowed to access the protected data.
+    pub fn lock(&self) -> GuardMut<'_, Self> {
+        let ctx = self.lock_noguard();
+        // SAFETY: The spinlock was just acquired.
+        unsafe { GuardMut::new(self, ctx) }
+    }
+
+    /// Locks the spinlock and gives the caller access to the data protected by it. Additionally it
+    /// disables interrupts (if they are enabled).
+    ///
+    /// When the lock in unlocked, the interrupt state (enabled/disabled) is restored.
+    pub fn lock_irqdisable(&self) -> GuardMut<'_, Self> {
+        let ctx = self.internal_lock_irqsave();
+        // SAFETY: The spinlock was just acquired.
+        unsafe { GuardMut::new(self, Some(ctx)) }
+    }
+
+    fn internal_lock_irqsave(&self) -> c_types::c_ulong {
+        // SAFETY: `spin_lock` points to valid memory.
+        unsafe { bindings::spin_lock_irqsave(self.spin_lock.get()) }
+    }
+}
+
+impl<T> CreatableLock for SpinLock<T> {
+    unsafe fn new_lock(data: Self::Inner) -> Self {
+        // SAFETY: The safety requirements of `new_lock` also require that `init_lock` be called.
+        unsafe { Self::new(data) }
+    }
+
+    unsafe fn init_lock(
+        self: Pin<&mut Self>,
+        name: &'static CStr,
+        key: *mut bindings::lock_class_key,
+    ) {
+        unsafe { bindings::__spin_lock_init(self.spin_lock.get(), name.as_char_ptr(), key) };
+    }
+}
+
+// SAFETY: The underlying kernel `spinlock_t` object ensures mutual exclusion.
+unsafe impl<T: ?Sized> Lock for SpinLock<T> {
+    type Inner = T;
+    type GuardContext = Option<c_types::c_ulong>;
+
+    fn lock_noguard(&self) -> Option<c_types::c_ulong> {
+        // SAFETY: `spin_lock` points to valid memory.
+        unsafe { bindings::spin_lock(self.spin_lock.get()) };
+        None
+    }
+
+    unsafe fn unlock(&self, ctx: &mut Option<c_types::c_ulong>) {
+        match ctx {
+            // SAFETY: The safety requirements of the function ensure that the spinlock is owned by
+            // the caller.
+            Some(v) => unsafe { bindings::spin_unlock_irqrestore(self.spin_lock.get(), *v) },
+            // SAFETY: The safety requirements of the function ensure that the spinlock is owned by
+            // the caller.
+            None => unsafe { bindings::spin_unlock(self.spin_lock.get()) },
+        }
+    }
+
+    fn relock(&self, ctx: &mut Self::GuardContext) {
+        match ctx {
+            Some(v) => *v = self.internal_lock_irqsave(),
+            None => *ctx = self.lock_noguard(),
+        }
+    }
+
+    fn locked_data(&self) -> &UnsafeCell<T> {
+        &self.data
+    }
+}
diff --git a/rust/kernel/sysctl.rs b/rust/kernel/sysctl.rs
new file mode 100644
index 000000000000..0c74245cb204
--- /dev/null
+++ b/rust/kernel/sysctl.rs
@@ -0,0 +1,197 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! System control.
+//!
+//! C header: [`include/linux/sysctl.h`](../../../../include/linux/sysctl.h)
+//!
+//! Reference: <https://www.kernel.org/doc/Documentation/sysctl/README>
+
+use alloc::boxed::Box;
+use alloc::vec::Vec;
+use core::mem;
+use core::ptr;
+use core::sync::atomic;
+
+use crate::{
+    bindings, c_types, error,
+    io_buffer::IoBufferWriter,
+    str::CStr,
+    types,
+    user_ptr::{UserSlicePtr, UserSlicePtrWriter},
+};
+
+/// Sysctl storage.
+pub trait SysctlStorage: Sync {
+    /// Writes a byte slice.
+    fn store_value(&self, data: &[u8]) -> (usize, error::Result);
+
+    /// Reads via a [`UserSlicePtrWriter`].
+    fn read_value(&self, data: &mut UserSlicePtrWriter) -> (usize, error::Result);
+}
+
+fn trim_whitespace(mut data: &[u8]) -> &[u8] {
+    while !data.is_empty() && (data[0] == b' ' || data[0] == b'\t' || data[0] == b'\n') {
+        data = &data[1..];
+    }
+    while !data.is_empty()
+        && (data[data.len() - 1] == b' '
+            || data[data.len() - 1] == b'\t'
+            || data[data.len() - 1] == b'\n')
+    {
+        data = &data[..data.len() - 1];
+    }
+    data
+}
+
+impl<T> SysctlStorage for &T
+where
+    T: SysctlStorage,
+{
+    fn store_value(&self, data: &[u8]) -> (usize, error::Result) {
+        (*self).store_value(data)
+    }
+
+    fn read_value(&self, data: &mut UserSlicePtrWriter) -> (usize, error::Result) {
+        (*self).read_value(data)
+    }
+}
+
+impl SysctlStorage for atomic::AtomicBool {
+    fn store_value(&self, data: &[u8]) -> (usize, error::Result) {
+        let result = match trim_whitespace(data) {
+            b"0" => {
+                self.store(false, atomic::Ordering::Relaxed);
+                Ok(())
+            }
+            b"1" => {
+                self.store(true, atomic::Ordering::Relaxed);
+                Ok(())
+            }
+            _ => Err(error::Error::EINVAL),
+        };
+        (data.len(), result)
+    }
+
+    fn read_value(&self, data: &mut UserSlicePtrWriter) -> (usize, error::Result) {
+        let value = if self.load(atomic::Ordering::Relaxed) {
+            b"1\n"
+        } else {
+            b"0\n"
+        };
+        (value.len(), data.write_slice(value))
+    }
+}
+
+/// Holds a single `sysctl` entry (and its table).
+pub struct Sysctl<T: SysctlStorage> {
+    inner: Box<T>,
+    // Responsible for keeping the `ctl_table` alive.
+    _table: Box<[bindings::ctl_table]>,
+    header: *mut bindings::ctl_table_header,
+}
+
+// SAFETY: The only public method we have is `get()`, which returns `&T`, and
+// `T: Sync`. Any new methods must adhere to this requirement.
+unsafe impl<T: SysctlStorage> Sync for Sysctl<T> {}
+
+unsafe extern "C" fn proc_handler<T: SysctlStorage>(
+    ctl: *mut bindings::ctl_table,
+    write: c_types::c_int,
+    buffer: *mut c_types::c_void,
+    len: *mut usize,
+    ppos: *mut bindings::loff_t,
+) -> c_types::c_int {
+    // If we are reading from some offset other than the beginning of the file,
+    // return an empty read to signal EOF.
+    if unsafe { *ppos } != 0 && write == 0 {
+        unsafe { *len = 0 };
+        return 0;
+    }
+
+    let data = unsafe { UserSlicePtr::new(buffer, *len) };
+    let storage = unsafe { &*((*ctl).data as *const T) };
+    let (bytes_processed, result) = if write != 0 {
+        let data = match data.read_all() {
+            Ok(r) => r,
+            Err(e) => return e.to_kernel_errno(),
+        };
+        storage.store_value(&data)
+    } else {
+        let mut writer = data.writer();
+        storage.read_value(&mut writer)
+    };
+    unsafe { *len = bytes_processed };
+    unsafe { *ppos += *len as bindings::loff_t };
+    match result {
+        Ok(()) => 0,
+        Err(e) => e.to_kernel_errno(),
+    }
+}
+
+impl<T: SysctlStorage> Sysctl<T> {
+    /// Registers a single entry in `sysctl`.
+    pub fn register(
+        path: &'static CStr,
+        name: &'static CStr,
+        storage: T,
+        mode: types::Mode,
+    ) -> error::Result<Sysctl<T>> {
+        if name.contains(&b'/') {
+            return Err(error::Error::EINVAL);
+        }
+
+        let storage = Box::try_new(storage)?;
+        let mut table = Vec::try_with_capacity(2)?;
+        table.try_push(bindings::ctl_table {
+            procname: name.as_char_ptr(),
+            mode: mode.as_int(),
+            data: &*storage as *const T as *mut c_types::c_void,
+            proc_handler: Some(proc_handler::<T>),
+
+            maxlen: 0,
+            child: ptr::null_mut(),
+            poll: ptr::null_mut(),
+            extra1: ptr::null_mut(),
+            extra2: ptr::null_mut(),
+        })?;
+        table.try_push(unsafe { mem::zeroed() })?;
+        let mut table = table.try_into_boxed_slice()?;
+
+        let result = unsafe { bindings::register_sysctl(path.as_char_ptr(), table.as_mut_ptr()) };
+        if result.is_null() {
+            return Err(error::Error::ENOMEM);
+        }
+
+        Ok(Sysctl {
+            inner: storage,
+            _table: table,
+            header: result,
+        })
+    }
+
+    /// Gets the storage.
+    pub fn get(&self) -> &T {
+        &self.inner
+    }
+}
+
+impl<T: SysctlStorage> Drop for Sysctl<T> {
+    fn drop(&mut self) {
+        unsafe {
+            bindings::unregister_sysctl_table(self.header);
+        }
+        self.header = ptr::null_mut();
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn test_trim_whitespace() {
+        assert_eq!(trim_whitespace(b"foo    "), b"foo");
+        assert_eq!(trim_whitespace(b"    foo"), b"foo");
+        assert_eq!(trim_whitespace(b"  foo  "), b"foo");
+    }
+}
diff --git a/rust/kernel/task.rs b/rust/kernel/task.rs
new file mode 100644
index 000000000000..7a2aff0e9219
--- /dev/null
+++ b/rust/kernel/task.rs
@@ -0,0 +1,182 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Tasks (threads and processes).
+//!
+//! C header: [`include/linux/sched.h`](../../../../include/linux/sched.h).
+
+use crate::bindings;
+use core::{marker::PhantomData, mem::ManuallyDrop, ops::Deref};
+
+/// Wraps the kernel's `struct task_struct`.
+///
+/// # Invariants
+///
+/// The pointer `Task::ptr` is non-null and valid. Its reference count is also non-zero.
+///
+/// # Examples
+///
+/// The following is an example of getting the PID of the current thread with zero additional cost
+/// when compared to the C version:
+///
+/// ```
+/// # use kernel::prelude::*;
+/// use kernel::task::Task;
+///
+/// # fn test() {
+/// Task::current().pid();
+/// # }
+/// ```
+///
+/// Getting the PID of the current process, also zero additional cost:
+///
+/// ```
+/// # use kernel::prelude::*;
+/// use kernel::task::Task;
+///
+/// # fn test() {
+/// Task::current().group_leader().pid();
+/// # }
+/// ```
+///
+/// Getting the current task and storing it in some struct. The reference count is automatically
+/// incremented when creating `State` and decremented when it is dropped:
+///
+/// ```
+/// # use kernel::prelude::*;
+/// use kernel::task::Task;
+///
+/// struct State {
+///     creator: Task,
+///     index: u32,
+/// }
+///
+/// impl State {
+///     fn new() -> Self {
+///         Self {
+///             creator: Task::current().clone(),
+///             index: 0,
+///         }
+///     }
+/// }
+/// ```
+pub struct Task {
+    pub(crate) ptr: *mut bindings::task_struct,
+}
+
+// SAFETY: Given that the task is referenced, it is OK to send it to another thread.
+unsafe impl Send for Task {}
+
+// SAFETY: It's OK to access `Task` through references from other threads because we're either
+// accessing properties that don't change (e.g., `pid`, `group_leader`) or that are properly
+// synchronised by C code (e.g., `signal_pending`).
+unsafe impl Sync for Task {}
+
+/// The type of process identifiers (PIDs).
+type Pid = bindings::pid_t;
+
+impl Task {
+    /// Returns a task reference for the currently executing task/thread.
+    pub fn current<'a>() -> TaskRef<'a> {
+        // SAFETY: Just an FFI call.
+        let ptr = unsafe { bindings::get_current() };
+
+        // SAFETY: If the current thread is still running, the current task is valid. Given
+        // that `TaskRef` is not `Send`, we know it cannot be transferred to another thread (where
+        // it could potentially outlive the caller).
+        unsafe { TaskRef::from_ptr(ptr) }
+    }
+
+    /// Returns the group leader of the given task.
+    pub fn group_leader(&self) -> TaskRef<'_> {
+        // SAFETY: By the type invariant, we know that `self.ptr` is non-null and valid.
+        let ptr = unsafe { (*self.ptr).group_leader };
+
+        // SAFETY: The lifetime of the returned task reference is tied to the lifetime of `self`,
+        // and given that a task has a reference to its group leader, we know it must be valid for
+        // the lifetime of the returned task reference.
+        unsafe { TaskRef::from_ptr(ptr) }
+    }
+
+    /// Returns the PID of the given task.
+    pub fn pid(&self) -> Pid {
+        // SAFETY: By the type invariant, we know that `self.ptr` is non-null and valid.
+        unsafe { (*self.ptr).pid }
+    }
+
+    /// Determines whether the given task has pending signals.
+    pub fn signal_pending(&self) -> bool {
+        // SAFETY: By the type invariant, we know that `self.ptr` is non-null and valid.
+        unsafe { bindings::signal_pending(self.ptr) != 0 }
+    }
+}
+
+impl PartialEq for Task {
+    fn eq(&self, other: &Self) -> bool {
+        self.ptr == other.ptr
+    }
+}
+
+impl Eq for Task {}
+
+impl Clone for Task {
+    fn clone(&self) -> Self {
+        // SAFETY: The type invariants guarantee that `self.ptr` has a non-zero reference count.
+        unsafe { bindings::get_task_struct(self.ptr) };
+
+        // INVARIANT: We incremented the reference count to account for the new `Task` being
+        // created.
+        Self { ptr: self.ptr }
+    }
+}
+
+impl Drop for Task {
+    fn drop(&mut self) {
+        // INVARIANT: We may decrement the refcount to zero, but the `Task` is being dropped, so
+        // this is not observable.
+        // SAFETY: The type invariants guarantee that `Task::ptr` has a non-zero reference count.
+        unsafe { bindings::put_task_struct(self.ptr) };
+    }
+}
+
+/// A wrapper for [`Task`] that doesn't automatically decrement the refcount when dropped.
+///
+/// We need the wrapper because [`ManuallyDrop`] alone would allow callers to call
+/// [`ManuallyDrop::into_inner`]. This would allow an unsafe sequence to be triggered without
+/// `unsafe` blocks because it would trigger an unbalanced call to `put_task_struct`.
+///
+/// We make this explicitly not [`Send`] so that we can use it to represent the current thread
+/// without having to increment/decrement its reference count.
+///
+/// # Invariants
+///
+/// The wrapped [`Task`] remains valid for the lifetime of the object.
+pub struct TaskRef<'a> {
+    task: ManuallyDrop<Task>,
+    _not_send: PhantomData<(&'a (), *mut ())>,
+}
+
+impl TaskRef<'_> {
+    /// Constructs a new `struct task_struct` wrapper that doesn't change its reference count.
+    ///
+    /// # Safety
+    ///
+    /// The pointer `ptr` must be non-null and valid for the lifetime of the object.
+    pub(crate) unsafe fn from_ptr(ptr: *mut bindings::task_struct) -> Self {
+        Self {
+            task: ManuallyDrop::new(Task { ptr }),
+            _not_send: PhantomData,
+        }
+    }
+}
+
+// SAFETY: It is OK to share a reference to the current thread with another thread because we know
+// the owner cannot go away while the shared reference exists (and `Task` itself is `Sync`).
+unsafe impl Sync for TaskRef<'_> {}
+
+impl Deref for TaskRef<'_> {
+    type Target = Task;
+
+    fn deref(&self) -> &Self::Target {
+        self.task.deref()
+    }
+}
diff --git a/rust/kernel/types.rs b/rust/kernel/types.rs
new file mode 100644
index 000000000000..64f11005b553
--- /dev/null
+++ b/rust/kernel/types.rs
@@ -0,0 +1,486 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Kernel types.
+//!
+//! C header: [`include/linux/types.h`](../../../../include/linux/types.h)
+
+use crate::{
+    bindings, c_types,
+    sync::{Ref, RefBorrow},
+};
+use alloc::boxed::Box;
+use core::{
+    cell::UnsafeCell,
+    mem::MaybeUninit,
+    ops::{self, Deref, DerefMut},
+    pin::Pin,
+};
+
+/// Permissions.
+///
+/// C header: [`include/uapi/linux/stat.h`](../../../../include/uapi/linux/stat.h)
+///
+/// C header: [`include/linux/stat.h`](../../../../include/linux/stat.h)
+pub struct Mode(bindings::umode_t);
+
+impl Mode {
+    /// Creates a [`Mode`] from an integer.
+    pub fn from_int(m: u16) -> Mode {
+        Mode(m)
+    }
+
+    /// Returns the mode as an integer.
+    pub fn as_int(&self) -> u16 {
+        self.0
+    }
+}
+
+/// Used to convert an object into a raw pointer that represents it.
+///
+/// It can eventually be converted back into the object. This is used to store objects as pointers
+/// in kernel data structures, for example, an implementation of [`FileOperations`] in `struct
+/// file::private_data`.
+pub trait PointerWrapper {
+    /// Type of values borrowed between calls to [`PointerWrapper::into_pointer`] and
+    /// [`PointerWrapper::from_pointer`].
+    type Borrowed<'a>;
+
+    /// Returns the raw pointer.
+    fn into_pointer(self) -> *const c_types::c_void;
+
+    /// Returns a borrowed value.
+    ///
+    /// # Safety
+    ///
+    /// `ptr` must have been returned by a previous call to [`PointerWrapper::into_pointer`].
+    /// Additionally, [`PointerWrapper::from_pointer`] can only be called after *all* values
+    /// returned by [`PointerWrapper::borrow`] have been dropped.
+    unsafe fn borrow<'a>(ptr: *const c_types::c_void) -> Self::Borrowed<'a>;
+
+    /// Returns the instance back from the raw pointer.
+    ///
+    /// # Safety
+    ///
+    /// The passed pointer must come from a previous call to [`PointerWrapper::into_pointer()`].
+    unsafe fn from_pointer(ptr: *const c_types::c_void) -> Self;
+}
+
+impl<T: 'static> PointerWrapper for Box<T> {
+    type Borrowed<'a> = &'a T;
+
+    fn into_pointer(self) -> *const c_types::c_void {
+        Box::into_raw(self) as _
+    }
+
+    unsafe fn borrow<'a>(ptr: *const c_types::c_void) -> &'a T {
+        // SAFETY: The safety requirements for this function ensure that the object is still alive,
+        // so it is safe to dereference the raw pointer.
+        // The safety requirements also ensure that the object remains alive for the lifetime of
+        // the returned value.
+        unsafe { &*ptr.cast() }
+    }
+
+    unsafe fn from_pointer(ptr: *const c_types::c_void) -> Self {
+        // SAFETY: The passed pointer comes from a previous call to [`Self::into_pointer()`].
+        unsafe { Box::from_raw(ptr as _) }
+    }
+}
+
+impl<T: 'static> PointerWrapper for Ref<T> {
+    type Borrowed<'a> = RefBorrow<'a, T>;
+
+    fn into_pointer(self) -> *const c_types::c_void {
+        Ref::into_usize(self) as _
+    }
+
+    unsafe fn borrow<'a>(ptr: *const c_types::c_void) -> RefBorrow<'a, T> {
+        // SAFETY: The safety requirements for this function ensure that the underlying object
+        // remains valid for the lifetime of the returned value.
+        unsafe { Ref::borrow_usize(ptr as _) }
+    }
+
+    unsafe fn from_pointer(ptr: *const c_types::c_void) -> Self {
+        // SAFETY: The passed pointer comes from a previous call to [`Self::into_pointer()`].
+        unsafe { Ref::from_usize(ptr as _) }
+    }
+}
+
+impl<T: PointerWrapper + Deref> PointerWrapper for Pin<T> {
+    type Borrowed<'a> = T::Borrowed<'a>;
+
+    fn into_pointer(self) -> *const c_types::c_void {
+        // SAFETY: We continue to treat the pointer as pinned by returning just a pointer to it to
+        // the caller.
+        let inner = unsafe { Pin::into_inner_unchecked(self) };
+        inner.into_pointer()
+    }
+
+    unsafe fn borrow<'a>(ptr: *const c_types::c_void) -> Self::Borrowed<'a> {
+        // SAFETY: The safety requirements for this function are the same as the ones for
+        // `T::borrow`.
+        unsafe { T::borrow(ptr) }
+    }
+
+    unsafe fn from_pointer(p: *const c_types::c_void) -> Self {
+        // SAFETY: The object was originally pinned.
+        // The passed pointer comes from a previous call to `inner::into_pointer()`.
+        unsafe { Pin::new_unchecked(T::from_pointer(p)) }
+    }
+}
+
+impl<T> PointerWrapper for *mut T {
+    type Borrowed<'a> = *mut T;
+
+    fn into_pointer(self) -> *const c_types::c_void {
+        self as _
+    }
+
+    unsafe fn borrow<'a>(ptr: *const c_types::c_void) -> Self::Borrowed<'a> {
+        ptr as _
+    }
+
+    unsafe fn from_pointer(ptr: *const c_types::c_void) -> Self {
+        ptr as _
+    }
+}
+
+impl PointerWrapper for () {
+    type Borrowed<'a> = ();
+
+    fn into_pointer(self) -> *const c_types::c_void {
+        // We use 1 to be different from a null pointer.
+        1usize as _
+    }
+
+    unsafe fn borrow<'a>(_: *const c_types::c_void) -> Self::Borrowed<'a> {}
+
+    unsafe fn from_pointer(_: *const c_types::c_void) -> Self {}
+}
+
+/// Runs a cleanup function/closure when dropped.
+///
+/// The [`ScopeGuard::dismiss`] function prevents the cleanup function from running.
+///
+/// # Examples
+///
+/// In the example below, we have multiple exit paths and we want to log regardless of which one is
+/// taken:
+/// ```
+/// # use kernel::prelude::*;
+/// # use kernel::ScopeGuard;
+/// fn example1(arg: bool) {
+///     let _log = ScopeGuard::new(|| pr_info!("example1 completed\n"));
+///
+///     if arg {
+///         return;
+///     }
+///
+///     // Do something...
+/// }
+/// ```
+///
+/// In the example below, we want to log the same message on all early exits but a different one on
+/// the main exit path:
+/// ```
+/// # use kernel::prelude::*;
+/// # use kernel::ScopeGuard;
+/// fn example2(arg: bool) {
+///     let log = ScopeGuard::new(|| pr_info!("example2 returned early\n"));
+///
+///     if arg {
+///         return;
+///     }
+///
+///     // (Other early returns...)
+///
+///     log.dismiss();
+///     pr_info!("example2 no early return\n");
+/// }
+/// ```
+///
+/// In the example below, we need a mutable object (the vector) to be accessible within the log
+/// function, so we wrap it in the [`ScopeGuard`]:
+/// ```
+/// # use kernel::prelude::*;
+/// # use kernel::ScopeGuard;
+/// fn example3(arg: bool) -> Result {
+///     let mut vec =
+///         ScopeGuard::new_with_data(Vec::new(), |v| pr_info!("vec had {} elements\n", v.len()));
+///
+///     vec.try_push(10u8)?;
+///     if arg {
+///         return Ok(());
+///     }
+///     vec.try_push(20u8)?;
+///     Ok(())
+/// }
+/// ```
+///
+/// # Invariants
+///
+/// The value stored in the struct is nearly always `Some(_)`, except between
+/// [`ScopeGuard::dismiss`] and [`ScopeGuard::drop`]: in this case, it will be `None` as the value
+/// will have been returned to the caller. Since  [`ScopeGuard::dismiss`] consumes the guard,
+/// callers won't be able to use it anymore.
+pub struct ScopeGuard<T, F: FnOnce(T)>(Option<(T, F)>);
+
+impl<T, F: FnOnce(T)> ScopeGuard<T, F> {
+    /// Creates a new guarded object wrapping the given data and with the given cleanup function.
+    pub fn new_with_data(data: T, cleanup_func: F) -> Self {
+        // INVARIANT: The struct is being initialised with `Some(_)`.
+        Self(Some((data, cleanup_func)))
+    }
+
+    /// Prevents the cleanup function from running and returns the guarded data.
+    pub fn dismiss(mut self) -> T {
+        // INVARIANT: This is the exception case in the invariant; it is not visible to callers
+        // because this function consumes `self`.
+        self.0.take().unwrap().0
+    }
+}
+
+impl ScopeGuard<(), Box<dyn FnOnce(())>> {
+    /// Creates a new guarded object with the given cleanup function.
+    pub fn new(cleanup: impl FnOnce()) -> ScopeGuard<(), impl FnOnce(())> {
+        ScopeGuard::new_with_data((), move |_| cleanup())
+    }
+}
+
+impl<T, F: FnOnce(T)> Deref for ScopeGuard<T, F> {
+    type Target = T;
+
+    fn deref(&self) -> &T {
+        // The type invariants guarantee that `unwrap` will succeed.
+        &self.0.as_ref().unwrap().0
+    }
+}
+
+impl<T, F: FnOnce(T)> DerefMut for ScopeGuard<T, F> {
+    fn deref_mut(&mut self) -> &mut T {
+        // The type invariants guarantee that `unwrap` will succeed.
+        &mut self.0.as_mut().unwrap().0
+    }
+}
+
+impl<T, F: FnOnce(T)> Drop for ScopeGuard<T, F> {
+    fn drop(&mut self) {
+        // Run the cleanup function if one is still present.
+        if let Some((data, cleanup)) = self.0.take() {
+            cleanup(data)
+        }
+    }
+}
+
+/// Stores an opaque value.
+///
+/// This is meant to be used with FFI objects that are never interpreted by Rust code.
+pub struct Opaque<T>(MaybeUninit<UnsafeCell<T>>);
+
+impl<T> Opaque<T> {
+    /// Creates a new opaque value.
+    pub fn new(value: T) -> Self {
+        Self(MaybeUninit::new(UnsafeCell::new(value)))
+    }
+
+    /// Creates an uninitialised value.
+    pub fn uninit() -> Self {
+        Self(MaybeUninit::uninit())
+    }
+
+    /// Returns a raw pointer to the opaque data.
+    pub fn get(&self) -> *mut T {
+        UnsafeCell::raw_get(self.0.as_ptr())
+    }
+}
+
+/// A bitmask.
+///
+/// It has a restriction that all bits must be the same, except one. For example, `0b1110111` and
+/// `0b1000` are acceptable masks.
+#[derive(Clone, Copy)]
+pub struct Bit<T> {
+    index: T,
+    inverted: bool,
+}
+
+/// Creates a bit mask with a single bit set.
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::prelude::*;
+/// # use kernel::bit;
+/// let mut x = 0xfeu32;
+///
+/// assert_eq!(x & bit(0), 0);
+/// assert_eq!(x & bit(1), 2);
+/// assert_eq!(x & bit(2), 4);
+/// assert_eq!(x & bit(3), 8);
+///
+/// x |= bit(0);
+/// assert_eq!(x, 0xff);
+///
+/// x &= !bit(1);
+/// assert_eq!(x, 0xfd);
+///
+/// x &= !bit(7);
+/// assert_eq!(x, 0x7d);
+///
+/// let y: u64 = bit(34).into();
+/// assert_eq!(y, 0x400000000);
+///
+/// assert_eq!(y | bit(35), 0xc00000000);
+/// ```
+pub fn bit<T: Copy>(index: T) -> Bit<T> {
+    Bit {
+        index,
+        inverted: false,
+    }
+}
+
+impl<T: Copy> ops::Not for Bit<T> {
+    type Output = Self;
+    fn not(self) -> Self {
+        Self {
+            index: self.index,
+            inverted: !self.inverted,
+        }
+    }
+}
+
+/// Implemented by integer types that allow counting the number of trailing zeroes.
+pub trait TrailingZeros {
+    /// Returns the number of trailing zeroes in the binary representation of `self`.
+    fn trailing_zeros(&self) -> u32;
+}
+
+macro_rules! define_unsigned_number_traits {
+    ($type_name:ty) => {
+        impl TrailingZeros for $type_name {
+            fn trailing_zeros(&self) -> u32 {
+                <$type_name>::trailing_zeros(*self)
+            }
+        }
+
+        impl<T: Copy> core::convert::From<Bit<T>> for $type_name
+        where
+            Self: ops::Shl<T, Output = Self> + core::convert::From<u8> + ops::Not<Output = Self>,
+        {
+            fn from(v: Bit<T>) -> Self {
+                let c = Self::from(1u8) << v.index;
+                if v.inverted {
+                    !c
+                } else {
+                    c
+                }
+            }
+        }
+
+        impl<T: Copy> ops::BitAnd<Bit<T>> for $type_name
+        where
+            Self: ops::Shl<T, Output = Self> + core::convert::From<u8>,
+        {
+            type Output = Self;
+            fn bitand(self, rhs: Bit<T>) -> Self::Output {
+                self & Self::from(rhs)
+            }
+        }
+
+        impl<T: Copy> ops::BitOr<Bit<T>> for $type_name
+        where
+            Self: ops::Shl<T, Output = Self> + core::convert::From<u8>,
+        {
+            type Output = Self;
+            fn bitor(self, rhs: Bit<T>) -> Self::Output {
+                self | Self::from(rhs)
+            }
+        }
+
+        impl<T: Copy> ops::BitAndAssign<Bit<T>> for $type_name
+        where
+            Self: ops::Shl<T, Output = Self> + core::convert::From<u8>,
+        {
+            fn bitand_assign(&mut self, rhs: Bit<T>) {
+                *self &= Self::from(rhs)
+            }
+        }
+
+        impl<T: Copy> ops::BitOrAssign<Bit<T>> for $type_name
+        where
+            Self: ops::Shl<T, Output = Self> + core::convert::From<u8>,
+        {
+            fn bitor_assign(&mut self, rhs: Bit<T>) {
+                *self |= Self::from(rhs)
+            }
+        }
+    };
+}
+
+define_unsigned_number_traits!(u8);
+define_unsigned_number_traits!(u16);
+define_unsigned_number_traits!(u32);
+define_unsigned_number_traits!(u64);
+define_unsigned_number_traits!(usize);
+
+/// Returns an iterator over the set bits of `value`.
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::prelude::*;
+/// use kernel::bits_iter;
+///
+/// let mut iter = bits_iter(5usize);
+/// assert_eq!(iter.next().unwrap(), 0);
+/// assert_eq!(iter.next().unwrap(), 2);
+/// assert!(iter.next().is_none());
+/// ```
+///
+/// ```
+/// # use kernel::prelude::*;
+/// use kernel::bits_iter;
+///
+/// fn print_bits(x: usize) {
+///     for bit in bits_iter(x) {
+///         println!("{}", bit);
+///     }
+/// }
+/// ```
+#[inline]
+pub fn bits_iter<T>(value: T) -> impl Iterator<Item = u32>
+where
+    T: core::cmp::PartialEq
+        + From<u8>
+        + ops::Shl<u32, Output = T>
+        + ops::Not<Output = T>
+        + ops::BitAndAssign
+        + TrailingZeros,
+{
+    struct BitIterator<U> {
+        value: U,
+    }
+
+    impl<U> Iterator for BitIterator<U>
+    where
+        U: core::cmp::PartialEq
+            + From<u8>
+            + ops::Shl<u32, Output = U>
+            + ops::Not<Output = U>
+            + ops::BitAndAssign
+            + TrailingZeros,
+    {
+        type Item = u32;
+
+        #[inline]
+        fn next(&mut self) -> Option<u32> {
+            if self.value == U::from(0u8) {
+                return None;
+            }
+            let ret = self.value.trailing_zeros();
+            self.value &= !(U::from(1u8) << ret);
+            Some(ret)
+        }
+    }
+
+    BitIterator { value }
+}
diff --git a/rust/kernel/user_ptr.rs b/rust/kernel/user_ptr.rs
new file mode 100644
index 000000000000..467ead639071
--- /dev/null
+++ b/rust/kernel/user_ptr.rs
@@ -0,0 +1,175 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! User pointers.
+//!
+//! C header: [`include/linux/uaccess.h`](../../../../include/linux/uaccess.h)
+
+use crate::{
+    bindings, c_types,
+    error::Error,
+    io_buffer::{IoBufferReader, IoBufferWriter},
+    Result,
+};
+use alloc::vec::Vec;
+
+/// A reference to an area in userspace memory, which can be either
+/// read-only or read-write.
+///
+/// All methods on this struct are safe: invalid pointers return
+/// `EFAULT`. Concurrent access, *including data races to/from userspace
+/// memory*, is permitted, because fundamentally another userspace
+/// thread/process could always be modifying memory at the same time
+/// (in the same way that userspace Rust's [`std::io`] permits data races
+/// with the contents of files on disk). In the presence of a race, the
+/// exact byte values read/written are unspecified but the operation is
+/// well-defined. Kernelspace code should validate its copy of data
+/// after completing a read, and not expect that multiple reads of the
+/// same address will return the same value.
+///
+/// All APIs enforce the invariant that a given byte of memory from userspace
+/// may only be read once. By preventing double-fetches we avoid TOCTOU
+/// vulnerabilities. This is accomplished by taking `self` by value to prevent
+/// obtaining multiple readers on a given [`UserSlicePtr`], and the readers
+/// only permitting forward reads.
+///
+/// Constructing a [`UserSlicePtr`] performs no checks on the provided
+/// address and length, it can safely be constructed inside a kernel thread
+/// with no current userspace process. Reads and writes wrap the kernel APIs
+/// `copy_from_user` and `copy_to_user`, which check the memory map of the
+/// current process and enforce that the address range is within the user
+/// range (no additional calls to `access_ok` are needed).
+///
+/// [`std::io`]: https://doc.rust-lang.org/std/io/index.html
+pub struct UserSlicePtr(*mut c_types::c_void, usize);
+
+impl UserSlicePtr {
+    /// Constructs a user slice from a raw pointer and a length in bytes.
+    ///
+    /// # Safety
+    ///
+    /// Callers must be careful to avoid time-of-check-time-of-use
+    /// (TOCTOU) issues. The simplest way is to create a single instance of
+    /// [`UserSlicePtr`] per user memory block as it reads each byte at
+    /// most once.
+    pub unsafe fn new(ptr: *mut c_types::c_void, length: usize) -> Self {
+        UserSlicePtr(ptr, length)
+    }
+
+    /// Reads the entirety of the user slice.
+    ///
+    /// Returns `EFAULT` if the address does not currently point to
+    /// mapped, readable memory.
+    pub fn read_all(self) -> Result<Vec<u8>> {
+        self.reader().read_all()
+    }
+
+    /// Constructs a [`UserSlicePtrReader`].
+    pub fn reader(self) -> UserSlicePtrReader {
+        UserSlicePtrReader(self.0, self.1)
+    }
+
+    /// Writes the provided slice into the user slice.
+    ///
+    /// Returns `EFAULT` if the address does not currently point to
+    /// mapped, writable memory (in which case some data from before the
+    /// fault may be written), or `data` is larger than the user slice
+    /// (in which case no data is written).
+    pub fn write_all(self, data: &[u8]) -> Result {
+        self.writer().write_slice(data)
+    }
+
+    /// Constructs a [`UserSlicePtrWriter`].
+    pub fn writer(self) -> UserSlicePtrWriter {
+        UserSlicePtrWriter(self.0, self.1)
+    }
+
+    /// Constructs both a [`UserSlicePtrReader`] and a [`UserSlicePtrWriter`].
+    pub fn reader_writer(self) -> (UserSlicePtrReader, UserSlicePtrWriter) {
+        (
+            UserSlicePtrReader(self.0, self.1),
+            UserSlicePtrWriter(self.0, self.1),
+        )
+    }
+}
+
+/// A reader for [`UserSlicePtr`].
+///
+/// Used to incrementally read from the user slice.
+pub struct UserSlicePtrReader(*mut c_types::c_void, usize);
+
+impl IoBufferReader for UserSlicePtrReader {
+    /// Returns the number of bytes left to be read from this.
+    ///
+    /// Note that even reading less than this number of bytes may fail.
+    fn len(&self) -> usize {
+        self.1
+    }
+
+    /// Reads raw data from the user slice into a raw kernel buffer.
+    ///
+    /// # Safety
+    ///
+    /// The output buffer must be valid.
+    unsafe fn read_raw(&mut self, out: *mut u8, len: usize) -> Result {
+        if len > self.1 || len > u32::MAX as usize {
+            return Err(Error::EFAULT);
+        }
+        let res = unsafe { bindings::copy_from_user(out as _, self.0, len as _) };
+        if res != 0 {
+            return Err(Error::EFAULT);
+        }
+        // Since this is not a pointer to a valid object in our program,
+        // we cannot use `add`, which has C-style rules for defined
+        // behavior.
+        self.0 = self.0.wrapping_add(len);
+        self.1 -= len;
+        Ok(())
+    }
+}
+
+/// A writer for [`UserSlicePtr`].
+///
+/// Used to incrementally write into the user slice.
+pub struct UserSlicePtrWriter(*mut c_types::c_void, usize);
+
+impl IoBufferWriter for UserSlicePtrWriter {
+    fn len(&self) -> usize {
+        self.1
+    }
+
+    fn clear(&mut self, mut len: usize) -> Result {
+        let mut ret = Ok(());
+        if len > self.1 {
+            ret = Err(Error::EFAULT);
+            len = self.1;
+        }
+
+        // SAFETY: The buffer will be validated by `clear_user`. We ensure that `len` is within
+        // bounds in the check above.
+        let left = unsafe { bindings::clear_user(self.0, len as _) } as usize;
+        if left != 0 {
+            ret = Err(Error::EFAULT);
+            len -= left;
+        }
+
+        self.0 = self.0.wrapping_add(len);
+        self.1 -= len;
+        ret
+    }
+
+    unsafe fn write_raw(&mut self, data: *const u8, len: usize) -> Result {
+        if len > self.1 || len > u32::MAX as usize {
+            return Err(Error::EFAULT);
+        }
+        let res = unsafe { bindings::copy_to_user(self.0, data as _, len as _) };
+        if res != 0 {
+            return Err(Error::EFAULT);
+        }
+        // Since this is not a pointer to a valid object in our program,
+        // we cannot use `add`, which has C-style rules for defined
+        // behavior.
+        self.0 = self.0.wrapping_add(len);
+        self.1 -= len;
+        Ok(())
+    }
+}
-- 
2.34.0


^ permalink raw reply related	[relevance 1%]

* [PATCH 16/19] samples: add Rust examples
    2021-12-06 14:03  1% ` [PATCH 09/19] rust: add `kernel` crate Miguel Ojeda
@ 2021-12-06 14:03  3% ` Miguel Ojeda
  1 sibling, 0 replies; 77+ results
From: Miguel Ojeda @ 2021-12-06 14:03 UTC (permalink / raw)
  To: Linus Torvalds, Greg Kroah-Hartman
  Cc: rust-for-linux, linux-kbuild, linux-doc, linux-kernel,
	Miguel Ojeda, Alex Gaynor, Finn Behrens, Wedson Almeida Filho,
	Sven Van Asbroeck, Gary Guo, Boris-Chengbiao Zhou, Ayaan Zaidi,
	Milan Landaverde

A set of Rust modules that showcase how Rust modules look like
and how to use the abstracted kernel features.

These samples also double as tests in the CI.

The semaphore sample comes with a C version for comparison.

Co-developed-by: Alex Gaynor <alex.gaynor@gmail.com>
Signed-off-by: Alex Gaynor <alex.gaynor@gmail.com>
Co-developed-by: Finn Behrens <me@kloenk.de>
Signed-off-by: Finn Behrens <me@kloenk.de>
Co-developed-by: Wedson Almeida Filho <wedsonaf@google.com>
Signed-off-by: Wedson Almeida Filho <wedsonaf@google.com>
Co-developed-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Co-developed-by: Sven Van Asbroeck <thesven73@gmail.com>
Signed-off-by: Sven Van Asbroeck <thesven73@gmail.com>
Co-developed-by: Gary Guo <gary@garyguo.net>
Signed-off-by: Gary Guo <gary@garyguo.net>
Co-developed-by: Boris-Chengbiao Zhou <bobo1239@web.de>
Signed-off-by: Boris-Chengbiao Zhou <bobo1239@web.de>
Co-developed-by: Ayaan Zaidi <zaidi.ayaan@gmail.com>
Signed-off-by: Ayaan Zaidi <zaidi.ayaan@gmail.com>
Co-developed-by: Milan Landaverde <milan@mdaverde.com>
Signed-off-by: Milan Landaverde <milan@mdaverde.com>
Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
---
 samples/Kconfig                        |   2 +
 samples/Makefile                       |   1 +
 samples/rust/Kconfig                   | 113 +++++++++++++
 samples/rust/Makefile                  |  12 ++
 samples/rust/rust_chrdev.rs            |  50 ++++++
 samples/rust/rust_minimal.rs           |  38 +++++
 samples/rust/rust_miscdev.rs           | 149 +++++++++++++++++
 samples/rust/rust_module_parameters.rs |  72 +++++++++
 samples/rust/rust_print.rs             |  57 +++++++
 samples/rust/rust_random.rs            |  61 +++++++
 samples/rust/rust_semaphore.rs         | 174 ++++++++++++++++++++
 samples/rust/rust_semaphore_c.c        | 212 +++++++++++++++++++++++++
 samples/rust/rust_stack_probing.rs     |  40 +++++
 samples/rust/rust_sync.rs              |  81 ++++++++++
 14 files changed, 1062 insertions(+)
 create mode 100644 samples/rust/Kconfig
 create mode 100644 samples/rust/Makefile
 create mode 100644 samples/rust/rust_chrdev.rs
 create mode 100644 samples/rust/rust_minimal.rs
 create mode 100644 samples/rust/rust_miscdev.rs
 create mode 100644 samples/rust/rust_module_parameters.rs
 create mode 100644 samples/rust/rust_print.rs
 create mode 100644 samples/rust/rust_random.rs
 create mode 100644 samples/rust/rust_semaphore.rs
 create mode 100644 samples/rust/rust_semaphore_c.c
 create mode 100644 samples/rust/rust_stack_probing.rs
 create mode 100644 samples/rust/rust_sync.rs

diff --git a/samples/Kconfig b/samples/Kconfig
index 43d2e9aa557f..a3a5166837b1 100644
--- a/samples/Kconfig
+++ b/samples/Kconfig
@@ -241,6 +241,8 @@ config SAMPLE_WATCH_QUEUE
 	  Build example userspace program to use the new mount_notify(),
 	  sb_notify() syscalls and the KEYCTL_WATCH_KEY keyctl() function.
 
+source "samples/rust/Kconfig"
+
 endif # SAMPLES
 
 config HAVE_SAMPLE_FTRACE_DIRECT
diff --git a/samples/Makefile b/samples/Makefile
index 4bcd6b93bffa..d66f49a9f080 100644
--- a/samples/Makefile
+++ b/samples/Makefile
@@ -32,3 +32,4 @@ obj-$(CONFIG_SAMPLE_INTEL_MEI)		+= mei/
 subdir-$(CONFIG_SAMPLE_WATCHDOG)	+= watchdog
 subdir-$(CONFIG_SAMPLE_WATCH_QUEUE)	+= watch_queue
 obj-$(CONFIG_DEBUG_KMEMLEAK_TEST)	+= kmemleak/
+obj-$(CONFIG_SAMPLES_RUST)		+= rust/
diff --git a/samples/rust/Kconfig b/samples/rust/Kconfig
new file mode 100644
index 000000000000..183a3c4dc80c
--- /dev/null
+++ b/samples/rust/Kconfig
@@ -0,0 +1,113 @@
+# SPDX-License-Identifier: GPL-2.0
+
+menuconfig SAMPLES_RUST
+	bool "Rust samples"
+	depends on RUST
+	help
+	  You can build sample Rust kernel code here.
+
+	  If unsure, say N.
+
+if SAMPLES_RUST
+
+config SAMPLE_RUST_MINIMAL
+	tristate "Minimal"
+	help
+	  This option builds the Rust minimal module sample.
+
+	  To compile this as a module, choose M here:
+	  the module will be called rust_minimal.
+
+	  If unsure, say N.
+
+config SAMPLE_RUST_PRINT
+	tristate "Printing macros"
+	help
+	  This option builds the Rust printing macros sample.
+
+	  To compile this as a module, choose M here:
+	  the module will be called rust_print.
+
+	  If unsure, say N.
+
+config SAMPLE_RUST_MODULE_PARAMETERS
+	tristate "Module parameters"
+	help
+	  This option builds the Rust module parameters sample.
+
+	  To compile this as a module, choose M here:
+	  the module will be called rust_module_parameters.
+
+	  If unsure, say N.
+
+config SAMPLE_RUST_SYNC
+	tristate "Synchronisation primitives"
+	help
+	  This option builds the Rust synchronisation primitives sample.
+
+	  To compile this as a module, choose M here:
+	  the module will be called rust_sync.
+
+	  If unsure, say N.
+
+config SAMPLE_RUST_CHRDEV
+	tristate "Character device"
+	help
+	  This option builds the Rust character device sample.
+
+	  To compile this as a module, choose M here:
+	  the module will be called rust_chrdev.
+
+	  If unsure, say N.
+
+config SAMPLE_RUST_MISCDEV
+	tristate "Miscellaneous device"
+	help
+	  This option builds the Rust miscellaneous device sample.
+
+	  To compile this as a module, choose M here:
+	  the module will be called rust_miscdev.
+
+	  If unsure, say N.
+
+config SAMPLE_RUST_STACK_PROBING
+	tristate "Stack probing"
+	help
+	  This option builds the Rust stack probing sample.
+
+	  To compile this as a module, choose M here:
+	  the module will be called rust_stack_probing.
+
+	  If unsure, say N.
+
+config SAMPLE_RUST_SEMAPHORE
+	tristate "Semaphore"
+	help
+	  This option builds the Rust semaphore sample.
+
+	  To compile this as a module, choose M here:
+	  the module will be called rust_semaphore.
+
+	  If unsure, say N.
+
+config SAMPLE_RUST_SEMAPHORE_C
+	tristate "Semaphore (in C, for comparison)"
+	help
+	  This option builds the Rust semaphore sample (in C, for comparison).
+
+	  To compile this as a module, choose M here:
+	  the module will be called rust_semaphore_c.
+
+	  If unsure, say N.
+
+config SAMPLE_RUST_RANDOM
+	tristate "Random"
+	help
+	  This option builds the Rust random sample.
+
+	  To compile this as a module, choose M here:
+	  the module will be called rust_random.
+
+	  If unsure, say N.
+
+endif # SAMPLES_RUST
diff --git a/samples/rust/Makefile b/samples/rust/Makefile
new file mode 100644
index 000000000000..48bc871ea1f8
--- /dev/null
+++ b/samples/rust/Makefile
@@ -0,0 +1,12 @@
+# SPDX-License-Identifier: GPL-2.0
+
+obj-$(CONFIG_SAMPLE_RUST_MINIMAL)		+= rust_minimal.o
+obj-$(CONFIG_SAMPLE_RUST_PRINT)			+= rust_print.o
+obj-$(CONFIG_SAMPLE_RUST_MODULE_PARAMETERS)	+= rust_module_parameters.o
+obj-$(CONFIG_SAMPLE_RUST_SYNC)			+= rust_sync.o
+obj-$(CONFIG_SAMPLE_RUST_CHRDEV)		+= rust_chrdev.o
+obj-$(CONFIG_SAMPLE_RUST_MISCDEV)		+= rust_miscdev.o
+obj-$(CONFIG_SAMPLE_RUST_STACK_PROBING)		+= rust_stack_probing.o
+obj-$(CONFIG_SAMPLE_RUST_SEMAPHORE)		+= rust_semaphore.o
+obj-$(CONFIG_SAMPLE_RUST_SEMAPHORE_C)		+= rust_semaphore_c.o
+obj-$(CONFIG_SAMPLE_RUST_RANDOM)		+= rust_random.o
diff --git a/samples/rust/rust_chrdev.rs b/samples/rust/rust_chrdev.rs
new file mode 100644
index 000000000000..5a37c59019d7
--- /dev/null
+++ b/samples/rust/rust_chrdev.rs
@@ -0,0 +1,50 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Rust character device sample
+
+#![no_std]
+#![feature(allocator_api, global_asm)]
+
+use kernel::prelude::*;
+use kernel::{chrdev, file_operations::FileOperations};
+
+module! {
+    type: RustChrdev,
+    name: b"rust_chrdev",
+    author: b"Rust for Linux Contributors",
+    description: b"Rust character device sample",
+    license: b"GPL v2",
+}
+
+#[derive(Default)]
+struct RustFile;
+
+impl FileOperations for RustFile {
+    kernel::declare_file_operations!();
+}
+
+struct RustChrdev {
+    _dev: Pin<Box<chrdev::Registration<2>>>,
+}
+
+impl KernelModule for RustChrdev {
+    fn init(name: &'static CStr, module: &'static ThisModule) -> Result<Self> {
+        pr_info!("Rust character device sample (init)\n");
+
+        let mut chrdev_reg = chrdev::Registration::new_pinned(name, 0, module)?;
+
+        // Register the same kind of device twice, we're just demonstrating
+        // that you can use multiple minors. There are two minors in this case
+        // because its type is `chrdev::Registration<2>`
+        chrdev_reg.as_mut().register::<RustFile>()?;
+        chrdev_reg.as_mut().register::<RustFile>()?;
+
+        Ok(RustChrdev { _dev: chrdev_reg })
+    }
+}
+
+impl Drop for RustChrdev {
+    fn drop(&mut self) {
+        pr_info!("Rust character device sample (exit)\n");
+    }
+}
diff --git a/samples/rust/rust_minimal.rs b/samples/rust/rust_minimal.rs
new file mode 100644
index 000000000000..3276dbe8ae94
--- /dev/null
+++ b/samples/rust/rust_minimal.rs
@@ -0,0 +1,38 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Rust minimal sample
+
+#![no_std]
+#![feature(allocator_api, global_asm)]
+
+use kernel::prelude::*;
+
+module! {
+    type: RustMinimal,
+    name: b"rust_minimal",
+    author: b"Rust for Linux Contributors",
+    description: b"Rust minimal sample",
+    license: b"GPL v2",
+}
+
+struct RustMinimal {
+    message: String,
+}
+
+impl KernelModule for RustMinimal {
+    fn init(_name: &'static CStr, _module: &'static ThisModule) -> Result<Self> {
+        pr_info!("Rust minimal sample (init)\n");
+        pr_info!("Am I built-in? {}\n", !cfg!(MODULE));
+
+        Ok(RustMinimal {
+            message: "on the heap!".try_to_owned()?,
+        })
+    }
+}
+
+impl Drop for RustMinimal {
+    fn drop(&mut self) {
+        pr_info!("My message is {}\n", self.message);
+        pr_info!("Rust minimal sample (exit)\n");
+    }
+}
diff --git a/samples/rust/rust_miscdev.rs b/samples/rust/rust_miscdev.rs
new file mode 100644
index 000000000000..65dd40027524
--- /dev/null
+++ b/samples/rust/rust_miscdev.rs
@@ -0,0 +1,149 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Rust miscellaneous device sample
+
+#![no_std]
+#![feature(allocator_api, global_asm)]
+
+use kernel::prelude::*;
+use kernel::{
+    file::File,
+    file_operations::{FileOpener, FileOperations},
+    io_buffer::{IoBufferReader, IoBufferWriter},
+    miscdev,
+    sync::{CondVar, Mutex, Ref, RefBorrow, UniqueRef},
+};
+
+module! {
+    type: RustMiscdev,
+    name: b"rust_miscdev",
+    author: b"Rust for Linux Contributors",
+    description: b"Rust miscellaneous device sample",
+    license: b"GPL v2",
+}
+
+const MAX_TOKENS: usize = 3;
+
+struct SharedStateInner {
+    token_count: usize,
+}
+
+struct SharedState {
+    state_changed: CondVar,
+    inner: Mutex<SharedStateInner>,
+}
+
+impl SharedState {
+    fn try_new() -> Result<Ref<Self>> {
+        let mut state = Pin::from(UniqueRef::try_new(Self {
+            // SAFETY: `condvar_init!` is called below.
+            state_changed: unsafe { CondVar::new() },
+            // SAFETY: `mutex_init!` is called below.
+            inner: unsafe { Mutex::new(SharedStateInner { token_count: 0 }) },
+        })?);
+
+        // SAFETY: `state_changed` is pinned when `state` is.
+        let pinned = unsafe { state.as_mut().map_unchecked_mut(|s| &mut s.state_changed) };
+        kernel::condvar_init!(pinned, "SharedState::state_changed");
+
+        // SAFETY: `inner` is pinned when `state` is.
+        let pinned = unsafe { state.as_mut().map_unchecked_mut(|s| &mut s.inner) };
+        kernel::mutex_init!(pinned, "SharedState::inner");
+
+        Ok(state.into())
+    }
+}
+
+struct Token;
+
+impl FileOpener<Ref<SharedState>> for Token {
+    fn open(shared: &Ref<SharedState>, _file: &File) -> Result<Self::Wrapper> {
+        Ok(shared.clone())
+    }
+}
+
+impl FileOperations for Token {
+    type Wrapper = Ref<SharedState>;
+
+    kernel::declare_file_operations!(read, write);
+
+    fn read(
+        shared: RefBorrow<'_, SharedState>,
+        _: &File,
+        data: &mut impl IoBufferWriter,
+        offset: u64,
+    ) -> Result<usize> {
+        // Succeed if the caller doesn't provide a buffer or if not at the start.
+        if data.is_empty() || offset != 0 {
+            return Ok(0);
+        }
+
+        {
+            let mut inner = shared.inner.lock();
+
+            // Wait until we are allowed to decrement the token count or a signal arrives.
+            while inner.token_count == 0 {
+                if shared.state_changed.wait(&mut inner) {
+                    return Err(Error::EINTR);
+                }
+            }
+
+            // Consume a token.
+            inner.token_count -= 1;
+        }
+
+        // Notify a possible writer waiting.
+        shared.state_changed.notify_all();
+
+        // Write a one-byte 1 to the reader.
+        data.write_slice(&[1u8; 1])?;
+        Ok(1)
+    }
+
+    fn write(
+        shared: RefBorrow<'_, SharedState>,
+        _: &File,
+        data: &mut impl IoBufferReader,
+        _offset: u64,
+    ) -> Result<usize> {
+        {
+            let mut inner = shared.inner.lock();
+
+            // Wait until we are allowed to increment the token count or a signal arrives.
+            while inner.token_count == MAX_TOKENS {
+                if shared.state_changed.wait(&mut inner) {
+                    return Err(Error::EINTR);
+                }
+            }
+
+            // Increment the number of token so that a reader can be released.
+            inner.token_count += 1;
+        }
+
+        // Notify a possible reader waiting.
+        shared.state_changed.notify_all();
+        Ok(data.len())
+    }
+}
+
+struct RustMiscdev {
+    _dev: Pin<Box<miscdev::Registration<Ref<SharedState>>>>,
+}
+
+impl KernelModule for RustMiscdev {
+    fn init(name: &'static CStr, _module: &'static ThisModule) -> Result<Self> {
+        pr_info!("Rust miscellaneous device sample (init)\n");
+
+        let state = SharedState::try_new()?;
+
+        Ok(RustMiscdev {
+            _dev: miscdev::Registration::new_pinned::<Token>(name, None, state)?,
+        })
+    }
+}
+
+impl Drop for RustMiscdev {
+    fn drop(&mut self) {
+        pr_info!("Rust miscellaneous device sample (exit)\n");
+    }
+}
diff --git a/samples/rust/rust_module_parameters.rs b/samples/rust/rust_module_parameters.rs
new file mode 100644
index 000000000000..5e4c39648010
--- /dev/null
+++ b/samples/rust/rust_module_parameters.rs
@@ -0,0 +1,72 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Rust module parameters sample
+
+#![no_std]
+#![feature(allocator_api, global_asm)]
+
+use kernel::prelude::*;
+
+module! {
+    type: RustModuleParameters,
+    name: b"rust_module_parameters",
+    author: b"Rust for Linux Contributors",
+    description: b"Rust module parameters sample",
+    license: b"GPL v2",
+    params: {
+        my_bool: bool {
+            default: true,
+            permissions: 0,
+            description: b"Example of bool",
+        },
+        my_i32: i32 {
+            default: 42,
+            permissions: 0o644,
+            description: b"Example of i32",
+        },
+        my_str: str {
+            default: b"default str val",
+            permissions: 0o644,
+            description: b"Example of a string param",
+        },
+        my_usize: usize {
+            default: 42,
+            permissions: 0o644,
+            description: b"Example of usize",
+        },
+        my_array: ArrayParam<i32, 3> {
+            default: [0, 1],
+            permissions: 0,
+            description: b"Example of array",
+        },
+    },
+}
+
+struct RustModuleParameters;
+
+impl KernelModule for RustModuleParameters {
+    fn init(_name: &'static CStr, module: &'static ThisModule) -> Result<Self> {
+        pr_info!("Rust module parameters sample (init)\n");
+
+        {
+            let lock = module.kernel_param_lock();
+            pr_info!("Parameters:\n");
+            pr_info!("  my_bool:    {}\n", my_bool.read());
+            pr_info!("  my_i32:     {}\n", my_i32.read(&lock));
+            pr_info!(
+                "  my_str:     {}\n",
+                core::str::from_utf8(my_str.read(&lock))?
+            );
+            pr_info!("  my_usize:   {}\n", my_usize.read(&lock));
+            pr_info!("  my_array:   {:?}\n", my_array.read());
+        }
+
+        Ok(RustModuleParameters)
+    }
+}
+
+impl Drop for RustModuleParameters {
+    fn drop(&mut self) {
+        pr_info!("Rust module parameters sample (exit)\n");
+    }
+}
diff --git a/samples/rust/rust_print.rs b/samples/rust/rust_print.rs
new file mode 100644
index 000000000000..1b4d14a2d9cc
--- /dev/null
+++ b/samples/rust/rust_print.rs
@@ -0,0 +1,57 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Rust printing macros sample
+
+#![no_std]
+#![feature(allocator_api, global_asm)]
+
+use kernel::prelude::*;
+use kernel::{pr_cont, str::CStr, ThisModule};
+
+module! {
+    type: RustPrint,
+    name: b"rust_print",
+    author: b"Rust for Linux Contributors",
+    description: b"Rust printing macros sample",
+    license: b"GPL v2",
+}
+
+struct RustPrint;
+
+impl KernelModule for RustPrint {
+    fn init(_name: &'static CStr, _module: &'static ThisModule) -> Result<Self> {
+        pr_info!("Rust printing macros sample (init)\n");
+
+        pr_emerg!("Emergency message (level 0) without args\n");
+        pr_alert!("Alert message (level 1) without args\n");
+        pr_crit!("Critical message (level 2) without args\n");
+        pr_err!("Error message (level 3) without args\n");
+        pr_warn!("Warning message (level 4) without args\n");
+        pr_notice!("Notice message (level 5) without args\n");
+        pr_info!("Info message (level 6) without args\n");
+
+        pr_info!("A line that");
+        pr_cont!(" is continued");
+        pr_cont!(" without args\n");
+
+        pr_emerg!("{} message (level {}) with args\n", "Emergency", 0);
+        pr_alert!("{} message (level {}) with args\n", "Alert", 1);
+        pr_crit!("{} message (level {}) with args\n", "Critical", 2);
+        pr_err!("{} message (level {}) with args\n", "Error", 3);
+        pr_warn!("{} message (level {}) with args\n", "Warning", 4);
+        pr_notice!("{} message (level {}) with args\n", "Notice", 5);
+        pr_info!("{} message (level {}) with args\n", "Info", 6);
+
+        pr_info!("A {} that", "line");
+        pr_cont!(" is {}", "continued");
+        pr_cont!(" with {}\n", "args");
+
+        Ok(RustPrint)
+    }
+}
+
+impl Drop for RustPrint {
+    fn drop(&mut self) {
+        pr_info!("Rust printing macros sample (exit)\n");
+    }
+}
diff --git a/samples/rust/rust_random.rs b/samples/rust/rust_random.rs
new file mode 100644
index 000000000000..ef28c5f84f71
--- /dev/null
+++ b/samples/rust/rust_random.rs
@@ -0,0 +1,61 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Rust random device
+//!
+//! Adapted from Alex Gaynor's original available at
+//! <https://github.com/alex/just-use/blob/master/src/lib.rs>.
+
+#![no_std]
+#![feature(allocator_api, global_asm)]
+
+use kernel::{
+    file::File,
+    file_operations::FileOperations,
+    io_buffer::{IoBufferReader, IoBufferWriter},
+    prelude::*,
+};
+
+#[derive(Default)]
+struct RandomFile;
+
+impl FileOperations for RandomFile {
+    kernel::declare_file_operations!(read, write, read_iter, write_iter);
+
+    fn read(_this: &Self, file: &File, buf: &mut impl IoBufferWriter, _: u64) -> Result<usize> {
+        let total_len = buf.len();
+        let mut chunkbuf = [0; 256];
+
+        while !buf.is_empty() {
+            let len = chunkbuf.len().min(buf.len());
+            let chunk = &mut chunkbuf[0..len];
+
+            if file.is_blocking() {
+                kernel::random::getrandom(chunk)?;
+            } else {
+                kernel::random::getrandom_nonblock(chunk)?;
+            }
+            buf.write_slice(chunk)?;
+        }
+        Ok(total_len)
+    }
+
+    fn write(_this: &Self, _file: &File, buf: &mut impl IoBufferReader, _: u64) -> Result<usize> {
+        let total_len = buf.len();
+        let mut chunkbuf = [0; 256];
+        while !buf.is_empty() {
+            let len = chunkbuf.len().min(buf.len());
+            let chunk = &mut chunkbuf[0..len];
+            buf.read_slice(chunk)?;
+            kernel::random::add_randomness(chunk);
+        }
+        Ok(total_len)
+    }
+}
+
+module_misc_device! {
+    type: RandomFile,
+    name: b"rust_random",
+    author: b"Rust for Linux Contributors",
+    description: b"Just use /dev/urandom: Now with early-boot safety",
+    license: b"GPL v2",
+}
diff --git a/samples/rust/rust_semaphore.rs b/samples/rust/rust_semaphore.rs
new file mode 100644
index 000000000000..28f7a34d2942
--- /dev/null
+++ b/samples/rust/rust_semaphore.rs
@@ -0,0 +1,174 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Rust semaphore sample
+//!
+//! A counting semaphore that can be used by userspace.
+//!
+//! The count is incremented by writes to the device. A write of `n` bytes results in an increment
+//! of `n`. It is decremented by reads; each read results in the count being decremented by 1. If
+//! the count is already zero, a read will block until another write increments it.
+//!
+//! This can be used in user space from the shell for example  as follows (assuming a node called
+//! `semaphore`): `cat semaphore` decrements the count by 1 (waiting for it to become non-zero
+//! before decrementing); `echo -n 123 > semaphore` increments the semaphore by 3, potentially
+//! unblocking up to 3 blocked readers.
+
+#![no_std]
+#![feature(allocator_api, global_asm, generic_associated_types)]
+
+use core::sync::atomic::{AtomicU64, Ordering};
+use kernel::{
+    condvar_init, declare_file_operations,
+    file::File,
+    file_operations::{FileOpener, FileOperations, IoctlCommand, IoctlHandler},
+    io_buffer::{IoBufferReader, IoBufferWriter},
+    miscdev::Registration,
+    mutex_init,
+    prelude::*,
+    sync::{CondVar, Mutex, Ref, UniqueRef},
+    user_ptr::{UserSlicePtrReader, UserSlicePtrWriter},
+};
+
+module! {
+    type: RustSemaphore,
+    name: b"rust_semaphore",
+    author: b"Rust for Linux Contributors",
+    description: b"Rust semaphore sample",
+    license: b"GPL v2",
+}
+
+struct SemaphoreInner {
+    count: usize,
+    max_seen: usize,
+}
+
+struct Semaphore {
+    changed: CondVar,
+    inner: Mutex<SemaphoreInner>,
+}
+
+struct FileState {
+    read_count: AtomicU64,
+    shared: Ref<Semaphore>,
+}
+
+impl FileState {
+    fn consume(&self) -> Result {
+        let mut inner = self.shared.inner.lock();
+        while inner.count == 0 {
+            if self.shared.changed.wait(&mut inner) {
+                return Err(Error::EINTR);
+            }
+        }
+        inner.count -= 1;
+        Ok(())
+    }
+}
+
+impl FileOpener<Ref<Semaphore>> for FileState {
+    fn open(shared: &Ref<Semaphore>, _file: &File) -> Result<Box<Self>> {
+        Ok(Box::try_new(Self {
+            read_count: AtomicU64::new(0),
+            shared: shared.clone(),
+        })?)
+    }
+}
+
+impl FileOperations for FileState {
+    declare_file_operations!(read, write, ioctl);
+
+    fn read(this: &Self, _: &File, data: &mut impl IoBufferWriter, offset: u64) -> Result<usize> {
+        if data.is_empty() || offset > 0 {
+            return Ok(0);
+        }
+        this.consume()?;
+        data.write_slice(&[0u8; 1])?;
+        this.read_count.fetch_add(1, Ordering::Relaxed);
+        Ok(1)
+    }
+
+    fn write(this: &Self, _: &File, data: &mut impl IoBufferReader, _offs: u64) -> Result<usize> {
+        {
+            let mut inner = this.shared.inner.lock();
+            inner.count = inner.count.saturating_add(data.len());
+            if inner.count > inner.max_seen {
+                inner.max_seen = inner.count;
+            }
+        }
+
+        this.shared.changed.notify_all();
+        Ok(data.len())
+    }
+
+    fn ioctl(this: &Self, file: &File, cmd: &mut IoctlCommand) -> Result<i32> {
+        cmd.dispatch::<Self>(this, file)
+    }
+}
+
+struct RustSemaphore {
+    _dev: Pin<Box<Registration<Ref<Semaphore>>>>,
+}
+
+impl KernelModule for RustSemaphore {
+    fn init(name: &'static CStr, _module: &'static ThisModule) -> Result<Self> {
+        pr_info!("Rust semaphore sample (init)\n");
+
+        let mut sema = Pin::from(UniqueRef::try_new(Semaphore {
+            // SAFETY: `condvar_init!` is called below.
+            changed: unsafe { CondVar::new() },
+
+            // SAFETY: `mutex_init!` is called below.
+            inner: unsafe {
+                Mutex::new(SemaphoreInner {
+                    count: 0,
+                    max_seen: 0,
+                })
+            },
+        })?);
+
+        // SAFETY: `changed` is pinned when `sema` is.
+        let pinned = unsafe { sema.as_mut().map_unchecked_mut(|s| &mut s.changed) };
+        condvar_init!(pinned, "Semaphore::changed");
+
+        // SAFETY: `inner` is pinned when `sema` is.
+        let pinned = unsafe { sema.as_mut().map_unchecked_mut(|s| &mut s.inner) };
+        mutex_init!(pinned, "Semaphore::inner");
+
+        Ok(Self {
+            _dev: Registration::new_pinned::<FileState>(name, None, sema.into())?,
+        })
+    }
+}
+
+impl Drop for RustSemaphore {
+    fn drop(&mut self) {
+        pr_info!("Rust semaphore sample (exit)\n");
+    }
+}
+
+const IOCTL_GET_READ_COUNT: u32 = 0x80086301;
+const IOCTL_SET_READ_COUNT: u32 = 0x40086301;
+
+impl IoctlHandler for FileState {
+    type Target<'a> = &'a Self;
+
+    fn read(this: &Self, _: &File, cmd: u32, writer: &mut UserSlicePtrWriter) -> Result<i32> {
+        match cmd {
+            IOCTL_GET_READ_COUNT => {
+                writer.write(&this.read_count.load(Ordering::Relaxed))?;
+                Ok(0)
+            }
+            _ => Err(Error::EINVAL),
+        }
+    }
+
+    fn write(this: &Self, _: &File, cmd: u32, reader: &mut UserSlicePtrReader) -> Result<i32> {
+        match cmd {
+            IOCTL_SET_READ_COUNT => {
+                this.read_count.store(reader.read()?, Ordering::Relaxed);
+                Ok(0)
+            }
+            _ => Err(Error::EINVAL),
+        }
+    }
+}
diff --git a/samples/rust/rust_semaphore_c.c b/samples/rust/rust_semaphore_c.c
new file mode 100644
index 000000000000..cdc121d4030d
--- /dev/null
+++ b/samples/rust/rust_semaphore_c.c
@@ -0,0 +1,212 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Rust semaphore sample (in C, for comparison)
+ *
+ * This is a C implementation of `rust_semaphore.rs`. Refer to the description
+ * in that file for details on the device.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/miscdevice.h>
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/slab.h>
+#include <linux/refcount.h>
+#include <linux/wait.h>
+
+#define IOCTL_GET_READ_COUNT _IOR('c', 1, u64)
+#define IOCTL_SET_READ_COUNT _IOW('c', 1, u64)
+
+struct semaphore_state {
+	struct kref ref;
+	struct miscdevice miscdev;
+	wait_queue_head_t changed;
+	struct mutex mutex;
+	size_t count;
+	size_t max_seen;
+};
+
+struct file_state {
+	atomic64_t read_count;
+	struct semaphore_state *shared;
+};
+
+static int semaphore_consume(struct semaphore_state *state)
+{
+	DEFINE_WAIT(wait);
+
+	mutex_lock(&state->mutex);
+	while (state->count == 0) {
+		prepare_to_wait(&state->changed, &wait, TASK_INTERRUPTIBLE);
+		mutex_unlock(&state->mutex);
+		schedule();
+		finish_wait(&state->changed, &wait);
+		if (signal_pending(current))
+			return -EINTR;
+		mutex_lock(&state->mutex);
+	}
+
+	state->count--;
+	mutex_unlock(&state->mutex);
+
+	return 0;
+}
+
+static int semaphore_open(struct inode *nodp, struct file *filp)
+{
+	struct semaphore_state *shared =
+		container_of(filp->private_data, struct semaphore_state, miscdev);
+	struct file_state *state;
+
+	state = kzalloc(sizeof(*state), GFP_KERNEL);
+	if (!state)
+		return -ENOMEM;
+
+	kref_get(&shared->ref);
+	state->shared = shared;
+	atomic64_set(&state->read_count, 0);
+
+	filp->private_data = state;
+
+	return 0;
+}
+
+static ssize_t semaphore_write(struct file *filp, const char __user *buffer, size_t count,
+			       loff_t *ppos)
+{
+	struct file_state *state = filp->private_data;
+	struct semaphore_state *shared = state->shared;
+
+	mutex_lock(&shared->mutex);
+
+	shared->count += count;
+	if (shared->count < count)
+		shared->count = SIZE_MAX;
+
+	if (shared->count > shared->max_seen)
+		shared->max_seen = shared->count;
+
+	mutex_unlock(&shared->mutex);
+
+	wake_up_all(&shared->changed);
+
+	return count;
+}
+
+static ssize_t semaphore_read(struct file *filp, char __user *buffer,
+			      size_t count, loff_t *ppos)
+{
+	struct file_state *state = filp->private_data;
+	char c = 0;
+	int ret;
+
+	if (count == 0 || *ppos > 0)
+		return 0;
+
+	ret = semaphore_consume(state->shared);
+	if (ret)
+		return ret;
+
+	if (copy_to_user(buffer, &c, sizeof(c)))
+		return -EFAULT;
+
+	atomic64_add(1, &state->read_count);
+	*ppos += 1;
+	return 1;
+}
+
+static long semaphore_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
+{
+	struct file_state *state = filp->private_data;
+	void __user *buffer = (void __user *)arg;
+	u64 value;
+
+	switch (cmd) {
+	case IOCTL_GET_READ_COUNT:
+		value = atomic64_read(&state->read_count);
+		if (copy_to_user(buffer, &value, sizeof(value)))
+			return -EFAULT;
+		return 0;
+	case IOCTL_SET_READ_COUNT:
+		if (copy_from_user(&value, buffer, sizeof(value)))
+			return -EFAULT;
+		atomic64_set(&state->read_count, value);
+		return 0;
+	default:
+		return -EINVAL;
+	}
+}
+
+static void semaphore_free(struct kref *kref)
+{
+	struct semaphore_state *device;
+
+	device = container_of(kref, struct semaphore_state, ref);
+	kfree(device);
+}
+
+static int semaphore_release(struct inode *nodp, struct file *filp)
+{
+	struct file_state *state = filp->private_data;
+
+	kref_put(&state->shared->ref, semaphore_free);
+	kfree(state);
+	return 0;
+}
+
+static const struct file_operations semaphore_fops = {
+	.owner = THIS_MODULE,
+	.open = semaphore_open,
+	.read = semaphore_read,
+	.write = semaphore_write,
+	.compat_ioctl = semaphore_ioctl,
+	.release = semaphore_release,
+};
+
+static struct semaphore_state *device;
+
+static int __init semaphore_init(void)
+{
+	int ret;
+	struct semaphore_state *state;
+
+	pr_info("Rust semaphore sample (in C, for comparison) (init)\n");
+
+	state = kzalloc(sizeof(*state), GFP_KERNEL);
+	if (!state)
+		return -ENOMEM;
+
+	mutex_init(&state->mutex);
+	kref_init(&state->ref);
+	init_waitqueue_head(&state->changed);
+
+	state->miscdev.fops = &semaphore_fops;
+	state->miscdev.minor = MISC_DYNAMIC_MINOR;
+	state->miscdev.name = "semaphore";
+
+	ret = misc_register(&state->miscdev);
+	if (ret < 0) {
+		kfree(state);
+		return ret;
+	}
+
+	device = state;
+
+	return 0;
+}
+
+static void __exit semaphore_exit(void)
+{
+	pr_info("Rust semaphore sample (in C, for comparison) (exit)\n");
+
+	misc_deregister(&device->miscdev);
+	kref_put(&device->ref, semaphore_free);
+}
+
+module_init(semaphore_init);
+module_exit(semaphore_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Rust for Linux Contributors");
+MODULE_DESCRIPTION("Rust semaphore sample (in C, for comparison)");
diff --git a/samples/rust/rust_stack_probing.rs b/samples/rust/rust_stack_probing.rs
new file mode 100644
index 000000000000..4f44fade96aa
--- /dev/null
+++ b/samples/rust/rust_stack_probing.rs
@@ -0,0 +1,40 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Rust stack probing sample
+
+#![no_std]
+#![feature(allocator_api, global_asm)]
+#![feature(bench_black_box)]
+
+use kernel::prelude::*;
+
+module! {
+    type: RustStackProbing,
+    name: b"rust_stack_probing",
+    author: b"Rust for Linux Contributors",
+    description: b"Rust stack probing sample",
+    license: b"GPL v2",
+}
+
+struct RustStackProbing;
+
+impl KernelModule for RustStackProbing {
+    fn init(_name: &'static CStr, _module: &'static ThisModule) -> Result<Self> {
+        pr_info!("Rust stack probing sample (init)\n");
+
+        // Including this large variable on the stack will trigger
+        // stack probing on the supported archs.
+        // This will verify that stack probing does not lead to
+        // any errors if we need to link `__rust_probestack`.
+        let x: [u64; 514] = core::hint::black_box([5; 514]);
+        pr_info!("Large array has length: {}\n", x.len());
+
+        Ok(RustStackProbing)
+    }
+}
+
+impl Drop for RustStackProbing {
+    fn drop(&mut self) {
+        pr_info!("Rust stack probing sample (exit)\n");
+    }
+}
diff --git a/samples/rust/rust_sync.rs b/samples/rust/rust_sync.rs
new file mode 100644
index 000000000000..f71f8928d16e
--- /dev/null
+++ b/samples/rust/rust_sync.rs
@@ -0,0 +1,81 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Rust synchronisation primitives sample
+
+#![no_std]
+#![feature(allocator_api, global_asm)]
+
+use kernel::prelude::*;
+use kernel::{
+    condvar_init, mutex_init, spinlock_init,
+    sync::{CondVar, Mutex, SpinLock},
+};
+
+module! {
+    type: RustSync,
+    name: b"rust_sync",
+    author: b"Rust for Linux Contributors",
+    description: b"Rust synchronisation primitives sample",
+    license: b"GPL v2",
+}
+
+struct RustSync;
+
+impl KernelModule for RustSync {
+    fn init(_name: &'static CStr, _module: &'static ThisModule) -> Result<Self> {
+        pr_info!("Rust synchronisation primitives sample (init)\n");
+
+        // Test mutexes.
+        {
+            // SAFETY: `init` is called below.
+            let mut data = Pin::from(Box::try_new(unsafe { Mutex::new(0) })?);
+            mutex_init!(data.as_mut(), "RustSync::init::data1");
+            *data.lock() = 10;
+            pr_info!("Value: {}\n", *data.lock());
+
+            // SAFETY: `init` is called below.
+            let mut cv = Pin::from(Box::try_new(unsafe { CondVar::new() })?);
+            condvar_init!(cv.as_mut(), "RustSync::init::cv1");
+
+            {
+                let mut guard = data.lock();
+                while *guard != 10 {
+                    let _ = cv.wait(&mut guard);
+                }
+            }
+            cv.notify_one();
+            cv.notify_all();
+            cv.free_waiters();
+        }
+
+        // Test spinlocks.
+        {
+            // SAFETY: `init` is called below.
+            let mut data = Pin::from(Box::try_new(unsafe { SpinLock::new(0) })?);
+            spinlock_init!(data.as_mut(), "RustSync::init::data2");
+            *data.lock() = 10;
+            pr_info!("Value: {}\n", *data.lock());
+
+            // SAFETY: `init` is called below.
+            let mut cv = Pin::from(Box::try_new(unsafe { CondVar::new() })?);
+            condvar_init!(cv.as_mut(), "RustSync::init::cv2");
+            {
+                let mut guard = data.lock();
+                while *guard != 10 {
+                    let _ = cv.wait(&mut guard);
+                }
+            }
+            cv.notify_one();
+            cv.notify_all();
+            cv.free_waiters();
+        }
+
+        Ok(RustSync)
+    }
+}
+
+impl Drop for RustSync {
+    fn drop(&mut self) {
+        pr_info!("Rust synchronisation primitives sample (exit)\n");
+    }
+}
-- 
2.34.0


^ permalink raw reply related	[relevance 3%]

* [PATCH v3 09/19] rust: add `kernel` crate
  @ 2022-01-17  5:33  1% ` Miguel Ojeda
  2022-01-17  5:33  3% ` [PATCH v3 16/19] samples: add Rust examples Miguel Ojeda
  1 sibling, 0 replies; 77+ results
From: Miguel Ojeda @ 2022-01-17  5:33 UTC (permalink / raw)
  To: Linus Torvalds, Greg Kroah-Hartman
  Cc: rust-for-linux, linux-kbuild, linux-doc, linux-kernel,
	Miguel Ojeda, Wedson Almeida Filho, Alex Gaynor, Geoffrey Thomas,
	Finn Behrens, Adam Bratschi-Kaye, Michael Ellerman,
	Sumera Priyadarsini, Sven Van Asbroeck, Gary Guo,
	Boris-Chengbiao Zhou, Boqun Feng, Fox Chen, Dan Robertson,
	Viktor Garske, Dariusz Sosnowski, Léo Lanteri Thauvin,
	Niklas Mohrin, Gioh Kim, Daniel Xu, Milan Landaverde,
	Morgan Bartlett, Hsiang-Cheng Yang, Maciej Falkowski

From: Wedson Almeida Filho <wedsonaf@google.com>

The `kernel` crate currently includes all the abstractions that wrap
kernel features written in C.

These abstractions call the C side of the kernel via the generated
bindings with the `bindgen` tool. Modules developed in Rust should
never call the bindings themselves.

In the future, as the abstractions grow in number, we may need
to split this crate into several, possibly following a similar
subdivision in subsystems as the kernel itself and/or moving
the code to the actual subsystems.

Co-developed-by: Alex Gaynor <alex.gaynor@gmail.com>
Signed-off-by: Alex Gaynor <alex.gaynor@gmail.com>
Co-developed-by: Geoffrey Thomas <geofft@ldpreload.com>
Signed-off-by: Geoffrey Thomas <geofft@ldpreload.com>
Co-developed-by: Finn Behrens <me@kloenk.de>
Signed-off-by: Finn Behrens <me@kloenk.de>
Co-developed-by: Adam Bratschi-Kaye <ark.email@gmail.com>
Signed-off-by: Adam Bratschi-Kaye <ark.email@gmail.com>
Co-developed-by: Michael Ellerman <mpe@ellerman.id.au>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Co-developed-by: Sumera Priyadarsini <sylphrenadin@gmail.com>
Signed-off-by: Sumera Priyadarsini <sylphrenadin@gmail.com>
Co-developed-by: Sven Van Asbroeck <thesven73@gmail.com>
Signed-off-by: Sven Van Asbroeck <thesven73@gmail.com>
Co-developed-by: Gary Guo <gary@garyguo.net>
Signed-off-by: Gary Guo <gary@garyguo.net>
Co-developed-by: Boris-Chengbiao Zhou <bobo1239@web.de>
Signed-off-by: Boris-Chengbiao Zhou <bobo1239@web.de>
Co-developed-by: Boqun Feng <boqun.feng@gmail.com>
Signed-off-by: Boqun Feng <boqun.feng@gmail.com>
Co-developed-by: Fox Chen <foxhlchen@gmail.com>
Signed-off-by: Fox Chen <foxhlchen@gmail.com>
Co-developed-by: Dan Robertson <daniel.robertson@starlab.io>
Signed-off-by: Dan Robertson <daniel.robertson@starlab.io>
Co-developed-by: Viktor Garske <viktor@v-gar.de>
Signed-off-by: Viktor Garske <viktor@v-gar.de>
Co-developed-by: Dariusz Sosnowski <dsosnowski@dsosnowski.pl>
Signed-off-by: Dariusz Sosnowski <dsosnowski@dsosnowski.pl>
Co-developed-by: Léo Lanteri Thauvin <leseulartichaut@gmail.com>
Signed-off-by: Léo Lanteri Thauvin <leseulartichaut@gmail.com>
Co-developed-by: Niklas Mohrin <dev@niklasmohrin.de>
Signed-off-by: Niklas Mohrin <dev@niklasmohrin.de>
Co-developed-by: Gioh Kim <gurugio@gmail.com>
Signed-off-by: Gioh Kim <gurugio@gmail.com>
Co-developed-by: Daniel Xu <dxu@dxuuu.xyz>
Signed-off-by: Daniel Xu <dxu@dxuuu.xyz>
Co-developed-by: Milan Landaverde <milan@mdaverde.com>
Signed-off-by: Milan Landaverde <milan@mdaverde.com>
Co-developed-by: Morgan Bartlett <mjmouse9999@gmail.com>
Signed-off-by: Morgan Bartlett <mjmouse9999@gmail.com>
Co-developed-by: Hsiang-Cheng Yang <rick68@gmail.com>
Signed-off-by: Hsiang-Cheng Yang <rick68@gmail.com>
Co-developed-by: Maciej Falkowski <m.falkowski@samsung.com>
Signed-off-by: Maciej Falkowski <m.falkowski@samsung.com>
Signed-off-by: Wedson Almeida Filho <wedsonaf@google.com>
Co-developed-by: Miguel Ojeda <ojeda@kernel.org>
Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
---
 include/linux/spinlock.h            |  17 +-
 kernel/printk/printk.c              |   5 +-
 rust/kernel/allocator.rs            |  65 +++
 rust/kernel/amba.rs                 | 259 ++++++++++
 rust/kernel/bindings.rs             |  47 ++
 rust/kernel/bindings_helper.h       |  31 ++
 rust/kernel/buffer.rs               |  52 ++
 rust/kernel/build_assert.rs         |  80 +++
 rust/kernel/c_types.rs              | 119 +++++
 rust/kernel/chrdev.rs               | 209 ++++++++
 rust/kernel/clk.rs                  |  75 +++
 rust/kernel/cred.rs                 |  73 +++
 rust/kernel/device.rs               | 549 +++++++++++++++++++++
 rust/kernel/driver.rs               | 440 +++++++++++++++++
 rust/kernel/error.rs                | 542 +++++++++++++++++++++
 rust/kernel/file.rs                 | 147 ++++++
 rust/kernel/file_operations.rs      | 726 ++++++++++++++++++++++++++++
 rust/kernel/gpio.rs                 | 477 ++++++++++++++++++
 rust/kernel/io_buffer.rs            | 153 ++++++
 rust/kernel/io_mem.rs               | 227 +++++++++
 rust/kernel/iov_iter.rs             |  81 ++++
 rust/kernel/irq.rs                  | 409 ++++++++++++++++
 rust/kernel/lib.rs                  | 262 ++++++++++
 rust/kernel/linked_list.rs          | 247 ++++++++++
 rust/kernel/miscdev.rs              | 196 ++++++++
 rust/kernel/module_param.rs         | 497 +++++++++++++++++++
 rust/kernel/of.rs                   |  63 +++
 rust/kernel/pages.rs                | 162 +++++++
 rust/kernel/platform.rs             | 224 +++++++++
 rust/kernel/power.rs                | 118 +++++
 rust/kernel/prelude.rs              |  36 ++
 rust/kernel/print.rs                | 441 +++++++++++++++++
 rust/kernel/random.rs               |  50 ++
 rust/kernel/raw_list.rs             | 361 ++++++++++++++
 rust/kernel/rbtree.rs               | 562 +++++++++++++++++++++
 rust/kernel/revocable.rs            | 163 +++++++
 rust/kernel/security.rs             |  36 ++
 rust/kernel/static_assert.rs        |  39 ++
 rust/kernel/std_vendor.rs           | 150 ++++++
 rust/kernel/str.rs                  | 375 ++++++++++++++
 rust/kernel/sync/arc.rs             | 500 +++++++++++++++++++
 rust/kernel/sync/condvar.rs         | 138 ++++++
 rust/kernel/sync/guard.rs           | 181 +++++++
 rust/kernel/sync/locked_by.rs       | 112 +++++
 rust/kernel/sync/mod.rs             |  92 ++++
 rust/kernel/sync/mutex.rs           | 112 +++++
 rust/kernel/sync/revocable_mutex.rs | 184 +++++++
 rust/kernel/sync/seqlock.rs         | 202 ++++++++
 rust/kernel/sync/spinlock.rs        | 180 +++++++
 rust/kernel/sysctl.rs               | 197 ++++++++
 rust/kernel/task.rs                 | 182 +++++++
 rust/kernel/types.rs                | 486 +++++++++++++++++++
 rust/kernel/user_ptr.rs             | 175 +++++++
 53 files changed, 11499 insertions(+), 7 deletions(-)
 create mode 100644 rust/kernel/allocator.rs
 create mode 100644 rust/kernel/amba.rs
 create mode 100644 rust/kernel/bindings.rs
 create mode 100644 rust/kernel/bindings_helper.h
 create mode 100644 rust/kernel/buffer.rs
 create mode 100644 rust/kernel/build_assert.rs
 create mode 100644 rust/kernel/c_types.rs
 create mode 100644 rust/kernel/chrdev.rs
 create mode 100644 rust/kernel/clk.rs
 create mode 100644 rust/kernel/cred.rs
 create mode 100644 rust/kernel/device.rs
 create mode 100644 rust/kernel/driver.rs
 create mode 100644 rust/kernel/error.rs
 create mode 100644 rust/kernel/file.rs
 create mode 100644 rust/kernel/file_operations.rs
 create mode 100644 rust/kernel/gpio.rs
 create mode 100644 rust/kernel/io_buffer.rs
 create mode 100644 rust/kernel/io_mem.rs
 create mode 100644 rust/kernel/iov_iter.rs
 create mode 100644 rust/kernel/irq.rs
 create mode 100644 rust/kernel/lib.rs
 create mode 100644 rust/kernel/linked_list.rs
 create mode 100644 rust/kernel/miscdev.rs
 create mode 100644 rust/kernel/module_param.rs
 create mode 100644 rust/kernel/of.rs
 create mode 100644 rust/kernel/pages.rs
 create mode 100644 rust/kernel/platform.rs
 create mode 100644 rust/kernel/power.rs
 create mode 100644 rust/kernel/prelude.rs
 create mode 100644 rust/kernel/print.rs
 create mode 100644 rust/kernel/random.rs
 create mode 100644 rust/kernel/raw_list.rs
 create mode 100644 rust/kernel/rbtree.rs
 create mode 100644 rust/kernel/revocable.rs
 create mode 100644 rust/kernel/security.rs
 create mode 100644 rust/kernel/static_assert.rs
 create mode 100644 rust/kernel/std_vendor.rs
 create mode 100644 rust/kernel/str.rs
 create mode 100644 rust/kernel/sync/arc.rs
 create mode 100644 rust/kernel/sync/condvar.rs
 create mode 100644 rust/kernel/sync/guard.rs
 create mode 100644 rust/kernel/sync/locked_by.rs
 create mode 100644 rust/kernel/sync/mod.rs
 create mode 100644 rust/kernel/sync/mutex.rs
 create mode 100644 rust/kernel/sync/revocable_mutex.rs
 create mode 100644 rust/kernel/sync/seqlock.rs
 create mode 100644 rust/kernel/sync/spinlock.rs
 create mode 100644 rust/kernel/sysctl.rs
 create mode 100644 rust/kernel/task.rs
 create mode 100644 rust/kernel/types.rs
 create mode 100644 rust/kernel/user_ptr.rs

diff --git a/include/linux/spinlock.h b/include/linux/spinlock.h
index b4e5ca23f840..40e467cdee2d 100644
--- a/include/linux/spinlock.h
+++ b/include/linux/spinlock.h
@@ -326,12 +326,17 @@ static __always_inline raw_spinlock_t *spinlock_check(spinlock_t *lock)
 
 #ifdef CONFIG_DEBUG_SPINLOCK
 
-# define spin_lock_init(lock)					\
-do {								\
-	static struct lock_class_key __key;			\
-								\
-	__raw_spin_lock_init(spinlock_check(lock),		\
-			     #lock, &__key, LD_WAIT_CONFIG);	\
+static inline void __spin_lock_init(spinlock_t *lock, const char *name,
+				    struct lock_class_key *key)
+{
+	__raw_spin_lock_init(spinlock_check(lock), name, key, LD_WAIT_CONFIG);
+}
+
+# define spin_lock_init(lock)			\
+do {						\
+	static struct lock_class_key __key;	\
+						\
+	__spin_lock_init(lock, #lock, &__key);	\
 } while (0)
 
 #else
diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
index 57b132b658e1..cbc35d586afb 100644
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -392,7 +392,10 @@ static struct latched_seq clear_seq = {
 /* the maximum size of a formatted record (i.e. with prefix added per line) */
 #define CONSOLE_LOG_MAX		1024
 
-/* the maximum size allowed to be reserved for a record */
+/*
+ * The maximum size allowed to be reserved for a record.
+ * Keep in sync with rust/kernel/print.rs.
+ */
 #define LOG_LINE_MAX		(CONSOLE_LOG_MAX - PREFIX_MAX)
 
 #define LOG_LEVEL(v)		((v) & 0x07)
diff --git a/rust/kernel/allocator.rs b/rust/kernel/allocator.rs
new file mode 100644
index 000000000000..4c5d2fc6f206
--- /dev/null
+++ b/rust/kernel/allocator.rs
@@ -0,0 +1,65 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Allocator support.
+
+use core::alloc::{GlobalAlloc, Layout};
+use core::ptr;
+
+use crate::bindings;
+use crate::c_types;
+
+struct KernelAllocator;
+
+unsafe impl GlobalAlloc for KernelAllocator {
+    unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
+        // `krealloc()` is used instead of `kmalloc()` because the latter is
+        // an inline function and cannot be bound to as a result.
+        unsafe { bindings::krealloc(ptr::null(), layout.size(), bindings::GFP_KERNEL) as *mut u8 }
+    }
+
+    unsafe fn dealloc(&self, ptr: *mut u8, _layout: Layout) {
+        unsafe {
+            bindings::kfree(ptr as *const c_types::c_void);
+        }
+    }
+}
+
+#[global_allocator]
+static ALLOCATOR: KernelAllocator = KernelAllocator;
+
+// `rustc` only generates these for some crate types. Even then, we would need
+// to extract the object file that has them from the archive. For the moment,
+// let's generate them ourselves instead.
+//
+// Note that `#[no_mangle]` implies exported too, nowadays.
+#[no_mangle]
+fn __rust_alloc(size: usize, _align: usize) -> *mut u8 {
+    unsafe { bindings::krealloc(core::ptr::null(), size, bindings::GFP_KERNEL) as *mut u8 }
+}
+
+#[no_mangle]
+fn __rust_dealloc(ptr: *mut u8, _size: usize, _align: usize) {
+    unsafe { bindings::kfree(ptr as *const c_types::c_void) };
+}
+
+#[no_mangle]
+fn __rust_realloc(ptr: *mut u8, _old_size: usize, _align: usize, new_size: usize) -> *mut u8 {
+    unsafe {
+        bindings::krealloc(
+            ptr as *const c_types::c_void,
+            new_size,
+            bindings::GFP_KERNEL,
+        ) as *mut u8
+    }
+}
+
+#[no_mangle]
+fn __rust_alloc_zeroed(size: usize, _align: usize) -> *mut u8 {
+    unsafe {
+        bindings::krealloc(
+            core::ptr::null(),
+            size,
+            bindings::GFP_KERNEL | bindings::__GFP_ZERO,
+        ) as *mut u8
+    }
+}
diff --git a/rust/kernel/amba.rs b/rust/kernel/amba.rs
new file mode 100644
index 000000000000..1775eda7dce6
--- /dev/null
+++ b/rust/kernel/amba.rs
@@ -0,0 +1,259 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Amba devices and drivers.
+//!
+//! C header: [`include/linux/amba/bus.h`](../../../../include/linux/amba/bus.h)
+
+use crate::{
+    bindings, c_types, device, driver, error::from_kernel_result, io_mem::Resource, power,
+    str::CStr, to_result, types::PointerWrapper, Result, ThisModule,
+};
+
+/// A registration of an amba driver.
+pub type Registration<T> = driver::Registration<Adapter<T>>;
+
+/// Id of an Amba device.
+#[derive(Clone, Copy)]
+pub struct DeviceId {
+    /// Device id.
+    pub id: u32,
+
+    /// Mask that identifies which bits are valid in the device id.
+    pub mask: u32,
+}
+
+// SAFETY: `ZERO` is all zeroed-out and `to_rawid` stores `offset` in `amba_id::data`.
+unsafe impl const driver::RawDeviceId for DeviceId {
+    type RawType = bindings::amba_id;
+    const ZERO: Self::RawType = bindings::amba_id {
+        id: 0,
+        mask: 0,
+        data: core::ptr::null_mut(),
+    };
+
+    fn to_rawid(&self, offset: isize) -> Self::RawType {
+        bindings::amba_id {
+            id: self.id,
+            mask: self.mask,
+            data: offset as _,
+        }
+    }
+}
+
+/// An amba driver.
+pub trait Driver {
+    /// Data stored on device by driver.
+    type Data: PointerWrapper + Send + Sync + driver::DeviceRemoval = ();
+
+    /// The type that implements the power-management operations.
+    ///
+    /// The default is a type that implements no power-management operations. Drivers that do
+    /// implement them need to specify the type (commonly [`Self`]).
+    type PowerOps: power::Operations<Data = Self::Data> = power::NoOperations<Self::Data>;
+
+    /// The type holding information about each device id supported by the driver.
+    type IdInfo: 'static = ();
+
+    /// The table of device ids supported by the driver.
+    const ID_TABLE: Option<driver::IdTable<'static, DeviceId, Self::IdInfo>> = None;
+
+    /// Probes for the device with the given id.
+    fn probe(dev: &mut Device, id_info: Option<&Self::IdInfo>) -> Result<Self::Data>;
+
+    /// Cleans any resources up that are associated with the device.
+    ///
+    /// This is called when the driver is detached from the device.
+    fn remove(_data: &Self::Data) {}
+}
+
+/// An adapter for the registration of Amba drivers.
+pub struct Adapter<T: Driver>(T);
+
+impl<T: Driver> driver::DriverOps for Adapter<T> {
+    type RegType = bindings::amba_driver;
+
+    unsafe fn register(
+        reg: *mut bindings::amba_driver,
+        name: &'static CStr,
+        module: &'static ThisModule,
+    ) -> Result {
+        // SAFETY: By the safety requirements of this function (defined in the trait defintion),
+        // `reg` is non-null and valid.
+        let amba = unsafe { &mut *reg };
+        amba.drv.name = name.as_char_ptr();
+        amba.drv.owner = module.0;
+        amba.probe = Some(probe_callback::<T>);
+        amba.remove = Some(remove_callback::<T>);
+        if let Some(t) = T::ID_TABLE {
+            amba.id_table = t.as_ref();
+        }
+        if cfg!(CONFIG_PM) {
+            // SAFETY: `probe_callback` sets the driver data after calling `T::Data::into_pointer`,
+            // and we guarantee that `T::Data` is the same as `T::PowerOps::Data` by a constraint
+            // in the type declaration.
+            amba.drv.pm = unsafe { power::OpsTable::<T::PowerOps>::build() };
+        }
+        // SAFETY: By the safety requirements of this function, `reg` is valid and fully
+        // initialised.
+        to_result(|| unsafe { bindings::amba_driver_register(reg) })
+    }
+
+    unsafe fn unregister(reg: *mut bindings::amba_driver) {
+        // SAFETY: By the safety requirements of this function (defined in the trait definition),
+        // `reg` was passed (and updated) by a previous successful call to `amba_driver_register`.
+        unsafe { bindings::amba_driver_unregister(reg) };
+    }
+}
+
+unsafe extern "C" fn probe_callback<T: Driver>(
+    adev: *mut bindings::amba_device,
+    aid: *const bindings::amba_id,
+) -> c_types::c_int {
+    from_kernel_result! {
+        // SAFETY: `adev` is valid by the contract with the C code. `dev` is alive only for the
+        // duration of this call, so it is guaranteed to remain alive for the lifetime of `dev`.
+        let mut dev = unsafe { Device::from_ptr(adev) };
+        // SAFETY: `aid` is valid by the requirements the contract with the C code.
+        let offset = unsafe { (*aid).data };
+        let info = if offset.is_null() {
+            None
+        } else {
+            // SAFETY: The offset comes from a previous call to `offset_from` in `IdArray::new`,
+            // which guarantees that the resulting pointer is within the table.
+            let ptr = unsafe { aid.cast::<u8>().offset(offset as _).cast::<Option<T::IdInfo>>() };
+            // SAFETY: The id table has a static lifetime, so `ptr` is guaranteed to be valid for
+            // read.
+            unsafe { (&*ptr).as_ref() }
+        };
+        let data = T::probe(&mut dev, info)?;
+        let ptr = T::Data::into_pointer(data);
+        // SAFETY: `adev` is valid for write by the contract with the C code.
+        unsafe { bindings::amba_set_drvdata(adev, ptr as _) };
+        Ok(0)
+    }
+}
+
+unsafe extern "C" fn remove_callback<T: Driver>(adev: *mut bindings::amba_device) {
+    // SAFETY: `adev` is valid by the contract with the C code.
+    let ptr = unsafe { bindings::amba_get_drvdata(adev) };
+    // SAFETY: The value returned by `amba_get_drvdata` was stored by a previous call to
+    // `amba_set_drvdata` in `probe_callback` above; the value comes from a call to
+    // `T::Data::into_pointer`.
+    let data = unsafe { T::Data::from_pointer(ptr) };
+    T::remove(&data);
+    <T::Data as driver::DeviceRemoval>::device_remove(&data);
+}
+
+/// An Amba device.
+///
+/// # Invariants
+///
+/// The field `ptr` is non-null and valid for the lifetime of the object.
+pub struct Device {
+    ptr: *mut bindings::amba_device,
+    res: Option<Resource>,
+}
+
+impl Device {
+    /// Creates a new device from the given pointer.
+    ///
+    /// # Safety
+    ///
+    /// `ptr` must be non-null and valid. It must remain valid for the lifetime of the returned
+    /// instance.
+    unsafe fn from_ptr(ptr: *mut bindings::amba_device) -> Self {
+        // SAFETY: The safety requirements of the function ensure that `ptr` is valid.
+        let dev = unsafe { &mut *ptr };
+        // INVARIANT: The safety requirements of the function ensure the lifetime invariant.
+        Self {
+            ptr,
+            res: Resource::new(dev.res.start, dev.res.end),
+        }
+    }
+
+    /// Returns the io mem resource associated with the device, if there is one.
+    ///
+    /// Ownership of the resource is transferred to the caller, so subsequent calls to this
+    /// function will return [`None`].
+    pub fn take_resource(&mut self) -> Option<Resource> {
+        self.res.take()
+    }
+
+    /// Returns the index-th irq associated with the device, if one exists.
+    pub fn irq(&self, index: usize) -> Option<u32> {
+        // SAFETY: By the type invariants, `self.ptr` is valid for read.
+        let dev = unsafe { &*self.ptr };
+        if index >= dev.irq.len() || dev.irq[index] == 0 {
+            None
+        } else {
+            Some(dev.irq[index])
+        }
+    }
+}
+
+// SAFETY: The device returned by `raw_device` is the raw Amba device.
+unsafe impl device::RawDevice for Device {
+    fn raw_device(&self) -> *mut bindings::device {
+        // SAFETY: By the type invariants, we know that `self.ptr` is non-null and valid.
+        unsafe { &mut (*self.ptr).dev }
+    }
+}
+
+/// Declares a kernel module that exposes a single amba driver.
+///
+/// # Examples
+///
+/// ```ignore
+/// # use kernel::prelude::*;
+/// # use kernel::{amba, define_amba_id_table, module_amba_driver};
+/// #
+/// struct MyDriver;
+/// impl amba::Driver for MyDriver {
+///     // [...]
+/// #   fn probe(_dev: &mut amba::Device, _id: Option<&Self::IdInfo>) -> Result {
+/// #       Ok(())
+/// #   }
+/// #   define_amba_id_table! {(), [
+/// #       ({ id: 0x00041061, mask: 0x000fffff }, None),
+/// #   ]}
+/// }
+///
+/// module_amba_driver! {
+///     type: MyDriver,
+///     name: b"module_name",
+///     author: b"Author name",
+///     license: b"GPL v2",
+/// }
+/// ```
+#[macro_export]
+macro_rules! module_amba_driver {
+    ($($f:tt)*) => {
+        $crate::module_driver!(<T>, $crate::amba::Adapter<T>, { $($f)* });
+    };
+}
+
+/// Defines the id table for amba devices.
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::prelude::*;
+/// # use kernel::{amba, define_amba_id_table};
+/// #
+/// # struct Sample;
+/// # impl kernel::amba::Driver for Sample {
+/// #   fn probe(_dev: &mut amba::Device, _id: Option<&Self::IdInfo>) -> Result {
+/// #       Ok(())
+/// #   }
+///     define_amba_id_table! {(), [
+///         ({ id: 0x00041061, mask: 0x000fffff }, None),
+///     ]}
+/// # }
+/// ```
+#[macro_export]
+macro_rules! define_amba_id_table {
+    ($data_type:ty, $($t:tt)*) => {
+        type IdInfo = $data_type;
+        $crate::define_id_table!(ID_TABLE, $crate::amba::DeviceId, $data_type, $($t)*);
+    };
+}
diff --git a/rust/kernel/bindings.rs b/rust/kernel/bindings.rs
new file mode 100644
index 000000000000..02678ca589c8
--- /dev/null
+++ b/rust/kernel/bindings.rs
@@ -0,0 +1,47 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Bindings
+//!
+//! Imports the generated bindings by `bindgen`.
+
+// See https://github.com/rust-lang/rust-bindgen/issues/1651.
+#![cfg_attr(test, allow(deref_nullptr))]
+#![cfg_attr(test, allow(unaligned_references))]
+#![cfg_attr(test, allow(unsafe_op_in_unsafe_fn))]
+#![allow(
+    clippy::all,
+    non_camel_case_types,
+    non_upper_case_globals,
+    non_snake_case,
+    improper_ctypes,
+    unreachable_pub,
+    unsafe_op_in_unsafe_fn
+)]
+
+mod bindings_raw {
+    // Use glob import here to expose all helpers.
+    // Symbols defined within the module will take precedence to the glob import.
+    pub use super::bindings_helper::*;
+    use crate::c_types;
+    include!(concat!(env!("OBJTREE"), "/rust/bindings_generated.rs"));
+}
+
+// When both a directly exposed symbol and a helper exists for the same function,
+// the directly exposed symbol is preferred and the helper becomes dead code, so
+// ignore the warning here.
+#[allow(dead_code)]
+mod bindings_helper {
+    // Import the generated bindings for types.
+    use super::bindings_raw::*;
+    use crate::c_types;
+    include!(concat!(
+        env!("OBJTREE"),
+        "/rust/bindings_helpers_generated.rs"
+    ));
+}
+
+pub use bindings_raw::*;
+
+pub const GFP_KERNEL: gfp_t = BINDINGS_GFP_KERNEL;
+pub const __GFP_ZERO: gfp_t = BINDINGS___GFP_ZERO;
+pub const __GFP_HIGHMEM: gfp_t = ___GFP_HIGHMEM;
diff --git a/rust/kernel/bindings_helper.h b/rust/kernel/bindings_helper.h
new file mode 100644
index 000000000000..99a7d785ae01
--- /dev/null
+++ b/rust/kernel/bindings_helper.h
@@ -0,0 +1,31 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#include <linux/cdev.h>
+#include <linux/clk.h>
+#include <linux/errname.h>
+#include <linux/fs.h>
+#include <linux/module.h>
+#include <linux/random.h>
+#include <linux/slab.h>
+#include <linux/sysctl.h>
+#include <linux/uaccess.h>
+#include <linux/uio.h>
+#include <linux/version.h>
+#include <linux/miscdevice.h>
+#include <linux/poll.h>
+#include <linux/mm.h>
+#include <linux/file.h>
+#include <uapi/linux/android/binder.h>
+#include <linux/platform_device.h>
+#include <linux/of_platform.h>
+#include <linux/security.h>
+#include <asm/io.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/irqdomain.h>
+#include <linux/amba/bus.h>
+#include <linux/gpio/driver.h>
+
+// `bindgen` gets confused at certain things
+const gfp_t BINDINGS_GFP_KERNEL = GFP_KERNEL;
+const gfp_t BINDINGS___GFP_ZERO = __GFP_ZERO;
diff --git a/rust/kernel/buffer.rs b/rust/kernel/buffer.rs
new file mode 100644
index 000000000000..48f429065323
--- /dev/null
+++ b/rust/kernel/buffer.rs
@@ -0,0 +1,52 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Struct for writing to a pre-allocated buffer with the [`write!`] macro.
+
+use core::fmt;
+
+/// A pre-allocated buffer that implements [`core::fmt::Write`].
+///
+/// Consecutive writes will append to what has already been written.
+/// Writes that don't fit in the buffer will fail.
+pub struct Buffer<'a> {
+    slice: &'a mut [u8],
+    pos: usize,
+}
+
+impl<'a> Buffer<'a> {
+    /// Creates a new buffer from an existing array.
+    pub fn new(slice: &'a mut [u8]) -> Self {
+        Buffer { slice, pos: 0 }
+    }
+
+    /// Creates a new buffer from a raw pointer.
+    ///
+    /// # Safety
+    ///
+    /// `ptr` must be valid for read and writes, have at least `len` bytes in
+    /// size, and remain valid and not be used by other threads for the lifetime
+    /// of the returned instance.
+    pub unsafe fn from_raw(ptr: *mut u8, len: usize) -> Self {
+        // SAFETY: The safety requirements of the function satisfy those of
+        // `from_raw_parts_mut`.
+        Self::new(unsafe { core::slice::from_raw_parts_mut(ptr, len) })
+    }
+
+    /// Number of bytes that have already been written to the buffer.
+    /// This will always be less than the length of the original array.
+    pub fn bytes_written(&self) -> usize {
+        self.pos
+    }
+}
+
+impl fmt::Write for Buffer<'_> {
+    fn write_str(&mut self, s: &str) -> fmt::Result {
+        if s.len() > self.slice.len() - self.pos {
+            Err(fmt::Error)
+        } else {
+            self.slice[self.pos..self.pos + s.len()].copy_from_slice(s.as_bytes());
+            self.pos += s.len();
+            Ok(())
+        }
+    }
+}
diff --git a/rust/kernel/build_assert.rs b/rust/kernel/build_assert.rs
new file mode 100644
index 000000000000..f726927185c0
--- /dev/null
+++ b/rust/kernel/build_assert.rs
@@ -0,0 +1,80 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Build-time assert.
+
+/// Fails the build if the code path calling `build_error!` can possibly be executed.
+///
+/// If the macro is executed in const context, `build_error!` will panic.
+/// If the compiler or optimizer cannot guarantee that `build_error!` can never
+/// be called, a build error will be triggered.
+///
+/// # Examples
+/// ```
+/// # use kernel::build_error;
+/// #[inline]
+/// fn foo(a: usize) -> usize {
+///     a.checked_add(1).unwrap_or_else(|| build_error!("overflow"))
+/// }
+/// ```
+#[macro_export]
+macro_rules! build_error {
+    () => {{
+        $crate::build_error("")
+    }};
+    ($msg:expr) => {{
+        $crate::build_error($msg)
+    }};
+}
+
+/// Asserts that a boolean expression is `true` at compile time.
+///
+/// If the condition is evaluated to `false` in const context, `build_assert!`
+/// will panic. If the compiler or optimizer cannot guarantee the condition will
+/// be evaluated to `true`, a build error will be triggered.
+///
+/// [`static_assert!`] should be preferred to `build_assert!` whenever possible.
+///
+/// # Examples
+///
+/// These examples show that different types of [`assert!`] will trigger errors
+/// at different stage of compilation. It is preferred to err as early as
+/// possible, so [`static_assert!`] should be used whenever possible.
+/// ```compile_fail
+/// # use kernel::prelude::*;
+/// fn foo() {
+///     static_assert!(1 > 1); // Compile-time error
+///     build_assert!(1 > 1); // Build-time error
+///     assert!(1 > 1); // Run-time error
+/// }
+/// ```
+///
+/// When the condition refers to generic parameters or parameters of an inline function,
+/// [`static_assert!`] cannot be used. Use `build_assert!` in this scenario.
+/// ```no_run
+/// # use kernel::prelude::*;
+/// fn foo<const N: usize>() {
+///     // `static_assert!(N > 1);` is not allowed
+///     build_assert!(N > 1); // Build-time check
+///     assert!(N > 1); // Run-time check
+/// }
+///
+/// #[inline]
+/// fn bar(n: usize) {
+///     // `static_assert!(n > 1);` is not allowed
+///     build_assert!(n > 1); // Build-time check
+///     assert!(n > 1); // Run-time check
+/// }
+/// ```
+#[macro_export]
+macro_rules! build_assert {
+    ($cond:expr $(,)?) => {{
+        if !$cond {
+            $crate::build_error(concat!("assertion failed: ", stringify!($cond)));
+        }
+    }};
+    ($cond:expr, $msg:expr) => {{
+        if !$cond {
+            $crate::build_error($msg);
+        }
+    }};
+}
diff --git a/rust/kernel/c_types.rs b/rust/kernel/c_types.rs
new file mode 100644
index 000000000000..07593a3ba8be
--- /dev/null
+++ b/rust/kernel/c_types.rs
@@ -0,0 +1,119 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! C types for the bindings.
+//!
+//! The bindings generated by `bindgen` use these types to map to the C ones.
+//!
+//! C's standard integer types may differ in width depending on
+//! the architecture, thus we need to conditionally compile those.
+
+#![allow(non_camel_case_types)]
+
+#[cfg(any(target_arch = "arm", target_arch = "x86", target_arch = "riscv32",))]
+mod c {
+    /// C `void` type.
+    pub type c_void = core::ffi::c_void;
+
+    /// C `char` type.
+    pub type c_char = i8;
+
+    /// C `signed char` type.
+    pub type c_schar = i8;
+
+    /// C `unsigned char` type.
+    pub type c_uchar = u8;
+
+    /// C `short` type.
+    pub type c_short = i16;
+
+    /// C `unsigned short` type.
+    pub type c_ushort = u16;
+
+    /// C `int` type.
+    pub type c_int = i32;
+
+    /// C `unsigned int` type.
+    pub type c_uint = u32;
+
+    /// C `long` type.
+    pub type c_long = i32;
+
+    /// C `unsigned long` type.
+    pub type c_ulong = u32;
+
+    /// C `long long` type.
+    pub type c_longlong = i64;
+
+    /// C `unsigned long long` type.
+    pub type c_ulonglong = u64;
+
+    /// C `ssize_t` type (typically defined in `<sys/types.h>` by POSIX).
+    ///
+    /// For some 32-bit architectures like this one, the kernel defines it as
+    /// `int`, i.e. it is an [`i32`].
+    pub type c_ssize_t = isize;
+
+    /// C `size_t` type (typically defined in `<stddef.h>`).
+    ///
+    /// For some 32-bit architectures like this one, the kernel defines it as
+    /// `unsigned int`, i.e. it is an [`u32`].
+    pub type c_size_t = usize;
+}
+
+#[cfg(any(
+    target_arch = "aarch64",
+    target_arch = "x86_64",
+    target_arch = "powerpc64",
+    target_arch = "riscv64",
+))]
+mod c {
+    /// C `void` type.
+    pub type c_void = core::ffi::c_void;
+
+    /// C `char` type.
+    pub type c_char = i8;
+
+    /// C `signed char` type.
+    pub type c_schar = i8;
+
+    /// C `unsigned char` type.
+    pub type c_uchar = u8;
+
+    /// C `short` type.
+    pub type c_short = i16;
+
+    /// C `unsigned short` type.
+    pub type c_ushort = u16;
+
+    /// C `int` type.
+    pub type c_int = i32;
+
+    /// C `unsigned int` type.
+    pub type c_uint = u32;
+
+    /// C `long` type.
+    pub type c_long = i64;
+
+    /// C `unsigned long` type.
+    pub type c_ulong = u64;
+
+    /// C `long long` type.
+    pub type c_longlong = i64;
+
+    /// C `unsigned long long` type.
+    pub type c_ulonglong = u64;
+
+    /// C `ssize_t` type (typically defined in `<sys/types.h>` by POSIX).
+    ///
+    /// For 64-bit architectures like this one, the kernel defines it as
+    /// `long`, i.e. it is an [`i64`].
+    pub type c_ssize_t = isize;
+
+    /// C `size_t` type (typically defined in `<stddef.h>`).
+    ///
+    /// For 64-bit architectures like this one, the kernel defines it as
+    /// `unsigned long`, i.e. it is an [`u64`].
+    pub type c_size_t = usize;
+}
+
+pub use c::*;
diff --git a/rust/kernel/chrdev.rs b/rust/kernel/chrdev.rs
new file mode 100644
index 000000000000..6dd744242183
--- /dev/null
+++ b/rust/kernel/chrdev.rs
@@ -0,0 +1,209 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Character devices.
+//!
+//! Also called "char devices", `chrdev`, `cdev`.
+//!
+//! C header: [`include/linux/cdev.h`](../../../../include/linux/cdev.h)
+//!
+//! Reference: <https://www.kernel.org/doc/html/latest/core-api/kernel-api.html#char-devices>
+
+use alloc::boxed::Box;
+use core::convert::TryInto;
+use core::marker::PhantomPinned;
+use core::pin::Pin;
+
+use crate::bindings;
+use crate::c_types;
+use crate::error::{Error, Result};
+use crate::file_operations;
+use crate::str::CStr;
+
+/// Character device.
+///
+/// # Invariants
+///
+/// - [`self.0`] is valid and non-null.
+/// - [`(*self.0).ops`] is valid, non-null and has static lifetime.
+/// - [`(*self.0).owner`] is valid and, if non-null, has module lifetime.
+struct Cdev(*mut bindings::cdev);
+
+impl Cdev {
+    fn alloc(
+        fops: &'static bindings::file_operations,
+        module: &'static crate::ThisModule,
+    ) -> Result<Self> {
+        // SAFETY: FFI call.
+        let cdev = unsafe { bindings::cdev_alloc() };
+        if cdev.is_null() {
+            return Err(Error::ENOMEM);
+        }
+        // SAFETY: `cdev` is valid and non-null since `cdev_alloc()`
+        // returned a valid pointer which was null-checked.
+        unsafe {
+            (*cdev).ops = fops;
+            (*cdev).owner = module.0;
+        }
+        // INVARIANTS:
+        // - [`self.0`] is valid and non-null.
+        // - [`(*self.0).ops`] is valid, non-null and has static lifetime,
+        //   because it was coerced from a reference with static lifetime.
+        // - [`(*self.0).owner`] is valid and, if non-null, has module lifetime,
+        //   guaranteed by the [`ThisModule`] invariant.
+        Ok(Self(cdev))
+    }
+
+    fn add(&mut self, dev: bindings::dev_t, count: c_types::c_uint) -> Result {
+        // SAFETY: according to the type invariants:
+        // - [`self.0`] can be safely passed to [`bindings::cdev_add`].
+        // - [`(*self.0).ops`] will live at least as long as [`self.0`].
+        // - [`(*self.0).owner`] will live at least as long as the
+        //   module, which is an implicit requirement.
+        let rc = unsafe { bindings::cdev_add(self.0, dev, count) };
+        if rc != 0 {
+            return Err(Error::from_kernel_errno(rc));
+        }
+        Ok(())
+    }
+}
+
+impl Drop for Cdev {
+    fn drop(&mut self) {
+        // SAFETY: [`self.0`] is valid and non-null by the type invariants.
+        unsafe {
+            bindings::cdev_del(self.0);
+        }
+    }
+}
+
+struct RegistrationInner<const N: usize> {
+    dev: bindings::dev_t,
+    used: usize,
+    cdevs: [Option<Cdev>; N],
+    _pin: PhantomPinned,
+}
+
+/// Character device registration.
+///
+/// May contain up to a fixed number (`N`) of devices. Must be pinned.
+pub struct Registration<const N: usize> {
+    name: &'static CStr,
+    minors_start: u16,
+    this_module: &'static crate::ThisModule,
+    inner: Option<RegistrationInner<N>>,
+}
+
+impl<const N: usize> Registration<{ N }> {
+    /// Creates a [`Registration`] object for a character device.
+    ///
+    /// This does *not* register the device: see [`Self::register()`].
+    ///
+    /// This associated function is intended to be used when you need to avoid
+    /// a memory allocation, e.g. when the [`Registration`] is a member of
+    /// a bigger structure inside your [`crate::KernelModule`] instance. If you
+    /// are going to pin the registration right away, call
+    /// [`Self::new_pinned()`] instead.
+    pub fn new(
+        name: &'static CStr,
+        minors_start: u16,
+        this_module: &'static crate::ThisModule,
+    ) -> Self {
+        Registration {
+            name,
+            minors_start,
+            this_module,
+            inner: None,
+        }
+    }
+
+    /// Creates a pinned [`Registration`] object for a character device.
+    ///
+    /// This does *not* register the device: see [`Self::register()`].
+    pub fn new_pinned(
+        name: &'static CStr,
+        minors_start: u16,
+        this_module: &'static crate::ThisModule,
+    ) -> Result<Pin<Box<Self>>> {
+        Ok(Pin::from(Box::try_new(Self::new(
+            name,
+            minors_start,
+            this_module,
+        ))?))
+    }
+
+    /// Registers a character device.
+    ///
+    /// You may call this once per device type, up to `N` times.
+    pub fn register<T: file_operations::FileOperations<OpenData = ()>>(
+        self: Pin<&mut Self>,
+    ) -> Result {
+        // SAFETY: We must ensure that we never move out of `this`.
+        let this = unsafe { self.get_unchecked_mut() };
+        if this.inner.is_none() {
+            let mut dev: bindings::dev_t = 0;
+            // SAFETY: Calling unsafe function. `this.name` has `'static`
+            // lifetime.
+            let res = unsafe {
+                bindings::alloc_chrdev_region(
+                    &mut dev,
+                    this.minors_start.into(),
+                    N.try_into()?,
+                    this.name.as_char_ptr(),
+                )
+            };
+            if res != 0 {
+                return Err(Error::from_kernel_errno(res));
+            }
+            const NONE: Option<Cdev> = None;
+            this.inner = Some(RegistrationInner {
+                dev,
+                used: 0,
+                cdevs: [NONE; N],
+                _pin: PhantomPinned,
+            });
+        }
+
+        let mut inner = this.inner.as_mut().unwrap();
+        if inner.used == N {
+            return Err(Error::EINVAL);
+        }
+
+        // SAFETY: The adapter doesn't retrieve any state yet, so it's compatible with any
+        // registration.
+        let fops = unsafe { file_operations::FileOperationsVtable::<Self, T>::build() };
+        let mut cdev = Cdev::alloc(fops, this.this_module)?;
+        cdev.add(inner.dev + inner.used as bindings::dev_t, 1)?;
+        inner.cdevs[inner.used].replace(cdev);
+        inner.used += 1;
+        Ok(())
+    }
+}
+
+impl<const N: usize> file_operations::FileOpenAdapter<()> for Registration<{ N }> {
+    unsafe fn convert(_inode: *mut bindings::inode, _file: *mut bindings::file) -> *const () {
+        // TODO: Update the SAFETY comment on the call to `FileOperationsVTable::build` above once
+        // this is updated to retrieve state.
+        &()
+    }
+}
+
+// SAFETY: `Registration` does not expose any of its state across threads
+// (it is fine for multiple threads to have a shared reference to it).
+unsafe impl<const N: usize> Sync for Registration<{ N }> {}
+
+impl<const N: usize> Drop for Registration<{ N }> {
+    fn drop(&mut self) {
+        if let Some(inner) = self.inner.as_mut() {
+            // Replicate kernel C behaviour: drop [`Cdev`]s before calling
+            // [`bindings::unregister_chrdev_region`].
+            for i in 0..inner.used {
+                inner.cdevs[i].take();
+            }
+            // SAFETY: [`self.inner`] is Some, so [`inner.dev`] was previously
+            // created using [`bindings::alloc_chrdev_region`].
+            unsafe {
+                bindings::unregister_chrdev_region(inner.dev, N.try_into().unwrap());
+            }
+        }
+    }
+}
diff --git a/rust/kernel/clk.rs b/rust/kernel/clk.rs
new file mode 100644
index 000000000000..381f1ff3bd23
--- /dev/null
+++ b/rust/kernel/clk.rs
@@ -0,0 +1,75 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Common clock framework.
+//!
+//! C header: [`include/linux/clk.h`](../../../../include/linux/clk.h)
+
+use crate::{bindings, error::Result, to_result};
+use core::mem::ManuallyDrop;
+
+/// Represents `struct clk *`.
+///
+/// # Invariants
+///
+/// The pointer is valid.
+pub struct Clk(*mut bindings::clk);
+
+impl Clk {
+    /// Creates new clock structure from a raw pointer.
+    ///
+    /// # Safety
+    ///
+    /// The pointer must be valid.
+    pub unsafe fn new(clk: *mut bindings::clk) -> Self {
+        Self(clk)
+    }
+
+    /// Returns value of the rate field of `struct clk`.
+    pub fn get_rate(&self) -> usize {
+        // SAFETY: the pointer is valid by the type invariant.
+        unsafe { bindings::clk_get_rate(self.0) as usize }
+    }
+
+    /// Prepares and enables the underlying hardware clock.
+    ///
+    /// This function should not be called in atomic context.
+    pub fn prepare_enable(self) -> Result<EnabledClk> {
+        // SAFETY: the pointer is valid by the type invariant.
+        to_result(|| unsafe { bindings::clk_prepare_enable(self.0) })?;
+        Ok(EnabledClk(self))
+    }
+}
+
+impl Drop for Clk {
+    fn drop(&mut self) {
+        // SAFETY: the pointer is valid by the type invariant.
+        unsafe { bindings::clk_put(self.0) };
+    }
+}
+
+/// A clock variant that is prepared and enabled.
+pub struct EnabledClk(Clk);
+
+impl EnabledClk {
+    /// Returns value of the rate field of `struct clk`.
+    pub fn get_rate(&self) -> usize {
+        self.0.get_rate()
+    }
+
+    /// Disables and later unprepares the underlying hardware clock prematurely.
+    ///
+    /// This function should not be called in atomic context.
+    pub fn disable_unprepare(self) -> Clk {
+        let mut clk = ManuallyDrop::new(self);
+        // SAFETY: the pointer is valid by the type invariant.
+        unsafe { bindings::clk_disable_unprepare(clk.0 .0) };
+        core::mem::replace(&mut clk.0, Clk(core::ptr::null_mut()))
+    }
+}
+
+impl Drop for EnabledClk {
+    fn drop(&mut self) {
+        // SAFETY: the pointer is valid by the type invariant.
+        unsafe { bindings::clk_disable_unprepare(self.0 .0) };
+    }
+}
diff --git a/rust/kernel/cred.rs b/rust/kernel/cred.rs
new file mode 100644
index 000000000000..1602aa6935ca
--- /dev/null
+++ b/rust/kernel/cred.rs
@@ -0,0 +1,73 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Credentials management.
+//!
+//! C header: [`include/linux/cred.h`](../../../../include/linux/cred.h)
+//!
+//! Reference: <https://www.kernel.org/doc/html/latest/security/credentials.html>
+
+use crate::bindings;
+use core::{marker::PhantomData, mem::ManuallyDrop, ops::Deref};
+
+/// Wraps the kernel's `struct cred`.
+///
+/// # Invariants
+///
+/// The pointer `Credential::ptr` is non-null and valid. Its reference count is also non-zero.
+pub struct Credential {
+    pub(crate) ptr: *const bindings::cred,
+}
+
+impl Clone for Credential {
+    fn clone(&self) -> Self {
+        // SAFETY: The type invariants guarantee that `self.ptr` has a non-zero reference count.
+        let ptr = unsafe { bindings::get_cred(self.ptr) };
+
+        // INVARIANT: We incremented the reference count to account for the new `Credential` being
+        // created.
+        Self { ptr }
+    }
+}
+
+impl Drop for Credential {
+    fn drop(&mut self) {
+        // SAFETY: The type invariants guarantee that `ptr` has a non-zero reference count.
+        unsafe { bindings::put_cred(self.ptr) };
+    }
+}
+
+/// A wrapper for [`Credential`] that doesn't automatically decrement the refcount when dropped.
+///
+/// We need the wrapper because [`ManuallyDrop`] alone would allow callers to call
+/// [`ManuallyDrop::into_inner`]. This would allow an unsafe sequence to be triggered without
+/// `unsafe` blocks because it would trigger an unbalanced call to `put_cred`.
+///
+/// # Invariants
+///
+/// The wrapped [`Credential`] remains valid for the lifetime of the object.
+pub struct CredentialRef<'a> {
+    cred: ManuallyDrop<Credential>,
+    _p: PhantomData<&'a ()>,
+}
+
+impl CredentialRef<'_> {
+    /// Constructs a new [`struct cred`] wrapper that doesn't change its reference count.
+    ///
+    /// # Safety
+    ///
+    /// The pointer `ptr` must be non-null and valid for the lifetime of the object.
+    pub(crate) unsafe fn from_ptr(ptr: *const bindings::cred) -> Self {
+        Self {
+            cred: ManuallyDrop::new(Credential { ptr }),
+            _p: PhantomData,
+        }
+    }
+}
+
+impl Deref for CredentialRef<'_> {
+    type Target = Credential;
+
+    fn deref(&self) -> &Self::Target {
+        self.cred.deref()
+    }
+}
diff --git a/rust/kernel/device.rs b/rust/kernel/device.rs
new file mode 100644
index 000000000000..0ec3dd668138
--- /dev/null
+++ b/rust/kernel/device.rs
@@ -0,0 +1,549 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Generic devices that are part of the kernel's driver model.
+//!
+//! C header: [`include/linux/device.h`](../../../../include/linux/device.h)
+
+#[cfg(CONFIG_COMMON_CLK)]
+use crate::{clk::Clk, error::from_kernel_err_ptr};
+
+use crate::{
+    bindings, c_str, c_types,
+    revocable::{Revocable, RevocableGuard},
+    str::CStr,
+    sync::{NeedsLockClass, RevocableMutex, RevocableMutexGuard, UniqueRef},
+    Result,
+};
+use core::{
+    fmt,
+    ops::{Deref, DerefMut},
+    pin::Pin,
+};
+
+/// A raw device.
+///
+/// # Safety
+///
+/// Implementers must ensure that the `*mut device` returned by [`RawDevice::raw_device`] is
+/// related to `self`, that is, actions on it will affect `self`. For example, if one calls
+/// `get_device`, then the refcount on the device represented by `self` will be incremented.
+///
+/// Additionally, implementers must ensure that the device is never renamed. Commit a5462516aa994
+/// has details on why `device_rename` should not be used.
+pub unsafe trait RawDevice {
+    /// Returns the raw `struct device` related to `self`.
+    fn raw_device(&self) -> *mut bindings::device;
+
+    /// Returns the name of the device.
+    fn name(&self) -> &CStr {
+        let ptr = self.raw_device();
+
+        // SAFETY: `ptr` is valid because `self` keeps it alive.
+        let name = unsafe { bindings::dev_name(ptr) };
+
+        // SAFETY: The name of the device remains valid while it is alive (because the device is
+        // never renamed, per the safety requirement of this trait). This is guaranteed to be the
+        // case because the reference to `self` outlives the one of the returned `CStr` (enforced
+        // by the compiler because of their lifetimes).
+        unsafe { CStr::from_char_ptr(name) }
+    }
+
+    /// Lookups a clock producer consumed by this device.
+    ///
+    /// Returns a managed reference to the clock producer.
+    #[cfg(CONFIG_COMMON_CLK)]
+    fn clk_get(&self, id: Option<&CStr>) -> Result<Clk> {
+        let id_ptr = match id {
+            Some(cstr) => cstr.as_char_ptr(),
+            None => core::ptr::null(),
+        };
+
+        // SAFETY: id_ptr is optional and may be either a valid pointer
+        // from the type invariant or NULL otherwise.
+        let clk_ptr = unsafe { from_kernel_err_ptr(bindings::clk_get(self.raw_device(), id_ptr)) }?;
+
+        // SAFETY: clock is initialized with valid pointer returned from `bindings::clk_get` call.
+        unsafe { Ok(Clk::new(clk_ptr)) }
+    }
+
+    /// Prints an emergency-level message (level 0) prefixed with device information.
+    ///
+    /// More details are available from [`dev_emerg`].
+    fn pr_emerg(&self, args: fmt::Arguments<'_>) {
+        // SAFETY: `klevel` is null-terminated, uses one of the kernel constants.
+        unsafe { self.printk(bindings::KERN_EMERG, args) };
+    }
+
+    /// Prints an alert-level message (level 1) prefixed with device information.
+    ///
+    /// More details are available from [`dev_alert`].
+    fn pr_alert(&self, args: fmt::Arguments<'_>) {
+        // SAFETY: `klevel` is null-terminated, uses one of the kernel constants.
+        unsafe { self.printk(bindings::KERN_ALERT, args) };
+    }
+
+    /// Prints a critical-level message (level 2) prefixed with device information.
+    ///
+    /// More details are available from [`dev_crit`].
+    fn pr_crit(&self, args: fmt::Arguments<'_>) {
+        // SAFETY: `klevel` is null-terminated, uses one of the kernel constants.
+        unsafe { self.printk(bindings::KERN_CRIT, args) };
+    }
+
+    /// Prints an error-level message (level 3) prefixed with device information.
+    ///
+    /// More details are available from [`dev_err`].
+    fn pr_err(&self, args: fmt::Arguments<'_>) {
+        // SAFETY: `klevel` is null-terminated, uses one of the kernel constants.
+        unsafe { self.printk(bindings::KERN_ERR, args) };
+    }
+
+    /// Prints a warning-level message (level 4) prefixed with device information.
+    ///
+    /// More details are available from [`dev_warn`].
+    fn pr_warn(&self, args: fmt::Arguments<'_>) {
+        // SAFETY: `klevel` is null-terminated, uses one of the kernel constants.
+        unsafe { self.printk(bindings::KERN_WARNING, args) };
+    }
+
+    /// Prints a notice-level message (level 5) prefixed with device information.
+    ///
+    /// More details are available from [`dev_notice`].
+    fn pr_notice(&self, args: fmt::Arguments<'_>) {
+        // SAFETY: `klevel` is null-terminated, uses one of the kernel constants.
+        unsafe { self.printk(bindings::KERN_NOTICE, args) };
+    }
+
+    /// Prints an info-level message (level 6) prefixed with device information.
+    ///
+    /// More details are available from [`dev_info`].
+    fn pr_info(&self, args: fmt::Arguments<'_>) {
+        // SAFETY: `klevel` is null-terminated, uses one of the kernel constants.
+        unsafe { self.printk(bindings::KERN_INFO, args) };
+    }
+
+    /// Prints a debug-level message (level 7) prefixed with device information.
+    ///
+    /// More details are available from [`dev_dbg`].
+    fn pr_dbg(&self, args: fmt::Arguments<'_>) {
+        if cfg!(debug_assertions) {
+            // SAFETY: `klevel` is null-terminated, uses one of the kernel constants.
+            unsafe { self.printk(bindings::KERN_DEBUG, args) };
+        }
+    }
+
+    /// Prints the provided message to the console.
+    ///
+    /// # Safety
+    ///
+    /// Callers must ensure that `klevel` is null-terminated; in particular, one of the
+    /// `KERN_*`constants, for example, `KERN_CRIT`, `KERN_ALERT`, etc.
+    unsafe fn printk(&self, klevel: &[u8], msg: fmt::Arguments<'_>) {
+        // SAFETY: `klevel` is null-terminated and one of the kernel constants. `self.raw_device`
+        // is valid because `self` is valid. The "%pA" format string expects a pointer to
+        // `fmt::Arguments`, which is what we're passing as the last argument.
+        unsafe {
+            bindings::_dev_printk(
+                klevel as *const _ as *const c_types::c_char,
+                self.raw_device(),
+                c_str!("%pA").as_char_ptr(),
+                &msg as *const _ as *const c_types::c_void,
+            )
+        };
+    }
+}
+
+/// A ref-counted device.
+///
+/// # Invariants
+///
+/// `ptr` is valid, non-null, and has a non-zero reference count. One of the references is owned by
+/// `self`, and will be decremented when `self` is dropped.
+pub struct Device {
+    pub(crate) ptr: *mut bindings::device,
+}
+
+// SAFETY: `Device` only holds a pointer to a C device, which is safe to be used from any thread.
+unsafe impl Send for Device {}
+
+// SAFETY: `Device` only holds a pointer to a C device, references to which are safe to be used
+// from any thread.
+unsafe impl Sync for Device {}
+
+impl Device {
+    /// Creates a new device instance.
+    ///
+    /// # Safety
+    ///
+    /// Callers must ensure that `ptr` is valid, non-null, and has a non-zero reference count.
+    pub unsafe fn new(ptr: *mut bindings::device) -> Self {
+        // SAFETY: By the safety requirements, ptr is valid and its refcounted will be incremented.
+        unsafe { bindings::get_device(ptr) };
+        // INVARIANT: The safety requirements satisfy all but one invariant, which is that `self`
+        // owns a reference. This is satisfied by the call to `get_device` above.
+        Self { ptr }
+    }
+
+    /// Creates a new device instance from an existing [`RawDevice`] instance.
+    pub fn from_dev(dev: &dyn RawDevice) -> Self {
+        // SAFETY: The requirements are satisfied by the existence of `RawDevice` and its safety
+        // requirements.
+        unsafe { Self::new(dev.raw_device()) }
+    }
+}
+
+// SAFETY: The device returned by `raw_device` is the one for which we hold a reference.
+unsafe impl RawDevice for Device {
+    fn raw_device(&self) -> *mut bindings::device {
+        self.ptr
+    }
+}
+
+impl Drop for Device {
+    fn drop(&mut self) {
+        // SAFETY: By the type invariants, we know that `self` owns a reference, so it is safe to
+        // relinquish it now.
+        unsafe { bindings::put_device(self.ptr) };
+    }
+}
+
+/// Device data.
+///
+/// When a device is removed (for whatever reason, for example, because the device was unplugged or
+/// because the user decided to unbind the driver), the driver is given a chance to clean its state
+/// up, and all io resources should ideally not be used anymore.
+///
+/// However, the device data is reference-counted because other subsystems hold pointers to it. So
+/// some device state must be freed and not used anymore, while others must remain accessible.
+///
+/// This struct separates the device data into three categories:
+/// 1. Registrations: are destroyed when the device is removed, but before the io resources
+///    become inaccessible.
+/// 2. Io resources: are available until the device is removed.
+/// 3. General data: remain available as long as the ref count is nonzero.
+///
+/// This struct implements the `DeviceRemoval` trait so that it can clean resources up even if not
+/// explicitly called by the device drivers.
+pub struct Data<T, U, V> {
+    registrations: RevocableMutex<T>,
+    resources: Revocable<U>,
+    general: V,
+}
+
+/// Safely creates an new reference-counted instance of [`Data`].
+#[doc(hidden)]
+#[macro_export]
+macro_rules! new_device_data {
+    ($reg:expr, $res:expr, $gen:expr, $name:literal) => {{
+        static mut CLASS1: core::mem::MaybeUninit<$crate::bindings::lock_class_key> =
+            core::mem::MaybeUninit::uninit();
+        static mut CLASS2: core::mem::MaybeUninit<$crate::bindings::lock_class_key> =
+            core::mem::MaybeUninit::uninit();
+        let regs = $reg;
+        let res = $res;
+        let gen = $gen;
+        let name = $crate::c_str!($name);
+        // SAFETY: `CLASS1` and `CLASS2` are never used by Rust code directly; the C portion of the
+        // kernel may change it though.
+        unsafe {
+            $crate::device::Data::try_new(
+                regs,
+                res,
+                gen,
+                name,
+                CLASS1.as_mut_ptr(),
+                CLASS2.as_mut_ptr(),
+            )
+        }
+    }};
+}
+
+impl<T, U, V> Data<T, U, V> {
+    /// Creates a new instance of `Data`.
+    ///
+    /// It is recommended that the [`new_device_data`] macro be used as it automatically creates
+    /// the lock classes.
+    ///
+    /// # Safety
+    ///
+    /// `key1` and `key2` must point to valid memory locations and remain valid until `self` is
+    /// dropped.
+    pub unsafe fn try_new(
+        registrations: T,
+        resources: U,
+        general: V,
+        name: &'static CStr,
+        key1: *mut bindings::lock_class_key,
+        key2: *mut bindings::lock_class_key,
+    ) -> Result<Pin<UniqueRef<Self>>> {
+        let mut ret = Pin::from(UniqueRef::try_new(Self {
+            // SAFETY: We call `RevocableMutex::init` below.
+            registrations: unsafe { RevocableMutex::new(registrations) },
+            resources: Revocable::new(resources),
+            general,
+        })?);
+
+        // SAFETY: `Data::registrations` is pinned when `Data` is.
+        let pinned = unsafe { ret.as_mut().map_unchecked_mut(|d| &mut d.registrations) };
+
+        // SAFETY: The safety requirements of this function satisfy those of `RevocableMutex::init`.
+        unsafe { pinned.init(name, key1, key2) };
+        Ok(ret)
+    }
+
+    /// Returns the resources if they're still available.
+    pub fn resources(&self) -> Option<RevocableGuard<'_, U>> {
+        self.resources.try_access()
+    }
+
+    /// Returns the locked registrations if they're still available.
+    pub fn registrations(&self) -> Option<RevocableMutexGuard<'_, T>> {
+        self.registrations.try_lock()
+    }
+}
+
+impl<T, U, V> crate::driver::DeviceRemoval for Data<T, U, V> {
+    fn device_remove(&self) {
+        // We revoke the registrations first so that resources are still available to them during
+        // unregistration.
+        self.registrations.revoke();
+
+        // Release resources now. General data remains available.
+        self.resources.revoke();
+    }
+}
+
+impl<T, U, V> Deref for Data<T, U, V> {
+    type Target = V;
+
+    fn deref(&self) -> &V {
+        &self.general
+    }
+}
+
+impl<T, U, V> DerefMut for Data<T, U, V> {
+    fn deref_mut(&mut self) -> &mut V {
+        &mut self.general
+    }
+}
+
+#[doc(hidden)]
+#[macro_export]
+macro_rules! dev_printk {
+    ($method:ident, $dev:expr, $($f:tt)*) => {
+        {
+            // We have an explicity `use` statement here so that callers of this macro are not
+            // required to explicitly use the `RawDevice` trait to use its functions.
+            use $crate::device::RawDevice;
+            ($dev).$method(core::format_args!($($f)*));
+        }
+    }
+}
+
+/// Prints an emergency-level message (level 0) prefixed with device information.
+///
+/// This level should be used if the system is unusable.
+///
+/// Equivalent to the kernel's `dev_emerg` macro.
+///
+/// Mimics the interface of [`std::print!`]. More information about the syntax is available from
+/// [`core::fmt`] and [`alloc::format!`].
+///
+/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::prelude::*;
+/// # use kernel::device::Device;
+///
+/// fn example(dev: &Device) {
+///     dev_emerg!(dev, "hello {}\n", "there");
+/// }
+/// ```
+#[macro_export]
+macro_rules! dev_emerg {
+    ($($f:tt)*) => { $crate::dev_printk!(pr_emerg, $($f)*); }
+}
+
+/// Prints an alert-level message (level 1) prefixed with device information.
+///
+/// This level should be used if action must be taken immediately.
+///
+/// Equivalent to the kernel's `dev_alert` macro.
+///
+/// Mimics the interface of [`std::print!`]. More information about the syntax is available from
+/// [`core::fmt`] and [`alloc::format!`].
+///
+/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::prelude::*;
+/// # use kernel::device::Device;
+///
+/// fn example(dev: &Device) {
+///     dev_alert!(dev, "hello {}\n", "there");
+/// }
+/// ```
+#[macro_export]
+macro_rules! dev_alert {
+    ($($f:tt)*) => { $crate::dev_printk!(pr_alert, $($f)*); }
+}
+
+/// Prints a critical-level message (level 2) prefixed with device information.
+///
+/// This level should be used in critical conditions.
+///
+/// Equivalent to the kernel's `dev_crit` macro.
+///
+/// Mimics the interface of [`std::print!`]. More information about the syntax is available from
+/// [`core::fmt`] and [`alloc::format!`].
+///
+/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::prelude::*;
+/// # use kernel::device::Device;
+///
+/// fn example(dev: &Device) {
+///     dev_crit!(dev, "hello {}\n", "there");
+/// }
+/// ```
+#[macro_export]
+macro_rules! dev_crit {
+    ($($f:tt)*) => { $crate::dev_printk!(pr_crit, $($f)*); }
+}
+
+/// Prints an error-level message (level 3) prefixed with device information.
+///
+/// This level should be used in error conditions.
+///
+/// Equivalent to the kernel's `dev_err` macro.
+///
+/// Mimics the interface of [`std::print!`]. More information about the syntax is available from
+/// [`core::fmt`] and [`alloc::format!`].
+///
+/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::prelude::*;
+/// # use kernel::device::Device;
+///
+/// fn example(dev: &Device) {
+///     dev_err!(dev, "hello {}\n", "there");
+/// }
+/// ```
+#[macro_export]
+macro_rules! dev_err {
+    ($($f:tt)*) => { $crate::dev_printk!(pr_err, $($f)*); }
+}
+
+/// Prints a warning-level message (level 4) prefixed with device information.
+///
+/// This level should be used in warning conditions.
+///
+/// Equivalent to the kernel's `dev_warn` macro.
+///
+/// Mimics the interface of [`std::print!`]. More information about the syntax is available from
+/// [`core::fmt`] and [`alloc::format!`].
+///
+/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::prelude::*;
+/// # use kernel::device::Device;
+///
+/// fn example(dev: &Device) {
+///     dev_warn!(dev, "hello {}\n", "there");
+/// }
+/// ```
+#[macro_export]
+macro_rules! dev_warn {
+    ($($f:tt)*) => { $crate::dev_printk!(pr_warn, $($f)*); }
+}
+
+/// Prints a notice-level message (level 5) prefixed with device information.
+///
+/// This level should be used in normal but significant conditions.
+///
+/// Equivalent to the kernel's `dev_notice` macro.
+///
+/// Mimics the interface of [`std::print!`]. More information about the syntax is available from
+/// [`core::fmt`] and [`alloc::format!`].
+///
+/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::prelude::*;
+/// # use kernel::device::Device;
+///
+/// fn example(dev: &Device) {
+///     dev_notice!(dev, "hello {}\n", "there");
+/// }
+/// ```
+#[macro_export]
+macro_rules! dev_notice {
+    ($($f:tt)*) => { $crate::dev_printk!(pr_notice, $($f)*); }
+}
+
+/// Prints an info-level message (level 6) prefixed with device information.
+///
+/// This level should be used for informational messages.
+///
+/// Equivalent to the kernel's `dev_info` macro.
+///
+/// Mimics the interface of [`std::print!`]. More information about the syntax is available from
+/// [`core::fmt`] and [`alloc::format!`].
+///
+/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::prelude::*;
+/// # use kernel::device::Device;
+///
+/// fn example(dev: &Device) {
+///     dev_info!(dev, "hello {}\n", "there");
+/// }
+/// ```
+#[macro_export]
+macro_rules! dev_info {
+    ($($f:tt)*) => { $crate::dev_printk!(pr_info, $($f)*); }
+}
+
+/// Prints a debug-level message (level 7) prefixed with device information.
+///
+/// This level should be used for debug messages.
+///
+/// Equivalent to the kernel's `dev_dbg` macro, except that it doesn't support dynamic debug yet.
+///
+/// Mimics the interface of [`std::print!`]. More information about the syntax is available from
+/// [`core::fmt`] and [`alloc::format!`].
+///
+/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::prelude::*;
+/// # use kernel::device::Device;
+///
+/// fn example(dev: &Device) {
+///     dev_dbg!(dev, "hello {}\n", "there");
+/// }
+/// ```
+#[macro_export]
+macro_rules! dev_dbg {
+    ($($f:tt)*) => { $crate::dev_printk!(pr_dbg, $($f)*); }
+}
diff --git a/rust/kernel/driver.rs b/rust/kernel/driver.rs
new file mode 100644
index 000000000000..9424c47e5e20
--- /dev/null
+++ b/rust/kernel/driver.rs
@@ -0,0 +1,440 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Generic support for drivers of different buses (e.g., PCI, Platform, Amba, etc.).
+//!
+//! Each bus/subsystem is expected to implement [`DriverOps`], which allows drivers to register
+//! using the [`Registration`] class.
+
+use crate::{str::CStr, sync::Ref, Error, KernelModule, Result, ThisModule};
+use alloc::boxed::Box;
+use core::{cell::UnsafeCell, marker::PhantomData, ops::Deref, pin::Pin};
+
+/// A subsystem (e.g., PCI, Platform, Amba, etc.) that allows drivers to be written for it.
+pub trait DriverOps {
+    /// The type that holds information about the registration. This is typically a struct defined
+    /// by the C portion of the kernel.
+    type RegType: Default;
+
+    /// Registers a driver.
+    ///
+    /// # Safety
+    ///
+    /// `reg` must point to valid, initialised, and writable memory. It may be modified by this
+    /// function to hold registration state.
+    ///
+    /// On success, `reg` must remain pinned and valid until the matching call to
+    /// [`DriverOps::unregister`].
+    unsafe fn register(
+        reg: *mut Self::RegType,
+        name: &'static CStr,
+        module: &'static ThisModule,
+    ) -> Result;
+
+    /// Unregisters a driver previously registered with [`DriverOps::register`].
+    ///
+    /// # Safety
+    ///
+    /// `reg` must point to valid writable memory, initialised by a previous successful call to
+    /// [`DriverOps::register`].
+    unsafe fn unregister(reg: *mut Self::RegType);
+}
+
+/// The registration of a driver.
+pub struct Registration<T: DriverOps> {
+    is_registered: bool,
+    concrete_reg: UnsafeCell<T::RegType>,
+}
+
+// SAFETY: `Registration` has no fields or methods accessible via `&Registration`, so it is safe to
+// share references to it with multiple threads as nothing can be done.
+unsafe impl<T: DriverOps> Sync for Registration<T> {}
+
+impl<T: DriverOps> Registration<T> {
+    /// Creates a new instance of the registration object.
+    pub fn new() -> Self {
+        Self {
+            is_registered: false,
+            concrete_reg: UnsafeCell::new(T::RegType::default()),
+        }
+    }
+
+    /// Allocates a pinned registration object and registers it.
+    ///
+    /// Returns a pinned heap-allocated representation of the registration.
+    pub fn new_pinned(name: &'static CStr, module: &'static ThisModule) -> Result<Pin<Box<Self>>> {
+        let mut reg = Pin::from(Box::try_new(Self::new())?);
+        reg.as_mut().register(name, module)?;
+        Ok(reg)
+    }
+
+    /// Registers a driver with its subsystem.
+    ///
+    /// It must be pinned because the memory block that represents the registration is potentially
+    /// self-referential.
+    pub fn register(
+        self: Pin<&mut Self>,
+        name: &'static CStr,
+        module: &'static ThisModule,
+    ) -> Result {
+        // SAFETY: We never move out of `this`.
+        let this = unsafe { self.get_unchecked_mut() };
+        if this.is_registered {
+            // Already registered.
+            return Err(Error::EINVAL);
+        }
+
+        // SAFETY: `concrete_reg` was initialised via its default constructor. It is only freed
+        // after `Self::drop` is called, which first calls `T::unregister`.
+        unsafe { T::register(this.concrete_reg.get(), name, module) }?;
+
+        this.is_registered = true;
+        Ok(())
+    }
+}
+
+impl<T: DriverOps> Default for Registration<T> {
+    fn default() -> Self {
+        Self::new()
+    }
+}
+
+impl<T: DriverOps> Drop for Registration<T> {
+    fn drop(&mut self) {
+        if self.is_registered {
+            // SAFETY: This path only runs if a previous call to `T::register` completed
+            // successfully.
+            unsafe { T::unregister(self.concrete_reg.get()) };
+        }
+    }
+}
+
+/// Conversion from a device id to a raw device id.
+///
+/// This is meant to be implemented by buses/subsystems so that they can use [`IdTable`] to
+/// guarantee (at compile-time) zero-termination of device id tables provided by drivers.
+///
+/// # Safety
+///
+/// Implementers must ensure that:
+///   * [`RawDeviceId::ZERO`] is actually a zeroed-out version of the raw device id.
+///   * [`RawDeviceId::to_rawid`] stores `offset` in the context/data field of the raw device id so
+///     that buses can recover the pointer to the data.
+pub unsafe trait RawDeviceId {
+    /// The raw type that holds the device id.
+    ///
+    /// Id tables created from [`Self`] are going to hold this type in its zero-terminated array.
+    type RawType: Copy;
+
+    /// A zeroed-out representation of the raw device id.
+    ///
+    /// Id tables created from [`Self`] use [`Self::ZERO`] as the sentinel to indicate the end of
+    /// the table.
+    const ZERO: Self::RawType;
+
+    /// Converts an id into a raw id.
+    ///
+    /// `offset` is the offset from the memory location where the raw device id is stored to the
+    /// location where its associated context information is stored. Implementations must store
+    /// this in the appropriate context/data field of the raw type.
+    fn to_rawid(&self, offset: isize) -> Self::RawType;
+}
+
+/// A zero-terminated device id array, followed by context data.
+#[repr(C)]
+pub struct IdArray<T: RawDeviceId, U, const N: usize> {
+    ids: [T::RawType; N],
+    sentinel: T::RawType,
+    id_infos: [Option<U>; N],
+}
+
+impl<T: RawDeviceId, U, const N: usize> IdArray<T, U, N> {
+    /// Creates a new instance of the array.
+    ///
+    /// The contents are derived from the given identifiers and context information.
+    pub const fn new(ids: [T; N], infos: [Option<U>; N]) -> Self
+    where
+        T: ~const RawDeviceId + Copy,
+    {
+        let mut array = Self {
+            ids: [T::ZERO; N],
+            sentinel: T::ZERO,
+            id_infos: infos,
+        };
+        let mut i = 0usize;
+        while i < N {
+            // SAFETY: Both pointers are within `array` (or one byte beyond), consequently they are
+            // derived from the same allocated object. We are using a `u8` pointer, whose size 1,
+            // so the pointers are necessarily 1-byte aligned.
+            let offset = unsafe {
+                (&array.id_infos[i] as *const _ as *const u8)
+                    .offset_from(&array.ids[i] as *const _ as _)
+            };
+            array.ids[i] = ids[i].to_rawid(offset);
+            i += 1;
+        }
+        array
+    }
+
+    /// Returns an `IdTable` backed by `self`.
+    ///
+    /// This is used to essentially erase the array size.
+    pub const fn as_table(&self) -> IdTable<'_, T, U> {
+        IdTable {
+            first: &self.ids[0],
+            _p: PhantomData,
+        }
+    }
+}
+
+/// A device id table.
+///
+/// The table is guaranteed to be zero-terminated and to be followed by an array of context data of
+/// type `Option<U>`.
+pub struct IdTable<'a, T: RawDeviceId, U> {
+    first: &'a T::RawType,
+    _p: PhantomData<&'a U>,
+}
+
+impl<T: RawDeviceId, U> const AsRef<T::RawType> for IdTable<'_, T, U> {
+    fn as_ref(&self) -> &T::RawType {
+        self.first
+    }
+}
+
+/// Counts the number of parenthesis-delimited, comma-separated items.
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::count_paren_items;
+///
+/// assert_eq!(0, count_paren_items!());
+/// assert_eq!(1, count_paren_items!((A)));
+/// assert_eq!(1, count_paren_items!((A),));
+/// assert_eq!(2, count_paren_items!((A), (B)));
+/// assert_eq!(2, count_paren_items!((A), (B),));
+/// assert_eq!(3, count_paren_items!((A), (B), (C)));
+/// assert_eq!(3, count_paren_items!((A), (B), (C),));
+/// ```
+#[macro_export]
+macro_rules! count_paren_items {
+    (($($item:tt)*), $($remaining:tt)*) => { 1 + $crate::count_paren_items!($($remaining)*) };
+    (($($item:tt)*)) => { 1 };
+    () => { 0 };
+}
+
+/// Converts a comma-separated list of pairs into an array with the first element. That is, it
+/// discards the second element of the pair.
+///
+/// Additionally, it automatically introduces a type if the first element is warpped in curly
+/// braces, for example, if it's `{v: 10}`, it becomes `X { v: 10 }`; this is to avoid repeating
+/// the type.
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::first_item;
+///
+/// #[derive(PartialEq, Debug)]
+/// struct X {
+///     v: u32,
+/// }
+///
+/// assert_eq!([] as [X; 0], first_item!(X, ));
+/// assert_eq!([X { v: 10 }], first_item!(X, ({ v: 10 }, Y)));
+/// assert_eq!([X { v: 10 }], first_item!(X, ({ v: 10 }, Y),));
+/// assert_eq!([X { v: 10 }], first_item!(X, (X { v: 10 }, Y)));
+/// assert_eq!([X { v: 10 }], first_item!(X, (X { v: 10 }, Y),));
+/// assert_eq!([X { v: 10 }, X { v: 20 }], first_item!(X, ({ v: 10 }, Y), ({ v: 20 }, Y)));
+/// assert_eq!([X { v: 10 }, X { v: 20 }], first_item!(X, ({ v: 10 }, Y), ({ v: 20 }, Y),));
+/// assert_eq!([X { v: 10 }, X { v: 20 }], first_item!(X, (X { v: 10 }, Y), (X { v: 20 }, Y)));
+/// assert_eq!([X { v: 10 }, X { v: 20 }], first_item!(X, (X { v: 10 }, Y), (X { v: 20 }, Y),));
+/// assert_eq!([X { v: 10 }, X { v: 20 }, X { v: 30 }],
+///            first_item!(X, ({ v: 10 }, Y), ({ v: 20 }, Y), ({v: 30}, Y)));
+/// assert_eq!([X { v: 10 }, X { v: 20 }, X { v: 30 }],
+///            first_item!(X, ({ v: 10 }, Y), ({ v: 20 }, Y), ({v: 30}, Y),));
+/// assert_eq!([X { v: 10 }, X { v: 20 }, X { v: 30 }],
+///            first_item!(X, (X { v: 10 }, Y), (X { v: 20 }, Y), (X {v: 30}, Y)));
+/// assert_eq!([X { v: 10 }, X { v: 20 }, X { v: 30 }],
+///            first_item!(X, (X { v: 10 }, Y), (X { v: 20 }, Y), (X {v: 30}, Y),));
+/// ```
+#[macro_export]
+macro_rules! first_item {
+    ($id_type:ty, $(({$($first:tt)*}, $second:expr)),* $(,)?) => {
+        {
+            type IdType = $id_type;
+            [$(IdType{$($first)*},)*]
+        }
+    };
+    ($id_type:ty, $(($first:expr, $second:expr)),* $(,)?) => { [$($first,)*] };
+}
+
+/// Converts a comma-separated list of pairs into an array with the second element. That is, it
+/// discards the first element of the pair.
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::second_item;
+///
+/// assert_eq!([] as [u32; 0], second_item!());
+/// assert_eq!([10u32], second_item!((X, 10u32)));
+/// assert_eq!([10u32], second_item!((X, 10u32),));
+/// assert_eq!([10u32], second_item!(({X}, 10u32)));
+/// assert_eq!([10u32], second_item!(({X}, 10u32),));
+/// assert_eq!([10u32, 20], second_item!((X, 10u32), (X, 20)));
+/// assert_eq!([10u32, 20], second_item!((X, 10u32), (X, 20),));
+/// assert_eq!([10u32, 20], second_item!(({X}, 10u32), ({X}, 20)));
+/// assert_eq!([10u32, 20], second_item!(({X}, 10u32), ({X}, 20),));
+/// assert_eq!([10u32, 20, 30], second_item!((X, 10u32), (X, 20), (X, 30)));
+/// assert_eq!([10u32, 20, 30], second_item!((X, 10u32), (X, 20), (X, 30),));
+/// assert_eq!([10u32, 20, 30], second_item!(({X}, 10u32), ({X}, 20), ({X}, 30)));
+/// assert_eq!([10u32, 20, 30], second_item!(({X}, 10u32), ({X}, 20), ({X}, 30),));
+/// ```
+#[macro_export]
+macro_rules! second_item {
+    ($(({$($first:tt)*}, $second:expr)),* $(,)?) => { [$($second,)*] };
+    ($(($first:expr, $second:expr)),* $(,)?) => { [$($second,)*] };
+}
+
+/// Defines a new constant [`IdArray`] with a concise syntax.
+///
+/// It is meant to be used by buses and subsystems to create a similar macro with their device id
+/// type already specified, i.e., with fewer parameters to the end user.
+///
+/// # Examples
+///
+/// ```
+/// #![feature(const_trait_impl)]
+/// # use kernel::{define_id_array, driver::RawDeviceId};
+///
+/// #[derive(Copy, Clone)]
+/// struct Id(u32);
+///
+/// // SAFETY: `ZERO` is all zeroes and `to_rawid` stores `offset` as the second element of the raw
+/// // device id pair.
+/// unsafe impl const RawDeviceId for Id {
+///     type RawType = (u64, isize);
+///     const ZERO: Self::RawType = (0, 0);
+///     fn to_rawid(&self, offset: isize) -> Self::RawType {
+///         (self.0 as u64 + 1, offset)
+///     }
+/// }
+///
+/// define_id_array!(A1, Id, (), []);
+/// define_id_array!(A2, Id, &'static [u8], [(Id(10), None)]);
+/// define_id_array!(A3, Id, &'static [u8], [(Id(10), Some(b"id1")), ]);
+/// define_id_array!(A4, Id, &'static [u8], [(Id(10), Some(b"id1")), (Id(20), Some(b"id2"))]);
+/// define_id_array!(A5, Id, &'static [u8], [(Id(10), Some(b"id1")), (Id(20), Some(b"id2")), ]);
+/// define_id_array!(A6, Id, &'static [u8], [(Id(10), None), (Id(20), Some(b"id2")), ]);
+/// define_id_array!(A7, Id, &'static [u8], [(Id(10), Some(b"id1")), (Id(20), None), ]);
+/// define_id_array!(A8, Id, &'static [u8], [(Id(10), None), (Id(20), None), ]);
+/// ```
+#[macro_export]
+macro_rules! define_id_array {
+    ($table_name:ident, $id_type:ty, $data_type:ty, [ $($t:tt)* ]) => {
+        const $table_name:
+            $crate::driver::IdArray<$id_type, $data_type, { $crate::count_paren_items!($($t)*) }> =
+                $crate::driver::IdArray::new(
+                    $crate::first_item!($id_type, $($t)*), $crate::second_item!($($t)*));
+    };
+}
+
+/// Defines a new constant [`IdTable`] with a concise syntax.
+///
+/// It is meant to be used by buses and subsystems to create a similar macro with their device id
+/// type already specified, i.e., with fewer parameters to the end user.
+///
+/// # Examples
+///
+/// ```
+/// #![feature(const_trait_impl)]
+/// # use kernel::{define_id_table, driver::RawDeviceId};
+///
+/// #[derive(Copy, Clone)]
+/// struct Id(u32);
+///
+/// // SAFETY: `ZERO` is all zeroes and `to_rawid` stores `offset` as the second element of the raw
+/// // device id pair.
+/// unsafe impl const RawDeviceId for Id {
+///     type RawType = (u64, isize);
+///     const ZERO: Self::RawType = (0, 0);
+///     fn to_rawid(&self, offset: isize) -> Self::RawType {
+///         (self.0 as u64 + 1, offset)
+///     }
+/// }
+///
+/// define_id_table!(T1, Id, &'static [u8], [(Id(10), None)]);
+/// define_id_table!(T2, Id, &'static [u8], [(Id(10), Some(b"id1")), ]);
+/// define_id_table!(T3, Id, &'static [u8], [(Id(10), Some(b"id1")), (Id(20), Some(b"id2"))]);
+/// define_id_table!(T4, Id, &'static [u8], [(Id(10), Some(b"id1")), (Id(20), Some(b"id2")), ]);
+/// define_id_table!(T5, Id, &'static [u8], [(Id(10), None), (Id(20), Some(b"id2")), ]);
+/// define_id_table!(T6, Id, &'static [u8], [(Id(10), Some(b"id1")), (Id(20), None), ]);
+/// define_id_table!(T7, Id, &'static [u8], [(Id(10), None), (Id(20), None), ]);
+/// ```
+#[macro_export]
+macro_rules! define_id_table {
+    ($table_name:ident, $id_type:ty, $data_type:ty, [ $($t:tt)* ]) => {
+        const $table_name: Option<$crate::driver::IdTable<'static, $id_type, $data_type>> = {
+            $crate::define_id_array!(ARRAY, $id_type, $data_type, [ $($t)* ]);
+            Some(ARRAY.as_table())
+        };
+    };
+}
+
+/// Custom code within device removal.
+pub trait DeviceRemoval {
+    /// Cleans resources up when the device is removed.
+    ///
+    /// This is called when a device is removed and offers implementers the chance to run some code
+    /// that cleans state up.
+    fn device_remove(&self);
+}
+
+impl DeviceRemoval for () {
+    fn device_remove(&self) {}
+}
+
+impl<T: DeviceRemoval> DeviceRemoval for Ref<T> {
+    fn device_remove(&self) {
+        self.deref().device_remove();
+    }
+}
+
+impl<T: DeviceRemoval> DeviceRemoval for Box<T> {
+    fn device_remove(&self) {
+        self.deref().device_remove();
+    }
+}
+
+/// A kernel module that only registers the given driver on init.
+///
+/// This is a helper struct to make it easier to define single-functionality modules, in this case,
+/// modules that offer a single driver.
+pub struct Module<T: DriverOps> {
+    _driver: Pin<Box<Registration<T>>>,
+}
+
+impl<T: DriverOps> KernelModule for Module<T> {
+    fn init(name: &'static CStr, module: &'static ThisModule) -> Result<Self> {
+        Ok(Self {
+            _driver: Registration::new_pinned(name, module)?,
+        })
+    }
+}
+
+/// Declares a kernel module that exposes a single driver.
+///
+/// It is meant to be used as a helper by other subsystems so they can more easily expose their own
+/// macros.
+#[macro_export]
+macro_rules! module_driver {
+    (<$gen_type:ident>, $driver_ops:ty, { type: $type:ty, $($f:tt)* }) => {
+        type Ops<$gen_type> = $driver_ops;
+        type ModuleType = $crate::driver::Module<Ops<$type>>;
+        $crate::prelude::module! {
+            type: ModuleType,
+            $($f)*
+        }
+    }
+}
diff --git a/rust/kernel/error.rs b/rust/kernel/error.rs
new file mode 100644
index 000000000000..93fa35c4df21
--- /dev/null
+++ b/rust/kernel/error.rs
@@ -0,0 +1,542 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Kernel errors.
+//!
+//! C header: [`include/uapi/asm-generic/errno-base.h`](../../../include/uapi/asm-generic/errno-base.h)
+
+use crate::str::CStr;
+use crate::{bindings, c_types};
+use alloc::{
+    alloc::{AllocError, LayoutError},
+    collections::TryReserveError,
+};
+use core::convert::From;
+use core::fmt;
+use core::num::TryFromIntError;
+use core::str::{self, Utf8Error};
+
+macro_rules! declare_err {
+    ($err:tt) => {
+        pub const $err: Self = Error(-(bindings::$err as i32));
+    };
+    ($err:tt, $($doc:expr),+) => {
+        $(
+        #[doc = $doc]
+        )*
+        pub const $err: Self = Error(-(bindings::$err as i32));
+    };
+}
+
+/// Generic integer kernel error.
+///
+/// The kernel defines a set of integer generic error codes based on C and
+/// POSIX ones. These codes may have a more specific meaning in some contexts.
+///
+/// # Invariants
+///
+/// The value is a valid `errno` (i.e. `>= -MAX_ERRNO && < 0`).
+#[derive(Clone, Copy, PartialEq, Eq)]
+pub struct Error(c_types::c_int);
+
+impl Error {
+    declare_err!(EPERM, "Operation not permitted.");
+
+    declare_err!(ENOENT, "No such file or directory.");
+
+    declare_err!(ESRCH, "No such process.");
+
+    declare_err!(EINTR, "Interrupted system call.");
+
+    declare_err!(EIO, "I/O error.");
+
+    declare_err!(ENXIO, "No such device or address.");
+
+    declare_err!(E2BIG, "Argument list too long.");
+
+    declare_err!(ENOEXEC, "Exec format error.");
+
+    declare_err!(EBADF, "Bad file number.");
+
+    declare_err!(ECHILD, "Exec format error.");
+
+    declare_err!(EAGAIN, "Try again.");
+
+    declare_err!(ENOMEM, "Out of memory.");
+
+    declare_err!(EACCES, "Permission denied.");
+
+    declare_err!(EFAULT, "Bad address.");
+
+    declare_err!(ENOTBLK, "Block device required.");
+
+    declare_err!(EBUSY, "Device or resource busy.");
+
+    declare_err!(EEXIST, "File exists.");
+
+    declare_err!(EXDEV, "Cross-device link.");
+
+    declare_err!(ENODEV, "No such device.");
+
+    declare_err!(ENOTDIR, "Not a directory.");
+
+    declare_err!(EISDIR, "Is a directory.");
+
+    declare_err!(EINVAL, "Invalid argument.");
+
+    declare_err!(ENFILE, "File table overflow.");
+
+    declare_err!(EMFILE, "Too many open files.");
+
+    declare_err!(ENOTTY, "Not a typewriter.");
+
+    declare_err!(ETXTBSY, "Text file busy.");
+
+    declare_err!(EFBIG, "File too large.");
+
+    declare_err!(ENOSPC, "No space left on device.");
+
+    declare_err!(ESPIPE, "Illegal seek.");
+
+    declare_err!(EROFS, "Read-only file system.");
+
+    declare_err!(EMLINK, "Too many links.");
+
+    declare_err!(EPIPE, "Broken pipe.");
+
+    declare_err!(EDOM, "Math argument out of domain of func.");
+
+    declare_err!(ERANGE, "Math result not representable.");
+
+    declare_err!(EDEADLK, "Resource deadlock would occur");
+
+    declare_err!(ENAMETOOLONG, "File name too long");
+
+    declare_err!(ENOLCK, "No record locks available");
+
+    declare_err!(
+        ENOSYS,
+        "Invalid system call number.",
+        "",
+        "This error code is special: arch syscall entry code will return",
+        "[`Self::ENOSYS`] if users try to call a syscall that doesn't exist.",
+        "To keep failures of syscalls that really do exist distinguishable from",
+        "failures due to attempts to use a nonexistent syscall, syscall",
+        "implementations should refrain from returning [`Self::ENOSYS`]."
+    );
+
+    declare_err!(ENOTEMPTY, "Directory not empty.");
+
+    declare_err!(ELOOP, "Too many symbolic links encountered.");
+
+    declare_err!(EWOULDBLOCK, "Operation would block.");
+
+    declare_err!(ENOMSG, "No message of desired type.");
+
+    declare_err!(EIDRM, "Identifier removed.");
+
+    declare_err!(ECHRNG, "Channel number out of range.");
+
+    declare_err!(EL2NSYNC, "Level 2 not synchronized.");
+
+    declare_err!(EL3HLT, "Level 3 halted.");
+
+    declare_err!(EL3RST, "Level 3 reset.");
+
+    declare_err!(ELNRNG, "Link number out of range.");
+
+    declare_err!(EUNATCH, "Protocol driver not attached.");
+
+    declare_err!(ENOCSI, "No CSI structure available.");
+
+    declare_err!(EL2HLT, "Level 2 halted.");
+
+    declare_err!(EBADE, "Invalid exchange.");
+
+    declare_err!(EBADR, "Invalid request descriptor.");
+
+    declare_err!(EXFULL, "Exchange full.");
+
+    declare_err!(ENOANO, "No anode.");
+
+    declare_err!(EBADRQC, "Invalid request code.");
+
+    declare_err!(EBADSLT, "Invalid slot.");
+
+    declare_err!(EDEADLOCK, "Resource deadlock would occur.");
+
+    declare_err!(EBFONT, "Bad font file format.");
+
+    declare_err!(ENOSTR, "Device not a stream.");
+
+    declare_err!(ENODATA, "No data available.");
+
+    declare_err!(ETIME, "Timer expired.");
+
+    declare_err!(ENOSR, "Out of streams resources.");
+
+    declare_err!(ENONET, "Machine is not on the network.");
+
+    declare_err!(ENOPKG, "Package not installed.");
+
+    declare_err!(EREMOTE, "Object is remote.");
+
+    declare_err!(ENOLINK, "Link has been severed.");
+
+    declare_err!(EADV, "Advertise error.");
+
+    declare_err!(ESRMNT, "Srmount error.");
+
+    declare_err!(ECOMM, "Communication error on send.");
+
+    declare_err!(EPROTO, "Protocol error.");
+
+    declare_err!(EMULTIHOP, "Multihop attempted.");
+
+    declare_err!(EDOTDOT, "RFS specific error.");
+
+    declare_err!(EBADMSG, "Not a data message.");
+
+    declare_err!(EOVERFLOW, "Value too large for defined data type.");
+
+    declare_err!(ENOTUNIQ, "Name not unique on network.");
+
+    declare_err!(EBADFD, "File descriptor in bad state.");
+
+    declare_err!(EREMCHG, "Remote address changed.");
+
+    declare_err!(ELIBACC, "Can not access a needed shared library.");
+
+    declare_err!(ELIBBAD, "Accessing a corrupted shared library.");
+
+    declare_err!(ELIBSCN, ".lib section in a.out corrupted.");
+
+    declare_err!(ELIBMAX, "Attempting to link in too many shared libraries.");
+
+    declare_err!(ELIBEXEC, "Cannot exec a shared library directly.");
+
+    declare_err!(EILSEQ, "Illegal byte sequence.");
+
+    declare_err!(ERESTART, "Interrupted system call should be restarted.");
+
+    declare_err!(ESTRPIPE, "Streams pipe error.");
+
+    declare_err!(EUSERS, "Too many users.");
+
+    declare_err!(ENOTSOCK, "Socket operation on non-socket.");
+
+    declare_err!(EDESTADDRREQ, "Destination address required.");
+
+    declare_err!(EMSGSIZE, "Message too long.");
+
+    declare_err!(EPROTOTYPE, "Protocol wrong type for socket.");
+
+    declare_err!(ENOPROTOOPT, "Protocol not available.");
+
+    declare_err!(EPROTONOSUPPORT, "Protocol not supported.");
+
+    declare_err!(ESOCKTNOSUPPORT, "Socket type not supported.");
+
+    declare_err!(EOPNOTSUPP, "Operation not supported on transport endpoint.");
+
+    declare_err!(EPFNOSUPPORT, "Protocol family not supported.");
+
+    declare_err!(EAFNOSUPPORT, "Address family not supported by protocol.");
+
+    declare_err!(EADDRINUSE, "Address already in use.");
+
+    declare_err!(EADDRNOTAVAIL, "Cannot assign requested address.");
+
+    declare_err!(ENETDOWN, "Network is down.");
+
+    declare_err!(ENETUNREACH, "Network is unreachable.");
+
+    declare_err!(ENETRESET, "Network dropped connection because of reset.");
+
+    declare_err!(ECONNABORTED, "Software caused connection abort.");
+
+    declare_err!(ECONNRESET, "Connection reset by peer.");
+
+    declare_err!(ENOBUFS, "No buffer space available.");
+
+    declare_err!(EISCONN, "Transport endpoint is already connected.");
+
+    declare_err!(ENOTCONN, "Transport endpoint is not connected.");
+
+    declare_err!(ESHUTDOWN, "Cannot send after transport endpoint shutdown.");
+
+    declare_err!(ETOOMANYREFS, "Too many references: cannot splice.");
+
+    declare_err!(ETIMEDOUT, "Connection timed out.");
+
+    declare_err!(ECONNREFUSED, "Connection refused.");
+
+    declare_err!(EHOSTDOWN, "Host is down.");
+
+    declare_err!(EHOSTUNREACH, "No route to host.");
+
+    declare_err!(EALREADY, "Operation already in progress.");
+
+    declare_err!(EINPROGRESS, "Operation now in progress.");
+
+    declare_err!(ESTALE, "Stale file handle.");
+
+    declare_err!(EUCLEAN, "Structure needs cleaning.");
+
+    declare_err!(ENOTNAM, "Not a XENIX named type file.");
+
+    declare_err!(ENAVAIL, "No XENIX semaphores available.");
+
+    declare_err!(EISNAM, "Is a named type file.");
+
+    declare_err!(EREMOTEIO, "Remote I/O error.");
+
+    declare_err!(EDQUOT, "Quota exceeded.");
+
+    declare_err!(ENOMEDIUM, "No medium found.");
+
+    declare_err!(EMEDIUMTYPE, "Wrong medium type.");
+
+    declare_err!(ECANCELED, "Operation Canceled.");
+
+    declare_err!(ENOKEY, "Required key not available.");
+
+    declare_err!(EKEYEXPIRED, "Key has expired.");
+
+    declare_err!(EKEYREVOKED, "Key has been revoked.");
+
+    declare_err!(EKEYREJECTED, "Key was rejected by service.");
+
+    declare_err!(EOWNERDEAD, "Owner died.", "", "For robust mutexes.");
+
+    declare_err!(ENOTRECOVERABLE, "State not recoverable.");
+
+    declare_err!(ERFKILL, "Operation not possible due to RF-kill.");
+
+    declare_err!(EHWPOISON, "Memory page has hardware error.");
+
+    declare_err!(ERESTARTSYS, "Restart the system call.");
+
+    declare_err!(ENOTSUPP, "Operation is not supported.");
+
+    /// Creates an [`Error`] from a kernel error code.
+    ///
+    /// It is a bug to pass an out-of-range `errno`. `EINVAL` would
+    /// be returned in such a case.
+    pub(crate) fn from_kernel_errno(errno: c_types::c_int) -> Error {
+        if errno < -(bindings::MAX_ERRNO as i32) || errno >= 0 {
+            // TODO: make it a `WARN_ONCE` once available.
+            crate::pr_warn!(
+                "attempted to create `Error` with out of range `errno`: {}",
+                errno
+            );
+            return Error::EINVAL;
+        }
+
+        // INVARIANT: the check above ensures the type invariant
+        // will hold.
+        Error(errno)
+    }
+
+    /// Creates an [`Error`] from a kernel error code.
+    ///
+    /// # Safety
+    ///
+    /// `errno` must be within error code range (i.e. `>= -MAX_ERRNO && < 0`).
+    pub(crate) unsafe fn from_kernel_errno_unchecked(errno: c_types::c_int) -> Error {
+        // INVARIANT: the contract ensures the type invariant
+        // will hold.
+        Error(errno)
+    }
+
+    /// Returns the kernel error code.
+    pub fn to_kernel_errno(self) -> c_types::c_int {
+        self.0
+    }
+}
+
+impl fmt::Debug for Error {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        // SAFETY: FFI call.
+        let name = unsafe { bindings::errname(-self.0) };
+
+        if name.is_null() {
+            // Print out number if no name can be found.
+            return f.debug_tuple("Error").field(&-self.0).finish();
+        }
+
+        // SAFETY: `'static` string from C, and is not NULL.
+        let cstr = unsafe { CStr::from_char_ptr(name) };
+        // SAFETY: These strings are ASCII-only.
+        let str = unsafe { str::from_utf8_unchecked(cstr) };
+        f.debug_tuple(str).finish()
+    }
+}
+
+impl From<TryFromIntError> for Error {
+    fn from(_: TryFromIntError) -> Error {
+        Error::EINVAL
+    }
+}
+
+impl From<Utf8Error> for Error {
+    fn from(_: Utf8Error) -> Error {
+        Error::EINVAL
+    }
+}
+
+impl From<TryReserveError> for Error {
+    fn from(_: TryReserveError) -> Error {
+        Error::ENOMEM
+    }
+}
+
+impl From<LayoutError> for Error {
+    fn from(_: LayoutError) -> Error {
+        Error::ENOMEM
+    }
+}
+
+impl From<core::fmt::Error> for Error {
+    fn from(_: core::fmt::Error) -> Error {
+        Error::EINVAL
+    }
+}
+
+/// A [`Result`] with an [`Error`] error type.
+///
+/// To be used as the return type for functions that may fail.
+///
+/// # Error codes in C and Rust
+///
+/// In C, it is common that functions indicate success or failure through
+/// their return value; modifying or returning extra data through non-`const`
+/// pointer parameters. In particular, in the kernel, functions that may fail
+/// typically return an `int` that represents a generic error code. We model
+/// those as [`Error`].
+///
+/// In Rust, it is idiomatic to model functions that may fail as returning
+/// a [`Result`]. Since in the kernel many functions return an error code,
+/// [`Result`] is a type alias for a [`core::result::Result`] that uses
+/// [`Error`] as its error type.
+///
+/// Note that even if a function does not return anything when it succeeds,
+/// it should still be modeled as returning a `Result` rather than
+/// just an [`Error`].
+pub type Result<T = ()> = core::result::Result<T, Error>;
+
+impl From<AllocError> for Error {
+    fn from(_: AllocError) -> Error {
+        Error::ENOMEM
+    }
+}
+
+// # Invariant: `-bindings::MAX_ERRNO` fits in an `i16`.
+crate::static_assert!(bindings::MAX_ERRNO <= -(i16::MIN as i32) as u32);
+
+pub(crate) fn from_kernel_result_helper<T>(r: Result<T>) -> T
+where
+    T: From<i16>,
+{
+    match r {
+        Ok(v) => v,
+        // NO-OVERFLOW: negative `errno`s are no smaller than `-bindings::MAX_ERRNO`,
+        // `-bindings::MAX_ERRNO` fits in an `i16` as per invariant above,
+        // therefore a negative `errno` always fits in an `i16` and will not overflow.
+        Err(e) => T::from(e.to_kernel_errno() as i16),
+    }
+}
+
+/// Transforms a [`crate::error::Result<T>`] to a kernel C integer result.
+///
+/// This is useful when calling Rust functions that return [`crate::error::Result<T>`]
+/// from inside `extern "C"` functions that need to return an integer
+/// error result.
+///
+/// `T` should be convertible to an `i16` via `From<i16>`.
+///
+/// # Examples
+///
+/// ```ignore
+/// # use kernel::from_kernel_result;
+/// # use kernel::c_types;
+/// # use kernel::bindings;
+/// unsafe extern "C" fn probe_callback(
+///     pdev: *mut bindings::platform_device,
+/// ) -> c_types::c_int {
+///     from_kernel_result! {
+///         let ptr = devm_alloc(pdev)?;
+///         bindings::platform_set_drvdata(pdev, ptr);
+///         Ok(0)
+///     }
+/// }
+/// ```
+macro_rules! from_kernel_result {
+    ($($tt:tt)*) => {{
+        $crate::error::from_kernel_result_helper((|| {
+            $($tt)*
+        })())
+    }};
+}
+
+pub(crate) use from_kernel_result;
+
+/// Transform a kernel "error pointer" to a normal pointer.
+///
+/// Some kernel C API functions return an "error pointer" which optionally
+/// embeds an `errno`. Callers are supposed to check the returned pointer
+/// for errors. This function performs the check and converts the "error pointer"
+/// to a normal pointer in an idiomatic fashion.
+///
+/// # Examples
+///
+/// ```ignore
+/// # use kernel::prelude::*;
+/// # use kernel::from_kernel_err_ptr;
+/// # use kernel::c_types;
+/// # use kernel::bindings;
+/// fn devm_platform_ioremap_resource(
+///     pdev: &mut PlatformDevice,
+///     index: u32,
+/// ) -> Result<*mut c_types::c_void> {
+///     // SAFETY: FFI call.
+///     unsafe {
+///         from_kernel_err_ptr(bindings::devm_platform_ioremap_resource(
+///             pdev.to_ptr(),
+///             index,
+///         ))
+///     }
+/// }
+/// ```
+// TODO: remove `dead_code` marker once an in-kernel client is available.
+#[allow(dead_code)]
+pub(crate) fn from_kernel_err_ptr<T>(ptr: *mut T) -> Result<*mut T> {
+    // CAST: casting a pointer to `*const c_types::c_void` is always valid.
+    let const_ptr: *const c_types::c_void = ptr.cast();
+    // SAFETY: the FFI function does not deref the pointer.
+    if unsafe { bindings::IS_ERR(const_ptr) } {
+        // SAFETY: the FFI function does not deref the pointer.
+        let err = unsafe { bindings::PTR_ERR(const_ptr) };
+        // CAST: if `IS_ERR()` returns `true`,
+        // then `PTR_ERR()` is guaranteed to return a
+        // negative value greater-or-equal to `-bindings::MAX_ERRNO`,
+        // which always fits in an `i16`, as per the invariant above.
+        // And an `i16` always fits in an `i32`. So casting `err` to
+        // an `i32` can never overflow, and is always valid.
+        //
+        // SAFETY: `IS_ERR()` ensures `err` is a
+        // negative value greater-or-equal to `-bindings::MAX_ERRNO`
+        return Err(unsafe { Error::from_kernel_errno_unchecked(err as i32) });
+    }
+    Ok(ptr)
+}
+
+/// Calls a kernel function that returns an integer error code on failure and converts the result
+/// to a [`Result`].
+pub fn to_result(func: impl FnOnce() -> c_types::c_int) -> Result {
+    let err = func();
+    if err < 0 {
+        Err(Error::from_kernel_errno(err))
+    } else {
+        Ok(())
+    }
+}
diff --git a/rust/kernel/file.rs b/rust/kernel/file.rs
new file mode 100644
index 000000000000..648628837d82
--- /dev/null
+++ b/rust/kernel/file.rs
@@ -0,0 +1,147 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Files and file descriptors.
+//!
+//! C headers: [`include/linux/fs.h`](../../../../include/linux/fs.h) and
+//! [`include/linux/file.h`](../../../../include/linux/file.h)
+
+use crate::{bindings, cred::CredentialRef, error::Error, Result};
+use core::{mem::ManuallyDrop, ops::Deref};
+
+/// Wraps the kernel's `struct file`.
+///
+/// # Invariants
+///
+/// The pointer `File::ptr` is non-null and valid. Its reference count is also non-zero.
+pub struct File {
+    pub(crate) ptr: *mut bindings::file,
+}
+
+impl File {
+    /// Constructs a new [`struct file`] wrapper from a file descriptor.
+    ///
+    /// The file descriptor belongs to the current process.
+    pub fn from_fd(fd: u32) -> Result<Self> {
+        // SAFETY: FFI call, there are no requirements on `fd`.
+        let ptr = unsafe { bindings::fget(fd) };
+        if ptr.is_null() {
+            return Err(Error::EBADF);
+        }
+
+        // INVARIANTS: We checked that `ptr` is non-null, so it is valid. `fget` increments the ref
+        // count before returning.
+        Ok(Self { ptr })
+    }
+
+    /// Returns the current seek/cursor/pointer position (`struct file::f_pos`).
+    pub fn pos(&self) -> u64 {
+        // SAFETY: `File::ptr` is guaranteed to be valid by the type invariants.
+        unsafe { (*self.ptr).f_pos as u64 }
+    }
+
+    /// Returns whether the file is in blocking mode.
+    pub fn is_blocking(&self) -> bool {
+        // SAFETY: `File::ptr` is guaranteed to be valid by the type invariants.
+        unsafe { (*self.ptr).f_flags & bindings::O_NONBLOCK == 0 }
+    }
+
+    /// Returns the credentials of the task that originally opened the file.
+    pub fn cred(&self) -> CredentialRef<'_> {
+        // SAFETY: `File::ptr` is guaranteed to be valid by the type invariants.
+        let ptr = unsafe { (*self.ptr).f_cred };
+        // SAFETY: The lifetimes of `self` and `CredentialRef` are tied, so it is guaranteed that
+        // the credential pointer remains valid (because the file is still alive, and it doesn't
+        // change over the lifetime of a file).
+        unsafe { CredentialRef::from_ptr(ptr) }
+    }
+
+    /// Returns the flags associated with the file.
+    pub fn flags(&self) -> u32 {
+        // SAFETY: `File::ptr` is guaranteed to be valid by the type invariants.
+        unsafe { (*self.ptr).f_flags }
+    }
+}
+
+impl Drop for File {
+    fn drop(&mut self) {
+        // SAFETY: The type invariants guarantee that `File::ptr` has a non-zero reference count.
+        unsafe { bindings::fput(self.ptr) };
+    }
+}
+
+/// A wrapper for [`File`] that doesn't automatically decrement the refcount when dropped.
+///
+/// We need the wrapper because [`ManuallyDrop`] alone would allow callers to call
+/// [`ManuallyDrop::into_inner`]. This would allow an unsafe sequence to be triggered without
+/// `unsafe` blocks because it would trigger an unbalanced call to `fput`.
+///
+/// # Invariants
+///
+/// The wrapped [`File`] remains valid for the lifetime of the object.
+pub(crate) struct FileRef(ManuallyDrop<File>);
+
+impl FileRef {
+    /// Constructs a new [`struct file`] wrapper that doesn't change its reference count.
+    ///
+    /// # Safety
+    ///
+    /// The pointer `ptr` must be non-null and valid for the lifetime of the object.
+    pub(crate) unsafe fn from_ptr(ptr: *mut bindings::file) -> Self {
+        Self(ManuallyDrop::new(File { ptr }))
+    }
+}
+
+impl Deref for FileRef {
+    type Target = File;
+
+    fn deref(&self) -> &Self::Target {
+        self.0.deref()
+    }
+}
+
+/// A file descriptor reservation.
+///
+/// This allows the creation of a file descriptor in two steps: first, we reserve a slot for it,
+/// then we commit or drop the reservation. The first step may fail (e.g., the current process ran
+/// out of available slots), but commit and drop never fail (and are mutually exclusive).
+pub struct FileDescriptorReservation {
+    fd: u32,
+}
+
+impl FileDescriptorReservation {
+    /// Creates a new file descriptor reservation.
+    pub fn new(flags: u32) -> Result<Self> {
+        // SAFETY: FFI call, there are no safety requirements on `flags`.
+        let fd = unsafe { bindings::get_unused_fd_flags(flags) };
+        if fd < 0 {
+            return Err(Error::from_kernel_errno(fd));
+        }
+        Ok(Self { fd: fd as _ })
+    }
+
+    /// Returns the file descriptor number that was reserved.
+    pub fn reserved_fd(&self) -> u32 {
+        self.fd
+    }
+
+    /// Commits the reservation.
+    ///
+    /// The previously reserved file descriptor is bound to `file`.
+    pub fn commit(self, file: File) {
+        // SAFETY: `self.fd` was previously returned by `get_unused_fd_flags`, and `file.ptr` is
+        // guaranteed to have an owned ref count by its type invariants.
+        unsafe { bindings::fd_install(self.fd, file.ptr) };
+
+        // `fd_install` consumes both the file descriptor and the file reference, so we cannot run
+        // the destructors.
+        core::mem::forget(self);
+        core::mem::forget(file);
+    }
+}
+
+impl Drop for FileDescriptorReservation {
+    fn drop(&mut self) {
+        // SAFETY: `self.fd` was returned by a previous call to `get_unused_fd_flags`.
+        unsafe { bindings::put_unused_fd(self.fd) };
+    }
+}
diff --git a/rust/kernel/file_operations.rs b/rust/kernel/file_operations.rs
new file mode 100644
index 000000000000..47b5dfeea09c
--- /dev/null
+++ b/rust/kernel/file_operations.rs
@@ -0,0 +1,726 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! File operations.
+//!
+//! C header: [`include/linux/fs.h`](../../../../include/linux/fs.h)
+
+use crate::{
+    bindings, c_types,
+    error::{from_kernel_result, Error, Result},
+    file::{File, FileRef},
+    io_buffer::{IoBufferReader, IoBufferWriter},
+    iov_iter::IovIter,
+    sync::CondVar,
+    types::PointerWrapper,
+    user_ptr::{UserSlicePtr, UserSlicePtrReader, UserSlicePtrWriter},
+};
+use core::convert::{TryFrom, TryInto};
+use core::{marker, mem, ptr};
+
+/// Wraps the kernel's `struct poll_table_struct`.
+///
+/// # Invariants
+///
+/// The pointer `PollTable::ptr` is null or valid.
+pub struct PollTable {
+    ptr: *mut bindings::poll_table_struct,
+}
+
+impl PollTable {
+    /// Constructors a new `struct poll_table_struct` wrapper.
+    ///
+    /// # Safety
+    ///
+    /// The pointer `ptr` must be either null or a valid pointer for the lifetime of the object.
+    unsafe fn from_ptr(ptr: *mut bindings::poll_table_struct) -> Self {
+        Self { ptr }
+    }
+
+    /// Associates the given file and condition variable to this poll table. It means notifying the
+    /// condition variable will notify the poll table as well; additionally, the association
+    /// between the condition variable and the file will automatically be undone by the kernel when
+    /// the file is destructed. To unilaterally remove the association before then, one can call
+    /// [`CondVar::free_waiters`].
+    ///
+    /// # Safety
+    ///
+    /// If the condition variable is destroyed before the file, then [`CondVar::free_waiters`] must
+    /// be called to ensure that all waiters are flushed out.
+    pub unsafe fn register_wait<'a>(&self, file: &'a File, cv: &'a CondVar) {
+        if self.ptr.is_null() {
+            return;
+        }
+
+        // SAFETY: `PollTable::ptr` is guaranteed to be valid by the type invariants and the null
+        // check above.
+        let table = unsafe { &*self.ptr };
+        if let Some(proc) = table._qproc {
+            // SAFETY: All pointers are known to be valid.
+            unsafe { proc(file.ptr as _, cv.wait_list.get(), self.ptr) }
+        }
+    }
+}
+
+/// Equivalent to [`std::io::SeekFrom`].
+///
+/// [`std::io::SeekFrom`]: https://doc.rust-lang.org/std/io/enum.SeekFrom.html
+pub enum SeekFrom {
+    /// Equivalent to C's `SEEK_SET`.
+    Start(u64),
+
+    /// Equivalent to C's `SEEK_END`.
+    End(i64),
+
+    /// Equivalent to C's `SEEK_CUR`.
+    Current(i64),
+}
+
+pub(crate) struct FileOperationsVtable<A, T>(marker::PhantomData<A>, marker::PhantomData<T>);
+
+impl<A: FileOpenAdapter<T::OpenData>, T: FileOperations> FileOperationsVtable<A, T> {
+    /// Called by the VFS when an inode should be opened.
+    ///
+    /// Calls `T::open` on the returned value of `A::convert`.
+    ///
+    /// # Safety
+    ///
+    /// The returned value of `A::convert` must be a valid non-null pointer and
+    /// `T:open` must return a valid non-null pointer on an `Ok` result.
+    unsafe extern "C" fn open_callback(
+        inode: *mut bindings::inode,
+        file: *mut bindings::file,
+    ) -> c_types::c_int {
+        from_kernel_result! {
+            // SAFETY: `A::convert` must return a valid non-null pointer that
+            // should point to data in the inode or file that lives longer
+            // than the following use of `T::open`.
+            let arg = unsafe { A::convert(inode, file) };
+            // SAFETY: The C contract guarantees that `file` is valid. Additionally,
+            // `fileref` never outlives this function, so it is guaranteed to be
+            // valid.
+            let fileref = unsafe { FileRef::from_ptr(file) };
+            // SAFETY: `arg` was previously returned by `A::convert` and must
+            // be a valid non-null pointer.
+            let ptr = T::open(unsafe { &*arg }, &fileref)?.into_pointer();
+            // SAFETY: The C contract guarantees that `private_data` is available
+            // for implementers of the file operations (no other C code accesses
+            // it), so we know that there are no concurrent threads/CPUs accessing
+            // it (it's not visible to any other Rust code).
+            unsafe { (*file).private_data = ptr as *mut c_types::c_void };
+            Ok(0)
+        }
+    }
+
+    unsafe extern "C" fn read_callback(
+        file: *mut bindings::file,
+        buf: *mut c_types::c_char,
+        len: c_types::c_size_t,
+        offset: *mut bindings::loff_t,
+    ) -> c_types::c_ssize_t {
+        from_kernel_result! {
+            let mut data = unsafe { UserSlicePtr::new(buf as *mut c_types::c_void, len).writer() };
+            // SAFETY: `private_data` was initialised by `open_callback` with a value returned by
+            // `T::Wrapper::into_pointer`. `T::Wrapper::from_pointer` is only called by the
+            // `release` callback, which the C API guarantees that will be called only when all
+            // references to `file` have been released, so we know it can't be called while this
+            // function is running.
+            let f = unsafe { T::Wrapper::borrow((*file).private_data) };
+            // No `FMODE_UNSIGNED_OFFSET` support, so `offset` must be in [0, 2^63).
+            // See discussion in https://github.com/fishinabarrel/linux-kernel-module-rust/pull/113
+            let read = T::read(
+                f,
+                unsafe { &FileRef::from_ptr(file) },
+                &mut data,
+                unsafe { *offset }.try_into()?,
+            )?;
+            unsafe { (*offset) += bindings::loff_t::try_from(read).unwrap() };
+            Ok(read as _)
+        }
+    }
+
+    unsafe extern "C" fn read_iter_callback(
+        iocb: *mut bindings::kiocb,
+        raw_iter: *mut bindings::iov_iter,
+    ) -> isize {
+        from_kernel_result! {
+            let mut iter = unsafe { IovIter::from_ptr(raw_iter) };
+            let file = unsafe { (*iocb).ki_filp };
+            let offset = unsafe { (*iocb).ki_pos };
+            // SAFETY: `private_data` was initialised by `open_callback` with a value returned by
+            // `T::Wrapper::into_pointer`. `T::Wrapper::from_pointer` is only called by the
+            // `release` callback, which the C API guarantees that will be called only when all
+            // references to `file` have been released, so we know it can't be called while this
+            // function is running.
+            let f = unsafe { T::Wrapper::borrow((*file).private_data) };
+            let read =
+                T::read(f, unsafe { &FileRef::from_ptr(file) }, &mut iter, offset.try_into()?)?;
+            unsafe { (*iocb).ki_pos += bindings::loff_t::try_from(read).unwrap() };
+            Ok(read as _)
+        }
+    }
+
+    unsafe extern "C" fn write_callback(
+        file: *mut bindings::file,
+        buf: *const c_types::c_char,
+        len: c_types::c_size_t,
+        offset: *mut bindings::loff_t,
+    ) -> c_types::c_ssize_t {
+        from_kernel_result! {
+            let mut data = unsafe { UserSlicePtr::new(buf as *mut c_types::c_void, len).reader() };
+            // SAFETY: `private_data` was initialised by `open_callback` with a value returned by
+            // `T::Wrapper::into_pointer`. `T::Wrapper::from_pointer` is only called by the
+            // `release` callback, which the C API guarantees that will be called only when all
+            // references to `file` have been released, so we know it can't be called while this
+            // function is running.
+            let f = unsafe { T::Wrapper::borrow((*file).private_data) };
+            // No `FMODE_UNSIGNED_OFFSET` support, so `offset` must be in [0, 2^63).
+            // See discussion in https://github.com/fishinabarrel/linux-kernel-module-rust/pull/113
+            let written = T::write(
+                f,
+                unsafe { &FileRef::from_ptr(file) },
+                &mut data,
+                unsafe { *offset }.try_into()?
+            )?;
+            unsafe { (*offset) += bindings::loff_t::try_from(written).unwrap() };
+            Ok(written as _)
+        }
+    }
+
+    unsafe extern "C" fn write_iter_callback(
+        iocb: *mut bindings::kiocb,
+        raw_iter: *mut bindings::iov_iter,
+    ) -> isize {
+        from_kernel_result! {
+            let mut iter = unsafe { IovIter::from_ptr(raw_iter) };
+            let file = unsafe { (*iocb).ki_filp };
+            let offset = unsafe { (*iocb).ki_pos };
+            // SAFETY: `private_data` was initialised by `open_callback` with a value returned by
+            // `T::Wrapper::into_pointer`. `T::Wrapper::from_pointer` is only called by the
+            // `release` callback, which the C API guarantees that will be called only when all
+            // references to `file` have been released, so we know it can't be called while this
+            // function is running.
+            let f = unsafe { T::Wrapper::borrow((*file).private_data) };
+            let written =
+                T::write(f, unsafe { &FileRef::from_ptr(file) }, &mut iter, offset.try_into()?)?;
+            unsafe { (*iocb).ki_pos += bindings::loff_t::try_from(written).unwrap() };
+            Ok(written as _)
+        }
+    }
+
+    unsafe extern "C" fn release_callback(
+        _inode: *mut bindings::inode,
+        file: *mut bindings::file,
+    ) -> c_types::c_int {
+        let ptr = mem::replace(unsafe { &mut (*file).private_data }, ptr::null_mut());
+        T::release(unsafe { T::Wrapper::from_pointer(ptr as _) }, unsafe {
+            &FileRef::from_ptr(file)
+        });
+        0
+    }
+
+    unsafe extern "C" fn llseek_callback(
+        file: *mut bindings::file,
+        offset: bindings::loff_t,
+        whence: c_types::c_int,
+    ) -> bindings::loff_t {
+        from_kernel_result! {
+            let off = match whence as u32 {
+                bindings::SEEK_SET => SeekFrom::Start(offset.try_into()?),
+                bindings::SEEK_CUR => SeekFrom::Current(offset),
+                bindings::SEEK_END => SeekFrom::End(offset),
+                _ => return Err(Error::EINVAL),
+            };
+            // SAFETY: `private_data` was initialised by `open_callback` with a value returned by
+            // `T::Wrapper::into_pointer`. `T::Wrapper::from_pointer` is only called by the
+            // `release` callback, which the C API guarantees that will be called only when all
+            // references to `file` have been released, so we know it can't be called while this
+            // function is running.
+            let f = unsafe { T::Wrapper::borrow((*file).private_data) };
+            let off = T::seek(f, unsafe { &FileRef::from_ptr(file) }, off)?;
+            Ok(off as bindings::loff_t)
+        }
+    }
+
+    unsafe extern "C" fn unlocked_ioctl_callback(
+        file: *mut bindings::file,
+        cmd: c_types::c_uint,
+        arg: c_types::c_ulong,
+    ) -> c_types::c_long {
+        from_kernel_result! {
+            // SAFETY: `private_data` was initialised by `open_callback` with a value returned by
+            // `T::Wrapper::into_pointer`. `T::Wrapper::from_pointer` is only called by the
+            // `release` callback, which the C API guarantees that will be called only when all
+            // references to `file` have been released, so we know it can't be called while this
+            // function is running.
+            let f = unsafe { T::Wrapper::borrow((*file).private_data) };
+            let mut cmd = IoctlCommand::new(cmd as _, arg as _);
+            let ret = T::ioctl(f, unsafe { &FileRef::from_ptr(file) }, &mut cmd)?;
+            Ok(ret as _)
+        }
+    }
+
+    unsafe extern "C" fn compat_ioctl_callback(
+        file: *mut bindings::file,
+        cmd: c_types::c_uint,
+        arg: c_types::c_ulong,
+    ) -> c_types::c_long {
+        from_kernel_result! {
+            // SAFETY: `private_data` was initialised by `open_callback` with a value returned by
+            // `T::Wrapper::into_pointer`. `T::Wrapper::from_pointer` is only called by the
+            // `release` callback, which the C API guarantees that will be called only when all
+            // references to `file` have been released, so we know it can't be called while this
+            // function is running.
+            let f = unsafe { T::Wrapper::borrow((*file).private_data) };
+            let mut cmd = IoctlCommand::new(cmd as _, arg as _);
+            let ret = T::compat_ioctl(f, unsafe { &FileRef::from_ptr(file) }, &mut cmd)?;
+            Ok(ret as _)
+        }
+    }
+
+    unsafe extern "C" fn mmap_callback(
+        file: *mut bindings::file,
+        vma: *mut bindings::vm_area_struct,
+    ) -> c_types::c_int {
+        from_kernel_result! {
+            // SAFETY: `private_data` was initialised by `open_callback` with a value returned by
+            // `T::Wrapper::into_pointer`. `T::Wrapper::from_pointer` is only called by the
+            // `release` callback, which the C API guarantees that will be called only when all
+            // references to `file` have been released, so we know it can't be called while this
+            // function is running.
+            let f = unsafe { T::Wrapper::borrow((*file).private_data) };
+            T::mmap(f, unsafe { &FileRef::from_ptr(file) }, unsafe { &mut *vma })?;
+            Ok(0)
+        }
+    }
+
+    unsafe extern "C" fn fsync_callback(
+        file: *mut bindings::file,
+        start: bindings::loff_t,
+        end: bindings::loff_t,
+        datasync: c_types::c_int,
+    ) -> c_types::c_int {
+        from_kernel_result! {
+            let start = start.try_into()?;
+            let end = end.try_into()?;
+            let datasync = datasync != 0;
+            // SAFETY: `private_data` was initialised by `open_callback` with a value returned by
+            // `T::Wrapper::into_pointer`. `T::Wrapper::from_pointer` is only called by the
+            // `release` callback, which the C API guarantees that will be called only when all
+            // references to `file` have been released, so we know it can't be called while this
+            // function is running.
+            let f = unsafe { T::Wrapper::borrow((*file).private_data) };
+            let res = T::fsync(f, unsafe { &FileRef::from_ptr(file) }, start, end, datasync)?;
+            Ok(res.try_into().unwrap())
+        }
+    }
+
+    unsafe extern "C" fn poll_callback(
+        file: *mut bindings::file,
+        wait: *mut bindings::poll_table_struct,
+    ) -> bindings::__poll_t {
+        // SAFETY: `private_data` was initialised by `open_callback` with a value returned by
+        // `T::Wrapper::into_pointer`. `T::Wrapper::from_pointer` is only called by the `release`
+        // callback, which the C API guarantees that will be called only when all references to
+        // `file` have been released, so we know it can't be called while this function is running.
+        let f = unsafe { T::Wrapper::borrow((*file).private_data) };
+        match T::poll(f, unsafe { &FileRef::from_ptr(file) }, unsafe {
+            &PollTable::from_ptr(wait)
+        }) {
+            Ok(v) => v,
+            Err(_) => bindings::POLLERR,
+        }
+    }
+
+    const VTABLE: bindings::file_operations = bindings::file_operations {
+        open: Some(Self::open_callback),
+        release: Some(Self::release_callback),
+        read: if T::TO_USE.read {
+            Some(Self::read_callback)
+        } else {
+            None
+        },
+        write: if T::TO_USE.write {
+            Some(Self::write_callback)
+        } else {
+            None
+        },
+        llseek: if T::TO_USE.seek {
+            Some(Self::llseek_callback)
+        } else {
+            None
+        },
+
+        check_flags: None,
+        compat_ioctl: if T::TO_USE.compat_ioctl {
+            Some(Self::compat_ioctl_callback)
+        } else {
+            None
+        },
+        copy_file_range: None,
+        fallocate: None,
+        fadvise: None,
+        fasync: None,
+        flock: None,
+        flush: None,
+        fsync: if T::TO_USE.fsync {
+            Some(Self::fsync_callback)
+        } else {
+            None
+        },
+        get_unmapped_area: None,
+        iterate: None,
+        iterate_shared: None,
+        iopoll: None,
+        lock: None,
+        mmap: if T::TO_USE.mmap {
+            Some(Self::mmap_callback)
+        } else {
+            None
+        },
+        mmap_supported_flags: 0,
+        owner: ptr::null_mut(),
+        poll: if T::TO_USE.poll {
+            Some(Self::poll_callback)
+        } else {
+            None
+        },
+        read_iter: if T::TO_USE.read_iter {
+            Some(Self::read_iter_callback)
+        } else {
+            None
+        },
+        remap_file_range: None,
+        sendpage: None,
+        setlease: None,
+        show_fdinfo: None,
+        splice_read: None,
+        splice_write: None,
+        unlocked_ioctl: if T::TO_USE.ioctl {
+            Some(Self::unlocked_ioctl_callback)
+        } else {
+            None
+        },
+        write_iter: if T::TO_USE.write_iter {
+            Some(Self::write_iter_callback)
+        } else {
+            None
+        },
+    };
+
+    /// Builds an instance of [`struct file_operations`].
+    ///
+    /// # Safety
+    ///
+    /// The caller must ensure that the adapter is compatible with the way the device is registered.
+    pub(crate) const unsafe fn build() -> &'static bindings::file_operations {
+        &Self::VTABLE
+    }
+}
+
+/// Represents which fields of [`struct file_operations`] should be populated with pointers.
+pub struct ToUse {
+    /// The `read` field of [`struct file_operations`].
+    pub read: bool,
+
+    /// The `read_iter` field of [`struct file_operations`].
+    pub read_iter: bool,
+
+    /// The `write` field of [`struct file_operations`].
+    pub write: bool,
+
+    /// The `write_iter` field of [`struct file_operations`].
+    pub write_iter: bool,
+
+    /// The `llseek` field of [`struct file_operations`].
+    pub seek: bool,
+
+    /// The `unlocked_ioctl` field of [`struct file_operations`].
+    pub ioctl: bool,
+
+    /// The `compat_ioctl` field of [`struct file_operations`].
+    pub compat_ioctl: bool,
+
+    /// The `fsync` field of [`struct file_operations`].
+    pub fsync: bool,
+
+    /// The `mmap` field of [`struct file_operations`].
+    pub mmap: bool,
+
+    /// The `poll` field of [`struct file_operations`].
+    pub poll: bool,
+}
+
+/// A constant version where all values are to set to `false`, that is, all supported fields will
+/// be set to null pointers.
+pub const USE_NONE: ToUse = ToUse {
+    read: false,
+    read_iter: false,
+    write: false,
+    write_iter: false,
+    seek: false,
+    ioctl: false,
+    compat_ioctl: false,
+    fsync: false,
+    mmap: false,
+    poll: false,
+};
+
+/// Defines the [`FileOperations::TO_USE`] field based on a list of fields to be populated.
+#[macro_export]
+macro_rules! declare_file_operations {
+    () => {
+        const TO_USE: $crate::file_operations::ToUse = $crate::file_operations::USE_NONE;
+    };
+    ($($i:ident),+) => {
+        const TO_USE: kernel::file_operations::ToUse =
+            $crate::file_operations::ToUse {
+                $($i: true),+ ,
+                ..$crate::file_operations::USE_NONE
+            };
+    };
+}
+
+/// Allows the handling of ioctls defined with the `_IO`, `_IOR`, `_IOW`, and `_IOWR` macros.
+///
+/// For each macro, there is a handler function that takes the appropriate types as arguments.
+pub trait IoctlHandler: Sync {
+    /// The type of the first argument to each associated function.
+    type Target<'a>;
+
+    /// Handles ioctls defined with the `_IO` macro, that is, with no buffer as argument.
+    fn pure(_this: Self::Target<'_>, _file: &File, _cmd: u32, _arg: usize) -> Result<i32> {
+        Err(Error::EINVAL)
+    }
+
+    /// Handles ioctls defined with the `_IOR` macro, that is, with an output buffer provided as
+    /// argument.
+    fn read(
+        _this: Self::Target<'_>,
+        _file: &File,
+        _cmd: u32,
+        _writer: &mut UserSlicePtrWriter,
+    ) -> Result<i32> {
+        Err(Error::EINVAL)
+    }
+
+    /// Handles ioctls defined with the `_IOW` macro, that is, with an input buffer provided as
+    /// argument.
+    fn write(
+        _this: Self::Target<'_>,
+        _file: &File,
+        _cmd: u32,
+        _reader: &mut UserSlicePtrReader,
+    ) -> Result<i32> {
+        Err(Error::EINVAL)
+    }
+
+    /// Handles ioctls defined with the `_IOWR` macro, that is, with a buffer for both input and
+    /// output provided as argument.
+    fn read_write(
+        _this: Self::Target<'_>,
+        _file: &File,
+        _cmd: u32,
+        _data: UserSlicePtr,
+    ) -> Result<i32> {
+        Err(Error::EINVAL)
+    }
+}
+
+/// Represents an ioctl command.
+///
+/// It can use the components of an ioctl command to dispatch ioctls using
+/// [`IoctlCommand::dispatch`].
+pub struct IoctlCommand {
+    cmd: u32,
+    arg: usize,
+    user_slice: Option<UserSlicePtr>,
+}
+
+impl IoctlCommand {
+    /// Constructs a new [`IoctlCommand`].
+    fn new(cmd: u32, arg: usize) -> Self {
+        let size = (cmd >> bindings::_IOC_SIZESHIFT) & bindings::_IOC_SIZEMASK;
+
+        // SAFETY: We only create one instance of the user slice per ioctl call, so TOCTOU issues
+        // are not possible.
+        let user_slice = Some(unsafe { UserSlicePtr::new(arg as _, size as _) });
+        Self {
+            cmd,
+            arg,
+            user_slice,
+        }
+    }
+
+    /// Dispatches the given ioctl to the appropriate handler based on the value of the command. It
+    /// also creates a [`UserSlicePtr`], [`UserSlicePtrReader`], or [`UserSlicePtrWriter`]
+    /// depending on the direction of the buffer of the command.
+    ///
+    /// It is meant to be used in implementations of [`FileOperations::ioctl`] and
+    /// [`FileOperations::compat_ioctl`].
+    pub fn dispatch<T: IoctlHandler>(
+        &mut self,
+        handler: T::Target<'_>,
+        file: &File,
+    ) -> Result<i32> {
+        let dir = (self.cmd >> bindings::_IOC_DIRSHIFT) & bindings::_IOC_DIRMASK;
+        if dir == bindings::_IOC_NONE {
+            return T::pure(handler, file, self.cmd, self.arg);
+        }
+
+        let data = self.user_slice.take().ok_or(Error::EINVAL)?;
+        const READ_WRITE: u32 = bindings::_IOC_READ | bindings::_IOC_WRITE;
+        match dir {
+            bindings::_IOC_WRITE => T::write(handler, file, self.cmd, &mut data.reader()),
+            bindings::_IOC_READ => T::read(handler, file, self.cmd, &mut data.writer()),
+            READ_WRITE => T::read_write(handler, file, self.cmd, data),
+            _ => Err(Error::EINVAL),
+        }
+    }
+
+    /// Returns the raw 32-bit value of the command and the ptr-sized argument.
+    pub fn raw(&self) -> (u32, usize) {
+        (self.cmd, self.arg)
+    }
+}
+
+/// Trait for extracting file open arguments from kernel data structures.
+///
+/// This is meant to be implemented by registration managers.
+pub trait FileOpenAdapter<T: Sync> {
+    /// Converts untyped data stored in [`struct inode`] and [`struct file`] (when [`struct
+    /// file_operations::open`] is called) into the given type. For example, for `miscdev`
+    /// devices, a pointer to the registered [`struct miscdev`] is stored in [`struct
+    /// file::private_data`].
+    ///
+    /// # Safety
+    ///
+    /// This function must be called only when [`struct file_operations::open`] is being called for
+    /// a file that was registered by the implementer. The returned pointer must be valid and
+    /// not-null.
+    unsafe fn convert(_inode: *mut bindings::inode, _file: *mut bindings::file) -> *const T;
+}
+
+/// Corresponds to the kernel's `struct file_operations`.
+///
+/// You implement this trait whenever you would create a `struct file_operations`.
+///
+/// File descriptors may be used from multiple threads/processes concurrently, so your type must be
+/// [`Sync`]. It must also be [`Send`] because [`FileOperations::release`] will be called from the
+/// thread that decrements that associated file's refcount to zero.
+pub trait FileOperations {
+    /// The methods to use to populate [`struct file_operations`].
+    const TO_USE: ToUse;
+
+    /// The pointer type that will be used to hold ourselves.
+    type Wrapper: PointerWrapper + Send + Sync = ();
+
+    /// The type of the context data passed to [`FileOperations::open`].
+    type OpenData: Sync = ();
+
+    /// Creates a new instance of this file.
+    ///
+    /// Corresponds to the `open` function pointer in `struct file_operations`.
+    fn open(context: &Self::OpenData, file: &File) -> Result<Self::Wrapper>;
+
+    /// Cleans up after the last reference to the file goes away.
+    ///
+    /// Note that the object is moved, so it will be freed automatically unless the implementation
+    /// moves it elsewhere.
+    ///
+    /// Corresponds to the `release` function pointer in `struct file_operations`.
+    fn release(_obj: Self::Wrapper, _file: &File) {}
+
+    /// Reads data from this file to the caller's buffer.
+    ///
+    /// Corresponds to the `read` and `read_iter` function pointers in `struct file_operations`.
+    fn read(
+        _this: <Self::Wrapper as PointerWrapper>::Borrowed<'_>,
+        _file: &File,
+        _data: &mut impl IoBufferWriter,
+        _offset: u64,
+    ) -> Result<usize> {
+        Err(Error::EINVAL)
+    }
+
+    /// Writes data from the caller's buffer to this file.
+    ///
+    /// Corresponds to the `write` and `write_iter` function pointers in `struct file_operations`.
+    fn write(
+        _this: <Self::Wrapper as PointerWrapper>::Borrowed<'_>,
+        _file: &File,
+        _data: &mut impl IoBufferReader,
+        _offset: u64,
+    ) -> Result<usize> {
+        Err(Error::EINVAL)
+    }
+
+    /// Changes the position of the file.
+    ///
+    /// Corresponds to the `llseek` function pointer in `struct file_operations`.
+    fn seek(
+        _this: <Self::Wrapper as PointerWrapper>::Borrowed<'_>,
+        _file: &File,
+        _offset: SeekFrom,
+    ) -> Result<u64> {
+        Err(Error::EINVAL)
+    }
+
+    /// Performs IO control operations that are specific to the file.
+    ///
+    /// Corresponds to the `unlocked_ioctl` function pointer in `struct file_operations`.
+    fn ioctl(
+        _this: <Self::Wrapper as PointerWrapper>::Borrowed<'_>,
+        _file: &File,
+        _cmd: &mut IoctlCommand,
+    ) -> Result<i32> {
+        Err(Error::ENOTTY)
+    }
+
+    /// Performs 32-bit IO control operations on that are specific to the file on 64-bit kernels.
+    ///
+    /// Corresponds to the `compat_ioctl` function pointer in `struct file_operations`.
+    fn compat_ioctl(
+        _this: <Self::Wrapper as PointerWrapper>::Borrowed<'_>,
+        _file: &File,
+        _cmd: &mut IoctlCommand,
+    ) -> Result<i32> {
+        Err(Error::ENOTTY)
+    }
+
+    /// Syncs pending changes to this file.
+    ///
+    /// Corresponds to the `fsync` function pointer in `struct file_operations`.
+    fn fsync(
+        _this: <Self::Wrapper as PointerWrapper>::Borrowed<'_>,
+        _file: &File,
+        _start: u64,
+        _end: u64,
+        _datasync: bool,
+    ) -> Result<u32> {
+        Err(Error::EINVAL)
+    }
+
+    /// Maps areas of the caller's virtual memory with device/file memory.
+    ///
+    /// Corresponds to the `mmap` function pointer in `struct file_operations`.
+    /// TODO: wrap `vm_area_struct` so that we don't have to expose it.
+    fn mmap(
+        _this: <Self::Wrapper as PointerWrapper>::Borrowed<'_>,
+        _file: &File,
+        _vma: &mut bindings::vm_area_struct,
+    ) -> Result {
+        Err(Error::EINVAL)
+    }
+
+    /// Checks the state of the file and optionally registers for notification when the state
+    /// changes.
+    ///
+    /// Corresponds to the `poll` function pointer in `struct file_operations`.
+    fn poll(
+        _this: <Self::Wrapper as PointerWrapper>::Borrowed<'_>,
+        _file: &File,
+        _table: &PollTable,
+    ) -> Result<u32> {
+        Ok(bindings::POLLIN | bindings::POLLOUT | bindings::POLLRDNORM | bindings::POLLWRNORM)
+    }
+}
diff --git a/rust/kernel/gpio.rs b/rust/kernel/gpio.rs
new file mode 100644
index 000000000000..d02524ded599
--- /dev/null
+++ b/rust/kernel/gpio.rs
@@ -0,0 +1,477 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Support for gpio device drivers.
+//!
+//! C header: [`include/linux/gpio/driver.h`](../../../../include/linux/gpio/driver.h)
+
+use crate::{
+    bindings, c_types, device, error::from_kernel_result, types::PointerWrapper, Error, Result,
+};
+use core::{
+    cell::UnsafeCell,
+    marker::{PhantomData, PhantomPinned},
+    pin::Pin,
+};
+
+#[cfg(CONFIG_GPIOLIB_IRQCHIP)]
+pub use irqchip::{ChipWithIrqChip, RegistrationWithIrqChip};
+
+/// The direction of a gpio line.
+pub enum LineDirection {
+    /// Direction is input.
+    In = bindings::GPIO_LINE_DIRECTION_IN as _,
+
+    /// Direction is output.
+    Out = bindings::GPIO_LINE_DIRECTION_OUT as _,
+}
+
+/// A gpio chip.
+pub trait Chip {
+    /// Context data associated with the gpio chip.
+    ///
+    /// It determines the type of the context data passed to each of the methods of the trait.
+    type Data: PointerWrapper + Sync + Send;
+
+    /// The methods to use to populate [`struct gpio_chip`]. This is typically populated with
+    /// [`declare_gpio_chip_operations`].
+    const TO_USE: ToUse;
+
+    /// Returns the direction of the given gpio line.
+    fn get_direction(
+        _data: <Self::Data as PointerWrapper>::Borrowed<'_>,
+        _offset: u32,
+    ) -> Result<LineDirection> {
+        Err(Error::ENOTSUPP)
+    }
+
+    /// Configures the direction as input of the given gpio line.
+    fn direction_input(
+        _data: <Self::Data as PointerWrapper>::Borrowed<'_>,
+        _offset: u32,
+    ) -> Result {
+        Err(Error::EIO)
+    }
+
+    /// Configures the direction as output of the given gpio line.
+    ///
+    /// The value that will be initially output is also specified.
+    fn direction_output(
+        _data: <Self::Data as PointerWrapper>::Borrowed<'_>,
+        _offset: u32,
+        _value: bool,
+    ) -> Result {
+        Err(Error::ENOTSUPP)
+    }
+
+    /// Returns the current value of the given gpio line.
+    fn get(_data: <Self::Data as PointerWrapper>::Borrowed<'_>, _offset: u32) -> Result<bool> {
+        Err(Error::EIO)
+    }
+
+    /// Sets the value of the given gpio line.
+    fn set(_data: <Self::Data as PointerWrapper>::Borrowed<'_>, _offset: u32, _value: bool) {}
+}
+
+/// Represents which fields of [`struct gpio_chip`] should be populated with pointers.
+///
+/// This is typically populated with the [`declare_gpio_chip_operations`] macro.
+pub struct ToUse {
+    /// The `get_direction` field of [`struct gpio_chip`].
+    pub get_direction: bool,
+
+    /// The `direction_input` field of [`struct gpio_chip`].
+    pub direction_input: bool,
+
+    /// The `direction_output` field of [`struct gpio_chip`].
+    pub direction_output: bool,
+
+    /// The `get` field of [`struct gpio_chip`].
+    pub get: bool,
+
+    /// The `set` field of [`struct gpio_chip`].
+    pub set: bool,
+}
+
+/// A constant version where all values are set to `false`, that is, all supported fields will be
+/// set to null pointers.
+pub const USE_NONE: ToUse = ToUse {
+    get_direction: false,
+    direction_input: false,
+    direction_output: false,
+    get: false,
+    set: false,
+};
+
+/// Defines the [`Chip::TO_USE`] field based on a list of fields to be populated.
+#[macro_export]
+macro_rules! declare_gpio_chip_operations {
+    () => {
+        const TO_USE: $crate::gpio::ToUse = $crate::gpio::USE_NONE;
+    };
+    ($($i:ident),+) => {
+        #[allow(clippy::needless_update)]
+        const TO_USE: $crate::gpio::ToUse =
+            $crate::gpio::ToUse {
+                $($i: true),+ ,
+                ..$crate::gpio::USE_NONE
+            };
+    };
+}
+
+/// A registration of a gpio chip.
+pub struct Registration<T: Chip> {
+    gc: UnsafeCell<bindings::gpio_chip>,
+    parent: Option<device::Device>,
+    _p: PhantomData<T>,
+    _pin: PhantomPinned,
+}
+
+impl<T: Chip> Registration<T> {
+    /// Creates a new [`Registration`] but does not register it yet.
+    ///
+    /// It is allowed to move.
+    pub fn new() -> Self {
+        Self {
+            parent: None,
+            gc: UnsafeCell::new(bindings::gpio_chip::default()),
+            _pin: PhantomPinned,
+            _p: PhantomData,
+        }
+    }
+
+    /// Registers a gpio chip with the rest of the kernel.
+    pub fn register(
+        self: Pin<&mut Self>,
+        gpio_count: u16,
+        base: Option<i32>,
+        parent: &dyn device::RawDevice,
+        data: T::Data,
+    ) -> Result {
+        if self.parent.is_some() {
+            // Already registered.
+            return Err(Error::EINVAL);
+        }
+
+        // SAFETY: We never move out of `this`.
+        let this = unsafe { self.get_unchecked_mut() };
+        {
+            let gc = this.gc.get_mut();
+
+            // Set up the callbacks.
+            gc.request = Some(bindings::gpiochip_generic_request);
+            gc.free = Some(bindings::gpiochip_generic_free);
+            if T::TO_USE.get_direction {
+                gc.get_direction = Some(get_direction_callback::<T>);
+            }
+            if T::TO_USE.direction_input {
+                gc.direction_input = Some(direction_input_callback::<T>);
+            }
+            if T::TO_USE.direction_output {
+                gc.direction_output = Some(direction_output_callback::<T>);
+            }
+            if T::TO_USE.get {
+                gc.get = Some(get_callback::<T>);
+            }
+            if T::TO_USE.set {
+                gc.set = Some(set_callback::<T>);
+            }
+
+            // When a base is not explicitly given, use -1 for one to be picked.
+            if let Some(b) = base {
+                gc.base = b;
+            } else {
+                gc.base = -1;
+            }
+
+            gc.ngpio = gpio_count;
+            gc.parent = parent.raw_device();
+            gc.label = parent.name().as_char_ptr();
+
+            // TODO: Define `gc.owner` as well.
+        }
+
+        let data_pointer = <T::Data as PointerWrapper>::into_pointer(data);
+        // SAFETY: `gc` was initilised above, so it is valid.
+        let ret = unsafe {
+            bindings::gpiochip_add_data_with_key(
+                this.gc.get(),
+                data_pointer as _,
+                core::ptr::null_mut(),
+                core::ptr::null_mut(),
+            )
+        };
+        if ret < 0 {
+            // SAFETY: `data_pointer` was returned by `into_pointer` above.
+            unsafe { T::Data::from_pointer(data_pointer) };
+            return Err(Error::from_kernel_errno(ret));
+        }
+
+        this.parent = Some(device::Device::from_dev(parent));
+        Ok(())
+    }
+}
+
+// SAFETY: `Registration` doesn't offer any methods or access to fields when shared between threads
+// or CPUs, so it is safe to share it.
+unsafe impl<T: Chip> Sync for Registration<T> {}
+
+// SAFETY: Registration with and unregistration from the gpio subsystem can happen from any thread.
+// Additionally, `T::Data` (which is dropped during unregistration) is `Send`, so it is ok to move
+// `Registration` to different threads.
+#[allow(clippy::non_send_fields_in_send_ty)]
+unsafe impl<T: Chip> Send for Registration<T> {}
+
+impl<T: Chip> Default for Registration<T> {
+    fn default() -> Self {
+        Self::new()
+    }
+}
+
+impl<T: Chip> Drop for Registration<T> {
+    /// Removes the registration from the kernel if it has completed successfully before.
+    fn drop(&mut self) {
+        if self.parent.is_some() {
+            // Get a pointer to the data stored in chip before destroying it.
+            // SAFETY: `gc` was during registration, which is guaranteed to have succeeded (because
+            // `parent` is `Some(_)`, so it remains valid.
+            let data_pointer = unsafe { bindings::gpiochip_get_data(self.gc.get()) };
+
+            // SAFETY: By the same argument above, `gc` is still valid.
+            unsafe { bindings::gpiochip_remove(self.gc.get()) };
+
+            // Free data as well.
+            // SAFETY: `data_pointer` was returned by `into_pointer` during registration.
+            unsafe { <T::Data as PointerWrapper>::from_pointer(data_pointer) };
+        }
+    }
+}
+
+unsafe extern "C" fn get_direction_callback<T: Chip>(
+    gc: *mut bindings::gpio_chip,
+    offset: c_types::c_uint,
+) -> c_types::c_int {
+    from_kernel_result! {
+        // SAFETY: The value stored as chip data was returned by `into_pointer` during registration.
+        let data = unsafe { T::Data::borrow(bindings::gpiochip_get_data(gc)) };
+        Ok(T::get_direction(data, offset)? as i32)
+    }
+}
+
+unsafe extern "C" fn direction_input_callback<T: Chip>(
+    gc: *mut bindings::gpio_chip,
+    offset: c_types::c_uint,
+) -> c_types::c_int {
+    from_kernel_result! {
+        // SAFETY: The value stored as chip data was returned by `into_pointer` during registration.
+        let data = unsafe { T::Data::borrow(bindings::gpiochip_get_data(gc)) };
+        T::direction_input(data, offset)?;
+        Ok(0)
+    }
+}
+
+unsafe extern "C" fn direction_output_callback<T: Chip>(
+    gc: *mut bindings::gpio_chip,
+    offset: c_types::c_uint,
+    value: c_types::c_int,
+) -> c_types::c_int {
+    from_kernel_result! {
+        // SAFETY: The value stored as chip data was returned by `into_pointer` during registration.
+        let data = unsafe { T::Data::borrow(bindings::gpiochip_get_data(gc)) };
+        T::direction_output(data, offset, value != 0)?;
+        Ok(0)
+    }
+}
+
+unsafe extern "C" fn get_callback<T: Chip>(
+    gc: *mut bindings::gpio_chip,
+    offset: c_types::c_uint,
+) -> c_types::c_int {
+    from_kernel_result! {
+        // SAFETY: The value stored as chip data was returned by `into_pointer` during registration.
+        let data = unsafe { T::Data::borrow(bindings::gpiochip_get_data(gc)) };
+        let v = T::get(data, offset)?;
+        Ok(v as _)
+    }
+}
+
+unsafe extern "C" fn set_callback<T: Chip>(
+    gc: *mut bindings::gpio_chip,
+    offset: c_types::c_uint,
+    value: c_types::c_int,
+) {
+    // SAFETY: The value stored as chip data was returned by `into_pointer` during registration.
+    let data = unsafe { T::Data::borrow(bindings::gpiochip_get_data(gc)) };
+    T::set(data, offset, value != 0);
+}
+
+#[cfg(CONFIG_GPIOLIB_IRQCHIP)]
+mod irqchip {
+    use super::*;
+    use crate::irq;
+
+    /// A gpio chip that includes an irq chip.
+    pub trait ChipWithIrqChip: Chip {
+        /// Implements the irq flow for the gpio chip.
+        fn handle_irq_flow(
+            _data: <Self::Data as PointerWrapper>::Borrowed<'_>,
+            _desc: &irq::Descriptor,
+            _domain: &irq::Domain,
+        );
+    }
+
+    /// A registration of a gpio chip that includes an irq chip.
+    pub struct RegistrationWithIrqChip<T: ChipWithIrqChip> {
+        reg: Registration<T>,
+        irq_chip: UnsafeCell<bindings::irq_chip>,
+        parent_irq: u32,
+    }
+
+    impl<T: ChipWithIrqChip> RegistrationWithIrqChip<T> {
+        /// Creates a new [`RegistrationWithIrqChip`] but does not register it yet.
+        ///
+        /// It is allowed to move.
+        pub fn new() -> Self {
+            Self {
+                reg: Registration::new(),
+                irq_chip: UnsafeCell::new(bindings::irq_chip::default()),
+                parent_irq: 0,
+            }
+        }
+
+        /// Registers a gpio chip and its irq chip with the rest of the kernel.
+        pub fn register<U: irq::Chip<Data = T::Data>>(
+            mut self: Pin<&mut Self>,
+            gpio_count: u16,
+            base: Option<i32>,
+            parent: &dyn device::RawDevice,
+            data: T::Data,
+            parent_irq: u32,
+        ) -> Result {
+            if self.reg.parent.is_some() {
+                // Already registered.
+                return Err(Error::EINVAL);
+            }
+
+            // SAFETY: We never move out of `this`.
+            let this = unsafe { self.as_mut().get_unchecked_mut() };
+
+            // Initialise the irq_chip.
+            {
+                let irq_chip = this.irq_chip.get_mut();
+                irq_chip.name = parent.name().as_char_ptr();
+
+                // SAFETY: The gpio subsystem configures a pointer to `gpio_chip` as the irq chip
+                // data, so we use `IrqChipAdapter` to convert to the `T::Data`, which is the same
+                // as `irq::Chip::Data` per the bound above.
+                unsafe { irq::init_chip::<IrqChipAdapter<U>>(irq_chip) };
+            }
+
+            // Initialise gc irq state.
+            {
+                let girq = &mut this.reg.gc.get_mut().irq;
+                girq.chip = this.irq_chip.get();
+                // SAFETY: By leaving `parent_handler_data` set to `null`, the gpio subsystem
+                // initialises it to a pointer to the gpio chip, which is what `FlowHandler<T>`
+                // expects.
+                girq.parent_handler = unsafe { irq::new_flow_handler::<FlowHandler<T>>() };
+                girq.num_parents = 1;
+                girq.parents = &mut this.parent_irq;
+                this.parent_irq = parent_irq;
+                girq.default_type = bindings::IRQ_TYPE_NONE;
+                girq.handler = Some(bindings::handle_bad_irq);
+            }
+
+            // SAFETY: `reg` is pinned when `self` is.
+            let pinned = unsafe { self.map_unchecked_mut(|r| &mut r.reg) };
+            pinned.register(gpio_count, base, parent, data)
+        }
+    }
+
+    impl<T: ChipWithIrqChip> Default for RegistrationWithIrqChip<T> {
+        fn default() -> Self {
+            Self::new()
+        }
+    }
+
+    // SAFETY: `RegistrationWithIrqChip` doesn't offer any methods or access to fields when shared
+    // between threads or CPUs, so it is safe to share it.
+    unsafe impl<T: ChipWithIrqChip> Sync for RegistrationWithIrqChip<T> {}
+
+    // SAFETY: Registration with and unregistration from the gpio subsystem (including irq chips for
+    // them) can happen from any thread. Additionally, `T::Data` (which is dropped during
+    // unregistration) is `Send`, so it is ok to move `Registration` to different threads.
+    #[allow(clippy::non_send_fields_in_send_ty)]
+    unsafe impl<T: ChipWithIrqChip> Send for RegistrationWithIrqChip<T> where T::Data: Send {}
+
+    struct FlowHandler<T: ChipWithIrqChip>(PhantomData<T>);
+
+    impl<T: ChipWithIrqChip> irq::FlowHandler for FlowHandler<T> {
+        type Data = *mut bindings::gpio_chip;
+
+        fn handle_irq_flow(gc: *mut bindings::gpio_chip, desc: &irq::Descriptor) {
+            // SAFETY: `FlowHandler` is only used in gpio chips, and it is removed when the gpio is
+            // unregistered, so we know that `gc` must still be valid. We also know that the value
+            // stored as gpio data was returned by `T::Data::into_pointer` again because
+            // `FlowHandler` is a private structure only used in this way.
+            let data = unsafe { T::Data::borrow(bindings::gpiochip_get_data(gc)) };
+
+            // SAFETY: `gc` is valid (see comment above), so we can dereference it.
+            let domain = unsafe { irq::Domain::from_ptr((*gc).irq.domain) };
+
+            T::handle_irq_flow(data, desc, &domain);
+        }
+    }
+
+    /// Adapter from an irq chip with `gpio_chip` pointer as context to one where the gpio chip
+    /// data is passed as context.
+    struct IrqChipAdapter<T: irq::Chip>(PhantomData<T>);
+
+    impl<T: irq::Chip> irq::Chip for IrqChipAdapter<T> {
+        type Data = *mut bindings::gpio_chip;
+        const TO_USE: irq::ToUse = T::TO_USE;
+
+        fn ack(gc: *mut bindings::gpio_chip, irq_data: &irq::IrqData) {
+            // SAFETY: `IrqChipAdapter` is a private struct, only used when the data stored in the
+            // gpio chip is known to come from `T::Data`, and only valid while the gpio chip is
+            // registered, so `gc` is valid.
+            let data = unsafe { T::Data::borrow(bindings::gpiochip_get_data(gc as _)) };
+            T::ack(data, irq_data);
+        }
+
+        fn mask(gc: *mut bindings::gpio_chip, irq_data: &irq::IrqData) {
+            // SAFETY: `IrqChipAdapter` is a private struct, only used when the data stored in the
+            // gpio chip is known to come from `T::Data`, and only valid while the gpio chip is
+            // registered, so `gc` is valid.
+            let data = unsafe { T::Data::borrow(bindings::gpiochip_get_data(gc as _)) };
+            T::mask(data, irq_data);
+        }
+
+        fn unmask(gc: *mut bindings::gpio_chip, irq_data: &irq::IrqData) {
+            // SAFETY: `IrqChipAdapter` is a private struct, only used when the data stored in the
+            // gpio chip is known to come from `T::Data`, and only valid while the gpio chip is
+            // registered, so `gc` is valid.
+            let data = unsafe { T::Data::borrow(bindings::gpiochip_get_data(gc as _)) };
+            T::unmask(data, irq_data);
+        }
+
+        fn set_type(
+            gc: *mut bindings::gpio_chip,
+            irq_data: &mut irq::LockedIrqData,
+            flow_type: u32,
+        ) -> Result<irq::ExtraResult> {
+            // SAFETY: `IrqChipAdapter` is a private struct, only used when the data stored in the
+            // gpio chip is known to come from `T::Data`, and only valid while the gpio chip is
+            // registered, so `gc` is valid.
+            let data = unsafe { T::Data::borrow(bindings::gpiochip_get_data(gc as _)) };
+            T::set_type(data, irq_data, flow_type)
+        }
+
+        fn set_wake(gc: *mut bindings::gpio_chip, irq_data: &irq::IrqData, on: bool) -> Result {
+            // SAFETY: `IrqChipAdapter` is a private struct, only used when the data stored in the
+            // gpio chip is known to come from `T::Data`, and only valid while the gpio chip is
+            // registered, so `gc` is valid.
+            let data = unsafe { T::Data::borrow(bindings::gpiochip_get_data(gc as _)) };
+            T::set_wake(data, irq_data, on)
+        }
+    }
+}
diff --git a/rust/kernel/io_buffer.rs b/rust/kernel/io_buffer.rs
new file mode 100644
index 000000000000..ccecc4763aca
--- /dev/null
+++ b/rust/kernel/io_buffer.rs
@@ -0,0 +1,153 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Buffers used in IO.
+
+use crate::Result;
+use alloc::vec::Vec;
+use core::mem::{size_of, MaybeUninit};
+
+/// Represents a buffer to be read from during IO.
+pub trait IoBufferReader {
+    /// Returns the number of bytes left to be read from the io buffer.
+    ///
+    /// Note that even reading less than this number of bytes may fail.
+    fn len(&self) -> usize;
+
+    /// Returns `true` if no data is available in the io buffer.
+    fn is_empty(&self) -> bool {
+        self.len() == 0
+    }
+
+    /// Reads raw data from the io buffer into a raw kernel buffer.
+    ///
+    /// # Safety
+    ///
+    /// The output buffer must be valid.
+    unsafe fn read_raw(&mut self, out: *mut u8, len: usize) -> Result;
+
+    /// Reads all data remaining in the io buffer.
+    ///
+    /// Returns `EFAULT` if the address does not currently point to mapped, readable memory.
+    fn read_all(&mut self) -> Result<Vec<u8>> {
+        let mut data = Vec::<u8>::new();
+        data.try_resize(self.len(), 0)?;
+
+        // SAFETY: The output buffer is valid as we just allocated it.
+        unsafe { self.read_raw(data.as_mut_ptr(), data.len())? };
+        Ok(data)
+    }
+
+    /// Reads a byte slice from the io buffer.
+    ///
+    /// Returns `EFAULT` if the byte slice is bigger than the remaining size of the user slice or
+    /// if the address does not currently point to mapped, readable memory.
+    fn read_slice(&mut self, data: &mut [u8]) -> Result {
+        // SAFETY: The output buffer is valid as it's coming from a live reference.
+        unsafe { self.read_raw(data.as_mut_ptr(), data.len()) }
+    }
+
+    /// Reads the contents of a plain old data (POD) type from the io buffer.
+    fn read<T: ReadableFromBytes>(&mut self) -> Result<T> {
+        let mut out = MaybeUninit::<T>::uninit();
+        // SAFETY: The buffer is valid as it was just allocated.
+        unsafe { self.read_raw(out.as_mut_ptr() as _, size_of::<T>()) }?;
+        // SAFETY: We just initialised the data.
+        Ok(unsafe { out.assume_init() })
+    }
+}
+
+/// Represents a buffer to be written to during IO.
+pub trait IoBufferWriter {
+    /// Returns the number of bytes left to be written into the io buffer.
+    ///
+    /// Note that even writing less than this number of bytes may fail.
+    fn len(&self) -> usize;
+
+    /// Returns `true` if the io buffer cannot hold any additional data.
+    fn is_empty(&self) -> bool {
+        self.len() == 0
+    }
+
+    /// Writes zeroes to the io buffer.
+    ///
+    /// Differently from the other write functions, `clear` will zero as much as it can and update
+    /// the writer internal state to reflect this. It will, however, return an error if it cannot
+    /// clear `len` bytes.
+    ///
+    /// For example, if a caller requests that 100 bytes be cleared but a segfault happens after
+    /// 20 bytes, then EFAULT is returned and the writer is advanced by 20 bytes.
+    fn clear(&mut self, len: usize) -> Result;
+
+    /// Writes a byte slice into the io buffer.
+    ///
+    /// Returns `EFAULT` if the byte slice is bigger than the remaining size of the io buffer or if
+    /// the address does not currently point to mapped, writable memory.
+    fn write_slice(&mut self, data: &[u8]) -> Result {
+        // SAFETY: The input buffer is valid as it's coming from a live reference.
+        unsafe { self.write_raw(data.as_ptr(), data.len()) }
+    }
+
+    /// Writes raw data to the io buffer from a raw kernel buffer.
+    ///
+    /// # Safety
+    ///
+    /// The input buffer must be valid.
+    unsafe fn write_raw(&mut self, data: *const u8, len: usize) -> Result;
+
+    /// Writes the contents of the given data into the io buffer.
+    fn write<T: WritableToBytes>(&mut self, data: &T) -> Result {
+        // SAFETY: The input buffer is valid as it's coming from a live
+        // reference to a type that implements `WritableToBytes`.
+        unsafe { self.write_raw(data as *const T as _, size_of::<T>()) }
+    }
+}
+
+/// Specifies that a type is safely readable from byte slices.
+///
+/// Not all types can be safely read from byte slices; examples from
+/// <https://doc.rust-lang.org/reference/behavior-considered-undefined.html> include `bool`
+/// that must be either `0` or `1`, and `char` that cannot be a surrogate or above `char::MAX`.
+///
+/// # Safety
+///
+/// Implementers must ensure that the type is made up only of types that can be safely read from
+/// arbitrary byte sequences (e.g., `u32`, `u64`, etc.).
+pub unsafe trait ReadableFromBytes {}
+
+// SAFETY: All bit patterns are acceptable values of the types below.
+unsafe impl ReadableFromBytes for u8 {}
+unsafe impl ReadableFromBytes for u16 {}
+unsafe impl ReadableFromBytes for u32 {}
+unsafe impl ReadableFromBytes for u64 {}
+unsafe impl ReadableFromBytes for usize {}
+unsafe impl ReadableFromBytes for i8 {}
+unsafe impl ReadableFromBytes for i16 {}
+unsafe impl ReadableFromBytes for i32 {}
+unsafe impl ReadableFromBytes for i64 {}
+unsafe impl ReadableFromBytes for isize {}
+
+/// Specifies that a type is safely writable to byte slices.
+///
+/// This means that we don't read undefined values (which leads to UB) in preparation for writing
+/// to the byte slice. It also ensures that no potentially sensitive information is leaked into the
+/// byte slices.
+///
+/// # Safety
+///
+/// A type must not include padding bytes and must be fully initialised to safely implement
+/// [`WritableToBytes`] (i.e., it doesn't contain [`MaybeUninit`] fields). A composition of
+/// writable types in a structure is not necessarily writable because it may result in padding
+/// bytes.
+pub unsafe trait WritableToBytes {}
+
+// SAFETY: Initialised instances of the following types have no uninitialised portions.
+unsafe impl WritableToBytes for u8 {}
+unsafe impl WritableToBytes for u16 {}
+unsafe impl WritableToBytes for u32 {}
+unsafe impl WritableToBytes for u64 {}
+unsafe impl WritableToBytes for usize {}
+unsafe impl WritableToBytes for i8 {}
+unsafe impl WritableToBytes for i16 {}
+unsafe impl WritableToBytes for i32 {}
+unsafe impl WritableToBytes for i64 {}
+unsafe impl WritableToBytes for isize {}
diff --git a/rust/kernel/io_mem.rs b/rust/kernel/io_mem.rs
new file mode 100644
index 000000000000..496c44f74c7b
--- /dev/null
+++ b/rust/kernel/io_mem.rs
@@ -0,0 +1,227 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Memory-mapped IO.
+//!
+//! C header: [`include/asm-generic/io.h`](../../../../include/asm-generic/io.h)
+
+#![allow(dead_code)]
+
+use crate::{bindings, Error, Result};
+use core::convert::TryInto;
+
+/// Represents a memory resource.
+pub struct Resource {
+    offset: bindings::resource_size_t,
+    size: bindings::resource_size_t,
+}
+
+impl Resource {
+    pub(crate) fn new(
+        start: bindings::resource_size_t,
+        end: bindings::resource_size_t,
+    ) -> Option<Self> {
+        if start == 0 {
+            return None;
+        }
+        Some(Self {
+            offset: start,
+            size: end.checked_sub(start)?.checked_add(1)?,
+        })
+    }
+}
+
+/// Represents a memory block of at least `SIZE` bytes.
+///
+/// # Invariants
+///
+/// `ptr` is a non-null and valid address of at least `SIZE` bytes and returned by an `ioremap`
+/// variant. `ptr` is also 8-byte aligned.
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::prelude::*;
+/// use kernel::io_mem::{IoMem, Resource};
+///
+/// fn test(res: Resource) -> Result {
+///     // Create an io mem block of at least 100 bytes.
+///     // SAFETY: No DMA operations are initiated through `mem`.
+///     let mem = unsafe { IoMem::<100>::try_new(res) }?;
+///
+///     // Read one byte from offset 10.
+///     let v = mem.readb(10);
+///
+///     // Write value to offset 20.
+///     mem.writeb(v, 20);
+///
+///     Ok(())
+/// }
+///
+/// ```
+pub struct IoMem<const SIZE: usize> {
+    ptr: usize,
+}
+
+macro_rules! define_read {
+    ($(#[$attr:meta])* $name:ident, $try_name:ident, $type_name:ty) => {
+        /// Reads IO data from the given offset known, at compile time.
+        ///
+        /// If the offset is not known at compile time, the build will fail.
+        $(#[$attr])*
+        pub fn $name(&self, offset: usize) -> $type_name {
+            Self::check_offset::<$type_name>(offset);
+            let ptr = self.ptr.wrapping_add(offset);
+            // SAFETY: The type invariants guarantee that `ptr` is a valid pointer. The check above
+            // guarantees that the code won't build if `offset` makes the read go out of bounds
+            // (including the type size).
+            unsafe { bindings::$name(ptr as _) }
+        }
+
+        /// Reads IO data from the given offset.
+        ///
+        /// It fails if/when the offset (plus the type size) is out of bounds.
+        $(#[$attr])*
+        pub fn $try_name(&self, offset: usize) -> Result<$type_name> {
+            if !Self::offset_ok::<$type_name>(offset) {
+                return Err(Error::EINVAL);
+            }
+            let ptr = self.ptr.wrapping_add(offset);
+            // SAFETY: The type invariants guarantee that `ptr` is a valid pointer. The check above
+            // returns an error if `offset` would make the read go out of bounds (including the
+            // type size).
+            Ok(unsafe { bindings::$name(ptr as _) })
+        }
+    };
+}
+
+macro_rules! define_write {
+    ($(#[$attr:meta])* $name:ident, $try_name:ident, $type_name:ty) => {
+        /// Writes IO data to the given offset, known at compile time.
+        ///
+        /// If the offset is not known at compile time, the build will fail.
+        $(#[$attr])*
+        pub fn $name(&self, value: $type_name, offset: usize) {
+            Self::check_offset::<$type_name>(offset);
+            let ptr = self.ptr.wrapping_add(offset);
+            // SAFETY: The type invariants guarantee that `ptr` is a valid pointer. The check above
+            // guarantees that the code won't link if `offset` makes the write go out of bounds
+            // (including the type size).
+            unsafe { bindings::$name(value, ptr as _) }
+        }
+
+        /// Writes IO data to the given offset.
+        ///
+        /// It fails if/when the offset (plus the type size) is out of bounds.
+        $(#[$attr])*
+        pub fn $try_name(&self, value: $type_name, offset: usize) -> Result {
+            if !Self::offset_ok::<$type_name>(offset) {
+                return Err(Error::EINVAL);
+            }
+            let ptr = self.ptr.wrapping_add(offset);
+            // SAFETY: The type invariants guarantee that `ptr` is a valid pointer. The check above
+            // returns an error if `offset` would make the write go out of bounds (including the
+            // type size).
+            unsafe { bindings::$name(value, ptr as _) };
+            Ok(())
+        }
+    };
+}
+
+impl<const SIZE: usize> IoMem<SIZE> {
+    /// Tries to create a new instance of a memory block.
+    ///
+    /// The resource described by `res` is mapped into the CPU's address space so that it can be
+    /// accessed directly. It is also consumed by this function so that it can't be mapped again
+    /// to a different address.
+    ///
+    /// # Safety
+    ///
+    /// Callers must ensure that either (a) the resulting interface cannot be used to initiate DMA
+    /// operations, or (b) that DMA operations initiated via the returned interface use DMA handles
+    /// allocated through the `dma` module.
+    pub unsafe fn try_new(res: Resource) -> Result<Self> {
+        // Check that the resource has at least `SIZE` bytes in it.
+        if res.size < SIZE.try_into()? {
+            return Err(Error::EINVAL);
+        }
+
+        // To be able to check pointers at compile time based only on offsets, we need to guarantee
+        // that the base pointer is minimally aligned. So we conservatively expect at least 8 bytes.
+        if res.offset % 8 != 0 {
+            crate::pr_err!("Physical address is not 64-bit aligned: {:x}", res.offset);
+            return Err(Error::EDOM);
+        }
+
+        // Try to map the resource.
+        // SAFETY: Just mapping the memory range.
+        let addr = unsafe { bindings::ioremap(res.offset, res.size as _) };
+        if addr.is_null() {
+            Err(Error::ENOMEM)
+        } else {
+            // INVARIANT: `addr` is non-null and was returned by `ioremap`, so it is valid. It is
+            // also 8-byte aligned because we checked it above.
+            Ok(Self { ptr: addr as usize })
+        }
+    }
+
+    const fn offset_ok<T>(offset: usize) -> bool {
+        let type_size = core::mem::size_of::<T>();
+        if let Some(end) = offset.checked_add(type_size) {
+            end <= SIZE && offset % type_size == 0
+        } else {
+            false
+        }
+    }
+
+    const fn check_offset<T>(offset: usize) {
+        crate::build_assert!(Self::offset_ok::<T>(offset), "IoMem offset overflow");
+    }
+
+    define_read!(readb, try_readb, u8);
+    define_read!(readw, try_readw, u16);
+    define_read!(readl, try_readl, u32);
+    define_read!(
+        #[cfg(CONFIG_64BIT)]
+        readq,
+        try_readq,
+        u64
+    );
+
+    define_read!(readb_relaxed, try_readb_relaxed, u8);
+    define_read!(readw_relaxed, try_readw_relaxed, u16);
+    define_read!(readl_relaxed, try_readl_relaxed, u32);
+    define_read!(
+        #[cfg(CONFIG_64BIT)]
+        readq_relaxed,
+        try_readq_relaxed,
+        u64
+    );
+
+    define_write!(writeb, try_writeb, u8);
+    define_write!(writew, try_writew, u16);
+    define_write!(writel, try_writel, u32);
+    define_write!(
+        #[cfg(CONFIG_64BIT)]
+        writeq,
+        try_writeq,
+        u64
+    );
+
+    define_write!(writeb_relaxed, try_writeb_relaxed, u8);
+    define_write!(writew_relaxed, try_writew_relaxed, u16);
+    define_write!(writel_relaxed, try_writel_relaxed, u32);
+    define_write!(
+        #[cfg(CONFIG_64BIT)]
+        writeq_relaxed,
+        try_writeq_relaxed,
+        u64
+    );
+}
+
+impl<const SIZE: usize> Drop for IoMem<SIZE> {
+    fn drop(&mut self) {
+        // SAFETY: By the type invariant, `self.ptr` is a value returned by a previous successful
+        // call to `ioremap`.
+        unsafe { bindings::iounmap(self.ptr as _) };
+    }
+}
diff --git a/rust/kernel/iov_iter.rs b/rust/kernel/iov_iter.rs
new file mode 100644
index 000000000000..fe738c529b84
--- /dev/null
+++ b/rust/kernel/iov_iter.rs
@@ -0,0 +1,81 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! IO vector iterators.
+//!
+//! C header: [`include/linux/uio.h`](../../../../include/linux/uio.h)
+
+use crate::{
+    bindings,
+    error::Error,
+    io_buffer::{IoBufferReader, IoBufferWriter},
+    Result,
+};
+
+/// Wraps the kernel's `struct iov_iter`.
+///
+/// # Invariants
+///
+/// The pointer `IovIter::ptr` is non-null and valid.
+pub struct IovIter {
+    ptr: *mut bindings::iov_iter,
+}
+
+impl IovIter {
+    fn common_len(&self) -> usize {
+        // SAFETY: `IovIter::ptr` is guaranteed to be valid by the type invariants.
+        unsafe { (*self.ptr).count }
+    }
+
+    /// Constructs a new [`struct iov_iter`] wrapper.
+    ///
+    /// # Safety
+    ///
+    /// The pointer `ptr` must be non-null and valid for the lifetime of the object.
+    pub(crate) unsafe fn from_ptr(ptr: *mut bindings::iov_iter) -> Self {
+        // INVARIANTS: the safety contract ensures the type invariant will hold.
+        Self { ptr }
+    }
+}
+
+impl IoBufferWriter for IovIter {
+    fn len(&self) -> usize {
+        self.common_len()
+    }
+
+    fn clear(&mut self, mut len: usize) -> Result {
+        while len > 0 {
+            // SAFETY: `IovIter::ptr` is guaranteed to be valid by the type invariants.
+            let written = unsafe { bindings::iov_iter_zero(len, self.ptr) };
+            if written == 0 {
+                return Err(Error::EFAULT);
+            }
+
+            len -= written;
+        }
+        Ok(())
+    }
+
+    unsafe fn write_raw(&mut self, data: *const u8, len: usize) -> Result {
+        let res = unsafe { bindings::copy_to_iter(data as _, len, self.ptr) };
+        if res != len {
+            Err(Error::EFAULT)
+        } else {
+            Ok(())
+        }
+    }
+}
+
+impl IoBufferReader for IovIter {
+    fn len(&self) -> usize {
+        self.common_len()
+    }
+
+    unsafe fn read_raw(&mut self, out: *mut u8, len: usize) -> Result {
+        let res = unsafe { bindings::copy_from_iter(out as _, len, self.ptr) };
+        if res != len {
+            Err(Error::EFAULT)
+        } else {
+            Ok(())
+        }
+    }
+}
diff --git a/rust/kernel/irq.rs b/rust/kernel/irq.rs
new file mode 100644
index 000000000000..ca62849a5dc0
--- /dev/null
+++ b/rust/kernel/irq.rs
@@ -0,0 +1,409 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Interrupts and interrupt chips.
+//!
+//! See <https://www.kernel.org/doc/Documentation/core-api/genericirq.rst>.
+//!
+//! C headers: [`include/linux/irq.h`](../../../../include/linux/irq.h) and
+//! [`include/linux/interrupt.h`](../../../../include/linux/interrupt.h).
+
+#![allow(dead_code)]
+
+use crate::{bindings, c_types, error::from_kernel_result, types::PointerWrapper, Error, Result};
+use core::ops::Deref;
+
+/// The type of irq hardware numbers.
+pub type HwNumber = bindings::irq_hw_number_t;
+
+/// Wraps the kernel's `struct irq_data`.
+///
+/// # Invariants
+///
+/// The pointer `IrqData::ptr` is non-null and valid.
+pub struct IrqData {
+    ptr: *mut bindings::irq_data,
+}
+
+impl IrqData {
+    /// Creates a new `IrqData` instance from a raw pointer.
+    ///
+    /// # Safety
+    ///
+    /// Callers must ensure that `ptr` is non-null and valid when the function is called, and that
+    /// it remains valid for the lifetime of the return [`IrqData`] instance.
+    unsafe fn from_ptr(ptr: *mut bindings::irq_data) -> Self {
+        // INVARIANTS: By the safety requirements, the instance we're creating satisfies the type
+        // invariants.
+        Self { ptr }
+    }
+
+    /// Returns the hardware irq number.
+    pub fn hwirq(&self) -> HwNumber {
+        // SAFETY: By the type invariants, it's ok to dereference `ptr`.
+        unsafe { (*self.ptr).hwirq }
+    }
+}
+
+/// Wraps the kernel's `struct irq_data` when it is locked.
+///
+/// Being locked allows additional operations to be performed on the data.
+pub struct LockedIrqData(IrqData);
+
+impl LockedIrqData {
+    /// Sets the high-level irq flow handler to the builtin one for level-triggered irqs.
+    pub fn set_level_handler(&mut self) {
+        // SAFETY: By the type invariants of `self.0`, we know `self.0.ptr` is valid.
+        unsafe { bindings::irq_set_handler_locked(self.0.ptr, Some(bindings::handle_level_irq)) };
+    }
+
+    /// Sets the high-level irq flow handler to the builtin one for edge-triggered irqs.
+    pub fn set_edge_handler(&mut self) {
+        // SAFETY: By the type invariants of `self.0`, we know `self.0.ptr` is valid.
+        unsafe { bindings::irq_set_handler_locked(self.0.ptr, Some(bindings::handle_edge_irq)) };
+    }
+
+    /// Sets the high-level irq flow handler to the builtin one for bad irqs.
+    pub fn set_bad_handler(&mut self) {
+        // SAFETY: By the type invariants of `self.0`, we know `self.0.ptr` is valid.
+        unsafe { bindings::irq_set_handler_locked(self.0.ptr, Some(bindings::handle_bad_irq)) };
+    }
+}
+
+impl Deref for LockedIrqData {
+    type Target = IrqData;
+
+    fn deref(&self) -> &Self::Target {
+        &self.0
+    }
+}
+
+/// Extra information returned by some of the [`Chip`] methods on success.
+pub enum ExtraResult {
+    /// Indicates that the caller (irq core) will update the descriptor state.
+    None = bindings::IRQ_SET_MASK_OK as _,
+
+    /// Indicates that the callee (irq chip implementation) already updated the descriptor state.
+    NoCopy = bindings::IRQ_SET_MASK_OK_NOCOPY as _,
+
+    /// Same as [`ExtraResult::None`] in terms of updating descriptor state. It is used in stacked
+    /// irq chips to indicate that descendant chips should be skipped.
+    Done = bindings::IRQ_SET_MASK_OK_DONE as _,
+}
+
+/// An irq chip.
+///
+/// It is a trait for the functions defined in [`struct irq_chip`].
+///
+/// [`struct irq_chip`]: ../../../include/linux/irq.h
+pub trait Chip: Sized {
+    /// The type of the context data stored in the irq chip and made available on each callback.
+    type Data: PointerWrapper;
+
+    /// The methods to use to populate [`struct irq_chip`]. This is typically populated with
+    /// [`declare_irq_chip_operations`].
+    const TO_USE: ToUse;
+
+    /// Called at the start of a new interrupt.
+    fn ack(data: <Self::Data as PointerWrapper>::Borrowed<'_>, irq_data: &IrqData);
+
+    /// Masks an interrupt source.
+    fn mask(data: <Self::Data as PointerWrapper>::Borrowed<'_>, irq_data: &IrqData);
+
+    /// Unmasks an interrupt source.
+    fn unmask(_data: <Self::Data as PointerWrapper>::Borrowed<'_>, irq_data: &IrqData);
+
+    /// Sets the flow type of an interrupt.
+    ///
+    /// The flow type is a combination of the constants in [`Type`].
+    fn set_type(
+        _data: <Self::Data as PointerWrapper>::Borrowed<'_>,
+        _irq_data: &mut LockedIrqData,
+        _flow_type: u32,
+    ) -> Result<ExtraResult> {
+        Ok(ExtraResult::None)
+    }
+
+    /// Enables or disables power-management wake-on of an interrupt.
+    fn set_wake(
+        _data: <Self::Data as PointerWrapper>::Borrowed<'_>,
+        _irq_data: &IrqData,
+        _on: bool,
+    ) -> Result {
+        Ok(())
+    }
+}
+
+/// Initialises `chip` with the callbacks defined in `T`.
+///
+/// # Safety
+///
+/// The caller must ensure that the value stored in the irq chip data is the result of calling
+/// [`PointerWrapper::into_pointer] for the [`T::Data`] type.
+pub(crate) unsafe fn init_chip<T: Chip>(chip: &mut bindings::irq_chip) {
+    chip.irq_ack = Some(irq_ack_callback::<T>);
+    chip.irq_mask = Some(irq_mask_callback::<T>);
+    chip.irq_unmask = Some(irq_unmask_callback::<T>);
+
+    if T::TO_USE.set_type {
+        chip.irq_set_type = Some(irq_set_type_callback::<T>);
+    }
+
+    if T::TO_USE.set_wake {
+        chip.irq_set_wake = Some(irq_set_wake_callback::<T>);
+    }
+}
+
+/// Represents which fields of [`struct irq_chip`] should be populated with pointers.
+///
+/// This is typically populated with the [`declare_irq_chip_operations`] macro.
+pub struct ToUse {
+    /// The `irq_set_type` field of [`struct irq_chip`].
+    pub set_type: bool,
+
+    /// The `irq_set_wake` field of [`struct irq_chip`].
+    pub set_wake: bool,
+}
+
+/// A constant version where all values are to set to `false`, that is, all supported fields will
+/// be set to null pointers.
+pub const USE_NONE: ToUse = ToUse {
+    set_type: false,
+    set_wake: false,
+};
+
+/// Defines the [`Chip::TO_USE`] field based on a list of fields to be populated.
+#[macro_export]
+macro_rules! declare_irq_chip_operations {
+    () => {
+        const TO_USE: $crate::irq::ToUse = $crate::irq::USE_NONE;
+    };
+    ($($i:ident),+) => {
+        #[allow(clippy::needless_update)]
+        const TO_USE: $crate::irq::ToUse =
+            $crate::irq::ToUse {
+                $($i: true),+ ,
+                ..$crate::irq::USE_NONE
+            };
+    };
+}
+
+/// Enables or disables power-management wake-on for the given irq number.
+pub fn set_wake(irq: u32, on: bool) -> Result {
+    // SAFETY: Just an FFI call, there are no extra requirements for safety.
+    let ret = unsafe { bindings::irq_set_irq_wake(irq, on as _) };
+    if ret < 0 {
+        Err(Error::from_kernel_errno(ret))
+    } else {
+        Ok(())
+    }
+}
+
+unsafe extern "C" fn irq_ack_callback<T: Chip>(irq_data: *mut bindings::irq_data) {
+    // SAFETY: The safety requirements of `init_chip`, which is the only place that uses this
+    // callback, ensure that the value stored as irq chip data comes from a previous call to
+    // `PointerWrapper::into_pointer`.
+    let data = unsafe { T::Data::borrow(bindings::irq_data_get_irq_chip_data(irq_data)) };
+
+    // SAFETY: The value returned by `IrqData` is only valid until the end of this function, and
+    // `irq_data` is guaranteed to be valid until then (by the contract with C code).
+    T::ack(data, unsafe { &IrqData::from_ptr(irq_data) })
+}
+
+unsafe extern "C" fn irq_mask_callback<T: Chip>(irq_data: *mut bindings::irq_data) {
+    // SAFETY: The safety requirements of `init_chip`, which is the only place that uses this
+    // callback, ensure that the value stored as irq chip data comes from a previous call to
+    // `PointerWrapper::into_pointer`.
+    let data = unsafe { T::Data::borrow(bindings::irq_data_get_irq_chip_data(irq_data)) };
+
+    // SAFETY: The value returned by `IrqData` is only valid until the end of this function, and
+    // `irq_data` is guaranteed to be valid until then (by the contract with C code).
+    T::mask(data, unsafe { &IrqData::from_ptr(irq_data) })
+}
+
+unsafe extern "C" fn irq_unmask_callback<T: Chip>(irq_data: *mut bindings::irq_data) {
+    // SAFETY: The safety requirements of `init_chip`, which is the only place that uses this
+    // callback, ensure that the value stored as irq chip data comes from a previous call to
+    // `PointerWrapper::into_pointer`.
+    let data = unsafe { T::Data::borrow(bindings::irq_data_get_irq_chip_data(irq_data)) };
+
+    // SAFETY: The value returned by `IrqData` is only valid until the end of this function, and
+    // `irq_data` is guaranteed to be valid until then (by the contract with C code).
+    T::unmask(data, unsafe { &IrqData::from_ptr(irq_data) })
+}
+
+unsafe extern "C" fn irq_set_type_callback<T: Chip>(
+    irq_data: *mut bindings::irq_data,
+    flow_type: c_types::c_uint,
+) -> c_types::c_int {
+    from_kernel_result! {
+        // SAFETY: The safety requirements of `init_chip`, which is the only place that uses this
+        // callback, ensure that the value stored as irq chip data comes from a previous call to
+        // `PointerWrapper::into_pointer`.
+        let data = unsafe { T::Data::borrow(bindings::irq_data_get_irq_chip_data(irq_data)) };
+
+        // SAFETY: The value returned by `IrqData` is only valid until the end of this function, and
+        // `irq_data` is guaranteed to be valid until then (by the contract with C code).
+        let ret = T::set_type(data, &mut LockedIrqData(unsafe { IrqData::from_ptr(irq_data) }), flow_type)?;
+        Ok(ret as _)
+    }
+}
+
+unsafe extern "C" fn irq_set_wake_callback<T: Chip>(
+    irq_data: *mut bindings::irq_data,
+    on: c_types::c_uint,
+) -> c_types::c_int {
+    from_kernel_result! {
+        // SAFETY: The safety requirements of `init_chip`, which is the only place that uses this
+        // callback, ensure that the value stored as irq chip data comes from a previous call to
+        // `PointerWrapper::into_pointer`.
+        let data = unsafe { T::Data::borrow(bindings::irq_data_get_irq_chip_data(irq_data)) };
+
+        // SAFETY: The value returned by `IrqData` is only valid until the end of this function, and
+        // `irq_data` is guaranteed to be valid until then (by the contract with C code).
+        T::set_wake(data, unsafe { &IrqData::from_ptr(irq_data) }, on != 0)?;
+        Ok(0)
+    }
+}
+
+/// Contains constants that describes how an interrupt can be triggered.
+///
+/// It is tagged with `non_exhaustive` to prevent users from instantiating it.
+#[non_exhaustive]
+pub struct Type;
+
+impl Type {
+    /// The interrupt cannot be triggered.
+    pub const NONE: u32 = bindings::IRQ_TYPE_NONE;
+
+    /// The interrupt is triggered when the signal goes from low to high.
+    pub const EDGE_RISING: u32 = bindings::IRQ_TYPE_EDGE_RISING;
+
+    /// The interrupt is triggered when the signal goes from high to low.
+    pub const EDGE_FALLING: u32 = bindings::IRQ_TYPE_EDGE_FALLING;
+
+    /// The interrupt is triggered when the signal goes from low to high and when it goes to high
+    /// to low.
+    pub const EDGE_BOTH: u32 = bindings::IRQ_TYPE_EDGE_BOTH;
+
+    /// The interrupt is triggered while the signal is held high.
+    pub const LEVEL_HIGH: u32 = bindings::IRQ_TYPE_LEVEL_HIGH;
+
+    /// The interrupt is triggered while the signal is held low.
+    pub const LEVEL_LOW: u32 = bindings::IRQ_TYPE_LEVEL_LOW;
+}
+
+/// Wraps the kernel's `struct irq_desc`.
+///
+/// # Invariants
+///
+/// The pointer `Descriptor::ptr` is non-null and valid.
+pub struct Descriptor {
+    pub(crate) ptr: *mut bindings::irq_desc,
+}
+
+impl Descriptor {
+    /// Constructs a new `struct irq_desc` wrapper.
+    ///
+    /// # Safety
+    ///
+    /// The pointer `ptr` must be non-null and valid for the lifetime of the returned object.
+    unsafe fn from_ptr(ptr: *mut bindings::irq_desc) -> Self {
+        // INVARIANT: The safety requirements ensure the invariant.
+        Self { ptr }
+    }
+
+    /// Calls `chained_irq_enter` and returns a guard that calls `chained_irq_exit` once dropped.
+    ///
+    /// It is meant to be used by chained irq handlers to dispatch irqs to the next handlers.
+    pub fn enter_chained(&self) -> ChainedGuard<'_> {
+        // SAFETY: By the type invariants, `ptr` is always non-null and valid.
+        let irq_chip = unsafe { bindings::irq_desc_get_chip(self.ptr) };
+
+        // SAFETY: By the type invariants, `ptr` is always non-null and valid. `irq_chip` was just
+        // returned from `ptr`, so it is still valid too.
+        unsafe { bindings::chained_irq_enter(irq_chip, self.ptr) };
+        ChainedGuard {
+            desc: self,
+            irq_chip,
+        }
+    }
+}
+
+/// A guard to call `chained_irq_exit` after `chained_irq_enter` was called.
+///
+/// It is also used as evidence that a previous `chained_irq_enter` was called. So there are no
+/// public constructors and it is only created after indeed calling `chained_irq_enter`.
+pub struct ChainedGuard<'a> {
+    desc: &'a Descriptor,
+    irq_chip: *mut bindings::irq_chip,
+}
+
+impl Drop for ChainedGuard<'_> {
+    fn drop(&mut self) {
+        // SAFETY: The lifetime of `ChainedGuard` guarantees that `self.desc` remains valid, so it
+        // also guarantess `irq_chip` (which was returned from it) and `self.desc.ptr` (guaranteed
+        // by the type invariants).
+        unsafe { bindings::chained_irq_exit(self.irq_chip, self.desc.ptr) };
+    }
+}
+
+/// Wraps the kernel's `struct irq_domain`.
+///
+/// # Invariants
+///
+/// The pointer `Domain::ptr` is non-null and valid.
+pub struct Domain {
+    ptr: *mut bindings::irq_domain,
+}
+
+impl Domain {
+    /// Constructs a new `struct irq_domain` wrapper.
+    ///
+    /// # Safety
+    ///
+    /// The pointer `ptr` must be non-null and valid for the lifetime of the returned object.
+    pub(crate) unsafe fn from_ptr(ptr: *mut bindings::irq_domain) -> Self {
+        // INVARIANT: The safety requirements ensure the invariant.
+        Self { ptr }
+    }
+
+    /// Invokes the chained handler of the given hw irq of the given domain.
+    ///
+    /// It requires evidence that `chained_irq_enter` was called, which is done by passing a
+    /// `ChainedGuard` instance.
+    pub fn generic_handle_chained(&self, hwirq: u32, _guard: &ChainedGuard<'_>) {
+        // SAFETY: `ptr` is valid by the type invariants.
+        unsafe { bindings::generic_handle_domain_irq(self.ptr, hwirq) };
+    }
+}
+
+/// A high-level irq flow handler.
+pub trait FlowHandler {
+    /// The data associated with the handler.
+    type Data: PointerWrapper;
+
+    /// Implements the irq flow for the given descriptor.
+    fn handle_irq_flow(data: <Self::Data as PointerWrapper>::Borrowed<'_>, desc: &Descriptor);
+}
+
+/// Returns the raw irq flow handler corresponding to the (high-level) one defined in `T`.
+///
+/// # Safety
+///
+/// The caller must ensure that the value stored in the irq handler data (as returned by
+/// `irq_desc_get_handler_data`) is the result of calling [`PointerWrapper::into_pointer] for the
+/// [`T::Data`] type.
+pub(crate) unsafe fn new_flow_handler<T: FlowHandler>() -> bindings::irq_flow_handler_t {
+    Some(irq_flow_handler::<T>)
+}
+
+unsafe extern "C" fn irq_flow_handler<T: FlowHandler>(desc: *mut bindings::irq_desc) {
+    // SAFETY: By the safety requirements of `new_flow_handler`, we know that the value returned by
+    // `irq_desc_get_handler_data` comes from calling `T::Data::into_pointer`. `desc` is valid by
+    // the C API contract.
+    let data = unsafe { T::Data::borrow(bindings::irq_desc_get_handler_data(desc)) };
+
+    // SAFETY: The C API guarantees that `desc` is valid for the duration of this call, which
+    // outlives the lifetime returned by `from_desc`.
+    T::handle_irq_flow(data, &unsafe { Descriptor::from_ptr(desc) });
+}
diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs
new file mode 100644
index 000000000000..1a541847ba4f
--- /dev/null
+++ b/rust/kernel/lib.rs
@@ -0,0 +1,262 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! The `kernel` crate.
+//!
+//! This crate contains the kernel APIs that have been ported or wrapped for
+//! usage by Rust code in the kernel and is shared by all of them.
+//!
+//! In other words, all the rest of the Rust code in the kernel (e.g. kernel
+//! modules written in Rust) depends on [`core`], [`alloc`] and this crate.
+//!
+//! If you need a kernel C API that is not ported or wrapped yet here, then
+//! do so first instead of bypassing this crate.
+
+#![no_std]
+#![feature(
+    allocator_api,
+    associated_type_defaults,
+    concat_idents,
+    const_fn_trait_bound,
+    const_mut_refs,
+    const_ptr_offset_from,
+    const_refs_to_cell,
+    const_trait_impl,
+    doc_cfg,
+    generic_associated_types,
+    maybe_uninit_extra,
+    ptr_metadata,
+    receiver_trait,
+    coerce_unsized,
+    dispatch_from_dyn,
+    unsize
+)]
+
+// Ensure conditional compilation based on the kernel configuration works;
+// otherwise we may silently break things like initcall handling.
+#[cfg(not(CONFIG_RUST))]
+compile_error!("Missing kernel configuration for conditional compilation");
+
+#[cfg(not(test))]
+#[cfg(not(testlib))]
+mod allocator;
+
+#[doc(hidden)]
+pub mod bindings;
+
+#[cfg(CONFIG_ARM_AMBA)]
+pub mod amba;
+pub mod buffer;
+pub mod c_types;
+pub mod chrdev;
+#[cfg(CONFIG_COMMON_CLK)]
+pub mod clk;
+pub mod cred;
+pub mod device;
+pub mod driver;
+mod error;
+pub mod file;
+pub mod file_operations;
+pub mod gpio;
+pub mod irq;
+pub mod miscdev;
+pub mod pages;
+pub mod power;
+pub mod revocable;
+pub mod security;
+pub mod str;
+pub mod task;
+
+pub mod linked_list;
+mod raw_list;
+pub mod rbtree;
+
+#[doc(hidden)]
+pub mod module_param;
+
+mod build_assert;
+pub mod prelude;
+pub mod print;
+pub mod random;
+mod static_assert;
+#[doc(hidden)]
+pub mod std_vendor;
+pub mod sync;
+
+#[cfg(any(CONFIG_SYSCTL, doc))]
+#[doc(cfg(CONFIG_SYSCTL))]
+pub mod sysctl;
+
+pub mod io_buffer;
+pub mod io_mem;
+pub mod iov_iter;
+pub mod of;
+pub mod platform;
+mod types;
+pub mod user_ptr;
+
+#[doc(hidden)]
+pub use build_error::build_error;
+
+pub use crate::error::{to_result, Error, Result};
+pub use crate::types::{bit, bits_iter, Mode, Opaque, ScopeGuard};
+
+use core::marker::PhantomData;
+
+/// Page size defined in terms of the `PAGE_SHIFT` macro from C.
+///
+/// [`PAGE_SHIFT`]: ../../../include/asm-generic/page.h
+pub const PAGE_SIZE: usize = 1 << bindings::PAGE_SHIFT;
+
+/// Prefix to appear before log messages printed from within the kernel crate.
+const __LOG_PREFIX: &[u8] = b"rust_kernel\0";
+
+/// The top level entrypoint to implementing a kernel module.
+///
+/// For any teardown or cleanup operations, your type may implement [`Drop`].
+pub trait KernelModule: Sized + Sync {
+    /// Called at module initialization time.
+    ///
+    /// Use this method to perform whatever setup or registration your module
+    /// should do.
+    ///
+    /// Equivalent to the `module_init` macro in the C API.
+    fn init(name: &'static str::CStr, module: &'static ThisModule) -> Result<Self>;
+}
+
+/// Equivalent to `THIS_MODULE` in the C API.
+///
+/// C header: `include/linux/export.h`
+pub struct ThisModule(*mut bindings::module);
+
+// SAFETY: `THIS_MODULE` may be used from all threads within a module.
+unsafe impl Sync for ThisModule {}
+
+impl ThisModule {
+    /// Creates a [`ThisModule`] given the `THIS_MODULE` pointer.
+    ///
+    /// # Safety
+    ///
+    /// The pointer must be equal to the right `THIS_MODULE`.
+    pub const unsafe fn from_ptr(ptr: *mut bindings::module) -> ThisModule {
+        ThisModule(ptr)
+    }
+
+    /// Locks the module parameters to access them.
+    ///
+    /// Returns a [`KParamGuard`] that will release the lock when dropped.
+    pub fn kernel_param_lock(&self) -> KParamGuard<'_> {
+        // SAFETY: `kernel_param_lock` will check if the pointer is null and
+        // use the built-in mutex in that case.
+        #[cfg(CONFIG_SYSFS)]
+        unsafe {
+            bindings::kernel_param_lock(self.0)
+        }
+
+        KParamGuard {
+            #[cfg(CONFIG_SYSFS)]
+            this_module: self,
+            phantom: PhantomData,
+        }
+    }
+}
+
+/// Scoped lock on the kernel parameters of [`ThisModule`].
+///
+/// Lock will be released when this struct is dropped.
+pub struct KParamGuard<'a> {
+    #[cfg(CONFIG_SYSFS)]
+    this_module: &'a ThisModule,
+    phantom: PhantomData<&'a ()>,
+}
+
+#[cfg(CONFIG_SYSFS)]
+impl<'a> Drop for KParamGuard<'a> {
+    fn drop(&mut self) {
+        // SAFETY: `kernel_param_lock` will check if the pointer is null and
+        // use the built-in mutex in that case. The existance of `self`
+        // guarantees that the lock is held.
+        unsafe { bindings::kernel_param_unlock(self.this_module.0) }
+    }
+}
+
+/// Calculates the offset of a field from the beginning of the struct it belongs to.
+///
+/// # Example
+///
+/// ```
+/// # use kernel::prelude::*;
+/// # use kernel::offset_of;
+/// struct Test {
+///     a: u64,
+///     b: u32,
+/// }
+///
+/// fn test() {
+///     // This prints `8`.
+///     pr_info!("{}\n", offset_of!(Test, b));
+/// }
+/// ```
+#[macro_export]
+macro_rules! offset_of {
+    ($type:ty, $($f:tt)*) => {{
+        let tmp = core::mem::MaybeUninit::<$type>::uninit();
+        let outer = tmp.as_ptr();
+        // To avoid warnings when nesting `unsafe` blocks.
+        #[allow(unused_unsafe)]
+        // SAFETY: The pointer is valid and aligned, just not initialised; `addr_of` ensures that
+        // we don't actually read from `outer` (which would be UB) nor create an intermediate
+        // reference.
+        let inner = unsafe { core::ptr::addr_of!((*outer).$($f)*) } as *const u8;
+        // To avoid warnings when nesting `unsafe` blocks.
+        #[allow(unused_unsafe)]
+        // SAFETY: The two pointers are within the same allocation block.
+        unsafe { inner.offset_from(outer as *const u8) }
+    }}
+}
+
+/// Produces a pointer to an object from a pointer to one of its fields.
+///
+/// # Safety
+///
+/// Callers must ensure that the pointer to the field is in fact a pointer to the specified field,
+/// as opposed to a pointer to another object of the same type. If this condition is not met,
+/// any dereference of the resulting pointer is UB.
+///
+/// # Example
+///
+/// ```
+/// # use kernel::prelude::*;
+/// # use kernel::container_of;
+/// struct Test {
+///     a: u64,
+///     b: u32,
+/// }
+///
+/// fn test() {
+///     let test = Test { a: 10, b: 20 };
+///     let b_ptr = &test.b;
+///     let test_alias = container_of!(b_ptr, Test, b);
+///     // This prints `true`.
+///     pr_info!("{}\n", core::ptr::eq(&test, test_alias));
+/// }
+/// ```
+#[macro_export]
+macro_rules! container_of {
+    ($ptr:expr, $type:ty, $($f:tt)*) => {{
+        let ptr = $ptr as *const _ as *const u8;
+        let offset = $crate::offset_of!($type, $($f)*);
+        ptr.wrapping_offset(-offset) as *const $type
+    }}
+}
+
+#[cfg(not(any(testlib, test)))]
+#[panic_handler]
+fn panic(info: &core::panic::PanicInfo<'_>) -> ! {
+    pr_emerg!("{}\n", info);
+    // SAFETY: FFI call.
+    unsafe { bindings::BUG() };
+    // Bindgen currently does not recognize `__noreturn` so `BUG` returns `()`
+    // instead of `!`.
+    // https://github.com/rust-lang/rust-bindgen/issues/2094
+    loop {}
+}
diff --git a/rust/kernel/linked_list.rs b/rust/kernel/linked_list.rs
new file mode 100644
index 000000000000..3330edcc7ca8
--- /dev/null
+++ b/rust/kernel/linked_list.rs
@@ -0,0 +1,247 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Linked lists.
+//!
+//! TODO: This module is a work in progress.
+
+use alloc::boxed::Box;
+use core::ptr::NonNull;
+
+pub use crate::raw_list::{Cursor, GetLinks, Links};
+use crate::{raw_list, raw_list::RawList, sync::Ref};
+
+// TODO: Use the one from `kernel::file_operations::PointerWrapper` instead.
+/// Wraps an object to be inserted in a linked list.
+pub trait Wrapper<T: ?Sized> {
+    /// Converts the wrapped object into a pointer that represents it.
+    fn into_pointer(self) -> NonNull<T>;
+
+    /// Converts the object back from the pointer representation.
+    ///
+    /// # Safety
+    ///
+    /// The passed pointer must come from a previous call to [`Wrapper::into_pointer()`].
+    unsafe fn from_pointer(ptr: NonNull<T>) -> Self;
+
+    /// Returns a reference to the wrapped object.
+    fn as_ref(&self) -> &T;
+}
+
+impl<T: ?Sized> Wrapper<T> for Box<T> {
+    fn into_pointer(self) -> NonNull<T> {
+        NonNull::new(Box::into_raw(self)).unwrap()
+    }
+
+    unsafe fn from_pointer(ptr: NonNull<T>) -> Self {
+        unsafe { Box::from_raw(ptr.as_ptr()) }
+    }
+
+    fn as_ref(&self) -> &T {
+        AsRef::as_ref(self)
+    }
+}
+
+impl<T: ?Sized> Wrapper<T> for Ref<T> {
+    fn into_pointer(self) -> NonNull<T> {
+        NonNull::new(Ref::into_raw(self) as _).unwrap()
+    }
+
+    unsafe fn from_pointer(ptr: NonNull<T>) -> Self {
+        // SAFETY: The safety requirements of `from_pointer` satisfy the ones from `Ref::from_raw`.
+        unsafe { Ref::from_raw(ptr.as_ptr() as _) }
+    }
+
+    fn as_ref(&self) -> &T {
+        AsRef::as_ref(self)
+    }
+}
+
+impl<T: ?Sized> Wrapper<T> for &T {
+    fn into_pointer(self) -> NonNull<T> {
+        NonNull::from(self)
+    }
+
+    unsafe fn from_pointer(ptr: NonNull<T>) -> Self {
+        unsafe { &*ptr.as_ptr() }
+    }
+
+    fn as_ref(&self) -> &T {
+        self
+    }
+}
+
+/// A descriptor of wrapped list elements.
+pub trait GetLinksWrapped: GetLinks {
+    /// Specifies which wrapper (e.g., `Box` and `Arc`) wraps the list entries.
+    type Wrapped: Wrapper<Self::EntryType>;
+}
+
+impl<T: ?Sized> GetLinksWrapped for Box<T>
+where
+    Box<T>: GetLinks,
+{
+    type Wrapped = Box<<Box<T> as GetLinks>::EntryType>;
+}
+
+impl<T: GetLinks + ?Sized> GetLinks for Box<T> {
+    type EntryType = T::EntryType;
+    fn get_links(data: &Self::EntryType) -> &Links<Self::EntryType> {
+        <T as GetLinks>::get_links(data)
+    }
+}
+
+impl<T: ?Sized> GetLinksWrapped for Ref<T>
+where
+    Ref<T>: GetLinks,
+{
+    type Wrapped = Ref<<Ref<T> as GetLinks>::EntryType>;
+}
+
+impl<T: GetLinks + ?Sized> GetLinks for Ref<T> {
+    type EntryType = T::EntryType;
+
+    fn get_links(data: &Self::EntryType) -> &Links<Self::EntryType> {
+        <T as GetLinks>::get_links(data)
+    }
+}
+
+/// A linked list.
+///
+/// Elements in the list are wrapped and ownership is transferred to the list while the element is
+/// in the list.
+pub struct List<G: GetLinksWrapped> {
+    list: RawList<G>,
+}
+
+impl<G: GetLinksWrapped> List<G> {
+    /// Constructs a new empty linked list.
+    pub fn new() -> Self {
+        Self {
+            list: RawList::new(),
+        }
+    }
+
+    /// Returns whether the list is empty.
+    pub fn is_empty(&self) -> bool {
+        self.list.is_empty()
+    }
+
+    /// Adds the given object to the end (back) of the list.
+    ///
+    /// It is dropped if it's already on this (or another) list; this can happen for
+    /// reference-counted objects, so dropping means decrementing the reference count.
+    pub fn push_back(&mut self, data: G::Wrapped) {
+        let ptr = data.into_pointer();
+
+        // SAFETY: We took ownership of the entry, so it is safe to insert it.
+        if !unsafe { self.list.push_back(ptr.as_ref()) } {
+            // If insertion failed, rebuild object so that it can be freed.
+            // SAFETY: We just called `into_pointer` above.
+            unsafe { G::Wrapped::from_pointer(ptr) };
+        }
+    }
+
+    /// Inserts the given object after `existing`.
+    ///
+    /// It is dropped if it's already on this (or another) list; this can happen for
+    /// reference-counted objects, so dropping means decrementing the reference count.
+    ///
+    /// # Safety
+    ///
+    /// Callers must ensure that `existing` points to a valid entry that is on the list.
+    pub unsafe fn insert_after(&mut self, existing: NonNull<G::EntryType>, data: G::Wrapped) {
+        let ptr = data.into_pointer();
+        let entry = unsafe { &*existing.as_ptr() };
+        if unsafe { !self.list.insert_after(entry, ptr.as_ref()) } {
+            // If insertion failed, rebuild object so that it can be freed.
+            unsafe { G::Wrapped::from_pointer(ptr) };
+        }
+    }
+
+    /// Removes the given entry.
+    ///
+    /// # Safety
+    ///
+    /// Callers must ensure that `data` is either on this list or in no list. It being on another
+    /// list leads to memory unsafety.
+    pub unsafe fn remove(&mut self, data: &G::Wrapped) -> Option<G::Wrapped> {
+        let entry_ref = Wrapper::as_ref(data);
+        if unsafe { self.list.remove(entry_ref) } {
+            Some(unsafe { G::Wrapped::from_pointer(NonNull::from(entry_ref)) })
+        } else {
+            None
+        }
+    }
+
+    /// Removes the element currently at the front of the list and returns it.
+    ///
+    /// Returns `None` if the list is empty.
+    pub fn pop_front(&mut self) -> Option<G::Wrapped> {
+        let front = self.list.pop_front()?;
+        // SAFETY: Elements on the list were inserted after a call to `into_pointer `.
+        Some(unsafe { G::Wrapped::from_pointer(front) })
+    }
+
+    /// Returns a cursor starting on the first (front) element of the list.
+    pub fn cursor_front(&self) -> Cursor<'_, G> {
+        self.list.cursor_front()
+    }
+
+    /// Returns a mutable cursor starting on the first (front) element of the list.
+    pub fn cursor_front_mut(&mut self) -> CursorMut<'_, G> {
+        CursorMut::new(self.list.cursor_front_mut())
+    }
+}
+
+impl<G: GetLinksWrapped> Default for List<G> {
+    fn default() -> Self {
+        Self::new()
+    }
+}
+
+impl<G: GetLinksWrapped> Drop for List<G> {
+    fn drop(&mut self) {
+        while self.pop_front().is_some() {}
+    }
+}
+
+/// A list cursor that allows traversing a linked list and inspecting & mutating elements.
+pub struct CursorMut<'a, G: GetLinksWrapped> {
+    cursor: raw_list::CursorMut<'a, G>,
+}
+
+impl<'a, G: GetLinksWrapped> CursorMut<'a, G> {
+    fn new(cursor: raw_list::CursorMut<'a, G>) -> Self {
+        Self { cursor }
+    }
+
+    /// Returns the element the cursor is currently positioned on.
+    pub fn current(&mut self) -> Option<&mut G::EntryType> {
+        self.cursor.current()
+    }
+
+    /// Removes the element the cursor is currently positioned on.
+    ///
+    /// After removal, it advances the cursor to the next element.
+    pub fn remove_current(&mut self) -> Option<G::Wrapped> {
+        let ptr = self.cursor.remove_current()?;
+
+        // SAFETY: Elements on the list were inserted after a call to `into_pointer `.
+        Some(unsafe { G::Wrapped::from_pointer(ptr) })
+    }
+
+    /// Returns the element immediately after the one the cursor is positioned on.
+    pub fn peek_next(&mut self) -> Option<&mut G::EntryType> {
+        self.cursor.peek_next()
+    }
+
+    /// Returns the element immediately before the one the cursor is positioned on.
+    pub fn peek_prev(&mut self) -> Option<&mut G::EntryType> {
+        self.cursor.peek_prev()
+    }
+
+    /// Moves the cursor to the next element.
+    pub fn move_next(&mut self) {
+        self.cursor.move_next();
+    }
+}
diff --git a/rust/kernel/miscdev.rs b/rust/kernel/miscdev.rs
new file mode 100644
index 000000000000..ccbd4f4cfe28
--- /dev/null
+++ b/rust/kernel/miscdev.rs
@@ -0,0 +1,196 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Miscellaneous devices.
+//!
+//! C header: [`include/linux/miscdevice.h`](../../../../include/linux/miscdevice.h)
+//!
+//! Reference: <https://www.kernel.org/doc/html/latest/driver-api/misc_devices.html>
+
+use crate::bindings;
+use crate::error::{Error, Result};
+use crate::file_operations::{FileOpenAdapter, FileOperations, FileOperationsVtable};
+use crate::{str::CStr, KernelModule, ThisModule};
+use alloc::boxed::Box;
+use core::marker::PhantomPinned;
+use core::{mem::MaybeUninit, pin::Pin};
+
+/// A registration of a miscellaneous device.
+///
+/// # Invariants
+///
+/// `Context` is always initialised when `registered` is `true`, and not initialised otherwise.
+pub struct Registration<T: FileOperations> {
+    registered: bool,
+    mdev: bindings::miscdevice,
+    _pin: PhantomPinned,
+
+    /// Context initialised on construction and made available to all file instances on
+    /// [`FileOperations::open`].
+    open_data: MaybeUninit<T::OpenData>,
+}
+
+impl<T: FileOperations> Registration<T> {
+    /// Creates a new [`Registration`] but does not register it yet.
+    ///
+    /// It is allowed to move.
+    pub fn new() -> Self {
+        // INVARIANT: `registered` is `false` and `open_data` is not initialised.
+        Self {
+            registered: false,
+            mdev: bindings::miscdevice::default(),
+            _pin: PhantomPinned,
+            open_data: MaybeUninit::uninit(),
+        }
+    }
+
+    /// Registers a miscellaneous device.
+    ///
+    /// Returns a pinned heap-allocated representation of the registration.
+    pub fn new_pinned(
+        name: &'static CStr,
+        minor: Option<i32>,
+        open_data: T::OpenData,
+    ) -> Result<Pin<Box<Self>>> {
+        let mut r = Pin::from(Box::try_new(Self::new())?);
+        r.as_mut().register(name, minor, open_data)?;
+        Ok(r)
+    }
+
+    /// Registers a miscellaneous device with the rest of the kernel.
+    ///
+    /// It must be pinned because the memory block that represents the registration is
+    /// self-referential. If a minor is not given, the kernel allocates a new one if possible.
+    pub fn register(
+        self: Pin<&mut Self>,
+        name: &'static CStr,
+        minor: Option<i32>,
+        open_data: T::OpenData,
+    ) -> Result {
+        // SAFETY: We must ensure that we never move out of `this`.
+        let this = unsafe { self.get_unchecked_mut() };
+        if this.registered {
+            // Already registered.
+            return Err(Error::EINVAL);
+        }
+
+        // SAFETY: The adapter is compatible with `misc_register`.
+        this.mdev.fops = unsafe { FileOperationsVtable::<Self, T>::build() };
+        this.mdev.name = name.as_char_ptr();
+        this.mdev.minor = minor.unwrap_or(bindings::MISC_DYNAMIC_MINOR as i32);
+
+        // We write to `open_data` here because as soon as `misc_register` succeeds, the file can be
+        // opened, so we need `open_data` configured ahead of time.
+        //
+        // INVARIANT: `registered` is set to `true`, but `open_data` is also initialised.
+        this.registered = true;
+        this.open_data.write(open_data);
+
+        let ret = unsafe { bindings::misc_register(&mut this.mdev) };
+        if ret < 0 {
+            // INVARIANT: `registered` is set back to `false` and the `open_data` is destructued.
+            this.registered = false;
+            // SAFETY: `open_data` was initialised a few lines above.
+            unsafe { this.open_data.assume_init_drop() };
+            return Err(Error::from_kernel_errno(ret));
+        }
+
+        Ok(())
+    }
+}
+
+impl<T: FileOperations> Default for Registration<T> {
+    fn default() -> Self {
+        Self::new()
+    }
+}
+
+impl<T: FileOperations> FileOpenAdapter<T::OpenData> for Registration<T> {
+    unsafe fn convert(
+        _inode: *mut bindings::inode,
+        file: *mut bindings::file,
+    ) -> *const T::OpenData {
+        // SAFETY: the caller must guarantee that `file` is valid.
+        let reg = crate::container_of!(unsafe { (*file).private_data }, Self, mdev);
+
+        // SAFETY: This function is only called while the misc device is still registered, so the
+        // registration must be valid. Additionally, the type invariants guarantee that while the
+        // miscdev is registered, `open_data` is initialised.
+        unsafe { (*reg).open_data.as_ptr() }
+    }
+}
+
+// SAFETY: The only method is `register()`, which requires a (pinned) mutable `Registration`, so it
+// is safe to pass `&Registration` to multiple threads because it offers no interior mutability.
+unsafe impl<T: FileOperations> Sync for Registration<T> {}
+
+// SAFETY: All functions work from any thread. So as long as the `Registration::open_data` is
+// `Send`, so is `Registration<T>`.
+unsafe impl<T: FileOperations> Send for Registration<T> where T::OpenData: Send {}
+
+impl<T: FileOperations> Drop for Registration<T> {
+    /// Removes the registration from the kernel if it has completed successfully before.
+    fn drop(&mut self) {
+        if self.registered {
+            // SAFETY: `registered` being `true` indicates that a previous call to  `misc_register`
+            // succeeded.
+            unsafe { bindings::misc_deregister(&mut self.mdev) };
+
+            // SAFETY: The type invariant guarantees that `open_data` is initialised when
+            // `registered` is `true`.
+            unsafe { self.open_data.assume_init_drop() };
+        }
+    }
+}
+
+/// Kernel module that exposes a single miscdev device implemented by `T`.
+pub struct Module<T: FileOperations<OpenData = ()>> {
+    _dev: Pin<Box<Registration<T>>>,
+}
+
+impl<T: FileOperations<OpenData = ()>> KernelModule for Module<T> {
+    fn init(name: &'static CStr, _module: &'static ThisModule) -> Result<Self> {
+        Ok(Self {
+            _dev: Registration::new_pinned(name, None, ())?,
+        })
+    }
+}
+
+/// Declares a kernel module that exposes a single misc device.
+///
+/// The `type` argument should be a type which implements the [`FileOpener`] trait. Also accepts
+/// various forms of kernel metadata.
+///
+/// C header: [`include/linux/moduleparam.h`](../../../include/linux/moduleparam.h)
+///
+/// [`FileOpener`]: ../kernel/file_operations/trait.FileOpener.html
+///
+/// # Examples
+///
+/// ```ignore
+/// use kernel::prelude::*;
+///
+/// module_misc_device! {
+///     type: MyFile,
+///     name: b"my_miscdev_kernel_module",
+///     author: b"Rust for Linux Contributors",
+///     description: b"My very own misc device kernel module!",
+///     license: b"GPL v2",
+/// }
+///
+/// #[derive(Default)]
+/// struct MyFile;
+///
+/// impl kernel::file_operations::FileOperations for MyFile {
+///     kernel::declare_file_operations!();
+/// }
+/// ```
+#[macro_export]
+macro_rules! module_misc_device {
+    (type: $type:ty, $($f:tt)*) => {
+        type ModuleType = kernel::miscdev::Module<$type>;
+        module! {
+            type: ModuleType,
+            $($f)*
+        }
+    }
+}
diff --git a/rust/kernel/module_param.rs b/rust/kernel/module_param.rs
new file mode 100644
index 000000000000..a588449c41fa
--- /dev/null
+++ b/rust/kernel/module_param.rs
@@ -0,0 +1,497 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Types for module parameters.
+//!
+//! C header: [`include/linux/moduleparam.h`](../../../include/linux/moduleparam.h)
+
+use crate::str::CStr;
+use core::fmt::Write;
+
+/// Types that can be used for module parameters.
+///
+/// Note that displaying the type in `sysfs` will fail if
+/// [`alloc::string::ToString::to_string`] (as implemented through the
+/// [`core::fmt::Display`] trait) writes more than [`PAGE_SIZE`]
+/// bytes (including an additional null terminator).
+///
+/// [`PAGE_SIZE`]: `crate::PAGE_SIZE`
+pub trait ModuleParam: core::fmt::Display + core::marker::Sized {
+    /// The `ModuleParam` will be used by the kernel module through this type.
+    ///
+    /// This may differ from `Self` if, for example, `Self` needs to track
+    /// ownership without exposing it or allocate extra space for other possible
+    /// parameter values. See [`StringParam`] or [`ArrayParam`] for examples.
+    type Value: ?Sized;
+
+    /// Whether the parameter is allowed to be set without an argument.
+    ///
+    /// Setting this to `true` allows the parameter to be passed without an
+    /// argument (e.g. just `module.param` instead of `module.param=foo`).
+    const NOARG_ALLOWED: bool;
+
+    /// Convert a parameter argument into the parameter value.
+    ///
+    /// `None` should be returned when parsing of the argument fails.
+    /// `arg == None` indicates that the parameter was passed without an
+    /// argument. If `NOARG_ALLOWED` is set to `false` then `arg` is guaranteed
+    /// to always be `Some(_)`.
+    ///
+    /// Parameters passed at boot time will be set before [`kmalloc`] is
+    /// available (even if the module is loaded at a later time). However, in
+    /// this case, the argument buffer will be valid for the entire lifetime of
+    /// the kernel. So implementations of this method which need to allocate
+    /// should first check that the allocator is available (with
+    /// [`crate::bindings::slab_is_available`]) and when it is not available
+    /// provide an alternative implementation which doesn't allocate. In cases
+    /// where the allocator is not available it is safe to save references to
+    /// `arg` in `Self`, but in other cases a copy should be made.
+    ///
+    /// [`kmalloc`]: ../../../include/linux/slab.h
+    fn try_from_param_arg(arg: Option<&'static [u8]>) -> Option<Self>;
+
+    /// Get the current value of the parameter for use in the kernel module.
+    ///
+    /// This function should not be used directly. Instead use the wrapper
+    /// `read` which will be generated by [`macros::module`].
+    fn value(&self) -> &Self::Value;
+
+    /// Set the module parameter from a string.
+    ///
+    /// Used to set the parameter value when loading the module or when set
+    /// through `sysfs`.
+    ///
+    /// # Safety
+    ///
+    /// If `val` is non-null then it must point to a valid null-terminated
+    /// string. The `arg` field of `param` must be an instance of `Self`.
+    unsafe extern "C" fn set_param(
+        val: *const crate::c_types::c_char,
+        param: *const crate::bindings::kernel_param,
+    ) -> crate::c_types::c_int {
+        let arg = if val.is_null() {
+            None
+        } else {
+            Some(unsafe { CStr::from_char_ptr(val).as_bytes() })
+        };
+        match Self::try_from_param_arg(arg) {
+            Some(new_value) => {
+                let old_value = unsafe { (*param).__bindgen_anon_1.arg as *mut Self };
+                let _ = unsafe { core::ptr::replace(old_value, new_value) };
+                0
+            }
+            None => crate::error::Error::EINVAL.to_kernel_errno(),
+        }
+    }
+
+    /// Write a string representation of the current parameter value to `buf`.
+    ///
+    /// Used for displaying the current parameter value in `sysfs`.
+    ///
+    /// # Safety
+    ///
+    /// `buf` must be a buffer of length at least `kernel::PAGE_SIZE` that is
+    /// writeable. The `arg` field of `param` must be an instance of `Self`.
+    unsafe extern "C" fn get_param(
+        buf: *mut crate::c_types::c_char,
+        param: *const crate::bindings::kernel_param,
+    ) -> crate::c_types::c_int {
+        let slice = unsafe { core::slice::from_raw_parts_mut(buf as *mut u8, crate::PAGE_SIZE) };
+        let mut buf = crate::buffer::Buffer::new(slice);
+        match unsafe { write!(buf, "{}\0", *((*param).__bindgen_anon_1.arg as *mut Self)) } {
+            Err(_) => crate::error::Error::EINVAL.to_kernel_errno(),
+            Ok(()) => buf.bytes_written() as crate::c_types::c_int,
+        }
+    }
+
+    /// Drop the parameter.
+    ///
+    /// Called when unloading a module.
+    ///
+    /// # Safety
+    ///
+    /// The `arg` field of `param` must be an instance of `Self`.
+    unsafe extern "C" fn free(arg: *mut crate::c_types::c_void) {
+        unsafe { core::ptr::drop_in_place(arg as *mut Self) };
+    }
+}
+
+/// Trait for parsing integers.
+///
+/// Strings begining with `0x`, `0o`, or `0b` are parsed as hex, octal, or
+/// binary respectively. Strings beginning with `0` otherwise are parsed as
+/// octal. Anything else is parsed as decimal. A leading `+` or `-` is also
+/// permitted. Any string parsed by [`kstrtol()`] or [`kstrtoul()`] will be
+/// successfully parsed.
+///
+/// [`kstrtol()`]: https://www.kernel.org/doc/html/latest/core-api/kernel-api.html#c.kstrtol
+/// [`kstrtoul()`]: https://www.kernel.org/doc/html/latest/core-api/kernel-api.html#c.kstrtoul
+trait ParseInt: Sized {
+    fn from_str_radix(src: &str, radix: u32) -> Result<Self, core::num::ParseIntError>;
+    fn checked_neg(self) -> Option<Self>;
+
+    fn from_str_unsigned(src: &str) -> Result<Self, core::num::ParseIntError> {
+        let (radix, digits) = if let Some(n) = src.strip_prefix("0x") {
+            (16, n)
+        } else if let Some(n) = src.strip_prefix("0X") {
+            (16, n)
+        } else if let Some(n) = src.strip_prefix("0o") {
+            (8, n)
+        } else if let Some(n) = src.strip_prefix("0O") {
+            (8, n)
+        } else if let Some(n) = src.strip_prefix("0b") {
+            (2, n)
+        } else if let Some(n) = src.strip_prefix("0B") {
+            (2, n)
+        } else if src.starts_with('0') {
+            (8, src)
+        } else {
+            (10, src)
+        };
+        Self::from_str_radix(digits, radix)
+    }
+
+    fn from_str(src: &str) -> Option<Self> {
+        match src.bytes().next() {
+            None => None,
+            Some(b'-') => Self::from_str_unsigned(&src[1..]).ok()?.checked_neg(),
+            Some(b'+') => Some(Self::from_str_unsigned(&src[1..]).ok()?),
+            Some(_) => Some(Self::from_str_unsigned(src).ok()?),
+        }
+    }
+}
+
+macro_rules! impl_parse_int {
+    ($ty:ident) => {
+        impl ParseInt for $ty {
+            fn from_str_radix(src: &str, radix: u32) -> Result<Self, core::num::ParseIntError> {
+                $ty::from_str_radix(src, radix)
+            }
+
+            fn checked_neg(self) -> Option<Self> {
+                self.checked_neg()
+            }
+        }
+    };
+}
+
+impl_parse_int!(i8);
+impl_parse_int!(u8);
+impl_parse_int!(i16);
+impl_parse_int!(u16);
+impl_parse_int!(i32);
+impl_parse_int!(u32);
+impl_parse_int!(i64);
+impl_parse_int!(u64);
+impl_parse_int!(isize);
+impl_parse_int!(usize);
+
+macro_rules! impl_module_param {
+    ($ty:ident) => {
+        impl ModuleParam for $ty {
+            type Value = $ty;
+
+            const NOARG_ALLOWED: bool = false;
+
+            fn try_from_param_arg(arg: Option<&'static [u8]>) -> Option<Self> {
+                let bytes = arg?;
+                let utf8 = core::str::from_utf8(bytes).ok()?;
+                <$ty as crate::module_param::ParseInt>::from_str(utf8)
+            }
+
+            fn value(&self) -> &Self::Value {
+                self
+            }
+        }
+    };
+}
+
+#[doc(hidden)]
+#[macro_export]
+/// Generate a static [`kernel_param_ops`](../../../include/linux/moduleparam.h) struct.
+///
+/// # Example
+/// ```ignore
+/// make_param_ops!(
+///     /// Documentation for new param ops.
+///     PARAM_OPS_MYTYPE, // Name for the static.
+///     MyType // A type which implements [`ModuleParam`].
+/// );
+/// ```
+macro_rules! make_param_ops {
+    ($ops:ident, $ty:ty) => {
+        $crate::make_param_ops!(
+            #[doc=""]
+            $ops,
+            $ty
+        );
+    };
+    ($(#[$meta:meta])* $ops:ident, $ty:ty) => {
+        $(#[$meta])*
+        ///
+        /// Static [`kernel_param_ops`](../../../include/linux/moduleparam.h)
+        /// struct generated by [`make_param_ops`].
+        pub static $ops: $crate::bindings::kernel_param_ops = $crate::bindings::kernel_param_ops {
+            flags: if <$ty as $crate::module_param::ModuleParam>::NOARG_ALLOWED {
+                $crate::bindings::KERNEL_PARAM_OPS_FL_NOARG
+            } else {
+                0
+            },
+            set: Some(<$ty as $crate::module_param::ModuleParam>::set_param),
+            get: Some(<$ty as $crate::module_param::ModuleParam>::get_param),
+            free: Some(<$ty as $crate::module_param::ModuleParam>::free),
+        };
+    };
+}
+
+impl_module_param!(i8);
+impl_module_param!(u8);
+impl_module_param!(i16);
+impl_module_param!(u16);
+impl_module_param!(i32);
+impl_module_param!(u32);
+impl_module_param!(i64);
+impl_module_param!(u64);
+impl_module_param!(isize);
+impl_module_param!(usize);
+
+make_param_ops!(
+    /// Rust implementation of [`kernel_param_ops`](../../../include/linux/moduleparam.h)
+    /// for [`i8`].
+    PARAM_OPS_I8,
+    i8
+);
+make_param_ops!(
+    /// Rust implementation of [`kernel_param_ops`](../../../include/linux/moduleparam.h)
+    /// for [`u8`].
+    PARAM_OPS_U8,
+    u8
+);
+make_param_ops!(
+    /// Rust implementation of [`kernel_param_ops`](../../../include/linux/moduleparam.h)
+    /// for [`i16`].
+    PARAM_OPS_I16,
+    i16
+);
+make_param_ops!(
+    /// Rust implementation of [`kernel_param_ops`](../../../include/linux/moduleparam.h)
+    /// for [`u16`].
+    PARAM_OPS_U16,
+    u16
+);
+make_param_ops!(
+    /// Rust implementation of [`kernel_param_ops`](../../../include/linux/moduleparam.h)
+    /// for [`i32`].
+    PARAM_OPS_I32,
+    i32
+);
+make_param_ops!(
+    /// Rust implementation of [`kernel_param_ops`](../../../include/linux/moduleparam.h)
+    /// for [`u32`].
+    PARAM_OPS_U32,
+    u32
+);
+make_param_ops!(
+    /// Rust implementation of [`kernel_param_ops`](../../../include/linux/moduleparam.h)
+    /// for [`i64`].
+    PARAM_OPS_I64,
+    i64
+);
+make_param_ops!(
+    /// Rust implementation of [`kernel_param_ops`](../../../include/linux/moduleparam.h)
+    /// for [`u64`].
+    PARAM_OPS_U64,
+    u64
+);
+make_param_ops!(
+    /// Rust implementation of [`kernel_param_ops`](../../../include/linux/moduleparam.h)
+    /// for [`isize`].
+    PARAM_OPS_ISIZE,
+    isize
+);
+make_param_ops!(
+    /// Rust implementation of [`kernel_param_ops`](../../../include/linux/moduleparam.h)
+    /// for [`usize`].
+    PARAM_OPS_USIZE,
+    usize
+);
+
+impl ModuleParam for bool {
+    type Value = bool;
+
+    const NOARG_ALLOWED: bool = true;
+
+    fn try_from_param_arg(arg: Option<&'static [u8]>) -> Option<Self> {
+        match arg {
+            None => Some(true),
+            Some(b"y") | Some(b"Y") | Some(b"1") | Some(b"true") => Some(true),
+            Some(b"n") | Some(b"N") | Some(b"0") | Some(b"false") => Some(false),
+            _ => None,
+        }
+    }
+
+    fn value(&self) -> &Self::Value {
+        self
+    }
+}
+
+make_param_ops!(
+    /// Rust implementation of [`kernel_param_ops`](../../../include/linux/moduleparam.h)
+    /// for [`bool`].
+    PARAM_OPS_BOOL,
+    bool
+);
+
+/// An array of at __most__ `N` values.
+///
+/// # Invariant
+///
+/// The first `self.used` elements of `self.values` are initialized.
+pub struct ArrayParam<T, const N: usize> {
+    values: [core::mem::MaybeUninit<T>; N],
+    used: usize,
+}
+
+impl<T, const N: usize> ArrayParam<T, { N }> {
+    fn values(&self) -> &[T] {
+        // SAFETY: The invariant maintained by `ArrayParam` allows us to cast
+        // the first `self.used` elements to `T`.
+        unsafe {
+            &*(&self.values[0..self.used] as *const [core::mem::MaybeUninit<T>] as *const [T])
+        }
+    }
+}
+
+impl<T: Copy, const N: usize> ArrayParam<T, { N }> {
+    const fn new() -> Self {
+        // INVARIANT: The first `self.used` elements of `self.values` are
+        // initialized.
+        ArrayParam {
+            values: [core::mem::MaybeUninit::uninit(); N],
+            used: 0,
+        }
+    }
+
+    const fn push(&mut self, val: T) {
+        if self.used < N {
+            // INVARIANT: The first `self.used` elements of `self.values` are
+            // initialized.
+            self.values[self.used] = core::mem::MaybeUninit::new(val);
+            self.used += 1;
+        }
+    }
+
+    /// Create an instance of `ArrayParam` initialized with `vals`.
+    ///
+    /// This function is only meant to be used in the [`module::module`] macro.
+    pub const fn create(vals: &[T]) -> Self {
+        let mut result = ArrayParam::new();
+        let mut i = 0;
+        while i < vals.len() {
+            result.push(vals[i]);
+            i += 1;
+        }
+        result
+    }
+}
+
+impl<T: core::fmt::Display, const N: usize> core::fmt::Display for ArrayParam<T, { N }> {
+    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
+        for val in self.values() {
+            write!(f, "{},", val)?;
+        }
+        Ok(())
+    }
+}
+
+impl<T: Copy + core::fmt::Display + ModuleParam, const N: usize> ModuleParam
+    for ArrayParam<T, { N }>
+{
+    type Value = [T];
+
+    const NOARG_ALLOWED: bool = false;
+
+    fn try_from_param_arg(arg: Option<&'static [u8]>) -> Option<Self> {
+        arg.and_then(|args| {
+            let mut result = Self::new();
+            for arg in args.split(|b| *b == b',') {
+                result.push(T::try_from_param_arg(Some(arg))?);
+            }
+            Some(result)
+        })
+    }
+
+    fn value(&self) -> &Self::Value {
+        self.values()
+    }
+}
+
+/// A C-style string parameter.
+///
+/// The Rust version of the [`charp`] parameter. This type is meant to be
+/// used by the [`macros::module`] macro, not handled directly. Instead use the
+/// `read` method generated by that macro.
+///
+/// [`charp`]: ../../../include/linux/moduleparam.h
+pub enum StringParam {
+    /// A borrowed parameter value.
+    ///
+    /// Either the default value (which is static in the module) or borrowed
+    /// from the original argument buffer used to set the value.
+    Ref(&'static [u8]),
+
+    /// A value that was allocated when the parameter was set.
+    ///
+    /// The value needs to be freed when the parameter is reset or the module is
+    /// unloaded.
+    Owned(alloc::vec::Vec<u8>),
+}
+
+impl StringParam {
+    fn bytes(&self) -> &[u8] {
+        match self {
+            StringParam::Ref(bytes) => *bytes,
+            StringParam::Owned(vec) => &vec[..],
+        }
+    }
+}
+
+impl core::fmt::Display for StringParam {
+    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
+        let bytes = self.bytes();
+        match core::str::from_utf8(bytes) {
+            Ok(utf8) => write!(f, "{}", utf8),
+            Err(_) => write!(f, "{:?}", bytes),
+        }
+    }
+}
+
+impl ModuleParam for StringParam {
+    type Value = [u8];
+
+    const NOARG_ALLOWED: bool = false;
+
+    fn try_from_param_arg(arg: Option<&'static [u8]>) -> Option<Self> {
+        // SAFETY: It is always safe to call [`slab_is_available`](../../../include/linux/slab.h).
+        let slab_available = unsafe { crate::bindings::slab_is_available() };
+        arg.and_then(|arg| {
+            if slab_available {
+                let mut vec = alloc::vec::Vec::new();
+                vec.try_extend_from_slice(arg).ok()?;
+                Some(StringParam::Owned(vec))
+            } else {
+                Some(StringParam::Ref(arg))
+            }
+        })
+    }
+
+    fn value(&self) -> &Self::Value {
+        self.bytes()
+    }
+}
+
+make_param_ops!(
+    /// Rust implementation of [`kernel_param_ops`](../../../include/linux/moduleparam.h)
+    /// for [`StringParam`].
+    PARAM_OPS_STR,
+    StringParam
+);
diff --git a/rust/kernel/of.rs b/rust/kernel/of.rs
new file mode 100644
index 000000000000..cdcd83244337
--- /dev/null
+++ b/rust/kernel/of.rs
@@ -0,0 +1,63 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Devicetree and Open Firmware abstractions.
+//!
+//! C header: [`include/linux/of_*.h`](../../../../include/linux/of_*.h)
+
+use crate::{bindings, driver, str::BStr};
+
+/// An open firmware device id.
+#[derive(Clone, Copy)]
+pub enum DeviceId {
+    /// An open firmware device id where only a compatible string is specified.
+    Compatible(&'static BStr),
+}
+
+/// Defines a const open firmware device id table that also carries per-entry data/context/info.
+///
+/// The name of the const is `OF_DEVICE_ID_TABLE`, which is what buses are expected to name their
+/// open firmware tables.
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::define_of_id_table;
+/// use kernel::of;
+///
+/// define_of_id_table! {u32, [
+///     (of::DeviceId::Compatible(b"test-device1,test-device2"), Some(0xff)),
+///     (of::DeviceId::Compatible(b"test-device3"), None),
+/// ]};
+/// ```
+#[macro_export]
+macro_rules! define_of_id_table {
+    ($data_type:ty, $($t:tt)*) => {
+        $crate::define_id_table!(OF_DEVICE_ID_TABLE, $crate::of::DeviceId, $data_type, $($t)*);
+    };
+}
+
+// SAFETY: `ZERO` is all zeroed-out and `to_rawid` stores `offset` in `of_device_id::data`.
+unsafe impl const driver::RawDeviceId for DeviceId {
+    type RawType = bindings::of_device_id;
+    const ZERO: Self::RawType = bindings::of_device_id {
+        name: [0; 32],
+        type_: [0; 32],
+        compatible: [0; 128],
+        data: core::ptr::null(),
+    };
+
+    fn to_rawid(&self, offset: isize) -> Self::RawType {
+        let DeviceId::Compatible(compatible) = self;
+        let mut id = Self::ZERO;
+        let mut i = 0;
+        while i < compatible.len() {
+            // If `compatible` does not fit in `id.compatible`, an "index out of bounds" build time
+            // error will be triggered.
+            id.compatible[i] = compatible[i] as _;
+            i += 1;
+        }
+        id.compatible[i] = b'\0' as _;
+        id.data = offset as _;
+        id
+    }
+}
diff --git a/rust/kernel/pages.rs b/rust/kernel/pages.rs
new file mode 100644
index 000000000000..de8358629fdd
--- /dev/null
+++ b/rust/kernel/pages.rs
@@ -0,0 +1,162 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Kernel page allocation and management.
+//!
+//! TODO: This module is a work in progress.
+
+use crate::{
+    bindings, c_types, io_buffer::IoBufferReader, user_ptr::UserSlicePtrReader, Error, Result,
+    PAGE_SIZE,
+};
+use core::{marker::PhantomData, ptr};
+
+/// A set of physical pages.
+///
+/// `Pages` holds a reference to a set of pages of order `ORDER`. Having the order as a generic
+/// const allows the struct to have the same size as a pointer.
+///
+/// # Invariants
+///
+/// The pointer `Pages::pages` is valid and points to 2^ORDER pages.
+pub struct Pages<const ORDER: u32> {
+    pages: *mut bindings::page,
+}
+
+impl<const ORDER: u32> Pages<ORDER> {
+    /// Allocates a new set of contiguous pages.
+    pub fn new() -> Result<Self> {
+        // TODO: Consider whether we want to allow callers to specify flags.
+        // SAFETY: This only allocates pages. We check that it succeeds in the next statement.
+        let pages = unsafe {
+            bindings::alloc_pages(
+                bindings::GFP_KERNEL | bindings::__GFP_ZERO | bindings::__GFP_HIGHMEM,
+                ORDER,
+            )
+        };
+        if pages.is_null() {
+            return Err(Error::ENOMEM);
+        }
+        // INVARIANTS: We checked that the allocation above succeeded>
+        Ok(Self { pages })
+    }
+
+    /// Maps a single page at the given address in the given VM area.
+    ///
+    /// This is only meant to be used by pages of order 0.
+    pub fn insert_page(&self, vma: &mut bindings::vm_area_struct, address: usize) -> Result {
+        if ORDER != 0 {
+            return Err(Error::EINVAL);
+        }
+
+        // SAFETY: We check above that the allocation is of order 0. The range of `address` is
+        // already checked by `vm_insert_page`.
+        let ret = unsafe { bindings::vm_insert_page(vma, address as _, self.pages) };
+        if ret != 0 {
+            Err(Error::from_kernel_errno(ret))
+        } else {
+            Ok(())
+        }
+    }
+
+    /// Copies data from the given [`UserSlicePtrReader`] into the pages.
+    pub fn copy_into_page(
+        &self,
+        reader: &mut UserSlicePtrReader,
+        offset: usize,
+        len: usize,
+    ) -> Result {
+        // TODO: For now this only works on the first page.
+        let end = offset.checked_add(len).ok_or(Error::EINVAL)?;
+        if end > PAGE_SIZE {
+            return Err(Error::EINVAL);
+        }
+
+        let mapping = self.kmap(0).ok_or(Error::EINVAL)?;
+
+        // SAFETY: We ensured that the buffer was valid with the check above.
+        unsafe { reader.read_raw((mapping.ptr as usize + offset) as _, len) }?;
+        Ok(())
+    }
+
+    /// Maps the pages and reads from them into the given buffer.
+    ///
+    /// # Safety
+    ///
+    /// Callers must ensure that the destination buffer is valid for the given length.
+    /// Additionally, if the raw buffer is intended to be recast, they must ensure that the data
+    /// can be safely cast; [`crate::io_buffer::ReadableFromBytes`] has more details about it.
+    pub unsafe fn read(&self, dest: *mut u8, offset: usize, len: usize) -> Result {
+        // TODO: For now this only works on the first page.
+        let end = offset.checked_add(len).ok_or(Error::EINVAL)?;
+        if end > PAGE_SIZE {
+            return Err(Error::EINVAL);
+        }
+
+        let mapping = self.kmap(0).ok_or(Error::EINVAL)?;
+        unsafe { ptr::copy((mapping.ptr as *mut u8).add(offset), dest, len) };
+        Ok(())
+    }
+
+    /// Maps the pages and writes into them from the given bufer.
+    ///
+    /// # Safety
+    ///
+    /// Callers must ensure that the buffer is valid for the given length. Additionally, if the
+    /// page is (or will be) mapped by userspace, they must ensure that no kernel data is leaked
+    /// through padding if it was cast from another type; [`crate::io_buffer::WritableToBytes`] has
+    /// more details about it.
+    pub unsafe fn write(&self, src: *const u8, offset: usize, len: usize) -> Result {
+        // TODO: For now this only works on the first page.
+        let end = offset.checked_add(len).ok_or(Error::EINVAL)?;
+        if end > PAGE_SIZE {
+            return Err(Error::EINVAL);
+        }
+
+        let mapping = self.kmap(0).ok_or(Error::EINVAL)?;
+        unsafe { ptr::copy(src, (mapping.ptr as *mut u8).add(offset), len) };
+        Ok(())
+    }
+
+    /// Maps the page at index `index`.
+    fn kmap(&self, index: usize) -> Option<PageMapping<'_>> {
+        if index >= 1usize << ORDER {
+            return None;
+        }
+
+        // SAFETY: We checked above that `index` is within range.
+        let page = unsafe { self.pages.add(index) };
+
+        // SAFETY: `page` is valid based on the checks above.
+        let ptr = unsafe { bindings::kmap(page) };
+        if ptr.is_null() {
+            return None;
+        }
+
+        Some(PageMapping {
+            page,
+            ptr,
+            _phantom: PhantomData,
+        })
+    }
+}
+
+impl<const ORDER: u32> Drop for Pages<ORDER> {
+    fn drop(&mut self) {
+        // SAFETY: By the type invariants, we know the pages are allocated with the given order.
+        unsafe { bindings::__free_pages(self.pages, ORDER) };
+    }
+}
+
+struct PageMapping<'a> {
+    page: *mut bindings::page,
+    ptr: *mut c_types::c_void,
+    _phantom: PhantomData<&'a i32>,
+}
+
+impl Drop for PageMapping<'_> {
+    fn drop(&mut self) {
+        // SAFETY: An instance of `PageMapping` is created only when `kmap` succeeded for the given
+        // page, so it is safe to unmap it here.
+        unsafe { bindings::kunmap(self.page) };
+    }
+}
diff --git a/rust/kernel/platform.rs b/rust/kernel/platform.rs
new file mode 100644
index 000000000000..8b912c21068b
--- /dev/null
+++ b/rust/kernel/platform.rs
@@ -0,0 +1,224 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Platform devices and drivers.
+//!
+//! Also called `platdev`, `pdev`.
+//!
+//! C header: [`include/linux/platform_device.h`](../../../../include/linux/platform_device.h)
+
+use crate::{
+    bindings, c_types,
+    device::{self, RawDevice},
+    driver,
+    error::{from_kernel_result, Result},
+    of,
+    str::CStr,
+    to_result,
+    types::PointerWrapper,
+    ThisModule,
+};
+
+/// A registration of a platform driver.
+pub type Registration<T> = driver::Registration<Adapter<T>>;
+
+/// An adapter for the registration of platform drivers.
+pub struct Adapter<T: Driver>(T);
+
+impl<T: Driver> driver::DriverOps for Adapter<T> {
+    type RegType = bindings::platform_driver;
+
+    unsafe fn register(
+        reg: *mut bindings::platform_driver,
+        name: &'static CStr,
+        module: &'static ThisModule,
+    ) -> Result {
+        // SAFETY: By the safety requirements of this function (defined in the trait defintion),
+        // `reg` is non-null and valid.
+        let pdrv = unsafe { &mut *reg };
+
+        pdrv.driver.name = name.as_char_ptr();
+        pdrv.probe = Some(Self::probe_callback);
+        pdrv.remove = Some(Self::remove_callback);
+        if let Some(t) = T::OF_DEVICE_ID_TABLE {
+            pdrv.driver.of_match_table = t.as_ref();
+        }
+        // SAFETY:
+        //   - `pdrv` lives at least until the call to `platform_driver_unregister()` returns.
+        //   - `name` pointer has static lifetime.
+        //   - `module.0` lives at least as long as the module.
+        //   - `probe()` and `remove()` are static functions.
+        //   - `of_match_table` is either a raw pointer with static lifetime,
+        //      as guaranteed by the [`driver::IdTable`] type, or null.
+        to_result(|| unsafe { bindings::__platform_driver_register(reg, module.0) })
+    }
+
+    unsafe fn unregister(reg: *mut bindings::platform_driver) {
+        // SAFETY: By the safety requirements of this function (defined in the trait definition),
+        // `reg` was passed (and updated) by a previous successful call to
+        // `platform_driver_register`.
+        unsafe { bindings::platform_driver_unregister(reg) };
+    }
+}
+
+impl<T: Driver> Adapter<T> {
+    fn get_id_info(dev: &Device) -> Option<&'static T::IdInfo> {
+        let table = T::OF_DEVICE_ID_TABLE?;
+
+        // SAFETY: `table` has static lifetime, so it is valid for read. `dev` is guaranteed to be
+        // valid while it's alive, so is the raw device returned by it.
+        let id = unsafe { bindings::of_match_device(table.as_ref(), dev.raw_device()) };
+        if id.is_null() {
+            return None;
+        }
+
+        // SAFETY: `id` is a pointer within the static table, so it's always valid.
+        let offset = unsafe { (*id).data };
+        if offset.is_null() {
+            return None;
+        }
+
+        // SAFETY: The offset comes from a previous call to `offset_from` in `IdArray::new`, which
+        // guarantees that the resulting pointer is within the table.
+        let ptr = unsafe {
+            id.cast::<u8>()
+                .offset(offset as _)
+                .cast::<Option<T::IdInfo>>()
+        };
+
+        // SAFETY: The id table has a static lifetime, so `ptr` is guaranteed to be valid for read.
+        unsafe { (&*ptr).as_ref() }
+    }
+
+    extern "C" fn probe_callback(pdev: *mut bindings::platform_device) -> c_types::c_int {
+        from_kernel_result! {
+            // SAFETY: `pdev` is valid by the contract with the C code. `dev` is alive only for the
+            // duration of this call, so it is guaranteed to remain alive for the lifetime of
+            // `pdev`.
+            let mut dev = unsafe { Device::from_ptr(pdev) };
+            let info = Self::get_id_info(&dev);
+            let data = T::probe(&mut dev, info)?;
+            // SAFETY: `pdev` is guaranteed to be a valid, non-null pointer.
+            unsafe { bindings::platform_set_drvdata(pdev, data.into_pointer() as _) };
+            Ok(0)
+        }
+    }
+
+    extern "C" fn remove_callback(pdev: *mut bindings::platform_device) -> c_types::c_int {
+        from_kernel_result! {
+            // SAFETY: `pdev` is guaranteed to be a valid, non-null pointer.
+            let ptr = unsafe { bindings::platform_get_drvdata(pdev) };
+            // SAFETY:
+            //   - we allocated this pointer using `T::Data::into_pointer`,
+            //     so it is safe to turn back into a `T::Data`.
+            //   - the allocation happened in `probe`, no-one freed the memory,
+            //     `remove` is the canonical kernel location to free driver data. so OK
+            //     to convert the pointer back to a Rust structure here.
+            let data = unsafe { T::Data::from_pointer(ptr) };
+            let ret = T::remove(&data);
+            <T::Data as driver::DeviceRemoval>::device_remove(&data);
+            ret?;
+            Ok(0)
+        }
+    }
+}
+
+/// A platform driver.
+pub trait Driver {
+    /// Data stored on device by driver.
+    ///
+    /// Corresponds to the data set or retrieved via the kernel's
+    /// `platform_{set,get}_drvdata()` functions.
+    ///
+    /// Require that `Data` implements `PointerWrapper`. We guarantee to
+    /// never move the underlying wrapped data structure. This allows
+    type Data: PointerWrapper + Send + Sync + driver::DeviceRemoval = ();
+
+    /// The type holding information about each device id supported by the driver.
+    type IdInfo: 'static = ();
+
+    /// The table of device ids supported by the driver.
+    const OF_DEVICE_ID_TABLE: Option<driver::IdTable<'static, of::DeviceId, Self::IdInfo>> = None;
+
+    /// Platform driver probe.
+    ///
+    /// Called when a new platform device is added or discovered.
+    /// Implementers should attempt to initialize the device here.
+    fn probe(dev: &mut Device, id_info: Option<&Self::IdInfo>) -> Result<Self::Data>;
+
+    /// Platform driver remove.
+    ///
+    /// Called when a platform device is removed.
+    /// Implementers should prepare the device for complete removal here.
+    fn remove(_data: &Self::Data) -> Result {
+        Ok(())
+    }
+}
+
+/// A platform device.
+///
+/// # Invariants
+///
+/// The field `ptr` is non-null and valid for the lifetime of the object.
+pub struct Device {
+    ptr: *mut bindings::platform_device,
+}
+
+impl Device {
+    /// Creates a new device from the given pointer.
+    ///
+    /// # Safety
+    ///
+    /// `ptr` must be non-null and valid. It must remain valid for the lifetime of the returned
+    /// instance.
+    unsafe fn from_ptr(ptr: *mut bindings::platform_device) -> Self {
+        // INVARIANT: The safety requirements of the function ensure the lifetime invariant.
+        Self { ptr }
+    }
+
+    /// Returns id of the platform device.
+    pub fn id(&self) -> i32 {
+        // SAFETY: By the type invariants, we know that `self.ptr` is non-null and valid.
+        unsafe { (*self.ptr).id }
+    }
+}
+
+// SAFETY: The device returned by `raw_device` is the raw platform device.
+unsafe impl device::RawDevice for Device {
+    fn raw_device(&self) -> *mut bindings::device {
+        // SAFETY: By the type invariants, we know that `self.ptr` is non-null and valid.
+        unsafe { &mut (*self.ptr).dev }
+    }
+}
+
+/// Declares a kernel module that exposes a single platform driver.
+///
+/// # Examples
+///
+/// ```ignore
+/// # use kernel::prelude::*;
+/// # use kernel::{platform, define_of_id_table, module_platform_driver};
+/// #
+/// struct MyDriver;
+/// impl platform::Driver for MyDriver {
+///     // [...]
+/// #   fn probe(_dev: &mut platform::Device, _id_info: Option<&Self::IdInfo>) -> Result {
+/// #       Ok(())
+/// #   }
+/// #   define_of_id_table! {(), [
+/// #       (of::DeviceId::Compatible(b"brcm,bcm2835-rng"), None),
+/// #   ]}
+/// }
+///
+/// module_platform_driver! {
+///     type: MyDriver,
+///     name: b"module_name",
+///     author: b"Author name",
+///     license: b"GPL v2",
+/// }
+/// ```
+#[macro_export]
+macro_rules! module_platform_driver {
+    ($($f:tt)*) => {
+        $crate::module_driver!(<T>, $crate::platform::Adapter<T>, { $($f)* });
+    };
+}
diff --git a/rust/kernel/power.rs b/rust/kernel/power.rs
new file mode 100644
index 000000000000..e318b5d9f0c0
--- /dev/null
+++ b/rust/kernel/power.rs
@@ -0,0 +1,118 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Power management interfaces.
+//!
+//! C header: [`include/linux/pm.h`](../../../../include/linux/pm.h)
+
+#![allow(dead_code)]
+
+use crate::{bindings, c_types, error::from_kernel_result, types::PointerWrapper, Result};
+use core::marker::PhantomData;
+
+/// Corresponds to the kernel's `struct dev_pm_ops`.
+///
+/// It is meant to be implemented by drivers that support power-management operations.
+pub trait Operations {
+    /// The type of the context data stored by the driver on each device.
+    type Data: PointerWrapper + Sync + Send;
+
+    /// Called before the system goes into a sleep state.
+    fn suspend(_data: <Self::Data as PointerWrapper>::Borrowed<'_>) -> Result {
+        Ok(())
+    }
+
+    /// Called after the system comes back from a sleep state.
+    fn resume(_data: <Self::Data as PointerWrapper>::Borrowed<'_>) -> Result {
+        Ok(())
+    }
+
+    /// Called before creating a hibernation image.
+    fn freeze(_data: <Self::Data as PointerWrapper>::Borrowed<'_>) -> Result {
+        Ok(())
+    }
+
+    /// Called after the system is restored from a hibernation image.
+    fn restore(_data: <Self::Data as PointerWrapper>::Borrowed<'_>) -> Result {
+        Ok(())
+    }
+}
+
+macro_rules! pm_callback {
+    ($callback:ident, $method:ident) => {
+        unsafe extern "C" fn $callback<T: Operations>(
+            dev: *mut bindings::device,
+        ) -> c_types::c_int {
+            from_kernel_result! {
+                // SAFETY: `dev` is valid as it was passed in by the C portion.
+                let ptr = unsafe { bindings::dev_get_drvdata(dev) };
+                // SAFETY: By the safety requirements of `OpsTable::build`, we know that `ptr` came
+                // from a previous call to `T::Data::into_pointer`.
+                let data = unsafe { T::Data::borrow(ptr) };
+                T::$method(data)?;
+                Ok(0)
+            }
+        }
+    };
+}
+
+pm_callback!(suspend_callback, suspend);
+pm_callback!(resume_callback, resume);
+pm_callback!(freeze_callback, freeze);
+pm_callback!(restore_callback, restore);
+
+pub(crate) struct OpsTable<T: Operations>(PhantomData<*const T>);
+
+impl<T: Operations> OpsTable<T> {
+    const VTABLE: bindings::dev_pm_ops = bindings::dev_pm_ops {
+        prepare: None,
+        complete: None,
+        suspend: Some(suspend_callback::<T>),
+        resume: Some(resume_callback::<T>),
+        freeze: Some(freeze_callback::<T>),
+        thaw: None,
+        poweroff: None,
+        restore: Some(restore_callback::<T>),
+        suspend_late: None,
+        resume_early: None,
+        freeze_late: None,
+        thaw_early: None,
+        poweroff_late: None,
+        restore_early: None,
+        suspend_noirq: None,
+        resume_noirq: None,
+        freeze_noirq: None,
+        thaw_noirq: None,
+        poweroff_noirq: None,
+        restore_noirq: None,
+        runtime_suspend: None,
+        runtime_resume: None,
+        runtime_idle: None,
+    };
+
+    /// Builds an instance of `struct dev_pm_ops`.
+    ///
+    /// # Safety
+    ///
+    /// The caller must ensure that `dev_get_drvdata` will result in a value returned by
+    /// [`T::Data::into_pointer`].
+    pub(crate) const unsafe fn build() -> &'static bindings::dev_pm_ops {
+        &Self::VTABLE
+    }
+}
+
+/// Implements the [`Operations`] trait as no-ops.
+///
+/// This is useful when one doesn't want to provide the implementation of any power-manager related
+/// operation.
+pub struct NoOperations<T: PointerWrapper>(PhantomData<T>);
+
+impl<T: PointerWrapper + Send + Sync> Operations for NoOperations<T> {
+    type Data = T;
+}
+
+// SAFETY: `NoOperation` provides no functionality, it is safe to send a reference to it to
+// different threads.
+unsafe impl<T: PointerWrapper> Sync for NoOperations<T> {}
+
+// SAFETY: `NoOperation` provides no functionality, it is safe to send it to different threads.
+unsafe impl<T: PointerWrapper> Send for NoOperations<T> {}
diff --git a/rust/kernel/prelude.rs b/rust/kernel/prelude.rs
new file mode 100644
index 000000000000..ad9e91307028
--- /dev/null
+++ b/rust/kernel/prelude.rs
@@ -0,0 +1,36 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! The `kernel` prelude.
+//!
+//! These are the most common items used by Rust code in the kernel,
+//! intended to be imported by all Rust code, for convenience.
+//!
+//! # Examples
+//!
+//! ```
+//! use kernel::prelude::*;
+//! ```
+
+pub use core::pin::Pin;
+
+pub use alloc::{boxed::Box, string::String, vec::Vec};
+
+pub use macros::module;
+
+pub use super::build_assert;
+
+pub use super::{
+    dbg, dev_alert, dev_crit, dev_dbg, dev_emerg, dev_err, dev_info, dev_notice, dev_warn,
+    pr_alert, pr_crit, pr_debug, pr_emerg, pr_err, pr_info, pr_notice, pr_warn,
+};
+
+pub use super::module_misc_device;
+
+#[cfg(CONFIG_ARM_AMBA)]
+pub use super::module_amba_driver;
+
+pub use super::static_assert;
+
+pub use super::{Error, KernelModule, Result};
+
+pub use super::{str::CStr, ThisModule};
diff --git a/rust/kernel/print.rs b/rust/kernel/print.rs
new file mode 100644
index 000000000000..328d893f87aa
--- /dev/null
+++ b/rust/kernel/print.rs
@@ -0,0 +1,441 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Printing facilities.
+//!
+//! C header: [`include/linux/printk.h`](../../../../include/linux/printk.h)
+//!
+//! Reference: <https://www.kernel.org/doc/html/latest/core-api/printk-basics.html>
+
+use core::cmp;
+use core::fmt;
+
+use crate::bindings;
+use crate::c_types::{c_char, c_void};
+
+// Called from `vsprintf` with format specifier `%pA`.
+#[no_mangle]
+unsafe fn rust_fmt_argument(buf: *mut c_char, end: *mut c_char, ptr: *const c_void) -> *mut c_char {
+    use fmt::Write;
+
+    // Use `usize` to use `saturating_*` functions.
+    struct Writer {
+        buf: usize,
+        end: usize,
+    }
+
+    impl Write for Writer {
+        fn write_str(&mut self, s: &str) -> fmt::Result {
+            // `buf` value after writing `len` bytes. This does not have to be bounded
+            // by `end`, but we don't want it to wrap around to 0.
+            let buf_new = self.buf.saturating_add(s.len());
+
+            // Amount that we can copy. `saturating_sub` ensures we get 0 if
+            // `buf` goes past `end`.
+            let len_to_copy = cmp::min(buf_new, self.end).saturating_sub(self.buf);
+
+            // SAFETY: In any case, `buf` is non-null and properly aligned.
+            // If `len_to_copy` is non-zero, then we know `buf` has not past
+            // `end` yet and so is valid.
+            unsafe {
+                core::ptr::copy_nonoverlapping(
+                    s.as_bytes().as_ptr(),
+                    self.buf as *mut u8,
+                    len_to_copy,
+                )
+            };
+
+            self.buf = buf_new;
+            Ok(())
+        }
+    }
+
+    let mut w = Writer {
+        buf: buf as _,
+        end: end as _,
+    };
+    let _ = w.write_fmt(unsafe { *(ptr as *const fmt::Arguments<'_>) });
+    w.buf as _
+}
+
+/// Format strings.
+///
+/// Public but hidden since it should only be used from public macros.
+#[doc(hidden)]
+pub mod format_strings {
+    use crate::bindings;
+
+    /// The length we copy from the `KERN_*` kernel prefixes.
+    const LENGTH_PREFIX: usize = 2;
+
+    /// The length of the fixed format strings.
+    pub const LENGTH: usize = 10;
+
+    /// Generates a fixed format string for the kernel's [`_printk`].
+    ///
+    /// The format string is always the same for a given level, i.e. for a
+    /// given `prefix`, which are the kernel's `KERN_*` constants.
+    ///
+    /// [`_printk`]: ../../../../include/linux/printk.h
+    const fn generate(is_cont: bool, prefix: &[u8; 3]) -> [u8; LENGTH] {
+        // Ensure the `KERN_*` macros are what we expect.
+        assert!(prefix[0] == b'\x01');
+        if is_cont {
+            assert!(prefix[1] == b'c');
+        } else {
+            assert!(prefix[1] >= b'0' && prefix[1] <= b'7');
+        }
+        assert!(prefix[2] == b'\x00');
+
+        let suffix: &[u8; LENGTH - LENGTH_PREFIX] = if is_cont {
+            b"%pA\0\0\0\0\0"
+        } else {
+            b"%s: %pA\0"
+        };
+
+        [
+            prefix[0], prefix[1], suffix[0], suffix[1], suffix[2], suffix[3], suffix[4], suffix[5],
+            suffix[6], suffix[7],
+        ]
+    }
+
+    // Generate the format strings at compile-time.
+    //
+    // This avoids the compiler generating the contents on the fly in the stack.
+    //
+    // Furthermore, `static` instead of `const` is used to share the strings
+    // for all the kernel.
+    pub static EMERG: [u8; LENGTH] = generate(false, bindings::KERN_EMERG);
+    pub static ALERT: [u8; LENGTH] = generate(false, bindings::KERN_ALERT);
+    pub static CRIT: [u8; LENGTH] = generate(false, bindings::KERN_CRIT);
+    pub static ERR: [u8; LENGTH] = generate(false, bindings::KERN_ERR);
+    pub static WARNING: [u8; LENGTH] = generate(false, bindings::KERN_WARNING);
+    pub static NOTICE: [u8; LENGTH] = generate(false, bindings::KERN_NOTICE);
+    pub static INFO: [u8; LENGTH] = generate(false, bindings::KERN_INFO);
+    pub static DEBUG: [u8; LENGTH] = generate(false, bindings::KERN_DEBUG);
+    pub static CONT: [u8; LENGTH] = generate(true, bindings::KERN_CONT);
+}
+
+/// Prints a message via the kernel's [`_printk`].
+///
+/// Public but hidden since it should only be used from public macros.
+///
+/// # Safety
+///
+/// The format string must be one of the ones in [`format_strings`], and
+/// the module name must be null-terminated.
+///
+/// [`_printk`]: ../../../../include/linux/_printk.h
+#[doc(hidden)]
+pub unsafe fn call_printk(
+    format_string: &[u8; format_strings::LENGTH],
+    module_name: &[u8],
+    args: fmt::Arguments<'_>,
+) {
+    // `_printk` does not seem to fail in any path.
+    unsafe {
+        bindings::_printk(
+            format_string.as_ptr() as _,
+            module_name.as_ptr(),
+            &args as *const _ as *const c_void,
+        );
+    }
+}
+
+/// Prints a message via the kernel's [`_printk`] for the `CONT` level.
+///
+/// Public but hidden since it should only be used from public macros.
+///
+/// [`_printk`]: ../../../../include/linux/printk.h
+#[doc(hidden)]
+pub fn call_printk_cont(args: fmt::Arguments<'_>) {
+    // `_printk` does not seem to fail in any path.
+    //
+    // SAFETY: The format string is fixed.
+    unsafe {
+        bindings::_printk(
+            format_strings::CONT.as_ptr() as _,
+            &args as *const _ as *const c_void,
+        );
+    }
+}
+
+/// Performs formatting and forwards the string to [`call_printk`].
+///
+/// Public but hidden since it should only be used from public macros.
+#[doc(hidden)]
+#[cfg(not(testlib))]
+#[macro_export]
+macro_rules! print_macro (
+    // The non-continuation cases (most of them, e.g. `INFO`).
+    ($format_string:path, false, $($arg:tt)+) => (
+        // SAFETY: This hidden macro should only be called by the documented
+        // printing macros which ensure the format string is one of the fixed
+        // ones. All `__LOG_PREFIX`s are null-terminated as they are generated
+        // by the `module!` proc macro or fixed values defined in a kernel
+        // crate.
+        unsafe {
+            $crate::print::call_printk(
+                &$format_string,
+                crate::__LOG_PREFIX,
+                format_args!($($arg)+),
+            );
+        }
+    );
+
+    // The `CONT` case.
+    ($format_string:path, true, $($arg:tt)+) => (
+        $crate::print::call_printk_cont(
+            format_args!($($arg)+),
+        );
+    );
+);
+
+/// Stub for doctests
+#[cfg(testlib)]
+#[macro_export]
+macro_rules! print_macro (
+    ($format_string:path, $e:expr, $($arg:tt)+) => (
+        ()
+    );
+);
+
+// We could use a macro to generate these macros. However, doing so ends
+// up being a bit ugly: it requires the dollar token trick to escape `$` as
+// well as playing with the `doc` attribute. Furthermore, they cannot be easily
+// imported in the prelude due to [1]. So, for the moment, we just write them
+// manually, like in the C side; while keeping most of the logic in another
+// macro, i.e. [`print_macro`].
+//
+// [1]: https://github.com/rust-lang/rust/issues/52234
+
+/// Prints an emergency-level message (level 0).
+///
+/// Use this level if the system is unusable.
+///
+/// Equivalent to the kernel's [`pr_emerg`] macro.
+///
+/// Mimics the interface of [`std::print!`]. See [`core::fmt`] and
+/// [`alloc::format!`] for information about the formatting syntax.
+///
+/// [`pr_emerg`]: https://www.kernel.org/doc/html/latest/core-api/printk-basics.html#c.pr_emerg
+/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::prelude::*;
+/// pr_emerg!("hello {}\n", "there");
+/// ```
+#[macro_export]
+macro_rules! pr_emerg (
+    ($($arg:tt)*) => (
+        $crate::print_macro!($crate::print::format_strings::EMERG, false, $($arg)*)
+    )
+);
+
+/// Prints an alert-level message (level 1).
+///
+/// Use this level if action must be taken immediately.
+///
+/// Equivalent to the kernel's [`pr_alert`] macro.
+///
+/// Mimics the interface of [`std::print!`]. See [`core::fmt`] and
+/// [`alloc::format!`] for information about the formatting syntax.
+///
+/// [`pr_alert`]: https://www.kernel.org/doc/html/latest/core-api/printk-basics.html#c.pr_alert
+/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::prelude::*;
+/// pr_alert!("hello {}\n", "there");
+/// ```
+#[macro_export]
+macro_rules! pr_alert (
+    ($($arg:tt)*) => (
+        $crate::print_macro!($crate::print::format_strings::ALERT, false, $($arg)*)
+    )
+);
+
+/// Prints a critical-level message (level 2).
+///
+/// Use this level for critical conditions.
+///
+/// Equivalent to the kernel's [`pr_crit`] macro.
+///
+/// Mimics the interface of [`std::print!`]. See [`core::fmt`] and
+/// [`alloc::format!`] for information about the formatting syntax.
+///
+/// [`pr_crit`]: https://www.kernel.org/doc/html/latest/core-api/printk-basics.html#c.pr_crit
+/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::prelude::*;
+/// pr_crit!("hello {}\n", "there");
+/// ```
+#[macro_export]
+macro_rules! pr_crit (
+    ($($arg:tt)*) => (
+        $crate::print_macro!($crate::print::format_strings::CRIT, false, $($arg)*)
+    )
+);
+
+/// Prints an error-level message (level 3).
+///
+/// Use this level for error conditions.
+///
+/// Equivalent to the kernel's [`pr_err`] macro.
+///
+/// Mimics the interface of [`std::print!`]. See [`core::fmt`] and
+/// [`alloc::format!`] for information about the formatting syntax.
+///
+/// [`pr_err`]: https://www.kernel.org/doc/html/latest/core-api/printk-basics.html#c.pr_err
+/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::prelude::*;
+/// pr_err!("hello {}\n", "there");
+/// ```
+#[macro_export]
+macro_rules! pr_err (
+    ($($arg:tt)*) => (
+        $crate::print_macro!($crate::print::format_strings::ERR, false, $($arg)*)
+    )
+);
+
+/// Prints a warning-level message (level 4).
+///
+/// Use this level for warning conditions.
+///
+/// Equivalent to the kernel's [`pr_warn`] macro.
+///
+/// Mimics the interface of [`std::print!`]. See [`core::fmt`] and
+/// [`alloc::format!`] for information about the formatting syntax.
+///
+/// [`pr_warn`]: https://www.kernel.org/doc/html/latest/core-api/printk-basics.html#c.pr_warn
+/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::prelude::*;
+/// pr_warn!("hello {}\n", "there");
+/// ```
+#[macro_export]
+macro_rules! pr_warn (
+    ($($arg:tt)*) => (
+        $crate::print_macro!($crate::print::format_strings::WARNING, false, $($arg)*)
+    )
+);
+
+/// Prints a notice-level message (level 5).
+///
+/// Use this level for normal but significant conditions.
+///
+/// Equivalent to the kernel's [`pr_notice`] macro.
+///
+/// Mimics the interface of [`std::print!`]. See [`core::fmt`] and
+/// [`alloc::format!`] for information about the formatting syntax.
+///
+/// [`pr_notice`]: https://www.kernel.org/doc/html/latest/core-api/printk-basics.html#c.pr_notice
+/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::prelude::*;
+/// pr_notice!("hello {}\n", "there");
+/// ```
+#[macro_export]
+macro_rules! pr_notice (
+    ($($arg:tt)*) => (
+        $crate::print_macro!($crate::print::format_strings::NOTICE, false, $($arg)*)
+    )
+);
+
+/// Prints an info-level message (level 6).
+///
+/// Use this level for informational messages.
+///
+/// Equivalent to the kernel's [`pr_info`] macro.
+///
+/// Mimics the interface of [`std::print!`]. See [`core::fmt`] and
+/// [`alloc::format!`] for information about the formatting syntax.
+///
+/// [`pr_info`]: https://www.kernel.org/doc/html/latest/core-api/printk-basics.html#c.pr_info
+/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::prelude::*;
+/// pr_info!("hello {}\n", "there");
+/// ```
+#[macro_export]
+#[doc(alias = "print")]
+macro_rules! pr_info (
+    ($($arg:tt)*) => (
+        $crate::print_macro!($crate::print::format_strings::INFO, false, $($arg)*)
+    )
+);
+
+/// Prints a debug-level message (level 7).
+///
+/// Use this level for debug messages.
+///
+/// Equivalent to the kernel's [`pr_debug`] macro, except that it doesn't support dynamic debug
+/// yet.
+///
+/// Mimics the interface of [`std::print!`]. See [`core::fmt`] and
+/// [`alloc::format!`] for information about the formatting syntax.
+///
+/// [`pr_debug`]: https://www.kernel.org/doc/html/latest/core-api/printk-basics.html#c.pr_debug
+/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::prelude::*;
+/// pr_debug!("hello {}\n", "there");
+/// ```
+#[macro_export]
+#[doc(alias = "print")]
+macro_rules! pr_debug (
+    ($($arg:tt)*) => (
+        if cfg!(debug_assertions) {
+            $crate::print_macro!($crate::print::format_strings::DEBUG, false, $($arg)*)
+        }
+    )
+);
+
+/// Continues a previous log message in the same line.
+///
+/// Use only when continuing a previous `pr_*!` macro (e.g. [`pr_info!`]).
+///
+/// Equivalent to the kernel's [`pr_cont`] macro.
+///
+/// Mimics the interface of [`std::print!`]. See [`core::fmt`] and
+/// [`alloc::format!`] for information about the formatting syntax.
+///
+/// [`pr_cont`]: https://www.kernel.org/doc/html/latest/core-api/printk-basics.html#c.pr_cont
+/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::prelude::*;
+/// # use kernel::pr_cont;
+/// pr_info!("hello");
+/// pr_cont!(" {}\n", "there");
+/// ```
+#[macro_export]
+macro_rules! pr_cont (
+    ($($arg:tt)*) => (
+        $crate::print_macro!($crate::print::format_strings::CONT, true, $($arg)*)
+    )
+);
diff --git a/rust/kernel/random.rs b/rust/kernel/random.rs
new file mode 100644
index 000000000000..723a89829f66
--- /dev/null
+++ b/rust/kernel/random.rs
@@ -0,0 +1,50 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Random numbers.
+//!
+//! C header: [`include/linux/random.h`](../../../../include/linux/random.h)
+
+use core::convert::TryInto;
+
+use crate::{bindings, c_types, error};
+
+/// Fills a byte slice with random bytes generated from the kernel's CSPRNG.
+///
+/// Ensures that the CSPRNG has been seeded before generating any random bytes,
+/// and will block until it is ready.
+pub fn getrandom(dest: &mut [u8]) -> error::Result {
+    let res = unsafe { bindings::wait_for_random_bytes() };
+    if res != 0 {
+        return Err(error::Error::from_kernel_errno(res));
+    }
+
+    unsafe {
+        bindings::get_random_bytes(
+            dest.as_mut_ptr() as *mut c_types::c_void,
+            dest.len().try_into()?,
+        );
+    }
+    Ok(())
+}
+
+/// Fills a byte slice with random bytes generated from the kernel's CSPRNG.
+///
+/// If the CSPRNG is not yet seeded, returns an `Err(EAGAIN)` immediately.
+pub fn getrandom_nonblock(dest: &mut [u8]) -> error::Result {
+    if !unsafe { bindings::rng_is_initialized() } {
+        return Err(error::Error::EAGAIN);
+    }
+    getrandom(dest)
+}
+
+/// Contributes the contents of a byte slice to the kernel's entropy pool.
+///
+/// Does *not* credit the kernel entropy counter though.
+pub fn add_randomness(data: &[u8]) {
+    unsafe {
+        bindings::add_device_randomness(
+            data.as_ptr() as *const c_types::c_void,
+            data.len().try_into().unwrap(),
+        );
+    }
+}
diff --git a/rust/kernel/raw_list.rs b/rust/kernel/raw_list.rs
new file mode 100644
index 000000000000..4bc4f4a24ad5
--- /dev/null
+++ b/rust/kernel/raw_list.rs
@@ -0,0 +1,361 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Raw lists.
+//!
+//! TODO: This module is a work in progress.
+
+use core::{
+    cell::UnsafeCell,
+    ptr,
+    ptr::NonNull,
+    sync::atomic::{AtomicBool, Ordering},
+};
+
+/// A descriptor of list elements.
+///
+/// It describes the type of list elements and provides a function to determine how to get the
+/// links to be used on a list.
+///
+/// A type that may be in multiple lists simultaneously neneds to implement one of these for each
+/// simultaneous list.
+pub trait GetLinks {
+    /// The type of the entries in the list.
+    type EntryType: ?Sized;
+
+    /// Returns the links to be used when linking an entry within a list.
+    fn get_links(data: &Self::EntryType) -> &Links<Self::EntryType>;
+}
+
+/// The links used to link an object on a linked list.
+///
+/// Instances of this type are usually embedded in structures and returned in calls to
+/// [`GetLinks::get_links`].
+pub struct Links<T: ?Sized> {
+    inserted: AtomicBool,
+    entry: UnsafeCell<ListEntry<T>>,
+}
+
+impl<T: ?Sized> Links<T> {
+    /// Constructs a new [`Links`] instance that isn't inserted on any lists yet.
+    pub fn new() -> Self {
+        Self {
+            inserted: AtomicBool::new(false),
+            entry: UnsafeCell::new(ListEntry::new()),
+        }
+    }
+
+    fn acquire_for_insertion(&self) -> bool {
+        self.inserted
+            .compare_exchange(false, true, Ordering::Acquire, Ordering::Relaxed)
+            .is_ok()
+    }
+
+    fn release_after_removal(&self) {
+        self.inserted.store(false, Ordering::Release);
+    }
+}
+
+impl<T: ?Sized> Default for Links<T> {
+    fn default() -> Self {
+        Self::new()
+    }
+}
+
+struct ListEntry<T: ?Sized> {
+    next: Option<NonNull<T>>,
+    prev: Option<NonNull<T>>,
+}
+
+impl<T: ?Sized> ListEntry<T> {
+    fn new() -> Self {
+        Self {
+            next: None,
+            prev: None,
+        }
+    }
+}
+
+/// A linked list.
+///
+/// # Invariants
+///
+/// The links of objects added to a list are owned by the list.
+pub(crate) struct RawList<G: GetLinks> {
+    head: Option<NonNull<G::EntryType>>,
+}
+
+impl<G: GetLinks> RawList<G> {
+    pub(crate) fn new() -> Self {
+        Self { head: None }
+    }
+
+    pub(crate) fn is_empty(&self) -> bool {
+        self.head.is_none()
+    }
+
+    fn insert_after_priv(
+        &mut self,
+        existing: &G::EntryType,
+        new_entry: &mut ListEntry<G::EntryType>,
+        new_ptr: Option<NonNull<G::EntryType>>,
+    ) {
+        {
+            // SAFETY: It's safe to get the previous entry of `existing` because the list cannot
+            // change.
+            let existing_links = unsafe { &mut *G::get_links(existing).entry.get() };
+            new_entry.next = existing_links.next;
+            existing_links.next = new_ptr;
+        }
+
+        new_entry.prev = Some(NonNull::from(existing));
+
+        // SAFETY: It's safe to get the next entry of `existing` because the list cannot change.
+        let next_links =
+            unsafe { &mut *G::get_links(new_entry.next.unwrap().as_ref()).entry.get() };
+        next_links.prev = new_ptr;
+    }
+
+    /// Inserts the given object after `existing`.
+    ///
+    /// # Safety
+    ///
+    /// Callers must ensure that `existing` points to a valid entry that is on the list.
+    pub(crate) unsafe fn insert_after(
+        &mut self,
+        existing: &G::EntryType,
+        new: &G::EntryType,
+    ) -> bool {
+        let links = G::get_links(new);
+        if !links.acquire_for_insertion() {
+            // Nothing to do if already inserted.
+            return false;
+        }
+
+        // SAFETY: The links are now owned by the list, so it is safe to get a mutable reference.
+        let new_entry = unsafe { &mut *links.entry.get() };
+        self.insert_after_priv(existing, new_entry, Some(NonNull::from(new)));
+        true
+    }
+
+    fn push_back_internal(&mut self, new: &G::EntryType) -> bool {
+        let links = G::get_links(new);
+        if !links.acquire_for_insertion() {
+            // Nothing to do if already inserted.
+            return false;
+        }
+
+        // SAFETY: The links are now owned by the list, so it is safe to get a mutable reference.
+        let new_entry = unsafe { &mut *links.entry.get() };
+        let new_ptr = Some(NonNull::from(new));
+        match self.back() {
+            // SAFETY: `back` is valid as the list cannot change.
+            Some(back) => self.insert_after_priv(unsafe { back.as_ref() }, new_entry, new_ptr),
+            None => {
+                self.head = new_ptr;
+                new_entry.next = new_ptr;
+                new_entry.prev = new_ptr;
+            }
+        }
+        true
+    }
+
+    pub(crate) unsafe fn push_back(&mut self, new: &G::EntryType) -> bool {
+        self.push_back_internal(new)
+    }
+
+    fn remove_internal(&mut self, data: &G::EntryType) -> bool {
+        let links = G::get_links(data);
+
+        // SAFETY: The links are now owned by the list, so it is safe to get a mutable reference.
+        let entry = unsafe { &mut *links.entry.get() };
+        let next = if let Some(next) = entry.next {
+            next
+        } else {
+            // Nothing to do if the entry is not on the list.
+            return false;
+        };
+
+        if ptr::eq(data, next.as_ptr()) {
+            // We're removing the only element.
+            self.head = None
+        } else {
+            // Update the head if we're removing it.
+            if let Some(raw_head) = self.head {
+                if ptr::eq(data, raw_head.as_ptr()) {
+                    self.head = Some(next);
+                }
+            }
+
+            // SAFETY: It's safe to get the previous entry because the list cannot change.
+            unsafe { &mut *G::get_links(entry.prev.unwrap().as_ref()).entry.get() }.next =
+                entry.next;
+
+            // SAFETY: It's safe to get the next entry because the list cannot change.
+            unsafe { &mut *G::get_links(next.as_ref()).entry.get() }.prev = entry.prev;
+        }
+
+        // Reset the links of the element we're removing so that we know it's not on any list.
+        entry.next = None;
+        entry.prev = None;
+        links.release_after_removal();
+        true
+    }
+
+    /// Removes the given entry.
+    ///
+    /// # Safety
+    ///
+    /// Callers must ensure that `data` is either on this list or in no list. It being on another
+    /// list leads to memory unsafety.
+    pub(crate) unsafe fn remove(&mut self, data: &G::EntryType) -> bool {
+        self.remove_internal(data)
+    }
+
+    fn pop_front_internal(&mut self) -> Option<NonNull<G::EntryType>> {
+        let head = self.head?;
+        // SAFETY: The head is on the list as we just got it from there and it cannot change.
+        unsafe { self.remove(head.as_ref()) };
+        Some(head)
+    }
+
+    pub(crate) fn pop_front(&mut self) -> Option<NonNull<G::EntryType>> {
+        self.pop_front_internal()
+    }
+
+    pub(crate) fn front(&self) -> Option<NonNull<G::EntryType>> {
+        self.head
+    }
+
+    pub(crate) fn back(&self) -> Option<NonNull<G::EntryType>> {
+        // SAFETY: The links of head are owned by the list, so it is safe to get a reference.
+        unsafe { &*G::get_links(self.head?.as_ref()).entry.get() }.prev
+    }
+
+    pub(crate) fn cursor_front(&self) -> Cursor<'_, G> {
+        Cursor::new(self, self.front())
+    }
+
+    pub(crate) fn cursor_front_mut(&mut self) -> CursorMut<'_, G> {
+        CursorMut::new(self, self.front())
+    }
+}
+
+struct CommonCursor<G: GetLinks> {
+    cur: Option<NonNull<G::EntryType>>,
+}
+
+impl<G: GetLinks> CommonCursor<G> {
+    fn new(cur: Option<NonNull<G::EntryType>>) -> Self {
+        Self { cur }
+    }
+
+    fn move_next(&mut self, list: &RawList<G>) {
+        match self.cur.take() {
+            None => self.cur = list.head,
+            Some(cur) => {
+                if let Some(head) = list.head {
+                    // SAFETY: We have a shared ref to the linked list, so the links can't change.
+                    let links = unsafe { &*G::get_links(cur.as_ref()).entry.get() };
+                    if links.next.unwrap() != head {
+                        self.cur = links.next;
+                    }
+                }
+            }
+        }
+    }
+
+    fn move_prev(&mut self, list: &RawList<G>) {
+        match list.head {
+            None => self.cur = None,
+            Some(head) => {
+                let next = match self.cur.take() {
+                    None => head,
+                    Some(cur) => {
+                        if cur == head {
+                            return;
+                        }
+                        cur
+                    }
+                };
+                // SAFETY: There's a shared ref to the list, so the links can't change.
+                let links = unsafe { &*G::get_links(next.as_ref()).entry.get() };
+                self.cur = links.prev;
+            }
+        }
+    }
+}
+
+/// A list cursor that allows traversing a linked list and inspecting elements.
+pub struct Cursor<'a, G: GetLinks> {
+    cursor: CommonCursor<G>,
+    list: &'a RawList<G>,
+}
+
+impl<'a, G: GetLinks> Cursor<'a, G> {
+    fn new(list: &'a RawList<G>, cur: Option<NonNull<G::EntryType>>) -> Self {
+        Self {
+            list,
+            cursor: CommonCursor::new(cur),
+        }
+    }
+
+    /// Returns the element the cursor is currently positioned on.
+    pub fn current(&self) -> Option<&'a G::EntryType> {
+        let cur = self.cursor.cur?;
+        // SAFETY: Objects must be kept alive while on the list.
+        Some(unsafe { &*cur.as_ptr() })
+    }
+
+    /// Moves the cursor to the next element.
+    pub fn move_next(&mut self) {
+        self.cursor.move_next(self.list);
+    }
+}
+
+pub(crate) struct CursorMut<'a, G: GetLinks> {
+    cursor: CommonCursor<G>,
+    list: &'a mut RawList<G>,
+}
+
+impl<'a, G: GetLinks> CursorMut<'a, G> {
+    fn new(list: &'a mut RawList<G>, cur: Option<NonNull<G::EntryType>>) -> Self {
+        Self {
+            list,
+            cursor: CommonCursor::new(cur),
+        }
+    }
+
+    pub(crate) fn current(&mut self) -> Option<&mut G::EntryType> {
+        let cur = self.cursor.cur?;
+        // SAFETY: Objects must be kept alive while on the list.
+        Some(unsafe { &mut *cur.as_ptr() })
+    }
+
+    /// Removes the entry the cursor is pointing to and advances the cursor to the next entry. It
+    /// returns a raw pointer to the removed element (if one is removed).
+    pub(crate) fn remove_current(&mut self) -> Option<NonNull<G::EntryType>> {
+        let entry = self.cursor.cur?;
+        self.cursor.move_next(self.list);
+        // SAFETY: The entry is on the list as we just got it from there and it cannot change.
+        unsafe { self.list.remove(entry.as_ref()) };
+        Some(entry)
+    }
+
+    pub(crate) fn peek_next(&mut self) -> Option<&mut G::EntryType> {
+        let mut new = CommonCursor::new(self.cursor.cur);
+        new.move_next(self.list);
+        // SAFETY: Objects must be kept alive while on the list.
+        Some(unsafe { &mut *new.cur?.as_ptr() })
+    }
+
+    pub(crate) fn peek_prev(&mut self) -> Option<&mut G::EntryType> {
+        let mut new = CommonCursor::new(self.cursor.cur);
+        new.move_prev(self.list);
+        // SAFETY: Objects must be kept alive while on the list.
+        Some(unsafe { &mut *new.cur?.as_ptr() })
+    }
+
+    pub(crate) fn move_next(&mut self) {
+        self.cursor.move_next(self.list);
+    }
+}
diff --git a/rust/kernel/rbtree.rs b/rust/kernel/rbtree.rs
new file mode 100644
index 000000000000..880252e9cde7
--- /dev/null
+++ b/rust/kernel/rbtree.rs
@@ -0,0 +1,562 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Red-black trees.
+//!
+//! C header: [`include/linux/rbtree.h`](../../../../include/linux/rbtree.h)
+//!
+//! Reference: <https://www.kernel.org/doc/html/latest/core-api/rbtree.html>
+
+use crate::{bindings, Result};
+use alloc::boxed::Box;
+use core::{
+    cmp::{Ord, Ordering},
+    iter::{IntoIterator, Iterator},
+    marker::PhantomData,
+    mem::MaybeUninit,
+    ptr::{addr_of_mut, NonNull},
+};
+
+struct Node<K, V> {
+    links: bindings::rb_node,
+    key: K,
+    value: V,
+}
+
+/// A red-black tree with owned nodes.
+///
+/// It is backed by the kernel C red-black trees.
+///
+/// # Invariants
+///
+/// Non-null parent/children pointers stored in instances of the `rb_node` C struct are always
+/// valid, and pointing to a field of our internal representation of a node.
+///
+/// # Examples
+///
+/// In the example below we do several operations on a tree. We note that insertions may fail if
+/// the system is out of memory.
+///
+/// ```
+/// # use kernel::prelude::*;
+/// use kernel::rbtree::RBTree;
+///
+/// fn rbtest() -> Result {
+///     // Create a new tree.
+///     let mut tree = RBTree::new();
+///
+///     // Insert three elements.
+///     tree.try_insert(20, 200)?;
+///     tree.try_insert(10, 100)?;
+///     tree.try_insert(30, 300)?;
+///
+///     // Check the nodes we just inserted.
+///     {
+///         let mut iter = tree.iter();
+///         assert_eq!(iter.next().unwrap(), (&10, &100));
+///         assert_eq!(iter.next().unwrap(), (&20, &200));
+///         assert_eq!(iter.next().unwrap(), (&30, &300));
+///         assert!(iter.next().is_none());
+///     }
+///
+///     // Print all elements.
+///     for (key, value) in &tree {
+///         pr_info!("{} = {}\n", key, value);
+///     }
+///
+///     // Replace one of the elements.
+///     tree.try_insert(10, 1000)?;
+///
+///     // Check that the tree reflects the replacement.
+///     {
+///         let mut iter = tree.iter();
+///         assert_eq!(iter.next().unwrap(), (&10, &1000));
+///         assert_eq!(iter.next().unwrap(), (&20, &200));
+///         assert_eq!(iter.next().unwrap(), (&30, &300));
+///         assert!(iter.next().is_none());
+///     }
+///
+///     // Change the value of one of the elements.
+///     *tree.get_mut(&30).unwrap() = 3000;
+///
+///     // Check that the tree reflects the update.
+///     {
+///         let mut iter = tree.iter();
+///         assert_eq!(iter.next().unwrap(), (&10, &1000));
+///         assert_eq!(iter.next().unwrap(), (&20, &200));
+///         assert_eq!(iter.next().unwrap(), (&30, &3000));
+///         assert!(iter.next().is_none());
+///     }
+///
+///     // Remove an element.
+///     tree.remove(&10);
+///
+///     // Check that the tree reflects the removal.
+///     {
+///         let mut iter = tree.iter();
+///         assert_eq!(iter.next().unwrap(), (&20, &200));
+///         assert_eq!(iter.next().unwrap(), (&30, &3000));
+///         assert!(iter.next().is_none());
+///     }
+///
+///     // Update all values.
+///     for value in tree.values_mut() {
+///         *value *= 10;
+///     }
+///
+///     // Check that the tree reflects the changes to values.
+///     {
+///         let mut iter = tree.iter();
+///         assert_eq!(iter.next().unwrap(), (&20, &2000));
+///         assert_eq!(iter.next().unwrap(), (&30, &30000));
+///         assert!(iter.next().is_none());
+///     }
+///
+///     Ok(())
+/// }
+/// ```
+///
+/// In the example below, we first allocate a node, acquire a spinlock, then insert the node into
+/// the tree. This is useful when the insertion context does not allow sleeping, for example, when
+/// holding a spinlock.
+///
+/// ```
+/// # use kernel::prelude::*;
+/// use kernel::{rbtree::RBTree, sync::SpinLock};
+///
+/// fn insert_test(tree: &SpinLock<RBTree<u32, u32>>) -> Result {
+///     // Pre-allocate node. This may fail (as it allocates memory).
+///     let node = RBTree::try_allocate_node(10, 100)?;
+///
+///     // Insert node while holding the lock. It is guaranteed to succeed with no allocation
+///     // attempts.
+///     let mut guard = tree.lock();
+///     guard.insert(node);
+///     Ok(())
+/// }
+/// ```
+///
+/// In the example below, we reuse an existing node allocation from an element we removed.
+///
+/// ```
+/// # use kernel::prelude::*;
+/// use kernel::rbtree::RBTree;
+///
+/// fn reuse_test() -> Result {
+///     // Create a new tree.
+///     let mut tree = RBTree::new();
+///
+///     // Insert three elements.
+///     tree.try_insert(20, 200)?;
+///     tree.try_insert(10, 100)?;
+///     tree.try_insert(30, 300)?;
+///
+///     // Check the nodes we just inserted.
+///     {
+///         let mut iter = tree.iter();
+///         assert_eq!(iter.next().unwrap(), (&10, &100));
+///         assert_eq!(iter.next().unwrap(), (&20, &200));
+///         assert_eq!(iter.next().unwrap(), (&30, &300));
+///         assert!(iter.next().is_none());
+///     }
+///
+///     // Remove a node, getting back ownership of it.
+///     let existing = tree.remove_node(&30).unwrap();
+///
+///     // Check that the tree reflects the removal.
+///     {
+///         let mut iter = tree.iter();
+///         assert_eq!(iter.next().unwrap(), (&10, &100));
+///         assert_eq!(iter.next().unwrap(), (&20, &200));
+///         assert!(iter.next().is_none());
+///     }
+///
+///     // Turn the node into a reservation so that we can reuse it with a different key/value.
+///     let reservation = existing.into_reservation();
+///
+///     // Insert a new node into the tree, reusing the previous allocation. This is guaranteed to
+///     // succeed (no memory allocations).
+///     tree.insert(reservation.into_node(15, 150));
+///
+///     // Check that the tree reflect the new insertion.
+///     {
+///         let mut iter = tree.iter();
+///         assert_eq!(iter.next().unwrap(), (&10, &100));
+///         assert_eq!(iter.next().unwrap(), (&15, &150));
+///         assert_eq!(iter.next().unwrap(), (&20, &200));
+///         assert!(iter.next().is_none());
+///     }
+///
+///     Ok(())
+/// }
+/// ```
+pub struct RBTree<K, V> {
+    root: bindings::rb_root,
+    _p: PhantomData<Node<K, V>>,
+}
+
+impl<K, V> RBTree<K, V> {
+    /// Creates a new and empty tree.
+    pub fn new() -> Self {
+        Self {
+            // INVARIANT: There are no nodes in the tree, so the invariant holds vacuously.
+            root: bindings::rb_root::default(),
+            _p: PhantomData,
+        }
+    }
+
+    /// Tries to insert a new value into the tree.
+    ///
+    /// It overwrites a node if one already exists with the same key and returns it (containing the
+    /// key/value pair). Returns [`None`] if a node with the same key didn't already exist.
+    ///
+    /// Returns an error if it cannot allocate memory for the new node.
+    pub fn try_insert(&mut self, key: K, value: V) -> Result<Option<RBTreeNode<K, V>>>
+    where
+        K: Ord,
+    {
+        Ok(self.insert(Self::try_allocate_node(key, value)?))
+    }
+
+    /// Allocates memory for a node to be eventually initialised and inserted into the tree via a
+    /// call to [`RBTree::insert`].
+    pub fn try_reserve_node() -> Result<RBTreeNodeReservation<K, V>> {
+        Ok(RBTreeNodeReservation {
+            node: Box::try_new(MaybeUninit::uninit())?,
+        })
+    }
+
+    /// Allocates and initialiases a node that can be inserted into the tree via
+    /// [`RBTree::insert`].
+    pub fn try_allocate_node(key: K, value: V) -> Result<RBTreeNode<K, V>> {
+        Ok(Self::try_reserve_node()?.into_node(key, value))
+    }
+
+    /// Inserts a new node into the tree.
+    ///
+    /// It overwrites a node if one already exists with the same key and returns it (containing the
+    /// key/value pair). Returns [`None`] if a node with the same key didn't already exist.
+    ///
+    /// This function always succeeds.
+    pub fn insert(&mut self, node: RBTreeNode<K, V>) -> Option<RBTreeNode<K, V>>
+    where
+        K: Ord,
+    {
+        let RBTreeNode { node } = node;
+        let node = Box::into_raw(node);
+        // SAFETY: `node` is valid at least until we call `Box::from_raw`, which only happens when
+        // the node is removed or replaced.
+        let node_links = unsafe { addr_of_mut!((*node).links) };
+        let mut new_link: &mut *mut bindings::rb_node = &mut self.root.rb_node;
+        let mut parent = core::ptr::null_mut();
+        while !new_link.is_null() {
+            let this = crate::container_of!(*new_link, Node<K, V>, links);
+
+            parent = *new_link;
+
+            // SAFETY: `this` is a non-null node so it is valid by the type invariants. `node` is
+            // valid until the node is removed.
+            match unsafe { (*node).key.cmp(&(*this).key) } {
+                // SAFETY: `parent` is a non-null node so it is valid by the type invariants.
+                Ordering::Less => new_link = unsafe { &mut (*parent).rb_left },
+                // SAFETY: `parent` is a non-null node so it is valid by the type invariants.
+                Ordering::Greater => new_link = unsafe { &mut (*parent).rb_right },
+                Ordering::Equal => {
+                    // INVARIANT: We are replacing an existing node with a new one, which is valid.
+                    // It remains valid because we "forgot" it with `Box::into_raw`.
+                    // SAFETY: All pointers are non-null and valid (parent, despite the name, really
+                    // is the node we're replacing).
+                    unsafe { bindings::rb_replace_node(parent, node_links, &mut self.root) };
+
+                    // INVARIANT: The node is being returned and the caller may free it, however,
+                    // it was removed from the tree. So the invariants still hold.
+                    return Some(RBTreeNode {
+                        // SAFETY: `this` was a node in the tree, so it is valid.
+                        node: unsafe { Box::from_raw(this as _) },
+                    });
+                }
+            }
+        }
+
+        // INVARIANT: We are linking in a new node, which is valid. It remains valid because we
+        // "forgot" it with `Box::into_raw`.
+        // SAFETY: All pointers are non-null and valid (`*new_link` is null, but `new_link` is a
+        // mutable reference).
+        unsafe { bindings::rb_link_node(node_links, parent, new_link) };
+
+        // SAFETY: All pointers are valid. `node` has just been inserted into the tree.
+        unsafe { bindings::rb_insert_color(node_links, &mut self.root) };
+        None
+    }
+
+    /// Returns a node with the given key, if one exists.
+    fn find(&self, key: &K) -> Option<NonNull<Node<K, V>>>
+    where
+        K: Ord,
+    {
+        let mut node = self.root.rb_node;
+        while !node.is_null() {
+            let this = crate::container_of!(node, Node<K, V>, links);
+            // SAFETY: `this` is a non-null node so it is valid by the type invariants.
+            node = match key.cmp(unsafe { &(*this).key }) {
+                // SAFETY: `node` is a non-null node so it is valid by the type invariants.
+                Ordering::Less => unsafe { (*node).rb_left },
+                // SAFETY: `node` is a non-null node so it is valid by the type invariants.
+                Ordering::Greater => unsafe { (*node).rb_right },
+                Ordering::Equal => return NonNull::new(this as _),
+            }
+        }
+        None
+    }
+
+    /// Returns a reference to the value corresponding to the key.
+    pub fn get(&self, key: &K) -> Option<&V>
+    where
+        K: Ord,
+    {
+        // SAFETY: The `find` return value is a node in the tree, so it is valid.
+        self.find(key).map(|node| unsafe { &node.as_ref().value })
+    }
+
+    /// Returns a mutable reference to the value corresponding to the key.
+    pub fn get_mut(&mut self, key: &K) -> Option<&mut V>
+    where
+        K: Ord,
+    {
+        // SAFETY: the `find` return value is a node in the tree, so it is valid.
+        self.find(key)
+            .map(|mut node| unsafe { &mut node.as_mut().value })
+    }
+
+    /// Removes the node with the given key from the tree.
+    ///
+    /// It returns the node that was removed if one exists, or [`None`] otherwise.
+    pub fn remove_node(&mut self, key: &K) -> Option<RBTreeNode<K, V>>
+    where
+        K: Ord,
+    {
+        let mut node = self.find(key)?;
+
+        // SAFETY: the `find` return value is a node in the tree, so it is valid.
+        unsafe { bindings::rb_erase(&mut node.as_mut().links, &mut self.root) };
+
+        // INVARIANT: The node is being returned and the caller may free it, however, it was
+        // removed from the tree. So the invariants still hold.
+        Some(RBTreeNode {
+            // SAFETY: the `find` return value was a node in the tree, so it is valid.
+            node: unsafe { Box::from_raw(node.as_ptr()) },
+        })
+    }
+
+    /// Removes the node with the given key from the tree.
+    ///
+    /// It returns the value that was removed if one exists, or [`None`] otherwise.
+    pub fn remove(&mut self, key: &K) -> Option<V>
+    where
+        K: Ord,
+    {
+        let node = self.remove_node(key)?;
+        let RBTreeNode { node } = node;
+        let Node {
+            links: _,
+            key: _,
+            value,
+        } = *node;
+        Some(value)
+    }
+
+    /// Returns an iterator over the tree nodes, sorted by key.
+    pub fn iter(&self) -> RBTreeIterator<'_, K, V> {
+        RBTreeIterator {
+            _tree: PhantomData,
+            // SAFETY: `root` is valid as it's embedded in `self` and we have a valid `self`.
+            next: unsafe { bindings::rb_first(&self.root) },
+        }
+    }
+
+    /// Returns a mutable iterator over the tree nodes, sorted by key.
+    pub fn iter_mut(&mut self) -> RBTreeIteratorMut<'_, K, V> {
+        RBTreeIteratorMut {
+            _tree: PhantomData,
+            // SAFETY: `root` is valid as it's embedded in `self` and we have a valid `self`.
+            next: unsafe { bindings::rb_first(&self.root) },
+        }
+    }
+
+    /// Returns an iterator over the keys of the nodes in the tree, in sorted order.
+    pub fn keys(&self) -> impl Iterator<Item = &'_ K> {
+        self.iter().map(|(k, _)| k)
+    }
+
+    /// Returns an iterator over the values of the nodes in the tree, sorted by key.
+    pub fn values(&self) -> impl Iterator<Item = &'_ V> {
+        self.iter().map(|(_, v)| v)
+    }
+
+    /// Returns a mutable iterator over the values of the nodes in the tree, sorted by key.
+    pub fn values_mut(&mut self) -> impl Iterator<Item = &'_ mut V> {
+        self.iter_mut().map(|(_, v)| v)
+    }
+}
+
+impl<K, V> Default for RBTree<K, V> {
+    fn default() -> Self {
+        Self::new()
+    }
+}
+
+impl<K, V> Drop for RBTree<K, V> {
+    fn drop(&mut self) {
+        // SAFETY: `root` is valid as it's embedded in `self` and we have a valid `self`.
+        let mut next = unsafe { bindings::rb_first_postorder(&self.root) };
+
+        // INVARIANT: The loop invariant is that all tree nodes from `next` in postorder are valid.
+        while !next.is_null() {
+            let this = crate::container_of!(next, Node<K, V>, links);
+
+            // Find out what the next node is before disposing of the current one.
+            // SAFETY: `next` and all nodes in postorder are still valid.
+            next = unsafe { bindings::rb_next_postorder(next) };
+
+            // INVARIANT: This is the destructor, so we break the type invariant during clean-up,
+            // but it is not observable. The loop invariant is still maintained.
+            // SAFETY: `this` is valid per the loop invariant.
+            unsafe { Box::from_raw(this as *mut Node<K, V>) };
+        }
+    }
+}
+
+impl<'a, K, V> IntoIterator for &'a RBTree<K, V> {
+    type Item = (&'a K, &'a V);
+    type IntoIter = RBTreeIterator<'a, K, V>;
+
+    fn into_iter(self) -> Self::IntoIter {
+        self.iter()
+    }
+}
+
+/// An iterator over the nodes of a [`RBTree`].
+///
+/// Instances are created by calling [`RBTree::iter`].
+pub struct RBTreeIterator<'a, K, V> {
+    _tree: PhantomData<&'a RBTree<K, V>>,
+    next: *mut bindings::rb_node,
+}
+
+impl<'a, K, V> Iterator for RBTreeIterator<'a, K, V> {
+    type Item = (&'a K, &'a V);
+
+    fn next(&mut self) -> Option<Self::Item> {
+        if self.next.is_null() {
+            return None;
+        }
+
+        let cur = crate::container_of!(self.next, Node<K, V>, links);
+
+        // SAFETY: The reference to the tree used to create the iterator outlives the iterator, so
+        // the tree cannot change. By the tree invariant, all nodes are valid.
+        self.next = unsafe { bindings::rb_next(self.next) };
+
+        // SAFETY: By the same reasoning above, it is safe to dereference the node. Additionally,
+        // it is ok to return a reference to members because the iterator must outlive it.
+        Some(unsafe { (&(*cur).key, &(*cur).value) })
+    }
+}
+
+impl<'a, K, V> IntoIterator for &'a mut RBTree<K, V> {
+    type Item = (&'a K, &'a mut V);
+    type IntoIter = RBTreeIteratorMut<'a, K, V>;
+
+    fn into_iter(self) -> Self::IntoIter {
+        self.iter_mut()
+    }
+}
+
+/// A mutable iterator over the nodes of a [`RBTree`].
+///
+/// Instances are created by calling [`RBTree::iter_mut`].
+pub struct RBTreeIteratorMut<'a, K, V> {
+    _tree: PhantomData<&'a RBTree<K, V>>,
+    next: *mut bindings::rb_node,
+}
+
+impl<'a, K, V> Iterator for RBTreeIteratorMut<'a, K, V> {
+    type Item = (&'a K, &'a mut V);
+
+    fn next(&mut self) -> Option<Self::Item> {
+        if self.next.is_null() {
+            return None;
+        }
+
+        let cur = crate::container_of!(self.next, Node<K, V>, links) as *mut Node<K, V>;
+
+        // SAFETY: The reference to the tree used to create the iterator outlives the iterator, so
+        // the tree cannot change (except for the value of previous nodes, but those don't affect
+        // the iteration process). By the tree invariant, all nodes are valid.
+        self.next = unsafe { bindings::rb_next(self.next) };
+
+        // SAFETY: By the same reasoning above, it is safe to dereference the node. Additionally,
+        // it is ok to return a reference to members because the iterator must outlive it.
+        Some(unsafe { (&(*cur).key, &mut (*cur).value) })
+    }
+}
+
+/// A memory reservation for a red-black tree node.
+///
+/// It contains the memory needed to hold a node that can be inserted into a red-black tree. One
+/// can be obtained by directly allocating it ([`RBTree::try_reserve_node`]) or by "uninitialising"
+/// ([`RBTreeNode::into_reservation`]) an actual node (usually returned by some operation like
+/// removal from a tree).
+pub struct RBTreeNodeReservation<K, V> {
+    node: Box<MaybeUninit<Node<K, V>>>,
+}
+
+impl<K, V> RBTreeNodeReservation<K, V> {
+    /// Initialises a node reservation.
+    ///
+    /// It then becomes an [`RBTreeNode`] that can be inserted into a tree.
+    pub fn into_node(mut self, key: K, value: V) -> RBTreeNode<K, V> {
+        let node_ptr = self.node.as_mut_ptr();
+        // SAFETY: `node_ptr` is valid, and so are its fields.
+        unsafe { addr_of_mut!((*node_ptr).links).write(bindings::rb_node::default()) };
+        // SAFETY: `node_ptr` is valid, and so are its fields.
+        unsafe { addr_of_mut!((*node_ptr).key).write(key) };
+        // SAFETY: `node_ptr` is valid, and so are its fields.
+        unsafe { addr_of_mut!((*node_ptr).value).write(value) };
+        let raw = Box::into_raw(self.node);
+        RBTreeNode {
+            // SAFETY: The pointer came from a `MaybeUninit<Node>` whose fields have all been
+            // initialised. Additionally, it has the same layout as `Node`.
+            node: unsafe { Box::from_raw(raw as _) },
+        }
+    }
+}
+
+/// A red-black tree node.
+///
+/// The node is fully initialised (with key and value) and can be inserted into a tree without any
+/// extra allocations or failure paths.
+pub struct RBTreeNode<K, V> {
+    node: Box<Node<K, V>>,
+}
+
+impl<K, V> RBTreeNode<K, V> {
+    /// "Uninitialises" a node.
+    ///
+    /// It then becomes a reservation that can be re-initialised into a different node (i.e., with
+    /// a different key and/or value).
+    ///
+    /// The existing key and value are dropped in-place as part of this operation, that is, memory
+    /// may be freed (but only for the key/value; memory for the node itself is kept for reuse).
+    pub fn into_reservation(self) -> RBTreeNodeReservation<K, V> {
+        let raw = Box::into_raw(self.node);
+        let mut ret = RBTreeNodeReservation {
+            // SAFETY: The pointer came from a valid `Node`, which has the same layout as
+            // `MaybeUninit<Node>`.
+            node: unsafe { Box::from_raw(raw as _) },
+        };
+        // SAFETY: Although the type is `MaybeUninit<Node>`, we know it has been initialised
+        // because it came from a `Node`. So it is safe to drop it.
+        unsafe { core::ptr::drop_in_place(ret.node.as_mut_ptr()) };
+        ret
+    }
+}
diff --git a/rust/kernel/revocable.rs b/rust/kernel/revocable.rs
new file mode 100644
index 000000000000..9cc65ca3a1b6
--- /dev/null
+++ b/rust/kernel/revocable.rs
@@ -0,0 +1,163 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Revocable objects.
+//!
+//! The [`Revocable`] type wraps other types and allows access to them to be revoked. The existence
+//! of a [`RevocableGuard`] ensures that objects remain valid.
+
+use crate::bindings;
+use core::{
+    cell::UnsafeCell,
+    marker::PhantomData,
+    mem::ManuallyDrop,
+    ops::Deref,
+    ptr::drop_in_place,
+    sync::atomic::{AtomicBool, Ordering},
+};
+
+/// An object that can become inaccessible at runtime.
+///
+/// Once access is revoked and all concurrent users complete (i.e., all existing instances of
+/// [`RevocableGuard`] are dropped), the wrapped object is also dropped.
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::revocable::Revocable;
+///
+/// struct Example {
+///     a: u32,
+///     b: u32,
+/// }
+///
+/// fn add_two(v: &Revocable<Example>) -> Option<u32> {
+///     let guard = v.try_access()?;
+///     Some(guard.a + guard.b)
+/// }
+///
+/// fn example() {
+///     let v = Revocable::new(Example { a: 10, b: 20 });
+///     assert_eq!(add_two(&v), Some(30));
+///     v.revoke();
+///     assert_eq!(add_two(&v), None);
+/// }
+/// ```
+pub struct Revocable<T: ?Sized> {
+    is_available: AtomicBool,
+    data: ManuallyDrop<UnsafeCell<T>>,
+}
+
+// SAFETY: `Revocable` is `Send` if the wrapped object is also `Send`. This is because while the
+// functionality exposed by `Revocable` can be accessed from any thread/CPU, it is possible that
+// this isn't supported by the wrapped object.
+unsafe impl<T: ?Sized + Send> Send for Revocable<T> {}
+
+// SAFETY: `Revocable` is `Sync` if the wrapped object is both `Send` and `Sync`. We require `Send`
+// from the wrapped object as well because  of `Revocable::revoke`, which can trigger the `Drop`
+// implementation of the wrapped object from an arbitrary thread.
+unsafe impl<T: ?Sized + Sync + Send> Sync for Revocable<T> {}
+
+impl<T> Revocable<T> {
+    /// Creates a new revocable instance of the given data.
+    pub fn new(data: T) -> Self {
+        Self {
+            is_available: AtomicBool::new(true),
+            data: ManuallyDrop::new(UnsafeCell::new(data)),
+        }
+    }
+}
+
+impl<T: ?Sized> Revocable<T> {
+    /// Tries to access the \[revocable\] wrapped object.
+    ///
+    /// Returns `None` if the object has been revoked and is therefore no longer accessible.
+    ///
+    /// Returns a guard that gives access to the object otherwise; the object is guaranteed to
+    /// remain accessible while the guard is alive. In such cases, callers are not allowed to sleep
+    /// because another CPU may be waiting to complete the revocation of this object.
+    pub fn try_access(&self) -> Option<RevocableGuard<'_, T>> {
+        let guard = RevocableGuard::new(self.data.get());
+        if self.is_available.load(Ordering::Relaxed) {
+            Some(guard)
+        } else {
+            None
+        }
+    }
+
+    /// Revokes access to and drops the wrapped object.
+    ///
+    /// Access to the object is revoked immediately to new callers of [`Revocable::try_access`]. If
+    /// there are concurrent users of the object (i.e., ones that called [`Revocable::try_access`]
+    /// beforehand and still haven't dropped the returned guard), this function waits for the
+    /// concurrent access to complete before dropping the wrapped object.
+    pub fn revoke(&self) {
+        if self
+            .is_available
+            .compare_exchange(true, false, Ordering::Relaxed, Ordering::Relaxed)
+            .is_ok()
+        {
+            // SAFETY: Just an FFI call, there are no further requirements.
+            unsafe { bindings::synchronize_rcu() };
+
+            // SAFETY: We know `self.data` is valid because only one CPU can succeed the
+            // `compare_exchange` above that takes `is_available` from `true` to `false`.
+            unsafe { drop_in_place(self.data.get()) };
+        }
+    }
+}
+
+impl<T: ?Sized> Drop for Revocable<T> {
+    fn drop(&mut self) {
+        // Drop only if the data hasn't been revoked yet (in which case it has already been
+        // dropped).
+        if *self.is_available.get_mut() {
+            // SAFETY: We know `self.data` is valid because no other CPU has changed
+            // `is_available` to `false` yet, and no other CPU can do it anymore because this CPU
+            // holds the only reference (mutable) to `self` now.
+            unsafe { drop_in_place(self.data.get()) };
+        }
+    }
+}
+
+/// A guard that allows access to a revocable object and keeps it alive.
+///
+/// CPUs may not sleep while holding on to [`RevocableGuard`] because it's in atomic context
+/// holding the RCU read-side lock.
+///
+/// # Invariants
+///
+/// The RCU read-side lock is held while the guard is alive.
+pub struct RevocableGuard<'a, T: ?Sized> {
+    data_ref: *const T,
+    _p: PhantomData<&'a ()>,
+}
+
+impl<T: ?Sized> RevocableGuard<'_, T> {
+    fn new(data_ref: *const T) -> Self {
+        // SAFETY: Just an FFI call, there are no further requirements.
+        unsafe { bindings::rcu_read_lock() };
+
+        // INVARIANTS: The RCU read-side lock was just acquired.
+        Self {
+            data_ref,
+            _p: PhantomData,
+        }
+    }
+}
+
+impl<T: ?Sized> Drop for RevocableGuard<'_, T> {
+    fn drop(&mut self) {
+        // SAFETY: By the type invariants, we know that we hold the RCU read-side lock.
+        unsafe { bindings::rcu_read_unlock() };
+    }
+}
+
+impl<T: ?Sized> Deref for RevocableGuard<'_, T> {
+    type Target = T;
+
+    fn deref(&self) -> &Self::Target {
+        // SAFETY: By the type invariants, we hold the rcu read-side lock, so the object is
+        // guaranteed to remain valid.
+        unsafe { &*self.data_ref }
+    }
+}
diff --git a/rust/kernel/security.rs b/rust/kernel/security.rs
new file mode 100644
index 000000000000..2004d01233f4
--- /dev/null
+++ b/rust/kernel/security.rs
@@ -0,0 +1,36 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Linux Security Modules (LSM).
+//!
+//! C header: [`include/linux/security.h`](../../../../include/linux/security.h).
+
+use crate::{bindings, cred::Credential, file::File, to_result, Result};
+
+/// Calls the security modules to determine if the given task can become the manager of a binder
+/// context.
+pub fn binder_set_context_mgr(mgr: &Credential) -> Result {
+    // SAFETY: By the `Credential` invariants, `mgr.ptr` is valid.
+    to_result(|| unsafe { bindings::security_binder_set_context_mgr(mgr.ptr) })
+}
+
+/// Calls the security modules to determine if binder transactions are allowed from task `from` to
+/// task `to`.
+pub fn binder_transaction(from: &Credential, to: &Credential) -> Result {
+    // SAFETY: By the `Credential` invariants, `from.ptr` and `to.ptr` are valid.
+    to_result(|| unsafe { bindings::security_binder_transaction(from.ptr, to.ptr) })
+}
+
+/// Calls the security modules to determine if task `from` is allowed to send binder objects
+/// (owned by itself or other processes) to task `to` through a binder transaction.
+pub fn binder_transfer_binder(from: &Credential, to: &Credential) -> Result {
+    // SAFETY: By the `Credential` invariants, `from.ptr` and `to.ptr` are valid.
+    to_result(|| unsafe { bindings::security_binder_transfer_binder(from.ptr, to.ptr) })
+}
+
+/// Calls the security modules to determine if task `from` is allowed to send the given file to
+/// task `to` (which would get its own file descriptor) through a binder transaction.
+pub fn binder_transfer_file(from: &Credential, to: &Credential, file: &File) -> Result {
+    // SAFETY: By the `Credential` invariants, `from.ptr` and `to.ptr` are valid. Similarly, by the
+    // `File` invariants, `file.ptr` is also valid.
+    to_result(|| unsafe { bindings::security_binder_transfer_file(from.ptr, to.ptr, file.ptr) })
+}
diff --git a/rust/kernel/static_assert.rs b/rust/kernel/static_assert.rs
new file mode 100644
index 000000000000..a80d8ab57564
--- /dev/null
+++ b/rust/kernel/static_assert.rs
@@ -0,0 +1,39 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Static assert.
+
+/// Static assert (i.e. compile-time assert).
+///
+/// Similar to C11 [`_Static_assert`] and C++11 [`static_assert`].
+///
+/// The feature may be added to Rust in the future: see [RFC 2790].
+///
+/// [`_Static_assert`]: https://en.cppreference.com/w/c/language/_Static_assert
+/// [`static_assert`]: https://en.cppreference.com/w/cpp/language/static_assert
+/// [RFC 2790]: https://github.com/rust-lang/rfcs/issues/2790
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::prelude::*;
+/// static_assert!(42 > 24);
+/// static_assert!(core::mem::size_of::<u8>() == 1);
+///
+/// const X: &[u8] = b"bar";
+/// static_assert!(X[1] == 'a' as u8);
+///
+/// const fn f(x: i32) -> i32 {
+///     x + 2
+/// }
+/// static_assert!(f(40) == 42);
+/// ```
+#[macro_export]
+macro_rules! static_assert {
+    ($condition:expr) => {
+        // Based on the latest one in `rustc`'s one before it was [removed].
+        //
+        // [removed]: https://github.com/rust-lang/rust/commit/c2dad1c6b9f9636198d7c561b47a2974f5103f6d
+        #[allow(dead_code)]
+        const _: () = [()][!($condition) as usize];
+    };
+}
diff --git a/rust/kernel/std_vendor.rs b/rust/kernel/std_vendor.rs
new file mode 100644
index 000000000000..492388d7ce10
--- /dev/null
+++ b/rust/kernel/std_vendor.rs
@@ -0,0 +1,150 @@
+// SPDX-License-Identifier: Apache-2.0 OR MIT
+
+//! The contents of this file come from the Rust standard library, hosted in the
+//! <https://github.com/rust-lang/rust> repository. For copyright details, see
+//! <https://github.com/rust-lang/rust/blob/master/COPYRIGHT>.
+
+/// [`std::dbg`], but using [`pr_info`] instead of [`eprintln`].
+///
+/// Prints and returns the value of a given expression for quick and dirty
+/// debugging.
+///
+/// An example:
+///
+/// ```rust
+/// let a = 2;
+/// let b = dbg!(a * 2) + 1;
+/// //      ^-- prints: [src/main.rs:2] a * 2 = 4
+/// assert_eq!(b, 5);
+/// ```
+///
+/// The macro works by using the `Debug` implementation of the type of
+/// the given expression to print the value with [`printk`] along with the
+/// source location of the macro invocation as well as the source code
+/// of the expression.
+///
+/// Invoking the macro on an expression moves and takes ownership of it
+/// before returning the evaluated expression unchanged. If the type
+/// of the expression does not implement `Copy` and you don't want
+/// to give up ownership, you can instead borrow with `dbg!(&expr)`
+/// for some expression `expr`.
+///
+/// The `dbg!` macro works exactly the same in release builds.
+/// This is useful when debugging issues that only occur in release
+/// builds or when debugging in release mode is significantly faster.
+///
+/// Note that the macro is intended as a debugging tool and therefore you
+/// should avoid having uses of it in version control for long periods
+/// (other than in tests and similar).
+///
+/// # Stability
+///
+/// The exact output printed by this macro should not be relied upon
+/// and is subject to future changes.
+///
+/// # Further examples
+///
+/// With a method call:
+///
+/// ```rust
+/// fn foo(n: usize) {
+///     if let Some(_) = dbg!(n.checked_sub(4)) {
+///         // ...
+///     }
+/// }
+///
+/// foo(3)
+/// ```
+///
+/// This prints to the kernel log:
+///
+/// ```text,ignore
+/// [src/main.rs:4] n.checked_sub(4) = None
+/// ```
+///
+/// Naive factorial implementation:
+///
+/// ```rust
+/// fn factorial(n: u32) -> u32 {
+///     if dbg!(n <= 1) {
+///         dbg!(1)
+///     } else {
+///         dbg!(n * factorial(n - 1))
+///     }
+/// }
+///
+/// dbg!(factorial(4));
+/// ```
+///
+/// This prints to the kernel log:
+///
+/// ```text,ignore
+/// [src/main.rs:3] n <= 1 = false
+/// [src/main.rs:3] n <= 1 = false
+/// [src/main.rs:3] n <= 1 = false
+/// [src/main.rs:3] n <= 1 = true
+/// [src/main.rs:4] 1 = 1
+/// [src/main.rs:5] n * factorial(n - 1) = 2
+/// [src/main.rs:5] n * factorial(n - 1) = 6
+/// [src/main.rs:5] n * factorial(n - 1) = 24
+/// [src/main.rs:11] factorial(4) = 24
+/// ```
+///
+/// The `dbg!(..)` macro moves the input:
+///
+/// ```compile_fail
+/// /// A wrapper around `usize` which importantly is not Copyable.
+/// #[derive(Debug)]
+/// struct NoCopy(usize);
+///
+/// let a = NoCopy(42);
+/// let _ = dbg!(a); // <-- `a` is moved here.
+/// let _ = dbg!(a); // <-- `a` is moved again; error!
+/// ```
+///
+/// You can also use `dbg!()` without a value to just print the
+/// file and line whenever it's reached.
+///
+/// Finally, if you want to `dbg!(..)` multiple values, it will treat them as
+/// a tuple (and return it, too):
+///
+/// ```
+/// assert_eq!(dbg!(1usize, 2u32), (1, 2));
+/// ```
+///
+/// However, a single argument with a trailing comma will still not be treated
+/// as a tuple, following the convention of ignoring trailing commas in macro
+/// invocations. You can use a 1-tuple directly if you need one:
+///
+/// ```
+/// assert_eq!(1, dbg!(1u32,)); // trailing comma ignored
+/// assert_eq!((1,), dbg!((1u32,))); // 1-tuple
+/// ```
+///
+/// [`std::dbg`]: https://doc.rust-lang.org/std/macro.dbg.html
+/// [`eprintln`]: https://doc.rust-lang.org/std/macro.eprintln.html
+/// [`printk`]: https://www.kernel.org/doc/html/latest/core-api/printk-basics.html
+#[macro_export]
+macro_rules! dbg {
+    // NOTE: We cannot use `concat!` to make a static string as a format argument
+    // of `pr_info!` because `file!` could contain a `{` or
+    // `$val` expression could be a block (`{ .. }`), in which case the `pr_info!`
+    // will be malformed.
+    () => {
+        $crate::pr_info!("[{}:{}]\n", ::core::file!(), ::core::line!())
+    };
+    ($val:expr $(,)?) => {
+        // Use of `match` here is intentional because it affects the lifetimes
+        // of temporaries - https://stackoverflow.com/a/48732525/1063961
+        match $val {
+            tmp => {
+                $crate::pr_info!("[{}:{}] {} = {:#?}\n",
+                    ::core::file!(), ::core::line!(), ::core::stringify!($val), &tmp);
+                tmp
+            }
+        }
+    };
+    ($($val:expr),+ $(,)?) => {
+        ($($crate::dbg!($val)),+,)
+    };
+}
diff --git a/rust/kernel/str.rs b/rust/kernel/str.rs
new file mode 100644
index 000000000000..840099f384b3
--- /dev/null
+++ b/rust/kernel/str.rs
@@ -0,0 +1,375 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! String representations.
+
+use core::fmt::{self, Write};
+use core::ops::{self, Deref, Index};
+
+use crate::bindings;
+use crate::c_types;
+
+/// Byte string without UTF-8 validity guarantee.
+///
+/// `BStr` is simply an alias to `[u8]`, but has a more evident semantical meaning.
+pub type BStr = [u8];
+
+/// Creates a new [`BStr`] from a string literal.
+///
+/// `b_str!` converts the supplied string literal to byte string, so non-ASCII
+/// characters can be included.
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::b_str;
+/// # use kernel::str::BStr;
+/// const MY_BSTR: &'static BStr = b_str!("My awesome BStr!");
+/// ```
+#[macro_export]
+macro_rules! b_str {
+    ($str:literal) => {{
+        const S: &'static str = $str;
+        const C: &'static $crate::str::BStr = S.as_bytes();
+        C
+    }};
+}
+
+/// Possible errors when using conversion functions in [`CStr`].
+#[derive(Debug, Clone, Copy)]
+pub enum CStrConvertError {
+    /// Supplied bytes contain an interior `NUL`.
+    InteriorNul,
+
+    /// Supplied bytes are not terminated by `NUL`.
+    NotNulTerminated,
+}
+
+impl From<CStrConvertError> for crate::Error {
+    #[inline]
+    fn from(_: CStrConvertError) -> crate::Error {
+        crate::Error::EINVAL
+    }
+}
+
+/// A string that is guaranteed to have exactly one `NUL` byte, which is at the
+/// end.
+///
+/// Used for interoperability with kernel APIs that take C strings.
+#[repr(transparent)]
+pub struct CStr([u8]);
+
+impl CStr {
+    /// Returns the length of this string excluding `NUL`.
+    #[inline]
+    pub const fn len(&self) -> usize {
+        self.len_with_nul() - 1
+    }
+
+    /// Returns the length of this string with `NUL`.
+    #[inline]
+    pub const fn len_with_nul(&self) -> usize {
+        // SAFETY: This is one of the invariant of `CStr`.
+        // We add a `unreachable_unchecked` here to hint the optimizer that
+        // the value returned from this function is non-zero.
+        if self.0.is_empty() {
+            unsafe { core::hint::unreachable_unchecked() };
+        }
+        self.0.len()
+    }
+
+    /// Returns `true` if the string only includes `NUL`.
+    #[inline]
+    pub const fn is_empty(&self) -> bool {
+        self.len() == 0
+    }
+
+    /// Wraps a raw C string pointer.
+    ///
+    /// # Safety
+    ///
+    /// `ptr` must be a valid pointer to a `NUL`-terminated C string, and it must
+    /// last at least `'a`. When `CStr` is alive, the memory pointed by `ptr`
+    /// must not be mutated.
+    #[inline]
+    pub unsafe fn from_char_ptr<'a>(ptr: *const c_types::c_char) -> &'a Self {
+        // SAFETY: The safety precondition guarantees `ptr` is a valid pointer
+        // to a `NUL`-terminated C string.
+        let len = unsafe { bindings::strlen(ptr) } + 1;
+        // SAFETY: Lifetime guaranteed by the safety precondition.
+        let bytes = unsafe { core::slice::from_raw_parts(ptr as _, len as _) };
+        // SAFETY: As `len` is returned by `strlen`, `bytes` does not contain interior `NUL`.
+        // As we have added 1 to `len`, the last byte is known to be `NUL`.
+        unsafe { Self::from_bytes_with_nul_unchecked(bytes) }
+    }
+
+    /// Creates a [`CStr`] from a `[u8]`.
+    ///
+    /// The provided slice must be `NUL`-terminated, does not contain any
+    /// interior `NUL` bytes.
+    pub const fn from_bytes_with_nul(bytes: &[u8]) -> Result<&Self, CStrConvertError> {
+        if bytes.is_empty() {
+            return Err(CStrConvertError::NotNulTerminated);
+        }
+        if bytes[bytes.len() - 1] != 0 {
+            return Err(CStrConvertError::NotNulTerminated);
+        }
+        let mut i = 0;
+        // `i + 1 < bytes.len()` allows LLVM to optimize away bounds checking,
+        // while it couldn't optimize away bounds checks for `i < bytes.len() - 1`.
+        while i + 1 < bytes.len() {
+            if bytes[i] == 0 {
+                return Err(CStrConvertError::InteriorNul);
+            }
+            i += 1;
+        }
+        // SAFETY: We just checked that all properties hold.
+        Ok(unsafe { Self::from_bytes_with_nul_unchecked(bytes) })
+    }
+
+    /// Creates a [`CStr`] from a `[u8]`, panic if input is not valid.
+    ///
+    /// This function is only meant to be used by `c_str!` macro, so
+    /// crates using `c_str!` macro don't have to enable `const_panic` feature.
+    #[doc(hidden)]
+    pub const fn from_bytes_with_nul_unwrap(bytes: &[u8]) -> &Self {
+        match Self::from_bytes_with_nul(bytes) {
+            Ok(v) => v,
+            Err(_) => panic!("string contains interior NUL"),
+        }
+    }
+
+    /// Creates a [`CStr`] from a `[u8]` without performing any additional
+    /// checks.
+    ///
+    /// # Safety
+    ///
+    /// `bytes` *must* end with a `NUL` byte, and should only have a single
+    /// `NUL` byte (or the string will be truncated).
+    #[inline]
+    pub const unsafe fn from_bytes_with_nul_unchecked(bytes: &[u8]) -> &CStr {
+        // SAFETY: Properties of `bytes` guaranteed by the safety precondition.
+        unsafe { core::mem::transmute(bytes) }
+    }
+
+    /// Returns a C pointer to the string.
+    #[inline]
+    pub const fn as_char_ptr(&self) -> *const c_types::c_char {
+        self.0.as_ptr() as _
+    }
+
+    /// Convert the string to a byte slice without the trailing 0 byte.
+    #[inline]
+    pub fn as_bytes(&self) -> &[u8] {
+        &self.0[..self.len()]
+    }
+
+    /// Convert the string to a byte slice containing the trailing 0 byte.
+    #[inline]
+    pub const fn as_bytes_with_nul(&self) -> &[u8] {
+        &self.0
+    }
+
+    /// Yields a [`&str`] slice if the [`CStr`] contains valid UTF-8.
+    ///
+    /// If the contents of the [`CStr`] are valid UTF-8 data, this
+    /// function will return the corresponding [`&str`] slice. Otherwise,
+    /// it will return an error with details of where UTF-8 validation failed.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # use kernel::str::CStr;
+    /// let cstr = CStr::from_bytes_with_nul(b"foo\0").unwrap();
+    /// assert_eq!(cstr.to_str(), Ok("foo"));
+    /// ```
+    #[inline]
+    pub fn to_str(&self) -> Result<&str, core::str::Utf8Error> {
+        core::str::from_utf8(self.as_bytes())
+    }
+
+    /// Unsafely convert this [`CStr`] into a [`&str`], without checking for
+    /// valid UTF-8.
+    ///
+    /// # Safety
+    ///
+    /// The contents must be valid UTF-8.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # use kernel::c_str;
+    /// # use kernel::str::CStr;
+    /// // SAFETY: String literals are guaranteed to be valid UTF-8
+    /// // by the Rust compiler.
+    /// let bar = c_str!("ツ");
+    /// assert_eq!(unsafe { bar.as_str_unchecked() }, "ツ");
+    /// ```
+    #[inline]
+    pub unsafe fn as_str_unchecked(&self) -> &str {
+        unsafe { core::str::from_utf8_unchecked(self.as_bytes()) }
+    }
+}
+
+impl fmt::Display for CStr {
+    /// Formats printable ASCII characters, escaping the rest.
+    ///
+    /// ```
+    /// # use kernel::c_str;
+    /// # use kernel::str::CStr;
+    /// let penguin = c_str!("🐧");
+    /// assert_eq!(format!("{}", penguin), "\\xf0\\x9f\\x90\\xa7");
+    ///
+    /// let ascii = c_str!("so \"cool\"");
+    /// assert_eq!(format!("{}", ascii), "so \"cool\"");
+    /// ```
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        for &c in self.as_bytes() {
+            if (0x20..0x7f).contains(&c) {
+                // Printable character
+                f.write_char(c as char)?;
+            } else {
+                write!(f, "\\x{:02x}", c)?;
+            }
+        }
+        Ok(())
+    }
+}
+
+impl fmt::Debug for CStr {
+    /// Formats printable ASCII characters with a double quote on either end, escaping the rest.
+    ///
+    /// ```
+    /// # use kernel::c_str;
+    /// # use kernel::str::CStr;
+    /// let penguin = c_str!("🐧");
+    /// assert_eq!(format!("{:?}", penguin), "\"\\xf0\\x9f\\x90\\xa7\"");
+    ///
+    /// // embedded double quotes are escaped
+    /// let ascii = c_str!("so \"cool\"");
+    /// assert_eq!(format!("{:?}", ascii), "\"so \\\"cool\\\"\"");
+    /// ```
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.write_str("\"")?;
+        for &c in self.as_bytes() {
+            match c {
+                // Printable characters
+                b'\"' => f.write_str("\\\"")?,
+                0x20..=0x7e => f.write_char(c as char)?,
+                _ => write!(f, "\\x{:02x}", c)?,
+            }
+        }
+        f.write_str("\"")
+    }
+}
+
+impl AsRef<BStr> for CStr {
+    #[inline]
+    fn as_ref(&self) -> &BStr {
+        self.as_bytes()
+    }
+}
+
+impl Deref for CStr {
+    type Target = BStr;
+
+    #[inline]
+    fn deref(&self) -> &Self::Target {
+        self.as_bytes()
+    }
+}
+
+impl Index<ops::RangeFrom<usize>> for CStr {
+    type Output = CStr;
+
+    #[inline]
+    fn index(&self, index: ops::RangeFrom<usize>) -> &Self::Output {
+        // Delegate bounds checking to slice.
+        // Assign to _ to mute clippy's unnecessary operation warning.
+        let _ = &self.as_bytes()[index.start..];
+        // SAFETY: We just checked the bounds.
+        unsafe { Self::from_bytes_with_nul_unchecked(&self.0[index.start..]) }
+    }
+}
+
+impl Index<ops::RangeFull> for CStr {
+    type Output = CStr;
+
+    #[inline]
+    fn index(&self, _index: ops::RangeFull) -> &Self::Output {
+        self
+    }
+}
+
+mod private {
+    use core::ops;
+
+    //  Marker trait for index types that can be forward to `BStr`.
+    pub trait CStrIndex {}
+
+    impl CStrIndex for usize {}
+    impl CStrIndex for ops::Range<usize> {}
+    impl CStrIndex for ops::RangeInclusive<usize> {}
+    impl CStrIndex for ops::RangeToInclusive<usize> {}
+}
+
+impl<Idx> Index<Idx> for CStr
+where
+    Idx: private::CStrIndex,
+    BStr: Index<Idx>,
+{
+    type Output = <BStr as Index<Idx>>::Output;
+
+    #[inline]
+    fn index(&self, index: Idx) -> &Self::Output {
+        &self.as_bytes()[index]
+    }
+}
+
+/// Creates a new [`CStr`] from a string literal.
+///
+/// The string literal should not contain any `NUL` bytes.
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::c_str;
+/// # use kernel::str::CStr;
+/// const MY_CSTR: &'static CStr = c_str!("My awesome CStr!");
+/// ```
+#[macro_export]
+macro_rules! c_str {
+    ($str:literal) => {{
+        const S: &str = concat!($str, "\0");
+        const C: &$crate::str::CStr = $crate::str::CStr::from_bytes_with_nul_unwrap(S.as_bytes());
+        C
+    }};
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn test_cstr_to_str() {
+        let good_bytes = b"\xf0\x9f\xa6\x80\0";
+        let checked_cstr = CStr::from_bytes_with_nul(good_bytes).unwrap();
+        let checked_str = checked_cstr.to_str().unwrap();
+        assert_eq!(checked_str, "🦀");
+    }
+
+    #[test]
+    #[should_panic]
+    fn test_cstr_to_str_panic() {
+        let bad_bytes = b"\xc3\x28\0";
+        let checked_cstr = CStr::from_bytes_with_nul(bad_bytes).unwrap();
+        checked_cstr.to_str().unwrap();
+    }
+
+    #[test]
+    fn test_cstr_as_str_unchecked() {
+        let good_bytes = b"\xf0\x9f\x90\xA7\0";
+        let checked_cstr = CStr::from_bytes_with_nul(good_bytes).unwrap();
+        let unchecked_str = unsafe { checked_cstr.as_str_unchecked() };
+        assert_eq!(unchecked_str, "🐧");
+    }
+}
diff --git a/rust/kernel/sync/arc.rs b/rust/kernel/sync/arc.rs
new file mode 100644
index 000000000000..cd98806b84ed
--- /dev/null
+++ b/rust/kernel/sync/arc.rs
@@ -0,0 +1,500 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! A reference-counted pointer.
+//!
+//! This module implements a way for users to create reference-counted objects and pointers to
+//! them. Such a pointer automatically increments and decrements the count, and drops the
+//! underlying object when it reaches zero. It is also safe to use concurrently from multiple
+//! threads.
+//!
+//! It is different from the standard library's [`Arc`] in a few ways:
+//! 1. It is backed by the kernel's `refcount_t` type.
+//! 2. It does not support weak references, which allows it to be half the size.
+//! 3. It saturates the reference count instead of aborting when it goes over a threshold.
+//! 4. It does not provide a `get_mut` method, so the ref counted object is pinned.
+//!
+//! [`Arc`]: https://doc.rust-lang.org/std/sync/struct.Arc.html
+
+use crate::{bindings, Error, Opaque, Result};
+use alloc::{
+    alloc::{alloc, dealloc},
+    vec::Vec,
+};
+use core::{
+    alloc::Layout,
+    convert::{AsRef, TryFrom},
+    marker::{PhantomData, Unsize},
+    mem::{ManuallyDrop, MaybeUninit},
+    ops::{Deref, DerefMut},
+    pin::Pin,
+    ptr::{self, NonNull},
+};
+
+/// A reference-counted pointer to an instance of `T`.
+///
+/// The reference count is incremented when new instances of [`Ref`] are created, and decremented
+/// when they are dropped. When the count reaches zero, the underlying `T` is also dropped.
+///
+/// # Invariants
+///
+/// The reference count on an instance of [`Ref`] is always non-zero.
+/// The object pointed to by [`Ref`] is always pinned.
+pub struct Ref<T: ?Sized> {
+    ptr: NonNull<RefInner<T>>,
+    _p: PhantomData<RefInner<T>>,
+}
+
+#[repr(C)]
+struct RefInner<T: ?Sized> {
+    refcount: Opaque<bindings::refcount_t>,
+    data: T,
+}
+
+// This is to allow [`Ref`] (and variants) to be used as the type of `self`.
+impl<T: ?Sized> core::ops::Receiver for Ref<T> {}
+
+// This is to allow [`RefBorrow`] (and variants) to be used as the type of `self`.
+impl<T: ?Sized> core::ops::Receiver for RefBorrow<'_, T> {}
+
+// This is to allow coercion from `Ref<T>` to `Ref<U>` if `T` can be converted to the
+// dynamically-sized type (DST) `U`.
+impl<T: ?Sized + Unsize<U>, U: ?Sized> core::ops::CoerceUnsized<Ref<U>> for Ref<T> {}
+
+// This is to allow `Ref<U>` to be dispatched on when `Ref<T>` can be coerced into `Ref<U>`.
+impl<T: ?Sized + Unsize<U>, U: ?Sized> core::ops::DispatchFromDyn<Ref<U>> for Ref<T> {}
+
+// SAFETY: It is safe to send `Ref<T>` to another thread when the underlying `T` is `Sync` because
+// it effectively means sharing `&T` (which is safe because `T` is `Sync`); additionally, it needs
+// `T` to be `Send` because any thread that has a `Ref<T>` may ultimately access `T` directly, for
+// example, when the reference count reaches zero and `T` is dropped.
+unsafe impl<T: ?Sized + Sync + Send> Send for Ref<T> {}
+
+// SAFETY: It is safe to send `&Ref<T>` to another thread when the underlying `T` is `Sync` for
+// the same reason as above. `T` needs to be `Send` as well because a thread can clone a `&Ref<T>`
+// into a `Ref<T>`, which may lead to `T` being accessed by the same reasoning as above.
+unsafe impl<T: ?Sized + Sync + Send> Sync for Ref<T> {}
+
+impl<T> Ref<T> {
+    /// Constructs a new reference counted instance of `T`.
+    pub fn try_new(contents: T) -> Result<Self> {
+        let layout = Layout::new::<RefInner<T>>();
+        // SAFETY: The layout size is guaranteed to be non-zero because `RefInner` contains the
+        // reference count.
+        let inner = NonNull::new(unsafe { alloc(layout) })
+            .ok_or(Error::ENOMEM)?
+            .cast::<RefInner<T>>();
+
+        // INVARIANT: The refcount is initialised to a non-zero value.
+        let value = RefInner {
+            // SAFETY: Just an FFI call that returns a `refcount_t` initialised to 1.
+            refcount: Opaque::new(unsafe { bindings::REFCOUNT_INIT(1) }),
+            data: contents,
+        };
+        // SAFETY: `inner` is writable and properly aligned.
+        unsafe { inner.as_ptr().write(value) };
+
+        // SAFETY: We just created `inner` with a reference count of 1, which is owned by the new
+        // `Ref` object.
+        Ok(unsafe { Self::from_inner(inner) })
+    }
+
+    /// Deconstructs a [`Ref`] object into a `usize`.
+    ///
+    /// It can be reconstructed once via [`Ref::from_usize`].
+    pub fn into_usize(obj: Self) -> usize {
+        ManuallyDrop::new(obj).ptr.as_ptr() as _
+    }
+
+    /// Borrows a [`Ref`] instance previously deconstructed via [`Ref::into_usize`].
+    ///
+    /// # Safety
+    ///
+    /// `encoded` must have been returned by a previous call to [`Ref::into_usize`]. Additionally,
+    /// [`Ref::from_usize`] can only be called after *all* instances of [`RefBorrow`] have been
+    /// dropped.
+    pub unsafe fn borrow_usize<'a>(encoded: usize) -> RefBorrow<'a, T> {
+        // SAFETY: By the safety requirement of this function, we know that `encoded` came from
+        // a previous call to `Ref::into_usize`.
+        let inner = NonNull::new(encoded as *mut RefInner<T>).unwrap();
+
+        // SAFETY: The safety requirements ensure that the object remains alive for the lifetime of
+        // the returned value. There is no way to create mutable references to the object.
+        unsafe { RefBorrow::new(inner) }
+    }
+
+    /// Recreates a [`Ref`] instance previously deconstructed via [`Ref::into_usize`].
+    ///
+    /// # Safety
+    ///
+    /// `encoded` must have been returned by a previous call to [`Ref::into_usize`]. Additionally,
+    /// it can only be called once for each previous call to [`Ref::into_usize`].
+    pub unsafe fn from_usize(encoded: usize) -> Self {
+        // SAFETY: By the safety invariants we know that `encoded` came from `Ref::into_usize`, so
+        // the reference count held then will be owned by the new `Ref` object.
+        unsafe { Self::from_inner(NonNull::new(encoded as _).unwrap()) }
+    }
+}
+
+impl<T: ?Sized> Ref<T> {
+    /// Constructs a new [`Ref`] from an existing [`RefInner`].
+    ///
+    /// # Safety
+    ///
+    /// The caller must ensure that `inner` points to a valid location and has a non-zero reference
+    /// count, one of which will be owned by the new [`Ref`] instance.
+    unsafe fn from_inner(inner: NonNull<RefInner<T>>) -> Self {
+        // INVARIANT: By the safety requirements, the invariants hold.
+        Ref {
+            ptr: inner,
+            _p: PhantomData,
+        }
+    }
+
+    /// Determines if two reference-counted pointers point to the same underlying instance of `T`.
+    pub fn ptr_eq(a: &Self, b: &Self) -> bool {
+        ptr::eq(a.ptr.as_ptr(), b.ptr.as_ptr())
+    }
+
+    /// Deconstructs a [`Ref`] object into a raw pointer.
+    ///
+    /// It can be reconstructed once via [`Ref::from_raw`].
+    pub fn into_raw(obj: Self) -> *const T {
+        let ret = &*obj as *const T;
+        core::mem::forget(obj);
+        ret
+    }
+
+    /// Recreates a [`Ref`] instance previously deconstructed via [`Ref::into_raw`].
+    ///
+    /// This code relies on the `repr(C)` layout of structs as described in
+    /// <https://doc.rust-lang.org/reference/type-layout.html#reprc-structs>.
+    ///
+    /// # Safety
+    ///
+    /// `ptr` must have been returned by a previous call to [`Ref::into_raw`]. Additionally, it
+    /// can only be called once for each previous call to [`Ref::into_raw`].
+    pub unsafe fn from_raw(ptr: *const T) -> Self {
+        // SAFETY: The safety requirement ensures that the pointer is valid.
+        let align = core::mem::align_of_val(unsafe { &*ptr });
+        let offset = Layout::new::<RefInner<()>>()
+            .align_to(align)
+            .unwrap()
+            .pad_to_align()
+            .size();
+        // SAFETY: The pointer is in bounds because by the safety requirements `ptr` came from
+        // `Ref::into_raw`, so it is a pointer `offset` bytes from the beginning of the allocation.
+        let data = unsafe { (ptr as *const u8).sub(offset) };
+        let metadata = ptr::metadata(ptr as *const RefInner<T>);
+        let ptr = ptr::from_raw_parts_mut(data as _, metadata);
+        // SAFETY: By the safety requirements we know that `ptr` came from `Ref::into_raw`, so the
+        // reference count held then will be owned by the new `Ref` object.
+        unsafe { Self::from_inner(NonNull::new(ptr).unwrap()) }
+    }
+
+    /// Returns a [`RefBorrow`] from the given [`Ref`].
+    ///
+    /// This is useful when the argument of a function call is a [`RefBorrow`] (e.g., in a method
+    /// receiver), but we have a [`Ref`] instead. Getting a [`RefBorrow`] is free when optimised.
+    #[inline]
+    pub fn as_ref_borrow(&self) -> RefBorrow<'_, T> {
+        // SAFETY: The constraint that lifetime of the shared reference must outlive that of
+        // the returned `RefBorrow` ensures that the object remains alive.
+        unsafe { RefBorrow::new(self.ptr) }
+    }
+}
+
+impl<T: ?Sized> Deref for Ref<T> {
+    type Target = T;
+
+    fn deref(&self) -> &Self::Target {
+        // SAFETY: By the type invariant, there is necessarily a reference to the object, so it is
+        // safe to dereference it.
+        unsafe { &self.ptr.as_ref().data }
+    }
+}
+
+impl<T: ?Sized> Clone for Ref<T> {
+    fn clone(&self) -> Self {
+        // INVARIANT: C `refcount_inc` saturates the refcount, so it cannot overflow to zero.
+        // SAFETY: By the type invariant, there is necessarily a reference to the object, so it is
+        // safe to increment the refcount.
+        unsafe { bindings::refcount_inc(self.ptr.as_ref().refcount.get()) };
+
+        // SAFETY: We just incremented the refcount. This increment is now owned by the new `Ref`.
+        unsafe { Self::from_inner(self.ptr) }
+    }
+}
+
+impl<T: ?Sized> AsRef<T> for Ref<T> {
+    fn as_ref(&self) -> &T {
+        // SAFETY: By the type invariant, there is necessarily a reference to the object, so it is
+        // safe to dereference it.
+        unsafe { &self.ptr.as_ref().data }
+    }
+}
+
+impl<T: ?Sized> Drop for Ref<T> {
+    fn drop(&mut self) {
+        // SAFETY: By the type invariant, there is necessarily a reference to the object. We cannot
+        // touch `refcount` after it's decremented to a non-zero value because another thread/CPU
+        // may concurrently decrement it to zero and free it. It is ok to have a raw pointer to
+        // freed/invalid memory as long as it is never dereferenced.
+        let refcount = unsafe { self.ptr.as_ref() }.refcount.get();
+
+        // INVARIANT: If the refcount reaches zero, there are no other instances of `Ref`, and
+        // this instance is being dropped, so the broken invariant is not observable.
+        // SAFETY: Also by the type invariant, we are allowed to decrement the refcount.
+        let is_zero = unsafe { bindings::refcount_dec_and_test(refcount) };
+        if is_zero {
+            // The count reached zero, we must free the memory.
+
+            // SAFETY: This thread holds the only remaining reference to `self`, so it is safe to
+            // get a mutable reference to it.
+            let inner = unsafe { self.ptr.as_mut() };
+            let layout = Layout::for_value(inner);
+            // SAFETY: The value stored in inner is valid.
+            unsafe { core::ptr::drop_in_place(inner) };
+            // SAFETY: The pointer was initialised from the result of a call to `alloc`.
+            unsafe { dealloc(self.ptr.cast().as_ptr(), layout) };
+        }
+    }
+}
+
+impl<T> TryFrom<Vec<T>> for Ref<[T]> {
+    type Error = Error;
+
+    fn try_from(mut v: Vec<T>) -> Result<Self> {
+        let value_layout = Layout::array::<T>(v.len())?;
+        let layout = Layout::new::<RefInner<()>>()
+            .extend(value_layout)?
+            .0
+            .pad_to_align();
+        // SAFETY: The layout size is guaranteed to be non-zero because `RefInner` contains the
+        // reference count.
+        let ptr = NonNull::new(unsafe { alloc(layout) }).ok_or(Error::ENOMEM)?;
+        let inner =
+            core::ptr::slice_from_raw_parts_mut(ptr.as_ptr() as _, v.len()) as *mut RefInner<[T]>;
+
+        // SAFETY: Just an FFI call that returns a `refcount_t` initialised to 1.
+        let count = Opaque::new(unsafe { bindings::REFCOUNT_INIT(1) });
+        // SAFETY: `inner.refcount` is writable and properly aligned.
+        unsafe { core::ptr::addr_of_mut!((*inner).refcount).write(count) };
+        // SAFETY: The contents of `v` as readable and properly aligned; `inner.data` is writable
+        // and properly aligned. There is no overlap between the two because `inner` is a new
+        // allocation.
+        unsafe {
+            core::ptr::copy_nonoverlapping(
+                v.as_ptr(),
+                core::ptr::addr_of_mut!((*inner).data) as *mut [T] as *mut T,
+                v.len(),
+            )
+        };
+        // SAFETY: We're setting the new length to zero, so it is <= to capacity, and old_len..0 is
+        // an empty range (so satisfies vacuously the requirement of being initialised).
+        unsafe { v.set_len(0) };
+        // SAFETY: We just created `inner` with a reference count of 1, which is owned by the new
+        // `Ref` object.
+        Ok(unsafe { Self::from_inner(NonNull::new(inner).unwrap()) })
+    }
+}
+
+impl<T: ?Sized> From<UniqueRef<T>> for Ref<T> {
+    fn from(item: UniqueRef<T>) -> Self {
+        item.inner
+    }
+}
+
+impl<T: ?Sized> From<UniqueRef<T>> for Pin<UniqueRef<T>> {
+    fn from(obj: UniqueRef<T>) -> Self {
+        // SAFETY: It is not possible to move/replace `T` inside a `Pin<UniqueRef<T>>` (unless `T`
+        // is `Unpin`), so it is ok to convert it to `Pin<UniqueRef<T>>`.
+        unsafe { Pin::new_unchecked(obj) }
+    }
+}
+
+impl<T: ?Sized> From<Pin<UniqueRef<T>>> for Ref<T> {
+    fn from(item: Pin<UniqueRef<T>>) -> Self {
+        // SAFETY: The type invariants of `Ref` guarantee that the data is pinned.
+        unsafe { Pin::into_inner_unchecked(item).inner }
+    }
+}
+
+/// A borrowed [`Ref`] with manually-managed lifetime.
+///
+/// # Invariants
+///
+/// There are no mutable references to the underlying [`Ref`], and it remains valid for the lifetime
+/// of the [`RefBorrow`] instance.
+pub struct RefBorrow<'a, T: ?Sized + 'a> {
+    inner: NonNull<RefInner<T>>,
+    _p: PhantomData<&'a ()>,
+}
+
+impl<T: ?Sized> Clone for RefBorrow<'_, T> {
+    fn clone(&self) -> Self {
+        *self
+    }
+}
+
+impl<T: ?Sized> Copy for RefBorrow<'_, T> {}
+
+impl<T: ?Sized> RefBorrow<'_, T> {
+    /// Creates a new [`RefBorrow`] instance.
+    ///
+    /// # Safety
+    ///
+    /// Callers must ensure the following for the lifetime of the returned [`RefBorrow`] instance:
+    /// 1. That `obj` remains valid;
+    /// 2. That no mutable references to `obj` are created.
+    unsafe fn new(inner: NonNull<RefInner<T>>) -> Self {
+        // INVARIANT: The safety requirements guarantee the invariants.
+        Self {
+            inner,
+            _p: PhantomData,
+        }
+    }
+}
+
+impl<T: ?Sized> From<RefBorrow<'_, T>> for Ref<T> {
+    fn from(b: RefBorrow<'_, T>) -> Self {
+        // SAFETY: The existence of `b` guarantees that the refcount is non-zero. `ManuallyDrop`
+        // guarantees that `drop` isn't called, so it's ok that the temporary `Ref` doesn't own the
+        // increment.
+        ManuallyDrop::new(unsafe { Ref::from_inner(b.inner) })
+            .deref()
+            .clone()
+    }
+}
+
+impl<T: ?Sized> Deref for RefBorrow<'_, T> {
+    type Target = T;
+
+    fn deref(&self) -> &Self::Target {
+        // SAFETY: By the type invariant, the underlying object is still alive with no mutable
+        // references to it, so it is safe to create a shared reference.
+        unsafe { &self.inner.as_ref().data }
+    }
+}
+
+/// A refcounted object that is known to have a refcount of 1.
+///
+/// It is mutable and can be converted to a [`Ref`] so that it can be shared.
+///
+/// # Invariants
+///
+/// `inner` always has a reference count of 1.
+///
+/// # Examples
+///
+/// In the following example, we make changes to the inner object before turning it into a
+/// `Ref<Test>` object (after which point, it cannot be mutated directly). Note that `x.into()`
+/// cannot fail.
+///
+/// ```
+/// # use kernel::prelude::*;
+/// use kernel::sync::{Ref, UniqueRef};
+///
+/// struct Example {
+///     a: u32,
+///     b: u32,
+/// }
+///
+/// fn test() -> Result<Ref<Example>> {
+///     let mut x = UniqueRef::try_new(Example { a: 10, b: 20 })?;
+///     x.a += 1;
+///     x.b += 1;
+///     Ok(x.into())
+/// }
+/// ```
+///
+/// In the following example we first allocate memory for a ref-counted `Example` but we don't
+/// initialise it on allocation. We do initialise it later with a call to [`UniqueRef::write`],
+/// followed by a conversion to `Ref<Example>`. This is particularly useful when allocation happens
+/// in one context (e.g., sleepable) and initialisation in another (e.g., atomic):
+///
+/// ```
+/// # use kernel::prelude::*;
+/// use kernel::sync::{Ref, UniqueRef};
+///
+/// struct Example {
+///     a: u32,
+///     b: u32,
+/// }
+///
+/// fn test2() -> Result<Ref<Example>> {
+///     let x = UniqueRef::try_new_uninit()?;
+///     Ok(x.write(Example { a: 10, b: 20 }).into())
+/// }
+/// ```
+///
+/// In the last example below, the caller gets a pinned instance of `Example` while converting to
+/// `Ref<Example>`; this is useful in scenarios where one needs a pinned reference during
+/// initialisation, for example, when initialising fields that are wrapped in locks.
+///
+/// ```
+/// # use kernel::prelude::*;
+/// use kernel::sync::{Ref, UniqueRef};
+///
+/// struct Example {
+///     a: u32,
+///     b: u32,
+/// }
+///
+/// fn test2() -> Result<Ref<Example>> {
+///     let mut pinned = Pin::from(UniqueRef::try_new(Example { a: 10, b: 20 })?);
+///     // We can modify `pinned` because it is `Unpin`.
+///     pinned.as_mut().a += 1;
+///     Ok(pinned.into())
+/// }
+/// ```
+pub struct UniqueRef<T: ?Sized> {
+    inner: Ref<T>,
+}
+
+impl<T> UniqueRef<T> {
+    /// Tries to allocate a new [`UniqueRef`] instance.
+    pub fn try_new(value: T) -> Result<Self> {
+        Ok(Self {
+            // INVARIANT: The newly-created object has a ref-count of 1.
+            inner: Ref::try_new(value)?,
+        })
+    }
+
+    /// Tries to allocate a new [`UniqueRef`] instance whose contents are not initialised yet.
+    pub fn try_new_uninit() -> Result<UniqueRef<MaybeUninit<T>>> {
+        Ok(UniqueRef::<MaybeUninit<T>> {
+            // INVARIANT: The newly-created object has a ref-count of 1.
+            inner: Ref::try_new(MaybeUninit::uninit())?,
+        })
+    }
+}
+
+impl<T> UniqueRef<MaybeUninit<T>> {
+    /// Converts a `UniqueRef<MaybeUninit<T>>` into a `UniqueRef<T>` by writing a value into it.
+    pub fn write(mut self, value: T) -> UniqueRef<T> {
+        self.deref_mut().write(value);
+        let inner = ManuallyDrop::new(self).inner.ptr;
+        UniqueRef {
+            // SAFETY: The new `Ref` is taking over `ptr` from `self.inner` (which won't be
+            // dropped). The types are compatible because `MaybeUninit<T>` is compatible with `T`.
+            inner: unsafe { Ref::from_inner(inner.cast()) },
+        }
+    }
+}
+
+impl<T: ?Sized> Deref for UniqueRef<T> {
+    type Target = T;
+
+    fn deref(&self) -> &Self::Target {
+        self.inner.deref()
+    }
+}
+
+impl<T: ?Sized> DerefMut for UniqueRef<T> {
+    fn deref_mut(&mut self) -> &mut Self::Target {
+        // SAFETY: By the `Ref` type invariant, there is necessarily a reference to the object, so
+        // it is safe to dereference it. Additionally, we know there is only one reference when
+        // it's inside a `UniqueRef`, so it is safe to get a mutable reference.
+        unsafe { &mut self.inner.ptr.as_mut().data }
+    }
+}
diff --git a/rust/kernel/sync/condvar.rs b/rust/kernel/sync/condvar.rs
new file mode 100644
index 000000000000..e36e73212316
--- /dev/null
+++ b/rust/kernel/sync/condvar.rs
@@ -0,0 +1,138 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! A condition variable.
+//!
+//! This module allows Rust code to use the kernel's [`struct wait_queue_head`] as a condition
+//! variable.
+
+use super::{GuardMut, Lock, NeedsLockClass};
+use crate::{bindings, str::CStr, task::Task, Opaque};
+use core::{marker::PhantomPinned, pin::Pin};
+
+/// Safely initialises a [`CondVar`] with the given name, generating a new lock class.
+#[macro_export]
+macro_rules! condvar_init {
+    ($condvar:expr, $name:literal) => {
+        $crate::init_with_lockdep!($condvar, $name)
+    };
+}
+
+// TODO: `bindgen` is not generating this constant. Figure out why.
+const POLLFREE: u32 = 0x4000;
+
+/// Exposes the kernel's [`struct wait_queue_head`] as a condition variable. It allows the caller to
+/// atomically release the given lock and go to sleep. It reacquires the lock when it wakes up. And
+/// it wakes up when notified by another thread (via [`CondVar::notify_one`] or
+/// [`CondVar::notify_all`]) or because the thread received a signal.
+///
+/// [`struct wait_queue_head`]: ../../../include/linux/wait.h
+pub struct CondVar {
+    pub(crate) wait_list: Opaque<bindings::wait_queue_head>,
+
+    /// A condvar needs to be pinned because it contains a [`struct list_head`] that is
+    /// self-referential, so it cannot be safely moved once it is initialised.
+    _pin: PhantomPinned,
+}
+
+// SAFETY: `CondVar` only uses a `struct wait_queue_head`, which is safe to use on any thread.
+#[allow(clippy::non_send_fields_in_send_ty)]
+unsafe impl Send for CondVar {}
+
+// SAFETY: `CondVar` only uses a `struct wait_queue_head`, which is safe to use on multiple threads
+// concurrently.
+unsafe impl Sync for CondVar {}
+
+impl CondVar {
+    /// Constructs a new conditional variable.
+    ///
+    /// # Safety
+    ///
+    /// The caller must call `CondVar::init` before using the conditional variable.
+    pub unsafe fn new() -> Self {
+        Self {
+            wait_list: Opaque::uninit(),
+            _pin: PhantomPinned,
+        }
+    }
+
+    /// Atomically releases the given lock (whose ownership is proven by the guard) and puts the
+    /// thread to sleep. It wakes up when notified by [`CondVar::notify_one`] or
+    /// [`CondVar::notify_all`], or when the thread receives a signal.
+    ///
+    /// Returns whether there is a signal pending.
+    #[must_use = "wait returns if a signal is pending, so the caller must check the return value"]
+    pub fn wait<L: Lock>(&self, guard: &mut GuardMut<'_, L>) -> bool {
+        let lock = guard.guard.lock;
+        let wait = Opaque::<bindings::wait_queue_entry>::uninit();
+
+        // SAFETY: `wait` points to valid memory.
+        unsafe { bindings::init_wait(wait.get()) };
+
+        // SAFETY: Both `wait` and `wait_list` point to valid memory.
+        unsafe {
+            bindings::prepare_to_wait_exclusive(
+                self.wait_list.get(),
+                wait.get(),
+                bindings::TASK_INTERRUPTIBLE as _,
+            )
+        };
+
+        // SAFETY: The guard is evidence that the caller owns the lock.
+        unsafe { lock.unlock(&mut guard.guard.context) };
+
+        // SAFETY: No arguments, switches to another thread.
+        unsafe { bindings::schedule() };
+
+        lock.relock(&mut guard.guard.context);
+
+        // SAFETY: Both `wait` and `wait_list` point to valid memory.
+        unsafe { bindings::finish_wait(self.wait_list.get(), wait.get()) };
+
+        Task::current().signal_pending()
+    }
+
+    /// Calls the kernel function to notify the appropriate number of threads with the given flags.
+    fn notify(&self, count: i32, flags: u32) {
+        // SAFETY: `wait_list` points to valid memory.
+        unsafe {
+            bindings::__wake_up(
+                self.wait_list.get(),
+                bindings::TASK_NORMAL,
+                count,
+                flags as _,
+            )
+        };
+    }
+
+    /// Wakes a single waiter up, if any. This is not 'sticky' in the sense that if no thread is
+    /// waiting, the notification is lost completely (as opposed to automatically waking up the
+    /// next waiter).
+    pub fn notify_one(&self) {
+        self.notify(1, 0);
+    }
+
+    /// Wakes all waiters up, if any. This is not 'sticky' in the sense that if no thread is
+    /// waiting, the notification is lost completely (as opposed to automatically waking up the
+    /// next waiter).
+    pub fn notify_all(&self) {
+        self.notify(0, 0);
+    }
+
+    /// Wakes all waiters up. If they were added by `epoll`, they are also removed from the list of
+    /// waiters. This is useful when cleaning up a condition variable that may be waited on by
+    /// threads that use `epoll`.
+    pub fn free_waiters(&self) {
+        self.notify(1, bindings::POLLHUP | POLLFREE);
+    }
+}
+
+impl NeedsLockClass for CondVar {
+    unsafe fn init(
+        self: Pin<&mut Self>,
+        name: &'static CStr,
+        key: *mut bindings::lock_class_key,
+        _: *mut bindings::lock_class_key,
+    ) {
+        unsafe { bindings::__init_waitqueue_head(self.wait_list.get(), name.as_char_ptr(), key) };
+    }
+}
diff --git a/rust/kernel/sync/guard.rs b/rust/kernel/sync/guard.rs
new file mode 100644
index 000000000000..9b0506a31fe7
--- /dev/null
+++ b/rust/kernel/sync/guard.rs
@@ -0,0 +1,181 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! A generic lock guard and trait.
+//!
+//! This module contains a lock guard that can be used with any locking primitive that implements
+//! the ([`Lock`]) trait. It also contains the definition of the trait, which can be leveraged by
+//! other constructs to work on generic locking primitives.
+
+use super::NeedsLockClass;
+use crate::{bindings, str::CStr};
+use core::pin::Pin;
+
+/// Allows mutual exclusion primitives that implement the [`Lock`] trait to automatically unlock
+/// when a guard goes out of scope. It also provides a safe and convenient way to access the data
+/// protected by the lock.
+#[must_use = "the lock unlocks immediately when the guard is unused"]
+pub struct GuardMut<'a, L: Lock + ?Sized> {
+    pub(crate) guard: Guard<'a, L>,
+}
+
+// SAFETY: `GuardMut` is sync when the data protected by the lock is also sync. This is more
+// conservative than the default compiler implementation; more details can be found on
+// https://github.com/rust-lang/rust/issues/41622 -- it refers to `MutexGuard` from the standard
+// library.
+unsafe impl<L> Sync for GuardMut<'_, L>
+where
+    L: Lock + ?Sized,
+    L::Inner: Sync,
+{
+}
+
+impl<L: Lock + ?Sized> core::ops::Deref for GuardMut<'_, L> {
+    type Target = L::Inner;
+
+    fn deref(&self) -> &Self::Target {
+        self.guard.deref()
+    }
+}
+
+impl<L: Lock + ?Sized> core::ops::DerefMut for GuardMut<'_, L> {
+    fn deref_mut(&mut self) -> &mut L::Inner {
+        // SAFETY: The caller owns the lock, so it is safe to deref the protected data.
+        unsafe { &mut *self.guard.lock.locked_data().get() }
+    }
+}
+
+impl<'a, L: Lock + ?Sized> GuardMut<'a, L> {
+    /// Constructs a new lock guard.
+    ///
+    /// # Safety
+    ///
+    /// The caller must ensure that it owns the lock.
+    pub(crate) unsafe fn new(lock: &'a L, context: L::GuardContext) -> Self {
+        // SAFETY: The safety requirements for this function satisfy the `Guard::new` ones.
+        Self {
+            guard: unsafe { Guard::new(lock, context) },
+        }
+    }
+}
+
+/// Allows mutual exclusion primitives that implement the [`Lock`] trait to automatically unlock
+/// when a guard goes out of scope. It also provides a safe and convenient way to immutably access
+/// the data protected by the lock.
+#[must_use = "the lock unlocks immediately when the guard is unused"]
+pub struct Guard<'a, L: Lock + ?Sized> {
+    pub(crate) lock: &'a L,
+    pub(crate) context: L::GuardContext,
+}
+
+// SAFETY: `Guard` is sync when the data protected by the lock is also sync. This is more
+// conservative than the default compiler implementation; more details can be found on
+// https://github.com/rust-lang/rust/issues/41622 -- it refers to `MutexGuard` from the standard
+// library.
+unsafe impl<L> Sync for Guard<'_, L>
+where
+    L: Lock + ?Sized,
+    L::Inner: Sync,
+{
+}
+
+impl<L: Lock + ?Sized> core::ops::Deref for Guard<'_, L> {
+    type Target = L::Inner;
+
+    fn deref(&self) -> &Self::Target {
+        // SAFETY: The caller owns the lock, so it is safe to deref the protected data.
+        unsafe { &*self.lock.locked_data().get() }
+    }
+}
+
+impl<L: Lock + ?Sized> Drop for Guard<'_, L> {
+    fn drop(&mut self) {
+        // SAFETY: The caller owns the lock, so it is safe to unlock it.
+        unsafe { self.lock.unlock(&mut self.context) };
+    }
+}
+
+impl<'a, L: Lock + ?Sized> Guard<'a, L> {
+    /// Constructs a new immutable lock guard.
+    ///
+    /// # Safety
+    ///
+    /// The caller must ensure that it owns the lock.
+    pub(crate) unsafe fn new(lock: &'a L, context: L::GuardContext) -> Self {
+        Self { lock, context }
+    }
+}
+
+/// A generic mutual exclusion primitive.
+///
+/// [`Guard`] and [`GuardMut`] are written such that any mutual exclusion primitive that can
+/// implement this trait can also benefit from having an automatic way to unlock itself.
+///
+/// # Safety
+///
+/// Implementers of this trait must ensure that only one thread/CPU may access the protected data
+/// once the lock is held, that is, between calls to `lock_noguard` and `unlock`.
+pub unsafe trait Lock {
+    /// The type of the data protected by the lock.
+    type Inner: ?Sized;
+
+    /// The type of context, if any, that needs to be stored in the guard.
+    type GuardContext;
+
+    /// Acquires the lock, making the caller its owner.
+    #[must_use]
+    fn lock_noguard(&self) -> Self::GuardContext;
+
+    /// Reacquires the lock, making the caller its owner.
+    ///
+    /// The guard context before the last unlock is passed in.
+    ///
+    /// Locks that don't require this state on relock can simply use the default implementation
+    /// that calls [`Lock::lock_noguard`].
+    fn relock(&self, ctx: &mut Self::GuardContext) {
+        *ctx = self.lock_noguard();
+    }
+
+    /// Releases the lock, giving up ownership of the lock.
+    ///
+    /// # Safety
+    ///
+    /// It must only be called by the current owner of the lock.
+    unsafe fn unlock(&self, context: &mut Self::GuardContext);
+
+    /// Returns the data protected by the lock.
+    fn locked_data(&self) -> &core::cell::UnsafeCell<Self::Inner>;
+}
+
+/// A generic mutual exclusion primitive that can be instantiated generically.
+pub trait CreatableLock: Lock {
+    /// Constructs a new instance of the lock.
+    ///
+    /// # Safety
+    ///
+    /// The caller must call [`CreatableLock::init_lock`] before using the lock.
+    unsafe fn new_lock(data: Self::Inner) -> Self;
+
+    /// Initialises the lock type instance so that it can be safely used.
+    ///
+    /// # Safety
+    ///
+    /// `key` must point to a valid memory location that will remain valid until the lock is
+    /// dropped.
+    unsafe fn init_lock(
+        self: Pin<&mut Self>,
+        name: &'static CStr,
+        key: *mut bindings::lock_class_key,
+    );
+}
+
+impl<L: CreatableLock> NeedsLockClass for L {
+    unsafe fn init(
+        self: Pin<&mut Self>,
+        name: &'static CStr,
+        key: *mut bindings::lock_class_key,
+        _: *mut bindings::lock_class_key,
+    ) {
+        // SAFETY: The safety requirements of this function satisfy those of `init_lock`.
+        unsafe { self.init_lock(name, key) };
+    }
+}
diff --git a/rust/kernel/sync/locked_by.rs b/rust/kernel/sync/locked_by.rs
new file mode 100644
index 000000000000..e7546e12b8df
--- /dev/null
+++ b/rust/kernel/sync/locked_by.rs
@@ -0,0 +1,112 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! A wrapper for data protected by a lock that does not wrap it.
+
+use super::{GuardMut, Lock};
+use core::{cell::UnsafeCell, ops::Deref, ptr};
+
+/// Allows access to some data to be serialised by a lock that does not wrap it.
+///
+/// In most cases, data protected by a lock is wrapped by the appropriate lock type, e.g.,
+/// [`super::Mutex`] or [`super::SpinLock`]. [`LockedBy`] is meant for cases when this is not
+/// possible. For example, if a container has a lock and some data in the contained elements needs
+/// to be protected by the same lock.
+///
+/// [`LockedBy`] wraps the data in lieu of another locking primitive, and only allows access to it
+/// when the caller shows evidence that 'external' lock is locked.
+///
+/// # Example
+///
+/// The following is an example for illustrative purposes: `InnerDirectory::bytes_used` is an
+/// aggregate of all `InnerFile::bytes_used` and must be kept consistent; so we wrap `InnerFile` in
+/// a `LockedBy` so that it shares a lock with `InnerDirectory`. This allows us to enforce at
+/// compile-time that access to `InnerFile` is only granted when an `InnerDirectory` is also
+/// locked; we enforce at run time that the right `InnerDirectory` is locked.
+///
+/// ```
+/// # use kernel::prelude::*;
+/// use kernel::sync::{LockedBy, Mutex};
+///
+/// struct InnerFile {
+///     bytes_used: u64,
+/// }
+///
+/// struct File {
+///     name: String,
+///     inner: LockedBy<InnerFile, Mutex<InnerDirectory>>,
+/// }
+///
+/// struct InnerDirectory {
+///     /// The sum of the bytes used by all files.
+///     bytes_used: u64,
+///     files: Vec<File>,
+/// }
+///
+/// struct Directory {
+///     name: String,
+///     inner: Mutex<InnerDirectory>,
+/// }
+/// ```
+pub struct LockedBy<T: ?Sized, L: Lock + ?Sized> {
+    owner: *const L::Inner,
+    data: UnsafeCell<T>,
+}
+
+// SAFETY: `LockedBy` can be transferred across thread boundaries iff the data it protects can.
+unsafe impl<T: ?Sized + Send, L: Lock + ?Sized> Send for LockedBy<T, L> {}
+
+// SAFETY: `LockedBy` serialises the interior mutability it provides, so it is `Sync` as long as the
+// data it protects is `Send`.
+unsafe impl<T: ?Sized + Send, L: Lock + ?Sized> Sync for LockedBy<T, L> {}
+
+impl<T, L: Lock + ?Sized> LockedBy<T, L> {
+    /// Constructs a new instance of [`LockedBy`].
+    ///
+    /// It stores a raw pointer to the owner that is never dereferenced. It is only used to ensure
+    /// that the right owner is being used to access the protected data. If the owner is freed, the
+    /// data becomes inaccessible; if another instance of the owner is allocated *on the same
+    /// memory location*, the data becomes accessible again: none of this affects memory safety
+    /// because in any case at most one thread (or CPU) can access the protected data at a time.
+    pub fn new(owner: &L, data: T) -> Self {
+        Self {
+            owner: owner.locked_data().get(),
+            data: UnsafeCell::new(data),
+        }
+    }
+}
+
+impl<T: ?Sized, L: Lock + ?Sized> LockedBy<T, L> {
+    /// Returns a reference to the protected data when the caller provides evidence (via a
+    /// [`GuardMut`]) that the owner is locked.
+    pub fn access<'a>(&'a self, guard: &'a GuardMut<'_, L>) -> &'a T {
+        if !ptr::eq(guard.deref(), self.owner) {
+            panic!("guard does not match owner");
+        }
+
+        // SAFETY: `guard` is evidence that the owner is locked.
+        unsafe { &mut *self.data.get() }
+    }
+
+    /// Returns a mutable reference to the protected data when the caller provides evidence (via a
+    /// mutable [`GuardMut`]) that the owner is locked mutably.
+    pub fn access_mut<'a>(&'a self, guard: &'a mut GuardMut<'_, L>) -> &'a mut T {
+        if !ptr::eq(guard.deref().deref(), self.owner) {
+            panic!("guard does not match owner");
+        }
+
+        // SAFETY: `guard` is evidence that the owner is locked.
+        unsafe { &mut *self.data.get() }
+    }
+
+    /// Returns a mutable reference to the protected data when the caller provides evidence (via a
+    /// mutable owner) that the owner is locked mutably. Showing a mutable reference to the owner
+    /// is sufficient because we know no other references can exist to it.
+    pub fn access_from_mut<'a>(&'a self, owner: &'a mut L::Inner) -> &'a mut T {
+        if !ptr::eq(owner, self.owner) {
+            panic!("mismatched owners");
+        }
+
+        // SAFETY: `owner` is evidence that there is only one reference to the owner.
+        unsafe { &mut *self.data.get() }
+    }
+}
diff --git a/rust/kernel/sync/mod.rs b/rust/kernel/sync/mod.rs
new file mode 100644
index 000000000000..51067fc7b6fc
--- /dev/null
+++ b/rust/kernel/sync/mod.rs
@@ -0,0 +1,92 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Synchronisation primitives.
+//!
+//! This module contains the kernel APIs related to synchronisation that have been ported or
+//! wrapped for usage by Rust code in the kernel and is shared by all of them.
+//!
+//! # Example
+//!
+//! ```no_run
+//! # use kernel::prelude::*;
+//! # use kernel::mutex_init;
+//! # use kernel::sync::Mutex;
+//! # use alloc::boxed::Box;
+//! # use core::pin::Pin;
+//! // SAFETY: `init` is called below.
+//! let mut data = Pin::from(Box::new(unsafe { Mutex::new(0) }));
+//! mutex_init!(data.as_mut(), "test::data");
+//! *data.lock() = 10;
+//! pr_info!("{}\n", *data.lock());
+//! ```
+
+use crate::{bindings, str::CStr};
+use core::pin::Pin;
+
+mod arc;
+mod condvar;
+mod guard;
+mod locked_by;
+mod mutex;
+mod revocable_mutex;
+mod seqlock;
+mod spinlock;
+
+pub use arc::{Ref, RefBorrow, UniqueRef};
+pub use condvar::CondVar;
+pub use guard::{CreatableLock, Guard, GuardMut, Lock};
+pub use locked_by::LockedBy;
+pub use mutex::Mutex;
+pub use revocable_mutex::{RevocableMutex, RevocableMutexGuard};
+pub use seqlock::{SeqLock, SeqLockReadGuard};
+pub use spinlock::SpinLock;
+
+/// Safely initialises an object that has an `init` function that takes a name and a lock class as
+/// arguments, examples of these are [`Mutex`] and [`SpinLock`]. Each of them also provides a more
+/// specialised name that uses this macro.
+#[doc(hidden)]
+#[macro_export]
+macro_rules! init_with_lockdep {
+    ($obj:expr, $name:literal) => {{
+        static mut CLASS1: core::mem::MaybeUninit<$crate::bindings::lock_class_key> =
+            core::mem::MaybeUninit::uninit();
+        static mut CLASS2: core::mem::MaybeUninit<$crate::bindings::lock_class_key> =
+            core::mem::MaybeUninit::uninit();
+        let obj = $obj;
+        let name = $crate::c_str!($name);
+        // SAFETY: `CLASS1` and `CLASS2` are never used by Rust code directly; the C portion of the
+        // kernel may change it though.
+        #[allow(unused_unsafe)]
+        unsafe {
+            $crate::sync::NeedsLockClass::init(obj, name, CLASS1.as_mut_ptr(), CLASS2.as_mut_ptr())
+        };
+    }};
+}
+
+/// A trait for types that need a lock class during initialisation.
+///
+/// Implementers of this trait benefit from the [`init_with_lockdep`] macro that generates a new
+/// class for each initialisation call site.
+pub trait NeedsLockClass {
+    /// Initialises the type instance so that it can be safely used.
+    ///
+    /// Callers are encouraged to use the [`init_with_lockdep`] macro as it automatically creates a
+    /// new lock class on each usage.
+    ///
+    /// # Safety
+    ///
+    /// `key1` and `key2` must point to valid memory locations and remain valid until `self` is
+    /// dropped.
+    unsafe fn init(
+        self: Pin<&mut Self>,
+        name: &'static CStr,
+        key1: *mut bindings::lock_class_key,
+        key2: *mut bindings::lock_class_key,
+    );
+}
+
+/// Reschedules the caller's task if needed.
+pub fn cond_resched() -> bool {
+    // SAFETY: No arguments, reschedules `current` if needed.
+    unsafe { bindings::cond_resched() != 0 }
+}
diff --git a/rust/kernel/sync/mutex.rs b/rust/kernel/sync/mutex.rs
new file mode 100644
index 000000000000..d6e5f11d2f74
--- /dev/null
+++ b/rust/kernel/sync/mutex.rs
@@ -0,0 +1,112 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! A kernel mutex.
+//!
+//! This module allows Rust code to use the kernel's [`struct mutex`].
+
+use super::{CreatableLock, GuardMut, Lock};
+use crate::{bindings, str::CStr, Opaque};
+use core::{cell::UnsafeCell, marker::PhantomPinned, pin::Pin};
+
+/// Safely initialises a [`Mutex`] with the given name, generating a new lock class.
+#[macro_export]
+macro_rules! mutex_init {
+    ($mutex:expr, $name:literal) => {
+        $crate::init_with_lockdep!($mutex, $name)
+    };
+}
+
+/// Exposes the kernel's [`struct mutex`]. When multiple threads attempt to lock the same mutex,
+/// only one at a time is allowed to progress, the others will block (sleep) until the mutex is
+/// unlocked, at which point another thread will be allowed to wake up and make progress.
+///
+/// A [`Mutex`] must first be initialised with a call to [`Mutex::init_lock`] before it can be
+/// used. The [`mutex_init`] macro is provided to automatically assign a new lock class to a mutex
+/// instance.
+///
+/// Since it may block, [`Mutex`] needs to be used with care in atomic contexts.
+///
+/// [`struct mutex`]: ../../../include/linux/mutex.h
+pub struct Mutex<T: ?Sized> {
+    /// The kernel `struct mutex` object.
+    mutex: Opaque<bindings::mutex>,
+
+    /// A mutex needs to be pinned because it contains a [`struct list_head`] that is
+    /// self-referential, so it cannot be safely moved once it is initialised.
+    _pin: PhantomPinned,
+
+    /// The data protected by the mutex.
+    data: UnsafeCell<T>,
+}
+
+// SAFETY: `Mutex` can be transferred across thread boundaries iff the data it protects can.
+#[allow(clippy::non_send_fields_in_send_ty)]
+unsafe impl<T: ?Sized + Send> Send for Mutex<T> {}
+
+// SAFETY: `Mutex` serialises the interior mutability it provides, so it is `Sync` as long as the
+// data it protects is `Send`.
+unsafe impl<T: ?Sized + Send> Sync for Mutex<T> {}
+
+impl<T> Mutex<T> {
+    /// Constructs a new mutex.
+    ///
+    /// # Safety
+    ///
+    /// The caller must call [`Mutex::init_lock`] before using the mutex.
+    pub unsafe fn new(t: T) -> Self {
+        Self {
+            mutex: Opaque::uninit(),
+            data: UnsafeCell::new(t),
+            _pin: PhantomPinned,
+        }
+    }
+}
+
+impl<T: ?Sized> Mutex<T> {
+    /// Locks the mutex and gives the caller access to the data protected by it. Only one thread at
+    /// a time is allowed to access the protected data.
+    pub fn lock(&self) -> GuardMut<'_, Self> {
+        let ctx = self.lock_noguard();
+        // SAFETY: The mutex was just acquired.
+        unsafe { GuardMut::new(self, ctx) }
+    }
+}
+
+impl<T> CreatableLock for Mutex<T> {
+    unsafe fn new_lock(data: Self::Inner) -> Self {
+        // SAFETY: The safety requirements of `new_lock` also require that `init_lock` be called.
+        unsafe { Self::new(data) }
+    }
+
+    unsafe fn init_lock(
+        self: Pin<&mut Self>,
+        name: &'static CStr,
+        key: *mut bindings::lock_class_key,
+    ) {
+        unsafe { bindings::__mutex_init(self.mutex.get(), name.as_char_ptr(), key) };
+    }
+}
+
+pub struct EmptyGuardContext;
+
+// SAFETY: The underlying kernel `struct mutex` object ensures mutual exclusion.
+unsafe impl<T: ?Sized> Lock for Mutex<T> {
+    type Inner = T;
+    type GuardContext = EmptyGuardContext;
+
+    fn lock_noguard(&self) -> EmptyGuardContext {
+        // SAFETY: `mutex` points to valid memory.
+        unsafe { bindings::mutex_lock(self.mutex.get()) };
+        EmptyGuardContext
+    }
+
+    unsafe fn unlock(&self, _: &mut EmptyGuardContext) {
+        // SAFETY: The safety requirements of the function ensure that the mutex is owned by the
+        // caller.
+        unsafe { bindings::mutex_unlock(self.mutex.get()) };
+    }
+
+    fn locked_data(&self) -> &UnsafeCell<T> {
+        &self.data
+    }
+}
diff --git a/rust/kernel/sync/revocable_mutex.rs b/rust/kernel/sync/revocable_mutex.rs
new file mode 100644
index 000000000000..0c3170213d05
--- /dev/null
+++ b/rust/kernel/sync/revocable_mutex.rs
@@ -0,0 +1,184 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! A kernel mutex where acccess to contents can be revoked at runtime.
+
+use crate::{
+    bindings,
+    str::CStr,
+    sync::{GuardMut, Mutex, NeedsLockClass},
+};
+use core::{
+    mem::ManuallyDrop,
+    ops::{Deref, DerefMut},
+    pin::Pin,
+};
+
+/// The state within a `RevocableMutex` that is protected by a mutex.
+///
+/// We don't use simply `Option<T>` because we need to drop in-place because the contents are
+/// implicitly pinned.
+struct RevocableMutexInner<T: ?Sized> {
+    is_available: bool,
+    data: ManuallyDrop<T>,
+}
+
+/// A mutex whose contents can become inaccessible at runtime.
+///
+/// Once access is revoked and all concurrent users complete (i.e., all existing instances of
+/// [`RevocableMutexGuard`] are dropped), the wrapped object is also dropped.
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::sync::RevocableMutex;
+/// # use kernel::revocable_mutex_init;
+/// # use core::pin::Pin;
+///
+/// struct Example {
+///     a: u32,
+///     b: u32,
+/// }
+///
+/// fn add_two(v: &RevocableMutex<Example>) -> Option<u32> {
+///     let guard = v.try_lock()?;
+///     Some(guard.a + guard.b)
+/// }
+///
+/// fn example() {
+///     // SAFETY: We call `revocable_mutex_init` immediately below.
+///     let mut v = unsafe { RevocableMutex::new(Example { a: 10, b: 20 }) };
+///     // SAFETY: We never move out of `v`.
+///     let pinned = unsafe { Pin::new_unchecked(&mut v) };
+///     revocable_mutex_init!(pinned, "example::v");
+///     assert_eq!(add_two(&v), Some(30));
+///     v.revoke();
+///     assert_eq!(add_two(&v), None);
+/// }
+/// ```
+pub struct RevocableMutex<T: ?Sized> {
+    inner: Mutex<RevocableMutexInner<T>>,
+}
+
+// SAFETY: `Mutex` can be transferred across thread boundaries iff the data it protects can.
+unsafe impl<T: ?Sized + Send> Send for RevocableMutex<T> {}
+
+// SAFETY: `Mutex` serialises the interior mutability it provides, so it is `Sync` as long as the
+// data it protects is `Send`.
+unsafe impl<T: ?Sized + Send> Sync for RevocableMutex<T> {}
+
+/// Safely initialises a [`RevocableMutex`] with the given name, generating a new lock class.
+#[macro_export]
+macro_rules! revocable_mutex_init {
+    ($mutex:expr, $name:literal) => {
+        $crate::init_with_lockdep!($mutex, $name)
+    };
+}
+
+impl<T> RevocableMutex<T> {
+    /// Creates a new revocable instance of the given data.
+    ///
+    /// # Safety
+    ///
+    /// The caller must call [`RevocableMutex::init`] before using the revocable mutex.
+    pub unsafe fn new(data: T) -> Self {
+        Self {
+            // SAFETY: The safety requirements of this function require that `RevocableMutex::init`
+            // be called before the returned object can be used. Mutex initialisation is called
+            // from `RevocableMutex::init`, so we satisfy the requirement from `Mutex`.
+            inner: unsafe {
+                Mutex::new(RevocableMutexInner {
+                    is_available: true,
+                    data: ManuallyDrop::new(data),
+                })
+            },
+        }
+    }
+}
+
+impl<T> NeedsLockClass for RevocableMutex<T> {
+    unsafe fn init(
+        self: Pin<&mut Self>,
+        name: &'static CStr,
+        key1: *mut bindings::lock_class_key,
+        key2: *mut bindings::lock_class_key,
+    ) {
+        // SAFETY: `inner` is pinned when `self` is.
+        let mutex = unsafe { self.map_unchecked_mut(|r| &mut r.inner) };
+
+        // SAFETY: The safety requirements of this function satisfy the ones for `Mutex::init`
+        // (they're the same).
+        unsafe { mutex.init(name, key1, key2) };
+    }
+}
+
+impl<T: ?Sized> RevocableMutex<T> {
+    /// Tries to lock (and access) the \[revocable\] wrapped object.
+    ///
+    /// Returns `None` if the object has been revoked and is therefore no longer accessible.
+    ///
+    /// Returns a guard that gives access to the object otherwise; the object is guaranteed to
+    /// remain accessible while the guard is alive. Callers are allowed to sleep while holding on
+    /// to the returned guard.
+    pub fn try_lock(&self) -> Option<RevocableMutexGuard<'_, T>> {
+        let inner = self.inner.lock();
+        if !inner.is_available {
+            return None;
+        }
+        Some(RevocableMutexGuard::new(inner))
+    }
+
+    /// Revokes access to and drops the wrapped object.
+    ///
+    /// Revocation and dropping happens after ongoing accessors complete.
+    pub fn revoke(&self) {
+        let mut inner = self.inner.lock();
+        if !inner.is_available {
+            // Already revoked.
+            return;
+        }
+
+        inner.is_available = false;
+
+        // SAFETY: We know `inner.data` is valid because `is_available` was true. We'll drop it
+        // here, and given that we set `is_available` to false above, it won't be dropped again.
+        unsafe { ManuallyDrop::drop(&mut inner.data) };
+    }
+}
+
+impl<T: ?Sized> Drop for RevocableMutex<T> {
+    fn drop(&mut self) {
+        self.revoke();
+    }
+}
+
+/// A guard that allows access to a revocable object and keeps it alive.
+pub struct RevocableMutexGuard<'a, T: ?Sized> {
+    guard: GuardMut<'a, Mutex<RevocableMutexInner<T>>>,
+}
+
+impl<'a, T: ?Sized> RevocableMutexGuard<'a, T> {
+    fn new(guard: GuardMut<'a, Mutex<RevocableMutexInner<T>>>) -> Self {
+        Self { guard }
+    }
+
+    /// Returns a pinned mutable reference to the wrapped object.
+    pub fn as_pinned_mut(&mut self) -> Pin<&mut T> {
+        // SAFETY: Revocable mutexes must be pinned, so we choose to always project the data as
+        // pinned as well (i.e., we guarantee we never move it).
+        unsafe { Pin::new_unchecked(&mut self.guard.data) }
+    }
+}
+
+impl<T: ?Sized> Deref for RevocableMutexGuard<'_, T> {
+    type Target = T;
+
+    fn deref(&self) -> &Self::Target {
+        &self.guard.data
+    }
+}
+
+impl<T: ?Sized> DerefMut for RevocableMutexGuard<'_, T> {
+    fn deref_mut(&mut self) -> &mut Self::Target {
+        &mut self.guard.data
+    }
+}
diff --git a/rust/kernel/sync/seqlock.rs b/rust/kernel/sync/seqlock.rs
new file mode 100644
index 000000000000..a45304cf0bb7
--- /dev/null
+++ b/rust/kernel/sync/seqlock.rs
@@ -0,0 +1,202 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! A kernel sequential lock (seqlock).
+//!
+//! This module allows Rust code to use the sequential locks based on the kernel's `seqcount_t` and
+//! any locks implementing the [`CreatableLock`] trait.
+//!
+//! See <https://www.kernel.org/doc/Documentation/locking/seqlock.rst>.
+
+use super::{CreatableLock, Guard, Lock, NeedsLockClass};
+use crate::{bindings, str::CStr, Opaque};
+use core::{cell::UnsafeCell, marker::PhantomPinned, ops::Deref, pin::Pin};
+
+/// Exposes sequential locks backed by the kernel's `seqcount_t`.
+///
+/// The write-side critical section is protected by a lock implementing the `CreatableLock` trait.
+///
+/// # Examples
+///
+///```
+/// # use kernel::prelude::*;
+/// use kernel::sync::{SeqLock, SpinLock};
+/// use core::sync::atomic::{AtomicU32, Ordering};
+///
+/// struct Example {
+///     a: AtomicU32,
+///     b: AtomicU32,
+/// }
+///
+/// fn get_sum(v: &SeqLock<SpinLock<Example>>) -> u32 {
+///     // Use `access` to access the fields of `Example`.
+///     v.access(|e| e.a.load(Ordering::Relaxed) + e.b.load(Ordering::Relaxed))
+/// }
+///
+/// fn get_sum_with_guard(v: &SeqLock<SpinLock<Example>>) -> u32 {
+///     // Use `read` and `need_retry` in a loop to access the fields of `Example`.
+///     loop {
+///         let guard = v.read();
+///         let sum = guard.a.load(Ordering::Relaxed) + guard.b.load(Ordering::Relaxed);
+///         if !guard.need_retry() {
+///             break sum;
+///         }
+///     }
+/// }
+///
+/// fn inc_each(v: &SeqLock<SpinLock<Example>>) {
+///     // Use a write-side guard to access the fields of `Example`.
+///     let guard = v.write();
+///     let a = guard.a.load(Ordering::Relaxed);
+///     guard.a.store(a + 1, Ordering::Relaxed);
+///     let b = guard.b.load(Ordering::Relaxed);
+///     guard.b.store(b + 1, Ordering::Relaxed);
+/// }
+/// ```
+pub struct SeqLock<L: CreatableLock + ?Sized> {
+    _p: PhantomPinned,
+    count: Opaque<bindings::seqcount>,
+    write_lock: L,
+}
+
+// SAFETY: `SeqLock` can be transferred across thread boundaries iff the data it protects and the
+// underlying lock can.
+#[allow(clippy::non_send_fields_in_send_ty)]
+unsafe impl<L: CreatableLock + Send> Send for SeqLock<L> where L::Inner: Send {}
+
+// SAFETY: `SeqLock` allows concurrent access to the data it protects by both readers and writers,
+// so it requires that the data it protects be `Sync`, as well as the underlying lock.
+unsafe impl<L: CreatableLock + Sync> Sync for SeqLock<L> where L::Inner: Sync {}
+
+impl<L: CreatableLock> SeqLock<L> {
+    /// Constructs a new instance of [`SeqLock`].
+    ///
+    /// # Safety
+    ///
+    /// The caller must call [`SeqLock::init`] before using the seqlock.
+    pub unsafe fn new(data: L::Inner) -> Self
+    where
+        L::Inner: Sized,
+    {
+        Self {
+            _p: PhantomPinned,
+            count: Opaque::uninit(),
+            // SAFETY: `L::init_lock` is called from `SeqLock::init`, which is required to be
+            // called by the function's safety requirements.
+            write_lock: unsafe { L::new_lock(data) },
+        }
+    }
+}
+
+impl<L: CreatableLock + ?Sized> SeqLock<L> {
+    /// Accesses the protected data in read mode.
+    ///
+    /// Readers and writers are allowed to run concurrently, so callers must check if they need to
+    /// refetch the values before they are used (e.g., because a writer changed them concurrently,
+    /// rendering them potentially inconsistent). The check is performed via calls to
+    /// [`SeqLockReadGuard::need_retry`].
+    pub fn read(&self) -> SeqLockReadGuard<'_, L> {
+        SeqLockReadGuard {
+            lock: self,
+            // SAFETY: `count` contains valid memory.
+            start_count: unsafe { bindings::read_seqcount_begin(self.count.get()) },
+        }
+    }
+
+    /// Accesses the protected data in read mode.
+    ///
+    /// The provided closure is called repeatedly if it may have accessed inconsistent data (e.g.,
+    /// because a concurrent writer modified it). This is a wrapper around [`SeqLock::read`] and
+    /// [`SeqLockReadGuard::need_retry`] in a loop.
+    pub fn access<F: Fn(&L::Inner) -> R, R>(&self, cb: F) -> R {
+        loop {
+            let guard = self.read();
+            let ret = cb(&guard);
+            if !guard.need_retry() {
+                return ret;
+            }
+        }
+    }
+
+    /// Locks the underlying lock and returns a guard that allows access to the protected data.
+    ///
+    /// The guard is not mutable though because readers are still allowed to concurrently access
+    /// the data. The protected data structure needs to provide interior mutability itself (e.g.,
+    /// via atomic types) for the individual fields that can be mutated.
+    pub fn write(&self) -> Guard<'_, Self> {
+        let ctx = self.lock_noguard();
+        // SAFETY: The seqlock was just acquired.
+        unsafe { Guard::new(self, ctx) }
+    }
+}
+
+impl<L: CreatableLock + ?Sized> NeedsLockClass for SeqLock<L> {
+    unsafe fn init(
+        mut self: Pin<&mut Self>,
+        name: &'static CStr,
+        key1: *mut bindings::lock_class_key,
+        key2: *mut bindings::lock_class_key,
+    ) {
+        // SAFETY: `write_lock` is pinned when `self` is.
+        let pinned = unsafe { self.as_mut().map_unchecked_mut(|s| &mut s.write_lock) };
+        // SAFETY: `key1` is valid by the safety requirements of this function.
+        unsafe { pinned.init_lock(name, key1) };
+        // SAFETY: `key2` is valid by the safety requirements of this function.
+        unsafe { bindings::__seqcount_init(self.count.get(), name.as_char_ptr(), key2) };
+    }
+}
+
+// SAFETY: The underlying lock ensures mutual exclusion.
+unsafe impl<L: CreatableLock + ?Sized> Lock for SeqLock<L> {
+    type Inner = L::Inner;
+    type GuardContext = L::GuardContext;
+
+    fn lock_noguard(&self) -> L::GuardContext {
+        let ctx = self.write_lock.lock_noguard();
+        // SAFETY: `count` contains valid memory.
+        unsafe { bindings::write_seqcount_begin(self.count.get()) };
+        ctx
+    }
+
+    fn relock(&self, ctx: &mut L::GuardContext) {
+        self.write_lock.relock(ctx);
+        // SAFETY: `count` contains valid memory.
+        unsafe { bindings::write_seqcount_begin(self.count.get()) };
+    }
+
+    unsafe fn unlock(&self, ctx: &mut L::GuardContext) {
+        // SAFETY: The safety requirements of the function ensure that lock is owned by the caller.
+        unsafe { bindings::write_seqcount_end(self.count.get()) };
+        // SAFETY: The safety requirements of the function ensure that lock is owned by the caller.
+        unsafe { self.write_lock.unlock(ctx) };
+    }
+
+    fn locked_data(&self) -> &UnsafeCell<L::Inner> {
+        self.write_lock.locked_data()
+    }
+}
+
+/// Allows read-side access to data protected by a sequential lock.
+pub struct SeqLockReadGuard<'a, L: CreatableLock + ?Sized> {
+    lock: &'a SeqLock<L>,
+    start_count: u32,
+}
+
+impl<L: CreatableLock + ?Sized> SeqLockReadGuard<'_, L> {
+    /// Determine if the callers needs to retry reading values.
+    ///
+    /// It returns `true` when a concurrent writer ran between the guard being created and
+    /// [`Self::need_retry`] being called.
+    pub fn need_retry(&self) -> bool {
+        // SAFETY: `count` is valid because the guard guarantees that the lock remains alive.
+        unsafe { bindings::read_seqcount_retry(self.lock.count.get(), self.start_count) != 0 }
+    }
+}
+
+impl<L: CreatableLock + ?Sized> Deref for SeqLockReadGuard<'_, L> {
+    type Target = L::Inner;
+
+    fn deref(&self) -> &Self::Target {
+        // SAFETY: We only ever allow shared access to the protected data.
+        unsafe { &*self.lock.locked_data().get() }
+    }
+}
diff --git a/rust/kernel/sync/spinlock.rs b/rust/kernel/sync/spinlock.rs
new file mode 100644
index 000000000000..f4bcf57043ca
--- /dev/null
+++ b/rust/kernel/sync/spinlock.rs
@@ -0,0 +1,180 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! A kernel spinlock.
+//!
+//! This module allows Rust code to use the kernel's [`struct spinlock`].
+//!
+//! See <https://www.kernel.org/doc/Documentation/locking/spinlocks.txt>.
+
+use super::{CreatableLock, GuardMut, Lock};
+use crate::{bindings, c_types, str::CStr, Opaque};
+use core::{cell::UnsafeCell, marker::PhantomPinned, pin::Pin};
+
+/// Safely initialises a [`SpinLock`] with the given name, generating a new lock class.
+#[macro_export]
+macro_rules! spinlock_init {
+    ($spinlock:expr, $name:literal) => {
+        $crate::init_with_lockdep!($spinlock, $name)
+    };
+}
+
+/// Exposes the kernel's [`spinlock_t`]. When multiple CPUs attempt to lock the same spinlock, only
+/// one at a time is allowed to progress, the others will block (spinning) until the spinlock is
+/// unlocked, at which point another CPU will be allowed to make progress.
+///
+/// A [`SpinLock`] must first be initialised with a call to [`SpinLock::init_lock`] before it can be
+/// used. The [`spinlock_init`] macro is provided to automatically assign a new lock class to a
+/// spinlock instance.
+///
+/// There are two ways to acquire the lock:
+///  - [`SpinLock::lock`], which doesn't manage interrupt state, so it should be used in only two
+///    cases: (a) when the caller knows that interrupts are disabled, or (b) when callers never use
+///    it in atomic context (e.g., interrupt handlers), in which case it is ok for interrupts to be
+///    enabled.
+///  - [`SpinLock::lock_irqdisable`], which disables interrupts if they are enabled before
+///    acquiring the lock. When the lock is released, the interrupt state is automatically returned
+///    to its value before [`SpinLock::lock_irqdisable`] was called.
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::prelude::*;
+/// # use kernel::sync::SpinLock;
+/// # use core::pin::Pin;
+///
+/// struct Example {
+///     a: u32,
+///     b: u32,
+/// }
+///
+/// // Function that acquires spinlock without changing interrupt state.
+/// fn lock_example(value: &SpinLock<Example>) {
+///     let mut guard = value.lock();
+///     guard.a = 10;
+///     guard.b = 20;
+/// }
+///
+/// // Function that acquires spinlock and disables interrupts while holding it.
+/// fn lock_irqdisable_example(value: &SpinLock<Example>) {
+///     let mut guard = value.lock_irqdisable();
+///     guard.a = 30;
+///     guard.b = 40;
+/// }
+///
+/// // Initialises a spinlock and calls the example functions.
+/// pub fn spinlock_example() {
+///     // SAFETY: `spinlock_init` is called below.
+///     let mut value = unsafe { SpinLock::new(Example { a: 1, b: 2 }) };
+///     // SAFETY: We don't move `value`.
+///     kernel::spinlock_init!(unsafe { Pin::new_unchecked(&mut value) }, "value");
+///     lock_example(&value);
+///     lock_irqdisable_example(&value);
+/// }
+/// ```
+///
+/// [`spinlock_t`]: ../../../include/linux/spinlock.h
+pub struct SpinLock<T: ?Sized> {
+    spin_lock: Opaque<bindings::spinlock>,
+
+    /// Spinlocks are architecture-defined. So we conservatively require them to be pinned in case
+    /// some architecture uses self-references now or in the future.
+    _pin: PhantomPinned,
+
+    data: UnsafeCell<T>,
+}
+
+// SAFETY: `SpinLock` can be transferred across thread boundaries iff the data it protects can.
+unsafe impl<T: ?Sized + Send> Send for SpinLock<T> {}
+
+// SAFETY: `SpinLock` serialises the interior mutability it provides, so it is `Sync` as long as the
+// data it protects is `Send`.
+unsafe impl<T: ?Sized + Send> Sync for SpinLock<T> {}
+
+impl<T> SpinLock<T> {
+    /// Constructs a new spinlock.
+    ///
+    /// # Safety
+    ///
+    /// The caller must call [`SpinLock::init_lock`] before using the spinlock.
+    pub unsafe fn new(t: T) -> Self {
+        Self {
+            spin_lock: Opaque::uninit(),
+            data: UnsafeCell::new(t),
+            _pin: PhantomPinned,
+        }
+    }
+}
+
+impl<T: ?Sized> SpinLock<T> {
+    /// Locks the spinlock and gives the caller access to the data protected by it. Only one thread
+    /// at a time is allowed to access the protected data.
+    pub fn lock(&self) -> GuardMut<'_, Self> {
+        let ctx = self.lock_noguard();
+        // SAFETY: The spinlock was just acquired.
+        unsafe { GuardMut::new(self, ctx) }
+    }
+
+    /// Locks the spinlock and gives the caller access to the data protected by it. Additionally it
+    /// disables interrupts (if they are enabled).
+    ///
+    /// When the lock in unlocked, the interrupt state (enabled/disabled) is restored.
+    pub fn lock_irqdisable(&self) -> GuardMut<'_, Self> {
+        let ctx = self.internal_lock_irqsave();
+        // SAFETY: The spinlock was just acquired.
+        unsafe { GuardMut::new(self, Some(ctx)) }
+    }
+
+    fn internal_lock_irqsave(&self) -> c_types::c_ulong {
+        // SAFETY: `spin_lock` points to valid memory.
+        unsafe { bindings::spin_lock_irqsave(self.spin_lock.get()) }
+    }
+}
+
+impl<T> CreatableLock for SpinLock<T> {
+    unsafe fn new_lock(data: Self::Inner) -> Self {
+        // SAFETY: The safety requirements of `new_lock` also require that `init_lock` be called.
+        unsafe { Self::new(data) }
+    }
+
+    unsafe fn init_lock(
+        self: Pin<&mut Self>,
+        name: &'static CStr,
+        key: *mut bindings::lock_class_key,
+    ) {
+        unsafe { bindings::__spin_lock_init(self.spin_lock.get(), name.as_char_ptr(), key) };
+    }
+}
+
+// SAFETY: The underlying kernel `spinlock_t` object ensures mutual exclusion.
+unsafe impl<T: ?Sized> Lock for SpinLock<T> {
+    type Inner = T;
+    type GuardContext = Option<c_types::c_ulong>;
+
+    fn lock_noguard(&self) -> Option<c_types::c_ulong> {
+        // SAFETY: `spin_lock` points to valid memory.
+        unsafe { bindings::spin_lock(self.spin_lock.get()) };
+        None
+    }
+
+    unsafe fn unlock(&self, ctx: &mut Option<c_types::c_ulong>) {
+        match ctx {
+            // SAFETY: The safety requirements of the function ensure that the spinlock is owned by
+            // the caller.
+            Some(v) => unsafe { bindings::spin_unlock_irqrestore(self.spin_lock.get(), *v) },
+            // SAFETY: The safety requirements of the function ensure that the spinlock is owned by
+            // the caller.
+            None => unsafe { bindings::spin_unlock(self.spin_lock.get()) },
+        }
+    }
+
+    fn relock(&self, ctx: &mut Self::GuardContext) {
+        match ctx {
+            Some(v) => *v = self.internal_lock_irqsave(),
+            None => *ctx = self.lock_noguard(),
+        }
+    }
+
+    fn locked_data(&self) -> &UnsafeCell<T> {
+        &self.data
+    }
+}
diff --git a/rust/kernel/sysctl.rs b/rust/kernel/sysctl.rs
new file mode 100644
index 000000000000..0c74245cb204
--- /dev/null
+++ b/rust/kernel/sysctl.rs
@@ -0,0 +1,197 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! System control.
+//!
+//! C header: [`include/linux/sysctl.h`](../../../../include/linux/sysctl.h)
+//!
+//! Reference: <https://www.kernel.org/doc/Documentation/sysctl/README>
+
+use alloc::boxed::Box;
+use alloc::vec::Vec;
+use core::mem;
+use core::ptr;
+use core::sync::atomic;
+
+use crate::{
+    bindings, c_types, error,
+    io_buffer::IoBufferWriter,
+    str::CStr,
+    types,
+    user_ptr::{UserSlicePtr, UserSlicePtrWriter},
+};
+
+/// Sysctl storage.
+pub trait SysctlStorage: Sync {
+    /// Writes a byte slice.
+    fn store_value(&self, data: &[u8]) -> (usize, error::Result);
+
+    /// Reads via a [`UserSlicePtrWriter`].
+    fn read_value(&self, data: &mut UserSlicePtrWriter) -> (usize, error::Result);
+}
+
+fn trim_whitespace(mut data: &[u8]) -> &[u8] {
+    while !data.is_empty() && (data[0] == b' ' || data[0] == b'\t' || data[0] == b'\n') {
+        data = &data[1..];
+    }
+    while !data.is_empty()
+        && (data[data.len() - 1] == b' '
+            || data[data.len() - 1] == b'\t'
+            || data[data.len() - 1] == b'\n')
+    {
+        data = &data[..data.len() - 1];
+    }
+    data
+}
+
+impl<T> SysctlStorage for &T
+where
+    T: SysctlStorage,
+{
+    fn store_value(&self, data: &[u8]) -> (usize, error::Result) {
+        (*self).store_value(data)
+    }
+
+    fn read_value(&self, data: &mut UserSlicePtrWriter) -> (usize, error::Result) {
+        (*self).read_value(data)
+    }
+}
+
+impl SysctlStorage for atomic::AtomicBool {
+    fn store_value(&self, data: &[u8]) -> (usize, error::Result) {
+        let result = match trim_whitespace(data) {
+            b"0" => {
+                self.store(false, atomic::Ordering::Relaxed);
+                Ok(())
+            }
+            b"1" => {
+                self.store(true, atomic::Ordering::Relaxed);
+                Ok(())
+            }
+            _ => Err(error::Error::EINVAL),
+        };
+        (data.len(), result)
+    }
+
+    fn read_value(&self, data: &mut UserSlicePtrWriter) -> (usize, error::Result) {
+        let value = if self.load(atomic::Ordering::Relaxed) {
+            b"1\n"
+        } else {
+            b"0\n"
+        };
+        (value.len(), data.write_slice(value))
+    }
+}
+
+/// Holds a single `sysctl` entry (and its table).
+pub struct Sysctl<T: SysctlStorage> {
+    inner: Box<T>,
+    // Responsible for keeping the `ctl_table` alive.
+    _table: Box<[bindings::ctl_table]>,
+    header: *mut bindings::ctl_table_header,
+}
+
+// SAFETY: The only public method we have is `get()`, which returns `&T`, and
+// `T: Sync`. Any new methods must adhere to this requirement.
+unsafe impl<T: SysctlStorage> Sync for Sysctl<T> {}
+
+unsafe extern "C" fn proc_handler<T: SysctlStorage>(
+    ctl: *mut bindings::ctl_table,
+    write: c_types::c_int,
+    buffer: *mut c_types::c_void,
+    len: *mut usize,
+    ppos: *mut bindings::loff_t,
+) -> c_types::c_int {
+    // If we are reading from some offset other than the beginning of the file,
+    // return an empty read to signal EOF.
+    if unsafe { *ppos } != 0 && write == 0 {
+        unsafe { *len = 0 };
+        return 0;
+    }
+
+    let data = unsafe { UserSlicePtr::new(buffer, *len) };
+    let storage = unsafe { &*((*ctl).data as *const T) };
+    let (bytes_processed, result) = if write != 0 {
+        let data = match data.read_all() {
+            Ok(r) => r,
+            Err(e) => return e.to_kernel_errno(),
+        };
+        storage.store_value(&data)
+    } else {
+        let mut writer = data.writer();
+        storage.read_value(&mut writer)
+    };
+    unsafe { *len = bytes_processed };
+    unsafe { *ppos += *len as bindings::loff_t };
+    match result {
+        Ok(()) => 0,
+        Err(e) => e.to_kernel_errno(),
+    }
+}
+
+impl<T: SysctlStorage> Sysctl<T> {
+    /// Registers a single entry in `sysctl`.
+    pub fn register(
+        path: &'static CStr,
+        name: &'static CStr,
+        storage: T,
+        mode: types::Mode,
+    ) -> error::Result<Sysctl<T>> {
+        if name.contains(&b'/') {
+            return Err(error::Error::EINVAL);
+        }
+
+        let storage = Box::try_new(storage)?;
+        let mut table = Vec::try_with_capacity(2)?;
+        table.try_push(bindings::ctl_table {
+            procname: name.as_char_ptr(),
+            mode: mode.as_int(),
+            data: &*storage as *const T as *mut c_types::c_void,
+            proc_handler: Some(proc_handler::<T>),
+
+            maxlen: 0,
+            child: ptr::null_mut(),
+            poll: ptr::null_mut(),
+            extra1: ptr::null_mut(),
+            extra2: ptr::null_mut(),
+        })?;
+        table.try_push(unsafe { mem::zeroed() })?;
+        let mut table = table.try_into_boxed_slice()?;
+
+        let result = unsafe { bindings::register_sysctl(path.as_char_ptr(), table.as_mut_ptr()) };
+        if result.is_null() {
+            return Err(error::Error::ENOMEM);
+        }
+
+        Ok(Sysctl {
+            inner: storage,
+            _table: table,
+            header: result,
+        })
+    }
+
+    /// Gets the storage.
+    pub fn get(&self) -> &T {
+        &self.inner
+    }
+}
+
+impl<T: SysctlStorage> Drop for Sysctl<T> {
+    fn drop(&mut self) {
+        unsafe {
+            bindings::unregister_sysctl_table(self.header);
+        }
+        self.header = ptr::null_mut();
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn test_trim_whitespace() {
+        assert_eq!(trim_whitespace(b"foo    "), b"foo");
+        assert_eq!(trim_whitespace(b"    foo"), b"foo");
+        assert_eq!(trim_whitespace(b"  foo  "), b"foo");
+    }
+}
diff --git a/rust/kernel/task.rs b/rust/kernel/task.rs
new file mode 100644
index 000000000000..7a2aff0e9219
--- /dev/null
+++ b/rust/kernel/task.rs
@@ -0,0 +1,182 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Tasks (threads and processes).
+//!
+//! C header: [`include/linux/sched.h`](../../../../include/linux/sched.h).
+
+use crate::bindings;
+use core::{marker::PhantomData, mem::ManuallyDrop, ops::Deref};
+
+/// Wraps the kernel's `struct task_struct`.
+///
+/// # Invariants
+///
+/// The pointer `Task::ptr` is non-null and valid. Its reference count is also non-zero.
+///
+/// # Examples
+///
+/// The following is an example of getting the PID of the current thread with zero additional cost
+/// when compared to the C version:
+///
+/// ```
+/// # use kernel::prelude::*;
+/// use kernel::task::Task;
+///
+/// # fn test() {
+/// Task::current().pid();
+/// # }
+/// ```
+///
+/// Getting the PID of the current process, also zero additional cost:
+///
+/// ```
+/// # use kernel::prelude::*;
+/// use kernel::task::Task;
+///
+/// # fn test() {
+/// Task::current().group_leader().pid();
+/// # }
+/// ```
+///
+/// Getting the current task and storing it in some struct. The reference count is automatically
+/// incremented when creating `State` and decremented when it is dropped:
+///
+/// ```
+/// # use kernel::prelude::*;
+/// use kernel::task::Task;
+///
+/// struct State {
+///     creator: Task,
+///     index: u32,
+/// }
+///
+/// impl State {
+///     fn new() -> Self {
+///         Self {
+///             creator: Task::current().clone(),
+///             index: 0,
+///         }
+///     }
+/// }
+/// ```
+pub struct Task {
+    pub(crate) ptr: *mut bindings::task_struct,
+}
+
+// SAFETY: Given that the task is referenced, it is OK to send it to another thread.
+unsafe impl Send for Task {}
+
+// SAFETY: It's OK to access `Task` through references from other threads because we're either
+// accessing properties that don't change (e.g., `pid`, `group_leader`) or that are properly
+// synchronised by C code (e.g., `signal_pending`).
+unsafe impl Sync for Task {}
+
+/// The type of process identifiers (PIDs).
+type Pid = bindings::pid_t;
+
+impl Task {
+    /// Returns a task reference for the currently executing task/thread.
+    pub fn current<'a>() -> TaskRef<'a> {
+        // SAFETY: Just an FFI call.
+        let ptr = unsafe { bindings::get_current() };
+
+        // SAFETY: If the current thread is still running, the current task is valid. Given
+        // that `TaskRef` is not `Send`, we know it cannot be transferred to another thread (where
+        // it could potentially outlive the caller).
+        unsafe { TaskRef::from_ptr(ptr) }
+    }
+
+    /// Returns the group leader of the given task.
+    pub fn group_leader(&self) -> TaskRef<'_> {
+        // SAFETY: By the type invariant, we know that `self.ptr` is non-null and valid.
+        let ptr = unsafe { (*self.ptr).group_leader };
+
+        // SAFETY: The lifetime of the returned task reference is tied to the lifetime of `self`,
+        // and given that a task has a reference to its group leader, we know it must be valid for
+        // the lifetime of the returned task reference.
+        unsafe { TaskRef::from_ptr(ptr) }
+    }
+
+    /// Returns the PID of the given task.
+    pub fn pid(&self) -> Pid {
+        // SAFETY: By the type invariant, we know that `self.ptr` is non-null and valid.
+        unsafe { (*self.ptr).pid }
+    }
+
+    /// Determines whether the given task has pending signals.
+    pub fn signal_pending(&self) -> bool {
+        // SAFETY: By the type invariant, we know that `self.ptr` is non-null and valid.
+        unsafe { bindings::signal_pending(self.ptr) != 0 }
+    }
+}
+
+impl PartialEq for Task {
+    fn eq(&self, other: &Self) -> bool {
+        self.ptr == other.ptr
+    }
+}
+
+impl Eq for Task {}
+
+impl Clone for Task {
+    fn clone(&self) -> Self {
+        // SAFETY: The type invariants guarantee that `self.ptr` has a non-zero reference count.
+        unsafe { bindings::get_task_struct(self.ptr) };
+
+        // INVARIANT: We incremented the reference count to account for the new `Task` being
+        // created.
+        Self { ptr: self.ptr }
+    }
+}
+
+impl Drop for Task {
+    fn drop(&mut self) {
+        // INVARIANT: We may decrement the refcount to zero, but the `Task` is being dropped, so
+        // this is not observable.
+        // SAFETY: The type invariants guarantee that `Task::ptr` has a non-zero reference count.
+        unsafe { bindings::put_task_struct(self.ptr) };
+    }
+}
+
+/// A wrapper for [`Task`] that doesn't automatically decrement the refcount when dropped.
+///
+/// We need the wrapper because [`ManuallyDrop`] alone would allow callers to call
+/// [`ManuallyDrop::into_inner`]. This would allow an unsafe sequence to be triggered without
+/// `unsafe` blocks because it would trigger an unbalanced call to `put_task_struct`.
+///
+/// We make this explicitly not [`Send`] so that we can use it to represent the current thread
+/// without having to increment/decrement its reference count.
+///
+/// # Invariants
+///
+/// The wrapped [`Task`] remains valid for the lifetime of the object.
+pub struct TaskRef<'a> {
+    task: ManuallyDrop<Task>,
+    _not_send: PhantomData<(&'a (), *mut ())>,
+}
+
+impl TaskRef<'_> {
+    /// Constructs a new `struct task_struct` wrapper that doesn't change its reference count.
+    ///
+    /// # Safety
+    ///
+    /// The pointer `ptr` must be non-null and valid for the lifetime of the object.
+    pub(crate) unsafe fn from_ptr(ptr: *mut bindings::task_struct) -> Self {
+        Self {
+            task: ManuallyDrop::new(Task { ptr }),
+            _not_send: PhantomData,
+        }
+    }
+}
+
+// SAFETY: It is OK to share a reference to the current thread with another thread because we know
+// the owner cannot go away while the shared reference exists (and `Task` itself is `Sync`).
+unsafe impl Sync for TaskRef<'_> {}
+
+impl Deref for TaskRef<'_> {
+    type Target = Task;
+
+    fn deref(&self) -> &Self::Target {
+        self.task.deref()
+    }
+}
diff --git a/rust/kernel/types.rs b/rust/kernel/types.rs
new file mode 100644
index 000000000000..64f11005b553
--- /dev/null
+++ b/rust/kernel/types.rs
@@ -0,0 +1,486 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Kernel types.
+//!
+//! C header: [`include/linux/types.h`](../../../../include/linux/types.h)
+
+use crate::{
+    bindings, c_types,
+    sync::{Ref, RefBorrow},
+};
+use alloc::boxed::Box;
+use core::{
+    cell::UnsafeCell,
+    mem::MaybeUninit,
+    ops::{self, Deref, DerefMut},
+    pin::Pin,
+};
+
+/// Permissions.
+///
+/// C header: [`include/uapi/linux/stat.h`](../../../../include/uapi/linux/stat.h)
+///
+/// C header: [`include/linux/stat.h`](../../../../include/linux/stat.h)
+pub struct Mode(bindings::umode_t);
+
+impl Mode {
+    /// Creates a [`Mode`] from an integer.
+    pub fn from_int(m: u16) -> Mode {
+        Mode(m)
+    }
+
+    /// Returns the mode as an integer.
+    pub fn as_int(&self) -> u16 {
+        self.0
+    }
+}
+
+/// Used to convert an object into a raw pointer that represents it.
+///
+/// It can eventually be converted back into the object. This is used to store objects as pointers
+/// in kernel data structures, for example, an implementation of [`FileOperations`] in `struct
+/// file::private_data`.
+pub trait PointerWrapper {
+    /// Type of values borrowed between calls to [`PointerWrapper::into_pointer`] and
+    /// [`PointerWrapper::from_pointer`].
+    type Borrowed<'a>;
+
+    /// Returns the raw pointer.
+    fn into_pointer(self) -> *const c_types::c_void;
+
+    /// Returns a borrowed value.
+    ///
+    /// # Safety
+    ///
+    /// `ptr` must have been returned by a previous call to [`PointerWrapper::into_pointer`].
+    /// Additionally, [`PointerWrapper::from_pointer`] can only be called after *all* values
+    /// returned by [`PointerWrapper::borrow`] have been dropped.
+    unsafe fn borrow<'a>(ptr: *const c_types::c_void) -> Self::Borrowed<'a>;
+
+    /// Returns the instance back from the raw pointer.
+    ///
+    /// # Safety
+    ///
+    /// The passed pointer must come from a previous call to [`PointerWrapper::into_pointer()`].
+    unsafe fn from_pointer(ptr: *const c_types::c_void) -> Self;
+}
+
+impl<T: 'static> PointerWrapper for Box<T> {
+    type Borrowed<'a> = &'a T;
+
+    fn into_pointer(self) -> *const c_types::c_void {
+        Box::into_raw(self) as _
+    }
+
+    unsafe fn borrow<'a>(ptr: *const c_types::c_void) -> &'a T {
+        // SAFETY: The safety requirements for this function ensure that the object is still alive,
+        // so it is safe to dereference the raw pointer.
+        // The safety requirements also ensure that the object remains alive for the lifetime of
+        // the returned value.
+        unsafe { &*ptr.cast() }
+    }
+
+    unsafe fn from_pointer(ptr: *const c_types::c_void) -> Self {
+        // SAFETY: The passed pointer comes from a previous call to [`Self::into_pointer()`].
+        unsafe { Box::from_raw(ptr as _) }
+    }
+}
+
+impl<T: 'static> PointerWrapper for Ref<T> {
+    type Borrowed<'a> = RefBorrow<'a, T>;
+
+    fn into_pointer(self) -> *const c_types::c_void {
+        Ref::into_usize(self) as _
+    }
+
+    unsafe fn borrow<'a>(ptr: *const c_types::c_void) -> RefBorrow<'a, T> {
+        // SAFETY: The safety requirements for this function ensure that the underlying object
+        // remains valid for the lifetime of the returned value.
+        unsafe { Ref::borrow_usize(ptr as _) }
+    }
+
+    unsafe fn from_pointer(ptr: *const c_types::c_void) -> Self {
+        // SAFETY: The passed pointer comes from a previous call to [`Self::into_pointer()`].
+        unsafe { Ref::from_usize(ptr as _) }
+    }
+}
+
+impl<T: PointerWrapper + Deref> PointerWrapper for Pin<T> {
+    type Borrowed<'a> = T::Borrowed<'a>;
+
+    fn into_pointer(self) -> *const c_types::c_void {
+        // SAFETY: We continue to treat the pointer as pinned by returning just a pointer to it to
+        // the caller.
+        let inner = unsafe { Pin::into_inner_unchecked(self) };
+        inner.into_pointer()
+    }
+
+    unsafe fn borrow<'a>(ptr: *const c_types::c_void) -> Self::Borrowed<'a> {
+        // SAFETY: The safety requirements for this function are the same as the ones for
+        // `T::borrow`.
+        unsafe { T::borrow(ptr) }
+    }
+
+    unsafe fn from_pointer(p: *const c_types::c_void) -> Self {
+        // SAFETY: The object was originally pinned.
+        // The passed pointer comes from a previous call to `inner::into_pointer()`.
+        unsafe { Pin::new_unchecked(T::from_pointer(p)) }
+    }
+}
+
+impl<T> PointerWrapper for *mut T {
+    type Borrowed<'a> = *mut T;
+
+    fn into_pointer(self) -> *const c_types::c_void {
+        self as _
+    }
+
+    unsafe fn borrow<'a>(ptr: *const c_types::c_void) -> Self::Borrowed<'a> {
+        ptr as _
+    }
+
+    unsafe fn from_pointer(ptr: *const c_types::c_void) -> Self {
+        ptr as _
+    }
+}
+
+impl PointerWrapper for () {
+    type Borrowed<'a> = ();
+
+    fn into_pointer(self) -> *const c_types::c_void {
+        // We use 1 to be different from a null pointer.
+        1usize as _
+    }
+
+    unsafe fn borrow<'a>(_: *const c_types::c_void) -> Self::Borrowed<'a> {}
+
+    unsafe fn from_pointer(_: *const c_types::c_void) -> Self {}
+}
+
+/// Runs a cleanup function/closure when dropped.
+///
+/// The [`ScopeGuard::dismiss`] function prevents the cleanup function from running.
+///
+/// # Examples
+///
+/// In the example below, we have multiple exit paths and we want to log regardless of which one is
+/// taken:
+/// ```
+/// # use kernel::prelude::*;
+/// # use kernel::ScopeGuard;
+/// fn example1(arg: bool) {
+///     let _log = ScopeGuard::new(|| pr_info!("example1 completed\n"));
+///
+///     if arg {
+///         return;
+///     }
+///
+///     // Do something...
+/// }
+/// ```
+///
+/// In the example below, we want to log the same message on all early exits but a different one on
+/// the main exit path:
+/// ```
+/// # use kernel::prelude::*;
+/// # use kernel::ScopeGuard;
+/// fn example2(arg: bool) {
+///     let log = ScopeGuard::new(|| pr_info!("example2 returned early\n"));
+///
+///     if arg {
+///         return;
+///     }
+///
+///     // (Other early returns...)
+///
+///     log.dismiss();
+///     pr_info!("example2 no early return\n");
+/// }
+/// ```
+///
+/// In the example below, we need a mutable object (the vector) to be accessible within the log
+/// function, so we wrap it in the [`ScopeGuard`]:
+/// ```
+/// # use kernel::prelude::*;
+/// # use kernel::ScopeGuard;
+/// fn example3(arg: bool) -> Result {
+///     let mut vec =
+///         ScopeGuard::new_with_data(Vec::new(), |v| pr_info!("vec had {} elements\n", v.len()));
+///
+///     vec.try_push(10u8)?;
+///     if arg {
+///         return Ok(());
+///     }
+///     vec.try_push(20u8)?;
+///     Ok(())
+/// }
+/// ```
+///
+/// # Invariants
+///
+/// The value stored in the struct is nearly always `Some(_)`, except between
+/// [`ScopeGuard::dismiss`] and [`ScopeGuard::drop`]: in this case, it will be `None` as the value
+/// will have been returned to the caller. Since  [`ScopeGuard::dismiss`] consumes the guard,
+/// callers won't be able to use it anymore.
+pub struct ScopeGuard<T, F: FnOnce(T)>(Option<(T, F)>);
+
+impl<T, F: FnOnce(T)> ScopeGuard<T, F> {
+    /// Creates a new guarded object wrapping the given data and with the given cleanup function.
+    pub fn new_with_data(data: T, cleanup_func: F) -> Self {
+        // INVARIANT: The struct is being initialised with `Some(_)`.
+        Self(Some((data, cleanup_func)))
+    }
+
+    /// Prevents the cleanup function from running and returns the guarded data.
+    pub fn dismiss(mut self) -> T {
+        // INVARIANT: This is the exception case in the invariant; it is not visible to callers
+        // because this function consumes `self`.
+        self.0.take().unwrap().0
+    }
+}
+
+impl ScopeGuard<(), Box<dyn FnOnce(())>> {
+    /// Creates a new guarded object with the given cleanup function.
+    pub fn new(cleanup: impl FnOnce()) -> ScopeGuard<(), impl FnOnce(())> {
+        ScopeGuard::new_with_data((), move |_| cleanup())
+    }
+}
+
+impl<T, F: FnOnce(T)> Deref for ScopeGuard<T, F> {
+    type Target = T;
+
+    fn deref(&self) -> &T {
+        // The type invariants guarantee that `unwrap` will succeed.
+        &self.0.as_ref().unwrap().0
+    }
+}
+
+impl<T, F: FnOnce(T)> DerefMut for ScopeGuard<T, F> {
+    fn deref_mut(&mut self) -> &mut T {
+        // The type invariants guarantee that `unwrap` will succeed.
+        &mut self.0.as_mut().unwrap().0
+    }
+}
+
+impl<T, F: FnOnce(T)> Drop for ScopeGuard<T, F> {
+    fn drop(&mut self) {
+        // Run the cleanup function if one is still present.
+        if let Some((data, cleanup)) = self.0.take() {
+            cleanup(data)
+        }
+    }
+}
+
+/// Stores an opaque value.
+///
+/// This is meant to be used with FFI objects that are never interpreted by Rust code.
+pub struct Opaque<T>(MaybeUninit<UnsafeCell<T>>);
+
+impl<T> Opaque<T> {
+    /// Creates a new opaque value.
+    pub fn new(value: T) -> Self {
+        Self(MaybeUninit::new(UnsafeCell::new(value)))
+    }
+
+    /// Creates an uninitialised value.
+    pub fn uninit() -> Self {
+        Self(MaybeUninit::uninit())
+    }
+
+    /// Returns a raw pointer to the opaque data.
+    pub fn get(&self) -> *mut T {
+        UnsafeCell::raw_get(self.0.as_ptr())
+    }
+}
+
+/// A bitmask.
+///
+/// It has a restriction that all bits must be the same, except one. For example, `0b1110111` and
+/// `0b1000` are acceptable masks.
+#[derive(Clone, Copy)]
+pub struct Bit<T> {
+    index: T,
+    inverted: bool,
+}
+
+/// Creates a bit mask with a single bit set.
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::prelude::*;
+/// # use kernel::bit;
+/// let mut x = 0xfeu32;
+///
+/// assert_eq!(x & bit(0), 0);
+/// assert_eq!(x & bit(1), 2);
+/// assert_eq!(x & bit(2), 4);
+/// assert_eq!(x & bit(3), 8);
+///
+/// x |= bit(0);
+/// assert_eq!(x, 0xff);
+///
+/// x &= !bit(1);
+/// assert_eq!(x, 0xfd);
+///
+/// x &= !bit(7);
+/// assert_eq!(x, 0x7d);
+///
+/// let y: u64 = bit(34).into();
+/// assert_eq!(y, 0x400000000);
+///
+/// assert_eq!(y | bit(35), 0xc00000000);
+/// ```
+pub fn bit<T: Copy>(index: T) -> Bit<T> {
+    Bit {
+        index,
+        inverted: false,
+    }
+}
+
+impl<T: Copy> ops::Not for Bit<T> {
+    type Output = Self;
+    fn not(self) -> Self {
+        Self {
+            index: self.index,
+            inverted: !self.inverted,
+        }
+    }
+}
+
+/// Implemented by integer types that allow counting the number of trailing zeroes.
+pub trait TrailingZeros {
+    /// Returns the number of trailing zeroes in the binary representation of `self`.
+    fn trailing_zeros(&self) -> u32;
+}
+
+macro_rules! define_unsigned_number_traits {
+    ($type_name:ty) => {
+        impl TrailingZeros for $type_name {
+            fn trailing_zeros(&self) -> u32 {
+                <$type_name>::trailing_zeros(*self)
+            }
+        }
+
+        impl<T: Copy> core::convert::From<Bit<T>> for $type_name
+        where
+            Self: ops::Shl<T, Output = Self> + core::convert::From<u8> + ops::Not<Output = Self>,
+        {
+            fn from(v: Bit<T>) -> Self {
+                let c = Self::from(1u8) << v.index;
+                if v.inverted {
+                    !c
+                } else {
+                    c
+                }
+            }
+        }
+
+        impl<T: Copy> ops::BitAnd<Bit<T>> for $type_name
+        where
+            Self: ops::Shl<T, Output = Self> + core::convert::From<u8>,
+        {
+            type Output = Self;
+            fn bitand(self, rhs: Bit<T>) -> Self::Output {
+                self & Self::from(rhs)
+            }
+        }
+
+        impl<T: Copy> ops::BitOr<Bit<T>> for $type_name
+        where
+            Self: ops::Shl<T, Output = Self> + core::convert::From<u8>,
+        {
+            type Output = Self;
+            fn bitor(self, rhs: Bit<T>) -> Self::Output {
+                self | Self::from(rhs)
+            }
+        }
+
+        impl<T: Copy> ops::BitAndAssign<Bit<T>> for $type_name
+        where
+            Self: ops::Shl<T, Output = Self> + core::convert::From<u8>,
+        {
+            fn bitand_assign(&mut self, rhs: Bit<T>) {
+                *self &= Self::from(rhs)
+            }
+        }
+
+        impl<T: Copy> ops::BitOrAssign<Bit<T>> for $type_name
+        where
+            Self: ops::Shl<T, Output = Self> + core::convert::From<u8>,
+        {
+            fn bitor_assign(&mut self, rhs: Bit<T>) {
+                *self |= Self::from(rhs)
+            }
+        }
+    };
+}
+
+define_unsigned_number_traits!(u8);
+define_unsigned_number_traits!(u16);
+define_unsigned_number_traits!(u32);
+define_unsigned_number_traits!(u64);
+define_unsigned_number_traits!(usize);
+
+/// Returns an iterator over the set bits of `value`.
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::prelude::*;
+/// use kernel::bits_iter;
+///
+/// let mut iter = bits_iter(5usize);
+/// assert_eq!(iter.next().unwrap(), 0);
+/// assert_eq!(iter.next().unwrap(), 2);
+/// assert!(iter.next().is_none());
+/// ```
+///
+/// ```
+/// # use kernel::prelude::*;
+/// use kernel::bits_iter;
+///
+/// fn print_bits(x: usize) {
+///     for bit in bits_iter(x) {
+///         println!("{}", bit);
+///     }
+/// }
+/// ```
+#[inline]
+pub fn bits_iter<T>(value: T) -> impl Iterator<Item = u32>
+where
+    T: core::cmp::PartialEq
+        + From<u8>
+        + ops::Shl<u32, Output = T>
+        + ops::Not<Output = T>
+        + ops::BitAndAssign
+        + TrailingZeros,
+{
+    struct BitIterator<U> {
+        value: U,
+    }
+
+    impl<U> Iterator for BitIterator<U>
+    where
+        U: core::cmp::PartialEq
+            + From<u8>
+            + ops::Shl<u32, Output = U>
+            + ops::Not<Output = U>
+            + ops::BitAndAssign
+            + TrailingZeros,
+    {
+        type Item = u32;
+
+        #[inline]
+        fn next(&mut self) -> Option<u32> {
+            if self.value == U::from(0u8) {
+                return None;
+            }
+            let ret = self.value.trailing_zeros();
+            self.value &= !(U::from(1u8) << ret);
+            Some(ret)
+        }
+    }
+
+    BitIterator { value }
+}
diff --git a/rust/kernel/user_ptr.rs b/rust/kernel/user_ptr.rs
new file mode 100644
index 000000000000..467ead639071
--- /dev/null
+++ b/rust/kernel/user_ptr.rs
@@ -0,0 +1,175 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! User pointers.
+//!
+//! C header: [`include/linux/uaccess.h`](../../../../include/linux/uaccess.h)
+
+use crate::{
+    bindings, c_types,
+    error::Error,
+    io_buffer::{IoBufferReader, IoBufferWriter},
+    Result,
+};
+use alloc::vec::Vec;
+
+/// A reference to an area in userspace memory, which can be either
+/// read-only or read-write.
+///
+/// All methods on this struct are safe: invalid pointers return
+/// `EFAULT`. Concurrent access, *including data races to/from userspace
+/// memory*, is permitted, because fundamentally another userspace
+/// thread/process could always be modifying memory at the same time
+/// (in the same way that userspace Rust's [`std::io`] permits data races
+/// with the contents of files on disk). In the presence of a race, the
+/// exact byte values read/written are unspecified but the operation is
+/// well-defined. Kernelspace code should validate its copy of data
+/// after completing a read, and not expect that multiple reads of the
+/// same address will return the same value.
+///
+/// All APIs enforce the invariant that a given byte of memory from userspace
+/// may only be read once. By preventing double-fetches we avoid TOCTOU
+/// vulnerabilities. This is accomplished by taking `self` by value to prevent
+/// obtaining multiple readers on a given [`UserSlicePtr`], and the readers
+/// only permitting forward reads.
+///
+/// Constructing a [`UserSlicePtr`] performs no checks on the provided
+/// address and length, it can safely be constructed inside a kernel thread
+/// with no current userspace process. Reads and writes wrap the kernel APIs
+/// `copy_from_user` and `copy_to_user`, which check the memory map of the
+/// current process and enforce that the address range is within the user
+/// range (no additional calls to `access_ok` are needed).
+///
+/// [`std::io`]: https://doc.rust-lang.org/std/io/index.html
+pub struct UserSlicePtr(*mut c_types::c_void, usize);
+
+impl UserSlicePtr {
+    /// Constructs a user slice from a raw pointer and a length in bytes.
+    ///
+    /// # Safety
+    ///
+    /// Callers must be careful to avoid time-of-check-time-of-use
+    /// (TOCTOU) issues. The simplest way is to create a single instance of
+    /// [`UserSlicePtr`] per user memory block as it reads each byte at
+    /// most once.
+    pub unsafe fn new(ptr: *mut c_types::c_void, length: usize) -> Self {
+        UserSlicePtr(ptr, length)
+    }
+
+    /// Reads the entirety of the user slice.
+    ///
+    /// Returns `EFAULT` if the address does not currently point to
+    /// mapped, readable memory.
+    pub fn read_all(self) -> Result<Vec<u8>> {
+        self.reader().read_all()
+    }
+
+    /// Constructs a [`UserSlicePtrReader`].
+    pub fn reader(self) -> UserSlicePtrReader {
+        UserSlicePtrReader(self.0, self.1)
+    }
+
+    /// Writes the provided slice into the user slice.
+    ///
+    /// Returns `EFAULT` if the address does not currently point to
+    /// mapped, writable memory (in which case some data from before the
+    /// fault may be written), or `data` is larger than the user slice
+    /// (in which case no data is written).
+    pub fn write_all(self, data: &[u8]) -> Result {
+        self.writer().write_slice(data)
+    }
+
+    /// Constructs a [`UserSlicePtrWriter`].
+    pub fn writer(self) -> UserSlicePtrWriter {
+        UserSlicePtrWriter(self.0, self.1)
+    }
+
+    /// Constructs both a [`UserSlicePtrReader`] and a [`UserSlicePtrWriter`].
+    pub fn reader_writer(self) -> (UserSlicePtrReader, UserSlicePtrWriter) {
+        (
+            UserSlicePtrReader(self.0, self.1),
+            UserSlicePtrWriter(self.0, self.1),
+        )
+    }
+}
+
+/// A reader for [`UserSlicePtr`].
+///
+/// Used to incrementally read from the user slice.
+pub struct UserSlicePtrReader(*mut c_types::c_void, usize);
+
+impl IoBufferReader for UserSlicePtrReader {
+    /// Returns the number of bytes left to be read from this.
+    ///
+    /// Note that even reading less than this number of bytes may fail.
+    fn len(&self) -> usize {
+        self.1
+    }
+
+    /// Reads raw data from the user slice into a raw kernel buffer.
+    ///
+    /// # Safety
+    ///
+    /// The output buffer must be valid.
+    unsafe fn read_raw(&mut self, out: *mut u8, len: usize) -> Result {
+        if len > self.1 || len > u32::MAX as usize {
+            return Err(Error::EFAULT);
+        }
+        let res = unsafe { bindings::copy_from_user(out as _, self.0, len as _) };
+        if res != 0 {
+            return Err(Error::EFAULT);
+        }
+        // Since this is not a pointer to a valid object in our program,
+        // we cannot use `add`, which has C-style rules for defined
+        // behavior.
+        self.0 = self.0.wrapping_add(len);
+        self.1 -= len;
+        Ok(())
+    }
+}
+
+/// A writer for [`UserSlicePtr`].
+///
+/// Used to incrementally write into the user slice.
+pub struct UserSlicePtrWriter(*mut c_types::c_void, usize);
+
+impl IoBufferWriter for UserSlicePtrWriter {
+    fn len(&self) -> usize {
+        self.1
+    }
+
+    fn clear(&mut self, mut len: usize) -> Result {
+        let mut ret = Ok(());
+        if len > self.1 {
+            ret = Err(Error::EFAULT);
+            len = self.1;
+        }
+
+        // SAFETY: The buffer will be validated by `clear_user`. We ensure that `len` is within
+        // bounds in the check above.
+        let left = unsafe { bindings::clear_user(self.0, len as _) } as usize;
+        if left != 0 {
+            ret = Err(Error::EFAULT);
+            len -= left;
+        }
+
+        self.0 = self.0.wrapping_add(len);
+        self.1 -= len;
+        ret
+    }
+
+    unsafe fn write_raw(&mut self, data: *const u8, len: usize) -> Result {
+        if len > self.1 || len > u32::MAX as usize {
+            return Err(Error::EFAULT);
+        }
+        let res = unsafe { bindings::copy_to_user(self.0, data as _, len as _) };
+        if res != 0 {
+            return Err(Error::EFAULT);
+        }
+        // Since this is not a pointer to a valid object in our program,
+        // we cannot use `add`, which has C-style rules for defined
+        // behavior.
+        self.0 = self.0.wrapping_add(len);
+        self.1 -= len;
+        Ok(())
+    }
+}
-- 
2.34.1


^ permalink raw reply related	[relevance 1%]

* [PATCH v3 16/19] samples: add Rust examples
    2022-01-17  5:33  1% ` [PATCH v3 09/19] rust: add `kernel` crate Miguel Ojeda
@ 2022-01-17  5:33  3% ` Miguel Ojeda
  1 sibling, 0 replies; 77+ results
From: Miguel Ojeda @ 2022-01-17  5:33 UTC (permalink / raw)
  To: Linus Torvalds, Greg Kroah-Hartman
  Cc: rust-for-linux, linux-kbuild, linux-doc, linux-kernel,
	Miguel Ojeda, Alex Gaynor, Finn Behrens, Wedson Almeida Filho,
	Sven Van Asbroeck, Gary Guo, Boris-Chengbiao Zhou, Ayaan Zaidi,
	Milan Landaverde

A set of Rust modules that showcase how Rust modules look like
and how to use the abstracted kernel features.

These samples also double as tests in the CI.

The semaphore sample comes with a C version for comparison.

Co-developed-by: Alex Gaynor <alex.gaynor@gmail.com>
Signed-off-by: Alex Gaynor <alex.gaynor@gmail.com>
Co-developed-by: Finn Behrens <me@kloenk.de>
Signed-off-by: Finn Behrens <me@kloenk.de>
Co-developed-by: Wedson Almeida Filho <wedsonaf@google.com>
Signed-off-by: Wedson Almeida Filho <wedsonaf@google.com>
Co-developed-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Co-developed-by: Sven Van Asbroeck <thesven73@gmail.com>
Signed-off-by: Sven Van Asbroeck <thesven73@gmail.com>
Co-developed-by: Gary Guo <gary@garyguo.net>
Signed-off-by: Gary Guo <gary@garyguo.net>
Co-developed-by: Boris-Chengbiao Zhou <bobo1239@web.de>
Signed-off-by: Boris-Chengbiao Zhou <bobo1239@web.de>
Co-developed-by: Ayaan Zaidi <zaidi.ayaan@gmail.com>
Signed-off-by: Ayaan Zaidi <zaidi.ayaan@gmail.com>
Co-developed-by: Milan Landaverde <milan@mdaverde.com>
Signed-off-by: Milan Landaverde <milan@mdaverde.com>
Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
---
 samples/Kconfig                        |   2 +
 samples/Makefile                       |   1 +
 samples/rust/Kconfig                   | 123 ++++++++++++++
 samples/rust/Makefile                  |  13 ++
 samples/rust/rust_chrdev.rs            |  53 +++++++
 samples/rust/rust_minimal.rs           |  38 +++++
 samples/rust/rust_miscdev.rs           | 147 +++++++++++++++++
 samples/rust/rust_module_parameters.rs |  72 +++++++++
 samples/rust/rust_platform.rs          |  25 +++
 samples/rust/rust_print.rs             |  57 +++++++
 samples/rust/rust_random.rs            |  64 ++++++++
 samples/rust/rust_semaphore.rs         | 175 ++++++++++++++++++++
 samples/rust/rust_semaphore_c.c        | 212 +++++++++++++++++++++++++
 samples/rust/rust_stack_probing.rs     |  40 +++++
 samples/rust/rust_sync.rs              |  81 ++++++++++
 15 files changed, 1103 insertions(+)
 create mode 100644 samples/rust/Kconfig
 create mode 100644 samples/rust/Makefile
 create mode 100644 samples/rust/rust_chrdev.rs
 create mode 100644 samples/rust/rust_minimal.rs
 create mode 100644 samples/rust/rust_miscdev.rs
 create mode 100644 samples/rust/rust_module_parameters.rs
 create mode 100644 samples/rust/rust_platform.rs
 create mode 100644 samples/rust/rust_print.rs
 create mode 100644 samples/rust/rust_random.rs
 create mode 100644 samples/rust/rust_semaphore.rs
 create mode 100644 samples/rust/rust_semaphore_c.c
 create mode 100644 samples/rust/rust_stack_probing.rs
 create mode 100644 samples/rust/rust_sync.rs

diff --git a/samples/Kconfig b/samples/Kconfig
index 43d2e9aa557f..a3a5166837b1 100644
--- a/samples/Kconfig
+++ b/samples/Kconfig
@@ -241,6 +241,8 @@ config SAMPLE_WATCH_QUEUE
 	  Build example userspace program to use the new mount_notify(),
 	  sb_notify() syscalls and the KEYCTL_WATCH_KEY keyctl() function.
 
+source "samples/rust/Kconfig"
+
 endif # SAMPLES
 
 config HAVE_SAMPLE_FTRACE_DIRECT
diff --git a/samples/Makefile b/samples/Makefile
index 4bcd6b93bffa..d66f49a9f080 100644
--- a/samples/Makefile
+++ b/samples/Makefile
@@ -32,3 +32,4 @@ obj-$(CONFIG_SAMPLE_INTEL_MEI)		+= mei/
 subdir-$(CONFIG_SAMPLE_WATCHDOG)	+= watchdog
 subdir-$(CONFIG_SAMPLE_WATCH_QUEUE)	+= watch_queue
 obj-$(CONFIG_DEBUG_KMEMLEAK_TEST)	+= kmemleak/
+obj-$(CONFIG_SAMPLES_RUST)		+= rust/
diff --git a/samples/rust/Kconfig b/samples/rust/Kconfig
new file mode 100644
index 000000000000..e234be7c341c
--- /dev/null
+++ b/samples/rust/Kconfig
@@ -0,0 +1,123 @@
+# SPDX-License-Identifier: GPL-2.0
+
+menuconfig SAMPLES_RUST
+	bool "Rust samples"
+	depends on RUST
+	help
+	  You can build sample Rust kernel code here.
+
+	  If unsure, say N.
+
+if SAMPLES_RUST
+
+config SAMPLE_RUST_MINIMAL
+	tristate "Minimal"
+	help
+	  This option builds the Rust minimal module sample.
+
+	  To compile this as a module, choose M here:
+	  the module will be called rust_minimal.
+
+	  If unsure, say N.
+
+config SAMPLE_RUST_PRINT
+	tristate "Printing macros"
+	help
+	  This option builds the Rust printing macros sample.
+
+	  To compile this as a module, choose M here:
+	  the module will be called rust_print.
+
+	  If unsure, say N.
+
+config SAMPLE_RUST_MODULE_PARAMETERS
+	tristate "Module parameters"
+	help
+	  This option builds the Rust module parameters sample.
+
+	  To compile this as a module, choose M here:
+	  the module will be called rust_module_parameters.
+
+	  If unsure, say N.
+
+config SAMPLE_RUST_SYNC
+	tristate "Synchronisation primitives"
+	help
+	  This option builds the Rust synchronisation primitives sample.
+
+	  To compile this as a module, choose M here:
+	  the module will be called rust_sync.
+
+	  If unsure, say N.
+
+config SAMPLE_RUST_CHRDEV
+	tristate "Character device"
+	help
+	  This option builds the Rust character device sample.
+
+	  To compile this as a module, choose M here:
+	  the module will be called rust_chrdev.
+
+	  If unsure, say N.
+
+config SAMPLE_RUST_MISCDEV
+	tristate "Miscellaneous device"
+	help
+	  This option builds the Rust miscellaneous device sample.
+
+	  To compile this as a module, choose M here:
+	  the module will be called rust_miscdev.
+
+	  If unsure, say N.
+
+config SAMPLE_RUST_STACK_PROBING
+	tristate "Stack probing"
+	help
+	  This option builds the Rust stack probing sample.
+
+	  To compile this as a module, choose M here:
+	  the module will be called rust_stack_probing.
+
+	  If unsure, say N.
+
+config SAMPLE_RUST_SEMAPHORE
+	tristate "Semaphore"
+	help
+	  This option builds the Rust semaphore sample.
+
+	  To compile this as a module, choose M here:
+	  the module will be called rust_semaphore.
+
+	  If unsure, say N.
+
+config SAMPLE_RUST_SEMAPHORE_C
+	tristate "Semaphore (in C, for comparison)"
+	help
+	  This option builds the Rust semaphore sample (in C, for comparison).
+
+	  To compile this as a module, choose M here:
+	  the module will be called rust_semaphore_c.
+
+	  If unsure, say N.
+
+config SAMPLE_RUST_RANDOM
+	tristate "Random"
+	help
+	  This option builds the Rust random sample.
+
+	  To compile this as a module, choose M here:
+	  the module will be called rust_random.
+
+	  If unsure, say N.
+
+config SAMPLE_RUST_PLATFORM
+	tristate "Platform device driver"
+	help
+	  This option builds the Rust platform device driver sample.
+
+	  To compile this as a module, choose M here:
+	  the module will be called rust_platform.
+
+	  If unsure, say N.
+
+endif # SAMPLES_RUST
diff --git a/samples/rust/Makefile b/samples/rust/Makefile
new file mode 100644
index 000000000000..96ffeb7d334a
--- /dev/null
+++ b/samples/rust/Makefile
@@ -0,0 +1,13 @@
+# SPDX-License-Identifier: GPL-2.0
+
+obj-$(CONFIG_SAMPLE_RUST_MINIMAL)		+= rust_minimal.o
+obj-$(CONFIG_SAMPLE_RUST_PRINT)			+= rust_print.o
+obj-$(CONFIG_SAMPLE_RUST_MODULE_PARAMETERS)	+= rust_module_parameters.o
+obj-$(CONFIG_SAMPLE_RUST_SYNC)			+= rust_sync.o
+obj-$(CONFIG_SAMPLE_RUST_CHRDEV)		+= rust_chrdev.o
+obj-$(CONFIG_SAMPLE_RUST_MISCDEV)		+= rust_miscdev.o
+obj-$(CONFIG_SAMPLE_RUST_STACK_PROBING)		+= rust_stack_probing.o
+obj-$(CONFIG_SAMPLE_RUST_SEMAPHORE)		+= rust_semaphore.o
+obj-$(CONFIG_SAMPLE_RUST_SEMAPHORE_C)		+= rust_semaphore_c.o
+obj-$(CONFIG_SAMPLE_RUST_RANDOM)		+= rust_random.o
+obj-$(CONFIG_SAMPLE_RUST_PLATFORM)		+= rust_platform.o
diff --git a/samples/rust/rust_chrdev.rs b/samples/rust/rust_chrdev.rs
new file mode 100644
index 000000000000..ea2635ee23ed
--- /dev/null
+++ b/samples/rust/rust_chrdev.rs
@@ -0,0 +1,53 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Rust character device sample
+
+#![no_std]
+#![feature(allocator_api, global_asm)]
+
+use kernel::prelude::*;
+use kernel::{chrdev, file, file_operations::FileOperations};
+
+module! {
+    type: RustChrdev,
+    name: b"rust_chrdev",
+    author: b"Rust for Linux Contributors",
+    description: b"Rust character device sample",
+    license: b"GPL v2",
+}
+
+struct RustFile;
+
+impl FileOperations for RustFile {
+    kernel::declare_file_operations!();
+
+    fn open(_shared: &(), _file: &file::File) -> Result {
+        Ok(())
+    }
+}
+
+struct RustChrdev {
+    _dev: Pin<Box<chrdev::Registration<2>>>,
+}
+
+impl KernelModule for RustChrdev {
+    fn init(name: &'static CStr, module: &'static ThisModule) -> Result<Self> {
+        pr_info!("Rust character device sample (init)\n");
+
+        let mut chrdev_reg = chrdev::Registration::new_pinned(name, 0, module)?;
+
+        // Register the same kind of device twice, we're just demonstrating
+        // that you can use multiple minors. There are two minors in this case
+        // because its type is `chrdev::Registration<2>`
+        chrdev_reg.as_mut().register::<RustFile>()?;
+        chrdev_reg.as_mut().register::<RustFile>()?;
+
+        Ok(RustChrdev { _dev: chrdev_reg })
+    }
+}
+
+impl Drop for RustChrdev {
+    fn drop(&mut self) {
+        pr_info!("Rust character device sample (exit)\n");
+    }
+}
diff --git a/samples/rust/rust_minimal.rs b/samples/rust/rust_minimal.rs
new file mode 100644
index 000000000000..3276dbe8ae94
--- /dev/null
+++ b/samples/rust/rust_minimal.rs
@@ -0,0 +1,38 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Rust minimal sample
+
+#![no_std]
+#![feature(allocator_api, global_asm)]
+
+use kernel::prelude::*;
+
+module! {
+    type: RustMinimal,
+    name: b"rust_minimal",
+    author: b"Rust for Linux Contributors",
+    description: b"Rust minimal sample",
+    license: b"GPL v2",
+}
+
+struct RustMinimal {
+    message: String,
+}
+
+impl KernelModule for RustMinimal {
+    fn init(_name: &'static CStr, _module: &'static ThisModule) -> Result<Self> {
+        pr_info!("Rust minimal sample (init)\n");
+        pr_info!("Am I built-in? {}\n", !cfg!(MODULE));
+
+        Ok(RustMinimal {
+            message: "on the heap!".try_to_owned()?,
+        })
+    }
+}
+
+impl Drop for RustMinimal {
+    fn drop(&mut self) {
+        pr_info!("My message is {}\n", self.message);
+        pr_info!("Rust minimal sample (exit)\n");
+    }
+}
diff --git a/samples/rust/rust_miscdev.rs b/samples/rust/rust_miscdev.rs
new file mode 100644
index 000000000000..1064a4caeb4f
--- /dev/null
+++ b/samples/rust/rust_miscdev.rs
@@ -0,0 +1,147 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Rust miscellaneous device sample
+
+#![no_std]
+#![feature(allocator_api, global_asm)]
+
+use kernel::prelude::*;
+use kernel::{
+    file::File,
+    file_operations::FileOperations,
+    io_buffer::{IoBufferReader, IoBufferWriter},
+    miscdev,
+    sync::{CondVar, Mutex, Ref, RefBorrow, UniqueRef},
+};
+
+module! {
+    type: RustMiscdev,
+    name: b"rust_miscdev",
+    author: b"Rust for Linux Contributors",
+    description: b"Rust miscellaneous device sample",
+    license: b"GPL v2",
+}
+
+const MAX_TOKENS: usize = 3;
+
+struct SharedStateInner {
+    token_count: usize,
+}
+
+struct SharedState {
+    state_changed: CondVar,
+    inner: Mutex<SharedStateInner>,
+}
+
+impl SharedState {
+    fn try_new() -> Result<Ref<Self>> {
+        let mut state = Pin::from(UniqueRef::try_new(Self {
+            // SAFETY: `condvar_init!` is called below.
+            state_changed: unsafe { CondVar::new() },
+            // SAFETY: `mutex_init!` is called below.
+            inner: unsafe { Mutex::new(SharedStateInner { token_count: 0 }) },
+        })?);
+
+        // SAFETY: `state_changed` is pinned when `state` is.
+        let pinned = unsafe { state.as_mut().map_unchecked_mut(|s| &mut s.state_changed) };
+        kernel::condvar_init!(pinned, "SharedState::state_changed");
+
+        // SAFETY: `inner` is pinned when `state` is.
+        let pinned = unsafe { state.as_mut().map_unchecked_mut(|s| &mut s.inner) };
+        kernel::mutex_init!(pinned, "SharedState::inner");
+
+        Ok(state.into())
+    }
+}
+
+struct Token;
+impl FileOperations for Token {
+    type Wrapper = Ref<SharedState>;
+    type OpenData = Ref<SharedState>;
+
+    kernel::declare_file_operations!(read, write);
+
+    fn open(shared: &Ref<SharedState>, _file: &File) -> Result<Self::Wrapper> {
+        Ok(shared.clone())
+    }
+
+    fn read(
+        shared: RefBorrow<'_, SharedState>,
+        _: &File,
+        data: &mut impl IoBufferWriter,
+        offset: u64,
+    ) -> Result<usize> {
+        // Succeed if the caller doesn't provide a buffer or if not at the start.
+        if data.is_empty() || offset != 0 {
+            return Ok(0);
+        }
+
+        {
+            let mut inner = shared.inner.lock();
+
+            // Wait until we are allowed to decrement the token count or a signal arrives.
+            while inner.token_count == 0 {
+                if shared.state_changed.wait(&mut inner) {
+                    return Err(Error::EINTR);
+                }
+            }
+
+            // Consume a token.
+            inner.token_count -= 1;
+        }
+
+        // Notify a possible writer waiting.
+        shared.state_changed.notify_all();
+
+        // Write a one-byte 1 to the reader.
+        data.write_slice(&[1u8; 1])?;
+        Ok(1)
+    }
+
+    fn write(
+        shared: RefBorrow<'_, SharedState>,
+        _: &File,
+        data: &mut impl IoBufferReader,
+        _offset: u64,
+    ) -> Result<usize> {
+        {
+            let mut inner = shared.inner.lock();
+
+            // Wait until we are allowed to increment the token count or a signal arrives.
+            while inner.token_count == MAX_TOKENS {
+                if shared.state_changed.wait(&mut inner) {
+                    return Err(Error::EINTR);
+                }
+            }
+
+            // Increment the number of token so that a reader can be released.
+            inner.token_count += 1;
+        }
+
+        // Notify a possible reader waiting.
+        shared.state_changed.notify_all();
+        Ok(data.len())
+    }
+}
+
+struct RustMiscdev {
+    _dev: Pin<Box<miscdev::Registration<Token>>>,
+}
+
+impl KernelModule for RustMiscdev {
+    fn init(name: &'static CStr, _module: &'static ThisModule) -> Result<Self> {
+        pr_info!("Rust miscellaneous device sample (init)\n");
+
+        let state = SharedState::try_new()?;
+
+        Ok(RustMiscdev {
+            _dev: miscdev::Registration::new_pinned(name, None, state)?,
+        })
+    }
+}
+
+impl Drop for RustMiscdev {
+    fn drop(&mut self) {
+        pr_info!("Rust miscellaneous device sample (exit)\n");
+    }
+}
diff --git a/samples/rust/rust_module_parameters.rs b/samples/rust/rust_module_parameters.rs
new file mode 100644
index 000000000000..5e4c39648010
--- /dev/null
+++ b/samples/rust/rust_module_parameters.rs
@@ -0,0 +1,72 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Rust module parameters sample
+
+#![no_std]
+#![feature(allocator_api, global_asm)]
+
+use kernel::prelude::*;
+
+module! {
+    type: RustModuleParameters,
+    name: b"rust_module_parameters",
+    author: b"Rust for Linux Contributors",
+    description: b"Rust module parameters sample",
+    license: b"GPL v2",
+    params: {
+        my_bool: bool {
+            default: true,
+            permissions: 0,
+            description: b"Example of bool",
+        },
+        my_i32: i32 {
+            default: 42,
+            permissions: 0o644,
+            description: b"Example of i32",
+        },
+        my_str: str {
+            default: b"default str val",
+            permissions: 0o644,
+            description: b"Example of a string param",
+        },
+        my_usize: usize {
+            default: 42,
+            permissions: 0o644,
+            description: b"Example of usize",
+        },
+        my_array: ArrayParam<i32, 3> {
+            default: [0, 1],
+            permissions: 0,
+            description: b"Example of array",
+        },
+    },
+}
+
+struct RustModuleParameters;
+
+impl KernelModule for RustModuleParameters {
+    fn init(_name: &'static CStr, module: &'static ThisModule) -> Result<Self> {
+        pr_info!("Rust module parameters sample (init)\n");
+
+        {
+            let lock = module.kernel_param_lock();
+            pr_info!("Parameters:\n");
+            pr_info!("  my_bool:    {}\n", my_bool.read());
+            pr_info!("  my_i32:     {}\n", my_i32.read(&lock));
+            pr_info!(
+                "  my_str:     {}\n",
+                core::str::from_utf8(my_str.read(&lock))?
+            );
+            pr_info!("  my_usize:   {}\n", my_usize.read(&lock));
+            pr_info!("  my_array:   {:?}\n", my_array.read());
+        }
+
+        Ok(RustModuleParameters)
+    }
+}
+
+impl Drop for RustModuleParameters {
+    fn drop(&mut self) {
+        pr_info!("Rust module parameters sample (exit)\n");
+    }
+}
diff --git a/samples/rust/rust_platform.rs b/samples/rust/rust_platform.rs
new file mode 100644
index 000000000000..43ff1694a278
--- /dev/null
+++ b/samples/rust/rust_platform.rs
@@ -0,0 +1,25 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Rust platform device driver sample.
+
+#![no_std]
+#![feature(allocator_api, global_asm)]
+
+use kernel::{module_platform_driver, of, platform, prelude::*};
+
+module_platform_driver! {
+    type: Driver,
+    name: b"rust_platform",
+    license: b"GPL v2",
+}
+
+struct Driver;
+impl platform::Driver for Driver {
+    kernel::define_of_id_table! {(), [
+        (of::DeviceId::Compatible(b"rust,sample"), None),
+    ]}
+
+    fn probe(_dev: &mut platform::Device, _id_info: Option<&Self::IdInfo>) -> Result {
+        Ok(())
+    }
+}
diff --git a/samples/rust/rust_print.rs b/samples/rust/rust_print.rs
new file mode 100644
index 000000000000..1b4d14a2d9cc
--- /dev/null
+++ b/samples/rust/rust_print.rs
@@ -0,0 +1,57 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Rust printing macros sample
+
+#![no_std]
+#![feature(allocator_api, global_asm)]
+
+use kernel::prelude::*;
+use kernel::{pr_cont, str::CStr, ThisModule};
+
+module! {
+    type: RustPrint,
+    name: b"rust_print",
+    author: b"Rust for Linux Contributors",
+    description: b"Rust printing macros sample",
+    license: b"GPL v2",
+}
+
+struct RustPrint;
+
+impl KernelModule for RustPrint {
+    fn init(_name: &'static CStr, _module: &'static ThisModule) -> Result<Self> {
+        pr_info!("Rust printing macros sample (init)\n");
+
+        pr_emerg!("Emergency message (level 0) without args\n");
+        pr_alert!("Alert message (level 1) without args\n");
+        pr_crit!("Critical message (level 2) without args\n");
+        pr_err!("Error message (level 3) without args\n");
+        pr_warn!("Warning message (level 4) without args\n");
+        pr_notice!("Notice message (level 5) without args\n");
+        pr_info!("Info message (level 6) without args\n");
+
+        pr_info!("A line that");
+        pr_cont!(" is continued");
+        pr_cont!(" without args\n");
+
+        pr_emerg!("{} message (level {}) with args\n", "Emergency", 0);
+        pr_alert!("{} message (level {}) with args\n", "Alert", 1);
+        pr_crit!("{} message (level {}) with args\n", "Critical", 2);
+        pr_err!("{} message (level {}) with args\n", "Error", 3);
+        pr_warn!("{} message (level {}) with args\n", "Warning", 4);
+        pr_notice!("{} message (level {}) with args\n", "Notice", 5);
+        pr_info!("{} message (level {}) with args\n", "Info", 6);
+
+        pr_info!("A {} that", "line");
+        pr_cont!(" is {}", "continued");
+        pr_cont!(" with {}\n", "args");
+
+        Ok(RustPrint)
+    }
+}
+
+impl Drop for RustPrint {
+    fn drop(&mut self) {
+        pr_info!("Rust printing macros sample (exit)\n");
+    }
+}
diff --git a/samples/rust/rust_random.rs b/samples/rust/rust_random.rs
new file mode 100644
index 000000000000..5dec88291f81
--- /dev/null
+++ b/samples/rust/rust_random.rs
@@ -0,0 +1,64 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Rust random device
+//!
+//! Adapted from Alex Gaynor's original available at
+//! <https://github.com/alex/just-use/blob/master/src/lib.rs>.
+
+#![no_std]
+#![feature(allocator_api, global_asm)]
+
+use kernel::{
+    file::File,
+    file_operations::FileOperations,
+    io_buffer::{IoBufferReader, IoBufferWriter},
+    prelude::*,
+};
+
+struct RandomFile;
+
+impl FileOperations for RandomFile {
+    kernel::declare_file_operations!(read, write, read_iter, write_iter);
+
+    fn open(_data: &(), _file: &File) -> Result {
+        Ok(())
+    }
+
+    fn read(_this: (), file: &File, buf: &mut impl IoBufferWriter, _: u64) -> Result<usize> {
+        let total_len = buf.len();
+        let mut chunkbuf = [0; 256];
+
+        while !buf.is_empty() {
+            let len = chunkbuf.len().min(buf.len());
+            let chunk = &mut chunkbuf[0..len];
+
+            if file.is_blocking() {
+                kernel::random::getrandom(chunk)?;
+            } else {
+                kernel::random::getrandom_nonblock(chunk)?;
+            }
+            buf.write_slice(chunk)?;
+        }
+        Ok(total_len)
+    }
+
+    fn write(_this: (), _file: &File, buf: &mut impl IoBufferReader, _: u64) -> Result<usize> {
+        let total_len = buf.len();
+        let mut chunkbuf = [0; 256];
+        while !buf.is_empty() {
+            let len = chunkbuf.len().min(buf.len());
+            let chunk = &mut chunkbuf[0..len];
+            buf.read_slice(chunk)?;
+            kernel::random::add_randomness(chunk);
+        }
+        Ok(total_len)
+    }
+}
+
+module_misc_device! {
+    type: RandomFile,
+    name: b"rust_random",
+    author: b"Rust for Linux Contributors",
+    description: b"Just use /dev/urandom: Now with early-boot safety",
+    license: b"GPL v2",
+}
diff --git a/samples/rust/rust_semaphore.rs b/samples/rust/rust_semaphore.rs
new file mode 100644
index 000000000000..7ba871ba67e3
--- /dev/null
+++ b/samples/rust/rust_semaphore.rs
@@ -0,0 +1,175 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Rust semaphore sample
+//!
+//! A counting semaphore that can be used by userspace.
+//!
+//! The count is incremented by writes to the device. A write of `n` bytes results in an increment
+//! of `n`. It is decremented by reads; each read results in the count being decremented by 1. If
+//! the count is already zero, a read will block until another write increments it.
+//!
+//! This can be used in user space from the shell for example  as follows (assuming a node called
+//! `semaphore`): `cat semaphore` decrements the count by 1 (waiting for it to become non-zero
+//! before decrementing); `echo -n 123 > semaphore` increments the semaphore by 3, potentially
+//! unblocking up to 3 blocked readers.
+
+#![no_std]
+#![feature(allocator_api, global_asm, generic_associated_types)]
+
+use core::sync::atomic::{AtomicU64, Ordering};
+use kernel::{
+    condvar_init, declare_file_operations,
+    file::File,
+    file_operations::{FileOperations, IoctlCommand, IoctlHandler},
+    io_buffer::{IoBufferReader, IoBufferWriter},
+    miscdev::Registration,
+    mutex_init,
+    prelude::*,
+    sync::{CondVar, Mutex, Ref, UniqueRef},
+    user_ptr::{UserSlicePtrReader, UserSlicePtrWriter},
+};
+
+module! {
+    type: RustSemaphore,
+    name: b"rust_semaphore",
+    author: b"Rust for Linux Contributors",
+    description: b"Rust semaphore sample",
+    license: b"GPL v2",
+}
+
+struct SemaphoreInner {
+    count: usize,
+    max_seen: usize,
+}
+
+struct Semaphore {
+    changed: CondVar,
+    inner: Mutex<SemaphoreInner>,
+}
+
+struct FileState {
+    read_count: AtomicU64,
+    shared: Ref<Semaphore>,
+}
+
+impl FileState {
+    fn consume(&self) -> Result {
+        let mut inner = self.shared.inner.lock();
+        while inner.count == 0 {
+            if self.shared.changed.wait(&mut inner) {
+                return Err(Error::EINTR);
+            }
+        }
+        inner.count -= 1;
+        Ok(())
+    }
+}
+
+impl FileOperations for FileState {
+    type Wrapper = Box<Self>;
+    type OpenData = Ref<Semaphore>;
+
+    declare_file_operations!(read, write, ioctl);
+
+    fn open(shared: &Ref<Semaphore>, _file: &File) -> Result<Box<Self>> {
+        Ok(Box::try_new(Self {
+            read_count: AtomicU64::new(0),
+            shared: shared.clone(),
+        })?)
+    }
+
+    fn read(this: &Self, _: &File, data: &mut impl IoBufferWriter, offset: u64) -> Result<usize> {
+        if data.is_empty() || offset > 0 {
+            return Ok(0);
+        }
+        this.consume()?;
+        data.write_slice(&[0u8; 1])?;
+        this.read_count.fetch_add(1, Ordering::Relaxed);
+        Ok(1)
+    }
+
+    fn write(this: &Self, _: &File, data: &mut impl IoBufferReader, _offs: u64) -> Result<usize> {
+        {
+            let mut inner = this.shared.inner.lock();
+            inner.count = inner.count.saturating_add(data.len());
+            if inner.count > inner.max_seen {
+                inner.max_seen = inner.count;
+            }
+        }
+
+        this.shared.changed.notify_all();
+        Ok(data.len())
+    }
+
+    fn ioctl(this: &Self, file: &File, cmd: &mut IoctlCommand) -> Result<i32> {
+        cmd.dispatch::<Self>(this, file)
+    }
+}
+
+struct RustSemaphore {
+    _dev: Pin<Box<Registration<FileState>>>,
+}
+
+impl KernelModule for RustSemaphore {
+    fn init(name: &'static CStr, _module: &'static ThisModule) -> Result<Self> {
+        pr_info!("Rust semaphore sample (init)\n");
+
+        let mut sema = Pin::from(UniqueRef::try_new(Semaphore {
+            // SAFETY: `condvar_init!` is called below.
+            changed: unsafe { CondVar::new() },
+
+            // SAFETY: `mutex_init!` is called below.
+            inner: unsafe {
+                Mutex::new(SemaphoreInner {
+                    count: 0,
+                    max_seen: 0,
+                })
+            },
+        })?);
+
+        // SAFETY: `changed` is pinned when `sema` is.
+        let pinned = unsafe { sema.as_mut().map_unchecked_mut(|s| &mut s.changed) };
+        condvar_init!(pinned, "Semaphore::changed");
+
+        // SAFETY: `inner` is pinned when `sema` is.
+        let pinned = unsafe { sema.as_mut().map_unchecked_mut(|s| &mut s.inner) };
+        mutex_init!(pinned, "Semaphore::inner");
+
+        Ok(Self {
+            _dev: Registration::new_pinned(name, None, sema.into())?,
+        })
+    }
+}
+
+impl Drop for RustSemaphore {
+    fn drop(&mut self) {
+        pr_info!("Rust semaphore sample (exit)\n");
+    }
+}
+
+const IOCTL_GET_READ_COUNT: u32 = 0x80086301;
+const IOCTL_SET_READ_COUNT: u32 = 0x40086301;
+
+impl IoctlHandler for FileState {
+    type Target<'a> = &'a Self;
+
+    fn read(this: &Self, _: &File, cmd: u32, writer: &mut UserSlicePtrWriter) -> Result<i32> {
+        match cmd {
+            IOCTL_GET_READ_COUNT => {
+                writer.write(&this.read_count.load(Ordering::Relaxed))?;
+                Ok(0)
+            }
+            _ => Err(Error::EINVAL),
+        }
+    }
+
+    fn write(this: &Self, _: &File, cmd: u32, reader: &mut UserSlicePtrReader) -> Result<i32> {
+        match cmd {
+            IOCTL_SET_READ_COUNT => {
+                this.read_count.store(reader.read()?, Ordering::Relaxed);
+                Ok(0)
+            }
+            _ => Err(Error::EINVAL),
+        }
+    }
+}
diff --git a/samples/rust/rust_semaphore_c.c b/samples/rust/rust_semaphore_c.c
new file mode 100644
index 000000000000..cdc121d4030d
--- /dev/null
+++ b/samples/rust/rust_semaphore_c.c
@@ -0,0 +1,212 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Rust semaphore sample (in C, for comparison)
+ *
+ * This is a C implementation of `rust_semaphore.rs`. Refer to the description
+ * in that file for details on the device.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/miscdevice.h>
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/slab.h>
+#include <linux/refcount.h>
+#include <linux/wait.h>
+
+#define IOCTL_GET_READ_COUNT _IOR('c', 1, u64)
+#define IOCTL_SET_READ_COUNT _IOW('c', 1, u64)
+
+struct semaphore_state {
+	struct kref ref;
+	struct miscdevice miscdev;
+	wait_queue_head_t changed;
+	struct mutex mutex;
+	size_t count;
+	size_t max_seen;
+};
+
+struct file_state {
+	atomic64_t read_count;
+	struct semaphore_state *shared;
+};
+
+static int semaphore_consume(struct semaphore_state *state)
+{
+	DEFINE_WAIT(wait);
+
+	mutex_lock(&state->mutex);
+	while (state->count == 0) {
+		prepare_to_wait(&state->changed, &wait, TASK_INTERRUPTIBLE);
+		mutex_unlock(&state->mutex);
+		schedule();
+		finish_wait(&state->changed, &wait);
+		if (signal_pending(current))
+			return -EINTR;
+		mutex_lock(&state->mutex);
+	}
+
+	state->count--;
+	mutex_unlock(&state->mutex);
+
+	return 0;
+}
+
+static int semaphore_open(struct inode *nodp, struct file *filp)
+{
+	struct semaphore_state *shared =
+		container_of(filp->private_data, struct semaphore_state, miscdev);
+	struct file_state *state;
+
+	state = kzalloc(sizeof(*state), GFP_KERNEL);
+	if (!state)
+		return -ENOMEM;
+
+	kref_get(&shared->ref);
+	state->shared = shared;
+	atomic64_set(&state->read_count, 0);
+
+	filp->private_data = state;
+
+	return 0;
+}
+
+static ssize_t semaphore_write(struct file *filp, const char __user *buffer, size_t count,
+			       loff_t *ppos)
+{
+	struct file_state *state = filp->private_data;
+	struct semaphore_state *shared = state->shared;
+
+	mutex_lock(&shared->mutex);
+
+	shared->count += count;
+	if (shared->count < count)
+		shared->count = SIZE_MAX;
+
+	if (shared->count > shared->max_seen)
+		shared->max_seen = shared->count;
+
+	mutex_unlock(&shared->mutex);
+
+	wake_up_all(&shared->changed);
+
+	return count;
+}
+
+static ssize_t semaphore_read(struct file *filp, char __user *buffer,
+			      size_t count, loff_t *ppos)
+{
+	struct file_state *state = filp->private_data;
+	char c = 0;
+	int ret;
+
+	if (count == 0 || *ppos > 0)
+		return 0;
+
+	ret = semaphore_consume(state->shared);
+	if (ret)
+		return ret;
+
+	if (copy_to_user(buffer, &c, sizeof(c)))
+		return -EFAULT;
+
+	atomic64_add(1, &state->read_count);
+	*ppos += 1;
+	return 1;
+}
+
+static long semaphore_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
+{
+	struct file_state *state = filp->private_data;
+	void __user *buffer = (void __user *)arg;
+	u64 value;
+
+	switch (cmd) {
+	case IOCTL_GET_READ_COUNT:
+		value = atomic64_read(&state->read_count);
+		if (copy_to_user(buffer, &value, sizeof(value)))
+			return -EFAULT;
+		return 0;
+	case IOCTL_SET_READ_COUNT:
+		if (copy_from_user(&value, buffer, sizeof(value)))
+			return -EFAULT;
+		atomic64_set(&state->read_count, value);
+		return 0;
+	default:
+		return -EINVAL;
+	}
+}
+
+static void semaphore_free(struct kref *kref)
+{
+	struct semaphore_state *device;
+
+	device = container_of(kref, struct semaphore_state, ref);
+	kfree(device);
+}
+
+static int semaphore_release(struct inode *nodp, struct file *filp)
+{
+	struct file_state *state = filp->private_data;
+
+	kref_put(&state->shared->ref, semaphore_free);
+	kfree(state);
+	return 0;
+}
+
+static const struct file_operations semaphore_fops = {
+	.owner = THIS_MODULE,
+	.open = semaphore_open,
+	.read = semaphore_read,
+	.write = semaphore_write,
+	.compat_ioctl = semaphore_ioctl,
+	.release = semaphore_release,
+};
+
+static struct semaphore_state *device;
+
+static int __init semaphore_init(void)
+{
+	int ret;
+	struct semaphore_state *state;
+
+	pr_info("Rust semaphore sample (in C, for comparison) (init)\n");
+
+	state = kzalloc(sizeof(*state), GFP_KERNEL);
+	if (!state)
+		return -ENOMEM;
+
+	mutex_init(&state->mutex);
+	kref_init(&state->ref);
+	init_waitqueue_head(&state->changed);
+
+	state->miscdev.fops = &semaphore_fops;
+	state->miscdev.minor = MISC_DYNAMIC_MINOR;
+	state->miscdev.name = "semaphore";
+
+	ret = misc_register(&state->miscdev);
+	if (ret < 0) {
+		kfree(state);
+		return ret;
+	}
+
+	device = state;
+
+	return 0;
+}
+
+static void __exit semaphore_exit(void)
+{
+	pr_info("Rust semaphore sample (in C, for comparison) (exit)\n");
+
+	misc_deregister(&device->miscdev);
+	kref_put(&device->ref, semaphore_free);
+}
+
+module_init(semaphore_init);
+module_exit(semaphore_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Rust for Linux Contributors");
+MODULE_DESCRIPTION("Rust semaphore sample (in C, for comparison)");
diff --git a/samples/rust/rust_stack_probing.rs b/samples/rust/rust_stack_probing.rs
new file mode 100644
index 000000000000..4f44fade96aa
--- /dev/null
+++ b/samples/rust/rust_stack_probing.rs
@@ -0,0 +1,40 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Rust stack probing sample
+
+#![no_std]
+#![feature(allocator_api, global_asm)]
+#![feature(bench_black_box)]
+
+use kernel::prelude::*;
+
+module! {
+    type: RustStackProbing,
+    name: b"rust_stack_probing",
+    author: b"Rust for Linux Contributors",
+    description: b"Rust stack probing sample",
+    license: b"GPL v2",
+}
+
+struct RustStackProbing;
+
+impl KernelModule for RustStackProbing {
+    fn init(_name: &'static CStr, _module: &'static ThisModule) -> Result<Self> {
+        pr_info!("Rust stack probing sample (init)\n");
+
+        // Including this large variable on the stack will trigger
+        // stack probing on the supported archs.
+        // This will verify that stack probing does not lead to
+        // any errors if we need to link `__rust_probestack`.
+        let x: [u64; 514] = core::hint::black_box([5; 514]);
+        pr_info!("Large array has length: {}\n", x.len());
+
+        Ok(RustStackProbing)
+    }
+}
+
+impl Drop for RustStackProbing {
+    fn drop(&mut self) {
+        pr_info!("Rust stack probing sample (exit)\n");
+    }
+}
diff --git a/samples/rust/rust_sync.rs b/samples/rust/rust_sync.rs
new file mode 100644
index 000000000000..f71f8928d16e
--- /dev/null
+++ b/samples/rust/rust_sync.rs
@@ -0,0 +1,81 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Rust synchronisation primitives sample
+
+#![no_std]
+#![feature(allocator_api, global_asm)]
+
+use kernel::prelude::*;
+use kernel::{
+    condvar_init, mutex_init, spinlock_init,
+    sync::{CondVar, Mutex, SpinLock},
+};
+
+module! {
+    type: RustSync,
+    name: b"rust_sync",
+    author: b"Rust for Linux Contributors",
+    description: b"Rust synchronisation primitives sample",
+    license: b"GPL v2",
+}
+
+struct RustSync;
+
+impl KernelModule for RustSync {
+    fn init(_name: &'static CStr, _module: &'static ThisModule) -> Result<Self> {
+        pr_info!("Rust synchronisation primitives sample (init)\n");
+
+        // Test mutexes.
+        {
+            // SAFETY: `init` is called below.
+            let mut data = Pin::from(Box::try_new(unsafe { Mutex::new(0) })?);
+            mutex_init!(data.as_mut(), "RustSync::init::data1");
+            *data.lock() = 10;
+            pr_info!("Value: {}\n", *data.lock());
+
+            // SAFETY: `init` is called below.
+            let mut cv = Pin::from(Box::try_new(unsafe { CondVar::new() })?);
+            condvar_init!(cv.as_mut(), "RustSync::init::cv1");
+
+            {
+                let mut guard = data.lock();
+                while *guard != 10 {
+                    let _ = cv.wait(&mut guard);
+                }
+            }
+            cv.notify_one();
+            cv.notify_all();
+            cv.free_waiters();
+        }
+
+        // Test spinlocks.
+        {
+            // SAFETY: `init` is called below.
+            let mut data = Pin::from(Box::try_new(unsafe { SpinLock::new(0) })?);
+            spinlock_init!(data.as_mut(), "RustSync::init::data2");
+            *data.lock() = 10;
+            pr_info!("Value: {}\n", *data.lock());
+
+            // SAFETY: `init` is called below.
+            let mut cv = Pin::from(Box::try_new(unsafe { CondVar::new() })?);
+            condvar_init!(cv.as_mut(), "RustSync::init::cv2");
+            {
+                let mut guard = data.lock();
+                while *guard != 10 {
+                    let _ = cv.wait(&mut guard);
+                }
+            }
+            cv.notify_one();
+            cv.notify_all();
+            cv.free_waiters();
+        }
+
+        Ok(RustSync)
+    }
+}
+
+impl Drop for RustSync {
+    fn drop(&mut self) {
+        pr_info!("Rust synchronisation primitives sample (exit)\n");
+    }
+}
-- 
2.34.1


^ permalink raw reply related	[relevance 3%]

* [PATCH v4 10/20] rust: add `kernel` crate
  @ 2022-02-12 13:03  1% ` Miguel Ojeda
  2022-02-12 13:03  3% ` [PATCH v4 17/20] samples: add Rust examples Miguel Ojeda
  1 sibling, 0 replies; 77+ results
From: Miguel Ojeda @ 2022-02-12 13:03 UTC (permalink / raw)
  To: Linus Torvalds, Greg Kroah-Hartman
  Cc: rust-for-linux, linux-kernel, Miguel Ojeda, Wedson Almeida Filho,
	Alex Gaynor, Geoffrey Thomas, Finn Behrens, Adam Bratschi-Kaye,
	Michael Ellerman, Sumera Priyadarsini, Sven Van Asbroeck,
	Gary Guo, Boris-Chengbiao Zhou, Boqun Feng, Fox Chen,
	Dan Robertson, Viktor Garske, Dariusz Sosnowski,
	Léo Lanteri Thauvin, Niklas Mohrin, Gioh Kim, Daniel Xu,
	Milan Landaverde, Morgan Bartlett, Maciej Falkowski,
	Jiapeng Chong, Petr Mladek, Sergey Senozhatsky, Steven Rostedt,
	John Ogness

From: Wedson Almeida Filho <wedsonaf@google.com>

The `kernel` crate currently includes all the abstractions that wrap
kernel features written in C.

These abstractions call the C side of the kernel via the generated
bindings with the `bindgen` tool. Modules developed in Rust should
never call the bindings themselves.

In the future, as the abstractions grow in number, we may need
to split this crate into several, possibly following a similar
subdivision in subsystems as the kernel itself and/or moving
the code to the actual subsystems.

Co-developed-by: Alex Gaynor <alex.gaynor@gmail.com>
Signed-off-by: Alex Gaynor <alex.gaynor@gmail.com>
Co-developed-by: Geoffrey Thomas <geofft@ldpreload.com>
Signed-off-by: Geoffrey Thomas <geofft@ldpreload.com>
Co-developed-by: Finn Behrens <me@kloenk.de>
Signed-off-by: Finn Behrens <me@kloenk.de>
Co-developed-by: Adam Bratschi-Kaye <ark.email@gmail.com>
Signed-off-by: Adam Bratschi-Kaye <ark.email@gmail.com>
Co-developed-by: Michael Ellerman <mpe@ellerman.id.au>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Co-developed-by: Sumera Priyadarsini <sylphrenadin@gmail.com>
Signed-off-by: Sumera Priyadarsini <sylphrenadin@gmail.com>
Co-developed-by: Sven Van Asbroeck <thesven73@gmail.com>
Signed-off-by: Sven Van Asbroeck <thesven73@gmail.com>
Co-developed-by: Gary Guo <gary@garyguo.net>
Signed-off-by: Gary Guo <gary@garyguo.net>
Co-developed-by: Boris-Chengbiao Zhou <bobo1239@web.de>
Signed-off-by: Boris-Chengbiao Zhou <bobo1239@web.de>
Co-developed-by: Boqun Feng <boqun.feng@gmail.com>
Signed-off-by: Boqun Feng <boqun.feng@gmail.com>
Co-developed-by: Fox Chen <foxhlchen@gmail.com>
Signed-off-by: Fox Chen <foxhlchen@gmail.com>
Co-developed-by: Dan Robertson <daniel.robertson@starlab.io>
Signed-off-by: Dan Robertson <daniel.robertson@starlab.io>
Co-developed-by: Viktor Garske <viktor@v-gar.de>
Signed-off-by: Viktor Garske <viktor@v-gar.de>
Co-developed-by: Dariusz Sosnowski <dsosnowski@dsosnowski.pl>
Signed-off-by: Dariusz Sosnowski <dsosnowski@dsosnowski.pl>
Co-developed-by: Léo Lanteri Thauvin <leseulartichaut@gmail.com>
Signed-off-by: Léo Lanteri Thauvin <leseulartichaut@gmail.com>
Co-developed-by: Niklas Mohrin <dev@niklasmohrin.de>
Signed-off-by: Niklas Mohrin <dev@niklasmohrin.de>
Co-developed-by: Gioh Kim <gurugio@gmail.com>
Signed-off-by: Gioh Kim <gurugio@gmail.com>
Co-developed-by: Daniel Xu <dxu@dxuuu.xyz>
Signed-off-by: Daniel Xu <dxu@dxuuu.xyz>
Co-developed-by: Milan Landaverde <milan@mdaverde.com>
Signed-off-by: Milan Landaverde <milan@mdaverde.com>
Co-developed-by: Morgan Bartlett <mjmouse9999@gmail.com>
Signed-off-by: Morgan Bartlett <mjmouse9999@gmail.com>
Co-developed-by: Maciej Falkowski <m.falkowski@samsung.com>
Signed-off-by: Maciej Falkowski <m.falkowski@samsung.com>
Co-developed-by: Jiapeng Chong <jiapeng.chong@linux.alibaba.com>
Signed-off-by: Jiapeng Chong <jiapeng.chong@linux.alibaba.com>
Signed-off-by: Wedson Almeida Filho <wedsonaf@google.com>
Co-developed-by: Miguel Ojeda <ojeda@kernel.org>
Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
---
 kernel/printk/printk.c         |   5 +-
 rust/kernel/allocator.rs       |  65 +++
 rust/kernel/amba.rs            | 259 ++++++++++++
 rust/kernel/bindings.rs        |  47 +++
 rust/kernel/bindings_helper.h  |  30 ++
 rust/kernel/buffer.rs          |  52 +++
 rust/kernel/build_assert.rs    |  80 ++++
 rust/kernel/c_types.rs         | 119 ++++++
 rust/kernel/chrdev.rs          | 209 ++++++++++
 rust/kernel/clk.rs             |  75 ++++
 rust/kernel/cred.rs            |  73 ++++
 rust/kernel/device.rs          | 554 +++++++++++++++++++++++++
 rust/kernel/driver.rs          | 440 ++++++++++++++++++++
 rust/kernel/error.rs           | 542 ++++++++++++++++++++++++
 rust/kernel/file.rs            | 147 +++++++
 rust/kernel/file_operations.rs | 734 +++++++++++++++++++++++++++++++++
 rust/kernel/gpio.rs            | 477 +++++++++++++++++++++
 rust/kernel/io_buffer.rs       | 153 +++++++
 rust/kernel/io_mem.rs          | 227 ++++++++++
 rust/kernel/iov_iter.rs        |  81 ++++
 rust/kernel/irq.rs             | 409 ++++++++++++++++++
 rust/kernel/lib.rs             | 261 ++++++++++++
 rust/kernel/linked_list.rs     | 247 +++++++++++
 rust/kernel/miscdev.rs         | 281 +++++++++++++
 rust/kernel/mm.rs              | 149 +++++++
 rust/kernel/module_param.rs    | 497 ++++++++++++++++++++++
 rust/kernel/of.rs              |  63 +++
 rust/kernel/pages.rs           | 144 +++++++
 rust/kernel/platform.rs        | 224 ++++++++++
 rust/kernel/power.rs           | 118 ++++++
 rust/kernel/prelude.rs         |  36 ++
 rust/kernel/print.rs           | 417 +++++++++++++++++++
 rust/kernel/random.rs          |  50 +++
 rust/kernel/raw_list.rs        | 361 ++++++++++++++++
 rust/kernel/rbtree.rs          | 562 +++++++++++++++++++++++++
 rust/kernel/revocable.rs       | 163 ++++++++
 rust/kernel/security.rs        |  36 ++
 rust/kernel/static_assert.rs   |  39 ++
 rust/kernel/std_vendor.rs      | 150 +++++++
 rust/kernel/str.rs             | 401 ++++++++++++++++++
 rust/kernel/sysctl.rs          | 197 +++++++++
 rust/kernel/task.rs            | 182 ++++++++
 rust/kernel/types.rs           | 486 ++++++++++++++++++++++
 rust/kernel/user_ptr.rs        | 175 ++++++++
 44 files changed, 10016 insertions(+), 1 deletion(-)
 create mode 100644 rust/kernel/allocator.rs
 create mode 100644 rust/kernel/amba.rs
 create mode 100644 rust/kernel/bindings.rs
 create mode 100644 rust/kernel/bindings_helper.h
 create mode 100644 rust/kernel/buffer.rs
 create mode 100644 rust/kernel/build_assert.rs
 create mode 100644 rust/kernel/c_types.rs
 create mode 100644 rust/kernel/chrdev.rs
 create mode 100644 rust/kernel/clk.rs
 create mode 100644 rust/kernel/cred.rs
 create mode 100644 rust/kernel/device.rs
 create mode 100644 rust/kernel/driver.rs
 create mode 100644 rust/kernel/error.rs
 create mode 100644 rust/kernel/file.rs
 create mode 100644 rust/kernel/file_operations.rs
 create mode 100644 rust/kernel/gpio.rs
 create mode 100644 rust/kernel/io_buffer.rs
 create mode 100644 rust/kernel/io_mem.rs
 create mode 100644 rust/kernel/iov_iter.rs
 create mode 100644 rust/kernel/irq.rs
 create mode 100644 rust/kernel/lib.rs
 create mode 100644 rust/kernel/linked_list.rs
 create mode 100644 rust/kernel/miscdev.rs
 create mode 100644 rust/kernel/mm.rs
 create mode 100644 rust/kernel/module_param.rs
 create mode 100644 rust/kernel/of.rs
 create mode 100644 rust/kernel/pages.rs
 create mode 100644 rust/kernel/platform.rs
 create mode 100644 rust/kernel/power.rs
 create mode 100644 rust/kernel/prelude.rs
 create mode 100644 rust/kernel/print.rs
 create mode 100644 rust/kernel/random.rs
 create mode 100644 rust/kernel/raw_list.rs
 create mode 100644 rust/kernel/rbtree.rs
 create mode 100644 rust/kernel/revocable.rs
 create mode 100644 rust/kernel/security.rs
 create mode 100644 rust/kernel/static_assert.rs
 create mode 100644 rust/kernel/std_vendor.rs
 create mode 100644 rust/kernel/str.rs
 create mode 100644 rust/kernel/sysctl.rs
 create mode 100644 rust/kernel/task.rs
 create mode 100644 rust/kernel/types.rs
 create mode 100644 rust/kernel/user_ptr.rs

diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
index 82abfaf3c2aa..c042386667f2 100644
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -392,7 +392,10 @@ static struct latched_seq clear_seq = {
 /* the maximum size of a formatted record (i.e. with prefix added per line) */
 #define CONSOLE_LOG_MAX		1024
 
-/* the maximum size allowed to be reserved for a record */
+/*
+ * The maximum size allowed to be reserved for a record.
+ * Keep in sync with rust/kernel/print.rs.
+ */
 #define LOG_LINE_MAX		(CONSOLE_LOG_MAX - PREFIX_MAX)
 
 #define LOG_LEVEL(v)		((v) & 0x07)
diff --git a/rust/kernel/allocator.rs b/rust/kernel/allocator.rs
new file mode 100644
index 000000000000..4c5d2fc6f206
--- /dev/null
+++ b/rust/kernel/allocator.rs
@@ -0,0 +1,65 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Allocator support.
+
+use core::alloc::{GlobalAlloc, Layout};
+use core::ptr;
+
+use crate::bindings;
+use crate::c_types;
+
+struct KernelAllocator;
+
+unsafe impl GlobalAlloc for KernelAllocator {
+    unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
+        // `krealloc()` is used instead of `kmalloc()` because the latter is
+        // an inline function and cannot be bound to as a result.
+        unsafe { bindings::krealloc(ptr::null(), layout.size(), bindings::GFP_KERNEL) as *mut u8 }
+    }
+
+    unsafe fn dealloc(&self, ptr: *mut u8, _layout: Layout) {
+        unsafe {
+            bindings::kfree(ptr as *const c_types::c_void);
+        }
+    }
+}
+
+#[global_allocator]
+static ALLOCATOR: KernelAllocator = KernelAllocator;
+
+// `rustc` only generates these for some crate types. Even then, we would need
+// to extract the object file that has them from the archive. For the moment,
+// let's generate them ourselves instead.
+//
+// Note that `#[no_mangle]` implies exported too, nowadays.
+#[no_mangle]
+fn __rust_alloc(size: usize, _align: usize) -> *mut u8 {
+    unsafe { bindings::krealloc(core::ptr::null(), size, bindings::GFP_KERNEL) as *mut u8 }
+}
+
+#[no_mangle]
+fn __rust_dealloc(ptr: *mut u8, _size: usize, _align: usize) {
+    unsafe { bindings::kfree(ptr as *const c_types::c_void) };
+}
+
+#[no_mangle]
+fn __rust_realloc(ptr: *mut u8, _old_size: usize, _align: usize, new_size: usize) -> *mut u8 {
+    unsafe {
+        bindings::krealloc(
+            ptr as *const c_types::c_void,
+            new_size,
+            bindings::GFP_KERNEL,
+        ) as *mut u8
+    }
+}
+
+#[no_mangle]
+fn __rust_alloc_zeroed(size: usize, _align: usize) -> *mut u8 {
+    unsafe {
+        bindings::krealloc(
+            core::ptr::null(),
+            size,
+            bindings::GFP_KERNEL | bindings::__GFP_ZERO,
+        ) as *mut u8
+    }
+}
diff --git a/rust/kernel/amba.rs b/rust/kernel/amba.rs
new file mode 100644
index 000000000000..1775eda7dce6
--- /dev/null
+++ b/rust/kernel/amba.rs
@@ -0,0 +1,259 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Amba devices and drivers.
+//!
+//! C header: [`include/linux/amba/bus.h`](../../../../include/linux/amba/bus.h)
+
+use crate::{
+    bindings, c_types, device, driver, error::from_kernel_result, io_mem::Resource, power,
+    str::CStr, to_result, types::PointerWrapper, Result, ThisModule,
+};
+
+/// A registration of an amba driver.
+pub type Registration<T> = driver::Registration<Adapter<T>>;
+
+/// Id of an Amba device.
+#[derive(Clone, Copy)]
+pub struct DeviceId {
+    /// Device id.
+    pub id: u32,
+
+    /// Mask that identifies which bits are valid in the device id.
+    pub mask: u32,
+}
+
+// SAFETY: `ZERO` is all zeroed-out and `to_rawid` stores `offset` in `amba_id::data`.
+unsafe impl const driver::RawDeviceId for DeviceId {
+    type RawType = bindings::amba_id;
+    const ZERO: Self::RawType = bindings::amba_id {
+        id: 0,
+        mask: 0,
+        data: core::ptr::null_mut(),
+    };
+
+    fn to_rawid(&self, offset: isize) -> Self::RawType {
+        bindings::amba_id {
+            id: self.id,
+            mask: self.mask,
+            data: offset as _,
+        }
+    }
+}
+
+/// An amba driver.
+pub trait Driver {
+    /// Data stored on device by driver.
+    type Data: PointerWrapper + Send + Sync + driver::DeviceRemoval = ();
+
+    /// The type that implements the power-management operations.
+    ///
+    /// The default is a type that implements no power-management operations. Drivers that do
+    /// implement them need to specify the type (commonly [`Self`]).
+    type PowerOps: power::Operations<Data = Self::Data> = power::NoOperations<Self::Data>;
+
+    /// The type holding information about each device id supported by the driver.
+    type IdInfo: 'static = ();
+
+    /// The table of device ids supported by the driver.
+    const ID_TABLE: Option<driver::IdTable<'static, DeviceId, Self::IdInfo>> = None;
+
+    /// Probes for the device with the given id.
+    fn probe(dev: &mut Device, id_info: Option<&Self::IdInfo>) -> Result<Self::Data>;
+
+    /// Cleans any resources up that are associated with the device.
+    ///
+    /// This is called when the driver is detached from the device.
+    fn remove(_data: &Self::Data) {}
+}
+
+/// An adapter for the registration of Amba drivers.
+pub struct Adapter<T: Driver>(T);
+
+impl<T: Driver> driver::DriverOps for Adapter<T> {
+    type RegType = bindings::amba_driver;
+
+    unsafe fn register(
+        reg: *mut bindings::amba_driver,
+        name: &'static CStr,
+        module: &'static ThisModule,
+    ) -> Result {
+        // SAFETY: By the safety requirements of this function (defined in the trait defintion),
+        // `reg` is non-null and valid.
+        let amba = unsafe { &mut *reg };
+        amba.drv.name = name.as_char_ptr();
+        amba.drv.owner = module.0;
+        amba.probe = Some(probe_callback::<T>);
+        amba.remove = Some(remove_callback::<T>);
+        if let Some(t) = T::ID_TABLE {
+            amba.id_table = t.as_ref();
+        }
+        if cfg!(CONFIG_PM) {
+            // SAFETY: `probe_callback` sets the driver data after calling `T::Data::into_pointer`,
+            // and we guarantee that `T::Data` is the same as `T::PowerOps::Data` by a constraint
+            // in the type declaration.
+            amba.drv.pm = unsafe { power::OpsTable::<T::PowerOps>::build() };
+        }
+        // SAFETY: By the safety requirements of this function, `reg` is valid and fully
+        // initialised.
+        to_result(|| unsafe { bindings::amba_driver_register(reg) })
+    }
+
+    unsafe fn unregister(reg: *mut bindings::amba_driver) {
+        // SAFETY: By the safety requirements of this function (defined in the trait definition),
+        // `reg` was passed (and updated) by a previous successful call to `amba_driver_register`.
+        unsafe { bindings::amba_driver_unregister(reg) };
+    }
+}
+
+unsafe extern "C" fn probe_callback<T: Driver>(
+    adev: *mut bindings::amba_device,
+    aid: *const bindings::amba_id,
+) -> c_types::c_int {
+    from_kernel_result! {
+        // SAFETY: `adev` is valid by the contract with the C code. `dev` is alive only for the
+        // duration of this call, so it is guaranteed to remain alive for the lifetime of `dev`.
+        let mut dev = unsafe { Device::from_ptr(adev) };
+        // SAFETY: `aid` is valid by the requirements the contract with the C code.
+        let offset = unsafe { (*aid).data };
+        let info = if offset.is_null() {
+            None
+        } else {
+            // SAFETY: The offset comes from a previous call to `offset_from` in `IdArray::new`,
+            // which guarantees that the resulting pointer is within the table.
+            let ptr = unsafe { aid.cast::<u8>().offset(offset as _).cast::<Option<T::IdInfo>>() };
+            // SAFETY: The id table has a static lifetime, so `ptr` is guaranteed to be valid for
+            // read.
+            unsafe { (&*ptr).as_ref() }
+        };
+        let data = T::probe(&mut dev, info)?;
+        let ptr = T::Data::into_pointer(data);
+        // SAFETY: `adev` is valid for write by the contract with the C code.
+        unsafe { bindings::amba_set_drvdata(adev, ptr as _) };
+        Ok(0)
+    }
+}
+
+unsafe extern "C" fn remove_callback<T: Driver>(adev: *mut bindings::amba_device) {
+    // SAFETY: `adev` is valid by the contract with the C code.
+    let ptr = unsafe { bindings::amba_get_drvdata(adev) };
+    // SAFETY: The value returned by `amba_get_drvdata` was stored by a previous call to
+    // `amba_set_drvdata` in `probe_callback` above; the value comes from a call to
+    // `T::Data::into_pointer`.
+    let data = unsafe { T::Data::from_pointer(ptr) };
+    T::remove(&data);
+    <T::Data as driver::DeviceRemoval>::device_remove(&data);
+}
+
+/// An Amba device.
+///
+/// # Invariants
+///
+/// The field `ptr` is non-null and valid for the lifetime of the object.
+pub struct Device {
+    ptr: *mut bindings::amba_device,
+    res: Option<Resource>,
+}
+
+impl Device {
+    /// Creates a new device from the given pointer.
+    ///
+    /// # Safety
+    ///
+    /// `ptr` must be non-null and valid. It must remain valid for the lifetime of the returned
+    /// instance.
+    unsafe fn from_ptr(ptr: *mut bindings::amba_device) -> Self {
+        // SAFETY: The safety requirements of the function ensure that `ptr` is valid.
+        let dev = unsafe { &mut *ptr };
+        // INVARIANT: The safety requirements of the function ensure the lifetime invariant.
+        Self {
+            ptr,
+            res: Resource::new(dev.res.start, dev.res.end),
+        }
+    }
+
+    /// Returns the io mem resource associated with the device, if there is one.
+    ///
+    /// Ownership of the resource is transferred to the caller, so subsequent calls to this
+    /// function will return [`None`].
+    pub fn take_resource(&mut self) -> Option<Resource> {
+        self.res.take()
+    }
+
+    /// Returns the index-th irq associated with the device, if one exists.
+    pub fn irq(&self, index: usize) -> Option<u32> {
+        // SAFETY: By the type invariants, `self.ptr` is valid for read.
+        let dev = unsafe { &*self.ptr };
+        if index >= dev.irq.len() || dev.irq[index] == 0 {
+            None
+        } else {
+            Some(dev.irq[index])
+        }
+    }
+}
+
+// SAFETY: The device returned by `raw_device` is the raw Amba device.
+unsafe impl device::RawDevice for Device {
+    fn raw_device(&self) -> *mut bindings::device {
+        // SAFETY: By the type invariants, we know that `self.ptr` is non-null and valid.
+        unsafe { &mut (*self.ptr).dev }
+    }
+}
+
+/// Declares a kernel module that exposes a single amba driver.
+///
+/// # Examples
+///
+/// ```ignore
+/// # use kernel::prelude::*;
+/// # use kernel::{amba, define_amba_id_table, module_amba_driver};
+/// #
+/// struct MyDriver;
+/// impl amba::Driver for MyDriver {
+///     // [...]
+/// #   fn probe(_dev: &mut amba::Device, _id: Option<&Self::IdInfo>) -> Result {
+/// #       Ok(())
+/// #   }
+/// #   define_amba_id_table! {(), [
+/// #       ({ id: 0x00041061, mask: 0x000fffff }, None),
+/// #   ]}
+/// }
+///
+/// module_amba_driver! {
+///     type: MyDriver,
+///     name: b"module_name",
+///     author: b"Author name",
+///     license: b"GPL v2",
+/// }
+/// ```
+#[macro_export]
+macro_rules! module_amba_driver {
+    ($($f:tt)*) => {
+        $crate::module_driver!(<T>, $crate::amba::Adapter<T>, { $($f)* });
+    };
+}
+
+/// Defines the id table for amba devices.
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::prelude::*;
+/// # use kernel::{amba, define_amba_id_table};
+/// #
+/// # struct Sample;
+/// # impl kernel::amba::Driver for Sample {
+/// #   fn probe(_dev: &mut amba::Device, _id: Option<&Self::IdInfo>) -> Result {
+/// #       Ok(())
+/// #   }
+///     define_amba_id_table! {(), [
+///         ({ id: 0x00041061, mask: 0x000fffff }, None),
+///     ]}
+/// # }
+/// ```
+#[macro_export]
+macro_rules! define_amba_id_table {
+    ($data_type:ty, $($t:tt)*) => {
+        type IdInfo = $data_type;
+        $crate::define_id_table!(ID_TABLE, $crate::amba::DeviceId, $data_type, $($t)*);
+    };
+}
diff --git a/rust/kernel/bindings.rs b/rust/kernel/bindings.rs
new file mode 100644
index 000000000000..29a21030688e
--- /dev/null
+++ b/rust/kernel/bindings.rs
@@ -0,0 +1,47 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Bindings.
+//!
+//! Imports the generated bindings by `bindgen`.
+
+// See https://github.com/rust-lang/rust-bindgen/issues/1651.
+#![cfg_attr(test, allow(deref_nullptr))]
+#![cfg_attr(test, allow(unaligned_references))]
+#![cfg_attr(test, allow(unsafe_op_in_unsafe_fn))]
+#![allow(
+    clippy::all,
+    non_camel_case_types,
+    non_upper_case_globals,
+    non_snake_case,
+    improper_ctypes,
+    unreachable_pub,
+    unsafe_op_in_unsafe_fn
+)]
+
+mod bindings_raw {
+    // Use glob import here to expose all helpers.
+    // Symbols defined within the module will take precedence to the glob import.
+    pub use super::bindings_helper::*;
+    use crate::c_types;
+    include!(concat!(env!("OBJTREE"), "/rust/bindings_generated.rs"));
+}
+
+// When both a directly exposed symbol and a helper exists for the same function,
+// the directly exposed symbol is preferred and the helper becomes dead code, so
+// ignore the warning here.
+#[allow(dead_code)]
+mod bindings_helper {
+    // Import the generated bindings for types.
+    use super::bindings_raw::*;
+    use crate::c_types;
+    include!(concat!(
+        env!("OBJTREE"),
+        "/rust/bindings_helpers_generated.rs"
+    ));
+}
+
+pub use bindings_raw::*;
+
+pub const GFP_KERNEL: gfp_t = BINDINGS_GFP_KERNEL;
+pub const __GFP_ZERO: gfp_t = BINDINGS___GFP_ZERO;
+pub const __GFP_HIGHMEM: gfp_t = ___GFP_HIGHMEM;
diff --git a/rust/kernel/bindings_helper.h b/rust/kernel/bindings_helper.h
new file mode 100644
index 000000000000..a79f3f398b93
--- /dev/null
+++ b/rust/kernel/bindings_helper.h
@@ -0,0 +1,30 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#include <linux/cdev.h>
+#include <linux/clk.h>
+#include <linux/errname.h>
+#include <linux/fs.h>
+#include <linux/module.h>
+#include <linux/random.h>
+#include <linux/slab.h>
+#include <linux/sysctl.h>
+#include <linux/uaccess.h>
+#include <linux/uio.h>
+#include <linux/miscdevice.h>
+#include <linux/poll.h>
+#include <linux/mm.h>
+#include <linux/file.h>
+#include <uapi/linux/android/binder.h>
+#include <linux/platform_device.h>
+#include <linux/of_platform.h>
+#include <linux/security.h>
+#include <asm/io.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/irqdomain.h>
+#include <linux/amba/bus.h>
+#include <linux/gpio/driver.h>
+
+// `bindgen` gets confused at certain things
+const gfp_t BINDINGS_GFP_KERNEL = GFP_KERNEL;
+const gfp_t BINDINGS___GFP_ZERO = __GFP_ZERO;
diff --git a/rust/kernel/buffer.rs b/rust/kernel/buffer.rs
new file mode 100644
index 000000000000..48f429065323
--- /dev/null
+++ b/rust/kernel/buffer.rs
@@ -0,0 +1,52 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Struct for writing to a pre-allocated buffer with the [`write!`] macro.
+
+use core::fmt;
+
+/// A pre-allocated buffer that implements [`core::fmt::Write`].
+///
+/// Consecutive writes will append to what has already been written.
+/// Writes that don't fit in the buffer will fail.
+pub struct Buffer<'a> {
+    slice: &'a mut [u8],
+    pos: usize,
+}
+
+impl<'a> Buffer<'a> {
+    /// Creates a new buffer from an existing array.
+    pub fn new(slice: &'a mut [u8]) -> Self {
+        Buffer { slice, pos: 0 }
+    }
+
+    /// Creates a new buffer from a raw pointer.
+    ///
+    /// # Safety
+    ///
+    /// `ptr` must be valid for read and writes, have at least `len` bytes in
+    /// size, and remain valid and not be used by other threads for the lifetime
+    /// of the returned instance.
+    pub unsafe fn from_raw(ptr: *mut u8, len: usize) -> Self {
+        // SAFETY: The safety requirements of the function satisfy those of
+        // `from_raw_parts_mut`.
+        Self::new(unsafe { core::slice::from_raw_parts_mut(ptr, len) })
+    }
+
+    /// Number of bytes that have already been written to the buffer.
+    /// This will always be less than the length of the original array.
+    pub fn bytes_written(&self) -> usize {
+        self.pos
+    }
+}
+
+impl fmt::Write for Buffer<'_> {
+    fn write_str(&mut self, s: &str) -> fmt::Result {
+        if s.len() > self.slice.len() - self.pos {
+            Err(fmt::Error)
+        } else {
+            self.slice[self.pos..self.pos + s.len()].copy_from_slice(s.as_bytes());
+            self.pos += s.len();
+            Ok(())
+        }
+    }
+}
diff --git a/rust/kernel/build_assert.rs b/rust/kernel/build_assert.rs
new file mode 100644
index 000000000000..f726927185c0
--- /dev/null
+++ b/rust/kernel/build_assert.rs
@@ -0,0 +1,80 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Build-time assert.
+
+/// Fails the build if the code path calling `build_error!` can possibly be executed.
+///
+/// If the macro is executed in const context, `build_error!` will panic.
+/// If the compiler or optimizer cannot guarantee that `build_error!` can never
+/// be called, a build error will be triggered.
+///
+/// # Examples
+/// ```
+/// # use kernel::build_error;
+/// #[inline]
+/// fn foo(a: usize) -> usize {
+///     a.checked_add(1).unwrap_or_else(|| build_error!("overflow"))
+/// }
+/// ```
+#[macro_export]
+macro_rules! build_error {
+    () => {{
+        $crate::build_error("")
+    }};
+    ($msg:expr) => {{
+        $crate::build_error($msg)
+    }};
+}
+
+/// Asserts that a boolean expression is `true` at compile time.
+///
+/// If the condition is evaluated to `false` in const context, `build_assert!`
+/// will panic. If the compiler or optimizer cannot guarantee the condition will
+/// be evaluated to `true`, a build error will be triggered.
+///
+/// [`static_assert!`] should be preferred to `build_assert!` whenever possible.
+///
+/// # Examples
+///
+/// These examples show that different types of [`assert!`] will trigger errors
+/// at different stage of compilation. It is preferred to err as early as
+/// possible, so [`static_assert!`] should be used whenever possible.
+/// ```compile_fail
+/// # use kernel::prelude::*;
+/// fn foo() {
+///     static_assert!(1 > 1); // Compile-time error
+///     build_assert!(1 > 1); // Build-time error
+///     assert!(1 > 1); // Run-time error
+/// }
+/// ```
+///
+/// When the condition refers to generic parameters or parameters of an inline function,
+/// [`static_assert!`] cannot be used. Use `build_assert!` in this scenario.
+/// ```no_run
+/// # use kernel::prelude::*;
+/// fn foo<const N: usize>() {
+///     // `static_assert!(N > 1);` is not allowed
+///     build_assert!(N > 1); // Build-time check
+///     assert!(N > 1); // Run-time check
+/// }
+///
+/// #[inline]
+/// fn bar(n: usize) {
+///     // `static_assert!(n > 1);` is not allowed
+///     build_assert!(n > 1); // Build-time check
+///     assert!(n > 1); // Run-time check
+/// }
+/// ```
+#[macro_export]
+macro_rules! build_assert {
+    ($cond:expr $(,)?) => {{
+        if !$cond {
+            $crate::build_error(concat!("assertion failed: ", stringify!($cond)));
+        }
+    }};
+    ($cond:expr, $msg:expr) => {{
+        if !$cond {
+            $crate::build_error($msg);
+        }
+    }};
+}
diff --git a/rust/kernel/c_types.rs b/rust/kernel/c_types.rs
new file mode 100644
index 000000000000..07593a3ba8be
--- /dev/null
+++ b/rust/kernel/c_types.rs
@@ -0,0 +1,119 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! C types for the bindings.
+//!
+//! The bindings generated by `bindgen` use these types to map to the C ones.
+//!
+//! C's standard integer types may differ in width depending on
+//! the architecture, thus we need to conditionally compile those.
+
+#![allow(non_camel_case_types)]
+
+#[cfg(any(target_arch = "arm", target_arch = "x86", target_arch = "riscv32",))]
+mod c {
+    /// C `void` type.
+    pub type c_void = core::ffi::c_void;
+
+    /// C `char` type.
+    pub type c_char = i8;
+
+    /// C `signed char` type.
+    pub type c_schar = i8;
+
+    /// C `unsigned char` type.
+    pub type c_uchar = u8;
+
+    /// C `short` type.
+    pub type c_short = i16;
+
+    /// C `unsigned short` type.
+    pub type c_ushort = u16;
+
+    /// C `int` type.
+    pub type c_int = i32;
+
+    /// C `unsigned int` type.
+    pub type c_uint = u32;
+
+    /// C `long` type.
+    pub type c_long = i32;
+
+    /// C `unsigned long` type.
+    pub type c_ulong = u32;
+
+    /// C `long long` type.
+    pub type c_longlong = i64;
+
+    /// C `unsigned long long` type.
+    pub type c_ulonglong = u64;
+
+    /// C `ssize_t` type (typically defined in `<sys/types.h>` by POSIX).
+    ///
+    /// For some 32-bit architectures like this one, the kernel defines it as
+    /// `int`, i.e. it is an [`i32`].
+    pub type c_ssize_t = isize;
+
+    /// C `size_t` type (typically defined in `<stddef.h>`).
+    ///
+    /// For some 32-bit architectures like this one, the kernel defines it as
+    /// `unsigned int`, i.e. it is an [`u32`].
+    pub type c_size_t = usize;
+}
+
+#[cfg(any(
+    target_arch = "aarch64",
+    target_arch = "x86_64",
+    target_arch = "powerpc64",
+    target_arch = "riscv64",
+))]
+mod c {
+    /// C `void` type.
+    pub type c_void = core::ffi::c_void;
+
+    /// C `char` type.
+    pub type c_char = i8;
+
+    /// C `signed char` type.
+    pub type c_schar = i8;
+
+    /// C `unsigned char` type.
+    pub type c_uchar = u8;
+
+    /// C `short` type.
+    pub type c_short = i16;
+
+    /// C `unsigned short` type.
+    pub type c_ushort = u16;
+
+    /// C `int` type.
+    pub type c_int = i32;
+
+    /// C `unsigned int` type.
+    pub type c_uint = u32;
+
+    /// C `long` type.
+    pub type c_long = i64;
+
+    /// C `unsigned long` type.
+    pub type c_ulong = u64;
+
+    /// C `long long` type.
+    pub type c_longlong = i64;
+
+    /// C `unsigned long long` type.
+    pub type c_ulonglong = u64;
+
+    /// C `ssize_t` type (typically defined in `<sys/types.h>` by POSIX).
+    ///
+    /// For 64-bit architectures like this one, the kernel defines it as
+    /// `long`, i.e. it is an [`i64`].
+    pub type c_ssize_t = isize;
+
+    /// C `size_t` type (typically defined in `<stddef.h>`).
+    ///
+    /// For 64-bit architectures like this one, the kernel defines it as
+    /// `unsigned long`, i.e. it is an [`u64`].
+    pub type c_size_t = usize;
+}
+
+pub use c::*;
diff --git a/rust/kernel/chrdev.rs b/rust/kernel/chrdev.rs
new file mode 100644
index 000000000000..9a15e113ebcf
--- /dev/null
+++ b/rust/kernel/chrdev.rs
@@ -0,0 +1,209 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Character devices.
+//!
+//! Also called "char devices", `chrdev`, `cdev`.
+//!
+//! C header: [`include/linux/cdev.h`](../../../../include/linux/cdev.h)
+//!
+//! Reference: <https://www.kernel.org/doc/html/latest/core-api/kernel-api.html#char-devices>
+
+use alloc::boxed::Box;
+use core::convert::TryInto;
+use core::marker::PhantomPinned;
+use core::pin::Pin;
+
+use crate::bindings;
+use crate::c_types;
+use crate::error::{Error, Result};
+use crate::file_operations;
+use crate::str::CStr;
+
+/// Character device.
+///
+/// # Invariants
+///
+///   - [`self.0`] is valid and non-null.
+///   - [`(*self.0).ops`] is valid, non-null and has static lifetime.
+///   - [`(*self.0).owner`] is valid and, if non-null, has module lifetime.
+struct Cdev(*mut bindings::cdev);
+
+impl Cdev {
+    fn alloc(
+        fops: &'static bindings::file_operations,
+        module: &'static crate::ThisModule,
+    ) -> Result<Self> {
+        // SAFETY: FFI call.
+        let cdev = unsafe { bindings::cdev_alloc() };
+        if cdev.is_null() {
+            return Err(Error::ENOMEM);
+        }
+        // SAFETY: `cdev` is valid and non-null since `cdev_alloc()`
+        // returned a valid pointer which was null-checked.
+        unsafe {
+            (*cdev).ops = fops;
+            (*cdev).owner = module.0;
+        }
+        // INVARIANTS:
+        //   - [`self.0`] is valid and non-null.
+        //   - [`(*self.0).ops`] is valid, non-null and has static lifetime,
+        //     because it was coerced from a reference with static lifetime.
+        //   - [`(*self.0).owner`] is valid and, if non-null, has module lifetime,
+        //     guaranteed by the [`ThisModule`] invariant.
+        Ok(Self(cdev))
+    }
+
+    fn add(&mut self, dev: bindings::dev_t, count: c_types::c_uint) -> Result {
+        // SAFETY: According to the type invariants:
+        //   - [`self.0`] can be safely passed to [`bindings::cdev_add`].
+        //   - [`(*self.0).ops`] will live at least as long as [`self.0`].
+        //   - [`(*self.0).owner`] will live at least as long as the
+        //     module, which is an implicit requirement.
+        let rc = unsafe { bindings::cdev_add(self.0, dev, count) };
+        if rc != 0 {
+            return Err(Error::from_kernel_errno(rc));
+        }
+        Ok(())
+    }
+}
+
+impl Drop for Cdev {
+    fn drop(&mut self) {
+        // SAFETY: [`self.0`] is valid and non-null by the type invariants.
+        unsafe {
+            bindings::cdev_del(self.0);
+        }
+    }
+}
+
+struct RegistrationInner<const N: usize> {
+    dev: bindings::dev_t,
+    used: usize,
+    cdevs: [Option<Cdev>; N],
+    _pin: PhantomPinned,
+}
+
+/// Character device registration.
+///
+/// May contain up to a fixed number (`N`) of devices. Must be pinned.
+pub struct Registration<const N: usize> {
+    name: &'static CStr,
+    minors_start: u16,
+    this_module: &'static crate::ThisModule,
+    inner: Option<RegistrationInner<N>>,
+}
+
+impl<const N: usize> Registration<{ N }> {
+    /// Creates a [`Registration`] object for a character device.
+    ///
+    /// This does *not* register the device: see [`Self::register()`].
+    ///
+    /// This associated function is intended to be used when you need to avoid
+    /// a memory allocation, e.g. when the [`Registration`] is a member of
+    /// a bigger structure inside your [`crate::KernelModule`] instance. If you
+    /// are going to pin the registration right away, call
+    /// [`Self::new_pinned()`] instead.
+    pub fn new(
+        name: &'static CStr,
+        minors_start: u16,
+        this_module: &'static crate::ThisModule,
+    ) -> Self {
+        Registration {
+            name,
+            minors_start,
+            this_module,
+            inner: None,
+        }
+    }
+
+    /// Creates a pinned [`Registration`] object for a character device.
+    ///
+    /// This does *not* register the device: see [`Self::register()`].
+    pub fn new_pinned(
+        name: &'static CStr,
+        minors_start: u16,
+        this_module: &'static crate::ThisModule,
+    ) -> Result<Pin<Box<Self>>> {
+        Ok(Pin::from(Box::try_new(Self::new(
+            name,
+            minors_start,
+            this_module,
+        ))?))
+    }
+
+    /// Registers a character device.
+    ///
+    /// You may call this once per device type, up to `N` times.
+    pub fn register<T: file_operations::FileOperations<OpenData = ()>>(
+        self: Pin<&mut Self>,
+    ) -> Result {
+        // SAFETY: We must ensure that we never move out of `this`.
+        let this = unsafe { self.get_unchecked_mut() };
+        if this.inner.is_none() {
+            let mut dev: bindings::dev_t = 0;
+            // SAFETY: Calling unsafe function. `this.name` has `'static`
+            // lifetime.
+            let res = unsafe {
+                bindings::alloc_chrdev_region(
+                    &mut dev,
+                    this.minors_start.into(),
+                    N.try_into()?,
+                    this.name.as_char_ptr(),
+                )
+            };
+            if res != 0 {
+                return Err(Error::from_kernel_errno(res));
+            }
+            const NONE: Option<Cdev> = None;
+            this.inner = Some(RegistrationInner {
+                dev,
+                used: 0,
+                cdevs: [NONE; N],
+                _pin: PhantomPinned,
+            });
+        }
+
+        let mut inner = this.inner.as_mut().unwrap();
+        if inner.used == N {
+            return Err(Error::EINVAL);
+        }
+
+        // SAFETY: The adapter doesn't retrieve any state yet, so it's compatible with any
+        // registration.
+        let fops = unsafe { file_operations::FileOperationsVtable::<Self, T>::build() };
+        let mut cdev = Cdev::alloc(fops, this.this_module)?;
+        cdev.add(inner.dev + inner.used as bindings::dev_t, 1)?;
+        inner.cdevs[inner.used].replace(cdev);
+        inner.used += 1;
+        Ok(())
+    }
+}
+
+impl<const N: usize> file_operations::FileOpenAdapter<()> for Registration<{ N }> {
+    unsafe fn convert(_inode: *mut bindings::inode, _file: *mut bindings::file) -> *const () {
+        // TODO: Update the SAFETY comment on the call to `FileOperationsVTable::build` above once
+        // this is updated to retrieve state.
+        &()
+    }
+}
+
+// SAFETY: `Registration` does not expose any of its state across threads
+// (it is fine for multiple threads to have a shared reference to it).
+unsafe impl<const N: usize> Sync for Registration<{ N }> {}
+
+impl<const N: usize> Drop for Registration<{ N }> {
+    fn drop(&mut self) {
+        if let Some(inner) = self.inner.as_mut() {
+            // Replicate kernel C behaviour: drop [`Cdev`]s before calling
+            // [`bindings::unregister_chrdev_region`].
+            for i in 0..inner.used {
+                inner.cdevs[i].take();
+            }
+            // SAFETY: [`self.inner`] is Some, so [`inner.dev`] was previously
+            // created using [`bindings::alloc_chrdev_region`].
+            unsafe {
+                bindings::unregister_chrdev_region(inner.dev, N.try_into().unwrap());
+            }
+        }
+    }
+}
diff --git a/rust/kernel/clk.rs b/rust/kernel/clk.rs
new file mode 100644
index 000000000000..46d3b81f5688
--- /dev/null
+++ b/rust/kernel/clk.rs
@@ -0,0 +1,75 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Common clock framework.
+//!
+//! C header: [`include/linux/clk.h`](../../../../include/linux/clk.h)
+
+use crate::{bindings, error::Result, to_result};
+use core::mem::ManuallyDrop;
+
+/// Represents `struct clk *`.
+///
+/// # Invariants
+///
+/// The pointer is valid.
+pub struct Clk(*mut bindings::clk);
+
+impl Clk {
+    /// Creates new clock structure from a raw pointer.
+    ///
+    /// # Safety
+    ///
+    /// The pointer must be valid.
+    pub unsafe fn new(clk: *mut bindings::clk) -> Self {
+        Self(clk)
+    }
+
+    /// Returns value of the rate field of `struct clk`.
+    pub fn get_rate(&self) -> usize {
+        // SAFETY: The pointer is valid by the type invariant.
+        unsafe { bindings::clk_get_rate(self.0) as usize }
+    }
+
+    /// Prepares and enables the underlying hardware clock.
+    ///
+    /// This function should not be called in atomic context.
+    pub fn prepare_enable(self) -> Result<EnabledClk> {
+        // SAFETY: The pointer is valid by the type invariant.
+        to_result(|| unsafe { bindings::clk_prepare_enable(self.0) })?;
+        Ok(EnabledClk(self))
+    }
+}
+
+impl Drop for Clk {
+    fn drop(&mut self) {
+        // SAFETY: The pointer is valid by the type invariant.
+        unsafe { bindings::clk_put(self.0) };
+    }
+}
+
+/// A clock variant that is prepared and enabled.
+pub struct EnabledClk(Clk);
+
+impl EnabledClk {
+    /// Returns value of the rate field of `struct clk`.
+    pub fn get_rate(&self) -> usize {
+        self.0.get_rate()
+    }
+
+    /// Disables and later unprepares the underlying hardware clock prematurely.
+    ///
+    /// This function should not be called in atomic context.
+    pub fn disable_unprepare(self) -> Clk {
+        let mut clk = ManuallyDrop::new(self);
+        // SAFETY: The pointer is valid by the type invariant.
+        unsafe { bindings::clk_disable_unprepare(clk.0 .0) };
+        core::mem::replace(&mut clk.0, Clk(core::ptr::null_mut()))
+    }
+}
+
+impl Drop for EnabledClk {
+    fn drop(&mut self) {
+        // SAFETY: The pointer is valid by the type invariant.
+        unsafe { bindings::clk_disable_unprepare(self.0 .0) };
+    }
+}
diff --git a/rust/kernel/cred.rs b/rust/kernel/cred.rs
new file mode 100644
index 000000000000..1602aa6935ca
--- /dev/null
+++ b/rust/kernel/cred.rs
@@ -0,0 +1,73 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Credentials management.
+//!
+//! C header: [`include/linux/cred.h`](../../../../include/linux/cred.h)
+//!
+//! Reference: <https://www.kernel.org/doc/html/latest/security/credentials.html>
+
+use crate::bindings;
+use core::{marker::PhantomData, mem::ManuallyDrop, ops::Deref};
+
+/// Wraps the kernel's `struct cred`.
+///
+/// # Invariants
+///
+/// The pointer `Credential::ptr` is non-null and valid. Its reference count is also non-zero.
+pub struct Credential {
+    pub(crate) ptr: *const bindings::cred,
+}
+
+impl Clone for Credential {
+    fn clone(&self) -> Self {
+        // SAFETY: The type invariants guarantee that `self.ptr` has a non-zero reference count.
+        let ptr = unsafe { bindings::get_cred(self.ptr) };
+
+        // INVARIANT: We incremented the reference count to account for the new `Credential` being
+        // created.
+        Self { ptr }
+    }
+}
+
+impl Drop for Credential {
+    fn drop(&mut self) {
+        // SAFETY: The type invariants guarantee that `ptr` has a non-zero reference count.
+        unsafe { bindings::put_cred(self.ptr) };
+    }
+}
+
+/// A wrapper for [`Credential`] that doesn't automatically decrement the refcount when dropped.
+///
+/// We need the wrapper because [`ManuallyDrop`] alone would allow callers to call
+/// [`ManuallyDrop::into_inner`]. This would allow an unsafe sequence to be triggered without
+/// `unsafe` blocks because it would trigger an unbalanced call to `put_cred`.
+///
+/// # Invariants
+///
+/// The wrapped [`Credential`] remains valid for the lifetime of the object.
+pub struct CredentialRef<'a> {
+    cred: ManuallyDrop<Credential>,
+    _p: PhantomData<&'a ()>,
+}
+
+impl CredentialRef<'_> {
+    /// Constructs a new [`struct cred`] wrapper that doesn't change its reference count.
+    ///
+    /// # Safety
+    ///
+    /// The pointer `ptr` must be non-null and valid for the lifetime of the object.
+    pub(crate) unsafe fn from_ptr(ptr: *const bindings::cred) -> Self {
+        Self {
+            cred: ManuallyDrop::new(Credential { ptr }),
+            _p: PhantomData,
+        }
+    }
+}
+
+impl Deref for CredentialRef<'_> {
+    type Target = Credential;
+
+    fn deref(&self) -> &Self::Target {
+        self.cred.deref()
+    }
+}
diff --git a/rust/kernel/device.rs b/rust/kernel/device.rs
new file mode 100644
index 000000000000..05a9484cbcd4
--- /dev/null
+++ b/rust/kernel/device.rs
@@ -0,0 +1,554 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Generic devices that are part of the kernel's driver model.
+//!
+//! C header: [`include/linux/device.h`](../../../../include/linux/device.h)
+
+#[cfg(CONFIG_COMMON_CLK)]
+use crate::{clk::Clk, error::from_kernel_err_ptr};
+
+use crate::{
+    bindings,
+    revocable::{Revocable, RevocableGuard},
+    str::CStr,
+    sync::{NeedsLockClass, RevocableMutex, RevocableMutexGuard, UniqueRef},
+    Result,
+};
+use core::{
+    fmt,
+    ops::{Deref, DerefMut},
+    pin::Pin,
+};
+
+#[cfg(CONFIG_PRINTK)]
+use crate::{c_str, c_types};
+
+/// A raw device.
+///
+/// # Safety
+///
+/// Implementers must ensure that the `*mut device` returned by [`RawDevice::raw_device`] is
+/// related to `self`, that is, actions on it will affect `self`. For example, if one calls
+/// `get_device`, then the refcount on the device represented by `self` will be incremented.
+///
+/// Additionally, implementers must ensure that the device is never renamed. Commit a5462516aa994
+/// has details on why `device_rename` should not be used.
+pub unsafe trait RawDevice {
+    /// Returns the raw `struct device` related to `self`.
+    fn raw_device(&self) -> *mut bindings::device;
+
+    /// Returns the name of the device.
+    fn name(&self) -> &CStr {
+        let ptr = self.raw_device();
+
+        // SAFETY: `ptr` is valid because `self` keeps it alive.
+        let name = unsafe { bindings::dev_name(ptr) };
+
+        // SAFETY: The name of the device remains valid while it is alive (because the device is
+        // never renamed, per the safety requirement of this trait). This is guaranteed to be the
+        // case because the reference to `self` outlives the one of the returned `CStr` (enforced
+        // by the compiler because of their lifetimes).
+        unsafe { CStr::from_char_ptr(name) }
+    }
+
+    /// Lookups a clock producer consumed by this device.
+    ///
+    /// Returns a managed reference to the clock producer.
+    #[cfg(CONFIG_COMMON_CLK)]
+    fn clk_get(&self, id: Option<&CStr>) -> Result<Clk> {
+        let id_ptr = match id {
+            Some(cstr) => cstr.as_char_ptr(),
+            None => core::ptr::null(),
+        };
+
+        // SAFETY: `id_ptr` is optional and may be either a valid pointer
+        // from the type invariant or NULL otherwise.
+        let clk_ptr = unsafe { from_kernel_err_ptr(bindings::clk_get(self.raw_device(), id_ptr)) }?;
+
+        // SAFETY: Clock is initialized with valid pointer returned from `bindings::clk_get` call.
+        unsafe { Ok(Clk::new(clk_ptr)) }
+    }
+
+    /// Prints an emergency-level message (level 0) prefixed with device information.
+    ///
+    /// More details are available from [`dev_emerg`].
+    fn pr_emerg(&self, args: fmt::Arguments<'_>) {
+        // SAFETY: `klevel` is null-terminated, uses one of the kernel constants.
+        unsafe { self.printk(bindings::KERN_EMERG, args) };
+    }
+
+    /// Prints an alert-level message (level 1) prefixed with device information.
+    ///
+    /// More details are available from [`dev_alert`].
+    fn pr_alert(&self, args: fmt::Arguments<'_>) {
+        // SAFETY: `klevel` is null-terminated, uses one of the kernel constants.
+        unsafe { self.printk(bindings::KERN_ALERT, args) };
+    }
+
+    /// Prints a critical-level message (level 2) prefixed with device information.
+    ///
+    /// More details are available from [`dev_crit`].
+    fn pr_crit(&self, args: fmt::Arguments<'_>) {
+        // SAFETY: `klevel` is null-terminated, uses one of the kernel constants.
+        unsafe { self.printk(bindings::KERN_CRIT, args) };
+    }
+
+    /// Prints an error-level message (level 3) prefixed with device information.
+    ///
+    /// More details are available from [`dev_err`].
+    fn pr_err(&self, args: fmt::Arguments<'_>) {
+        // SAFETY: `klevel` is null-terminated, uses one of the kernel constants.
+        unsafe { self.printk(bindings::KERN_ERR, args) };
+    }
+
+    /// Prints a warning-level message (level 4) prefixed with device information.
+    ///
+    /// More details are available from [`dev_warn`].
+    fn pr_warn(&self, args: fmt::Arguments<'_>) {
+        // SAFETY: `klevel` is null-terminated, uses one of the kernel constants.
+        unsafe { self.printk(bindings::KERN_WARNING, args) };
+    }
+
+    /// Prints a notice-level message (level 5) prefixed with device information.
+    ///
+    /// More details are available from [`dev_notice`].
+    fn pr_notice(&self, args: fmt::Arguments<'_>) {
+        // SAFETY: `klevel` is null-terminated, uses one of the kernel constants.
+        unsafe { self.printk(bindings::KERN_NOTICE, args) };
+    }
+
+    /// Prints an info-level message (level 6) prefixed with device information.
+    ///
+    /// More details are available from [`dev_info`].
+    fn pr_info(&self, args: fmt::Arguments<'_>) {
+        // SAFETY: `klevel` is null-terminated, uses one of the kernel constants.
+        unsafe { self.printk(bindings::KERN_INFO, args) };
+    }
+
+    /// Prints a debug-level message (level 7) prefixed with device information.
+    ///
+    /// More details are available from [`dev_dbg`].
+    fn pr_dbg(&self, args: fmt::Arguments<'_>) {
+        if cfg!(debug_assertions) {
+            // SAFETY: `klevel` is null-terminated, uses one of the kernel constants.
+            unsafe { self.printk(bindings::KERN_DEBUG, args) };
+        }
+    }
+
+    /// Prints the provided message to the console.
+    ///
+    /// # Safety
+    ///
+    /// Callers must ensure that `klevel` is null-terminated; in particular, one of the
+    /// `KERN_*`constants, for example, `KERN_CRIT`, `KERN_ALERT`, etc.
+    #[cfg_attr(not(CONFIG_PRINTK), allow(unused_variables))]
+    unsafe fn printk(&self, klevel: &[u8], msg: fmt::Arguments<'_>) {
+        // SAFETY: `klevel` is null-terminated and one of the kernel constants. `self.raw_device`
+        // is valid because `self` is valid. The "%pA" format string expects a pointer to
+        // `fmt::Arguments`, which is what we're passing as the last argument.
+        #[cfg(CONFIG_PRINTK)]
+        unsafe {
+            bindings::_dev_printk(
+                klevel as *const _ as *const c_types::c_char,
+                self.raw_device(),
+                c_str!("%pA").as_char_ptr(),
+                &msg as *const _ as *const c_types::c_void,
+            )
+        };
+    }
+}
+
+/// A ref-counted device.
+///
+/// # Invariants
+///
+/// `ptr` is valid, non-null, and has a non-zero reference count. One of the references is owned by
+/// `self`, and will be decremented when `self` is dropped.
+pub struct Device {
+    pub(crate) ptr: *mut bindings::device,
+}
+
+// SAFETY: `Device` only holds a pointer to a C device, which is safe to be used from any thread.
+unsafe impl Send for Device {}
+
+// SAFETY: `Device` only holds a pointer to a C device, references to which are safe to be used
+// from any thread.
+unsafe impl Sync for Device {}
+
+impl Device {
+    /// Creates a new device instance.
+    ///
+    /// # Safety
+    ///
+    /// Callers must ensure that `ptr` is valid, non-null, and has a non-zero reference count.
+    pub unsafe fn new(ptr: *mut bindings::device) -> Self {
+        // SAFETY: By the safety requirements, ptr is valid and its refcounted will be incremented.
+        unsafe { bindings::get_device(ptr) };
+        // INVARIANT: The safety requirements satisfy all but one invariant, which is that `self`
+        // owns a reference. This is satisfied by the call to `get_device` above.
+        Self { ptr }
+    }
+
+    /// Creates a new device instance from an existing [`RawDevice`] instance.
+    pub fn from_dev(dev: &dyn RawDevice) -> Self {
+        // SAFETY: The requirements are satisfied by the existence of `RawDevice` and its safety
+        // requirements.
+        unsafe { Self::new(dev.raw_device()) }
+    }
+}
+
+// SAFETY: The device returned by `raw_device` is the one for which we hold a reference.
+unsafe impl RawDevice for Device {
+    fn raw_device(&self) -> *mut bindings::device {
+        self.ptr
+    }
+}
+
+impl Drop for Device {
+    fn drop(&mut self) {
+        // SAFETY: By the type invariants, we know that `self` owns a reference, so it is safe to
+        // relinquish it now.
+        unsafe { bindings::put_device(self.ptr) };
+    }
+}
+
+/// Device data.
+///
+/// When a device is removed (for whatever reason, for example, because the device was unplugged or
+/// because the user decided to unbind the driver), the driver is given a chance to clean its state
+/// up, and all io resources should ideally not be used anymore.
+///
+/// However, the device data is reference-counted because other subsystems hold pointers to it. So
+/// some device state must be freed and not used anymore, while others must remain accessible.
+///
+/// This struct separates the device data into three categories:
+///   1. Registrations: are destroyed when the device is removed, but before the io resources
+///      become inaccessible.
+///   2. Io resources: are available until the device is removed.
+///   3. General data: remain available as long as the ref count is nonzero.
+///
+/// This struct implements the `DeviceRemoval` trait so that it can clean resources up even if not
+/// explicitly called by the device drivers.
+pub struct Data<T, U, V> {
+    registrations: RevocableMutex<T>,
+    resources: Revocable<U>,
+    general: V,
+}
+
+/// Safely creates an new reference-counted instance of [`Data`].
+#[doc(hidden)]
+#[macro_export]
+macro_rules! new_device_data {
+    ($reg:expr, $res:expr, $gen:expr, $name:literal) => {{
+        static mut CLASS1: core::mem::MaybeUninit<$crate::bindings::lock_class_key> =
+            core::mem::MaybeUninit::uninit();
+        static mut CLASS2: core::mem::MaybeUninit<$crate::bindings::lock_class_key> =
+            core::mem::MaybeUninit::uninit();
+        let regs = $reg;
+        let res = $res;
+        let gen = $gen;
+        let name = $crate::c_str!($name);
+        // SAFETY: `CLASS1` and `CLASS2` are never used by Rust code directly; the C portion of the
+        // kernel may change it though.
+        unsafe {
+            $crate::device::Data::try_new(
+                regs,
+                res,
+                gen,
+                name,
+                CLASS1.as_mut_ptr(),
+                CLASS2.as_mut_ptr(),
+            )
+        }
+    }};
+}
+
+impl<T, U, V> Data<T, U, V> {
+    /// Creates a new instance of `Data`.
+    ///
+    /// It is recommended that the [`new_device_data`] macro be used as it automatically creates
+    /// the lock classes.
+    ///
+    /// # Safety
+    ///
+    /// `key1` and `key2` must point to valid memory locations and remain valid until `self` is
+    /// dropped.
+    pub unsafe fn try_new(
+        registrations: T,
+        resources: U,
+        general: V,
+        name: &'static CStr,
+        key1: *mut bindings::lock_class_key,
+        key2: *mut bindings::lock_class_key,
+    ) -> Result<Pin<UniqueRef<Self>>> {
+        let mut ret = Pin::from(UniqueRef::try_new(Self {
+            // SAFETY: We call `RevocableMutex::init` below.
+            registrations: unsafe { RevocableMutex::new(registrations) },
+            resources: Revocable::new(resources),
+            general,
+        })?);
+
+        // SAFETY: `Data::registrations` is pinned when `Data` is.
+        let pinned = unsafe { ret.as_mut().map_unchecked_mut(|d| &mut d.registrations) };
+
+        // SAFETY: The safety requirements of this function satisfy those of `RevocableMutex::init`.
+        unsafe { pinned.init(name, key1, key2) };
+        Ok(ret)
+    }
+
+    /// Returns the resources if they're still available.
+    pub fn resources(&self) -> Option<RevocableGuard<'_, U>> {
+        self.resources.try_access()
+    }
+
+    /// Returns the locked registrations if they're still available.
+    pub fn registrations(&self) -> Option<RevocableMutexGuard<'_, T>> {
+        self.registrations.try_lock()
+    }
+}
+
+impl<T, U, V> crate::driver::DeviceRemoval for Data<T, U, V> {
+    fn device_remove(&self) {
+        // We revoke the registrations first so that resources are still available to them during
+        // unregistration.
+        self.registrations.revoke();
+
+        // Release resources now. General data remains available.
+        self.resources.revoke();
+    }
+}
+
+impl<T, U, V> Deref for Data<T, U, V> {
+    type Target = V;
+
+    fn deref(&self) -> &V {
+        &self.general
+    }
+}
+
+impl<T, U, V> DerefMut for Data<T, U, V> {
+    fn deref_mut(&mut self) -> &mut V {
+        &mut self.general
+    }
+}
+
+#[doc(hidden)]
+#[macro_export]
+macro_rules! dev_printk {
+    ($method:ident, $dev:expr, $($f:tt)*) => {
+        {
+            // We have an explicity `use` statement here so that callers of this macro are not
+            // required to explicitly use the `RawDevice` trait to use its functions.
+            use $crate::device::RawDevice;
+            ($dev).$method(core::format_args!($($f)*));
+        }
+    }
+}
+
+/// Prints an emergency-level message (level 0) prefixed with device information.
+///
+/// This level should be used if the system is unusable.
+///
+/// Equivalent to the kernel's `dev_emerg` macro.
+///
+/// Mimics the interface of [`std::print!`]. More information about the syntax is available from
+/// [`core::fmt`] and [`alloc::format!`].
+///
+/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::prelude::*;
+/// # use kernel::device::Device;
+///
+/// fn example(dev: &Device) {
+///     dev_emerg!(dev, "hello {}\n", "there");
+/// }
+/// ```
+#[macro_export]
+macro_rules! dev_emerg {
+    ($($f:tt)*) => { $crate::dev_printk!(pr_emerg, $($f)*); }
+}
+
+/// Prints an alert-level message (level 1) prefixed with device information.
+///
+/// This level should be used if action must be taken immediately.
+///
+/// Equivalent to the kernel's `dev_alert` macro.
+///
+/// Mimics the interface of [`std::print!`]. More information about the syntax is available from
+/// [`core::fmt`] and [`alloc::format!`].
+///
+/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::prelude::*;
+/// # use kernel::device::Device;
+///
+/// fn example(dev: &Device) {
+///     dev_alert!(dev, "hello {}\n", "there");
+/// }
+/// ```
+#[macro_export]
+macro_rules! dev_alert {
+    ($($f:tt)*) => { $crate::dev_printk!(pr_alert, $($f)*); }
+}
+
+/// Prints a critical-level message (level 2) prefixed with device information.
+///
+/// This level should be used in critical conditions.
+///
+/// Equivalent to the kernel's `dev_crit` macro.
+///
+/// Mimics the interface of [`std::print!`]. More information about the syntax is available from
+/// [`core::fmt`] and [`alloc::format!`].
+///
+/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::prelude::*;
+/// # use kernel::device::Device;
+///
+/// fn example(dev: &Device) {
+///     dev_crit!(dev, "hello {}\n", "there");
+/// }
+/// ```
+#[macro_export]
+macro_rules! dev_crit {
+    ($($f:tt)*) => { $crate::dev_printk!(pr_crit, $($f)*); }
+}
+
+/// Prints an error-level message (level 3) prefixed with device information.
+///
+/// This level should be used in error conditions.
+///
+/// Equivalent to the kernel's `dev_err` macro.
+///
+/// Mimics the interface of [`std::print!`]. More information about the syntax is available from
+/// [`core::fmt`] and [`alloc::format!`].
+///
+/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::prelude::*;
+/// # use kernel::device::Device;
+///
+/// fn example(dev: &Device) {
+///     dev_err!(dev, "hello {}\n", "there");
+/// }
+/// ```
+#[macro_export]
+macro_rules! dev_err {
+    ($($f:tt)*) => { $crate::dev_printk!(pr_err, $($f)*); }
+}
+
+/// Prints a warning-level message (level 4) prefixed with device information.
+///
+/// This level should be used in warning conditions.
+///
+/// Equivalent to the kernel's `dev_warn` macro.
+///
+/// Mimics the interface of [`std::print!`]. More information about the syntax is available from
+/// [`core::fmt`] and [`alloc::format!`].
+///
+/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::prelude::*;
+/// # use kernel::device::Device;
+///
+/// fn example(dev: &Device) {
+///     dev_warn!(dev, "hello {}\n", "there");
+/// }
+/// ```
+#[macro_export]
+macro_rules! dev_warn {
+    ($($f:tt)*) => { $crate::dev_printk!(pr_warn, $($f)*); }
+}
+
+/// Prints a notice-level message (level 5) prefixed with device information.
+///
+/// This level should be used in normal but significant conditions.
+///
+/// Equivalent to the kernel's `dev_notice` macro.
+///
+/// Mimics the interface of [`std::print!`]. More information about the syntax is available from
+/// [`core::fmt`] and [`alloc::format!`].
+///
+/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::prelude::*;
+/// # use kernel::device::Device;
+///
+/// fn example(dev: &Device) {
+///     dev_notice!(dev, "hello {}\n", "there");
+/// }
+/// ```
+#[macro_export]
+macro_rules! dev_notice {
+    ($($f:tt)*) => { $crate::dev_printk!(pr_notice, $($f)*); }
+}
+
+/// Prints an info-level message (level 6) prefixed with device information.
+///
+/// This level should be used for informational messages.
+///
+/// Equivalent to the kernel's `dev_info` macro.
+///
+/// Mimics the interface of [`std::print!`]. More information about the syntax is available from
+/// [`core::fmt`] and [`alloc::format!`].
+///
+/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::prelude::*;
+/// # use kernel::device::Device;
+///
+/// fn example(dev: &Device) {
+///     dev_info!(dev, "hello {}\n", "there");
+/// }
+/// ```
+#[macro_export]
+macro_rules! dev_info {
+    ($($f:tt)*) => { $crate::dev_printk!(pr_info, $($f)*); }
+}
+
+/// Prints a debug-level message (level 7) prefixed with device information.
+///
+/// This level should be used for debug messages.
+///
+/// Equivalent to the kernel's `dev_dbg` macro, except that it doesn't support dynamic debug yet.
+///
+/// Mimics the interface of [`std::print!`]. More information about the syntax is available from
+/// [`core::fmt`] and [`alloc::format!`].
+///
+/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::prelude::*;
+/// # use kernel::device::Device;
+///
+/// fn example(dev: &Device) {
+///     dev_dbg!(dev, "hello {}\n", "there");
+/// }
+/// ```
+#[macro_export]
+macro_rules! dev_dbg {
+    ($($f:tt)*) => { $crate::dev_printk!(pr_dbg, $($f)*); }
+}
diff --git a/rust/kernel/driver.rs b/rust/kernel/driver.rs
new file mode 100644
index 000000000000..c42e09f8d4f4
--- /dev/null
+++ b/rust/kernel/driver.rs
@@ -0,0 +1,440 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Generic support for drivers of different buses (e.g., PCI, Platform, Amba, etc.).
+//!
+//! Each bus/subsystem is expected to implement [`DriverOps`], which allows drivers to register
+//! using the [`Registration`] class.
+
+use crate::{str::CStr, sync::Ref, Error, KernelModule, Result, ThisModule};
+use alloc::boxed::Box;
+use core::{cell::UnsafeCell, marker::PhantomData, ops::Deref, pin::Pin};
+
+/// A subsystem (e.g., PCI, Platform, Amba, etc.) that allows drivers to be written for it.
+pub trait DriverOps {
+    /// The type that holds information about the registration. This is typically a struct defined
+    /// by the C portion of the kernel.
+    type RegType: Default;
+
+    /// Registers a driver.
+    ///
+    /// # Safety
+    ///
+    /// `reg` must point to valid, initialised, and writable memory. It may be modified by this
+    /// function to hold registration state.
+    ///
+    /// On success, `reg` must remain pinned and valid until the matching call to
+    /// [`DriverOps::unregister`].
+    unsafe fn register(
+        reg: *mut Self::RegType,
+        name: &'static CStr,
+        module: &'static ThisModule,
+    ) -> Result;
+
+    /// Unregisters a driver previously registered with [`DriverOps::register`].
+    ///
+    /// # Safety
+    ///
+    /// `reg` must point to valid writable memory, initialised by a previous successful call to
+    /// [`DriverOps::register`].
+    unsafe fn unregister(reg: *mut Self::RegType);
+}
+
+/// The registration of a driver.
+pub struct Registration<T: DriverOps> {
+    is_registered: bool,
+    concrete_reg: UnsafeCell<T::RegType>,
+}
+
+// SAFETY: `Registration` has no fields or methods accessible via `&Registration`, so it is safe to
+// share references to it with multiple threads as nothing can be done.
+unsafe impl<T: DriverOps> Sync for Registration<T> {}
+
+impl<T: DriverOps> Registration<T> {
+    /// Creates a new instance of the registration object.
+    pub fn new() -> Self {
+        Self {
+            is_registered: false,
+            concrete_reg: UnsafeCell::new(T::RegType::default()),
+        }
+    }
+
+    /// Allocates a pinned registration object and registers it.
+    ///
+    /// Returns a pinned heap-allocated representation of the registration.
+    pub fn new_pinned(name: &'static CStr, module: &'static ThisModule) -> Result<Pin<Box<Self>>> {
+        let mut reg = Pin::from(Box::try_new(Self::new())?);
+        reg.as_mut().register(name, module)?;
+        Ok(reg)
+    }
+
+    /// Registers a driver with its subsystem.
+    ///
+    /// It must be pinned because the memory block that represents the registration is potentially
+    /// self-referential.
+    pub fn register(
+        self: Pin<&mut Self>,
+        name: &'static CStr,
+        module: &'static ThisModule,
+    ) -> Result {
+        // SAFETY: We never move out of `this`.
+        let this = unsafe { self.get_unchecked_mut() };
+        if this.is_registered {
+            // Already registered.
+            return Err(Error::EINVAL);
+        }
+
+        // SAFETY: `concrete_reg` was initialised via its default constructor. It is only freed
+        // after `Self::drop` is called, which first calls `T::unregister`.
+        unsafe { T::register(this.concrete_reg.get(), name, module) }?;
+
+        this.is_registered = true;
+        Ok(())
+    }
+}
+
+impl<T: DriverOps> Default for Registration<T> {
+    fn default() -> Self {
+        Self::new()
+    }
+}
+
+impl<T: DriverOps> Drop for Registration<T> {
+    fn drop(&mut self) {
+        if self.is_registered {
+            // SAFETY: This path only runs if a previous call to `T::register` completed
+            // successfully.
+            unsafe { T::unregister(self.concrete_reg.get()) };
+        }
+    }
+}
+
+/// Conversion from a device id to a raw device id.
+///
+/// This is meant to be implemented by buses/subsystems so that they can use [`IdTable`] to
+/// guarantee (at compile-time) zero-termination of device id tables provided by drivers.
+///
+/// # Safety
+///
+/// Implementers must ensure that:
+///   - [`RawDeviceId::ZERO`] is actually a zeroed-out version of the raw device id.
+///   - [`RawDeviceId::to_rawid`] stores `offset` in the context/data field of the raw device id so
+///     that buses can recover the pointer to the data.
+pub unsafe trait RawDeviceId {
+    /// The raw type that holds the device id.
+    ///
+    /// Id tables created from [`Self`] are going to hold this type in its zero-terminated array.
+    type RawType: Copy;
+
+    /// A zeroed-out representation of the raw device id.
+    ///
+    /// Id tables created from [`Self`] use [`Self::ZERO`] as the sentinel to indicate the end of
+    /// the table.
+    const ZERO: Self::RawType;
+
+    /// Converts an id into a raw id.
+    ///
+    /// `offset` is the offset from the memory location where the raw device id is stored to the
+    /// location where its associated context information is stored. Implementations must store
+    /// this in the appropriate context/data field of the raw type.
+    fn to_rawid(&self, offset: isize) -> Self::RawType;
+}
+
+/// A zero-terminated device id array, followed by context data.
+#[repr(C)]
+pub struct IdArray<T: RawDeviceId, U, const N: usize> {
+    ids: [T::RawType; N],
+    sentinel: T::RawType,
+    id_infos: [Option<U>; N],
+}
+
+impl<T: RawDeviceId, U, const N: usize> IdArray<T, U, N> {
+    /// Creates a new instance of the array.
+    ///
+    /// The contents are derived from the given identifiers and context information.
+    pub const fn new(ids: [T; N], infos: [Option<U>; N]) -> Self
+    where
+        T: ~const RawDeviceId + Copy,
+    {
+        let mut array = Self {
+            ids: [T::ZERO; N],
+            sentinel: T::ZERO,
+            id_infos: infos,
+        };
+        let mut i = 0usize;
+        while i < N {
+            // SAFETY: Both pointers are within `array` (or one byte beyond), consequently they are
+            // derived from the same allocated object. We are using a `u8` pointer, whose size 1,
+            // so the pointers are necessarily 1-byte aligned.
+            let offset = unsafe {
+                (&array.id_infos[i] as *const _ as *const u8)
+                    .offset_from(&array.ids[i] as *const _ as _)
+            };
+            array.ids[i] = ids[i].to_rawid(offset);
+            i += 1;
+        }
+        array
+    }
+
+    /// Returns an `IdTable` backed by `self`.
+    ///
+    /// This is used to essentially erase the array size.
+    pub const fn as_table(&self) -> IdTable<'_, T, U> {
+        IdTable {
+            first: &self.ids[0],
+            _p: PhantomData,
+        }
+    }
+}
+
+/// A device id table.
+///
+/// The table is guaranteed to be zero-terminated and to be followed by an array of context data of
+/// type `Option<U>`.
+pub struct IdTable<'a, T: RawDeviceId, U> {
+    first: &'a T::RawType,
+    _p: PhantomData<&'a U>,
+}
+
+impl<T: RawDeviceId, U> const AsRef<T::RawType> for IdTable<'_, T, U> {
+    fn as_ref(&self) -> &T::RawType {
+        self.first
+    }
+}
+
+/// Counts the number of parenthesis-delimited, comma-separated items.
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::count_paren_items;
+///
+/// assert_eq!(0, count_paren_items!());
+/// assert_eq!(1, count_paren_items!((A)));
+/// assert_eq!(1, count_paren_items!((A),));
+/// assert_eq!(2, count_paren_items!((A), (B)));
+/// assert_eq!(2, count_paren_items!((A), (B),));
+/// assert_eq!(3, count_paren_items!((A), (B), (C)));
+/// assert_eq!(3, count_paren_items!((A), (B), (C),));
+/// ```
+#[macro_export]
+macro_rules! count_paren_items {
+    (($($item:tt)*), $($remaining:tt)*) => { 1 + $crate::count_paren_items!($($remaining)*) };
+    (($($item:tt)*)) => { 1 };
+    () => { 0 };
+}
+
+/// Converts a comma-separated list of pairs into an array with the first element. That is, it
+/// discards the second element of the pair.
+///
+/// Additionally, it automatically introduces a type if the first element is warpped in curly
+/// braces, for example, if it's `{v: 10}`, it becomes `X { v: 10 }`; this is to avoid repeating
+/// the type.
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::first_item;
+///
+/// #[derive(PartialEq, Debug)]
+/// struct X {
+///     v: u32,
+/// }
+///
+/// assert_eq!([] as [X; 0], first_item!(X, ));
+/// assert_eq!([X { v: 10 }], first_item!(X, ({ v: 10 }, Y)));
+/// assert_eq!([X { v: 10 }], first_item!(X, ({ v: 10 }, Y),));
+/// assert_eq!([X { v: 10 }], first_item!(X, (X { v: 10 }, Y)));
+/// assert_eq!([X { v: 10 }], first_item!(X, (X { v: 10 }, Y),));
+/// assert_eq!([X { v: 10 }, X { v: 20 }], first_item!(X, ({ v: 10 }, Y), ({ v: 20 }, Y)));
+/// assert_eq!([X { v: 10 }, X { v: 20 }], first_item!(X, ({ v: 10 }, Y), ({ v: 20 }, Y),));
+/// assert_eq!([X { v: 10 }, X { v: 20 }], first_item!(X, (X { v: 10 }, Y), (X { v: 20 }, Y)));
+/// assert_eq!([X { v: 10 }, X { v: 20 }], first_item!(X, (X { v: 10 }, Y), (X { v: 20 }, Y),));
+/// assert_eq!([X { v: 10 }, X { v: 20 }, X { v: 30 }],
+///            first_item!(X, ({ v: 10 }, Y), ({ v: 20 }, Y), ({v: 30}, Y)));
+/// assert_eq!([X { v: 10 }, X { v: 20 }, X { v: 30 }],
+///            first_item!(X, ({ v: 10 }, Y), ({ v: 20 }, Y), ({v: 30}, Y),));
+/// assert_eq!([X { v: 10 }, X { v: 20 }, X { v: 30 }],
+///            first_item!(X, (X { v: 10 }, Y), (X { v: 20 }, Y), (X {v: 30}, Y)));
+/// assert_eq!([X { v: 10 }, X { v: 20 }, X { v: 30 }],
+///            first_item!(X, (X { v: 10 }, Y), (X { v: 20 }, Y), (X {v: 30}, Y),));
+/// ```
+#[macro_export]
+macro_rules! first_item {
+    ($id_type:ty, $(({$($first:tt)*}, $second:expr)),* $(,)?) => {
+        {
+            type IdType = $id_type;
+            [$(IdType{$($first)*},)*]
+        }
+    };
+    ($id_type:ty, $(($first:expr, $second:expr)),* $(,)?) => { [$($first,)*] };
+}
+
+/// Converts a comma-separated list of pairs into an array with the second element. That is, it
+/// discards the first element of the pair.
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::second_item;
+///
+/// assert_eq!([] as [u32; 0], second_item!());
+/// assert_eq!([10u32], second_item!((X, 10u32)));
+/// assert_eq!([10u32], second_item!((X, 10u32),));
+/// assert_eq!([10u32], second_item!(({X}, 10u32)));
+/// assert_eq!([10u32], second_item!(({X}, 10u32),));
+/// assert_eq!([10u32, 20], second_item!((X, 10u32), (X, 20)));
+/// assert_eq!([10u32, 20], second_item!((X, 10u32), (X, 20),));
+/// assert_eq!([10u32, 20], second_item!(({X}, 10u32), ({X}, 20)));
+/// assert_eq!([10u32, 20], second_item!(({X}, 10u32), ({X}, 20),));
+/// assert_eq!([10u32, 20, 30], second_item!((X, 10u32), (X, 20), (X, 30)));
+/// assert_eq!([10u32, 20, 30], second_item!((X, 10u32), (X, 20), (X, 30),));
+/// assert_eq!([10u32, 20, 30], second_item!(({X}, 10u32), ({X}, 20), ({X}, 30)));
+/// assert_eq!([10u32, 20, 30], second_item!(({X}, 10u32), ({X}, 20), ({X}, 30),));
+/// ```
+#[macro_export]
+macro_rules! second_item {
+    ($(({$($first:tt)*}, $second:expr)),* $(,)?) => { [$($second,)*] };
+    ($(($first:expr, $second:expr)),* $(,)?) => { [$($second,)*] };
+}
+
+/// Defines a new constant [`IdArray`] with a concise syntax.
+///
+/// It is meant to be used by buses and subsystems to create a similar macro with their device id
+/// type already specified, i.e., with fewer parameters to the end user.
+///
+/// # Examples
+///
+/// ```
+/// #![feature(const_trait_impl)]
+/// # use kernel::{define_id_array, driver::RawDeviceId};
+///
+/// #[derive(Copy, Clone)]
+/// struct Id(u32);
+///
+/// // SAFETY: `ZERO` is all zeroes and `to_rawid` stores `offset` as the second element of the raw
+/// // device id pair.
+/// unsafe impl const RawDeviceId for Id {
+///     type RawType = (u64, isize);
+///     const ZERO: Self::RawType = (0, 0);
+///     fn to_rawid(&self, offset: isize) -> Self::RawType {
+///         (self.0 as u64 + 1, offset)
+///     }
+/// }
+///
+/// define_id_array!(A1, Id, (), []);
+/// define_id_array!(A2, Id, &'static [u8], [(Id(10), None)]);
+/// define_id_array!(A3, Id, &'static [u8], [(Id(10), Some(b"id1")), ]);
+/// define_id_array!(A4, Id, &'static [u8], [(Id(10), Some(b"id1")), (Id(20), Some(b"id2"))]);
+/// define_id_array!(A5, Id, &'static [u8], [(Id(10), Some(b"id1")), (Id(20), Some(b"id2")), ]);
+/// define_id_array!(A6, Id, &'static [u8], [(Id(10), None), (Id(20), Some(b"id2")), ]);
+/// define_id_array!(A7, Id, &'static [u8], [(Id(10), Some(b"id1")), (Id(20), None), ]);
+/// define_id_array!(A8, Id, &'static [u8], [(Id(10), None), (Id(20), None), ]);
+/// ```
+#[macro_export]
+macro_rules! define_id_array {
+    ($table_name:ident, $id_type:ty, $data_type:ty, [ $($t:tt)* ]) => {
+        const $table_name:
+            $crate::driver::IdArray<$id_type, $data_type, { $crate::count_paren_items!($($t)*) }> =
+                $crate::driver::IdArray::new(
+                    $crate::first_item!($id_type, $($t)*), $crate::second_item!($($t)*));
+    };
+}
+
+/// Defines a new constant [`IdTable`] with a concise syntax.
+///
+/// It is meant to be used by buses and subsystems to create a similar macro with their device id
+/// type already specified, i.e., with fewer parameters to the end user.
+///
+/// # Examples
+///
+/// ```
+/// #![feature(const_trait_impl)]
+/// # use kernel::{define_id_table, driver::RawDeviceId};
+///
+/// #[derive(Copy, Clone)]
+/// struct Id(u32);
+///
+/// // SAFETY: `ZERO` is all zeroes and `to_rawid` stores `offset` as the second element of the raw
+/// // device id pair.
+/// unsafe impl const RawDeviceId for Id {
+///     type RawType = (u64, isize);
+///     const ZERO: Self::RawType = (0, 0);
+///     fn to_rawid(&self, offset: isize) -> Self::RawType {
+///         (self.0 as u64 + 1, offset)
+///     }
+/// }
+///
+/// define_id_table!(T1, Id, &'static [u8], [(Id(10), None)]);
+/// define_id_table!(T2, Id, &'static [u8], [(Id(10), Some(b"id1")), ]);
+/// define_id_table!(T3, Id, &'static [u8], [(Id(10), Some(b"id1")), (Id(20), Some(b"id2"))]);
+/// define_id_table!(T4, Id, &'static [u8], [(Id(10), Some(b"id1")), (Id(20), Some(b"id2")), ]);
+/// define_id_table!(T5, Id, &'static [u8], [(Id(10), None), (Id(20), Some(b"id2")), ]);
+/// define_id_table!(T6, Id, &'static [u8], [(Id(10), Some(b"id1")), (Id(20), None), ]);
+/// define_id_table!(T7, Id, &'static [u8], [(Id(10), None), (Id(20), None), ]);
+/// ```
+#[macro_export]
+macro_rules! define_id_table {
+    ($table_name:ident, $id_type:ty, $data_type:ty, [ $($t:tt)* ]) => {
+        const $table_name: Option<$crate::driver::IdTable<'static, $id_type, $data_type>> = {
+            $crate::define_id_array!(ARRAY, $id_type, $data_type, [ $($t)* ]);
+            Some(ARRAY.as_table())
+        };
+    };
+}
+
+/// Custom code within device removal.
+pub trait DeviceRemoval {
+    /// Cleans resources up when the device is removed.
+    ///
+    /// This is called when a device is removed and offers implementers the chance to run some code
+    /// that cleans state up.
+    fn device_remove(&self);
+}
+
+impl DeviceRemoval for () {
+    fn device_remove(&self) {}
+}
+
+impl<T: DeviceRemoval> DeviceRemoval for Ref<T> {
+    fn device_remove(&self) {
+        self.deref().device_remove();
+    }
+}
+
+impl<T: DeviceRemoval> DeviceRemoval for Box<T> {
+    fn device_remove(&self) {
+        self.deref().device_remove();
+    }
+}
+
+/// A kernel module that only registers the given driver on init.
+///
+/// This is a helper struct to make it easier to define single-functionality modules, in this case,
+/// modules that offer a single driver.
+pub struct Module<T: DriverOps> {
+    _driver: Pin<Box<Registration<T>>>,
+}
+
+impl<T: DriverOps> KernelModule for Module<T> {
+    fn init(name: &'static CStr, module: &'static ThisModule) -> Result<Self> {
+        Ok(Self {
+            _driver: Registration::new_pinned(name, module)?,
+        })
+    }
+}
+
+/// Declares a kernel module that exposes a single driver.
+///
+/// It is meant to be used as a helper by other subsystems so they can more easily expose their own
+/// macros.
+#[macro_export]
+macro_rules! module_driver {
+    (<$gen_type:ident>, $driver_ops:ty, { type: $type:ty, $($f:tt)* }) => {
+        type Ops<$gen_type> = $driver_ops;
+        type ModuleType = $crate::driver::Module<Ops<$type>>;
+        $crate::prelude::module! {
+            type: ModuleType,
+            $($f)*
+        }
+    }
+}
diff --git a/rust/kernel/error.rs b/rust/kernel/error.rs
new file mode 100644
index 000000000000..803884a00225
--- /dev/null
+++ b/rust/kernel/error.rs
@@ -0,0 +1,542 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Kernel errors.
+//!
+//! C header: [`include/uapi/asm-generic/errno-base.h`](../../../include/uapi/asm-generic/errno-base.h)
+
+use crate::str::CStr;
+use crate::{bindings, c_types};
+use alloc::{
+    alloc::{AllocError, LayoutError},
+    collections::TryReserveError,
+};
+use core::convert::From;
+use core::fmt;
+use core::num::TryFromIntError;
+use core::str::{self, Utf8Error};
+
+macro_rules! declare_err {
+    ($err:tt) => {
+        pub const $err: Self = Error(-(bindings::$err as i32));
+    };
+    ($err:tt, $($doc:expr),+) => {
+        $(
+        #[doc = $doc]
+        )*
+        pub const $err: Self = Error(-(bindings::$err as i32));
+    };
+}
+
+/// Generic integer kernel error.
+///
+/// The kernel defines a set of integer generic error codes based on C and
+/// POSIX ones. These codes may have a more specific meaning in some contexts.
+///
+/// # Invariants
+///
+/// The value is a valid `errno` (i.e. `>= -MAX_ERRNO && < 0`).
+#[derive(Clone, Copy, PartialEq, Eq)]
+pub struct Error(c_types::c_int);
+
+impl Error {
+    declare_err!(EPERM, "Operation not permitted.");
+
+    declare_err!(ENOENT, "No such file or directory.");
+
+    declare_err!(ESRCH, "No such process.");
+
+    declare_err!(EINTR, "Interrupted system call.");
+
+    declare_err!(EIO, "I/O error.");
+
+    declare_err!(ENXIO, "No such device or address.");
+
+    declare_err!(E2BIG, "Argument list too long.");
+
+    declare_err!(ENOEXEC, "Exec format error.");
+
+    declare_err!(EBADF, "Bad file number.");
+
+    declare_err!(ECHILD, "Exec format error.");
+
+    declare_err!(EAGAIN, "Try again.");
+
+    declare_err!(ENOMEM, "Out of memory.");
+
+    declare_err!(EACCES, "Permission denied.");
+
+    declare_err!(EFAULT, "Bad address.");
+
+    declare_err!(ENOTBLK, "Block device required.");
+
+    declare_err!(EBUSY, "Device or resource busy.");
+
+    declare_err!(EEXIST, "File exists.");
+
+    declare_err!(EXDEV, "Cross-device link.");
+
+    declare_err!(ENODEV, "No such device.");
+
+    declare_err!(ENOTDIR, "Not a directory.");
+
+    declare_err!(EISDIR, "Is a directory.");
+
+    declare_err!(EINVAL, "Invalid argument.");
+
+    declare_err!(ENFILE, "File table overflow.");
+
+    declare_err!(EMFILE, "Too many open files.");
+
+    declare_err!(ENOTTY, "Not a typewriter.");
+
+    declare_err!(ETXTBSY, "Text file busy.");
+
+    declare_err!(EFBIG, "File too large.");
+
+    declare_err!(ENOSPC, "No space left on device.");
+
+    declare_err!(ESPIPE, "Illegal seek.");
+
+    declare_err!(EROFS, "Read-only file system.");
+
+    declare_err!(EMLINK, "Too many links.");
+
+    declare_err!(EPIPE, "Broken pipe.");
+
+    declare_err!(EDOM, "Math argument out of domain of func.");
+
+    declare_err!(ERANGE, "Math result not representable.");
+
+    declare_err!(EDEADLK, "Resource deadlock would occur");
+
+    declare_err!(ENAMETOOLONG, "File name too long");
+
+    declare_err!(ENOLCK, "No record locks available");
+
+    declare_err!(
+        ENOSYS,
+        "Invalid system call number.",
+        "",
+        "This error code is special: arch syscall entry code will return",
+        "[`Self::ENOSYS`] if users try to call a syscall that doesn't exist.",
+        "To keep failures of syscalls that really do exist distinguishable from",
+        "failures due to attempts to use a nonexistent syscall, syscall",
+        "implementations should refrain from returning [`Self::ENOSYS`]."
+    );
+
+    declare_err!(ENOTEMPTY, "Directory not empty.");
+
+    declare_err!(ELOOP, "Too many symbolic links encountered.");
+
+    declare_err!(EWOULDBLOCK, "Operation would block.");
+
+    declare_err!(ENOMSG, "No message of desired type.");
+
+    declare_err!(EIDRM, "Identifier removed.");
+
+    declare_err!(ECHRNG, "Channel number out of range.");
+
+    declare_err!(EL2NSYNC, "Level 2 not synchronized.");
+
+    declare_err!(EL3HLT, "Level 3 halted.");
+
+    declare_err!(EL3RST, "Level 3 reset.");
+
+    declare_err!(ELNRNG, "Link number out of range.");
+
+    declare_err!(EUNATCH, "Protocol driver not attached.");
+
+    declare_err!(ENOCSI, "No CSI structure available.");
+
+    declare_err!(EL2HLT, "Level 2 halted.");
+
+    declare_err!(EBADE, "Invalid exchange.");
+
+    declare_err!(EBADR, "Invalid request descriptor.");
+
+    declare_err!(EXFULL, "Exchange full.");
+
+    declare_err!(ENOANO, "No anode.");
+
+    declare_err!(EBADRQC, "Invalid request code.");
+
+    declare_err!(EBADSLT, "Invalid slot.");
+
+    declare_err!(EDEADLOCK, "Resource deadlock would occur.");
+
+    declare_err!(EBFONT, "Bad font file format.");
+
+    declare_err!(ENOSTR, "Device not a stream.");
+
+    declare_err!(ENODATA, "No data available.");
+
+    declare_err!(ETIME, "Timer expired.");
+
+    declare_err!(ENOSR, "Out of streams resources.");
+
+    declare_err!(ENONET, "Machine is not on the network.");
+
+    declare_err!(ENOPKG, "Package not installed.");
+
+    declare_err!(EREMOTE, "Object is remote.");
+
+    declare_err!(ENOLINK, "Link has been severed.");
+
+    declare_err!(EADV, "Advertise error.");
+
+    declare_err!(ESRMNT, "Srmount error.");
+
+    declare_err!(ECOMM, "Communication error on send.");
+
+    declare_err!(EPROTO, "Protocol error.");
+
+    declare_err!(EMULTIHOP, "Multihop attempted.");
+
+    declare_err!(EDOTDOT, "RFS specific error.");
+
+    declare_err!(EBADMSG, "Not a data message.");
+
+    declare_err!(EOVERFLOW, "Value too large for defined data type.");
+
+    declare_err!(ENOTUNIQ, "Name not unique on network.");
+
+    declare_err!(EBADFD, "File descriptor in bad state.");
+
+    declare_err!(EREMCHG, "Remote address changed.");
+
+    declare_err!(ELIBACC, "Can not access a needed shared library.");
+
+    declare_err!(ELIBBAD, "Accessing a corrupted shared library.");
+
+    declare_err!(ELIBSCN, ".lib section in a.out corrupted.");
+
+    declare_err!(ELIBMAX, "Attempting to link in too many shared libraries.");
+
+    declare_err!(ELIBEXEC, "Cannot exec a shared library directly.");
+
+    declare_err!(EILSEQ, "Illegal byte sequence.");
+
+    declare_err!(ERESTART, "Interrupted system call should be restarted.");
+
+    declare_err!(ESTRPIPE, "Streams pipe error.");
+
+    declare_err!(EUSERS, "Too many users.");
+
+    declare_err!(ENOTSOCK, "Socket operation on non-socket.");
+
+    declare_err!(EDESTADDRREQ, "Destination address required.");
+
+    declare_err!(EMSGSIZE, "Message too long.");
+
+    declare_err!(EPROTOTYPE, "Protocol wrong type for socket.");
+
+    declare_err!(ENOPROTOOPT, "Protocol not available.");
+
+    declare_err!(EPROTONOSUPPORT, "Protocol not supported.");
+
+    declare_err!(ESOCKTNOSUPPORT, "Socket type not supported.");
+
+    declare_err!(EOPNOTSUPP, "Operation not supported on transport endpoint.");
+
+    declare_err!(EPFNOSUPPORT, "Protocol family not supported.");
+
+    declare_err!(EAFNOSUPPORT, "Address family not supported by protocol.");
+
+    declare_err!(EADDRINUSE, "Address already in use.");
+
+    declare_err!(EADDRNOTAVAIL, "Cannot assign requested address.");
+
+    declare_err!(ENETDOWN, "Network is down.");
+
+    declare_err!(ENETUNREACH, "Network is unreachable.");
+
+    declare_err!(ENETRESET, "Network dropped connection because of reset.");
+
+    declare_err!(ECONNABORTED, "Software caused connection abort.");
+
+    declare_err!(ECONNRESET, "Connection reset by peer.");
+
+    declare_err!(ENOBUFS, "No buffer space available.");
+
+    declare_err!(EISCONN, "Transport endpoint is already connected.");
+
+    declare_err!(ENOTCONN, "Transport endpoint is not connected.");
+
+    declare_err!(ESHUTDOWN, "Cannot send after transport endpoint shutdown.");
+
+    declare_err!(ETOOMANYREFS, "Too many references: cannot splice.");
+
+    declare_err!(ETIMEDOUT, "Connection timed out.");
+
+    declare_err!(ECONNREFUSED, "Connection refused.");
+
+    declare_err!(EHOSTDOWN, "Host is down.");
+
+    declare_err!(EHOSTUNREACH, "No route to host.");
+
+    declare_err!(EALREADY, "Operation already in progress.");
+
+    declare_err!(EINPROGRESS, "Operation now in progress.");
+
+    declare_err!(ESTALE, "Stale file handle.");
+
+    declare_err!(EUCLEAN, "Structure needs cleaning.");
+
+    declare_err!(ENOTNAM, "Not a XENIX named type file.");
+
+    declare_err!(ENAVAIL, "No XENIX semaphores available.");
+
+    declare_err!(EISNAM, "Is a named type file.");
+
+    declare_err!(EREMOTEIO, "Remote I/O error.");
+
+    declare_err!(EDQUOT, "Quota exceeded.");
+
+    declare_err!(ENOMEDIUM, "No medium found.");
+
+    declare_err!(EMEDIUMTYPE, "Wrong medium type.");
+
+    declare_err!(ECANCELED, "Operation Canceled.");
+
+    declare_err!(ENOKEY, "Required key not available.");
+
+    declare_err!(EKEYEXPIRED, "Key has expired.");
+
+    declare_err!(EKEYREVOKED, "Key has been revoked.");
+
+    declare_err!(EKEYREJECTED, "Key was rejected by service.");
+
+    declare_err!(EOWNERDEAD, "Owner died.", "", "For robust mutexes.");
+
+    declare_err!(ENOTRECOVERABLE, "State not recoverable.");
+
+    declare_err!(ERFKILL, "Operation not possible due to RF-kill.");
+
+    declare_err!(EHWPOISON, "Memory page has hardware error.");
+
+    declare_err!(ERESTARTSYS, "Restart the system call.");
+
+    declare_err!(ENOTSUPP, "Operation is not supported.");
+
+    /// Creates an [`Error`] from a kernel error code.
+    ///
+    /// It is a bug to pass an out-of-range `errno`. `EINVAL` would
+    /// be returned in such a case.
+    pub(crate) fn from_kernel_errno(errno: c_types::c_int) -> Error {
+        if errno < -(bindings::MAX_ERRNO as i32) || errno >= 0 {
+            // TODO: Make it a `WARN_ONCE` once available.
+            crate::pr_warn!(
+                "attempted to create `Error` with out of range `errno`: {}",
+                errno
+            );
+            return Error::EINVAL;
+        }
+
+        // INVARIANT: The check above ensures the type invariant
+        // will hold.
+        Error(errno)
+    }
+
+    /// Creates an [`Error`] from a kernel error code.
+    ///
+    /// # Safety
+    ///
+    /// `errno` must be within error code range (i.e. `>= -MAX_ERRNO && < 0`).
+    pub(crate) unsafe fn from_kernel_errno_unchecked(errno: c_types::c_int) -> Error {
+        // INVARIANT: The contract ensures the type invariant
+        // will hold.
+        Error(errno)
+    }
+
+    /// Returns the kernel error code.
+    pub fn to_kernel_errno(self) -> c_types::c_int {
+        self.0
+    }
+}
+
+impl fmt::Debug for Error {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        // SAFETY: FFI call.
+        let name = unsafe { bindings::errname(-self.0) };
+
+        if name.is_null() {
+            // Print out number if no name can be found.
+            return f.debug_tuple("Error").field(&-self.0).finish();
+        }
+
+        // SAFETY: `'static` string from C, and is not NULL.
+        let cstr = unsafe { CStr::from_char_ptr(name) };
+        // SAFETY: These strings are ASCII-only.
+        let str = unsafe { str::from_utf8_unchecked(cstr) };
+        f.debug_tuple(str).finish()
+    }
+}
+
+impl From<TryFromIntError> for Error {
+    fn from(_: TryFromIntError) -> Error {
+        Error::EINVAL
+    }
+}
+
+impl From<Utf8Error> for Error {
+    fn from(_: Utf8Error) -> Error {
+        Error::EINVAL
+    }
+}
+
+impl From<TryReserveError> for Error {
+    fn from(_: TryReserveError) -> Error {
+        Error::ENOMEM
+    }
+}
+
+impl From<LayoutError> for Error {
+    fn from(_: LayoutError) -> Error {
+        Error::ENOMEM
+    }
+}
+
+impl From<core::fmt::Error> for Error {
+    fn from(_: core::fmt::Error) -> Error {
+        Error::EINVAL
+    }
+}
+
+/// A [`Result`] with an [`Error`] error type.
+///
+/// To be used as the return type for functions that may fail.
+///
+/// # Error codes in C and Rust
+///
+/// In C, it is common that functions indicate success or failure through
+/// their return value; modifying or returning extra data through non-`const`
+/// pointer parameters. In particular, in the kernel, functions that may fail
+/// typically return an `int` that represents a generic error code. We model
+/// those as [`Error`].
+///
+/// In Rust, it is idiomatic to model functions that may fail as returning
+/// a [`Result`]. Since in the kernel many functions return an error code,
+/// [`Result`] is a type alias for a [`core::result::Result`] that uses
+/// [`Error`] as its error type.
+///
+/// Note that even if a function does not return anything when it succeeds,
+/// it should still be modeled as returning a `Result` rather than
+/// just an [`Error`].
+pub type Result<T = ()> = core::result::Result<T, Error>;
+
+impl From<AllocError> for Error {
+    fn from(_: AllocError) -> Error {
+        Error::ENOMEM
+    }
+}
+
+// # Invariant: `-bindings::MAX_ERRNO` fits in an `i16`.
+crate::static_assert!(bindings::MAX_ERRNO <= -(i16::MIN as i32) as u32);
+
+pub(crate) fn from_kernel_result_helper<T>(r: Result<T>) -> T
+where
+    T: From<i16>,
+{
+    match r {
+        Ok(v) => v,
+        // NO-OVERFLOW: negative `errno`s are no smaller than `-bindings::MAX_ERRNO`,
+        // `-bindings::MAX_ERRNO` fits in an `i16` as per invariant above,
+        // therefore a negative `errno` always fits in an `i16` and will not overflow.
+        Err(e) => T::from(e.to_kernel_errno() as i16),
+    }
+}
+
+/// Transforms a [`crate::error::Result<T>`] to a kernel C integer result.
+///
+/// This is useful when calling Rust functions that return [`crate::error::Result<T>`]
+/// from inside `extern "C"` functions that need to return an integer
+/// error result.
+///
+/// `T` should be convertible to an `i16` via `From<i16>`.
+///
+/// # Examples
+///
+/// ```ignore
+/// # use kernel::from_kernel_result;
+/// # use kernel::c_types;
+/// # use kernel::bindings;
+/// unsafe extern "C" fn probe_callback(
+///     pdev: *mut bindings::platform_device,
+/// ) -> c_types::c_int {
+///     from_kernel_result! {
+///         let ptr = devm_alloc(pdev)?;
+///         bindings::platform_set_drvdata(pdev, ptr);
+///         Ok(0)
+///     }
+/// }
+/// ```
+macro_rules! from_kernel_result {
+    ($($tt:tt)*) => {{
+        $crate::error::from_kernel_result_helper((|| {
+            $($tt)*
+        })())
+    }};
+}
+
+pub(crate) use from_kernel_result;
+
+/// Transform a kernel "error pointer" to a normal pointer.
+///
+/// Some kernel C API functions return an "error pointer" which optionally
+/// embeds an `errno`. Callers are supposed to check the returned pointer
+/// for errors. This function performs the check and converts the "error pointer"
+/// to a normal pointer in an idiomatic fashion.
+///
+/// # Examples
+///
+/// ```ignore
+/// # use kernel::prelude::*;
+/// # use kernel::from_kernel_err_ptr;
+/// # use kernel::c_types;
+/// # use kernel::bindings;
+/// fn devm_platform_ioremap_resource(
+///     pdev: &mut PlatformDevice,
+///     index: u32,
+/// ) -> Result<*mut c_types::c_void> {
+///     // SAFETY: FFI call.
+///     unsafe {
+///         from_kernel_err_ptr(bindings::devm_platform_ioremap_resource(
+///             pdev.to_ptr(),
+///             index,
+///         ))
+///     }
+/// }
+/// ```
+// TODO: Remove `dead_code` marker once an in-kernel client is available.
+#[allow(dead_code)]
+pub(crate) fn from_kernel_err_ptr<T>(ptr: *mut T) -> Result<*mut T> {
+    // CAST: Casting a pointer to `*const c_types::c_void` is always valid.
+    let const_ptr: *const c_types::c_void = ptr.cast();
+    // SAFETY: The FFI function does not deref the pointer.
+    if unsafe { bindings::IS_ERR(const_ptr) } {
+        // SAFETY: The FFI function does not deref the pointer.
+        let err = unsafe { bindings::PTR_ERR(const_ptr) };
+        // CAST: If `IS_ERR()` returns `true`,
+        // then `PTR_ERR()` is guaranteed to return a
+        // negative value greater-or-equal to `-bindings::MAX_ERRNO`,
+        // which always fits in an `i16`, as per the invariant above.
+        // And an `i16` always fits in an `i32`. So casting `err` to
+        // an `i32` can never overflow, and is always valid.
+        //
+        // SAFETY: `IS_ERR()` ensures `err` is a
+        // negative value greater-or-equal to `-bindings::MAX_ERRNO`.
+        return Err(unsafe { Error::from_kernel_errno_unchecked(err as i32) });
+    }
+    Ok(ptr)
+}
+
+/// Calls a kernel function that returns an integer error code on failure and converts the result
+/// to a [`Result`].
+pub fn to_result(func: impl FnOnce() -> c_types::c_int) -> Result {
+    let err = func();
+    if err < 0 {
+        Err(Error::from_kernel_errno(err))
+    } else {
+        Ok(())
+    }
+}
diff --git a/rust/kernel/file.rs b/rust/kernel/file.rs
new file mode 100644
index 000000000000..648628837d82
--- /dev/null
+++ b/rust/kernel/file.rs
@@ -0,0 +1,147 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Files and file descriptors.
+//!
+//! C headers: [`include/linux/fs.h`](../../../../include/linux/fs.h) and
+//! [`include/linux/file.h`](../../../../include/linux/file.h)
+
+use crate::{bindings, cred::CredentialRef, error::Error, Result};
+use core::{mem::ManuallyDrop, ops::Deref};
+
+/// Wraps the kernel's `struct file`.
+///
+/// # Invariants
+///
+/// The pointer `File::ptr` is non-null and valid. Its reference count is also non-zero.
+pub struct File {
+    pub(crate) ptr: *mut bindings::file,
+}
+
+impl File {
+    /// Constructs a new [`struct file`] wrapper from a file descriptor.
+    ///
+    /// The file descriptor belongs to the current process.
+    pub fn from_fd(fd: u32) -> Result<Self> {
+        // SAFETY: FFI call, there are no requirements on `fd`.
+        let ptr = unsafe { bindings::fget(fd) };
+        if ptr.is_null() {
+            return Err(Error::EBADF);
+        }
+
+        // INVARIANTS: We checked that `ptr` is non-null, so it is valid. `fget` increments the ref
+        // count before returning.
+        Ok(Self { ptr })
+    }
+
+    /// Returns the current seek/cursor/pointer position (`struct file::f_pos`).
+    pub fn pos(&self) -> u64 {
+        // SAFETY: `File::ptr` is guaranteed to be valid by the type invariants.
+        unsafe { (*self.ptr).f_pos as u64 }
+    }
+
+    /// Returns whether the file is in blocking mode.
+    pub fn is_blocking(&self) -> bool {
+        // SAFETY: `File::ptr` is guaranteed to be valid by the type invariants.
+        unsafe { (*self.ptr).f_flags & bindings::O_NONBLOCK == 0 }
+    }
+
+    /// Returns the credentials of the task that originally opened the file.
+    pub fn cred(&self) -> CredentialRef<'_> {
+        // SAFETY: `File::ptr` is guaranteed to be valid by the type invariants.
+        let ptr = unsafe { (*self.ptr).f_cred };
+        // SAFETY: The lifetimes of `self` and `CredentialRef` are tied, so it is guaranteed that
+        // the credential pointer remains valid (because the file is still alive, and it doesn't
+        // change over the lifetime of a file).
+        unsafe { CredentialRef::from_ptr(ptr) }
+    }
+
+    /// Returns the flags associated with the file.
+    pub fn flags(&self) -> u32 {
+        // SAFETY: `File::ptr` is guaranteed to be valid by the type invariants.
+        unsafe { (*self.ptr).f_flags }
+    }
+}
+
+impl Drop for File {
+    fn drop(&mut self) {
+        // SAFETY: The type invariants guarantee that `File::ptr` has a non-zero reference count.
+        unsafe { bindings::fput(self.ptr) };
+    }
+}
+
+/// A wrapper for [`File`] that doesn't automatically decrement the refcount when dropped.
+///
+/// We need the wrapper because [`ManuallyDrop`] alone would allow callers to call
+/// [`ManuallyDrop::into_inner`]. This would allow an unsafe sequence to be triggered without
+/// `unsafe` blocks because it would trigger an unbalanced call to `fput`.
+///
+/// # Invariants
+///
+/// The wrapped [`File`] remains valid for the lifetime of the object.
+pub(crate) struct FileRef(ManuallyDrop<File>);
+
+impl FileRef {
+    /// Constructs a new [`struct file`] wrapper that doesn't change its reference count.
+    ///
+    /// # Safety
+    ///
+    /// The pointer `ptr` must be non-null and valid for the lifetime of the object.
+    pub(crate) unsafe fn from_ptr(ptr: *mut bindings::file) -> Self {
+        Self(ManuallyDrop::new(File { ptr }))
+    }
+}
+
+impl Deref for FileRef {
+    type Target = File;
+
+    fn deref(&self) -> &Self::Target {
+        self.0.deref()
+    }
+}
+
+/// A file descriptor reservation.
+///
+/// This allows the creation of a file descriptor in two steps: first, we reserve a slot for it,
+/// then we commit or drop the reservation. The first step may fail (e.g., the current process ran
+/// out of available slots), but commit and drop never fail (and are mutually exclusive).
+pub struct FileDescriptorReservation {
+    fd: u32,
+}
+
+impl FileDescriptorReservation {
+    /// Creates a new file descriptor reservation.
+    pub fn new(flags: u32) -> Result<Self> {
+        // SAFETY: FFI call, there are no safety requirements on `flags`.
+        let fd = unsafe { bindings::get_unused_fd_flags(flags) };
+        if fd < 0 {
+            return Err(Error::from_kernel_errno(fd));
+        }
+        Ok(Self { fd: fd as _ })
+    }
+
+    /// Returns the file descriptor number that was reserved.
+    pub fn reserved_fd(&self) -> u32 {
+        self.fd
+    }
+
+    /// Commits the reservation.
+    ///
+    /// The previously reserved file descriptor is bound to `file`.
+    pub fn commit(self, file: File) {
+        // SAFETY: `self.fd` was previously returned by `get_unused_fd_flags`, and `file.ptr` is
+        // guaranteed to have an owned ref count by its type invariants.
+        unsafe { bindings::fd_install(self.fd, file.ptr) };
+
+        // `fd_install` consumes both the file descriptor and the file reference, so we cannot run
+        // the destructors.
+        core::mem::forget(self);
+        core::mem::forget(file);
+    }
+}
+
+impl Drop for FileDescriptorReservation {
+    fn drop(&mut self) {
+        // SAFETY: `self.fd` was returned by a previous call to `get_unused_fd_flags`.
+        unsafe { bindings::put_unused_fd(self.fd) };
+    }
+}
diff --git a/rust/kernel/file_operations.rs b/rust/kernel/file_operations.rs
new file mode 100644
index 000000000000..da252fb6eadf
--- /dev/null
+++ b/rust/kernel/file_operations.rs
@@ -0,0 +1,734 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! File operations.
+//!
+//! C header: [`include/linux/fs.h`](../../../../include/linux/fs.h)
+
+use crate::{
+    bindings, c_types,
+    error::{from_kernel_result, Error, Result},
+    file::{File, FileRef},
+    io_buffer::{IoBufferReader, IoBufferWriter},
+    iov_iter::IovIter,
+    mm,
+    sync::CondVar,
+    types::PointerWrapper,
+    user_ptr::{UserSlicePtr, UserSlicePtrReader, UserSlicePtrWriter},
+};
+use core::convert::{TryFrom, TryInto};
+use core::{marker, mem, ptr};
+
+/// Wraps the kernel's `struct poll_table_struct`.
+///
+/// # Invariants
+///
+/// The pointer `PollTable::ptr` is null or valid.
+pub struct PollTable {
+    ptr: *mut bindings::poll_table_struct,
+}
+
+impl PollTable {
+    /// Constructors a new `struct poll_table_struct` wrapper.
+    ///
+    /// # Safety
+    ///
+    /// The pointer `ptr` must be either null or a valid pointer for the lifetime of the object.
+    unsafe fn from_ptr(ptr: *mut bindings::poll_table_struct) -> Self {
+        Self { ptr }
+    }
+
+    /// Associates the given file and condition variable to this poll table. It means notifying the
+    /// condition variable will notify the poll table as well; additionally, the association
+    /// between the condition variable and the file will automatically be undone by the kernel when
+    /// the file is destructed. To unilaterally remove the association before then, one can call
+    /// [`CondVar::free_waiters`].
+    ///
+    /// # Safety
+    ///
+    /// If the condition variable is destroyed before the file, then [`CondVar::free_waiters`] must
+    /// be called to ensure that all waiters are flushed out.
+    pub unsafe fn register_wait<'a>(&self, file: &'a File, cv: &'a CondVar) {
+        if self.ptr.is_null() {
+            return;
+        }
+
+        // SAFETY: `PollTable::ptr` is guaranteed to be valid by the type invariants and the null
+        // check above.
+        let table = unsafe { &*self.ptr };
+        if let Some(proc) = table._qproc {
+            // SAFETY: All pointers are known to be valid.
+            unsafe { proc(file.ptr as _, cv.wait_list.get(), self.ptr) }
+        }
+    }
+}
+
+/// Equivalent to [`std::io::SeekFrom`].
+///
+/// [`std::io::SeekFrom`]: https://doc.rust-lang.org/std/io/enum.SeekFrom.html
+pub enum SeekFrom {
+    /// Equivalent to C's `SEEK_SET`.
+    Start(u64),
+
+    /// Equivalent to C's `SEEK_END`.
+    End(i64),
+
+    /// Equivalent to C's `SEEK_CUR`.
+    Current(i64),
+}
+
+pub(crate) struct FileOperationsVtable<A, T>(marker::PhantomData<A>, marker::PhantomData<T>);
+
+impl<A: FileOpenAdapter<T::OpenData>, T: FileOperations> FileOperationsVtable<A, T> {
+    /// Called by the VFS when an inode should be opened.
+    ///
+    /// Calls `T::open` on the returned value of `A::convert`.
+    ///
+    /// # Safety
+    ///
+    /// The returned value of `A::convert` must be a valid non-null pointer and
+    /// `T:open` must return a valid non-null pointer on an `Ok` result.
+    unsafe extern "C" fn open_callback(
+        inode: *mut bindings::inode,
+        file: *mut bindings::file,
+    ) -> c_types::c_int {
+        from_kernel_result! {
+            // SAFETY: `A::convert` must return a valid non-null pointer that
+            // should point to data in the inode or file that lives longer
+            // than the following use of `T::open`.
+            let arg = unsafe { A::convert(inode, file) };
+            // SAFETY: The C contract guarantees that `file` is valid. Additionally,
+            // `fileref` never outlives this function, so it is guaranteed to be
+            // valid.
+            let fileref = unsafe { FileRef::from_ptr(file) };
+            // SAFETY: `arg` was previously returned by `A::convert` and must
+            // be a valid non-null pointer.
+            let ptr = T::open(unsafe { &*arg }, &fileref)?.into_pointer();
+            // SAFETY: The C contract guarantees that `private_data` is available
+            // for implementers of the file operations (no other C code accesses
+            // it), so we know that there are no concurrent threads/CPUs accessing
+            // it (it's not visible to any other Rust code).
+            unsafe { (*file).private_data = ptr as *mut c_types::c_void };
+            Ok(0)
+        }
+    }
+
+    unsafe extern "C" fn read_callback(
+        file: *mut bindings::file,
+        buf: *mut c_types::c_char,
+        len: c_types::c_size_t,
+        offset: *mut bindings::loff_t,
+    ) -> c_types::c_ssize_t {
+        from_kernel_result! {
+            let mut data = unsafe { UserSlicePtr::new(buf as *mut c_types::c_void, len).writer() };
+            // SAFETY: `private_data` was initialised by `open_callback` with a value returned by
+            // `T::Wrapper::into_pointer`. `T::Wrapper::from_pointer` is only called by the
+            // `release` callback, which the C API guarantees that will be called only when all
+            // references to `file` have been released, so we know it can't be called while this
+            // function is running.
+            let f = unsafe { T::Wrapper::borrow((*file).private_data) };
+            // No `FMODE_UNSIGNED_OFFSET` support, so `offset` must be in [0, 2^63).
+            // See discussion in https://github.com/fishinabarrel/linux-kernel-module-rust/pull/113
+            let read = T::read(
+                f,
+                unsafe { &FileRef::from_ptr(file) },
+                &mut data,
+                unsafe { *offset }.try_into()?,
+            )?;
+            unsafe { (*offset) += bindings::loff_t::try_from(read).unwrap() };
+            Ok(read as _)
+        }
+    }
+
+    unsafe extern "C" fn read_iter_callback(
+        iocb: *mut bindings::kiocb,
+        raw_iter: *mut bindings::iov_iter,
+    ) -> isize {
+        from_kernel_result! {
+            let mut iter = unsafe { IovIter::from_ptr(raw_iter) };
+            let file = unsafe { (*iocb).ki_filp };
+            let offset = unsafe { (*iocb).ki_pos };
+            // SAFETY: `private_data` was initialised by `open_callback` with a value returned by
+            // `T::Wrapper::into_pointer`. `T::Wrapper::from_pointer` is only called by the
+            // `release` callback, which the C API guarantees that will be called only when all
+            // references to `file` have been released, so we know it can't be called while this
+            // function is running.
+            let f = unsafe { T::Wrapper::borrow((*file).private_data) };
+            let read =
+                T::read(f, unsafe { &FileRef::from_ptr(file) }, &mut iter, offset.try_into()?)?;
+            unsafe { (*iocb).ki_pos += bindings::loff_t::try_from(read).unwrap() };
+            Ok(read as _)
+        }
+    }
+
+    unsafe extern "C" fn write_callback(
+        file: *mut bindings::file,
+        buf: *const c_types::c_char,
+        len: c_types::c_size_t,
+        offset: *mut bindings::loff_t,
+    ) -> c_types::c_ssize_t {
+        from_kernel_result! {
+            let mut data = unsafe { UserSlicePtr::new(buf as *mut c_types::c_void, len).reader() };
+            // SAFETY: `private_data` was initialised by `open_callback` with a value returned by
+            // `T::Wrapper::into_pointer`. `T::Wrapper::from_pointer` is only called by the
+            // `release` callback, which the C API guarantees that will be called only when all
+            // references to `file` have been released, so we know it can't be called while this
+            // function is running.
+            let f = unsafe { T::Wrapper::borrow((*file).private_data) };
+            // No `FMODE_UNSIGNED_OFFSET` support, so `offset` must be in [0, 2^63).
+            // See discussion in https://github.com/fishinabarrel/linux-kernel-module-rust/pull/113
+            let written = T::write(
+                f,
+                unsafe { &FileRef::from_ptr(file) },
+                &mut data,
+                unsafe { *offset }.try_into()?
+            )?;
+            unsafe { (*offset) += bindings::loff_t::try_from(written).unwrap() };
+            Ok(written as _)
+        }
+    }
+
+    unsafe extern "C" fn write_iter_callback(
+        iocb: *mut bindings::kiocb,
+        raw_iter: *mut bindings::iov_iter,
+    ) -> isize {
+        from_kernel_result! {
+            let mut iter = unsafe { IovIter::from_ptr(raw_iter) };
+            let file = unsafe { (*iocb).ki_filp };
+            let offset = unsafe { (*iocb).ki_pos };
+            // SAFETY: `private_data` was initialised by `open_callback` with a value returned by
+            // `T::Wrapper::into_pointer`. `T::Wrapper::from_pointer` is only called by the
+            // `release` callback, which the C API guarantees that will be called only when all
+            // references to `file` have been released, so we know it can't be called while this
+            // function is running.
+            let f = unsafe { T::Wrapper::borrow((*file).private_data) };
+            let written =
+                T::write(f, unsafe { &FileRef::from_ptr(file) }, &mut iter, offset.try_into()?)?;
+            unsafe { (*iocb).ki_pos += bindings::loff_t::try_from(written).unwrap() };
+            Ok(written as _)
+        }
+    }
+
+    unsafe extern "C" fn release_callback(
+        _inode: *mut bindings::inode,
+        file: *mut bindings::file,
+    ) -> c_types::c_int {
+        let ptr = mem::replace(unsafe { &mut (*file).private_data }, ptr::null_mut());
+        T::release(unsafe { T::Wrapper::from_pointer(ptr as _) }, unsafe {
+            &FileRef::from_ptr(file)
+        });
+        0
+    }
+
+    unsafe extern "C" fn llseek_callback(
+        file: *mut bindings::file,
+        offset: bindings::loff_t,
+        whence: c_types::c_int,
+    ) -> bindings::loff_t {
+        from_kernel_result! {
+            let off = match whence as u32 {
+                bindings::SEEK_SET => SeekFrom::Start(offset.try_into()?),
+                bindings::SEEK_CUR => SeekFrom::Current(offset),
+                bindings::SEEK_END => SeekFrom::End(offset),
+                _ => return Err(Error::EINVAL),
+            };
+            // SAFETY: `private_data` was initialised by `open_callback` with a value returned by
+            // `T::Wrapper::into_pointer`. `T::Wrapper::from_pointer` is only called by the
+            // `release` callback, which the C API guarantees that will be called only when all
+            // references to `file` have been released, so we know it can't be called while this
+            // function is running.
+            let f = unsafe { T::Wrapper::borrow((*file).private_data) };
+            let off = T::seek(f, unsafe { &FileRef::from_ptr(file) }, off)?;
+            Ok(off as bindings::loff_t)
+        }
+    }
+
+    unsafe extern "C" fn unlocked_ioctl_callback(
+        file: *mut bindings::file,
+        cmd: c_types::c_uint,
+        arg: c_types::c_ulong,
+    ) -> c_types::c_long {
+        from_kernel_result! {
+            // SAFETY: `private_data` was initialised by `open_callback` with a value returned by
+            // `T::Wrapper::into_pointer`. `T::Wrapper::from_pointer` is only called by the
+            // `release` callback, which the C API guarantees that will be called only when all
+            // references to `file` have been released, so we know it can't be called while this
+            // function is running.
+            let f = unsafe { T::Wrapper::borrow((*file).private_data) };
+            let mut cmd = IoctlCommand::new(cmd as _, arg as _);
+            let ret = T::ioctl(f, unsafe { &FileRef::from_ptr(file) }, &mut cmd)?;
+            Ok(ret as _)
+        }
+    }
+
+    unsafe extern "C" fn compat_ioctl_callback(
+        file: *mut bindings::file,
+        cmd: c_types::c_uint,
+        arg: c_types::c_ulong,
+    ) -> c_types::c_long {
+        from_kernel_result! {
+            // SAFETY: `private_data` was initialised by `open_callback` with a value returned by
+            // `T::Wrapper::into_pointer`. `T::Wrapper::from_pointer` is only called by the
+            // `release` callback, which the C API guarantees that will be called only when all
+            // references to `file` have been released, so we know it can't be called while this
+            // function is running.
+            let f = unsafe { T::Wrapper::borrow((*file).private_data) };
+            let mut cmd = IoctlCommand::new(cmd as _, arg as _);
+            let ret = T::compat_ioctl(f, unsafe { &FileRef::from_ptr(file) }, &mut cmd)?;
+            Ok(ret as _)
+        }
+    }
+
+    unsafe extern "C" fn mmap_callback(
+        file: *mut bindings::file,
+        vma: *mut bindings::vm_area_struct,
+    ) -> c_types::c_int {
+        from_kernel_result! {
+            // SAFETY: `private_data` was initialised by `open_callback` with a value returned by
+            // `T::Wrapper::into_pointer`. `T::Wrapper::from_pointer` is only called by the
+            // `release` callback, which the C API guarantees that will be called only when all
+            // references to `file` have been released, so we know it can't be called while this
+            // function is running.
+            let f = unsafe { T::Wrapper::borrow((*file).private_data) };
+
+            // SAFETY: The C API guarantees that `vma` is valid for the duration of this call.
+            // `area` only lives within this call, so it is guaranteed to be valid.
+            let mut area = unsafe { mm::virt::Area::from_ptr(vma) };
+
+            // SAFETY: The C API guarantees that `file` is valid for the duration of this call,
+            // which is longer than the lifetime of the file reference.
+            T::mmap(f, unsafe { &FileRef::from_ptr(file) }, &mut area)?;
+            Ok(0)
+        }
+    }
+
+    unsafe extern "C" fn fsync_callback(
+        file: *mut bindings::file,
+        start: bindings::loff_t,
+        end: bindings::loff_t,
+        datasync: c_types::c_int,
+    ) -> c_types::c_int {
+        from_kernel_result! {
+            let start = start.try_into()?;
+            let end = end.try_into()?;
+            let datasync = datasync != 0;
+            // SAFETY: `private_data` was initialised by `open_callback` with a value returned by
+            // `T::Wrapper::into_pointer`. `T::Wrapper::from_pointer` is only called by the
+            // `release` callback, which the C API guarantees that will be called only when all
+            // references to `file` have been released, so we know it can't be called while this
+            // function is running.
+            let f = unsafe { T::Wrapper::borrow((*file).private_data) };
+            let res = T::fsync(f, unsafe { &FileRef::from_ptr(file) }, start, end, datasync)?;
+            Ok(res.try_into().unwrap())
+        }
+    }
+
+    unsafe extern "C" fn poll_callback(
+        file: *mut bindings::file,
+        wait: *mut bindings::poll_table_struct,
+    ) -> bindings::__poll_t {
+        // SAFETY: `private_data` was initialised by `open_callback` with a value returned by
+        // `T::Wrapper::into_pointer`. `T::Wrapper::from_pointer` is only called by the `release`
+        // callback, which the C API guarantees that will be called only when all references to
+        // `file` have been released, so we know it can't be called while this function is running.
+        let f = unsafe { T::Wrapper::borrow((*file).private_data) };
+        match T::poll(f, unsafe { &FileRef::from_ptr(file) }, unsafe {
+            &PollTable::from_ptr(wait)
+        }) {
+            Ok(v) => v,
+            Err(_) => bindings::POLLERR,
+        }
+    }
+
+    const VTABLE: bindings::file_operations = bindings::file_operations {
+        open: Some(Self::open_callback),
+        release: Some(Self::release_callback),
+        read: if T::TO_USE.read {
+            Some(Self::read_callback)
+        } else {
+            None
+        },
+        write: if T::TO_USE.write {
+            Some(Self::write_callback)
+        } else {
+            None
+        },
+        llseek: if T::TO_USE.seek {
+            Some(Self::llseek_callback)
+        } else {
+            None
+        },
+
+        check_flags: None,
+        compat_ioctl: if T::TO_USE.compat_ioctl {
+            Some(Self::compat_ioctl_callback)
+        } else {
+            None
+        },
+        copy_file_range: None,
+        fallocate: None,
+        fadvise: None,
+        fasync: None,
+        flock: None,
+        flush: None,
+        fsync: if T::TO_USE.fsync {
+            Some(Self::fsync_callback)
+        } else {
+            None
+        },
+        get_unmapped_area: None,
+        iterate: None,
+        iterate_shared: None,
+        iopoll: None,
+        lock: None,
+        mmap: if T::TO_USE.mmap {
+            Some(Self::mmap_callback)
+        } else {
+            None
+        },
+        mmap_supported_flags: 0,
+        owner: ptr::null_mut(),
+        poll: if T::TO_USE.poll {
+            Some(Self::poll_callback)
+        } else {
+            None
+        },
+        read_iter: if T::TO_USE.read_iter {
+            Some(Self::read_iter_callback)
+        } else {
+            None
+        },
+        remap_file_range: None,
+        sendpage: None,
+        setlease: None,
+        show_fdinfo: None,
+        splice_read: None,
+        splice_write: None,
+        unlocked_ioctl: if T::TO_USE.ioctl {
+            Some(Self::unlocked_ioctl_callback)
+        } else {
+            None
+        },
+        write_iter: if T::TO_USE.write_iter {
+            Some(Self::write_iter_callback)
+        } else {
+            None
+        },
+    };
+
+    /// Builds an instance of [`struct file_operations`].
+    ///
+    /// # Safety
+    ///
+    /// The caller must ensure that the adapter is compatible with the way the device is registered.
+    pub(crate) const unsafe fn build() -> &'static bindings::file_operations {
+        &Self::VTABLE
+    }
+}
+
+/// Represents which fields of [`struct file_operations`] should be populated with pointers.
+pub struct ToUse {
+    /// The `read` field of [`struct file_operations`].
+    pub read: bool,
+
+    /// The `read_iter` field of [`struct file_operations`].
+    pub read_iter: bool,
+
+    /// The `write` field of [`struct file_operations`].
+    pub write: bool,
+
+    /// The `write_iter` field of [`struct file_operations`].
+    pub write_iter: bool,
+
+    /// The `llseek` field of [`struct file_operations`].
+    pub seek: bool,
+
+    /// The `unlocked_ioctl` field of [`struct file_operations`].
+    pub ioctl: bool,
+
+    /// The `compat_ioctl` field of [`struct file_operations`].
+    pub compat_ioctl: bool,
+
+    /// The `fsync` field of [`struct file_operations`].
+    pub fsync: bool,
+
+    /// The `mmap` field of [`struct file_operations`].
+    pub mmap: bool,
+
+    /// The `poll` field of [`struct file_operations`].
+    pub poll: bool,
+}
+
+/// A constant version where all values are to set to `false`, that is, all supported fields will
+/// be set to null pointers.
+pub const USE_NONE: ToUse = ToUse {
+    read: false,
+    read_iter: false,
+    write: false,
+    write_iter: false,
+    seek: false,
+    ioctl: false,
+    compat_ioctl: false,
+    fsync: false,
+    mmap: false,
+    poll: false,
+};
+
+/// Defines the [`FileOperations::TO_USE`] field based on a list of fields to be populated.
+#[macro_export]
+macro_rules! declare_file_operations {
+    () => {
+        const TO_USE: $crate::file_operations::ToUse = $crate::file_operations::USE_NONE;
+    };
+    ($($i:ident),+) => {
+        const TO_USE: kernel::file_operations::ToUse =
+            $crate::file_operations::ToUse {
+                $($i: true),+ ,
+                ..$crate::file_operations::USE_NONE
+            };
+    };
+}
+
+/// Allows the handling of ioctls defined with the `_IO`, `_IOR`, `_IOW`, and `_IOWR` macros.
+///
+/// For each macro, there is a handler function that takes the appropriate types as arguments.
+pub trait IoctlHandler: Sync {
+    /// The type of the first argument to each associated function.
+    type Target<'a>;
+
+    /// Handles ioctls defined with the `_IO` macro, that is, with no buffer as argument.
+    fn pure(_this: Self::Target<'_>, _file: &File, _cmd: u32, _arg: usize) -> Result<i32> {
+        Err(Error::EINVAL)
+    }
+
+    /// Handles ioctls defined with the `_IOR` macro, that is, with an output buffer provided as
+    /// argument.
+    fn read(
+        _this: Self::Target<'_>,
+        _file: &File,
+        _cmd: u32,
+        _writer: &mut UserSlicePtrWriter,
+    ) -> Result<i32> {
+        Err(Error::EINVAL)
+    }
+
+    /// Handles ioctls defined with the `_IOW` macro, that is, with an input buffer provided as
+    /// argument.
+    fn write(
+        _this: Self::Target<'_>,
+        _file: &File,
+        _cmd: u32,
+        _reader: &mut UserSlicePtrReader,
+    ) -> Result<i32> {
+        Err(Error::EINVAL)
+    }
+
+    /// Handles ioctls defined with the `_IOWR` macro, that is, with a buffer for both input and
+    /// output provided as argument.
+    fn read_write(
+        _this: Self::Target<'_>,
+        _file: &File,
+        _cmd: u32,
+        _data: UserSlicePtr,
+    ) -> Result<i32> {
+        Err(Error::EINVAL)
+    }
+}
+
+/// Represents an ioctl command.
+///
+/// It can use the components of an ioctl command to dispatch ioctls using
+/// [`IoctlCommand::dispatch`].
+pub struct IoctlCommand {
+    cmd: u32,
+    arg: usize,
+    user_slice: Option<UserSlicePtr>,
+}
+
+impl IoctlCommand {
+    /// Constructs a new [`IoctlCommand`].
+    fn new(cmd: u32, arg: usize) -> Self {
+        let size = (cmd >> bindings::_IOC_SIZESHIFT) & bindings::_IOC_SIZEMASK;
+
+        // SAFETY: We only create one instance of the user slice per ioctl call, so TOCTOU issues
+        // are not possible.
+        let user_slice = Some(unsafe { UserSlicePtr::new(arg as _, size as _) });
+        Self {
+            cmd,
+            arg,
+            user_slice,
+        }
+    }
+
+    /// Dispatches the given ioctl to the appropriate handler based on the value of the command. It
+    /// also creates a [`UserSlicePtr`], [`UserSlicePtrReader`], or [`UserSlicePtrWriter`]
+    /// depending on the direction of the buffer of the command.
+    ///
+    /// It is meant to be used in implementations of [`FileOperations::ioctl`] and
+    /// [`FileOperations::compat_ioctl`].
+    pub fn dispatch<T: IoctlHandler>(
+        &mut self,
+        handler: T::Target<'_>,
+        file: &File,
+    ) -> Result<i32> {
+        let dir = (self.cmd >> bindings::_IOC_DIRSHIFT) & bindings::_IOC_DIRMASK;
+        if dir == bindings::_IOC_NONE {
+            return T::pure(handler, file, self.cmd, self.arg);
+        }
+
+        let data = self.user_slice.take().ok_or(Error::EINVAL)?;
+        const READ_WRITE: u32 = bindings::_IOC_READ | bindings::_IOC_WRITE;
+        match dir {
+            bindings::_IOC_WRITE => T::write(handler, file, self.cmd, &mut data.reader()),
+            bindings::_IOC_READ => T::read(handler, file, self.cmd, &mut data.writer()),
+            READ_WRITE => T::read_write(handler, file, self.cmd, data),
+            _ => Err(Error::EINVAL),
+        }
+    }
+
+    /// Returns the raw 32-bit value of the command and the ptr-sized argument.
+    pub fn raw(&self) -> (u32, usize) {
+        (self.cmd, self.arg)
+    }
+}
+
+/// Trait for extracting file open arguments from kernel data structures.
+///
+/// This is meant to be implemented by registration managers.
+pub trait FileOpenAdapter<T: Sync> {
+    /// Converts untyped data stored in [`struct inode`] and [`struct file`] (when [`struct
+    /// file_operations::open`] is called) into the given type. For example, for `miscdev`
+    /// devices, a pointer to the registered [`struct miscdev`] is stored in [`struct
+    /// file::private_data`].
+    ///
+    /// # Safety
+    ///
+    /// This function must be called only when [`struct file_operations::open`] is being called for
+    /// a file that was registered by the implementer. The returned pointer must be valid and
+    /// not-null.
+    unsafe fn convert(_inode: *mut bindings::inode, _file: *mut bindings::file) -> *const T;
+}
+
+/// Corresponds to the kernel's `struct file_operations`.
+///
+/// You implement this trait whenever you would create a `struct file_operations`.
+///
+/// File descriptors may be used from multiple threads/processes concurrently, so your type must be
+/// [`Sync`]. It must also be [`Send`] because [`FileOperations::release`] will be called from the
+/// thread that decrements that associated file's refcount to zero.
+pub trait FileOperations {
+    /// The methods to use to populate [`struct file_operations`].
+    const TO_USE: ToUse;
+
+    /// The pointer type that will be used to hold ourselves.
+    type Wrapper: PointerWrapper + Send + Sync = ();
+
+    /// The type of the context data passed to [`FileOperations::open`].
+    type OpenData: Sync = ();
+
+    /// Creates a new instance of this file.
+    ///
+    /// Corresponds to the `open` function pointer in `struct file_operations`.
+    fn open(context: &Self::OpenData, file: &File) -> Result<Self::Wrapper>;
+
+    /// Cleans up after the last reference to the file goes away.
+    ///
+    /// Note that the object is moved, so it will be freed automatically unless the implementation
+    /// moves it elsewhere.
+    ///
+    /// Corresponds to the `release` function pointer in `struct file_operations`.
+    fn release(_obj: Self::Wrapper, _file: &File) {}
+
+    /// Reads data from this file to the caller's buffer.
+    ///
+    /// Corresponds to the `read` and `read_iter` function pointers in `struct file_operations`.
+    fn read(
+        _this: <Self::Wrapper as PointerWrapper>::Borrowed<'_>,
+        _file: &File,
+        _data: &mut impl IoBufferWriter,
+        _offset: u64,
+    ) -> Result<usize> {
+        Err(Error::EINVAL)
+    }
+
+    /// Writes data from the caller's buffer to this file.
+    ///
+    /// Corresponds to the `write` and `write_iter` function pointers in `struct file_operations`.
+    fn write(
+        _this: <Self::Wrapper as PointerWrapper>::Borrowed<'_>,
+        _file: &File,
+        _data: &mut impl IoBufferReader,
+        _offset: u64,
+    ) -> Result<usize> {
+        Err(Error::EINVAL)
+    }
+
+    /// Changes the position of the file.
+    ///
+    /// Corresponds to the `llseek` function pointer in `struct file_operations`.
+    fn seek(
+        _this: <Self::Wrapper as PointerWrapper>::Borrowed<'_>,
+        _file: &File,
+        _offset: SeekFrom,
+    ) -> Result<u64> {
+        Err(Error::EINVAL)
+    }
+
+    /// Performs IO control operations that are specific to the file.
+    ///
+    /// Corresponds to the `unlocked_ioctl` function pointer in `struct file_operations`.
+    fn ioctl(
+        _this: <Self::Wrapper as PointerWrapper>::Borrowed<'_>,
+        _file: &File,
+        _cmd: &mut IoctlCommand,
+    ) -> Result<i32> {
+        Err(Error::ENOTTY)
+    }
+
+    /// Performs 32-bit IO control operations on that are specific to the file on 64-bit kernels.
+    ///
+    /// Corresponds to the `compat_ioctl` function pointer in `struct file_operations`.
+    fn compat_ioctl(
+        _this: <Self::Wrapper as PointerWrapper>::Borrowed<'_>,
+        _file: &File,
+        _cmd: &mut IoctlCommand,
+    ) -> Result<i32> {
+        Err(Error::ENOTTY)
+    }
+
+    /// Syncs pending changes to this file.
+    ///
+    /// Corresponds to the `fsync` function pointer in `struct file_operations`.
+    fn fsync(
+        _this: <Self::Wrapper as PointerWrapper>::Borrowed<'_>,
+        _file: &File,
+        _start: u64,
+        _end: u64,
+        _datasync: bool,
+    ) -> Result<u32> {
+        Err(Error::EINVAL)
+    }
+
+    /// Maps areas of the caller's virtual memory with device/file memory.
+    ///
+    /// Corresponds to the `mmap` function pointer in `struct file_operations`.
+    /// TODO: Wrap `vm_area_struct` so that we don't have to expose it.
+    fn mmap(
+        _this: <Self::Wrapper as PointerWrapper>::Borrowed<'_>,
+        _file: &File,
+        _vma: &mut mm::virt::Area,
+    ) -> Result {
+        Err(Error::EINVAL)
+    }
+
+    /// Checks the state of the file and optionally registers for notification when the state
+    /// changes.
+    ///
+    /// Corresponds to the `poll` function pointer in `struct file_operations`.
+    fn poll(
+        _this: <Self::Wrapper as PointerWrapper>::Borrowed<'_>,
+        _file: &File,
+        _table: &PollTable,
+    ) -> Result<u32> {
+        Ok(bindings::POLLIN | bindings::POLLOUT | bindings::POLLRDNORM | bindings::POLLWRNORM)
+    }
+}
diff --git a/rust/kernel/gpio.rs b/rust/kernel/gpio.rs
new file mode 100644
index 000000000000..d02524ded599
--- /dev/null
+++ b/rust/kernel/gpio.rs
@@ -0,0 +1,477 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Support for gpio device drivers.
+//!
+//! C header: [`include/linux/gpio/driver.h`](../../../../include/linux/gpio/driver.h)
+
+use crate::{
+    bindings, c_types, device, error::from_kernel_result, types::PointerWrapper, Error, Result,
+};
+use core::{
+    cell::UnsafeCell,
+    marker::{PhantomData, PhantomPinned},
+    pin::Pin,
+};
+
+#[cfg(CONFIG_GPIOLIB_IRQCHIP)]
+pub use irqchip::{ChipWithIrqChip, RegistrationWithIrqChip};
+
+/// The direction of a gpio line.
+pub enum LineDirection {
+    /// Direction is input.
+    In = bindings::GPIO_LINE_DIRECTION_IN as _,
+
+    /// Direction is output.
+    Out = bindings::GPIO_LINE_DIRECTION_OUT as _,
+}
+
+/// A gpio chip.
+pub trait Chip {
+    /// Context data associated with the gpio chip.
+    ///
+    /// It determines the type of the context data passed to each of the methods of the trait.
+    type Data: PointerWrapper + Sync + Send;
+
+    /// The methods to use to populate [`struct gpio_chip`]. This is typically populated with
+    /// [`declare_gpio_chip_operations`].
+    const TO_USE: ToUse;
+
+    /// Returns the direction of the given gpio line.
+    fn get_direction(
+        _data: <Self::Data as PointerWrapper>::Borrowed<'_>,
+        _offset: u32,
+    ) -> Result<LineDirection> {
+        Err(Error::ENOTSUPP)
+    }
+
+    /// Configures the direction as input of the given gpio line.
+    fn direction_input(
+        _data: <Self::Data as PointerWrapper>::Borrowed<'_>,
+        _offset: u32,
+    ) -> Result {
+        Err(Error::EIO)
+    }
+
+    /// Configures the direction as output of the given gpio line.
+    ///
+    /// The value that will be initially output is also specified.
+    fn direction_output(
+        _data: <Self::Data as PointerWrapper>::Borrowed<'_>,
+        _offset: u32,
+        _value: bool,
+    ) -> Result {
+        Err(Error::ENOTSUPP)
+    }
+
+    /// Returns the current value of the given gpio line.
+    fn get(_data: <Self::Data as PointerWrapper>::Borrowed<'_>, _offset: u32) -> Result<bool> {
+        Err(Error::EIO)
+    }
+
+    /// Sets the value of the given gpio line.
+    fn set(_data: <Self::Data as PointerWrapper>::Borrowed<'_>, _offset: u32, _value: bool) {}
+}
+
+/// Represents which fields of [`struct gpio_chip`] should be populated with pointers.
+///
+/// This is typically populated with the [`declare_gpio_chip_operations`] macro.
+pub struct ToUse {
+    /// The `get_direction` field of [`struct gpio_chip`].
+    pub get_direction: bool,
+
+    /// The `direction_input` field of [`struct gpio_chip`].
+    pub direction_input: bool,
+
+    /// The `direction_output` field of [`struct gpio_chip`].
+    pub direction_output: bool,
+
+    /// The `get` field of [`struct gpio_chip`].
+    pub get: bool,
+
+    /// The `set` field of [`struct gpio_chip`].
+    pub set: bool,
+}
+
+/// A constant version where all values are set to `false`, that is, all supported fields will be
+/// set to null pointers.
+pub const USE_NONE: ToUse = ToUse {
+    get_direction: false,
+    direction_input: false,
+    direction_output: false,
+    get: false,
+    set: false,
+};
+
+/// Defines the [`Chip::TO_USE`] field based on a list of fields to be populated.
+#[macro_export]
+macro_rules! declare_gpio_chip_operations {
+    () => {
+        const TO_USE: $crate::gpio::ToUse = $crate::gpio::USE_NONE;
+    };
+    ($($i:ident),+) => {
+        #[allow(clippy::needless_update)]
+        const TO_USE: $crate::gpio::ToUse =
+            $crate::gpio::ToUse {
+                $($i: true),+ ,
+                ..$crate::gpio::USE_NONE
+            };
+    };
+}
+
+/// A registration of a gpio chip.
+pub struct Registration<T: Chip> {
+    gc: UnsafeCell<bindings::gpio_chip>,
+    parent: Option<device::Device>,
+    _p: PhantomData<T>,
+    _pin: PhantomPinned,
+}
+
+impl<T: Chip> Registration<T> {
+    /// Creates a new [`Registration`] but does not register it yet.
+    ///
+    /// It is allowed to move.
+    pub fn new() -> Self {
+        Self {
+            parent: None,
+            gc: UnsafeCell::new(bindings::gpio_chip::default()),
+            _pin: PhantomPinned,
+            _p: PhantomData,
+        }
+    }
+
+    /// Registers a gpio chip with the rest of the kernel.
+    pub fn register(
+        self: Pin<&mut Self>,
+        gpio_count: u16,
+        base: Option<i32>,
+        parent: &dyn device::RawDevice,
+        data: T::Data,
+    ) -> Result {
+        if self.parent.is_some() {
+            // Already registered.
+            return Err(Error::EINVAL);
+        }
+
+        // SAFETY: We never move out of `this`.
+        let this = unsafe { self.get_unchecked_mut() };
+        {
+            let gc = this.gc.get_mut();
+
+            // Set up the callbacks.
+            gc.request = Some(bindings::gpiochip_generic_request);
+            gc.free = Some(bindings::gpiochip_generic_free);
+            if T::TO_USE.get_direction {
+                gc.get_direction = Some(get_direction_callback::<T>);
+            }
+            if T::TO_USE.direction_input {
+                gc.direction_input = Some(direction_input_callback::<T>);
+            }
+            if T::TO_USE.direction_output {
+                gc.direction_output = Some(direction_output_callback::<T>);
+            }
+            if T::TO_USE.get {
+                gc.get = Some(get_callback::<T>);
+            }
+            if T::TO_USE.set {
+                gc.set = Some(set_callback::<T>);
+            }
+
+            // When a base is not explicitly given, use -1 for one to be picked.
+            if let Some(b) = base {
+                gc.base = b;
+            } else {
+                gc.base = -1;
+            }
+
+            gc.ngpio = gpio_count;
+            gc.parent = parent.raw_device();
+            gc.label = parent.name().as_char_ptr();
+
+            // TODO: Define `gc.owner` as well.
+        }
+
+        let data_pointer = <T::Data as PointerWrapper>::into_pointer(data);
+        // SAFETY: `gc` was initilised above, so it is valid.
+        let ret = unsafe {
+            bindings::gpiochip_add_data_with_key(
+                this.gc.get(),
+                data_pointer as _,
+                core::ptr::null_mut(),
+                core::ptr::null_mut(),
+            )
+        };
+        if ret < 0 {
+            // SAFETY: `data_pointer` was returned by `into_pointer` above.
+            unsafe { T::Data::from_pointer(data_pointer) };
+            return Err(Error::from_kernel_errno(ret));
+        }
+
+        this.parent = Some(device::Device::from_dev(parent));
+        Ok(())
+    }
+}
+
+// SAFETY: `Registration` doesn't offer any methods or access to fields when shared between threads
+// or CPUs, so it is safe to share it.
+unsafe impl<T: Chip> Sync for Registration<T> {}
+
+// SAFETY: Registration with and unregistration from the gpio subsystem can happen from any thread.
+// Additionally, `T::Data` (which is dropped during unregistration) is `Send`, so it is ok to move
+// `Registration` to different threads.
+#[allow(clippy::non_send_fields_in_send_ty)]
+unsafe impl<T: Chip> Send for Registration<T> {}
+
+impl<T: Chip> Default for Registration<T> {
+    fn default() -> Self {
+        Self::new()
+    }
+}
+
+impl<T: Chip> Drop for Registration<T> {
+    /// Removes the registration from the kernel if it has completed successfully before.
+    fn drop(&mut self) {
+        if self.parent.is_some() {
+            // Get a pointer to the data stored in chip before destroying it.
+            // SAFETY: `gc` was during registration, which is guaranteed to have succeeded (because
+            // `parent` is `Some(_)`, so it remains valid.
+            let data_pointer = unsafe { bindings::gpiochip_get_data(self.gc.get()) };
+
+            // SAFETY: By the same argument above, `gc` is still valid.
+            unsafe { bindings::gpiochip_remove(self.gc.get()) };
+
+            // Free data as well.
+            // SAFETY: `data_pointer` was returned by `into_pointer` during registration.
+            unsafe { <T::Data as PointerWrapper>::from_pointer(data_pointer) };
+        }
+    }
+}
+
+unsafe extern "C" fn get_direction_callback<T: Chip>(
+    gc: *mut bindings::gpio_chip,
+    offset: c_types::c_uint,
+) -> c_types::c_int {
+    from_kernel_result! {
+        // SAFETY: The value stored as chip data was returned by `into_pointer` during registration.
+        let data = unsafe { T::Data::borrow(bindings::gpiochip_get_data(gc)) };
+        Ok(T::get_direction(data, offset)? as i32)
+    }
+}
+
+unsafe extern "C" fn direction_input_callback<T: Chip>(
+    gc: *mut bindings::gpio_chip,
+    offset: c_types::c_uint,
+) -> c_types::c_int {
+    from_kernel_result! {
+        // SAFETY: The value stored as chip data was returned by `into_pointer` during registration.
+        let data = unsafe { T::Data::borrow(bindings::gpiochip_get_data(gc)) };
+        T::direction_input(data, offset)?;
+        Ok(0)
+    }
+}
+
+unsafe extern "C" fn direction_output_callback<T: Chip>(
+    gc: *mut bindings::gpio_chip,
+    offset: c_types::c_uint,
+    value: c_types::c_int,
+) -> c_types::c_int {
+    from_kernel_result! {
+        // SAFETY: The value stored as chip data was returned by `into_pointer` during registration.
+        let data = unsafe { T::Data::borrow(bindings::gpiochip_get_data(gc)) };
+        T::direction_output(data, offset, value != 0)?;
+        Ok(0)
+    }
+}
+
+unsafe extern "C" fn get_callback<T: Chip>(
+    gc: *mut bindings::gpio_chip,
+    offset: c_types::c_uint,
+) -> c_types::c_int {
+    from_kernel_result! {
+        // SAFETY: The value stored as chip data was returned by `into_pointer` during registration.
+        let data = unsafe { T::Data::borrow(bindings::gpiochip_get_data(gc)) };
+        let v = T::get(data, offset)?;
+        Ok(v as _)
+    }
+}
+
+unsafe extern "C" fn set_callback<T: Chip>(
+    gc: *mut bindings::gpio_chip,
+    offset: c_types::c_uint,
+    value: c_types::c_int,
+) {
+    // SAFETY: The value stored as chip data was returned by `into_pointer` during registration.
+    let data = unsafe { T::Data::borrow(bindings::gpiochip_get_data(gc)) };
+    T::set(data, offset, value != 0);
+}
+
+#[cfg(CONFIG_GPIOLIB_IRQCHIP)]
+mod irqchip {
+    use super::*;
+    use crate::irq;
+
+    /// A gpio chip that includes an irq chip.
+    pub trait ChipWithIrqChip: Chip {
+        /// Implements the irq flow for the gpio chip.
+        fn handle_irq_flow(
+            _data: <Self::Data as PointerWrapper>::Borrowed<'_>,
+            _desc: &irq::Descriptor,
+            _domain: &irq::Domain,
+        );
+    }
+
+    /// A registration of a gpio chip that includes an irq chip.
+    pub struct RegistrationWithIrqChip<T: ChipWithIrqChip> {
+        reg: Registration<T>,
+        irq_chip: UnsafeCell<bindings::irq_chip>,
+        parent_irq: u32,
+    }
+
+    impl<T: ChipWithIrqChip> RegistrationWithIrqChip<T> {
+        /// Creates a new [`RegistrationWithIrqChip`] but does not register it yet.
+        ///
+        /// It is allowed to move.
+        pub fn new() -> Self {
+            Self {
+                reg: Registration::new(),
+                irq_chip: UnsafeCell::new(bindings::irq_chip::default()),
+                parent_irq: 0,
+            }
+        }
+
+        /// Registers a gpio chip and its irq chip with the rest of the kernel.
+        pub fn register<U: irq::Chip<Data = T::Data>>(
+            mut self: Pin<&mut Self>,
+            gpio_count: u16,
+            base: Option<i32>,
+            parent: &dyn device::RawDevice,
+            data: T::Data,
+            parent_irq: u32,
+        ) -> Result {
+            if self.reg.parent.is_some() {
+                // Already registered.
+                return Err(Error::EINVAL);
+            }
+
+            // SAFETY: We never move out of `this`.
+            let this = unsafe { self.as_mut().get_unchecked_mut() };
+
+            // Initialise the irq_chip.
+            {
+                let irq_chip = this.irq_chip.get_mut();
+                irq_chip.name = parent.name().as_char_ptr();
+
+                // SAFETY: The gpio subsystem configures a pointer to `gpio_chip` as the irq chip
+                // data, so we use `IrqChipAdapter` to convert to the `T::Data`, which is the same
+                // as `irq::Chip::Data` per the bound above.
+                unsafe { irq::init_chip::<IrqChipAdapter<U>>(irq_chip) };
+            }
+
+            // Initialise gc irq state.
+            {
+                let girq = &mut this.reg.gc.get_mut().irq;
+                girq.chip = this.irq_chip.get();
+                // SAFETY: By leaving `parent_handler_data` set to `null`, the gpio subsystem
+                // initialises it to a pointer to the gpio chip, which is what `FlowHandler<T>`
+                // expects.
+                girq.parent_handler = unsafe { irq::new_flow_handler::<FlowHandler<T>>() };
+                girq.num_parents = 1;
+                girq.parents = &mut this.parent_irq;
+                this.parent_irq = parent_irq;
+                girq.default_type = bindings::IRQ_TYPE_NONE;
+                girq.handler = Some(bindings::handle_bad_irq);
+            }
+
+            // SAFETY: `reg` is pinned when `self` is.
+            let pinned = unsafe { self.map_unchecked_mut(|r| &mut r.reg) };
+            pinned.register(gpio_count, base, parent, data)
+        }
+    }
+
+    impl<T: ChipWithIrqChip> Default for RegistrationWithIrqChip<T> {
+        fn default() -> Self {
+            Self::new()
+        }
+    }
+
+    // SAFETY: `RegistrationWithIrqChip` doesn't offer any methods or access to fields when shared
+    // between threads or CPUs, so it is safe to share it.
+    unsafe impl<T: ChipWithIrqChip> Sync for RegistrationWithIrqChip<T> {}
+
+    // SAFETY: Registration with and unregistration from the gpio subsystem (including irq chips for
+    // them) can happen from any thread. Additionally, `T::Data` (which is dropped during
+    // unregistration) is `Send`, so it is ok to move `Registration` to different threads.
+    #[allow(clippy::non_send_fields_in_send_ty)]
+    unsafe impl<T: ChipWithIrqChip> Send for RegistrationWithIrqChip<T> where T::Data: Send {}
+
+    struct FlowHandler<T: ChipWithIrqChip>(PhantomData<T>);
+
+    impl<T: ChipWithIrqChip> irq::FlowHandler for FlowHandler<T> {
+        type Data = *mut bindings::gpio_chip;
+
+        fn handle_irq_flow(gc: *mut bindings::gpio_chip, desc: &irq::Descriptor) {
+            // SAFETY: `FlowHandler` is only used in gpio chips, and it is removed when the gpio is
+            // unregistered, so we know that `gc` must still be valid. We also know that the value
+            // stored as gpio data was returned by `T::Data::into_pointer` again because
+            // `FlowHandler` is a private structure only used in this way.
+            let data = unsafe { T::Data::borrow(bindings::gpiochip_get_data(gc)) };
+
+            // SAFETY: `gc` is valid (see comment above), so we can dereference it.
+            let domain = unsafe { irq::Domain::from_ptr((*gc).irq.domain) };
+
+            T::handle_irq_flow(data, desc, &domain);
+        }
+    }
+
+    /// Adapter from an irq chip with `gpio_chip` pointer as context to one where the gpio chip
+    /// data is passed as context.
+    struct IrqChipAdapter<T: irq::Chip>(PhantomData<T>);
+
+    impl<T: irq::Chip> irq::Chip for IrqChipAdapter<T> {
+        type Data = *mut bindings::gpio_chip;
+        const TO_USE: irq::ToUse = T::TO_USE;
+
+        fn ack(gc: *mut bindings::gpio_chip, irq_data: &irq::IrqData) {
+            // SAFETY: `IrqChipAdapter` is a private struct, only used when the data stored in the
+            // gpio chip is known to come from `T::Data`, and only valid while the gpio chip is
+            // registered, so `gc` is valid.
+            let data = unsafe { T::Data::borrow(bindings::gpiochip_get_data(gc as _)) };
+            T::ack(data, irq_data);
+        }
+
+        fn mask(gc: *mut bindings::gpio_chip, irq_data: &irq::IrqData) {
+            // SAFETY: `IrqChipAdapter` is a private struct, only used when the data stored in the
+            // gpio chip is known to come from `T::Data`, and only valid while the gpio chip is
+            // registered, so `gc` is valid.
+            let data = unsafe { T::Data::borrow(bindings::gpiochip_get_data(gc as _)) };
+            T::mask(data, irq_data);
+        }
+
+        fn unmask(gc: *mut bindings::gpio_chip, irq_data: &irq::IrqData) {
+            // SAFETY: `IrqChipAdapter` is a private struct, only used when the data stored in the
+            // gpio chip is known to come from `T::Data`, and only valid while the gpio chip is
+            // registered, so `gc` is valid.
+            let data = unsafe { T::Data::borrow(bindings::gpiochip_get_data(gc as _)) };
+            T::unmask(data, irq_data);
+        }
+
+        fn set_type(
+            gc: *mut bindings::gpio_chip,
+            irq_data: &mut irq::LockedIrqData,
+            flow_type: u32,
+        ) -> Result<irq::ExtraResult> {
+            // SAFETY: `IrqChipAdapter` is a private struct, only used when the data stored in the
+            // gpio chip is known to come from `T::Data`, and only valid while the gpio chip is
+            // registered, so `gc` is valid.
+            let data = unsafe { T::Data::borrow(bindings::gpiochip_get_data(gc as _)) };
+            T::set_type(data, irq_data, flow_type)
+        }
+
+        fn set_wake(gc: *mut bindings::gpio_chip, irq_data: &irq::IrqData, on: bool) -> Result {
+            // SAFETY: `IrqChipAdapter` is a private struct, only used when the data stored in the
+            // gpio chip is known to come from `T::Data`, and only valid while the gpio chip is
+            // registered, so `gc` is valid.
+            let data = unsafe { T::Data::borrow(bindings::gpiochip_get_data(gc as _)) };
+            T::set_wake(data, irq_data, on)
+        }
+    }
+}
diff --git a/rust/kernel/io_buffer.rs b/rust/kernel/io_buffer.rs
new file mode 100644
index 000000000000..ccecc4763aca
--- /dev/null
+++ b/rust/kernel/io_buffer.rs
@@ -0,0 +1,153 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Buffers used in IO.
+
+use crate::Result;
+use alloc::vec::Vec;
+use core::mem::{size_of, MaybeUninit};
+
+/// Represents a buffer to be read from during IO.
+pub trait IoBufferReader {
+    /// Returns the number of bytes left to be read from the io buffer.
+    ///
+    /// Note that even reading less than this number of bytes may fail.
+    fn len(&self) -> usize;
+
+    /// Returns `true` if no data is available in the io buffer.
+    fn is_empty(&self) -> bool {
+        self.len() == 0
+    }
+
+    /// Reads raw data from the io buffer into a raw kernel buffer.
+    ///
+    /// # Safety
+    ///
+    /// The output buffer must be valid.
+    unsafe fn read_raw(&mut self, out: *mut u8, len: usize) -> Result;
+
+    /// Reads all data remaining in the io buffer.
+    ///
+    /// Returns `EFAULT` if the address does not currently point to mapped, readable memory.
+    fn read_all(&mut self) -> Result<Vec<u8>> {
+        let mut data = Vec::<u8>::new();
+        data.try_resize(self.len(), 0)?;
+
+        // SAFETY: The output buffer is valid as we just allocated it.
+        unsafe { self.read_raw(data.as_mut_ptr(), data.len())? };
+        Ok(data)
+    }
+
+    /// Reads a byte slice from the io buffer.
+    ///
+    /// Returns `EFAULT` if the byte slice is bigger than the remaining size of the user slice or
+    /// if the address does not currently point to mapped, readable memory.
+    fn read_slice(&mut self, data: &mut [u8]) -> Result {
+        // SAFETY: The output buffer is valid as it's coming from a live reference.
+        unsafe { self.read_raw(data.as_mut_ptr(), data.len()) }
+    }
+
+    /// Reads the contents of a plain old data (POD) type from the io buffer.
+    fn read<T: ReadableFromBytes>(&mut self) -> Result<T> {
+        let mut out = MaybeUninit::<T>::uninit();
+        // SAFETY: The buffer is valid as it was just allocated.
+        unsafe { self.read_raw(out.as_mut_ptr() as _, size_of::<T>()) }?;
+        // SAFETY: We just initialised the data.
+        Ok(unsafe { out.assume_init() })
+    }
+}
+
+/// Represents a buffer to be written to during IO.
+pub trait IoBufferWriter {
+    /// Returns the number of bytes left to be written into the io buffer.
+    ///
+    /// Note that even writing less than this number of bytes may fail.
+    fn len(&self) -> usize;
+
+    /// Returns `true` if the io buffer cannot hold any additional data.
+    fn is_empty(&self) -> bool {
+        self.len() == 0
+    }
+
+    /// Writes zeroes to the io buffer.
+    ///
+    /// Differently from the other write functions, `clear` will zero as much as it can and update
+    /// the writer internal state to reflect this. It will, however, return an error if it cannot
+    /// clear `len` bytes.
+    ///
+    /// For example, if a caller requests that 100 bytes be cleared but a segfault happens after
+    /// 20 bytes, then EFAULT is returned and the writer is advanced by 20 bytes.
+    fn clear(&mut self, len: usize) -> Result;
+
+    /// Writes a byte slice into the io buffer.
+    ///
+    /// Returns `EFAULT` if the byte slice is bigger than the remaining size of the io buffer or if
+    /// the address does not currently point to mapped, writable memory.
+    fn write_slice(&mut self, data: &[u8]) -> Result {
+        // SAFETY: The input buffer is valid as it's coming from a live reference.
+        unsafe { self.write_raw(data.as_ptr(), data.len()) }
+    }
+
+    /// Writes raw data to the io buffer from a raw kernel buffer.
+    ///
+    /// # Safety
+    ///
+    /// The input buffer must be valid.
+    unsafe fn write_raw(&mut self, data: *const u8, len: usize) -> Result;
+
+    /// Writes the contents of the given data into the io buffer.
+    fn write<T: WritableToBytes>(&mut self, data: &T) -> Result {
+        // SAFETY: The input buffer is valid as it's coming from a live
+        // reference to a type that implements `WritableToBytes`.
+        unsafe { self.write_raw(data as *const T as _, size_of::<T>()) }
+    }
+}
+
+/// Specifies that a type is safely readable from byte slices.
+///
+/// Not all types can be safely read from byte slices; examples from
+/// <https://doc.rust-lang.org/reference/behavior-considered-undefined.html> include `bool`
+/// that must be either `0` or `1`, and `char` that cannot be a surrogate or above `char::MAX`.
+///
+/// # Safety
+///
+/// Implementers must ensure that the type is made up only of types that can be safely read from
+/// arbitrary byte sequences (e.g., `u32`, `u64`, etc.).
+pub unsafe trait ReadableFromBytes {}
+
+// SAFETY: All bit patterns are acceptable values of the types below.
+unsafe impl ReadableFromBytes for u8 {}
+unsafe impl ReadableFromBytes for u16 {}
+unsafe impl ReadableFromBytes for u32 {}
+unsafe impl ReadableFromBytes for u64 {}
+unsafe impl ReadableFromBytes for usize {}
+unsafe impl ReadableFromBytes for i8 {}
+unsafe impl ReadableFromBytes for i16 {}
+unsafe impl ReadableFromBytes for i32 {}
+unsafe impl ReadableFromBytes for i64 {}
+unsafe impl ReadableFromBytes for isize {}
+
+/// Specifies that a type is safely writable to byte slices.
+///
+/// This means that we don't read undefined values (which leads to UB) in preparation for writing
+/// to the byte slice. It also ensures that no potentially sensitive information is leaked into the
+/// byte slices.
+///
+/// # Safety
+///
+/// A type must not include padding bytes and must be fully initialised to safely implement
+/// [`WritableToBytes`] (i.e., it doesn't contain [`MaybeUninit`] fields). A composition of
+/// writable types in a structure is not necessarily writable because it may result in padding
+/// bytes.
+pub unsafe trait WritableToBytes {}
+
+// SAFETY: Initialised instances of the following types have no uninitialised portions.
+unsafe impl WritableToBytes for u8 {}
+unsafe impl WritableToBytes for u16 {}
+unsafe impl WritableToBytes for u32 {}
+unsafe impl WritableToBytes for u64 {}
+unsafe impl WritableToBytes for usize {}
+unsafe impl WritableToBytes for i8 {}
+unsafe impl WritableToBytes for i16 {}
+unsafe impl WritableToBytes for i32 {}
+unsafe impl WritableToBytes for i64 {}
+unsafe impl WritableToBytes for isize {}
diff --git a/rust/kernel/io_mem.rs b/rust/kernel/io_mem.rs
new file mode 100644
index 000000000000..496c44f74c7b
--- /dev/null
+++ b/rust/kernel/io_mem.rs
@@ -0,0 +1,227 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Memory-mapped IO.
+//!
+//! C header: [`include/asm-generic/io.h`](../../../../include/asm-generic/io.h)
+
+#![allow(dead_code)]
+
+use crate::{bindings, Error, Result};
+use core::convert::TryInto;
+
+/// Represents a memory resource.
+pub struct Resource {
+    offset: bindings::resource_size_t,
+    size: bindings::resource_size_t,
+}
+
+impl Resource {
+    pub(crate) fn new(
+        start: bindings::resource_size_t,
+        end: bindings::resource_size_t,
+    ) -> Option<Self> {
+        if start == 0 {
+            return None;
+        }
+        Some(Self {
+            offset: start,
+            size: end.checked_sub(start)?.checked_add(1)?,
+        })
+    }
+}
+
+/// Represents a memory block of at least `SIZE` bytes.
+///
+/// # Invariants
+///
+/// `ptr` is a non-null and valid address of at least `SIZE` bytes and returned by an `ioremap`
+/// variant. `ptr` is also 8-byte aligned.
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::prelude::*;
+/// use kernel::io_mem::{IoMem, Resource};
+///
+/// fn test(res: Resource) -> Result {
+///     // Create an io mem block of at least 100 bytes.
+///     // SAFETY: No DMA operations are initiated through `mem`.
+///     let mem = unsafe { IoMem::<100>::try_new(res) }?;
+///
+///     // Read one byte from offset 10.
+///     let v = mem.readb(10);
+///
+///     // Write value to offset 20.
+///     mem.writeb(v, 20);
+///
+///     Ok(())
+/// }
+///
+/// ```
+pub struct IoMem<const SIZE: usize> {
+    ptr: usize,
+}
+
+macro_rules! define_read {
+    ($(#[$attr:meta])* $name:ident, $try_name:ident, $type_name:ty) => {
+        /// Reads IO data from the given offset known, at compile time.
+        ///
+        /// If the offset is not known at compile time, the build will fail.
+        $(#[$attr])*
+        pub fn $name(&self, offset: usize) -> $type_name {
+            Self::check_offset::<$type_name>(offset);
+            let ptr = self.ptr.wrapping_add(offset);
+            // SAFETY: The type invariants guarantee that `ptr` is a valid pointer. The check above
+            // guarantees that the code won't build if `offset` makes the read go out of bounds
+            // (including the type size).
+            unsafe { bindings::$name(ptr as _) }
+        }
+
+        /// Reads IO data from the given offset.
+        ///
+        /// It fails if/when the offset (plus the type size) is out of bounds.
+        $(#[$attr])*
+        pub fn $try_name(&self, offset: usize) -> Result<$type_name> {
+            if !Self::offset_ok::<$type_name>(offset) {
+                return Err(Error::EINVAL);
+            }
+            let ptr = self.ptr.wrapping_add(offset);
+            // SAFETY: The type invariants guarantee that `ptr` is a valid pointer. The check above
+            // returns an error if `offset` would make the read go out of bounds (including the
+            // type size).
+            Ok(unsafe { bindings::$name(ptr as _) })
+        }
+    };
+}
+
+macro_rules! define_write {
+    ($(#[$attr:meta])* $name:ident, $try_name:ident, $type_name:ty) => {
+        /// Writes IO data to the given offset, known at compile time.
+        ///
+        /// If the offset is not known at compile time, the build will fail.
+        $(#[$attr])*
+        pub fn $name(&self, value: $type_name, offset: usize) {
+            Self::check_offset::<$type_name>(offset);
+            let ptr = self.ptr.wrapping_add(offset);
+            // SAFETY: The type invariants guarantee that `ptr` is a valid pointer. The check above
+            // guarantees that the code won't link if `offset` makes the write go out of bounds
+            // (including the type size).
+            unsafe { bindings::$name(value, ptr as _) }
+        }
+
+        /// Writes IO data to the given offset.
+        ///
+        /// It fails if/when the offset (plus the type size) is out of bounds.
+        $(#[$attr])*
+        pub fn $try_name(&self, value: $type_name, offset: usize) -> Result {
+            if !Self::offset_ok::<$type_name>(offset) {
+                return Err(Error::EINVAL);
+            }
+            let ptr = self.ptr.wrapping_add(offset);
+            // SAFETY: The type invariants guarantee that `ptr` is a valid pointer. The check above
+            // returns an error if `offset` would make the write go out of bounds (including the
+            // type size).
+            unsafe { bindings::$name(value, ptr as _) };
+            Ok(())
+        }
+    };
+}
+
+impl<const SIZE: usize> IoMem<SIZE> {
+    /// Tries to create a new instance of a memory block.
+    ///
+    /// The resource described by `res` is mapped into the CPU's address space so that it can be
+    /// accessed directly. It is also consumed by this function so that it can't be mapped again
+    /// to a different address.
+    ///
+    /// # Safety
+    ///
+    /// Callers must ensure that either (a) the resulting interface cannot be used to initiate DMA
+    /// operations, or (b) that DMA operations initiated via the returned interface use DMA handles
+    /// allocated through the `dma` module.
+    pub unsafe fn try_new(res: Resource) -> Result<Self> {
+        // Check that the resource has at least `SIZE` bytes in it.
+        if res.size < SIZE.try_into()? {
+            return Err(Error::EINVAL);
+        }
+
+        // To be able to check pointers at compile time based only on offsets, we need to guarantee
+        // that the base pointer is minimally aligned. So we conservatively expect at least 8 bytes.
+        if res.offset % 8 != 0 {
+            crate::pr_err!("Physical address is not 64-bit aligned: {:x}", res.offset);
+            return Err(Error::EDOM);
+        }
+
+        // Try to map the resource.
+        // SAFETY: Just mapping the memory range.
+        let addr = unsafe { bindings::ioremap(res.offset, res.size as _) };
+        if addr.is_null() {
+            Err(Error::ENOMEM)
+        } else {
+            // INVARIANT: `addr` is non-null and was returned by `ioremap`, so it is valid. It is
+            // also 8-byte aligned because we checked it above.
+            Ok(Self { ptr: addr as usize })
+        }
+    }
+
+    const fn offset_ok<T>(offset: usize) -> bool {
+        let type_size = core::mem::size_of::<T>();
+        if let Some(end) = offset.checked_add(type_size) {
+            end <= SIZE && offset % type_size == 0
+        } else {
+            false
+        }
+    }
+
+    const fn check_offset<T>(offset: usize) {
+        crate::build_assert!(Self::offset_ok::<T>(offset), "IoMem offset overflow");
+    }
+
+    define_read!(readb, try_readb, u8);
+    define_read!(readw, try_readw, u16);
+    define_read!(readl, try_readl, u32);
+    define_read!(
+        #[cfg(CONFIG_64BIT)]
+        readq,
+        try_readq,
+        u64
+    );
+
+    define_read!(readb_relaxed, try_readb_relaxed, u8);
+    define_read!(readw_relaxed, try_readw_relaxed, u16);
+    define_read!(readl_relaxed, try_readl_relaxed, u32);
+    define_read!(
+        #[cfg(CONFIG_64BIT)]
+        readq_relaxed,
+        try_readq_relaxed,
+        u64
+    );
+
+    define_write!(writeb, try_writeb, u8);
+    define_write!(writew, try_writew, u16);
+    define_write!(writel, try_writel, u32);
+    define_write!(
+        #[cfg(CONFIG_64BIT)]
+        writeq,
+        try_writeq,
+        u64
+    );
+
+    define_write!(writeb_relaxed, try_writeb_relaxed, u8);
+    define_write!(writew_relaxed, try_writew_relaxed, u16);
+    define_write!(writel_relaxed, try_writel_relaxed, u32);
+    define_write!(
+        #[cfg(CONFIG_64BIT)]
+        writeq_relaxed,
+        try_writeq_relaxed,
+        u64
+    );
+}
+
+impl<const SIZE: usize> Drop for IoMem<SIZE> {
+    fn drop(&mut self) {
+        // SAFETY: By the type invariant, `self.ptr` is a value returned by a previous successful
+        // call to `ioremap`.
+        unsafe { bindings::iounmap(self.ptr as _) };
+    }
+}
diff --git a/rust/kernel/iov_iter.rs b/rust/kernel/iov_iter.rs
new file mode 100644
index 000000000000..fe738c529b84
--- /dev/null
+++ b/rust/kernel/iov_iter.rs
@@ -0,0 +1,81 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! IO vector iterators.
+//!
+//! C header: [`include/linux/uio.h`](../../../../include/linux/uio.h)
+
+use crate::{
+    bindings,
+    error::Error,
+    io_buffer::{IoBufferReader, IoBufferWriter},
+    Result,
+};
+
+/// Wraps the kernel's `struct iov_iter`.
+///
+/// # Invariants
+///
+/// The pointer `IovIter::ptr` is non-null and valid.
+pub struct IovIter {
+    ptr: *mut bindings::iov_iter,
+}
+
+impl IovIter {
+    fn common_len(&self) -> usize {
+        // SAFETY: `IovIter::ptr` is guaranteed to be valid by the type invariants.
+        unsafe { (*self.ptr).count }
+    }
+
+    /// Constructs a new [`struct iov_iter`] wrapper.
+    ///
+    /// # Safety
+    ///
+    /// The pointer `ptr` must be non-null and valid for the lifetime of the object.
+    pub(crate) unsafe fn from_ptr(ptr: *mut bindings::iov_iter) -> Self {
+        // INVARIANTS: the safety contract ensures the type invariant will hold.
+        Self { ptr }
+    }
+}
+
+impl IoBufferWriter for IovIter {
+    fn len(&self) -> usize {
+        self.common_len()
+    }
+
+    fn clear(&mut self, mut len: usize) -> Result {
+        while len > 0 {
+            // SAFETY: `IovIter::ptr` is guaranteed to be valid by the type invariants.
+            let written = unsafe { bindings::iov_iter_zero(len, self.ptr) };
+            if written == 0 {
+                return Err(Error::EFAULT);
+            }
+
+            len -= written;
+        }
+        Ok(())
+    }
+
+    unsafe fn write_raw(&mut self, data: *const u8, len: usize) -> Result {
+        let res = unsafe { bindings::copy_to_iter(data as _, len, self.ptr) };
+        if res != len {
+            Err(Error::EFAULT)
+        } else {
+            Ok(())
+        }
+    }
+}
+
+impl IoBufferReader for IovIter {
+    fn len(&self) -> usize {
+        self.common_len()
+    }
+
+    unsafe fn read_raw(&mut self, out: *mut u8, len: usize) -> Result {
+        let res = unsafe { bindings::copy_from_iter(out as _, len, self.ptr) };
+        if res != len {
+            Err(Error::EFAULT)
+        } else {
+            Ok(())
+        }
+    }
+}
diff --git a/rust/kernel/irq.rs b/rust/kernel/irq.rs
new file mode 100644
index 000000000000..ca62849a5dc0
--- /dev/null
+++ b/rust/kernel/irq.rs
@@ -0,0 +1,409 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Interrupts and interrupt chips.
+//!
+//! See <https://www.kernel.org/doc/Documentation/core-api/genericirq.rst>.
+//!
+//! C headers: [`include/linux/irq.h`](../../../../include/linux/irq.h) and
+//! [`include/linux/interrupt.h`](../../../../include/linux/interrupt.h).
+
+#![allow(dead_code)]
+
+use crate::{bindings, c_types, error::from_kernel_result, types::PointerWrapper, Error, Result};
+use core::ops::Deref;
+
+/// The type of irq hardware numbers.
+pub type HwNumber = bindings::irq_hw_number_t;
+
+/// Wraps the kernel's `struct irq_data`.
+///
+/// # Invariants
+///
+/// The pointer `IrqData::ptr` is non-null and valid.
+pub struct IrqData {
+    ptr: *mut bindings::irq_data,
+}
+
+impl IrqData {
+    /// Creates a new `IrqData` instance from a raw pointer.
+    ///
+    /// # Safety
+    ///
+    /// Callers must ensure that `ptr` is non-null and valid when the function is called, and that
+    /// it remains valid for the lifetime of the return [`IrqData`] instance.
+    unsafe fn from_ptr(ptr: *mut bindings::irq_data) -> Self {
+        // INVARIANTS: By the safety requirements, the instance we're creating satisfies the type
+        // invariants.
+        Self { ptr }
+    }
+
+    /// Returns the hardware irq number.
+    pub fn hwirq(&self) -> HwNumber {
+        // SAFETY: By the type invariants, it's ok to dereference `ptr`.
+        unsafe { (*self.ptr).hwirq }
+    }
+}
+
+/// Wraps the kernel's `struct irq_data` when it is locked.
+///
+/// Being locked allows additional operations to be performed on the data.
+pub struct LockedIrqData(IrqData);
+
+impl LockedIrqData {
+    /// Sets the high-level irq flow handler to the builtin one for level-triggered irqs.
+    pub fn set_level_handler(&mut self) {
+        // SAFETY: By the type invariants of `self.0`, we know `self.0.ptr` is valid.
+        unsafe { bindings::irq_set_handler_locked(self.0.ptr, Some(bindings::handle_level_irq)) };
+    }
+
+    /// Sets the high-level irq flow handler to the builtin one for edge-triggered irqs.
+    pub fn set_edge_handler(&mut self) {
+        // SAFETY: By the type invariants of `self.0`, we know `self.0.ptr` is valid.
+        unsafe { bindings::irq_set_handler_locked(self.0.ptr, Some(bindings::handle_edge_irq)) };
+    }
+
+    /// Sets the high-level irq flow handler to the builtin one for bad irqs.
+    pub fn set_bad_handler(&mut self) {
+        // SAFETY: By the type invariants of `self.0`, we know `self.0.ptr` is valid.
+        unsafe { bindings::irq_set_handler_locked(self.0.ptr, Some(bindings::handle_bad_irq)) };
+    }
+}
+
+impl Deref for LockedIrqData {
+    type Target = IrqData;
+
+    fn deref(&self) -> &Self::Target {
+        &self.0
+    }
+}
+
+/// Extra information returned by some of the [`Chip`] methods on success.
+pub enum ExtraResult {
+    /// Indicates that the caller (irq core) will update the descriptor state.
+    None = bindings::IRQ_SET_MASK_OK as _,
+
+    /// Indicates that the callee (irq chip implementation) already updated the descriptor state.
+    NoCopy = bindings::IRQ_SET_MASK_OK_NOCOPY as _,
+
+    /// Same as [`ExtraResult::None`] in terms of updating descriptor state. It is used in stacked
+    /// irq chips to indicate that descendant chips should be skipped.
+    Done = bindings::IRQ_SET_MASK_OK_DONE as _,
+}
+
+/// An irq chip.
+///
+/// It is a trait for the functions defined in [`struct irq_chip`].
+///
+/// [`struct irq_chip`]: ../../../include/linux/irq.h
+pub trait Chip: Sized {
+    /// The type of the context data stored in the irq chip and made available on each callback.
+    type Data: PointerWrapper;
+
+    /// The methods to use to populate [`struct irq_chip`]. This is typically populated with
+    /// [`declare_irq_chip_operations`].
+    const TO_USE: ToUse;
+
+    /// Called at the start of a new interrupt.
+    fn ack(data: <Self::Data as PointerWrapper>::Borrowed<'_>, irq_data: &IrqData);
+
+    /// Masks an interrupt source.
+    fn mask(data: <Self::Data as PointerWrapper>::Borrowed<'_>, irq_data: &IrqData);
+
+    /// Unmasks an interrupt source.
+    fn unmask(_data: <Self::Data as PointerWrapper>::Borrowed<'_>, irq_data: &IrqData);
+
+    /// Sets the flow type of an interrupt.
+    ///
+    /// The flow type is a combination of the constants in [`Type`].
+    fn set_type(
+        _data: <Self::Data as PointerWrapper>::Borrowed<'_>,
+        _irq_data: &mut LockedIrqData,
+        _flow_type: u32,
+    ) -> Result<ExtraResult> {
+        Ok(ExtraResult::None)
+    }
+
+    /// Enables or disables power-management wake-on of an interrupt.
+    fn set_wake(
+        _data: <Self::Data as PointerWrapper>::Borrowed<'_>,
+        _irq_data: &IrqData,
+        _on: bool,
+    ) -> Result {
+        Ok(())
+    }
+}
+
+/// Initialises `chip` with the callbacks defined in `T`.
+///
+/// # Safety
+///
+/// The caller must ensure that the value stored in the irq chip data is the result of calling
+/// [`PointerWrapper::into_pointer] for the [`T::Data`] type.
+pub(crate) unsafe fn init_chip<T: Chip>(chip: &mut bindings::irq_chip) {
+    chip.irq_ack = Some(irq_ack_callback::<T>);
+    chip.irq_mask = Some(irq_mask_callback::<T>);
+    chip.irq_unmask = Some(irq_unmask_callback::<T>);
+
+    if T::TO_USE.set_type {
+        chip.irq_set_type = Some(irq_set_type_callback::<T>);
+    }
+
+    if T::TO_USE.set_wake {
+        chip.irq_set_wake = Some(irq_set_wake_callback::<T>);
+    }
+}
+
+/// Represents which fields of [`struct irq_chip`] should be populated with pointers.
+///
+/// This is typically populated with the [`declare_irq_chip_operations`] macro.
+pub struct ToUse {
+    /// The `irq_set_type` field of [`struct irq_chip`].
+    pub set_type: bool,
+
+    /// The `irq_set_wake` field of [`struct irq_chip`].
+    pub set_wake: bool,
+}
+
+/// A constant version where all values are to set to `false`, that is, all supported fields will
+/// be set to null pointers.
+pub const USE_NONE: ToUse = ToUse {
+    set_type: false,
+    set_wake: false,
+};
+
+/// Defines the [`Chip::TO_USE`] field based on a list of fields to be populated.
+#[macro_export]
+macro_rules! declare_irq_chip_operations {
+    () => {
+        const TO_USE: $crate::irq::ToUse = $crate::irq::USE_NONE;
+    };
+    ($($i:ident),+) => {
+        #[allow(clippy::needless_update)]
+        const TO_USE: $crate::irq::ToUse =
+            $crate::irq::ToUse {
+                $($i: true),+ ,
+                ..$crate::irq::USE_NONE
+            };
+    };
+}
+
+/// Enables or disables power-management wake-on for the given irq number.
+pub fn set_wake(irq: u32, on: bool) -> Result {
+    // SAFETY: Just an FFI call, there are no extra requirements for safety.
+    let ret = unsafe { bindings::irq_set_irq_wake(irq, on as _) };
+    if ret < 0 {
+        Err(Error::from_kernel_errno(ret))
+    } else {
+        Ok(())
+    }
+}
+
+unsafe extern "C" fn irq_ack_callback<T: Chip>(irq_data: *mut bindings::irq_data) {
+    // SAFETY: The safety requirements of `init_chip`, which is the only place that uses this
+    // callback, ensure that the value stored as irq chip data comes from a previous call to
+    // `PointerWrapper::into_pointer`.
+    let data = unsafe { T::Data::borrow(bindings::irq_data_get_irq_chip_data(irq_data)) };
+
+    // SAFETY: The value returned by `IrqData` is only valid until the end of this function, and
+    // `irq_data` is guaranteed to be valid until then (by the contract with C code).
+    T::ack(data, unsafe { &IrqData::from_ptr(irq_data) })
+}
+
+unsafe extern "C" fn irq_mask_callback<T: Chip>(irq_data: *mut bindings::irq_data) {
+    // SAFETY: The safety requirements of `init_chip`, which is the only place that uses this
+    // callback, ensure that the value stored as irq chip data comes from a previous call to
+    // `PointerWrapper::into_pointer`.
+    let data = unsafe { T::Data::borrow(bindings::irq_data_get_irq_chip_data(irq_data)) };
+
+    // SAFETY: The value returned by `IrqData` is only valid until the end of this function, and
+    // `irq_data` is guaranteed to be valid until then (by the contract with C code).
+    T::mask(data, unsafe { &IrqData::from_ptr(irq_data) })
+}
+
+unsafe extern "C" fn irq_unmask_callback<T: Chip>(irq_data: *mut bindings::irq_data) {
+    // SAFETY: The safety requirements of `init_chip`, which is the only place that uses this
+    // callback, ensure that the value stored as irq chip data comes from a previous call to
+    // `PointerWrapper::into_pointer`.
+    let data = unsafe { T::Data::borrow(bindings::irq_data_get_irq_chip_data(irq_data)) };
+
+    // SAFETY: The value returned by `IrqData` is only valid until the end of this function, and
+    // `irq_data` is guaranteed to be valid until then (by the contract with C code).
+    T::unmask(data, unsafe { &IrqData::from_ptr(irq_data) })
+}
+
+unsafe extern "C" fn irq_set_type_callback<T: Chip>(
+    irq_data: *mut bindings::irq_data,
+    flow_type: c_types::c_uint,
+) -> c_types::c_int {
+    from_kernel_result! {
+        // SAFETY: The safety requirements of `init_chip`, which is the only place that uses this
+        // callback, ensure that the value stored as irq chip data comes from a previous call to
+        // `PointerWrapper::into_pointer`.
+        let data = unsafe { T::Data::borrow(bindings::irq_data_get_irq_chip_data(irq_data)) };
+
+        // SAFETY: The value returned by `IrqData` is only valid until the end of this function, and
+        // `irq_data` is guaranteed to be valid until then (by the contract with C code).
+        let ret = T::set_type(data, &mut LockedIrqData(unsafe { IrqData::from_ptr(irq_data) }), flow_type)?;
+        Ok(ret as _)
+    }
+}
+
+unsafe extern "C" fn irq_set_wake_callback<T: Chip>(
+    irq_data: *mut bindings::irq_data,
+    on: c_types::c_uint,
+) -> c_types::c_int {
+    from_kernel_result! {
+        // SAFETY: The safety requirements of `init_chip`, which is the only place that uses this
+        // callback, ensure that the value stored as irq chip data comes from a previous call to
+        // `PointerWrapper::into_pointer`.
+        let data = unsafe { T::Data::borrow(bindings::irq_data_get_irq_chip_data(irq_data)) };
+
+        // SAFETY: The value returned by `IrqData` is only valid until the end of this function, and
+        // `irq_data` is guaranteed to be valid until then (by the contract with C code).
+        T::set_wake(data, unsafe { &IrqData::from_ptr(irq_data) }, on != 0)?;
+        Ok(0)
+    }
+}
+
+/// Contains constants that describes how an interrupt can be triggered.
+///
+/// It is tagged with `non_exhaustive` to prevent users from instantiating it.
+#[non_exhaustive]
+pub struct Type;
+
+impl Type {
+    /// The interrupt cannot be triggered.
+    pub const NONE: u32 = bindings::IRQ_TYPE_NONE;
+
+    /// The interrupt is triggered when the signal goes from low to high.
+    pub const EDGE_RISING: u32 = bindings::IRQ_TYPE_EDGE_RISING;
+
+    /// The interrupt is triggered when the signal goes from high to low.
+    pub const EDGE_FALLING: u32 = bindings::IRQ_TYPE_EDGE_FALLING;
+
+    /// The interrupt is triggered when the signal goes from low to high and when it goes to high
+    /// to low.
+    pub const EDGE_BOTH: u32 = bindings::IRQ_TYPE_EDGE_BOTH;
+
+    /// The interrupt is triggered while the signal is held high.
+    pub const LEVEL_HIGH: u32 = bindings::IRQ_TYPE_LEVEL_HIGH;
+
+    /// The interrupt is triggered while the signal is held low.
+    pub const LEVEL_LOW: u32 = bindings::IRQ_TYPE_LEVEL_LOW;
+}
+
+/// Wraps the kernel's `struct irq_desc`.
+///
+/// # Invariants
+///
+/// The pointer `Descriptor::ptr` is non-null and valid.
+pub struct Descriptor {
+    pub(crate) ptr: *mut bindings::irq_desc,
+}
+
+impl Descriptor {
+    /// Constructs a new `struct irq_desc` wrapper.
+    ///
+    /// # Safety
+    ///
+    /// The pointer `ptr` must be non-null and valid for the lifetime of the returned object.
+    unsafe fn from_ptr(ptr: *mut bindings::irq_desc) -> Self {
+        // INVARIANT: The safety requirements ensure the invariant.
+        Self { ptr }
+    }
+
+    /// Calls `chained_irq_enter` and returns a guard that calls `chained_irq_exit` once dropped.
+    ///
+    /// It is meant to be used by chained irq handlers to dispatch irqs to the next handlers.
+    pub fn enter_chained(&self) -> ChainedGuard<'_> {
+        // SAFETY: By the type invariants, `ptr` is always non-null and valid.
+        let irq_chip = unsafe { bindings::irq_desc_get_chip(self.ptr) };
+
+        // SAFETY: By the type invariants, `ptr` is always non-null and valid. `irq_chip` was just
+        // returned from `ptr`, so it is still valid too.
+        unsafe { bindings::chained_irq_enter(irq_chip, self.ptr) };
+        ChainedGuard {
+            desc: self,
+            irq_chip,
+        }
+    }
+}
+
+/// A guard to call `chained_irq_exit` after `chained_irq_enter` was called.
+///
+/// It is also used as evidence that a previous `chained_irq_enter` was called. So there are no
+/// public constructors and it is only created after indeed calling `chained_irq_enter`.
+pub struct ChainedGuard<'a> {
+    desc: &'a Descriptor,
+    irq_chip: *mut bindings::irq_chip,
+}
+
+impl Drop for ChainedGuard<'_> {
+    fn drop(&mut self) {
+        // SAFETY: The lifetime of `ChainedGuard` guarantees that `self.desc` remains valid, so it
+        // also guarantess `irq_chip` (which was returned from it) and `self.desc.ptr` (guaranteed
+        // by the type invariants).
+        unsafe { bindings::chained_irq_exit(self.irq_chip, self.desc.ptr) };
+    }
+}
+
+/// Wraps the kernel's `struct irq_domain`.
+///
+/// # Invariants
+///
+/// The pointer `Domain::ptr` is non-null and valid.
+pub struct Domain {
+    ptr: *mut bindings::irq_domain,
+}
+
+impl Domain {
+    /// Constructs a new `struct irq_domain` wrapper.
+    ///
+    /// # Safety
+    ///
+    /// The pointer `ptr` must be non-null and valid for the lifetime of the returned object.
+    pub(crate) unsafe fn from_ptr(ptr: *mut bindings::irq_domain) -> Self {
+        // INVARIANT: The safety requirements ensure the invariant.
+        Self { ptr }
+    }
+
+    /// Invokes the chained handler of the given hw irq of the given domain.
+    ///
+    /// It requires evidence that `chained_irq_enter` was called, which is done by passing a
+    /// `ChainedGuard` instance.
+    pub fn generic_handle_chained(&self, hwirq: u32, _guard: &ChainedGuard<'_>) {
+        // SAFETY: `ptr` is valid by the type invariants.
+        unsafe { bindings::generic_handle_domain_irq(self.ptr, hwirq) };
+    }
+}
+
+/// A high-level irq flow handler.
+pub trait FlowHandler {
+    /// The data associated with the handler.
+    type Data: PointerWrapper;
+
+    /// Implements the irq flow for the given descriptor.
+    fn handle_irq_flow(data: <Self::Data as PointerWrapper>::Borrowed<'_>, desc: &Descriptor);
+}
+
+/// Returns the raw irq flow handler corresponding to the (high-level) one defined in `T`.
+///
+/// # Safety
+///
+/// The caller must ensure that the value stored in the irq handler data (as returned by
+/// `irq_desc_get_handler_data`) is the result of calling [`PointerWrapper::into_pointer] for the
+/// [`T::Data`] type.
+pub(crate) unsafe fn new_flow_handler<T: FlowHandler>() -> bindings::irq_flow_handler_t {
+    Some(irq_flow_handler::<T>)
+}
+
+unsafe extern "C" fn irq_flow_handler<T: FlowHandler>(desc: *mut bindings::irq_desc) {
+    // SAFETY: By the safety requirements of `new_flow_handler`, we know that the value returned by
+    // `irq_desc_get_handler_data` comes from calling `T::Data::into_pointer`. `desc` is valid by
+    // the C API contract.
+    let data = unsafe { T::Data::borrow(bindings::irq_desc_get_handler_data(desc)) };
+
+    // SAFETY: The C API guarantees that `desc` is valid for the duration of this call, which
+    // outlives the lifetime returned by `from_desc`.
+    T::handle_irq_flow(data, &unsafe { Descriptor::from_ptr(desc) });
+}
diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs
new file mode 100644
index 000000000000..f22ad1ab522f
--- /dev/null
+++ b/rust/kernel/lib.rs
@@ -0,0 +1,261 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! The `kernel` crate.
+//!
+//! This crate contains the kernel APIs that have been ported or wrapped for
+//! usage by Rust code in the kernel and is shared by all of them.
+//!
+//! In other words, all the rest of the Rust code in the kernel (e.g. kernel
+//! modules written in Rust) depends on [`core`], [`alloc`] and this crate.
+//!
+//! If you need a kernel C API that is not ported or wrapped yet here, then
+//! do so first instead of bypassing this crate.
+
+#![no_std]
+#![feature(allocator_api)]
+#![feature(associated_type_defaults)]
+#![feature(concat_idents)]
+#![feature(const_fn_trait_bound)]
+#![feature(const_mut_refs)]
+#![feature(const_ptr_offset_from)]
+#![feature(const_refs_to_cell)]
+#![feature(const_trait_impl)]
+#![feature(doc_cfg)]
+#![feature(generic_associated_types)]
+#![feature(maybe_uninit_extra)]
+#![feature(ptr_metadata)]
+#![feature(receiver_trait)]
+#![feature(coerce_unsized)]
+#![feature(dispatch_from_dyn)]
+#![feature(unsize)]
+
+// Ensure conditional compilation based on the kernel configuration works;
+// otherwise we may silently break things like initcall handling.
+#[cfg(not(CONFIG_RUST))]
+compile_error!("Missing kernel configuration for conditional compilation");
+
+#[cfg(not(test))]
+#[cfg(not(testlib))]
+mod allocator;
+
+#[doc(hidden)]
+pub mod bindings;
+
+#[cfg(CONFIG_ARM_AMBA)]
+pub mod amba;
+pub mod buffer;
+pub mod c_types;
+pub mod chrdev;
+#[cfg(CONFIG_COMMON_CLK)]
+pub mod clk;
+pub mod cred;
+pub mod device;
+pub mod driver;
+mod error;
+pub mod file;
+pub mod file_operations;
+pub mod gpio;
+pub mod irq;
+pub mod miscdev;
+pub mod mm;
+pub mod pages;
+pub mod power;
+pub mod revocable;
+pub mod security;
+pub mod str;
+pub mod task;
+
+pub mod linked_list;
+mod raw_list;
+pub mod rbtree;
+
+#[doc(hidden)]
+pub mod module_param;
+
+mod build_assert;
+pub mod prelude;
+pub mod print;
+pub mod random;
+mod static_assert;
+#[doc(hidden)]
+pub mod std_vendor;
+pub mod sync;
+
+#[cfg(any(CONFIG_SYSCTL, doc))]
+#[doc(cfg(CONFIG_SYSCTL))]
+pub mod sysctl;
+
+pub mod io_buffer;
+pub mod io_mem;
+pub mod iov_iter;
+pub mod of;
+pub mod platform;
+mod types;
+pub mod user_ptr;
+
+#[doc(hidden)]
+pub use build_error::build_error;
+
+pub use crate::error::{to_result, Error, Result};
+pub use crate::types::{bit, bits_iter, Mode, Opaque, ScopeGuard};
+
+use core::marker::PhantomData;
+
+/// Page size defined in terms of the `PAGE_SHIFT` macro from C.
+///
+/// [`PAGE_SHIFT`]: ../../../include/asm-generic/page.h
+pub const PAGE_SIZE: usize = 1 << bindings::PAGE_SHIFT;
+
+/// Prefix to appear before log messages printed from within the kernel crate.
+const __LOG_PREFIX: &[u8] = b"rust_kernel\0";
+
+/// The top level entrypoint to implementing a kernel module.
+///
+/// For any teardown or cleanup operations, your type may implement [`Drop`].
+pub trait KernelModule: Sized + Sync {
+    /// Called at module initialization time.
+    ///
+    /// Use this method to perform whatever setup or registration your module
+    /// should do.
+    ///
+    /// Equivalent to the `module_init` macro in the C API.
+    fn init(name: &'static str::CStr, module: &'static ThisModule) -> Result<Self>;
+}
+
+/// Equivalent to `THIS_MODULE` in the C API.
+///
+/// C header: `include/linux/export.h`
+pub struct ThisModule(*mut bindings::module);
+
+// SAFETY: `THIS_MODULE` may be used from all threads within a module.
+unsafe impl Sync for ThisModule {}
+
+impl ThisModule {
+    /// Creates a [`ThisModule`] given the `THIS_MODULE` pointer.
+    ///
+    /// # Safety
+    ///
+    /// The pointer must be equal to the right `THIS_MODULE`.
+    pub const unsafe fn from_ptr(ptr: *mut bindings::module) -> ThisModule {
+        ThisModule(ptr)
+    }
+
+    /// Locks the module parameters to access them.
+    ///
+    /// Returns a [`KParamGuard`] that will release the lock when dropped.
+    pub fn kernel_param_lock(&self) -> KParamGuard<'_> {
+        // SAFETY: `kernel_param_lock` will check if the pointer is null and
+        // use the built-in mutex in that case.
+        #[cfg(CONFIG_SYSFS)]
+        unsafe {
+            bindings::kernel_param_lock(self.0)
+        }
+
+        KParamGuard {
+            #[cfg(CONFIG_SYSFS)]
+            this_module: self,
+            phantom: PhantomData,
+        }
+    }
+}
+
+/// Scoped lock on the kernel parameters of [`ThisModule`].
+///
+/// Lock will be released when this struct is dropped.
+pub struct KParamGuard<'a> {
+    #[cfg(CONFIG_SYSFS)]
+    this_module: &'a ThisModule,
+    phantom: PhantomData<&'a ()>,
+}
+
+#[cfg(CONFIG_SYSFS)]
+impl<'a> Drop for KParamGuard<'a> {
+    fn drop(&mut self) {
+        // SAFETY: `kernel_param_lock` will check if the pointer is null and
+        // use the built-in mutex in that case. The existance of `self`
+        // guarantees that the lock is held.
+        unsafe { bindings::kernel_param_unlock(self.this_module.0) }
+    }
+}
+
+/// Calculates the offset of a field from the beginning of the struct it belongs to.
+///
+/// # Example
+///
+/// ```
+/// # use kernel::prelude::*;
+/// # use kernel::offset_of;
+/// struct Test {
+///     a: u64,
+///     b: u32,
+/// }
+///
+/// fn test() {
+///     // This prints `8`.
+///     pr_info!("{}\n", offset_of!(Test, b));
+/// }
+/// ```
+#[macro_export]
+macro_rules! offset_of {
+    ($type:ty, $($f:tt)*) => {{
+        let tmp = core::mem::MaybeUninit::<$type>::uninit();
+        let outer = tmp.as_ptr();
+        // To avoid warnings when nesting `unsafe` blocks.
+        #[allow(unused_unsafe)]
+        // SAFETY: The pointer is valid and aligned, just not initialised; `addr_of` ensures that
+        // we don't actually read from `outer` (which would be UB) nor create an intermediate
+        // reference.
+        let inner = unsafe { core::ptr::addr_of!((*outer).$($f)*) } as *const u8;
+        // To avoid warnings when nesting `unsafe` blocks.
+        #[allow(unused_unsafe)]
+        // SAFETY: The two pointers are within the same allocation block.
+        unsafe { inner.offset_from(outer as *const u8) }
+    }}
+}
+
+/// Produces a pointer to an object from a pointer to one of its fields.
+///
+/// # Safety
+///
+/// Callers must ensure that the pointer to the field is in fact a pointer to the specified field,
+/// as opposed to a pointer to another object of the same type. If this condition is not met,
+/// any dereference of the resulting pointer is UB.
+///
+/// # Example
+///
+/// ```
+/// # use kernel::prelude::*;
+/// # use kernel::container_of;
+/// struct Test {
+///     a: u64,
+///     b: u32,
+/// }
+///
+/// fn test() {
+///     let test = Test { a: 10, b: 20 };
+///     let b_ptr = &test.b;
+///     let test_alias = container_of!(b_ptr, Test, b);
+///     // This prints `true`.
+///     pr_info!("{}\n", core::ptr::eq(&test, test_alias));
+/// }
+/// ```
+#[macro_export]
+macro_rules! container_of {
+    ($ptr:expr, $type:ty, $($f:tt)*) => {{
+        let ptr = $ptr as *const _ as *const u8;
+        let offset = $crate::offset_of!($type, $($f)*);
+        ptr.wrapping_offset(-offset) as *const $type
+    }}
+}
+
+#[cfg(not(any(testlib, test)))]
+#[panic_handler]
+fn panic(info: &core::panic::PanicInfo<'_>) -> ! {
+    pr_emerg!("{}\n", info);
+    // SAFETY: FFI call.
+    unsafe { bindings::BUG() };
+    // Bindgen currently does not recognize `__noreturn` so `BUG` returns `()`
+    // instead of `!`.
+    // https://github.com/rust-lang/rust-bindgen/issues/2094
+    loop {}
+}
diff --git a/rust/kernel/linked_list.rs b/rust/kernel/linked_list.rs
new file mode 100644
index 000000000000..3330edcc7ca8
--- /dev/null
+++ b/rust/kernel/linked_list.rs
@@ -0,0 +1,247 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Linked lists.
+//!
+//! TODO: This module is a work in progress.
+
+use alloc::boxed::Box;
+use core::ptr::NonNull;
+
+pub use crate::raw_list::{Cursor, GetLinks, Links};
+use crate::{raw_list, raw_list::RawList, sync::Ref};
+
+// TODO: Use the one from `kernel::file_operations::PointerWrapper` instead.
+/// Wraps an object to be inserted in a linked list.
+pub trait Wrapper<T: ?Sized> {
+    /// Converts the wrapped object into a pointer that represents it.
+    fn into_pointer(self) -> NonNull<T>;
+
+    /// Converts the object back from the pointer representation.
+    ///
+    /// # Safety
+    ///
+    /// The passed pointer must come from a previous call to [`Wrapper::into_pointer()`].
+    unsafe fn from_pointer(ptr: NonNull<T>) -> Self;
+
+    /// Returns a reference to the wrapped object.
+    fn as_ref(&self) -> &T;
+}
+
+impl<T: ?Sized> Wrapper<T> for Box<T> {
+    fn into_pointer(self) -> NonNull<T> {
+        NonNull::new(Box::into_raw(self)).unwrap()
+    }
+
+    unsafe fn from_pointer(ptr: NonNull<T>) -> Self {
+        unsafe { Box::from_raw(ptr.as_ptr()) }
+    }
+
+    fn as_ref(&self) -> &T {
+        AsRef::as_ref(self)
+    }
+}
+
+impl<T: ?Sized> Wrapper<T> for Ref<T> {
+    fn into_pointer(self) -> NonNull<T> {
+        NonNull::new(Ref::into_raw(self) as _).unwrap()
+    }
+
+    unsafe fn from_pointer(ptr: NonNull<T>) -> Self {
+        // SAFETY: The safety requirements of `from_pointer` satisfy the ones from `Ref::from_raw`.
+        unsafe { Ref::from_raw(ptr.as_ptr() as _) }
+    }
+
+    fn as_ref(&self) -> &T {
+        AsRef::as_ref(self)
+    }
+}
+
+impl<T: ?Sized> Wrapper<T> for &T {
+    fn into_pointer(self) -> NonNull<T> {
+        NonNull::from(self)
+    }
+
+    unsafe fn from_pointer(ptr: NonNull<T>) -> Self {
+        unsafe { &*ptr.as_ptr() }
+    }
+
+    fn as_ref(&self) -> &T {
+        self
+    }
+}
+
+/// A descriptor of wrapped list elements.
+pub trait GetLinksWrapped: GetLinks {
+    /// Specifies which wrapper (e.g., `Box` and `Arc`) wraps the list entries.
+    type Wrapped: Wrapper<Self::EntryType>;
+}
+
+impl<T: ?Sized> GetLinksWrapped for Box<T>
+where
+    Box<T>: GetLinks,
+{
+    type Wrapped = Box<<Box<T> as GetLinks>::EntryType>;
+}
+
+impl<T: GetLinks + ?Sized> GetLinks for Box<T> {
+    type EntryType = T::EntryType;
+    fn get_links(data: &Self::EntryType) -> &Links<Self::EntryType> {
+        <T as GetLinks>::get_links(data)
+    }
+}
+
+impl<T: ?Sized> GetLinksWrapped for Ref<T>
+where
+    Ref<T>: GetLinks,
+{
+    type Wrapped = Ref<<Ref<T> as GetLinks>::EntryType>;
+}
+
+impl<T: GetLinks + ?Sized> GetLinks for Ref<T> {
+    type EntryType = T::EntryType;
+
+    fn get_links(data: &Self::EntryType) -> &Links<Self::EntryType> {
+        <T as GetLinks>::get_links(data)
+    }
+}
+
+/// A linked list.
+///
+/// Elements in the list are wrapped and ownership is transferred to the list while the element is
+/// in the list.
+pub struct List<G: GetLinksWrapped> {
+    list: RawList<G>,
+}
+
+impl<G: GetLinksWrapped> List<G> {
+    /// Constructs a new empty linked list.
+    pub fn new() -> Self {
+        Self {
+            list: RawList::new(),
+        }
+    }
+
+    /// Returns whether the list is empty.
+    pub fn is_empty(&self) -> bool {
+        self.list.is_empty()
+    }
+
+    /// Adds the given object to the end (back) of the list.
+    ///
+    /// It is dropped if it's already on this (or another) list; this can happen for
+    /// reference-counted objects, so dropping means decrementing the reference count.
+    pub fn push_back(&mut self, data: G::Wrapped) {
+        let ptr = data.into_pointer();
+
+        // SAFETY: We took ownership of the entry, so it is safe to insert it.
+        if !unsafe { self.list.push_back(ptr.as_ref()) } {
+            // If insertion failed, rebuild object so that it can be freed.
+            // SAFETY: We just called `into_pointer` above.
+            unsafe { G::Wrapped::from_pointer(ptr) };
+        }
+    }
+
+    /// Inserts the given object after `existing`.
+    ///
+    /// It is dropped if it's already on this (or another) list; this can happen for
+    /// reference-counted objects, so dropping means decrementing the reference count.
+    ///
+    /// # Safety
+    ///
+    /// Callers must ensure that `existing` points to a valid entry that is on the list.
+    pub unsafe fn insert_after(&mut self, existing: NonNull<G::EntryType>, data: G::Wrapped) {
+        let ptr = data.into_pointer();
+        let entry = unsafe { &*existing.as_ptr() };
+        if unsafe { !self.list.insert_after(entry, ptr.as_ref()) } {
+            // If insertion failed, rebuild object so that it can be freed.
+            unsafe { G::Wrapped::from_pointer(ptr) };
+        }
+    }
+
+    /// Removes the given entry.
+    ///
+    /// # Safety
+    ///
+    /// Callers must ensure that `data` is either on this list or in no list. It being on another
+    /// list leads to memory unsafety.
+    pub unsafe fn remove(&mut self, data: &G::Wrapped) -> Option<G::Wrapped> {
+        let entry_ref = Wrapper::as_ref(data);
+        if unsafe { self.list.remove(entry_ref) } {
+            Some(unsafe { G::Wrapped::from_pointer(NonNull::from(entry_ref)) })
+        } else {
+            None
+        }
+    }
+
+    /// Removes the element currently at the front of the list and returns it.
+    ///
+    /// Returns `None` if the list is empty.
+    pub fn pop_front(&mut self) -> Option<G::Wrapped> {
+        let front = self.list.pop_front()?;
+        // SAFETY: Elements on the list were inserted after a call to `into_pointer `.
+        Some(unsafe { G::Wrapped::from_pointer(front) })
+    }
+
+    /// Returns a cursor starting on the first (front) element of the list.
+    pub fn cursor_front(&self) -> Cursor<'_, G> {
+        self.list.cursor_front()
+    }
+
+    /// Returns a mutable cursor starting on the first (front) element of the list.
+    pub fn cursor_front_mut(&mut self) -> CursorMut<'_, G> {
+        CursorMut::new(self.list.cursor_front_mut())
+    }
+}
+
+impl<G: GetLinksWrapped> Default for List<G> {
+    fn default() -> Self {
+        Self::new()
+    }
+}
+
+impl<G: GetLinksWrapped> Drop for List<G> {
+    fn drop(&mut self) {
+        while self.pop_front().is_some() {}
+    }
+}
+
+/// A list cursor that allows traversing a linked list and inspecting & mutating elements.
+pub struct CursorMut<'a, G: GetLinksWrapped> {
+    cursor: raw_list::CursorMut<'a, G>,
+}
+
+impl<'a, G: GetLinksWrapped> CursorMut<'a, G> {
+    fn new(cursor: raw_list::CursorMut<'a, G>) -> Self {
+        Self { cursor }
+    }
+
+    /// Returns the element the cursor is currently positioned on.
+    pub fn current(&mut self) -> Option<&mut G::EntryType> {
+        self.cursor.current()
+    }
+
+    /// Removes the element the cursor is currently positioned on.
+    ///
+    /// After removal, it advances the cursor to the next element.
+    pub fn remove_current(&mut self) -> Option<G::Wrapped> {
+        let ptr = self.cursor.remove_current()?;
+
+        // SAFETY: Elements on the list were inserted after a call to `into_pointer `.
+        Some(unsafe { G::Wrapped::from_pointer(ptr) })
+    }
+
+    /// Returns the element immediately after the one the cursor is positioned on.
+    pub fn peek_next(&mut self) -> Option<&mut G::EntryType> {
+        self.cursor.peek_next()
+    }
+
+    /// Returns the element immediately before the one the cursor is positioned on.
+    pub fn peek_prev(&mut self) -> Option<&mut G::EntryType> {
+        self.cursor.peek_prev()
+    }
+
+    /// Moves the cursor to the next element.
+    pub fn move_next(&mut self) {
+        self.cursor.move_next();
+    }
+}
diff --git a/rust/kernel/miscdev.rs b/rust/kernel/miscdev.rs
new file mode 100644
index 000000000000..8ec30a18059e
--- /dev/null
+++ b/rust/kernel/miscdev.rs
@@ -0,0 +1,281 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Miscellaneous devices.
+//!
+//! C header: [`include/linux/miscdevice.h`](../../../../include/linux/miscdevice.h)
+//!
+//! Reference: <https://www.kernel.org/doc/html/latest/driver-api/misc_devices.html>
+
+use crate::bindings;
+use crate::error::{Error, Result};
+use crate::file_operations::{FileOpenAdapter, FileOperations, FileOperationsVtable};
+use crate::{device, str::CStr, KernelModule, ThisModule};
+use alloc::boxed::Box;
+use core::marker::PhantomPinned;
+use core::{mem::MaybeUninit, pin::Pin};
+
+/// Options which can be used to configure how a misc device is registered.
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::{c_str, device::RawDevice, file_operations::FileOperations, miscdev, prelude::*};
+/// pub fn example(
+///     reg: Pin<&mut miscdev::Registration<impl FileOperations<OpenData = ()>>>,
+///     parent: &dyn RawDevice,
+/// ) -> Result {
+///     miscdev::Options::new()
+///         .mode(0o600)
+///         .minor(10)
+///         .parent(parent)
+///         .register(reg, c_str!("sample"), ())
+/// }
+/// ```
+#[derive(Default)]
+pub struct Options<'a> {
+    minor: Option<i32>,
+    mode: Option<u16>,
+    parent: Option<&'a dyn device::RawDevice>,
+}
+
+impl<'a> Options<'a> {
+    /// Creates new [`Options`] instance with the required fields.
+    pub const fn new() -> Self {
+        Self {
+            minor: None,
+            mode: None,
+            parent: None,
+        }
+    }
+
+    /// Sets the minor device number.
+    pub const fn minor(&mut self, v: i32) -> &mut Self {
+        self.minor = Some(v);
+        self
+    }
+
+    /// Sets the device mode.
+    ///
+    /// This is usually an octal number and describes who can perform read/write/execute operations
+    /// on the device.
+    pub const fn mode(&mut self, m: u16) -> &mut Self {
+        self.mode = Some(m);
+        self
+    }
+
+    /// Sets the device parent.
+    pub const fn parent(&mut self, p: &'a dyn device::RawDevice) -> &mut Self {
+        self.parent = Some(p);
+        self
+    }
+
+    /// Registers a misc device using the configured options.
+    pub fn register<T: FileOperations>(
+        &self,
+        reg: Pin<&mut Registration<T>>,
+        name: &'static CStr,
+        open_data: T::OpenData,
+    ) -> Result {
+        reg.register_with_options(name, open_data, self)
+    }
+
+    /// Allocates a new registration of a misc device and completes the registration with the
+    /// configured options.
+    pub fn register_new<T: FileOperations>(
+        &self,
+        name: &'static CStr,
+        open_data: T::OpenData,
+    ) -> Result<Pin<Box<Registration<T>>>> {
+        let mut r = Pin::from(Box::try_new(Registration::new())?);
+        self.register(r.as_mut(), name, open_data)?;
+        Ok(r)
+    }
+}
+
+/// A registration of a miscellaneous device.
+///
+/// # Invariants
+///
+/// `Context` is always initialised when `registered` is `true`, and not initialised otherwise.
+pub struct Registration<T: FileOperations> {
+    registered: bool,
+    mdev: bindings::miscdevice,
+    _pin: PhantomPinned,
+
+    /// Context initialised on construction and made available to all file instances on
+    /// [`FileOperations::open`].
+    open_data: MaybeUninit<T::OpenData>,
+}
+
+impl<T: FileOperations> Registration<T> {
+    /// Creates a new [`Registration`] but does not register it yet.
+    ///
+    /// It is allowed to move.
+    pub fn new() -> Self {
+        // INVARIANT: `registered` is `false` and `open_data` is not initialised.
+        Self {
+            registered: false,
+            mdev: bindings::miscdevice::default(),
+            _pin: PhantomPinned,
+            open_data: MaybeUninit::uninit(),
+        }
+    }
+
+    /// Registers a miscellaneous device.
+    ///
+    /// Returns a pinned heap-allocated representation of the registration.
+    pub fn new_pinned(name: &'static CStr, open_data: T::OpenData) -> Result<Pin<Box<Self>>> {
+        Options::new().register_new(name, open_data)
+    }
+
+    /// Registers a miscellaneous device with the rest of the kernel.
+    ///
+    /// It must be pinned because the memory block that represents the registration is
+    /// self-referential.
+    pub fn register(self: Pin<&mut Self>, name: &'static CStr, open_data: T::OpenData) -> Result {
+        Options::new().register(self, name, open_data)
+    }
+
+    /// Registers a miscellaneous device with the rest of the kernel. Additional optional settings
+    /// are provided via the `opts` parameter.
+    ///
+    /// It must be pinned because the memory block that represents the registration is
+    /// self-referential.
+    pub fn register_with_options(
+        self: Pin<&mut Self>,
+        name: &'static CStr,
+        open_data: T::OpenData,
+        opts: &Options<'_>,
+    ) -> Result {
+        // SAFETY: We must ensure that we never move out of `this`.
+        let this = unsafe { self.get_unchecked_mut() };
+        if this.registered {
+            // Already registered.
+            return Err(Error::EINVAL);
+        }
+
+        // SAFETY: The adapter is compatible with `misc_register`.
+        this.mdev.fops = unsafe { FileOperationsVtable::<Self, T>::build() };
+        this.mdev.name = name.as_char_ptr();
+        this.mdev.minor = opts.minor.unwrap_or(bindings::MISC_DYNAMIC_MINOR as i32);
+        this.mdev.mode = opts.mode.unwrap_or(0);
+        this.mdev.parent = opts
+            .parent
+            .map_or(core::ptr::null_mut(), |p| p.raw_device());
+
+        // We write to `open_data` here because as soon as `misc_register` succeeds, the file can be
+        // opened, so we need `open_data` configured ahead of time.
+        //
+        // INVARIANT: `registered` is set to `true`, but `open_data` is also initialised.
+        this.registered = true;
+        this.open_data.write(open_data);
+
+        let ret = unsafe { bindings::misc_register(&mut this.mdev) };
+        if ret < 0 {
+            // INVARIANT: `registered` is set back to `false` and the `open_data` is destructued.
+            this.registered = false;
+            // SAFETY: `open_data` was initialised a few lines above.
+            unsafe { this.open_data.assume_init_drop() };
+            return Err(Error::from_kernel_errno(ret));
+        }
+
+        Ok(())
+    }
+}
+
+impl<T: FileOperations> Default for Registration<T> {
+    fn default() -> Self {
+        Self::new()
+    }
+}
+
+impl<T: FileOperations> FileOpenAdapter<T::OpenData> for Registration<T> {
+    unsafe fn convert(
+        _inode: *mut bindings::inode,
+        file: *mut bindings::file,
+    ) -> *const T::OpenData {
+        // SAFETY: The caller must guarantee that `file` is valid.
+        let reg = crate::container_of!(unsafe { (*file).private_data }, Self, mdev);
+
+        // SAFETY: This function is only called while the misc device is still registered, so the
+        // registration must be valid. Additionally, the type invariants guarantee that while the
+        // miscdev is registered, `open_data` is initialised.
+        unsafe { (*reg).open_data.as_ptr() }
+    }
+}
+
+// SAFETY: The only method is `register()`, which requires a (pinned) mutable `Registration`, so it
+// is safe to pass `&Registration` to multiple threads because it offers no interior mutability.
+unsafe impl<T: FileOperations> Sync for Registration<T> {}
+
+// SAFETY: All functions work from any thread. So as long as the `Registration::open_data` is
+// `Send`, so is `Registration<T>`.
+unsafe impl<T: FileOperations> Send for Registration<T> where T::OpenData: Send {}
+
+impl<T: FileOperations> Drop for Registration<T> {
+    /// Removes the registration from the kernel if it has completed successfully before.
+    fn drop(&mut self) {
+        if self.registered {
+            // SAFETY: `registered` being `true` indicates that a previous call to  `misc_register`
+            // succeeded.
+            unsafe { bindings::misc_deregister(&mut self.mdev) };
+
+            // SAFETY: The type invariant guarantees that `open_data` is initialised when
+            // `registered` is `true`.
+            unsafe { self.open_data.assume_init_drop() };
+        }
+    }
+}
+
+/// Kernel module that exposes a single miscdev device implemented by `T`.
+pub struct Module<T: FileOperations<OpenData = ()>> {
+    _dev: Pin<Box<Registration<T>>>,
+}
+
+impl<T: FileOperations<OpenData = ()>> KernelModule for Module<T> {
+    fn init(name: &'static CStr, _module: &'static ThisModule) -> Result<Self> {
+        Ok(Self {
+            _dev: Registration::new_pinned(name, ())?,
+        })
+    }
+}
+
+/// Declares a kernel module that exposes a single misc device.
+///
+/// The `type` argument should be a type which implements the [`FileOpener`] trait. Also accepts
+/// various forms of kernel metadata.
+///
+/// C header: [`include/linux/moduleparam.h`](../../../include/linux/moduleparam.h)
+///
+/// [`FileOpener`]: ../kernel/file_operations/trait.FileOpener.html
+///
+/// # Examples
+///
+/// ```ignore
+/// use kernel::prelude::*;
+///
+/// module_misc_device! {
+///     type: MyFile,
+///     name: b"my_miscdev_kernel_module",
+///     author: b"Rust for Linux Contributors",
+///     description: b"My very own misc device kernel module!",
+///     license: b"GPL v2",
+/// }
+///
+/// #[derive(Default)]
+/// struct MyFile;
+///
+/// impl kernel::file_operations::FileOperations for MyFile {
+///     kernel::declare_file_operations!();
+/// }
+/// ```
+#[macro_export]
+macro_rules! module_misc_device {
+    (type: $type:ty, $($f:tt)*) => {
+        type ModuleType = kernel::miscdev::Module<$type>;
+        module! {
+            type: ModuleType,
+            $($f)*
+        }
+    }
+}
diff --git a/rust/kernel/mm.rs b/rust/kernel/mm.rs
new file mode 100644
index 000000000000..322f94f501e0
--- /dev/null
+++ b/rust/kernel/mm.rs
@@ -0,0 +1,149 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Memory management.
+//!
+//! C header: [`include/linux/mm.h`](../../../../include/linux/mm.h)
+
+use crate::{bindings, pages, to_result, Result};
+
+/// Virtual memory.
+pub mod virt {
+    use super::*;
+
+    /// A wrapper for the kernel's `struct vm_area_struct`.
+    ///
+    /// It represents an area of virtual memory.
+    ///
+    /// # Invariants
+    ///
+    /// `vma` is always non-null and valid.
+    pub struct Area {
+        vma: *mut bindings::vm_area_struct,
+    }
+
+    impl Area {
+        /// Creates a new instance of a virtual memory area.
+        ///
+        /// # Safety
+        ///
+        /// Callers must ensure that `vma` is non-null and valid for the duration of the new area's
+        /// lifetime.
+        pub(crate) unsafe fn from_ptr(vma: *mut bindings::vm_area_struct) -> Self {
+            // INVARIANTS: The safety requirements guarantee the invariants.
+            Self { vma }
+        }
+
+        /// Returns the flags associated with the virtual memory area.
+        ///
+        /// The possible flags are a combination of the constants in [`flags`].
+        pub fn flags(&self) -> usize {
+            // SAFETY: `self.vma` is valid by the type invariants.
+            unsafe { (*self.vma).vm_flags as _ }
+        }
+
+        /// Sets the flags associated with the virtual memory area.
+        ///
+        /// The possible flags are a combination of the constants in [`flags`].
+        pub fn set_flags(&mut self, flags: usize) {
+            // SAFETY: `self.vma` is valid by the type invariants.
+            unsafe { (*self.vma).vm_flags = flags as _ };
+        }
+
+        /// Returns the start address of the virtual memory area.
+        pub fn start(&self) -> usize {
+            // SAFETY: `self.vma` is valid by the type invariants.
+            unsafe { (*self.vma).vm_start as _ }
+        }
+
+        /// Returns the end address of the virtual memory area.
+        pub fn end(&self) -> usize {
+            // SAFETY: `self.vma` is valid by the type invariants.
+            unsafe { (*self.vma).vm_end as _ }
+        }
+
+        /// Maps a single page at the given address within the virtual memory area.
+        pub fn insert_page(&mut self, address: usize, page: &pages::Pages<0>) -> Result {
+            // SAFETY: The page is guaranteed to be order 0 by the type system. The range of
+            // `address` is already checked by `vm_insert_page`. `self.vma` and `page.pages` are
+            // guaranteed by their repective type invariants to be valid.
+            to_result(|| unsafe { bindings::vm_insert_page(self.vma, address as _, page.pages) })
+        }
+    }
+
+    /// Container for [`Area`] flags.
+    pub mod flags {
+        use crate::bindings;
+
+        /// No flags are set.
+        pub const NONE: usize = bindings::VM_NONE as _;
+
+        /// Mapping allows reads.
+        pub const READ: usize = bindings::VM_READ as _;
+
+        /// Mapping allows writes.
+        pub const WRITE: usize = bindings::VM_WRITE as _;
+
+        /// Mapping allows execution.
+        pub const EXEC: usize = bindings::VM_EXEC as _;
+
+        /// Mapping is shared.
+        pub const SHARED: usize = bindings::VM_SHARED as _;
+
+        /// Mapping may be updated to allow reads.
+        pub const MAYREAD: usize = bindings::VM_MAYREAD as _;
+
+        /// Mapping may be updated to allow writes.
+        pub const MAYWRITE: usize = bindings::VM_MAYWRITE as _;
+
+        /// Mapping may be updated to allow execution.
+        pub const MAYEXEC: usize = bindings::VM_MAYEXEC as _;
+
+        /// Mapping may be updated to be shared.
+        pub const MAYSHARE: usize = bindings::VM_MAYSHARE as _;
+
+        /// Do not copy this vma on fork.
+        pub const DONTCOPY: usize = bindings::VM_DONTCOPY as _;
+
+        /// Cannot expand with mremap().
+        pub const DONTEXPAND: usize = bindings::VM_DONTEXPAND as _;
+
+        /// Lock the pages covered when they are faulted in.
+        pub const LOCKONFAULT: usize = bindings::VM_LOCKONFAULT as _;
+
+        /// Is a VM accounted object.
+        pub const ACCOUNT: usize = bindings::VM_ACCOUNT as _;
+
+        /// should the VM suppress accounting.
+        pub const NORESERVE: usize = bindings::VM_NORESERVE as _;
+
+        /// Huge TLB Page VM.
+        pub const HUGETLB: usize = bindings::VM_HUGETLB as _;
+
+        /// Synchronous page faults.
+        pub const SYNC: usize = bindings::VM_SYNC as _;
+
+        /// Architecture-specific flag.
+        pub const ARCH_1: usize = bindings::VM_ARCH_1 as _;
+
+        /// Wipe VMA contents in child..
+        pub const WIPEONFORK: usize = bindings::VM_WIPEONFORK as _;
+
+        /// Do not include in the core dump.
+        pub const DONTDUMP: usize = bindings::VM_DONTDUMP as _;
+
+        /// Not soft dirty clean area.
+        pub const SOFTDIRTY: usize = bindings::VM_SOFTDIRTY as _;
+
+        /// Can contain "struct page" and pure PFN pages.
+        pub const MIXEDMAP: usize = bindings::VM_MIXEDMAP as _;
+
+        /// MADV_HUGEPAGE marked this vma.
+        pub const HUGEPAGE: usize = bindings::VM_HUGEPAGE as _;
+
+        /// MADV_NOHUGEPAGE marked this vma.
+        pub const NOHUGEPAGE: usize = bindings::VM_NOHUGEPAGE as _;
+
+        /// KSM may merge identical pages.
+        pub const MERGEABLE: usize = bindings::VM_MERGEABLE as _;
+    }
+}
diff --git a/rust/kernel/module_param.rs b/rust/kernel/module_param.rs
new file mode 100644
index 000000000000..a588449c41fa
--- /dev/null
+++ b/rust/kernel/module_param.rs
@@ -0,0 +1,497 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Types for module parameters.
+//!
+//! C header: [`include/linux/moduleparam.h`](../../../include/linux/moduleparam.h)
+
+use crate::str::CStr;
+use core::fmt::Write;
+
+/// Types that can be used for module parameters.
+///
+/// Note that displaying the type in `sysfs` will fail if
+/// [`alloc::string::ToString::to_string`] (as implemented through the
+/// [`core::fmt::Display`] trait) writes more than [`PAGE_SIZE`]
+/// bytes (including an additional null terminator).
+///
+/// [`PAGE_SIZE`]: `crate::PAGE_SIZE`
+pub trait ModuleParam: core::fmt::Display + core::marker::Sized {
+    /// The `ModuleParam` will be used by the kernel module through this type.
+    ///
+    /// This may differ from `Self` if, for example, `Self` needs to track
+    /// ownership without exposing it or allocate extra space for other possible
+    /// parameter values. See [`StringParam`] or [`ArrayParam`] for examples.
+    type Value: ?Sized;
+
+    /// Whether the parameter is allowed to be set without an argument.
+    ///
+    /// Setting this to `true` allows the parameter to be passed without an
+    /// argument (e.g. just `module.param` instead of `module.param=foo`).
+    const NOARG_ALLOWED: bool;
+
+    /// Convert a parameter argument into the parameter value.
+    ///
+    /// `None` should be returned when parsing of the argument fails.
+    /// `arg == None` indicates that the parameter was passed without an
+    /// argument. If `NOARG_ALLOWED` is set to `false` then `arg` is guaranteed
+    /// to always be `Some(_)`.
+    ///
+    /// Parameters passed at boot time will be set before [`kmalloc`] is
+    /// available (even if the module is loaded at a later time). However, in
+    /// this case, the argument buffer will be valid for the entire lifetime of
+    /// the kernel. So implementations of this method which need to allocate
+    /// should first check that the allocator is available (with
+    /// [`crate::bindings::slab_is_available`]) and when it is not available
+    /// provide an alternative implementation which doesn't allocate. In cases
+    /// where the allocator is not available it is safe to save references to
+    /// `arg` in `Self`, but in other cases a copy should be made.
+    ///
+    /// [`kmalloc`]: ../../../include/linux/slab.h
+    fn try_from_param_arg(arg: Option<&'static [u8]>) -> Option<Self>;
+
+    /// Get the current value of the parameter for use in the kernel module.
+    ///
+    /// This function should not be used directly. Instead use the wrapper
+    /// `read` which will be generated by [`macros::module`].
+    fn value(&self) -> &Self::Value;
+
+    /// Set the module parameter from a string.
+    ///
+    /// Used to set the parameter value when loading the module or when set
+    /// through `sysfs`.
+    ///
+    /// # Safety
+    ///
+    /// If `val` is non-null then it must point to a valid null-terminated
+    /// string. The `arg` field of `param` must be an instance of `Self`.
+    unsafe extern "C" fn set_param(
+        val: *const crate::c_types::c_char,
+        param: *const crate::bindings::kernel_param,
+    ) -> crate::c_types::c_int {
+        let arg = if val.is_null() {
+            None
+        } else {
+            Some(unsafe { CStr::from_char_ptr(val).as_bytes() })
+        };
+        match Self::try_from_param_arg(arg) {
+            Some(new_value) => {
+                let old_value = unsafe { (*param).__bindgen_anon_1.arg as *mut Self };
+                let _ = unsafe { core::ptr::replace(old_value, new_value) };
+                0
+            }
+            None => crate::error::Error::EINVAL.to_kernel_errno(),
+        }
+    }
+
+    /// Write a string representation of the current parameter value to `buf`.
+    ///
+    /// Used for displaying the current parameter value in `sysfs`.
+    ///
+    /// # Safety
+    ///
+    /// `buf` must be a buffer of length at least `kernel::PAGE_SIZE` that is
+    /// writeable. The `arg` field of `param` must be an instance of `Self`.
+    unsafe extern "C" fn get_param(
+        buf: *mut crate::c_types::c_char,
+        param: *const crate::bindings::kernel_param,
+    ) -> crate::c_types::c_int {
+        let slice = unsafe { core::slice::from_raw_parts_mut(buf as *mut u8, crate::PAGE_SIZE) };
+        let mut buf = crate::buffer::Buffer::new(slice);
+        match unsafe { write!(buf, "{}\0", *((*param).__bindgen_anon_1.arg as *mut Self)) } {
+            Err(_) => crate::error::Error::EINVAL.to_kernel_errno(),
+            Ok(()) => buf.bytes_written() as crate::c_types::c_int,
+        }
+    }
+
+    /// Drop the parameter.
+    ///
+    /// Called when unloading a module.
+    ///
+    /// # Safety
+    ///
+    /// The `arg` field of `param` must be an instance of `Self`.
+    unsafe extern "C" fn free(arg: *mut crate::c_types::c_void) {
+        unsafe { core::ptr::drop_in_place(arg as *mut Self) };
+    }
+}
+
+/// Trait for parsing integers.
+///
+/// Strings begining with `0x`, `0o`, or `0b` are parsed as hex, octal, or
+/// binary respectively. Strings beginning with `0` otherwise are parsed as
+/// octal. Anything else is parsed as decimal. A leading `+` or `-` is also
+/// permitted. Any string parsed by [`kstrtol()`] or [`kstrtoul()`] will be
+/// successfully parsed.
+///
+/// [`kstrtol()`]: https://www.kernel.org/doc/html/latest/core-api/kernel-api.html#c.kstrtol
+/// [`kstrtoul()`]: https://www.kernel.org/doc/html/latest/core-api/kernel-api.html#c.kstrtoul
+trait ParseInt: Sized {
+    fn from_str_radix(src: &str, radix: u32) -> Result<Self, core::num::ParseIntError>;
+    fn checked_neg(self) -> Option<Self>;
+
+    fn from_str_unsigned(src: &str) -> Result<Self, core::num::ParseIntError> {
+        let (radix, digits) = if let Some(n) = src.strip_prefix("0x") {
+            (16, n)
+        } else if let Some(n) = src.strip_prefix("0X") {
+            (16, n)
+        } else if let Some(n) = src.strip_prefix("0o") {
+            (8, n)
+        } else if let Some(n) = src.strip_prefix("0O") {
+            (8, n)
+        } else if let Some(n) = src.strip_prefix("0b") {
+            (2, n)
+        } else if let Some(n) = src.strip_prefix("0B") {
+            (2, n)
+        } else if src.starts_with('0') {
+            (8, src)
+        } else {
+            (10, src)
+        };
+        Self::from_str_radix(digits, radix)
+    }
+
+    fn from_str(src: &str) -> Option<Self> {
+        match src.bytes().next() {
+            None => None,
+            Some(b'-') => Self::from_str_unsigned(&src[1..]).ok()?.checked_neg(),
+            Some(b'+') => Some(Self::from_str_unsigned(&src[1..]).ok()?),
+            Some(_) => Some(Self::from_str_unsigned(src).ok()?),
+        }
+    }
+}
+
+macro_rules! impl_parse_int {
+    ($ty:ident) => {
+        impl ParseInt for $ty {
+            fn from_str_radix(src: &str, radix: u32) -> Result<Self, core::num::ParseIntError> {
+                $ty::from_str_radix(src, radix)
+            }
+
+            fn checked_neg(self) -> Option<Self> {
+                self.checked_neg()
+            }
+        }
+    };
+}
+
+impl_parse_int!(i8);
+impl_parse_int!(u8);
+impl_parse_int!(i16);
+impl_parse_int!(u16);
+impl_parse_int!(i32);
+impl_parse_int!(u32);
+impl_parse_int!(i64);
+impl_parse_int!(u64);
+impl_parse_int!(isize);
+impl_parse_int!(usize);
+
+macro_rules! impl_module_param {
+    ($ty:ident) => {
+        impl ModuleParam for $ty {
+            type Value = $ty;
+
+            const NOARG_ALLOWED: bool = false;
+
+            fn try_from_param_arg(arg: Option<&'static [u8]>) -> Option<Self> {
+                let bytes = arg?;
+                let utf8 = core::str::from_utf8(bytes).ok()?;
+                <$ty as crate::module_param::ParseInt>::from_str(utf8)
+            }
+
+            fn value(&self) -> &Self::Value {
+                self
+            }
+        }
+    };
+}
+
+#[doc(hidden)]
+#[macro_export]
+/// Generate a static [`kernel_param_ops`](../../../include/linux/moduleparam.h) struct.
+///
+/// # Example
+/// ```ignore
+/// make_param_ops!(
+///     /// Documentation for new param ops.
+///     PARAM_OPS_MYTYPE, // Name for the static.
+///     MyType // A type which implements [`ModuleParam`].
+/// );
+/// ```
+macro_rules! make_param_ops {
+    ($ops:ident, $ty:ty) => {
+        $crate::make_param_ops!(
+            #[doc=""]
+            $ops,
+            $ty
+        );
+    };
+    ($(#[$meta:meta])* $ops:ident, $ty:ty) => {
+        $(#[$meta])*
+        ///
+        /// Static [`kernel_param_ops`](../../../include/linux/moduleparam.h)
+        /// struct generated by [`make_param_ops`].
+        pub static $ops: $crate::bindings::kernel_param_ops = $crate::bindings::kernel_param_ops {
+            flags: if <$ty as $crate::module_param::ModuleParam>::NOARG_ALLOWED {
+                $crate::bindings::KERNEL_PARAM_OPS_FL_NOARG
+            } else {
+                0
+            },
+            set: Some(<$ty as $crate::module_param::ModuleParam>::set_param),
+            get: Some(<$ty as $crate::module_param::ModuleParam>::get_param),
+            free: Some(<$ty as $crate::module_param::ModuleParam>::free),
+        };
+    };
+}
+
+impl_module_param!(i8);
+impl_module_param!(u8);
+impl_module_param!(i16);
+impl_module_param!(u16);
+impl_module_param!(i32);
+impl_module_param!(u32);
+impl_module_param!(i64);
+impl_module_param!(u64);
+impl_module_param!(isize);
+impl_module_param!(usize);
+
+make_param_ops!(
+    /// Rust implementation of [`kernel_param_ops`](../../../include/linux/moduleparam.h)
+    /// for [`i8`].
+    PARAM_OPS_I8,
+    i8
+);
+make_param_ops!(
+    /// Rust implementation of [`kernel_param_ops`](../../../include/linux/moduleparam.h)
+    /// for [`u8`].
+    PARAM_OPS_U8,
+    u8
+);
+make_param_ops!(
+    /// Rust implementation of [`kernel_param_ops`](../../../include/linux/moduleparam.h)
+    /// for [`i16`].
+    PARAM_OPS_I16,
+    i16
+);
+make_param_ops!(
+    /// Rust implementation of [`kernel_param_ops`](../../../include/linux/moduleparam.h)
+    /// for [`u16`].
+    PARAM_OPS_U16,
+    u16
+);
+make_param_ops!(
+    /// Rust implementation of [`kernel_param_ops`](../../../include/linux/moduleparam.h)
+    /// for [`i32`].
+    PARAM_OPS_I32,
+    i32
+);
+make_param_ops!(
+    /// Rust implementation of [`kernel_param_ops`](../../../include/linux/moduleparam.h)
+    /// for [`u32`].
+    PARAM_OPS_U32,
+    u32
+);
+make_param_ops!(
+    /// Rust implementation of [`kernel_param_ops`](../../../include/linux/moduleparam.h)
+    /// for [`i64`].
+    PARAM_OPS_I64,
+    i64
+);
+make_param_ops!(
+    /// Rust implementation of [`kernel_param_ops`](../../../include/linux/moduleparam.h)
+    /// for [`u64`].
+    PARAM_OPS_U64,
+    u64
+);
+make_param_ops!(
+    /// Rust implementation of [`kernel_param_ops`](../../../include/linux/moduleparam.h)
+    /// for [`isize`].
+    PARAM_OPS_ISIZE,
+    isize
+);
+make_param_ops!(
+    /// Rust implementation of [`kernel_param_ops`](../../../include/linux/moduleparam.h)
+    /// for [`usize`].
+    PARAM_OPS_USIZE,
+    usize
+);
+
+impl ModuleParam for bool {
+    type Value = bool;
+
+    const NOARG_ALLOWED: bool = true;
+
+    fn try_from_param_arg(arg: Option<&'static [u8]>) -> Option<Self> {
+        match arg {
+            None => Some(true),
+            Some(b"y") | Some(b"Y") | Some(b"1") | Some(b"true") => Some(true),
+            Some(b"n") | Some(b"N") | Some(b"0") | Some(b"false") => Some(false),
+            _ => None,
+        }
+    }
+
+    fn value(&self) -> &Self::Value {
+        self
+    }
+}
+
+make_param_ops!(
+    /// Rust implementation of [`kernel_param_ops`](../../../include/linux/moduleparam.h)
+    /// for [`bool`].
+    PARAM_OPS_BOOL,
+    bool
+);
+
+/// An array of at __most__ `N` values.
+///
+/// # Invariant
+///
+/// The first `self.used` elements of `self.values` are initialized.
+pub struct ArrayParam<T, const N: usize> {
+    values: [core::mem::MaybeUninit<T>; N],
+    used: usize,
+}
+
+impl<T, const N: usize> ArrayParam<T, { N }> {
+    fn values(&self) -> &[T] {
+        // SAFETY: The invariant maintained by `ArrayParam` allows us to cast
+        // the first `self.used` elements to `T`.
+        unsafe {
+            &*(&self.values[0..self.used] as *const [core::mem::MaybeUninit<T>] as *const [T])
+        }
+    }
+}
+
+impl<T: Copy, const N: usize> ArrayParam<T, { N }> {
+    const fn new() -> Self {
+        // INVARIANT: The first `self.used` elements of `self.values` are
+        // initialized.
+        ArrayParam {
+            values: [core::mem::MaybeUninit::uninit(); N],
+            used: 0,
+        }
+    }
+
+    const fn push(&mut self, val: T) {
+        if self.used < N {
+            // INVARIANT: The first `self.used` elements of `self.values` are
+            // initialized.
+            self.values[self.used] = core::mem::MaybeUninit::new(val);
+            self.used += 1;
+        }
+    }
+
+    /// Create an instance of `ArrayParam` initialized with `vals`.
+    ///
+    /// This function is only meant to be used in the [`module::module`] macro.
+    pub const fn create(vals: &[T]) -> Self {
+        let mut result = ArrayParam::new();
+        let mut i = 0;
+        while i < vals.len() {
+            result.push(vals[i]);
+            i += 1;
+        }
+        result
+    }
+}
+
+impl<T: core::fmt::Display, const N: usize> core::fmt::Display for ArrayParam<T, { N }> {
+    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
+        for val in self.values() {
+            write!(f, "{},", val)?;
+        }
+        Ok(())
+    }
+}
+
+impl<T: Copy + core::fmt::Display + ModuleParam, const N: usize> ModuleParam
+    for ArrayParam<T, { N }>
+{
+    type Value = [T];
+
+    const NOARG_ALLOWED: bool = false;
+
+    fn try_from_param_arg(arg: Option<&'static [u8]>) -> Option<Self> {
+        arg.and_then(|args| {
+            let mut result = Self::new();
+            for arg in args.split(|b| *b == b',') {
+                result.push(T::try_from_param_arg(Some(arg))?);
+            }
+            Some(result)
+        })
+    }
+
+    fn value(&self) -> &Self::Value {
+        self.values()
+    }
+}
+
+/// A C-style string parameter.
+///
+/// The Rust version of the [`charp`] parameter. This type is meant to be
+/// used by the [`macros::module`] macro, not handled directly. Instead use the
+/// `read` method generated by that macro.
+///
+/// [`charp`]: ../../../include/linux/moduleparam.h
+pub enum StringParam {
+    /// A borrowed parameter value.
+    ///
+    /// Either the default value (which is static in the module) or borrowed
+    /// from the original argument buffer used to set the value.
+    Ref(&'static [u8]),
+
+    /// A value that was allocated when the parameter was set.
+    ///
+    /// The value needs to be freed when the parameter is reset or the module is
+    /// unloaded.
+    Owned(alloc::vec::Vec<u8>),
+}
+
+impl StringParam {
+    fn bytes(&self) -> &[u8] {
+        match self {
+            StringParam::Ref(bytes) => *bytes,
+            StringParam::Owned(vec) => &vec[..],
+        }
+    }
+}
+
+impl core::fmt::Display for StringParam {
+    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
+        let bytes = self.bytes();
+        match core::str::from_utf8(bytes) {
+            Ok(utf8) => write!(f, "{}", utf8),
+            Err(_) => write!(f, "{:?}", bytes),
+        }
+    }
+}
+
+impl ModuleParam for StringParam {
+    type Value = [u8];
+
+    const NOARG_ALLOWED: bool = false;
+
+    fn try_from_param_arg(arg: Option<&'static [u8]>) -> Option<Self> {
+        // SAFETY: It is always safe to call [`slab_is_available`](../../../include/linux/slab.h).
+        let slab_available = unsafe { crate::bindings::slab_is_available() };
+        arg.and_then(|arg| {
+            if slab_available {
+                let mut vec = alloc::vec::Vec::new();
+                vec.try_extend_from_slice(arg).ok()?;
+                Some(StringParam::Owned(vec))
+            } else {
+                Some(StringParam::Ref(arg))
+            }
+        })
+    }
+
+    fn value(&self) -> &Self::Value {
+        self.bytes()
+    }
+}
+
+make_param_ops!(
+    /// Rust implementation of [`kernel_param_ops`](../../../include/linux/moduleparam.h)
+    /// for [`StringParam`].
+    PARAM_OPS_STR,
+    StringParam
+);
diff --git a/rust/kernel/of.rs b/rust/kernel/of.rs
new file mode 100644
index 000000000000..cdcd83244337
--- /dev/null
+++ b/rust/kernel/of.rs
@@ -0,0 +1,63 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Devicetree and Open Firmware abstractions.
+//!
+//! C header: [`include/linux/of_*.h`](../../../../include/linux/of_*.h)
+
+use crate::{bindings, driver, str::BStr};
+
+/// An open firmware device id.
+#[derive(Clone, Copy)]
+pub enum DeviceId {
+    /// An open firmware device id where only a compatible string is specified.
+    Compatible(&'static BStr),
+}
+
+/// Defines a const open firmware device id table that also carries per-entry data/context/info.
+///
+/// The name of the const is `OF_DEVICE_ID_TABLE`, which is what buses are expected to name their
+/// open firmware tables.
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::define_of_id_table;
+/// use kernel::of;
+///
+/// define_of_id_table! {u32, [
+///     (of::DeviceId::Compatible(b"test-device1,test-device2"), Some(0xff)),
+///     (of::DeviceId::Compatible(b"test-device3"), None),
+/// ]};
+/// ```
+#[macro_export]
+macro_rules! define_of_id_table {
+    ($data_type:ty, $($t:tt)*) => {
+        $crate::define_id_table!(OF_DEVICE_ID_TABLE, $crate::of::DeviceId, $data_type, $($t)*);
+    };
+}
+
+// SAFETY: `ZERO` is all zeroed-out and `to_rawid` stores `offset` in `of_device_id::data`.
+unsafe impl const driver::RawDeviceId for DeviceId {
+    type RawType = bindings::of_device_id;
+    const ZERO: Self::RawType = bindings::of_device_id {
+        name: [0; 32],
+        type_: [0; 32],
+        compatible: [0; 128],
+        data: core::ptr::null(),
+    };
+
+    fn to_rawid(&self, offset: isize) -> Self::RawType {
+        let DeviceId::Compatible(compatible) = self;
+        let mut id = Self::ZERO;
+        let mut i = 0;
+        while i < compatible.len() {
+            // If `compatible` does not fit in `id.compatible`, an "index out of bounds" build time
+            // error will be triggered.
+            id.compatible[i] = compatible[i] as _;
+            i += 1;
+        }
+        id.compatible[i] = b'\0' as _;
+        id.data = offset as _;
+        id
+    }
+}
diff --git a/rust/kernel/pages.rs b/rust/kernel/pages.rs
new file mode 100644
index 000000000000..81a1b48e3823
--- /dev/null
+++ b/rust/kernel/pages.rs
@@ -0,0 +1,144 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Kernel page allocation and management.
+//!
+//! TODO: This module is a work in progress.
+
+use crate::{
+    bindings, c_types, io_buffer::IoBufferReader, user_ptr::UserSlicePtrReader, Error, Result,
+    PAGE_SIZE,
+};
+use core::{marker::PhantomData, ptr};
+
+/// A set of physical pages.
+///
+/// `Pages` holds a reference to a set of pages of order `ORDER`. Having the order as a generic
+/// const allows the struct to have the same size as a pointer.
+///
+/// # Invariants
+///
+/// The pointer `Pages::pages` is valid and points to 2^ORDER pages.
+pub struct Pages<const ORDER: u32> {
+    pub(crate) pages: *mut bindings::page,
+}
+
+impl<const ORDER: u32> Pages<ORDER> {
+    /// Allocates a new set of contiguous pages.
+    pub fn new() -> Result<Self> {
+        // TODO: Consider whether we want to allow callers to specify flags.
+        // SAFETY: This only allocates pages. We check that it succeeds in the next statement.
+        let pages = unsafe {
+            bindings::alloc_pages(
+                bindings::GFP_KERNEL | bindings::__GFP_ZERO | bindings::__GFP_HIGHMEM,
+                ORDER,
+            )
+        };
+        if pages.is_null() {
+            return Err(Error::ENOMEM);
+        }
+        // INVARIANTS: We checked that the allocation above succeeded>
+        Ok(Self { pages })
+    }
+
+    /// Copies data from the given [`UserSlicePtrReader`] into the pages.
+    pub fn copy_into_page(
+        &self,
+        reader: &mut UserSlicePtrReader,
+        offset: usize,
+        len: usize,
+    ) -> Result {
+        // TODO: For now this only works on the first page.
+        let end = offset.checked_add(len).ok_or(Error::EINVAL)?;
+        if end > PAGE_SIZE {
+            return Err(Error::EINVAL);
+        }
+
+        let mapping = self.kmap(0).ok_or(Error::EINVAL)?;
+
+        // SAFETY: We ensured that the buffer was valid with the check above.
+        unsafe { reader.read_raw((mapping.ptr as usize + offset) as _, len) }?;
+        Ok(())
+    }
+
+    /// Maps the pages and reads from them into the given buffer.
+    ///
+    /// # Safety
+    ///
+    /// Callers must ensure that the destination buffer is valid for the given length.
+    /// Additionally, if the raw buffer is intended to be recast, they must ensure that the data
+    /// can be safely cast; [`crate::io_buffer::ReadableFromBytes`] has more details about it.
+    pub unsafe fn read(&self, dest: *mut u8, offset: usize, len: usize) -> Result {
+        // TODO: For now this only works on the first page.
+        let end = offset.checked_add(len).ok_or(Error::EINVAL)?;
+        if end > PAGE_SIZE {
+            return Err(Error::EINVAL);
+        }
+
+        let mapping = self.kmap(0).ok_or(Error::EINVAL)?;
+        unsafe { ptr::copy((mapping.ptr as *mut u8).add(offset), dest, len) };
+        Ok(())
+    }
+
+    /// Maps the pages and writes into them from the given bufer.
+    ///
+    /// # Safety
+    ///
+    /// Callers must ensure that the buffer is valid for the given length. Additionally, if the
+    /// page is (or will be) mapped by userspace, they must ensure that no kernel data is leaked
+    /// through padding if it was cast from another type; [`crate::io_buffer::WritableToBytes`] has
+    /// more details about it.
+    pub unsafe fn write(&self, src: *const u8, offset: usize, len: usize) -> Result {
+        // TODO: For now this only works on the first page.
+        let end = offset.checked_add(len).ok_or(Error::EINVAL)?;
+        if end > PAGE_SIZE {
+            return Err(Error::EINVAL);
+        }
+
+        let mapping = self.kmap(0).ok_or(Error::EINVAL)?;
+        unsafe { ptr::copy(src, (mapping.ptr as *mut u8).add(offset), len) };
+        Ok(())
+    }
+
+    /// Maps the page at index `index`.
+    fn kmap(&self, index: usize) -> Option<PageMapping<'_>> {
+        if index >= 1usize << ORDER {
+            return None;
+        }
+
+        // SAFETY: We checked above that `index` is within range.
+        let page = unsafe { self.pages.add(index) };
+
+        // SAFETY: `page` is valid based on the checks above.
+        let ptr = unsafe { bindings::kmap(page) };
+        if ptr.is_null() {
+            return None;
+        }
+
+        Some(PageMapping {
+            page,
+            ptr,
+            _phantom: PhantomData,
+        })
+    }
+}
+
+impl<const ORDER: u32> Drop for Pages<ORDER> {
+    fn drop(&mut self) {
+        // SAFETY: By the type invariants, we know the pages are allocated with the given order.
+        unsafe { bindings::__free_pages(self.pages, ORDER) };
+    }
+}
+
+struct PageMapping<'a> {
+    page: *mut bindings::page,
+    ptr: *mut c_types::c_void,
+    _phantom: PhantomData<&'a i32>,
+}
+
+impl Drop for PageMapping<'_> {
+    fn drop(&mut self) {
+        // SAFETY: An instance of `PageMapping` is created only when `kmap` succeeded for the given
+        // page, so it is safe to unmap it here.
+        unsafe { bindings::kunmap(self.page) };
+    }
+}
diff --git a/rust/kernel/platform.rs b/rust/kernel/platform.rs
new file mode 100644
index 000000000000..8b912c21068b
--- /dev/null
+++ b/rust/kernel/platform.rs
@@ -0,0 +1,224 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Platform devices and drivers.
+//!
+//! Also called `platdev`, `pdev`.
+//!
+//! C header: [`include/linux/platform_device.h`](../../../../include/linux/platform_device.h)
+
+use crate::{
+    bindings, c_types,
+    device::{self, RawDevice},
+    driver,
+    error::{from_kernel_result, Result},
+    of,
+    str::CStr,
+    to_result,
+    types::PointerWrapper,
+    ThisModule,
+};
+
+/// A registration of a platform driver.
+pub type Registration<T> = driver::Registration<Adapter<T>>;
+
+/// An adapter for the registration of platform drivers.
+pub struct Adapter<T: Driver>(T);
+
+impl<T: Driver> driver::DriverOps for Adapter<T> {
+    type RegType = bindings::platform_driver;
+
+    unsafe fn register(
+        reg: *mut bindings::platform_driver,
+        name: &'static CStr,
+        module: &'static ThisModule,
+    ) -> Result {
+        // SAFETY: By the safety requirements of this function (defined in the trait defintion),
+        // `reg` is non-null and valid.
+        let pdrv = unsafe { &mut *reg };
+
+        pdrv.driver.name = name.as_char_ptr();
+        pdrv.probe = Some(Self::probe_callback);
+        pdrv.remove = Some(Self::remove_callback);
+        if let Some(t) = T::OF_DEVICE_ID_TABLE {
+            pdrv.driver.of_match_table = t.as_ref();
+        }
+        // SAFETY:
+        //   - `pdrv` lives at least until the call to `platform_driver_unregister()` returns.
+        //   - `name` pointer has static lifetime.
+        //   - `module.0` lives at least as long as the module.
+        //   - `probe()` and `remove()` are static functions.
+        //   - `of_match_table` is either a raw pointer with static lifetime,
+        //      as guaranteed by the [`driver::IdTable`] type, or null.
+        to_result(|| unsafe { bindings::__platform_driver_register(reg, module.0) })
+    }
+
+    unsafe fn unregister(reg: *mut bindings::platform_driver) {
+        // SAFETY: By the safety requirements of this function (defined in the trait definition),
+        // `reg` was passed (and updated) by a previous successful call to
+        // `platform_driver_register`.
+        unsafe { bindings::platform_driver_unregister(reg) };
+    }
+}
+
+impl<T: Driver> Adapter<T> {
+    fn get_id_info(dev: &Device) -> Option<&'static T::IdInfo> {
+        let table = T::OF_DEVICE_ID_TABLE?;
+
+        // SAFETY: `table` has static lifetime, so it is valid for read. `dev` is guaranteed to be
+        // valid while it's alive, so is the raw device returned by it.
+        let id = unsafe { bindings::of_match_device(table.as_ref(), dev.raw_device()) };
+        if id.is_null() {
+            return None;
+        }
+
+        // SAFETY: `id` is a pointer within the static table, so it's always valid.
+        let offset = unsafe { (*id).data };
+        if offset.is_null() {
+            return None;
+        }
+
+        // SAFETY: The offset comes from a previous call to `offset_from` in `IdArray::new`, which
+        // guarantees that the resulting pointer is within the table.
+        let ptr = unsafe {
+            id.cast::<u8>()
+                .offset(offset as _)
+                .cast::<Option<T::IdInfo>>()
+        };
+
+        // SAFETY: The id table has a static lifetime, so `ptr` is guaranteed to be valid for read.
+        unsafe { (&*ptr).as_ref() }
+    }
+
+    extern "C" fn probe_callback(pdev: *mut bindings::platform_device) -> c_types::c_int {
+        from_kernel_result! {
+            // SAFETY: `pdev` is valid by the contract with the C code. `dev` is alive only for the
+            // duration of this call, so it is guaranteed to remain alive for the lifetime of
+            // `pdev`.
+            let mut dev = unsafe { Device::from_ptr(pdev) };
+            let info = Self::get_id_info(&dev);
+            let data = T::probe(&mut dev, info)?;
+            // SAFETY: `pdev` is guaranteed to be a valid, non-null pointer.
+            unsafe { bindings::platform_set_drvdata(pdev, data.into_pointer() as _) };
+            Ok(0)
+        }
+    }
+
+    extern "C" fn remove_callback(pdev: *mut bindings::platform_device) -> c_types::c_int {
+        from_kernel_result! {
+            // SAFETY: `pdev` is guaranteed to be a valid, non-null pointer.
+            let ptr = unsafe { bindings::platform_get_drvdata(pdev) };
+            // SAFETY:
+            //   - we allocated this pointer using `T::Data::into_pointer`,
+            //     so it is safe to turn back into a `T::Data`.
+            //   - the allocation happened in `probe`, no-one freed the memory,
+            //     `remove` is the canonical kernel location to free driver data. so OK
+            //     to convert the pointer back to a Rust structure here.
+            let data = unsafe { T::Data::from_pointer(ptr) };
+            let ret = T::remove(&data);
+            <T::Data as driver::DeviceRemoval>::device_remove(&data);
+            ret?;
+            Ok(0)
+        }
+    }
+}
+
+/// A platform driver.
+pub trait Driver {
+    /// Data stored on device by driver.
+    ///
+    /// Corresponds to the data set or retrieved via the kernel's
+    /// `platform_{set,get}_drvdata()` functions.
+    ///
+    /// Require that `Data` implements `PointerWrapper`. We guarantee to
+    /// never move the underlying wrapped data structure. This allows
+    type Data: PointerWrapper + Send + Sync + driver::DeviceRemoval = ();
+
+    /// The type holding information about each device id supported by the driver.
+    type IdInfo: 'static = ();
+
+    /// The table of device ids supported by the driver.
+    const OF_DEVICE_ID_TABLE: Option<driver::IdTable<'static, of::DeviceId, Self::IdInfo>> = None;
+
+    /// Platform driver probe.
+    ///
+    /// Called when a new platform device is added or discovered.
+    /// Implementers should attempt to initialize the device here.
+    fn probe(dev: &mut Device, id_info: Option<&Self::IdInfo>) -> Result<Self::Data>;
+
+    /// Platform driver remove.
+    ///
+    /// Called when a platform device is removed.
+    /// Implementers should prepare the device for complete removal here.
+    fn remove(_data: &Self::Data) -> Result {
+        Ok(())
+    }
+}
+
+/// A platform device.
+///
+/// # Invariants
+///
+/// The field `ptr` is non-null and valid for the lifetime of the object.
+pub struct Device {
+    ptr: *mut bindings::platform_device,
+}
+
+impl Device {
+    /// Creates a new device from the given pointer.
+    ///
+    /// # Safety
+    ///
+    /// `ptr` must be non-null and valid. It must remain valid for the lifetime of the returned
+    /// instance.
+    unsafe fn from_ptr(ptr: *mut bindings::platform_device) -> Self {
+        // INVARIANT: The safety requirements of the function ensure the lifetime invariant.
+        Self { ptr }
+    }
+
+    /// Returns id of the platform device.
+    pub fn id(&self) -> i32 {
+        // SAFETY: By the type invariants, we know that `self.ptr` is non-null and valid.
+        unsafe { (*self.ptr).id }
+    }
+}
+
+// SAFETY: The device returned by `raw_device` is the raw platform device.
+unsafe impl device::RawDevice for Device {
+    fn raw_device(&self) -> *mut bindings::device {
+        // SAFETY: By the type invariants, we know that `self.ptr` is non-null and valid.
+        unsafe { &mut (*self.ptr).dev }
+    }
+}
+
+/// Declares a kernel module that exposes a single platform driver.
+///
+/// # Examples
+///
+/// ```ignore
+/// # use kernel::prelude::*;
+/// # use kernel::{platform, define_of_id_table, module_platform_driver};
+/// #
+/// struct MyDriver;
+/// impl platform::Driver for MyDriver {
+///     // [...]
+/// #   fn probe(_dev: &mut platform::Device, _id_info: Option<&Self::IdInfo>) -> Result {
+/// #       Ok(())
+/// #   }
+/// #   define_of_id_table! {(), [
+/// #       (of::DeviceId::Compatible(b"brcm,bcm2835-rng"), None),
+/// #   ]}
+/// }
+///
+/// module_platform_driver! {
+///     type: MyDriver,
+///     name: b"module_name",
+///     author: b"Author name",
+///     license: b"GPL v2",
+/// }
+/// ```
+#[macro_export]
+macro_rules! module_platform_driver {
+    ($($f:tt)*) => {
+        $crate::module_driver!(<T>, $crate::platform::Adapter<T>, { $($f)* });
+    };
+}
diff --git a/rust/kernel/power.rs b/rust/kernel/power.rs
new file mode 100644
index 000000000000..e318b5d9f0c0
--- /dev/null
+++ b/rust/kernel/power.rs
@@ -0,0 +1,118 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Power management interfaces.
+//!
+//! C header: [`include/linux/pm.h`](../../../../include/linux/pm.h)
+
+#![allow(dead_code)]
+
+use crate::{bindings, c_types, error::from_kernel_result, types::PointerWrapper, Result};
+use core::marker::PhantomData;
+
+/// Corresponds to the kernel's `struct dev_pm_ops`.
+///
+/// It is meant to be implemented by drivers that support power-management operations.
+pub trait Operations {
+    /// The type of the context data stored by the driver on each device.
+    type Data: PointerWrapper + Sync + Send;
+
+    /// Called before the system goes into a sleep state.
+    fn suspend(_data: <Self::Data as PointerWrapper>::Borrowed<'_>) -> Result {
+        Ok(())
+    }
+
+    /// Called after the system comes back from a sleep state.
+    fn resume(_data: <Self::Data as PointerWrapper>::Borrowed<'_>) -> Result {
+        Ok(())
+    }
+
+    /// Called before creating a hibernation image.
+    fn freeze(_data: <Self::Data as PointerWrapper>::Borrowed<'_>) -> Result {
+        Ok(())
+    }
+
+    /// Called after the system is restored from a hibernation image.
+    fn restore(_data: <Self::Data as PointerWrapper>::Borrowed<'_>) -> Result {
+        Ok(())
+    }
+}
+
+macro_rules! pm_callback {
+    ($callback:ident, $method:ident) => {
+        unsafe extern "C" fn $callback<T: Operations>(
+            dev: *mut bindings::device,
+        ) -> c_types::c_int {
+            from_kernel_result! {
+                // SAFETY: `dev` is valid as it was passed in by the C portion.
+                let ptr = unsafe { bindings::dev_get_drvdata(dev) };
+                // SAFETY: By the safety requirements of `OpsTable::build`, we know that `ptr` came
+                // from a previous call to `T::Data::into_pointer`.
+                let data = unsafe { T::Data::borrow(ptr) };
+                T::$method(data)?;
+                Ok(0)
+            }
+        }
+    };
+}
+
+pm_callback!(suspend_callback, suspend);
+pm_callback!(resume_callback, resume);
+pm_callback!(freeze_callback, freeze);
+pm_callback!(restore_callback, restore);
+
+pub(crate) struct OpsTable<T: Operations>(PhantomData<*const T>);
+
+impl<T: Operations> OpsTable<T> {
+    const VTABLE: bindings::dev_pm_ops = bindings::dev_pm_ops {
+        prepare: None,
+        complete: None,
+        suspend: Some(suspend_callback::<T>),
+        resume: Some(resume_callback::<T>),
+        freeze: Some(freeze_callback::<T>),
+        thaw: None,
+        poweroff: None,
+        restore: Some(restore_callback::<T>),
+        suspend_late: None,
+        resume_early: None,
+        freeze_late: None,
+        thaw_early: None,
+        poweroff_late: None,
+        restore_early: None,
+        suspend_noirq: None,
+        resume_noirq: None,
+        freeze_noirq: None,
+        thaw_noirq: None,
+        poweroff_noirq: None,
+        restore_noirq: None,
+        runtime_suspend: None,
+        runtime_resume: None,
+        runtime_idle: None,
+    };
+
+    /// Builds an instance of `struct dev_pm_ops`.
+    ///
+    /// # Safety
+    ///
+    /// The caller must ensure that `dev_get_drvdata` will result in a value returned by
+    /// [`T::Data::into_pointer`].
+    pub(crate) const unsafe fn build() -> &'static bindings::dev_pm_ops {
+        &Self::VTABLE
+    }
+}
+
+/// Implements the [`Operations`] trait as no-ops.
+///
+/// This is useful when one doesn't want to provide the implementation of any power-manager related
+/// operation.
+pub struct NoOperations<T: PointerWrapper>(PhantomData<T>);
+
+impl<T: PointerWrapper + Send + Sync> Operations for NoOperations<T> {
+    type Data = T;
+}
+
+// SAFETY: `NoOperation` provides no functionality, it is safe to send a reference to it to
+// different threads.
+unsafe impl<T: PointerWrapper> Sync for NoOperations<T> {}
+
+// SAFETY: `NoOperation` provides no functionality, it is safe to send it to different threads.
+unsafe impl<T: PointerWrapper> Send for NoOperations<T> {}
diff --git a/rust/kernel/prelude.rs b/rust/kernel/prelude.rs
new file mode 100644
index 000000000000..ad9e91307028
--- /dev/null
+++ b/rust/kernel/prelude.rs
@@ -0,0 +1,36 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! The `kernel` prelude.
+//!
+//! These are the most common items used by Rust code in the kernel,
+//! intended to be imported by all Rust code, for convenience.
+//!
+//! # Examples
+//!
+//! ```
+//! use kernel::prelude::*;
+//! ```
+
+pub use core::pin::Pin;
+
+pub use alloc::{boxed::Box, string::String, vec::Vec};
+
+pub use macros::module;
+
+pub use super::build_assert;
+
+pub use super::{
+    dbg, dev_alert, dev_crit, dev_dbg, dev_emerg, dev_err, dev_info, dev_notice, dev_warn,
+    pr_alert, pr_crit, pr_debug, pr_emerg, pr_err, pr_info, pr_notice, pr_warn,
+};
+
+pub use super::module_misc_device;
+
+#[cfg(CONFIG_ARM_AMBA)]
+pub use super::module_amba_driver;
+
+pub use super::static_assert;
+
+pub use super::{Error, KernelModule, Result};
+
+pub use super::{str::CStr, ThisModule};
diff --git a/rust/kernel/print.rs b/rust/kernel/print.rs
new file mode 100644
index 000000000000..dba4ef10c722
--- /dev/null
+++ b/rust/kernel/print.rs
@@ -0,0 +1,417 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Printing facilities.
+//!
+//! C header: [`include/linux/printk.h`](../../../../include/linux/printk.h)
+//!
+//! Reference: <https://www.kernel.org/doc/html/latest/core-api/printk-basics.html>
+
+use core::fmt;
+
+use crate::{
+    c_types::{c_char, c_void},
+    str::Formatter,
+};
+
+#[cfg(CONFIG_PRINTK)]
+use crate::bindings;
+
+// Called from `vsprintf` with format specifier `%pA`.
+#[no_mangle]
+unsafe fn rust_fmt_argument(buf: *mut c_char, end: *mut c_char, ptr: *const c_void) -> *mut c_char {
+    use fmt::Write;
+
+    let mut w = Formatter {
+        buf: buf as _,
+        end: end as _,
+    };
+    let _ = w.write_fmt(unsafe { *(ptr as *const fmt::Arguments<'_>) });
+    w.buf as _
+}
+
+/// Format strings.
+///
+/// Public but hidden since it should only be used from public macros.
+#[doc(hidden)]
+pub mod format_strings {
+    use crate::bindings;
+
+    /// The length we copy from the `KERN_*` kernel prefixes.
+    const LENGTH_PREFIX: usize = 2;
+
+    /// The length of the fixed format strings.
+    pub const LENGTH: usize = 10;
+
+    /// Generates a fixed format string for the kernel's [`_printk`].
+    ///
+    /// The format string is always the same for a given level, i.e. for a
+    /// given `prefix`, which are the kernel's `KERN_*` constants.
+    ///
+    /// [`_printk`]: ../../../../include/linux/printk.h
+    const fn generate(is_cont: bool, prefix: &[u8; 3]) -> [u8; LENGTH] {
+        // Ensure the `KERN_*` macros are what we expect.
+        assert!(prefix[0] == b'\x01');
+        if is_cont {
+            assert!(prefix[1] == b'c');
+        } else {
+            assert!(prefix[1] >= b'0' && prefix[1] <= b'7');
+        }
+        assert!(prefix[2] == b'\x00');
+
+        let suffix: &[u8; LENGTH - LENGTH_PREFIX] = if is_cont {
+            b"%pA\0\0\0\0\0"
+        } else {
+            b"%s: %pA\0"
+        };
+
+        [
+            prefix[0], prefix[1], suffix[0], suffix[1], suffix[2], suffix[3], suffix[4], suffix[5],
+            suffix[6], suffix[7],
+        ]
+    }
+
+    // Generate the format strings at compile-time.
+    //
+    // This avoids the compiler generating the contents on the fly in the stack.
+    //
+    // Furthermore, `static` instead of `const` is used to share the strings
+    // for all the kernel.
+    pub static EMERG: [u8; LENGTH] = generate(false, bindings::KERN_EMERG);
+    pub static ALERT: [u8; LENGTH] = generate(false, bindings::KERN_ALERT);
+    pub static CRIT: [u8; LENGTH] = generate(false, bindings::KERN_CRIT);
+    pub static ERR: [u8; LENGTH] = generate(false, bindings::KERN_ERR);
+    pub static WARNING: [u8; LENGTH] = generate(false, bindings::KERN_WARNING);
+    pub static NOTICE: [u8; LENGTH] = generate(false, bindings::KERN_NOTICE);
+    pub static INFO: [u8; LENGTH] = generate(false, bindings::KERN_INFO);
+    pub static DEBUG: [u8; LENGTH] = generate(false, bindings::KERN_DEBUG);
+    pub static CONT: [u8; LENGTH] = generate(true, bindings::KERN_CONT);
+}
+
+/// Prints a message via the kernel's [`_printk`].
+///
+/// Public but hidden since it should only be used from public macros.
+///
+/// # Safety
+///
+/// The format string must be one of the ones in [`format_strings`], and
+/// the module name must be null-terminated.
+///
+/// [`_printk`]: ../../../../include/linux/_printk.h
+#[doc(hidden)]
+#[cfg_attr(not(CONFIG_PRINTK), allow(unused_variables))]
+pub unsafe fn call_printk(
+    format_string: &[u8; format_strings::LENGTH],
+    module_name: &[u8],
+    args: fmt::Arguments<'_>,
+) {
+    // `_printk` does not seem to fail in any path.
+    #[cfg(CONFIG_PRINTK)]
+    unsafe {
+        bindings::_printk(
+            format_string.as_ptr() as _,
+            module_name.as_ptr(),
+            &args as *const _ as *const c_void,
+        );
+    }
+}
+
+/// Prints a message via the kernel's [`_printk`] for the `CONT` level.
+///
+/// Public but hidden since it should only be used from public macros.
+///
+/// [`_printk`]: ../../../../include/linux/printk.h
+#[doc(hidden)]
+#[cfg_attr(not(CONFIG_PRINTK), allow(unused_variables))]
+pub fn call_printk_cont(args: fmt::Arguments<'_>) {
+    // `_printk` does not seem to fail in any path.
+    //
+    // SAFETY: The format string is fixed.
+    #[cfg(CONFIG_PRINTK)]
+    unsafe {
+        bindings::_printk(
+            format_strings::CONT.as_ptr() as _,
+            &args as *const _ as *const c_void,
+        );
+    }
+}
+
+/// Performs formatting and forwards the string to [`call_printk`].
+///
+/// Public but hidden since it should only be used from public macros.
+#[doc(hidden)]
+#[cfg(not(testlib))]
+#[macro_export]
+macro_rules! print_macro (
+    // The non-continuation cases (most of them, e.g. `INFO`).
+    ($format_string:path, false, $($arg:tt)+) => (
+        // SAFETY: This hidden macro should only be called by the documented
+        // printing macros which ensure the format string is one of the fixed
+        // ones. All `__LOG_PREFIX`s are null-terminated as they are generated
+        // by the `module!` proc macro or fixed values defined in a kernel
+        // crate.
+        unsafe {
+            $crate::print::call_printk(
+                &$format_string,
+                crate::__LOG_PREFIX,
+                format_args!($($arg)+),
+            );
+        }
+    );
+
+    // The `CONT` case.
+    ($format_string:path, true, $($arg:tt)+) => (
+        $crate::print::call_printk_cont(
+            format_args!($($arg)+),
+        );
+    );
+);
+
+/// Stub for doctests
+#[cfg(testlib)]
+#[macro_export]
+macro_rules! print_macro (
+    ($format_string:path, $e:expr, $($arg:tt)+) => (
+        ()
+    );
+);
+
+// We could use a macro to generate these macros. However, doing so ends
+// up being a bit ugly: it requires the dollar token trick to escape `$` as
+// well as playing with the `doc` attribute. Furthermore, they cannot be easily
+// imported in the prelude due to [1]. So, for the moment, we just write them
+// manually, like in the C side; while keeping most of the logic in another
+// macro, i.e. [`print_macro`].
+//
+// [1]: https://github.com/rust-lang/rust/issues/52234
+
+/// Prints an emergency-level message (level 0).
+///
+/// Use this level if the system is unusable.
+///
+/// Equivalent to the kernel's [`pr_emerg`] macro.
+///
+/// Mimics the interface of [`std::print!`]. See [`core::fmt`] and
+/// [`alloc::format!`] for information about the formatting syntax.
+///
+/// [`pr_emerg`]: https://www.kernel.org/doc/html/latest/core-api/printk-basics.html#c.pr_emerg
+/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::prelude::*;
+/// pr_emerg!("hello {}\n", "there");
+/// ```
+#[macro_export]
+macro_rules! pr_emerg (
+    ($($arg:tt)*) => (
+        $crate::print_macro!($crate::print::format_strings::EMERG, false, $($arg)*)
+    )
+);
+
+/// Prints an alert-level message (level 1).
+///
+/// Use this level if action must be taken immediately.
+///
+/// Equivalent to the kernel's [`pr_alert`] macro.
+///
+/// Mimics the interface of [`std::print!`]. See [`core::fmt`] and
+/// [`alloc::format!`] for information about the formatting syntax.
+///
+/// [`pr_alert`]: https://www.kernel.org/doc/html/latest/core-api/printk-basics.html#c.pr_alert
+/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::prelude::*;
+/// pr_alert!("hello {}\n", "there");
+/// ```
+#[macro_export]
+macro_rules! pr_alert (
+    ($($arg:tt)*) => (
+        $crate::print_macro!($crate::print::format_strings::ALERT, false, $($arg)*)
+    )
+);
+
+/// Prints a critical-level message (level 2).
+///
+/// Use this level for critical conditions.
+///
+/// Equivalent to the kernel's [`pr_crit`] macro.
+///
+/// Mimics the interface of [`std::print!`]. See [`core::fmt`] and
+/// [`alloc::format!`] for information about the formatting syntax.
+///
+/// [`pr_crit`]: https://www.kernel.org/doc/html/latest/core-api/printk-basics.html#c.pr_crit
+/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::prelude::*;
+/// pr_crit!("hello {}\n", "there");
+/// ```
+#[macro_export]
+macro_rules! pr_crit (
+    ($($arg:tt)*) => (
+        $crate::print_macro!($crate::print::format_strings::CRIT, false, $($arg)*)
+    )
+);
+
+/// Prints an error-level message (level 3).
+///
+/// Use this level for error conditions.
+///
+/// Equivalent to the kernel's [`pr_err`] macro.
+///
+/// Mimics the interface of [`std::print!`]. See [`core::fmt`] and
+/// [`alloc::format!`] for information about the formatting syntax.
+///
+/// [`pr_err`]: https://www.kernel.org/doc/html/latest/core-api/printk-basics.html#c.pr_err
+/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::prelude::*;
+/// pr_err!("hello {}\n", "there");
+/// ```
+#[macro_export]
+macro_rules! pr_err (
+    ($($arg:tt)*) => (
+        $crate::print_macro!($crate::print::format_strings::ERR, false, $($arg)*)
+    )
+);
+
+/// Prints a warning-level message (level 4).
+///
+/// Use this level for warning conditions.
+///
+/// Equivalent to the kernel's [`pr_warn`] macro.
+///
+/// Mimics the interface of [`std::print!`]. See [`core::fmt`] and
+/// [`alloc::format!`] for information about the formatting syntax.
+///
+/// [`pr_warn`]: https://www.kernel.org/doc/html/latest/core-api/printk-basics.html#c.pr_warn
+/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::prelude::*;
+/// pr_warn!("hello {}\n", "there");
+/// ```
+#[macro_export]
+macro_rules! pr_warn (
+    ($($arg:tt)*) => (
+        $crate::print_macro!($crate::print::format_strings::WARNING, false, $($arg)*)
+    )
+);
+
+/// Prints a notice-level message (level 5).
+///
+/// Use this level for normal but significant conditions.
+///
+/// Equivalent to the kernel's [`pr_notice`] macro.
+///
+/// Mimics the interface of [`std::print!`]. See [`core::fmt`] and
+/// [`alloc::format!`] for information about the formatting syntax.
+///
+/// [`pr_notice`]: https://www.kernel.org/doc/html/latest/core-api/printk-basics.html#c.pr_notice
+/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::prelude::*;
+/// pr_notice!("hello {}\n", "there");
+/// ```
+#[macro_export]
+macro_rules! pr_notice (
+    ($($arg:tt)*) => (
+        $crate::print_macro!($crate::print::format_strings::NOTICE, false, $($arg)*)
+    )
+);
+
+/// Prints an info-level message (level 6).
+///
+/// Use this level for informational messages.
+///
+/// Equivalent to the kernel's [`pr_info`] macro.
+///
+/// Mimics the interface of [`std::print!`]. See [`core::fmt`] and
+/// [`alloc::format!`] for information about the formatting syntax.
+///
+/// [`pr_info`]: https://www.kernel.org/doc/html/latest/core-api/printk-basics.html#c.pr_info
+/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::prelude::*;
+/// pr_info!("hello {}\n", "there");
+/// ```
+#[macro_export]
+#[doc(alias = "print")]
+macro_rules! pr_info (
+    ($($arg:tt)*) => (
+        $crate::print_macro!($crate::print::format_strings::INFO, false, $($arg)*)
+    )
+);
+
+/// Prints a debug-level message (level 7).
+///
+/// Use this level for debug messages.
+///
+/// Equivalent to the kernel's [`pr_debug`] macro, except that it doesn't support dynamic debug
+/// yet.
+///
+/// Mimics the interface of [`std::print!`]. See [`core::fmt`] and
+/// [`alloc::format!`] for information about the formatting syntax.
+///
+/// [`pr_debug`]: https://www.kernel.org/doc/html/latest/core-api/printk-basics.html#c.pr_debug
+/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::prelude::*;
+/// pr_debug!("hello {}\n", "there");
+/// ```
+#[macro_export]
+#[doc(alias = "print")]
+macro_rules! pr_debug (
+    ($($arg:tt)*) => (
+        if cfg!(debug_assertions) {
+            $crate::print_macro!($crate::print::format_strings::DEBUG, false, $($arg)*)
+        }
+    )
+);
+
+/// Continues a previous log message in the same line.
+///
+/// Use only when continuing a previous `pr_*!` macro (e.g. [`pr_info!`]).
+///
+/// Equivalent to the kernel's [`pr_cont`] macro.
+///
+/// Mimics the interface of [`std::print!`]. See [`core::fmt`] and
+/// [`alloc::format!`] for information about the formatting syntax.
+///
+/// [`pr_cont`]: https://www.kernel.org/doc/html/latest/core-api/printk-basics.html#c.pr_cont
+/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::prelude::*;
+/// # use kernel::pr_cont;
+/// pr_info!("hello");
+/// pr_cont!(" {}\n", "there");
+/// ```
+#[macro_export]
+macro_rules! pr_cont (
+    ($($arg:tt)*) => (
+        $crate::print_macro!($crate::print::format_strings::CONT, true, $($arg)*)
+    )
+);
diff --git a/rust/kernel/random.rs b/rust/kernel/random.rs
new file mode 100644
index 000000000000..723a89829f66
--- /dev/null
+++ b/rust/kernel/random.rs
@@ -0,0 +1,50 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Random numbers.
+//!
+//! C header: [`include/linux/random.h`](../../../../include/linux/random.h)
+
+use core::convert::TryInto;
+
+use crate::{bindings, c_types, error};
+
+/// Fills a byte slice with random bytes generated from the kernel's CSPRNG.
+///
+/// Ensures that the CSPRNG has been seeded before generating any random bytes,
+/// and will block until it is ready.
+pub fn getrandom(dest: &mut [u8]) -> error::Result {
+    let res = unsafe { bindings::wait_for_random_bytes() };
+    if res != 0 {
+        return Err(error::Error::from_kernel_errno(res));
+    }
+
+    unsafe {
+        bindings::get_random_bytes(
+            dest.as_mut_ptr() as *mut c_types::c_void,
+            dest.len().try_into()?,
+        );
+    }
+    Ok(())
+}
+
+/// Fills a byte slice with random bytes generated from the kernel's CSPRNG.
+///
+/// If the CSPRNG is not yet seeded, returns an `Err(EAGAIN)` immediately.
+pub fn getrandom_nonblock(dest: &mut [u8]) -> error::Result {
+    if !unsafe { bindings::rng_is_initialized() } {
+        return Err(error::Error::EAGAIN);
+    }
+    getrandom(dest)
+}
+
+/// Contributes the contents of a byte slice to the kernel's entropy pool.
+///
+/// Does *not* credit the kernel entropy counter though.
+pub fn add_randomness(data: &[u8]) {
+    unsafe {
+        bindings::add_device_randomness(
+            data.as_ptr() as *const c_types::c_void,
+            data.len().try_into().unwrap(),
+        );
+    }
+}
diff --git a/rust/kernel/raw_list.rs b/rust/kernel/raw_list.rs
new file mode 100644
index 000000000000..4bc4f4a24ad5
--- /dev/null
+++ b/rust/kernel/raw_list.rs
@@ -0,0 +1,361 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Raw lists.
+//!
+//! TODO: This module is a work in progress.
+
+use core::{
+    cell::UnsafeCell,
+    ptr,
+    ptr::NonNull,
+    sync::atomic::{AtomicBool, Ordering},
+};
+
+/// A descriptor of list elements.
+///
+/// It describes the type of list elements and provides a function to determine how to get the
+/// links to be used on a list.
+///
+/// A type that may be in multiple lists simultaneously neneds to implement one of these for each
+/// simultaneous list.
+pub trait GetLinks {
+    /// The type of the entries in the list.
+    type EntryType: ?Sized;
+
+    /// Returns the links to be used when linking an entry within a list.
+    fn get_links(data: &Self::EntryType) -> &Links<Self::EntryType>;
+}
+
+/// The links used to link an object on a linked list.
+///
+/// Instances of this type are usually embedded in structures and returned in calls to
+/// [`GetLinks::get_links`].
+pub struct Links<T: ?Sized> {
+    inserted: AtomicBool,
+    entry: UnsafeCell<ListEntry<T>>,
+}
+
+impl<T: ?Sized> Links<T> {
+    /// Constructs a new [`Links`] instance that isn't inserted on any lists yet.
+    pub fn new() -> Self {
+        Self {
+            inserted: AtomicBool::new(false),
+            entry: UnsafeCell::new(ListEntry::new()),
+        }
+    }
+
+    fn acquire_for_insertion(&self) -> bool {
+        self.inserted
+            .compare_exchange(false, true, Ordering::Acquire, Ordering::Relaxed)
+            .is_ok()
+    }
+
+    fn release_after_removal(&self) {
+        self.inserted.store(false, Ordering::Release);
+    }
+}
+
+impl<T: ?Sized> Default for Links<T> {
+    fn default() -> Self {
+        Self::new()
+    }
+}
+
+struct ListEntry<T: ?Sized> {
+    next: Option<NonNull<T>>,
+    prev: Option<NonNull<T>>,
+}
+
+impl<T: ?Sized> ListEntry<T> {
+    fn new() -> Self {
+        Self {
+            next: None,
+            prev: None,
+        }
+    }
+}
+
+/// A linked list.
+///
+/// # Invariants
+///
+/// The links of objects added to a list are owned by the list.
+pub(crate) struct RawList<G: GetLinks> {
+    head: Option<NonNull<G::EntryType>>,
+}
+
+impl<G: GetLinks> RawList<G> {
+    pub(crate) fn new() -> Self {
+        Self { head: None }
+    }
+
+    pub(crate) fn is_empty(&self) -> bool {
+        self.head.is_none()
+    }
+
+    fn insert_after_priv(
+        &mut self,
+        existing: &G::EntryType,
+        new_entry: &mut ListEntry<G::EntryType>,
+        new_ptr: Option<NonNull<G::EntryType>>,
+    ) {
+        {
+            // SAFETY: It's safe to get the previous entry of `existing` because the list cannot
+            // change.
+            let existing_links = unsafe { &mut *G::get_links(existing).entry.get() };
+            new_entry.next = existing_links.next;
+            existing_links.next = new_ptr;
+        }
+
+        new_entry.prev = Some(NonNull::from(existing));
+
+        // SAFETY: It's safe to get the next entry of `existing` because the list cannot change.
+        let next_links =
+            unsafe { &mut *G::get_links(new_entry.next.unwrap().as_ref()).entry.get() };
+        next_links.prev = new_ptr;
+    }
+
+    /// Inserts the given object after `existing`.
+    ///
+    /// # Safety
+    ///
+    /// Callers must ensure that `existing` points to a valid entry that is on the list.
+    pub(crate) unsafe fn insert_after(
+        &mut self,
+        existing: &G::EntryType,
+        new: &G::EntryType,
+    ) -> bool {
+        let links = G::get_links(new);
+        if !links.acquire_for_insertion() {
+            // Nothing to do if already inserted.
+            return false;
+        }
+
+        // SAFETY: The links are now owned by the list, so it is safe to get a mutable reference.
+        let new_entry = unsafe { &mut *links.entry.get() };
+        self.insert_after_priv(existing, new_entry, Some(NonNull::from(new)));
+        true
+    }
+
+    fn push_back_internal(&mut self, new: &G::EntryType) -> bool {
+        let links = G::get_links(new);
+        if !links.acquire_for_insertion() {
+            // Nothing to do if already inserted.
+            return false;
+        }
+
+        // SAFETY: The links are now owned by the list, so it is safe to get a mutable reference.
+        let new_entry = unsafe { &mut *links.entry.get() };
+        let new_ptr = Some(NonNull::from(new));
+        match self.back() {
+            // SAFETY: `back` is valid as the list cannot change.
+            Some(back) => self.insert_after_priv(unsafe { back.as_ref() }, new_entry, new_ptr),
+            None => {
+                self.head = new_ptr;
+                new_entry.next = new_ptr;
+                new_entry.prev = new_ptr;
+            }
+        }
+        true
+    }
+
+    pub(crate) unsafe fn push_back(&mut self, new: &G::EntryType) -> bool {
+        self.push_back_internal(new)
+    }
+
+    fn remove_internal(&mut self, data: &G::EntryType) -> bool {
+        let links = G::get_links(data);
+
+        // SAFETY: The links are now owned by the list, so it is safe to get a mutable reference.
+        let entry = unsafe { &mut *links.entry.get() };
+        let next = if let Some(next) = entry.next {
+            next
+        } else {
+            // Nothing to do if the entry is not on the list.
+            return false;
+        };
+
+        if ptr::eq(data, next.as_ptr()) {
+            // We're removing the only element.
+            self.head = None
+        } else {
+            // Update the head if we're removing it.
+            if let Some(raw_head) = self.head {
+                if ptr::eq(data, raw_head.as_ptr()) {
+                    self.head = Some(next);
+                }
+            }
+
+            // SAFETY: It's safe to get the previous entry because the list cannot change.
+            unsafe { &mut *G::get_links(entry.prev.unwrap().as_ref()).entry.get() }.next =
+                entry.next;
+
+            // SAFETY: It's safe to get the next entry because the list cannot change.
+            unsafe { &mut *G::get_links(next.as_ref()).entry.get() }.prev = entry.prev;
+        }
+
+        // Reset the links of the element we're removing so that we know it's not on any list.
+        entry.next = None;
+        entry.prev = None;
+        links.release_after_removal();
+        true
+    }
+
+    /// Removes the given entry.
+    ///
+    /// # Safety
+    ///
+    /// Callers must ensure that `data` is either on this list or in no list. It being on another
+    /// list leads to memory unsafety.
+    pub(crate) unsafe fn remove(&mut self, data: &G::EntryType) -> bool {
+        self.remove_internal(data)
+    }
+
+    fn pop_front_internal(&mut self) -> Option<NonNull<G::EntryType>> {
+        let head = self.head?;
+        // SAFETY: The head is on the list as we just got it from there and it cannot change.
+        unsafe { self.remove(head.as_ref()) };
+        Some(head)
+    }
+
+    pub(crate) fn pop_front(&mut self) -> Option<NonNull<G::EntryType>> {
+        self.pop_front_internal()
+    }
+
+    pub(crate) fn front(&self) -> Option<NonNull<G::EntryType>> {
+        self.head
+    }
+
+    pub(crate) fn back(&self) -> Option<NonNull<G::EntryType>> {
+        // SAFETY: The links of head are owned by the list, so it is safe to get a reference.
+        unsafe { &*G::get_links(self.head?.as_ref()).entry.get() }.prev
+    }
+
+    pub(crate) fn cursor_front(&self) -> Cursor<'_, G> {
+        Cursor::new(self, self.front())
+    }
+
+    pub(crate) fn cursor_front_mut(&mut self) -> CursorMut<'_, G> {
+        CursorMut::new(self, self.front())
+    }
+}
+
+struct CommonCursor<G: GetLinks> {
+    cur: Option<NonNull<G::EntryType>>,
+}
+
+impl<G: GetLinks> CommonCursor<G> {
+    fn new(cur: Option<NonNull<G::EntryType>>) -> Self {
+        Self { cur }
+    }
+
+    fn move_next(&mut self, list: &RawList<G>) {
+        match self.cur.take() {
+            None => self.cur = list.head,
+            Some(cur) => {
+                if let Some(head) = list.head {
+                    // SAFETY: We have a shared ref to the linked list, so the links can't change.
+                    let links = unsafe { &*G::get_links(cur.as_ref()).entry.get() };
+                    if links.next.unwrap() != head {
+                        self.cur = links.next;
+                    }
+                }
+            }
+        }
+    }
+
+    fn move_prev(&mut self, list: &RawList<G>) {
+        match list.head {
+            None => self.cur = None,
+            Some(head) => {
+                let next = match self.cur.take() {
+                    None => head,
+                    Some(cur) => {
+                        if cur == head {
+                            return;
+                        }
+                        cur
+                    }
+                };
+                // SAFETY: There's a shared ref to the list, so the links can't change.
+                let links = unsafe { &*G::get_links(next.as_ref()).entry.get() };
+                self.cur = links.prev;
+            }
+        }
+    }
+}
+
+/// A list cursor that allows traversing a linked list and inspecting elements.
+pub struct Cursor<'a, G: GetLinks> {
+    cursor: CommonCursor<G>,
+    list: &'a RawList<G>,
+}
+
+impl<'a, G: GetLinks> Cursor<'a, G> {
+    fn new(list: &'a RawList<G>, cur: Option<NonNull<G::EntryType>>) -> Self {
+        Self {
+            list,
+            cursor: CommonCursor::new(cur),
+        }
+    }
+
+    /// Returns the element the cursor is currently positioned on.
+    pub fn current(&self) -> Option<&'a G::EntryType> {
+        let cur = self.cursor.cur?;
+        // SAFETY: Objects must be kept alive while on the list.
+        Some(unsafe { &*cur.as_ptr() })
+    }
+
+    /// Moves the cursor to the next element.
+    pub fn move_next(&mut self) {
+        self.cursor.move_next(self.list);
+    }
+}
+
+pub(crate) struct CursorMut<'a, G: GetLinks> {
+    cursor: CommonCursor<G>,
+    list: &'a mut RawList<G>,
+}
+
+impl<'a, G: GetLinks> CursorMut<'a, G> {
+    fn new(list: &'a mut RawList<G>, cur: Option<NonNull<G::EntryType>>) -> Self {
+        Self {
+            list,
+            cursor: CommonCursor::new(cur),
+        }
+    }
+
+    pub(crate) fn current(&mut self) -> Option<&mut G::EntryType> {
+        let cur = self.cursor.cur?;
+        // SAFETY: Objects must be kept alive while on the list.
+        Some(unsafe { &mut *cur.as_ptr() })
+    }
+
+    /// Removes the entry the cursor is pointing to and advances the cursor to the next entry. It
+    /// returns a raw pointer to the removed element (if one is removed).
+    pub(crate) fn remove_current(&mut self) -> Option<NonNull<G::EntryType>> {
+        let entry = self.cursor.cur?;
+        self.cursor.move_next(self.list);
+        // SAFETY: The entry is on the list as we just got it from there and it cannot change.
+        unsafe { self.list.remove(entry.as_ref()) };
+        Some(entry)
+    }
+
+    pub(crate) fn peek_next(&mut self) -> Option<&mut G::EntryType> {
+        let mut new = CommonCursor::new(self.cursor.cur);
+        new.move_next(self.list);
+        // SAFETY: Objects must be kept alive while on the list.
+        Some(unsafe { &mut *new.cur?.as_ptr() })
+    }
+
+    pub(crate) fn peek_prev(&mut self) -> Option<&mut G::EntryType> {
+        let mut new = CommonCursor::new(self.cursor.cur);
+        new.move_prev(self.list);
+        // SAFETY: Objects must be kept alive while on the list.
+        Some(unsafe { &mut *new.cur?.as_ptr() })
+    }
+
+    pub(crate) fn move_next(&mut self) {
+        self.cursor.move_next(self.list);
+    }
+}
diff --git a/rust/kernel/rbtree.rs b/rust/kernel/rbtree.rs
new file mode 100644
index 000000000000..71112e306ec3
--- /dev/null
+++ b/rust/kernel/rbtree.rs
@@ -0,0 +1,562 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Red-black trees.
+//!
+//! C header: [`include/linux/rbtree.h`](../../../../include/linux/rbtree.h)
+//!
+//! Reference: <https://www.kernel.org/doc/html/latest/core-api/rbtree.html>
+
+use crate::{bindings, Result};
+use alloc::boxed::Box;
+use core::{
+    cmp::{Ord, Ordering},
+    iter::{IntoIterator, Iterator},
+    marker::PhantomData,
+    mem::MaybeUninit,
+    ptr::{addr_of_mut, NonNull},
+};
+
+struct Node<K, V> {
+    links: bindings::rb_node,
+    key: K,
+    value: V,
+}
+
+/// A red-black tree with owned nodes.
+///
+/// It is backed by the kernel C red-black trees.
+///
+/// # Invariants
+///
+/// Non-null parent/children pointers stored in instances of the `rb_node` C struct are always
+/// valid, and pointing to a field of our internal representation of a node.
+///
+/// # Examples
+///
+/// In the example below we do several operations on a tree. We note that insertions may fail if
+/// the system is out of memory.
+///
+/// ```
+/// # use kernel::prelude::*;
+/// use kernel::rbtree::RBTree;
+///
+/// fn rbtest() -> Result {
+///     // Create a new tree.
+///     let mut tree = RBTree::new();
+///
+///     // Insert three elements.
+///     tree.try_insert(20, 200)?;
+///     tree.try_insert(10, 100)?;
+///     tree.try_insert(30, 300)?;
+///
+///     // Check the nodes we just inserted.
+///     {
+///         let mut iter = tree.iter();
+///         assert_eq!(iter.next().unwrap(), (&10, &100));
+///         assert_eq!(iter.next().unwrap(), (&20, &200));
+///         assert_eq!(iter.next().unwrap(), (&30, &300));
+///         assert!(iter.next().is_none());
+///     }
+///
+///     // Print all elements.
+///     for (key, value) in &tree {
+///         pr_info!("{} = {}\n", key, value);
+///     }
+///
+///     // Replace one of the elements.
+///     tree.try_insert(10, 1000)?;
+///
+///     // Check that the tree reflects the replacement.
+///     {
+///         let mut iter = tree.iter();
+///         assert_eq!(iter.next().unwrap(), (&10, &1000));
+///         assert_eq!(iter.next().unwrap(), (&20, &200));
+///         assert_eq!(iter.next().unwrap(), (&30, &300));
+///         assert!(iter.next().is_none());
+///     }
+///
+///     // Change the value of one of the elements.
+///     *tree.get_mut(&30).unwrap() = 3000;
+///
+///     // Check that the tree reflects the update.
+///     {
+///         let mut iter = tree.iter();
+///         assert_eq!(iter.next().unwrap(), (&10, &1000));
+///         assert_eq!(iter.next().unwrap(), (&20, &200));
+///         assert_eq!(iter.next().unwrap(), (&30, &3000));
+///         assert!(iter.next().is_none());
+///     }
+///
+///     // Remove an element.
+///     tree.remove(&10);
+///
+///     // Check that the tree reflects the removal.
+///     {
+///         let mut iter = tree.iter();
+///         assert_eq!(iter.next().unwrap(), (&20, &200));
+///         assert_eq!(iter.next().unwrap(), (&30, &3000));
+///         assert!(iter.next().is_none());
+///     }
+///
+///     // Update all values.
+///     for value in tree.values_mut() {
+///         *value *= 10;
+///     }
+///
+///     // Check that the tree reflects the changes to values.
+///     {
+///         let mut iter = tree.iter();
+///         assert_eq!(iter.next().unwrap(), (&20, &2000));
+///         assert_eq!(iter.next().unwrap(), (&30, &30000));
+///         assert!(iter.next().is_none());
+///     }
+///
+///     Ok(())
+/// }
+/// ```
+///
+/// In the example below, we first allocate a node, acquire a spinlock, then insert the node into
+/// the tree. This is useful when the insertion context does not allow sleeping, for example, when
+/// holding a spinlock.
+///
+/// ```
+/// # use kernel::prelude::*;
+/// use kernel::{rbtree::RBTree, sync::SpinLock};
+///
+/// fn insert_test(tree: &SpinLock<RBTree<u32, u32>>) -> Result {
+///     // Pre-allocate node. This may fail (as it allocates memory).
+///     let node = RBTree::try_allocate_node(10, 100)?;
+///
+///     // Insert node while holding the lock. It is guaranteed to succeed with no allocation
+///     // attempts.
+///     let mut guard = tree.lock();
+///     guard.insert(node);
+///     Ok(())
+/// }
+/// ```
+///
+/// In the example below, we reuse an existing node allocation from an element we removed.
+///
+/// ```
+/// # use kernel::prelude::*;
+/// use kernel::rbtree::RBTree;
+///
+/// fn reuse_test() -> Result {
+///     // Create a new tree.
+///     let mut tree = RBTree::new();
+///
+///     // Insert three elements.
+///     tree.try_insert(20, 200)?;
+///     tree.try_insert(10, 100)?;
+///     tree.try_insert(30, 300)?;
+///
+///     // Check the nodes we just inserted.
+///     {
+///         let mut iter = tree.iter();
+///         assert_eq!(iter.next().unwrap(), (&10, &100));
+///         assert_eq!(iter.next().unwrap(), (&20, &200));
+///         assert_eq!(iter.next().unwrap(), (&30, &300));
+///         assert!(iter.next().is_none());
+///     }
+///
+///     // Remove a node, getting back ownership of it.
+///     let existing = tree.remove_node(&30).unwrap();
+///
+///     // Check that the tree reflects the removal.
+///     {
+///         let mut iter = tree.iter();
+///         assert_eq!(iter.next().unwrap(), (&10, &100));
+///         assert_eq!(iter.next().unwrap(), (&20, &200));
+///         assert!(iter.next().is_none());
+///     }
+///
+///     // Turn the node into a reservation so that we can reuse it with a different key/value.
+///     let reservation = existing.into_reservation();
+///
+///     // Insert a new node into the tree, reusing the previous allocation. This is guaranteed to
+///     // succeed (no memory allocations).
+///     tree.insert(reservation.into_node(15, 150));
+///
+///     // Check that the tree reflect the new insertion.
+///     {
+///         let mut iter = tree.iter();
+///         assert_eq!(iter.next().unwrap(), (&10, &100));
+///         assert_eq!(iter.next().unwrap(), (&15, &150));
+///         assert_eq!(iter.next().unwrap(), (&20, &200));
+///         assert!(iter.next().is_none());
+///     }
+///
+///     Ok(())
+/// }
+/// ```
+pub struct RBTree<K, V> {
+    root: bindings::rb_root,
+    _p: PhantomData<Node<K, V>>,
+}
+
+impl<K, V> RBTree<K, V> {
+    /// Creates a new and empty tree.
+    pub fn new() -> Self {
+        Self {
+            // INVARIANT: There are no nodes in the tree, so the invariant holds vacuously.
+            root: bindings::rb_root::default(),
+            _p: PhantomData,
+        }
+    }
+
+    /// Tries to insert a new value into the tree.
+    ///
+    /// It overwrites a node if one already exists with the same key and returns it (containing the
+    /// key/value pair). Returns [`None`] if a node with the same key didn't already exist.
+    ///
+    /// Returns an error if it cannot allocate memory for the new node.
+    pub fn try_insert(&mut self, key: K, value: V) -> Result<Option<RBTreeNode<K, V>>>
+    where
+        K: Ord,
+    {
+        Ok(self.insert(Self::try_allocate_node(key, value)?))
+    }
+
+    /// Allocates memory for a node to be eventually initialised and inserted into the tree via a
+    /// call to [`RBTree::insert`].
+    pub fn try_reserve_node() -> Result<RBTreeNodeReservation<K, V>> {
+        Ok(RBTreeNodeReservation {
+            node: Box::try_new(MaybeUninit::uninit())?,
+        })
+    }
+
+    /// Allocates and initialiases a node that can be inserted into the tree via
+    /// [`RBTree::insert`].
+    pub fn try_allocate_node(key: K, value: V) -> Result<RBTreeNode<K, V>> {
+        Ok(Self::try_reserve_node()?.into_node(key, value))
+    }
+
+    /// Inserts a new node into the tree.
+    ///
+    /// It overwrites a node if one already exists with the same key and returns it (containing the
+    /// key/value pair). Returns [`None`] if a node with the same key didn't already exist.
+    ///
+    /// This function always succeeds.
+    pub fn insert(&mut self, node: RBTreeNode<K, V>) -> Option<RBTreeNode<K, V>>
+    where
+        K: Ord,
+    {
+        let RBTreeNode { node } = node;
+        let node = Box::into_raw(node);
+        // SAFETY: `node` is valid at least until we call `Box::from_raw`, which only happens when
+        // the node is removed or replaced.
+        let node_links = unsafe { addr_of_mut!((*node).links) };
+        let mut new_link: &mut *mut bindings::rb_node = &mut self.root.rb_node;
+        let mut parent = core::ptr::null_mut();
+        while !new_link.is_null() {
+            let this = crate::container_of!(*new_link, Node<K, V>, links);
+
+            parent = *new_link;
+
+            // SAFETY: `this` is a non-null node so it is valid by the type invariants. `node` is
+            // valid until the node is removed.
+            match unsafe { (*node).key.cmp(&(*this).key) } {
+                // SAFETY: `parent` is a non-null node so it is valid by the type invariants.
+                Ordering::Less => new_link = unsafe { &mut (*parent).rb_left },
+                // SAFETY: `parent` is a non-null node so it is valid by the type invariants.
+                Ordering::Greater => new_link = unsafe { &mut (*parent).rb_right },
+                Ordering::Equal => {
+                    // INVARIANT: We are replacing an existing node with a new one, which is valid.
+                    // It remains valid because we "forgot" it with `Box::into_raw`.
+                    // SAFETY: All pointers are non-null and valid (parent, despite the name, really
+                    // is the node we're replacing).
+                    unsafe { bindings::rb_replace_node(parent, node_links, &mut self.root) };
+
+                    // INVARIANT: The node is being returned and the caller may free it, however,
+                    // it was removed from the tree. So the invariants still hold.
+                    return Some(RBTreeNode {
+                        // SAFETY: `this` was a node in the tree, so it is valid.
+                        node: unsafe { Box::from_raw(this as _) },
+                    });
+                }
+            }
+        }
+
+        // INVARIANT: We are linking in a new node, which is valid. It remains valid because we
+        // "forgot" it with `Box::into_raw`.
+        // SAFETY: All pointers are non-null and valid (`*new_link` is null, but `new_link` is a
+        // mutable reference).
+        unsafe { bindings::rb_link_node(node_links, parent, new_link) };
+
+        // SAFETY: All pointers are valid. `node` has just been inserted into the tree.
+        unsafe { bindings::rb_insert_color(node_links, &mut self.root) };
+        None
+    }
+
+    /// Returns a node with the given key, if one exists.
+    fn find(&self, key: &K) -> Option<NonNull<Node<K, V>>>
+    where
+        K: Ord,
+    {
+        let mut node = self.root.rb_node;
+        while !node.is_null() {
+            let this = crate::container_of!(node, Node<K, V>, links);
+            // SAFETY: `this` is a non-null node so it is valid by the type invariants.
+            node = match key.cmp(unsafe { &(*this).key }) {
+                // SAFETY: `node` is a non-null node so it is valid by the type invariants.
+                Ordering::Less => unsafe { (*node).rb_left },
+                // SAFETY: `node` is a non-null node so it is valid by the type invariants.
+                Ordering::Greater => unsafe { (*node).rb_right },
+                Ordering::Equal => return NonNull::new(this as _),
+            }
+        }
+        None
+    }
+
+    /// Returns a reference to the value corresponding to the key.
+    pub fn get(&self, key: &K) -> Option<&V>
+    where
+        K: Ord,
+    {
+        // SAFETY: The `find` return value is a node in the tree, so it is valid.
+        self.find(key).map(|node| unsafe { &node.as_ref().value })
+    }
+
+    /// Returns a mutable reference to the value corresponding to the key.
+    pub fn get_mut(&mut self, key: &K) -> Option<&mut V>
+    where
+        K: Ord,
+    {
+        // SAFETY: The `find` return value is a node in the tree, so it is valid.
+        self.find(key)
+            .map(|mut node| unsafe { &mut node.as_mut().value })
+    }
+
+    /// Removes the node with the given key from the tree.
+    ///
+    /// It returns the node that was removed if one exists, or [`None`] otherwise.
+    pub fn remove_node(&mut self, key: &K) -> Option<RBTreeNode<K, V>>
+    where
+        K: Ord,
+    {
+        let mut node = self.find(key)?;
+
+        // SAFETY: The `find` return value is a node in the tree, so it is valid.
+        unsafe { bindings::rb_erase(&mut node.as_mut().links, &mut self.root) };
+
+        // INVARIANT: The node is being returned and the caller may free it, however, it was
+        // removed from the tree. So the invariants still hold.
+        Some(RBTreeNode {
+            // SAFETY: The `find` return value was a node in the tree, so it is valid.
+            node: unsafe { Box::from_raw(node.as_ptr()) },
+        })
+    }
+
+    /// Removes the node with the given key from the tree.
+    ///
+    /// It returns the value that was removed if one exists, or [`None`] otherwise.
+    pub fn remove(&mut self, key: &K) -> Option<V>
+    where
+        K: Ord,
+    {
+        let node = self.remove_node(key)?;
+        let RBTreeNode { node } = node;
+        let Node {
+            links: _,
+            key: _,
+            value,
+        } = *node;
+        Some(value)
+    }
+
+    /// Returns an iterator over the tree nodes, sorted by key.
+    pub fn iter(&self) -> RBTreeIterator<'_, K, V> {
+        RBTreeIterator {
+            _tree: PhantomData,
+            // SAFETY: `root` is valid as it's embedded in `self` and we have a valid `self`.
+            next: unsafe { bindings::rb_first(&self.root) },
+        }
+    }
+
+    /// Returns a mutable iterator over the tree nodes, sorted by key.
+    pub fn iter_mut(&mut self) -> RBTreeIteratorMut<'_, K, V> {
+        RBTreeIteratorMut {
+            _tree: PhantomData,
+            // SAFETY: `root` is valid as it's embedded in `self` and we have a valid `self`.
+            next: unsafe { bindings::rb_first(&self.root) },
+        }
+    }
+
+    /// Returns an iterator over the keys of the nodes in the tree, in sorted order.
+    pub fn keys(&self) -> impl Iterator<Item = &'_ K> {
+        self.iter().map(|(k, _)| k)
+    }
+
+    /// Returns an iterator over the values of the nodes in the tree, sorted by key.
+    pub fn values(&self) -> impl Iterator<Item = &'_ V> {
+        self.iter().map(|(_, v)| v)
+    }
+
+    /// Returns a mutable iterator over the values of the nodes in the tree, sorted by key.
+    pub fn values_mut(&mut self) -> impl Iterator<Item = &'_ mut V> {
+        self.iter_mut().map(|(_, v)| v)
+    }
+}
+
+impl<K, V> Default for RBTree<K, V> {
+    fn default() -> Self {
+        Self::new()
+    }
+}
+
+impl<K, V> Drop for RBTree<K, V> {
+    fn drop(&mut self) {
+        // SAFETY: `root` is valid as it's embedded in `self` and we have a valid `self`.
+        let mut next = unsafe { bindings::rb_first_postorder(&self.root) };
+
+        // INVARIANT: The loop invariant is that all tree nodes from `next` in postorder are valid.
+        while !next.is_null() {
+            let this = crate::container_of!(next, Node<K, V>, links);
+
+            // Find out what the next node is before disposing of the current one.
+            // SAFETY: `next` and all nodes in postorder are still valid.
+            next = unsafe { bindings::rb_next_postorder(next) };
+
+            // INVARIANT: This is the destructor, so we break the type invariant during clean-up,
+            // but it is not observable. The loop invariant is still maintained.
+            // SAFETY: `this` is valid per the loop invariant.
+            unsafe { Box::from_raw(this as *mut Node<K, V>) };
+        }
+    }
+}
+
+impl<'a, K, V> IntoIterator for &'a RBTree<K, V> {
+    type Item = (&'a K, &'a V);
+    type IntoIter = RBTreeIterator<'a, K, V>;
+
+    fn into_iter(self) -> Self::IntoIter {
+        self.iter()
+    }
+}
+
+/// An iterator over the nodes of a [`RBTree`].
+///
+/// Instances are created by calling [`RBTree::iter`].
+pub struct RBTreeIterator<'a, K, V> {
+    _tree: PhantomData<&'a RBTree<K, V>>,
+    next: *mut bindings::rb_node,
+}
+
+impl<'a, K, V> Iterator for RBTreeIterator<'a, K, V> {
+    type Item = (&'a K, &'a V);
+
+    fn next(&mut self) -> Option<Self::Item> {
+        if self.next.is_null() {
+            return None;
+        }
+
+        let cur = crate::container_of!(self.next, Node<K, V>, links);
+
+        // SAFETY: The reference to the tree used to create the iterator outlives the iterator, so
+        // the tree cannot change. By the tree invariant, all nodes are valid.
+        self.next = unsafe { bindings::rb_next(self.next) };
+
+        // SAFETY: By the same reasoning above, it is safe to dereference the node. Additionally,
+        // it is ok to return a reference to members because the iterator must outlive it.
+        Some(unsafe { (&(*cur).key, &(*cur).value) })
+    }
+}
+
+impl<'a, K, V> IntoIterator for &'a mut RBTree<K, V> {
+    type Item = (&'a K, &'a mut V);
+    type IntoIter = RBTreeIteratorMut<'a, K, V>;
+
+    fn into_iter(self) -> Self::IntoIter {
+        self.iter_mut()
+    }
+}
+
+/// A mutable iterator over the nodes of a [`RBTree`].
+///
+/// Instances are created by calling [`RBTree::iter_mut`].
+pub struct RBTreeIteratorMut<'a, K, V> {
+    _tree: PhantomData<&'a RBTree<K, V>>,
+    next: *mut bindings::rb_node,
+}
+
+impl<'a, K, V> Iterator for RBTreeIteratorMut<'a, K, V> {
+    type Item = (&'a K, &'a mut V);
+
+    fn next(&mut self) -> Option<Self::Item> {
+        if self.next.is_null() {
+            return None;
+        }
+
+        let cur = crate::container_of!(self.next, Node<K, V>, links) as *mut Node<K, V>;
+
+        // SAFETY: The reference to the tree used to create the iterator outlives the iterator, so
+        // the tree cannot change (except for the value of previous nodes, but those don't affect
+        // the iteration process). By the tree invariant, all nodes are valid.
+        self.next = unsafe { bindings::rb_next(self.next) };
+
+        // SAFETY: By the same reasoning above, it is safe to dereference the node. Additionally,
+        // it is ok to return a reference to members because the iterator must outlive it.
+        Some(unsafe { (&(*cur).key, &mut (*cur).value) })
+    }
+}
+
+/// A memory reservation for a red-black tree node.
+///
+/// It contains the memory needed to hold a node that can be inserted into a red-black tree. One
+/// can be obtained by directly allocating it ([`RBTree::try_reserve_node`]) or by "uninitialising"
+/// ([`RBTreeNode::into_reservation`]) an actual node (usually returned by some operation like
+/// removal from a tree).
+pub struct RBTreeNodeReservation<K, V> {
+    node: Box<MaybeUninit<Node<K, V>>>,
+}
+
+impl<K, V> RBTreeNodeReservation<K, V> {
+    /// Initialises a node reservation.
+    ///
+    /// It then becomes an [`RBTreeNode`] that can be inserted into a tree.
+    pub fn into_node(mut self, key: K, value: V) -> RBTreeNode<K, V> {
+        let node_ptr = self.node.as_mut_ptr();
+        // SAFETY: `node_ptr` is valid, and so are its fields.
+        unsafe { addr_of_mut!((*node_ptr).links).write(bindings::rb_node::default()) };
+        // SAFETY: `node_ptr` is valid, and so are its fields.
+        unsafe { addr_of_mut!((*node_ptr).key).write(key) };
+        // SAFETY: `node_ptr` is valid, and so are its fields.
+        unsafe { addr_of_mut!((*node_ptr).value).write(value) };
+        let raw = Box::into_raw(self.node);
+        RBTreeNode {
+            // SAFETY: The pointer came from a `MaybeUninit<Node>` whose fields have all been
+            // initialised. Additionally, it has the same layout as `Node`.
+            node: unsafe { Box::from_raw(raw as _) },
+        }
+    }
+}
+
+/// A red-black tree node.
+///
+/// The node is fully initialised (with key and value) and can be inserted into a tree without any
+/// extra allocations or failure paths.
+pub struct RBTreeNode<K, V> {
+    node: Box<Node<K, V>>,
+}
+
+impl<K, V> RBTreeNode<K, V> {
+    /// "Uninitialises" a node.
+    ///
+    /// It then becomes a reservation that can be re-initialised into a different node (i.e., with
+    /// a different key and/or value).
+    ///
+    /// The existing key and value are dropped in-place as part of this operation, that is, memory
+    /// may be freed (but only for the key/value; memory for the node itself is kept for reuse).
+    pub fn into_reservation(self) -> RBTreeNodeReservation<K, V> {
+        let raw = Box::into_raw(self.node);
+        let mut ret = RBTreeNodeReservation {
+            // SAFETY: The pointer came from a valid `Node`, which has the same layout as
+            // `MaybeUninit<Node>`.
+            node: unsafe { Box::from_raw(raw as _) },
+        };
+        // SAFETY: Although the type is `MaybeUninit<Node>`, we know it has been initialised
+        // because it came from a `Node`. So it is safe to drop it.
+        unsafe { core::ptr::drop_in_place(ret.node.as_mut_ptr()) };
+        ret
+    }
+}
diff --git a/rust/kernel/revocable.rs b/rust/kernel/revocable.rs
new file mode 100644
index 000000000000..9cc65ca3a1b6
--- /dev/null
+++ b/rust/kernel/revocable.rs
@@ -0,0 +1,163 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Revocable objects.
+//!
+//! The [`Revocable`] type wraps other types and allows access to them to be revoked. The existence
+//! of a [`RevocableGuard`] ensures that objects remain valid.
+
+use crate::bindings;
+use core::{
+    cell::UnsafeCell,
+    marker::PhantomData,
+    mem::ManuallyDrop,
+    ops::Deref,
+    ptr::drop_in_place,
+    sync::atomic::{AtomicBool, Ordering},
+};
+
+/// An object that can become inaccessible at runtime.
+///
+/// Once access is revoked and all concurrent users complete (i.e., all existing instances of
+/// [`RevocableGuard`] are dropped), the wrapped object is also dropped.
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::revocable::Revocable;
+///
+/// struct Example {
+///     a: u32,
+///     b: u32,
+/// }
+///
+/// fn add_two(v: &Revocable<Example>) -> Option<u32> {
+///     let guard = v.try_access()?;
+///     Some(guard.a + guard.b)
+/// }
+///
+/// fn example() {
+///     let v = Revocable::new(Example { a: 10, b: 20 });
+///     assert_eq!(add_two(&v), Some(30));
+///     v.revoke();
+///     assert_eq!(add_two(&v), None);
+/// }
+/// ```
+pub struct Revocable<T: ?Sized> {
+    is_available: AtomicBool,
+    data: ManuallyDrop<UnsafeCell<T>>,
+}
+
+// SAFETY: `Revocable` is `Send` if the wrapped object is also `Send`. This is because while the
+// functionality exposed by `Revocable` can be accessed from any thread/CPU, it is possible that
+// this isn't supported by the wrapped object.
+unsafe impl<T: ?Sized + Send> Send for Revocable<T> {}
+
+// SAFETY: `Revocable` is `Sync` if the wrapped object is both `Send` and `Sync`. We require `Send`
+// from the wrapped object as well because  of `Revocable::revoke`, which can trigger the `Drop`
+// implementation of the wrapped object from an arbitrary thread.
+unsafe impl<T: ?Sized + Sync + Send> Sync for Revocable<T> {}
+
+impl<T> Revocable<T> {
+    /// Creates a new revocable instance of the given data.
+    pub fn new(data: T) -> Self {
+        Self {
+            is_available: AtomicBool::new(true),
+            data: ManuallyDrop::new(UnsafeCell::new(data)),
+        }
+    }
+}
+
+impl<T: ?Sized> Revocable<T> {
+    /// Tries to access the \[revocable\] wrapped object.
+    ///
+    /// Returns `None` if the object has been revoked and is therefore no longer accessible.
+    ///
+    /// Returns a guard that gives access to the object otherwise; the object is guaranteed to
+    /// remain accessible while the guard is alive. In such cases, callers are not allowed to sleep
+    /// because another CPU may be waiting to complete the revocation of this object.
+    pub fn try_access(&self) -> Option<RevocableGuard<'_, T>> {
+        let guard = RevocableGuard::new(self.data.get());
+        if self.is_available.load(Ordering::Relaxed) {
+            Some(guard)
+        } else {
+            None
+        }
+    }
+
+    /// Revokes access to and drops the wrapped object.
+    ///
+    /// Access to the object is revoked immediately to new callers of [`Revocable::try_access`]. If
+    /// there are concurrent users of the object (i.e., ones that called [`Revocable::try_access`]
+    /// beforehand and still haven't dropped the returned guard), this function waits for the
+    /// concurrent access to complete before dropping the wrapped object.
+    pub fn revoke(&self) {
+        if self
+            .is_available
+            .compare_exchange(true, false, Ordering::Relaxed, Ordering::Relaxed)
+            .is_ok()
+        {
+            // SAFETY: Just an FFI call, there are no further requirements.
+            unsafe { bindings::synchronize_rcu() };
+
+            // SAFETY: We know `self.data` is valid because only one CPU can succeed the
+            // `compare_exchange` above that takes `is_available` from `true` to `false`.
+            unsafe { drop_in_place(self.data.get()) };
+        }
+    }
+}
+
+impl<T: ?Sized> Drop for Revocable<T> {
+    fn drop(&mut self) {
+        // Drop only if the data hasn't been revoked yet (in which case it has already been
+        // dropped).
+        if *self.is_available.get_mut() {
+            // SAFETY: We know `self.data` is valid because no other CPU has changed
+            // `is_available` to `false` yet, and no other CPU can do it anymore because this CPU
+            // holds the only reference (mutable) to `self` now.
+            unsafe { drop_in_place(self.data.get()) };
+        }
+    }
+}
+
+/// A guard that allows access to a revocable object and keeps it alive.
+///
+/// CPUs may not sleep while holding on to [`RevocableGuard`] because it's in atomic context
+/// holding the RCU read-side lock.
+///
+/// # Invariants
+///
+/// The RCU read-side lock is held while the guard is alive.
+pub struct RevocableGuard<'a, T: ?Sized> {
+    data_ref: *const T,
+    _p: PhantomData<&'a ()>,
+}
+
+impl<T: ?Sized> RevocableGuard<'_, T> {
+    fn new(data_ref: *const T) -> Self {
+        // SAFETY: Just an FFI call, there are no further requirements.
+        unsafe { bindings::rcu_read_lock() };
+
+        // INVARIANTS: The RCU read-side lock was just acquired.
+        Self {
+            data_ref,
+            _p: PhantomData,
+        }
+    }
+}
+
+impl<T: ?Sized> Drop for RevocableGuard<'_, T> {
+    fn drop(&mut self) {
+        // SAFETY: By the type invariants, we know that we hold the RCU read-side lock.
+        unsafe { bindings::rcu_read_unlock() };
+    }
+}
+
+impl<T: ?Sized> Deref for RevocableGuard<'_, T> {
+    type Target = T;
+
+    fn deref(&self) -> &Self::Target {
+        // SAFETY: By the type invariants, we hold the rcu read-side lock, so the object is
+        // guaranteed to remain valid.
+        unsafe { &*self.data_ref }
+    }
+}
diff --git a/rust/kernel/security.rs b/rust/kernel/security.rs
new file mode 100644
index 000000000000..2004d01233f4
--- /dev/null
+++ b/rust/kernel/security.rs
@@ -0,0 +1,36 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Linux Security Modules (LSM).
+//!
+//! C header: [`include/linux/security.h`](../../../../include/linux/security.h).
+
+use crate::{bindings, cred::Credential, file::File, to_result, Result};
+
+/// Calls the security modules to determine if the given task can become the manager of a binder
+/// context.
+pub fn binder_set_context_mgr(mgr: &Credential) -> Result {
+    // SAFETY: By the `Credential` invariants, `mgr.ptr` is valid.
+    to_result(|| unsafe { bindings::security_binder_set_context_mgr(mgr.ptr) })
+}
+
+/// Calls the security modules to determine if binder transactions are allowed from task `from` to
+/// task `to`.
+pub fn binder_transaction(from: &Credential, to: &Credential) -> Result {
+    // SAFETY: By the `Credential` invariants, `from.ptr` and `to.ptr` are valid.
+    to_result(|| unsafe { bindings::security_binder_transaction(from.ptr, to.ptr) })
+}
+
+/// Calls the security modules to determine if task `from` is allowed to send binder objects
+/// (owned by itself or other processes) to task `to` through a binder transaction.
+pub fn binder_transfer_binder(from: &Credential, to: &Credential) -> Result {
+    // SAFETY: By the `Credential` invariants, `from.ptr` and `to.ptr` are valid.
+    to_result(|| unsafe { bindings::security_binder_transfer_binder(from.ptr, to.ptr) })
+}
+
+/// Calls the security modules to determine if task `from` is allowed to send the given file to
+/// task `to` (which would get its own file descriptor) through a binder transaction.
+pub fn binder_transfer_file(from: &Credential, to: &Credential, file: &File) -> Result {
+    // SAFETY: By the `Credential` invariants, `from.ptr` and `to.ptr` are valid. Similarly, by the
+    // `File` invariants, `file.ptr` is also valid.
+    to_result(|| unsafe { bindings::security_binder_transfer_file(from.ptr, to.ptr, file.ptr) })
+}
diff --git a/rust/kernel/static_assert.rs b/rust/kernel/static_assert.rs
new file mode 100644
index 000000000000..a80d8ab57564
--- /dev/null
+++ b/rust/kernel/static_assert.rs
@@ -0,0 +1,39 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Static assert.
+
+/// Static assert (i.e. compile-time assert).
+///
+/// Similar to C11 [`_Static_assert`] and C++11 [`static_assert`].
+///
+/// The feature may be added to Rust in the future: see [RFC 2790].
+///
+/// [`_Static_assert`]: https://en.cppreference.com/w/c/language/_Static_assert
+/// [`static_assert`]: https://en.cppreference.com/w/cpp/language/static_assert
+/// [RFC 2790]: https://github.com/rust-lang/rfcs/issues/2790
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::prelude::*;
+/// static_assert!(42 > 24);
+/// static_assert!(core::mem::size_of::<u8>() == 1);
+///
+/// const X: &[u8] = b"bar";
+/// static_assert!(X[1] == 'a' as u8);
+///
+/// const fn f(x: i32) -> i32 {
+///     x + 2
+/// }
+/// static_assert!(f(40) == 42);
+/// ```
+#[macro_export]
+macro_rules! static_assert {
+    ($condition:expr) => {
+        // Based on the latest one in `rustc`'s one before it was [removed].
+        //
+        // [removed]: https://github.com/rust-lang/rust/commit/c2dad1c6b9f9636198d7c561b47a2974f5103f6d
+        #[allow(dead_code)]
+        const _: () = [()][!($condition) as usize];
+    };
+}
diff --git a/rust/kernel/std_vendor.rs b/rust/kernel/std_vendor.rs
new file mode 100644
index 000000000000..492388d7ce10
--- /dev/null
+++ b/rust/kernel/std_vendor.rs
@@ -0,0 +1,150 @@
+// SPDX-License-Identifier: Apache-2.0 OR MIT
+
+//! The contents of this file come from the Rust standard library, hosted in the
+//! <https://github.com/rust-lang/rust> repository. For copyright details, see
+//! <https://github.com/rust-lang/rust/blob/master/COPYRIGHT>.
+
+/// [`std::dbg`], but using [`pr_info`] instead of [`eprintln`].
+///
+/// Prints and returns the value of a given expression for quick and dirty
+/// debugging.
+///
+/// An example:
+///
+/// ```rust
+/// let a = 2;
+/// let b = dbg!(a * 2) + 1;
+/// //      ^-- prints: [src/main.rs:2] a * 2 = 4
+/// assert_eq!(b, 5);
+/// ```
+///
+/// The macro works by using the `Debug` implementation of the type of
+/// the given expression to print the value with [`printk`] along with the
+/// source location of the macro invocation as well as the source code
+/// of the expression.
+///
+/// Invoking the macro on an expression moves and takes ownership of it
+/// before returning the evaluated expression unchanged. If the type
+/// of the expression does not implement `Copy` and you don't want
+/// to give up ownership, you can instead borrow with `dbg!(&expr)`
+/// for some expression `expr`.
+///
+/// The `dbg!` macro works exactly the same in release builds.
+/// This is useful when debugging issues that only occur in release
+/// builds or when debugging in release mode is significantly faster.
+///
+/// Note that the macro is intended as a debugging tool and therefore you
+/// should avoid having uses of it in version control for long periods
+/// (other than in tests and similar).
+///
+/// # Stability
+///
+/// The exact output printed by this macro should not be relied upon
+/// and is subject to future changes.
+///
+/// # Further examples
+///
+/// With a method call:
+///
+/// ```rust
+/// fn foo(n: usize) {
+///     if let Some(_) = dbg!(n.checked_sub(4)) {
+///         // ...
+///     }
+/// }
+///
+/// foo(3)
+/// ```
+///
+/// This prints to the kernel log:
+///
+/// ```text,ignore
+/// [src/main.rs:4] n.checked_sub(4) = None
+/// ```
+///
+/// Naive factorial implementation:
+///
+/// ```rust
+/// fn factorial(n: u32) -> u32 {
+///     if dbg!(n <= 1) {
+///         dbg!(1)
+///     } else {
+///         dbg!(n * factorial(n - 1))
+///     }
+/// }
+///
+/// dbg!(factorial(4));
+/// ```
+///
+/// This prints to the kernel log:
+///
+/// ```text,ignore
+/// [src/main.rs:3] n <= 1 = false
+/// [src/main.rs:3] n <= 1 = false
+/// [src/main.rs:3] n <= 1 = false
+/// [src/main.rs:3] n <= 1 = true
+/// [src/main.rs:4] 1 = 1
+/// [src/main.rs:5] n * factorial(n - 1) = 2
+/// [src/main.rs:5] n * factorial(n - 1) = 6
+/// [src/main.rs:5] n * factorial(n - 1) = 24
+/// [src/main.rs:11] factorial(4) = 24
+/// ```
+///
+/// The `dbg!(..)` macro moves the input:
+///
+/// ```compile_fail
+/// /// A wrapper around `usize` which importantly is not Copyable.
+/// #[derive(Debug)]
+/// struct NoCopy(usize);
+///
+/// let a = NoCopy(42);
+/// let _ = dbg!(a); // <-- `a` is moved here.
+/// let _ = dbg!(a); // <-- `a` is moved again; error!
+/// ```
+///
+/// You can also use `dbg!()` without a value to just print the
+/// file and line whenever it's reached.
+///
+/// Finally, if you want to `dbg!(..)` multiple values, it will treat them as
+/// a tuple (and return it, too):
+///
+/// ```
+/// assert_eq!(dbg!(1usize, 2u32), (1, 2));
+/// ```
+///
+/// However, a single argument with a trailing comma will still not be treated
+/// as a tuple, following the convention of ignoring trailing commas in macro
+/// invocations. You can use a 1-tuple directly if you need one:
+///
+/// ```
+/// assert_eq!(1, dbg!(1u32,)); // trailing comma ignored
+/// assert_eq!((1,), dbg!((1u32,))); // 1-tuple
+/// ```
+///
+/// [`std::dbg`]: https://doc.rust-lang.org/std/macro.dbg.html
+/// [`eprintln`]: https://doc.rust-lang.org/std/macro.eprintln.html
+/// [`printk`]: https://www.kernel.org/doc/html/latest/core-api/printk-basics.html
+#[macro_export]
+macro_rules! dbg {
+    // NOTE: We cannot use `concat!` to make a static string as a format argument
+    // of `pr_info!` because `file!` could contain a `{` or
+    // `$val` expression could be a block (`{ .. }`), in which case the `pr_info!`
+    // will be malformed.
+    () => {
+        $crate::pr_info!("[{}:{}]\n", ::core::file!(), ::core::line!())
+    };
+    ($val:expr $(,)?) => {
+        // Use of `match` here is intentional because it affects the lifetimes
+        // of temporaries - https://stackoverflow.com/a/48732525/1063961
+        match $val {
+            tmp => {
+                $crate::pr_info!("[{}:{}] {} = {:#?}\n",
+                    ::core::file!(), ::core::line!(), ::core::stringify!($val), &tmp);
+                tmp
+            }
+        }
+    };
+    ($($val:expr),+ $(,)?) => {
+        ($($crate::dbg!($val)),+,)
+    };
+}
diff --git a/rust/kernel/str.rs b/rust/kernel/str.rs
new file mode 100644
index 000000000000..48960e44d205
--- /dev/null
+++ b/rust/kernel/str.rs
@@ -0,0 +1,401 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! String representations.
+
+use core::fmt::{self, Write};
+use core::ops::{self, Deref, Index};
+
+use crate::bindings;
+use crate::c_types;
+
+/// Byte string without UTF-8 validity guarantee.
+///
+/// `BStr` is simply an alias to `[u8]`, but has a more evident semantical meaning.
+pub type BStr = [u8];
+
+/// Creates a new [`BStr`] from a string literal.
+///
+/// `b_str!` converts the supplied string literal to byte string, so non-ASCII
+/// characters can be included.
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::b_str;
+/// # use kernel::str::BStr;
+/// const MY_BSTR: &'static BStr = b_str!("My awesome BStr!");
+/// ```
+#[macro_export]
+macro_rules! b_str {
+    ($str:literal) => {{
+        const S: &'static str = $str;
+        const C: &'static $crate::str::BStr = S.as_bytes();
+        C
+    }};
+}
+
+/// Possible errors when using conversion functions in [`CStr`].
+#[derive(Debug, Clone, Copy)]
+pub enum CStrConvertError {
+    /// Supplied bytes contain an interior `NUL`.
+    InteriorNul,
+
+    /// Supplied bytes are not terminated by `NUL`.
+    NotNulTerminated,
+}
+
+impl From<CStrConvertError> for crate::Error {
+    #[inline]
+    fn from(_: CStrConvertError) -> crate::Error {
+        crate::Error::EINVAL
+    }
+}
+
+/// A string that is guaranteed to have exactly one `NUL` byte, which is at the
+/// end.
+///
+/// Used for interoperability with kernel APIs that take C strings.
+#[repr(transparent)]
+pub struct CStr([u8]);
+
+impl CStr {
+    /// Returns the length of this string excluding `NUL`.
+    #[inline]
+    pub const fn len(&self) -> usize {
+        self.len_with_nul() - 1
+    }
+
+    /// Returns the length of this string with `NUL`.
+    #[inline]
+    pub const fn len_with_nul(&self) -> usize {
+        // SAFETY: This is one of the invariant of `CStr`.
+        // We add a `unreachable_unchecked` here to hint the optimizer that
+        // the value returned from this function is non-zero.
+        if self.0.is_empty() {
+            unsafe { core::hint::unreachable_unchecked() };
+        }
+        self.0.len()
+    }
+
+    /// Returns `true` if the string only includes `NUL`.
+    #[inline]
+    pub const fn is_empty(&self) -> bool {
+        self.len() == 0
+    }
+
+    /// Wraps a raw C string pointer.
+    ///
+    /// # Safety
+    ///
+    /// `ptr` must be a valid pointer to a `NUL`-terminated C string, and it must
+    /// last at least `'a`. When `CStr` is alive, the memory pointed by `ptr`
+    /// must not be mutated.
+    #[inline]
+    pub unsafe fn from_char_ptr<'a>(ptr: *const c_types::c_char) -> &'a Self {
+        // SAFETY: The safety precondition guarantees `ptr` is a valid pointer
+        // to a `NUL`-terminated C string.
+        let len = unsafe { bindings::strlen(ptr) } + 1;
+        // SAFETY: Lifetime guaranteed by the safety precondition.
+        let bytes = unsafe { core::slice::from_raw_parts(ptr as _, len as _) };
+        // SAFETY: As `len` is returned by `strlen`, `bytes` does not contain interior `NUL`.
+        // As we have added 1 to `len`, the last byte is known to be `NUL`.
+        unsafe { Self::from_bytes_with_nul_unchecked(bytes) }
+    }
+
+    /// Creates a [`CStr`] from a `[u8]`.
+    ///
+    /// The provided slice must be `NUL`-terminated, does not contain any
+    /// interior `NUL` bytes.
+    pub const fn from_bytes_with_nul(bytes: &[u8]) -> Result<&Self, CStrConvertError> {
+        if bytes.is_empty() {
+            return Err(CStrConvertError::NotNulTerminated);
+        }
+        if bytes[bytes.len() - 1] != 0 {
+            return Err(CStrConvertError::NotNulTerminated);
+        }
+        let mut i = 0;
+        // `i + 1 < bytes.len()` allows LLVM to optimize away bounds checking,
+        // while it couldn't optimize away bounds checks for `i < bytes.len() - 1`.
+        while i + 1 < bytes.len() {
+            if bytes[i] == 0 {
+                return Err(CStrConvertError::InteriorNul);
+            }
+            i += 1;
+        }
+        // SAFETY: We just checked that all properties hold.
+        Ok(unsafe { Self::from_bytes_with_nul_unchecked(bytes) })
+    }
+
+    /// Creates a [`CStr`] from a `[u8]`, panic if input is not valid.
+    ///
+    /// This function is only meant to be used by `c_str!` macro, so
+    /// crates using `c_str!` macro don't have to enable `const_panic` feature.
+    #[doc(hidden)]
+    pub const fn from_bytes_with_nul_unwrap(bytes: &[u8]) -> &Self {
+        match Self::from_bytes_with_nul(bytes) {
+            Ok(v) => v,
+            Err(_) => panic!("string contains interior NUL"),
+        }
+    }
+
+    /// Creates a [`CStr`] from a `[u8]` without performing any additional
+    /// checks.
+    ///
+    /// # Safety
+    ///
+    /// `bytes` *must* end with a `NUL` byte, and should only have a single
+    /// `NUL` byte (or the string will be truncated).
+    #[inline]
+    pub const unsafe fn from_bytes_with_nul_unchecked(bytes: &[u8]) -> &CStr {
+        // SAFETY: Properties of `bytes` guaranteed by the safety precondition.
+        unsafe { core::mem::transmute(bytes) }
+    }
+
+    /// Returns a C pointer to the string.
+    #[inline]
+    pub const fn as_char_ptr(&self) -> *const c_types::c_char {
+        self.0.as_ptr() as _
+    }
+
+    /// Convert the string to a byte slice without the trailing 0 byte.
+    #[inline]
+    pub fn as_bytes(&self) -> &[u8] {
+        &self.0[..self.len()]
+    }
+
+    /// Convert the string to a byte slice containing the trailing 0 byte.
+    #[inline]
+    pub const fn as_bytes_with_nul(&self) -> &[u8] {
+        &self.0
+    }
+
+    /// Yields a [`&str`] slice if the [`CStr`] contains valid UTF-8.
+    ///
+    /// If the contents of the [`CStr`] are valid UTF-8 data, this
+    /// function will return the corresponding [`&str`] slice. Otherwise,
+    /// it will return an error with details of where UTF-8 validation failed.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # use kernel::str::CStr;
+    /// let cstr = CStr::from_bytes_with_nul(b"foo\0").unwrap();
+    /// assert_eq!(cstr.to_str(), Ok("foo"));
+    /// ```
+    #[inline]
+    pub fn to_str(&self) -> Result<&str, core::str::Utf8Error> {
+        core::str::from_utf8(self.as_bytes())
+    }
+
+    /// Unsafely convert this [`CStr`] into a [`&str`], without checking for
+    /// valid UTF-8.
+    ///
+    /// # Safety
+    ///
+    /// The contents must be valid UTF-8.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # use kernel::c_str;
+    /// # use kernel::str::CStr;
+    /// // SAFETY: String literals are guaranteed to be valid UTF-8
+    /// // by the Rust compiler.
+    /// let bar = c_str!("ツ");
+    /// assert_eq!(unsafe { bar.as_str_unchecked() }, "ツ");
+    /// ```
+    #[inline]
+    pub unsafe fn as_str_unchecked(&self) -> &str {
+        unsafe { core::str::from_utf8_unchecked(self.as_bytes()) }
+    }
+}
+
+impl fmt::Display for CStr {
+    /// Formats printable ASCII characters, escaping the rest.
+    ///
+    /// ```
+    /// # use kernel::c_str;
+    /// # use kernel::str::CStr;
+    /// let penguin = c_str!("🐧");
+    /// assert_eq!(format!("{}", penguin), "\\xf0\\x9f\\x90\\xa7");
+    ///
+    /// let ascii = c_str!("so \"cool\"");
+    /// assert_eq!(format!("{}", ascii), "so \"cool\"");
+    /// ```
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        for &c in self.as_bytes() {
+            if (0x20..0x7f).contains(&c) {
+                // Printable character
+                f.write_char(c as char)?;
+            } else {
+                write!(f, "\\x{:02x}", c)?;
+            }
+        }
+        Ok(())
+    }
+}
+
+impl fmt::Debug for CStr {
+    /// Formats printable ASCII characters with a double quote on either end, escaping the rest.
+    ///
+    /// ```
+    /// # use kernel::c_str;
+    /// # use kernel::str::CStr;
+    /// let penguin = c_str!("🐧");
+    /// assert_eq!(format!("{:?}", penguin), "\"\\xf0\\x9f\\x90\\xa7\"");
+    ///
+    /// // embedded double quotes are escaped
+    /// let ascii = c_str!("so \"cool\"");
+    /// assert_eq!(format!("{:?}", ascii), "\"so \\\"cool\\\"\"");
+    /// ```
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.write_str("\"")?;
+        for &c in self.as_bytes() {
+            match c {
+                // Printable characters
+                b'\"' => f.write_str("\\\"")?,
+                0x20..=0x7e => f.write_char(c as char)?,
+                _ => write!(f, "\\x{:02x}", c)?,
+            }
+        }
+        f.write_str("\"")
+    }
+}
+
+impl AsRef<BStr> for CStr {
+    #[inline]
+    fn as_ref(&self) -> &BStr {
+        self.as_bytes()
+    }
+}
+
+impl Deref for CStr {
+    type Target = BStr;
+
+    #[inline]
+    fn deref(&self) -> &Self::Target {
+        self.as_bytes()
+    }
+}
+
+impl Index<ops::RangeFrom<usize>> for CStr {
+    type Output = CStr;
+
+    #[inline]
+    fn index(&self, index: ops::RangeFrom<usize>) -> &Self::Output {
+        // Delegate bounds checking to slice.
+        // Assign to _ to mute clippy's unnecessary operation warning.
+        let _ = &self.as_bytes()[index.start..];
+        // SAFETY: We just checked the bounds.
+        unsafe { Self::from_bytes_with_nul_unchecked(&self.0[index.start..]) }
+    }
+}
+
+impl Index<ops::RangeFull> for CStr {
+    type Output = CStr;
+
+    #[inline]
+    fn index(&self, _index: ops::RangeFull) -> &Self::Output {
+        self
+    }
+}
+
+mod private {
+    use core::ops;
+
+    // Marker trait for index types that can be forward to `BStr`.
+    pub trait CStrIndex {}
+
+    impl CStrIndex for usize {}
+    impl CStrIndex for ops::Range<usize> {}
+    impl CStrIndex for ops::RangeInclusive<usize> {}
+    impl CStrIndex for ops::RangeToInclusive<usize> {}
+}
+
+impl<Idx> Index<Idx> for CStr
+where
+    Idx: private::CStrIndex,
+    BStr: Index<Idx>,
+{
+    type Output = <BStr as Index<Idx>>::Output;
+
+    #[inline]
+    fn index(&self, index: Idx) -> &Self::Output {
+        &self.as_bytes()[index]
+    }
+}
+
+/// Creates a new [`CStr`] from a string literal.
+///
+/// The string literal should not contain any `NUL` bytes.
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::c_str;
+/// # use kernel::str::CStr;
+/// const MY_CSTR: &'static CStr = c_str!("My awesome CStr!");
+/// ```
+#[macro_export]
+macro_rules! c_str {
+    ($str:expr) => {{
+        const S: &str = concat!($str, "\0");
+        const C: &$crate::str::CStr = $crate::str::CStr::from_bytes_with_nul_unwrap(S.as_bytes());
+        C
+    }};
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn test_cstr_to_str() {
+        let good_bytes = b"\xf0\x9f\xa6\x80\0";
+        let checked_cstr = CStr::from_bytes_with_nul(good_bytes).unwrap();
+        let checked_str = checked_cstr.to_str().unwrap();
+        assert_eq!(checked_str, "🦀");
+    }
+
+    #[test]
+    #[should_panic]
+    fn test_cstr_to_str_panic() {
+        let bad_bytes = b"\xc3\x28\0";
+        let checked_cstr = CStr::from_bytes_with_nul(bad_bytes).unwrap();
+        checked_cstr.to_str().unwrap();
+    }
+
+    #[test]
+    fn test_cstr_as_str_unchecked() {
+        let good_bytes = b"\xf0\x9f\x90\xA7\0";
+        let checked_cstr = CStr::from_bytes_with_nul(good_bytes).unwrap();
+        let unchecked_str = unsafe { checked_cstr.as_str_unchecked() };
+        assert_eq!(unchecked_str, "🐧");
+    }
+}
+
+// Use `usize` to use `saturating_*` functions.
+pub(crate) struct Formatter {
+    pub(crate) buf: usize,
+    pub(crate) end: usize,
+}
+
+impl fmt::Write for Formatter {
+    fn write_str(&mut self, s: &str) -> fmt::Result {
+        // `buf` value after writing `len` bytes. This does not have to be bounded by `end`, but we
+        // don't want it to wrap around to 0.
+        let buf_new = self.buf.saturating_add(s.len());
+
+        // Amount that we can copy. `saturating_sub` ensures we get 0 if `buf` goes past `end`.
+        let len_to_copy = core::cmp::min(buf_new, self.end).saturating_sub(self.buf);
+
+        // SAFETY: In any case, `buf` is non-null and properly aligned.  If `len_to_copy` is
+        // non-zero, then we know `buf` has not past `end` yet and so is valid.
+        unsafe {
+            core::ptr::copy_nonoverlapping(s.as_bytes().as_ptr(), self.buf as *mut u8, len_to_copy)
+        };
+
+        self.buf = buf_new;
+        Ok(())
+    }
+}
diff --git a/rust/kernel/sysctl.rs b/rust/kernel/sysctl.rs
new file mode 100644
index 000000000000..0c74245cb204
--- /dev/null
+++ b/rust/kernel/sysctl.rs
@@ -0,0 +1,197 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! System control.
+//!
+//! C header: [`include/linux/sysctl.h`](../../../../include/linux/sysctl.h)
+//!
+//! Reference: <https://www.kernel.org/doc/Documentation/sysctl/README>
+
+use alloc::boxed::Box;
+use alloc::vec::Vec;
+use core::mem;
+use core::ptr;
+use core::sync::atomic;
+
+use crate::{
+    bindings, c_types, error,
+    io_buffer::IoBufferWriter,
+    str::CStr,
+    types,
+    user_ptr::{UserSlicePtr, UserSlicePtrWriter},
+};
+
+/// Sysctl storage.
+pub trait SysctlStorage: Sync {
+    /// Writes a byte slice.
+    fn store_value(&self, data: &[u8]) -> (usize, error::Result);
+
+    /// Reads via a [`UserSlicePtrWriter`].
+    fn read_value(&self, data: &mut UserSlicePtrWriter) -> (usize, error::Result);
+}
+
+fn trim_whitespace(mut data: &[u8]) -> &[u8] {
+    while !data.is_empty() && (data[0] == b' ' || data[0] == b'\t' || data[0] == b'\n') {
+        data = &data[1..];
+    }
+    while !data.is_empty()
+        && (data[data.len() - 1] == b' '
+            || data[data.len() - 1] == b'\t'
+            || data[data.len() - 1] == b'\n')
+    {
+        data = &data[..data.len() - 1];
+    }
+    data
+}
+
+impl<T> SysctlStorage for &T
+where
+    T: SysctlStorage,
+{
+    fn store_value(&self, data: &[u8]) -> (usize, error::Result) {
+        (*self).store_value(data)
+    }
+
+    fn read_value(&self, data: &mut UserSlicePtrWriter) -> (usize, error::Result) {
+        (*self).read_value(data)
+    }
+}
+
+impl SysctlStorage for atomic::AtomicBool {
+    fn store_value(&self, data: &[u8]) -> (usize, error::Result) {
+        let result = match trim_whitespace(data) {
+            b"0" => {
+                self.store(false, atomic::Ordering::Relaxed);
+                Ok(())
+            }
+            b"1" => {
+                self.store(true, atomic::Ordering::Relaxed);
+                Ok(())
+            }
+            _ => Err(error::Error::EINVAL),
+        };
+        (data.len(), result)
+    }
+
+    fn read_value(&self, data: &mut UserSlicePtrWriter) -> (usize, error::Result) {
+        let value = if self.load(atomic::Ordering::Relaxed) {
+            b"1\n"
+        } else {
+            b"0\n"
+        };
+        (value.len(), data.write_slice(value))
+    }
+}
+
+/// Holds a single `sysctl` entry (and its table).
+pub struct Sysctl<T: SysctlStorage> {
+    inner: Box<T>,
+    // Responsible for keeping the `ctl_table` alive.
+    _table: Box<[bindings::ctl_table]>,
+    header: *mut bindings::ctl_table_header,
+}
+
+// SAFETY: The only public method we have is `get()`, which returns `&T`, and
+// `T: Sync`. Any new methods must adhere to this requirement.
+unsafe impl<T: SysctlStorage> Sync for Sysctl<T> {}
+
+unsafe extern "C" fn proc_handler<T: SysctlStorage>(
+    ctl: *mut bindings::ctl_table,
+    write: c_types::c_int,
+    buffer: *mut c_types::c_void,
+    len: *mut usize,
+    ppos: *mut bindings::loff_t,
+) -> c_types::c_int {
+    // If we are reading from some offset other than the beginning of the file,
+    // return an empty read to signal EOF.
+    if unsafe { *ppos } != 0 && write == 0 {
+        unsafe { *len = 0 };
+        return 0;
+    }
+
+    let data = unsafe { UserSlicePtr::new(buffer, *len) };
+    let storage = unsafe { &*((*ctl).data as *const T) };
+    let (bytes_processed, result) = if write != 0 {
+        let data = match data.read_all() {
+            Ok(r) => r,
+            Err(e) => return e.to_kernel_errno(),
+        };
+        storage.store_value(&data)
+    } else {
+        let mut writer = data.writer();
+        storage.read_value(&mut writer)
+    };
+    unsafe { *len = bytes_processed };
+    unsafe { *ppos += *len as bindings::loff_t };
+    match result {
+        Ok(()) => 0,
+        Err(e) => e.to_kernel_errno(),
+    }
+}
+
+impl<T: SysctlStorage> Sysctl<T> {
+    /// Registers a single entry in `sysctl`.
+    pub fn register(
+        path: &'static CStr,
+        name: &'static CStr,
+        storage: T,
+        mode: types::Mode,
+    ) -> error::Result<Sysctl<T>> {
+        if name.contains(&b'/') {
+            return Err(error::Error::EINVAL);
+        }
+
+        let storage = Box::try_new(storage)?;
+        let mut table = Vec::try_with_capacity(2)?;
+        table.try_push(bindings::ctl_table {
+            procname: name.as_char_ptr(),
+            mode: mode.as_int(),
+            data: &*storage as *const T as *mut c_types::c_void,
+            proc_handler: Some(proc_handler::<T>),
+
+            maxlen: 0,
+            child: ptr::null_mut(),
+            poll: ptr::null_mut(),
+            extra1: ptr::null_mut(),
+            extra2: ptr::null_mut(),
+        })?;
+        table.try_push(unsafe { mem::zeroed() })?;
+        let mut table = table.try_into_boxed_slice()?;
+
+        let result = unsafe { bindings::register_sysctl(path.as_char_ptr(), table.as_mut_ptr()) };
+        if result.is_null() {
+            return Err(error::Error::ENOMEM);
+        }
+
+        Ok(Sysctl {
+            inner: storage,
+            _table: table,
+            header: result,
+        })
+    }
+
+    /// Gets the storage.
+    pub fn get(&self) -> &T {
+        &self.inner
+    }
+}
+
+impl<T: SysctlStorage> Drop for Sysctl<T> {
+    fn drop(&mut self) {
+        unsafe {
+            bindings::unregister_sysctl_table(self.header);
+        }
+        self.header = ptr::null_mut();
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn test_trim_whitespace() {
+        assert_eq!(trim_whitespace(b"foo    "), b"foo");
+        assert_eq!(trim_whitespace(b"    foo"), b"foo");
+        assert_eq!(trim_whitespace(b"  foo  "), b"foo");
+    }
+}
diff --git a/rust/kernel/task.rs b/rust/kernel/task.rs
new file mode 100644
index 000000000000..7a2aff0e9219
--- /dev/null
+++ b/rust/kernel/task.rs
@@ -0,0 +1,182 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Tasks (threads and processes).
+//!
+//! C header: [`include/linux/sched.h`](../../../../include/linux/sched.h).
+
+use crate::bindings;
+use core::{marker::PhantomData, mem::ManuallyDrop, ops::Deref};
+
+/// Wraps the kernel's `struct task_struct`.
+///
+/// # Invariants
+///
+/// The pointer `Task::ptr` is non-null and valid. Its reference count is also non-zero.
+///
+/// # Examples
+///
+/// The following is an example of getting the PID of the current thread with zero additional cost
+/// when compared to the C version:
+///
+/// ```
+/// # use kernel::prelude::*;
+/// use kernel::task::Task;
+///
+/// # fn test() {
+/// Task::current().pid();
+/// # }
+/// ```
+///
+/// Getting the PID of the current process, also zero additional cost:
+///
+/// ```
+/// # use kernel::prelude::*;
+/// use kernel::task::Task;
+///
+/// # fn test() {
+/// Task::current().group_leader().pid();
+/// # }
+/// ```
+///
+/// Getting the current task and storing it in some struct. The reference count is automatically
+/// incremented when creating `State` and decremented when it is dropped:
+///
+/// ```
+/// # use kernel::prelude::*;
+/// use kernel::task::Task;
+///
+/// struct State {
+///     creator: Task,
+///     index: u32,
+/// }
+///
+/// impl State {
+///     fn new() -> Self {
+///         Self {
+///             creator: Task::current().clone(),
+///             index: 0,
+///         }
+///     }
+/// }
+/// ```
+pub struct Task {
+    pub(crate) ptr: *mut bindings::task_struct,
+}
+
+// SAFETY: Given that the task is referenced, it is OK to send it to another thread.
+unsafe impl Send for Task {}
+
+// SAFETY: It's OK to access `Task` through references from other threads because we're either
+// accessing properties that don't change (e.g., `pid`, `group_leader`) or that are properly
+// synchronised by C code (e.g., `signal_pending`).
+unsafe impl Sync for Task {}
+
+/// The type of process identifiers (PIDs).
+type Pid = bindings::pid_t;
+
+impl Task {
+    /// Returns a task reference for the currently executing task/thread.
+    pub fn current<'a>() -> TaskRef<'a> {
+        // SAFETY: Just an FFI call.
+        let ptr = unsafe { bindings::get_current() };
+
+        // SAFETY: If the current thread is still running, the current task is valid. Given
+        // that `TaskRef` is not `Send`, we know it cannot be transferred to another thread (where
+        // it could potentially outlive the caller).
+        unsafe { TaskRef::from_ptr(ptr) }
+    }
+
+    /// Returns the group leader of the given task.
+    pub fn group_leader(&self) -> TaskRef<'_> {
+        // SAFETY: By the type invariant, we know that `self.ptr` is non-null and valid.
+        let ptr = unsafe { (*self.ptr).group_leader };
+
+        // SAFETY: The lifetime of the returned task reference is tied to the lifetime of `self`,
+        // and given that a task has a reference to its group leader, we know it must be valid for
+        // the lifetime of the returned task reference.
+        unsafe { TaskRef::from_ptr(ptr) }
+    }
+
+    /// Returns the PID of the given task.
+    pub fn pid(&self) -> Pid {
+        // SAFETY: By the type invariant, we know that `self.ptr` is non-null and valid.
+        unsafe { (*self.ptr).pid }
+    }
+
+    /// Determines whether the given task has pending signals.
+    pub fn signal_pending(&self) -> bool {
+        // SAFETY: By the type invariant, we know that `self.ptr` is non-null and valid.
+        unsafe { bindings::signal_pending(self.ptr) != 0 }
+    }
+}
+
+impl PartialEq for Task {
+    fn eq(&self, other: &Self) -> bool {
+        self.ptr == other.ptr
+    }
+}
+
+impl Eq for Task {}
+
+impl Clone for Task {
+    fn clone(&self) -> Self {
+        // SAFETY: The type invariants guarantee that `self.ptr` has a non-zero reference count.
+        unsafe { bindings::get_task_struct(self.ptr) };
+
+        // INVARIANT: We incremented the reference count to account for the new `Task` being
+        // created.
+        Self { ptr: self.ptr }
+    }
+}
+
+impl Drop for Task {
+    fn drop(&mut self) {
+        // INVARIANT: We may decrement the refcount to zero, but the `Task` is being dropped, so
+        // this is not observable.
+        // SAFETY: The type invariants guarantee that `Task::ptr` has a non-zero reference count.
+        unsafe { bindings::put_task_struct(self.ptr) };
+    }
+}
+
+/// A wrapper for [`Task`] that doesn't automatically decrement the refcount when dropped.
+///
+/// We need the wrapper because [`ManuallyDrop`] alone would allow callers to call
+/// [`ManuallyDrop::into_inner`]. This would allow an unsafe sequence to be triggered without
+/// `unsafe` blocks because it would trigger an unbalanced call to `put_task_struct`.
+///
+/// We make this explicitly not [`Send`] so that we can use it to represent the current thread
+/// without having to increment/decrement its reference count.
+///
+/// # Invariants
+///
+/// The wrapped [`Task`] remains valid for the lifetime of the object.
+pub struct TaskRef<'a> {
+    task: ManuallyDrop<Task>,
+    _not_send: PhantomData<(&'a (), *mut ())>,
+}
+
+impl TaskRef<'_> {
+    /// Constructs a new `struct task_struct` wrapper that doesn't change its reference count.
+    ///
+    /// # Safety
+    ///
+    /// The pointer `ptr` must be non-null and valid for the lifetime of the object.
+    pub(crate) unsafe fn from_ptr(ptr: *mut bindings::task_struct) -> Self {
+        Self {
+            task: ManuallyDrop::new(Task { ptr }),
+            _not_send: PhantomData,
+        }
+    }
+}
+
+// SAFETY: It is OK to share a reference to the current thread with another thread because we know
+// the owner cannot go away while the shared reference exists (and `Task` itself is `Sync`).
+unsafe impl Sync for TaskRef<'_> {}
+
+impl Deref for TaskRef<'_> {
+    type Target = Task;
+
+    fn deref(&self) -> &Self::Target {
+        self.task.deref()
+    }
+}
diff --git a/rust/kernel/types.rs b/rust/kernel/types.rs
new file mode 100644
index 000000000000..61186fc89049
--- /dev/null
+++ b/rust/kernel/types.rs
@@ -0,0 +1,486 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Kernel types.
+//!
+//! C header: [`include/linux/types.h`](../../../../include/linux/types.h)
+
+use crate::{
+    bindings, c_types,
+    sync::{Ref, RefBorrow},
+};
+use alloc::boxed::Box;
+use core::{
+    cell::UnsafeCell,
+    mem::MaybeUninit,
+    ops::{self, Deref, DerefMut},
+    pin::Pin,
+};
+
+/// Permissions.
+///
+/// C header: [`include/uapi/linux/stat.h`](../../../../include/uapi/linux/stat.h)
+///
+/// C header: [`include/linux/stat.h`](../../../../include/linux/stat.h)
+pub struct Mode(bindings::umode_t);
+
+impl Mode {
+    /// Creates a [`Mode`] from an integer.
+    pub fn from_int(m: u16) -> Mode {
+        Mode(m)
+    }
+
+    /// Returns the mode as an integer.
+    pub fn as_int(&self) -> u16 {
+        self.0
+    }
+}
+
+/// Used to convert an object into a raw pointer that represents it.
+///
+/// It can eventually be converted back into the object. This is used to store objects as pointers
+/// in kernel data structures, for example, an implementation of [`FileOperations`] in `struct
+/// file::private_data`.
+pub trait PointerWrapper {
+    /// Type of values borrowed between calls to [`PointerWrapper::into_pointer`] and
+    /// [`PointerWrapper::from_pointer`].
+    type Borrowed<'a>;
+
+    /// Returns the raw pointer.
+    fn into_pointer(self) -> *const c_types::c_void;
+
+    /// Returns a borrowed value.
+    ///
+    /// # Safety
+    ///
+    /// `ptr` must have been returned by a previous call to [`PointerWrapper::into_pointer`].
+    /// Additionally, [`PointerWrapper::from_pointer`] can only be called after *all* values
+    /// returned by [`PointerWrapper::borrow`] have been dropped.
+    unsafe fn borrow<'a>(ptr: *const c_types::c_void) -> Self::Borrowed<'a>;
+
+    /// Returns the instance back from the raw pointer.
+    ///
+    /// # Safety
+    ///
+    /// The passed pointer must come from a previous call to [`PointerWrapper::into_pointer()`].
+    unsafe fn from_pointer(ptr: *const c_types::c_void) -> Self;
+}
+
+impl<T: 'static> PointerWrapper for Box<T> {
+    type Borrowed<'a> = &'a T;
+
+    fn into_pointer(self) -> *const c_types::c_void {
+        Box::into_raw(self) as _
+    }
+
+    unsafe fn borrow<'a>(ptr: *const c_types::c_void) -> &'a T {
+        // SAFETY: The safety requirements for this function ensure that the object is still alive,
+        // so it is safe to dereference the raw pointer.
+        // The safety requirements also ensure that the object remains alive for the lifetime of
+        // the returned value.
+        unsafe { &*ptr.cast() }
+    }
+
+    unsafe fn from_pointer(ptr: *const c_types::c_void) -> Self {
+        // SAFETY: The passed pointer comes from a previous call to [`Self::into_pointer()`].
+        unsafe { Box::from_raw(ptr as _) }
+    }
+}
+
+impl<T: 'static> PointerWrapper for Ref<T> {
+    type Borrowed<'a> = RefBorrow<'a, T>;
+
+    fn into_pointer(self) -> *const c_types::c_void {
+        Ref::into_usize(self) as _
+    }
+
+    unsafe fn borrow<'a>(ptr: *const c_types::c_void) -> RefBorrow<'a, T> {
+        // SAFETY: The safety requirements for this function ensure that the underlying object
+        // remains valid for the lifetime of the returned value.
+        unsafe { Ref::borrow_usize(ptr as _) }
+    }
+
+    unsafe fn from_pointer(ptr: *const c_types::c_void) -> Self {
+        // SAFETY: The passed pointer comes from a previous call to [`Self::into_pointer()`].
+        unsafe { Ref::from_usize(ptr as _) }
+    }
+}
+
+impl<T: PointerWrapper + Deref> PointerWrapper for Pin<T> {
+    type Borrowed<'a> = T::Borrowed<'a>;
+
+    fn into_pointer(self) -> *const c_types::c_void {
+        // SAFETY: We continue to treat the pointer as pinned by returning just a pointer to it to
+        // the caller.
+        let inner = unsafe { Pin::into_inner_unchecked(self) };
+        inner.into_pointer()
+    }
+
+    unsafe fn borrow<'a>(ptr: *const c_types::c_void) -> Self::Borrowed<'a> {
+        // SAFETY: The safety requirements for this function are the same as the ones for
+        // `T::borrow`.
+        unsafe { T::borrow(ptr) }
+    }
+
+    unsafe fn from_pointer(p: *const c_types::c_void) -> Self {
+        // SAFETY: The object was originally pinned.
+        // The passed pointer comes from a previous call to `inner::into_pointer()`.
+        unsafe { Pin::new_unchecked(T::from_pointer(p)) }
+    }
+}
+
+impl<T> PointerWrapper for *mut T {
+    type Borrowed<'a> = *mut T;
+
+    fn into_pointer(self) -> *const c_types::c_void {
+        self as _
+    }
+
+    unsafe fn borrow<'a>(ptr: *const c_types::c_void) -> Self::Borrowed<'a> {
+        ptr as _
+    }
+
+    unsafe fn from_pointer(ptr: *const c_types::c_void) -> Self {
+        ptr as _
+    }
+}
+
+impl PointerWrapper for () {
+    type Borrowed<'a> = ();
+
+    fn into_pointer(self) -> *const c_types::c_void {
+        // We use 1 to be different from a null pointer.
+        1usize as _
+    }
+
+    unsafe fn borrow<'a>(_: *const c_types::c_void) -> Self::Borrowed<'a> {}
+
+    unsafe fn from_pointer(_: *const c_types::c_void) -> Self {}
+}
+
+/// Runs a cleanup function/closure when dropped.
+///
+/// The [`ScopeGuard::dismiss`] function prevents the cleanup function from running.
+///
+/// # Examples
+///
+/// In the example below, we have multiple exit paths and we want to log regardless of which one is
+/// taken:
+/// ```
+/// # use kernel::prelude::*;
+/// # use kernel::ScopeGuard;
+/// fn example1(arg: bool) {
+///     let _log = ScopeGuard::new(|| pr_info!("example1 completed\n"));
+///
+///     if arg {
+///         return;
+///     }
+///
+///     // Do something...
+/// }
+/// ```
+///
+/// In the example below, we want to log the same message on all early exits but a different one on
+/// the main exit path:
+/// ```
+/// # use kernel::prelude::*;
+/// # use kernel::ScopeGuard;
+/// fn example2(arg: bool) {
+///     let log = ScopeGuard::new(|| pr_info!("example2 returned early\n"));
+///
+///     if arg {
+///         return;
+///     }
+///
+///     // (Other early returns...)
+///
+///     log.dismiss();
+///     pr_info!("example2 no early return\n");
+/// }
+/// ```
+///
+/// In the example below, we need a mutable object (the vector) to be accessible within the log
+/// function, so we wrap it in the [`ScopeGuard`]:
+/// ```
+/// # use kernel::prelude::*;
+/// # use kernel::ScopeGuard;
+/// fn example3(arg: bool) -> Result {
+///     let mut vec =
+///         ScopeGuard::new_with_data(Vec::new(), |v| pr_info!("vec had {} elements\n", v.len()));
+///
+///     vec.try_push(10u8)?;
+///     if arg {
+///         return Ok(());
+///     }
+///     vec.try_push(20u8)?;
+///     Ok(())
+/// }
+/// ```
+///
+/// # Invariants
+///
+/// The value stored in the struct is nearly always `Some(_)`, except between
+/// [`ScopeGuard::dismiss`] and [`ScopeGuard::drop`]: in this case, it will be `None` as the value
+/// will have been returned to the caller. Since  [`ScopeGuard::dismiss`] consumes the guard,
+/// callers won't be able to use it anymore.
+pub struct ScopeGuard<T, F: FnOnce(T)>(Option<(T, F)>);
+
+impl<T, F: FnOnce(T)> ScopeGuard<T, F> {
+    /// Creates a new guarded object wrapping the given data and with the given cleanup function.
+    pub fn new_with_data(data: T, cleanup_func: F) -> Self {
+        // INVARIANT: The struct is being initialised with `Some(_)`.
+        Self(Some((data, cleanup_func)))
+    }
+
+    /// Prevents the cleanup function from running and returns the guarded data.
+    pub fn dismiss(mut self) -> T {
+        // INVARIANT: This is the exception case in the invariant; it is not visible to callers
+        // because this function consumes `self`.
+        self.0.take().unwrap().0
+    }
+}
+
+impl ScopeGuard<(), Box<dyn FnOnce(())>> {
+    /// Creates a new guarded object with the given cleanup function.
+    pub fn new(cleanup: impl FnOnce()) -> ScopeGuard<(), impl FnOnce(())> {
+        ScopeGuard::new_with_data((), move |_| cleanup())
+    }
+}
+
+impl<T, F: FnOnce(T)> Deref for ScopeGuard<T, F> {
+    type Target = T;
+
+    fn deref(&self) -> &T {
+        // The type invariants guarantee that `unwrap` will succeed.
+        &self.0.as_ref().unwrap().0
+    }
+}
+
+impl<T, F: FnOnce(T)> DerefMut for ScopeGuard<T, F> {
+    fn deref_mut(&mut self) -> &mut T {
+        // The type invariants guarantee that `unwrap` will succeed.
+        &mut self.0.as_mut().unwrap().0
+    }
+}
+
+impl<T, F: FnOnce(T)> Drop for ScopeGuard<T, F> {
+    fn drop(&mut self) {
+        // Run the cleanup function if one is still present.
+        if let Some((data, cleanup)) = self.0.take() {
+            cleanup(data)
+        }
+    }
+}
+
+/// Stores an opaque value.
+///
+/// This is meant to be used with FFI objects that are never interpreted by Rust code.
+pub struct Opaque<T>(MaybeUninit<UnsafeCell<T>>);
+
+impl<T> Opaque<T> {
+    /// Creates a new opaque value.
+    pub fn new(value: T) -> Self {
+        Self(MaybeUninit::new(UnsafeCell::new(value)))
+    }
+
+    /// Creates an uninitialised value.
+    pub const fn uninit() -> Self {
+        Self(MaybeUninit::uninit())
+    }
+
+    /// Returns a raw pointer to the opaque data.
+    pub fn get(&self) -> *mut T {
+        UnsafeCell::raw_get(self.0.as_ptr())
+    }
+}
+
+/// A bitmask.
+///
+/// It has a restriction that all bits must be the same, except one. For example, `0b1110111` and
+/// `0b1000` are acceptable masks.
+#[derive(Clone, Copy)]
+pub struct Bit<T> {
+    index: T,
+    inverted: bool,
+}
+
+/// Creates a bit mask with a single bit set.
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::prelude::*;
+/// # use kernel::bit;
+/// let mut x = 0xfeu32;
+///
+/// assert_eq!(x & bit(0), 0);
+/// assert_eq!(x & bit(1), 2);
+/// assert_eq!(x & bit(2), 4);
+/// assert_eq!(x & bit(3), 8);
+///
+/// x |= bit(0);
+/// assert_eq!(x, 0xff);
+///
+/// x &= !bit(1);
+/// assert_eq!(x, 0xfd);
+///
+/// x &= !bit(7);
+/// assert_eq!(x, 0x7d);
+///
+/// let y: u64 = bit(34).into();
+/// assert_eq!(y, 0x400000000);
+///
+/// assert_eq!(y | bit(35), 0xc00000000);
+/// ```
+pub fn bit<T: Copy>(index: T) -> Bit<T> {
+    Bit {
+        index,
+        inverted: false,
+    }
+}
+
+impl<T: Copy> ops::Not for Bit<T> {
+    type Output = Self;
+    fn not(self) -> Self {
+        Self {
+            index: self.index,
+            inverted: !self.inverted,
+        }
+    }
+}
+
+/// Implemented by integer types that allow counting the number of trailing zeroes.
+pub trait TrailingZeros {
+    /// Returns the number of trailing zeroes in the binary representation of `self`.
+    fn trailing_zeros(&self) -> u32;
+}
+
+macro_rules! define_unsigned_number_traits {
+    ($type_name:ty) => {
+        impl TrailingZeros for $type_name {
+            fn trailing_zeros(&self) -> u32 {
+                <$type_name>::trailing_zeros(*self)
+            }
+        }
+
+        impl<T: Copy> core::convert::From<Bit<T>> for $type_name
+        where
+            Self: ops::Shl<T, Output = Self> + core::convert::From<u8> + ops::Not<Output = Self>,
+        {
+            fn from(v: Bit<T>) -> Self {
+                let c = Self::from(1u8) << v.index;
+                if v.inverted {
+                    !c
+                } else {
+                    c
+                }
+            }
+        }
+
+        impl<T: Copy> ops::BitAnd<Bit<T>> for $type_name
+        where
+            Self: ops::Shl<T, Output = Self> + core::convert::From<u8>,
+        {
+            type Output = Self;
+            fn bitand(self, rhs: Bit<T>) -> Self::Output {
+                self & Self::from(rhs)
+            }
+        }
+
+        impl<T: Copy> ops::BitOr<Bit<T>> for $type_name
+        where
+            Self: ops::Shl<T, Output = Self> + core::convert::From<u8>,
+        {
+            type Output = Self;
+            fn bitor(self, rhs: Bit<T>) -> Self::Output {
+                self | Self::from(rhs)
+            }
+        }
+
+        impl<T: Copy> ops::BitAndAssign<Bit<T>> for $type_name
+        where
+            Self: ops::Shl<T, Output = Self> + core::convert::From<u8>,
+        {
+            fn bitand_assign(&mut self, rhs: Bit<T>) {
+                *self &= Self::from(rhs)
+            }
+        }
+
+        impl<T: Copy> ops::BitOrAssign<Bit<T>> for $type_name
+        where
+            Self: ops::Shl<T, Output = Self> + core::convert::From<u8>,
+        {
+            fn bitor_assign(&mut self, rhs: Bit<T>) {
+                *self |= Self::from(rhs)
+            }
+        }
+    };
+}
+
+define_unsigned_number_traits!(u8);
+define_unsigned_number_traits!(u16);
+define_unsigned_number_traits!(u32);
+define_unsigned_number_traits!(u64);
+define_unsigned_number_traits!(usize);
+
+/// Returns an iterator over the set bits of `value`.
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::prelude::*;
+/// use kernel::bits_iter;
+///
+/// let mut iter = bits_iter(5usize);
+/// assert_eq!(iter.next().unwrap(), 0);
+/// assert_eq!(iter.next().unwrap(), 2);
+/// assert!(iter.next().is_none());
+/// ```
+///
+/// ```
+/// # use kernel::prelude::*;
+/// use kernel::bits_iter;
+///
+/// fn print_bits(x: usize) {
+///     for bit in bits_iter(x) {
+///         println!("{}", bit);
+///     }
+/// }
+/// ```
+#[inline]
+pub fn bits_iter<T>(value: T) -> impl Iterator<Item = u32>
+where
+    T: core::cmp::PartialEq
+        + From<u8>
+        + ops::Shl<u32, Output = T>
+        + ops::Not<Output = T>
+        + ops::BitAndAssign
+        + TrailingZeros,
+{
+    struct BitIterator<U> {
+        value: U,
+    }
+
+    impl<U> Iterator for BitIterator<U>
+    where
+        U: core::cmp::PartialEq
+            + From<u8>
+            + ops::Shl<u32, Output = U>
+            + ops::Not<Output = U>
+            + ops::BitAndAssign
+            + TrailingZeros,
+    {
+        type Item = u32;
+
+        #[inline]
+        fn next(&mut self) -> Option<u32> {
+            if self.value == U::from(0u8) {
+                return None;
+            }
+            let ret = self.value.trailing_zeros();
+            self.value &= !(U::from(1u8) << ret);
+            Some(ret)
+        }
+    }
+
+    BitIterator { value }
+}
diff --git a/rust/kernel/user_ptr.rs b/rust/kernel/user_ptr.rs
new file mode 100644
index 000000000000..467ead639071
--- /dev/null
+++ b/rust/kernel/user_ptr.rs
@@ -0,0 +1,175 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! User pointers.
+//!
+//! C header: [`include/linux/uaccess.h`](../../../../include/linux/uaccess.h)
+
+use crate::{
+    bindings, c_types,
+    error::Error,
+    io_buffer::{IoBufferReader, IoBufferWriter},
+    Result,
+};
+use alloc::vec::Vec;
+
+/// A reference to an area in userspace memory, which can be either
+/// read-only or read-write.
+///
+/// All methods on this struct are safe: invalid pointers return
+/// `EFAULT`. Concurrent access, *including data races to/from userspace
+/// memory*, is permitted, because fundamentally another userspace
+/// thread/process could always be modifying memory at the same time
+/// (in the same way that userspace Rust's [`std::io`] permits data races
+/// with the contents of files on disk). In the presence of a race, the
+/// exact byte values read/written are unspecified but the operation is
+/// well-defined. Kernelspace code should validate its copy of data
+/// after completing a read, and not expect that multiple reads of the
+/// same address will return the same value.
+///
+/// All APIs enforce the invariant that a given byte of memory from userspace
+/// may only be read once. By preventing double-fetches we avoid TOCTOU
+/// vulnerabilities. This is accomplished by taking `self` by value to prevent
+/// obtaining multiple readers on a given [`UserSlicePtr`], and the readers
+/// only permitting forward reads.
+///
+/// Constructing a [`UserSlicePtr`] performs no checks on the provided
+/// address and length, it can safely be constructed inside a kernel thread
+/// with no current userspace process. Reads and writes wrap the kernel APIs
+/// `copy_from_user` and `copy_to_user`, which check the memory map of the
+/// current process and enforce that the address range is within the user
+/// range (no additional calls to `access_ok` are needed).
+///
+/// [`std::io`]: https://doc.rust-lang.org/std/io/index.html
+pub struct UserSlicePtr(*mut c_types::c_void, usize);
+
+impl UserSlicePtr {
+    /// Constructs a user slice from a raw pointer and a length in bytes.
+    ///
+    /// # Safety
+    ///
+    /// Callers must be careful to avoid time-of-check-time-of-use
+    /// (TOCTOU) issues. The simplest way is to create a single instance of
+    /// [`UserSlicePtr`] per user memory block as it reads each byte at
+    /// most once.
+    pub unsafe fn new(ptr: *mut c_types::c_void, length: usize) -> Self {
+        UserSlicePtr(ptr, length)
+    }
+
+    /// Reads the entirety of the user slice.
+    ///
+    /// Returns `EFAULT` if the address does not currently point to
+    /// mapped, readable memory.
+    pub fn read_all(self) -> Result<Vec<u8>> {
+        self.reader().read_all()
+    }
+
+    /// Constructs a [`UserSlicePtrReader`].
+    pub fn reader(self) -> UserSlicePtrReader {
+        UserSlicePtrReader(self.0, self.1)
+    }
+
+    /// Writes the provided slice into the user slice.
+    ///
+    /// Returns `EFAULT` if the address does not currently point to
+    /// mapped, writable memory (in which case some data from before the
+    /// fault may be written), or `data` is larger than the user slice
+    /// (in which case no data is written).
+    pub fn write_all(self, data: &[u8]) -> Result {
+        self.writer().write_slice(data)
+    }
+
+    /// Constructs a [`UserSlicePtrWriter`].
+    pub fn writer(self) -> UserSlicePtrWriter {
+        UserSlicePtrWriter(self.0, self.1)
+    }
+
+    /// Constructs both a [`UserSlicePtrReader`] and a [`UserSlicePtrWriter`].
+    pub fn reader_writer(self) -> (UserSlicePtrReader, UserSlicePtrWriter) {
+        (
+            UserSlicePtrReader(self.0, self.1),
+            UserSlicePtrWriter(self.0, self.1),
+        )
+    }
+}
+
+/// A reader for [`UserSlicePtr`].
+///
+/// Used to incrementally read from the user slice.
+pub struct UserSlicePtrReader(*mut c_types::c_void, usize);
+
+impl IoBufferReader for UserSlicePtrReader {
+    /// Returns the number of bytes left to be read from this.
+    ///
+    /// Note that even reading less than this number of bytes may fail.
+    fn len(&self) -> usize {
+        self.1
+    }
+
+    /// Reads raw data from the user slice into a raw kernel buffer.
+    ///
+    /// # Safety
+    ///
+    /// The output buffer must be valid.
+    unsafe fn read_raw(&mut self, out: *mut u8, len: usize) -> Result {
+        if len > self.1 || len > u32::MAX as usize {
+            return Err(Error::EFAULT);
+        }
+        let res = unsafe { bindings::copy_from_user(out as _, self.0, len as _) };
+        if res != 0 {
+            return Err(Error::EFAULT);
+        }
+        // Since this is not a pointer to a valid object in our program,
+        // we cannot use `add`, which has C-style rules for defined
+        // behavior.
+        self.0 = self.0.wrapping_add(len);
+        self.1 -= len;
+        Ok(())
+    }
+}
+
+/// A writer for [`UserSlicePtr`].
+///
+/// Used to incrementally write into the user slice.
+pub struct UserSlicePtrWriter(*mut c_types::c_void, usize);
+
+impl IoBufferWriter for UserSlicePtrWriter {
+    fn len(&self) -> usize {
+        self.1
+    }
+
+    fn clear(&mut self, mut len: usize) -> Result {
+        let mut ret = Ok(());
+        if len > self.1 {
+            ret = Err(Error::EFAULT);
+            len = self.1;
+        }
+
+        // SAFETY: The buffer will be validated by `clear_user`. We ensure that `len` is within
+        // bounds in the check above.
+        let left = unsafe { bindings::clear_user(self.0, len as _) } as usize;
+        if left != 0 {
+            ret = Err(Error::EFAULT);
+            len -= left;
+        }
+
+        self.0 = self.0.wrapping_add(len);
+        self.1 -= len;
+        ret
+    }
+
+    unsafe fn write_raw(&mut self, data: *const u8, len: usize) -> Result {
+        if len > self.1 || len > u32::MAX as usize {
+            return Err(Error::EFAULT);
+        }
+        let res = unsafe { bindings::copy_to_user(self.0, data as _, len as _) };
+        if res != 0 {
+            return Err(Error::EFAULT);
+        }
+        // Since this is not a pointer to a valid object in our program,
+        // we cannot use `add`, which has C-style rules for defined
+        // behavior.
+        self.0 = self.0.wrapping_add(len);
+        self.1 -= len;
+        Ok(())
+    }
+}
-- 
2.35.1


^ permalink raw reply related	[relevance 1%]

* [PATCH v4 17/20] samples: add Rust examples
    2022-02-12 13:03  1% ` [PATCH v4 10/20] rust: add `kernel` crate Miguel Ojeda
@ 2022-02-12 13:03  3% ` Miguel Ojeda
  1 sibling, 0 replies; 77+ results
From: Miguel Ojeda @ 2022-02-12 13:03 UTC (permalink / raw)
  To: Linus Torvalds, Greg Kroah-Hartman
  Cc: rust-for-linux, linux-kernel, Miguel Ojeda, Alex Gaynor,
	Finn Behrens, Wedson Almeida Filho, Sven Van Asbroeck, Gary Guo,
	Boris-Chengbiao Zhou, Ayaan Zaidi, Milan Landaverde

A set of Rust modules that showcase how Rust modules look like
and how to use the abstracted kernel features.

These samples also double as tests in the CI.

The semaphore sample comes with a C version for comparison.

Co-developed-by: Alex Gaynor <alex.gaynor@gmail.com>
Signed-off-by: Alex Gaynor <alex.gaynor@gmail.com>
Co-developed-by: Finn Behrens <me@kloenk.de>
Signed-off-by: Finn Behrens <me@kloenk.de>
Co-developed-by: Wedson Almeida Filho <wedsonaf@google.com>
Signed-off-by: Wedson Almeida Filho <wedsonaf@google.com>
Co-developed-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Co-developed-by: Sven Van Asbroeck <thesven73@gmail.com>
Signed-off-by: Sven Van Asbroeck <thesven73@gmail.com>
Co-developed-by: Gary Guo <gary@garyguo.net>
Signed-off-by: Gary Guo <gary@garyguo.net>
Co-developed-by: Boris-Chengbiao Zhou <bobo1239@web.de>
Signed-off-by: Boris-Chengbiao Zhou <bobo1239@web.de>
Co-developed-by: Ayaan Zaidi <zaidi.ayaan@gmail.com>
Signed-off-by: Ayaan Zaidi <zaidi.ayaan@gmail.com>
Co-developed-by: Milan Landaverde <milan@mdaverde.com>
Signed-off-by: Milan Landaverde <milan@mdaverde.com>
Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
---
 samples/Kconfig                        |   2 +
 samples/Makefile                       |   1 +
 samples/rust/Kconfig                   | 123 ++++++++++++++
 samples/rust/Makefile                  |  13 ++
 samples/rust/rust_chrdev.rs            |  50 ++++++
 samples/rust/rust_minimal.rs           |  35 ++++
 samples/rust/rust_miscdev.rs           | 144 +++++++++++++++++
 samples/rust/rust_module_parameters.rs |  69 ++++++++
 samples/rust/rust_platform.rs          |  22 +++
 samples/rust/rust_print.rs             |  54 +++++++
 samples/rust/rust_random.rs            |  61 +++++++
 samples/rust/rust_semaphore.rs         | 172 ++++++++++++++++++++
 samples/rust/rust_semaphore_c.c        | 212 +++++++++++++++++++++++++
 samples/rust/rust_stack_probing.rs     |  36 +++++
 samples/rust/rust_sync.rs              |  78 +++++++++
 15 files changed, 1072 insertions(+)
 create mode 100644 samples/rust/Kconfig
 create mode 100644 samples/rust/Makefile
 create mode 100644 samples/rust/rust_chrdev.rs
 create mode 100644 samples/rust/rust_minimal.rs
 create mode 100644 samples/rust/rust_miscdev.rs
 create mode 100644 samples/rust/rust_module_parameters.rs
 create mode 100644 samples/rust/rust_platform.rs
 create mode 100644 samples/rust/rust_print.rs
 create mode 100644 samples/rust/rust_random.rs
 create mode 100644 samples/rust/rust_semaphore.rs
 create mode 100644 samples/rust/rust_semaphore_c.c
 create mode 100644 samples/rust/rust_stack_probing.rs
 create mode 100644 samples/rust/rust_sync.rs

diff --git a/samples/Kconfig b/samples/Kconfig
index 22cc921ae291..9a82039aae49 100644
--- a/samples/Kconfig
+++ b/samples/Kconfig
@@ -250,6 +250,8 @@ config SAMPLE_CORESIGHT_SYSCFG
 	  This demonstrates how a user may create their own CoreSight
 	  configurations and easily load them into the system at runtime.
 
+source "samples/rust/Kconfig"
+
 endif # SAMPLES
 
 config HAVE_SAMPLE_FTRACE_DIRECT
diff --git a/samples/Makefile b/samples/Makefile
index 1ae4de99c983..fc5e9760ea32 100644
--- a/samples/Makefile
+++ b/samples/Makefile
@@ -33,3 +33,4 @@ subdir-$(CONFIG_SAMPLE_WATCHDOG)	+= watchdog
 subdir-$(CONFIG_SAMPLE_WATCH_QUEUE)	+= watch_queue
 obj-$(CONFIG_DEBUG_KMEMLEAK_TEST)	+= kmemleak/
 obj-$(CONFIG_SAMPLE_CORESIGHT_SYSCFG)	+= coresight/
+obj-$(CONFIG_SAMPLES_RUST)		+= rust/
diff --git a/samples/rust/Kconfig b/samples/rust/Kconfig
new file mode 100644
index 000000000000..e234be7c341c
--- /dev/null
+++ b/samples/rust/Kconfig
@@ -0,0 +1,123 @@
+# SPDX-License-Identifier: GPL-2.0
+
+menuconfig SAMPLES_RUST
+	bool "Rust samples"
+	depends on RUST
+	help
+	  You can build sample Rust kernel code here.
+
+	  If unsure, say N.
+
+if SAMPLES_RUST
+
+config SAMPLE_RUST_MINIMAL
+	tristate "Minimal"
+	help
+	  This option builds the Rust minimal module sample.
+
+	  To compile this as a module, choose M here:
+	  the module will be called rust_minimal.
+
+	  If unsure, say N.
+
+config SAMPLE_RUST_PRINT
+	tristate "Printing macros"
+	help
+	  This option builds the Rust printing macros sample.
+
+	  To compile this as a module, choose M here:
+	  the module will be called rust_print.
+
+	  If unsure, say N.
+
+config SAMPLE_RUST_MODULE_PARAMETERS
+	tristate "Module parameters"
+	help
+	  This option builds the Rust module parameters sample.
+
+	  To compile this as a module, choose M here:
+	  the module will be called rust_module_parameters.
+
+	  If unsure, say N.
+
+config SAMPLE_RUST_SYNC
+	tristate "Synchronisation primitives"
+	help
+	  This option builds the Rust synchronisation primitives sample.
+
+	  To compile this as a module, choose M here:
+	  the module will be called rust_sync.
+
+	  If unsure, say N.
+
+config SAMPLE_RUST_CHRDEV
+	tristate "Character device"
+	help
+	  This option builds the Rust character device sample.
+
+	  To compile this as a module, choose M here:
+	  the module will be called rust_chrdev.
+
+	  If unsure, say N.
+
+config SAMPLE_RUST_MISCDEV
+	tristate "Miscellaneous device"
+	help
+	  This option builds the Rust miscellaneous device sample.
+
+	  To compile this as a module, choose M here:
+	  the module will be called rust_miscdev.
+
+	  If unsure, say N.
+
+config SAMPLE_RUST_STACK_PROBING
+	tristate "Stack probing"
+	help
+	  This option builds the Rust stack probing sample.
+
+	  To compile this as a module, choose M here:
+	  the module will be called rust_stack_probing.
+
+	  If unsure, say N.
+
+config SAMPLE_RUST_SEMAPHORE
+	tristate "Semaphore"
+	help
+	  This option builds the Rust semaphore sample.
+
+	  To compile this as a module, choose M here:
+	  the module will be called rust_semaphore.
+
+	  If unsure, say N.
+
+config SAMPLE_RUST_SEMAPHORE_C
+	tristate "Semaphore (in C, for comparison)"
+	help
+	  This option builds the Rust semaphore sample (in C, for comparison).
+
+	  To compile this as a module, choose M here:
+	  the module will be called rust_semaphore_c.
+
+	  If unsure, say N.
+
+config SAMPLE_RUST_RANDOM
+	tristate "Random"
+	help
+	  This option builds the Rust random sample.
+
+	  To compile this as a module, choose M here:
+	  the module will be called rust_random.
+
+	  If unsure, say N.
+
+config SAMPLE_RUST_PLATFORM
+	tristate "Platform device driver"
+	help
+	  This option builds the Rust platform device driver sample.
+
+	  To compile this as a module, choose M here:
+	  the module will be called rust_platform.
+
+	  If unsure, say N.
+
+endif # SAMPLES_RUST
diff --git a/samples/rust/Makefile b/samples/rust/Makefile
new file mode 100644
index 000000000000..96ffeb7d334a
--- /dev/null
+++ b/samples/rust/Makefile
@@ -0,0 +1,13 @@
+# SPDX-License-Identifier: GPL-2.0
+
+obj-$(CONFIG_SAMPLE_RUST_MINIMAL)		+= rust_minimal.o
+obj-$(CONFIG_SAMPLE_RUST_PRINT)			+= rust_print.o
+obj-$(CONFIG_SAMPLE_RUST_MODULE_PARAMETERS)	+= rust_module_parameters.o
+obj-$(CONFIG_SAMPLE_RUST_SYNC)			+= rust_sync.o
+obj-$(CONFIG_SAMPLE_RUST_CHRDEV)		+= rust_chrdev.o
+obj-$(CONFIG_SAMPLE_RUST_MISCDEV)		+= rust_miscdev.o
+obj-$(CONFIG_SAMPLE_RUST_STACK_PROBING)		+= rust_stack_probing.o
+obj-$(CONFIG_SAMPLE_RUST_SEMAPHORE)		+= rust_semaphore.o
+obj-$(CONFIG_SAMPLE_RUST_SEMAPHORE_C)		+= rust_semaphore_c.o
+obj-$(CONFIG_SAMPLE_RUST_RANDOM)		+= rust_random.o
+obj-$(CONFIG_SAMPLE_RUST_PLATFORM)		+= rust_platform.o
diff --git a/samples/rust/rust_chrdev.rs b/samples/rust/rust_chrdev.rs
new file mode 100644
index 000000000000..343859f1afdd
--- /dev/null
+++ b/samples/rust/rust_chrdev.rs
@@ -0,0 +1,50 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Rust character device sample.
+
+use kernel::prelude::*;
+use kernel::{chrdev, file, file_operations::FileOperations};
+
+module! {
+    type: RustChrdev,
+    name: b"rust_chrdev",
+    author: b"Rust for Linux Contributors",
+    description: b"Rust character device sample",
+    license: b"GPL v2",
+}
+
+struct RustFile;
+
+impl FileOperations for RustFile {
+    kernel::declare_file_operations!();
+
+    fn open(_shared: &(), _file: &file::File) -> Result {
+        Ok(())
+    }
+}
+
+struct RustChrdev {
+    _dev: Pin<Box<chrdev::Registration<2>>>,
+}
+
+impl KernelModule for RustChrdev {
+    fn init(name: &'static CStr, module: &'static ThisModule) -> Result<Self> {
+        pr_info!("Rust character device sample (init)\n");
+
+        let mut chrdev_reg = chrdev::Registration::new_pinned(name, 0, module)?;
+
+        // Register the same kind of device twice, we're just demonstrating
+        // that you can use multiple minors. There are two minors in this case
+        // because its type is `chrdev::Registration<2>`
+        chrdev_reg.as_mut().register::<RustFile>()?;
+        chrdev_reg.as_mut().register::<RustFile>()?;
+
+        Ok(RustChrdev { _dev: chrdev_reg })
+    }
+}
+
+impl Drop for RustChrdev {
+    fn drop(&mut self) {
+        pr_info!("Rust character device sample (exit)\n");
+    }
+}
diff --git a/samples/rust/rust_minimal.rs b/samples/rust/rust_minimal.rs
new file mode 100644
index 000000000000..f0488262bcc9
--- /dev/null
+++ b/samples/rust/rust_minimal.rs
@@ -0,0 +1,35 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Rust minimal sample.
+
+use kernel::prelude::*;
+
+module! {
+    type: RustMinimal,
+    name: b"rust_minimal",
+    author: b"Rust for Linux Contributors",
+    description: b"Rust minimal sample",
+    license: b"GPL v2",
+}
+
+struct RustMinimal {
+    message: String,
+}
+
+impl KernelModule for RustMinimal {
+    fn init(_name: &'static CStr, _module: &'static ThisModule) -> Result<Self> {
+        pr_info!("Rust minimal sample (init)\n");
+        pr_info!("Am I built-in? {}\n", !cfg!(MODULE));
+
+        Ok(RustMinimal {
+            message: "on the heap!".try_to_owned()?,
+        })
+    }
+}
+
+impl Drop for RustMinimal {
+    fn drop(&mut self) {
+        pr_info!("My message is {}\n", self.message);
+        pr_info!("Rust minimal sample (exit)\n");
+    }
+}
diff --git a/samples/rust/rust_miscdev.rs b/samples/rust/rust_miscdev.rs
new file mode 100644
index 000000000000..9db0c3e53977
--- /dev/null
+++ b/samples/rust/rust_miscdev.rs
@@ -0,0 +1,144 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Rust miscellaneous device sample.
+
+use kernel::prelude::*;
+use kernel::{
+    file::File,
+    file_operations::FileOperations,
+    io_buffer::{IoBufferReader, IoBufferWriter},
+    miscdev,
+    sync::{CondVar, Mutex, Ref, RefBorrow, UniqueRef},
+};
+
+module! {
+    type: RustMiscdev,
+    name: b"rust_miscdev",
+    author: b"Rust for Linux Contributors",
+    description: b"Rust miscellaneous device sample",
+    license: b"GPL v2",
+}
+
+const MAX_TOKENS: usize = 3;
+
+struct SharedStateInner {
+    token_count: usize,
+}
+
+struct SharedState {
+    state_changed: CondVar,
+    inner: Mutex<SharedStateInner>,
+}
+
+impl SharedState {
+    fn try_new() -> Result<Ref<Self>> {
+        let mut state = Pin::from(UniqueRef::try_new(Self {
+            // SAFETY: `condvar_init!` is called below.
+            state_changed: unsafe { CondVar::new() },
+            // SAFETY: `mutex_init!` is called below.
+            inner: unsafe { Mutex::new(SharedStateInner { token_count: 0 }) },
+        })?);
+
+        // SAFETY: `state_changed` is pinned when `state` is.
+        let pinned = unsafe { state.as_mut().map_unchecked_mut(|s| &mut s.state_changed) };
+        kernel::condvar_init!(pinned, "SharedState::state_changed");
+
+        // SAFETY: `inner` is pinned when `state` is.
+        let pinned = unsafe { state.as_mut().map_unchecked_mut(|s| &mut s.inner) };
+        kernel::mutex_init!(pinned, "SharedState::inner");
+
+        Ok(state.into())
+    }
+}
+
+struct Token;
+impl FileOperations for Token {
+    type Wrapper = Ref<SharedState>;
+    type OpenData = Ref<SharedState>;
+
+    kernel::declare_file_operations!(read, write);
+
+    fn open(shared: &Ref<SharedState>, _file: &File) -> Result<Self::Wrapper> {
+        Ok(shared.clone())
+    }
+
+    fn read(
+        shared: RefBorrow<'_, SharedState>,
+        _: &File,
+        data: &mut impl IoBufferWriter,
+        offset: u64,
+    ) -> Result<usize> {
+        // Succeed if the caller doesn't provide a buffer or if not at the start.
+        if data.is_empty() || offset != 0 {
+            return Ok(0);
+        }
+
+        {
+            let mut inner = shared.inner.lock();
+
+            // Wait until we are allowed to decrement the token count or a signal arrives.
+            while inner.token_count == 0 {
+                if shared.state_changed.wait(&mut inner) {
+                    return Err(Error::EINTR);
+                }
+            }
+
+            // Consume a token.
+            inner.token_count -= 1;
+        }
+
+        // Notify a possible writer waiting.
+        shared.state_changed.notify_all();
+
+        // Write a one-byte 1 to the reader.
+        data.write_slice(&[1u8; 1])?;
+        Ok(1)
+    }
+
+    fn write(
+        shared: RefBorrow<'_, SharedState>,
+        _: &File,
+        data: &mut impl IoBufferReader,
+        _offset: u64,
+    ) -> Result<usize> {
+        {
+            let mut inner = shared.inner.lock();
+
+            // Wait until we are allowed to increment the token count or a signal arrives.
+            while inner.token_count == MAX_TOKENS {
+                if shared.state_changed.wait(&mut inner) {
+                    return Err(Error::EINTR);
+                }
+            }
+
+            // Increment the number of token so that a reader can be released.
+            inner.token_count += 1;
+        }
+
+        // Notify a possible reader waiting.
+        shared.state_changed.notify_all();
+        Ok(data.len())
+    }
+}
+
+struct RustMiscdev {
+    _dev: Pin<Box<miscdev::Registration<Token>>>,
+}
+
+impl KernelModule for RustMiscdev {
+    fn init(name: &'static CStr, _module: &'static ThisModule) -> Result<Self> {
+        pr_info!("Rust miscellaneous device sample (init)\n");
+
+        let state = SharedState::try_new()?;
+
+        Ok(RustMiscdev {
+            _dev: miscdev::Registration::new_pinned(name, state)?,
+        })
+    }
+}
+
+impl Drop for RustMiscdev {
+    fn drop(&mut self) {
+        pr_info!("Rust miscellaneous device sample (exit)\n");
+    }
+}
diff --git a/samples/rust/rust_module_parameters.rs b/samples/rust/rust_module_parameters.rs
new file mode 100644
index 000000000000..22459beba831
--- /dev/null
+++ b/samples/rust/rust_module_parameters.rs
@@ -0,0 +1,69 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Rust module parameters sample.
+
+use kernel::prelude::*;
+
+module! {
+    type: RustModuleParameters,
+    name: b"rust_module_parameters",
+    author: b"Rust for Linux Contributors",
+    description: b"Rust module parameters sample",
+    license: b"GPL v2",
+    params: {
+        my_bool: bool {
+            default: true,
+            permissions: 0,
+            description: b"Example of bool",
+        },
+        my_i32: i32 {
+            default: 42,
+            permissions: 0o644,
+            description: b"Example of i32",
+        },
+        my_str: str {
+            default: b"default str val",
+            permissions: 0o644,
+            description: b"Example of a string param",
+        },
+        my_usize: usize {
+            default: 42,
+            permissions: 0o644,
+            description: b"Example of usize",
+        },
+        my_array: ArrayParam<i32, 3> {
+            default: [0, 1],
+            permissions: 0,
+            description: b"Example of array",
+        },
+    },
+}
+
+struct RustModuleParameters;
+
+impl KernelModule for RustModuleParameters {
+    fn init(_name: &'static CStr, module: &'static ThisModule) -> Result<Self> {
+        pr_info!("Rust module parameters sample (init)\n");
+
+        {
+            let lock = module.kernel_param_lock();
+            pr_info!("Parameters:\n");
+            pr_info!("  my_bool:    {}\n", my_bool.read());
+            pr_info!("  my_i32:     {}\n", my_i32.read(&lock));
+            pr_info!(
+                "  my_str:     {}\n",
+                core::str::from_utf8(my_str.read(&lock))?
+            );
+            pr_info!("  my_usize:   {}\n", my_usize.read(&lock));
+            pr_info!("  my_array:   {:?}\n", my_array.read());
+        }
+
+        Ok(RustModuleParameters)
+    }
+}
+
+impl Drop for RustModuleParameters {
+    fn drop(&mut self) {
+        pr_info!("Rust module parameters sample (exit)\n");
+    }
+}
diff --git a/samples/rust/rust_platform.rs b/samples/rust/rust_platform.rs
new file mode 100644
index 000000000000..c0b740094c59
--- /dev/null
+++ b/samples/rust/rust_platform.rs
@@ -0,0 +1,22 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Rust platform device driver sample.
+
+use kernel::{module_platform_driver, of, platform, prelude::*};
+
+module_platform_driver! {
+    type: Driver,
+    name: b"rust_platform",
+    license: b"GPL v2",
+}
+
+struct Driver;
+impl platform::Driver for Driver {
+    kernel::define_of_id_table! {(), [
+        (of::DeviceId::Compatible(b"rust,sample"), None),
+    ]}
+
+    fn probe(_dev: &mut platform::Device, _id_info: Option<&Self::IdInfo>) -> Result {
+        Ok(())
+    }
+}
diff --git a/samples/rust/rust_print.rs b/samples/rust/rust_print.rs
new file mode 100644
index 000000000000..4a6b423af835
--- /dev/null
+++ b/samples/rust/rust_print.rs
@@ -0,0 +1,54 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Rust printing macros sample.
+
+use kernel::prelude::*;
+use kernel::{pr_cont, str::CStr, ThisModule};
+
+module! {
+    type: RustPrint,
+    name: b"rust_print",
+    author: b"Rust for Linux Contributors",
+    description: b"Rust printing macros sample",
+    license: b"GPL v2",
+}
+
+struct RustPrint;
+
+impl KernelModule for RustPrint {
+    fn init(_name: &'static CStr, _module: &'static ThisModule) -> Result<Self> {
+        pr_info!("Rust printing macros sample (init)\n");
+
+        pr_emerg!("Emergency message (level 0) without args\n");
+        pr_alert!("Alert message (level 1) without args\n");
+        pr_crit!("Critical message (level 2) without args\n");
+        pr_err!("Error message (level 3) without args\n");
+        pr_warn!("Warning message (level 4) without args\n");
+        pr_notice!("Notice message (level 5) without args\n");
+        pr_info!("Info message (level 6) without args\n");
+
+        pr_info!("A line that");
+        pr_cont!(" is continued");
+        pr_cont!(" without args\n");
+
+        pr_emerg!("{} message (level {}) with args\n", "Emergency", 0);
+        pr_alert!("{} message (level {}) with args\n", "Alert", 1);
+        pr_crit!("{} message (level {}) with args\n", "Critical", 2);
+        pr_err!("{} message (level {}) with args\n", "Error", 3);
+        pr_warn!("{} message (level {}) with args\n", "Warning", 4);
+        pr_notice!("{} message (level {}) with args\n", "Notice", 5);
+        pr_info!("{} message (level {}) with args\n", "Info", 6);
+
+        pr_info!("A {} that", "line");
+        pr_cont!(" is {}", "continued");
+        pr_cont!(" with {}\n", "args");
+
+        Ok(RustPrint)
+    }
+}
+
+impl Drop for RustPrint {
+    fn drop(&mut self) {
+        pr_info!("Rust printing macros sample (exit)\n");
+    }
+}
diff --git a/samples/rust/rust_random.rs b/samples/rust/rust_random.rs
new file mode 100644
index 000000000000..c1319513b170
--- /dev/null
+++ b/samples/rust/rust_random.rs
@@ -0,0 +1,61 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Rust random device.
+//!
+//! Adapted from Alex Gaynor's original available at
+//! <https://github.com/alex/just-use/blob/master/src/lib.rs>.
+
+use kernel::{
+    file::File,
+    file_operations::FileOperations,
+    io_buffer::{IoBufferReader, IoBufferWriter},
+    prelude::*,
+};
+
+struct RandomFile;
+
+impl FileOperations for RandomFile {
+    kernel::declare_file_operations!(read, write, read_iter, write_iter);
+
+    fn open(_data: &(), _file: &File) -> Result {
+        Ok(())
+    }
+
+    fn read(_this: (), file: &File, buf: &mut impl IoBufferWriter, _: u64) -> Result<usize> {
+        let total_len = buf.len();
+        let mut chunkbuf = [0; 256];
+
+        while !buf.is_empty() {
+            let len = chunkbuf.len().min(buf.len());
+            let chunk = &mut chunkbuf[0..len];
+
+            if file.is_blocking() {
+                kernel::random::getrandom(chunk)?;
+            } else {
+                kernel::random::getrandom_nonblock(chunk)?;
+            }
+            buf.write_slice(chunk)?;
+        }
+        Ok(total_len)
+    }
+
+    fn write(_this: (), _file: &File, buf: &mut impl IoBufferReader, _: u64) -> Result<usize> {
+        let total_len = buf.len();
+        let mut chunkbuf = [0; 256];
+        while !buf.is_empty() {
+            let len = chunkbuf.len().min(buf.len());
+            let chunk = &mut chunkbuf[0..len];
+            buf.read_slice(chunk)?;
+            kernel::random::add_randomness(chunk);
+        }
+        Ok(total_len)
+    }
+}
+
+module_misc_device! {
+    type: RandomFile,
+    name: b"rust_random",
+    author: b"Rust for Linux Contributors",
+    description: b"Just use /dev/urandom: Now with early-boot safety",
+    license: b"GPL v2",
+}
diff --git a/samples/rust/rust_semaphore.rs b/samples/rust/rust_semaphore.rs
new file mode 100644
index 000000000000..de3fc3739de3
--- /dev/null
+++ b/samples/rust/rust_semaphore.rs
@@ -0,0 +1,172 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Rust semaphore sample.
+//!
+//! A counting semaphore that can be used by userspace.
+//!
+//! The count is incremented by writes to the device. A write of `n` bytes results in an increment
+//! of `n`. It is decremented by reads; each read results in the count being decremented by 1. If
+//! the count is already zero, a read will block until another write increments it.
+//!
+//! This can be used in user space from the shell for example  as follows (assuming a node called
+//! `semaphore`): `cat semaphore` decrements the count by 1 (waiting for it to become non-zero
+//! before decrementing); `echo -n 123 > semaphore` increments the semaphore by 3, potentially
+//! unblocking up to 3 blocked readers.
+
+use core::sync::atomic::{AtomicU64, Ordering};
+use kernel::{
+    condvar_init, declare_file_operations,
+    file::File,
+    file_operations::{FileOperations, IoctlCommand, IoctlHandler},
+    io_buffer::{IoBufferReader, IoBufferWriter},
+    miscdev::Registration,
+    mutex_init,
+    prelude::*,
+    sync::{CondVar, Mutex, Ref, UniqueRef},
+    user_ptr::{UserSlicePtrReader, UserSlicePtrWriter},
+};
+
+module! {
+    type: RustSemaphore,
+    name: b"rust_semaphore",
+    author: b"Rust for Linux Contributors",
+    description: b"Rust semaphore sample",
+    license: b"GPL v2",
+}
+
+struct SemaphoreInner {
+    count: usize,
+    max_seen: usize,
+}
+
+struct Semaphore {
+    changed: CondVar,
+    inner: Mutex<SemaphoreInner>,
+}
+
+struct FileState {
+    read_count: AtomicU64,
+    shared: Ref<Semaphore>,
+}
+
+impl FileState {
+    fn consume(&self) -> Result {
+        let mut inner = self.shared.inner.lock();
+        while inner.count == 0 {
+            if self.shared.changed.wait(&mut inner) {
+                return Err(Error::EINTR);
+            }
+        }
+        inner.count -= 1;
+        Ok(())
+    }
+}
+
+impl FileOperations for FileState {
+    type Wrapper = Box<Self>;
+    type OpenData = Ref<Semaphore>;
+
+    declare_file_operations!(read, write, ioctl);
+
+    fn open(shared: &Ref<Semaphore>, _file: &File) -> Result<Box<Self>> {
+        Ok(Box::try_new(Self {
+            read_count: AtomicU64::new(0),
+            shared: shared.clone(),
+        })?)
+    }
+
+    fn read(this: &Self, _: &File, data: &mut impl IoBufferWriter, offset: u64) -> Result<usize> {
+        if data.is_empty() || offset > 0 {
+            return Ok(0);
+        }
+        this.consume()?;
+        data.write_slice(&[0u8; 1])?;
+        this.read_count.fetch_add(1, Ordering::Relaxed);
+        Ok(1)
+    }
+
+    fn write(this: &Self, _: &File, data: &mut impl IoBufferReader, _offs: u64) -> Result<usize> {
+        {
+            let mut inner = this.shared.inner.lock();
+            inner.count = inner.count.saturating_add(data.len());
+            if inner.count > inner.max_seen {
+                inner.max_seen = inner.count;
+            }
+        }
+
+        this.shared.changed.notify_all();
+        Ok(data.len())
+    }
+
+    fn ioctl(this: &Self, file: &File, cmd: &mut IoctlCommand) -> Result<i32> {
+        cmd.dispatch::<Self>(this, file)
+    }
+}
+
+struct RustSemaphore {
+    _dev: Pin<Box<Registration<FileState>>>,
+}
+
+impl KernelModule for RustSemaphore {
+    fn init(name: &'static CStr, _module: &'static ThisModule) -> Result<Self> {
+        pr_info!("Rust semaphore sample (init)\n");
+
+        let mut sema = Pin::from(UniqueRef::try_new(Semaphore {
+            // SAFETY: `condvar_init!` is called below.
+            changed: unsafe { CondVar::new() },
+
+            // SAFETY: `mutex_init!` is called below.
+            inner: unsafe {
+                Mutex::new(SemaphoreInner {
+                    count: 0,
+                    max_seen: 0,
+                })
+            },
+        })?);
+
+        // SAFETY: `changed` is pinned when `sema` is.
+        let pinned = unsafe { sema.as_mut().map_unchecked_mut(|s| &mut s.changed) };
+        condvar_init!(pinned, "Semaphore::changed");
+
+        // SAFETY: `inner` is pinned when `sema` is.
+        let pinned = unsafe { sema.as_mut().map_unchecked_mut(|s| &mut s.inner) };
+        mutex_init!(pinned, "Semaphore::inner");
+
+        Ok(Self {
+            _dev: Registration::new_pinned(name, sema.into())?,
+        })
+    }
+}
+
+impl Drop for RustSemaphore {
+    fn drop(&mut self) {
+        pr_info!("Rust semaphore sample (exit)\n");
+    }
+}
+
+const IOCTL_GET_READ_COUNT: u32 = 0x80086301;
+const IOCTL_SET_READ_COUNT: u32 = 0x40086301;
+
+impl IoctlHandler for FileState {
+    type Target<'a> = &'a Self;
+
+    fn read(this: &Self, _: &File, cmd: u32, writer: &mut UserSlicePtrWriter) -> Result<i32> {
+        match cmd {
+            IOCTL_GET_READ_COUNT => {
+                writer.write(&this.read_count.load(Ordering::Relaxed))?;
+                Ok(0)
+            }
+            _ => Err(Error::EINVAL),
+        }
+    }
+
+    fn write(this: &Self, _: &File, cmd: u32, reader: &mut UserSlicePtrReader) -> Result<i32> {
+        match cmd {
+            IOCTL_SET_READ_COUNT => {
+                this.read_count.store(reader.read()?, Ordering::Relaxed);
+                Ok(0)
+            }
+            _ => Err(Error::EINVAL),
+        }
+    }
+}
diff --git a/samples/rust/rust_semaphore_c.c b/samples/rust/rust_semaphore_c.c
new file mode 100644
index 000000000000..cdc121d4030d
--- /dev/null
+++ b/samples/rust/rust_semaphore_c.c
@@ -0,0 +1,212 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Rust semaphore sample (in C, for comparison)
+ *
+ * This is a C implementation of `rust_semaphore.rs`. Refer to the description
+ * in that file for details on the device.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/miscdevice.h>
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/slab.h>
+#include <linux/refcount.h>
+#include <linux/wait.h>
+
+#define IOCTL_GET_READ_COUNT _IOR('c', 1, u64)
+#define IOCTL_SET_READ_COUNT _IOW('c', 1, u64)
+
+struct semaphore_state {
+	struct kref ref;
+	struct miscdevice miscdev;
+	wait_queue_head_t changed;
+	struct mutex mutex;
+	size_t count;
+	size_t max_seen;
+};
+
+struct file_state {
+	atomic64_t read_count;
+	struct semaphore_state *shared;
+};
+
+static int semaphore_consume(struct semaphore_state *state)
+{
+	DEFINE_WAIT(wait);
+
+	mutex_lock(&state->mutex);
+	while (state->count == 0) {
+		prepare_to_wait(&state->changed, &wait, TASK_INTERRUPTIBLE);
+		mutex_unlock(&state->mutex);
+		schedule();
+		finish_wait(&state->changed, &wait);
+		if (signal_pending(current))
+			return -EINTR;
+		mutex_lock(&state->mutex);
+	}
+
+	state->count--;
+	mutex_unlock(&state->mutex);
+
+	return 0;
+}
+
+static int semaphore_open(struct inode *nodp, struct file *filp)
+{
+	struct semaphore_state *shared =
+		container_of(filp->private_data, struct semaphore_state, miscdev);
+	struct file_state *state;
+
+	state = kzalloc(sizeof(*state), GFP_KERNEL);
+	if (!state)
+		return -ENOMEM;
+
+	kref_get(&shared->ref);
+	state->shared = shared;
+	atomic64_set(&state->read_count, 0);
+
+	filp->private_data = state;
+
+	return 0;
+}
+
+static ssize_t semaphore_write(struct file *filp, const char __user *buffer, size_t count,
+			       loff_t *ppos)
+{
+	struct file_state *state = filp->private_data;
+	struct semaphore_state *shared = state->shared;
+
+	mutex_lock(&shared->mutex);
+
+	shared->count += count;
+	if (shared->count < count)
+		shared->count = SIZE_MAX;
+
+	if (shared->count > shared->max_seen)
+		shared->max_seen = shared->count;
+
+	mutex_unlock(&shared->mutex);
+
+	wake_up_all(&shared->changed);
+
+	return count;
+}
+
+static ssize_t semaphore_read(struct file *filp, char __user *buffer,
+			      size_t count, loff_t *ppos)
+{
+	struct file_state *state = filp->private_data;
+	char c = 0;
+	int ret;
+
+	if (count == 0 || *ppos > 0)
+		return 0;
+
+	ret = semaphore_consume(state->shared);
+	if (ret)
+		return ret;
+
+	if (copy_to_user(buffer, &c, sizeof(c)))
+		return -EFAULT;
+
+	atomic64_add(1, &state->read_count);
+	*ppos += 1;
+	return 1;
+}
+
+static long semaphore_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
+{
+	struct file_state *state = filp->private_data;
+	void __user *buffer = (void __user *)arg;
+	u64 value;
+
+	switch (cmd) {
+	case IOCTL_GET_READ_COUNT:
+		value = atomic64_read(&state->read_count);
+		if (copy_to_user(buffer, &value, sizeof(value)))
+			return -EFAULT;
+		return 0;
+	case IOCTL_SET_READ_COUNT:
+		if (copy_from_user(&value, buffer, sizeof(value)))
+			return -EFAULT;
+		atomic64_set(&state->read_count, value);
+		return 0;
+	default:
+		return -EINVAL;
+	}
+}
+
+static void semaphore_free(struct kref *kref)
+{
+	struct semaphore_state *device;
+
+	device = container_of(kref, struct semaphore_state, ref);
+	kfree(device);
+}
+
+static int semaphore_release(struct inode *nodp, struct file *filp)
+{
+	struct file_state *state = filp->private_data;
+
+	kref_put(&state->shared->ref, semaphore_free);
+	kfree(state);
+	return 0;
+}
+
+static const struct file_operations semaphore_fops = {
+	.owner = THIS_MODULE,
+	.open = semaphore_open,
+	.read = semaphore_read,
+	.write = semaphore_write,
+	.compat_ioctl = semaphore_ioctl,
+	.release = semaphore_release,
+};
+
+static struct semaphore_state *device;
+
+static int __init semaphore_init(void)
+{
+	int ret;
+	struct semaphore_state *state;
+
+	pr_info("Rust semaphore sample (in C, for comparison) (init)\n");
+
+	state = kzalloc(sizeof(*state), GFP_KERNEL);
+	if (!state)
+		return -ENOMEM;
+
+	mutex_init(&state->mutex);
+	kref_init(&state->ref);
+	init_waitqueue_head(&state->changed);
+
+	state->miscdev.fops = &semaphore_fops;
+	state->miscdev.minor = MISC_DYNAMIC_MINOR;
+	state->miscdev.name = "semaphore";
+
+	ret = misc_register(&state->miscdev);
+	if (ret < 0) {
+		kfree(state);
+		return ret;
+	}
+
+	device = state;
+
+	return 0;
+}
+
+static void __exit semaphore_exit(void)
+{
+	pr_info("Rust semaphore sample (in C, for comparison) (exit)\n");
+
+	misc_deregister(&device->miscdev);
+	kref_put(&device->ref, semaphore_free);
+}
+
+module_init(semaphore_init);
+module_exit(semaphore_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Rust for Linux Contributors");
+MODULE_DESCRIPTION("Rust semaphore sample (in C, for comparison)");
diff --git a/samples/rust/rust_stack_probing.rs b/samples/rust/rust_stack_probing.rs
new file mode 100644
index 000000000000..214d4d1f6528
--- /dev/null
+++ b/samples/rust/rust_stack_probing.rs
@@ -0,0 +1,36 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Rust stack probing sample.
+
+use kernel::prelude::*;
+
+module! {
+    type: RustStackProbing,
+    name: b"rust_stack_probing",
+    author: b"Rust for Linux Contributors",
+    description: b"Rust stack probing sample",
+    license: b"GPL v2",
+}
+
+struct RustStackProbing;
+
+impl KernelModule for RustStackProbing {
+    fn init(_name: &'static CStr, _module: &'static ThisModule) -> Result<Self> {
+        pr_info!("Rust stack probing sample (init)\n");
+
+        // Including this large variable on the stack will trigger
+        // stack probing on the supported archs.
+        // This will verify that stack probing does not lead to
+        // any errors if we need to link `__rust_probestack`.
+        let x: [u64; 514] = core::hint::black_box([5; 514]);
+        pr_info!("Large array has length: {}\n", x.len());
+
+        Ok(RustStackProbing)
+    }
+}
+
+impl Drop for RustStackProbing {
+    fn drop(&mut self) {
+        pr_info!("Rust stack probing sample (exit)\n");
+    }
+}
diff --git a/samples/rust/rust_sync.rs b/samples/rust/rust_sync.rs
new file mode 100644
index 000000000000..e3b8860798d4
--- /dev/null
+++ b/samples/rust/rust_sync.rs
@@ -0,0 +1,78 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Rust synchronisation primitives sample.
+
+use kernel::prelude::*;
+use kernel::{
+    condvar_init, mutex_init, spinlock_init,
+    sync::{CondVar, Mutex, SpinLock},
+};
+
+module! {
+    type: RustSync,
+    name: b"rust_sync",
+    author: b"Rust for Linux Contributors",
+    description: b"Rust synchronisation primitives sample",
+    license: b"GPL v2",
+}
+
+struct RustSync;
+
+impl KernelModule for RustSync {
+    fn init(_name: &'static CStr, _module: &'static ThisModule) -> Result<Self> {
+        pr_info!("Rust synchronisation primitives sample (init)\n");
+
+        // Test mutexes.
+        {
+            // SAFETY: `init` is called below.
+            let mut data = Pin::from(Box::try_new(unsafe { Mutex::new(0) })?);
+            mutex_init!(data.as_mut(), "RustSync::init::data1");
+            *data.lock() = 10;
+            pr_info!("Value: {}\n", *data.lock());
+
+            // SAFETY: `init` is called below.
+            let mut cv = Pin::from(Box::try_new(unsafe { CondVar::new() })?);
+            condvar_init!(cv.as_mut(), "RustSync::init::cv1");
+
+            {
+                let mut guard = data.lock();
+                while *guard != 10 {
+                    let _ = cv.wait(&mut guard);
+                }
+            }
+            cv.notify_one();
+            cv.notify_all();
+            cv.free_waiters();
+        }
+
+        // Test spinlocks.
+        {
+            // SAFETY: `init` is called below.
+            let mut data = Pin::from(Box::try_new(unsafe { SpinLock::new(0) })?);
+            spinlock_init!(data.as_mut(), "RustSync::init::data2");
+            *data.lock() = 10;
+            pr_info!("Value: {}\n", *data.lock());
+
+            // SAFETY: `init` is called below.
+            let mut cv = Pin::from(Box::try_new(unsafe { CondVar::new() })?);
+            condvar_init!(cv.as_mut(), "RustSync::init::cv2");
+            {
+                let mut guard = data.lock();
+                while *guard != 10 {
+                    let _ = cv.wait(&mut guard);
+                }
+            }
+            cv.notify_one();
+            cv.notify_all();
+            cv.free_waiters();
+        }
+
+        Ok(RustSync)
+    }
+}
+
+impl Drop for RustSync {
+    fn drop(&mut self) {
+        pr_info!("Rust synchronisation primitives sample (exit)\n");
+    }
+}
-- 
2.35.1


^ permalink raw reply related	[relevance 3%]

* [PATCH v5 10/20] rust: add `kernel` crate
  @ 2022-03-17 18:09  1% ` Miguel Ojeda
  2022-03-17 18:10  3% ` [PATCH v5 17/20] samples: add Rust examples Miguel Ojeda
  1 sibling, 0 replies; 77+ results
From: Miguel Ojeda @ 2022-03-17 18:09 UTC (permalink / raw)
  To: Linus Torvalds, Greg Kroah-Hartman
  Cc: rust-for-linux, linux-kernel, Miguel Ojeda, Wedson Almeida Filho,
	Alex Gaynor, Geoffrey Thomas, Finn Behrens, Adam Bratschi-Kaye,
	Michael Ellerman, Sumera Priyadarsini, Sven Van Asbroeck,
	Gary Guo, Boris-Chengbiao Zhou, Boqun Feng, Fox Chen,
	Dan Robertson, Viktor Garske, Dariusz Sosnowski,
	Léo Lanteri Thauvin, Niklas Mohrin, Gioh Kim, Daniel Xu,
	Milan Landaverde, Morgan Bartlett, Maciej Falkowski,
	Jiapeng Chong

From: Wedson Almeida Filho <wedsonaf@google.com>

The `kernel` crate currently includes all the abstractions that wrap
kernel features written in C.

These abstractions call the C side of the kernel via the generated
bindings with the `bindgen` tool. Modules developed in Rust should
never call the bindings themselves.

In the future, as the abstractions grow in number, we may need
to split this crate into several, possibly following a similar
subdivision in subsystems as the kernel itself and/or moving
the code to the actual subsystems.

Co-developed-by: Alex Gaynor <alex.gaynor@gmail.com>
Signed-off-by: Alex Gaynor <alex.gaynor@gmail.com>
Co-developed-by: Geoffrey Thomas <geofft@ldpreload.com>
Signed-off-by: Geoffrey Thomas <geofft@ldpreload.com>
Co-developed-by: Finn Behrens <me@kloenk.de>
Signed-off-by: Finn Behrens <me@kloenk.de>
Co-developed-by: Adam Bratschi-Kaye <ark.email@gmail.com>
Signed-off-by: Adam Bratschi-Kaye <ark.email@gmail.com>
Co-developed-by: Michael Ellerman <mpe@ellerman.id.au>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Co-developed-by: Sumera Priyadarsini <sylphrenadin@gmail.com>
Signed-off-by: Sumera Priyadarsini <sylphrenadin@gmail.com>
Co-developed-by: Sven Van Asbroeck <thesven73@gmail.com>
Signed-off-by: Sven Van Asbroeck <thesven73@gmail.com>
Co-developed-by: Gary Guo <gary@garyguo.net>
Signed-off-by: Gary Guo <gary@garyguo.net>
Co-developed-by: Boris-Chengbiao Zhou <bobo1239@web.de>
Signed-off-by: Boris-Chengbiao Zhou <bobo1239@web.de>
Co-developed-by: Boqun Feng <boqun.feng@gmail.com>
Signed-off-by: Boqun Feng <boqun.feng@gmail.com>
Co-developed-by: Fox Chen <foxhlchen@gmail.com>
Signed-off-by: Fox Chen <foxhlchen@gmail.com>
Co-developed-by: Dan Robertson <daniel.robertson@starlab.io>
Signed-off-by: Dan Robertson <daniel.robertson@starlab.io>
Co-developed-by: Viktor Garske <viktor@v-gar.de>
Signed-off-by: Viktor Garske <viktor@v-gar.de>
Co-developed-by: Dariusz Sosnowski <dsosnowski@dsosnowski.pl>
Signed-off-by: Dariusz Sosnowski <dsosnowski@dsosnowski.pl>
Co-developed-by: Léo Lanteri Thauvin <leseulartichaut@gmail.com>
Signed-off-by: Léo Lanteri Thauvin <leseulartichaut@gmail.com>
Co-developed-by: Niklas Mohrin <dev@niklasmohrin.de>
Signed-off-by: Niklas Mohrin <dev@niklasmohrin.de>
Co-developed-by: Gioh Kim <gurugio@gmail.com>
Signed-off-by: Gioh Kim <gurugio@gmail.com>
Co-developed-by: Daniel Xu <dxu@dxuuu.xyz>
Signed-off-by: Daniel Xu <dxu@dxuuu.xyz>
Co-developed-by: Milan Landaverde <milan@mdaverde.com>
Signed-off-by: Milan Landaverde <milan@mdaverde.com>
Co-developed-by: Morgan Bartlett <mjmouse9999@gmail.com>
Signed-off-by: Morgan Bartlett <mjmouse9999@gmail.com>
Co-developed-by: Maciej Falkowski <m.falkowski@samsung.com>
Signed-off-by: Maciej Falkowski <m.falkowski@samsung.com>
Co-developed-by: Jiapeng Chong <jiapeng.chong@linux.alibaba.com>
Signed-off-by: Jiapeng Chong <jiapeng.chong@linux.alibaba.com>
Signed-off-by: Wedson Almeida Filho <wedsonaf@google.com>
Co-developed-by: Miguel Ojeda <ojeda@kernel.org>
Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
---
 rust/kernel/allocator.rs      |  65 +++
 rust/kernel/amba.rs           | 259 ++++++++++
 rust/kernel/bindings.rs       |  47 ++
 rust/kernel/bindings_helper.h |  37 ++
 rust/kernel/build_assert.rs   |  80 ++++
 rust/kernel/c_types.rs        | 119 +++++
 rust/kernel/chrdev.rs         | 207 ++++++++
 rust/kernel/clk.rs            |  75 +++
 rust/kernel/cred.rs           |  73 +++
 rust/kernel/device.rs         | 554 +++++++++++++++++++++
 rust/kernel/driver.rs         | 440 +++++++++++++++++
 rust/kernel/error.rs          | 560 ++++++++++++++++++++++
 rust/kernel/file.rs           | 873 ++++++++++++++++++++++++++++++++++
 rust/kernel/gpio.rs           | 478 +++++++++++++++++++
 rust/kernel/hwrng.rs          | 242 ++++++++++
 rust/kernel/io_buffer.rs      | 153 ++++++
 rust/kernel/io_mem.rs         | 237 +++++++++
 rust/kernel/iov_iter.rs       |  81 ++++
 rust/kernel/irq.rs            | 409 ++++++++++++++++
 rust/kernel/lib.rs            | 260 ++++++++++
 rust/kernel/linked_list.rs    | 247 ++++++++++
 rust/kernel/miscdev.rs        | 291 ++++++++++++
 rust/kernel/mm.rs             | 149 ++++++
 rust/kernel/module_param.rs   | 498 +++++++++++++++++++
 rust/kernel/of.rs             |  63 +++
 rust/kernel/pages.rs          | 144 ++++++
 rust/kernel/platform.rs       | 224 +++++++++
 rust/kernel/power.rs          | 118 +++++
 rust/kernel/prelude.rs        |  36 ++
 rust/kernel/print.rs          | 414 ++++++++++++++++
 rust/kernel/random.rs         |  50 ++
 rust/kernel/raw_list.rs       | 361 ++++++++++++++
 rust/kernel/rbtree.rs         | 562 ++++++++++++++++++++++
 rust/kernel/revocable.rs      | 163 +++++++
 rust/kernel/security.rs       |  36 ++
 rust/kernel/static_assert.rs  |  39 ++
 rust/kernel/std_vendor.rs     | 150 ++++++
 rust/kernel/str.rs            | 592 +++++++++++++++++++++++
 rust/kernel/sysctl.rs         | 199 ++++++++
 rust/kernel/task.rs           | 182 +++++++
 rust/kernel/types.rs          | 569 ++++++++++++++++++++++
 rust/kernel/user_ptr.rs       | 175 +++++++
 42 files changed, 10511 insertions(+)
 create mode 100644 rust/kernel/allocator.rs
 create mode 100644 rust/kernel/amba.rs
 create mode 100644 rust/kernel/bindings.rs
 create mode 100644 rust/kernel/bindings_helper.h
 create mode 100644 rust/kernel/build_assert.rs
 create mode 100644 rust/kernel/c_types.rs
 create mode 100644 rust/kernel/chrdev.rs
 create mode 100644 rust/kernel/clk.rs
 create mode 100644 rust/kernel/cred.rs
 create mode 100644 rust/kernel/device.rs
 create mode 100644 rust/kernel/driver.rs
 create mode 100644 rust/kernel/error.rs
 create mode 100644 rust/kernel/file.rs
 create mode 100644 rust/kernel/gpio.rs
 create mode 100644 rust/kernel/hwrng.rs
 create mode 100644 rust/kernel/io_buffer.rs
 create mode 100644 rust/kernel/io_mem.rs
 create mode 100644 rust/kernel/iov_iter.rs
 create mode 100644 rust/kernel/irq.rs
 create mode 100644 rust/kernel/lib.rs
 create mode 100644 rust/kernel/linked_list.rs
 create mode 100644 rust/kernel/miscdev.rs
 create mode 100644 rust/kernel/mm.rs
 create mode 100644 rust/kernel/module_param.rs
 create mode 100644 rust/kernel/of.rs
 create mode 100644 rust/kernel/pages.rs
 create mode 100644 rust/kernel/platform.rs
 create mode 100644 rust/kernel/power.rs
 create mode 100644 rust/kernel/prelude.rs
 create mode 100644 rust/kernel/print.rs
 create mode 100644 rust/kernel/random.rs
 create mode 100644 rust/kernel/raw_list.rs
 create mode 100644 rust/kernel/rbtree.rs
 create mode 100644 rust/kernel/revocable.rs
 create mode 100644 rust/kernel/security.rs
 create mode 100644 rust/kernel/static_assert.rs
 create mode 100644 rust/kernel/std_vendor.rs
 create mode 100644 rust/kernel/str.rs
 create mode 100644 rust/kernel/sysctl.rs
 create mode 100644 rust/kernel/task.rs
 create mode 100644 rust/kernel/types.rs
 create mode 100644 rust/kernel/user_ptr.rs

diff --git a/rust/kernel/allocator.rs b/rust/kernel/allocator.rs
new file mode 100644
index 000000000000..4c5d2fc6f206
--- /dev/null
+++ b/rust/kernel/allocator.rs
@@ -0,0 +1,65 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Allocator support.
+
+use core::alloc::{GlobalAlloc, Layout};
+use core::ptr;
+
+use crate::bindings;
+use crate::c_types;
+
+struct KernelAllocator;
+
+unsafe impl GlobalAlloc for KernelAllocator {
+    unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
+        // `krealloc()` is used instead of `kmalloc()` because the latter is
+        // an inline function and cannot be bound to as a result.
+        unsafe { bindings::krealloc(ptr::null(), layout.size(), bindings::GFP_KERNEL) as *mut u8 }
+    }
+
+    unsafe fn dealloc(&self, ptr: *mut u8, _layout: Layout) {
+        unsafe {
+            bindings::kfree(ptr as *const c_types::c_void);
+        }
+    }
+}
+
+#[global_allocator]
+static ALLOCATOR: KernelAllocator = KernelAllocator;
+
+// `rustc` only generates these for some crate types. Even then, we would need
+// to extract the object file that has them from the archive. For the moment,
+// let's generate them ourselves instead.
+//
+// Note that `#[no_mangle]` implies exported too, nowadays.
+#[no_mangle]
+fn __rust_alloc(size: usize, _align: usize) -> *mut u8 {
+    unsafe { bindings::krealloc(core::ptr::null(), size, bindings::GFP_KERNEL) as *mut u8 }
+}
+
+#[no_mangle]
+fn __rust_dealloc(ptr: *mut u8, _size: usize, _align: usize) {
+    unsafe { bindings::kfree(ptr as *const c_types::c_void) };
+}
+
+#[no_mangle]
+fn __rust_realloc(ptr: *mut u8, _old_size: usize, _align: usize, new_size: usize) -> *mut u8 {
+    unsafe {
+        bindings::krealloc(
+            ptr as *const c_types::c_void,
+            new_size,
+            bindings::GFP_KERNEL,
+        ) as *mut u8
+    }
+}
+
+#[no_mangle]
+fn __rust_alloc_zeroed(size: usize, _align: usize) -> *mut u8 {
+    unsafe {
+        bindings::krealloc(
+            core::ptr::null(),
+            size,
+            bindings::GFP_KERNEL | bindings::__GFP_ZERO,
+        ) as *mut u8
+    }
+}
diff --git a/rust/kernel/amba.rs b/rust/kernel/amba.rs
new file mode 100644
index 000000000000..1775eda7dce6
--- /dev/null
+++ b/rust/kernel/amba.rs
@@ -0,0 +1,259 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Amba devices and drivers.
+//!
+//! C header: [`include/linux/amba/bus.h`](../../../../include/linux/amba/bus.h)
+
+use crate::{
+    bindings, c_types, device, driver, error::from_kernel_result, io_mem::Resource, power,
+    str::CStr, to_result, types::PointerWrapper, Result, ThisModule,
+};
+
+/// A registration of an amba driver.
+pub type Registration<T> = driver::Registration<Adapter<T>>;
+
+/// Id of an Amba device.
+#[derive(Clone, Copy)]
+pub struct DeviceId {
+    /// Device id.
+    pub id: u32,
+
+    /// Mask that identifies which bits are valid in the device id.
+    pub mask: u32,
+}
+
+// SAFETY: `ZERO` is all zeroed-out and `to_rawid` stores `offset` in `amba_id::data`.
+unsafe impl const driver::RawDeviceId for DeviceId {
+    type RawType = bindings::amba_id;
+    const ZERO: Self::RawType = bindings::amba_id {
+        id: 0,
+        mask: 0,
+        data: core::ptr::null_mut(),
+    };
+
+    fn to_rawid(&self, offset: isize) -> Self::RawType {
+        bindings::amba_id {
+            id: self.id,
+            mask: self.mask,
+            data: offset as _,
+        }
+    }
+}
+
+/// An amba driver.
+pub trait Driver {
+    /// Data stored on device by driver.
+    type Data: PointerWrapper + Send + Sync + driver::DeviceRemoval = ();
+
+    /// The type that implements the power-management operations.
+    ///
+    /// The default is a type that implements no power-management operations. Drivers that do
+    /// implement them need to specify the type (commonly [`Self`]).
+    type PowerOps: power::Operations<Data = Self::Data> = power::NoOperations<Self::Data>;
+
+    /// The type holding information about each device id supported by the driver.
+    type IdInfo: 'static = ();
+
+    /// The table of device ids supported by the driver.
+    const ID_TABLE: Option<driver::IdTable<'static, DeviceId, Self::IdInfo>> = None;
+
+    /// Probes for the device with the given id.
+    fn probe(dev: &mut Device, id_info: Option<&Self::IdInfo>) -> Result<Self::Data>;
+
+    /// Cleans any resources up that are associated with the device.
+    ///
+    /// This is called when the driver is detached from the device.
+    fn remove(_data: &Self::Data) {}
+}
+
+/// An adapter for the registration of Amba drivers.
+pub struct Adapter<T: Driver>(T);
+
+impl<T: Driver> driver::DriverOps for Adapter<T> {
+    type RegType = bindings::amba_driver;
+
+    unsafe fn register(
+        reg: *mut bindings::amba_driver,
+        name: &'static CStr,
+        module: &'static ThisModule,
+    ) -> Result {
+        // SAFETY: By the safety requirements of this function (defined in the trait defintion),
+        // `reg` is non-null and valid.
+        let amba = unsafe { &mut *reg };
+        amba.drv.name = name.as_char_ptr();
+        amba.drv.owner = module.0;
+        amba.probe = Some(probe_callback::<T>);
+        amba.remove = Some(remove_callback::<T>);
+        if let Some(t) = T::ID_TABLE {
+            amba.id_table = t.as_ref();
+        }
+        if cfg!(CONFIG_PM) {
+            // SAFETY: `probe_callback` sets the driver data after calling `T::Data::into_pointer`,
+            // and we guarantee that `T::Data` is the same as `T::PowerOps::Data` by a constraint
+            // in the type declaration.
+            amba.drv.pm = unsafe { power::OpsTable::<T::PowerOps>::build() };
+        }
+        // SAFETY: By the safety requirements of this function, `reg` is valid and fully
+        // initialised.
+        to_result(|| unsafe { bindings::amba_driver_register(reg) })
+    }
+
+    unsafe fn unregister(reg: *mut bindings::amba_driver) {
+        // SAFETY: By the safety requirements of this function (defined in the trait definition),
+        // `reg` was passed (and updated) by a previous successful call to `amba_driver_register`.
+        unsafe { bindings::amba_driver_unregister(reg) };
+    }
+}
+
+unsafe extern "C" fn probe_callback<T: Driver>(
+    adev: *mut bindings::amba_device,
+    aid: *const bindings::amba_id,
+) -> c_types::c_int {
+    from_kernel_result! {
+        // SAFETY: `adev` is valid by the contract with the C code. `dev` is alive only for the
+        // duration of this call, so it is guaranteed to remain alive for the lifetime of `dev`.
+        let mut dev = unsafe { Device::from_ptr(adev) };
+        // SAFETY: `aid` is valid by the requirements the contract with the C code.
+        let offset = unsafe { (*aid).data };
+        let info = if offset.is_null() {
+            None
+        } else {
+            // SAFETY: The offset comes from a previous call to `offset_from` in `IdArray::new`,
+            // which guarantees that the resulting pointer is within the table.
+            let ptr = unsafe { aid.cast::<u8>().offset(offset as _).cast::<Option<T::IdInfo>>() };
+            // SAFETY: The id table has a static lifetime, so `ptr` is guaranteed to be valid for
+            // read.
+            unsafe { (&*ptr).as_ref() }
+        };
+        let data = T::probe(&mut dev, info)?;
+        let ptr = T::Data::into_pointer(data);
+        // SAFETY: `adev` is valid for write by the contract with the C code.
+        unsafe { bindings::amba_set_drvdata(adev, ptr as _) };
+        Ok(0)
+    }
+}
+
+unsafe extern "C" fn remove_callback<T: Driver>(adev: *mut bindings::amba_device) {
+    // SAFETY: `adev` is valid by the contract with the C code.
+    let ptr = unsafe { bindings::amba_get_drvdata(adev) };
+    // SAFETY: The value returned by `amba_get_drvdata` was stored by a previous call to
+    // `amba_set_drvdata` in `probe_callback` above; the value comes from a call to
+    // `T::Data::into_pointer`.
+    let data = unsafe { T::Data::from_pointer(ptr) };
+    T::remove(&data);
+    <T::Data as driver::DeviceRemoval>::device_remove(&data);
+}
+
+/// An Amba device.
+///
+/// # Invariants
+///
+/// The field `ptr` is non-null and valid for the lifetime of the object.
+pub struct Device {
+    ptr: *mut bindings::amba_device,
+    res: Option<Resource>,
+}
+
+impl Device {
+    /// Creates a new device from the given pointer.
+    ///
+    /// # Safety
+    ///
+    /// `ptr` must be non-null and valid. It must remain valid for the lifetime of the returned
+    /// instance.
+    unsafe fn from_ptr(ptr: *mut bindings::amba_device) -> Self {
+        // SAFETY: The safety requirements of the function ensure that `ptr` is valid.
+        let dev = unsafe { &mut *ptr };
+        // INVARIANT: The safety requirements of the function ensure the lifetime invariant.
+        Self {
+            ptr,
+            res: Resource::new(dev.res.start, dev.res.end),
+        }
+    }
+
+    /// Returns the io mem resource associated with the device, if there is one.
+    ///
+    /// Ownership of the resource is transferred to the caller, so subsequent calls to this
+    /// function will return [`None`].
+    pub fn take_resource(&mut self) -> Option<Resource> {
+        self.res.take()
+    }
+
+    /// Returns the index-th irq associated with the device, if one exists.
+    pub fn irq(&self, index: usize) -> Option<u32> {
+        // SAFETY: By the type invariants, `self.ptr` is valid for read.
+        let dev = unsafe { &*self.ptr };
+        if index >= dev.irq.len() || dev.irq[index] == 0 {
+            None
+        } else {
+            Some(dev.irq[index])
+        }
+    }
+}
+
+// SAFETY: The device returned by `raw_device` is the raw Amba device.
+unsafe impl device::RawDevice for Device {
+    fn raw_device(&self) -> *mut bindings::device {
+        // SAFETY: By the type invariants, we know that `self.ptr` is non-null and valid.
+        unsafe { &mut (*self.ptr).dev }
+    }
+}
+
+/// Declares a kernel module that exposes a single amba driver.
+///
+/// # Examples
+///
+/// ```ignore
+/// # use kernel::prelude::*;
+/// # use kernel::{amba, define_amba_id_table, module_amba_driver};
+/// #
+/// struct MyDriver;
+/// impl amba::Driver for MyDriver {
+///     // [...]
+/// #   fn probe(_dev: &mut amba::Device, _id: Option<&Self::IdInfo>) -> Result {
+/// #       Ok(())
+/// #   }
+/// #   define_amba_id_table! {(), [
+/// #       ({ id: 0x00041061, mask: 0x000fffff }, None),
+/// #   ]}
+/// }
+///
+/// module_amba_driver! {
+///     type: MyDriver,
+///     name: b"module_name",
+///     author: b"Author name",
+///     license: b"GPL v2",
+/// }
+/// ```
+#[macro_export]
+macro_rules! module_amba_driver {
+    ($($f:tt)*) => {
+        $crate::module_driver!(<T>, $crate::amba::Adapter<T>, { $($f)* });
+    };
+}
+
+/// Defines the id table for amba devices.
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::prelude::*;
+/// # use kernel::{amba, define_amba_id_table};
+/// #
+/// # struct Sample;
+/// # impl kernel::amba::Driver for Sample {
+/// #   fn probe(_dev: &mut amba::Device, _id: Option<&Self::IdInfo>) -> Result {
+/// #       Ok(())
+/// #   }
+///     define_amba_id_table! {(), [
+///         ({ id: 0x00041061, mask: 0x000fffff }, None),
+///     ]}
+/// # }
+/// ```
+#[macro_export]
+macro_rules! define_amba_id_table {
+    ($data_type:ty, $($t:tt)*) => {
+        type IdInfo = $data_type;
+        $crate::define_id_table!(ID_TABLE, $crate::amba::DeviceId, $data_type, $($t)*);
+    };
+}
diff --git a/rust/kernel/bindings.rs b/rust/kernel/bindings.rs
new file mode 100644
index 000000000000..29a21030688e
--- /dev/null
+++ b/rust/kernel/bindings.rs
@@ -0,0 +1,47 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Bindings.
+//!
+//! Imports the generated bindings by `bindgen`.
+
+// See https://github.com/rust-lang/rust-bindgen/issues/1651.
+#![cfg_attr(test, allow(deref_nullptr))]
+#![cfg_attr(test, allow(unaligned_references))]
+#![cfg_attr(test, allow(unsafe_op_in_unsafe_fn))]
+#![allow(
+    clippy::all,
+    non_camel_case_types,
+    non_upper_case_globals,
+    non_snake_case,
+    improper_ctypes,
+    unreachable_pub,
+    unsafe_op_in_unsafe_fn
+)]
+
+mod bindings_raw {
+    // Use glob import here to expose all helpers.
+    // Symbols defined within the module will take precedence to the glob import.
+    pub use super::bindings_helper::*;
+    use crate::c_types;
+    include!(concat!(env!("OBJTREE"), "/rust/bindings_generated.rs"));
+}
+
+// When both a directly exposed symbol and a helper exists for the same function,
+// the directly exposed symbol is preferred and the helper becomes dead code, so
+// ignore the warning here.
+#[allow(dead_code)]
+mod bindings_helper {
+    // Import the generated bindings for types.
+    use super::bindings_raw::*;
+    use crate::c_types;
+    include!(concat!(
+        env!("OBJTREE"),
+        "/rust/bindings_helpers_generated.rs"
+    ));
+}
+
+pub use bindings_raw::*;
+
+pub const GFP_KERNEL: gfp_t = BINDINGS_GFP_KERNEL;
+pub const __GFP_ZERO: gfp_t = BINDINGS___GFP_ZERO;
+pub const __GFP_HIGHMEM: gfp_t = ___GFP_HIGHMEM;
diff --git a/rust/kernel/bindings_helper.h b/rust/kernel/bindings_helper.h
new file mode 100644
index 000000000000..4151cb25f52d
--- /dev/null
+++ b/rust/kernel/bindings_helper.h
@@ -0,0 +1,37 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Header that contains the code (mostly headers) for which Rust bindings
+ * will be automatically generated by `bindgen`.
+ *
+ * Sorted alphabetically.
+ */
+
+#include <asm/io.h>
+#include <linux/amba/bus.h>
+#include <linux/cdev.h>
+#include <linux/clk.h>
+#include <linux/errname.h>
+#include <linux/file.h>
+#include <linux/fs.h>
+#include <linux/gpio/driver.h>
+#include <linux/hw_random.h>
+#include <linux/interrupt.h>
+#include <linux/irqdomain.h>
+#include <linux/irq.h>
+#include <linux/miscdevice.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/poll.h>
+#include <linux/random.h>
+#include <linux/security.h>
+#include <linux/slab.h>
+#include <linux/sysctl.h>
+#include <linux/uaccess.h>
+#include <linux/uio.h>
+#include <uapi/linux/android/binder.h>
+
+/* `bindgen` gets confused at certain things. */
+const gfp_t BINDINGS_GFP_KERNEL = GFP_KERNEL;
+const gfp_t BINDINGS___GFP_ZERO = __GFP_ZERO;
diff --git a/rust/kernel/build_assert.rs b/rust/kernel/build_assert.rs
new file mode 100644
index 000000000000..f726927185c0
--- /dev/null
+++ b/rust/kernel/build_assert.rs
@@ -0,0 +1,80 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Build-time assert.
+
+/// Fails the build if the code path calling `build_error!` can possibly be executed.
+///
+/// If the macro is executed in const context, `build_error!` will panic.
+/// If the compiler or optimizer cannot guarantee that `build_error!` can never
+/// be called, a build error will be triggered.
+///
+/// # Examples
+/// ```
+/// # use kernel::build_error;
+/// #[inline]
+/// fn foo(a: usize) -> usize {
+///     a.checked_add(1).unwrap_or_else(|| build_error!("overflow"))
+/// }
+/// ```
+#[macro_export]
+macro_rules! build_error {
+    () => {{
+        $crate::build_error("")
+    }};
+    ($msg:expr) => {{
+        $crate::build_error($msg)
+    }};
+}
+
+/// Asserts that a boolean expression is `true` at compile time.
+///
+/// If the condition is evaluated to `false` in const context, `build_assert!`
+/// will panic. If the compiler or optimizer cannot guarantee the condition will
+/// be evaluated to `true`, a build error will be triggered.
+///
+/// [`static_assert!`] should be preferred to `build_assert!` whenever possible.
+///
+/// # Examples
+///
+/// These examples show that different types of [`assert!`] will trigger errors
+/// at different stage of compilation. It is preferred to err as early as
+/// possible, so [`static_assert!`] should be used whenever possible.
+/// ```compile_fail
+/// # use kernel::prelude::*;
+/// fn foo() {
+///     static_assert!(1 > 1); // Compile-time error
+///     build_assert!(1 > 1); // Build-time error
+///     assert!(1 > 1); // Run-time error
+/// }
+/// ```
+///
+/// When the condition refers to generic parameters or parameters of an inline function,
+/// [`static_assert!`] cannot be used. Use `build_assert!` in this scenario.
+/// ```no_run
+/// # use kernel::prelude::*;
+/// fn foo<const N: usize>() {
+///     // `static_assert!(N > 1);` is not allowed
+///     build_assert!(N > 1); // Build-time check
+///     assert!(N > 1); // Run-time check
+/// }
+///
+/// #[inline]
+/// fn bar(n: usize) {
+///     // `static_assert!(n > 1);` is not allowed
+///     build_assert!(n > 1); // Build-time check
+///     assert!(n > 1); // Run-time check
+/// }
+/// ```
+#[macro_export]
+macro_rules! build_assert {
+    ($cond:expr $(,)?) => {{
+        if !$cond {
+            $crate::build_error(concat!("assertion failed: ", stringify!($cond)));
+        }
+    }};
+    ($cond:expr, $msg:expr) => {{
+        if !$cond {
+            $crate::build_error($msg);
+        }
+    }};
+}
diff --git a/rust/kernel/c_types.rs b/rust/kernel/c_types.rs
new file mode 100644
index 000000000000..07593a3ba8be
--- /dev/null
+++ b/rust/kernel/c_types.rs
@@ -0,0 +1,119 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! C types for the bindings.
+//!
+//! The bindings generated by `bindgen` use these types to map to the C ones.
+//!
+//! C's standard integer types may differ in width depending on
+//! the architecture, thus we need to conditionally compile those.
+
+#![allow(non_camel_case_types)]
+
+#[cfg(any(target_arch = "arm", target_arch = "x86", target_arch = "riscv32",))]
+mod c {
+    /// C `void` type.
+    pub type c_void = core::ffi::c_void;
+
+    /// C `char` type.
+    pub type c_char = i8;
+
+    /// C `signed char` type.
+    pub type c_schar = i8;
+
+    /// C `unsigned char` type.
+    pub type c_uchar = u8;
+
+    /// C `short` type.
+    pub type c_short = i16;
+
+    /// C `unsigned short` type.
+    pub type c_ushort = u16;
+
+    /// C `int` type.
+    pub type c_int = i32;
+
+    /// C `unsigned int` type.
+    pub type c_uint = u32;
+
+    /// C `long` type.
+    pub type c_long = i32;
+
+    /// C `unsigned long` type.
+    pub type c_ulong = u32;
+
+    /// C `long long` type.
+    pub type c_longlong = i64;
+
+    /// C `unsigned long long` type.
+    pub type c_ulonglong = u64;
+
+    /// C `ssize_t` type (typically defined in `<sys/types.h>` by POSIX).
+    ///
+    /// For some 32-bit architectures like this one, the kernel defines it as
+    /// `int`, i.e. it is an [`i32`].
+    pub type c_ssize_t = isize;
+
+    /// C `size_t` type (typically defined in `<stddef.h>`).
+    ///
+    /// For some 32-bit architectures like this one, the kernel defines it as
+    /// `unsigned int`, i.e. it is an [`u32`].
+    pub type c_size_t = usize;
+}
+
+#[cfg(any(
+    target_arch = "aarch64",
+    target_arch = "x86_64",
+    target_arch = "powerpc64",
+    target_arch = "riscv64",
+))]
+mod c {
+    /// C `void` type.
+    pub type c_void = core::ffi::c_void;
+
+    /// C `char` type.
+    pub type c_char = i8;
+
+    /// C `signed char` type.
+    pub type c_schar = i8;
+
+    /// C `unsigned char` type.
+    pub type c_uchar = u8;
+
+    /// C `short` type.
+    pub type c_short = i16;
+
+    /// C `unsigned short` type.
+    pub type c_ushort = u16;
+
+    /// C `int` type.
+    pub type c_int = i32;
+
+    /// C `unsigned int` type.
+    pub type c_uint = u32;
+
+    /// C `long` type.
+    pub type c_long = i64;
+
+    /// C `unsigned long` type.
+    pub type c_ulong = u64;
+
+    /// C `long long` type.
+    pub type c_longlong = i64;
+
+    /// C `unsigned long long` type.
+    pub type c_ulonglong = u64;
+
+    /// C `ssize_t` type (typically defined in `<sys/types.h>` by POSIX).
+    ///
+    /// For 64-bit architectures like this one, the kernel defines it as
+    /// `long`, i.e. it is an [`i64`].
+    pub type c_ssize_t = isize;
+
+    /// C `size_t` type (typically defined in `<stddef.h>`).
+    ///
+    /// For 64-bit architectures like this one, the kernel defines it as
+    /// `unsigned long`, i.e. it is an [`u64`].
+    pub type c_size_t = usize;
+}
+
+pub use c::*;
diff --git a/rust/kernel/chrdev.rs b/rust/kernel/chrdev.rs
new file mode 100644
index 000000000000..889a2f74fca1
--- /dev/null
+++ b/rust/kernel/chrdev.rs
@@ -0,0 +1,207 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Character devices.
+//!
+//! Also called "char devices", `chrdev`, `cdev`.
+//!
+//! C header: [`include/linux/cdev.h`](../../../../include/linux/cdev.h)
+//!
+//! Reference: <https://www.kernel.org/doc/html/latest/core-api/kernel-api.html#char-devices>
+
+use alloc::boxed::Box;
+use core::convert::TryInto;
+use core::marker::PhantomPinned;
+use core::pin::Pin;
+
+use crate::bindings;
+use crate::c_types;
+use crate::error::{code::*, Error, Result};
+use crate::file;
+use crate::str::CStr;
+
+/// Character device.
+///
+/// # Invariants
+///
+///   - [`self.0`] is valid and non-null.
+///   - [`(*self.0).ops`] is valid, non-null and has static lifetime.
+///   - [`(*self.0).owner`] is valid and, if non-null, has module lifetime.
+struct Cdev(*mut bindings::cdev);
+
+impl Cdev {
+    fn alloc(
+        fops: &'static bindings::file_operations,
+        module: &'static crate::ThisModule,
+    ) -> Result<Self> {
+        // SAFETY: FFI call.
+        let cdev = unsafe { bindings::cdev_alloc() };
+        if cdev.is_null() {
+            return Err(ENOMEM);
+        }
+        // SAFETY: `cdev` is valid and non-null since `cdev_alloc()`
+        // returned a valid pointer which was null-checked.
+        unsafe {
+            (*cdev).ops = fops;
+            (*cdev).owner = module.0;
+        }
+        // INVARIANTS:
+        //   - [`self.0`] is valid and non-null.
+        //   - [`(*self.0).ops`] is valid, non-null and has static lifetime,
+        //     because it was coerced from a reference with static lifetime.
+        //   - [`(*self.0).owner`] is valid and, if non-null, has module lifetime,
+        //     guaranteed by the [`ThisModule`] invariant.
+        Ok(Self(cdev))
+    }
+
+    fn add(&mut self, dev: bindings::dev_t, count: c_types::c_uint) -> Result {
+        // SAFETY: According to the type invariants:
+        //   - [`self.0`] can be safely passed to [`bindings::cdev_add`].
+        //   - [`(*self.0).ops`] will live at least as long as [`self.0`].
+        //   - [`(*self.0).owner`] will live at least as long as the
+        //     module, which is an implicit requirement.
+        let rc = unsafe { bindings::cdev_add(self.0, dev, count) };
+        if rc != 0 {
+            return Err(Error::from_kernel_errno(rc));
+        }
+        Ok(())
+    }
+}
+
+impl Drop for Cdev {
+    fn drop(&mut self) {
+        // SAFETY: [`self.0`] is valid and non-null by the type invariants.
+        unsafe {
+            bindings::cdev_del(self.0);
+        }
+    }
+}
+
+struct RegistrationInner<const N: usize> {
+    dev: bindings::dev_t,
+    used: usize,
+    cdevs: [Option<Cdev>; N],
+    _pin: PhantomPinned,
+}
+
+/// Character device registration.
+///
+/// May contain up to a fixed number (`N`) of devices. Must be pinned.
+pub struct Registration<const N: usize> {
+    name: &'static CStr,
+    minors_start: u16,
+    this_module: &'static crate::ThisModule,
+    inner: Option<RegistrationInner<N>>,
+}
+
+impl<const N: usize> Registration<{ N }> {
+    /// Creates a [`Registration`] object for a character device.
+    ///
+    /// This does *not* register the device: see [`Self::register()`].
+    ///
+    /// This associated function is intended to be used when you need to avoid
+    /// a memory allocation, e.g. when the [`Registration`] is a member of
+    /// a bigger structure inside your [`crate::KernelModule`] instance. If you
+    /// are going to pin the registration right away, call
+    /// [`Self::new_pinned()`] instead.
+    pub fn new(
+        name: &'static CStr,
+        minors_start: u16,
+        this_module: &'static crate::ThisModule,
+    ) -> Self {
+        Registration {
+            name,
+            minors_start,
+            this_module,
+            inner: None,
+        }
+    }
+
+    /// Creates a pinned [`Registration`] object for a character device.
+    ///
+    /// This does *not* register the device: see [`Self::register()`].
+    pub fn new_pinned(
+        name: &'static CStr,
+        minors_start: u16,
+        this_module: &'static crate::ThisModule,
+    ) -> Result<Pin<Box<Self>>> {
+        Ok(Pin::from(Box::try_new(Self::new(
+            name,
+            minors_start,
+            this_module,
+        ))?))
+    }
+
+    /// Registers a character device.
+    ///
+    /// You may call this once per device type, up to `N` times.
+    pub fn register<T: file::Operations<OpenData = ()>>(self: Pin<&mut Self>) -> Result {
+        // SAFETY: We must ensure that we never move out of `this`.
+        let this = unsafe { self.get_unchecked_mut() };
+        if this.inner.is_none() {
+            let mut dev: bindings::dev_t = 0;
+            // SAFETY: Calling unsafe function. `this.name` has `'static`
+            // lifetime.
+            let res = unsafe {
+                bindings::alloc_chrdev_region(
+                    &mut dev,
+                    this.minors_start.into(),
+                    N.try_into()?,
+                    this.name.as_char_ptr(),
+                )
+            };
+            if res != 0 {
+                return Err(Error::from_kernel_errno(res));
+            }
+            const NONE: Option<Cdev> = None;
+            this.inner = Some(RegistrationInner {
+                dev,
+                used: 0,
+                cdevs: [NONE; N],
+                _pin: PhantomPinned,
+            });
+        }
+
+        let mut inner = this.inner.as_mut().unwrap();
+        if inner.used == N {
+            return Err(EINVAL);
+        }
+
+        // SAFETY: The adapter doesn't retrieve any state yet, so it's compatible with any
+        // registration.
+        let fops = unsafe { file::OperationsVtable::<Self, T>::build() };
+        let mut cdev = Cdev::alloc(fops, this.this_module)?;
+        cdev.add(inner.dev + inner.used as bindings::dev_t, 1)?;
+        inner.cdevs[inner.used].replace(cdev);
+        inner.used += 1;
+        Ok(())
+    }
+}
+
+impl<const N: usize> file::OpenAdapter<()> for Registration<{ N }> {
+    unsafe fn convert(_inode: *mut bindings::inode, _file: *mut bindings::file) -> *const () {
+        // TODO: Update the SAFETY comment on the call to `FileOperationsVTable::build` above once
+        // this is updated to retrieve state.
+        &()
+    }
+}
+
+// SAFETY: `Registration` does not expose any of its state across threads
+// (it is fine for multiple threads to have a shared reference to it).
+unsafe impl<const N: usize> Sync for Registration<{ N }> {}
+
+impl<const N: usize> Drop for Registration<{ N }> {
+    fn drop(&mut self) {
+        if let Some(inner) = self.inner.as_mut() {
+            // Replicate kernel C behaviour: drop [`Cdev`]s before calling
+            // [`bindings::unregister_chrdev_region`].
+            for i in 0..inner.used {
+                inner.cdevs[i].take();
+            }
+            // SAFETY: [`self.inner`] is Some, so [`inner.dev`] was previously
+            // created using [`bindings::alloc_chrdev_region`].
+            unsafe {
+                bindings::unregister_chrdev_region(inner.dev, N.try_into().unwrap());
+            }
+        }
+    }
+}
diff --git a/rust/kernel/clk.rs b/rust/kernel/clk.rs
new file mode 100644
index 000000000000..46d3b81f5688
--- /dev/null
+++ b/rust/kernel/clk.rs
@@ -0,0 +1,75 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Common clock framework.
+//!
+//! C header: [`include/linux/clk.h`](../../../../include/linux/clk.h)
+
+use crate::{bindings, error::Result, to_result};
+use core::mem::ManuallyDrop;
+
+/// Represents `struct clk *`.
+///
+/// # Invariants
+///
+/// The pointer is valid.
+pub struct Clk(*mut bindings::clk);
+
+impl Clk {
+    /// Creates new clock structure from a raw pointer.
+    ///
+    /// # Safety
+    ///
+    /// The pointer must be valid.
+    pub unsafe fn new(clk: *mut bindings::clk) -> Self {
+        Self(clk)
+    }
+
+    /// Returns value of the rate field of `struct clk`.
+    pub fn get_rate(&self) -> usize {
+        // SAFETY: The pointer is valid by the type invariant.
+        unsafe { bindings::clk_get_rate(self.0) as usize }
+    }
+
+    /// Prepares and enables the underlying hardware clock.
+    ///
+    /// This function should not be called in atomic context.
+    pub fn prepare_enable(self) -> Result<EnabledClk> {
+        // SAFETY: The pointer is valid by the type invariant.
+        to_result(|| unsafe { bindings::clk_prepare_enable(self.0) })?;
+        Ok(EnabledClk(self))
+    }
+}
+
+impl Drop for Clk {
+    fn drop(&mut self) {
+        // SAFETY: The pointer is valid by the type invariant.
+        unsafe { bindings::clk_put(self.0) };
+    }
+}
+
+/// A clock variant that is prepared and enabled.
+pub struct EnabledClk(Clk);
+
+impl EnabledClk {
+    /// Returns value of the rate field of `struct clk`.
+    pub fn get_rate(&self) -> usize {
+        self.0.get_rate()
+    }
+
+    /// Disables and later unprepares the underlying hardware clock prematurely.
+    ///
+    /// This function should not be called in atomic context.
+    pub fn disable_unprepare(self) -> Clk {
+        let mut clk = ManuallyDrop::new(self);
+        // SAFETY: The pointer is valid by the type invariant.
+        unsafe { bindings::clk_disable_unprepare(clk.0 .0) };
+        core::mem::replace(&mut clk.0, Clk(core::ptr::null_mut()))
+    }
+}
+
+impl Drop for EnabledClk {
+    fn drop(&mut self) {
+        // SAFETY: The pointer is valid by the type invariant.
+        unsafe { bindings::clk_disable_unprepare(self.0 .0) };
+    }
+}
diff --git a/rust/kernel/cred.rs b/rust/kernel/cred.rs
new file mode 100644
index 000000000000..1602aa6935ca
--- /dev/null
+++ b/rust/kernel/cred.rs
@@ -0,0 +1,73 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Credentials management.
+//!
+//! C header: [`include/linux/cred.h`](../../../../include/linux/cred.h)
+//!
+//! Reference: <https://www.kernel.org/doc/html/latest/security/credentials.html>
+
+use crate::bindings;
+use core::{marker::PhantomData, mem::ManuallyDrop, ops::Deref};
+
+/// Wraps the kernel's `struct cred`.
+///
+/// # Invariants
+///
+/// The pointer `Credential::ptr` is non-null and valid. Its reference count is also non-zero.
+pub struct Credential {
+    pub(crate) ptr: *const bindings::cred,
+}
+
+impl Clone for Credential {
+    fn clone(&self) -> Self {
+        // SAFETY: The type invariants guarantee that `self.ptr` has a non-zero reference count.
+        let ptr = unsafe { bindings::get_cred(self.ptr) };
+
+        // INVARIANT: We incremented the reference count to account for the new `Credential` being
+        // created.
+        Self { ptr }
+    }
+}
+
+impl Drop for Credential {
+    fn drop(&mut self) {
+        // SAFETY: The type invariants guarantee that `ptr` has a non-zero reference count.
+        unsafe { bindings::put_cred(self.ptr) };
+    }
+}
+
+/// A wrapper for [`Credential`] that doesn't automatically decrement the refcount when dropped.
+///
+/// We need the wrapper because [`ManuallyDrop`] alone would allow callers to call
+/// [`ManuallyDrop::into_inner`]. This would allow an unsafe sequence to be triggered without
+/// `unsafe` blocks because it would trigger an unbalanced call to `put_cred`.
+///
+/// # Invariants
+///
+/// The wrapped [`Credential`] remains valid for the lifetime of the object.
+pub struct CredentialRef<'a> {
+    cred: ManuallyDrop<Credential>,
+    _p: PhantomData<&'a ()>,
+}
+
+impl CredentialRef<'_> {
+    /// Constructs a new [`struct cred`] wrapper that doesn't change its reference count.
+    ///
+    /// # Safety
+    ///
+    /// The pointer `ptr` must be non-null and valid for the lifetime of the object.
+    pub(crate) unsafe fn from_ptr(ptr: *const bindings::cred) -> Self {
+        Self {
+            cred: ManuallyDrop::new(Credential { ptr }),
+            _p: PhantomData,
+        }
+    }
+}
+
+impl Deref for CredentialRef<'_> {
+    type Target = Credential;
+
+    fn deref(&self) -> &Self::Target {
+        self.cred.deref()
+    }
+}
diff --git a/rust/kernel/device.rs b/rust/kernel/device.rs
new file mode 100644
index 000000000000..05a9484cbcd4
--- /dev/null
+++ b/rust/kernel/device.rs
@@ -0,0 +1,554 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Generic devices that are part of the kernel's driver model.
+//!
+//! C header: [`include/linux/device.h`](../../../../include/linux/device.h)
+
+#[cfg(CONFIG_COMMON_CLK)]
+use crate::{clk::Clk, error::from_kernel_err_ptr};
+
+use crate::{
+    bindings,
+    revocable::{Revocable, RevocableGuard},
+    str::CStr,
+    sync::{NeedsLockClass, RevocableMutex, RevocableMutexGuard, UniqueRef},
+    Result,
+};
+use core::{
+    fmt,
+    ops::{Deref, DerefMut},
+    pin::Pin,
+};
+
+#[cfg(CONFIG_PRINTK)]
+use crate::{c_str, c_types};
+
+/// A raw device.
+///
+/// # Safety
+///
+/// Implementers must ensure that the `*mut device` returned by [`RawDevice::raw_device`] is
+/// related to `self`, that is, actions on it will affect `self`. For example, if one calls
+/// `get_device`, then the refcount on the device represented by `self` will be incremented.
+///
+/// Additionally, implementers must ensure that the device is never renamed. Commit a5462516aa994
+/// has details on why `device_rename` should not be used.
+pub unsafe trait RawDevice {
+    /// Returns the raw `struct device` related to `self`.
+    fn raw_device(&self) -> *mut bindings::device;
+
+    /// Returns the name of the device.
+    fn name(&self) -> &CStr {
+        let ptr = self.raw_device();
+
+        // SAFETY: `ptr` is valid because `self` keeps it alive.
+        let name = unsafe { bindings::dev_name(ptr) };
+
+        // SAFETY: The name of the device remains valid while it is alive (because the device is
+        // never renamed, per the safety requirement of this trait). This is guaranteed to be the
+        // case because the reference to `self` outlives the one of the returned `CStr` (enforced
+        // by the compiler because of their lifetimes).
+        unsafe { CStr::from_char_ptr(name) }
+    }
+
+    /// Lookups a clock producer consumed by this device.
+    ///
+    /// Returns a managed reference to the clock producer.
+    #[cfg(CONFIG_COMMON_CLK)]
+    fn clk_get(&self, id: Option<&CStr>) -> Result<Clk> {
+        let id_ptr = match id {
+            Some(cstr) => cstr.as_char_ptr(),
+            None => core::ptr::null(),
+        };
+
+        // SAFETY: `id_ptr` is optional and may be either a valid pointer
+        // from the type invariant or NULL otherwise.
+        let clk_ptr = unsafe { from_kernel_err_ptr(bindings::clk_get(self.raw_device(), id_ptr)) }?;
+
+        // SAFETY: Clock is initialized with valid pointer returned from `bindings::clk_get` call.
+        unsafe { Ok(Clk::new(clk_ptr)) }
+    }
+
+    /// Prints an emergency-level message (level 0) prefixed with device information.
+    ///
+    /// More details are available from [`dev_emerg`].
+    fn pr_emerg(&self, args: fmt::Arguments<'_>) {
+        // SAFETY: `klevel` is null-terminated, uses one of the kernel constants.
+        unsafe { self.printk(bindings::KERN_EMERG, args) };
+    }
+
+    /// Prints an alert-level message (level 1) prefixed with device information.
+    ///
+    /// More details are available from [`dev_alert`].
+    fn pr_alert(&self, args: fmt::Arguments<'_>) {
+        // SAFETY: `klevel` is null-terminated, uses one of the kernel constants.
+        unsafe { self.printk(bindings::KERN_ALERT, args) };
+    }
+
+    /// Prints a critical-level message (level 2) prefixed with device information.
+    ///
+    /// More details are available from [`dev_crit`].
+    fn pr_crit(&self, args: fmt::Arguments<'_>) {
+        // SAFETY: `klevel` is null-terminated, uses one of the kernel constants.
+        unsafe { self.printk(bindings::KERN_CRIT, args) };
+    }
+
+    /// Prints an error-level message (level 3) prefixed with device information.
+    ///
+    /// More details are available from [`dev_err`].
+    fn pr_err(&self, args: fmt::Arguments<'_>) {
+        // SAFETY: `klevel` is null-terminated, uses one of the kernel constants.
+        unsafe { self.printk(bindings::KERN_ERR, args) };
+    }
+
+    /// Prints a warning-level message (level 4) prefixed with device information.
+    ///
+    /// More details are available from [`dev_warn`].
+    fn pr_warn(&self, args: fmt::Arguments<'_>) {
+        // SAFETY: `klevel` is null-terminated, uses one of the kernel constants.
+        unsafe { self.printk(bindings::KERN_WARNING, args) };
+    }
+
+    /// Prints a notice-level message (level 5) prefixed with device information.
+    ///
+    /// More details are available from [`dev_notice`].
+    fn pr_notice(&self, args: fmt::Arguments<'_>) {
+        // SAFETY: `klevel` is null-terminated, uses one of the kernel constants.
+        unsafe { self.printk(bindings::KERN_NOTICE, args) };
+    }
+
+    /// Prints an info-level message (level 6) prefixed with device information.
+    ///
+    /// More details are available from [`dev_info`].
+    fn pr_info(&self, args: fmt::Arguments<'_>) {
+        // SAFETY: `klevel` is null-terminated, uses one of the kernel constants.
+        unsafe { self.printk(bindings::KERN_INFO, args) };
+    }
+
+    /// Prints a debug-level message (level 7) prefixed with device information.
+    ///
+    /// More details are available from [`dev_dbg`].
+    fn pr_dbg(&self, args: fmt::Arguments<'_>) {
+        if cfg!(debug_assertions) {
+            // SAFETY: `klevel` is null-terminated, uses one of the kernel constants.
+            unsafe { self.printk(bindings::KERN_DEBUG, args) };
+        }
+    }
+
+    /// Prints the provided message to the console.
+    ///
+    /// # Safety
+    ///
+    /// Callers must ensure that `klevel` is null-terminated; in particular, one of the
+    /// `KERN_*`constants, for example, `KERN_CRIT`, `KERN_ALERT`, etc.
+    #[cfg_attr(not(CONFIG_PRINTK), allow(unused_variables))]
+    unsafe fn printk(&self, klevel: &[u8], msg: fmt::Arguments<'_>) {
+        // SAFETY: `klevel` is null-terminated and one of the kernel constants. `self.raw_device`
+        // is valid because `self` is valid. The "%pA" format string expects a pointer to
+        // `fmt::Arguments`, which is what we're passing as the last argument.
+        #[cfg(CONFIG_PRINTK)]
+        unsafe {
+            bindings::_dev_printk(
+                klevel as *const _ as *const c_types::c_char,
+                self.raw_device(),
+                c_str!("%pA").as_char_ptr(),
+                &msg as *const _ as *const c_types::c_void,
+            )
+        };
+    }
+}
+
+/// A ref-counted device.
+///
+/// # Invariants
+///
+/// `ptr` is valid, non-null, and has a non-zero reference count. One of the references is owned by
+/// `self`, and will be decremented when `self` is dropped.
+pub struct Device {
+    pub(crate) ptr: *mut bindings::device,
+}
+
+// SAFETY: `Device` only holds a pointer to a C device, which is safe to be used from any thread.
+unsafe impl Send for Device {}
+
+// SAFETY: `Device` only holds a pointer to a C device, references to which are safe to be used
+// from any thread.
+unsafe impl Sync for Device {}
+
+impl Device {
+    /// Creates a new device instance.
+    ///
+    /// # Safety
+    ///
+    /// Callers must ensure that `ptr` is valid, non-null, and has a non-zero reference count.
+    pub unsafe fn new(ptr: *mut bindings::device) -> Self {
+        // SAFETY: By the safety requirements, ptr is valid and its refcounted will be incremented.
+        unsafe { bindings::get_device(ptr) };
+        // INVARIANT: The safety requirements satisfy all but one invariant, which is that `self`
+        // owns a reference. This is satisfied by the call to `get_device` above.
+        Self { ptr }
+    }
+
+    /// Creates a new device instance from an existing [`RawDevice`] instance.
+    pub fn from_dev(dev: &dyn RawDevice) -> Self {
+        // SAFETY: The requirements are satisfied by the existence of `RawDevice` and its safety
+        // requirements.
+        unsafe { Self::new(dev.raw_device()) }
+    }
+}
+
+// SAFETY: The device returned by `raw_device` is the one for which we hold a reference.
+unsafe impl RawDevice for Device {
+    fn raw_device(&self) -> *mut bindings::device {
+        self.ptr
+    }
+}
+
+impl Drop for Device {
+    fn drop(&mut self) {
+        // SAFETY: By the type invariants, we know that `self` owns a reference, so it is safe to
+        // relinquish it now.
+        unsafe { bindings::put_device(self.ptr) };
+    }
+}
+
+/// Device data.
+///
+/// When a device is removed (for whatever reason, for example, because the device was unplugged or
+/// because the user decided to unbind the driver), the driver is given a chance to clean its state
+/// up, and all io resources should ideally not be used anymore.
+///
+/// However, the device data is reference-counted because other subsystems hold pointers to it. So
+/// some device state must be freed and not used anymore, while others must remain accessible.
+///
+/// This struct separates the device data into three categories:
+///   1. Registrations: are destroyed when the device is removed, but before the io resources
+///      become inaccessible.
+///   2. Io resources: are available until the device is removed.
+///   3. General data: remain available as long as the ref count is nonzero.
+///
+/// This struct implements the `DeviceRemoval` trait so that it can clean resources up even if not
+/// explicitly called by the device drivers.
+pub struct Data<T, U, V> {
+    registrations: RevocableMutex<T>,
+    resources: Revocable<U>,
+    general: V,
+}
+
+/// Safely creates an new reference-counted instance of [`Data`].
+#[doc(hidden)]
+#[macro_export]
+macro_rules! new_device_data {
+    ($reg:expr, $res:expr, $gen:expr, $name:literal) => {{
+        static mut CLASS1: core::mem::MaybeUninit<$crate::bindings::lock_class_key> =
+            core::mem::MaybeUninit::uninit();
+        static mut CLASS2: core::mem::MaybeUninit<$crate::bindings::lock_class_key> =
+            core::mem::MaybeUninit::uninit();
+        let regs = $reg;
+        let res = $res;
+        let gen = $gen;
+        let name = $crate::c_str!($name);
+        // SAFETY: `CLASS1` and `CLASS2` are never used by Rust code directly; the C portion of the
+        // kernel may change it though.
+        unsafe {
+            $crate::device::Data::try_new(
+                regs,
+                res,
+                gen,
+                name,
+                CLASS1.as_mut_ptr(),
+                CLASS2.as_mut_ptr(),
+            )
+        }
+    }};
+}
+
+impl<T, U, V> Data<T, U, V> {
+    /// Creates a new instance of `Data`.
+    ///
+    /// It is recommended that the [`new_device_data`] macro be used as it automatically creates
+    /// the lock classes.
+    ///
+    /// # Safety
+    ///
+    /// `key1` and `key2` must point to valid memory locations and remain valid until `self` is
+    /// dropped.
+    pub unsafe fn try_new(
+        registrations: T,
+        resources: U,
+        general: V,
+        name: &'static CStr,
+        key1: *mut bindings::lock_class_key,
+        key2: *mut bindings::lock_class_key,
+    ) -> Result<Pin<UniqueRef<Self>>> {
+        let mut ret = Pin::from(UniqueRef::try_new(Self {
+            // SAFETY: We call `RevocableMutex::init` below.
+            registrations: unsafe { RevocableMutex::new(registrations) },
+            resources: Revocable::new(resources),
+            general,
+        })?);
+
+        // SAFETY: `Data::registrations` is pinned when `Data` is.
+        let pinned = unsafe { ret.as_mut().map_unchecked_mut(|d| &mut d.registrations) };
+
+        // SAFETY: The safety requirements of this function satisfy those of `RevocableMutex::init`.
+        unsafe { pinned.init(name, key1, key2) };
+        Ok(ret)
+    }
+
+    /// Returns the resources if they're still available.
+    pub fn resources(&self) -> Option<RevocableGuard<'_, U>> {
+        self.resources.try_access()
+    }
+
+    /// Returns the locked registrations if they're still available.
+    pub fn registrations(&self) -> Option<RevocableMutexGuard<'_, T>> {
+        self.registrations.try_lock()
+    }
+}
+
+impl<T, U, V> crate::driver::DeviceRemoval for Data<T, U, V> {
+    fn device_remove(&self) {
+        // We revoke the registrations first so that resources are still available to them during
+        // unregistration.
+        self.registrations.revoke();
+
+        // Release resources now. General data remains available.
+        self.resources.revoke();
+    }
+}
+
+impl<T, U, V> Deref for Data<T, U, V> {
+    type Target = V;
+
+    fn deref(&self) -> &V {
+        &self.general
+    }
+}
+
+impl<T, U, V> DerefMut for Data<T, U, V> {
+    fn deref_mut(&mut self) -> &mut V {
+        &mut self.general
+    }
+}
+
+#[doc(hidden)]
+#[macro_export]
+macro_rules! dev_printk {
+    ($method:ident, $dev:expr, $($f:tt)*) => {
+        {
+            // We have an explicity `use` statement here so that callers of this macro are not
+            // required to explicitly use the `RawDevice` trait to use its functions.
+            use $crate::device::RawDevice;
+            ($dev).$method(core::format_args!($($f)*));
+        }
+    }
+}
+
+/// Prints an emergency-level message (level 0) prefixed with device information.
+///
+/// This level should be used if the system is unusable.
+///
+/// Equivalent to the kernel's `dev_emerg` macro.
+///
+/// Mimics the interface of [`std::print!`]. More information about the syntax is available from
+/// [`core::fmt`] and [`alloc::format!`].
+///
+/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::prelude::*;
+/// # use kernel::device::Device;
+///
+/// fn example(dev: &Device) {
+///     dev_emerg!(dev, "hello {}\n", "there");
+/// }
+/// ```
+#[macro_export]
+macro_rules! dev_emerg {
+    ($($f:tt)*) => { $crate::dev_printk!(pr_emerg, $($f)*); }
+}
+
+/// Prints an alert-level message (level 1) prefixed with device information.
+///
+/// This level should be used if action must be taken immediately.
+///
+/// Equivalent to the kernel's `dev_alert` macro.
+///
+/// Mimics the interface of [`std::print!`]. More information about the syntax is available from
+/// [`core::fmt`] and [`alloc::format!`].
+///
+/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::prelude::*;
+/// # use kernel::device::Device;
+///
+/// fn example(dev: &Device) {
+///     dev_alert!(dev, "hello {}\n", "there");
+/// }
+/// ```
+#[macro_export]
+macro_rules! dev_alert {
+    ($($f:tt)*) => { $crate::dev_printk!(pr_alert, $($f)*); }
+}
+
+/// Prints a critical-level message (level 2) prefixed with device information.
+///
+/// This level should be used in critical conditions.
+///
+/// Equivalent to the kernel's `dev_crit` macro.
+///
+/// Mimics the interface of [`std::print!`]. More information about the syntax is available from
+/// [`core::fmt`] and [`alloc::format!`].
+///
+/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::prelude::*;
+/// # use kernel::device::Device;
+///
+/// fn example(dev: &Device) {
+///     dev_crit!(dev, "hello {}\n", "there");
+/// }
+/// ```
+#[macro_export]
+macro_rules! dev_crit {
+    ($($f:tt)*) => { $crate::dev_printk!(pr_crit, $($f)*); }
+}
+
+/// Prints an error-level message (level 3) prefixed with device information.
+///
+/// This level should be used in error conditions.
+///
+/// Equivalent to the kernel's `dev_err` macro.
+///
+/// Mimics the interface of [`std::print!`]. More information about the syntax is available from
+/// [`core::fmt`] and [`alloc::format!`].
+///
+/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::prelude::*;
+/// # use kernel::device::Device;
+///
+/// fn example(dev: &Device) {
+///     dev_err!(dev, "hello {}\n", "there");
+/// }
+/// ```
+#[macro_export]
+macro_rules! dev_err {
+    ($($f:tt)*) => { $crate::dev_printk!(pr_err, $($f)*); }
+}
+
+/// Prints a warning-level message (level 4) prefixed with device information.
+///
+/// This level should be used in warning conditions.
+///
+/// Equivalent to the kernel's `dev_warn` macro.
+///
+/// Mimics the interface of [`std::print!`]. More information about the syntax is available from
+/// [`core::fmt`] and [`alloc::format!`].
+///
+/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::prelude::*;
+/// # use kernel::device::Device;
+///
+/// fn example(dev: &Device) {
+///     dev_warn!(dev, "hello {}\n", "there");
+/// }
+/// ```
+#[macro_export]
+macro_rules! dev_warn {
+    ($($f:tt)*) => { $crate::dev_printk!(pr_warn, $($f)*); }
+}
+
+/// Prints a notice-level message (level 5) prefixed with device information.
+///
+/// This level should be used in normal but significant conditions.
+///
+/// Equivalent to the kernel's `dev_notice` macro.
+///
+/// Mimics the interface of [`std::print!`]. More information about the syntax is available from
+/// [`core::fmt`] and [`alloc::format!`].
+///
+/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::prelude::*;
+/// # use kernel::device::Device;
+///
+/// fn example(dev: &Device) {
+///     dev_notice!(dev, "hello {}\n", "there");
+/// }
+/// ```
+#[macro_export]
+macro_rules! dev_notice {
+    ($($f:tt)*) => { $crate::dev_printk!(pr_notice, $($f)*); }
+}
+
+/// Prints an info-level message (level 6) prefixed with device information.
+///
+/// This level should be used for informational messages.
+///
+/// Equivalent to the kernel's `dev_info` macro.
+///
+/// Mimics the interface of [`std::print!`]. More information about the syntax is available from
+/// [`core::fmt`] and [`alloc::format!`].
+///
+/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::prelude::*;
+/// # use kernel::device::Device;
+///
+/// fn example(dev: &Device) {
+///     dev_info!(dev, "hello {}\n", "there");
+/// }
+/// ```
+#[macro_export]
+macro_rules! dev_info {
+    ($($f:tt)*) => { $crate::dev_printk!(pr_info, $($f)*); }
+}
+
+/// Prints a debug-level message (level 7) prefixed with device information.
+///
+/// This level should be used for debug messages.
+///
+/// Equivalent to the kernel's `dev_dbg` macro, except that it doesn't support dynamic debug yet.
+///
+/// Mimics the interface of [`std::print!`]. More information about the syntax is available from
+/// [`core::fmt`] and [`alloc::format!`].
+///
+/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::prelude::*;
+/// # use kernel::device::Device;
+///
+/// fn example(dev: &Device) {
+///     dev_dbg!(dev, "hello {}\n", "there");
+/// }
+/// ```
+#[macro_export]
+macro_rules! dev_dbg {
+    ($($f:tt)*) => { $crate::dev_printk!(pr_dbg, $($f)*); }
+}
diff --git a/rust/kernel/driver.rs b/rust/kernel/driver.rs
new file mode 100644
index 000000000000..21fa790b1dc9
--- /dev/null
+++ b/rust/kernel/driver.rs
@@ -0,0 +1,440 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Generic support for drivers of different buses (e.g., PCI, Platform, Amba, etc.).
+//!
+//! Each bus/subsystem is expected to implement [`DriverOps`], which allows drivers to register
+//! using the [`Registration`] class.
+
+use crate::{error::code::*, str::CStr, sync::Ref, KernelModule, Result, ThisModule};
+use alloc::boxed::Box;
+use core::{cell::UnsafeCell, marker::PhantomData, ops::Deref, pin::Pin};
+
+/// A subsystem (e.g., PCI, Platform, Amba, etc.) that allows drivers to be written for it.
+pub trait DriverOps {
+    /// The type that holds information about the registration. This is typically a struct defined
+    /// by the C portion of the kernel.
+    type RegType: Default;
+
+    /// Registers a driver.
+    ///
+    /// # Safety
+    ///
+    /// `reg` must point to valid, initialised, and writable memory. It may be modified by this
+    /// function to hold registration state.
+    ///
+    /// On success, `reg` must remain pinned and valid until the matching call to
+    /// [`DriverOps::unregister`].
+    unsafe fn register(
+        reg: *mut Self::RegType,
+        name: &'static CStr,
+        module: &'static ThisModule,
+    ) -> Result;
+
+    /// Unregisters a driver previously registered with [`DriverOps::register`].
+    ///
+    /// # Safety
+    ///
+    /// `reg` must point to valid writable memory, initialised by a previous successful call to
+    /// [`DriverOps::register`].
+    unsafe fn unregister(reg: *mut Self::RegType);
+}
+
+/// The registration of a driver.
+pub struct Registration<T: DriverOps> {
+    is_registered: bool,
+    concrete_reg: UnsafeCell<T::RegType>,
+}
+
+// SAFETY: `Registration` has no fields or methods accessible via `&Registration`, so it is safe to
+// share references to it with multiple threads as nothing can be done.
+unsafe impl<T: DriverOps> Sync for Registration<T> {}
+
+impl<T: DriverOps> Registration<T> {
+    /// Creates a new instance of the registration object.
+    pub fn new() -> Self {
+        Self {
+            is_registered: false,
+            concrete_reg: UnsafeCell::new(T::RegType::default()),
+        }
+    }
+
+    /// Allocates a pinned registration object and registers it.
+    ///
+    /// Returns a pinned heap-allocated representation of the registration.
+    pub fn new_pinned(name: &'static CStr, module: &'static ThisModule) -> Result<Pin<Box<Self>>> {
+        let mut reg = Pin::from(Box::try_new(Self::new())?);
+        reg.as_mut().register(name, module)?;
+        Ok(reg)
+    }
+
+    /// Registers a driver with its subsystem.
+    ///
+    /// It must be pinned because the memory block that represents the registration is potentially
+    /// self-referential.
+    pub fn register(
+        self: Pin<&mut Self>,
+        name: &'static CStr,
+        module: &'static ThisModule,
+    ) -> Result {
+        // SAFETY: We never move out of `this`.
+        let this = unsafe { self.get_unchecked_mut() };
+        if this.is_registered {
+            // Already registered.
+            return Err(EINVAL);
+        }
+
+        // SAFETY: `concrete_reg` was initialised via its default constructor. It is only freed
+        // after `Self::drop` is called, which first calls `T::unregister`.
+        unsafe { T::register(this.concrete_reg.get(), name, module) }?;
+
+        this.is_registered = true;
+        Ok(())
+    }
+}
+
+impl<T: DriverOps> Default for Registration<T> {
+    fn default() -> Self {
+        Self::new()
+    }
+}
+
+impl<T: DriverOps> Drop for Registration<T> {
+    fn drop(&mut self) {
+        if self.is_registered {
+            // SAFETY: This path only runs if a previous call to `T::register` completed
+            // successfully.
+            unsafe { T::unregister(self.concrete_reg.get()) };
+        }
+    }
+}
+
+/// Conversion from a device id to a raw device id.
+///
+/// This is meant to be implemented by buses/subsystems so that they can use [`IdTable`] to
+/// guarantee (at compile-time) zero-termination of device id tables provided by drivers.
+///
+/// # Safety
+///
+/// Implementers must ensure that:
+///   - [`RawDeviceId::ZERO`] is actually a zeroed-out version of the raw device id.
+///   - [`RawDeviceId::to_rawid`] stores `offset` in the context/data field of the raw device id so
+///     that buses can recover the pointer to the data.
+pub unsafe trait RawDeviceId {
+    /// The raw type that holds the device id.
+    ///
+    /// Id tables created from [`Self`] are going to hold this type in its zero-terminated array.
+    type RawType: Copy;
+
+    /// A zeroed-out representation of the raw device id.
+    ///
+    /// Id tables created from [`Self`] use [`Self::ZERO`] as the sentinel to indicate the end of
+    /// the table.
+    const ZERO: Self::RawType;
+
+    /// Converts an id into a raw id.
+    ///
+    /// `offset` is the offset from the memory location where the raw device id is stored to the
+    /// location where its associated context information is stored. Implementations must store
+    /// this in the appropriate context/data field of the raw type.
+    fn to_rawid(&self, offset: isize) -> Self::RawType;
+}
+
+/// A zero-terminated device id array, followed by context data.
+#[repr(C)]
+pub struct IdArray<T: RawDeviceId, U, const N: usize> {
+    ids: [T::RawType; N],
+    sentinel: T::RawType,
+    id_infos: [Option<U>; N],
+}
+
+impl<T: RawDeviceId, U, const N: usize> IdArray<T, U, N> {
+    /// Creates a new instance of the array.
+    ///
+    /// The contents are derived from the given identifiers and context information.
+    pub const fn new(ids: [T; N], infos: [Option<U>; N]) -> Self
+    where
+        T: ~const RawDeviceId + Copy,
+    {
+        let mut array = Self {
+            ids: [T::ZERO; N],
+            sentinel: T::ZERO,
+            id_infos: infos,
+        };
+        let mut i = 0usize;
+        while i < N {
+            // SAFETY: Both pointers are within `array` (or one byte beyond), consequently they are
+            // derived from the same allocated object. We are using a `u8` pointer, whose size 1,
+            // so the pointers are necessarily 1-byte aligned.
+            let offset = unsafe {
+                (&array.id_infos[i] as *const _ as *const u8)
+                    .offset_from(&array.ids[i] as *const _ as _)
+            };
+            array.ids[i] = ids[i].to_rawid(offset);
+            i += 1;
+        }
+        array
+    }
+
+    /// Returns an `IdTable` backed by `self`.
+    ///
+    /// This is used to essentially erase the array size.
+    pub const fn as_table(&self) -> IdTable<'_, T, U> {
+        IdTable {
+            first: &self.ids[0],
+            _p: PhantomData,
+        }
+    }
+}
+
+/// A device id table.
+///
+/// The table is guaranteed to be zero-terminated and to be followed by an array of context data of
+/// type `Option<U>`.
+pub struct IdTable<'a, T: RawDeviceId, U> {
+    first: &'a T::RawType,
+    _p: PhantomData<&'a U>,
+}
+
+impl<T: RawDeviceId, U> const AsRef<T::RawType> for IdTable<'_, T, U> {
+    fn as_ref(&self) -> &T::RawType {
+        self.first
+    }
+}
+
+/// Counts the number of parenthesis-delimited, comma-separated items.
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::count_paren_items;
+///
+/// assert_eq!(0, count_paren_items!());
+/// assert_eq!(1, count_paren_items!((A)));
+/// assert_eq!(1, count_paren_items!((A),));
+/// assert_eq!(2, count_paren_items!((A), (B)));
+/// assert_eq!(2, count_paren_items!((A), (B),));
+/// assert_eq!(3, count_paren_items!((A), (B), (C)));
+/// assert_eq!(3, count_paren_items!((A), (B), (C),));
+/// ```
+#[macro_export]
+macro_rules! count_paren_items {
+    (($($item:tt)*), $($remaining:tt)*) => { 1 + $crate::count_paren_items!($($remaining)*) };
+    (($($item:tt)*)) => { 1 };
+    () => { 0 };
+}
+
+/// Converts a comma-separated list of pairs into an array with the first element. That is, it
+/// discards the second element of the pair.
+///
+/// Additionally, it automatically introduces a type if the first element is warpped in curly
+/// braces, for example, if it's `{v: 10}`, it becomes `X { v: 10 }`; this is to avoid repeating
+/// the type.
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::first_item;
+///
+/// #[derive(PartialEq, Debug)]
+/// struct X {
+///     v: u32,
+/// }
+///
+/// assert_eq!([] as [X; 0], first_item!(X, ));
+/// assert_eq!([X { v: 10 }], first_item!(X, ({ v: 10 }, Y)));
+/// assert_eq!([X { v: 10 }], first_item!(X, ({ v: 10 }, Y),));
+/// assert_eq!([X { v: 10 }], first_item!(X, (X { v: 10 }, Y)));
+/// assert_eq!([X { v: 10 }], first_item!(X, (X { v: 10 }, Y),));
+/// assert_eq!([X { v: 10 }, X { v: 20 }], first_item!(X, ({ v: 10 }, Y), ({ v: 20 }, Y)));
+/// assert_eq!([X { v: 10 }, X { v: 20 }], first_item!(X, ({ v: 10 }, Y), ({ v: 20 }, Y),));
+/// assert_eq!([X { v: 10 }, X { v: 20 }], first_item!(X, (X { v: 10 }, Y), (X { v: 20 }, Y)));
+/// assert_eq!([X { v: 10 }, X { v: 20 }], first_item!(X, (X { v: 10 }, Y), (X { v: 20 }, Y),));
+/// assert_eq!([X { v: 10 }, X { v: 20 }, X { v: 30 }],
+///            first_item!(X, ({ v: 10 }, Y), ({ v: 20 }, Y), ({v: 30}, Y)));
+/// assert_eq!([X { v: 10 }, X { v: 20 }, X { v: 30 }],
+///            first_item!(X, ({ v: 10 }, Y), ({ v: 20 }, Y), ({v: 30}, Y),));
+/// assert_eq!([X { v: 10 }, X { v: 20 }, X { v: 30 }],
+///            first_item!(X, (X { v: 10 }, Y), (X { v: 20 }, Y), (X {v: 30}, Y)));
+/// assert_eq!([X { v: 10 }, X { v: 20 }, X { v: 30 }],
+///            first_item!(X, (X { v: 10 }, Y), (X { v: 20 }, Y), (X {v: 30}, Y),));
+/// ```
+#[macro_export]
+macro_rules! first_item {
+    ($id_type:ty, $(({$($first:tt)*}, $second:expr)),* $(,)?) => {
+        {
+            type IdType = $id_type;
+            [$(IdType{$($first)*},)*]
+        }
+    };
+    ($id_type:ty, $(($first:expr, $second:expr)),* $(,)?) => { [$($first,)*] };
+}
+
+/// Converts a comma-separated list of pairs into an array with the second element. That is, it
+/// discards the first element of the pair.
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::second_item;
+///
+/// assert_eq!([] as [u32; 0], second_item!());
+/// assert_eq!([10u32], second_item!((X, 10u32)));
+/// assert_eq!([10u32], second_item!((X, 10u32),));
+/// assert_eq!([10u32], second_item!(({X}, 10u32)));
+/// assert_eq!([10u32], second_item!(({X}, 10u32),));
+/// assert_eq!([10u32, 20], second_item!((X, 10u32), (X, 20)));
+/// assert_eq!([10u32, 20], second_item!((X, 10u32), (X, 20),));
+/// assert_eq!([10u32, 20], second_item!(({X}, 10u32), ({X}, 20)));
+/// assert_eq!([10u32, 20], second_item!(({X}, 10u32), ({X}, 20),));
+/// assert_eq!([10u32, 20, 30], second_item!((X, 10u32), (X, 20), (X, 30)));
+/// assert_eq!([10u32, 20, 30], second_item!((X, 10u32), (X, 20), (X, 30),));
+/// assert_eq!([10u32, 20, 30], second_item!(({X}, 10u32), ({X}, 20), ({X}, 30)));
+/// assert_eq!([10u32, 20, 30], second_item!(({X}, 10u32), ({X}, 20), ({X}, 30),));
+/// ```
+#[macro_export]
+macro_rules! second_item {
+    ($(({$($first:tt)*}, $second:expr)),* $(,)?) => { [$($second,)*] };
+    ($(($first:expr, $second:expr)),* $(,)?) => { [$($second,)*] };
+}
+
+/// Defines a new constant [`IdArray`] with a concise syntax.
+///
+/// It is meant to be used by buses and subsystems to create a similar macro with their device id
+/// type already specified, i.e., with fewer parameters to the end user.
+///
+/// # Examples
+///
+/// ```
+/// #![feature(const_trait_impl)]
+/// # use kernel::{define_id_array, driver::RawDeviceId};
+///
+/// #[derive(Copy, Clone)]
+/// struct Id(u32);
+///
+/// // SAFETY: `ZERO` is all zeroes and `to_rawid` stores `offset` as the second element of the raw
+/// // device id pair.
+/// unsafe impl const RawDeviceId for Id {
+///     type RawType = (u64, isize);
+///     const ZERO: Self::RawType = (0, 0);
+///     fn to_rawid(&self, offset: isize) -> Self::RawType {
+///         (self.0 as u64 + 1, offset)
+///     }
+/// }
+///
+/// define_id_array!(A1, Id, (), []);
+/// define_id_array!(A2, Id, &'static [u8], [(Id(10), None)]);
+/// define_id_array!(A3, Id, &'static [u8], [(Id(10), Some(b"id1")), ]);
+/// define_id_array!(A4, Id, &'static [u8], [(Id(10), Some(b"id1")), (Id(20), Some(b"id2"))]);
+/// define_id_array!(A5, Id, &'static [u8], [(Id(10), Some(b"id1")), (Id(20), Some(b"id2")), ]);
+/// define_id_array!(A6, Id, &'static [u8], [(Id(10), None), (Id(20), Some(b"id2")), ]);
+/// define_id_array!(A7, Id, &'static [u8], [(Id(10), Some(b"id1")), (Id(20), None), ]);
+/// define_id_array!(A8, Id, &'static [u8], [(Id(10), None), (Id(20), None), ]);
+/// ```
+#[macro_export]
+macro_rules! define_id_array {
+    ($table_name:ident, $id_type:ty, $data_type:ty, [ $($t:tt)* ]) => {
+        const $table_name:
+            $crate::driver::IdArray<$id_type, $data_type, { $crate::count_paren_items!($($t)*) }> =
+                $crate::driver::IdArray::new(
+                    $crate::first_item!($id_type, $($t)*), $crate::second_item!($($t)*));
+    };
+}
+
+/// Defines a new constant [`IdTable`] with a concise syntax.
+///
+/// It is meant to be used by buses and subsystems to create a similar macro with their device id
+/// type already specified, i.e., with fewer parameters to the end user.
+///
+/// # Examples
+///
+/// ```
+/// #![feature(const_trait_impl)]
+/// # use kernel::{define_id_table, driver::RawDeviceId};
+///
+/// #[derive(Copy, Clone)]
+/// struct Id(u32);
+///
+/// // SAFETY: `ZERO` is all zeroes and `to_rawid` stores `offset` as the second element of the raw
+/// // device id pair.
+/// unsafe impl const RawDeviceId for Id {
+///     type RawType = (u64, isize);
+///     const ZERO: Self::RawType = (0, 0);
+///     fn to_rawid(&self, offset: isize) -> Self::RawType {
+///         (self.0 as u64 + 1, offset)
+///     }
+/// }
+///
+/// define_id_table!(T1, Id, &'static [u8], [(Id(10), None)]);
+/// define_id_table!(T2, Id, &'static [u8], [(Id(10), Some(b"id1")), ]);
+/// define_id_table!(T3, Id, &'static [u8], [(Id(10), Some(b"id1")), (Id(20), Some(b"id2"))]);
+/// define_id_table!(T4, Id, &'static [u8], [(Id(10), Some(b"id1")), (Id(20), Some(b"id2")), ]);
+/// define_id_table!(T5, Id, &'static [u8], [(Id(10), None), (Id(20), Some(b"id2")), ]);
+/// define_id_table!(T6, Id, &'static [u8], [(Id(10), Some(b"id1")), (Id(20), None), ]);
+/// define_id_table!(T7, Id, &'static [u8], [(Id(10), None), (Id(20), None), ]);
+/// ```
+#[macro_export]
+macro_rules! define_id_table {
+    ($table_name:ident, $id_type:ty, $data_type:ty, [ $($t:tt)* ]) => {
+        const $table_name: Option<$crate::driver::IdTable<'static, $id_type, $data_type>> = {
+            $crate::define_id_array!(ARRAY, $id_type, $data_type, [ $($t)* ]);
+            Some(ARRAY.as_table())
+        };
+    };
+}
+
+/// Custom code within device removal.
+pub trait DeviceRemoval {
+    /// Cleans resources up when the device is removed.
+    ///
+    /// This is called when a device is removed and offers implementers the chance to run some code
+    /// that cleans state up.
+    fn device_remove(&self);
+}
+
+impl DeviceRemoval for () {
+    fn device_remove(&self) {}
+}
+
+impl<T: DeviceRemoval> DeviceRemoval for Ref<T> {
+    fn device_remove(&self) {
+        self.deref().device_remove();
+    }
+}
+
+impl<T: DeviceRemoval> DeviceRemoval for Box<T> {
+    fn device_remove(&self) {
+        self.deref().device_remove();
+    }
+}
+
+/// A kernel module that only registers the given driver on init.
+///
+/// This is a helper struct to make it easier to define single-functionality modules, in this case,
+/// modules that offer a single driver.
+pub struct Module<T: DriverOps> {
+    _driver: Pin<Box<Registration<T>>>,
+}
+
+impl<T: DriverOps> KernelModule for Module<T> {
+    fn init(name: &'static CStr, module: &'static ThisModule) -> Result<Self> {
+        Ok(Self {
+            _driver: Registration::new_pinned(name, module)?,
+        })
+    }
+}
+
+/// Declares a kernel module that exposes a single driver.
+///
+/// It is meant to be used as a helper by other subsystems so they can more easily expose their own
+/// macros.
+#[macro_export]
+macro_rules! module_driver {
+    (<$gen_type:ident>, $driver_ops:ty, { type: $type:ty, $($f:tt)* }) => {
+        type Ops<$gen_type> = $driver_ops;
+        type ModuleType = $crate::driver::Module<Ops<$type>>;
+        $crate::prelude::module! {
+            type: ModuleType,
+            $($f)*
+        }
+    }
+}
diff --git a/rust/kernel/error.rs b/rust/kernel/error.rs
new file mode 100644
index 000000000000..65cf1e7597cf
--- /dev/null
+++ b/rust/kernel/error.rs
@@ -0,0 +1,560 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Kernel errors.
+//!
+//! C header: [`include/uapi/asm-generic/errno-base.h`](../../../include/uapi/asm-generic/errno-base.h)
+
+use crate::str::CStr;
+use crate::{bindings, c_types};
+use alloc::{
+    alloc::{AllocError, LayoutError},
+    collections::TryReserveError,
+};
+use core::convert::From;
+use core::fmt;
+use core::num::TryFromIntError;
+use core::str::{self, Utf8Error};
+
+/// Contains the C-compatible error codes.
+pub mod code {
+    macro_rules! declare_err {
+        ($err:tt $(,)? $($doc:expr),+) => {
+            $(
+            #[doc = $doc]
+            )*
+            pub const $err: super::Error = super::Error(-(crate::bindings::$err as i32));
+        };
+    }
+
+    declare_err!(EPERM, "Operation not permitted.");
+
+    declare_err!(ENOENT, "No such file or directory.");
+
+    declare_err!(ESRCH, "No such process.");
+
+    declare_err!(EINTR, "Interrupted system call.");
+
+    declare_err!(EIO, "I/O error.");
+
+    declare_err!(ENXIO, "No such device or address.");
+
+    declare_err!(E2BIG, "Argument list too long.");
+
+    declare_err!(ENOEXEC, "Exec format error.");
+
+    declare_err!(EBADF, "Bad file number.");
+
+    declare_err!(ECHILD, "Exec format error.");
+
+    declare_err!(EAGAIN, "Try again.");
+
+    declare_err!(ENOMEM, "Out of memory.");
+
+    declare_err!(EACCES, "Permission denied.");
+
+    declare_err!(EFAULT, "Bad address.");
+
+    declare_err!(ENOTBLK, "Block device required.");
+
+    declare_err!(EBUSY, "Device or resource busy.");
+
+    declare_err!(EEXIST, "File exists.");
+
+    declare_err!(EXDEV, "Cross-device link.");
+
+    declare_err!(ENODEV, "No such device.");
+
+    declare_err!(ENOTDIR, "Not a directory.");
+
+    declare_err!(EISDIR, "Is a directory.");
+
+    declare_err!(EINVAL, "Invalid argument.");
+
+    declare_err!(ENFILE, "File table overflow.");
+
+    declare_err!(EMFILE, "Too many open files.");
+
+    declare_err!(ENOTTY, "Not a typewriter.");
+
+    declare_err!(ETXTBSY, "Text file busy.");
+
+    declare_err!(EFBIG, "File too large.");
+
+    declare_err!(ENOSPC, "No space left on device.");
+
+    declare_err!(ESPIPE, "Illegal seek.");
+
+    declare_err!(EROFS, "Read-only file system.");
+
+    declare_err!(EMLINK, "Too many links.");
+
+    declare_err!(EPIPE, "Broken pipe.");
+
+    declare_err!(EDOM, "Math argument out of domain of func.");
+
+    declare_err!(ERANGE, "Math result not representable.");
+
+    declare_err!(EDEADLK, "Resource deadlock would occur");
+
+    declare_err!(ENAMETOOLONG, "File name too long");
+
+    declare_err!(ENOLCK, "No record locks available");
+
+    declare_err!(
+        ENOSYS,
+        "Invalid system call number.",
+        "",
+        "This error code is special: arch syscall entry code will return",
+        "[`ENOSYS`] if users try to call a syscall that doesn't exist.",
+        "To keep failures of syscalls that really do exist distinguishable from",
+        "failures due to attempts to use a nonexistent syscall, syscall",
+        "implementations should refrain from returning [`ENOSYS`]."
+    );
+
+    declare_err!(ENOTEMPTY, "Directory not empty.");
+
+    declare_err!(ELOOP, "Too many symbolic links encountered.");
+
+    declare_err!(EWOULDBLOCK, "Operation would block.");
+
+    declare_err!(ENOMSG, "No message of desired type.");
+
+    declare_err!(EIDRM, "Identifier removed.");
+
+    declare_err!(ECHRNG, "Channel number out of range.");
+
+    declare_err!(EL2NSYNC, "Level 2 not synchronized.");
+
+    declare_err!(EL3HLT, "Level 3 halted.");
+
+    declare_err!(EL3RST, "Level 3 reset.");
+
+    declare_err!(ELNRNG, "Link number out of range.");
+
+    declare_err!(EUNATCH, "Protocol driver not attached.");
+
+    declare_err!(ENOCSI, "No CSI structure available.");
+
+    declare_err!(EL2HLT, "Level 2 halted.");
+
+    declare_err!(EBADE, "Invalid exchange.");
+
+    declare_err!(EBADR, "Invalid request descriptor.");
+
+    declare_err!(EXFULL, "Exchange full.");
+
+    declare_err!(ENOANO, "No anode.");
+
+    declare_err!(EBADRQC, "Invalid request code.");
+
+    declare_err!(EBADSLT, "Invalid slot.");
+
+    declare_err!(EDEADLOCK, "Resource deadlock would occur.");
+
+    declare_err!(EBFONT, "Bad font file format.");
+
+    declare_err!(ENOSTR, "Device not a stream.");
+
+    declare_err!(ENODATA, "No data available.");
+
+    declare_err!(ETIME, "Timer expired.");
+
+    declare_err!(ENOSR, "Out of streams resources.");
+
+    declare_err!(ENONET, "Machine is not on the network.");
+
+    declare_err!(ENOPKG, "Package not installed.");
+
+    declare_err!(EREMOTE, "Object is remote.");
+
+    declare_err!(ENOLINK, "Link has been severed.");
+
+    declare_err!(EADV, "Advertise error.");
+
+    declare_err!(ESRMNT, "Srmount error.");
+
+    declare_err!(ECOMM, "Communication error on send.");
+
+    declare_err!(EPROTO, "Protocol error.");
+
+    declare_err!(EMULTIHOP, "Multihop attempted.");
+
+    declare_err!(EDOTDOT, "RFS specific error.");
+
+    declare_err!(EBADMSG, "Not a data message.");
+
+    declare_err!(EOVERFLOW, "Value too large for defined data type.");
+
+    declare_err!(ENOTUNIQ, "Name not unique on network.");
+
+    declare_err!(EBADFD, "File descriptor in bad state.");
+
+    declare_err!(EREMCHG, "Remote address changed.");
+
+    declare_err!(ELIBACC, "Can not access a needed shared library.");
+
+    declare_err!(ELIBBAD, "Accessing a corrupted shared library.");
+
+    declare_err!(ELIBSCN, ".lib section in a.out corrupted.");
+
+    declare_err!(ELIBMAX, "Attempting to link in too many shared libraries.");
+
+    declare_err!(ELIBEXEC, "Cannot exec a shared library directly.");
+
+    declare_err!(EILSEQ, "Illegal byte sequence.");
+
+    declare_err!(ERESTART, "Interrupted system call should be restarted.");
+
+    declare_err!(ESTRPIPE, "Streams pipe error.");
+
+    declare_err!(EUSERS, "Too many users.");
+
+    declare_err!(ENOTSOCK, "Socket operation on non-socket.");
+
+    declare_err!(EDESTADDRREQ, "Destination address required.");
+
+    declare_err!(EMSGSIZE, "Message too long.");
+
+    declare_err!(EPROTOTYPE, "Protocol wrong type for socket.");
+
+    declare_err!(ENOPROTOOPT, "Protocol not available.");
+
+    declare_err!(EPROTONOSUPPORT, "Protocol not supported.");
+
+    declare_err!(ESOCKTNOSUPPORT, "Socket type not supported.");
+
+    declare_err!(EOPNOTSUPP, "Operation not supported on transport endpoint.");
+
+    declare_err!(EPFNOSUPPORT, "Protocol family not supported.");
+
+    declare_err!(EAFNOSUPPORT, "Address family not supported by protocol.");
+
+    declare_err!(EADDRINUSE, "Address already in use.");
+
+    declare_err!(EADDRNOTAVAIL, "Cannot assign requested address.");
+
+    declare_err!(ENETDOWN, "Network is down.");
+
+    declare_err!(ENETUNREACH, "Network is unreachable.");
+
+    declare_err!(ENETRESET, "Network dropped connection because of reset.");
+
+    declare_err!(ECONNABORTED, "Software caused connection abort.");
+
+    declare_err!(ECONNRESET, "Connection reset by peer.");
+
+    declare_err!(ENOBUFS, "No buffer space available.");
+
+    declare_err!(EISCONN, "Transport endpoint is already connected.");
+
+    declare_err!(ENOTCONN, "Transport endpoint is not connected.");
+
+    declare_err!(ESHUTDOWN, "Cannot send after transport endpoint shutdown.");
+
+    declare_err!(ETOOMANYREFS, "Too many references: cannot splice.");
+
+    declare_err!(ETIMEDOUT, "Connection timed out.");
+
+    declare_err!(ECONNREFUSED, "Connection refused.");
+
+    declare_err!(EHOSTDOWN, "Host is down.");
+
+    declare_err!(EHOSTUNREACH, "No route to host.");
+
+    declare_err!(EALREADY, "Operation already in progress.");
+
+    declare_err!(EINPROGRESS, "Operation now in progress.");
+
+    declare_err!(ESTALE, "Stale file handle.");
+
+    declare_err!(EUCLEAN, "Structure needs cleaning.");
+
+    declare_err!(ENOTNAM, "Not a XENIX named type file.");
+
+    declare_err!(ENAVAIL, "No XENIX semaphores available.");
+
+    declare_err!(EISNAM, "Is a named type file.");
+
+    declare_err!(EREMOTEIO, "Remote I/O error.");
+
+    declare_err!(EDQUOT, "Quota exceeded.");
+
+    declare_err!(ENOMEDIUM, "No medium found.");
+
+    declare_err!(EMEDIUMTYPE, "Wrong medium type.");
+
+    declare_err!(ECANCELED, "Operation Canceled.");
+
+    declare_err!(ENOKEY, "Required key not available.");
+
+    declare_err!(EKEYEXPIRED, "Key has expired.");
+
+    declare_err!(EKEYREVOKED, "Key has been revoked.");
+
+    declare_err!(EKEYREJECTED, "Key was rejected by service.");
+
+    declare_err!(EOWNERDEAD, "Owner died.", "", "For robust mutexes.");
+
+    declare_err!(ENOTRECOVERABLE, "State not recoverable.");
+
+    declare_err!(ERFKILL, "Operation not possible due to RF-kill.");
+
+    declare_err!(EHWPOISON, "Memory page has hardware error.");
+
+    declare_err!(ERESTARTSYS, "Restart the system call.");
+
+    declare_err!(ENOTSUPP, "Operation is not supported.");
+}
+
+/// Generic integer kernel error.
+///
+/// The kernel defines a set of integer generic error codes based on C and
+/// POSIX ones. These codes may have a more specific meaning in some contexts.
+///
+/// # Invariants
+///
+/// The value is a valid `errno` (i.e. `>= -MAX_ERRNO && < 0`).
+#[derive(Clone, Copy, PartialEq, Eq)]
+pub struct Error(c_types::c_int);
+
+impl Error {
+    /// Creates an [`Error`] from a kernel error code.
+    ///
+    /// It is a bug to pass an out-of-range `errno`. `EINVAL` would
+    /// be returned in such a case.
+    pub(crate) fn from_kernel_errno(errno: c_types::c_int) -> Error {
+        if errno < -(bindings::MAX_ERRNO as i32) || errno >= 0 {
+            // TODO: Make it a `WARN_ONCE` once available.
+            crate::pr_warn!(
+                "attempted to create `Error` with out of range `errno`: {}",
+                errno
+            );
+            return code::EINVAL;
+        }
+
+        // INVARIANT: The check above ensures the type invariant
+        // will hold.
+        Error(errno)
+    }
+
+    /// Creates an [`Error`] from a kernel error code.
+    ///
+    /// # Safety
+    ///
+    /// `errno` must be within error code range (i.e. `>= -MAX_ERRNO && < 0`).
+    pub(crate) unsafe fn from_kernel_errno_unchecked(errno: c_types::c_int) -> Error {
+        // INVARIANT: The contract ensures the type invariant
+        // will hold.
+        Error(errno)
+    }
+
+    /// Returns the kernel error code.
+    pub fn to_kernel_errno(self) -> c_types::c_int {
+        self.0
+    }
+
+    /// Returns a string representing the error, if one exists.
+    #[cfg(not(testlib))]
+    pub fn name(&self) -> Option<&'static CStr> {
+        // SAFETY: Just an FFI call, there are no extra safety requirements.
+        let ptr = unsafe { bindings::errname(-self.0) };
+        if ptr.is_null() {
+            None
+        } else {
+            // SAFETY: The string returned by `errname` is static and `NUL`-terminated.
+            Some(unsafe { CStr::from_char_ptr(ptr) })
+        }
+    }
+
+    /// Returns a string representing the error, if one exists.
+    ///
+    /// When `testlib` is configured, this always returns `None` to avoid the dependency on a
+    /// kernel function so that tests that use this (e.g., by calling [`Result::unwrap`]) can still
+    /// run in userspace.
+    #[cfg(testlib)]
+    pub fn name(&self) -> Option<&'static CStr> {
+        None
+    }
+}
+
+impl fmt::Debug for Error {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match self.name() {
+            // Print out number if no name can be found.
+            None => f.debug_tuple("Error").field(&-self.0).finish(),
+            // SAFETY: These strings are ASCII-only.
+            Some(name) => f
+                .debug_tuple(unsafe { str::from_utf8_unchecked(name) })
+                .finish(),
+        }
+    }
+}
+
+impl From<TryFromIntError> for Error {
+    fn from(_: TryFromIntError) -> Error {
+        code::EINVAL
+    }
+}
+
+impl From<Utf8Error> for Error {
+    fn from(_: Utf8Error) -> Error {
+        code::EINVAL
+    }
+}
+
+impl From<TryReserveError> for Error {
+    fn from(_: TryReserveError) -> Error {
+        code::ENOMEM
+    }
+}
+
+impl From<LayoutError> for Error {
+    fn from(_: LayoutError) -> Error {
+        code::ENOMEM
+    }
+}
+
+impl From<core::fmt::Error> for Error {
+    fn from(_: core::fmt::Error) -> Error {
+        code::EINVAL
+    }
+}
+
+/// A [`Result`] with an [`Error`] error type.
+///
+/// To be used as the return type for functions that may fail.
+///
+/// # Error codes in C and Rust
+///
+/// In C, it is common that functions indicate success or failure through
+/// their return value; modifying or returning extra data through non-`const`
+/// pointer parameters. In particular, in the kernel, functions that may fail
+/// typically return an `int` that represents a generic error code. We model
+/// those as [`Error`].
+///
+/// In Rust, it is idiomatic to model functions that may fail as returning
+/// a [`Result`]. Since in the kernel many functions return an error code,
+/// [`Result`] is a type alias for a [`core::result::Result`] that uses
+/// [`Error`] as its error type.
+///
+/// Note that even if a function does not return anything when it succeeds,
+/// it should still be modeled as returning a `Result` rather than
+/// just an [`Error`].
+pub type Result<T = ()> = core::result::Result<T, Error>;
+
+impl From<AllocError> for Error {
+    fn from(_: AllocError) -> Error {
+        code::ENOMEM
+    }
+}
+
+// # Invariant: `-bindings::MAX_ERRNO` fits in an `i16`.
+crate::static_assert!(bindings::MAX_ERRNO <= -(i16::MIN as i32) as u32);
+
+pub(crate) fn from_kernel_result_helper<T>(r: Result<T>) -> T
+where
+    T: From<i16>,
+{
+    match r {
+        Ok(v) => v,
+        // NO-OVERFLOW: negative `errno`s are no smaller than `-bindings::MAX_ERRNO`,
+        // `-bindings::MAX_ERRNO` fits in an `i16` as per invariant above,
+        // therefore a negative `errno` always fits in an `i16` and will not overflow.
+        Err(e) => T::from(e.to_kernel_errno() as i16),
+    }
+}
+
+/// Transforms a [`crate::error::Result<T>`] to a kernel C integer result.
+///
+/// This is useful when calling Rust functions that return [`crate::error::Result<T>`]
+/// from inside `extern "C"` functions that need to return an integer
+/// error result.
+///
+/// `T` should be convertible to an `i16` via `From<i16>`.
+///
+/// # Examples
+///
+/// ```ignore
+/// # use kernel::from_kernel_result;
+/// # use kernel::c_types;
+/// # use kernel::bindings;
+/// unsafe extern "C" fn probe_callback(
+///     pdev: *mut bindings::platform_device,
+/// ) -> c_types::c_int {
+///     from_kernel_result! {
+///         let ptr = devm_alloc(pdev)?;
+///         bindings::platform_set_drvdata(pdev, ptr);
+///         Ok(0)
+///     }
+/// }
+/// ```
+macro_rules! from_kernel_result {
+    ($($tt:tt)*) => {{
+        $crate::error::from_kernel_result_helper((|| {
+            $($tt)*
+        })())
+    }};
+}
+
+pub(crate) use from_kernel_result;
+
+/// Transform a kernel "error pointer" to a normal pointer.
+///
+/// Some kernel C API functions return an "error pointer" which optionally
+/// embeds an `errno`. Callers are supposed to check the returned pointer
+/// for errors. This function performs the check and converts the "error pointer"
+/// to a normal pointer in an idiomatic fashion.
+///
+/// # Examples
+///
+/// ```ignore
+/// # use kernel::prelude::*;
+/// # use kernel::from_kernel_err_ptr;
+/// # use kernel::c_types;
+/// # use kernel::bindings;
+/// fn devm_platform_ioremap_resource(
+///     pdev: &mut PlatformDevice,
+///     index: u32,
+/// ) -> Result<*mut c_types::c_void> {
+///     // SAFETY: FFI call.
+///     unsafe {
+///         from_kernel_err_ptr(bindings::devm_platform_ioremap_resource(
+///             pdev.to_ptr(),
+///             index,
+///         ))
+///     }
+/// }
+/// ```
+// TODO: Remove `dead_code` marker once an in-kernel client is available.
+#[allow(dead_code)]
+pub(crate) fn from_kernel_err_ptr<T>(ptr: *mut T) -> Result<*mut T> {
+    // CAST: Casting a pointer to `*const c_types::c_void` is always valid.
+    let const_ptr: *const c_types::c_void = ptr.cast();
+    // SAFETY: The FFI function does not deref the pointer.
+    if unsafe { bindings::IS_ERR(const_ptr) } {
+        // SAFETY: The FFI function does not deref the pointer.
+        let err = unsafe { bindings::PTR_ERR(const_ptr) };
+        // CAST: If `IS_ERR()` returns `true`,
+        // then `PTR_ERR()` is guaranteed to return a
+        // negative value greater-or-equal to `-bindings::MAX_ERRNO`,
+        // which always fits in an `i16`, as per the invariant above.
+        // And an `i16` always fits in an `i32`. So casting `err` to
+        // an `i32` can never overflow, and is always valid.
+        //
+        // SAFETY: `IS_ERR()` ensures `err` is a
+        // negative value greater-or-equal to `-bindings::MAX_ERRNO`.
+        return Err(unsafe { Error::from_kernel_errno_unchecked(err as i32) });
+    }
+    Ok(ptr)
+}
+
+/// Calls a kernel function that returns an integer error code on failure and converts the result
+/// to a [`Result`].
+pub fn to_result(func: impl FnOnce() -> c_types::c_int) -> Result {
+    let err = func();
+    if err < 0 {
+        Err(Error::from_kernel_errno(err))
+    } else {
+        Ok(())
+    }
+}
diff --git a/rust/kernel/file.rs b/rust/kernel/file.rs
new file mode 100644
index 000000000000..7f4adfd4b80a
--- /dev/null
+++ b/rust/kernel/file.rs
@@ -0,0 +1,873 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Files and file descriptors.
+//!
+//! C headers: [`include/linux/fs.h`](../../../../include/linux/fs.h) and
+//! [`include/linux/file.h`](../../../../include/linux/file.h)
+
+use crate::{
+    bindings, c_types,
+    cred::CredentialRef,
+    error::{code::*, from_kernel_result, Error, Result},
+    io_buffer::{IoBufferReader, IoBufferWriter},
+    iov_iter::IovIter,
+    mm,
+    sync::CondVar,
+    types::PointerWrapper,
+    user_ptr::{UserSlicePtr, UserSlicePtrReader, UserSlicePtrWriter},
+};
+use core::convert::{TryFrom, TryInto};
+use core::{marker, mem, mem::ManuallyDrop, ops::Deref, ptr};
+
+/// Wraps the kernel's `struct file`.
+///
+/// # Invariants
+///
+/// The pointer `File::ptr` is non-null and valid. Its reference count is also non-zero.
+pub struct File {
+    pub(crate) ptr: *mut bindings::file,
+}
+
+impl File {
+    /// Constructs a new [`struct file`] wrapper from a file descriptor.
+    ///
+    /// The file descriptor belongs to the current process.
+    pub fn from_fd(fd: u32) -> Result<Self> {
+        // SAFETY: FFI call, there are no requirements on `fd`.
+        let ptr = unsafe { bindings::fget(fd) };
+        if ptr.is_null() {
+            return Err(EBADF);
+        }
+
+        // INVARIANTS: We checked that `ptr` is non-null, so it is valid. `fget` increments the ref
+        // count before returning.
+        Ok(Self { ptr })
+    }
+
+    /// Returns the current seek/cursor/pointer position (`struct file::f_pos`).
+    pub fn pos(&self) -> u64 {
+        // SAFETY: `File::ptr` is guaranteed to be valid by the type invariants.
+        unsafe { (*self.ptr).f_pos as u64 }
+    }
+
+    /// Returns whether the file is in blocking mode.
+    pub fn is_blocking(&self) -> bool {
+        // SAFETY: `File::ptr` is guaranteed to be valid by the type invariants.
+        unsafe { (*self.ptr).f_flags & bindings::O_NONBLOCK == 0 }
+    }
+
+    /// Returns the credentials of the task that originally opened the file.
+    pub fn cred(&self) -> CredentialRef<'_> {
+        // SAFETY: `File::ptr` is guaranteed to be valid by the type invariants.
+        let ptr = unsafe { (*self.ptr).f_cred };
+        // SAFETY: The lifetimes of `self` and `CredentialRef` are tied, so it is guaranteed that
+        // the credential pointer remains valid (because the file is still alive, and it doesn't
+        // change over the lifetime of a file).
+        unsafe { CredentialRef::from_ptr(ptr) }
+    }
+
+    /// Returns the flags associated with the file.
+    pub fn flags(&self) -> u32 {
+        // SAFETY: `File::ptr` is guaranteed to be valid by the type invariants.
+        unsafe { (*self.ptr).f_flags }
+    }
+}
+
+impl Drop for File {
+    fn drop(&mut self) {
+        // SAFETY: The type invariants guarantee that `File::ptr` has a non-zero reference count.
+        unsafe { bindings::fput(self.ptr) };
+    }
+}
+
+/// A wrapper for [`File`] that doesn't automatically decrement the refcount when dropped.
+///
+/// We need the wrapper because [`ManuallyDrop`] alone would allow callers to call
+/// [`ManuallyDrop::into_inner`]. This would allow an unsafe sequence to be triggered without
+/// `unsafe` blocks because it would trigger an unbalanced call to `fput`.
+///
+/// # Invariants
+///
+/// The wrapped [`File`] remains valid for the lifetime of the object.
+pub(crate) struct FileRef(ManuallyDrop<File>);
+
+impl FileRef {
+    /// Constructs a new [`struct file`] wrapper that doesn't change its reference count.
+    ///
+    /// # Safety
+    ///
+    /// The pointer `ptr` must be non-null and valid for the lifetime of the object.
+    pub(crate) unsafe fn from_ptr(ptr: *mut bindings::file) -> Self {
+        Self(ManuallyDrop::new(File { ptr }))
+    }
+}
+
+impl Deref for FileRef {
+    type Target = File;
+
+    fn deref(&self) -> &Self::Target {
+        self.0.deref()
+    }
+}
+
+/// A file descriptor reservation.
+///
+/// This allows the creation of a file descriptor in two steps: first, we reserve a slot for it,
+/// then we commit or drop the reservation. The first step may fail (e.g., the current process ran
+/// out of available slots), but commit and drop never fail (and are mutually exclusive).
+pub struct FileDescriptorReservation {
+    fd: u32,
+}
+
+impl FileDescriptorReservation {
+    /// Creates a new file descriptor reservation.
+    pub fn new(flags: u32) -> Result<Self> {
+        // SAFETY: FFI call, there are no safety requirements on `flags`.
+        let fd = unsafe { bindings::get_unused_fd_flags(flags) };
+        if fd < 0 {
+            return Err(Error::from_kernel_errno(fd));
+        }
+        Ok(Self { fd: fd as _ })
+    }
+
+    /// Returns the file descriptor number that was reserved.
+    pub fn reserved_fd(&self) -> u32 {
+        self.fd
+    }
+
+    /// Commits the reservation.
+    ///
+    /// The previously reserved file descriptor is bound to `file`.
+    pub fn commit(self, file: File) {
+        // SAFETY: `self.fd` was previously returned by `get_unused_fd_flags`, and `file.ptr` is
+        // guaranteed to have an owned ref count by its type invariants.
+        unsafe { bindings::fd_install(self.fd, file.ptr) };
+
+        // `fd_install` consumes both the file descriptor and the file reference, so we cannot run
+        // the destructors.
+        core::mem::forget(self);
+        core::mem::forget(file);
+    }
+}
+
+impl Drop for FileDescriptorReservation {
+    fn drop(&mut self) {
+        // SAFETY: `self.fd` was returned by a previous call to `get_unused_fd_flags`.
+        unsafe { bindings::put_unused_fd(self.fd) };
+    }
+}
+
+/// Wraps the kernel's `struct poll_table_struct`.
+///
+/// # Invariants
+///
+/// The pointer `PollTable::ptr` is null or valid.
+pub struct PollTable {
+    ptr: *mut bindings::poll_table_struct,
+}
+
+impl PollTable {
+    /// Constructors a new `struct poll_table_struct` wrapper.
+    ///
+    /// # Safety
+    ///
+    /// The pointer `ptr` must be either null or a valid pointer for the lifetime of the object.
+    unsafe fn from_ptr(ptr: *mut bindings::poll_table_struct) -> Self {
+        Self { ptr }
+    }
+
+    /// Associates the given file and condition variable to this poll table. It means notifying the
+    /// condition variable will notify the poll table as well; additionally, the association
+    /// between the condition variable and the file will automatically be undone by the kernel when
+    /// the file is destructed. To unilaterally remove the association before then, one can call
+    /// [`CondVar::free_waiters`].
+    ///
+    /// # Safety
+    ///
+    /// If the condition variable is destroyed before the file, then [`CondVar::free_waiters`] must
+    /// be called to ensure that all waiters are flushed out.
+    pub unsafe fn register_wait<'a>(&self, file: &'a File, cv: &'a CondVar) {
+        if self.ptr.is_null() {
+            return;
+        }
+
+        // SAFETY: `PollTable::ptr` is guaranteed to be valid by the type invariants and the null
+        // check above.
+        let table = unsafe { &*self.ptr };
+        if let Some(proc) = table._qproc {
+            // SAFETY: All pointers are known to be valid.
+            unsafe { proc(file.ptr as _, cv.wait_list.get(), self.ptr) }
+        }
+    }
+}
+
+/// Equivalent to [`std::io::SeekFrom`].
+///
+/// [`std::io::SeekFrom`]: https://doc.rust-lang.org/std/io/enum.SeekFrom.html
+pub enum SeekFrom {
+    /// Equivalent to C's `SEEK_SET`.
+    Start(u64),
+
+    /// Equivalent to C's `SEEK_END`.
+    End(i64),
+
+    /// Equivalent to C's `SEEK_CUR`.
+    Current(i64),
+}
+
+pub(crate) struct OperationsVtable<A, T>(marker::PhantomData<A>, marker::PhantomData<T>);
+
+impl<A: OpenAdapter<T::OpenData>, T: Operations> OperationsVtable<A, T> {
+    /// Called by the VFS when an inode should be opened.
+    ///
+    /// Calls `T::open` on the returned value of `A::convert`.
+    ///
+    /// # Safety
+    ///
+    /// The returned value of `A::convert` must be a valid non-null pointer and
+    /// `T:open` must return a valid non-null pointer on an `Ok` result.
+    unsafe extern "C" fn open_callback(
+        inode: *mut bindings::inode,
+        file: *mut bindings::file,
+    ) -> c_types::c_int {
+        from_kernel_result! {
+            // SAFETY: `A::convert` must return a valid non-null pointer that
+            // should point to data in the inode or file that lives longer
+            // than the following use of `T::open`.
+            let arg = unsafe { A::convert(inode, file) };
+            // SAFETY: The C contract guarantees that `file` is valid. Additionally,
+            // `fileref` never outlives this function, so it is guaranteed to be
+            // valid.
+            let fileref = unsafe { FileRef::from_ptr(file) };
+            // SAFETY: `arg` was previously returned by `A::convert` and must
+            // be a valid non-null pointer.
+            let ptr = T::open(unsafe { &*arg }, &fileref)?.into_pointer();
+            // SAFETY: The C contract guarantees that `private_data` is available
+            // for implementers of the file operations (no other C code accesses
+            // it), so we know that there are no concurrent threads/CPUs accessing
+            // it (it's not visible to any other Rust code).
+            unsafe { (*file).private_data = ptr as *mut c_types::c_void };
+            Ok(0)
+        }
+    }
+
+    unsafe extern "C" fn read_callback(
+        file: *mut bindings::file,
+        buf: *mut c_types::c_char,
+        len: c_types::c_size_t,
+        offset: *mut bindings::loff_t,
+    ) -> c_types::c_ssize_t {
+        from_kernel_result! {
+            let mut data = unsafe { UserSlicePtr::new(buf as *mut c_types::c_void, len).writer() };
+            // SAFETY: `private_data` was initialised by `open_callback` with a value returned by
+            // `T::Data::into_pointer`. `T::Data::from_pointer` is only called by the
+            // `release` callback, which the C API guarantees that will be called only when all
+            // references to `file` have been released, so we know it can't be called while this
+            // function is running.
+            let f = unsafe { T::Data::borrow((*file).private_data) };
+            // No `FMODE_UNSIGNED_OFFSET` support, so `offset` must be in [0, 2^63).
+            // See discussion in https://github.com/fishinabarrel/linux-kernel-module-rust/pull/113
+            let read = T::read(
+                f,
+                unsafe { &FileRef::from_ptr(file) },
+                &mut data,
+                unsafe { *offset }.try_into()?,
+            )?;
+            unsafe { (*offset) += bindings::loff_t::try_from(read).unwrap() };
+            Ok(read as _)
+        }
+    }
+
+    unsafe extern "C" fn read_iter_callback(
+        iocb: *mut bindings::kiocb,
+        raw_iter: *mut bindings::iov_iter,
+    ) -> isize {
+        from_kernel_result! {
+            let mut iter = unsafe { IovIter::from_ptr(raw_iter) };
+            let file = unsafe { (*iocb).ki_filp };
+            let offset = unsafe { (*iocb).ki_pos };
+            // SAFETY: `private_data` was initialised by `open_callback` with a value returned by
+            // `T::Data::into_pointer`. `T::Data::from_pointer` is only called by the
+            // `release` callback, which the C API guarantees that will be called only when all
+            // references to `file` have been released, so we know it can't be called while this
+            // function is running.
+            let f = unsafe { T::Data::borrow((*file).private_data) };
+            let read =
+                T::read(f, unsafe { &FileRef::from_ptr(file) }, &mut iter, offset.try_into()?)?;
+            unsafe { (*iocb).ki_pos += bindings::loff_t::try_from(read).unwrap() };
+            Ok(read as _)
+        }
+    }
+
+    unsafe extern "C" fn write_callback(
+        file: *mut bindings::file,
+        buf: *const c_types::c_char,
+        len: c_types::c_size_t,
+        offset: *mut bindings::loff_t,
+    ) -> c_types::c_ssize_t {
+        from_kernel_result! {
+            let mut data = unsafe { UserSlicePtr::new(buf as *mut c_types::c_void, len).reader() };
+            // SAFETY: `private_data` was initialised by `open_callback` with a value returned by
+            // `T::Data::into_pointer`. `T::Data::from_pointer` is only called by the
+            // `release` callback, which the C API guarantees that will be called only when all
+            // references to `file` have been released, so we know it can't be called while this
+            // function is running.
+            let f = unsafe { T::Data::borrow((*file).private_data) };
+            // No `FMODE_UNSIGNED_OFFSET` support, so `offset` must be in [0, 2^63).
+            // See discussion in https://github.com/fishinabarrel/linux-kernel-module-rust/pull/113
+            let written = T::write(
+                f,
+                unsafe { &FileRef::from_ptr(file) },
+                &mut data,
+                unsafe { *offset }.try_into()?
+            )?;
+            unsafe { (*offset) += bindings::loff_t::try_from(written).unwrap() };
+            Ok(written as _)
+        }
+    }
+
+    unsafe extern "C" fn write_iter_callback(
+        iocb: *mut bindings::kiocb,
+        raw_iter: *mut bindings::iov_iter,
+    ) -> isize {
+        from_kernel_result! {
+            let mut iter = unsafe { IovIter::from_ptr(raw_iter) };
+            let file = unsafe { (*iocb).ki_filp };
+            let offset = unsafe { (*iocb).ki_pos };
+            // SAFETY: `private_data` was initialised by `open_callback` with a value returned by
+            // `T::Data::into_pointer`. `T::Data::from_pointer` is only called by the
+            // `release` callback, which the C API guarantees that will be called only when all
+            // references to `file` have been released, so we know it can't be called while this
+            // function is running.
+            let f = unsafe { T::Data::borrow((*file).private_data) };
+            let written =
+                T::write(f, unsafe { &FileRef::from_ptr(file) }, &mut iter, offset.try_into()?)?;
+            unsafe { (*iocb).ki_pos += bindings::loff_t::try_from(written).unwrap() };
+            Ok(written as _)
+        }
+    }
+
+    unsafe extern "C" fn release_callback(
+        _inode: *mut bindings::inode,
+        file: *mut bindings::file,
+    ) -> c_types::c_int {
+        let ptr = mem::replace(unsafe { &mut (*file).private_data }, ptr::null_mut());
+        T::release(unsafe { T::Data::from_pointer(ptr as _) }, unsafe {
+            &FileRef::from_ptr(file)
+        });
+        0
+    }
+
+    unsafe extern "C" fn llseek_callback(
+        file: *mut bindings::file,
+        offset: bindings::loff_t,
+        whence: c_types::c_int,
+    ) -> bindings::loff_t {
+        from_kernel_result! {
+            let off = match whence as u32 {
+                bindings::SEEK_SET => SeekFrom::Start(offset.try_into()?),
+                bindings::SEEK_CUR => SeekFrom::Current(offset),
+                bindings::SEEK_END => SeekFrom::End(offset),
+                _ => return Err(EINVAL),
+            };
+            // SAFETY: `private_data` was initialised by `open_callback` with a value returned by
+            // `T::Data::into_pointer`. `T::Data::from_pointer` is only called by the
+            // `release` callback, which the C API guarantees that will be called only when all
+            // references to `file` have been released, so we know it can't be called while this
+            // function is running.
+            let f = unsafe { T::Data::borrow((*file).private_data) };
+            let off = T::seek(f, unsafe { &FileRef::from_ptr(file) }, off)?;
+            Ok(off as bindings::loff_t)
+        }
+    }
+
+    unsafe extern "C" fn unlocked_ioctl_callback(
+        file: *mut bindings::file,
+        cmd: c_types::c_uint,
+        arg: c_types::c_ulong,
+    ) -> c_types::c_long {
+        from_kernel_result! {
+            // SAFETY: `private_data` was initialised by `open_callback` with a value returned by
+            // `T::Data::into_pointer`. `T::Data::from_pointer` is only called by the
+            // `release` callback, which the C API guarantees that will be called only when all
+            // references to `file` have been released, so we know it can't be called while this
+            // function is running.
+            let f = unsafe { T::Data::borrow((*file).private_data) };
+            let mut cmd = IoctlCommand::new(cmd as _, arg as _);
+            let ret = T::ioctl(f, unsafe { &FileRef::from_ptr(file) }, &mut cmd)?;
+            Ok(ret as _)
+        }
+    }
+
+    unsafe extern "C" fn compat_ioctl_callback(
+        file: *mut bindings::file,
+        cmd: c_types::c_uint,
+        arg: c_types::c_ulong,
+    ) -> c_types::c_long {
+        from_kernel_result! {
+            // SAFETY: `private_data` was initialised by `open_callback` with a value returned by
+            // `T::Data::into_pointer`. `T::Data::from_pointer` is only called by the
+            // `release` callback, which the C API guarantees that will be called only when all
+            // references to `file` have been released, so we know it can't be called while this
+            // function is running.
+            let f = unsafe { T::Data::borrow((*file).private_data) };
+            let mut cmd = IoctlCommand::new(cmd as _, arg as _);
+            let ret = T::compat_ioctl(f, unsafe { &FileRef::from_ptr(file) }, &mut cmd)?;
+            Ok(ret as _)
+        }
+    }
+
+    unsafe extern "C" fn mmap_callback(
+        file: *mut bindings::file,
+        vma: *mut bindings::vm_area_struct,
+    ) -> c_types::c_int {
+        from_kernel_result! {
+            // SAFETY: `private_data` was initialised by `open_callback` with a value returned by
+            // `T::Data::into_pointer`. `T::Data::from_pointer` is only called by the
+            // `release` callback, which the C API guarantees that will be called only when all
+            // references to `file` have been released, so we know it can't be called while this
+            // function is running.
+            let f = unsafe { T::Data::borrow((*file).private_data) };
+
+            // SAFETY: The C API guarantees that `vma` is valid for the duration of this call.
+            // `area` only lives within this call, so it is guaranteed to be valid.
+            let mut area = unsafe { mm::virt::Area::from_ptr(vma) };
+
+            // SAFETY: The C API guarantees that `file` is valid for the duration of this call,
+            // which is longer than the lifetime of the file reference.
+            T::mmap(f, unsafe { &FileRef::from_ptr(file) }, &mut area)?;
+            Ok(0)
+        }
+    }
+
+    unsafe extern "C" fn fsync_callback(
+        file: *mut bindings::file,
+        start: bindings::loff_t,
+        end: bindings::loff_t,
+        datasync: c_types::c_int,
+    ) -> c_types::c_int {
+        from_kernel_result! {
+            let start = start.try_into()?;
+            let end = end.try_into()?;
+            let datasync = datasync != 0;
+            // SAFETY: `private_data` was initialised by `open_callback` with a value returned by
+            // `T::Data::into_pointer`. `T::Data::from_pointer` is only called by the
+            // `release` callback, which the C API guarantees that will be called only when all
+            // references to `file` have been released, so we know it can't be called while this
+            // function is running.
+            let f = unsafe { T::Data::borrow((*file).private_data) };
+            let res = T::fsync(f, unsafe { &FileRef::from_ptr(file) }, start, end, datasync)?;
+            Ok(res.try_into().unwrap())
+        }
+    }
+
+    unsafe extern "C" fn poll_callback(
+        file: *mut bindings::file,
+        wait: *mut bindings::poll_table_struct,
+    ) -> bindings::__poll_t {
+        // SAFETY: `private_data` was initialised by `open_callback` with a value returned by
+        // `T::Data::into_pointer`. `T::Data::from_pointer` is only called by the `release`
+        // callback, which the C API guarantees that will be called only when all references to
+        // `file` have been released, so we know it can't be called while this function is running.
+        let f = unsafe { T::Data::borrow((*file).private_data) };
+        match T::poll(f, unsafe { &FileRef::from_ptr(file) }, unsafe {
+            &PollTable::from_ptr(wait)
+        }) {
+            Ok(v) => v,
+            Err(_) => bindings::POLLERR,
+        }
+    }
+
+    const VTABLE: bindings::file_operations = bindings::file_operations {
+        open: Some(Self::open_callback),
+        release: Some(Self::release_callback),
+        read: if T::TO_USE.read {
+            Some(Self::read_callback)
+        } else {
+            None
+        },
+        write: if T::TO_USE.write {
+            Some(Self::write_callback)
+        } else {
+            None
+        },
+        llseek: if T::TO_USE.seek {
+            Some(Self::llseek_callback)
+        } else {
+            None
+        },
+
+        check_flags: None,
+        compat_ioctl: if T::TO_USE.compat_ioctl {
+            Some(Self::compat_ioctl_callback)
+        } else {
+            None
+        },
+        copy_file_range: None,
+        fallocate: None,
+        fadvise: None,
+        fasync: None,
+        flock: None,
+        flush: None,
+        fsync: if T::TO_USE.fsync {
+            Some(Self::fsync_callback)
+        } else {
+            None
+        },
+        get_unmapped_area: None,
+        iterate: None,
+        iterate_shared: None,
+        iopoll: None,
+        lock: None,
+        mmap: if T::TO_USE.mmap {
+            Some(Self::mmap_callback)
+        } else {
+            None
+        },
+        mmap_supported_flags: 0,
+        owner: ptr::null_mut(),
+        poll: if T::TO_USE.poll {
+            Some(Self::poll_callback)
+        } else {
+            None
+        },
+        read_iter: if T::TO_USE.read_iter {
+            Some(Self::read_iter_callback)
+        } else {
+            None
+        },
+        remap_file_range: None,
+        sendpage: None,
+        setlease: None,
+        show_fdinfo: None,
+        splice_read: None,
+        splice_write: None,
+        unlocked_ioctl: if T::TO_USE.ioctl {
+            Some(Self::unlocked_ioctl_callback)
+        } else {
+            None
+        },
+        write_iter: if T::TO_USE.write_iter {
+            Some(Self::write_iter_callback)
+        } else {
+            None
+        },
+    };
+
+    /// Builds an instance of [`struct file_operations`].
+    ///
+    /// # Safety
+    ///
+    /// The caller must ensure that the adapter is compatible with the way the device is registered.
+    pub(crate) const unsafe fn build() -> &'static bindings::file_operations {
+        &Self::VTABLE
+    }
+}
+
+/// Represents which fields of [`struct file_operations`] should be populated with pointers.
+pub struct ToUse {
+    /// The `read` field of [`struct file_operations`].
+    pub read: bool,
+
+    /// The `read_iter` field of [`struct file_operations`].
+    pub read_iter: bool,
+
+    /// The `write` field of [`struct file_operations`].
+    pub write: bool,
+
+    /// The `write_iter` field of [`struct file_operations`].
+    pub write_iter: bool,
+
+    /// The `llseek` field of [`struct file_operations`].
+    pub seek: bool,
+
+    /// The `unlocked_ioctl` field of [`struct file_operations`].
+    pub ioctl: bool,
+
+    /// The `compat_ioctl` field of [`struct file_operations`].
+    pub compat_ioctl: bool,
+
+    /// The `fsync` field of [`struct file_operations`].
+    pub fsync: bool,
+
+    /// The `mmap` field of [`struct file_operations`].
+    pub mmap: bool,
+
+    /// The `poll` field of [`struct file_operations`].
+    pub poll: bool,
+}
+
+/// A constant version where all values are to set to `false`, that is, all supported fields will
+/// be set to null pointers.
+pub const USE_NONE: ToUse = ToUse {
+    read: false,
+    read_iter: false,
+    write: false,
+    write_iter: false,
+    seek: false,
+    ioctl: false,
+    compat_ioctl: false,
+    fsync: false,
+    mmap: false,
+    poll: false,
+};
+
+/// Defines the [`Operations::TO_USE`] field based on a list of fields to be populated.
+#[macro_export]
+macro_rules! declare_file_operations {
+    () => {
+        const TO_USE: $crate::file::ToUse = $crate::file::USE_NONE;
+    };
+    ($($i:ident),+) => {
+        const TO_USE: kernel::file::ToUse =
+            $crate::file::ToUse {
+                $($i: true),+ ,
+                ..$crate::file::USE_NONE
+            };
+    };
+}
+
+/// Allows the handling of ioctls defined with the `_IO`, `_IOR`, `_IOW`, and `_IOWR` macros.
+///
+/// For each macro, there is a handler function that takes the appropriate types as arguments.
+pub trait IoctlHandler: Sync {
+    /// The type of the first argument to each associated function.
+    type Target<'a>;
+
+    /// Handles ioctls defined with the `_IO` macro, that is, with no buffer as argument.
+    fn pure(_this: Self::Target<'_>, _file: &File, _cmd: u32, _arg: usize) -> Result<i32> {
+        Err(EINVAL)
+    }
+
+    /// Handles ioctls defined with the `_IOR` macro, that is, with an output buffer provided as
+    /// argument.
+    fn read(
+        _this: Self::Target<'_>,
+        _file: &File,
+        _cmd: u32,
+        _writer: &mut UserSlicePtrWriter,
+    ) -> Result<i32> {
+        Err(EINVAL)
+    }
+
+    /// Handles ioctls defined with the `_IOW` macro, that is, with an input buffer provided as
+    /// argument.
+    fn write(
+        _this: Self::Target<'_>,
+        _file: &File,
+        _cmd: u32,
+        _reader: &mut UserSlicePtrReader,
+    ) -> Result<i32> {
+        Err(EINVAL)
+    }
+
+    /// Handles ioctls defined with the `_IOWR` macro, that is, with a buffer for both input and
+    /// output provided as argument.
+    fn read_write(
+        _this: Self::Target<'_>,
+        _file: &File,
+        _cmd: u32,
+        _data: UserSlicePtr,
+    ) -> Result<i32> {
+        Err(EINVAL)
+    }
+}
+
+/// Represents an ioctl command.
+///
+/// It can use the components of an ioctl command to dispatch ioctls using
+/// [`IoctlCommand::dispatch`].
+pub struct IoctlCommand {
+    cmd: u32,
+    arg: usize,
+    user_slice: Option<UserSlicePtr>,
+}
+
+impl IoctlCommand {
+    /// Constructs a new [`IoctlCommand`].
+    fn new(cmd: u32, arg: usize) -> Self {
+        let size = (cmd >> bindings::_IOC_SIZESHIFT) & bindings::_IOC_SIZEMASK;
+
+        // SAFETY: We only create one instance of the user slice per ioctl call, so TOCTOU issues
+        // are not possible.
+        let user_slice = Some(unsafe { UserSlicePtr::new(arg as _, size as _) });
+        Self {
+            cmd,
+            arg,
+            user_slice,
+        }
+    }
+
+    /// Dispatches the given ioctl to the appropriate handler based on the value of the command. It
+    /// also creates a [`UserSlicePtr`], [`UserSlicePtrReader`], or [`UserSlicePtrWriter`]
+    /// depending on the direction of the buffer of the command.
+    ///
+    /// It is meant to be used in implementations of [`Operations::ioctl`] and
+    /// [`Operations::compat_ioctl`].
+    pub fn dispatch<T: IoctlHandler>(
+        &mut self,
+        handler: T::Target<'_>,
+        file: &File,
+    ) -> Result<i32> {
+        let dir = (self.cmd >> bindings::_IOC_DIRSHIFT) & bindings::_IOC_DIRMASK;
+        if dir == bindings::_IOC_NONE {
+            return T::pure(handler, file, self.cmd, self.arg);
+        }
+
+        let data = self.user_slice.take().ok_or(EINVAL)?;
+        const READ_WRITE: u32 = bindings::_IOC_READ | bindings::_IOC_WRITE;
+        match dir {
+            bindings::_IOC_WRITE => T::write(handler, file, self.cmd, &mut data.reader()),
+            bindings::_IOC_READ => T::read(handler, file, self.cmd, &mut data.writer()),
+            READ_WRITE => T::read_write(handler, file, self.cmd, data),
+            _ => Err(EINVAL),
+        }
+    }
+
+    /// Returns the raw 32-bit value of the command and the ptr-sized argument.
+    pub fn raw(&self) -> (u32, usize) {
+        (self.cmd, self.arg)
+    }
+}
+
+/// Trait for extracting file open arguments from kernel data structures.
+///
+/// This is meant to be implemented by registration managers.
+pub trait OpenAdapter<T: Sync> {
+    /// Converts untyped data stored in [`struct inode`] and [`struct file`] (when [`struct
+    /// file_operations::open`] is called) into the given type. For example, for `miscdev`
+    /// devices, a pointer to the registered [`struct miscdev`] is stored in [`struct
+    /// file::private_data`].
+    ///
+    /// # Safety
+    ///
+    /// This function must be called only when [`struct file_operations::open`] is being called for
+    /// a file that was registered by the implementer. The returned pointer must be valid and
+    /// not-null.
+    unsafe fn convert(_inode: *mut bindings::inode, _file: *mut bindings::file) -> *const T;
+}
+
+/// Corresponds to the kernel's `struct file_operations`.
+///
+/// You implement this trait whenever you would create a `struct file_operations`.
+///
+/// File descriptors may be used from multiple threads/processes concurrently, so your type must be
+/// [`Sync`]. It must also be [`Send`] because [`Operations::release`] will be called from the
+/// thread that decrements that associated file's refcount to zero.
+pub trait Operations {
+    /// The methods to use to populate [`struct file_operations`].
+    const TO_USE: ToUse;
+
+    /// The type of the context data returned by [`Operations::open`] and made available to
+    /// other methods.
+    type Data: PointerWrapper + Send + Sync = ();
+
+    /// The type of the context data passed to [`Operations::open`].
+    type OpenData: Sync = ();
+
+    /// Creates a new instance of this file.
+    ///
+    /// Corresponds to the `open` function pointer in `struct file_operations`.
+    fn open(context: &Self::OpenData, file: &File) -> Result<Self::Data>;
+
+    /// Cleans up after the last reference to the file goes away.
+    ///
+    /// Note that context data is moved, so it will be freed automatically unless the
+    /// implementation moves it elsewhere.
+    ///
+    /// Corresponds to the `release` function pointer in `struct file_operations`.
+    fn release(_data: Self::Data, _file: &File) {}
+
+    /// Reads data from this file to the caller's buffer.
+    ///
+    /// Corresponds to the `read` and `read_iter` function pointers in `struct file_operations`.
+    fn read(
+        _data: <Self::Data as PointerWrapper>::Borrowed<'_>,
+        _file: &File,
+        _writer: &mut impl IoBufferWriter,
+        _offset: u64,
+    ) -> Result<usize> {
+        Err(EINVAL)
+    }
+
+    /// Writes data from the caller's buffer to this file.
+    ///
+    /// Corresponds to the `write` and `write_iter` function pointers in `struct file_operations`.
+    fn write(
+        _data: <Self::Data as PointerWrapper>::Borrowed<'_>,
+        _file: &File,
+        _reader: &mut impl IoBufferReader,
+        _offset: u64,
+    ) -> Result<usize> {
+        Err(EINVAL)
+    }
+
+    /// Changes the position of the file.
+    ///
+    /// Corresponds to the `llseek` function pointer in `struct file_operations`.
+    fn seek(
+        _data: <Self::Data as PointerWrapper>::Borrowed<'_>,
+        _file: &File,
+        _offset: SeekFrom,
+    ) -> Result<u64> {
+        Err(EINVAL)
+    }
+
+    /// Performs IO control operations that are specific to the file.
+    ///
+    /// Corresponds to the `unlocked_ioctl` function pointer in `struct file_operations`.
+    fn ioctl(
+        _data: <Self::Data as PointerWrapper>::Borrowed<'_>,
+        _file: &File,
+        _cmd: &mut IoctlCommand,
+    ) -> Result<i32> {
+        Err(ENOTTY)
+    }
+
+    /// Performs 32-bit IO control operations on that are specific to the file on 64-bit kernels.
+    ///
+    /// Corresponds to the `compat_ioctl` function pointer in `struct file_operations`.
+    fn compat_ioctl(
+        _data: <Self::Data as PointerWrapper>::Borrowed<'_>,
+        _file: &File,
+        _cmd: &mut IoctlCommand,
+    ) -> Result<i32> {
+        Err(ENOTTY)
+    }
+
+    /// Syncs pending changes to this file.
+    ///
+    /// Corresponds to the `fsync` function pointer in `struct file_operations`.
+    fn fsync(
+        _data: <Self::Data as PointerWrapper>::Borrowed<'_>,
+        _file: &File,
+        _start: u64,
+        _end: u64,
+        _datasync: bool,
+    ) -> Result<u32> {
+        Err(EINVAL)
+    }
+
+    /// Maps areas of the caller's virtual memory with device/file memory.
+    ///
+    /// Corresponds to the `mmap` function pointer in `struct file_operations`.
+    fn mmap(
+        _data: <Self::Data as PointerWrapper>::Borrowed<'_>,
+        _file: &File,
+        _vma: &mut mm::virt::Area,
+    ) -> Result {
+        Err(EINVAL)
+    }
+
+    /// Checks the state of the file and optionally registers for notification when the state
+    /// changes.
+    ///
+    /// Corresponds to the `poll` function pointer in `struct file_operations`.
+    fn poll(
+        _data: <Self::Data as PointerWrapper>::Borrowed<'_>,
+        _file: &File,
+        _table: &PollTable,
+    ) -> Result<u32> {
+        Ok(bindings::POLLIN | bindings::POLLOUT | bindings::POLLRDNORM | bindings::POLLWRNORM)
+    }
+}
diff --git a/rust/kernel/gpio.rs b/rust/kernel/gpio.rs
new file mode 100644
index 000000000000..2e4365dfcf74
--- /dev/null
+++ b/rust/kernel/gpio.rs
@@ -0,0 +1,478 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Support for gpio device drivers.
+//!
+//! C header: [`include/linux/gpio/driver.h`](../../../../include/linux/gpio/driver.h)
+
+use crate::{
+    bindings, c_types, device, error::code::*, error::from_kernel_result, types::PointerWrapper,
+    Error, Result,
+};
+use core::{
+    cell::UnsafeCell,
+    marker::{PhantomData, PhantomPinned},
+    pin::Pin,
+};
+
+#[cfg(CONFIG_GPIOLIB_IRQCHIP)]
+pub use irqchip::{ChipWithIrqChip, RegistrationWithIrqChip};
+
+/// The direction of a gpio line.
+pub enum LineDirection {
+    /// Direction is input.
+    In = bindings::GPIO_LINE_DIRECTION_IN as _,
+
+    /// Direction is output.
+    Out = bindings::GPIO_LINE_DIRECTION_OUT as _,
+}
+
+/// A gpio chip.
+pub trait Chip {
+    /// Context data associated with the gpio chip.
+    ///
+    /// It determines the type of the context data passed to each of the methods of the trait.
+    type Data: PointerWrapper + Sync + Send;
+
+    /// The methods to use to populate [`struct gpio_chip`]. This is typically populated with
+    /// [`declare_gpio_chip_operations`].
+    const TO_USE: ToUse;
+
+    /// Returns the direction of the given gpio line.
+    fn get_direction(
+        _data: <Self::Data as PointerWrapper>::Borrowed<'_>,
+        _offset: u32,
+    ) -> Result<LineDirection> {
+        Err(ENOTSUPP)
+    }
+
+    /// Configures the direction as input of the given gpio line.
+    fn direction_input(
+        _data: <Self::Data as PointerWrapper>::Borrowed<'_>,
+        _offset: u32,
+    ) -> Result {
+        Err(EIO)
+    }
+
+    /// Configures the direction as output of the given gpio line.
+    ///
+    /// The value that will be initially output is also specified.
+    fn direction_output(
+        _data: <Self::Data as PointerWrapper>::Borrowed<'_>,
+        _offset: u32,
+        _value: bool,
+    ) -> Result {
+        Err(ENOTSUPP)
+    }
+
+    /// Returns the current value of the given gpio line.
+    fn get(_data: <Self::Data as PointerWrapper>::Borrowed<'_>, _offset: u32) -> Result<bool> {
+        Err(EIO)
+    }
+
+    /// Sets the value of the given gpio line.
+    fn set(_data: <Self::Data as PointerWrapper>::Borrowed<'_>, _offset: u32, _value: bool) {}
+}
+
+/// Represents which fields of [`struct gpio_chip`] should be populated with pointers.
+///
+/// This is typically populated with the [`declare_gpio_chip_operations`] macro.
+pub struct ToUse {
+    /// The `get_direction` field of [`struct gpio_chip`].
+    pub get_direction: bool,
+
+    /// The `direction_input` field of [`struct gpio_chip`].
+    pub direction_input: bool,
+
+    /// The `direction_output` field of [`struct gpio_chip`].
+    pub direction_output: bool,
+
+    /// The `get` field of [`struct gpio_chip`].
+    pub get: bool,
+
+    /// The `set` field of [`struct gpio_chip`].
+    pub set: bool,
+}
+
+/// A constant version where all values are set to `false`, that is, all supported fields will be
+/// set to null pointers.
+pub const USE_NONE: ToUse = ToUse {
+    get_direction: false,
+    direction_input: false,
+    direction_output: false,
+    get: false,
+    set: false,
+};
+
+/// Defines the [`Chip::TO_USE`] field based on a list of fields to be populated.
+#[macro_export]
+macro_rules! declare_gpio_chip_operations {
+    () => {
+        const TO_USE: $crate::gpio::ToUse = $crate::gpio::USE_NONE;
+    };
+    ($($i:ident),+) => {
+        #[allow(clippy::needless_update)]
+        const TO_USE: $crate::gpio::ToUse =
+            $crate::gpio::ToUse {
+                $($i: true),+ ,
+                ..$crate::gpio::USE_NONE
+            };
+    };
+}
+
+/// A registration of a gpio chip.
+pub struct Registration<T: Chip> {
+    gc: UnsafeCell<bindings::gpio_chip>,
+    parent: Option<device::Device>,
+    _p: PhantomData<T>,
+    _pin: PhantomPinned,
+}
+
+impl<T: Chip> Registration<T> {
+    /// Creates a new [`Registration`] but does not register it yet.
+    ///
+    /// It is allowed to move.
+    pub fn new() -> Self {
+        Self {
+            parent: None,
+            gc: UnsafeCell::new(bindings::gpio_chip::default()),
+            _pin: PhantomPinned,
+            _p: PhantomData,
+        }
+    }
+
+    /// Registers a gpio chip with the rest of the kernel.
+    pub fn register(
+        self: Pin<&mut Self>,
+        gpio_count: u16,
+        base: Option<i32>,
+        parent: &dyn device::RawDevice,
+        data: T::Data,
+    ) -> Result {
+        if self.parent.is_some() {
+            // Already registered.
+            return Err(EINVAL);
+        }
+
+        // SAFETY: We never move out of `this`.
+        let this = unsafe { self.get_unchecked_mut() };
+        {
+            let gc = this.gc.get_mut();
+
+            // Set up the callbacks.
+            gc.request = Some(bindings::gpiochip_generic_request);
+            gc.free = Some(bindings::gpiochip_generic_free);
+            if T::TO_USE.get_direction {
+                gc.get_direction = Some(get_direction_callback::<T>);
+            }
+            if T::TO_USE.direction_input {
+                gc.direction_input = Some(direction_input_callback::<T>);
+            }
+            if T::TO_USE.direction_output {
+                gc.direction_output = Some(direction_output_callback::<T>);
+            }
+            if T::TO_USE.get {
+                gc.get = Some(get_callback::<T>);
+            }
+            if T::TO_USE.set {
+                gc.set = Some(set_callback::<T>);
+            }
+
+            // When a base is not explicitly given, use -1 for one to be picked.
+            if let Some(b) = base {
+                gc.base = b;
+            } else {
+                gc.base = -1;
+            }
+
+            gc.ngpio = gpio_count;
+            gc.parent = parent.raw_device();
+            gc.label = parent.name().as_char_ptr();
+
+            // TODO: Define `gc.owner` as well.
+        }
+
+        let data_pointer = <T::Data as PointerWrapper>::into_pointer(data);
+        // SAFETY: `gc` was initilised above, so it is valid.
+        let ret = unsafe {
+            bindings::gpiochip_add_data_with_key(
+                this.gc.get(),
+                data_pointer as _,
+                core::ptr::null_mut(),
+                core::ptr::null_mut(),
+            )
+        };
+        if ret < 0 {
+            // SAFETY: `data_pointer` was returned by `into_pointer` above.
+            unsafe { T::Data::from_pointer(data_pointer) };
+            return Err(Error::from_kernel_errno(ret));
+        }
+
+        this.parent = Some(device::Device::from_dev(parent));
+        Ok(())
+    }
+}
+
+// SAFETY: `Registration` doesn't offer any methods or access to fields when shared between threads
+// or CPUs, so it is safe to share it.
+unsafe impl<T: Chip> Sync for Registration<T> {}
+
+// SAFETY: Registration with and unregistration from the gpio subsystem can happen from any thread.
+// Additionally, `T::Data` (which is dropped during unregistration) is `Send`, so it is ok to move
+// `Registration` to different threads.
+#[allow(clippy::non_send_fields_in_send_ty)]
+unsafe impl<T: Chip> Send for Registration<T> {}
+
+impl<T: Chip> Default for Registration<T> {
+    fn default() -> Self {
+        Self::new()
+    }
+}
+
+impl<T: Chip> Drop for Registration<T> {
+    /// Removes the registration from the kernel if it has completed successfully before.
+    fn drop(&mut self) {
+        if self.parent.is_some() {
+            // Get a pointer to the data stored in chip before destroying it.
+            // SAFETY: `gc` was during registration, which is guaranteed to have succeeded (because
+            // `parent` is `Some(_)`, so it remains valid.
+            let data_pointer = unsafe { bindings::gpiochip_get_data(self.gc.get()) };
+
+            // SAFETY: By the same argument above, `gc` is still valid.
+            unsafe { bindings::gpiochip_remove(self.gc.get()) };
+
+            // Free data as well.
+            // SAFETY: `data_pointer` was returned by `into_pointer` during registration.
+            unsafe { <T::Data as PointerWrapper>::from_pointer(data_pointer) };
+        }
+    }
+}
+
+unsafe extern "C" fn get_direction_callback<T: Chip>(
+    gc: *mut bindings::gpio_chip,
+    offset: c_types::c_uint,
+) -> c_types::c_int {
+    from_kernel_result! {
+        // SAFETY: The value stored as chip data was returned by `into_pointer` during registration.
+        let data = unsafe { T::Data::borrow(bindings::gpiochip_get_data(gc)) };
+        Ok(T::get_direction(data, offset)? as i32)
+    }
+}
+
+unsafe extern "C" fn direction_input_callback<T: Chip>(
+    gc: *mut bindings::gpio_chip,
+    offset: c_types::c_uint,
+) -> c_types::c_int {
+    from_kernel_result! {
+        // SAFETY: The value stored as chip data was returned by `into_pointer` during registration.
+        let data = unsafe { T::Data::borrow(bindings::gpiochip_get_data(gc)) };
+        T::direction_input(data, offset)?;
+        Ok(0)
+    }
+}
+
+unsafe extern "C" fn direction_output_callback<T: Chip>(
+    gc: *mut bindings::gpio_chip,
+    offset: c_types::c_uint,
+    value: c_types::c_int,
+) -> c_types::c_int {
+    from_kernel_result! {
+        // SAFETY: The value stored as chip data was returned by `into_pointer` during registration.
+        let data = unsafe { T::Data::borrow(bindings::gpiochip_get_data(gc)) };
+        T::direction_output(data, offset, value != 0)?;
+        Ok(0)
+    }
+}
+
+unsafe extern "C" fn get_callback<T: Chip>(
+    gc: *mut bindings::gpio_chip,
+    offset: c_types::c_uint,
+) -> c_types::c_int {
+    from_kernel_result! {
+        // SAFETY: The value stored as chip data was returned by `into_pointer` during registration.
+        let data = unsafe { T::Data::borrow(bindings::gpiochip_get_data(gc)) };
+        let v = T::get(data, offset)?;
+        Ok(v as _)
+    }
+}
+
+unsafe extern "C" fn set_callback<T: Chip>(
+    gc: *mut bindings::gpio_chip,
+    offset: c_types::c_uint,
+    value: c_types::c_int,
+) {
+    // SAFETY: The value stored as chip data was returned by `into_pointer` during registration.
+    let data = unsafe { T::Data::borrow(bindings::gpiochip_get_data(gc)) };
+    T::set(data, offset, value != 0);
+}
+
+#[cfg(CONFIG_GPIOLIB_IRQCHIP)]
+mod irqchip {
+    use super::*;
+    use crate::irq;
+
+    /// A gpio chip that includes an irq chip.
+    pub trait ChipWithIrqChip: Chip {
+        /// Implements the irq flow for the gpio chip.
+        fn handle_irq_flow(
+            _data: <Self::Data as PointerWrapper>::Borrowed<'_>,
+            _desc: &irq::Descriptor,
+            _domain: &irq::Domain,
+        );
+    }
+
+    /// A registration of a gpio chip that includes an irq chip.
+    pub struct RegistrationWithIrqChip<T: ChipWithIrqChip> {
+        reg: Registration<T>,
+        irq_chip: UnsafeCell<bindings::irq_chip>,
+        parent_irq: u32,
+    }
+
+    impl<T: ChipWithIrqChip> RegistrationWithIrqChip<T> {
+        /// Creates a new [`RegistrationWithIrqChip`] but does not register it yet.
+        ///
+        /// It is allowed to move.
+        pub fn new() -> Self {
+            Self {
+                reg: Registration::new(),
+                irq_chip: UnsafeCell::new(bindings::irq_chip::default()),
+                parent_irq: 0,
+            }
+        }
+
+        /// Registers a gpio chip and its irq chip with the rest of the kernel.
+        pub fn register<U: irq::Chip<Data = T::Data>>(
+            mut self: Pin<&mut Self>,
+            gpio_count: u16,
+            base: Option<i32>,
+            parent: &dyn device::RawDevice,
+            data: T::Data,
+            parent_irq: u32,
+        ) -> Result {
+            if self.reg.parent.is_some() {
+                // Already registered.
+                return Err(EINVAL);
+            }
+
+            // SAFETY: We never move out of `this`.
+            let this = unsafe { self.as_mut().get_unchecked_mut() };
+
+            // Initialise the irq_chip.
+            {
+                let irq_chip = this.irq_chip.get_mut();
+                irq_chip.name = parent.name().as_char_ptr();
+
+                // SAFETY: The gpio subsystem configures a pointer to `gpio_chip` as the irq chip
+                // data, so we use `IrqChipAdapter` to convert to the `T::Data`, which is the same
+                // as `irq::Chip::Data` per the bound above.
+                unsafe { irq::init_chip::<IrqChipAdapter<U>>(irq_chip) };
+            }
+
+            // Initialise gc irq state.
+            {
+                let girq = &mut this.reg.gc.get_mut().irq;
+                girq.chip = this.irq_chip.get();
+                // SAFETY: By leaving `parent_handler_data` set to `null`, the gpio subsystem
+                // initialises it to a pointer to the gpio chip, which is what `FlowHandler<T>`
+                // expects.
+                girq.parent_handler = unsafe { irq::new_flow_handler::<FlowHandler<T>>() };
+                girq.num_parents = 1;
+                girq.parents = &mut this.parent_irq;
+                this.parent_irq = parent_irq;
+                girq.default_type = bindings::IRQ_TYPE_NONE;
+                girq.handler = Some(bindings::handle_bad_irq);
+            }
+
+            // SAFETY: `reg` is pinned when `self` is.
+            let pinned = unsafe { self.map_unchecked_mut(|r| &mut r.reg) };
+            pinned.register(gpio_count, base, parent, data)
+        }
+    }
+
+    impl<T: ChipWithIrqChip> Default for RegistrationWithIrqChip<T> {
+        fn default() -> Self {
+            Self::new()
+        }
+    }
+
+    // SAFETY: `RegistrationWithIrqChip` doesn't offer any methods or access to fields when shared
+    // between threads or CPUs, so it is safe to share it.
+    unsafe impl<T: ChipWithIrqChip> Sync for RegistrationWithIrqChip<T> {}
+
+    // SAFETY: Registration with and unregistration from the gpio subsystem (including irq chips for
+    // them) can happen from any thread. Additionally, `T::Data` (which is dropped during
+    // unregistration) is `Send`, so it is ok to move `Registration` to different threads.
+    #[allow(clippy::non_send_fields_in_send_ty)]
+    unsafe impl<T: ChipWithIrqChip> Send for RegistrationWithIrqChip<T> where T::Data: Send {}
+
+    struct FlowHandler<T: ChipWithIrqChip>(PhantomData<T>);
+
+    impl<T: ChipWithIrqChip> irq::FlowHandler for FlowHandler<T> {
+        type Data = *mut bindings::gpio_chip;
+
+        fn handle_irq_flow(gc: *mut bindings::gpio_chip, desc: &irq::Descriptor) {
+            // SAFETY: `FlowHandler` is only used in gpio chips, and it is removed when the gpio is
+            // unregistered, so we know that `gc` must still be valid. We also know that the value
+            // stored as gpio data was returned by `T::Data::into_pointer` again because
+            // `FlowHandler` is a private structure only used in this way.
+            let data = unsafe { T::Data::borrow(bindings::gpiochip_get_data(gc)) };
+
+            // SAFETY: `gc` is valid (see comment above), so we can dereference it.
+            let domain = unsafe { irq::Domain::from_ptr((*gc).irq.domain) };
+
+            T::handle_irq_flow(data, desc, &domain);
+        }
+    }
+
+    /// Adapter from an irq chip with `gpio_chip` pointer as context to one where the gpio chip
+    /// data is passed as context.
+    struct IrqChipAdapter<T: irq::Chip>(PhantomData<T>);
+
+    impl<T: irq::Chip> irq::Chip for IrqChipAdapter<T> {
+        type Data = *mut bindings::gpio_chip;
+        const TO_USE: irq::ToUse = T::TO_USE;
+
+        fn ack(gc: *mut bindings::gpio_chip, irq_data: &irq::IrqData) {
+            // SAFETY: `IrqChipAdapter` is a private struct, only used when the data stored in the
+            // gpio chip is known to come from `T::Data`, and only valid while the gpio chip is
+            // registered, so `gc` is valid.
+            let data = unsafe { T::Data::borrow(bindings::gpiochip_get_data(gc as _)) };
+            T::ack(data, irq_data);
+        }
+
+        fn mask(gc: *mut bindings::gpio_chip, irq_data: &irq::IrqData) {
+            // SAFETY: `IrqChipAdapter` is a private struct, only used when the data stored in the
+            // gpio chip is known to come from `T::Data`, and only valid while the gpio chip is
+            // registered, so `gc` is valid.
+            let data = unsafe { T::Data::borrow(bindings::gpiochip_get_data(gc as _)) };
+            T::mask(data, irq_data);
+        }
+
+        fn unmask(gc: *mut bindings::gpio_chip, irq_data: &irq::IrqData) {
+            // SAFETY: `IrqChipAdapter` is a private struct, only used when the data stored in the
+            // gpio chip is known to come from `T::Data`, and only valid while the gpio chip is
+            // registered, so `gc` is valid.
+            let data = unsafe { T::Data::borrow(bindings::gpiochip_get_data(gc as _)) };
+            T::unmask(data, irq_data);
+        }
+
+        fn set_type(
+            gc: *mut bindings::gpio_chip,
+            irq_data: &mut irq::LockedIrqData,
+            flow_type: u32,
+        ) -> Result<irq::ExtraResult> {
+            // SAFETY: `IrqChipAdapter` is a private struct, only used when the data stored in the
+            // gpio chip is known to come from `T::Data`, and only valid while the gpio chip is
+            // registered, so `gc` is valid.
+            let data = unsafe { T::Data::borrow(bindings::gpiochip_get_data(gc as _)) };
+            T::set_type(data, irq_data, flow_type)
+        }
+
+        fn set_wake(gc: *mut bindings::gpio_chip, irq_data: &irq::IrqData, on: bool) -> Result {
+            // SAFETY: `IrqChipAdapter` is a private struct, only used when the data stored in the
+            // gpio chip is known to come from `T::Data`, and only valid while the gpio chip is
+            // registered, so `gc` is valid.
+            let data = unsafe { T::Data::borrow(bindings::gpiochip_get_data(gc as _)) };
+            T::set_wake(data, irq_data, on)
+        }
+    }
+}
diff --git a/rust/kernel/hwrng.rs b/rust/kernel/hwrng.rs
new file mode 100644
index 000000000000..a50de9510631
--- /dev/null
+++ b/rust/kernel/hwrng.rs
@@ -0,0 +1,242 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Hardware Random Number Generator.
+//!
+//! C header: [`include/linux/hw_random.h`](../../../../include/linux/hw_random.h)
+
+use alloc::{boxed::Box, slice::from_raw_parts_mut};
+
+use crate::{
+    bindings, c_types, error::code::*, error::from_kernel_result, str::CString, to_result,
+    types::PointerWrapper, Result, ScopeGuard,
+};
+
+use core::{cell::UnsafeCell, fmt, marker::PhantomData, pin::Pin};
+
+/// This trait is implemented in order to provide callbacks to `struct hwrng`.
+pub trait Operations {
+    /// The methods to use to populate [`struct hwrng`].
+    const TO_USE: ToUse;
+
+    /// The pointer type that will be used to hold user-defined data type.
+    type Data: PointerWrapper + Send + Sync = ();
+
+    /// Initialization callback, can be left undefined.
+    fn init(_data: <Self::Data as PointerWrapper>::Borrowed<'_>) -> Result {
+        Err(EINVAL)
+    }
+
+    /// Cleanup callback, can be left undefined.
+    fn cleanup(_data: Self::Data) {}
+
+    /// Read data into the provided buffer.
+    /// Drivers can fill up to max bytes of data into the buffer.
+    /// The buffer is aligned for any type and its size is a multiple of 4 and >= 32 bytes.
+    fn read(
+        data: <Self::Data as PointerWrapper>::Borrowed<'_>,
+        buffer: &mut [u8],
+        wait: bool,
+    ) -> Result<u32>;
+}
+
+/// Registration structure for Hardware Random Number Generator driver.
+pub struct Registration<T: Operations> {
+    hwrng: UnsafeCell<bindings::hwrng>,
+    name: Option<CString>,
+    registered: bool,
+    _p: PhantomData<T>,
+}
+
+impl<T: Operations> Registration<T> {
+    /// Creates new instance of registration.
+    ///
+    /// The data must be registered.
+    pub fn new() -> Self {
+        Self {
+            hwrng: UnsafeCell::new(bindings::hwrng::default()),
+            name: None,
+            registered: false,
+            _p: PhantomData,
+        }
+    }
+
+    /// Returns a registered and pinned, heap-allocated representation of the registration.
+    pub fn new_pinned(
+        name: fmt::Arguments<'_>,
+        quality: u16,
+        data: T::Data,
+    ) -> Result<Pin<Box<Self>>> {
+        let mut reg = Pin::from(Box::try_new(Self::new())?);
+        reg.as_mut().register(name, quality, data)?;
+        Ok(reg)
+    }
+
+    /// Registers a hwrng device within the rest of the kernel.
+    ///
+    /// It must be pinned because the memory block that represents
+    /// the registration may be self-referential.
+    pub fn register(
+        self: Pin<&mut Self>,
+        name: fmt::Arguments<'_>,
+        quality: u16,
+        data: T::Data,
+    ) -> Result {
+        // SAFETY: We never move out of `this`.
+        let this = unsafe { self.get_unchecked_mut() };
+
+        if this.registered {
+            return Err(EINVAL);
+        }
+
+        let data_pointer = data.into_pointer();
+
+        // SAFETY: `data_pointer` comes from the call to `data.into_pointer()` above.
+        let guard = ScopeGuard::new(|| unsafe {
+            T::Data::from_pointer(data_pointer);
+        });
+
+        let name = CString::try_from_fmt(name)?;
+
+        // SAFETY: Registration is pinned and contains allocated and set to zero `bindings::hwrng` structure.
+        Self::init_hwrng(
+            unsafe { &mut *this.hwrng.get() },
+            &name,
+            quality,
+            data_pointer,
+        );
+
+        // SAFETY: `bindings::hwrng` is initialized above which guarantees safety.
+        to_result(|| unsafe { bindings::hwrng_register(this.hwrng.get()) })?;
+
+        this.registered = true;
+        this.name = Some(name);
+        guard.dismiss();
+        Ok(())
+    }
+
+    fn init_hwrng(
+        hwrng: &mut bindings::hwrng,
+        name: &CString,
+        quality: u16,
+        data: *const c_types::c_void,
+    ) {
+        hwrng.name = name.as_char_ptr();
+
+        hwrng.init = if T::TO_USE.init {
+            Some(Self::init_callback)
+        } else {
+            None
+        };
+        hwrng.cleanup = if T::TO_USE.cleanup {
+            Some(Self::cleanup_callback)
+        } else {
+            None
+        };
+        hwrng.data_present = None;
+        hwrng.data_read = None;
+        hwrng.read = Some(Self::read_callback);
+
+        hwrng.priv_ = data as _;
+        hwrng.quality = quality;
+
+        // SAFETY: All fields are properly initialized as
+        // remaining fields `list`, `ref` and `cleanup_done` are already
+        // zeroed by `bindings::hwrng::default()` call.
+    }
+
+    unsafe extern "C" fn init_callback(rng: *mut bindings::hwrng) -> c_types::c_int {
+        from_kernel_result! {
+            // SAFETY: `priv` private data field was initialized during creation of
+            // the `bindings::hwrng` in `Self::init_hwrng` method. This callback is only
+            // called once the driver is registered.
+            let data = unsafe { T::Data::borrow((*rng).priv_ as *const _) };
+            T::init(data)?;
+            Ok(0)
+        }
+    }
+
+    unsafe extern "C" fn cleanup_callback(rng: *mut bindings::hwrng) {
+        // SAFETY: `priv` private data field was initialized during creation of
+        // the `bindings::hwrng` in `Self::init_hwrng` method. This callback is only
+        // called once the driver is registered.
+        let data = unsafe { T::Data::from_pointer((*rng).priv_ as *const _) };
+        T::cleanup(data);
+    }
+
+    unsafe extern "C" fn read_callback(
+        rng: *mut bindings::hwrng,
+        data: *mut c_types::c_void,
+        max: usize,
+        wait: bindings::bool_,
+    ) -> c_types::c_int {
+        from_kernel_result! {
+            // SAFETY: `priv` private data field was initialized during creation of
+            // the `bindings::hwrng` in `Self::init_hwrng` method. This callback is only
+            // called once the driver is registered.
+            let drv_data = unsafe { T::Data::borrow((*rng).priv_ as *const _) };
+
+            // SAFETY: Slice is created from `data` and `max` arguments that are C's buffer
+            // along with its size in bytes that are safe for this conversion.
+            let buffer = unsafe { from_raw_parts_mut(data as *mut u8, max) };
+            let ret = T::read(drv_data, buffer, wait)?;
+            Ok(ret as _)
+        }
+    }
+}
+
+impl<T: Operations> Default for Registration<T> {
+    fn default() -> Self {
+        Self::new()
+    }
+}
+
+/// Represents which callbacks of [`struct hwrng`] should be populated with pointers.
+pub struct ToUse {
+    /// The `init` field of [`struct hwrng`].
+    pub init: bool,
+
+    /// The `cleanup` field of [`struct hwrng`].
+    pub cleanup: bool,
+}
+
+/// A constant version where all values are to set to `false`, that is, all supported fields will
+/// be set to null pointers.
+pub const USE_NONE: ToUse = ToUse {
+    init: false,
+    cleanup: false,
+};
+
+/// Defines the [`Operations::TO_USE`] field based on a list of fields to be populated.
+#[macro_export]
+macro_rules! declare_hwrng_operations {
+    () => {
+        const TO_USE: $crate::hwrng::ToUse = $crate::hwrng::USE_NONE;
+    };
+    ($($i:ident),+) => {
+        #[allow(clippy::needless_update)]
+        const TO_USE: kernel::hwrng::ToUse =
+            $crate::hwrng::ToUse {
+                $($i: true),+ ,
+                ..$crate::hwrng::USE_NONE
+            };
+    };
+}
+
+// SAFETY: `Registration` does not expose any of its state across threads.
+unsafe impl<T: Operations> Sync for Registration<T> {}
+
+// SAFETY: `Registration` is not restricted to a single thread,
+// its `T::Data` is also `Send` so it may be moved to different threads.
+#[allow(clippy::non_send_fields_in_send_ty)]
+unsafe impl<T: Operations> Send for Registration<T> {}
+
+impl<T: Operations> Drop for Registration<T> {
+    /// Removes the registration from the kernel if it has completed successfully before.
+    fn drop(&mut self) {
+        // SAFETY: The instance of Registration<T> is unregistered only
+        // after being initialized and registered before.
+        if self.registered {
+            unsafe { bindings::hwrng_unregister(self.hwrng.get()) };
+        }
+    }
+}
diff --git a/rust/kernel/io_buffer.rs b/rust/kernel/io_buffer.rs
new file mode 100644
index 000000000000..ccecc4763aca
--- /dev/null
+++ b/rust/kernel/io_buffer.rs
@@ -0,0 +1,153 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Buffers used in IO.
+
+use crate::Result;
+use alloc::vec::Vec;
+use core::mem::{size_of, MaybeUninit};
+
+/// Represents a buffer to be read from during IO.
+pub trait IoBufferReader {
+    /// Returns the number of bytes left to be read from the io buffer.
+    ///
+    /// Note that even reading less than this number of bytes may fail.
+    fn len(&self) -> usize;
+
+    /// Returns `true` if no data is available in the io buffer.
+    fn is_empty(&self) -> bool {
+        self.len() == 0
+    }
+
+    /// Reads raw data from the io buffer into a raw kernel buffer.
+    ///
+    /// # Safety
+    ///
+    /// The output buffer must be valid.
+    unsafe fn read_raw(&mut self, out: *mut u8, len: usize) -> Result;
+
+    /// Reads all data remaining in the io buffer.
+    ///
+    /// Returns `EFAULT` if the address does not currently point to mapped, readable memory.
+    fn read_all(&mut self) -> Result<Vec<u8>> {
+        let mut data = Vec::<u8>::new();
+        data.try_resize(self.len(), 0)?;
+
+        // SAFETY: The output buffer is valid as we just allocated it.
+        unsafe { self.read_raw(data.as_mut_ptr(), data.len())? };
+        Ok(data)
+    }
+
+    /// Reads a byte slice from the io buffer.
+    ///
+    /// Returns `EFAULT` if the byte slice is bigger than the remaining size of the user slice or
+    /// if the address does not currently point to mapped, readable memory.
+    fn read_slice(&mut self, data: &mut [u8]) -> Result {
+        // SAFETY: The output buffer is valid as it's coming from a live reference.
+        unsafe { self.read_raw(data.as_mut_ptr(), data.len()) }
+    }
+
+    /// Reads the contents of a plain old data (POD) type from the io buffer.
+    fn read<T: ReadableFromBytes>(&mut self) -> Result<T> {
+        let mut out = MaybeUninit::<T>::uninit();
+        // SAFETY: The buffer is valid as it was just allocated.
+        unsafe { self.read_raw(out.as_mut_ptr() as _, size_of::<T>()) }?;
+        // SAFETY: We just initialised the data.
+        Ok(unsafe { out.assume_init() })
+    }
+}
+
+/// Represents a buffer to be written to during IO.
+pub trait IoBufferWriter {
+    /// Returns the number of bytes left to be written into the io buffer.
+    ///
+    /// Note that even writing less than this number of bytes may fail.
+    fn len(&self) -> usize;
+
+    /// Returns `true` if the io buffer cannot hold any additional data.
+    fn is_empty(&self) -> bool {
+        self.len() == 0
+    }
+
+    /// Writes zeroes to the io buffer.
+    ///
+    /// Differently from the other write functions, `clear` will zero as much as it can and update
+    /// the writer internal state to reflect this. It will, however, return an error if it cannot
+    /// clear `len` bytes.
+    ///
+    /// For example, if a caller requests that 100 bytes be cleared but a segfault happens after
+    /// 20 bytes, then EFAULT is returned and the writer is advanced by 20 bytes.
+    fn clear(&mut self, len: usize) -> Result;
+
+    /// Writes a byte slice into the io buffer.
+    ///
+    /// Returns `EFAULT` if the byte slice is bigger than the remaining size of the io buffer or if
+    /// the address does not currently point to mapped, writable memory.
+    fn write_slice(&mut self, data: &[u8]) -> Result {
+        // SAFETY: The input buffer is valid as it's coming from a live reference.
+        unsafe { self.write_raw(data.as_ptr(), data.len()) }
+    }
+
+    /// Writes raw data to the io buffer from a raw kernel buffer.
+    ///
+    /// # Safety
+    ///
+    /// The input buffer must be valid.
+    unsafe fn write_raw(&mut self, data: *const u8, len: usize) -> Result;
+
+    /// Writes the contents of the given data into the io buffer.
+    fn write<T: WritableToBytes>(&mut self, data: &T) -> Result {
+        // SAFETY: The input buffer is valid as it's coming from a live
+        // reference to a type that implements `WritableToBytes`.
+        unsafe { self.write_raw(data as *const T as _, size_of::<T>()) }
+    }
+}
+
+/// Specifies that a type is safely readable from byte slices.
+///
+/// Not all types can be safely read from byte slices; examples from
+/// <https://doc.rust-lang.org/reference/behavior-considered-undefined.html> include `bool`
+/// that must be either `0` or `1`, and `char` that cannot be a surrogate or above `char::MAX`.
+///
+/// # Safety
+///
+/// Implementers must ensure that the type is made up only of types that can be safely read from
+/// arbitrary byte sequences (e.g., `u32`, `u64`, etc.).
+pub unsafe trait ReadableFromBytes {}
+
+// SAFETY: All bit patterns are acceptable values of the types below.
+unsafe impl ReadableFromBytes for u8 {}
+unsafe impl ReadableFromBytes for u16 {}
+unsafe impl ReadableFromBytes for u32 {}
+unsafe impl ReadableFromBytes for u64 {}
+unsafe impl ReadableFromBytes for usize {}
+unsafe impl ReadableFromBytes for i8 {}
+unsafe impl ReadableFromBytes for i16 {}
+unsafe impl ReadableFromBytes for i32 {}
+unsafe impl ReadableFromBytes for i64 {}
+unsafe impl ReadableFromBytes for isize {}
+
+/// Specifies that a type is safely writable to byte slices.
+///
+/// This means that we don't read undefined values (which leads to UB) in preparation for writing
+/// to the byte slice. It also ensures that no potentially sensitive information is leaked into the
+/// byte slices.
+///
+/// # Safety
+///
+/// A type must not include padding bytes and must be fully initialised to safely implement
+/// [`WritableToBytes`] (i.e., it doesn't contain [`MaybeUninit`] fields). A composition of
+/// writable types in a structure is not necessarily writable because it may result in padding
+/// bytes.
+pub unsafe trait WritableToBytes {}
+
+// SAFETY: Initialised instances of the following types have no uninitialised portions.
+unsafe impl WritableToBytes for u8 {}
+unsafe impl WritableToBytes for u16 {}
+unsafe impl WritableToBytes for u32 {}
+unsafe impl WritableToBytes for u64 {}
+unsafe impl WritableToBytes for usize {}
+unsafe impl WritableToBytes for i8 {}
+unsafe impl WritableToBytes for i16 {}
+unsafe impl WritableToBytes for i32 {}
+unsafe impl WritableToBytes for i64 {}
+unsafe impl WritableToBytes for isize {}
diff --git a/rust/kernel/io_mem.rs b/rust/kernel/io_mem.rs
new file mode 100644
index 000000000000..19df48d8e2f8
--- /dev/null
+++ b/rust/kernel/io_mem.rs
@@ -0,0 +1,237 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Memory-mapped IO.
+//!
+//! C header: [`include/asm-generic/io.h`](../../../../include/asm-generic/io.h)
+
+#![allow(dead_code)]
+
+use crate::{bindings, error::code::*, Result};
+use core::convert::TryInto;
+
+/// Represents a memory resource.
+pub struct Resource {
+    offset: bindings::resource_size_t,
+    size: bindings::resource_size_t,
+}
+
+impl Resource {
+    pub(crate) fn new(
+        start: bindings::resource_size_t,
+        end: bindings::resource_size_t,
+    ) -> Option<Self> {
+        if start == 0 {
+            return None;
+        }
+        Some(Self {
+            offset: start,
+            size: end.checked_sub(start)?.checked_add(1)?,
+        })
+    }
+}
+
+/// Represents a memory block of at least `SIZE` bytes.
+///
+/// # Invariants
+///
+/// `ptr` is a non-null and valid address of at least `SIZE` bytes and returned by an `ioremap`
+/// variant. `ptr` is also 8-byte aligned.
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::prelude::*;
+/// use kernel::io_mem::{IoMem, Resource};
+///
+/// fn test(res: Resource) -> Result {
+///     // Create an io mem block of at least 100 bytes.
+///     // SAFETY: No DMA operations are initiated through `mem`.
+///     let mem = unsafe { IoMem::<100>::try_new(res) }?;
+///
+///     // Read one byte from offset 10.
+///     let v = mem.readb(10);
+///
+///     // Write value to offset 20.
+///     mem.writeb(v, 20);
+///
+///     Ok(())
+/// }
+///
+/// ```
+pub struct IoMem<const SIZE: usize> {
+    ptr: usize,
+}
+
+macro_rules! define_read {
+    ($(#[$attr:meta])* $name:ident, $try_name:ident, $type_name:ty) => {
+        /// Reads IO data from the given offset known, at compile time.
+        ///
+        /// If the offset is not known at compile time, the build will fail.
+        $(#[$attr])*
+        pub fn $name(&self, offset: usize) -> $type_name {
+            Self::check_offset::<$type_name>(offset);
+            let ptr = self.ptr.wrapping_add(offset);
+            // SAFETY: The type invariants guarantee that `ptr` is a valid pointer. The check above
+            // guarantees that the code won't build if `offset` makes the read go out of bounds
+            // (including the type size).
+            unsafe { bindings::$name(ptr as _) }
+        }
+
+        /// Reads IO data from the given offset.
+        ///
+        /// It fails if/when the offset (plus the type size) is out of bounds.
+        $(#[$attr])*
+        pub fn $try_name(&self, offset: usize) -> Result<$type_name> {
+            if !Self::offset_ok::<$type_name>(offset) {
+                return Err(EINVAL);
+            }
+            let ptr = self.ptr.wrapping_add(offset);
+            // SAFETY: The type invariants guarantee that `ptr` is a valid pointer. The check above
+            // returns an error if `offset` would make the read go out of bounds (including the
+            // type size).
+            Ok(unsafe { bindings::$name(ptr as _) })
+        }
+    };
+}
+
+macro_rules! define_write {
+    ($(#[$attr:meta])* $name:ident, $try_name:ident, $type_name:ty) => {
+        /// Writes IO data to the given offset, known at compile time.
+        ///
+        /// If the offset is not known at compile time, the build will fail.
+        $(#[$attr])*
+        pub fn $name(&self, value: $type_name, offset: usize) {
+            Self::check_offset::<$type_name>(offset);
+            let ptr = self.ptr.wrapping_add(offset);
+            // SAFETY: The type invariants guarantee that `ptr` is a valid pointer. The check above
+            // guarantees that the code won't link if `offset` makes the write go out of bounds
+            // (including the type size).
+            unsafe { bindings::$name(value, ptr as _) }
+        }
+
+        /// Writes IO data to the given offset.
+        ///
+        /// It fails if/when the offset (plus the type size) is out of bounds.
+        $(#[$attr])*
+        pub fn $try_name(&self, value: $type_name, offset: usize) -> Result {
+            if !Self::offset_ok::<$type_name>(offset) {
+                return Err(EINVAL);
+            }
+            let ptr = self.ptr.wrapping_add(offset);
+            // SAFETY: The type invariants guarantee that `ptr` is a valid pointer. The check above
+            // returns an error if `offset` would make the write go out of bounds (including the
+            // type size).
+            unsafe { bindings::$name(value, ptr as _) };
+            Ok(())
+        }
+    };
+}
+
+impl<const SIZE: usize> IoMem<SIZE> {
+    /// Tries to create a new instance of a memory block.
+    ///
+    /// The resource described by `res` is mapped into the CPU's address space so that it can be
+    /// accessed directly. It is also consumed by this function so that it can't be mapped again
+    /// to a different address.
+    ///
+    /// # Safety
+    ///
+    /// Callers must ensure that either (a) the resulting interface cannot be used to initiate DMA
+    /// operations, or (b) that DMA operations initiated via the returned interface use DMA handles
+    /// allocated through the `dma` module.
+    pub unsafe fn try_new(res: Resource) -> Result<Self> {
+        // Check that the resource has at least `SIZE` bytes in it.
+        if res.size < SIZE.try_into()? {
+            return Err(EINVAL);
+        }
+
+        // To be able to check pointers at compile time based only on offsets, we need to guarantee
+        // that the base pointer is minimally aligned. So we conservatively expect at least 8 bytes.
+        if res.offset % 8 != 0 {
+            crate::pr_err!("Physical address is not 64-bit aligned: {:x}", res.offset);
+            return Err(EDOM);
+        }
+
+        // Try to map the resource.
+        // SAFETY: Just mapping the memory range.
+        let addr = unsafe { bindings::ioremap(res.offset, res.size as _) };
+        if addr.is_null() {
+            Err(ENOMEM)
+        } else {
+            // INVARIANT: `addr` is non-null and was returned by `ioremap`, so it is valid. It is
+            // also 8-byte aligned because we checked it above.
+            Ok(Self { ptr: addr as usize })
+        }
+    }
+
+    const fn offset_ok<T>(offset: usize) -> bool {
+        let type_size = core::mem::size_of::<T>();
+        if let Some(end) = offset.checked_add(type_size) {
+            end <= SIZE && offset % type_size == 0
+        } else {
+            false
+        }
+    }
+
+    fn offset_ok_of_val<T: ?Sized>(offset: usize, value: &T) -> bool {
+        let value_size = core::mem::size_of_val(value);
+        let value_alignment = core::mem::align_of_val(value);
+        if let Some(end) = offset.checked_add(value_size) {
+            end <= SIZE && offset % value_alignment == 0
+        } else {
+            false
+        }
+    }
+
+    const fn check_offset<T>(offset: usize) {
+        crate::build_assert!(Self::offset_ok::<T>(offset), "IoMem offset overflow");
+    }
+
+    define_read!(readb, try_readb, u8);
+    define_read!(readw, try_readw, u16);
+    define_read!(readl, try_readl, u32);
+    define_read!(
+        #[cfg(CONFIG_64BIT)]
+        readq,
+        try_readq,
+        u64
+    );
+
+    define_read!(readb_relaxed, try_readb_relaxed, u8);
+    define_read!(readw_relaxed, try_readw_relaxed, u16);
+    define_read!(readl_relaxed, try_readl_relaxed, u32);
+    define_read!(
+        #[cfg(CONFIG_64BIT)]
+        readq_relaxed,
+        try_readq_relaxed,
+        u64
+    );
+
+    define_write!(writeb, try_writeb, u8);
+    define_write!(writew, try_writew, u16);
+    define_write!(writel, try_writel, u32);
+    define_write!(
+        #[cfg(CONFIG_64BIT)]
+        writeq,
+        try_writeq,
+        u64
+    );
+
+    define_write!(writeb_relaxed, try_writeb_relaxed, u8);
+    define_write!(writew_relaxed, try_writew_relaxed, u16);
+    define_write!(writel_relaxed, try_writel_relaxed, u32);
+    define_write!(
+        #[cfg(CONFIG_64BIT)]
+        writeq_relaxed,
+        try_writeq_relaxed,
+        u64
+    );
+}
+
+impl<const SIZE: usize> Drop for IoMem<SIZE> {
+    fn drop(&mut self) {
+        // SAFETY: By the type invariant, `self.ptr` is a value returned by a previous successful
+        // call to `ioremap`.
+        unsafe { bindings::iounmap(self.ptr as _) };
+    }
+}
diff --git a/rust/kernel/iov_iter.rs b/rust/kernel/iov_iter.rs
new file mode 100644
index 000000000000..b9b8dc882bd0
--- /dev/null
+++ b/rust/kernel/iov_iter.rs
@@ -0,0 +1,81 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! IO vector iterators.
+//!
+//! C header: [`include/linux/uio.h`](../../../../include/linux/uio.h)
+
+use crate::{
+    bindings,
+    error::code::*,
+    io_buffer::{IoBufferReader, IoBufferWriter},
+    Result,
+};
+
+/// Wraps the kernel's `struct iov_iter`.
+///
+/// # Invariants
+///
+/// The pointer `IovIter::ptr` is non-null and valid.
+pub struct IovIter {
+    ptr: *mut bindings::iov_iter,
+}
+
+impl IovIter {
+    fn common_len(&self) -> usize {
+        // SAFETY: `IovIter::ptr` is guaranteed to be valid by the type invariants.
+        unsafe { (*self.ptr).count }
+    }
+
+    /// Constructs a new [`struct iov_iter`] wrapper.
+    ///
+    /// # Safety
+    ///
+    /// The pointer `ptr` must be non-null and valid for the lifetime of the object.
+    pub(crate) unsafe fn from_ptr(ptr: *mut bindings::iov_iter) -> Self {
+        // INVARIANTS: the safety contract ensures the type invariant will hold.
+        Self { ptr }
+    }
+}
+
+impl IoBufferWriter for IovIter {
+    fn len(&self) -> usize {
+        self.common_len()
+    }
+
+    fn clear(&mut self, mut len: usize) -> Result {
+        while len > 0 {
+            // SAFETY: `IovIter::ptr` is guaranteed to be valid by the type invariants.
+            let written = unsafe { bindings::iov_iter_zero(len, self.ptr) };
+            if written == 0 {
+                return Err(EFAULT);
+            }
+
+            len -= written;
+        }
+        Ok(())
+    }
+
+    unsafe fn write_raw(&mut self, data: *const u8, len: usize) -> Result {
+        let res = unsafe { bindings::copy_to_iter(data as _, len, self.ptr) };
+        if res != len {
+            Err(EFAULT)
+        } else {
+            Ok(())
+        }
+    }
+}
+
+impl IoBufferReader for IovIter {
+    fn len(&self) -> usize {
+        self.common_len()
+    }
+
+    unsafe fn read_raw(&mut self, out: *mut u8, len: usize) -> Result {
+        let res = unsafe { bindings::copy_from_iter(out as _, len, self.ptr) };
+        if res != len {
+            Err(EFAULT)
+        } else {
+            Ok(())
+        }
+    }
+}
diff --git a/rust/kernel/irq.rs b/rust/kernel/irq.rs
new file mode 100644
index 000000000000..ca62849a5dc0
--- /dev/null
+++ b/rust/kernel/irq.rs
@@ -0,0 +1,409 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Interrupts and interrupt chips.
+//!
+//! See <https://www.kernel.org/doc/Documentation/core-api/genericirq.rst>.
+//!
+//! C headers: [`include/linux/irq.h`](../../../../include/linux/irq.h) and
+//! [`include/linux/interrupt.h`](../../../../include/linux/interrupt.h).
+
+#![allow(dead_code)]
+
+use crate::{bindings, c_types, error::from_kernel_result, types::PointerWrapper, Error, Result};
+use core::ops::Deref;
+
+/// The type of irq hardware numbers.
+pub type HwNumber = bindings::irq_hw_number_t;
+
+/// Wraps the kernel's `struct irq_data`.
+///
+/// # Invariants
+///
+/// The pointer `IrqData::ptr` is non-null and valid.
+pub struct IrqData {
+    ptr: *mut bindings::irq_data,
+}
+
+impl IrqData {
+    /// Creates a new `IrqData` instance from a raw pointer.
+    ///
+    /// # Safety
+    ///
+    /// Callers must ensure that `ptr` is non-null and valid when the function is called, and that
+    /// it remains valid for the lifetime of the return [`IrqData`] instance.
+    unsafe fn from_ptr(ptr: *mut bindings::irq_data) -> Self {
+        // INVARIANTS: By the safety requirements, the instance we're creating satisfies the type
+        // invariants.
+        Self { ptr }
+    }
+
+    /// Returns the hardware irq number.
+    pub fn hwirq(&self) -> HwNumber {
+        // SAFETY: By the type invariants, it's ok to dereference `ptr`.
+        unsafe { (*self.ptr).hwirq }
+    }
+}
+
+/// Wraps the kernel's `struct irq_data` when it is locked.
+///
+/// Being locked allows additional operations to be performed on the data.
+pub struct LockedIrqData(IrqData);
+
+impl LockedIrqData {
+    /// Sets the high-level irq flow handler to the builtin one for level-triggered irqs.
+    pub fn set_level_handler(&mut self) {
+        // SAFETY: By the type invariants of `self.0`, we know `self.0.ptr` is valid.
+        unsafe { bindings::irq_set_handler_locked(self.0.ptr, Some(bindings::handle_level_irq)) };
+    }
+
+    /// Sets the high-level irq flow handler to the builtin one for edge-triggered irqs.
+    pub fn set_edge_handler(&mut self) {
+        // SAFETY: By the type invariants of `self.0`, we know `self.0.ptr` is valid.
+        unsafe { bindings::irq_set_handler_locked(self.0.ptr, Some(bindings::handle_edge_irq)) };
+    }
+
+    /// Sets the high-level irq flow handler to the builtin one for bad irqs.
+    pub fn set_bad_handler(&mut self) {
+        // SAFETY: By the type invariants of `self.0`, we know `self.0.ptr` is valid.
+        unsafe { bindings::irq_set_handler_locked(self.0.ptr, Some(bindings::handle_bad_irq)) };
+    }
+}
+
+impl Deref for LockedIrqData {
+    type Target = IrqData;
+
+    fn deref(&self) -> &Self::Target {
+        &self.0
+    }
+}
+
+/// Extra information returned by some of the [`Chip`] methods on success.
+pub enum ExtraResult {
+    /// Indicates that the caller (irq core) will update the descriptor state.
+    None = bindings::IRQ_SET_MASK_OK as _,
+
+    /// Indicates that the callee (irq chip implementation) already updated the descriptor state.
+    NoCopy = bindings::IRQ_SET_MASK_OK_NOCOPY as _,
+
+    /// Same as [`ExtraResult::None`] in terms of updating descriptor state. It is used in stacked
+    /// irq chips to indicate that descendant chips should be skipped.
+    Done = bindings::IRQ_SET_MASK_OK_DONE as _,
+}
+
+/// An irq chip.
+///
+/// It is a trait for the functions defined in [`struct irq_chip`].
+///
+/// [`struct irq_chip`]: ../../../include/linux/irq.h
+pub trait Chip: Sized {
+    /// The type of the context data stored in the irq chip and made available on each callback.
+    type Data: PointerWrapper;
+
+    /// The methods to use to populate [`struct irq_chip`]. This is typically populated with
+    /// [`declare_irq_chip_operations`].
+    const TO_USE: ToUse;
+
+    /// Called at the start of a new interrupt.
+    fn ack(data: <Self::Data as PointerWrapper>::Borrowed<'_>, irq_data: &IrqData);
+
+    /// Masks an interrupt source.
+    fn mask(data: <Self::Data as PointerWrapper>::Borrowed<'_>, irq_data: &IrqData);
+
+    /// Unmasks an interrupt source.
+    fn unmask(_data: <Self::Data as PointerWrapper>::Borrowed<'_>, irq_data: &IrqData);
+
+    /// Sets the flow type of an interrupt.
+    ///
+    /// The flow type is a combination of the constants in [`Type`].
+    fn set_type(
+        _data: <Self::Data as PointerWrapper>::Borrowed<'_>,
+        _irq_data: &mut LockedIrqData,
+        _flow_type: u32,
+    ) -> Result<ExtraResult> {
+        Ok(ExtraResult::None)
+    }
+
+    /// Enables or disables power-management wake-on of an interrupt.
+    fn set_wake(
+        _data: <Self::Data as PointerWrapper>::Borrowed<'_>,
+        _irq_data: &IrqData,
+        _on: bool,
+    ) -> Result {
+        Ok(())
+    }
+}
+
+/// Initialises `chip` with the callbacks defined in `T`.
+///
+/// # Safety
+///
+/// The caller must ensure that the value stored in the irq chip data is the result of calling
+/// [`PointerWrapper::into_pointer] for the [`T::Data`] type.
+pub(crate) unsafe fn init_chip<T: Chip>(chip: &mut bindings::irq_chip) {
+    chip.irq_ack = Some(irq_ack_callback::<T>);
+    chip.irq_mask = Some(irq_mask_callback::<T>);
+    chip.irq_unmask = Some(irq_unmask_callback::<T>);
+
+    if T::TO_USE.set_type {
+        chip.irq_set_type = Some(irq_set_type_callback::<T>);
+    }
+
+    if T::TO_USE.set_wake {
+        chip.irq_set_wake = Some(irq_set_wake_callback::<T>);
+    }
+}
+
+/// Represents which fields of [`struct irq_chip`] should be populated with pointers.
+///
+/// This is typically populated with the [`declare_irq_chip_operations`] macro.
+pub struct ToUse {
+    /// The `irq_set_type` field of [`struct irq_chip`].
+    pub set_type: bool,
+
+    /// The `irq_set_wake` field of [`struct irq_chip`].
+    pub set_wake: bool,
+}
+
+/// A constant version where all values are to set to `false`, that is, all supported fields will
+/// be set to null pointers.
+pub const USE_NONE: ToUse = ToUse {
+    set_type: false,
+    set_wake: false,
+};
+
+/// Defines the [`Chip::TO_USE`] field based on a list of fields to be populated.
+#[macro_export]
+macro_rules! declare_irq_chip_operations {
+    () => {
+        const TO_USE: $crate::irq::ToUse = $crate::irq::USE_NONE;
+    };
+    ($($i:ident),+) => {
+        #[allow(clippy::needless_update)]
+        const TO_USE: $crate::irq::ToUse =
+            $crate::irq::ToUse {
+                $($i: true),+ ,
+                ..$crate::irq::USE_NONE
+            };
+    };
+}
+
+/// Enables or disables power-management wake-on for the given irq number.
+pub fn set_wake(irq: u32, on: bool) -> Result {
+    // SAFETY: Just an FFI call, there are no extra requirements for safety.
+    let ret = unsafe { bindings::irq_set_irq_wake(irq, on as _) };
+    if ret < 0 {
+        Err(Error::from_kernel_errno(ret))
+    } else {
+        Ok(())
+    }
+}
+
+unsafe extern "C" fn irq_ack_callback<T: Chip>(irq_data: *mut bindings::irq_data) {
+    // SAFETY: The safety requirements of `init_chip`, which is the only place that uses this
+    // callback, ensure that the value stored as irq chip data comes from a previous call to
+    // `PointerWrapper::into_pointer`.
+    let data = unsafe { T::Data::borrow(bindings::irq_data_get_irq_chip_data(irq_data)) };
+
+    // SAFETY: The value returned by `IrqData` is only valid until the end of this function, and
+    // `irq_data` is guaranteed to be valid until then (by the contract with C code).
+    T::ack(data, unsafe { &IrqData::from_ptr(irq_data) })
+}
+
+unsafe extern "C" fn irq_mask_callback<T: Chip>(irq_data: *mut bindings::irq_data) {
+    // SAFETY: The safety requirements of `init_chip`, which is the only place that uses this
+    // callback, ensure that the value stored as irq chip data comes from a previous call to
+    // `PointerWrapper::into_pointer`.
+    let data = unsafe { T::Data::borrow(bindings::irq_data_get_irq_chip_data(irq_data)) };
+
+    // SAFETY: The value returned by `IrqData` is only valid until the end of this function, and
+    // `irq_data` is guaranteed to be valid until then (by the contract with C code).
+    T::mask(data, unsafe { &IrqData::from_ptr(irq_data) })
+}
+
+unsafe extern "C" fn irq_unmask_callback<T: Chip>(irq_data: *mut bindings::irq_data) {
+    // SAFETY: The safety requirements of `init_chip`, which is the only place that uses this
+    // callback, ensure that the value stored as irq chip data comes from a previous call to
+    // `PointerWrapper::into_pointer`.
+    let data = unsafe { T::Data::borrow(bindings::irq_data_get_irq_chip_data(irq_data)) };
+
+    // SAFETY: The value returned by `IrqData` is only valid until the end of this function, and
+    // `irq_data` is guaranteed to be valid until then (by the contract with C code).
+    T::unmask(data, unsafe { &IrqData::from_ptr(irq_data) })
+}
+
+unsafe extern "C" fn irq_set_type_callback<T: Chip>(
+    irq_data: *mut bindings::irq_data,
+    flow_type: c_types::c_uint,
+) -> c_types::c_int {
+    from_kernel_result! {
+        // SAFETY: The safety requirements of `init_chip`, which is the only place that uses this
+        // callback, ensure that the value stored as irq chip data comes from a previous call to
+        // `PointerWrapper::into_pointer`.
+        let data = unsafe { T::Data::borrow(bindings::irq_data_get_irq_chip_data(irq_data)) };
+
+        // SAFETY: The value returned by `IrqData` is only valid until the end of this function, and
+        // `irq_data` is guaranteed to be valid until then (by the contract with C code).
+        let ret = T::set_type(data, &mut LockedIrqData(unsafe { IrqData::from_ptr(irq_data) }), flow_type)?;
+        Ok(ret as _)
+    }
+}
+
+unsafe extern "C" fn irq_set_wake_callback<T: Chip>(
+    irq_data: *mut bindings::irq_data,
+    on: c_types::c_uint,
+) -> c_types::c_int {
+    from_kernel_result! {
+        // SAFETY: The safety requirements of `init_chip`, which is the only place that uses this
+        // callback, ensure that the value stored as irq chip data comes from a previous call to
+        // `PointerWrapper::into_pointer`.
+        let data = unsafe { T::Data::borrow(bindings::irq_data_get_irq_chip_data(irq_data)) };
+
+        // SAFETY: The value returned by `IrqData` is only valid until the end of this function, and
+        // `irq_data` is guaranteed to be valid until then (by the contract with C code).
+        T::set_wake(data, unsafe { &IrqData::from_ptr(irq_data) }, on != 0)?;
+        Ok(0)
+    }
+}
+
+/// Contains constants that describes how an interrupt can be triggered.
+///
+/// It is tagged with `non_exhaustive` to prevent users from instantiating it.
+#[non_exhaustive]
+pub struct Type;
+
+impl Type {
+    /// The interrupt cannot be triggered.
+    pub const NONE: u32 = bindings::IRQ_TYPE_NONE;
+
+    /// The interrupt is triggered when the signal goes from low to high.
+    pub const EDGE_RISING: u32 = bindings::IRQ_TYPE_EDGE_RISING;
+
+    /// The interrupt is triggered when the signal goes from high to low.
+    pub const EDGE_FALLING: u32 = bindings::IRQ_TYPE_EDGE_FALLING;
+
+    /// The interrupt is triggered when the signal goes from low to high and when it goes to high
+    /// to low.
+    pub const EDGE_BOTH: u32 = bindings::IRQ_TYPE_EDGE_BOTH;
+
+    /// The interrupt is triggered while the signal is held high.
+    pub const LEVEL_HIGH: u32 = bindings::IRQ_TYPE_LEVEL_HIGH;
+
+    /// The interrupt is triggered while the signal is held low.
+    pub const LEVEL_LOW: u32 = bindings::IRQ_TYPE_LEVEL_LOW;
+}
+
+/// Wraps the kernel's `struct irq_desc`.
+///
+/// # Invariants
+///
+/// The pointer `Descriptor::ptr` is non-null and valid.
+pub struct Descriptor {
+    pub(crate) ptr: *mut bindings::irq_desc,
+}
+
+impl Descriptor {
+    /// Constructs a new `struct irq_desc` wrapper.
+    ///
+    /// # Safety
+    ///
+    /// The pointer `ptr` must be non-null and valid for the lifetime of the returned object.
+    unsafe fn from_ptr(ptr: *mut bindings::irq_desc) -> Self {
+        // INVARIANT: The safety requirements ensure the invariant.
+        Self { ptr }
+    }
+
+    /// Calls `chained_irq_enter` and returns a guard that calls `chained_irq_exit` once dropped.
+    ///
+    /// It is meant to be used by chained irq handlers to dispatch irqs to the next handlers.
+    pub fn enter_chained(&self) -> ChainedGuard<'_> {
+        // SAFETY: By the type invariants, `ptr` is always non-null and valid.
+        let irq_chip = unsafe { bindings::irq_desc_get_chip(self.ptr) };
+
+        // SAFETY: By the type invariants, `ptr` is always non-null and valid. `irq_chip` was just
+        // returned from `ptr`, so it is still valid too.
+        unsafe { bindings::chained_irq_enter(irq_chip, self.ptr) };
+        ChainedGuard {
+            desc: self,
+            irq_chip,
+        }
+    }
+}
+
+/// A guard to call `chained_irq_exit` after `chained_irq_enter` was called.
+///
+/// It is also used as evidence that a previous `chained_irq_enter` was called. So there are no
+/// public constructors and it is only created after indeed calling `chained_irq_enter`.
+pub struct ChainedGuard<'a> {
+    desc: &'a Descriptor,
+    irq_chip: *mut bindings::irq_chip,
+}
+
+impl Drop for ChainedGuard<'_> {
+    fn drop(&mut self) {
+        // SAFETY: The lifetime of `ChainedGuard` guarantees that `self.desc` remains valid, so it
+        // also guarantess `irq_chip` (which was returned from it) and `self.desc.ptr` (guaranteed
+        // by the type invariants).
+        unsafe { bindings::chained_irq_exit(self.irq_chip, self.desc.ptr) };
+    }
+}
+
+/// Wraps the kernel's `struct irq_domain`.
+///
+/// # Invariants
+///
+/// The pointer `Domain::ptr` is non-null and valid.
+pub struct Domain {
+    ptr: *mut bindings::irq_domain,
+}
+
+impl Domain {
+    /// Constructs a new `struct irq_domain` wrapper.
+    ///
+    /// # Safety
+    ///
+    /// The pointer `ptr` must be non-null and valid for the lifetime of the returned object.
+    pub(crate) unsafe fn from_ptr(ptr: *mut bindings::irq_domain) -> Self {
+        // INVARIANT: The safety requirements ensure the invariant.
+        Self { ptr }
+    }
+
+    /// Invokes the chained handler of the given hw irq of the given domain.
+    ///
+    /// It requires evidence that `chained_irq_enter` was called, which is done by passing a
+    /// `ChainedGuard` instance.
+    pub fn generic_handle_chained(&self, hwirq: u32, _guard: &ChainedGuard<'_>) {
+        // SAFETY: `ptr` is valid by the type invariants.
+        unsafe { bindings::generic_handle_domain_irq(self.ptr, hwirq) };
+    }
+}
+
+/// A high-level irq flow handler.
+pub trait FlowHandler {
+    /// The data associated with the handler.
+    type Data: PointerWrapper;
+
+    /// Implements the irq flow for the given descriptor.
+    fn handle_irq_flow(data: <Self::Data as PointerWrapper>::Borrowed<'_>, desc: &Descriptor);
+}
+
+/// Returns the raw irq flow handler corresponding to the (high-level) one defined in `T`.
+///
+/// # Safety
+///
+/// The caller must ensure that the value stored in the irq handler data (as returned by
+/// `irq_desc_get_handler_data`) is the result of calling [`PointerWrapper::into_pointer] for the
+/// [`T::Data`] type.
+pub(crate) unsafe fn new_flow_handler<T: FlowHandler>() -> bindings::irq_flow_handler_t {
+    Some(irq_flow_handler::<T>)
+}
+
+unsafe extern "C" fn irq_flow_handler<T: FlowHandler>(desc: *mut bindings::irq_desc) {
+    // SAFETY: By the safety requirements of `new_flow_handler`, we know that the value returned by
+    // `irq_desc_get_handler_data` comes from calling `T::Data::into_pointer`. `desc` is valid by
+    // the C API contract.
+    let data = unsafe { T::Data::borrow(bindings::irq_desc_get_handler_data(desc)) };
+
+    // SAFETY: The C API guarantees that `desc` is valid for the duration of this call, which
+    // outlives the lifetime returned by `from_desc`.
+    T::handle_irq_flow(data, &unsafe { Descriptor::from_ptr(desc) });
+}
diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs
new file mode 100644
index 000000000000..269c552ecda0
--- /dev/null
+++ b/rust/kernel/lib.rs
@@ -0,0 +1,260 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! The `kernel` crate.
+//!
+//! This crate contains the kernel APIs that have been ported or wrapped for
+//! usage by Rust code in the kernel and is shared by all of them.
+//!
+//! In other words, all the rest of the Rust code in the kernel (e.g. kernel
+//! modules written in Rust) depends on [`core`], [`alloc`] and this crate.
+//!
+//! If you need a kernel C API that is not ported or wrapped yet here, then
+//! do so first instead of bypassing this crate.
+
+#![no_std]
+#![feature(allocator_api)]
+#![feature(associated_type_defaults)]
+#![feature(concat_idents)]
+#![feature(const_fn_trait_bound)]
+#![feature(const_mut_refs)]
+#![feature(const_ptr_offset_from)]
+#![feature(const_refs_to_cell)]
+#![feature(const_trait_impl)]
+#![feature(doc_cfg)]
+#![feature(generic_associated_types)]
+#![feature(maybe_uninit_extra)]
+#![feature(ptr_metadata)]
+#![feature(receiver_trait)]
+#![feature(coerce_unsized)]
+#![feature(dispatch_from_dyn)]
+#![feature(unsize)]
+
+// Ensure conditional compilation based on the kernel configuration works;
+// otherwise we may silently break things like initcall handling.
+#[cfg(not(CONFIG_RUST))]
+compile_error!("Missing kernel configuration for conditional compilation");
+
+#[cfg(not(test))]
+#[cfg(not(testlib))]
+mod allocator;
+
+#[doc(hidden)]
+pub mod bindings;
+
+#[cfg(CONFIG_ARM_AMBA)]
+pub mod amba;
+pub mod c_types;
+pub mod chrdev;
+#[cfg(CONFIG_COMMON_CLK)]
+pub mod clk;
+pub mod cred;
+pub mod device;
+pub mod driver;
+pub mod error;
+pub mod file;
+pub mod gpio;
+pub mod hwrng;
+pub mod irq;
+pub mod miscdev;
+pub mod mm;
+pub mod pages;
+pub mod power;
+pub mod revocable;
+pub mod security;
+pub mod str;
+pub mod task;
+
+pub mod linked_list;
+mod raw_list;
+pub mod rbtree;
+
+#[doc(hidden)]
+pub mod module_param;
+
+mod build_assert;
+pub mod prelude;
+pub mod print;
+pub mod random;
+mod static_assert;
+#[doc(hidden)]
+pub mod std_vendor;
+pub mod sync;
+
+#[cfg(any(CONFIG_SYSCTL, doc))]
+#[doc(cfg(CONFIG_SYSCTL))]
+pub mod sysctl;
+
+pub mod io_buffer;
+pub mod io_mem;
+pub mod iov_iter;
+pub mod of;
+pub mod platform;
+mod types;
+pub mod user_ptr;
+
+#[doc(hidden)]
+pub use build_error::build_error;
+
+pub use crate::error::{to_result, Error, Result};
+pub use crate::types::{bit, bits_iter, Bool, False, Mode, Opaque, ScopeGuard, True};
+
+use core::marker::PhantomData;
+
+/// Page size defined in terms of the `PAGE_SHIFT` macro from C.
+///
+/// [`PAGE_SHIFT`]: ../../../include/asm-generic/page.h
+pub const PAGE_SIZE: usize = 1 << bindings::PAGE_SHIFT;
+
+/// Prefix to appear before log messages printed from within the kernel crate.
+const __LOG_PREFIX: &[u8] = b"rust_kernel\0";
+
+/// The top level entrypoint to implementing a kernel module.
+///
+/// For any teardown or cleanup operations, your type may implement [`Drop`].
+pub trait KernelModule: Sized + Sync {
+    /// Called at module initialization time.
+    ///
+    /// Use this method to perform whatever setup or registration your module
+    /// should do.
+    ///
+    /// Equivalent to the `module_init` macro in the C API.
+    fn init(name: &'static str::CStr, module: &'static ThisModule) -> Result<Self>;
+}
+
+/// Equivalent to `THIS_MODULE` in the C API.
+///
+/// C header: `include/linux/export.h`
+pub struct ThisModule(*mut bindings::module);
+
+// SAFETY: `THIS_MODULE` may be used from all threads within a module.
+unsafe impl Sync for ThisModule {}
+
+impl ThisModule {
+    /// Creates a [`ThisModule`] given the `THIS_MODULE` pointer.
+    ///
+    /// # Safety
+    ///
+    /// The pointer must be equal to the right `THIS_MODULE`.
+    pub const unsafe fn from_ptr(ptr: *mut bindings::module) -> ThisModule {
+        ThisModule(ptr)
+    }
+
+    /// Locks the module parameters to access them.
+    ///
+    /// Returns a [`KParamGuard`] that will release the lock when dropped.
+    pub fn kernel_param_lock(&self) -> KParamGuard<'_> {
+        // SAFETY: `kernel_param_lock` will check if the pointer is null and
+        // use the built-in mutex in that case.
+        #[cfg(CONFIG_SYSFS)]
+        unsafe {
+            bindings::kernel_param_lock(self.0)
+        }
+
+        KParamGuard {
+            #[cfg(CONFIG_SYSFS)]
+            this_module: self,
+            phantom: PhantomData,
+        }
+    }
+}
+
+/// Scoped lock on the kernel parameters of [`ThisModule`].
+///
+/// Lock will be released when this struct is dropped.
+pub struct KParamGuard<'a> {
+    #[cfg(CONFIG_SYSFS)]
+    this_module: &'a ThisModule,
+    phantom: PhantomData<&'a ()>,
+}
+
+#[cfg(CONFIG_SYSFS)]
+impl<'a> Drop for KParamGuard<'a> {
+    fn drop(&mut self) {
+        // SAFETY: `kernel_param_lock` will check if the pointer is null and
+        // use the built-in mutex in that case. The existance of `self`
+        // guarantees that the lock is held.
+        unsafe { bindings::kernel_param_unlock(self.this_module.0) }
+    }
+}
+
+/// Calculates the offset of a field from the beginning of the struct it belongs to.
+///
+/// # Example
+///
+/// ```
+/// # use kernel::prelude::*;
+/// # use kernel::offset_of;
+/// struct Test {
+///     a: u64,
+///     b: u32,
+/// }
+///
+/// fn test() {
+///     // This prints `8`.
+///     pr_info!("{}\n", offset_of!(Test, b));
+/// }
+/// ```
+#[macro_export]
+macro_rules! offset_of {
+    ($type:ty, $($f:tt)*) => {{
+        let tmp = core::mem::MaybeUninit::<$type>::uninit();
+        let outer = tmp.as_ptr();
+        // To avoid warnings when nesting `unsafe` blocks.
+        #[allow(unused_unsafe)]
+        // SAFETY: The pointer is valid and aligned, just not initialised; `addr_of` ensures that
+        // we don't actually read from `outer` (which would be UB) nor create an intermediate
+        // reference.
+        let inner = unsafe { core::ptr::addr_of!((*outer).$($f)*) } as *const u8;
+        // To avoid warnings when nesting `unsafe` blocks.
+        #[allow(unused_unsafe)]
+        // SAFETY: The two pointers are within the same allocation block.
+        unsafe { inner.offset_from(outer as *const u8) }
+    }}
+}
+
+/// Produces a pointer to an object from a pointer to one of its fields.
+///
+/// # Safety
+///
+/// Callers must ensure that the pointer to the field is in fact a pointer to the specified field,
+/// as opposed to a pointer to another object of the same type. If this condition is not met,
+/// any dereference of the resulting pointer is UB.
+///
+/// # Example
+///
+/// ```
+/// # use kernel::prelude::*;
+/// # use kernel::container_of;
+/// struct Test {
+///     a: u64,
+///     b: u32,
+/// }
+///
+/// fn test() {
+///     let test = Test { a: 10, b: 20 };
+///     let b_ptr = &test.b;
+///     let test_alias = container_of!(b_ptr, Test, b);
+///     // This prints `true`.
+///     pr_info!("{}\n", core::ptr::eq(&test, test_alias));
+/// }
+/// ```
+#[macro_export]
+macro_rules! container_of {
+    ($ptr:expr, $type:ty, $($f:tt)*) => {{
+        let ptr = $ptr as *const _ as *const u8;
+        let offset = $crate::offset_of!($type, $($f)*);
+        ptr.wrapping_offset(-offset) as *const $type
+    }}
+}
+
+#[cfg(not(any(testlib, test)))]
+#[panic_handler]
+fn panic(info: &core::panic::PanicInfo<'_>) -> ! {
+    pr_emerg!("{}\n", info);
+    // SAFETY: FFI call.
+    unsafe { bindings::BUG() };
+    // Bindgen currently does not recognize `__noreturn` so `BUG` returns `()`
+    // instead of `!`.
+    // https://github.com/rust-lang/rust-bindgen/issues/2094
+    loop {}
+}
diff --git a/rust/kernel/linked_list.rs b/rust/kernel/linked_list.rs
new file mode 100644
index 000000000000..3330edcc7ca8
--- /dev/null
+++ b/rust/kernel/linked_list.rs
@@ -0,0 +1,247 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Linked lists.
+//!
+//! TODO: This module is a work in progress.
+
+use alloc::boxed::Box;
+use core::ptr::NonNull;
+
+pub use crate::raw_list::{Cursor, GetLinks, Links};
+use crate::{raw_list, raw_list::RawList, sync::Ref};
+
+// TODO: Use the one from `kernel::file_operations::PointerWrapper` instead.
+/// Wraps an object to be inserted in a linked list.
+pub trait Wrapper<T: ?Sized> {
+    /// Converts the wrapped object into a pointer that represents it.
+    fn into_pointer(self) -> NonNull<T>;
+
+    /// Converts the object back from the pointer representation.
+    ///
+    /// # Safety
+    ///
+    /// The passed pointer must come from a previous call to [`Wrapper::into_pointer()`].
+    unsafe fn from_pointer(ptr: NonNull<T>) -> Self;
+
+    /// Returns a reference to the wrapped object.
+    fn as_ref(&self) -> &T;
+}
+
+impl<T: ?Sized> Wrapper<T> for Box<T> {
+    fn into_pointer(self) -> NonNull<T> {
+        NonNull::new(Box::into_raw(self)).unwrap()
+    }
+
+    unsafe fn from_pointer(ptr: NonNull<T>) -> Self {
+        unsafe { Box::from_raw(ptr.as_ptr()) }
+    }
+
+    fn as_ref(&self) -> &T {
+        AsRef::as_ref(self)
+    }
+}
+
+impl<T: ?Sized> Wrapper<T> for Ref<T> {
+    fn into_pointer(self) -> NonNull<T> {
+        NonNull::new(Ref::into_raw(self) as _).unwrap()
+    }
+
+    unsafe fn from_pointer(ptr: NonNull<T>) -> Self {
+        // SAFETY: The safety requirements of `from_pointer` satisfy the ones from `Ref::from_raw`.
+        unsafe { Ref::from_raw(ptr.as_ptr() as _) }
+    }
+
+    fn as_ref(&self) -> &T {
+        AsRef::as_ref(self)
+    }
+}
+
+impl<T: ?Sized> Wrapper<T> for &T {
+    fn into_pointer(self) -> NonNull<T> {
+        NonNull::from(self)
+    }
+
+    unsafe fn from_pointer(ptr: NonNull<T>) -> Self {
+        unsafe { &*ptr.as_ptr() }
+    }
+
+    fn as_ref(&self) -> &T {
+        self
+    }
+}
+
+/// A descriptor of wrapped list elements.
+pub trait GetLinksWrapped: GetLinks {
+    /// Specifies which wrapper (e.g., `Box` and `Arc`) wraps the list entries.
+    type Wrapped: Wrapper<Self::EntryType>;
+}
+
+impl<T: ?Sized> GetLinksWrapped for Box<T>
+where
+    Box<T>: GetLinks,
+{
+    type Wrapped = Box<<Box<T> as GetLinks>::EntryType>;
+}
+
+impl<T: GetLinks + ?Sized> GetLinks for Box<T> {
+    type EntryType = T::EntryType;
+    fn get_links(data: &Self::EntryType) -> &Links<Self::EntryType> {
+        <T as GetLinks>::get_links(data)
+    }
+}
+
+impl<T: ?Sized> GetLinksWrapped for Ref<T>
+where
+    Ref<T>: GetLinks,
+{
+    type Wrapped = Ref<<Ref<T> as GetLinks>::EntryType>;
+}
+
+impl<T: GetLinks + ?Sized> GetLinks for Ref<T> {
+    type EntryType = T::EntryType;
+
+    fn get_links(data: &Self::EntryType) -> &Links<Self::EntryType> {
+        <T as GetLinks>::get_links(data)
+    }
+}
+
+/// A linked list.
+///
+/// Elements in the list are wrapped and ownership is transferred to the list while the element is
+/// in the list.
+pub struct List<G: GetLinksWrapped> {
+    list: RawList<G>,
+}
+
+impl<G: GetLinksWrapped> List<G> {
+    /// Constructs a new empty linked list.
+    pub fn new() -> Self {
+        Self {
+            list: RawList::new(),
+        }
+    }
+
+    /// Returns whether the list is empty.
+    pub fn is_empty(&self) -> bool {
+        self.list.is_empty()
+    }
+
+    /// Adds the given object to the end (back) of the list.
+    ///
+    /// It is dropped if it's already on this (or another) list; this can happen for
+    /// reference-counted objects, so dropping means decrementing the reference count.
+    pub fn push_back(&mut self, data: G::Wrapped) {
+        let ptr = data.into_pointer();
+
+        // SAFETY: We took ownership of the entry, so it is safe to insert it.
+        if !unsafe { self.list.push_back(ptr.as_ref()) } {
+            // If insertion failed, rebuild object so that it can be freed.
+            // SAFETY: We just called `into_pointer` above.
+            unsafe { G::Wrapped::from_pointer(ptr) };
+        }
+    }
+
+    /// Inserts the given object after `existing`.
+    ///
+    /// It is dropped if it's already on this (or another) list; this can happen for
+    /// reference-counted objects, so dropping means decrementing the reference count.
+    ///
+    /// # Safety
+    ///
+    /// Callers must ensure that `existing` points to a valid entry that is on the list.
+    pub unsafe fn insert_after(&mut self, existing: NonNull<G::EntryType>, data: G::Wrapped) {
+        let ptr = data.into_pointer();
+        let entry = unsafe { &*existing.as_ptr() };
+        if unsafe { !self.list.insert_after(entry, ptr.as_ref()) } {
+            // If insertion failed, rebuild object so that it can be freed.
+            unsafe { G::Wrapped::from_pointer(ptr) };
+        }
+    }
+
+    /// Removes the given entry.
+    ///
+    /// # Safety
+    ///
+    /// Callers must ensure that `data` is either on this list or in no list. It being on another
+    /// list leads to memory unsafety.
+    pub unsafe fn remove(&mut self, data: &G::Wrapped) -> Option<G::Wrapped> {
+        let entry_ref = Wrapper::as_ref(data);
+        if unsafe { self.list.remove(entry_ref) } {
+            Some(unsafe { G::Wrapped::from_pointer(NonNull::from(entry_ref)) })
+        } else {
+            None
+        }
+    }
+
+    /// Removes the element currently at the front of the list and returns it.
+    ///
+    /// Returns `None` if the list is empty.
+    pub fn pop_front(&mut self) -> Option<G::Wrapped> {
+        let front = self.list.pop_front()?;
+        // SAFETY: Elements on the list were inserted after a call to `into_pointer `.
+        Some(unsafe { G::Wrapped::from_pointer(front) })
+    }
+
+    /// Returns a cursor starting on the first (front) element of the list.
+    pub fn cursor_front(&self) -> Cursor<'_, G> {
+        self.list.cursor_front()
+    }
+
+    /// Returns a mutable cursor starting on the first (front) element of the list.
+    pub fn cursor_front_mut(&mut self) -> CursorMut<'_, G> {
+        CursorMut::new(self.list.cursor_front_mut())
+    }
+}
+
+impl<G: GetLinksWrapped> Default for List<G> {
+    fn default() -> Self {
+        Self::new()
+    }
+}
+
+impl<G: GetLinksWrapped> Drop for List<G> {
+    fn drop(&mut self) {
+        while self.pop_front().is_some() {}
+    }
+}
+
+/// A list cursor that allows traversing a linked list and inspecting & mutating elements.
+pub struct CursorMut<'a, G: GetLinksWrapped> {
+    cursor: raw_list::CursorMut<'a, G>,
+}
+
+impl<'a, G: GetLinksWrapped> CursorMut<'a, G> {
+    fn new(cursor: raw_list::CursorMut<'a, G>) -> Self {
+        Self { cursor }
+    }
+
+    /// Returns the element the cursor is currently positioned on.
+    pub fn current(&mut self) -> Option<&mut G::EntryType> {
+        self.cursor.current()
+    }
+
+    /// Removes the element the cursor is currently positioned on.
+    ///
+    /// After removal, it advances the cursor to the next element.
+    pub fn remove_current(&mut self) -> Option<G::Wrapped> {
+        let ptr = self.cursor.remove_current()?;
+
+        // SAFETY: Elements on the list were inserted after a call to `into_pointer `.
+        Some(unsafe { G::Wrapped::from_pointer(ptr) })
+    }
+
+    /// Returns the element immediately after the one the cursor is positioned on.
+    pub fn peek_next(&mut self) -> Option<&mut G::EntryType> {
+        self.cursor.peek_next()
+    }
+
+    /// Returns the element immediately before the one the cursor is positioned on.
+    pub fn peek_prev(&mut self) -> Option<&mut G::EntryType> {
+        self.cursor.peek_prev()
+    }
+
+    /// Moves the cursor to the next element.
+    pub fn move_next(&mut self) {
+        self.cursor.move_next();
+    }
+}
diff --git a/rust/kernel/miscdev.rs b/rust/kernel/miscdev.rs
new file mode 100644
index 000000000000..e1a2401031cf
--- /dev/null
+++ b/rust/kernel/miscdev.rs
@@ -0,0 +1,291 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Miscellaneous devices.
+//!
+//! C header: [`include/linux/miscdevice.h`](../../../../include/linux/miscdevice.h)
+//!
+//! Reference: <https://www.kernel.org/doc/html/latest/driver-api/misc_devices.html>
+
+use crate::bindings;
+use crate::error::{code::*, Error, Result};
+use crate::file;
+use crate::{device, str::CStr, str::CString, KernelModule, ThisModule};
+use alloc::boxed::Box;
+use core::marker::PhantomPinned;
+use core::{fmt, mem::MaybeUninit, pin::Pin};
+
+/// Options which can be used to configure how a misc device is registered.
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::{c_str, device::RawDevice, file, miscdev, prelude::*};
+/// pub fn example(
+///     reg: Pin<&mut miscdev::Registration<impl file::Operations<OpenData = ()>>>,
+///     parent: &dyn RawDevice,
+/// ) -> Result {
+///     miscdev::Options::new()
+///         .mode(0o600)
+///         .minor(10)
+///         .parent(parent)
+///         .register(reg, fmt!("sample"), ())
+/// }
+/// ```
+#[derive(Default)]
+pub struct Options<'a> {
+    minor: Option<i32>,
+    mode: Option<u16>,
+    parent: Option<&'a dyn device::RawDevice>,
+}
+
+impl<'a> Options<'a> {
+    /// Creates new [`Options`] instance with the required fields.
+    pub const fn new() -> Self {
+        Self {
+            minor: None,
+            mode: None,
+            parent: None,
+        }
+    }
+
+    /// Sets the minor device number.
+    pub const fn minor(&mut self, v: i32) -> &mut Self {
+        self.minor = Some(v);
+        self
+    }
+
+    /// Sets the device mode.
+    ///
+    /// This is usually an octal number and describes who can perform read/write/execute operations
+    /// on the device.
+    pub const fn mode(&mut self, m: u16) -> &mut Self {
+        self.mode = Some(m);
+        self
+    }
+
+    /// Sets the device parent.
+    pub const fn parent(&mut self, p: &'a dyn device::RawDevice) -> &mut Self {
+        self.parent = Some(p);
+        self
+    }
+
+    /// Registers a misc device using the configured options.
+    pub fn register<T: file::Operations>(
+        &self,
+        reg: Pin<&mut Registration<T>>,
+        name: fmt::Arguments<'_>,
+        open_data: T::OpenData,
+    ) -> Result {
+        reg.register_with_options(name, open_data, self)
+    }
+
+    /// Allocates a new registration of a misc device and completes the registration with the
+    /// configured options.
+    pub fn register_new<T: file::Operations>(
+        &self,
+        name: fmt::Arguments<'_>,
+        open_data: T::OpenData,
+    ) -> Result<Pin<Box<Registration<T>>>> {
+        let mut r = Pin::from(Box::try_new(Registration::new())?);
+        self.register(r.as_mut(), name, open_data)?;
+        Ok(r)
+    }
+}
+
+/// A registration of a miscellaneous device.
+///
+/// # Invariants
+///
+/// `Context` is always initialised when `registered` is `true`, and not initialised otherwise.
+pub struct Registration<T: file::Operations> {
+    registered: bool,
+    mdev: bindings::miscdevice,
+    name: Option<CString>,
+    _pin: PhantomPinned,
+
+    /// Context initialised on construction and made available to all file instances on
+    /// [`file::Operations::open`].
+    open_data: MaybeUninit<T::OpenData>,
+}
+
+impl<T: file::Operations> Registration<T> {
+    /// Creates a new [`Registration`] but does not register it yet.
+    ///
+    /// It is allowed to move.
+    pub fn new() -> Self {
+        // INVARIANT: `registered` is `false` and `open_data` is not initialised.
+        Self {
+            registered: false,
+            mdev: bindings::miscdevice::default(),
+            name: None,
+            _pin: PhantomPinned,
+            open_data: MaybeUninit::uninit(),
+        }
+    }
+
+    /// Registers a miscellaneous device.
+    ///
+    /// Returns a pinned heap-allocated representation of the registration.
+    pub fn new_pinned(name: fmt::Arguments<'_>, open_data: T::OpenData) -> Result<Pin<Box<Self>>> {
+        Options::new().register_new(name, open_data)
+    }
+
+    /// Registers a miscellaneous device with the rest of the kernel.
+    ///
+    /// It must be pinned because the memory block that represents the registration is
+    /// self-referential.
+    pub fn register(
+        self: Pin<&mut Self>,
+        name: fmt::Arguments<'_>,
+        open_data: T::OpenData,
+    ) -> Result {
+        Options::new().register(self, name, open_data)
+    }
+
+    /// Registers a miscellaneous device with the rest of the kernel. Additional optional settings
+    /// are provided via the `opts` parameter.
+    ///
+    /// It must be pinned because the memory block that represents the registration is
+    /// self-referential.
+    pub fn register_with_options(
+        self: Pin<&mut Self>,
+        name: fmt::Arguments<'_>,
+        open_data: T::OpenData,
+        opts: &Options<'_>,
+    ) -> Result {
+        // SAFETY: We must ensure that we never move out of `this`.
+        let this = unsafe { self.get_unchecked_mut() };
+        if this.registered {
+            // Already registered.
+            return Err(EINVAL);
+        }
+
+        let name = CString::try_from_fmt(name)?;
+
+        // SAFETY: The adapter is compatible with `misc_register`.
+        this.mdev.fops = unsafe { file::OperationsVtable::<Self, T>::build() };
+        this.mdev.name = name.as_char_ptr();
+        this.mdev.minor = opts.minor.unwrap_or(bindings::MISC_DYNAMIC_MINOR as i32);
+        this.mdev.mode = opts.mode.unwrap_or(0);
+        this.mdev.parent = opts
+            .parent
+            .map_or(core::ptr::null_mut(), |p| p.raw_device());
+
+        // We write to `open_data` here because as soon as `misc_register` succeeds, the file can be
+        // opened, so we need `open_data` configured ahead of time.
+        //
+        // INVARIANT: `registered` is set to `true`, but `open_data` is also initialised.
+        this.registered = true;
+        this.open_data.write(open_data);
+
+        let ret = unsafe { bindings::misc_register(&mut this.mdev) };
+        if ret < 0 {
+            // INVARIANT: `registered` is set back to `false` and the `open_data` is destructued.
+            this.registered = false;
+            // SAFETY: `open_data` was initialised a few lines above.
+            unsafe { this.open_data.assume_init_drop() };
+            return Err(Error::from_kernel_errno(ret));
+        }
+
+        this.name = Some(name);
+
+        Ok(())
+    }
+}
+
+impl<T: file::Operations> Default for Registration<T> {
+    fn default() -> Self {
+        Self::new()
+    }
+}
+
+impl<T: file::Operations> file::OpenAdapter<T::OpenData> for Registration<T> {
+    unsafe fn convert(
+        _inode: *mut bindings::inode,
+        file: *mut bindings::file,
+    ) -> *const T::OpenData {
+        // SAFETY: The caller must guarantee that `file` is valid.
+        let reg = crate::container_of!(unsafe { (*file).private_data }, Self, mdev);
+
+        // SAFETY: This function is only called while the misc device is still registered, so the
+        // registration must be valid. Additionally, the type invariants guarantee that while the
+        // miscdev is registered, `open_data` is initialised.
+        unsafe { (*reg).open_data.as_ptr() }
+    }
+}
+
+// SAFETY: The only method is `register()`, which requires a (pinned) mutable `Registration`, so it
+// is safe to pass `&Registration` to multiple threads because it offers no interior mutability.
+unsafe impl<T: file::Operations> Sync for Registration<T> {}
+
+// SAFETY: All functions work from any thread. So as long as the `Registration::open_data` is
+// `Send`, so is `Registration<T>`.
+unsafe impl<T: file::Operations> Send for Registration<T> where T::OpenData: Send {}
+
+impl<T: file::Operations> Drop for Registration<T> {
+    /// Removes the registration from the kernel if it has completed successfully before.
+    fn drop(&mut self) {
+        if self.registered {
+            // SAFETY: `registered` being `true` indicates that a previous call to  `misc_register`
+            // succeeded.
+            unsafe { bindings::misc_deregister(&mut self.mdev) };
+
+            // SAFETY: The type invariant guarantees that `open_data` is initialised when
+            // `registered` is `true`.
+            unsafe { self.open_data.assume_init_drop() };
+        }
+    }
+}
+
+/// Kernel module that exposes a single miscdev device implemented by `T`.
+pub struct Module<T: file::Operations<OpenData = ()>> {
+    _dev: Pin<Box<Registration<T>>>,
+}
+
+impl<T: file::Operations<OpenData = ()>> KernelModule for Module<T> {
+    fn init(name: &'static CStr, _module: &'static ThisModule) -> Result<Self> {
+        Ok(Self {
+            _dev: Registration::new_pinned(crate::fmt!("{name}"), ())?,
+        })
+    }
+}
+
+/// Declares a kernel module that exposes a single misc device.
+///
+/// The `type` argument should be a type which implements the [`FileOpener`] trait. Also accepts
+/// various forms of kernel metadata.
+///
+/// C header: [`include/linux/moduleparam.h`](../../../include/linux/moduleparam.h)
+///
+/// [`FileOpener`]: ../kernel/file_operations/trait.FileOpener.html
+///
+/// # Examples
+///
+/// ```ignore
+/// use kernel::prelude::*;
+///
+/// module_misc_device! {
+///     type: MyFile,
+///     name: b"my_miscdev_kernel_module",
+///     author: b"Rust for Linux Contributors",
+///     description: b"My very own misc device kernel module!",
+///     license: b"GPL v2",
+/// }
+///
+/// #[derive(Default)]
+/// struct MyFile;
+///
+/// impl kernel::file::Operations for MyFile {
+///     kernel::declare_file_operations!();
+/// }
+/// ```
+#[macro_export]
+macro_rules! module_misc_device {
+    (type: $type:ty, $($f:tt)*) => {
+        type ModuleType = kernel::miscdev::Module<$type>;
+        module! {
+            type: ModuleType,
+            $($f)*
+        }
+    }
+}
diff --git a/rust/kernel/mm.rs b/rust/kernel/mm.rs
new file mode 100644
index 000000000000..322f94f501e0
--- /dev/null
+++ b/rust/kernel/mm.rs
@@ -0,0 +1,149 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Memory management.
+//!
+//! C header: [`include/linux/mm.h`](../../../../include/linux/mm.h)
+
+use crate::{bindings, pages, to_result, Result};
+
+/// Virtual memory.
+pub mod virt {
+    use super::*;
+
+    /// A wrapper for the kernel's `struct vm_area_struct`.
+    ///
+    /// It represents an area of virtual memory.
+    ///
+    /// # Invariants
+    ///
+    /// `vma` is always non-null and valid.
+    pub struct Area {
+        vma: *mut bindings::vm_area_struct,
+    }
+
+    impl Area {
+        /// Creates a new instance of a virtual memory area.
+        ///
+        /// # Safety
+        ///
+        /// Callers must ensure that `vma` is non-null and valid for the duration of the new area's
+        /// lifetime.
+        pub(crate) unsafe fn from_ptr(vma: *mut bindings::vm_area_struct) -> Self {
+            // INVARIANTS: The safety requirements guarantee the invariants.
+            Self { vma }
+        }
+
+        /// Returns the flags associated with the virtual memory area.
+        ///
+        /// The possible flags are a combination of the constants in [`flags`].
+        pub fn flags(&self) -> usize {
+            // SAFETY: `self.vma` is valid by the type invariants.
+            unsafe { (*self.vma).vm_flags as _ }
+        }
+
+        /// Sets the flags associated with the virtual memory area.
+        ///
+        /// The possible flags are a combination of the constants in [`flags`].
+        pub fn set_flags(&mut self, flags: usize) {
+            // SAFETY: `self.vma` is valid by the type invariants.
+            unsafe { (*self.vma).vm_flags = flags as _ };
+        }
+
+        /// Returns the start address of the virtual memory area.
+        pub fn start(&self) -> usize {
+            // SAFETY: `self.vma` is valid by the type invariants.
+            unsafe { (*self.vma).vm_start as _ }
+        }
+
+        /// Returns the end address of the virtual memory area.
+        pub fn end(&self) -> usize {
+            // SAFETY: `self.vma` is valid by the type invariants.
+            unsafe { (*self.vma).vm_end as _ }
+        }
+
+        /// Maps a single page at the given address within the virtual memory area.
+        pub fn insert_page(&mut self, address: usize, page: &pages::Pages<0>) -> Result {
+            // SAFETY: The page is guaranteed to be order 0 by the type system. The range of
+            // `address` is already checked by `vm_insert_page`. `self.vma` and `page.pages` are
+            // guaranteed by their repective type invariants to be valid.
+            to_result(|| unsafe { bindings::vm_insert_page(self.vma, address as _, page.pages) })
+        }
+    }
+
+    /// Container for [`Area`] flags.
+    pub mod flags {
+        use crate::bindings;
+
+        /// No flags are set.
+        pub const NONE: usize = bindings::VM_NONE as _;
+
+        /// Mapping allows reads.
+        pub const READ: usize = bindings::VM_READ as _;
+
+        /// Mapping allows writes.
+        pub const WRITE: usize = bindings::VM_WRITE as _;
+
+        /// Mapping allows execution.
+        pub const EXEC: usize = bindings::VM_EXEC as _;
+
+        /// Mapping is shared.
+        pub const SHARED: usize = bindings::VM_SHARED as _;
+
+        /// Mapping may be updated to allow reads.
+        pub const MAYREAD: usize = bindings::VM_MAYREAD as _;
+
+        /// Mapping may be updated to allow writes.
+        pub const MAYWRITE: usize = bindings::VM_MAYWRITE as _;
+
+        /// Mapping may be updated to allow execution.
+        pub const MAYEXEC: usize = bindings::VM_MAYEXEC as _;
+
+        /// Mapping may be updated to be shared.
+        pub const MAYSHARE: usize = bindings::VM_MAYSHARE as _;
+
+        /// Do not copy this vma on fork.
+        pub const DONTCOPY: usize = bindings::VM_DONTCOPY as _;
+
+        /// Cannot expand with mremap().
+        pub const DONTEXPAND: usize = bindings::VM_DONTEXPAND as _;
+
+        /// Lock the pages covered when they are faulted in.
+        pub const LOCKONFAULT: usize = bindings::VM_LOCKONFAULT as _;
+
+        /// Is a VM accounted object.
+        pub const ACCOUNT: usize = bindings::VM_ACCOUNT as _;
+
+        /// should the VM suppress accounting.
+        pub const NORESERVE: usize = bindings::VM_NORESERVE as _;
+
+        /// Huge TLB Page VM.
+        pub const HUGETLB: usize = bindings::VM_HUGETLB as _;
+
+        /// Synchronous page faults.
+        pub const SYNC: usize = bindings::VM_SYNC as _;
+
+        /// Architecture-specific flag.
+        pub const ARCH_1: usize = bindings::VM_ARCH_1 as _;
+
+        /// Wipe VMA contents in child..
+        pub const WIPEONFORK: usize = bindings::VM_WIPEONFORK as _;
+
+        /// Do not include in the core dump.
+        pub const DONTDUMP: usize = bindings::VM_DONTDUMP as _;
+
+        /// Not soft dirty clean area.
+        pub const SOFTDIRTY: usize = bindings::VM_SOFTDIRTY as _;
+
+        /// Can contain "struct page" and pure PFN pages.
+        pub const MIXEDMAP: usize = bindings::VM_MIXEDMAP as _;
+
+        /// MADV_HUGEPAGE marked this vma.
+        pub const HUGEPAGE: usize = bindings::VM_HUGEPAGE as _;
+
+        /// MADV_NOHUGEPAGE marked this vma.
+        pub const NOHUGEPAGE: usize = bindings::VM_NOHUGEPAGE as _;
+
+        /// KSM may merge identical pages.
+        pub const MERGEABLE: usize = bindings::VM_MERGEABLE as _;
+    }
+}
diff --git a/rust/kernel/module_param.rs b/rust/kernel/module_param.rs
new file mode 100644
index 000000000000..5065dffa817e
--- /dev/null
+++ b/rust/kernel/module_param.rs
@@ -0,0 +1,498 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Types for module parameters.
+//!
+//! C header: [`include/linux/moduleparam.h`](../../../include/linux/moduleparam.h)
+
+use crate::error::{code::*, from_kernel_result};
+use crate::str::{CStr, Formatter};
+use core::fmt::Write;
+
+/// Types that can be used for module parameters.
+///
+/// Note that displaying the type in `sysfs` will fail if
+/// [`alloc::string::ToString::to_string`] (as implemented through the
+/// [`core::fmt::Display`] trait) writes more than [`PAGE_SIZE`]
+/// bytes (including an additional null terminator).
+///
+/// [`PAGE_SIZE`]: `crate::PAGE_SIZE`
+pub trait ModuleParam: core::fmt::Display + core::marker::Sized {
+    /// The `ModuleParam` will be used by the kernel module through this type.
+    ///
+    /// This may differ from `Self` if, for example, `Self` needs to track
+    /// ownership without exposing it or allocate extra space for other possible
+    /// parameter values. See [`StringParam`] or [`ArrayParam`] for examples.
+    type Value: ?Sized;
+
+    /// Whether the parameter is allowed to be set without an argument.
+    ///
+    /// Setting this to `true` allows the parameter to be passed without an
+    /// argument (e.g. just `module.param` instead of `module.param=foo`).
+    const NOARG_ALLOWED: bool;
+
+    /// Convert a parameter argument into the parameter value.
+    ///
+    /// `None` should be returned when parsing of the argument fails.
+    /// `arg == None` indicates that the parameter was passed without an
+    /// argument. If `NOARG_ALLOWED` is set to `false` then `arg` is guaranteed
+    /// to always be `Some(_)`.
+    ///
+    /// Parameters passed at boot time will be set before [`kmalloc`] is
+    /// available (even if the module is loaded at a later time). However, in
+    /// this case, the argument buffer will be valid for the entire lifetime of
+    /// the kernel. So implementations of this method which need to allocate
+    /// should first check that the allocator is available (with
+    /// [`crate::bindings::slab_is_available`]) and when it is not available
+    /// provide an alternative implementation which doesn't allocate. In cases
+    /// where the allocator is not available it is safe to save references to
+    /// `arg` in `Self`, but in other cases a copy should be made.
+    ///
+    /// [`kmalloc`]: ../../../include/linux/slab.h
+    fn try_from_param_arg(arg: Option<&'static [u8]>) -> Option<Self>;
+
+    /// Get the current value of the parameter for use in the kernel module.
+    ///
+    /// This function should not be used directly. Instead use the wrapper
+    /// `read` which will be generated by [`macros::module`].
+    fn value(&self) -> &Self::Value;
+
+    /// Set the module parameter from a string.
+    ///
+    /// Used to set the parameter value when loading the module or when set
+    /// through `sysfs`.
+    ///
+    /// # Safety
+    ///
+    /// If `val` is non-null then it must point to a valid null-terminated
+    /// string. The `arg` field of `param` must be an instance of `Self`.
+    unsafe extern "C" fn set_param(
+        val: *const crate::c_types::c_char,
+        param: *const crate::bindings::kernel_param,
+    ) -> crate::c_types::c_int {
+        let arg = if val.is_null() {
+            None
+        } else {
+            Some(unsafe { CStr::from_char_ptr(val).as_bytes() })
+        };
+        match Self::try_from_param_arg(arg) {
+            Some(new_value) => {
+                let old_value = unsafe { (*param).__bindgen_anon_1.arg as *mut Self };
+                let _ = unsafe { core::ptr::replace(old_value, new_value) };
+                0
+            }
+            None => EINVAL.to_kernel_errno(),
+        }
+    }
+
+    /// Write a string representation of the current parameter value to `buf`.
+    ///
+    /// Used for displaying the current parameter value in `sysfs`.
+    ///
+    /// # Safety
+    ///
+    /// `buf` must be a buffer of length at least `kernel::PAGE_SIZE` that is
+    /// writeable. The `arg` field of `param` must be an instance of `Self`.
+    unsafe extern "C" fn get_param(
+        buf: *mut crate::c_types::c_char,
+        param: *const crate::bindings::kernel_param,
+    ) -> crate::c_types::c_int {
+        from_kernel_result! {
+            // SAFETY: The C contracts guarantees that the buffer is at least `PAGE_SIZE` bytes.
+            let mut f = unsafe { Formatter::from_buffer(buf.cast(), crate::PAGE_SIZE) };
+            unsafe { write!(f, "{}\0", *((*param).__bindgen_anon_1.arg as *mut Self)) }?;
+            Ok(f.bytes_written().try_into()?)
+        }
+    }
+
+    /// Drop the parameter.
+    ///
+    /// Called when unloading a module.
+    ///
+    /// # Safety
+    ///
+    /// The `arg` field of `param` must be an instance of `Self`.
+    unsafe extern "C" fn free(arg: *mut crate::c_types::c_void) {
+        unsafe { core::ptr::drop_in_place(arg as *mut Self) };
+    }
+}
+
+/// Trait for parsing integers.
+///
+/// Strings begining with `0x`, `0o`, or `0b` are parsed as hex, octal, or
+/// binary respectively. Strings beginning with `0` otherwise are parsed as
+/// octal. Anything else is parsed as decimal. A leading `+` or `-` is also
+/// permitted. Any string parsed by [`kstrtol()`] or [`kstrtoul()`] will be
+/// successfully parsed.
+///
+/// [`kstrtol()`]: https://www.kernel.org/doc/html/latest/core-api/kernel-api.html#c.kstrtol
+/// [`kstrtoul()`]: https://www.kernel.org/doc/html/latest/core-api/kernel-api.html#c.kstrtoul
+trait ParseInt: Sized {
+    fn from_str_radix(src: &str, radix: u32) -> Result<Self, core::num::ParseIntError>;
+    fn checked_neg(self) -> Option<Self>;
+
+    fn from_str_unsigned(src: &str) -> Result<Self, core::num::ParseIntError> {
+        let (radix, digits) = if let Some(n) = src.strip_prefix("0x") {
+            (16, n)
+        } else if let Some(n) = src.strip_prefix("0X") {
+            (16, n)
+        } else if let Some(n) = src.strip_prefix("0o") {
+            (8, n)
+        } else if let Some(n) = src.strip_prefix("0O") {
+            (8, n)
+        } else if let Some(n) = src.strip_prefix("0b") {
+            (2, n)
+        } else if let Some(n) = src.strip_prefix("0B") {
+            (2, n)
+        } else if src.starts_with('0') {
+            (8, src)
+        } else {
+            (10, src)
+        };
+        Self::from_str_radix(digits, radix)
+    }
+
+    fn from_str(src: &str) -> Option<Self> {
+        match src.bytes().next() {
+            None => None,
+            Some(b'-') => Self::from_str_unsigned(&src[1..]).ok()?.checked_neg(),
+            Some(b'+') => Some(Self::from_str_unsigned(&src[1..]).ok()?),
+            Some(_) => Some(Self::from_str_unsigned(src).ok()?),
+        }
+    }
+}
+
+macro_rules! impl_parse_int {
+    ($ty:ident) => {
+        impl ParseInt for $ty {
+            fn from_str_radix(src: &str, radix: u32) -> Result<Self, core::num::ParseIntError> {
+                $ty::from_str_radix(src, radix)
+            }
+
+            fn checked_neg(self) -> Option<Self> {
+                self.checked_neg()
+            }
+        }
+    };
+}
+
+impl_parse_int!(i8);
+impl_parse_int!(u8);
+impl_parse_int!(i16);
+impl_parse_int!(u16);
+impl_parse_int!(i32);
+impl_parse_int!(u32);
+impl_parse_int!(i64);
+impl_parse_int!(u64);
+impl_parse_int!(isize);
+impl_parse_int!(usize);
+
+macro_rules! impl_module_param {
+    ($ty:ident) => {
+        impl ModuleParam for $ty {
+            type Value = $ty;
+
+            const NOARG_ALLOWED: bool = false;
+
+            fn try_from_param_arg(arg: Option<&'static [u8]>) -> Option<Self> {
+                let bytes = arg?;
+                let utf8 = core::str::from_utf8(bytes).ok()?;
+                <$ty as crate::module_param::ParseInt>::from_str(utf8)
+            }
+
+            fn value(&self) -> &Self::Value {
+                self
+            }
+        }
+    };
+}
+
+#[doc(hidden)]
+#[macro_export]
+/// Generate a static [`kernel_param_ops`](../../../include/linux/moduleparam.h) struct.
+///
+/// # Example
+/// ```ignore
+/// make_param_ops!(
+///     /// Documentation for new param ops.
+///     PARAM_OPS_MYTYPE, // Name for the static.
+///     MyType // A type which implements [`ModuleParam`].
+/// );
+/// ```
+macro_rules! make_param_ops {
+    ($ops:ident, $ty:ty) => {
+        $crate::make_param_ops!(
+            #[doc=""]
+            $ops,
+            $ty
+        );
+    };
+    ($(#[$meta:meta])* $ops:ident, $ty:ty) => {
+        $(#[$meta])*
+        ///
+        /// Static [`kernel_param_ops`](../../../include/linux/moduleparam.h)
+        /// struct generated by [`make_param_ops`].
+        pub static $ops: $crate::bindings::kernel_param_ops = $crate::bindings::kernel_param_ops {
+            flags: if <$ty as $crate::module_param::ModuleParam>::NOARG_ALLOWED {
+                $crate::bindings::KERNEL_PARAM_OPS_FL_NOARG
+            } else {
+                0
+            },
+            set: Some(<$ty as $crate::module_param::ModuleParam>::set_param),
+            get: Some(<$ty as $crate::module_param::ModuleParam>::get_param),
+            free: Some(<$ty as $crate::module_param::ModuleParam>::free),
+        };
+    };
+}
+
+impl_module_param!(i8);
+impl_module_param!(u8);
+impl_module_param!(i16);
+impl_module_param!(u16);
+impl_module_param!(i32);
+impl_module_param!(u32);
+impl_module_param!(i64);
+impl_module_param!(u64);
+impl_module_param!(isize);
+impl_module_param!(usize);
+
+make_param_ops!(
+    /// Rust implementation of [`kernel_param_ops`](../../../include/linux/moduleparam.h)
+    /// for [`i8`].
+    PARAM_OPS_I8,
+    i8
+);
+make_param_ops!(
+    /// Rust implementation of [`kernel_param_ops`](../../../include/linux/moduleparam.h)
+    /// for [`u8`].
+    PARAM_OPS_U8,
+    u8
+);
+make_param_ops!(
+    /// Rust implementation of [`kernel_param_ops`](../../../include/linux/moduleparam.h)
+    /// for [`i16`].
+    PARAM_OPS_I16,
+    i16
+);
+make_param_ops!(
+    /// Rust implementation of [`kernel_param_ops`](../../../include/linux/moduleparam.h)
+    /// for [`u16`].
+    PARAM_OPS_U16,
+    u16
+);
+make_param_ops!(
+    /// Rust implementation of [`kernel_param_ops`](../../../include/linux/moduleparam.h)
+    /// for [`i32`].
+    PARAM_OPS_I32,
+    i32
+);
+make_param_ops!(
+    /// Rust implementation of [`kernel_param_ops`](../../../include/linux/moduleparam.h)
+    /// for [`u32`].
+    PARAM_OPS_U32,
+    u32
+);
+make_param_ops!(
+    /// Rust implementation of [`kernel_param_ops`](../../../include/linux/moduleparam.h)
+    /// for [`i64`].
+    PARAM_OPS_I64,
+    i64
+);
+make_param_ops!(
+    /// Rust implementation of [`kernel_param_ops`](../../../include/linux/moduleparam.h)
+    /// for [`u64`].
+    PARAM_OPS_U64,
+    u64
+);
+make_param_ops!(
+    /// Rust implementation of [`kernel_param_ops`](../../../include/linux/moduleparam.h)
+    /// for [`isize`].
+    PARAM_OPS_ISIZE,
+    isize
+);
+make_param_ops!(
+    /// Rust implementation of [`kernel_param_ops`](../../../include/linux/moduleparam.h)
+    /// for [`usize`].
+    PARAM_OPS_USIZE,
+    usize
+);
+
+impl ModuleParam for bool {
+    type Value = bool;
+
+    const NOARG_ALLOWED: bool = true;
+
+    fn try_from_param_arg(arg: Option<&'static [u8]>) -> Option<Self> {
+        match arg {
+            None => Some(true),
+            Some(b"y") | Some(b"Y") | Some(b"1") | Some(b"true") => Some(true),
+            Some(b"n") | Some(b"N") | Some(b"0") | Some(b"false") => Some(false),
+            _ => None,
+        }
+    }
+
+    fn value(&self) -> &Self::Value {
+        self
+    }
+}
+
+make_param_ops!(
+    /// Rust implementation of [`kernel_param_ops`](../../../include/linux/moduleparam.h)
+    /// for [`bool`].
+    PARAM_OPS_BOOL,
+    bool
+);
+
+/// An array of at __most__ `N` values.
+///
+/// # Invariant
+///
+/// The first `self.used` elements of `self.values` are initialized.
+pub struct ArrayParam<T, const N: usize> {
+    values: [core::mem::MaybeUninit<T>; N],
+    used: usize,
+}
+
+impl<T, const N: usize> ArrayParam<T, { N }> {
+    fn values(&self) -> &[T] {
+        // SAFETY: The invariant maintained by `ArrayParam` allows us to cast
+        // the first `self.used` elements to `T`.
+        unsafe {
+            &*(&self.values[0..self.used] as *const [core::mem::MaybeUninit<T>] as *const [T])
+        }
+    }
+}
+
+impl<T: Copy, const N: usize> ArrayParam<T, { N }> {
+    const fn new() -> Self {
+        // INVARIANT: The first `self.used` elements of `self.values` are
+        // initialized.
+        ArrayParam {
+            values: [core::mem::MaybeUninit::uninit(); N],
+            used: 0,
+        }
+    }
+
+    const fn push(&mut self, val: T) {
+        if self.used < N {
+            // INVARIANT: The first `self.used` elements of `self.values` are
+            // initialized.
+            self.values[self.used] = core::mem::MaybeUninit::new(val);
+            self.used += 1;
+        }
+    }
+
+    /// Create an instance of `ArrayParam` initialized with `vals`.
+    ///
+    /// This function is only meant to be used in the [`module::module`] macro.
+    pub const fn create(vals: &[T]) -> Self {
+        let mut result = ArrayParam::new();
+        let mut i = 0;
+        while i < vals.len() {
+            result.push(vals[i]);
+            i += 1;
+        }
+        result
+    }
+}
+
+impl<T: core::fmt::Display, const N: usize> core::fmt::Display for ArrayParam<T, { N }> {
+    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
+        for val in self.values() {
+            write!(f, "{},", val)?;
+        }
+        Ok(())
+    }
+}
+
+impl<T: Copy + core::fmt::Display + ModuleParam, const N: usize> ModuleParam
+    for ArrayParam<T, { N }>
+{
+    type Value = [T];
+
+    const NOARG_ALLOWED: bool = false;
+
+    fn try_from_param_arg(arg: Option<&'static [u8]>) -> Option<Self> {
+        arg.and_then(|args| {
+            let mut result = Self::new();
+            for arg in args.split(|b| *b == b',') {
+                result.push(T::try_from_param_arg(Some(arg))?);
+            }
+            Some(result)
+        })
+    }
+
+    fn value(&self) -> &Self::Value {
+        self.values()
+    }
+}
+
+/// A C-style string parameter.
+///
+/// The Rust version of the [`charp`] parameter. This type is meant to be
+/// used by the [`macros::module`] macro, not handled directly. Instead use the
+/// `read` method generated by that macro.
+///
+/// [`charp`]: ../../../include/linux/moduleparam.h
+pub enum StringParam {
+    /// A borrowed parameter value.
+    ///
+    /// Either the default value (which is static in the module) or borrowed
+    /// from the original argument buffer used to set the value.
+    Ref(&'static [u8]),
+
+    /// A value that was allocated when the parameter was set.
+    ///
+    /// The value needs to be freed when the parameter is reset or the module is
+    /// unloaded.
+    Owned(alloc::vec::Vec<u8>),
+}
+
+impl StringParam {
+    fn bytes(&self) -> &[u8] {
+        match self {
+            StringParam::Ref(bytes) => *bytes,
+            StringParam::Owned(vec) => &vec[..],
+        }
+    }
+}
+
+impl core::fmt::Display for StringParam {
+    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
+        let bytes = self.bytes();
+        match core::str::from_utf8(bytes) {
+            Ok(utf8) => write!(f, "{}", utf8),
+            Err(_) => write!(f, "{:?}", bytes),
+        }
+    }
+}
+
+impl ModuleParam for StringParam {
+    type Value = [u8];
+
+    const NOARG_ALLOWED: bool = false;
+
+    fn try_from_param_arg(arg: Option<&'static [u8]>) -> Option<Self> {
+        // SAFETY: It is always safe to call [`slab_is_available`](../../../include/linux/slab.h).
+        let slab_available = unsafe { crate::bindings::slab_is_available() };
+        arg.and_then(|arg| {
+            if slab_available {
+                let mut vec = alloc::vec::Vec::new();
+                vec.try_extend_from_slice(arg).ok()?;
+                Some(StringParam::Owned(vec))
+            } else {
+                Some(StringParam::Ref(arg))
+            }
+        })
+    }
+
+    fn value(&self) -> &Self::Value {
+        self.bytes()
+    }
+}
+
+make_param_ops!(
+    /// Rust implementation of [`kernel_param_ops`](../../../include/linux/moduleparam.h)
+    /// for [`StringParam`].
+    PARAM_OPS_STR,
+    StringParam
+);
diff --git a/rust/kernel/of.rs b/rust/kernel/of.rs
new file mode 100644
index 000000000000..cdcd83244337
--- /dev/null
+++ b/rust/kernel/of.rs
@@ -0,0 +1,63 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Devicetree and Open Firmware abstractions.
+//!
+//! C header: [`include/linux/of_*.h`](../../../../include/linux/of_*.h)
+
+use crate::{bindings, driver, str::BStr};
+
+/// An open firmware device id.
+#[derive(Clone, Copy)]
+pub enum DeviceId {
+    /// An open firmware device id where only a compatible string is specified.
+    Compatible(&'static BStr),
+}
+
+/// Defines a const open firmware device id table that also carries per-entry data/context/info.
+///
+/// The name of the const is `OF_DEVICE_ID_TABLE`, which is what buses are expected to name their
+/// open firmware tables.
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::define_of_id_table;
+/// use kernel::of;
+///
+/// define_of_id_table! {u32, [
+///     (of::DeviceId::Compatible(b"test-device1,test-device2"), Some(0xff)),
+///     (of::DeviceId::Compatible(b"test-device3"), None),
+/// ]};
+/// ```
+#[macro_export]
+macro_rules! define_of_id_table {
+    ($data_type:ty, $($t:tt)*) => {
+        $crate::define_id_table!(OF_DEVICE_ID_TABLE, $crate::of::DeviceId, $data_type, $($t)*);
+    };
+}
+
+// SAFETY: `ZERO` is all zeroed-out and `to_rawid` stores `offset` in `of_device_id::data`.
+unsafe impl const driver::RawDeviceId for DeviceId {
+    type RawType = bindings::of_device_id;
+    const ZERO: Self::RawType = bindings::of_device_id {
+        name: [0; 32],
+        type_: [0; 32],
+        compatible: [0; 128],
+        data: core::ptr::null(),
+    };
+
+    fn to_rawid(&self, offset: isize) -> Self::RawType {
+        let DeviceId::Compatible(compatible) = self;
+        let mut id = Self::ZERO;
+        let mut i = 0;
+        while i < compatible.len() {
+            // If `compatible` does not fit in `id.compatible`, an "index out of bounds" build time
+            // error will be triggered.
+            id.compatible[i] = compatible[i] as _;
+            i += 1;
+        }
+        id.compatible[i] = b'\0' as _;
+        id.data = offset as _;
+        id
+    }
+}
diff --git a/rust/kernel/pages.rs b/rust/kernel/pages.rs
new file mode 100644
index 000000000000..02c0d500fae4
--- /dev/null
+++ b/rust/kernel/pages.rs
@@ -0,0 +1,144 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Kernel page allocation and management.
+//!
+//! TODO: This module is a work in progress.
+
+use crate::{
+    bindings, c_types, error::code::*, io_buffer::IoBufferReader, user_ptr::UserSlicePtrReader,
+    Result, PAGE_SIZE,
+};
+use core::{marker::PhantomData, ptr};
+
+/// A set of physical pages.
+///
+/// `Pages` holds a reference to a set of pages of order `ORDER`. Having the order as a generic
+/// const allows the struct to have the same size as a pointer.
+///
+/// # Invariants
+///
+/// The pointer `Pages::pages` is valid and points to 2^ORDER pages.
+pub struct Pages<const ORDER: u32> {
+    pub(crate) pages: *mut bindings::page,
+}
+
+impl<const ORDER: u32> Pages<ORDER> {
+    /// Allocates a new set of contiguous pages.
+    pub fn new() -> Result<Self> {
+        // TODO: Consider whether we want to allow callers to specify flags.
+        // SAFETY: This only allocates pages. We check that it succeeds in the next statement.
+        let pages = unsafe {
+            bindings::alloc_pages(
+                bindings::GFP_KERNEL | bindings::__GFP_ZERO | bindings::__GFP_HIGHMEM,
+                ORDER,
+            )
+        };
+        if pages.is_null() {
+            return Err(ENOMEM);
+        }
+        // INVARIANTS: We checked that the allocation above succeeded>
+        Ok(Self { pages })
+    }
+
+    /// Copies data from the given [`UserSlicePtrReader`] into the pages.
+    pub fn copy_into_page(
+        &self,
+        reader: &mut UserSlicePtrReader,
+        offset: usize,
+        len: usize,
+    ) -> Result {
+        // TODO: For now this only works on the first page.
+        let end = offset.checked_add(len).ok_or(EINVAL)?;
+        if end > PAGE_SIZE {
+            return Err(EINVAL);
+        }
+
+        let mapping = self.kmap(0).ok_or(EINVAL)?;
+
+        // SAFETY: We ensured that the buffer was valid with the check above.
+        unsafe { reader.read_raw((mapping.ptr as usize + offset) as _, len) }?;
+        Ok(())
+    }
+
+    /// Maps the pages and reads from them into the given buffer.
+    ///
+    /// # Safety
+    ///
+    /// Callers must ensure that the destination buffer is valid for the given length.
+    /// Additionally, if the raw buffer is intended to be recast, they must ensure that the data
+    /// can be safely cast; [`crate::io_buffer::ReadableFromBytes`] has more details about it.
+    pub unsafe fn read(&self, dest: *mut u8, offset: usize, len: usize) -> Result {
+        // TODO: For now this only works on the first page.
+        let end = offset.checked_add(len).ok_or(EINVAL)?;
+        if end > PAGE_SIZE {
+            return Err(EINVAL);
+        }
+
+        let mapping = self.kmap(0).ok_or(EINVAL)?;
+        unsafe { ptr::copy((mapping.ptr as *mut u8).add(offset), dest, len) };
+        Ok(())
+    }
+
+    /// Maps the pages and writes into them from the given bufer.
+    ///
+    /// # Safety
+    ///
+    /// Callers must ensure that the buffer is valid for the given length. Additionally, if the
+    /// page is (or will be) mapped by userspace, they must ensure that no kernel data is leaked
+    /// through padding if it was cast from another type; [`crate::io_buffer::WritableToBytes`] has
+    /// more details about it.
+    pub unsafe fn write(&self, src: *const u8, offset: usize, len: usize) -> Result {
+        // TODO: For now this only works on the first page.
+        let end = offset.checked_add(len).ok_or(EINVAL)?;
+        if end > PAGE_SIZE {
+            return Err(EINVAL);
+        }
+
+        let mapping = self.kmap(0).ok_or(EINVAL)?;
+        unsafe { ptr::copy(src, (mapping.ptr as *mut u8).add(offset), len) };
+        Ok(())
+    }
+
+    /// Maps the page at index `index`.
+    fn kmap(&self, index: usize) -> Option<PageMapping<'_>> {
+        if index >= 1usize << ORDER {
+            return None;
+        }
+
+        // SAFETY: We checked above that `index` is within range.
+        let page = unsafe { self.pages.add(index) };
+
+        // SAFETY: `page` is valid based on the checks above.
+        let ptr = unsafe { bindings::kmap(page) };
+        if ptr.is_null() {
+            return None;
+        }
+
+        Some(PageMapping {
+            page,
+            ptr,
+            _phantom: PhantomData,
+        })
+    }
+}
+
+impl<const ORDER: u32> Drop for Pages<ORDER> {
+    fn drop(&mut self) {
+        // SAFETY: By the type invariants, we know the pages are allocated with the given order.
+        unsafe { bindings::__free_pages(self.pages, ORDER) };
+    }
+}
+
+struct PageMapping<'a> {
+    page: *mut bindings::page,
+    ptr: *mut c_types::c_void,
+    _phantom: PhantomData<&'a i32>,
+}
+
+impl Drop for PageMapping<'_> {
+    fn drop(&mut self) {
+        // SAFETY: An instance of `PageMapping` is created only when `kmap` succeeded for the given
+        // page, so it is safe to unmap it here.
+        unsafe { bindings::kunmap(self.page) };
+    }
+}
diff --git a/rust/kernel/platform.rs b/rust/kernel/platform.rs
new file mode 100644
index 000000000000..8b912c21068b
--- /dev/null
+++ b/rust/kernel/platform.rs
@@ -0,0 +1,224 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Platform devices and drivers.
+//!
+//! Also called `platdev`, `pdev`.
+//!
+//! C header: [`include/linux/platform_device.h`](../../../../include/linux/platform_device.h)
+
+use crate::{
+    bindings, c_types,
+    device::{self, RawDevice},
+    driver,
+    error::{from_kernel_result, Result},
+    of,
+    str::CStr,
+    to_result,
+    types::PointerWrapper,
+    ThisModule,
+};
+
+/// A registration of a platform driver.
+pub type Registration<T> = driver::Registration<Adapter<T>>;
+
+/// An adapter for the registration of platform drivers.
+pub struct Adapter<T: Driver>(T);
+
+impl<T: Driver> driver::DriverOps for Adapter<T> {
+    type RegType = bindings::platform_driver;
+
+    unsafe fn register(
+        reg: *mut bindings::platform_driver,
+        name: &'static CStr,
+        module: &'static ThisModule,
+    ) -> Result {
+        // SAFETY: By the safety requirements of this function (defined in the trait defintion),
+        // `reg` is non-null and valid.
+        let pdrv = unsafe { &mut *reg };
+
+        pdrv.driver.name = name.as_char_ptr();
+        pdrv.probe = Some(Self::probe_callback);
+        pdrv.remove = Some(Self::remove_callback);
+        if let Some(t) = T::OF_DEVICE_ID_TABLE {
+            pdrv.driver.of_match_table = t.as_ref();
+        }
+        // SAFETY:
+        //   - `pdrv` lives at least until the call to `platform_driver_unregister()` returns.
+        //   - `name` pointer has static lifetime.
+        //   - `module.0` lives at least as long as the module.
+        //   - `probe()` and `remove()` are static functions.
+        //   - `of_match_table` is either a raw pointer with static lifetime,
+        //      as guaranteed by the [`driver::IdTable`] type, or null.
+        to_result(|| unsafe { bindings::__platform_driver_register(reg, module.0) })
+    }
+
+    unsafe fn unregister(reg: *mut bindings::platform_driver) {
+        // SAFETY: By the safety requirements of this function (defined in the trait definition),
+        // `reg` was passed (and updated) by a previous successful call to
+        // `platform_driver_register`.
+        unsafe { bindings::platform_driver_unregister(reg) };
+    }
+}
+
+impl<T: Driver> Adapter<T> {
+    fn get_id_info(dev: &Device) -> Option<&'static T::IdInfo> {
+        let table = T::OF_DEVICE_ID_TABLE?;
+
+        // SAFETY: `table` has static lifetime, so it is valid for read. `dev` is guaranteed to be
+        // valid while it's alive, so is the raw device returned by it.
+        let id = unsafe { bindings::of_match_device(table.as_ref(), dev.raw_device()) };
+        if id.is_null() {
+            return None;
+        }
+
+        // SAFETY: `id` is a pointer within the static table, so it's always valid.
+        let offset = unsafe { (*id).data };
+        if offset.is_null() {
+            return None;
+        }
+
+        // SAFETY: The offset comes from a previous call to `offset_from` in `IdArray::new`, which
+        // guarantees that the resulting pointer is within the table.
+        let ptr = unsafe {
+            id.cast::<u8>()
+                .offset(offset as _)
+                .cast::<Option<T::IdInfo>>()
+        };
+
+        // SAFETY: The id table has a static lifetime, so `ptr` is guaranteed to be valid for read.
+        unsafe { (&*ptr).as_ref() }
+    }
+
+    extern "C" fn probe_callback(pdev: *mut bindings::platform_device) -> c_types::c_int {
+        from_kernel_result! {
+            // SAFETY: `pdev` is valid by the contract with the C code. `dev` is alive only for the
+            // duration of this call, so it is guaranteed to remain alive for the lifetime of
+            // `pdev`.
+            let mut dev = unsafe { Device::from_ptr(pdev) };
+            let info = Self::get_id_info(&dev);
+            let data = T::probe(&mut dev, info)?;
+            // SAFETY: `pdev` is guaranteed to be a valid, non-null pointer.
+            unsafe { bindings::platform_set_drvdata(pdev, data.into_pointer() as _) };
+            Ok(0)
+        }
+    }
+
+    extern "C" fn remove_callback(pdev: *mut bindings::platform_device) -> c_types::c_int {
+        from_kernel_result! {
+            // SAFETY: `pdev` is guaranteed to be a valid, non-null pointer.
+            let ptr = unsafe { bindings::platform_get_drvdata(pdev) };
+            // SAFETY:
+            //   - we allocated this pointer using `T::Data::into_pointer`,
+            //     so it is safe to turn back into a `T::Data`.
+            //   - the allocation happened in `probe`, no-one freed the memory,
+            //     `remove` is the canonical kernel location to free driver data. so OK
+            //     to convert the pointer back to a Rust structure here.
+            let data = unsafe { T::Data::from_pointer(ptr) };
+            let ret = T::remove(&data);
+            <T::Data as driver::DeviceRemoval>::device_remove(&data);
+            ret?;
+            Ok(0)
+        }
+    }
+}
+
+/// A platform driver.
+pub trait Driver {
+    /// Data stored on device by driver.
+    ///
+    /// Corresponds to the data set or retrieved via the kernel's
+    /// `platform_{set,get}_drvdata()` functions.
+    ///
+    /// Require that `Data` implements `PointerWrapper`. We guarantee to
+    /// never move the underlying wrapped data structure. This allows
+    type Data: PointerWrapper + Send + Sync + driver::DeviceRemoval = ();
+
+    /// The type holding information about each device id supported by the driver.
+    type IdInfo: 'static = ();
+
+    /// The table of device ids supported by the driver.
+    const OF_DEVICE_ID_TABLE: Option<driver::IdTable<'static, of::DeviceId, Self::IdInfo>> = None;
+
+    /// Platform driver probe.
+    ///
+    /// Called when a new platform device is added or discovered.
+    /// Implementers should attempt to initialize the device here.
+    fn probe(dev: &mut Device, id_info: Option<&Self::IdInfo>) -> Result<Self::Data>;
+
+    /// Platform driver remove.
+    ///
+    /// Called when a platform device is removed.
+    /// Implementers should prepare the device for complete removal here.
+    fn remove(_data: &Self::Data) -> Result {
+        Ok(())
+    }
+}
+
+/// A platform device.
+///
+/// # Invariants
+///
+/// The field `ptr` is non-null and valid for the lifetime of the object.
+pub struct Device {
+    ptr: *mut bindings::platform_device,
+}
+
+impl Device {
+    /// Creates a new device from the given pointer.
+    ///
+    /// # Safety
+    ///
+    /// `ptr` must be non-null and valid. It must remain valid for the lifetime of the returned
+    /// instance.
+    unsafe fn from_ptr(ptr: *mut bindings::platform_device) -> Self {
+        // INVARIANT: The safety requirements of the function ensure the lifetime invariant.
+        Self { ptr }
+    }
+
+    /// Returns id of the platform device.
+    pub fn id(&self) -> i32 {
+        // SAFETY: By the type invariants, we know that `self.ptr` is non-null and valid.
+        unsafe { (*self.ptr).id }
+    }
+}
+
+// SAFETY: The device returned by `raw_device` is the raw platform device.
+unsafe impl device::RawDevice for Device {
+    fn raw_device(&self) -> *mut bindings::device {
+        // SAFETY: By the type invariants, we know that `self.ptr` is non-null and valid.
+        unsafe { &mut (*self.ptr).dev }
+    }
+}
+
+/// Declares a kernel module that exposes a single platform driver.
+///
+/// # Examples
+///
+/// ```ignore
+/// # use kernel::prelude::*;
+/// # use kernel::{platform, define_of_id_table, module_platform_driver};
+/// #
+/// struct MyDriver;
+/// impl platform::Driver for MyDriver {
+///     // [...]
+/// #   fn probe(_dev: &mut platform::Device, _id_info: Option<&Self::IdInfo>) -> Result {
+/// #       Ok(())
+/// #   }
+/// #   define_of_id_table! {(), [
+/// #       (of::DeviceId::Compatible(b"brcm,bcm2835-rng"), None),
+/// #   ]}
+/// }
+///
+/// module_platform_driver! {
+///     type: MyDriver,
+///     name: b"module_name",
+///     author: b"Author name",
+///     license: b"GPL v2",
+/// }
+/// ```
+#[macro_export]
+macro_rules! module_platform_driver {
+    ($($f:tt)*) => {
+        $crate::module_driver!(<T>, $crate::platform::Adapter<T>, { $($f)* });
+    };
+}
diff --git a/rust/kernel/power.rs b/rust/kernel/power.rs
new file mode 100644
index 000000000000..e318b5d9f0c0
--- /dev/null
+++ b/rust/kernel/power.rs
@@ -0,0 +1,118 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Power management interfaces.
+//!
+//! C header: [`include/linux/pm.h`](../../../../include/linux/pm.h)
+
+#![allow(dead_code)]
+
+use crate::{bindings, c_types, error::from_kernel_result, types::PointerWrapper, Result};
+use core::marker::PhantomData;
+
+/// Corresponds to the kernel's `struct dev_pm_ops`.
+///
+/// It is meant to be implemented by drivers that support power-management operations.
+pub trait Operations {
+    /// The type of the context data stored by the driver on each device.
+    type Data: PointerWrapper + Sync + Send;
+
+    /// Called before the system goes into a sleep state.
+    fn suspend(_data: <Self::Data as PointerWrapper>::Borrowed<'_>) -> Result {
+        Ok(())
+    }
+
+    /// Called after the system comes back from a sleep state.
+    fn resume(_data: <Self::Data as PointerWrapper>::Borrowed<'_>) -> Result {
+        Ok(())
+    }
+
+    /// Called before creating a hibernation image.
+    fn freeze(_data: <Self::Data as PointerWrapper>::Borrowed<'_>) -> Result {
+        Ok(())
+    }
+
+    /// Called after the system is restored from a hibernation image.
+    fn restore(_data: <Self::Data as PointerWrapper>::Borrowed<'_>) -> Result {
+        Ok(())
+    }
+}
+
+macro_rules! pm_callback {
+    ($callback:ident, $method:ident) => {
+        unsafe extern "C" fn $callback<T: Operations>(
+            dev: *mut bindings::device,
+        ) -> c_types::c_int {
+            from_kernel_result! {
+                // SAFETY: `dev` is valid as it was passed in by the C portion.
+                let ptr = unsafe { bindings::dev_get_drvdata(dev) };
+                // SAFETY: By the safety requirements of `OpsTable::build`, we know that `ptr` came
+                // from a previous call to `T::Data::into_pointer`.
+                let data = unsafe { T::Data::borrow(ptr) };
+                T::$method(data)?;
+                Ok(0)
+            }
+        }
+    };
+}
+
+pm_callback!(suspend_callback, suspend);
+pm_callback!(resume_callback, resume);
+pm_callback!(freeze_callback, freeze);
+pm_callback!(restore_callback, restore);
+
+pub(crate) struct OpsTable<T: Operations>(PhantomData<*const T>);
+
+impl<T: Operations> OpsTable<T> {
+    const VTABLE: bindings::dev_pm_ops = bindings::dev_pm_ops {
+        prepare: None,
+        complete: None,
+        suspend: Some(suspend_callback::<T>),
+        resume: Some(resume_callback::<T>),
+        freeze: Some(freeze_callback::<T>),
+        thaw: None,
+        poweroff: None,
+        restore: Some(restore_callback::<T>),
+        suspend_late: None,
+        resume_early: None,
+        freeze_late: None,
+        thaw_early: None,
+        poweroff_late: None,
+        restore_early: None,
+        suspend_noirq: None,
+        resume_noirq: None,
+        freeze_noirq: None,
+        thaw_noirq: None,
+        poweroff_noirq: None,
+        restore_noirq: None,
+        runtime_suspend: None,
+        runtime_resume: None,
+        runtime_idle: None,
+    };
+
+    /// Builds an instance of `struct dev_pm_ops`.
+    ///
+    /// # Safety
+    ///
+    /// The caller must ensure that `dev_get_drvdata` will result in a value returned by
+    /// [`T::Data::into_pointer`].
+    pub(crate) const unsafe fn build() -> &'static bindings::dev_pm_ops {
+        &Self::VTABLE
+    }
+}
+
+/// Implements the [`Operations`] trait as no-ops.
+///
+/// This is useful when one doesn't want to provide the implementation of any power-manager related
+/// operation.
+pub struct NoOperations<T: PointerWrapper>(PhantomData<T>);
+
+impl<T: PointerWrapper + Send + Sync> Operations for NoOperations<T> {
+    type Data = T;
+}
+
+// SAFETY: `NoOperation` provides no functionality, it is safe to send a reference to it to
+// different threads.
+unsafe impl<T: PointerWrapper> Sync for NoOperations<T> {}
+
+// SAFETY: `NoOperation` provides no functionality, it is safe to send it to different threads.
+unsafe impl<T: PointerWrapper> Send for NoOperations<T> {}
diff --git a/rust/kernel/prelude.rs b/rust/kernel/prelude.rs
new file mode 100644
index 000000000000..cc5894fba420
--- /dev/null
+++ b/rust/kernel/prelude.rs
@@ -0,0 +1,36 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! The `kernel` prelude.
+//!
+//! These are the most common items used by Rust code in the kernel,
+//! intended to be imported by all Rust code, for convenience.
+//!
+//! # Examples
+//!
+//! ```
+//! use kernel::prelude::*;
+//! ```
+
+pub use core::pin::Pin;
+
+pub use alloc::{boxed::Box, string::String, vec::Vec};
+
+pub use macros::module;
+
+pub use super::build_assert;
+
+pub use super::{
+    dbg, dev_alert, dev_crit, dev_dbg, dev_emerg, dev_err, dev_info, dev_notice, dev_warn, fmt,
+    pr_alert, pr_crit, pr_debug, pr_emerg, pr_err, pr_info, pr_notice, pr_warn,
+};
+
+pub use super::module_misc_device;
+
+#[cfg(CONFIG_ARM_AMBA)]
+pub use super::module_amba_driver;
+
+pub use super::static_assert;
+
+pub use super::{error::code::*, Error, KernelModule, Result};
+
+pub use super::{str::CStr, ThisModule};
diff --git a/rust/kernel/print.rs b/rust/kernel/print.rs
new file mode 100644
index 000000000000..59e92f74cd8d
--- /dev/null
+++ b/rust/kernel/print.rs
@@ -0,0 +1,414 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Printing facilities.
+//!
+//! C header: [`include/linux/printk.h`](../../../../include/linux/printk.h)
+//!
+//! Reference: <https://www.kernel.org/doc/html/latest/core-api/printk-basics.html>
+
+use core::fmt;
+
+use crate::{
+    c_types::{c_char, c_void},
+    str::RawFormatter,
+};
+
+#[cfg(CONFIG_PRINTK)]
+use crate::bindings;
+
+// Called from `vsprintf` with format specifier `%pA`.
+#[no_mangle]
+unsafe fn rust_fmt_argument(buf: *mut c_char, end: *mut c_char, ptr: *const c_void) -> *mut c_char {
+    use fmt::Write;
+    // SAFETY: The C contract guarantees that `buf` is valid if it's less than `end`.
+    let mut w = unsafe { RawFormatter::from_ptrs(buf.cast(), end.cast()) };
+    let _ = w.write_fmt(unsafe { *(ptr as *const fmt::Arguments<'_>) });
+    w.pos().cast()
+}
+
+/// Format strings.
+///
+/// Public but hidden since it should only be used from public macros.
+#[doc(hidden)]
+pub mod format_strings {
+    use crate::bindings;
+
+    /// The length we copy from the `KERN_*` kernel prefixes.
+    const LENGTH_PREFIX: usize = 2;
+
+    /// The length of the fixed format strings.
+    pub const LENGTH: usize = 10;
+
+    /// Generates a fixed format string for the kernel's [`_printk`].
+    ///
+    /// The format string is always the same for a given level, i.e. for a
+    /// given `prefix`, which are the kernel's `KERN_*` constants.
+    ///
+    /// [`_printk`]: ../../../../include/linux/printk.h
+    const fn generate(is_cont: bool, prefix: &[u8; 3]) -> [u8; LENGTH] {
+        // Ensure the `KERN_*` macros are what we expect.
+        assert!(prefix[0] == b'\x01');
+        if is_cont {
+            assert!(prefix[1] == b'c');
+        } else {
+            assert!(prefix[1] >= b'0' && prefix[1] <= b'7');
+        }
+        assert!(prefix[2] == b'\x00');
+
+        let suffix: &[u8; LENGTH - LENGTH_PREFIX] = if is_cont {
+            b"%pA\0\0\0\0\0"
+        } else {
+            b"%s: %pA\0"
+        };
+
+        [
+            prefix[0], prefix[1], suffix[0], suffix[1], suffix[2], suffix[3], suffix[4], suffix[5],
+            suffix[6], suffix[7],
+        ]
+    }
+
+    // Generate the format strings at compile-time.
+    //
+    // This avoids the compiler generating the contents on the fly in the stack.
+    //
+    // Furthermore, `static` instead of `const` is used to share the strings
+    // for all the kernel.
+    pub static EMERG: [u8; LENGTH] = generate(false, bindings::KERN_EMERG);
+    pub static ALERT: [u8; LENGTH] = generate(false, bindings::KERN_ALERT);
+    pub static CRIT: [u8; LENGTH] = generate(false, bindings::KERN_CRIT);
+    pub static ERR: [u8; LENGTH] = generate(false, bindings::KERN_ERR);
+    pub static WARNING: [u8; LENGTH] = generate(false, bindings::KERN_WARNING);
+    pub static NOTICE: [u8; LENGTH] = generate(false, bindings::KERN_NOTICE);
+    pub static INFO: [u8; LENGTH] = generate(false, bindings::KERN_INFO);
+    pub static DEBUG: [u8; LENGTH] = generate(false, bindings::KERN_DEBUG);
+    pub static CONT: [u8; LENGTH] = generate(true, bindings::KERN_CONT);
+}
+
+/// Prints a message via the kernel's [`_printk`].
+///
+/// Public but hidden since it should only be used from public macros.
+///
+/// # Safety
+///
+/// The format string must be one of the ones in [`format_strings`], and
+/// the module name must be null-terminated.
+///
+/// [`_printk`]: ../../../../include/linux/_printk.h
+#[doc(hidden)]
+#[cfg_attr(not(CONFIG_PRINTK), allow(unused_variables))]
+pub unsafe fn call_printk(
+    format_string: &[u8; format_strings::LENGTH],
+    module_name: &[u8],
+    args: fmt::Arguments<'_>,
+) {
+    // `_printk` does not seem to fail in any path.
+    #[cfg(CONFIG_PRINTK)]
+    unsafe {
+        bindings::_printk(
+            format_string.as_ptr() as _,
+            module_name.as_ptr(),
+            &args as *const _ as *const c_void,
+        );
+    }
+}
+
+/// Prints a message via the kernel's [`_printk`] for the `CONT` level.
+///
+/// Public but hidden since it should only be used from public macros.
+///
+/// [`_printk`]: ../../../../include/linux/printk.h
+#[doc(hidden)]
+#[cfg_attr(not(CONFIG_PRINTK), allow(unused_variables))]
+pub fn call_printk_cont(args: fmt::Arguments<'_>) {
+    // `_printk` does not seem to fail in any path.
+    //
+    // SAFETY: The format string is fixed.
+    #[cfg(CONFIG_PRINTK)]
+    unsafe {
+        bindings::_printk(
+            format_strings::CONT.as_ptr() as _,
+            &args as *const _ as *const c_void,
+        );
+    }
+}
+
+/// Performs formatting and forwards the string to [`call_printk`].
+///
+/// Public but hidden since it should only be used from public macros.
+#[doc(hidden)]
+#[cfg(not(testlib))]
+#[macro_export]
+macro_rules! print_macro (
+    // The non-continuation cases (most of them, e.g. `INFO`).
+    ($format_string:path, false, $($arg:tt)+) => (
+        // SAFETY: This hidden macro should only be called by the documented
+        // printing macros which ensure the format string is one of the fixed
+        // ones. All `__LOG_PREFIX`s are null-terminated as they are generated
+        // by the `module!` proc macro or fixed values defined in a kernel
+        // crate.
+        unsafe {
+            $crate::print::call_printk(
+                &$format_string,
+                crate::__LOG_PREFIX,
+                format_args!($($arg)+),
+            );
+        }
+    );
+
+    // The `CONT` case.
+    ($format_string:path, true, $($arg:tt)+) => (
+        $crate::print::call_printk_cont(
+            format_args!($($arg)+),
+        );
+    );
+);
+
+/// Stub for doctests
+#[cfg(testlib)]
+#[macro_export]
+macro_rules! print_macro (
+    ($format_string:path, $e:expr, $($arg:tt)+) => (
+        ()
+    );
+);
+
+// We could use a macro to generate these macros. However, doing so ends
+// up being a bit ugly: it requires the dollar token trick to escape `$` as
+// well as playing with the `doc` attribute. Furthermore, they cannot be easily
+// imported in the prelude due to [1]. So, for the moment, we just write them
+// manually, like in the C side; while keeping most of the logic in another
+// macro, i.e. [`print_macro`].
+//
+// [1]: https://github.com/rust-lang/rust/issues/52234
+
+/// Prints an emergency-level message (level 0).
+///
+/// Use this level if the system is unusable.
+///
+/// Equivalent to the kernel's [`pr_emerg`] macro.
+///
+/// Mimics the interface of [`std::print!`]. See [`core::fmt`] and
+/// [`alloc::format!`] for information about the formatting syntax.
+///
+/// [`pr_emerg`]: https://www.kernel.org/doc/html/latest/core-api/printk-basics.html#c.pr_emerg
+/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::prelude::*;
+/// pr_emerg!("hello {}\n", "there");
+/// ```
+#[macro_export]
+macro_rules! pr_emerg (
+    ($($arg:tt)*) => (
+        $crate::print_macro!($crate::print::format_strings::EMERG, false, $($arg)*)
+    )
+);
+
+/// Prints an alert-level message (level 1).
+///
+/// Use this level if action must be taken immediately.
+///
+/// Equivalent to the kernel's [`pr_alert`] macro.
+///
+/// Mimics the interface of [`std::print!`]. See [`core::fmt`] and
+/// [`alloc::format!`] for information about the formatting syntax.
+///
+/// [`pr_alert`]: https://www.kernel.org/doc/html/latest/core-api/printk-basics.html#c.pr_alert
+/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::prelude::*;
+/// pr_alert!("hello {}\n", "there");
+/// ```
+#[macro_export]
+macro_rules! pr_alert (
+    ($($arg:tt)*) => (
+        $crate::print_macro!($crate::print::format_strings::ALERT, false, $($arg)*)
+    )
+);
+
+/// Prints a critical-level message (level 2).
+///
+/// Use this level for critical conditions.
+///
+/// Equivalent to the kernel's [`pr_crit`] macro.
+///
+/// Mimics the interface of [`std::print!`]. See [`core::fmt`] and
+/// [`alloc::format!`] for information about the formatting syntax.
+///
+/// [`pr_crit`]: https://www.kernel.org/doc/html/latest/core-api/printk-basics.html#c.pr_crit
+/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::prelude::*;
+/// pr_crit!("hello {}\n", "there");
+/// ```
+#[macro_export]
+macro_rules! pr_crit (
+    ($($arg:tt)*) => (
+        $crate::print_macro!($crate::print::format_strings::CRIT, false, $($arg)*)
+    )
+);
+
+/// Prints an error-level message (level 3).
+///
+/// Use this level for error conditions.
+///
+/// Equivalent to the kernel's [`pr_err`] macro.
+///
+/// Mimics the interface of [`std::print!`]. See [`core::fmt`] and
+/// [`alloc::format!`] for information about the formatting syntax.
+///
+/// [`pr_err`]: https://www.kernel.org/doc/html/latest/core-api/printk-basics.html#c.pr_err
+/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::prelude::*;
+/// pr_err!("hello {}\n", "there");
+/// ```
+#[macro_export]
+macro_rules! pr_err (
+    ($($arg:tt)*) => (
+        $crate::print_macro!($crate::print::format_strings::ERR, false, $($arg)*)
+    )
+);
+
+/// Prints a warning-level message (level 4).
+///
+/// Use this level for warning conditions.
+///
+/// Equivalent to the kernel's [`pr_warn`] macro.
+///
+/// Mimics the interface of [`std::print!`]. See [`core::fmt`] and
+/// [`alloc::format!`] for information about the formatting syntax.
+///
+/// [`pr_warn`]: https://www.kernel.org/doc/html/latest/core-api/printk-basics.html#c.pr_warn
+/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::prelude::*;
+/// pr_warn!("hello {}\n", "there");
+/// ```
+#[macro_export]
+macro_rules! pr_warn (
+    ($($arg:tt)*) => (
+        $crate::print_macro!($crate::print::format_strings::WARNING, false, $($arg)*)
+    )
+);
+
+/// Prints a notice-level message (level 5).
+///
+/// Use this level for normal but significant conditions.
+///
+/// Equivalent to the kernel's [`pr_notice`] macro.
+///
+/// Mimics the interface of [`std::print!`]. See [`core::fmt`] and
+/// [`alloc::format!`] for information about the formatting syntax.
+///
+/// [`pr_notice`]: https://www.kernel.org/doc/html/latest/core-api/printk-basics.html#c.pr_notice
+/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::prelude::*;
+/// pr_notice!("hello {}\n", "there");
+/// ```
+#[macro_export]
+macro_rules! pr_notice (
+    ($($arg:tt)*) => (
+        $crate::print_macro!($crate::print::format_strings::NOTICE, false, $($arg)*)
+    )
+);
+
+/// Prints an info-level message (level 6).
+///
+/// Use this level for informational messages.
+///
+/// Equivalent to the kernel's [`pr_info`] macro.
+///
+/// Mimics the interface of [`std::print!`]. See [`core::fmt`] and
+/// [`alloc::format!`] for information about the formatting syntax.
+///
+/// [`pr_info`]: https://www.kernel.org/doc/html/latest/core-api/printk-basics.html#c.pr_info
+/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::prelude::*;
+/// pr_info!("hello {}\n", "there");
+/// ```
+#[macro_export]
+#[doc(alias = "print")]
+macro_rules! pr_info (
+    ($($arg:tt)*) => (
+        $crate::print_macro!($crate::print::format_strings::INFO, false, $($arg)*)
+    )
+);
+
+/// Prints a debug-level message (level 7).
+///
+/// Use this level for debug messages.
+///
+/// Equivalent to the kernel's [`pr_debug`] macro, except that it doesn't support dynamic debug
+/// yet.
+///
+/// Mimics the interface of [`std::print!`]. See [`core::fmt`] and
+/// [`alloc::format!`] for information about the formatting syntax.
+///
+/// [`pr_debug`]: https://www.kernel.org/doc/html/latest/core-api/printk-basics.html#c.pr_debug
+/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::prelude::*;
+/// pr_debug!("hello {}\n", "there");
+/// ```
+#[macro_export]
+#[doc(alias = "print")]
+macro_rules! pr_debug (
+    ($($arg:tt)*) => (
+        if cfg!(debug_assertions) {
+            $crate::print_macro!($crate::print::format_strings::DEBUG, false, $($arg)*)
+        }
+    )
+);
+
+/// Continues a previous log message in the same line.
+///
+/// Use only when continuing a previous `pr_*!` macro (e.g. [`pr_info!`]).
+///
+/// Equivalent to the kernel's [`pr_cont`] macro.
+///
+/// Mimics the interface of [`std::print!`]. See [`core::fmt`] and
+/// [`alloc::format!`] for information about the formatting syntax.
+///
+/// [`pr_cont`]: https://www.kernel.org/doc/html/latest/core-api/printk-basics.html#c.pr_cont
+/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::prelude::*;
+/// # use kernel::pr_cont;
+/// pr_info!("hello");
+/// pr_cont!(" {}\n", "there");
+/// ```
+#[macro_export]
+macro_rules! pr_cont (
+    ($($arg:tt)*) => (
+        $crate::print_macro!($crate::print::format_strings::CONT, true, $($arg)*)
+    )
+);
diff --git a/rust/kernel/random.rs b/rust/kernel/random.rs
new file mode 100644
index 000000000000..6e0e847f909e
--- /dev/null
+++ b/rust/kernel/random.rs
@@ -0,0 +1,50 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Random numbers.
+//!
+//! C header: [`include/linux/random.h`](../../../../include/linux/random.h)
+
+use core::convert::TryInto;
+
+use crate::{bindings, c_types, error::code::*, Error, Result};
+
+/// Fills a byte slice with random bytes generated from the kernel's CSPRNG.
+///
+/// Ensures that the CSPRNG has been seeded before generating any random bytes,
+/// and will block until it is ready.
+pub fn getrandom(dest: &mut [u8]) -> Result {
+    let res = unsafe { bindings::wait_for_random_bytes() };
+    if res != 0 {
+        return Err(Error::from_kernel_errno(res));
+    }
+
+    unsafe {
+        bindings::get_random_bytes(
+            dest.as_mut_ptr() as *mut c_types::c_void,
+            dest.len().try_into()?,
+        );
+    }
+    Ok(())
+}
+
+/// Fills a byte slice with random bytes generated from the kernel's CSPRNG.
+///
+/// If the CSPRNG is not yet seeded, returns an `Err(EAGAIN)` immediately.
+pub fn getrandom_nonblock(dest: &mut [u8]) -> Result {
+    if !unsafe { bindings::rng_is_initialized() } {
+        return Err(EAGAIN);
+    }
+    getrandom(dest)
+}
+
+/// Contributes the contents of a byte slice to the kernel's entropy pool.
+///
+/// Does *not* credit the kernel entropy counter though.
+pub fn add_randomness(data: &[u8]) {
+    unsafe {
+        bindings::add_device_randomness(
+            data.as_ptr() as *const c_types::c_void,
+            data.len().try_into().unwrap(),
+        );
+    }
+}
diff --git a/rust/kernel/raw_list.rs b/rust/kernel/raw_list.rs
new file mode 100644
index 000000000000..4bc4f4a24ad5
--- /dev/null
+++ b/rust/kernel/raw_list.rs
@@ -0,0 +1,361 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Raw lists.
+//!
+//! TODO: This module is a work in progress.
+
+use core::{
+    cell::UnsafeCell,
+    ptr,
+    ptr::NonNull,
+    sync::atomic::{AtomicBool, Ordering},
+};
+
+/// A descriptor of list elements.
+///
+/// It describes the type of list elements and provides a function to determine how to get the
+/// links to be used on a list.
+///
+/// A type that may be in multiple lists simultaneously neneds to implement one of these for each
+/// simultaneous list.
+pub trait GetLinks {
+    /// The type of the entries in the list.
+    type EntryType: ?Sized;
+
+    /// Returns the links to be used when linking an entry within a list.
+    fn get_links(data: &Self::EntryType) -> &Links<Self::EntryType>;
+}
+
+/// The links used to link an object on a linked list.
+///
+/// Instances of this type are usually embedded in structures and returned in calls to
+/// [`GetLinks::get_links`].
+pub struct Links<T: ?Sized> {
+    inserted: AtomicBool,
+    entry: UnsafeCell<ListEntry<T>>,
+}
+
+impl<T: ?Sized> Links<T> {
+    /// Constructs a new [`Links`] instance that isn't inserted on any lists yet.
+    pub fn new() -> Self {
+        Self {
+            inserted: AtomicBool::new(false),
+            entry: UnsafeCell::new(ListEntry::new()),
+        }
+    }
+
+    fn acquire_for_insertion(&self) -> bool {
+        self.inserted
+            .compare_exchange(false, true, Ordering::Acquire, Ordering::Relaxed)
+            .is_ok()
+    }
+
+    fn release_after_removal(&self) {
+        self.inserted.store(false, Ordering::Release);
+    }
+}
+
+impl<T: ?Sized> Default for Links<T> {
+    fn default() -> Self {
+        Self::new()
+    }
+}
+
+struct ListEntry<T: ?Sized> {
+    next: Option<NonNull<T>>,
+    prev: Option<NonNull<T>>,
+}
+
+impl<T: ?Sized> ListEntry<T> {
+    fn new() -> Self {
+        Self {
+            next: None,
+            prev: None,
+        }
+    }
+}
+
+/// A linked list.
+///
+/// # Invariants
+///
+/// The links of objects added to a list are owned by the list.
+pub(crate) struct RawList<G: GetLinks> {
+    head: Option<NonNull<G::EntryType>>,
+}
+
+impl<G: GetLinks> RawList<G> {
+    pub(crate) fn new() -> Self {
+        Self { head: None }
+    }
+
+    pub(crate) fn is_empty(&self) -> bool {
+        self.head.is_none()
+    }
+
+    fn insert_after_priv(
+        &mut self,
+        existing: &G::EntryType,
+        new_entry: &mut ListEntry<G::EntryType>,
+        new_ptr: Option<NonNull<G::EntryType>>,
+    ) {
+        {
+            // SAFETY: It's safe to get the previous entry of `existing` because the list cannot
+            // change.
+            let existing_links = unsafe { &mut *G::get_links(existing).entry.get() };
+            new_entry.next = existing_links.next;
+            existing_links.next = new_ptr;
+        }
+
+        new_entry.prev = Some(NonNull::from(existing));
+
+        // SAFETY: It's safe to get the next entry of `existing` because the list cannot change.
+        let next_links =
+            unsafe { &mut *G::get_links(new_entry.next.unwrap().as_ref()).entry.get() };
+        next_links.prev = new_ptr;
+    }
+
+    /// Inserts the given object after `existing`.
+    ///
+    /// # Safety
+    ///
+    /// Callers must ensure that `existing` points to a valid entry that is on the list.
+    pub(crate) unsafe fn insert_after(
+        &mut self,
+        existing: &G::EntryType,
+        new: &G::EntryType,
+    ) -> bool {
+        let links = G::get_links(new);
+        if !links.acquire_for_insertion() {
+            // Nothing to do if already inserted.
+            return false;
+        }
+
+        // SAFETY: The links are now owned by the list, so it is safe to get a mutable reference.
+        let new_entry = unsafe { &mut *links.entry.get() };
+        self.insert_after_priv(existing, new_entry, Some(NonNull::from(new)));
+        true
+    }
+
+    fn push_back_internal(&mut self, new: &G::EntryType) -> bool {
+        let links = G::get_links(new);
+        if !links.acquire_for_insertion() {
+            // Nothing to do if already inserted.
+            return false;
+        }
+
+        // SAFETY: The links are now owned by the list, so it is safe to get a mutable reference.
+        let new_entry = unsafe { &mut *links.entry.get() };
+        let new_ptr = Some(NonNull::from(new));
+        match self.back() {
+            // SAFETY: `back` is valid as the list cannot change.
+            Some(back) => self.insert_after_priv(unsafe { back.as_ref() }, new_entry, new_ptr),
+            None => {
+                self.head = new_ptr;
+                new_entry.next = new_ptr;
+                new_entry.prev = new_ptr;
+            }
+        }
+        true
+    }
+
+    pub(crate) unsafe fn push_back(&mut self, new: &G::EntryType) -> bool {
+        self.push_back_internal(new)
+    }
+
+    fn remove_internal(&mut self, data: &G::EntryType) -> bool {
+        let links = G::get_links(data);
+
+        // SAFETY: The links are now owned by the list, so it is safe to get a mutable reference.
+        let entry = unsafe { &mut *links.entry.get() };
+        let next = if let Some(next) = entry.next {
+            next
+        } else {
+            // Nothing to do if the entry is not on the list.
+            return false;
+        };
+
+        if ptr::eq(data, next.as_ptr()) {
+            // We're removing the only element.
+            self.head = None
+        } else {
+            // Update the head if we're removing it.
+            if let Some(raw_head) = self.head {
+                if ptr::eq(data, raw_head.as_ptr()) {
+                    self.head = Some(next);
+                }
+            }
+
+            // SAFETY: It's safe to get the previous entry because the list cannot change.
+            unsafe { &mut *G::get_links(entry.prev.unwrap().as_ref()).entry.get() }.next =
+                entry.next;
+
+            // SAFETY: It's safe to get the next entry because the list cannot change.
+            unsafe { &mut *G::get_links(next.as_ref()).entry.get() }.prev = entry.prev;
+        }
+
+        // Reset the links of the element we're removing so that we know it's not on any list.
+        entry.next = None;
+        entry.prev = None;
+        links.release_after_removal();
+        true
+    }
+
+    /// Removes the given entry.
+    ///
+    /// # Safety
+    ///
+    /// Callers must ensure that `data` is either on this list or in no list. It being on another
+    /// list leads to memory unsafety.
+    pub(crate) unsafe fn remove(&mut self, data: &G::EntryType) -> bool {
+        self.remove_internal(data)
+    }
+
+    fn pop_front_internal(&mut self) -> Option<NonNull<G::EntryType>> {
+        let head = self.head?;
+        // SAFETY: The head is on the list as we just got it from there and it cannot change.
+        unsafe { self.remove(head.as_ref()) };
+        Some(head)
+    }
+
+    pub(crate) fn pop_front(&mut self) -> Option<NonNull<G::EntryType>> {
+        self.pop_front_internal()
+    }
+
+    pub(crate) fn front(&self) -> Option<NonNull<G::EntryType>> {
+        self.head
+    }
+
+    pub(crate) fn back(&self) -> Option<NonNull<G::EntryType>> {
+        // SAFETY: The links of head are owned by the list, so it is safe to get a reference.
+        unsafe { &*G::get_links(self.head?.as_ref()).entry.get() }.prev
+    }
+
+    pub(crate) fn cursor_front(&self) -> Cursor<'_, G> {
+        Cursor::new(self, self.front())
+    }
+
+    pub(crate) fn cursor_front_mut(&mut self) -> CursorMut<'_, G> {
+        CursorMut::new(self, self.front())
+    }
+}
+
+struct CommonCursor<G: GetLinks> {
+    cur: Option<NonNull<G::EntryType>>,
+}
+
+impl<G: GetLinks> CommonCursor<G> {
+    fn new(cur: Option<NonNull<G::EntryType>>) -> Self {
+        Self { cur }
+    }
+
+    fn move_next(&mut self, list: &RawList<G>) {
+        match self.cur.take() {
+            None => self.cur = list.head,
+            Some(cur) => {
+                if let Some(head) = list.head {
+                    // SAFETY: We have a shared ref to the linked list, so the links can't change.
+                    let links = unsafe { &*G::get_links(cur.as_ref()).entry.get() };
+                    if links.next.unwrap() != head {
+                        self.cur = links.next;
+                    }
+                }
+            }
+        }
+    }
+
+    fn move_prev(&mut self, list: &RawList<G>) {
+        match list.head {
+            None => self.cur = None,
+            Some(head) => {
+                let next = match self.cur.take() {
+                    None => head,
+                    Some(cur) => {
+                        if cur == head {
+                            return;
+                        }
+                        cur
+                    }
+                };
+                // SAFETY: There's a shared ref to the list, so the links can't change.
+                let links = unsafe { &*G::get_links(next.as_ref()).entry.get() };
+                self.cur = links.prev;
+            }
+        }
+    }
+}
+
+/// A list cursor that allows traversing a linked list and inspecting elements.
+pub struct Cursor<'a, G: GetLinks> {
+    cursor: CommonCursor<G>,
+    list: &'a RawList<G>,
+}
+
+impl<'a, G: GetLinks> Cursor<'a, G> {
+    fn new(list: &'a RawList<G>, cur: Option<NonNull<G::EntryType>>) -> Self {
+        Self {
+            list,
+            cursor: CommonCursor::new(cur),
+        }
+    }
+
+    /// Returns the element the cursor is currently positioned on.
+    pub fn current(&self) -> Option<&'a G::EntryType> {
+        let cur = self.cursor.cur?;
+        // SAFETY: Objects must be kept alive while on the list.
+        Some(unsafe { &*cur.as_ptr() })
+    }
+
+    /// Moves the cursor to the next element.
+    pub fn move_next(&mut self) {
+        self.cursor.move_next(self.list);
+    }
+}
+
+pub(crate) struct CursorMut<'a, G: GetLinks> {
+    cursor: CommonCursor<G>,
+    list: &'a mut RawList<G>,
+}
+
+impl<'a, G: GetLinks> CursorMut<'a, G> {
+    fn new(list: &'a mut RawList<G>, cur: Option<NonNull<G::EntryType>>) -> Self {
+        Self {
+            list,
+            cursor: CommonCursor::new(cur),
+        }
+    }
+
+    pub(crate) fn current(&mut self) -> Option<&mut G::EntryType> {
+        let cur = self.cursor.cur?;
+        // SAFETY: Objects must be kept alive while on the list.
+        Some(unsafe { &mut *cur.as_ptr() })
+    }
+
+    /// Removes the entry the cursor is pointing to and advances the cursor to the next entry. It
+    /// returns a raw pointer to the removed element (if one is removed).
+    pub(crate) fn remove_current(&mut self) -> Option<NonNull<G::EntryType>> {
+        let entry = self.cursor.cur?;
+        self.cursor.move_next(self.list);
+        // SAFETY: The entry is on the list as we just got it from there and it cannot change.
+        unsafe { self.list.remove(entry.as_ref()) };
+        Some(entry)
+    }
+
+    pub(crate) fn peek_next(&mut self) -> Option<&mut G::EntryType> {
+        let mut new = CommonCursor::new(self.cursor.cur);
+        new.move_next(self.list);
+        // SAFETY: Objects must be kept alive while on the list.
+        Some(unsafe { &mut *new.cur?.as_ptr() })
+    }
+
+    pub(crate) fn peek_prev(&mut self) -> Option<&mut G::EntryType> {
+        let mut new = CommonCursor::new(self.cursor.cur);
+        new.move_prev(self.list);
+        // SAFETY: Objects must be kept alive while on the list.
+        Some(unsafe { &mut *new.cur?.as_ptr() })
+    }
+
+    pub(crate) fn move_next(&mut self) {
+        self.cursor.move_next(self.list);
+    }
+}
diff --git a/rust/kernel/rbtree.rs b/rust/kernel/rbtree.rs
new file mode 100644
index 000000000000..71112e306ec3
--- /dev/null
+++ b/rust/kernel/rbtree.rs
@@ -0,0 +1,562 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Red-black trees.
+//!
+//! C header: [`include/linux/rbtree.h`](../../../../include/linux/rbtree.h)
+//!
+//! Reference: <https://www.kernel.org/doc/html/latest/core-api/rbtree.html>
+
+use crate::{bindings, Result};
+use alloc::boxed::Box;
+use core::{
+    cmp::{Ord, Ordering},
+    iter::{IntoIterator, Iterator},
+    marker::PhantomData,
+    mem::MaybeUninit,
+    ptr::{addr_of_mut, NonNull},
+};
+
+struct Node<K, V> {
+    links: bindings::rb_node,
+    key: K,
+    value: V,
+}
+
+/// A red-black tree with owned nodes.
+///
+/// It is backed by the kernel C red-black trees.
+///
+/// # Invariants
+///
+/// Non-null parent/children pointers stored in instances of the `rb_node` C struct are always
+/// valid, and pointing to a field of our internal representation of a node.
+///
+/// # Examples
+///
+/// In the example below we do several operations on a tree. We note that insertions may fail if
+/// the system is out of memory.
+///
+/// ```
+/// # use kernel::prelude::*;
+/// use kernel::rbtree::RBTree;
+///
+/// fn rbtest() -> Result {
+///     // Create a new tree.
+///     let mut tree = RBTree::new();
+///
+///     // Insert three elements.
+///     tree.try_insert(20, 200)?;
+///     tree.try_insert(10, 100)?;
+///     tree.try_insert(30, 300)?;
+///
+///     // Check the nodes we just inserted.
+///     {
+///         let mut iter = tree.iter();
+///         assert_eq!(iter.next().unwrap(), (&10, &100));
+///         assert_eq!(iter.next().unwrap(), (&20, &200));
+///         assert_eq!(iter.next().unwrap(), (&30, &300));
+///         assert!(iter.next().is_none());
+///     }
+///
+///     // Print all elements.
+///     for (key, value) in &tree {
+///         pr_info!("{} = {}\n", key, value);
+///     }
+///
+///     // Replace one of the elements.
+///     tree.try_insert(10, 1000)?;
+///
+///     // Check that the tree reflects the replacement.
+///     {
+///         let mut iter = tree.iter();
+///         assert_eq!(iter.next().unwrap(), (&10, &1000));
+///         assert_eq!(iter.next().unwrap(), (&20, &200));
+///         assert_eq!(iter.next().unwrap(), (&30, &300));
+///         assert!(iter.next().is_none());
+///     }
+///
+///     // Change the value of one of the elements.
+///     *tree.get_mut(&30).unwrap() = 3000;
+///
+///     // Check that the tree reflects the update.
+///     {
+///         let mut iter = tree.iter();
+///         assert_eq!(iter.next().unwrap(), (&10, &1000));
+///         assert_eq!(iter.next().unwrap(), (&20, &200));
+///         assert_eq!(iter.next().unwrap(), (&30, &3000));
+///         assert!(iter.next().is_none());
+///     }
+///
+///     // Remove an element.
+///     tree.remove(&10);
+///
+///     // Check that the tree reflects the removal.
+///     {
+///         let mut iter = tree.iter();
+///         assert_eq!(iter.next().unwrap(), (&20, &200));
+///         assert_eq!(iter.next().unwrap(), (&30, &3000));
+///         assert!(iter.next().is_none());
+///     }
+///
+///     // Update all values.
+///     for value in tree.values_mut() {
+///         *value *= 10;
+///     }
+///
+///     // Check that the tree reflects the changes to values.
+///     {
+///         let mut iter = tree.iter();
+///         assert_eq!(iter.next().unwrap(), (&20, &2000));
+///         assert_eq!(iter.next().unwrap(), (&30, &30000));
+///         assert!(iter.next().is_none());
+///     }
+///
+///     Ok(())
+/// }
+/// ```
+///
+/// In the example below, we first allocate a node, acquire a spinlock, then insert the node into
+/// the tree. This is useful when the insertion context does not allow sleeping, for example, when
+/// holding a spinlock.
+///
+/// ```
+/// # use kernel::prelude::*;
+/// use kernel::{rbtree::RBTree, sync::SpinLock};
+///
+/// fn insert_test(tree: &SpinLock<RBTree<u32, u32>>) -> Result {
+///     // Pre-allocate node. This may fail (as it allocates memory).
+///     let node = RBTree::try_allocate_node(10, 100)?;
+///
+///     // Insert node while holding the lock. It is guaranteed to succeed with no allocation
+///     // attempts.
+///     let mut guard = tree.lock();
+///     guard.insert(node);
+///     Ok(())
+/// }
+/// ```
+///
+/// In the example below, we reuse an existing node allocation from an element we removed.
+///
+/// ```
+/// # use kernel::prelude::*;
+/// use kernel::rbtree::RBTree;
+///
+/// fn reuse_test() -> Result {
+///     // Create a new tree.
+///     let mut tree = RBTree::new();
+///
+///     // Insert three elements.
+///     tree.try_insert(20, 200)?;
+///     tree.try_insert(10, 100)?;
+///     tree.try_insert(30, 300)?;
+///
+///     // Check the nodes we just inserted.
+///     {
+///         let mut iter = tree.iter();
+///         assert_eq!(iter.next().unwrap(), (&10, &100));
+///         assert_eq!(iter.next().unwrap(), (&20, &200));
+///         assert_eq!(iter.next().unwrap(), (&30, &300));
+///         assert!(iter.next().is_none());
+///     }
+///
+///     // Remove a node, getting back ownership of it.
+///     let existing = tree.remove_node(&30).unwrap();
+///
+///     // Check that the tree reflects the removal.
+///     {
+///         let mut iter = tree.iter();
+///         assert_eq!(iter.next().unwrap(), (&10, &100));
+///         assert_eq!(iter.next().unwrap(), (&20, &200));
+///         assert!(iter.next().is_none());
+///     }
+///
+///     // Turn the node into a reservation so that we can reuse it with a different key/value.
+///     let reservation = existing.into_reservation();
+///
+///     // Insert a new node into the tree, reusing the previous allocation. This is guaranteed to
+///     // succeed (no memory allocations).
+///     tree.insert(reservation.into_node(15, 150));
+///
+///     // Check that the tree reflect the new insertion.
+///     {
+///         let mut iter = tree.iter();
+///         assert_eq!(iter.next().unwrap(), (&10, &100));
+///         assert_eq!(iter.next().unwrap(), (&15, &150));
+///         assert_eq!(iter.next().unwrap(), (&20, &200));
+///         assert!(iter.next().is_none());
+///     }
+///
+///     Ok(())
+/// }
+/// ```
+pub struct RBTree<K, V> {
+    root: bindings::rb_root,
+    _p: PhantomData<Node<K, V>>,
+}
+
+impl<K, V> RBTree<K, V> {
+    /// Creates a new and empty tree.
+    pub fn new() -> Self {
+        Self {
+            // INVARIANT: There are no nodes in the tree, so the invariant holds vacuously.
+            root: bindings::rb_root::default(),
+            _p: PhantomData,
+        }
+    }
+
+    /// Tries to insert a new value into the tree.
+    ///
+    /// It overwrites a node if one already exists with the same key and returns it (containing the
+    /// key/value pair). Returns [`None`] if a node with the same key didn't already exist.
+    ///
+    /// Returns an error if it cannot allocate memory for the new node.
+    pub fn try_insert(&mut self, key: K, value: V) -> Result<Option<RBTreeNode<K, V>>>
+    where
+        K: Ord,
+    {
+        Ok(self.insert(Self::try_allocate_node(key, value)?))
+    }
+
+    /// Allocates memory for a node to be eventually initialised and inserted into the tree via a
+    /// call to [`RBTree::insert`].
+    pub fn try_reserve_node() -> Result<RBTreeNodeReservation<K, V>> {
+        Ok(RBTreeNodeReservation {
+            node: Box::try_new(MaybeUninit::uninit())?,
+        })
+    }
+
+    /// Allocates and initialiases a node that can be inserted into the tree via
+    /// [`RBTree::insert`].
+    pub fn try_allocate_node(key: K, value: V) -> Result<RBTreeNode<K, V>> {
+        Ok(Self::try_reserve_node()?.into_node(key, value))
+    }
+
+    /// Inserts a new node into the tree.
+    ///
+    /// It overwrites a node if one already exists with the same key and returns it (containing the
+    /// key/value pair). Returns [`None`] if a node with the same key didn't already exist.
+    ///
+    /// This function always succeeds.
+    pub fn insert(&mut self, node: RBTreeNode<K, V>) -> Option<RBTreeNode<K, V>>
+    where
+        K: Ord,
+    {
+        let RBTreeNode { node } = node;
+        let node = Box::into_raw(node);
+        // SAFETY: `node` is valid at least until we call `Box::from_raw`, which only happens when
+        // the node is removed or replaced.
+        let node_links = unsafe { addr_of_mut!((*node).links) };
+        let mut new_link: &mut *mut bindings::rb_node = &mut self.root.rb_node;
+        let mut parent = core::ptr::null_mut();
+        while !new_link.is_null() {
+            let this = crate::container_of!(*new_link, Node<K, V>, links);
+
+            parent = *new_link;
+
+            // SAFETY: `this` is a non-null node so it is valid by the type invariants. `node` is
+            // valid until the node is removed.
+            match unsafe { (*node).key.cmp(&(*this).key) } {
+                // SAFETY: `parent` is a non-null node so it is valid by the type invariants.
+                Ordering::Less => new_link = unsafe { &mut (*parent).rb_left },
+                // SAFETY: `parent` is a non-null node so it is valid by the type invariants.
+                Ordering::Greater => new_link = unsafe { &mut (*parent).rb_right },
+                Ordering::Equal => {
+                    // INVARIANT: We are replacing an existing node with a new one, which is valid.
+                    // It remains valid because we "forgot" it with `Box::into_raw`.
+                    // SAFETY: All pointers are non-null and valid (parent, despite the name, really
+                    // is the node we're replacing).
+                    unsafe { bindings::rb_replace_node(parent, node_links, &mut self.root) };
+
+                    // INVARIANT: The node is being returned and the caller may free it, however,
+                    // it was removed from the tree. So the invariants still hold.
+                    return Some(RBTreeNode {
+                        // SAFETY: `this` was a node in the tree, so it is valid.
+                        node: unsafe { Box::from_raw(this as _) },
+                    });
+                }
+            }
+        }
+
+        // INVARIANT: We are linking in a new node, which is valid. It remains valid because we
+        // "forgot" it with `Box::into_raw`.
+        // SAFETY: All pointers are non-null and valid (`*new_link` is null, but `new_link` is a
+        // mutable reference).
+        unsafe { bindings::rb_link_node(node_links, parent, new_link) };
+
+        // SAFETY: All pointers are valid. `node` has just been inserted into the tree.
+        unsafe { bindings::rb_insert_color(node_links, &mut self.root) };
+        None
+    }
+
+    /// Returns a node with the given key, if one exists.
+    fn find(&self, key: &K) -> Option<NonNull<Node<K, V>>>
+    where
+        K: Ord,
+    {
+        let mut node = self.root.rb_node;
+        while !node.is_null() {
+            let this = crate::container_of!(node, Node<K, V>, links);
+            // SAFETY: `this` is a non-null node so it is valid by the type invariants.
+            node = match key.cmp(unsafe { &(*this).key }) {
+                // SAFETY: `node` is a non-null node so it is valid by the type invariants.
+                Ordering::Less => unsafe { (*node).rb_left },
+                // SAFETY: `node` is a non-null node so it is valid by the type invariants.
+                Ordering::Greater => unsafe { (*node).rb_right },
+                Ordering::Equal => return NonNull::new(this as _),
+            }
+        }
+        None
+    }
+
+    /// Returns a reference to the value corresponding to the key.
+    pub fn get(&self, key: &K) -> Option<&V>
+    where
+        K: Ord,
+    {
+        // SAFETY: The `find` return value is a node in the tree, so it is valid.
+        self.find(key).map(|node| unsafe { &node.as_ref().value })
+    }
+
+    /// Returns a mutable reference to the value corresponding to the key.
+    pub fn get_mut(&mut self, key: &K) -> Option<&mut V>
+    where
+        K: Ord,
+    {
+        // SAFETY: The `find` return value is a node in the tree, so it is valid.
+        self.find(key)
+            .map(|mut node| unsafe { &mut node.as_mut().value })
+    }
+
+    /// Removes the node with the given key from the tree.
+    ///
+    /// It returns the node that was removed if one exists, or [`None`] otherwise.
+    pub fn remove_node(&mut self, key: &K) -> Option<RBTreeNode<K, V>>
+    where
+        K: Ord,
+    {
+        let mut node = self.find(key)?;
+
+        // SAFETY: The `find` return value is a node in the tree, so it is valid.
+        unsafe { bindings::rb_erase(&mut node.as_mut().links, &mut self.root) };
+
+        // INVARIANT: The node is being returned and the caller may free it, however, it was
+        // removed from the tree. So the invariants still hold.
+        Some(RBTreeNode {
+            // SAFETY: The `find` return value was a node in the tree, so it is valid.
+            node: unsafe { Box::from_raw(node.as_ptr()) },
+        })
+    }
+
+    /// Removes the node with the given key from the tree.
+    ///
+    /// It returns the value that was removed if one exists, or [`None`] otherwise.
+    pub fn remove(&mut self, key: &K) -> Option<V>
+    where
+        K: Ord,
+    {
+        let node = self.remove_node(key)?;
+        let RBTreeNode { node } = node;
+        let Node {
+            links: _,
+            key: _,
+            value,
+        } = *node;
+        Some(value)
+    }
+
+    /// Returns an iterator over the tree nodes, sorted by key.
+    pub fn iter(&self) -> RBTreeIterator<'_, K, V> {
+        RBTreeIterator {
+            _tree: PhantomData,
+            // SAFETY: `root` is valid as it's embedded in `self` and we have a valid `self`.
+            next: unsafe { bindings::rb_first(&self.root) },
+        }
+    }
+
+    /// Returns a mutable iterator over the tree nodes, sorted by key.
+    pub fn iter_mut(&mut self) -> RBTreeIteratorMut<'_, K, V> {
+        RBTreeIteratorMut {
+            _tree: PhantomData,
+            // SAFETY: `root` is valid as it's embedded in `self` and we have a valid `self`.
+            next: unsafe { bindings::rb_first(&self.root) },
+        }
+    }
+
+    /// Returns an iterator over the keys of the nodes in the tree, in sorted order.
+    pub fn keys(&self) -> impl Iterator<Item = &'_ K> {
+        self.iter().map(|(k, _)| k)
+    }
+
+    /// Returns an iterator over the values of the nodes in the tree, sorted by key.
+    pub fn values(&self) -> impl Iterator<Item = &'_ V> {
+        self.iter().map(|(_, v)| v)
+    }
+
+    /// Returns a mutable iterator over the values of the nodes in the tree, sorted by key.
+    pub fn values_mut(&mut self) -> impl Iterator<Item = &'_ mut V> {
+        self.iter_mut().map(|(_, v)| v)
+    }
+}
+
+impl<K, V> Default for RBTree<K, V> {
+    fn default() -> Self {
+        Self::new()
+    }
+}
+
+impl<K, V> Drop for RBTree<K, V> {
+    fn drop(&mut self) {
+        // SAFETY: `root` is valid as it's embedded in `self` and we have a valid `self`.
+        let mut next = unsafe { bindings::rb_first_postorder(&self.root) };
+
+        // INVARIANT: The loop invariant is that all tree nodes from `next` in postorder are valid.
+        while !next.is_null() {
+            let this = crate::container_of!(next, Node<K, V>, links);
+
+            // Find out what the next node is before disposing of the current one.
+            // SAFETY: `next` and all nodes in postorder are still valid.
+            next = unsafe { bindings::rb_next_postorder(next) };
+
+            // INVARIANT: This is the destructor, so we break the type invariant during clean-up,
+            // but it is not observable. The loop invariant is still maintained.
+            // SAFETY: `this` is valid per the loop invariant.
+            unsafe { Box::from_raw(this as *mut Node<K, V>) };
+        }
+    }
+}
+
+impl<'a, K, V> IntoIterator for &'a RBTree<K, V> {
+    type Item = (&'a K, &'a V);
+    type IntoIter = RBTreeIterator<'a, K, V>;
+
+    fn into_iter(self) -> Self::IntoIter {
+        self.iter()
+    }
+}
+
+/// An iterator over the nodes of a [`RBTree`].
+///
+/// Instances are created by calling [`RBTree::iter`].
+pub struct RBTreeIterator<'a, K, V> {
+    _tree: PhantomData<&'a RBTree<K, V>>,
+    next: *mut bindings::rb_node,
+}
+
+impl<'a, K, V> Iterator for RBTreeIterator<'a, K, V> {
+    type Item = (&'a K, &'a V);
+
+    fn next(&mut self) -> Option<Self::Item> {
+        if self.next.is_null() {
+            return None;
+        }
+
+        let cur = crate::container_of!(self.next, Node<K, V>, links);
+
+        // SAFETY: The reference to the tree used to create the iterator outlives the iterator, so
+        // the tree cannot change. By the tree invariant, all nodes are valid.
+        self.next = unsafe { bindings::rb_next(self.next) };
+
+        // SAFETY: By the same reasoning above, it is safe to dereference the node. Additionally,
+        // it is ok to return a reference to members because the iterator must outlive it.
+        Some(unsafe { (&(*cur).key, &(*cur).value) })
+    }
+}
+
+impl<'a, K, V> IntoIterator for &'a mut RBTree<K, V> {
+    type Item = (&'a K, &'a mut V);
+    type IntoIter = RBTreeIteratorMut<'a, K, V>;
+
+    fn into_iter(self) -> Self::IntoIter {
+        self.iter_mut()
+    }
+}
+
+/// A mutable iterator over the nodes of a [`RBTree`].
+///
+/// Instances are created by calling [`RBTree::iter_mut`].
+pub struct RBTreeIteratorMut<'a, K, V> {
+    _tree: PhantomData<&'a RBTree<K, V>>,
+    next: *mut bindings::rb_node,
+}
+
+impl<'a, K, V> Iterator for RBTreeIteratorMut<'a, K, V> {
+    type Item = (&'a K, &'a mut V);
+
+    fn next(&mut self) -> Option<Self::Item> {
+        if self.next.is_null() {
+            return None;
+        }
+
+        let cur = crate::container_of!(self.next, Node<K, V>, links) as *mut Node<K, V>;
+
+        // SAFETY: The reference to the tree used to create the iterator outlives the iterator, so
+        // the tree cannot change (except for the value of previous nodes, but those don't affect
+        // the iteration process). By the tree invariant, all nodes are valid.
+        self.next = unsafe { bindings::rb_next(self.next) };
+
+        // SAFETY: By the same reasoning above, it is safe to dereference the node. Additionally,
+        // it is ok to return a reference to members because the iterator must outlive it.
+        Some(unsafe { (&(*cur).key, &mut (*cur).value) })
+    }
+}
+
+/// A memory reservation for a red-black tree node.
+///
+/// It contains the memory needed to hold a node that can be inserted into a red-black tree. One
+/// can be obtained by directly allocating it ([`RBTree::try_reserve_node`]) or by "uninitialising"
+/// ([`RBTreeNode::into_reservation`]) an actual node (usually returned by some operation like
+/// removal from a tree).
+pub struct RBTreeNodeReservation<K, V> {
+    node: Box<MaybeUninit<Node<K, V>>>,
+}
+
+impl<K, V> RBTreeNodeReservation<K, V> {
+    /// Initialises a node reservation.
+    ///
+    /// It then becomes an [`RBTreeNode`] that can be inserted into a tree.
+    pub fn into_node(mut self, key: K, value: V) -> RBTreeNode<K, V> {
+        let node_ptr = self.node.as_mut_ptr();
+        // SAFETY: `node_ptr` is valid, and so are its fields.
+        unsafe { addr_of_mut!((*node_ptr).links).write(bindings::rb_node::default()) };
+        // SAFETY: `node_ptr` is valid, and so are its fields.
+        unsafe { addr_of_mut!((*node_ptr).key).write(key) };
+        // SAFETY: `node_ptr` is valid, and so are its fields.
+        unsafe { addr_of_mut!((*node_ptr).value).write(value) };
+        let raw = Box::into_raw(self.node);
+        RBTreeNode {
+            // SAFETY: The pointer came from a `MaybeUninit<Node>` whose fields have all been
+            // initialised. Additionally, it has the same layout as `Node`.
+            node: unsafe { Box::from_raw(raw as _) },
+        }
+    }
+}
+
+/// A red-black tree node.
+///
+/// The node is fully initialised (with key and value) and can be inserted into a tree without any
+/// extra allocations or failure paths.
+pub struct RBTreeNode<K, V> {
+    node: Box<Node<K, V>>,
+}
+
+impl<K, V> RBTreeNode<K, V> {
+    /// "Uninitialises" a node.
+    ///
+    /// It then becomes a reservation that can be re-initialised into a different node (i.e., with
+    /// a different key and/or value).
+    ///
+    /// The existing key and value are dropped in-place as part of this operation, that is, memory
+    /// may be freed (but only for the key/value; memory for the node itself is kept for reuse).
+    pub fn into_reservation(self) -> RBTreeNodeReservation<K, V> {
+        let raw = Box::into_raw(self.node);
+        let mut ret = RBTreeNodeReservation {
+            // SAFETY: The pointer came from a valid `Node`, which has the same layout as
+            // `MaybeUninit<Node>`.
+            node: unsafe { Box::from_raw(raw as _) },
+        };
+        // SAFETY: Although the type is `MaybeUninit<Node>`, we know it has been initialised
+        // because it came from a `Node`. So it is safe to drop it.
+        unsafe { core::ptr::drop_in_place(ret.node.as_mut_ptr()) };
+        ret
+    }
+}
diff --git a/rust/kernel/revocable.rs b/rust/kernel/revocable.rs
new file mode 100644
index 000000000000..9cc65ca3a1b6
--- /dev/null
+++ b/rust/kernel/revocable.rs
@@ -0,0 +1,163 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Revocable objects.
+//!
+//! The [`Revocable`] type wraps other types and allows access to them to be revoked. The existence
+//! of a [`RevocableGuard`] ensures that objects remain valid.
+
+use crate::bindings;
+use core::{
+    cell::UnsafeCell,
+    marker::PhantomData,
+    mem::ManuallyDrop,
+    ops::Deref,
+    ptr::drop_in_place,
+    sync::atomic::{AtomicBool, Ordering},
+};
+
+/// An object that can become inaccessible at runtime.
+///
+/// Once access is revoked and all concurrent users complete (i.e., all existing instances of
+/// [`RevocableGuard`] are dropped), the wrapped object is also dropped.
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::revocable::Revocable;
+///
+/// struct Example {
+///     a: u32,
+///     b: u32,
+/// }
+///
+/// fn add_two(v: &Revocable<Example>) -> Option<u32> {
+///     let guard = v.try_access()?;
+///     Some(guard.a + guard.b)
+/// }
+///
+/// fn example() {
+///     let v = Revocable::new(Example { a: 10, b: 20 });
+///     assert_eq!(add_two(&v), Some(30));
+///     v.revoke();
+///     assert_eq!(add_two(&v), None);
+/// }
+/// ```
+pub struct Revocable<T: ?Sized> {
+    is_available: AtomicBool,
+    data: ManuallyDrop<UnsafeCell<T>>,
+}
+
+// SAFETY: `Revocable` is `Send` if the wrapped object is also `Send`. This is because while the
+// functionality exposed by `Revocable` can be accessed from any thread/CPU, it is possible that
+// this isn't supported by the wrapped object.
+unsafe impl<T: ?Sized + Send> Send for Revocable<T> {}
+
+// SAFETY: `Revocable` is `Sync` if the wrapped object is both `Send` and `Sync`. We require `Send`
+// from the wrapped object as well because  of `Revocable::revoke`, which can trigger the `Drop`
+// implementation of the wrapped object from an arbitrary thread.
+unsafe impl<T: ?Sized + Sync + Send> Sync for Revocable<T> {}
+
+impl<T> Revocable<T> {
+    /// Creates a new revocable instance of the given data.
+    pub fn new(data: T) -> Self {
+        Self {
+            is_available: AtomicBool::new(true),
+            data: ManuallyDrop::new(UnsafeCell::new(data)),
+        }
+    }
+}
+
+impl<T: ?Sized> Revocable<T> {
+    /// Tries to access the \[revocable\] wrapped object.
+    ///
+    /// Returns `None` if the object has been revoked and is therefore no longer accessible.
+    ///
+    /// Returns a guard that gives access to the object otherwise; the object is guaranteed to
+    /// remain accessible while the guard is alive. In such cases, callers are not allowed to sleep
+    /// because another CPU may be waiting to complete the revocation of this object.
+    pub fn try_access(&self) -> Option<RevocableGuard<'_, T>> {
+        let guard = RevocableGuard::new(self.data.get());
+        if self.is_available.load(Ordering::Relaxed) {
+            Some(guard)
+        } else {
+            None
+        }
+    }
+
+    /// Revokes access to and drops the wrapped object.
+    ///
+    /// Access to the object is revoked immediately to new callers of [`Revocable::try_access`]. If
+    /// there are concurrent users of the object (i.e., ones that called [`Revocable::try_access`]
+    /// beforehand and still haven't dropped the returned guard), this function waits for the
+    /// concurrent access to complete before dropping the wrapped object.
+    pub fn revoke(&self) {
+        if self
+            .is_available
+            .compare_exchange(true, false, Ordering::Relaxed, Ordering::Relaxed)
+            .is_ok()
+        {
+            // SAFETY: Just an FFI call, there are no further requirements.
+            unsafe { bindings::synchronize_rcu() };
+
+            // SAFETY: We know `self.data` is valid because only one CPU can succeed the
+            // `compare_exchange` above that takes `is_available` from `true` to `false`.
+            unsafe { drop_in_place(self.data.get()) };
+        }
+    }
+}
+
+impl<T: ?Sized> Drop for Revocable<T> {
+    fn drop(&mut self) {
+        // Drop only if the data hasn't been revoked yet (in which case it has already been
+        // dropped).
+        if *self.is_available.get_mut() {
+            // SAFETY: We know `self.data` is valid because no other CPU has changed
+            // `is_available` to `false` yet, and no other CPU can do it anymore because this CPU
+            // holds the only reference (mutable) to `self` now.
+            unsafe { drop_in_place(self.data.get()) };
+        }
+    }
+}
+
+/// A guard that allows access to a revocable object and keeps it alive.
+///
+/// CPUs may not sleep while holding on to [`RevocableGuard`] because it's in atomic context
+/// holding the RCU read-side lock.
+///
+/// # Invariants
+///
+/// The RCU read-side lock is held while the guard is alive.
+pub struct RevocableGuard<'a, T: ?Sized> {
+    data_ref: *const T,
+    _p: PhantomData<&'a ()>,
+}
+
+impl<T: ?Sized> RevocableGuard<'_, T> {
+    fn new(data_ref: *const T) -> Self {
+        // SAFETY: Just an FFI call, there are no further requirements.
+        unsafe { bindings::rcu_read_lock() };
+
+        // INVARIANTS: The RCU read-side lock was just acquired.
+        Self {
+            data_ref,
+            _p: PhantomData,
+        }
+    }
+}
+
+impl<T: ?Sized> Drop for RevocableGuard<'_, T> {
+    fn drop(&mut self) {
+        // SAFETY: By the type invariants, we know that we hold the RCU read-side lock.
+        unsafe { bindings::rcu_read_unlock() };
+    }
+}
+
+impl<T: ?Sized> Deref for RevocableGuard<'_, T> {
+    type Target = T;
+
+    fn deref(&self) -> &Self::Target {
+        // SAFETY: By the type invariants, we hold the rcu read-side lock, so the object is
+        // guaranteed to remain valid.
+        unsafe { &*self.data_ref }
+    }
+}
diff --git a/rust/kernel/security.rs b/rust/kernel/security.rs
new file mode 100644
index 000000000000..2004d01233f4
--- /dev/null
+++ b/rust/kernel/security.rs
@@ -0,0 +1,36 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Linux Security Modules (LSM).
+//!
+//! C header: [`include/linux/security.h`](../../../../include/linux/security.h).
+
+use crate::{bindings, cred::Credential, file::File, to_result, Result};
+
+/// Calls the security modules to determine if the given task can become the manager of a binder
+/// context.
+pub fn binder_set_context_mgr(mgr: &Credential) -> Result {
+    // SAFETY: By the `Credential` invariants, `mgr.ptr` is valid.
+    to_result(|| unsafe { bindings::security_binder_set_context_mgr(mgr.ptr) })
+}
+
+/// Calls the security modules to determine if binder transactions are allowed from task `from` to
+/// task `to`.
+pub fn binder_transaction(from: &Credential, to: &Credential) -> Result {
+    // SAFETY: By the `Credential` invariants, `from.ptr` and `to.ptr` are valid.
+    to_result(|| unsafe { bindings::security_binder_transaction(from.ptr, to.ptr) })
+}
+
+/// Calls the security modules to determine if task `from` is allowed to send binder objects
+/// (owned by itself or other processes) to task `to` through a binder transaction.
+pub fn binder_transfer_binder(from: &Credential, to: &Credential) -> Result {
+    // SAFETY: By the `Credential` invariants, `from.ptr` and `to.ptr` are valid.
+    to_result(|| unsafe { bindings::security_binder_transfer_binder(from.ptr, to.ptr) })
+}
+
+/// Calls the security modules to determine if task `from` is allowed to send the given file to
+/// task `to` (which would get its own file descriptor) through a binder transaction.
+pub fn binder_transfer_file(from: &Credential, to: &Credential, file: &File) -> Result {
+    // SAFETY: By the `Credential` invariants, `from.ptr` and `to.ptr` are valid. Similarly, by the
+    // `File` invariants, `file.ptr` is also valid.
+    to_result(|| unsafe { bindings::security_binder_transfer_file(from.ptr, to.ptr, file.ptr) })
+}
diff --git a/rust/kernel/static_assert.rs b/rust/kernel/static_assert.rs
new file mode 100644
index 000000000000..a80d8ab57564
--- /dev/null
+++ b/rust/kernel/static_assert.rs
@@ -0,0 +1,39 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Static assert.
+
+/// Static assert (i.e. compile-time assert).
+///
+/// Similar to C11 [`_Static_assert`] and C++11 [`static_assert`].
+///
+/// The feature may be added to Rust in the future: see [RFC 2790].
+///
+/// [`_Static_assert`]: https://en.cppreference.com/w/c/language/_Static_assert
+/// [`static_assert`]: https://en.cppreference.com/w/cpp/language/static_assert
+/// [RFC 2790]: https://github.com/rust-lang/rfcs/issues/2790
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::prelude::*;
+/// static_assert!(42 > 24);
+/// static_assert!(core::mem::size_of::<u8>() == 1);
+///
+/// const X: &[u8] = b"bar";
+/// static_assert!(X[1] == 'a' as u8);
+///
+/// const fn f(x: i32) -> i32 {
+///     x + 2
+/// }
+/// static_assert!(f(40) == 42);
+/// ```
+#[macro_export]
+macro_rules! static_assert {
+    ($condition:expr) => {
+        // Based on the latest one in `rustc`'s one before it was [removed].
+        //
+        // [removed]: https://github.com/rust-lang/rust/commit/c2dad1c6b9f9636198d7c561b47a2974f5103f6d
+        #[allow(dead_code)]
+        const _: () = [()][!($condition) as usize];
+    };
+}
diff --git a/rust/kernel/std_vendor.rs b/rust/kernel/std_vendor.rs
new file mode 100644
index 000000000000..492388d7ce10
--- /dev/null
+++ b/rust/kernel/std_vendor.rs
@@ -0,0 +1,150 @@
+// SPDX-License-Identifier: Apache-2.0 OR MIT
+
+//! The contents of this file come from the Rust standard library, hosted in the
+//! <https://github.com/rust-lang/rust> repository. For copyright details, see
+//! <https://github.com/rust-lang/rust/blob/master/COPYRIGHT>.
+
+/// [`std::dbg`], but using [`pr_info`] instead of [`eprintln`].
+///
+/// Prints and returns the value of a given expression for quick and dirty
+/// debugging.
+///
+/// An example:
+///
+/// ```rust
+/// let a = 2;
+/// let b = dbg!(a * 2) + 1;
+/// //      ^-- prints: [src/main.rs:2] a * 2 = 4
+/// assert_eq!(b, 5);
+/// ```
+///
+/// The macro works by using the `Debug` implementation of the type of
+/// the given expression to print the value with [`printk`] along with the
+/// source location of the macro invocation as well as the source code
+/// of the expression.
+///
+/// Invoking the macro on an expression moves and takes ownership of it
+/// before returning the evaluated expression unchanged. If the type
+/// of the expression does not implement `Copy` and you don't want
+/// to give up ownership, you can instead borrow with `dbg!(&expr)`
+/// for some expression `expr`.
+///
+/// The `dbg!` macro works exactly the same in release builds.
+/// This is useful when debugging issues that only occur in release
+/// builds or when debugging in release mode is significantly faster.
+///
+/// Note that the macro is intended as a debugging tool and therefore you
+/// should avoid having uses of it in version control for long periods
+/// (other than in tests and similar).
+///
+/// # Stability
+///
+/// The exact output printed by this macro should not be relied upon
+/// and is subject to future changes.
+///
+/// # Further examples
+///
+/// With a method call:
+///
+/// ```rust
+/// fn foo(n: usize) {
+///     if let Some(_) = dbg!(n.checked_sub(4)) {
+///         // ...
+///     }
+/// }
+///
+/// foo(3)
+/// ```
+///
+/// This prints to the kernel log:
+///
+/// ```text,ignore
+/// [src/main.rs:4] n.checked_sub(4) = None
+/// ```
+///
+/// Naive factorial implementation:
+///
+/// ```rust
+/// fn factorial(n: u32) -> u32 {
+///     if dbg!(n <= 1) {
+///         dbg!(1)
+///     } else {
+///         dbg!(n * factorial(n - 1))
+///     }
+/// }
+///
+/// dbg!(factorial(4));
+/// ```
+///
+/// This prints to the kernel log:
+///
+/// ```text,ignore
+/// [src/main.rs:3] n <= 1 = false
+/// [src/main.rs:3] n <= 1 = false
+/// [src/main.rs:3] n <= 1 = false
+/// [src/main.rs:3] n <= 1 = true
+/// [src/main.rs:4] 1 = 1
+/// [src/main.rs:5] n * factorial(n - 1) = 2
+/// [src/main.rs:5] n * factorial(n - 1) = 6
+/// [src/main.rs:5] n * factorial(n - 1) = 24
+/// [src/main.rs:11] factorial(4) = 24
+/// ```
+///
+/// The `dbg!(..)` macro moves the input:
+///
+/// ```compile_fail
+/// /// A wrapper around `usize` which importantly is not Copyable.
+/// #[derive(Debug)]
+/// struct NoCopy(usize);
+///
+/// let a = NoCopy(42);
+/// let _ = dbg!(a); // <-- `a` is moved here.
+/// let _ = dbg!(a); // <-- `a` is moved again; error!
+/// ```
+///
+/// You can also use `dbg!()` without a value to just print the
+/// file and line whenever it's reached.
+///
+/// Finally, if you want to `dbg!(..)` multiple values, it will treat them as
+/// a tuple (and return it, too):
+///
+/// ```
+/// assert_eq!(dbg!(1usize, 2u32), (1, 2));
+/// ```
+///
+/// However, a single argument with a trailing comma will still not be treated
+/// as a tuple, following the convention of ignoring trailing commas in macro
+/// invocations. You can use a 1-tuple directly if you need one:
+///
+/// ```
+/// assert_eq!(1, dbg!(1u32,)); // trailing comma ignored
+/// assert_eq!((1,), dbg!((1u32,))); // 1-tuple
+/// ```
+///
+/// [`std::dbg`]: https://doc.rust-lang.org/std/macro.dbg.html
+/// [`eprintln`]: https://doc.rust-lang.org/std/macro.eprintln.html
+/// [`printk`]: https://www.kernel.org/doc/html/latest/core-api/printk-basics.html
+#[macro_export]
+macro_rules! dbg {
+    // NOTE: We cannot use `concat!` to make a static string as a format argument
+    // of `pr_info!` because `file!` could contain a `{` or
+    // `$val` expression could be a block (`{ .. }`), in which case the `pr_info!`
+    // will be malformed.
+    () => {
+        $crate::pr_info!("[{}:{}]\n", ::core::file!(), ::core::line!())
+    };
+    ($val:expr $(,)?) => {
+        // Use of `match` here is intentional because it affects the lifetimes
+        // of temporaries - https://stackoverflow.com/a/48732525/1063961
+        match $val {
+            tmp => {
+                $crate::pr_info!("[{}:{}] {} = {:#?}\n",
+                    ::core::file!(), ::core::line!(), ::core::stringify!($val), &tmp);
+                tmp
+            }
+        }
+    };
+    ($($val:expr),+ $(,)?) => {
+        ($($crate::dbg!($val)),+,)
+    };
+}
diff --git a/rust/kernel/str.rs b/rust/kernel/str.rs
new file mode 100644
index 000000000000..0be85038c0d5
--- /dev/null
+++ b/rust/kernel/str.rs
@@ -0,0 +1,592 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! String representations.
+
+use alloc::vec::Vec;
+use core::fmt::{self, Write};
+use core::ops::{self, Deref, Index};
+
+use crate::{bindings, c_types, error::code::*, Error};
+
+/// Byte string without UTF-8 validity guarantee.
+///
+/// `BStr` is simply an alias to `[u8]`, but has a more evident semantical meaning.
+pub type BStr = [u8];
+
+/// Creates a new [`BStr`] from a string literal.
+///
+/// `b_str!` converts the supplied string literal to byte string, so non-ASCII
+/// characters can be included.
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::b_str;
+/// # use kernel::str::BStr;
+/// const MY_BSTR: &'static BStr = b_str!("My awesome BStr!");
+/// ```
+#[macro_export]
+macro_rules! b_str {
+    ($str:literal) => {{
+        const S: &'static str = $str;
+        const C: &'static $crate::str::BStr = S.as_bytes();
+        C
+    }};
+}
+
+/// Possible errors when using conversion functions in [`CStr`].
+#[derive(Debug, Clone, Copy)]
+pub enum CStrConvertError {
+    /// Supplied bytes contain an interior `NUL`.
+    InteriorNul,
+
+    /// Supplied bytes are not terminated by `NUL`.
+    NotNulTerminated,
+}
+
+impl From<CStrConvertError> for Error {
+    #[inline]
+    fn from(_: CStrConvertError) -> Error {
+        EINVAL
+    }
+}
+
+/// A string that is guaranteed to have exactly one `NUL` byte, which is at the
+/// end.
+///
+/// Used for interoperability with kernel APIs that take C strings.
+#[repr(transparent)]
+pub struct CStr([u8]);
+
+impl CStr {
+    /// Returns the length of this string excluding `NUL`.
+    #[inline]
+    pub const fn len(&self) -> usize {
+        self.len_with_nul() - 1
+    }
+
+    /// Returns the length of this string with `NUL`.
+    #[inline]
+    pub const fn len_with_nul(&self) -> usize {
+        // SAFETY: This is one of the invariant of `CStr`.
+        // We add a `unreachable_unchecked` here to hint the optimizer that
+        // the value returned from this function is non-zero.
+        if self.0.is_empty() {
+            unsafe { core::hint::unreachable_unchecked() };
+        }
+        self.0.len()
+    }
+
+    /// Returns `true` if the string only includes `NUL`.
+    #[inline]
+    pub const fn is_empty(&self) -> bool {
+        self.len() == 0
+    }
+
+    /// Wraps a raw C string pointer.
+    ///
+    /// # Safety
+    ///
+    /// `ptr` must be a valid pointer to a `NUL`-terminated C string, and it must
+    /// last at least `'a`. When `CStr` is alive, the memory pointed by `ptr`
+    /// must not be mutated.
+    #[inline]
+    pub unsafe fn from_char_ptr<'a>(ptr: *const c_types::c_char) -> &'a Self {
+        // SAFETY: The safety precondition guarantees `ptr` is a valid pointer
+        // to a `NUL`-terminated C string.
+        let len = unsafe { bindings::strlen(ptr) } + 1;
+        // SAFETY: Lifetime guaranteed by the safety precondition.
+        let bytes = unsafe { core::slice::from_raw_parts(ptr as _, len as _) };
+        // SAFETY: As `len` is returned by `strlen`, `bytes` does not contain interior `NUL`.
+        // As we have added 1 to `len`, the last byte is known to be `NUL`.
+        unsafe { Self::from_bytes_with_nul_unchecked(bytes) }
+    }
+
+    /// Creates a [`CStr`] from a `[u8]`.
+    ///
+    /// The provided slice must be `NUL`-terminated, does not contain any
+    /// interior `NUL` bytes.
+    pub const fn from_bytes_with_nul(bytes: &[u8]) -> Result<&Self, CStrConvertError> {
+        if bytes.is_empty() {
+            return Err(CStrConvertError::NotNulTerminated);
+        }
+        if bytes[bytes.len() - 1] != 0 {
+            return Err(CStrConvertError::NotNulTerminated);
+        }
+        let mut i = 0;
+        // `i + 1 < bytes.len()` allows LLVM to optimize away bounds checking,
+        // while it couldn't optimize away bounds checks for `i < bytes.len() - 1`.
+        while i + 1 < bytes.len() {
+            if bytes[i] == 0 {
+                return Err(CStrConvertError::InteriorNul);
+            }
+            i += 1;
+        }
+        // SAFETY: We just checked that all properties hold.
+        Ok(unsafe { Self::from_bytes_with_nul_unchecked(bytes) })
+    }
+
+    /// Creates a [`CStr`] from a `[u8]`, panic if input is not valid.
+    ///
+    /// This function is only meant to be used by `c_str!` macro, so
+    /// crates using `c_str!` macro don't have to enable `const_panic` feature.
+    #[doc(hidden)]
+    pub const fn from_bytes_with_nul_unwrap(bytes: &[u8]) -> &Self {
+        match Self::from_bytes_with_nul(bytes) {
+            Ok(v) => v,
+            Err(_) => panic!("string contains interior NUL"),
+        }
+    }
+
+    /// Creates a [`CStr`] from a `[u8]` without performing any additional
+    /// checks.
+    ///
+    /// # Safety
+    ///
+    /// `bytes` *must* end with a `NUL` byte, and should only have a single
+    /// `NUL` byte (or the string will be truncated).
+    #[inline]
+    pub const unsafe fn from_bytes_with_nul_unchecked(bytes: &[u8]) -> &CStr {
+        // SAFETY: Properties of `bytes` guaranteed by the safety precondition.
+        unsafe { core::mem::transmute(bytes) }
+    }
+
+    /// Returns a C pointer to the string.
+    #[inline]
+    pub const fn as_char_ptr(&self) -> *const c_types::c_char {
+        self.0.as_ptr() as _
+    }
+
+    /// Convert the string to a byte slice without the trailing 0 byte.
+    #[inline]
+    pub fn as_bytes(&self) -> &[u8] {
+        &self.0[..self.len()]
+    }
+
+    /// Convert the string to a byte slice containing the trailing 0 byte.
+    #[inline]
+    pub const fn as_bytes_with_nul(&self) -> &[u8] {
+        &self.0
+    }
+
+    /// Yields a [`&str`] slice if the [`CStr`] contains valid UTF-8.
+    ///
+    /// If the contents of the [`CStr`] are valid UTF-8 data, this
+    /// function will return the corresponding [`&str`] slice. Otherwise,
+    /// it will return an error with details of where UTF-8 validation failed.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # use kernel::str::CStr;
+    /// let cstr = CStr::from_bytes_with_nul(b"foo\0").unwrap();
+    /// assert_eq!(cstr.to_str(), Ok("foo"));
+    /// ```
+    #[inline]
+    pub fn to_str(&self) -> Result<&str, core::str::Utf8Error> {
+        core::str::from_utf8(self.as_bytes())
+    }
+
+    /// Unsafely convert this [`CStr`] into a [`&str`], without checking for
+    /// valid UTF-8.
+    ///
+    /// # Safety
+    ///
+    /// The contents must be valid UTF-8.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # use kernel::c_str;
+    /// # use kernel::str::CStr;
+    /// // SAFETY: String literals are guaranteed to be valid UTF-8
+    /// // by the Rust compiler.
+    /// let bar = c_str!("ツ");
+    /// assert_eq!(unsafe { bar.as_str_unchecked() }, "ツ");
+    /// ```
+    #[inline]
+    pub unsafe fn as_str_unchecked(&self) -> &str {
+        unsafe { core::str::from_utf8_unchecked(self.as_bytes()) }
+    }
+}
+
+impl fmt::Display for CStr {
+    /// Formats printable ASCII characters, escaping the rest.
+    ///
+    /// ```
+    /// # use kernel::c_str;
+    /// # use kernel::str::CStr;
+    /// let penguin = c_str!("🐧");
+    /// assert_eq!(format!("{}", penguin), "\\xf0\\x9f\\x90\\xa7");
+    ///
+    /// let ascii = c_str!("so \"cool\"");
+    /// assert_eq!(format!("{}", ascii), "so \"cool\"");
+    /// ```
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        for &c in self.as_bytes() {
+            if (0x20..0x7f).contains(&c) {
+                // Printable character
+                f.write_char(c as char)?;
+            } else {
+                write!(f, "\\x{:02x}", c)?;
+            }
+        }
+        Ok(())
+    }
+}
+
+impl fmt::Debug for CStr {
+    /// Formats printable ASCII characters with a double quote on either end, escaping the rest.
+    ///
+    /// ```
+    /// # use kernel::c_str;
+    /// # use kernel::str::CStr;
+    /// let penguin = c_str!("🐧");
+    /// assert_eq!(format!("{:?}", penguin), "\"\\xf0\\x9f\\x90\\xa7\"");
+    ///
+    /// // embedded double quotes are escaped
+    /// let ascii = c_str!("so \"cool\"");
+    /// assert_eq!(format!("{:?}", ascii), "\"so \\\"cool\\\"\"");
+    /// ```
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.write_str("\"")?;
+        for &c in self.as_bytes() {
+            match c {
+                // Printable characters
+                b'\"' => f.write_str("\\\"")?,
+                0x20..=0x7e => f.write_char(c as char)?,
+                _ => write!(f, "\\x{:02x}", c)?,
+            }
+        }
+        f.write_str("\"")
+    }
+}
+
+impl AsRef<BStr> for CStr {
+    #[inline]
+    fn as_ref(&self) -> &BStr {
+        self.as_bytes()
+    }
+}
+
+impl Deref for CStr {
+    type Target = BStr;
+
+    #[inline]
+    fn deref(&self) -> &Self::Target {
+        self.as_bytes()
+    }
+}
+
+impl Index<ops::RangeFrom<usize>> for CStr {
+    type Output = CStr;
+
+    #[inline]
+    fn index(&self, index: ops::RangeFrom<usize>) -> &Self::Output {
+        // Delegate bounds checking to slice.
+        // Assign to _ to mute clippy's unnecessary operation warning.
+        let _ = &self.as_bytes()[index.start..];
+        // SAFETY: We just checked the bounds.
+        unsafe { Self::from_bytes_with_nul_unchecked(&self.0[index.start..]) }
+    }
+}
+
+impl Index<ops::RangeFull> for CStr {
+    type Output = CStr;
+
+    #[inline]
+    fn index(&self, _index: ops::RangeFull) -> &Self::Output {
+        self
+    }
+}
+
+mod private {
+    use core::ops;
+
+    // Marker trait for index types that can be forward to `BStr`.
+    pub trait CStrIndex {}
+
+    impl CStrIndex for usize {}
+    impl CStrIndex for ops::Range<usize> {}
+    impl CStrIndex for ops::RangeInclusive<usize> {}
+    impl CStrIndex for ops::RangeToInclusive<usize> {}
+}
+
+impl<Idx> Index<Idx> for CStr
+where
+    Idx: private::CStrIndex,
+    BStr: Index<Idx>,
+{
+    type Output = <BStr as Index<Idx>>::Output;
+
+    #[inline]
+    fn index(&self, index: Idx) -> &Self::Output {
+        &self.as_bytes()[index]
+    }
+}
+
+/// Creates a new [`CStr`] from a string literal.
+///
+/// The string literal should not contain any `NUL` bytes.
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::c_str;
+/// # use kernel::str::CStr;
+/// const MY_CSTR: &'static CStr = c_str!("My awesome CStr!");
+/// ```
+#[macro_export]
+macro_rules! c_str {
+    ($str:expr) => {{
+        const S: &str = concat!($str, "\0");
+        const C: &$crate::str::CStr = $crate::str::CStr::from_bytes_with_nul_unwrap(S.as_bytes());
+        C
+    }};
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn test_cstr_to_str() {
+        let good_bytes = b"\xf0\x9f\xa6\x80\0";
+        let checked_cstr = CStr::from_bytes_with_nul(good_bytes).unwrap();
+        let checked_str = checked_cstr.to_str().unwrap();
+        assert_eq!(checked_str, "🦀");
+    }
+
+    #[test]
+    #[should_panic]
+    fn test_cstr_to_str_panic() {
+        let bad_bytes = b"\xc3\x28\0";
+        let checked_cstr = CStr::from_bytes_with_nul(bad_bytes).unwrap();
+        checked_cstr.to_str().unwrap();
+    }
+
+    #[test]
+    fn test_cstr_as_str_unchecked() {
+        let good_bytes = b"\xf0\x9f\x90\xA7\0";
+        let checked_cstr = CStr::from_bytes_with_nul(good_bytes).unwrap();
+        let unchecked_str = unsafe { checked_cstr.as_str_unchecked() };
+        assert_eq!(unchecked_str, "🐧");
+    }
+}
+
+/// Allows formatting of [`fmt::Arguments`] into a raw buffer.
+///
+/// It does not fail if callers write past the end of the buffer so that they can calculate the
+/// size required to fit everything.
+///
+/// # Invariants
+///
+/// The memory region between `pos` (inclusive) and `end` (exclusive) is valid for writes if `pos`
+/// is less than `end`.
+pub(crate) struct RawFormatter {
+    // Use `usize` to use `saturating_*` functions.
+    beg: usize,
+    pos: usize,
+    end: usize,
+}
+
+impl RawFormatter {
+    /// Creates a new instance of [`RawFormatter`] with an empty buffer.
+    fn new() -> Self {
+        // INVARIANT: The buffer is empty, so the region that needs to be writable is empty.
+        Self {
+            beg: 0,
+            pos: 0,
+            end: 0,
+        }
+    }
+
+    /// Creates a new instance of [`RawFormatter`] with the given buffer pointers.
+    ///
+    /// # Safety
+    ///
+    /// If `pos` is less than `end`, then the region between `pos` (inclusive) and `end`
+    /// (exclusive) must be valid for writes for the lifetime of the returned [`RawFormatter`].
+    pub(crate) unsafe fn from_ptrs(pos: *mut u8, end: *mut u8) -> Self {
+        // INVARIANT: The safety requierments guarantee the type invariants.
+        Self {
+            beg: pos as _,
+            pos: pos as _,
+            end: end as _,
+        }
+    }
+
+    /// Creates a new instance of [`RawFormatter`] with the given buffer.
+    ///
+    /// # Safety
+    ///
+    /// The memory region starting at `buf` and extending for `len` bytes must be valid for writes
+    /// for the lifetime of the returned [`RawFormatter`].
+    pub(crate) unsafe fn from_buffer(buf: *mut u8, len: usize) -> Self {
+        let pos = buf as usize;
+        // INVARIANT: We ensure that `end` is never less then `buf`, and the safety requirements
+        // guarantees that the memory region is valid for writes.
+        Self {
+            pos,
+            beg: pos,
+            end: pos.saturating_add(len),
+        }
+    }
+
+    /// Returns the current insert position.
+    ///
+    /// N.B. It may point to invalid memory.
+    pub(crate) fn pos(&self) -> *mut u8 {
+        self.pos as _
+    }
+
+    /// Return the number of bytes written to the formatter.
+    pub(crate) fn bytes_written(&self) -> usize {
+        self.pos - self.beg
+    }
+}
+
+impl fmt::Write for RawFormatter {
+    fn write_str(&mut self, s: &str) -> fmt::Result {
+        // `pos` value after writing `len` bytes. This does not have to be bounded by `end`, but we
+        // don't want it to wrap around to 0.
+        let pos_new = self.pos.saturating_add(s.len());
+
+        // Amount that we can copy. `saturating_sub` ensures we get 0 if `pos` goes past `end`.
+        let len_to_copy = core::cmp::min(pos_new, self.end).saturating_sub(self.pos);
+
+        if len_to_copy > 0 {
+            // SAFETY: If `len_to_copy` is non-zero, then we know `pos` has not gone past `end`
+            // yet, so it is valid for write per the type invariants.
+            unsafe {
+                core::ptr::copy_nonoverlapping(
+                    s.as_bytes().as_ptr(),
+                    self.pos as *mut u8,
+                    len_to_copy,
+                )
+            };
+        }
+
+        self.pos = pos_new;
+        Ok(())
+    }
+}
+
+/// Allows formatting of [`fmt::Arguments`] into a raw buffer.
+///
+/// Fails if callers attempt to write more than will fit in the buffer.
+pub(crate) struct Formatter(RawFormatter);
+
+impl Formatter {
+    /// Creates a new instance of [`Formatter`] with the given buffer.
+    ///
+    /// # Safety
+    ///
+    /// The memory region starting at `buf` and extending for `len` bytes must be valid for writes
+    /// for the lifetime of the returned [`Formatter`].
+    pub(crate) unsafe fn from_buffer(buf: *mut u8, len: usize) -> Self {
+        // SAFETY: The safety requirements of this function satisfy those of the callee.
+        Self(unsafe { RawFormatter::from_buffer(buf, len) })
+    }
+}
+
+impl Deref for Formatter {
+    type Target = RawFormatter;
+
+    fn deref(&self) -> &Self::Target {
+        &self.0
+    }
+}
+
+impl fmt::Write for Formatter {
+    fn write_str(&mut self, s: &str) -> fmt::Result {
+        self.0.write_str(s)?;
+
+        // Fail the request if we go past the end of the buffer.
+        if self.0.pos > self.0.end {
+            Err(fmt::Error)
+        } else {
+            Ok(())
+        }
+    }
+}
+
+/// An owned string that is guaranteed to have exactly one `NUL` byte, which is at the end.
+///
+/// Used for interoperability with kernel APIs that take C strings.
+///
+/// # Invariants
+///
+/// The string is always `NUL`-terminated and contains no other `NUL` bytes.
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::prelude::*;
+/// use kernel::str::CString;
+///
+/// let s = CString::try_from_fmt(fmt!("{}{}{}", "abc", 10, 20)).unwrap();
+/// assert_eq!(s.as_bytes_with_nul(), "abc1020\0".as_bytes());
+///
+/// let tmp = "testing";
+/// let s = CString::try_from_fmt(fmt!("{tmp}{}", 123)).unwrap();
+/// assert_eq!(s.as_bytes_with_nul(), "testing123\0".as_bytes());
+///
+/// // This fails because it has an embedded `NUL` byte.
+/// let s = CString::try_from_fmt(fmt!("a\0b{}", 123));
+/// assert_eq!(s.is_ok(), false);
+/// ```
+pub struct CString {
+    buf: Vec<u8>,
+}
+
+impl CString {
+    /// Creates an instance of [`CString`] from the given formatted arguments.
+    pub fn try_from_fmt(args: fmt::Arguments<'_>) -> Result<Self, Error> {
+        // Calculate the size needed (formatted string plus `NUL` terminator).
+        let mut f = RawFormatter::new();
+        f.write_fmt(args)?;
+        f.write_str("\0")?;
+        let size = f.bytes_written();
+
+        // Allocate a vector with the required number of bytes, and write to it.
+        let mut buf = Vec::try_with_capacity(size)?;
+        // SAFETY: The buffer stored in `buf` is at least of size `size` and is valid for writes.
+        let mut f = unsafe { Formatter::from_buffer(buf.as_mut_ptr(), size) };
+        f.write_fmt(args)?;
+        f.write_str("\0")?;
+
+        // SAFETY: The number of bytes that can be written to `f` is bounded by `size`, which is
+        // `buf`'s capacity. The contents of the buffer have been initialised by writes to `f`.
+        unsafe { buf.set_len(f.bytes_written()) };
+
+        // Check that there are no `NUL` bytes before the end.
+        // SAFETY: The buffer is valid for read because `f.bytes_written()` is bounded by `size`
+        // (which the minimum buffer size) and is non-zero (we wrote at least the `NUL` terminator)
+        // so `f.bytes_written() - 1` doesn't underflow.
+        let ptr = unsafe { bindings::memchr(buf.as_ptr().cast(), 0, (f.bytes_written() - 1) as _) };
+        if !ptr.is_null() {
+            return Err(EINVAL);
+        }
+
+        // INVARIANT: We wrote the `NUL` terminator and checked above that no other `NUL` bytes
+        // exist in the buffer.
+        Ok(Self { buf })
+    }
+}
+
+impl Deref for CString {
+    type Target = CStr;
+
+    fn deref(&self) -> &Self::Target {
+        // SAFETY: The type invariants guarantee that the string is `NUL`-terminated and that no
+        // other `NUL` bytes exist.
+        unsafe { CStr::from_bytes_with_nul_unchecked(self.buf.as_slice()) }
+    }
+}
+
+/// A convenience alias for [`core::format_args`].
+#[macro_export]
+macro_rules! fmt {
+    ($($f:tt)*) => ( core::format_args!($($f)*) )
+}
diff --git a/rust/kernel/sysctl.rs b/rust/kernel/sysctl.rs
new file mode 100644
index 000000000000..63bf76d03d93
--- /dev/null
+++ b/rust/kernel/sysctl.rs
@@ -0,0 +1,199 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! System control.
+//!
+//! C header: [`include/linux/sysctl.h`](../../../../include/linux/sysctl.h)
+//!
+//! Reference: <https://www.kernel.org/doc/Documentation/sysctl/README>
+
+use alloc::boxed::Box;
+use alloc::vec::Vec;
+use core::mem;
+use core::ptr;
+use core::sync::atomic;
+
+use crate::{
+    bindings, c_types,
+    error::code::*,
+    io_buffer::IoBufferWriter,
+    str::CStr,
+    types,
+    user_ptr::{UserSlicePtr, UserSlicePtrWriter},
+    Result,
+};
+
+/// Sysctl storage.
+pub trait SysctlStorage: Sync {
+    /// Writes a byte slice.
+    fn store_value(&self, data: &[u8]) -> (usize, Result);
+
+    /// Reads via a [`UserSlicePtrWriter`].
+    fn read_value(&self, data: &mut UserSlicePtrWriter) -> (usize, Result);
+}
+
+fn trim_whitespace(mut data: &[u8]) -> &[u8] {
+    while !data.is_empty() && (data[0] == b' ' || data[0] == b'\t' || data[0] == b'\n') {
+        data = &data[1..];
+    }
+    while !data.is_empty()
+        && (data[data.len() - 1] == b' '
+            || data[data.len() - 1] == b'\t'
+            || data[data.len() - 1] == b'\n')
+    {
+        data = &data[..data.len() - 1];
+    }
+    data
+}
+
+impl<T> SysctlStorage for &T
+where
+    T: SysctlStorage,
+{
+    fn store_value(&self, data: &[u8]) -> (usize, Result) {
+        (*self).store_value(data)
+    }
+
+    fn read_value(&self, data: &mut UserSlicePtrWriter) -> (usize, Result) {
+        (*self).read_value(data)
+    }
+}
+
+impl SysctlStorage for atomic::AtomicBool {
+    fn store_value(&self, data: &[u8]) -> (usize, Result) {
+        let result = match trim_whitespace(data) {
+            b"0" => {
+                self.store(false, atomic::Ordering::Relaxed);
+                Ok(())
+            }
+            b"1" => {
+                self.store(true, atomic::Ordering::Relaxed);
+                Ok(())
+            }
+            _ => Err(EINVAL),
+        };
+        (data.len(), result)
+    }
+
+    fn read_value(&self, data: &mut UserSlicePtrWriter) -> (usize, Result) {
+        let value = if self.load(atomic::Ordering::Relaxed) {
+            b"1\n"
+        } else {
+            b"0\n"
+        };
+        (value.len(), data.write_slice(value))
+    }
+}
+
+/// Holds a single `sysctl` entry (and its table).
+pub struct Sysctl<T: SysctlStorage> {
+    inner: Box<T>,
+    // Responsible for keeping the `ctl_table` alive.
+    _table: Box<[bindings::ctl_table]>,
+    header: *mut bindings::ctl_table_header,
+}
+
+// SAFETY: The only public method we have is `get()`, which returns `&T`, and
+// `T: Sync`. Any new methods must adhere to this requirement.
+unsafe impl<T: SysctlStorage> Sync for Sysctl<T> {}
+
+unsafe extern "C" fn proc_handler<T: SysctlStorage>(
+    ctl: *mut bindings::ctl_table,
+    write: c_types::c_int,
+    buffer: *mut c_types::c_void,
+    len: *mut usize,
+    ppos: *mut bindings::loff_t,
+) -> c_types::c_int {
+    // If we are reading from some offset other than the beginning of the file,
+    // return an empty read to signal EOF.
+    if unsafe { *ppos } != 0 && write == 0 {
+        unsafe { *len = 0 };
+        return 0;
+    }
+
+    let data = unsafe { UserSlicePtr::new(buffer, *len) };
+    let storage = unsafe { &*((*ctl).data as *const T) };
+    let (bytes_processed, result) = if write != 0 {
+        let data = match data.read_all() {
+            Ok(r) => r,
+            Err(e) => return e.to_kernel_errno(),
+        };
+        storage.store_value(&data)
+    } else {
+        let mut writer = data.writer();
+        storage.read_value(&mut writer)
+    };
+    unsafe { *len = bytes_processed };
+    unsafe { *ppos += *len as bindings::loff_t };
+    match result {
+        Ok(()) => 0,
+        Err(e) => e.to_kernel_errno(),
+    }
+}
+
+impl<T: SysctlStorage> Sysctl<T> {
+    /// Registers a single entry in `sysctl`.
+    pub fn register(
+        path: &'static CStr,
+        name: &'static CStr,
+        storage: T,
+        mode: types::Mode,
+    ) -> Result<Sysctl<T>> {
+        if name.contains(&b'/') {
+            return Err(EINVAL);
+        }
+
+        let storage = Box::try_new(storage)?;
+        let mut table = Vec::try_with_capacity(2)?;
+        table.try_push(bindings::ctl_table {
+            procname: name.as_char_ptr(),
+            mode: mode.as_int(),
+            data: &*storage as *const T as *mut c_types::c_void,
+            proc_handler: Some(proc_handler::<T>),
+
+            maxlen: 0,
+            child: ptr::null_mut(),
+            poll: ptr::null_mut(),
+            extra1: ptr::null_mut(),
+            extra2: ptr::null_mut(),
+        })?;
+        table.try_push(unsafe { mem::zeroed() })?;
+        let mut table = table.try_into_boxed_slice()?;
+
+        let result = unsafe { bindings::register_sysctl(path.as_char_ptr(), table.as_mut_ptr()) };
+        if result.is_null() {
+            return Err(ENOMEM);
+        }
+
+        Ok(Sysctl {
+            inner: storage,
+            _table: table,
+            header: result,
+        })
+    }
+
+    /// Gets the storage.
+    pub fn get(&self) -> &T {
+        &self.inner
+    }
+}
+
+impl<T: SysctlStorage> Drop for Sysctl<T> {
+    fn drop(&mut self) {
+        unsafe {
+            bindings::unregister_sysctl_table(self.header);
+        }
+        self.header = ptr::null_mut();
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn test_trim_whitespace() {
+        assert_eq!(trim_whitespace(b"foo    "), b"foo");
+        assert_eq!(trim_whitespace(b"    foo"), b"foo");
+        assert_eq!(trim_whitespace(b"  foo  "), b"foo");
+    }
+}
diff --git a/rust/kernel/task.rs b/rust/kernel/task.rs
new file mode 100644
index 000000000000..7a2aff0e9219
--- /dev/null
+++ b/rust/kernel/task.rs
@@ -0,0 +1,182 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Tasks (threads and processes).
+//!
+//! C header: [`include/linux/sched.h`](../../../../include/linux/sched.h).
+
+use crate::bindings;
+use core::{marker::PhantomData, mem::ManuallyDrop, ops::Deref};
+
+/// Wraps the kernel's `struct task_struct`.
+///
+/// # Invariants
+///
+/// The pointer `Task::ptr` is non-null and valid. Its reference count is also non-zero.
+///
+/// # Examples
+///
+/// The following is an example of getting the PID of the current thread with zero additional cost
+/// when compared to the C version:
+///
+/// ```
+/// # use kernel::prelude::*;
+/// use kernel::task::Task;
+///
+/// # fn test() {
+/// Task::current().pid();
+/// # }
+/// ```
+///
+/// Getting the PID of the current process, also zero additional cost:
+///
+/// ```
+/// # use kernel::prelude::*;
+/// use kernel::task::Task;
+///
+/// # fn test() {
+/// Task::current().group_leader().pid();
+/// # }
+/// ```
+///
+/// Getting the current task and storing it in some struct. The reference count is automatically
+/// incremented when creating `State` and decremented when it is dropped:
+///
+/// ```
+/// # use kernel::prelude::*;
+/// use kernel::task::Task;
+///
+/// struct State {
+///     creator: Task,
+///     index: u32,
+/// }
+///
+/// impl State {
+///     fn new() -> Self {
+///         Self {
+///             creator: Task::current().clone(),
+///             index: 0,
+///         }
+///     }
+/// }
+/// ```
+pub struct Task {
+    pub(crate) ptr: *mut bindings::task_struct,
+}
+
+// SAFETY: Given that the task is referenced, it is OK to send it to another thread.
+unsafe impl Send for Task {}
+
+// SAFETY: It's OK to access `Task` through references from other threads because we're either
+// accessing properties that don't change (e.g., `pid`, `group_leader`) or that are properly
+// synchronised by C code (e.g., `signal_pending`).
+unsafe impl Sync for Task {}
+
+/// The type of process identifiers (PIDs).
+type Pid = bindings::pid_t;
+
+impl Task {
+    /// Returns a task reference for the currently executing task/thread.
+    pub fn current<'a>() -> TaskRef<'a> {
+        // SAFETY: Just an FFI call.
+        let ptr = unsafe { bindings::get_current() };
+
+        // SAFETY: If the current thread is still running, the current task is valid. Given
+        // that `TaskRef` is not `Send`, we know it cannot be transferred to another thread (where
+        // it could potentially outlive the caller).
+        unsafe { TaskRef::from_ptr(ptr) }
+    }
+
+    /// Returns the group leader of the given task.
+    pub fn group_leader(&self) -> TaskRef<'_> {
+        // SAFETY: By the type invariant, we know that `self.ptr` is non-null and valid.
+        let ptr = unsafe { (*self.ptr).group_leader };
+
+        // SAFETY: The lifetime of the returned task reference is tied to the lifetime of `self`,
+        // and given that a task has a reference to its group leader, we know it must be valid for
+        // the lifetime of the returned task reference.
+        unsafe { TaskRef::from_ptr(ptr) }
+    }
+
+    /// Returns the PID of the given task.
+    pub fn pid(&self) -> Pid {
+        // SAFETY: By the type invariant, we know that `self.ptr` is non-null and valid.
+        unsafe { (*self.ptr).pid }
+    }
+
+    /// Determines whether the given task has pending signals.
+    pub fn signal_pending(&self) -> bool {
+        // SAFETY: By the type invariant, we know that `self.ptr` is non-null and valid.
+        unsafe { bindings::signal_pending(self.ptr) != 0 }
+    }
+}
+
+impl PartialEq for Task {
+    fn eq(&self, other: &Self) -> bool {
+        self.ptr == other.ptr
+    }
+}
+
+impl Eq for Task {}
+
+impl Clone for Task {
+    fn clone(&self) -> Self {
+        // SAFETY: The type invariants guarantee that `self.ptr` has a non-zero reference count.
+        unsafe { bindings::get_task_struct(self.ptr) };
+
+        // INVARIANT: We incremented the reference count to account for the new `Task` being
+        // created.
+        Self { ptr: self.ptr }
+    }
+}
+
+impl Drop for Task {
+    fn drop(&mut self) {
+        // INVARIANT: We may decrement the refcount to zero, but the `Task` is being dropped, so
+        // this is not observable.
+        // SAFETY: The type invariants guarantee that `Task::ptr` has a non-zero reference count.
+        unsafe { bindings::put_task_struct(self.ptr) };
+    }
+}
+
+/// A wrapper for [`Task`] that doesn't automatically decrement the refcount when dropped.
+///
+/// We need the wrapper because [`ManuallyDrop`] alone would allow callers to call
+/// [`ManuallyDrop::into_inner`]. This would allow an unsafe sequence to be triggered without
+/// `unsafe` blocks because it would trigger an unbalanced call to `put_task_struct`.
+///
+/// We make this explicitly not [`Send`] so that we can use it to represent the current thread
+/// without having to increment/decrement its reference count.
+///
+/// # Invariants
+///
+/// The wrapped [`Task`] remains valid for the lifetime of the object.
+pub struct TaskRef<'a> {
+    task: ManuallyDrop<Task>,
+    _not_send: PhantomData<(&'a (), *mut ())>,
+}
+
+impl TaskRef<'_> {
+    /// Constructs a new `struct task_struct` wrapper that doesn't change its reference count.
+    ///
+    /// # Safety
+    ///
+    /// The pointer `ptr` must be non-null and valid for the lifetime of the object.
+    pub(crate) unsafe fn from_ptr(ptr: *mut bindings::task_struct) -> Self {
+        Self {
+            task: ManuallyDrop::new(Task { ptr }),
+            _not_send: PhantomData,
+        }
+    }
+}
+
+// SAFETY: It is OK to share a reference to the current thread with another thread because we know
+// the owner cannot go away while the shared reference exists (and `Task` itself is `Sync`).
+unsafe impl Sync for TaskRef<'_> {}
+
+impl Deref for TaskRef<'_> {
+    type Target = Task;
+
+    fn deref(&self) -> &Self::Target {
+        self.task.deref()
+    }
+}
diff --git a/rust/kernel/types.rs b/rust/kernel/types.rs
new file mode 100644
index 000000000000..28b93055e8b8
--- /dev/null
+++ b/rust/kernel/types.rs
@@ -0,0 +1,569 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Kernel types.
+//!
+//! C header: [`include/linux/types.h`](../../../../include/linux/types.h)
+
+use crate::{
+    bindings, c_types,
+    sync::{Ref, RefBorrow},
+};
+use alloc::boxed::Box;
+use core::{
+    cell::UnsafeCell,
+    mem::MaybeUninit,
+    ops::{self, Deref, DerefMut},
+    pin::Pin,
+};
+
+/// Permissions.
+///
+/// C header: [`include/uapi/linux/stat.h`](../../../../include/uapi/linux/stat.h)
+///
+/// C header: [`include/linux/stat.h`](../../../../include/linux/stat.h)
+pub struct Mode(bindings::umode_t);
+
+impl Mode {
+    /// Creates a [`Mode`] from an integer.
+    pub fn from_int(m: u16) -> Mode {
+        Mode(m)
+    }
+
+    /// Returns the mode as an integer.
+    pub fn as_int(&self) -> u16 {
+        self.0
+    }
+}
+
+/// Used to convert an object into a raw pointer that represents it.
+///
+/// It can eventually be converted back into the object. This is used to store objects as pointers
+/// in kernel data structures, for example, an implementation of [`FileOperations`] in `struct
+/// file::private_data`.
+pub trait PointerWrapper {
+    /// Type of values borrowed between calls to [`PointerWrapper::into_pointer`] and
+    /// [`PointerWrapper::from_pointer`].
+    type Borrowed<'a>;
+
+    /// Returns the raw pointer.
+    fn into_pointer(self) -> *const c_types::c_void;
+
+    /// Returns a borrowed value.
+    ///
+    /// # Safety
+    ///
+    /// `ptr` must have been returned by a previous call to [`PointerWrapper::into_pointer`].
+    /// Additionally, [`PointerWrapper::from_pointer`] can only be called after *all* values
+    /// returned by [`PointerWrapper::borrow`] have been dropped.
+    unsafe fn borrow<'a>(ptr: *const c_types::c_void) -> Self::Borrowed<'a>;
+
+    /// Returns the instance back from the raw pointer.
+    ///
+    /// # Safety
+    ///
+    /// The passed pointer must come from a previous call to [`PointerWrapper::into_pointer()`].
+    unsafe fn from_pointer(ptr: *const c_types::c_void) -> Self;
+}
+
+impl<T: 'static> PointerWrapper for Box<T> {
+    type Borrowed<'a> = &'a T;
+
+    fn into_pointer(self) -> *const c_types::c_void {
+        Box::into_raw(self) as _
+    }
+
+    unsafe fn borrow<'a>(ptr: *const c_types::c_void) -> &'a T {
+        // SAFETY: The safety requirements for this function ensure that the object is still alive,
+        // so it is safe to dereference the raw pointer.
+        // The safety requirements also ensure that the object remains alive for the lifetime of
+        // the returned value.
+        unsafe { &*ptr.cast() }
+    }
+
+    unsafe fn from_pointer(ptr: *const c_types::c_void) -> Self {
+        // SAFETY: The passed pointer comes from a previous call to [`Self::into_pointer()`].
+        unsafe { Box::from_raw(ptr as _) }
+    }
+}
+
+impl<T: 'static> PointerWrapper for Ref<T> {
+    type Borrowed<'a> = RefBorrow<'a, T>;
+
+    fn into_pointer(self) -> *const c_types::c_void {
+        Ref::into_usize(self) as _
+    }
+
+    unsafe fn borrow<'a>(ptr: *const c_types::c_void) -> RefBorrow<'a, T> {
+        // SAFETY: The safety requirements for this function ensure that the underlying object
+        // remains valid for the lifetime of the returned value.
+        unsafe { Ref::borrow_usize(ptr as _) }
+    }
+
+    unsafe fn from_pointer(ptr: *const c_types::c_void) -> Self {
+        // SAFETY: The passed pointer comes from a previous call to [`Self::into_pointer()`].
+        unsafe { Ref::from_usize(ptr as _) }
+    }
+}
+
+impl<T: PointerWrapper + Deref> PointerWrapper for Pin<T> {
+    type Borrowed<'a> = T::Borrowed<'a>;
+
+    fn into_pointer(self) -> *const c_types::c_void {
+        // SAFETY: We continue to treat the pointer as pinned by returning just a pointer to it to
+        // the caller.
+        let inner = unsafe { Pin::into_inner_unchecked(self) };
+        inner.into_pointer()
+    }
+
+    unsafe fn borrow<'a>(ptr: *const c_types::c_void) -> Self::Borrowed<'a> {
+        // SAFETY: The safety requirements for this function are the same as the ones for
+        // `T::borrow`.
+        unsafe { T::borrow(ptr) }
+    }
+
+    unsafe fn from_pointer(p: *const c_types::c_void) -> Self {
+        // SAFETY: The object was originally pinned.
+        // The passed pointer comes from a previous call to `inner::into_pointer()`.
+        unsafe { Pin::new_unchecked(T::from_pointer(p)) }
+    }
+}
+
+impl<T> PointerWrapper for *mut T {
+    type Borrowed<'a> = *mut T;
+
+    fn into_pointer(self) -> *const c_types::c_void {
+        self as _
+    }
+
+    unsafe fn borrow<'a>(ptr: *const c_types::c_void) -> Self::Borrowed<'a> {
+        ptr as _
+    }
+
+    unsafe fn from_pointer(ptr: *const c_types::c_void) -> Self {
+        ptr as _
+    }
+}
+
+impl PointerWrapper for () {
+    type Borrowed<'a> = ();
+
+    fn into_pointer(self) -> *const c_types::c_void {
+        // We use 1 to be different from a null pointer.
+        1usize as _
+    }
+
+    unsafe fn borrow<'a>(_: *const c_types::c_void) -> Self::Borrowed<'a> {}
+
+    unsafe fn from_pointer(_: *const c_types::c_void) -> Self {}
+}
+
+/// Runs a cleanup function/closure when dropped.
+///
+/// The [`ScopeGuard::dismiss`] function prevents the cleanup function from running.
+///
+/// # Examples
+///
+/// In the example below, we have multiple exit paths and we want to log regardless of which one is
+/// taken:
+/// ```
+/// # use kernel::prelude::*;
+/// # use kernel::ScopeGuard;
+/// fn example1(arg: bool) {
+///     let _log = ScopeGuard::new(|| pr_info!("example1 completed\n"));
+///
+///     if arg {
+///         return;
+///     }
+///
+///     // Do something...
+/// }
+/// ```
+///
+/// In the example below, we want to log the same message on all early exits but a different one on
+/// the main exit path:
+/// ```
+/// # use kernel::prelude::*;
+/// # use kernel::ScopeGuard;
+/// fn example2(arg: bool) {
+///     let log = ScopeGuard::new(|| pr_info!("example2 returned early\n"));
+///
+///     if arg {
+///         return;
+///     }
+///
+///     // (Other early returns...)
+///
+///     log.dismiss();
+///     pr_info!("example2 no early return\n");
+/// }
+/// ```
+///
+/// In the example below, we need a mutable object (the vector) to be accessible within the log
+/// function, so we wrap it in the [`ScopeGuard`]:
+/// ```
+/// # use kernel::prelude::*;
+/// # use kernel::ScopeGuard;
+/// fn example3(arg: bool) -> Result {
+///     let mut vec =
+///         ScopeGuard::new_with_data(Vec::new(), |v| pr_info!("vec had {} elements\n", v.len()));
+///
+///     vec.try_push(10u8)?;
+///     if arg {
+///         return Ok(());
+///     }
+///     vec.try_push(20u8)?;
+///     Ok(())
+/// }
+/// ```
+///
+/// # Invariants
+///
+/// The value stored in the struct is nearly always `Some(_)`, except between
+/// [`ScopeGuard::dismiss`] and [`ScopeGuard::drop`]: in this case, it will be `None` as the value
+/// will have been returned to the caller. Since  [`ScopeGuard::dismiss`] consumes the guard,
+/// callers won't be able to use it anymore.
+pub struct ScopeGuard<T, F: FnOnce(T)>(Option<(T, F)>);
+
+impl<T, F: FnOnce(T)> ScopeGuard<T, F> {
+    /// Creates a new guarded object wrapping the given data and with the given cleanup function.
+    pub fn new_with_data(data: T, cleanup_func: F) -> Self {
+        // INVARIANT: The struct is being initialised with `Some(_)`.
+        Self(Some((data, cleanup_func)))
+    }
+
+    /// Prevents the cleanup function from running and returns the guarded data.
+    pub fn dismiss(mut self) -> T {
+        // INVARIANT: This is the exception case in the invariant; it is not visible to callers
+        // because this function consumes `self`.
+        self.0.take().unwrap().0
+    }
+}
+
+impl ScopeGuard<(), Box<dyn FnOnce(())>> {
+    /// Creates a new guarded object with the given cleanup function.
+    pub fn new(cleanup: impl FnOnce()) -> ScopeGuard<(), impl FnOnce(())> {
+        ScopeGuard::new_with_data((), move |_| cleanup())
+    }
+}
+
+impl<T, F: FnOnce(T)> Deref for ScopeGuard<T, F> {
+    type Target = T;
+
+    fn deref(&self) -> &T {
+        // The type invariants guarantee that `unwrap` will succeed.
+        &self.0.as_ref().unwrap().0
+    }
+}
+
+impl<T, F: FnOnce(T)> DerefMut for ScopeGuard<T, F> {
+    fn deref_mut(&mut self) -> &mut T {
+        // The type invariants guarantee that `unwrap` will succeed.
+        &mut self.0.as_mut().unwrap().0
+    }
+}
+
+impl<T, F: FnOnce(T)> Drop for ScopeGuard<T, F> {
+    fn drop(&mut self) {
+        // Run the cleanup function if one is still present.
+        if let Some((data, cleanup)) = self.0.take() {
+            cleanup(data)
+        }
+    }
+}
+
+/// Stores an opaque value.
+///
+/// This is meant to be used with FFI objects that are never interpreted by Rust code.
+pub struct Opaque<T>(MaybeUninit<UnsafeCell<T>>);
+
+impl<T> Opaque<T> {
+    /// Creates a new opaque value.
+    pub fn new(value: T) -> Self {
+        Self(MaybeUninit::new(UnsafeCell::new(value)))
+    }
+
+    /// Creates an uninitialised value.
+    pub const fn uninit() -> Self {
+        Self(MaybeUninit::uninit())
+    }
+
+    /// Returns a raw pointer to the opaque data.
+    pub fn get(&self) -> *mut T {
+        UnsafeCell::raw_get(self.0.as_ptr())
+    }
+}
+
+/// A bitmask.
+///
+/// It has a restriction that all bits must be the same, except one. For example, `0b1110111` and
+/// `0b1000` are acceptable masks.
+#[derive(Clone, Copy)]
+pub struct Bit<T> {
+    index: T,
+    inverted: bool,
+}
+
+/// Creates a bit mask with a single bit set.
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::prelude::*;
+/// # use kernel::bit;
+/// let mut x = 0xfeu32;
+///
+/// assert_eq!(x & bit(0), 0);
+/// assert_eq!(x & bit(1), 2);
+/// assert_eq!(x & bit(2), 4);
+/// assert_eq!(x & bit(3), 8);
+///
+/// x |= bit(0);
+/// assert_eq!(x, 0xff);
+///
+/// x &= !bit(1);
+/// assert_eq!(x, 0xfd);
+///
+/// x &= !bit(7);
+/// assert_eq!(x, 0x7d);
+///
+/// let y: u64 = bit(34).into();
+/// assert_eq!(y, 0x400000000);
+///
+/// assert_eq!(y | bit(35), 0xc00000000);
+/// ```
+pub fn bit<T: Copy>(index: T) -> Bit<T> {
+    Bit {
+        index,
+        inverted: false,
+    }
+}
+
+impl<T: Copy> ops::Not for Bit<T> {
+    type Output = Self;
+    fn not(self) -> Self {
+        Self {
+            index: self.index,
+            inverted: !self.inverted,
+        }
+    }
+}
+
+/// Implemented by integer types that allow counting the number of trailing zeroes.
+pub trait TrailingZeros {
+    /// Returns the number of trailing zeroes in the binary representation of `self`.
+    fn trailing_zeros(&self) -> u32;
+}
+
+macro_rules! define_unsigned_number_traits {
+    ($type_name:ty) => {
+        impl TrailingZeros for $type_name {
+            fn trailing_zeros(&self) -> u32 {
+                <$type_name>::trailing_zeros(*self)
+            }
+        }
+
+        impl<T: Copy> core::convert::From<Bit<T>> for $type_name
+        where
+            Self: ops::Shl<T, Output = Self> + core::convert::From<u8> + ops::Not<Output = Self>,
+        {
+            fn from(v: Bit<T>) -> Self {
+                let c = Self::from(1u8) << v.index;
+                if v.inverted {
+                    !c
+                } else {
+                    c
+                }
+            }
+        }
+
+        impl<T: Copy> ops::BitAnd<Bit<T>> for $type_name
+        where
+            Self: ops::Shl<T, Output = Self> + core::convert::From<u8>,
+        {
+            type Output = Self;
+            fn bitand(self, rhs: Bit<T>) -> Self::Output {
+                self & Self::from(rhs)
+            }
+        }
+
+        impl<T: Copy> ops::BitOr<Bit<T>> for $type_name
+        where
+            Self: ops::Shl<T, Output = Self> + core::convert::From<u8>,
+        {
+            type Output = Self;
+            fn bitor(self, rhs: Bit<T>) -> Self::Output {
+                self | Self::from(rhs)
+            }
+        }
+
+        impl<T: Copy> ops::BitAndAssign<Bit<T>> for $type_name
+        where
+            Self: ops::Shl<T, Output = Self> + core::convert::From<u8>,
+        {
+            fn bitand_assign(&mut self, rhs: Bit<T>) {
+                *self &= Self::from(rhs)
+            }
+        }
+
+        impl<T: Copy> ops::BitOrAssign<Bit<T>> for $type_name
+        where
+            Self: ops::Shl<T, Output = Self> + core::convert::From<u8>,
+        {
+            fn bitor_assign(&mut self, rhs: Bit<T>) {
+                *self |= Self::from(rhs)
+            }
+        }
+    };
+}
+
+define_unsigned_number_traits!(u8);
+define_unsigned_number_traits!(u16);
+define_unsigned_number_traits!(u32);
+define_unsigned_number_traits!(u64);
+define_unsigned_number_traits!(usize);
+
+/// Returns an iterator over the set bits of `value`.
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::prelude::*;
+/// use kernel::bits_iter;
+///
+/// let mut iter = bits_iter(5usize);
+/// assert_eq!(iter.next().unwrap(), 0);
+/// assert_eq!(iter.next().unwrap(), 2);
+/// assert!(iter.next().is_none());
+/// ```
+///
+/// ```
+/// # use kernel::prelude::*;
+/// use kernel::bits_iter;
+///
+/// fn print_bits(x: usize) {
+///     for bit in bits_iter(x) {
+///         println!("{}", bit);
+///     }
+/// }
+/// ```
+#[inline]
+pub fn bits_iter<T>(value: T) -> impl Iterator<Item = u32>
+where
+    T: core::cmp::PartialEq
+        + From<u8>
+        + ops::Shl<u32, Output = T>
+        + ops::Not<Output = T>
+        + ops::BitAndAssign
+        + TrailingZeros,
+{
+    struct BitIterator<U> {
+        value: U,
+    }
+
+    impl<U> Iterator for BitIterator<U>
+    where
+        U: core::cmp::PartialEq
+            + From<u8>
+            + ops::Shl<u32, Output = U>
+            + ops::Not<Output = U>
+            + ops::BitAndAssign
+            + TrailingZeros,
+    {
+        type Item = u32;
+
+        #[inline]
+        fn next(&mut self) -> Option<u32> {
+            if self.value == U::from(0u8) {
+                return None;
+            }
+            let ret = self.value.trailing_zeros();
+            self.value &= !(U::from(1u8) << ret);
+            Some(ret)
+        }
+    }
+
+    BitIterator { value }
+}
+
+/// A trait for boolean types.
+///
+/// This is meant to be used in type states to allow booelan constraints in implementation blocks.
+/// In the example below, the implementation containing `MyType::set_value` could _not_ be
+/// constrained to type states containing `Writable = true` if `Writable` were a constant instead
+/// of a type.
+///
+/// # Safety
+///
+/// No additional implementations of [`Bool`] should be provided, as [`True`] and [`False`] are
+/// already provided.
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::{Bool, False, True};
+/// use core::marker::PhantomData;
+///
+/// // Type state specifies whether the type is writable.
+/// trait MyTypeState {
+///     type Writable: Bool;
+/// }
+///
+/// // In state S1, the type is writable.
+/// struct S1;
+/// impl MyTypeState for S1 {
+///     type Writable = True;
+/// }
+///
+/// // In state S2, the type is not writable.
+/// struct S2;
+/// impl MyTypeState for S2 {
+///     type Writable = False;
+/// }
+///
+/// struct MyType<T: MyTypeState> {
+///     value: u32,
+///     _p: PhantomData<T>,
+/// }
+///
+/// impl<T: MyTypeState> MyType<T> {
+///     fn new(value: u32) -> Self {
+///         Self {
+///             value,
+///             _p: PhantomData,
+///         }
+///     }
+/// }
+///
+/// // This implementation block only applies if the type state is writable.
+/// impl<T> MyType<T>
+/// where
+///     T: MyTypeState<Writable = True>,
+/// {
+///     fn set_value(&mut self, v: u32) {
+///         self.value = v;
+///     }
+/// }
+///
+/// pub(crate) fn test() {
+///     let mut x = MyType::<S1>::new(10);
+///     let mut y = MyType::<S2>::new(20);
+///
+///     x.set_value(30);
+///
+///     // The code below fails to compile because `S2` is not writable.
+///     // y.set_value(40);
+/// }
+/// ```
+pub unsafe trait Bool {}
+
+/// Represents the `true` value for types with [`Bool`] bound.
+pub struct True;
+
+// SAFETY: This is one of the only two implementations of `Bool`.
+unsafe impl Bool for True {}
+
+/// Represents the `false` value for types wth [`Bool`] bound.
+pub struct False;
+
+// SAFETY: This is one of the only two implementations of `Bool`.
+unsafe impl Bool for False {}
diff --git a/rust/kernel/user_ptr.rs b/rust/kernel/user_ptr.rs
new file mode 100644
index 000000000000..8489e80923c7
--- /dev/null
+++ b/rust/kernel/user_ptr.rs
@@ -0,0 +1,175 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! User pointers.
+//!
+//! C header: [`include/linux/uaccess.h`](../../../../include/linux/uaccess.h)
+
+use crate::{
+    bindings, c_types,
+    error::code::*,
+    io_buffer::{IoBufferReader, IoBufferWriter},
+    Result,
+};
+use alloc::vec::Vec;
+
+/// A reference to an area in userspace memory, which can be either
+/// read-only or read-write.
+///
+/// All methods on this struct are safe: invalid pointers return
+/// `EFAULT`. Concurrent access, *including data races to/from userspace
+/// memory*, is permitted, because fundamentally another userspace
+/// thread/process could always be modifying memory at the same time
+/// (in the same way that userspace Rust's [`std::io`] permits data races
+/// with the contents of files on disk). In the presence of a race, the
+/// exact byte values read/written are unspecified but the operation is
+/// well-defined. Kernelspace code should validate its copy of data
+/// after completing a read, and not expect that multiple reads of the
+/// same address will return the same value.
+///
+/// All APIs enforce the invariant that a given byte of memory from userspace
+/// may only be read once. By preventing double-fetches we avoid TOCTOU
+/// vulnerabilities. This is accomplished by taking `self` by value to prevent
+/// obtaining multiple readers on a given [`UserSlicePtr`], and the readers
+/// only permitting forward reads.
+///
+/// Constructing a [`UserSlicePtr`] performs no checks on the provided
+/// address and length, it can safely be constructed inside a kernel thread
+/// with no current userspace process. Reads and writes wrap the kernel APIs
+/// `copy_from_user` and `copy_to_user`, which check the memory map of the
+/// current process and enforce that the address range is within the user
+/// range (no additional calls to `access_ok` are needed).
+///
+/// [`std::io`]: https://doc.rust-lang.org/std/io/index.html
+pub struct UserSlicePtr(*mut c_types::c_void, usize);
+
+impl UserSlicePtr {
+    /// Constructs a user slice from a raw pointer and a length in bytes.
+    ///
+    /// # Safety
+    ///
+    /// Callers must be careful to avoid time-of-check-time-of-use
+    /// (TOCTOU) issues. The simplest way is to create a single instance of
+    /// [`UserSlicePtr`] per user memory block as it reads each byte at
+    /// most once.
+    pub unsafe fn new(ptr: *mut c_types::c_void, length: usize) -> Self {
+        UserSlicePtr(ptr, length)
+    }
+
+    /// Reads the entirety of the user slice.
+    ///
+    /// Returns `EFAULT` if the address does not currently point to
+    /// mapped, readable memory.
+    pub fn read_all(self) -> Result<Vec<u8>> {
+        self.reader().read_all()
+    }
+
+    /// Constructs a [`UserSlicePtrReader`].
+    pub fn reader(self) -> UserSlicePtrReader {
+        UserSlicePtrReader(self.0, self.1)
+    }
+
+    /// Writes the provided slice into the user slice.
+    ///
+    /// Returns `EFAULT` if the address does not currently point to
+    /// mapped, writable memory (in which case some data from before the
+    /// fault may be written), or `data` is larger than the user slice
+    /// (in which case no data is written).
+    pub fn write_all(self, data: &[u8]) -> Result {
+        self.writer().write_slice(data)
+    }
+
+    /// Constructs a [`UserSlicePtrWriter`].
+    pub fn writer(self) -> UserSlicePtrWriter {
+        UserSlicePtrWriter(self.0, self.1)
+    }
+
+    /// Constructs both a [`UserSlicePtrReader`] and a [`UserSlicePtrWriter`].
+    pub fn reader_writer(self) -> (UserSlicePtrReader, UserSlicePtrWriter) {
+        (
+            UserSlicePtrReader(self.0, self.1),
+            UserSlicePtrWriter(self.0, self.1),
+        )
+    }
+}
+
+/// A reader for [`UserSlicePtr`].
+///
+/// Used to incrementally read from the user slice.
+pub struct UserSlicePtrReader(*mut c_types::c_void, usize);
+
+impl IoBufferReader for UserSlicePtrReader {
+    /// Returns the number of bytes left to be read from this.
+    ///
+    /// Note that even reading less than this number of bytes may fail.
+    fn len(&self) -> usize {
+        self.1
+    }
+
+    /// Reads raw data from the user slice into a raw kernel buffer.
+    ///
+    /// # Safety
+    ///
+    /// The output buffer must be valid.
+    unsafe fn read_raw(&mut self, out: *mut u8, len: usize) -> Result {
+        if len > self.1 || len > u32::MAX as usize {
+            return Err(EFAULT);
+        }
+        let res = unsafe { bindings::copy_from_user(out as _, self.0, len as _) };
+        if res != 0 {
+            return Err(EFAULT);
+        }
+        // Since this is not a pointer to a valid object in our program,
+        // we cannot use `add`, which has C-style rules for defined
+        // behavior.
+        self.0 = self.0.wrapping_add(len);
+        self.1 -= len;
+        Ok(())
+    }
+}
+
+/// A writer for [`UserSlicePtr`].
+///
+/// Used to incrementally write into the user slice.
+pub struct UserSlicePtrWriter(*mut c_types::c_void, usize);
+
+impl IoBufferWriter for UserSlicePtrWriter {
+    fn len(&self) -> usize {
+        self.1
+    }
+
+    fn clear(&mut self, mut len: usize) -> Result {
+        let mut ret = Ok(());
+        if len > self.1 {
+            ret = Err(EFAULT);
+            len = self.1;
+        }
+
+        // SAFETY: The buffer will be validated by `clear_user`. We ensure that `len` is within
+        // bounds in the check above.
+        let left = unsafe { bindings::clear_user(self.0, len as _) } as usize;
+        if left != 0 {
+            ret = Err(EFAULT);
+            len -= left;
+        }
+
+        self.0 = self.0.wrapping_add(len);
+        self.1 -= len;
+        ret
+    }
+
+    unsafe fn write_raw(&mut self, data: *const u8, len: usize) -> Result {
+        if len > self.1 || len > u32::MAX as usize {
+            return Err(EFAULT);
+        }
+        let res = unsafe { bindings::copy_to_user(self.0, data as _, len as _) };
+        if res != 0 {
+            return Err(EFAULT);
+        }
+        // Since this is not a pointer to a valid object in our program,
+        // we cannot use `add`, which has C-style rules for defined
+        // behavior.
+        self.0 = self.0.wrapping_add(len);
+        self.1 -= len;
+        Ok(())
+    }
+}
-- 
2.35.1


^ permalink raw reply related	[relevance 1%]

* [PATCH v5 17/20] samples: add Rust examples
    2022-03-17 18:09  1% ` [PATCH v5 10/20] rust: add `kernel` crate Miguel Ojeda
@ 2022-03-17 18:10  3% ` Miguel Ojeda
  1 sibling, 0 replies; 77+ results
From: Miguel Ojeda @ 2022-03-17 18:10 UTC (permalink / raw)
  To: Linus Torvalds, Greg Kroah-Hartman
  Cc: rust-for-linux, linux-kernel, Miguel Ojeda, Alex Gaynor,
	Finn Behrens, Wedson Almeida Filho, Sven Van Asbroeck, Gary Guo,
	Boris-Chengbiao Zhou, Ayaan Zaidi, Milan Landaverde

A set of Rust modules that showcase how Rust modules look like
and how to use the abstracted kernel features, as well as
an example of a Rust host program with several modules.

These samples also double as tests in the CI.

The semaphore sample comes with a C version for comparison.

Co-developed-by: Alex Gaynor <alex.gaynor@gmail.com>
Signed-off-by: Alex Gaynor <alex.gaynor@gmail.com>
Co-developed-by: Finn Behrens <me@kloenk.de>
Signed-off-by: Finn Behrens <me@kloenk.de>
Co-developed-by: Wedson Almeida Filho <wedsonaf@google.com>
Signed-off-by: Wedson Almeida Filho <wedsonaf@google.com>
Co-developed-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Co-developed-by: Sven Van Asbroeck <thesven73@gmail.com>
Signed-off-by: Sven Van Asbroeck <thesven73@gmail.com>
Co-developed-by: Gary Guo <gary@garyguo.net>
Signed-off-by: Gary Guo <gary@garyguo.net>
Co-developed-by: Boris-Chengbiao Zhou <bobo1239@web.de>
Signed-off-by: Boris-Chengbiao Zhou <bobo1239@web.de>
Co-developed-by: Ayaan Zaidi <zaidi.ayaan@gmail.com>
Signed-off-by: Ayaan Zaidi <zaidi.ayaan@gmail.com>
Co-developed-by: Milan Landaverde <milan@mdaverde.com>
Signed-off-by: Milan Landaverde <milan@mdaverde.com>
Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
---
 samples/Kconfig                        |   2 +
 samples/Makefile                       |   1 +
 samples/rust/Kconfig                   | 130 +++++++++++++++
 samples/rust/Makefile                  |  15 ++
 samples/rust/hostprogs/.gitignore      |   3 +
 samples/rust/hostprogs/Makefile        |   5 +
 samples/rust/hostprogs/a.rs            |   7 +
 samples/rust/hostprogs/b.rs            |   5 +
 samples/rust/hostprogs/single.rs       |  12 ++
 samples/rust/rust_chrdev.rs            |  50 ++++++
 samples/rust/rust_minimal.rs           |  35 ++++
 samples/rust/rust_miscdev.rs           | 143 +++++++++++++++++
 samples/rust/rust_module_parameters.rs |  69 ++++++++
 samples/rust/rust_platform.rs          |  22 +++
 samples/rust/rust_print.rs             |  54 +++++++
 samples/rust/rust_random.rs            |  60 +++++++
 samples/rust/rust_semaphore.rs         | 171 ++++++++++++++++++++
 samples/rust/rust_semaphore_c.c        | 212 +++++++++++++++++++++++++
 samples/rust/rust_stack_probing.rs     |  36 +++++
 samples/rust/rust_sync.rs              |  93 +++++++++++
 20 files changed, 1125 insertions(+)
 create mode 100644 samples/rust/Kconfig
 create mode 100644 samples/rust/Makefile
 create mode 100644 samples/rust/hostprogs/.gitignore
 create mode 100644 samples/rust/hostprogs/Makefile
 create mode 100644 samples/rust/hostprogs/a.rs
 create mode 100644 samples/rust/hostprogs/b.rs
 create mode 100644 samples/rust/hostprogs/single.rs
 create mode 100644 samples/rust/rust_chrdev.rs
 create mode 100644 samples/rust/rust_minimal.rs
 create mode 100644 samples/rust/rust_miscdev.rs
 create mode 100644 samples/rust/rust_module_parameters.rs
 create mode 100644 samples/rust/rust_platform.rs
 create mode 100644 samples/rust/rust_print.rs
 create mode 100644 samples/rust/rust_random.rs
 create mode 100644 samples/rust/rust_semaphore.rs
 create mode 100644 samples/rust/rust_semaphore_c.c
 create mode 100644 samples/rust/rust_stack_probing.rs
 create mode 100644 samples/rust/rust_sync.rs

diff --git a/samples/Kconfig b/samples/Kconfig
index 22cc921ae291..9a82039aae49 100644
--- a/samples/Kconfig
+++ b/samples/Kconfig
@@ -250,6 +250,8 @@ config SAMPLE_CORESIGHT_SYSCFG
 	  This demonstrates how a user may create their own CoreSight
 	  configurations and easily load them into the system at runtime.
 
+source "samples/rust/Kconfig"
+
 endif # SAMPLES
 
 config HAVE_SAMPLE_FTRACE_DIRECT
diff --git a/samples/Makefile b/samples/Makefile
index 1ae4de99c983..fc5e9760ea32 100644
--- a/samples/Makefile
+++ b/samples/Makefile
@@ -33,3 +33,4 @@ subdir-$(CONFIG_SAMPLE_WATCHDOG)	+= watchdog
 subdir-$(CONFIG_SAMPLE_WATCH_QUEUE)	+= watch_queue
 obj-$(CONFIG_DEBUG_KMEMLEAK_TEST)	+= kmemleak/
 obj-$(CONFIG_SAMPLE_CORESIGHT_SYSCFG)	+= coresight/
+obj-$(CONFIG_SAMPLES_RUST)		+= rust/
diff --git a/samples/rust/Kconfig b/samples/rust/Kconfig
new file mode 100644
index 000000000000..68caf9947978
--- /dev/null
+++ b/samples/rust/Kconfig
@@ -0,0 +1,130 @@
+# SPDX-License-Identifier: GPL-2.0
+
+menuconfig SAMPLES_RUST
+	bool "Rust samples"
+	depends on RUST
+	help
+	  You can build sample Rust kernel code here.
+
+	  If unsure, say N.
+
+if SAMPLES_RUST
+
+config SAMPLE_RUST_MINIMAL
+	tristate "Minimal"
+	help
+	  This option builds the Rust minimal module sample.
+
+	  To compile this as a module, choose M here:
+	  the module will be called rust_minimal.
+
+	  If unsure, say N.
+
+config SAMPLE_RUST_PRINT
+	tristate "Printing macros"
+	help
+	  This option builds the Rust printing macros sample.
+
+	  To compile this as a module, choose M here:
+	  the module will be called rust_print.
+
+	  If unsure, say N.
+
+config SAMPLE_RUST_MODULE_PARAMETERS
+	tristate "Module parameters"
+	help
+	  This option builds the Rust module parameters sample.
+
+	  To compile this as a module, choose M here:
+	  the module will be called rust_module_parameters.
+
+	  If unsure, say N.
+
+config SAMPLE_RUST_SYNC
+	tristate "Synchronisation primitives"
+	help
+	  This option builds the Rust synchronisation primitives sample.
+
+	  To compile this as a module, choose M here:
+	  the module will be called rust_sync.
+
+	  If unsure, say N.
+
+config SAMPLE_RUST_CHRDEV
+	tristate "Character device"
+	help
+	  This option builds the Rust character device sample.
+
+	  To compile this as a module, choose M here:
+	  the module will be called rust_chrdev.
+
+	  If unsure, say N.
+
+config SAMPLE_RUST_MISCDEV
+	tristate "Miscellaneous device"
+	help
+	  This option builds the Rust miscellaneous device sample.
+
+	  To compile this as a module, choose M here:
+	  the module will be called rust_miscdev.
+
+	  If unsure, say N.
+
+config SAMPLE_RUST_STACK_PROBING
+	tristate "Stack probing"
+	help
+	  This option builds the Rust stack probing sample.
+
+	  To compile this as a module, choose M here:
+	  the module will be called rust_stack_probing.
+
+	  If unsure, say N.
+
+config SAMPLE_RUST_SEMAPHORE
+	tristate "Semaphore"
+	help
+	  This option builds the Rust semaphore sample.
+
+	  To compile this as a module, choose M here:
+	  the module will be called rust_semaphore.
+
+	  If unsure, say N.
+
+config SAMPLE_RUST_SEMAPHORE_C
+	tristate "Semaphore (in C, for comparison)"
+	help
+	  This option builds the Rust semaphore sample (in C, for comparison).
+
+	  To compile this as a module, choose M here:
+	  the module will be called rust_semaphore_c.
+
+	  If unsure, say N.
+
+config SAMPLE_RUST_RANDOM
+	tristate "Random"
+	help
+	  This option builds the Rust random sample.
+
+	  To compile this as a module, choose M here:
+	  the module will be called rust_random.
+
+	  If unsure, say N.
+
+config SAMPLE_RUST_PLATFORM
+	tristate "Platform device driver"
+	help
+	  This option builds the Rust platform device driver sample.
+
+	  To compile this as a module, choose M here:
+	  the module will be called rust_platform.
+
+	  If unsure, say N.
+
+config SAMPLE_RUST_HOSTPROGS
+	bool "Host programs"
+	help
+	  This option builds the Rust host program samples.
+
+	  If unsure, say N.
+
+endif # SAMPLES_RUST
diff --git a/samples/rust/Makefile b/samples/rust/Makefile
new file mode 100644
index 000000000000..c1a401cf94f1
--- /dev/null
+++ b/samples/rust/Makefile
@@ -0,0 +1,15 @@
+# SPDX-License-Identifier: GPL-2.0
+
+obj-$(CONFIG_SAMPLE_RUST_MINIMAL)		+= rust_minimal.o
+obj-$(CONFIG_SAMPLE_RUST_PRINT)			+= rust_print.o
+obj-$(CONFIG_SAMPLE_RUST_MODULE_PARAMETERS)	+= rust_module_parameters.o
+obj-$(CONFIG_SAMPLE_RUST_SYNC)			+= rust_sync.o
+obj-$(CONFIG_SAMPLE_RUST_CHRDEV)		+= rust_chrdev.o
+obj-$(CONFIG_SAMPLE_RUST_MISCDEV)		+= rust_miscdev.o
+obj-$(CONFIG_SAMPLE_RUST_STACK_PROBING)		+= rust_stack_probing.o
+obj-$(CONFIG_SAMPLE_RUST_SEMAPHORE)		+= rust_semaphore.o
+obj-$(CONFIG_SAMPLE_RUST_SEMAPHORE_C)		+= rust_semaphore_c.o
+obj-$(CONFIG_SAMPLE_RUST_RANDOM)		+= rust_random.o
+obj-$(CONFIG_SAMPLE_RUST_PLATFORM)		+= rust_platform.o
+
+subdir-$(CONFIG_SAMPLE_RUST_HOSTPROGS)		+= hostprogs
diff --git a/samples/rust/hostprogs/.gitignore b/samples/rust/hostprogs/.gitignore
new file mode 100644
index 000000000000..a6c173da5048
--- /dev/null
+++ b/samples/rust/hostprogs/.gitignore
@@ -0,0 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0
+
+single
diff --git a/samples/rust/hostprogs/Makefile b/samples/rust/hostprogs/Makefile
new file mode 100644
index 000000000000..8ddcbd7416db
--- /dev/null
+++ b/samples/rust/hostprogs/Makefile
@@ -0,0 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0
+
+hostprogs-always-y := single
+
+single-rust := y
diff --git a/samples/rust/hostprogs/a.rs b/samples/rust/hostprogs/a.rs
new file mode 100644
index 000000000000..f7a4a3d0f4e0
--- /dev/null
+++ b/samples/rust/hostprogs/a.rs
@@ -0,0 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Rust single host program sample: module `a`.
+
+pub(crate) fn f(x: i32) {
+    println!("The number is {}.", x);
+}
diff --git a/samples/rust/hostprogs/b.rs b/samples/rust/hostprogs/b.rs
new file mode 100644
index 000000000000..c1675890648f
--- /dev/null
+++ b/samples/rust/hostprogs/b.rs
@@ -0,0 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Rust single host program sample: module `b`.
+
+pub(crate) const CONSTANT: i32 = 42;
diff --git a/samples/rust/hostprogs/single.rs b/samples/rust/hostprogs/single.rs
new file mode 100644
index 000000000000..8c48a119339a
--- /dev/null
+++ b/samples/rust/hostprogs/single.rs
@@ -0,0 +1,12 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Rust single host program sample.
+
+mod a;
+mod b;
+
+fn main() {
+    println!("Hello world!");
+
+    a::f(b::CONSTANT);
+}
diff --git a/samples/rust/rust_chrdev.rs b/samples/rust/rust_chrdev.rs
new file mode 100644
index 000000000000..b4350ddae430
--- /dev/null
+++ b/samples/rust/rust_chrdev.rs
@@ -0,0 +1,50 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Rust character device sample.
+
+use kernel::prelude::*;
+use kernel::{chrdev, file};
+
+module! {
+    type: RustChrdev,
+    name: b"rust_chrdev",
+    author: b"Rust for Linux Contributors",
+    description: b"Rust character device sample",
+    license: b"GPL v2",
+}
+
+struct RustFile;
+
+impl file::Operations for RustFile {
+    kernel::declare_file_operations!();
+
+    fn open(_shared: &(), _file: &file::File) -> Result {
+        Ok(())
+    }
+}
+
+struct RustChrdev {
+    _dev: Pin<Box<chrdev::Registration<2>>>,
+}
+
+impl KernelModule for RustChrdev {
+    fn init(name: &'static CStr, module: &'static ThisModule) -> Result<Self> {
+        pr_info!("Rust character device sample (init)\n");
+
+        let mut chrdev_reg = chrdev::Registration::new_pinned(name, 0, module)?;
+
+        // Register the same kind of device twice, we're just demonstrating
+        // that you can use multiple minors. There are two minors in this case
+        // because its type is `chrdev::Registration<2>`
+        chrdev_reg.as_mut().register::<RustFile>()?;
+        chrdev_reg.as_mut().register::<RustFile>()?;
+
+        Ok(RustChrdev { _dev: chrdev_reg })
+    }
+}
+
+impl Drop for RustChrdev {
+    fn drop(&mut self) {
+        pr_info!("Rust character device sample (exit)\n");
+    }
+}
diff --git a/samples/rust/rust_minimal.rs b/samples/rust/rust_minimal.rs
new file mode 100644
index 000000000000..f0488262bcc9
--- /dev/null
+++ b/samples/rust/rust_minimal.rs
@@ -0,0 +1,35 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Rust minimal sample.
+
+use kernel::prelude::*;
+
+module! {
+    type: RustMinimal,
+    name: b"rust_minimal",
+    author: b"Rust for Linux Contributors",
+    description: b"Rust minimal sample",
+    license: b"GPL v2",
+}
+
+struct RustMinimal {
+    message: String,
+}
+
+impl KernelModule for RustMinimal {
+    fn init(_name: &'static CStr, _module: &'static ThisModule) -> Result<Self> {
+        pr_info!("Rust minimal sample (init)\n");
+        pr_info!("Am I built-in? {}\n", !cfg!(MODULE));
+
+        Ok(RustMinimal {
+            message: "on the heap!".try_to_owned()?,
+        })
+    }
+}
+
+impl Drop for RustMinimal {
+    fn drop(&mut self) {
+        pr_info!("My message is {}\n", self.message);
+        pr_info!("Rust minimal sample (exit)\n");
+    }
+}
diff --git a/samples/rust/rust_miscdev.rs b/samples/rust/rust_miscdev.rs
new file mode 100644
index 000000000000..4a18dfc85c2e
--- /dev/null
+++ b/samples/rust/rust_miscdev.rs
@@ -0,0 +1,143 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Rust miscellaneous device sample.
+
+use kernel::prelude::*;
+use kernel::{
+    file::{self, File},
+    io_buffer::{IoBufferReader, IoBufferWriter},
+    miscdev,
+    sync::{CondVar, Mutex, Ref, RefBorrow, UniqueRef},
+};
+
+module! {
+    type: RustMiscdev,
+    name: b"rust_miscdev",
+    author: b"Rust for Linux Contributors",
+    description: b"Rust miscellaneous device sample",
+    license: b"GPL v2",
+}
+
+const MAX_TOKENS: usize = 3;
+
+struct SharedStateInner {
+    token_count: usize,
+}
+
+struct SharedState {
+    state_changed: CondVar,
+    inner: Mutex<SharedStateInner>,
+}
+
+impl SharedState {
+    fn try_new() -> Result<Ref<Self>> {
+        let mut state = Pin::from(UniqueRef::try_new(Self {
+            // SAFETY: `condvar_init!` is called below.
+            state_changed: unsafe { CondVar::new() },
+            // SAFETY: `mutex_init!` is called below.
+            inner: unsafe { Mutex::new(SharedStateInner { token_count: 0 }) },
+        })?);
+
+        // SAFETY: `state_changed` is pinned when `state` is.
+        let pinned = unsafe { state.as_mut().map_unchecked_mut(|s| &mut s.state_changed) };
+        kernel::condvar_init!(pinned, "SharedState::state_changed");
+
+        // SAFETY: `inner` is pinned when `state` is.
+        let pinned = unsafe { state.as_mut().map_unchecked_mut(|s| &mut s.inner) };
+        kernel::mutex_init!(pinned, "SharedState::inner");
+
+        Ok(state.into())
+    }
+}
+
+struct Token;
+impl file::Operations for Token {
+    type Data = Ref<SharedState>;
+    type OpenData = Ref<SharedState>;
+
+    kernel::declare_file_operations!(read, write);
+
+    fn open(shared: &Ref<SharedState>, _file: &File) -> Result<Self::Data> {
+        Ok(shared.clone())
+    }
+
+    fn read(
+        shared: RefBorrow<'_, SharedState>,
+        _: &File,
+        data: &mut impl IoBufferWriter,
+        offset: u64,
+    ) -> Result<usize> {
+        // Succeed if the caller doesn't provide a buffer or if not at the start.
+        if data.is_empty() || offset != 0 {
+            return Ok(0);
+        }
+
+        {
+            let mut inner = shared.inner.lock();
+
+            // Wait until we are allowed to decrement the token count or a signal arrives.
+            while inner.token_count == 0 {
+                if shared.state_changed.wait(&mut inner) {
+                    return Err(EINTR);
+                }
+            }
+
+            // Consume a token.
+            inner.token_count -= 1;
+        }
+
+        // Notify a possible writer waiting.
+        shared.state_changed.notify_all();
+
+        // Write a one-byte 1 to the reader.
+        data.write_slice(&[1u8; 1])?;
+        Ok(1)
+    }
+
+    fn write(
+        shared: RefBorrow<'_, SharedState>,
+        _: &File,
+        data: &mut impl IoBufferReader,
+        _offset: u64,
+    ) -> Result<usize> {
+        {
+            let mut inner = shared.inner.lock();
+
+            // Wait until we are allowed to increment the token count or a signal arrives.
+            while inner.token_count == MAX_TOKENS {
+                if shared.state_changed.wait(&mut inner) {
+                    return Err(EINTR);
+                }
+            }
+
+            // Increment the number of token so that a reader can be released.
+            inner.token_count += 1;
+        }
+
+        // Notify a possible reader waiting.
+        shared.state_changed.notify_all();
+        Ok(data.len())
+    }
+}
+
+struct RustMiscdev {
+    _dev: Pin<Box<miscdev::Registration<Token>>>,
+}
+
+impl KernelModule for RustMiscdev {
+    fn init(name: &'static CStr, _module: &'static ThisModule) -> Result<Self> {
+        pr_info!("Rust miscellaneous device sample (init)\n");
+
+        let state = SharedState::try_new()?;
+
+        Ok(RustMiscdev {
+            _dev: miscdev::Registration::new_pinned(fmt!("{name}"), state)?,
+        })
+    }
+}
+
+impl Drop for RustMiscdev {
+    fn drop(&mut self) {
+        pr_info!("Rust miscellaneous device sample (exit)\n");
+    }
+}
diff --git a/samples/rust/rust_module_parameters.rs b/samples/rust/rust_module_parameters.rs
new file mode 100644
index 000000000000..22459beba831
--- /dev/null
+++ b/samples/rust/rust_module_parameters.rs
@@ -0,0 +1,69 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Rust module parameters sample.
+
+use kernel::prelude::*;
+
+module! {
+    type: RustModuleParameters,
+    name: b"rust_module_parameters",
+    author: b"Rust for Linux Contributors",
+    description: b"Rust module parameters sample",
+    license: b"GPL v2",
+    params: {
+        my_bool: bool {
+            default: true,
+            permissions: 0,
+            description: b"Example of bool",
+        },
+        my_i32: i32 {
+            default: 42,
+            permissions: 0o644,
+            description: b"Example of i32",
+        },
+        my_str: str {
+            default: b"default str val",
+            permissions: 0o644,
+            description: b"Example of a string param",
+        },
+        my_usize: usize {
+            default: 42,
+            permissions: 0o644,
+            description: b"Example of usize",
+        },
+        my_array: ArrayParam<i32, 3> {
+            default: [0, 1],
+            permissions: 0,
+            description: b"Example of array",
+        },
+    },
+}
+
+struct RustModuleParameters;
+
+impl KernelModule for RustModuleParameters {
+    fn init(_name: &'static CStr, module: &'static ThisModule) -> Result<Self> {
+        pr_info!("Rust module parameters sample (init)\n");
+
+        {
+            let lock = module.kernel_param_lock();
+            pr_info!("Parameters:\n");
+            pr_info!("  my_bool:    {}\n", my_bool.read());
+            pr_info!("  my_i32:     {}\n", my_i32.read(&lock));
+            pr_info!(
+                "  my_str:     {}\n",
+                core::str::from_utf8(my_str.read(&lock))?
+            );
+            pr_info!("  my_usize:   {}\n", my_usize.read(&lock));
+            pr_info!("  my_array:   {:?}\n", my_array.read());
+        }
+
+        Ok(RustModuleParameters)
+    }
+}
+
+impl Drop for RustModuleParameters {
+    fn drop(&mut self) {
+        pr_info!("Rust module parameters sample (exit)\n");
+    }
+}
diff --git a/samples/rust/rust_platform.rs b/samples/rust/rust_platform.rs
new file mode 100644
index 000000000000..c0b740094c59
--- /dev/null
+++ b/samples/rust/rust_platform.rs
@@ -0,0 +1,22 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Rust platform device driver sample.
+
+use kernel::{module_platform_driver, of, platform, prelude::*};
+
+module_platform_driver! {
+    type: Driver,
+    name: b"rust_platform",
+    license: b"GPL v2",
+}
+
+struct Driver;
+impl platform::Driver for Driver {
+    kernel::define_of_id_table! {(), [
+        (of::DeviceId::Compatible(b"rust,sample"), None),
+    ]}
+
+    fn probe(_dev: &mut platform::Device, _id_info: Option<&Self::IdInfo>) -> Result {
+        Ok(())
+    }
+}
diff --git a/samples/rust/rust_print.rs b/samples/rust/rust_print.rs
new file mode 100644
index 000000000000..4a6b423af835
--- /dev/null
+++ b/samples/rust/rust_print.rs
@@ -0,0 +1,54 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Rust printing macros sample.
+
+use kernel::prelude::*;
+use kernel::{pr_cont, str::CStr, ThisModule};
+
+module! {
+    type: RustPrint,
+    name: b"rust_print",
+    author: b"Rust for Linux Contributors",
+    description: b"Rust printing macros sample",
+    license: b"GPL v2",
+}
+
+struct RustPrint;
+
+impl KernelModule for RustPrint {
+    fn init(_name: &'static CStr, _module: &'static ThisModule) -> Result<Self> {
+        pr_info!("Rust printing macros sample (init)\n");
+
+        pr_emerg!("Emergency message (level 0) without args\n");
+        pr_alert!("Alert message (level 1) without args\n");
+        pr_crit!("Critical message (level 2) without args\n");
+        pr_err!("Error message (level 3) without args\n");
+        pr_warn!("Warning message (level 4) without args\n");
+        pr_notice!("Notice message (level 5) without args\n");
+        pr_info!("Info message (level 6) without args\n");
+
+        pr_info!("A line that");
+        pr_cont!(" is continued");
+        pr_cont!(" without args\n");
+
+        pr_emerg!("{} message (level {}) with args\n", "Emergency", 0);
+        pr_alert!("{} message (level {}) with args\n", "Alert", 1);
+        pr_crit!("{} message (level {}) with args\n", "Critical", 2);
+        pr_err!("{} message (level {}) with args\n", "Error", 3);
+        pr_warn!("{} message (level {}) with args\n", "Warning", 4);
+        pr_notice!("{} message (level {}) with args\n", "Notice", 5);
+        pr_info!("{} message (level {}) with args\n", "Info", 6);
+
+        pr_info!("A {} that", "line");
+        pr_cont!(" is {}", "continued");
+        pr_cont!(" with {}\n", "args");
+
+        Ok(RustPrint)
+    }
+}
+
+impl Drop for RustPrint {
+    fn drop(&mut self) {
+        pr_info!("Rust printing macros sample (exit)\n");
+    }
+}
diff --git a/samples/rust/rust_random.rs b/samples/rust/rust_random.rs
new file mode 100644
index 000000000000..241fbbfb8673
--- /dev/null
+++ b/samples/rust/rust_random.rs
@@ -0,0 +1,60 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Rust random device.
+//!
+//! Adapted from Alex Gaynor's original available at
+//! <https://github.com/alex/just-use/blob/master/src/lib.rs>.
+
+use kernel::{
+    file::{self, File},
+    io_buffer::{IoBufferReader, IoBufferWriter},
+    prelude::*,
+};
+
+struct RandomFile;
+
+impl file::Operations for RandomFile {
+    kernel::declare_file_operations!(read, write, read_iter, write_iter);
+
+    fn open(_data: &(), _file: &File) -> Result {
+        Ok(())
+    }
+
+    fn read(_this: (), file: &File, buf: &mut impl IoBufferWriter, _: u64) -> Result<usize> {
+        let total_len = buf.len();
+        let mut chunkbuf = [0; 256];
+
+        while !buf.is_empty() {
+            let len = chunkbuf.len().min(buf.len());
+            let chunk = &mut chunkbuf[0..len];
+
+            if file.is_blocking() {
+                kernel::random::getrandom(chunk)?;
+            } else {
+                kernel::random::getrandom_nonblock(chunk)?;
+            }
+            buf.write_slice(chunk)?;
+        }
+        Ok(total_len)
+    }
+
+    fn write(_this: (), _file: &File, buf: &mut impl IoBufferReader, _: u64) -> Result<usize> {
+        let total_len = buf.len();
+        let mut chunkbuf = [0; 256];
+        while !buf.is_empty() {
+            let len = chunkbuf.len().min(buf.len());
+            let chunk = &mut chunkbuf[0..len];
+            buf.read_slice(chunk)?;
+            kernel::random::add_randomness(chunk);
+        }
+        Ok(total_len)
+    }
+}
+
+module_misc_device! {
+    type: RandomFile,
+    name: b"rust_random",
+    author: b"Rust for Linux Contributors",
+    description: b"Just use /dev/urandom: Now with early-boot safety",
+    license: b"GPL v2",
+}
diff --git a/samples/rust/rust_semaphore.rs b/samples/rust/rust_semaphore.rs
new file mode 100644
index 000000000000..ee4325f7743b
--- /dev/null
+++ b/samples/rust/rust_semaphore.rs
@@ -0,0 +1,171 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Rust semaphore sample.
+//!
+//! A counting semaphore that can be used by userspace.
+//!
+//! The count is incremented by writes to the device. A write of `n` bytes results in an increment
+//! of `n`. It is decremented by reads; each read results in the count being decremented by 1. If
+//! the count is already zero, a read will block until another write increments it.
+//!
+//! This can be used in user space from the shell for example  as follows (assuming a node called
+//! `semaphore`): `cat semaphore` decrements the count by 1 (waiting for it to become non-zero
+//! before decrementing); `echo -n 123 > semaphore` increments the semaphore by 3, potentially
+//! unblocking up to 3 blocked readers.
+
+use core::sync::atomic::{AtomicU64, Ordering};
+use kernel::{
+    condvar_init, declare_file_operations,
+    file::{self, File, IoctlCommand, IoctlHandler},
+    io_buffer::{IoBufferReader, IoBufferWriter},
+    miscdev::Registration,
+    mutex_init,
+    prelude::*,
+    sync::{CondVar, Mutex, Ref, UniqueRef},
+    user_ptr::{UserSlicePtrReader, UserSlicePtrWriter},
+};
+
+module! {
+    type: RustSemaphore,
+    name: b"rust_semaphore",
+    author: b"Rust for Linux Contributors",
+    description: b"Rust semaphore sample",
+    license: b"GPL v2",
+}
+
+struct SemaphoreInner {
+    count: usize,
+    max_seen: usize,
+}
+
+struct Semaphore {
+    changed: CondVar,
+    inner: Mutex<SemaphoreInner>,
+}
+
+struct FileState {
+    read_count: AtomicU64,
+    shared: Ref<Semaphore>,
+}
+
+impl FileState {
+    fn consume(&self) -> Result {
+        let mut inner = self.shared.inner.lock();
+        while inner.count == 0 {
+            if self.shared.changed.wait(&mut inner) {
+                return Err(EINTR);
+            }
+        }
+        inner.count -= 1;
+        Ok(())
+    }
+}
+
+impl file::Operations for FileState {
+    type Data = Box<Self>;
+    type OpenData = Ref<Semaphore>;
+
+    declare_file_operations!(read, write, ioctl);
+
+    fn open(shared: &Ref<Semaphore>, _file: &File) -> Result<Box<Self>> {
+        Ok(Box::try_new(Self {
+            read_count: AtomicU64::new(0),
+            shared: shared.clone(),
+        })?)
+    }
+
+    fn read(this: &Self, _: &File, data: &mut impl IoBufferWriter, offset: u64) -> Result<usize> {
+        if data.is_empty() || offset > 0 {
+            return Ok(0);
+        }
+        this.consume()?;
+        data.write_slice(&[0u8; 1])?;
+        this.read_count.fetch_add(1, Ordering::Relaxed);
+        Ok(1)
+    }
+
+    fn write(this: &Self, _: &File, data: &mut impl IoBufferReader, _offs: u64) -> Result<usize> {
+        {
+            let mut inner = this.shared.inner.lock();
+            inner.count = inner.count.saturating_add(data.len());
+            if inner.count > inner.max_seen {
+                inner.max_seen = inner.count;
+            }
+        }
+
+        this.shared.changed.notify_all();
+        Ok(data.len())
+    }
+
+    fn ioctl(this: &Self, file: &File, cmd: &mut IoctlCommand) -> Result<i32> {
+        cmd.dispatch::<Self>(this, file)
+    }
+}
+
+struct RustSemaphore {
+    _dev: Pin<Box<Registration<FileState>>>,
+}
+
+impl KernelModule for RustSemaphore {
+    fn init(name: &'static CStr, _module: &'static ThisModule) -> Result<Self> {
+        pr_info!("Rust semaphore sample (init)\n");
+
+        let mut sema = Pin::from(UniqueRef::try_new(Semaphore {
+            // SAFETY: `condvar_init!` is called below.
+            changed: unsafe { CondVar::new() },
+
+            // SAFETY: `mutex_init!` is called below.
+            inner: unsafe {
+                Mutex::new(SemaphoreInner {
+                    count: 0,
+                    max_seen: 0,
+                })
+            },
+        })?);
+
+        // SAFETY: `changed` is pinned when `sema` is.
+        let pinned = unsafe { sema.as_mut().map_unchecked_mut(|s| &mut s.changed) };
+        condvar_init!(pinned, "Semaphore::changed");
+
+        // SAFETY: `inner` is pinned when `sema` is.
+        let pinned = unsafe { sema.as_mut().map_unchecked_mut(|s| &mut s.inner) };
+        mutex_init!(pinned, "Semaphore::inner");
+
+        Ok(Self {
+            _dev: Registration::new_pinned(fmt!("{name}"), sema.into())?,
+        })
+    }
+}
+
+impl Drop for RustSemaphore {
+    fn drop(&mut self) {
+        pr_info!("Rust semaphore sample (exit)\n");
+    }
+}
+
+const IOCTL_GET_READ_COUNT: u32 = 0x80086301;
+const IOCTL_SET_READ_COUNT: u32 = 0x40086301;
+
+impl IoctlHandler for FileState {
+    type Target<'a> = &'a Self;
+
+    fn read(this: &Self, _: &File, cmd: u32, writer: &mut UserSlicePtrWriter) -> Result<i32> {
+        match cmd {
+            IOCTL_GET_READ_COUNT => {
+                writer.write(&this.read_count.load(Ordering::Relaxed))?;
+                Ok(0)
+            }
+            _ => Err(EINVAL),
+        }
+    }
+
+    fn write(this: &Self, _: &File, cmd: u32, reader: &mut UserSlicePtrReader) -> Result<i32> {
+        match cmd {
+            IOCTL_SET_READ_COUNT => {
+                this.read_count.store(reader.read()?, Ordering::Relaxed);
+                Ok(0)
+            }
+            _ => Err(EINVAL),
+        }
+    }
+}
diff --git a/samples/rust/rust_semaphore_c.c b/samples/rust/rust_semaphore_c.c
new file mode 100644
index 000000000000..cdc121d4030d
--- /dev/null
+++ b/samples/rust/rust_semaphore_c.c
@@ -0,0 +1,212 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Rust semaphore sample (in C, for comparison)
+ *
+ * This is a C implementation of `rust_semaphore.rs`. Refer to the description
+ * in that file for details on the device.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/miscdevice.h>
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/slab.h>
+#include <linux/refcount.h>
+#include <linux/wait.h>
+
+#define IOCTL_GET_READ_COUNT _IOR('c', 1, u64)
+#define IOCTL_SET_READ_COUNT _IOW('c', 1, u64)
+
+struct semaphore_state {
+	struct kref ref;
+	struct miscdevice miscdev;
+	wait_queue_head_t changed;
+	struct mutex mutex;
+	size_t count;
+	size_t max_seen;
+};
+
+struct file_state {
+	atomic64_t read_count;
+	struct semaphore_state *shared;
+};
+
+static int semaphore_consume(struct semaphore_state *state)
+{
+	DEFINE_WAIT(wait);
+
+	mutex_lock(&state->mutex);
+	while (state->count == 0) {
+		prepare_to_wait(&state->changed, &wait, TASK_INTERRUPTIBLE);
+		mutex_unlock(&state->mutex);
+		schedule();
+		finish_wait(&state->changed, &wait);
+		if (signal_pending(current))
+			return -EINTR;
+		mutex_lock(&state->mutex);
+	}
+
+	state->count--;
+	mutex_unlock(&state->mutex);
+
+	return 0;
+}
+
+static int semaphore_open(struct inode *nodp, struct file *filp)
+{
+	struct semaphore_state *shared =
+		container_of(filp->private_data, struct semaphore_state, miscdev);
+	struct file_state *state;
+
+	state = kzalloc(sizeof(*state), GFP_KERNEL);
+	if (!state)
+		return -ENOMEM;
+
+	kref_get(&shared->ref);
+	state->shared = shared;
+	atomic64_set(&state->read_count, 0);
+
+	filp->private_data = state;
+
+	return 0;
+}
+
+static ssize_t semaphore_write(struct file *filp, const char __user *buffer, size_t count,
+			       loff_t *ppos)
+{
+	struct file_state *state = filp->private_data;
+	struct semaphore_state *shared = state->shared;
+
+	mutex_lock(&shared->mutex);
+
+	shared->count += count;
+	if (shared->count < count)
+		shared->count = SIZE_MAX;
+
+	if (shared->count > shared->max_seen)
+		shared->max_seen = shared->count;
+
+	mutex_unlock(&shared->mutex);
+
+	wake_up_all(&shared->changed);
+
+	return count;
+}
+
+static ssize_t semaphore_read(struct file *filp, char __user *buffer,
+			      size_t count, loff_t *ppos)
+{
+	struct file_state *state = filp->private_data;
+	char c = 0;
+	int ret;
+
+	if (count == 0 || *ppos > 0)
+		return 0;
+
+	ret = semaphore_consume(state->shared);
+	if (ret)
+		return ret;
+
+	if (copy_to_user(buffer, &c, sizeof(c)))
+		return -EFAULT;
+
+	atomic64_add(1, &state->read_count);
+	*ppos += 1;
+	return 1;
+}
+
+static long semaphore_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
+{
+	struct file_state *state = filp->private_data;
+	void __user *buffer = (void __user *)arg;
+	u64 value;
+
+	switch (cmd) {
+	case IOCTL_GET_READ_COUNT:
+		value = atomic64_read(&state->read_count);
+		if (copy_to_user(buffer, &value, sizeof(value)))
+			return -EFAULT;
+		return 0;
+	case IOCTL_SET_READ_COUNT:
+		if (copy_from_user(&value, buffer, sizeof(value)))
+			return -EFAULT;
+		atomic64_set(&state->read_count, value);
+		return 0;
+	default:
+		return -EINVAL;
+	}
+}
+
+static void semaphore_free(struct kref *kref)
+{
+	struct semaphore_state *device;
+
+	device = container_of(kref, struct semaphore_state, ref);
+	kfree(device);
+}
+
+static int semaphore_release(struct inode *nodp, struct file *filp)
+{
+	struct file_state *state = filp->private_data;
+
+	kref_put(&state->shared->ref, semaphore_free);
+	kfree(state);
+	return 0;
+}
+
+static const struct file_operations semaphore_fops = {
+	.owner = THIS_MODULE,
+	.open = semaphore_open,
+	.read = semaphore_read,
+	.write = semaphore_write,
+	.compat_ioctl = semaphore_ioctl,
+	.release = semaphore_release,
+};
+
+static struct semaphore_state *device;
+
+static int __init semaphore_init(void)
+{
+	int ret;
+	struct semaphore_state *state;
+
+	pr_info("Rust semaphore sample (in C, for comparison) (init)\n");
+
+	state = kzalloc(sizeof(*state), GFP_KERNEL);
+	if (!state)
+		return -ENOMEM;
+
+	mutex_init(&state->mutex);
+	kref_init(&state->ref);
+	init_waitqueue_head(&state->changed);
+
+	state->miscdev.fops = &semaphore_fops;
+	state->miscdev.minor = MISC_DYNAMIC_MINOR;
+	state->miscdev.name = "semaphore";
+
+	ret = misc_register(&state->miscdev);
+	if (ret < 0) {
+		kfree(state);
+		return ret;
+	}
+
+	device = state;
+
+	return 0;
+}
+
+static void __exit semaphore_exit(void)
+{
+	pr_info("Rust semaphore sample (in C, for comparison) (exit)\n");
+
+	misc_deregister(&device->miscdev);
+	kref_put(&device->ref, semaphore_free);
+}
+
+module_init(semaphore_init);
+module_exit(semaphore_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Rust for Linux Contributors");
+MODULE_DESCRIPTION("Rust semaphore sample (in C, for comparison)");
diff --git a/samples/rust/rust_stack_probing.rs b/samples/rust/rust_stack_probing.rs
new file mode 100644
index 000000000000..214d4d1f6528
--- /dev/null
+++ b/samples/rust/rust_stack_probing.rs
@@ -0,0 +1,36 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Rust stack probing sample.
+
+use kernel::prelude::*;
+
+module! {
+    type: RustStackProbing,
+    name: b"rust_stack_probing",
+    author: b"Rust for Linux Contributors",
+    description: b"Rust stack probing sample",
+    license: b"GPL v2",
+}
+
+struct RustStackProbing;
+
+impl KernelModule for RustStackProbing {
+    fn init(_name: &'static CStr, _module: &'static ThisModule) -> Result<Self> {
+        pr_info!("Rust stack probing sample (init)\n");
+
+        // Including this large variable on the stack will trigger
+        // stack probing on the supported archs.
+        // This will verify that stack probing does not lead to
+        // any errors if we need to link `__rust_probestack`.
+        let x: [u64; 514] = core::hint::black_box([5; 514]);
+        pr_info!("Large array has length: {}\n", x.len());
+
+        Ok(RustStackProbing)
+    }
+}
+
+impl Drop for RustStackProbing {
+    fn drop(&mut self) {
+        pr_info!("Rust stack probing sample (exit)\n");
+    }
+}
diff --git a/samples/rust/rust_sync.rs b/samples/rust/rust_sync.rs
new file mode 100644
index 000000000000..f89f678dcb0d
--- /dev/null
+++ b/samples/rust/rust_sync.rs
@@ -0,0 +1,93 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Rust synchronisation primitives sample.
+
+use kernel::prelude::*;
+use kernel::{
+    condvar_init, mutex_init, spinlock_init,
+    sync::{CondVar, Mutex, SpinLock},
+};
+
+module! {
+    type: RustSync,
+    name: b"rust_sync",
+    author: b"Rust for Linux Contributors",
+    description: b"Rust synchronisation primitives sample",
+    license: b"GPL v2",
+}
+
+kernel::init_static_sync! {
+    static SAMPLE_MUTEX: Mutex<u32> = 10;
+    static SAMPLE_CONDVAR: CondVar;
+}
+
+struct RustSync;
+
+impl KernelModule for RustSync {
+    fn init(_name: &'static CStr, _module: &'static ThisModule) -> Result<Self> {
+        pr_info!("Rust synchronisation primitives sample (init)\n");
+
+        // Test mutexes.
+        {
+            // SAFETY: `init` is called below.
+            let mut data = Pin::from(Box::try_new(unsafe { Mutex::new(0) })?);
+            mutex_init!(data.as_mut(), "RustSync::init::data1");
+            *data.lock() = 10;
+            pr_info!("Value: {}\n", *data.lock());
+
+            // SAFETY: `init` is called below.
+            let mut cv = Pin::from(Box::try_new(unsafe { CondVar::new() })?);
+            condvar_init!(cv.as_mut(), "RustSync::init::cv1");
+
+            {
+                let mut guard = data.lock();
+                while *guard != 10 {
+                    let _ = cv.wait(&mut guard);
+                }
+            }
+            cv.notify_one();
+            cv.notify_all();
+            cv.free_waiters();
+        }
+
+        // Test static mutex + condvar.
+        *SAMPLE_MUTEX.lock() = 20;
+
+        {
+            let mut guard = SAMPLE_MUTEX.lock();
+            while *guard != 20 {
+                let _ = SAMPLE_CONDVAR.wait(&mut guard);
+            }
+        }
+
+        // Test spinlocks.
+        {
+            // SAFETY: `init` is called below.
+            let mut data = Pin::from(Box::try_new(unsafe { SpinLock::new(0) })?);
+            spinlock_init!(data.as_mut(), "RustSync::init::data2");
+            *data.lock() = 10;
+            pr_info!("Value: {}\n", *data.lock());
+
+            // SAFETY: `init` is called below.
+            let mut cv = Pin::from(Box::try_new(unsafe { CondVar::new() })?);
+            condvar_init!(cv.as_mut(), "RustSync::init::cv2");
+            {
+                let mut guard = data.lock();
+                while *guard != 10 {
+                    let _ = cv.wait(&mut guard);
+                }
+            }
+            cv.notify_one();
+            cv.notify_all();
+            cv.free_waiters();
+        }
+
+        Ok(RustSync)
+    }
+}
+
+impl Drop for RustSync {
+    fn drop(&mut self) {
+        pr_info!("Rust synchronisation primitives sample (exit)\n");
+    }
+}
-- 
2.35.1


^ permalink raw reply related	[relevance 3%]

* [PATCH bpf-next] bpf/bpftool: add unprivileged_bpf_disabled check against value of 2
@ 2022-03-22 14:49 14% Milan Landaverde
  2022-03-22 15:54  6% ` Quentin Monnet
  0 siblings, 1 reply; 77+ results
From: Milan Landaverde @ 2022-03-22 14:49 UTC (permalink / raw)
  Cc: milan, Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko,
	Martin KaFai Lau, Song Liu, Yonghong Song, John Fastabend,
	KP Singh, Quentin Monnet, Paul Chaignon, Niklas Söderlund,
	netdev, bpf, linux-kernel

In [1], we added a kconfig knob that can set
/proc/sys/kernel/unprivileged_bpf_disabled to 2

We now check against this value in bpftool feature probe

[1] https://lore.kernel.org/bpf/74ec548079189e4e4dffaeb42b8987bb3c852eee.1620765074.git.daniel@iogearbox.net

Signed-off-by: Milan Landaverde <milan@mdaverde.com>
---
 tools/bpf/bpftool/feature.c | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/tools/bpf/bpftool/feature.c b/tools/bpf/bpftool/feature.c
index c2f43a5d38e0..290998c82de1 100644
--- a/tools/bpf/bpftool/feature.c
+++ b/tools/bpf/bpftool/feature.c
@@ -207,7 +207,10 @@ static void probe_unprivileged_disabled(void)
 			printf("bpf() syscall for unprivileged users is enabled\n");
 			break;
 		case 1:
-			printf("bpf() syscall restricted to privileged users\n");
+			printf("bpf() syscall restricted to privileged users (without recovery)\n");
+			break;
+		case 2:
+			printf("bpf() syscall restricted to privileged users (admin can change)\n");
 			break;
 		case -1:
 			printf("Unable to retrieve required privileges for bpf() syscall\n");
-- 
2.32.0


^ permalink raw reply related	[relevance 14%]

* Re: [PATCH bpf-next] bpf/bpftool: add unprivileged_bpf_disabled check against value of 2
  2022-03-22 14:49 14% [PATCH bpf-next] bpf/bpftool: add unprivileged_bpf_disabled check against value of 2 Milan Landaverde
@ 2022-03-22 15:54  6% ` Quentin Monnet
  2022-03-22 17:39  0%   ` KP Singh
  0 siblings, 1 reply; 77+ results
From: Quentin Monnet @ 2022-03-22 15:54 UTC (permalink / raw)
  To: Milan Landaverde
  Cc: Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko,
	Martin KaFai Lau, Song Liu, Yonghong Song, John Fastabend,
	KP Singh, Paul Chaignon, Niklas Söderlund, netdev, bpf,
	linux-kernel

2022-03-22 10:49 UTC-0400 ~ Milan Landaverde <milan@mdaverde.com>
> In [1], we added a kconfig knob that can set
> /proc/sys/kernel/unprivileged_bpf_disabled to 2
> 
> We now check against this value in bpftool feature probe
> 
> [1] https://lore.kernel.org/bpf/74ec548079189e4e4dffaeb42b8987bb3c852eee.1620765074.git.daniel@iogearbox.net
> 
> Signed-off-by: Milan Landaverde <milan@mdaverde.com>

Acked-by: Quentin Monnet <quentin@isovalent.com>

Thanks!

^ permalink raw reply	[relevance 6%]

* Re: [PATCH bpf-next] bpf/bpftool: add unprivileged_bpf_disabled check against value of 2
  2022-03-22 15:54  6% ` Quentin Monnet
@ 2022-03-22 17:39  0%   ` KP Singh
  0 siblings, 0 replies; 77+ results
From: KP Singh @ 2022-03-22 17:39 UTC (permalink / raw)
  To: Quentin Monnet
  Cc: Milan Landaverde, Alexei Starovoitov, Daniel Borkmann,
	Andrii Nakryiko, Martin KaFai Lau, Song Liu, Yonghong Song,
	John Fastabend, Paul Chaignon, Niklas Söderlund, netdev,
	bpf, linux-kernel

On Tue, Mar 22, 2022 at 4:54 PM Quentin Monnet <quentin@isovalent.com> wrote:
>
> 2022-03-22 10:49 UTC-0400 ~ Milan Landaverde <milan@mdaverde.com>
> > In [1], we added a kconfig knob that can set
> > /proc/sys/kernel/unprivileged_bpf_disabled to 2
> >
> > We now check against this value in bpftool feature probe
> >
> > [1] https://lore.kernel.org/bpf/74ec548079189e4e4dffaeb42b8987bb3c852eee.1620765074.git.daniel@iogearbox.net
> >
> > Signed-off-by: Milan Landaverde <milan@mdaverde.com>
>
> Acked-by: Quentin Monnet <quentin@isovalent.com>

Acked-by: KP Singh <kpsingh@kernel.org>

Thanks, this is very useful!

^ permalink raw reply	[relevance 0%]

* pull-request: bpf 2022-03-29
@ 2022-03-29 23:49  4% Alexei Starovoitov
  0 siblings, 0 replies; 77+ results
From: Alexei Starovoitov @ 2022-03-29 23:49 UTC (permalink / raw)
  To: davem; +Cc: daniel, peterz, mhiramat, kuba, andrii, netdev, bpf, kernel-team

Hi David, hi Jakub,

The following pull-request contains BPF updates for your *net* tree.

We've added 16 non-merge commits during the last 1 day(s) which contain
a total of 24 files changed, 354 insertions(+), 187 deletions(-).

The main changes are:

1) x86 specific bits of fprobe/rethook, from Masami and Peter.

2) ice/xsk fixes, from Maciej and Magnus.

3) Various small fixes, from Andrii, Yonghong, Geliang and others.

Please consider pulling these changes from:

  git://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf.git

Thanks a lot!

Also thanks to reporters, reviewers and testers of commits in this pull-request:

Arnaldo Carvalho de Melo, Dan Carpenter, Jiri Olsa, kernel test robot, 
KP Singh, Martin KaFai Lau, Masami Hiramatsu, Quentin Monnet, Yonghong 
Song

----------------------------------------------------------------

The following changes since commit d717e4cae0fe77e10a27e8545a967b8c379873ac:

  Merge tag 'net-5.18-rc0' of git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net (2022-03-28 17:02:04 -0700)

are available in the Git repository at:

  https://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf.git 

for you to fetch changes up to ccaff3d56acc47c257a99b2807b7c78a9467cf09:

  selftests/bpf: Fix clang compilation errors (2022-03-28 20:00:11 -0700)

----------------------------------------------------------------
Alexei Starovoitov (3):
      Merge branch 'fprobe: Fixes for Sparse and Smatch warnings'
      Merge branch 'kprobes: rethook: x86: Replace kretprobe trampoline with rethook'
      Merge branch 'xsk: another round of fixes'

Andrii Nakryiko (1):
      selftests/bpf: fix selftest after random: Urandom_read tracepoint removal

Geliang Tang (1):
      bpf: Sync comments for bpf_get_stack

Jiri Olsa (1):
      bpftool: Fix generated code in codegen_asserts

Maciej Fijalkowski (2):
      ice: xsk: Stop Rx processing when ntc catches ntu
      ice: xsk: Fix indexing in ice_tx_xsk_pool()

Magnus Karlsson (2):
      xsk: Do not write NULL in SW ring at allocation failure
      ice: xsk: Eliminate unnecessary loop iteration

Masami Hiramatsu (5):
      fprobe: Fix smatch type mismatch warning
      fprobe: Fix sparse warning for acccessing __rcu ftrace_hash
      kprobes: Use rethook for kretprobe if possible
      x86,rethook,kprobes: Replace kretprobe with rethook on x86
      x86,kprobes: Fix optprobe trampoline to generate complete pt_regs

Milan Landaverde (1):
      bpf/bpftool: Add unprivileged_bpf_disabled check against value of 2

Peter Zijlstra (1):
      x86,rethook: Fix arch_rethook_trampoline() to generate a complete pt_regs

Yonghong Song (1):
      selftests/bpf: Fix clang compilation errors

Yuntao Wang (1):
      bpf: Fix maximum permitted number of arguments check

 arch/Kconfig                                       |   8 +-
 arch/x86/Kconfig                                   |   1 +
 arch/x86/include/asm/unwind.h                      |  23 ++--
 arch/x86/kernel/Makefile                           |   1 +
 arch/x86/kernel/kprobes/common.h                   |   1 +
 arch/x86/kernel/kprobes/core.c                     | 107 -----------------
 arch/x86/kernel/kprobes/opt.c                      |  25 ++--
 arch/x86/kernel/rethook.c                          | 127 +++++++++++++++++++++
 arch/x86/kernel/unwind_orc.c                       |  10 +-
 drivers/net/ethernet/intel/ice/ice.h               |   2 +-
 drivers/net/ethernet/intel/ice/ice_xsk.c           |   5 +-
 include/linux/kprobes.h                            |  51 ++++++++-
 kernel/Makefile                                    |   1 +
 kernel/bpf/btf.c                                   |   2 +-
 kernel/kprobes.c                                   | 124 ++++++++++++++++----
 kernel/trace/fprobe.c                              |   8 +-
 kernel/trace/trace_kprobe.c                        |   4 +-
 net/xdp/xsk_buff_pool.c                            |   8 +-
 tools/bpf/bpftool/feature.c                        |   5 +-
 tools/bpf/bpftool/gen.c                            |   2 +-
 tools/include/uapi/linux/bpf.h                     |   8 +-
 .../selftests/bpf/prog_tests/get_stack_raw_tp.c    |   3 -
 .../selftests/bpf/progs/test_stacktrace_build_id.c |  12 +-
 tools/testing/selftests/bpf/test_lpm_map.c         |   3 +-
 24 files changed, 354 insertions(+), 187 deletions(-)
 create mode 100644 arch/x86/kernel/rethook.c

^ permalink raw reply	[relevance 4%]

* [PATCH bpf-next 2/3] bpf/bpftool: add missing link types
  2022-03-31 15:45 13% [PATCH bpf-next 0/3] bpf/bpftool: add program & link type names Milan Landaverde
  2022-03-31 15:45 14% ` [PATCH bpf-next 1/3] bpf/bpftool: add syscall prog type Milan Landaverde
@ 2022-03-31 15:45 14% ` Milan Landaverde
  2022-04-01 16:05  6%   ` Quentin Monnet
  2022-03-31 15:45 14% ` [PATCH bpf-next 3/3] bpf/bpftool: handle libbpf_probe_prog_type errors Milan Landaverde
  2 siblings, 1 reply; 77+ results
From: Milan Landaverde @ 2022-03-31 15:45 UTC (permalink / raw)
  To: bpf
  Cc: milan, ast, daniel, andrii, kafai, songliubraving, yhs,
	john.fastabend, kpsingh, quentin, davemarchevsky, sdf, netdev,
	linux-kernel

Will display the link type names in bpftool link show output

Signed-off-by: Milan Landaverde <milan@mdaverde.com>
---
 tools/bpf/bpftool/link.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/tools/bpf/bpftool/link.c b/tools/bpf/bpftool/link.c
index 97dec81950e5..9392ef390828 100644
--- a/tools/bpf/bpftool/link.c
+++ b/tools/bpf/bpftool/link.c
@@ -20,6 +20,8 @@ static const char * const link_type_name[] = {
 	[BPF_LINK_TYPE_CGROUP]			= "cgroup",
 	[BPF_LINK_TYPE_ITER]			= "iter",
 	[BPF_LINK_TYPE_NETNS]			= "netns",
+	[BPF_LINK_TYPE_XDP]				= "xdp",
+	[BPF_LINK_TYPE_PERF_EVENT]		= "perf_event",
 };
 
 static struct hashmap *link_table;
-- 
2.32.0


^ permalink raw reply related	[relevance 14%]

* [PATCH bpf-next 1/3] bpf/bpftool: add syscall prog type
  2022-03-31 15:45 13% [PATCH bpf-next 0/3] bpf/bpftool: add program & link type names Milan Landaverde
@ 2022-03-31 15:45 14% ` Milan Landaverde
  2022-04-01 16:04  6%   ` Quentin Monnet
  2022-03-31 15:45 14% ` [PATCH bpf-next 2/3] bpf/bpftool: add missing link types Milan Landaverde
  2022-03-31 15:45 14% ` [PATCH bpf-next 3/3] bpf/bpftool: handle libbpf_probe_prog_type errors Milan Landaverde
  2 siblings, 1 reply; 77+ results
From: Milan Landaverde @ 2022-03-31 15:45 UTC (permalink / raw)
  To: bpf
  Cc: milan, ast, daniel, andrii, kafai, songliubraving, yhs,
	john.fastabend, kpsingh, quentin, davemarchevsky, sdf, netdev,
	linux-kernel

In addition to displaying the program type in bpftool prog show
this enables us to be able to query bpf_prog_type_syscall
availability through feature probe as well as see
which helpers are available in those programs (such as
bpf_sys_bpf and bpf_sys_close)

Signed-off-by: Milan Landaverde <milan@mdaverde.com>
---
 tools/bpf/bpftool/prog.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/tools/bpf/bpftool/prog.c b/tools/bpf/bpftool/prog.c
index bc4e05542c2b..8643b37d4e43 100644
--- a/tools/bpf/bpftool/prog.c
+++ b/tools/bpf/bpftool/prog.c
@@ -68,6 +68,7 @@ const char * const prog_type_name[] = {
 	[BPF_PROG_TYPE_EXT]			= "ext",
 	[BPF_PROG_TYPE_LSM]			= "lsm",
 	[BPF_PROG_TYPE_SK_LOOKUP]		= "sk_lookup",
+	[BPF_PROG_TYPE_SYSCALL]			= "syscall",
 };
 
 const size_t prog_type_name_size = ARRAY_SIZE(prog_type_name);
-- 
2.32.0


^ permalink raw reply related	[relevance 14%]

* [PATCH bpf-next 0/3] bpf/bpftool: add program & link type names
@ 2022-03-31 15:45 13% Milan Landaverde
  2022-03-31 15:45 14% ` [PATCH bpf-next 1/3] bpf/bpftool: add syscall prog type Milan Landaverde
                   ` (2 more replies)
  0 siblings, 3 replies; 77+ results
From: Milan Landaverde @ 2022-03-31 15:45 UTC (permalink / raw)
  To: bpf
  Cc: milan, ast, daniel, andrii, kafai, songliubraving, yhs,
	john.fastabend, kpsingh, quentin, davemarchevsky, sdf, netdev,
	linux-kernel

With the addition of the syscall prog type we should now
be able to see feature probe info for that prog type:

    $ bpftool feature probe kernel
    ...
    eBPF program_type syscall is available
    ...
    eBPF helpers supported for program type syscall:
        ...
        - bpf_sys_bpf
        - bpf_sys_close

And for the link types, their names should aid in
the output.

Before:
    $ bpftool link show
    50: type 7  prog 5042
	    bpf_cookie 0
	    pids vfsstat(394433)

After:
    $ bpftool link show
    57: perf_event  prog 5058
	    bpf_cookie 0
	    pids vfsstat(394725)

Milan Landaverde (3):
  bpf/bpftool: add syscall prog type
  bpf/bpftool: add missing link types
  bpf/bpftool: handle libbpf_probe_prog_type errors

 tools/bpf/bpftool/feature.c | 2 +-
 tools/bpf/bpftool/link.c    | 2 ++
 tools/bpf/bpftool/prog.c    | 1 +
 3 files changed, 4 insertions(+), 1 deletion(-)

--
2.32.0


^ permalink raw reply	[relevance 13%]

* [PATCH bpf-next 3/3] bpf/bpftool: handle libbpf_probe_prog_type errors
  2022-03-31 15:45 13% [PATCH bpf-next 0/3] bpf/bpftool: add program & link type names Milan Landaverde
  2022-03-31 15:45 14% ` [PATCH bpf-next 1/3] bpf/bpftool: add syscall prog type Milan Landaverde
  2022-03-31 15:45 14% ` [PATCH bpf-next 2/3] bpf/bpftool: add missing link types Milan Landaverde
@ 2022-03-31 15:45 14% ` Milan Landaverde
  2022-04-01 16:05  6%   ` Quentin Monnet
  2 siblings, 1 reply; 77+ results
From: Milan Landaverde @ 2022-03-31 15:45 UTC (permalink / raw)
  To: bpf
  Cc: milan, ast, daniel, andrii, kafai, songliubraving, yhs,
	john.fastabend, kpsingh, quentin, davemarchevsky, sdf, netdev,
	linux-kernel

Previously [1], we were using bpf_probe_prog_type which returned a
bool, but the new libbpf_probe_bpf_prog_type can return a negative
error code on failure. This change decides for bpftool to declare
a program type is not available on probe failure.

[1] https://lore.kernel.org/bpf/20220202225916.3313522-3-andrii@kernel.org/

Signed-off-by: Milan Landaverde <milan@mdaverde.com>
---
 tools/bpf/bpftool/feature.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/tools/bpf/bpftool/feature.c b/tools/bpf/bpftool/feature.c
index c2f43a5d38e0..b2fbaa7a6b15 100644
--- a/tools/bpf/bpftool/feature.c
+++ b/tools/bpf/bpftool/feature.c
@@ -564,7 +564,7 @@ probe_prog_type(enum bpf_prog_type prog_type, bool *supported_types,
 
 		res = probe_prog_type_ifindex(prog_type, ifindex);
 	} else {
-		res = libbpf_probe_bpf_prog_type(prog_type, NULL);
+		res = libbpf_probe_bpf_prog_type(prog_type, NULL) > 0;
 	}
 
 #ifdef USE_LIBCAP
-- 
2.32.0


^ permalink raw reply related	[relevance 14%]

* [GIT PULL] Networking for 5.18-rc1
@ 2022-03-31 17:24  3% Jakub Kicinski
  0 siblings, 0 replies; 77+ results
From: Jakub Kicinski @ 2022-03-31 17:24 UTC (permalink / raw)
  To: torvalds; +Cc: kuba, davem, netdev, linux-kernel

Hi Linus!

The following changes since commit d717e4cae0fe77e10a27e8545a967b8c379873ac:

  Merge tag 'net-5.18-rc0' of git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net (2022-03-28 17:02:04 -0700)

are available in the Git repository at:

  git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net.git tags/net-5.18-rc1

for you to fetch changes up to 9d570741aec1e1ebd37823b34a2958f24809ff24:

  vxlan: do not feed vxlan_vnifilter_dump_dev with non vxlan devices (2022-03-31 08:53:01 -0700)

----------------------------------------------------------------
Networking fixes for 5.18-rc1 and rethook patches.

Features:

 - kprobes: rethook: x86: replace kretprobe trampoline with rethook

Current release - regressions:

 - sfc: avoid null-deref on systems without NUMA awareness
   in the new queue sizing code

Current release - new code bugs:

 - vxlan: do not feed vxlan_vnifilter_dump_dev with non-vxlan devices

 - eth: lan966x: fix null-deref on PHY pointer in timestamp ioctl
   when interface is down

Previous releases - always broken:

 - openvswitch: correct neighbor discovery target mask field
   in the flow dump

 - wireguard: ignore v6 endpoints when ipv6 is disabled and fix a leak

 - rxrpc: fix call timer start racing with call destruction

 - rxrpc: fix null-deref when security type is rxrpc_no_security

 - can: fix UAF bugs around echo skbs in multiple drivers

Misc:

 - docs: move netdev-FAQ to the "process" section of the documentation

Signed-off-by: Jakub Kicinski <kuba@kernel.org>

----------------------------------------------------------------
Alexei Starovoitov (3):
      Merge branch 'fprobe: Fixes for Sparse and Smatch warnings'
      Merge branch 'kprobes: rethook: x86: Replace kretprobe trampoline with rethook'
      Merge branch 'xsk: another round of fixes'

Andrii Nakryiko (1):
      selftests/bpf: fix selftest after random: Urandom_read tracepoint removal

David Howells (1):
      rxrpc: Fix call timer start racing with call destruction

Duoming Zhou (2):
      ax25: fix UAF bug in ax25_send_control()
      ax25: Fix UAF bugs in ax25 timers

Eric Dumazet (1):
      vxlan: do not feed vxlan_vnifilter_dump_dev with non vxlan devices

Geliang Tang (1):
      bpf: Sync comments for bpf_get_stack

Guangbin Huang (1):
      net: hns3: fix software vlan talbe of vlan 0 inconsistent with hardware

Hangyu Hua (3):
      can: ems_usb: ems_usb_start_xmit(): fix double dev_kfree_skb() in error path
      can: usb_8dev: usb_8dev_start_xmit(): fix double dev_kfree_skb() in error path
      can: mcba_usb: mcba_usb_start_xmit(): fix double dev_kfree_skb in error path

Jakub Kicinski (17):
      Merge https://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf
      Merge branch 'wireguard-patches-for-5-18-rc1'
      docs: netdev: replace references to old archives
      docs: netdev: minor reword
      docs: netdev: move the patch marking section up
      docs: netdev: turn the net-next closed into a Warning
      docs: netdev: note that RFC postings are allowed any time
      docs: netdev: shorten the name and mention msgid for patch status
      docs: netdev: rephrase the 'Under review' question
      docs: netdev: rephrase the 'should I update patchwork' question
      docs: netdev: add a question about re-posting frequency
      docs: netdev: make the testing requirement more stringent
      docs: netdev: add missing back ticks
      docs: netdev: call out the merge window in tag checking
      docs: netdev: broaden the new vs old code formatting guidelines
      docs: netdev: move the netdev-FAQ to the process pages
      Merge tag 'linux-can-fixes-for-5.18-20220331' of git://git.kernel.org/pub/scm/linux/kernel/git/mkl/linux-can

Jason A. Donenfeld (3):
      wireguard: queueing: use CFI-safe ptr_ring cleanup function
      wireguard: selftests: simplify RNG seeding
      wireguard: socket: ignore v6 endpoints when ipv6 is disabled

Jiri Olsa (1):
      bpftool: Fix generated code in codegen_asserts

Jonathan Lemon (1):
      ptp: ocp: handle error from nvmem_device_find

Maciej Fijalkowski (2):
      ice: xsk: Stop Rx processing when ntc catches ntu
      ice: xsk: Fix indexing in ice_tx_xsk_pool()

Magnus Karlsson (2):
      xsk: Do not write NULL in SW ring at allocation failure
      ice: xsk: Eliminate unnecessary loop iteration

Marc Kleine-Budde (2):
      can: m_can: m_can_tx_handler(): fix use after free of skb
      can: gs_usb: gs_make_candev(): fix memory leak for devices with extended bit timing configuration

Martin Habets (1):
      sfc: Avoid NULL pointer dereference on systems without numa awareness

Martin Varghese (1):
      openvswitch: Fixed nd target mask field in the flow dump.

Masami Hiramatsu (5):
      fprobe: Fix smatch type mismatch warning
      fprobe: Fix sparse warning for acccessing __rcu ftrace_hash
      kprobes: Use rethook for kretprobe if possible
      x86,rethook,kprobes: Replace kretprobe with rethook on x86
      x86,kprobes: Fix optprobe trampoline to generate complete pt_regs

Michael Walle (1):
      net: lan966x: fix kernel oops on ioctl when I/F is down

Milan Landaverde (1):
      bpf/bpftool: Add unprivileged_bpf_disabled check against value of 2

Oliver Hartkopp (1):
      can: isotp: restore accidentally removed MSG_PEEK feature

Paolo Abeni (3):
      Merge branch 'fix-uaf-bugs-caused-by-ax25_release'
      Merge branch 'docs-update-and-move-the-netdev-faq'
      Merge branch 'net-hns3-add-two-fixes-for-net'

Pavel Skripkin (1):
      can: mcba_usb: properly check endpoint type

Peter Zijlstra (1):
      x86,rethook: Fix arch_rethook_trampoline() to generate a complete pt_regs

Randy Dunlap (1):
      net: sparx5: uses, depends on BRIDGE or !BRIDGE

Stéphane Graber (1):
      openvswitch: Add recirc_id to recirc warning

Tom Rix (1):
      can: mcp251xfd: mcp251xfd_register_get_dev_id(): fix return of error value

Vinod Koul (1):
      dt-bindings: net: qcom,ethqos: Document SM8150 SoC compatible

Wang Hai (1):
      wireguard: socket: free skb in send6 when ipv6 is disabled

Xiaolong Huang (1):
      rxrpc: fix some null-ptr-deref bugs in server_key.c

Yonghong Song (1):
      selftests/bpf: Fix clang compilation errors

Yufeng Mo (1):
      net: hns3: fix the concurrency between functions reading debugfs

Yuntao Wang (1):
      bpf: Fix maximum permitted number of arguments check

Zheng Yongjun (1):
      net: dsa: felix: fix possible NULL pointer dereference

 Documentation/bpf/bpf_devel_QA.rst                 |   2 +-
 .../devicetree/bindings/net/qcom,ethqos.txt        |   4 +-
 Documentation/networking/index.rst                 |   3 +-
 Documentation/process/maintainer-handbooks.rst     |   1 +
 .../maintainer-netdev.rst}                         | 114 ++++++++++--------
 MAINTAINERS                                        |   1 +
 arch/Kconfig                                       |   8 +-
 arch/x86/Kconfig                                   |   1 +
 arch/x86/include/asm/unwind.h                      |  23 ++--
 arch/x86/kernel/Makefile                           |   1 +
 arch/x86/kernel/kprobes/common.h                   |   1 +
 arch/x86/kernel/kprobes/core.c                     | 107 -----------------
 arch/x86/kernel/kprobes/opt.c                      |  25 ++--
 arch/x86/kernel/rethook.c                          | 127 +++++++++++++++++++++
 arch/x86/kernel/unwind_orc.c                       |  10 +-
 drivers/net/can/m_can/m_can.c                      |   5 +-
 drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c     |   2 +-
 drivers/net/can/usb/ems_usb.c                      |   1 -
 drivers/net/can/usb/gs_usb.c                       |   2 +
 drivers/net/can/usb/mcba_usb.c                     |  27 +++--
 drivers/net/can/usb/usb_8dev.c                     |  30 +++--
 drivers/net/dsa/ocelot/felix_vsc9959.c             |   4 +
 drivers/net/ethernet/hisilicon/hns3/hnae3.h        |   1 +
 drivers/net/ethernet/hisilicon/hns3/hns3_debugfs.c |  15 ++-
 drivers/net/ethernet/hisilicon/hns3/hns3_debugfs.h |   1 -
 .../ethernet/hisilicon/hns3/hns3pf/hclge_main.c    |   6 +-
 drivers/net/ethernet/intel/ice/ice.h               |   2 +-
 drivers/net/ethernet/intel/ice/ice_xsk.c           |   5 +-
 .../net/ethernet/microchip/lan966x/lan966x_main.c  |   3 +
 drivers/net/ethernet/microchip/sparx5/Kconfig      |   1 +
 drivers/net/ethernet/sfc/efx_channels.c            |  11 +-
 drivers/net/vxlan/vxlan_vnifilter.c                |   6 +
 drivers/net/wireguard/queueing.c                   |   3 +-
 drivers/net/wireguard/socket.c                     |   5 +-
 drivers/ptp/ptp_ocp.c                              |  15 +--
 include/linux/kprobes.h                            |  51 ++++++++-
 include/trace/events/rxrpc.h                       |   8 +-
 kernel/Makefile                                    |   1 +
 kernel/bpf/btf.c                                   |   2 +-
 kernel/kprobes.c                                   | 124 ++++++++++++++++----
 kernel/trace/fprobe.c                              |   8 +-
 kernel/trace/trace_kprobe.c                        |   4 +-
 net/ax25/af_ax25.c                                 |  13 ++-
 net/can/isotp.c                                    |   2 +-
 net/openvswitch/actions.c                          |   4 +-
 net/openvswitch/flow_netlink.c                     |   4 +-
 net/rxrpc/ar-internal.h                            |  15 ++-
 net/rxrpc/call_event.c                             |   2 +-
 net/rxrpc/call_object.c                            |  40 ++++++-
 net/rxrpc/server_key.c                             |   7 +-
 net/xdp/xsk_buff_pool.c                            |   8 +-
 tools/bpf/bpftool/feature.c                        |   5 +-
 tools/bpf/bpftool/gen.c                            |   2 +-
 tools/include/uapi/linux/bpf.h                     |   8 +-
 .../selftests/bpf/prog_tests/get_stack_raw_tp.c    |   3 -
 .../selftests/bpf/progs/test_stacktrace_build_id.c |  12 +-
 tools/testing/selftests/bpf/test_lpm_map.c         |   3 +-
 tools/testing/selftests/wireguard/qemu/init.c      |  26 ++---
 58 files changed, 588 insertions(+), 337 deletions(-)
 rename Documentation/{networking/netdev-FAQ.rst => process/maintainer-netdev.rst} (75%)
 create mode 100644 arch/x86/kernel/rethook.c

^ permalink raw reply	[relevance 3%]

* Re: [PATCH bpf-next 3/3] bpf/bpftool: handle libbpf_probe_prog_type errors
  2022-03-31 15:45 14% ` [PATCH bpf-next 3/3] bpf/bpftool: handle libbpf_probe_prog_type errors Milan Landaverde
@ 2022-04-01 16:05  6%   ` Quentin Monnet
  2022-04-01 18:42  0%     ` Andrii Nakryiko
  0 siblings, 1 reply; 77+ results
From: Quentin Monnet @ 2022-04-01 16:05 UTC (permalink / raw)
  To: Milan Landaverde, bpf
  Cc: ast, daniel, andrii, kafai, songliubraving, yhs, john.fastabend,
	kpsingh, davemarchevsky, sdf, netdev, linux-kernel

2022-03-31 11:45 UTC-0400 ~ Milan Landaverde <milan@mdaverde.com>
> Previously [1], we were using bpf_probe_prog_type which returned a
> bool, but the new libbpf_probe_bpf_prog_type can return a negative
> error code on failure. This change decides for bpftool to declare
> a program type is not available on probe failure.
> 
> [1] https://lore.kernel.org/bpf/20220202225916.3313522-3-andrii@kernel.org/
> 
> Signed-off-by: Milan Landaverde <milan@mdaverde.com>
> ---
>  tools/bpf/bpftool/feature.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/tools/bpf/bpftool/feature.c b/tools/bpf/bpftool/feature.c
> index c2f43a5d38e0..b2fbaa7a6b15 100644
> --- a/tools/bpf/bpftool/feature.c
> +++ b/tools/bpf/bpftool/feature.c
> @@ -564,7 +564,7 @@ probe_prog_type(enum bpf_prog_type prog_type, bool *supported_types,
>  
>  		res = probe_prog_type_ifindex(prog_type, ifindex);
>  	} else {
> -		res = libbpf_probe_bpf_prog_type(prog_type, NULL);
> +		res = libbpf_probe_bpf_prog_type(prog_type, NULL) > 0;
>  	}
>  
>  #ifdef USE_LIBCAP

Reviewed-by: Quentin Monnet <quentin@isovalent.com>

Thanks!

^ permalink raw reply	[relevance 6%]

* Re: [PATCH bpf-next 2/3] bpf/bpftool: add missing link types
  2022-03-31 15:45 14% ` [PATCH bpf-next 2/3] bpf/bpftool: add missing link types Milan Landaverde
@ 2022-04-01 16:05  6%   ` Quentin Monnet
  2022-04-04 21:55  0%     ` Andrii Nakryiko
  0 siblings, 1 reply; 77+ results
From: Quentin Monnet @ 2022-04-01 16:05 UTC (permalink / raw)
  To: Milan Landaverde, bpf
  Cc: ast, daniel, andrii, kafai, songliubraving, yhs, john.fastabend,
	kpsingh, davemarchevsky, sdf, netdev, linux-kernel

2022-03-31 11:45 UTC-0400 ~ Milan Landaverde <milan@mdaverde.com>
> Will display the link type names in bpftool link show output
> 
> Signed-off-by: Milan Landaverde <milan@mdaverde.com>
> ---
>  tools/bpf/bpftool/link.c | 2 ++
>  1 file changed, 2 insertions(+)
> 
> diff --git a/tools/bpf/bpftool/link.c b/tools/bpf/bpftool/link.c
> index 97dec81950e5..9392ef390828 100644
> --- a/tools/bpf/bpftool/link.c
> +++ b/tools/bpf/bpftool/link.c
> @@ -20,6 +20,8 @@ static const char * const link_type_name[] = {
>  	[BPF_LINK_TYPE_CGROUP]			= "cgroup",
>  	[BPF_LINK_TYPE_ITER]			= "iter",
>  	[BPF_LINK_TYPE_NETNS]			= "netns",
> +	[BPF_LINK_TYPE_XDP]				= "xdp",
> +	[BPF_LINK_TYPE_PERF_EVENT]		= "perf_event",

Since this goes into bpf-next, we should add BPF_LINK_TYPE_KPROBE_MULTI
as well.

Quentin

^ permalink raw reply	[relevance 6%]

* Re: [PATCH bpf-next 1/3] bpf/bpftool: add syscall prog type
  2022-03-31 15:45 14% ` [PATCH bpf-next 1/3] bpf/bpftool: add syscall prog type Milan Landaverde
@ 2022-04-01 16:04  6%   ` Quentin Monnet
  2022-04-01 18:40  0%     ` Andrii Nakryiko
  0 siblings, 1 reply; 77+ results
From: Quentin Monnet @ 2022-04-01 16:04 UTC (permalink / raw)
  To: Milan Landaverde, bpf
  Cc: ast, daniel, andrii, kafai, songliubraving, yhs, john.fastabend,
	kpsingh, davemarchevsky, sdf, netdev, linux-kernel

2022-03-31 11:45 UTC-0400 ~ Milan Landaverde <milan@mdaverde.com>
> In addition to displaying the program type in bpftool prog show
> this enables us to be able to query bpf_prog_type_syscall
> availability through feature probe as well as see
> which helpers are available in those programs (such as
> bpf_sys_bpf and bpf_sys_close)
> 
> Signed-off-by: Milan Landaverde <milan@mdaverde.com>
> ---
>  tools/bpf/bpftool/prog.c | 1 +
>  1 file changed, 1 insertion(+)
> 
> diff --git a/tools/bpf/bpftool/prog.c b/tools/bpf/bpftool/prog.c
> index bc4e05542c2b..8643b37d4e43 100644
> --- a/tools/bpf/bpftool/prog.c
> +++ b/tools/bpf/bpftool/prog.c
> @@ -68,6 +68,7 @@ const char * const prog_type_name[] = {
>  	[BPF_PROG_TYPE_EXT]			= "ext",
>  	[BPF_PROG_TYPE_LSM]			= "lsm",
>  	[BPF_PROG_TYPE_SK_LOOKUP]		= "sk_lookup",
> +	[BPF_PROG_TYPE_SYSCALL]			= "syscall",
>  };
>  
>  const size_t prog_type_name_size = ARRAY_SIZE(prog_type_name);

Reviewed-by: Quentin Monnet <quentin@isovalent.com>

Thanks! This one should have been caught by CI :/. Instead it complains
when you add it. This is because BPF_PROG_TYPE_SYSCALL in the UAPI
header has a comment next to it, and the regex used in
tools/testing/selftests/bpf/test_bpftool_synctypes.py to extract the
program types does not account for it. The fix should be:

------
diff --git a/tools/testing/selftests/bpf/test_bpftool_synctypes.py
b/tools/testing/selftests/bpf/test_bpftool_synctypes.py
index 6bf21e47882a..cd239cbfd80c 100755
--- a/tools/testing/selftests/bpf/test_bpftool_synctypes.py
+++ b/tools/testing/selftests/bpf/test_bpftool_synctypes.py
@@ -180,7 +180,7 @@ class FileExtractor(object):
         @enum_name: name of the enum to parse
         """
         start_marker = re.compile(f'enum {enum_name} {{\n')
-        pattern = re.compile('^\s*(BPF_\w+),?$')
+        pattern = re.compile('^\s*(BPF_\w+),?( /\* .* \*/)?$')
         end_marker = re.compile('^};')
         parser = BlockParser(self.reader)
         parser.search_block(start_marker)
------

I can submit this separately as a patch.

Quentin

^ permalink raw reply related	[relevance 6%]

* Re: [PATCH bpf-next 1/3] bpf/bpftool: add syscall prog type
  2022-04-01 16:04  6%   ` Quentin Monnet
@ 2022-04-01 18:40  0%     ` Andrii Nakryiko
  2022-04-01 21:20  0%       ` Quentin Monnet
  0 siblings, 1 reply; 77+ results
From: Andrii Nakryiko @ 2022-04-01 18:40 UTC (permalink / raw)
  To: Quentin Monnet
  Cc: Milan Landaverde, bpf, Alexei Starovoitov, Daniel Borkmann,
	Andrii Nakryiko, Martin Lau, Song Liu, Yonghong Song,
	john fastabend, KP Singh, Dave Marchevsky, Stanislav Fomichev,
	Networking, open list

On Fri, Apr 1, 2022 at 9:04 AM Quentin Monnet <quentin@isovalent.com> wrote:
>
> 2022-03-31 11:45 UTC-0400 ~ Milan Landaverde <milan@mdaverde.com>
> > In addition to displaying the program type in bpftool prog show
> > this enables us to be able to query bpf_prog_type_syscall
> > availability through feature probe as well as see
> > which helpers are available in those programs (such as
> > bpf_sys_bpf and bpf_sys_close)
> >
> > Signed-off-by: Milan Landaverde <milan@mdaverde.com>
> > ---
> >  tools/bpf/bpftool/prog.c | 1 +
> >  1 file changed, 1 insertion(+)
> >
> > diff --git a/tools/bpf/bpftool/prog.c b/tools/bpf/bpftool/prog.c
> > index bc4e05542c2b..8643b37d4e43 100644
> > --- a/tools/bpf/bpftool/prog.c
> > +++ b/tools/bpf/bpftool/prog.c
> > @@ -68,6 +68,7 @@ const char * const prog_type_name[] = {
> >       [BPF_PROG_TYPE_EXT]                     = "ext",
> >       [BPF_PROG_TYPE_LSM]                     = "lsm",
> >       [BPF_PROG_TYPE_SK_LOOKUP]               = "sk_lookup",
> > +     [BPF_PROG_TYPE_SYSCALL]                 = "syscall",
> >  };
> >
> >  const size_t prog_type_name_size = ARRAY_SIZE(prog_type_name);
>
> Reviewed-by: Quentin Monnet <quentin@isovalent.com>
>
> Thanks! This one should have been caught by CI :/. Instead it complains
> when you add it. This is because BPF_PROG_TYPE_SYSCALL in the UAPI
> header has a comment next to it, and the regex used in
> tools/testing/selftests/bpf/test_bpftool_synctypes.py to extract the
> program types does not account for it. The fix should be:
>
> ------
> diff --git a/tools/testing/selftests/bpf/test_bpftool_synctypes.py
> b/tools/testing/selftests/bpf/test_bpftool_synctypes.py
> index 6bf21e47882a..cd239cbfd80c 100755
> --- a/tools/testing/selftests/bpf/test_bpftool_synctypes.py
> +++ b/tools/testing/selftests/bpf/test_bpftool_synctypes.py
> @@ -180,7 +180,7 @@ class FileExtractor(object):
>          @enum_name: name of the enum to parse
>          """
>          start_marker = re.compile(f'enum {enum_name} {{\n')
> -        pattern = re.compile('^\s*(BPF_\w+),?$')
> +        pattern = re.compile('^\s*(BPF_\w+),?( /\* .* \*/)?$')

small nit: do you need those spaces inside /* and */? why make
unnecessary assumptions about proper formatting? ;)

>          end_marker = re.compile('^};')
>          parser = BlockParser(self.reader)
>          parser.search_block(start_marker)
> ------
>
> I can submit this separately as a patch.
>
> Quentin

^ permalink raw reply	[relevance 0%]

* Re: [PATCH bpf-next 3/3] bpf/bpftool: handle libbpf_probe_prog_type errors
  2022-04-01 16:05  6%   ` Quentin Monnet
@ 2022-04-01 18:42  0%     ` Andrii Nakryiko
  2022-04-01 21:33  0%       ` Quentin Monnet
  0 siblings, 1 reply; 77+ results
From: Andrii Nakryiko @ 2022-04-01 18:42 UTC (permalink / raw)
  To: Quentin Monnet
  Cc: Milan Landaverde, bpf, Alexei Starovoitov, Daniel Borkmann,
	Andrii Nakryiko, Martin Lau, Song Liu, Yonghong Song,
	john fastabend, KP Singh, Dave Marchevsky, Stanislav Fomichev,
	Networking, open list

On Fri, Apr 1, 2022 at 9:05 AM Quentin Monnet <quentin@isovalent.com> wrote:
>
> 2022-03-31 11:45 UTC-0400 ~ Milan Landaverde <milan@mdaverde.com>
> > Previously [1], we were using bpf_probe_prog_type which returned a
> > bool, but the new libbpf_probe_bpf_prog_type can return a negative
> > error code on failure. This change decides for bpftool to declare
> > a program type is not available on probe failure.
> >
> > [1] https://lore.kernel.org/bpf/20220202225916.3313522-3-andrii@kernel.org/
> >
> > Signed-off-by: Milan Landaverde <milan@mdaverde.com>
> > ---
> >  tools/bpf/bpftool/feature.c | 2 +-
> >  1 file changed, 1 insertion(+), 1 deletion(-)
> >
> > diff --git a/tools/bpf/bpftool/feature.c b/tools/bpf/bpftool/feature.c
> > index c2f43a5d38e0..b2fbaa7a6b15 100644
> > --- a/tools/bpf/bpftool/feature.c
> > +++ b/tools/bpf/bpftool/feature.c
> > @@ -564,7 +564,7 @@ probe_prog_type(enum bpf_prog_type prog_type, bool *supported_types,
> >
> >               res = probe_prog_type_ifindex(prog_type, ifindex);
> >       } else {
> > -             res = libbpf_probe_bpf_prog_type(prog_type, NULL);
> > +             res = libbpf_probe_bpf_prog_type(prog_type, NULL) > 0;
> >       }
> >
> >  #ifdef USE_LIBCAP
>

A completely unrelated question to you, Quentin. How hard is bpftool's
dependency on libcap? We've recently removed libcap from selftests, I
wonder if it would be possible to do that for bpftool as well to
reduce amount of shared libraries bpftool depends on.

> Reviewed-by: Quentin Monnet <quentin@isovalent.com>
>
> Thanks!

^ permalink raw reply	[relevance 0%]

* Re: [PATCH bpf-next 1/3] bpf/bpftool: add syscall prog type
  2022-04-01 18:40  0%     ` Andrii Nakryiko
@ 2022-04-01 21:20  0%       ` Quentin Monnet
  0 siblings, 0 replies; 77+ results
From: Quentin Monnet @ 2022-04-01 21:20 UTC (permalink / raw)
  To: Andrii Nakryiko
  Cc: Milan Landaverde, bpf, Alexei Starovoitov, Daniel Borkmann,
	Andrii Nakryiko, Martin Lau, Song Liu, Yonghong Song,
	john fastabend, KP Singh, Dave Marchevsky, Stanislav Fomichev,
	Networking, open list

On Fri, 1 Apr 2022 at 19:40, Andrii Nakryiko <andrii.nakryiko@gmail.com> wrote:
>
> On Fri, Apr 1, 2022 at 9:04 AM Quentin Monnet <quentin@isovalent.com> wrote:
> >
> > 2022-03-31 11:45 UTC-0400 ~ Milan Landaverde <milan@mdaverde.com>
> > > In addition to displaying the program type in bpftool prog show
> > > this enables us to be able to query bpf_prog_type_syscall
> > > availability through feature probe as well as see
> > > which helpers are available in those programs (such as
> > > bpf_sys_bpf and bpf_sys_close)
> > >
> > > Signed-off-by: Milan Landaverde <milan@mdaverde.com>
> > > ---
> > >  tools/bpf/bpftool/prog.c | 1 +
> > >  1 file changed, 1 insertion(+)
> > >
> > > diff --git a/tools/bpf/bpftool/prog.c b/tools/bpf/bpftool/prog.c
> > > index bc4e05542c2b..8643b37d4e43 100644
> > > --- a/tools/bpf/bpftool/prog.c
> > > +++ b/tools/bpf/bpftool/prog.c
> > > @@ -68,6 +68,7 @@ const char * const prog_type_name[] = {
> > >       [BPF_PROG_TYPE_EXT]                     = "ext",
> > >       [BPF_PROG_TYPE_LSM]                     = "lsm",
> > >       [BPF_PROG_TYPE_SK_LOOKUP]               = "sk_lookup",
> > > +     [BPF_PROG_TYPE_SYSCALL]                 = "syscall",
> > >  };
> > >
> > >  const size_t prog_type_name_size = ARRAY_SIZE(prog_type_name);
> >
> > Reviewed-by: Quentin Monnet <quentin@isovalent.com>
> >
> > Thanks! This one should have been caught by CI :/. Instead it complains
> > when you add it. This is because BPF_PROG_TYPE_SYSCALL in the UAPI
> > header has a comment next to it, and the regex used in
> > tools/testing/selftests/bpf/test_bpftool_synctypes.py to extract the
> > program types does not account for it. The fix should be:
> >
> > ------
> > diff --git a/tools/testing/selftests/bpf/test_bpftool_synctypes.py
> > b/tools/testing/selftests/bpf/test_bpftool_synctypes.py
> > index 6bf21e47882a..cd239cbfd80c 100755
> > --- a/tools/testing/selftests/bpf/test_bpftool_synctypes.py
> > +++ b/tools/testing/selftests/bpf/test_bpftool_synctypes.py
> > @@ -180,7 +180,7 @@ class FileExtractor(object):
> >          @enum_name: name of the enum to parse
> >          """
> >          start_marker = re.compile(f'enum {enum_name} {{\n')
> > -        pattern = re.compile('^\s*(BPF_\w+),?$')
> > +        pattern = re.compile('^\s*(BPF_\w+),?( /\* .* \*/)?$')
>
> small nit: do you need those spaces inside /* and */? why make
> unnecessary assumptions about proper formatting? ;)

No I don't need the spaces, I'll remove them indeed, thanks. I'll send
the patch next week.

^ permalink raw reply	[relevance 0%]

* Re: [PATCH bpf-next 3/3] bpf/bpftool: handle libbpf_probe_prog_type errors
  2022-04-01 18:42  0%     ` Andrii Nakryiko
@ 2022-04-01 21:33  0%       ` Quentin Monnet
  2022-04-03 23:51  0%         ` Andrii Nakryiko
  0 siblings, 1 reply; 77+ results
From: Quentin Monnet @ 2022-04-01 21:33 UTC (permalink / raw)
  To: Andrii Nakryiko
  Cc: Milan Landaverde, bpf, Alexei Starovoitov, Daniel Borkmann,
	Andrii Nakryiko, Martin Lau, Song Liu, Yonghong Song,
	john fastabend, KP Singh, Dave Marchevsky, Stanislav Fomichev,
	Networking, open list

On Fri, 1 Apr 2022 at 19:42, Andrii Nakryiko <andrii.nakryiko@gmail.com> wrote:
>
> On Fri, Apr 1, 2022 at 9:05 AM Quentin Monnet <quentin@isovalent.com> wrote:
> >
> > 2022-03-31 11:45 UTC-0400 ~ Milan Landaverde <milan@mdaverde.com>
> > > Previously [1], we were using bpf_probe_prog_type which returned a
> > > bool, but the new libbpf_probe_bpf_prog_type can return a negative
> > > error code on failure. This change decides for bpftool to declare
> > > a program type is not available on probe failure.
> > >
> > > [1] https://lore.kernel.org/bpf/20220202225916.3313522-3-andrii@kernel.org/
> > >
> > > Signed-off-by: Milan Landaverde <milan@mdaverde.com>
> > > ---
> > >  tools/bpf/bpftool/feature.c | 2 +-
> > >  1 file changed, 1 insertion(+), 1 deletion(-)
> > >
> > > diff --git a/tools/bpf/bpftool/feature.c b/tools/bpf/bpftool/feature.c
> > > index c2f43a5d38e0..b2fbaa7a6b15 100644
> > > --- a/tools/bpf/bpftool/feature.c
> > > +++ b/tools/bpf/bpftool/feature.c
> > > @@ -564,7 +564,7 @@ probe_prog_type(enum bpf_prog_type prog_type, bool *supported_types,
> > >
> > >               res = probe_prog_type_ifindex(prog_type, ifindex);
> > >       } else {
> > > -             res = libbpf_probe_bpf_prog_type(prog_type, NULL);
> > > +             res = libbpf_probe_bpf_prog_type(prog_type, NULL) > 0;
> > >       }
> > >
> > >  #ifdef USE_LIBCAP
> >
>
> A completely unrelated question to you, Quentin. How hard is bpftool's
> dependency on libcap? We've recently removed libcap from selftests, I
> wonder if it would be possible to do that for bpftool as well to
> reduce amount of shared libraries bpftool depends on.

There's not a super-strong dependency on it. It's used in feature
probing, for two things.

First one is to be accurate when we check that the user has the right
capabilities for probing efficiently the system. A workaround consists
in checking that we run with uid=0 (root), although it's less
accurate.

Second thing is probing as an unprivileged user: if bpftool is run to
probe as root but with the "unprivileged" keyword, libcap is used to
drop the CAP_SYS_ADMIN and run the probes without it. I don't know if
there's an easy alternative to libcap for that. Also I don't know how
many people use this feature, but I remember that this was added
because there was some demand at the time, so presumably there are
users relying on this.

This being said, libcap is optional for compiling bpftool, so you
should be able to have it work just as well if the library is not
available on the system? Basically you'd just lose the ability to
probe as an unprivileged user. Do you need to remove the optional
dependency completely?

Quentin

PS: Not directly related but since we're talking of libcap, we
recently discovered that the lib is apparently changing errno when it
maybe shouldn't and plays badly with batch mode:
https://stackoverflow.com/questions/71608181/bpf-xdp-bpftool-batch-file-returns-error-reading-batch-file-failed-opera

^ permalink raw reply	[relevance 0%]

* [linux-linus test] 169100: tolerable FAIL - PUSHED
@ 2022-04-02  0:44  3% osstest service owner
  0 siblings, 0 replies; 77+ results
From: osstest service owner @ 2022-04-02  0:44 UTC (permalink / raw)
  To: xen-devel

flight 169100 linux-linus real [real]
flight 169121 linux-linus real-retest [real]
http://logs.test-lab.xenproject.org/osstest/logs/169100/
http://logs.test-lab.xenproject.org/osstest/logs/169121/

Failures :-/ but no regressions.

Tests which are failing intermittently (not blocking):
 test-amd64-amd64-libvirt-qcow2  8 xen-boot          fail pass in 169121-retest

Tests which did not succeed, but are not blocking:
 test-amd64-amd64-libvirt-qcow2 14 migrate-support-check fail in 169121 never pass
 test-amd64-amd64-xl-qemut-win7-amd64 19 guest-stop            fail like 169055
 test-armhf-armhf-libvirt     16 saverestore-support-check    fail  like 169055
 test-amd64-amd64-xl-qemuu-ws16-amd64 19 guest-stop            fail like 169055
 test-amd64-amd64-qemuu-nested-amd 20 debian-hvm-install/l1/l2 fail like 169055
 test-amd64-amd64-xl-qemut-ws16-amd64 19 guest-stop            fail like 169055
 test-amd64-amd64-xl-qemuu-win7-amd64 19 guest-stop            fail like 169055
 test-armhf-armhf-libvirt-qcow2 15 saverestore-support-check   fail like 169055
 test-armhf-armhf-libvirt-raw 15 saverestore-support-check    fail  like 169055
 test-arm64-arm64-xl-seattle  15 migrate-support-check        fail   never pass
 test-arm64-arm64-xl-seattle  16 saverestore-support-check    fail   never pass
 test-amd64-amd64-libvirt-xsm 15 migrate-support-check        fail   never pass
 test-amd64-amd64-libvirt     15 migrate-support-check        fail   never pass
 test-arm64-arm64-xl-credit2  15 migrate-support-check        fail   never pass
 test-arm64-arm64-xl-credit2  16 saverestore-support-check    fail   never pass
 test-arm64-arm64-xl-credit1  15 migrate-support-check        fail   never pass
 test-arm64-arm64-xl-thunderx 15 migrate-support-check        fail   never pass
 test-arm64-arm64-xl-credit1  16 saverestore-support-check    fail   never pass
 test-arm64-arm64-xl-thunderx 16 saverestore-support-check    fail   never pass
 test-arm64-arm64-xl-xsm      15 migrate-support-check        fail   never pass
 test-arm64-arm64-xl-xsm      16 saverestore-support-check    fail   never pass
 test-arm64-arm64-libvirt-xsm 15 migrate-support-check        fail   never pass
 test-arm64-arm64-xl          15 migrate-support-check        fail   never pass
 test-arm64-arm64-libvirt-xsm 16 saverestore-support-check    fail   never pass
 test-arm64-arm64-xl          16 saverestore-support-check    fail   never pass
 test-amd64-amd64-libvirt-qemuu-debianhvm-amd64-xsm 13 migrate-support-check fail never pass
 test-amd64-amd64-libvirt-raw 14 migrate-support-check        fail   never pass
 test-arm64-arm64-libvirt-raw 14 migrate-support-check        fail   never pass
 test-arm64-arm64-libvirt-raw 15 saverestore-support-check    fail   never pass
 test-armhf-armhf-xl          15 migrate-support-check        fail   never pass
 test-armhf-armhf-xl-multivcpu 15 migrate-support-check        fail  never pass
 test-armhf-armhf-xl          16 saverestore-support-check    fail   never pass
 test-armhf-armhf-xl-multivcpu 16 saverestore-support-check    fail  never pass
 test-armhf-armhf-xl-credit2  15 migrate-support-check        fail   never pass
 test-armhf-armhf-xl-credit2  16 saverestore-support-check    fail   never pass
 test-arm64-arm64-xl-vhd      14 migrate-support-check        fail   never pass
 test-arm64-arm64-xl-vhd      15 saverestore-support-check    fail   never pass
 test-armhf-armhf-xl-credit1  15 migrate-support-check        fail   never pass
 test-armhf-armhf-xl-credit1  16 saverestore-support-check    fail   never pass
 test-armhf-armhf-libvirt     15 migrate-support-check        fail   never pass
 test-armhf-armhf-xl-cubietruck 15 migrate-support-check        fail never pass
 test-armhf-armhf-xl-cubietruck 16 saverestore-support-check    fail never pass
 test-armhf-armhf-xl-rtds     15 migrate-support-check        fail   never pass
 test-armhf-armhf-xl-rtds     16 saverestore-support-check    fail   never pass
 test-armhf-armhf-libvirt-qcow2 14 migrate-support-check        fail never pass
 test-armhf-armhf-libvirt-raw 14 migrate-support-check        fail   never pass
 test-armhf-armhf-xl-arndale  15 migrate-support-check        fail   never pass
 test-armhf-armhf-xl-arndale  16 saverestore-support-check    fail   never pass
 test-armhf-armhf-xl-vhd      14 migrate-support-check        fail   never pass
 test-armhf-armhf-xl-vhd      15 saverestore-support-check    fail   never pass

version targeted for testing:
 linux                e8b767f5e04097aaedcd6e06e2270f9fe5282696
baseline version:
 linux                787af64d05cd528aac9ad16752d11bb1c6061bb9

Last test of basis   169055  2022-03-31 02:32:32 Z    1 days
Testing same since   169100  2022-04-01 04:55:02 Z    0 days    1 attempts

------------------------------------------------------------
People who touched revisions under test:
  Akira Yokosawa <akiyks@gmail.com>
  Alexander Lobakin <alexandr.lobakin@intel.com>
  Alexei Starovoitov <ast@kernel.org>
  Alistair Francis <alistair@alistair23.me>
  Andreas Gruenbacher <agruenba@redhat.com>
  Andrew Melnychenko <andrew@daynix.com>
  Andrew Price <anprice@redhat.com>
  Andrii Nakryiko <andrii@kernel.org>
  Andy Shevchenko <andriy.shevchenko@linux.intel.com>
  Anirudh Rayabharam <mail@anirudhrb.com>
  Anton Ivanov <anton.ivanov@cambridgegreys.com>
  Arnaldo Carvalho de Melo <acme@redhat.com>
  Baokun Li <libaokun1@huawei.com>
  Benjamin Beichler <benjamin.beichler@uni-rostock.de>
  Bhupesh Sharma <bhupesh.sharma@linaro.org>
  Bob Peterson <rpeterso@redhat.com>
  Borislav Petkov <bp@suse.de>
  Brendan Higgins <brendanhiggins@google.com>
  Changbin Du <changbin.du@gmail.com>
  Chris Packham <chris.packham@alliedtelesis.co.nz>
  Daniel Bristot de Oliveira <bristot@kernel.org>
  David Gow <davidgow@google.com>
  David Hildenbrand <david@redhat.com>
  David Howells <dhowells@redhat.com>
  Derek Will <derekrobertwill@gmail.com>
  Duoming Zhou <duoming@zju.edu.cn>
  Eduardo Valentin <eduval@amazon.com>
  Eduardo Valentin <evalenti@kernel.org>
  Eelco Chaudron <echaudro@redhat.com>
  Eli Cohen <elic@nvidia.com>
  Elliot Berman <quic_eberman@quicinc.com>
  Eric Dumazet <edumazet@google.com>
  Florian Fainelli <f.fainelli@gmail.com>
  Frédéric Danis <frederic.danis@collabora.com>
  Gautam Dawar <gautam.dawar@xilinx.com>
  Gautam Dawar <gdawar@xilinx.com>
  Gavin Shan <gshan@redhat.com>
  Geert Uytterhoeven <geert+renesas@glider.be>
  Geert Uytterhoeven <geert@linux-m68k.org>
  Geliang Tang <geliang.tang@suse.com>
  Glenn Washburn <development@efficientek.com>
  Guangbin Huang <huangguangbin2@huawei.com>
  Guenter Roeck <linux@roeck-us.net>
  Guilherme G. Piccoli <gpiccoli@igalia.com>
  Hangyu Hua <hbh25y@gmail.com>
  Herbert Xu <herbert@gondor.apana.org.au>
  hongnanli <hongnan.li@linux.alibaba.com>
  Jakob Koschel <jakobkoschel@gmail.com>
  Jakub Kicinski <kuba@kernel.org>
  Jason A. Donenfeld <Jason@zx2c4.com>
  Jason Wang <jasowang@redhat.com>
  Jean Delvare <jdelvare@suse.de>
  Jeff Layton <jlayton@kernel.org>
  Jeff Layton <jlayton@redhat.com>
  Jeffle Xu <jefflexu@linux.alibaba.com>
  Jiri Olsa <jolsa@kernel.org>
  Johannes Berg <johannes.berg@intel.com>
  Jonathan Cameron <Jonathan.Cameron@huawei.com>
  Jonathan Corbet <corbet@lwn.net>
  Jonathan Lemon <jonathan.lemon@gmail.com>
  Kees Cook <keescook@chromium.org>
  Keir Fraser <keirf@google.com>
  KP Singh <kpsingh@kernel.org>
  lei he <helei.sig11@bytedance.com>
  Linus Torvalds <torvalds@linux-foundation.org>
  Linus Walleij <linus.walleij@linaro.org>
  Longpeng &lt;<a href="mailto:longpeng2@huawei.com" target="_blank">longpeng2@huawei.com</a>&gt;<br>
  Longpeng &lt;<a href="mailto:longpeng2@huawei.com" target="_blank">longpeng2@huawei.com</a>&gt;<br></blockquote><div><br></div><div>Acked-by: Jason Wang &lt;<a href="mailto:jasowang@redhat.com">jasowang@redhat.com</a>&gt;</div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
  Longpeng <longpeng2@huawei.com>
  Maciej Fijalkowski <maciej.fijalkowski@intel.com>
  Magnus Karlsson <magnus.karlsson@intel.com>
  Marc Dionne <marc.dionne@auristor.com>
  Marc Kleine-Budde <mkl@pengutronix.de>
  Martin Habets <habetsm.xilinx@gmail.com>
  Martin KaFai Lau <kafai@fb.com>
  Martin Varghese <martin.varghese@nokia.com>
  Masahiro Yamada <masahiroy@kernel.org>
  Masami Hiramatsu <mhiramat@kernel.org>
  Mauro Carvalho Chehab <mchehab@kernel.org>
  Miaohe Lin <linmiaohe@huawei.com>
  Miaoqian Lin <linmq006@gmail.com>
  Michael Kelley <mikelley@microsoft.com>
  Michael Qiu <qiudayu@archeros.com>
  Michael S. Tsirkin <mst@redhat.com>
  Michael Walle <michael@walle.cc>
  Miguel Ojeda <ojeda@kernel.org>
  Milan Landaverde <milan@mdaverde.com>
  Nathan Chancellor <nathan@kernel.org>
  Nathan Chancellor <nathan@kernel.org> #Kconfig tweaks
  Oliver Hartkopp <socketcan@hartkopp.net>
  Paolo Abeni <pabeni@redhat.com>
  Pavel Skripkin <paskripkin@gmail.com>
  Peter Zijlstra (Intel) <peterz@infradead.org>
  Peter Zijlstra <peterz@infradead.org>
  Quentin Monnet <quentin@isovalent.com>
  Rafael J. Wysocki <rafael.j.wysocki@intel.com>
  Rafał Miłecki <rafal@milecki.pl>
  Randy Dunlap <rdunlap@infradead.org>
  Richard Weinberger <richard@nod.at>
  Rob Herring <robh@kernel.org>
  Robert Richter <rrichter@amd.com>
  Roopa Prabhu <roopa@nvidia.com>
  Stefano Garzarella <sgarzare@redhat.com>
  Stephane Graber <stgraber@ubuntu.com>
  Stéphane Graber <stgraber@ubuntu.com>
  Suravee Suthikulpanit <suravee.suthikulpanit@amd.com>
  Terry Bowman <terry.bowman@amd.com>
  Thanh Quan <thanh.quan.xn@renesas.com>
  Tom Rix <trix@redhat.com>
  Vasant Hegde <vasant.hegde@amd.com>
  Vincent Whitchurch <vincent.whitchurch@axis.com>
  Vinod Koul <vkoul@kernel.org>
  Wang Hai <wanghai38@huawei.com>
  Wim Van Sebroeck <wim@linux-watchdog.org>
  Xiaolong Huang <butterflyhuangxx@gmail.com>
  Xuan Zhuo <xuanzhuo@linux.alibaba.com>
  Yang Li <yang.lee@linux.alibaba.com>
  Yonghong Song <yhs@fb.com>
  Yufeng Mo <moyufeng@huawei.com>
  Yuntao Wang <ytcoode@gmail.com>
  Zheng Yongjun <zhengyongjun3@huawei.com>
  zhenwei pi <pizhenwei@bytedance.com>
  Zhihao Cheng <chengzhihao1@huawei.com>
  Zhu Lingshan <lingshan.zhu@intel.com>

jobs:
 build-amd64-xsm                                              pass    
 build-arm64-xsm                                              pass    
 build-i386-xsm                                               pass    
 build-amd64                                                  pass    
 build-arm64                                                  pass    
 build-armhf                                                  pass    
 build-i386                                                   pass    
 build-amd64-libvirt                                          pass    
 build-arm64-libvirt                                          pass    
 build-armhf-libvirt                                          pass    
 build-i386-libvirt                                           pass    
 build-amd64-pvops                                            pass    
 build-arm64-pvops                                            pass    
 build-armhf-pvops                                            pass    
 build-i386-pvops                                             pass    
 test-amd64-amd64-xl                                          pass    
 test-amd64-coresched-amd64-xl                                pass    
 test-arm64-arm64-xl                                          pass    
 test-armhf-armhf-xl                                          pass    
 test-amd64-amd64-libvirt-qemuu-debianhvm-amd64-xsm           pass    
 test-amd64-amd64-xl-qemut-stubdom-debianhvm-amd64-xsm        pass    
 test-amd64-amd64-xl-qemut-debianhvm-i386-xsm                 pass    
 test-amd64-amd64-xl-qemuu-debianhvm-i386-xsm                 pass    
 test-amd64-amd64-libvirt-xsm                                 pass    
 test-arm64-arm64-libvirt-xsm                                 pass    
 test-amd64-amd64-xl-xsm                                      pass    
 test-arm64-arm64-xl-xsm                                      pass    
 test-amd64-amd64-qemuu-nested-amd                            fail    
 test-amd64-amd64-xl-pvhv2-amd                                pass    
 test-amd64-amd64-dom0pvh-xl-amd                              pass    
 test-amd64-amd64-xl-qemut-debianhvm-amd64                    pass    
 test-amd64-amd64-xl-qemuu-debianhvm-amd64                    pass    
 test-amd64-amd64-freebsd11-amd64                             pass    
 test-amd64-amd64-freebsd12-amd64                             pass    
 test-amd64-amd64-xl-qemuu-ovmf-amd64                         pass    
 test-amd64-amd64-xl-qemut-win7-amd64                         fail    
 test-amd64-amd64-xl-qemuu-win7-amd64                         fail    
 test-amd64-amd64-xl-qemut-ws16-amd64                         fail    
 test-amd64-amd64-xl-qemuu-ws16-amd64                         fail    
 test-armhf-armhf-xl-arndale                                  pass    
 test-amd64-amd64-examine-bios                                pass    
 test-amd64-amd64-xl-credit1                                  pass    
 test-arm64-arm64-xl-credit1                                  pass    
 test-armhf-armhf-xl-credit1                                  pass    
 test-amd64-amd64-xl-credit2                                  pass    
 test-arm64-arm64-xl-credit2                                  pass    
 test-armhf-armhf-xl-credit2                                  pass    
 test-armhf-armhf-xl-cubietruck                               pass    
 test-amd64-amd64-xl-qemuu-dmrestrict-amd64-dmrestrict        pass    
 test-amd64-amd64-examine                                     pass    
 test-arm64-arm64-examine                                     pass    
 test-armhf-armhf-examine                                     pass    
 test-amd64-amd64-qemuu-nested-intel                          pass    
 test-amd64-amd64-xl-pvhv2-intel                              pass    
 test-amd64-amd64-dom0pvh-xl-intel                            pass    
 test-amd64-amd64-libvirt                                     pass    
 test-armhf-armhf-libvirt                                     pass    
 test-amd64-amd64-xl-multivcpu                                pass    
 test-armhf-armhf-xl-multivcpu                                pass    
 test-amd64-amd64-pair                                        pass    
 test-amd64-amd64-libvirt-pair                                pass    
 test-amd64-amd64-xl-pvshim                                   pass    
 test-amd64-amd64-pygrub                                      pass    
 test-amd64-amd64-libvirt-qcow2                               fail    
 test-armhf-armhf-libvirt-qcow2                               pass    
 test-amd64-amd64-libvirt-raw                                 pass    
 test-arm64-arm64-libvirt-raw                                 pass    
 test-armhf-armhf-libvirt-raw                                 pass    
 test-amd64-amd64-xl-rtds                                     pass    
 test-armhf-armhf-xl-rtds                                     pass    
 test-arm64-arm64-xl-seattle                                  pass    
 test-amd64-amd64-xl-qemuu-debianhvm-amd64-shadow             pass    
 test-amd64-amd64-xl-shadow                                   pass    
 test-arm64-arm64-xl-thunderx                                 pass    
 test-amd64-amd64-examine-uefi                                pass    
 test-amd64-amd64-xl-vhd                                      pass    
 test-arm64-arm64-xl-vhd                                      pass    
 test-armhf-armhf-xl-vhd                                      pass    


------------------------------------------------------------
sg-report-flight on osstest.test-lab.xenproject.org
logs: /home/logs/logs
images: /home/logs/images

Logs, config files, etc. are available at
    http://logs.test-lab.xenproject.org/osstest/logs

Explanation of these reports, and of osstest in general, is at
    http://xenbits.xen.org/gitweb/?p=osstest.git;a=blob;f=README.email;hb=master
    http://xenbits.xen.org/gitweb/?p=osstest.git;a=blob;f=README;hb=master

Test harness code can be found at
    http://xenbits.xen.org/gitweb?p=osstest.git;a=summary


Pushing revision :

hint: The 'hooks/update' hook was ignored because it's not set as executable.
hint: You can disable this warning with `git config advice.ignoredHook false`.
hint: The 'hooks/post-receive' hook was ignored because it's not set as executable.
hint: You can disable this warning with `git config advice.ignoredHook false`.
hint: The 'hooks/post-update' hook was ignored because it's not set as executable.
hint: You can disable this warning with `git config advice.ignoredHook false`.
To xenbits.xen.org:/home/xen/git/linux-pvops.git
   787af64d05cd..e8b767f5e040  e8b767f5e04097aaedcd6e06e2270f9fe5282696 -> tested/linux-linus


^ permalink raw reply	[relevance 3%]

* Re: [PATCH bpf-next 3/3] bpf/bpftool: handle libbpf_probe_prog_type errors
  2022-04-01 21:33  0%       ` Quentin Monnet
@ 2022-04-03 23:51  0%         ` Andrii Nakryiko
  0 siblings, 0 replies; 77+ results
From: Andrii Nakryiko @ 2022-04-03 23:51 UTC (permalink / raw)
  To: Quentin Monnet
  Cc: Milan Landaverde, bpf, Alexei Starovoitov, Daniel Borkmann,
	Andrii Nakryiko, Martin Lau, Song Liu, Yonghong Song,
	john fastabend, KP Singh, Dave Marchevsky, Stanislav Fomichev,
	Networking, open list

On Fri, Apr 1, 2022 at 2:33 PM Quentin Monnet <quentin@isovalent.com> wrote:
>
> On Fri, 1 Apr 2022 at 19:42, Andrii Nakryiko <andrii.nakryiko@gmail.com> wrote:
> >
> > On Fri, Apr 1, 2022 at 9:05 AM Quentin Monnet <quentin@isovalent.com> wrote:
> > >
> > > 2022-03-31 11:45 UTC-0400 ~ Milan Landaverde <milan@mdaverde.com>
> > > > Previously [1], we were using bpf_probe_prog_type which returned a
> > > > bool, but the new libbpf_probe_bpf_prog_type can return a negative
> > > > error code on failure. This change decides for bpftool to declare
> > > > a program type is not available on probe failure.
> > > >
> > > > [1] https://lore.kernel.org/bpf/20220202225916.3313522-3-andrii@kernel.org/
> > > >
> > > > Signed-off-by: Milan Landaverde <milan@mdaverde.com>
> > > > ---
> > > >  tools/bpf/bpftool/feature.c | 2 +-
> > > >  1 file changed, 1 insertion(+), 1 deletion(-)
> > > >
> > > > diff --git a/tools/bpf/bpftool/feature.c b/tools/bpf/bpftool/feature.c
> > > > index c2f43a5d38e0..b2fbaa7a6b15 100644
> > > > --- a/tools/bpf/bpftool/feature.c
> > > > +++ b/tools/bpf/bpftool/feature.c
> > > > @@ -564,7 +564,7 @@ probe_prog_type(enum bpf_prog_type prog_type, bool *supported_types,
> > > >
> > > >               res = probe_prog_type_ifindex(prog_type, ifindex);
> > > >       } else {
> > > > -             res = libbpf_probe_bpf_prog_type(prog_type, NULL);
> > > > +             res = libbpf_probe_bpf_prog_type(prog_type, NULL) > 0;
> > > >       }
> > > >
> > > >  #ifdef USE_LIBCAP
> > >
> >
> > A completely unrelated question to you, Quentin. How hard is bpftool's
> > dependency on libcap? We've recently removed libcap from selftests, I
> > wonder if it would be possible to do that for bpftool as well to
> > reduce amount of shared libraries bpftool depends on.
>
> There's not a super-strong dependency on it. It's used in feature
> probing, for two things.
>
> First one is to be accurate when we check that the user has the right
> capabilities for probing efficiently the system. A workaround consists
> in checking that we run with uid=0 (root), although it's less
> accurate.
>
> Second thing is probing as an unprivileged user: if bpftool is run to
> probe as root but with the "unprivileged" keyword, libcap is used to
> drop the CAP_SYS_ADMIN and run the probes without it. I don't know if
> there's an easy alternative to libcap for that. Also I don't know how
> many people use this feature, but I remember that this was added
> because there was some demand at the time, so presumably there are
> users relying on this.
>
> This being said, libcap is optional for compiling bpftool, so you
> should be able to have it work just as well if the library is not
> available on the system? Basically you'd just lose the ability to
> probe as an unprivileged user. Do you need to remove the optional
> dependency completely?

Well, see recent patches from Martin:

82cb2b30773e bpf: selftests: Remove libcap usage from test_progs
b1c2768a82b9 bpf: selftests: Remove libcap usage from test_verifier
663af70aabb7 bpf: selftests: Add helpers to directly use the capget
and capset syscall

We completely got rid of libcap dependency and ended up with more
straightforward code. So I was wondering if this is possible for
bpftool. The less unnecessary library dependencies - the better. The
less feature detection -- the better. That's my only line of thought
here :)

>
> Quentin
>
> PS: Not directly related but since we're talking of libcap, we
> recently discovered that the lib is apparently changing errno when it
> maybe shouldn't and plays badly with batch mode:
> https://stackoverflow.com/questions/71608181/bpf-xdp-bpftool-batch-file-returns-error-reading-batch-file-failed-opera

just another argument in favor of getting rid of extra layers of dependencies

^ permalink raw reply	[relevance 0%]

* [PATCH bpf-next] selftests/bpf: Fix parsing of prog types in UAPI hdr for bpftool sync
@ 2022-04-04 14:09  6% Quentin Monnet
  0 siblings, 0 replies; 77+ results
From: Quentin Monnet @ 2022-04-04 14:09 UTC (permalink / raw)
  To: Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko
  Cc: netdev, bpf, Quentin Monnet, Milan Landaverde

The script for checking that various lists of types in bpftool remain in
sync with the UAPI BPF header uses a regex to parse enum bpf_prog_type.
If this enum contains a set of values different from the list of program
types in bpftool, it complains.

This script should have reported the addition, some time ago, of the new
BPF_PROG_TYPE_SYSCALL, which was not reported to bpftool's program types
list. It failed to do so, because it failed to parse that new type from
the enum. This is because the new value, in the BPF header, has an
explicative comment on the same line, and the regex does not support
that.

Let's update the script to support parsing enum values when they have
comments on the same line.

Cc: Andrii Nakryiko <andrii@kernel.org>
Cc: Milan Landaverde <milan@mdaverde.com>
Signed-off-by: Quentin Monnet <quentin@isovalent.com>
---
 tools/testing/selftests/bpf/test_bpftool_synctypes.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/tools/testing/selftests/bpf/test_bpftool_synctypes.py b/tools/testing/selftests/bpf/test_bpftool_synctypes.py
index 6bf21e47882a..c0e7acd698ed 100755
--- a/tools/testing/selftests/bpf/test_bpftool_synctypes.py
+++ b/tools/testing/selftests/bpf/test_bpftool_synctypes.py
@@ -180,7 +180,7 @@ class FileExtractor(object):
         @enum_name: name of the enum to parse
         """
         start_marker = re.compile(f'enum {enum_name} {{\n')
-        pattern = re.compile('^\s*(BPF_\w+),?$')
+        pattern = re.compile('^\s*(BPF_\w+),?(\s+/\*.*\*/)?$')
         end_marker = re.compile('^};')
         parser = BlockParser(self.reader)
         parser.search_block(start_marker)
-- 
2.32.0


^ permalink raw reply related	[relevance 6%]

* Re: [PATCH bpf-next 2/3] bpf/bpftool: add missing link types
  2022-04-01 16:05  6%   ` Quentin Monnet
@ 2022-04-04 21:55  0%     ` Andrii Nakryiko
  0 siblings, 0 replies; 77+ results
From: Andrii Nakryiko @ 2022-04-04 21:55 UTC (permalink / raw)
  To: Quentin Monnet
  Cc: Milan Landaverde, bpf, Alexei Starovoitov, Daniel Borkmann,
	Andrii Nakryiko, Martin Lau, Song Liu, Yonghong Song,
	john fastabend, KP Singh, Dave Marchevsky, Stanislav Fomichev,
	Networking, open list

On Fri, Apr 1, 2022 at 9:05 AM Quentin Monnet <quentin@isovalent.com> wrote:
>
> 2022-03-31 11:45 UTC-0400 ~ Milan Landaverde <milan@mdaverde.com>
> > Will display the link type names in bpftool link show output
> >
> > Signed-off-by: Milan Landaverde <milan@mdaverde.com>
> > ---
> >  tools/bpf/bpftool/link.c | 2 ++
> >  1 file changed, 2 insertions(+)
> >
> > diff --git a/tools/bpf/bpftool/link.c b/tools/bpf/bpftool/link.c
> > index 97dec81950e5..9392ef390828 100644
> > --- a/tools/bpf/bpftool/link.c
> > +++ b/tools/bpf/bpftool/link.c
> > @@ -20,6 +20,8 @@ static const char * const link_type_name[] = {
> >       [BPF_LINK_TYPE_CGROUP]                  = "cgroup",
> >       [BPF_LINK_TYPE_ITER]                    = "iter",
> >       [BPF_LINK_TYPE_NETNS]                   = "netns",
> > +     [BPF_LINK_TYPE_XDP]                             = "xdp",

fixed indentation here and added KPROBE_MULTI while applying

> > +     [BPF_LINK_TYPE_PERF_EVENT]              = "perf_event",
>
> Since this goes into bpf-next, we should add BPF_LINK_TYPE_KPROBE_MULTI
> as well.
>
> Quentin

^ permalink raw reply	[relevance 0%]

* pull-request: bpf-next 2022-04-09
@ 2022-04-08 23:17  4% Daniel Borkmann
  0 siblings, 0 replies; 77+ results
From: Daniel Borkmann @ 2022-04-08 23:17 UTC (permalink / raw)
  To: davem; +Cc: kuba, pabeni, daniel, ast, andrii, netdev, bpf

Hi David, hi Jakub,

The following pull-request contains BPF updates for your *net-next* tree.

We've added 63 non-merge commits during the last 9 day(s) which contain
a total of 68 files changed, 4852 insertions(+), 619 deletions(-).

The main changes are:

1) Add libbpf support for USDT (User Statically-Defined Tracing) probes.
   USDTs are an abstraction built on top of uprobes, critical for tracing
   and BPF, and widely used in production applications, from Andrii Nakryiko.

2) While Andrii was adding support for x86{-64}-specific logic of parsing
   USDT argument specification, Ilya followed-up with USDT support for s390
   architecture, from Ilya Leoshkevich.

3) Support name-based attaching for uprobe BPF programs in libbpf. The format
   supported is `u[ret]probe/binary_path:[raw_offset|function[+offset]]`, e.g.
   attaching to libc malloc can be done in BPF via SEC("uprobe/libc.so.6:malloc")
   now, from Alan Maguire.

4) Various load/store optimizations for the arm64 JIT to shrink the image
   size by using arm64 str/ldr immediate instructions. Also enable pointer
   authentication to verify return address for JITed code, from Xu Kuohai.

5) BPF verifier fixes for write access checks to helper functions, e.g.
   rd-only memory from bpf_*_cpu_ptr() must not be passed to helpers that
   write into passed buffers, from Kumar Kartikeya Dwivedi.

6) Fix overly excessive stack map allocation for its base map structure and
   buckets which slipped-in from cleanups during the rlimit accounting removal
   back then, from Yuntao Wang.

7) Extend the unstable CT lookup helpers for XDP and tc/BPF to report netfilter
   connection tracking tuple direction, from Lorenzo Bianconi.

8) Improve bpftool dump to show BPF program/link type names, Milan Landaverde.

9) Minor cleanups all over the place from various others.

Please consider pulling these changes from:

  git://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next.git

Thanks a lot!

Also thanks to reporters, reviewers and testers of commits in this pull-request:

Abaci Robot, Alan Maguire, Dave Marchevsky, Hao Luo, Hengqi Chen, Joanne 
Koong, Naresh Kamboju, Quentin Monnet, Shuah Khan, Yonghong Song

----------------------------------------------------------------

The following changes since commit 2975dbdc3989cd66a4cb5a7c5510de2de8ee4d14:

  Merge tag 'net-5.18-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net (2022-03-31 11:23:31 -0700)

are available in the Git repository at:

  https://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next.git 

for you to fetch changes up to b45043192b3e481304062938a6561da2ceea46a6:

  bpf: Fix excessive memory allocation in stack_map_alloc() (2022-04-09 00:28:21 +0200)

----------------------------------------------------------------
Alan Maguire (8):
      libbpf: auto-resolve programs/libraries when necessary for uprobes
      libbpf: Support function name-based attach uprobes
      libbpf: Add auto-attach for uprobes based on section name
      selftests/bpf: Add tests for u[ret]probe attach by name
      selftests/bpf: Add tests for uprobe auto-attach via skeleton
      libbpf: Improve library identification for uprobe binary path resolution
      libbpf: Improve string parsing for uprobe auto-attach
      selftests/bpf: Uprobe tests should verify param/return values

Alexander Lobakin (1):
      samples: bpf: Fix linking xdp_router_ipv4 after migration

Alexei Starovoitov (1):
      Merge branch 'Add libbpf support for USDTs'

Andrii Nakryiko (17):
      Merge branch 'libbpf: name-based u[ret]probe attach'
      Merge branch 'bpf/bpftool: add program & link type names'
      libbpf: Add BPF-side of USDT support
      libbpf: Wire up USDT API and bpf_link integration
      libbpf: Add USDT notes parsing and resolution logic
      libbpf: Wire up spec management and other arch-independent USDT logic
      libbpf: Add x86-specific USDT arg spec parsing logic
      selftests/bpf: Add basic USDT selftests
      selftests/bpf: Add urandom_read shared lib and USDTs
      Merge branch 'libbpf: uprobe name-based attach followups'
      libbpf: Fix use #ifdef instead of #if to avoid compiler warning
      Merge branch 'Add USDT support for s390'
      libbpf: Use strlcpy() in path resolution fallback logic
      libbpf: Allow WEAK and GLOBAL bindings during BTF fixup
      libbpf: Don't error out on CO-RE relos for overriden weak subprogs
      libbpf: Use weak hidden modifier for USDT BPF-side API functions
      selftests/bpf: Add CO-RE relos into linked_funcs selftests

Artem Savkov (1):
      selftests/bpf: Use bpf_num_possible_cpus() in per-cpu map allocations

Colin Ian King (1):
      libbpf: Fix spelling mistake "libaries" -> "libraries"

Eyal Birger (1):
      selftests/bpf: Remove unused variable from bpf_sk_assign test

Haiyue Wang (1):
      bpf: Correct the comment for BTF kind bitfield

Haowen Bai (2):
      selftests/bpf: Return true/false (not 1/0) from bool functions
      libbpf: Potential NULL dereference in usdt_manager_attach_usdt()

Ilya Leoshkevich (5):
      selftests/bpf: Define SYS_NANOSLEEP_KPROBE_NAME for aarch64
      libbpf: Support Debian in resolve_full_path()
      libbpf: Minor style improvements in USDT code
      libbpf: Make BPF-side of USDT support work on big-endian machines
      libbpf: Add s390-specific USDT arg spec parsing logic

Jakob Koschel (1):
      bpf: Replace usage of supported with dedicated list iterator variable

Jiapeng Chong (1):
      bpf: Use swap() instead of open coding it

Kumar Kartikeya Dwivedi (5):
      bpf: Do write access check for kfunc and global func
      bpf: Check PTR_TO_MEM | MEM_RDONLY in check_helper_mem_access
      bpf: Reject writes for PTR_TO_MAP_KEY in check_helper_mem_access
      selftests/bpf: Test passing rdonly mem to global func
      selftests/bpf: Test for writes to map key from BPF helpers

Lorenzo Bianconi (3):
      samples: bpf: Convert xdp_router_ipv4 to XDP samples helper
      net: netfilter: Reports ct direction in CT lookup helpers for XDP and TC-BPF
      samples, bpf: Move routes monitor in xdp_router_ipv4 in a dedicated thread

Milan Landaverde (3):
      bpftool: Add syscall prog type
      bpftool: Add missing link types
      bpftool: Handle libbpf_probe_prog_type errors

Nikolay Borisov (1):
      selftests/bpf: Fix vfs_link kprobe definition

Quentin Monnet (1):
      selftests/bpf: Fix parsing of prog types in UAPI hdr for bpftool sync

Song Chen (1):
      sample: bpf: syscall_tp_user: Print result of verify_map

Xu Kuohai (6):
      arm64, insn: Add ldr/str with immediate offset
      bpf, arm64: Optimize BPF store/load using arm64 str/ldr(immediate offset)
      bpf, arm64: Adjust the offset of str/ldr(immediate) to positive number
      bpf, tests: Add tests for BPF_LDX/BPF_STX with different offsets
      bpf, tests: Add load store test case for tail call
      bpf, arm64: Sign return address for JITed code

Yauheni Kaliuta (1):
      bpf, test_offload.py: Skip base maps without names

Yuntao Wang (7):
      bpf: Remove redundant assignment to smap->map.value_size
      selftests/bpf: Fix cd_flavor_subdir() of test_progs
      libbpf: Don't return -EINVAL if hdr_len < offsetofend(core_relo_len)
      selftests/bpf: Fix file descriptor leak in load_kallsyms()
      selftests/bpf: Fix issues in parse_num_list()
      selftests/bpf: Fix return value checks in perf_event_stackmap test
      bpf: Fix excessive memory allocation in stack_map_alloc()

 arch/arm64/include/asm/insn.h                      |    9 +
 arch/arm64/lib/insn.c                              |   67 +-
 arch/arm64/net/bpf_jit.h                           |   17 +
 arch/arm64/net/bpf_jit_comp.c                      |  255 +++-
 include/uapi/linux/btf.h                           |    4 +-
 kernel/bpf/bpf_iter.c                              |   30 +-
 kernel/bpf/stackmap.c                              |    2 -
 kernel/bpf/verifier.c                              |   61 +-
 kernel/trace/bpf_trace.c                           |    6 +-
 lib/test_bpf.c                                     |  315 ++++-
 net/netfilter/nf_conntrack_bpf.c                   |   22 +-
 samples/bpf/Makefile                               |   10 +-
 samples/bpf/syscall_tp_user.c                      |    3 +
 samples/bpf/xdp_router_ipv4.bpf.c                  |  180 +++
 samples/bpf/xdp_router_ipv4_kern.c                 |  186 ---
 samples/bpf/xdp_router_ipv4_user.c                 |  455 +++----
 tools/bpf/bpftool/feature.c                        |    2 +-
 tools/bpf/bpftool/link.c                           |    3 +
 tools/bpf/bpftool/prog.c                           |    1 +
 tools/include/uapi/linux/btf.h                     |    4 +-
 tools/lib/bpf/Build                                |    3 +-
 tools/lib/bpf/Makefile                             |    2 +-
 tools/lib/bpf/btf.c                                |    6 +-
 tools/lib/bpf/libbpf.c                             |  488 ++++++-
 tools/lib/bpf/libbpf.h                             |   41 +-
 tools/lib/bpf/libbpf.map                           |    1 +
 tools/lib/bpf/libbpf_internal.h                    |   30 +
 tools/lib/bpf/usdt.bpf.h                           |  259 ++++
 tools/lib/bpf/usdt.c                               | 1335 ++++++++++++++++++++
 tools/testing/selftests/bpf/Makefile               |   25 +-
 .../selftests/bpf/prog_tests/attach_probe.c        |   85 +-
 tools/testing/selftests/bpf/prog_tests/for_each.c  |   12 +
 tools/testing/selftests/bpf/prog_tests/ksyms_btf.c |   17 +-
 tools/testing/selftests/bpf/prog_tests/netcnt.c    |    2 +-
 .../selftests/bpf/prog_tests/test_global_funcs.c   |    1 +
 .../selftests/bpf/prog_tests/uprobe_autoattach.c   |   49 +
 tools/testing/selftests/bpf/prog_tests/usdt.c      |  421 ++++++
 .../bpf/progs/for_each_map_elem_write_key.c        |   27 +
 tools/testing/selftests/bpf/progs/linked_funcs1.c  |    8 +
 tools/testing/selftests/bpf/progs/linked_funcs2.c  |    8 +
 .../selftests/bpf/progs/perf_event_stackmap.c      |    4 +-
 tools/testing/selftests/bpf/progs/profiler.inc.h   |    5 +-
 .../selftests/bpf/progs/test_attach_probe.c        |   41 +-
 .../testing/selftests/bpf/progs/test_bpf_cookie.c  |    4 +-
 .../selftests/bpf/progs/test_global_func17.c       |   16 +
 .../bpf/progs/test_ksyms_btf_write_check.c         |   18 +-
 .../selftests/bpf/progs/test_l4lb_noinline.c       |    2 +-
 tools/testing/selftests/bpf/progs/test_sk_assign.c |    4 +-
 .../selftests/bpf/progs/test_task_pt_regs.c        |    2 +-
 .../selftests/bpf/progs/test_uprobe_autoattach.c   |   73 ++
 .../selftests/bpf/progs/test_urandom_usdt.c        |   70 +
 tools/testing/selftests/bpf/progs/test_usdt.c      |   96 ++
 .../selftests/bpf/progs/test_usdt_multispec.c      |   32 +
 .../selftests/bpf/progs/test_xdp_noinline.c        |   12 +-
 tools/testing/selftests/bpf/progs/trigger_bench.c  |    2 +-
 tools/testing/selftests/bpf/sdt-config.h           |    6 +
 tools/testing/selftests/bpf/sdt.h                  |  513 ++++++++
 .../selftests/bpf/test_bpftool_synctypes.py        |    2 +-
 tools/testing/selftests/bpf/test_cgroup_storage.c  |    3 +-
 tools/testing/selftests/bpf/test_offload.py        |    2 +-
 tools/testing/selftests/bpf/test_progs.c           |    6 +-
 tools/testing/selftests/bpf/test_progs.h           |    2 +
 tools/testing/selftests/bpf/testing_helpers.c      |    2 +-
 tools/testing/selftests/bpf/trace_helpers.c        |    9 +-
 tools/testing/selftests/bpf/urandom_read.c         |   63 +-
 tools/testing/selftests/bpf/urandom_read_aux.c     |    9 +
 tools/testing/selftests/bpf/urandom_read_lib1.c    |   13 +
 tools/testing/selftests/bpf/urandom_read_lib2.c    |    8 +
 68 files changed, 4852 insertions(+), 619 deletions(-)
 create mode 100644 samples/bpf/xdp_router_ipv4.bpf.c
 delete mode 100644 samples/bpf/xdp_router_ipv4_kern.c
 create mode 100644 tools/lib/bpf/usdt.bpf.h
 create mode 100644 tools/lib/bpf/usdt.c
 create mode 100644 tools/testing/selftests/bpf/prog_tests/uprobe_autoattach.c
 create mode 100644 tools/testing/selftests/bpf/prog_tests/usdt.c
 create mode 100644 tools/testing/selftests/bpf/progs/for_each_map_elem_write_key.c
 create mode 100644 tools/testing/selftests/bpf/progs/test_global_func17.c
 create mode 100644 tools/testing/selftests/bpf/progs/test_uprobe_autoattach.c
 create mode 100644 tools/testing/selftests/bpf/progs/test_urandom_usdt.c
 create mode 100644 tools/testing/selftests/bpf/progs/test_usdt.c
 create mode 100644 tools/testing/selftests/bpf/progs/test_usdt_multispec.c
 create mode 100644 tools/testing/selftests/bpf/sdt-config.h
 create mode 100644 tools/testing/selftests/bpf/sdt.h
 create mode 100644 tools/testing/selftests/bpf/urandom_read_aux.c
 create mode 100644 tools/testing/selftests/bpf/urandom_read_lib1.c
 create mode 100644 tools/testing/selftests/bpf/urandom_read_lib2.c

^ permalink raw reply	[relevance 4%]

* [PATCH bpf-next 0/2] bpftool: fix feature output when helper probes fail
@ 2022-05-04 16:13 13% Milan Landaverde
  2022-05-04 16:13 13% ` [PATCH bpf-next 1/2] bpftool: adjust for error codes from libbpf probes Milan Landaverde
                   ` (2 more replies)
  0 siblings, 3 replies; 77+ results
From: Milan Landaverde @ 2022-05-04 16:13 UTC (permalink / raw)
  Cc: milan, Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko,
	Martin KaFai Lau, Song Liu, Yonghong Song, John Fastabend,
	KP Singh, Quentin Monnet, Paul Chaignon, Niklas Söderlund,
	netdev, bpf, linux-kernel

Currently in bpftool's feature probe, we incorrectly tell the user that
all of the helper functions are supported for program types where helper
probing fails or is explicitly unsupported[1]:

$ bpftool feature probe
...
eBPF helpers supported for program type tracing:
	- bpf_map_lookup_elem
	- bpf_map_update_elem
	- bpf_map_delete_elem
	...
	- bpf_redirect_neigh
	- bpf_check_mtu
	- bpf_sys_bpf
	- bpf_sys_close

This patch adjusts bpftool to relay to the user when helper support
can't be determined:

$ bpftool feature probe
...
eBPF helpers supported for program type lirc_mode2:
    Program type not supported
eBPF helpers supported for program type tracing:
    Could not determine which helpers are available
eBPF helpers supported for program type struct_opts:
    Could not determine which helpers are available
eBPF helpers supported for program type ext:
    Could not determine which helpers are available

Rather than imply that no helpers are available for the program type, we
let the user know that helper function probing failed entirely.

[1] https://lore.kernel.org/bpf/20211217171202.3352835-2-andrii@kernel.org/

Milan Landaverde (2):
  bpftool: adjust for error codes from libbpf probes
  bpftool: output message if no helpers found in feature probing

 tools/bpf/bpftool/feature.c | 22 +++++++++++++++++-----
 1 file changed, 17 insertions(+), 5 deletions(-)

--
2.32.0


^ permalink raw reply	[relevance 13%]

* [PATCH bpf-next 1/2] bpftool: adjust for error codes from libbpf probes
  2022-05-04 16:13 13% [PATCH bpf-next 0/2] bpftool: fix feature output when helper probes fail Milan Landaverde
@ 2022-05-04 16:13 13% ` Milan Landaverde
  2022-05-04 16:13 13% ` [PATCH bpf-next 2/2] bpftool: output message if no helpers found in feature probing Milan Landaverde
  2022-05-05 10:15  6% ` [PATCH bpf-next 0/2] bpftool: fix feature output when helper probes fail Quentin Monnet
  2 siblings, 0 replies; 77+ results
From: Milan Landaverde @ 2022-05-04 16:13 UTC (permalink / raw)
  Cc: milan, Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko,
	Martin KaFai Lau, Song Liu, Yonghong Song, John Fastabend,
	KP Singh, Quentin Monnet, Paul Chaignon, Niklas Söderlund,
	netdev, bpf, linux-kernel

Originally [1], libbpf's (now deprecated) probe functions returned a bool
to acknowledge support but the new APIs return an int with a possible
negative error code to reflect probe failure. This change decides for
bpftool to declare maps and helpers are not available on probe failures.

[1]: https://lore.kernel.org/bpf/20220202225916.3313522-3-andrii@kernel.org/

Signed-off-by: Milan Landaverde <milan@mdaverde.com>
---
 tools/bpf/bpftool/feature.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/tools/bpf/bpftool/feature.c b/tools/bpf/bpftool/feature.c
index be130e35462f..c532c8855c24 100644
--- a/tools/bpf/bpftool/feature.c
+++ b/tools/bpf/bpftool/feature.c
@@ -638,7 +638,7 @@ probe_map_type(enum bpf_map_type map_type, const char *define_prefix,
 
 		res = probe_map_type_ifindex(map_type, ifindex);
 	} else {
-		res = libbpf_probe_bpf_map_type(map_type, NULL);
+		res = libbpf_probe_bpf_map_type(map_type, NULL) > 0;
 	}
 
 	/* Probe result depends on the success of map creation, no additional
@@ -701,7 +701,7 @@ probe_helper_for_progtype(enum bpf_prog_type prog_type, bool supported_type,
 		if (ifindex)
 			res = probe_helper_ifindex(id, prog_type, ifindex);
 		else
-			res = libbpf_probe_bpf_helper(prog_type, id, NULL);
+			res = libbpf_probe_bpf_helper(prog_type, id, NULL) > 0;
 #ifdef USE_LIBCAP
 		/* Probe may succeed even if program load fails, for
 		 * unprivileged users check that we did not fail because of
-- 
2.32.0


^ permalink raw reply related	[relevance 13%]

* [PATCH bpf-next 2/2] bpftool: output message if no helpers found in feature probing
  2022-05-04 16:13 13% [PATCH bpf-next 0/2] bpftool: fix feature output when helper probes fail Milan Landaverde
  2022-05-04 16:13 13% ` [PATCH bpf-next 1/2] bpftool: adjust for error codes from libbpf probes Milan Landaverde
@ 2022-05-04 16:13 13% ` Milan Landaverde
  2022-05-05 10:15  6% ` [PATCH bpf-next 0/2] bpftool: fix feature output when helper probes fail Quentin Monnet
  2 siblings, 0 replies; 77+ results
From: Milan Landaverde @ 2022-05-04 16:13 UTC (permalink / raw)
  Cc: milan, Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko,
	Martin KaFai Lau, Song Liu, Yonghong Song, John Fastabend,
	KP Singh, Quentin Monnet, Paul Chaignon, Niklas Söderlund,
	netdev, bpf, linux-kernel

Currently in libbpf, we have hardcoded program types that are not
supported for helper function probing (e.g. tracing, ext, lsm).
Due to this (and other legitimate failures), bpftool feature probe returns
empty for those program type helper functions.

Instead of implying to the user that there are no helper functions
available for a program type, we output a message to the user explaining
that helper function probing failed for that program type.

Signed-off-by: Milan Landaverde <milan@mdaverde.com>
---
 tools/bpf/bpftool/feature.c | 18 +++++++++++++++---
 1 file changed, 15 insertions(+), 3 deletions(-)

diff --git a/tools/bpf/bpftool/feature.c b/tools/bpf/bpftool/feature.c
index c532c8855c24..d12f46051aac 100644
--- a/tools/bpf/bpftool/feature.c
+++ b/tools/bpf/bpftool/feature.c
@@ -690,7 +690,7 @@ probe_helper_ifindex(enum bpf_func_id id, enum bpf_prog_type prog_type,
 	return res;
 }
 
-static void
+static bool
 probe_helper_for_progtype(enum bpf_prog_type prog_type, bool supported_type,
 			  const char *define_prefix, unsigned int id,
 			  const char *ptype_name, __u32 ifindex)
@@ -723,6 +723,8 @@ probe_helper_for_progtype(enum bpf_prog_type prog_type, bool supported_type,
 		if (res)
 			printf("\n\t- %s", helper_name[id]);
 	}
+
+	return res;
 }
 
 static void
@@ -732,6 +734,7 @@ probe_helpers_for_progtype(enum bpf_prog_type prog_type, bool supported_type,
 	const char *ptype_name = prog_type_name[prog_type];
 	char feat_name[128];
 	unsigned int id;
+	bool probe_res = false;
 
 	if (ifindex)
 		/* Only test helpers for offload-able program types */
@@ -764,7 +767,7 @@ probe_helpers_for_progtype(enum bpf_prog_type prog_type, bool supported_type,
 				continue;
 			/* fallthrough */
 		default:
-			probe_helper_for_progtype(prog_type, supported_type,
+			probe_res |= probe_helper_for_progtype(prog_type, supported_type,
 						  define_prefix, id, ptype_name,
 						  ifindex);
 		}
@@ -772,8 +775,17 @@ probe_helpers_for_progtype(enum bpf_prog_type prog_type, bool supported_type,
 
 	if (json_output)
 		jsonw_end_array(json_wtr);
-	else if (!define_prefix)
+	else if (!define_prefix) {
 		printf("\n");
+		if (!probe_res) {
+			if (!supported_type)
+				printf("\tProgram type not supported\n");
+			else
+				printf("\tCould not determine which helpers are available\n");
+		}
+	}
+
+
 }
 
 static void
-- 
2.32.0


^ permalink raw reply related	[relevance 13%]

* Re: [PATCH bpf-next 0/2] bpftool: fix feature output when helper probes fail
  2022-05-04 16:13 13% [PATCH bpf-next 0/2] bpftool: fix feature output when helper probes fail Milan Landaverde
  2022-05-04 16:13 13% ` [PATCH bpf-next 1/2] bpftool: adjust for error codes from libbpf probes Milan Landaverde
  2022-05-04 16:13 13% ` [PATCH bpf-next 2/2] bpftool: output message if no helpers found in feature probing Milan Landaverde
@ 2022-05-05 10:15  6% ` Quentin Monnet
  2 siblings, 0 replies; 77+ results
From: Quentin Monnet @ 2022-05-05 10:15 UTC (permalink / raw)
  To: Milan Landaverde
  Cc: Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko,
	Martin KaFai Lau, Song Liu, Yonghong Song, John Fastabend,
	KP Singh, Paul Chaignon, Niklas Söderlund, netdev, bpf,
	linux-kernel

2022-05-04 12:13 UTC-0400 ~ Milan Landaverde <milan@mdaverde.com>
> Currently in bpftool's feature probe, we incorrectly tell the user that
> all of the helper functions are supported for program types where helper
> probing fails or is explicitly unsupported[1]:
> 
> $ bpftool feature probe
> ...
> eBPF helpers supported for program type tracing:
> 	- bpf_map_lookup_elem
> 	- bpf_map_update_elem
> 	- bpf_map_delete_elem
> 	...
> 	- bpf_redirect_neigh
> 	- bpf_check_mtu
> 	- bpf_sys_bpf
> 	- bpf_sys_close
> 
> This patch adjusts bpftool to relay to the user when helper support
> can't be determined:
> 
> $ bpftool feature probe
> ...
> eBPF helpers supported for program type lirc_mode2:
>     Program type not supported
> eBPF helpers supported for program type tracing:
>     Could not determine which helpers are available
> eBPF helpers supported for program type struct_opts:
>     Could not determine which helpers are available
> eBPF helpers supported for program type ext:
>     Could not determine which helpers are available
> 
> Rather than imply that no helpers are available for the program type, we
> let the user know that helper function probing failed entirely.
> 
> [1] https://lore.kernel.org/bpf/20211217171202.3352835-2-andrii@kernel.org/
> 
> Milan Landaverde (2):
>   bpftool: adjust for error codes from libbpf probes
>   bpftool: output message if no helpers found in feature probing
> 
>  tools/bpf/bpftool/feature.c | 22 +++++++++++++++++-----
>  1 file changed, 17 insertions(+), 5 deletions(-)
> 
> --
> 2.32.0
> 

Looks good to me, thank you

Reviewed-by: Quentin Monnet <quentin@isovalent.com>

^ permalink raw reply	[relevance 6%]

* Re: [PATCH] bpftool: Use sysfs vmlinux when dumping BTF by ID
  @ 2022-05-06  1:32  7% ` Milan Landaverde
  0 siblings, 0 replies; 77+ results
From: Milan Landaverde @ 2022-05-06  1:32 UTC (permalink / raw)
  To: Larysa Zaremba
  Cc: Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko, netdev,
	bpf, linux-kernel, Martin KaFai Lau, Song Liu, Yonghong Song,
	Maciej Fijalkowski, Alexander Lobakin

Hello! Just ran into this. I think we also need to pass in errno
here to strerror instead of err:

On Thu, Apr 28, 2022 at 01:08:40PM +0200, Larysa Zaremba wrote:
>  		if (err) {
>  			p_err("get btf by id (%u): %s", btf_id, strerror(err));
>  			goto done;
>

Currently, the error output without a base btf reads:

$ bpftool btf dump id 816
Error: get btf by id (816): Unknown error -22

When it should (or at least intends to) read:

$ bpftool btf dump id 816
Error: get btf by id (816): Invalid argument

I was going to send this patch but if a v2 is going to be sent, figured
I mention it. Thanks!

^ permalink raw reply	[relevance 7%]

* [PATCH v6 12/23] rust: add `kernel` crate
  @ 2022-05-07  5:24  1% ` Miguel Ojeda
  2022-05-07  5:24  3% ` [PATCH v6 20/23] samples: add Rust examples Miguel Ojeda
  1 sibling, 0 replies; 77+ results
From: Miguel Ojeda @ 2022-05-07  5:24 UTC (permalink / raw)
  To: Linus Torvalds, Greg Kroah-Hartman
  Cc: rust-for-linux, linux-kernel, Jarkko Sakkinen, Miguel Ojeda,
	Wedson Almeida Filho, Alex Gaynor, Geoffrey Thomas, Finn Behrens,
	Adam Bratschi-Kaye, Michael Ellerman, Sumera Priyadarsini,
	Sven Van Asbroeck, Gary Guo, Boris-Chengbiao Zhou, Boqun Feng,
	Fox Chen, Dan Robertson, Viktor Garske, Dariusz Sosnowski,
	Léo Lanteri Thauvin, Niklas Mohrin, Gioh Kim, Daniel Xu,
	Milan Landaverde, Morgan Bartlett, Maciej Falkowski,
	Jiapeng Chong, Nándor István Krácser

From: Wedson Almeida Filho <wedsonaf@google.com>

The `kernel` crate currently includes all the abstractions that wrap
kernel features written in C.

These abstractions call the C side of the kernel via the generated
bindings with the `bindgen` tool. Modules developed in Rust should
never call the bindings themselves.

In the future, as the abstractions grow in number, we may need
to split this crate into several, possibly following a similar
subdivision in subsystems as the kernel itself and/or moving
the code to the actual subsystems.

Co-developed-by: Alex Gaynor <alex.gaynor@gmail.com>
Signed-off-by: Alex Gaynor <alex.gaynor@gmail.com>
Co-developed-by: Geoffrey Thomas <geofft@ldpreload.com>
Signed-off-by: Geoffrey Thomas <geofft@ldpreload.com>
Co-developed-by: Finn Behrens <me@kloenk.de>
Signed-off-by: Finn Behrens <me@kloenk.de>
Co-developed-by: Adam Bratschi-Kaye <ark.email@gmail.com>
Signed-off-by: Adam Bratschi-Kaye <ark.email@gmail.com>
Co-developed-by: Michael Ellerman <mpe@ellerman.id.au>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Co-developed-by: Sumera Priyadarsini <sylphrenadin@gmail.com>
Signed-off-by: Sumera Priyadarsini <sylphrenadin@gmail.com>
Co-developed-by: Sven Van Asbroeck <thesven73@gmail.com>
Signed-off-by: Sven Van Asbroeck <thesven73@gmail.com>
Co-developed-by: Gary Guo <gary@garyguo.net>
Signed-off-by: Gary Guo <gary@garyguo.net>
Co-developed-by: Boris-Chengbiao Zhou <bobo1239@web.de>
Signed-off-by: Boris-Chengbiao Zhou <bobo1239@web.de>
Co-developed-by: Boqun Feng <boqun.feng@gmail.com>
Signed-off-by: Boqun Feng <boqun.feng@gmail.com>
Co-developed-by: Fox Chen <foxhlchen@gmail.com>
Signed-off-by: Fox Chen <foxhlchen@gmail.com>
Co-developed-by: Dan Robertson <daniel.robertson@starlab.io>
Signed-off-by: Dan Robertson <daniel.robertson@starlab.io>
Co-developed-by: Viktor Garske <viktor@v-gar.de>
Signed-off-by: Viktor Garske <viktor@v-gar.de>
Co-developed-by: Dariusz Sosnowski <dsosnowski@dsosnowski.pl>
Signed-off-by: Dariusz Sosnowski <dsosnowski@dsosnowski.pl>
Co-developed-by: Léo Lanteri Thauvin <leseulartichaut@gmail.com>
Signed-off-by: Léo Lanteri Thauvin <leseulartichaut@gmail.com>
Co-developed-by: Niklas Mohrin <dev@niklasmohrin.de>
Signed-off-by: Niklas Mohrin <dev@niklasmohrin.de>
Co-developed-by: Gioh Kim <gurugio@gmail.com>
Signed-off-by: Gioh Kim <gurugio@gmail.com>
Co-developed-by: Daniel Xu <dxu@dxuuu.xyz>
Signed-off-by: Daniel Xu <dxu@dxuuu.xyz>
Co-developed-by: Milan Landaverde <milan@mdaverde.com>
Signed-off-by: Milan Landaverde <milan@mdaverde.com>
Co-developed-by: Morgan Bartlett <mjmouse9999@gmail.com>
Signed-off-by: Morgan Bartlett <mjmouse9999@gmail.com>
Co-developed-by: Maciej Falkowski <m.falkowski@samsung.com>
Signed-off-by: Maciej Falkowski <m.falkowski@samsung.com>
Co-developed-by: Jiapeng Chong <jiapeng.chong@linux.alibaba.com>
Signed-off-by: Jiapeng Chong <jiapeng.chong@linux.alibaba.com>
Co-developed-by: Nándor István Krácser <bonifaido@gmail.com>
Signed-off-by: Nándor István Krácser <bonifaido@gmail.com>
Signed-off-by: Wedson Almeida Filho <wedsonaf@google.com>
Co-developed-by: Miguel Ojeda <ojeda@kernel.org>
Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
---
 rust/kernel/allocator.rs      |  65 +++
 rust/kernel/amba.rs           | 257 ++++++++++
 rust/kernel/bindings.rs       |  47 ++
 rust/kernel/bindings_helper.h |  46 ++
 rust/kernel/build_assert.rs   |  82 ++++
 rust/kernel/c_types.rs        | 119 +++++
 rust/kernel/chrdev.rs         | 207 ++++++++
 rust/kernel/clk.rs            |  79 ++++
 rust/kernel/cred.rs           |  46 ++
 rust/kernel/device.rs         | 546 +++++++++++++++++++++
 rust/kernel/driver.rs         | 442 +++++++++++++++++
 rust/kernel/error.rs          | 565 ++++++++++++++++++++++
 rust/kernel/file.rs           | 860 ++++++++++++++++++++++++++++++++++
 rust/kernel/gpio.rs           | 478 +++++++++++++++++++
 rust/kernel/hwrng.rs          | 242 ++++++++++
 rust/kernel/io_buffer.rs      | 153 ++++++
 rust/kernel/io_mem.rs         | 275 +++++++++++
 rust/kernel/iov_iter.rs       |  81 ++++
 rust/kernel/irq.rs            | 409 ++++++++++++++++
 rust/kernel/kasync.rs         |   6 +
 rust/kernel/kasync/net.rs     | 322 +++++++++++++
 rust/kernel/kunit.rs          |  91 ++++
 rust/kernel/lib.rs            | 260 ++++++++++
 rust/kernel/linked_list.rs    | 247 ++++++++++
 rust/kernel/miscdev.rs        | 291 ++++++++++++
 rust/kernel/mm.rs             | 149 ++++++
 rust/kernel/module_param.rs   | 498 ++++++++++++++++++++
 rust/kernel/net.rs            | 392 ++++++++++++++++
 rust/kernel/net/filter.rs     | 447 ++++++++++++++++++
 rust/kernel/of.rs             |  63 +++
 rust/kernel/pages.rs          | 144 ++++++
 rust/kernel/platform.rs       | 223 +++++++++
 rust/kernel/power.rs          | 118 +++++
 rust/kernel/prelude.rs        |  36 ++
 rust/kernel/print.rs          | 405 ++++++++++++++++
 rust/kernel/random.rs         |  42 ++
 rust/kernel/raw_list.rs       | 361 ++++++++++++++
 rust/kernel/rbtree.rs         | 563 ++++++++++++++++++++++
 rust/kernel/revocable.rs      | 161 +++++++
 rust/kernel/security.rs       |  38 ++
 rust/kernel/static_assert.rs  |  38 ++
 rust/kernel/std_vendor.rs     | 160 +++++++
 rust/kernel/str.rs            | 597 +++++++++++++++++++++++
 rust/kernel/sysctl.rs         | 199 ++++++++
 rust/kernel/task.rs           | 175 +++++++
 rust/kernel/types.rs          | 679 +++++++++++++++++++++++++++
 rust/kernel/user_ptr.rs       | 175 +++++++
 47 files changed, 11879 insertions(+)
 create mode 100644 rust/kernel/allocator.rs
 create mode 100644 rust/kernel/amba.rs
 create mode 100644 rust/kernel/bindings.rs
 create mode 100644 rust/kernel/bindings_helper.h
 create mode 100644 rust/kernel/build_assert.rs
 create mode 100644 rust/kernel/c_types.rs
 create mode 100644 rust/kernel/chrdev.rs
 create mode 100644 rust/kernel/clk.rs
 create mode 100644 rust/kernel/cred.rs
 create mode 100644 rust/kernel/device.rs
 create mode 100644 rust/kernel/driver.rs
 create mode 100644 rust/kernel/error.rs
 create mode 100644 rust/kernel/file.rs
 create mode 100644 rust/kernel/gpio.rs
 create mode 100644 rust/kernel/hwrng.rs
 create mode 100644 rust/kernel/io_buffer.rs
 create mode 100644 rust/kernel/io_mem.rs
 create mode 100644 rust/kernel/iov_iter.rs
 create mode 100644 rust/kernel/irq.rs
 create mode 100644 rust/kernel/kasync.rs
 create mode 100644 rust/kernel/kasync/net.rs
 create mode 100644 rust/kernel/kunit.rs
 create mode 100644 rust/kernel/lib.rs
 create mode 100644 rust/kernel/linked_list.rs
 create mode 100644 rust/kernel/miscdev.rs
 create mode 100644 rust/kernel/mm.rs
 create mode 100644 rust/kernel/module_param.rs
 create mode 100644 rust/kernel/net.rs
 create mode 100644 rust/kernel/net/filter.rs
 create mode 100644 rust/kernel/of.rs
 create mode 100644 rust/kernel/pages.rs
 create mode 100644 rust/kernel/platform.rs
 create mode 100644 rust/kernel/power.rs
 create mode 100644 rust/kernel/prelude.rs
 create mode 100644 rust/kernel/print.rs
 create mode 100644 rust/kernel/random.rs
 create mode 100644 rust/kernel/raw_list.rs
 create mode 100644 rust/kernel/rbtree.rs
 create mode 100644 rust/kernel/revocable.rs
 create mode 100644 rust/kernel/security.rs
 create mode 100644 rust/kernel/static_assert.rs
 create mode 100644 rust/kernel/std_vendor.rs
 create mode 100644 rust/kernel/str.rs
 create mode 100644 rust/kernel/sysctl.rs
 create mode 100644 rust/kernel/task.rs
 create mode 100644 rust/kernel/types.rs
 create mode 100644 rust/kernel/user_ptr.rs

diff --git a/rust/kernel/allocator.rs b/rust/kernel/allocator.rs
new file mode 100644
index 000000000000..4c5d2fc6f206
--- /dev/null
+++ b/rust/kernel/allocator.rs
@@ -0,0 +1,65 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Allocator support.
+
+use core::alloc::{GlobalAlloc, Layout};
+use core::ptr;
+
+use crate::bindings;
+use crate::c_types;
+
+struct KernelAllocator;
+
+unsafe impl GlobalAlloc for KernelAllocator {
+    unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
+        // `krealloc()` is used instead of `kmalloc()` because the latter is
+        // an inline function and cannot be bound to as a result.
+        unsafe { bindings::krealloc(ptr::null(), layout.size(), bindings::GFP_KERNEL) as *mut u8 }
+    }
+
+    unsafe fn dealloc(&self, ptr: *mut u8, _layout: Layout) {
+        unsafe {
+            bindings::kfree(ptr as *const c_types::c_void);
+        }
+    }
+}
+
+#[global_allocator]
+static ALLOCATOR: KernelAllocator = KernelAllocator;
+
+// `rustc` only generates these for some crate types. Even then, we would need
+// to extract the object file that has them from the archive. For the moment,
+// let's generate them ourselves instead.
+//
+// Note that `#[no_mangle]` implies exported too, nowadays.
+#[no_mangle]
+fn __rust_alloc(size: usize, _align: usize) -> *mut u8 {
+    unsafe { bindings::krealloc(core::ptr::null(), size, bindings::GFP_KERNEL) as *mut u8 }
+}
+
+#[no_mangle]
+fn __rust_dealloc(ptr: *mut u8, _size: usize, _align: usize) {
+    unsafe { bindings::kfree(ptr as *const c_types::c_void) };
+}
+
+#[no_mangle]
+fn __rust_realloc(ptr: *mut u8, _old_size: usize, _align: usize, new_size: usize) -> *mut u8 {
+    unsafe {
+        bindings::krealloc(
+            ptr as *const c_types::c_void,
+            new_size,
+            bindings::GFP_KERNEL,
+        ) as *mut u8
+    }
+}
+
+#[no_mangle]
+fn __rust_alloc_zeroed(size: usize, _align: usize) -> *mut u8 {
+    unsafe {
+        bindings::krealloc(
+            core::ptr::null(),
+            size,
+            bindings::GFP_KERNEL | bindings::__GFP_ZERO,
+        ) as *mut u8
+    }
+}
diff --git a/rust/kernel/amba.rs b/rust/kernel/amba.rs
new file mode 100644
index 000000000000..bd38d6ed4075
--- /dev/null
+++ b/rust/kernel/amba.rs
@@ -0,0 +1,257 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Amba devices and drivers.
+//!
+//! C header: [`include/linux/amba/bus.h`](../../../../include/linux/amba/bus.h)
+
+use crate::{
+    bindings, c_types, device, driver, error::from_kernel_result, io_mem::Resource, power,
+    str::CStr, to_result, types::PointerWrapper, Result, ThisModule,
+};
+
+/// A registration of an amba driver.
+pub type Registration<T> = driver::Registration<Adapter<T>>;
+
+/// Id of an Amba device.
+#[derive(Clone, Copy)]
+pub struct DeviceId {
+    /// Device id.
+    pub id: u32,
+
+    /// Mask that identifies which bits are valid in the device id.
+    pub mask: u32,
+}
+
+// SAFETY: `ZERO` is all zeroed-out and `to_rawid` stores `offset` in `amba_id::data`.
+unsafe impl const driver::RawDeviceId for DeviceId {
+    type RawType = bindings::amba_id;
+    const ZERO: Self::RawType = bindings::amba_id {
+        id: 0,
+        mask: 0,
+        data: core::ptr::null_mut(),
+    };
+
+    fn to_rawid(&self, offset: isize) -> Self::RawType {
+        bindings::amba_id {
+            id: self.id,
+            mask: self.mask,
+            data: offset as _,
+        }
+    }
+}
+
+/// An amba driver.
+pub trait Driver {
+    /// Data stored on device by driver.
+    type Data: PointerWrapper + Send + Sync + driver::DeviceRemoval = ();
+
+    /// The type that implements the power-management operations.
+    ///
+    /// The default is a type that implements no power-management operations. Drivers that do
+    /// implement them need to specify the type (commonly [`Self`]).
+    type PowerOps: power::Operations<Data = Self::Data> = power::NoOperations<Self::Data>;
+
+    /// The type holding information about each device id supported by the driver.
+    type IdInfo: 'static = ();
+
+    /// The table of device ids supported by the driver.
+    const ID_TABLE: Option<driver::IdTable<'static, DeviceId, Self::IdInfo>> = None;
+
+    /// Probes for the device with the given id.
+    fn probe(dev: &mut Device, id_info: Option<&Self::IdInfo>) -> Result<Self::Data>;
+
+    /// Cleans any resources up that are associated with the device.
+    ///
+    /// This is called when the driver is detached from the device.
+    fn remove(_data: &Self::Data) {}
+}
+
+/// An adapter for the registration of Amba drivers.
+pub struct Adapter<T: Driver>(T);
+
+impl<T: Driver> driver::DriverOps for Adapter<T> {
+    type RegType = bindings::amba_driver;
+
+    unsafe fn register(
+        reg: *mut bindings::amba_driver,
+        name: &'static CStr,
+        module: &'static ThisModule,
+    ) -> Result {
+        // SAFETY: By the safety requirements of this function (defined in the trait defintion),
+        // `reg` is non-null and valid.
+        let amba = unsafe { &mut *reg };
+        amba.drv.name = name.as_char_ptr();
+        amba.drv.owner = module.0;
+        amba.probe = Some(probe_callback::<T>);
+        amba.remove = Some(remove_callback::<T>);
+        if let Some(t) = T::ID_TABLE {
+            amba.id_table = t.as_ref();
+        }
+        if cfg!(CONFIG_PM) {
+            // SAFETY: `probe_callback` sets the driver data after calling `T::Data::into_pointer`,
+            // and we guarantee that `T::Data` is the same as `T::PowerOps::Data` by a constraint
+            // in the type declaration.
+            amba.drv.pm = unsafe { power::OpsTable::<T::PowerOps>::build() };
+        }
+        // SAFETY: By the safety requirements of this function, `reg` is valid and fully
+        // initialised.
+        to_result(|| unsafe { bindings::amba_driver_register(reg) })
+    }
+
+    unsafe fn unregister(reg: *mut bindings::amba_driver) {
+        // SAFETY: By the safety requirements of this function (defined in the trait definition),
+        // `reg` was passed (and updated) by a previous successful call to `amba_driver_register`.
+        unsafe { bindings::amba_driver_unregister(reg) };
+    }
+}
+
+unsafe extern "C" fn probe_callback<T: Driver>(
+    adev: *mut bindings::amba_device,
+    aid: *const bindings::amba_id,
+) -> c_types::c_int {
+    from_kernel_result! {
+        // SAFETY: `adev` is valid by the contract with the C code. `dev` is alive only for the
+        // duration of this call, so it is guaranteed to remain alive for the lifetime of `dev`.
+        let mut dev = unsafe { Device::from_ptr(adev) };
+        // SAFETY: `aid` is valid by the requirements the contract with the C code.
+        let offset = unsafe { (*aid).data };
+        let info = if offset.is_null() {
+            None
+        } else {
+            // SAFETY: The offset comes from a previous call to `offset_from` in `IdArray::new`,
+            // which guarantees that the resulting pointer is within the table.
+            let ptr = unsafe { aid.cast::<u8>().offset(offset as _).cast::<Option<T::IdInfo>>() };
+            // SAFETY: The id table has a static lifetime, so `ptr` is guaranteed to be valid for
+            // read.
+            unsafe { (&*ptr).as_ref() }
+        };
+        let data = T::probe(&mut dev, info)?;
+        let ptr = T::Data::into_pointer(data);
+        // SAFETY: `adev` is valid for write by the contract with the C code.
+        unsafe { bindings::amba_set_drvdata(adev, ptr as _) };
+        Ok(0)
+    }
+}
+
+unsafe extern "C" fn remove_callback<T: Driver>(adev: *mut bindings::amba_device) {
+    // SAFETY: `adev` is valid by the contract with the C code.
+    let ptr = unsafe { bindings::amba_get_drvdata(adev) };
+    // SAFETY: The value returned by `amba_get_drvdata` was stored by a previous call to
+    // `amba_set_drvdata` in `probe_callback` above; the value comes from a call to
+    // `T::Data::into_pointer`.
+    let data = unsafe { T::Data::from_pointer(ptr) };
+    T::remove(&data);
+    <T::Data as driver::DeviceRemoval>::device_remove(&data);
+}
+
+/// An Amba device.
+///
+/// # Invariants
+///
+/// The field `ptr` is non-null and valid for the lifetime of the object.
+pub struct Device {
+    ptr: *mut bindings::amba_device,
+    res: Option<Resource>,
+}
+
+impl Device {
+    /// Creates a new device from the given pointer.
+    ///
+    /// # Safety
+    ///
+    /// `ptr` must be non-null and valid. It must remain valid for the lifetime of the returned
+    /// instance.
+    unsafe fn from_ptr(ptr: *mut bindings::amba_device) -> Self {
+        // SAFETY: The safety requirements of the function ensure that `ptr` is valid.
+        let dev = unsafe { &mut *ptr };
+        // INVARIANT: The safety requirements of the function ensure the lifetime invariant.
+        Self {
+            ptr,
+            res: Resource::new(dev.res.start, dev.res.end),
+        }
+    }
+
+    /// Returns the io mem resource associated with the device, if there is one.
+    ///
+    /// Ownership of the resource is transferred to the caller, so subsequent calls to this
+    /// function will return [`None`].
+    pub fn take_resource(&mut self) -> Option<Resource> {
+        self.res.take()
+    }
+
+    /// Returns the index-th irq associated with the device, if one exists.
+    pub fn irq(&self, index: usize) -> Option<u32> {
+        // SAFETY: By the type invariants, `self.ptr` is valid for read.
+        let dev = unsafe { &*self.ptr };
+        if index >= dev.irq.len() || dev.irq[index] == 0 {
+            None
+        } else {
+            Some(dev.irq[index])
+        }
+    }
+}
+
+// SAFETY: The device returned by `raw_device` is the raw Amba device.
+unsafe impl device::RawDevice for Device {
+    fn raw_device(&self) -> *mut bindings::device {
+        // SAFETY: By the type invariants, we know that `self.ptr` is non-null and valid.
+        unsafe { &mut (*self.ptr).dev }
+    }
+}
+
+/// Declares a kernel module that exposes a single amba driver.
+///
+/// # Examples
+///
+/// ```ignore
+/// # use kernel::{amba, define_amba_id_table, module_amba_driver};
+/// #
+/// struct MyDriver;
+/// impl amba::Driver for MyDriver {
+///     // [...]
+/// #   fn probe(_dev: &mut amba::Device, _id: Option<&Self::IdInfo>) -> Result {
+/// #       Ok(())
+/// #   }
+/// #   define_amba_id_table! {(), [
+/// #       ({ id: 0x00041061, mask: 0x000fffff }, None),
+/// #   ]}
+/// }
+///
+/// module_amba_driver! {
+///     type: MyDriver,
+///     name: b"module_name",
+///     author: b"Author name",
+///     license: b"GPL v2",
+/// }
+/// ```
+#[macro_export]
+macro_rules! module_amba_driver {
+    ($($f:tt)*) => {
+        $crate::module_driver!(<T>, $crate::amba::Adapter<T>, { $($f)* });
+    };
+}
+
+/// Defines the id table for amba devices.
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::{amba, define_amba_id_table};
+/// #
+/// # struct Sample;
+/// # impl kernel::amba::Driver for Sample {
+/// #   fn probe(_dev: &mut amba::Device, _id: Option<&Self::IdInfo>) -> Result {
+/// #       Ok(())
+/// #   }
+///     define_amba_id_table! {(), [
+///         ({ id: 0x00041061, mask: 0x000fffff }, None),
+///     ]}
+/// # }
+/// ```
+#[macro_export]
+macro_rules! define_amba_id_table {
+    ($data_type:ty, $($t:tt)*) => {
+        type IdInfo = $data_type;
+        $crate::define_id_table!(ID_TABLE, $crate::amba::DeviceId, $data_type, $($t)*);
+    };
+}
diff --git a/rust/kernel/bindings.rs b/rust/kernel/bindings.rs
new file mode 100644
index 000000000000..29a21030688e
--- /dev/null
+++ b/rust/kernel/bindings.rs
@@ -0,0 +1,47 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Bindings.
+//!
+//! Imports the generated bindings by `bindgen`.
+
+// See https://github.com/rust-lang/rust-bindgen/issues/1651.
+#![cfg_attr(test, allow(deref_nullptr))]
+#![cfg_attr(test, allow(unaligned_references))]
+#![cfg_attr(test, allow(unsafe_op_in_unsafe_fn))]
+#![allow(
+    clippy::all,
+    non_camel_case_types,
+    non_upper_case_globals,
+    non_snake_case,
+    improper_ctypes,
+    unreachable_pub,
+    unsafe_op_in_unsafe_fn
+)]
+
+mod bindings_raw {
+    // Use glob import here to expose all helpers.
+    // Symbols defined within the module will take precedence to the glob import.
+    pub use super::bindings_helper::*;
+    use crate::c_types;
+    include!(concat!(env!("OBJTREE"), "/rust/bindings_generated.rs"));
+}
+
+// When both a directly exposed symbol and a helper exists for the same function,
+// the directly exposed symbol is preferred and the helper becomes dead code, so
+// ignore the warning here.
+#[allow(dead_code)]
+mod bindings_helper {
+    // Import the generated bindings for types.
+    use super::bindings_raw::*;
+    use crate::c_types;
+    include!(concat!(
+        env!("OBJTREE"),
+        "/rust/bindings_helpers_generated.rs"
+    ));
+}
+
+pub use bindings_raw::*;
+
+pub const GFP_KERNEL: gfp_t = BINDINGS_GFP_KERNEL;
+pub const __GFP_ZERO: gfp_t = BINDINGS___GFP_ZERO;
+pub const __GFP_HIGHMEM: gfp_t = ___GFP_HIGHMEM;
diff --git a/rust/kernel/bindings_helper.h b/rust/kernel/bindings_helper.h
new file mode 100644
index 000000000000..1c1e6ae2ac18
--- /dev/null
+++ b/rust/kernel/bindings_helper.h
@@ -0,0 +1,46 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Header that contains the code (mostly headers) for which Rust bindings
+ * will be automatically generated by `bindgen`.
+ *
+ * Sorted alphabetically.
+ */
+
+#include <asm/io.h>
+#include <kunit/test.h>
+#include <linux/amba/bus.h>
+#include <linux/cdev.h>
+#include <linux/clk.h>
+#include <linux/errname.h>
+#include <linux/file.h>
+#include <linux/fs.h>
+#include <linux/gpio/driver.h>
+#include <linux/hw_random.h>
+#include <linux/interrupt.h>
+#include <linux/irqdomain.h>
+#include <linux/irq.h>
+#include <linux/miscdevice.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/poll.h>
+#include <linux/random.h>
+#include <linux/security.h>
+#include <linux/slab.h>
+#include <linux/sysctl.h>
+#include <linux/uaccess.h>
+#include <linux/uio.h>
+#include <uapi/linux/android/binder.h>
+#include <linux/netfilter.h>
+#include <linux/netfilter_ipv4.h>
+#include <linux/netfilter_ipv6.h>
+#include <linux/netfilter_arp.h>
+
+/* `bindgen` gets confused at certain things. */
+const gfp_t BINDINGS_GFP_KERNEL = GFP_KERNEL;
+const gfp_t BINDINGS___GFP_ZERO = __GFP_ZERO;
+const __poll_t BINDINGS_EPOLLIN = EPOLLIN;
+const __poll_t BINDINGS_EPOLLOUT = EPOLLOUT;
+const __poll_t BINDINGS_EPOLLERR = EPOLLERR;
+const __poll_t BINDINGS_EPOLLHUP = EPOLLHUP;
diff --git a/rust/kernel/build_assert.rs b/rust/kernel/build_assert.rs
new file mode 100644
index 000000000000..18cffec7d037
--- /dev/null
+++ b/rust/kernel/build_assert.rs
@@ -0,0 +1,82 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Build-time assert.
+
+/// Fails the build if the code path calling `build_error!` can possibly be executed.
+///
+/// If the macro is executed in const context, `build_error!` will panic.
+/// If the compiler or optimizer cannot guarantee that `build_error!` can never
+/// be called, a build error will be triggered.
+///
+/// # Examples
+/// ```
+/// # use kernel::build_error;
+/// #[inline]
+/// fn foo(a: usize) -> usize {
+///     a.checked_add(1).unwrap_or_else(|| build_error!("overflow"))
+/// }
+///
+/// assert_eq!(foo(usize::MAX - 1), usize::MAX); // OK.
+/// // foo(usize::MAX); // Fails to compile.
+/// ```
+#[macro_export]
+macro_rules! build_error {
+    () => {{
+        $crate::build_error("")
+    }};
+    ($msg:expr) => {{
+        $crate::build_error($msg)
+    }};
+}
+
+/// Asserts that a boolean expression is `true` at compile time.
+///
+/// If the condition is evaluated to `false` in const context, `build_assert!`
+/// will panic. If the compiler or optimizer cannot guarantee the condition will
+/// be evaluated to `true`, a build error will be triggered.
+///
+/// [`static_assert!`] should be preferred to `build_assert!` whenever possible.
+///
+/// # Examples
+///
+/// These examples show that different types of [`assert!`] will trigger errors
+/// at different stage of compilation. It is preferred to err as early as
+/// possible, so [`static_assert!`] should be used whenever possible.
+// TODO: Could be `compile_fail` when supported.
+/// ```ignore
+/// fn foo() {
+///     static_assert!(1 > 1); // Compile-time error
+///     build_assert!(1 > 1); // Build-time error
+///     assert!(1 > 1); // Run-time error
+/// }
+/// ```
+///
+/// When the condition refers to generic parameters or parameters of an inline function,
+/// [`static_assert!`] cannot be used. Use `build_assert!` in this scenario.
+/// ```
+/// fn foo<const N: usize>() {
+///     // `static_assert!(N > 1);` is not allowed
+///     build_assert!(N > 1); // Build-time check
+///     assert!(N > 1); // Run-time check
+/// }
+///
+/// #[inline]
+/// fn bar(n: usize) {
+///     // `static_assert!(n > 1);` is not allowed
+///     build_assert!(n > 1); // Build-time check
+///     assert!(n > 1); // Run-time check
+/// }
+/// ```
+#[macro_export]
+macro_rules! build_assert {
+    ($cond:expr $(,)?) => {{
+        if !$cond {
+            $crate::build_error(concat!("assertion failed: ", stringify!($cond)));
+        }
+    }};
+    ($cond:expr, $msg:expr) => {{
+        if !$cond {
+            $crate::build_error($msg);
+        }
+    }};
+}
diff --git a/rust/kernel/c_types.rs b/rust/kernel/c_types.rs
new file mode 100644
index 000000000000..07593a3ba8be
--- /dev/null
+++ b/rust/kernel/c_types.rs
@@ -0,0 +1,119 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! C types for the bindings.
+//!
+//! The bindings generated by `bindgen` use these types to map to the C ones.
+//!
+//! C's standard integer types may differ in width depending on
+//! the architecture, thus we need to conditionally compile those.
+
+#![allow(non_camel_case_types)]
+
+#[cfg(any(target_arch = "arm", target_arch = "x86", target_arch = "riscv32",))]
+mod c {
+    /// C `void` type.
+    pub type c_void = core::ffi::c_void;
+
+    /// C `char` type.
+    pub type c_char = i8;
+
+    /// C `signed char` type.
+    pub type c_schar = i8;
+
+    /// C `unsigned char` type.
+    pub type c_uchar = u8;
+
+    /// C `short` type.
+    pub type c_short = i16;
+
+    /// C `unsigned short` type.
+    pub type c_ushort = u16;
+
+    /// C `int` type.
+    pub type c_int = i32;
+
+    /// C `unsigned int` type.
+    pub type c_uint = u32;
+
+    /// C `long` type.
+    pub type c_long = i32;
+
+    /// C `unsigned long` type.
+    pub type c_ulong = u32;
+
+    /// C `long long` type.
+    pub type c_longlong = i64;
+
+    /// C `unsigned long long` type.
+    pub type c_ulonglong = u64;
+
+    /// C `ssize_t` type (typically defined in `<sys/types.h>` by POSIX).
+    ///
+    /// For some 32-bit architectures like this one, the kernel defines it as
+    /// `int`, i.e. it is an [`i32`].
+    pub type c_ssize_t = isize;
+
+    /// C `size_t` type (typically defined in `<stddef.h>`).
+    ///
+    /// For some 32-bit architectures like this one, the kernel defines it as
+    /// `unsigned int`, i.e. it is an [`u32`].
+    pub type c_size_t = usize;
+}
+
+#[cfg(any(
+    target_arch = "aarch64",
+    target_arch = "x86_64",
+    target_arch = "powerpc64",
+    target_arch = "riscv64",
+))]
+mod c {
+    /// C `void` type.
+    pub type c_void = core::ffi::c_void;
+
+    /// C `char` type.
+    pub type c_char = i8;
+
+    /// C `signed char` type.
+    pub type c_schar = i8;
+
+    /// C `unsigned char` type.
+    pub type c_uchar = u8;
+
+    /// C `short` type.
+    pub type c_short = i16;
+
+    /// C `unsigned short` type.
+    pub type c_ushort = u16;
+
+    /// C `int` type.
+    pub type c_int = i32;
+
+    /// C `unsigned int` type.
+    pub type c_uint = u32;
+
+    /// C `long` type.
+    pub type c_long = i64;
+
+    /// C `unsigned long` type.
+    pub type c_ulong = u64;
+
+    /// C `long long` type.
+    pub type c_longlong = i64;
+
+    /// C `unsigned long long` type.
+    pub type c_ulonglong = u64;
+
+    /// C `ssize_t` type (typically defined in `<sys/types.h>` by POSIX).
+    ///
+    /// For 64-bit architectures like this one, the kernel defines it as
+    /// `long`, i.e. it is an [`i64`].
+    pub type c_ssize_t = isize;
+
+    /// C `size_t` type (typically defined in `<stddef.h>`).
+    ///
+    /// For 64-bit architectures like this one, the kernel defines it as
+    /// `unsigned long`, i.e. it is an [`u64`].
+    pub type c_size_t = usize;
+}
+
+pub use c::*;
diff --git a/rust/kernel/chrdev.rs b/rust/kernel/chrdev.rs
new file mode 100644
index 000000000000..85a52c2d0b8a
--- /dev/null
+++ b/rust/kernel/chrdev.rs
@@ -0,0 +1,207 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Character devices.
+//!
+//! Also called "char devices", `chrdev`, `cdev`.
+//!
+//! C header: [`include/linux/cdev.h`](../../../../include/linux/cdev.h)
+//!
+//! Reference: <https://www.kernel.org/doc/html/latest/core-api/kernel-api.html#char-devices>
+
+use alloc::boxed::Box;
+use core::convert::TryInto;
+use core::marker::PhantomPinned;
+use core::pin::Pin;
+
+use crate::bindings;
+use crate::c_types;
+use crate::error::{code::*, Error, Result};
+use crate::file;
+use crate::str::CStr;
+
+/// Character device.
+///
+/// # Invariants
+///
+///   - [`self.0`] is valid and non-null.
+///   - [`(*self.0).ops`] is valid, non-null and has static lifetime.
+///   - [`(*self.0).owner`] is valid and, if non-null, has module lifetime.
+struct Cdev(*mut bindings::cdev);
+
+impl Cdev {
+    fn alloc(
+        fops: &'static bindings::file_operations,
+        module: &'static crate::ThisModule,
+    ) -> Result<Self> {
+        // SAFETY: FFI call.
+        let cdev = unsafe { bindings::cdev_alloc() };
+        if cdev.is_null() {
+            return Err(ENOMEM);
+        }
+        // SAFETY: `cdev` is valid and non-null since `cdev_alloc()`
+        // returned a valid pointer which was null-checked.
+        unsafe {
+            (*cdev).ops = fops;
+            (*cdev).owner = module.0;
+        }
+        // INVARIANTS:
+        //   - [`self.0`] is valid and non-null.
+        //   - [`(*self.0).ops`] is valid, non-null and has static lifetime,
+        //     because it was coerced from a reference with static lifetime.
+        //   - [`(*self.0).owner`] is valid and, if non-null, has module lifetime,
+        //     guaranteed by the [`ThisModule`] invariant.
+        Ok(Self(cdev))
+    }
+
+    fn add(&mut self, dev: bindings::dev_t, count: c_types::c_uint) -> Result {
+        // SAFETY: According to the type invariants:
+        //   - [`self.0`] can be safely passed to [`bindings::cdev_add`].
+        //   - [`(*self.0).ops`] will live at least as long as [`self.0`].
+        //   - [`(*self.0).owner`] will live at least as long as the
+        //     module, which is an implicit requirement.
+        let rc = unsafe { bindings::cdev_add(self.0, dev, count) };
+        if rc != 0 {
+            return Err(Error::from_kernel_errno(rc));
+        }
+        Ok(())
+    }
+}
+
+impl Drop for Cdev {
+    fn drop(&mut self) {
+        // SAFETY: [`self.0`] is valid and non-null by the type invariants.
+        unsafe {
+            bindings::cdev_del(self.0);
+        }
+    }
+}
+
+struct RegistrationInner<const N: usize> {
+    dev: bindings::dev_t,
+    used: usize,
+    cdevs: [Option<Cdev>; N],
+    _pin: PhantomPinned,
+}
+
+/// Character device registration.
+///
+/// May contain up to a fixed number (`N`) of devices. Must be pinned.
+pub struct Registration<const N: usize> {
+    name: &'static CStr,
+    minors_start: u16,
+    this_module: &'static crate::ThisModule,
+    inner: Option<RegistrationInner<N>>,
+}
+
+impl<const N: usize> Registration<{ N }> {
+    /// Creates a [`Registration`] object for a character device.
+    ///
+    /// This does *not* register the device: see [`Self::register()`].
+    ///
+    /// This associated function is intended to be used when you need to avoid
+    /// a memory allocation, e.g. when the [`Registration`] is a member of
+    /// a bigger structure inside your [`crate::Module`] instance. If you
+    /// are going to pin the registration right away, call
+    /// [`Self::new_pinned()`] instead.
+    pub fn new(
+        name: &'static CStr,
+        minors_start: u16,
+        this_module: &'static crate::ThisModule,
+    ) -> Self {
+        Registration {
+            name,
+            minors_start,
+            this_module,
+            inner: None,
+        }
+    }
+
+    /// Creates a pinned [`Registration`] object for a character device.
+    ///
+    /// This does *not* register the device: see [`Self::register()`].
+    pub fn new_pinned(
+        name: &'static CStr,
+        minors_start: u16,
+        this_module: &'static crate::ThisModule,
+    ) -> Result<Pin<Box<Self>>> {
+        Ok(Pin::from(Box::try_new(Self::new(
+            name,
+            minors_start,
+            this_module,
+        ))?))
+    }
+
+    /// Registers a character device.
+    ///
+    /// You may call this once per device type, up to `N` times.
+    pub fn register<T: file::Operations<OpenData = ()>>(self: Pin<&mut Self>) -> Result {
+        // SAFETY: We must ensure that we never move out of `this`.
+        let this = unsafe { self.get_unchecked_mut() };
+        if this.inner.is_none() {
+            let mut dev: bindings::dev_t = 0;
+            // SAFETY: Calling unsafe function. `this.name` has `'static`
+            // lifetime.
+            let res = unsafe {
+                bindings::alloc_chrdev_region(
+                    &mut dev,
+                    this.minors_start.into(),
+                    N.try_into()?,
+                    this.name.as_char_ptr(),
+                )
+            };
+            if res != 0 {
+                return Err(Error::from_kernel_errno(res));
+            }
+            const NONE: Option<Cdev> = None;
+            this.inner = Some(RegistrationInner {
+                dev,
+                used: 0,
+                cdevs: [NONE; N],
+                _pin: PhantomPinned,
+            });
+        }
+
+        let mut inner = this.inner.as_mut().unwrap();
+        if inner.used == N {
+            return Err(EINVAL);
+        }
+
+        // SAFETY: The adapter doesn't retrieve any state yet, so it's compatible with any
+        // registration.
+        let fops = unsafe { file::OperationsVtable::<Self, T>::build() };
+        let mut cdev = Cdev::alloc(fops, this.this_module)?;
+        cdev.add(inner.dev + inner.used as bindings::dev_t, 1)?;
+        inner.cdevs[inner.used].replace(cdev);
+        inner.used += 1;
+        Ok(())
+    }
+}
+
+impl<const N: usize> file::OpenAdapter<()> for Registration<{ N }> {
+    unsafe fn convert(_inode: *mut bindings::inode, _file: *mut bindings::file) -> *const () {
+        // TODO: Update the SAFETY comment on the call to `FileOperationsVTable::build` above once
+        // this is updated to retrieve state.
+        &()
+    }
+}
+
+// SAFETY: `Registration` does not expose any of its state across threads
+// (it is fine for multiple threads to have a shared reference to it).
+unsafe impl<const N: usize> Sync for Registration<{ N }> {}
+
+impl<const N: usize> Drop for Registration<{ N }> {
+    fn drop(&mut self) {
+        if let Some(inner) = self.inner.as_mut() {
+            // Replicate kernel C behaviour: drop [`Cdev`]s before calling
+            // [`bindings::unregister_chrdev_region`].
+            for i in 0..inner.used {
+                inner.cdevs[i].take();
+            }
+            // SAFETY: [`self.inner`] is Some, so [`inner.dev`] was previously
+            // created using [`bindings::alloc_chrdev_region`].
+            unsafe {
+                bindings::unregister_chrdev_region(inner.dev, N.try_into().unwrap());
+            }
+        }
+    }
+}
diff --git a/rust/kernel/clk.rs b/rust/kernel/clk.rs
new file mode 100644
index 000000000000..840e39fe5723
--- /dev/null
+++ b/rust/kernel/clk.rs
@@ -0,0 +1,79 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Common clock framework.
+//!
+//! C header: [`include/linux/clk.h`](../../../../include/linux/clk.h)
+
+use crate::{bindings, error::Result, to_result};
+use core::mem::ManuallyDrop;
+
+/// Represents `struct clk *`.
+///
+/// # Invariants
+///
+/// The pointer is valid.
+pub struct Clk(*mut bindings::clk);
+
+impl Clk {
+    /// Creates new clock structure from a raw pointer.
+    ///
+    /// # Safety
+    ///
+    /// The pointer must be valid.
+    pub unsafe fn new(clk: *mut bindings::clk) -> Self {
+        Self(clk)
+    }
+
+    /// Returns value of the rate field of `struct clk`.
+    pub fn get_rate(&self) -> usize {
+        // SAFETY: The pointer is valid by the type invariant.
+        unsafe { bindings::clk_get_rate(self.0) as usize }
+    }
+
+    /// Prepares and enables the underlying hardware clock.
+    ///
+    /// This function should not be called in atomic context.
+    pub fn prepare_enable(self) -> Result<EnabledClk> {
+        // SAFETY: The pointer is valid by the type invariant.
+        to_result(|| unsafe { bindings::clk_prepare_enable(self.0) })?;
+        Ok(EnabledClk(self))
+    }
+}
+
+impl Drop for Clk {
+    fn drop(&mut self) {
+        // SAFETY: The pointer is valid by the type invariant.
+        unsafe { bindings::clk_put(self.0) };
+    }
+}
+
+// SAFETY: `Clk` is not restricted to a single thread so it it safe
+// to move it between threads.
+unsafe impl Send for Clk {}
+
+/// A clock variant that is prepared and enabled.
+pub struct EnabledClk(Clk);
+
+impl EnabledClk {
+    /// Returns value of the rate field of `struct clk`.
+    pub fn get_rate(&self) -> usize {
+        self.0.get_rate()
+    }
+
+    /// Disables and later unprepares the underlying hardware clock prematurely.
+    ///
+    /// This function should not be called in atomic context.
+    pub fn disable_unprepare(self) -> Clk {
+        let mut clk = ManuallyDrop::new(self);
+        // SAFETY: The pointer is valid by the type invariant.
+        unsafe { bindings::clk_disable_unprepare(clk.0 .0) };
+        core::mem::replace(&mut clk.0, Clk(core::ptr::null_mut()))
+    }
+}
+
+impl Drop for EnabledClk {
+    fn drop(&mut self) {
+        // SAFETY: The pointer is valid by the type invariant.
+        unsafe { bindings::clk_disable_unprepare(self.0 .0) };
+    }
+}
diff --git a/rust/kernel/cred.rs b/rust/kernel/cred.rs
new file mode 100644
index 000000000000..beacc71d92ac
--- /dev/null
+++ b/rust/kernel/cred.rs
@@ -0,0 +1,46 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Credentials management.
+//!
+//! C header: [`include/linux/cred.h`](../../../../include/linux/cred.h)
+//!
+//! Reference: <https://www.kernel.org/doc/html/latest/security/credentials.html>
+
+use crate::{bindings, AlwaysRefCounted};
+use core::cell::UnsafeCell;
+
+/// Wraps the kernel's `struct cred`.
+///
+/// # Invariants
+///
+/// Instances of this type are always ref-counted, that is, a call to `get_cred` ensures that the
+/// allocation remains valid at least until the matching call to `put_cred`.
+#[repr(transparent)]
+pub struct Credential(pub(crate) UnsafeCell<bindings::cred>);
+
+impl Credential {
+    /// Creates a reference to a [`Credential`] from a valid pointer.
+    ///
+    /// # Safety
+    ///
+    /// The caller must ensure that `ptr` is valid and remains valid for the lifetime of the
+    /// returned [`Credential`] reference.
+    pub(crate) unsafe fn from_ptr<'a>(ptr: *const bindings::cred) -> &'a Self {
+        // SAFETY: The safety requirements guarantee the validity of the dereference, while the
+        // `Credential` type being transparent makes the cast ok.
+        unsafe { &*ptr.cast() }
+    }
+}
+
+// SAFETY: The type invariants guarantee that `Credential` is always ref-counted.
+unsafe impl AlwaysRefCounted for Credential {
+    fn inc_ref(&self) {
+        // SAFETY: The existence of a shared reference means that the refcount is nonzero.
+        unsafe { bindings::get_cred(self.0.get()) };
+    }
+
+    unsafe fn dec_ref(obj: core::ptr::NonNull<Self>) {
+        // SAFETY: The safety requirements guarantee that the refcount is nonzero.
+        unsafe { bindings::put_cred(obj.cast().as_ptr()) };
+    }
+}
diff --git a/rust/kernel/device.rs b/rust/kernel/device.rs
new file mode 100644
index 000000000000..236d278f5576
--- /dev/null
+++ b/rust/kernel/device.rs
@@ -0,0 +1,546 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Generic devices that are part of the kernel's driver model.
+//!
+//! C header: [`include/linux/device.h`](../../../../include/linux/device.h)
+
+#[cfg(CONFIG_COMMON_CLK)]
+use crate::{clk::Clk, error::from_kernel_err_ptr};
+
+use crate::{
+    bindings,
+    revocable::{Revocable, RevocableGuard},
+    str::CStr,
+    sync::{NeedsLockClass, RevocableMutex, RevocableMutexGuard, UniqueRef},
+    Result,
+};
+use core::{
+    fmt,
+    ops::{Deref, DerefMut},
+    pin::Pin,
+};
+
+#[cfg(CONFIG_PRINTK)]
+use crate::{c_str, c_types};
+
+/// A raw device.
+///
+/// # Safety
+///
+/// Implementers must ensure that the `*mut device` returned by [`RawDevice::raw_device`] is
+/// related to `self`, that is, actions on it will affect `self`. For example, if one calls
+/// `get_device`, then the refcount on the device represented by `self` will be incremented.
+///
+/// Additionally, implementers must ensure that the device is never renamed. Commit a5462516aa994
+/// has details on why `device_rename` should not be used.
+pub unsafe trait RawDevice {
+    /// Returns the raw `struct device` related to `self`.
+    fn raw_device(&self) -> *mut bindings::device;
+
+    /// Returns the name of the device.
+    fn name(&self) -> &CStr {
+        let ptr = self.raw_device();
+
+        // SAFETY: `ptr` is valid because `self` keeps it alive.
+        let name = unsafe { bindings::dev_name(ptr) };
+
+        // SAFETY: The name of the device remains valid while it is alive (because the device is
+        // never renamed, per the safety requirement of this trait). This is guaranteed to be the
+        // case because the reference to `self` outlives the one of the returned `CStr` (enforced
+        // by the compiler because of their lifetimes).
+        unsafe { CStr::from_char_ptr(name) }
+    }
+
+    /// Lookups a clock producer consumed by this device.
+    ///
+    /// Returns a managed reference to the clock producer.
+    #[cfg(CONFIG_COMMON_CLK)]
+    fn clk_get(&self, id: Option<&CStr>) -> Result<Clk> {
+        let id_ptr = match id {
+            Some(cstr) => cstr.as_char_ptr(),
+            None => core::ptr::null(),
+        };
+
+        // SAFETY: `id_ptr` is optional and may be either a valid pointer
+        // from the type invariant or NULL otherwise.
+        let clk_ptr = unsafe { from_kernel_err_ptr(bindings::clk_get(self.raw_device(), id_ptr)) }?;
+
+        // SAFETY: Clock is initialized with valid pointer returned from `bindings::clk_get` call.
+        unsafe { Ok(Clk::new(clk_ptr)) }
+    }
+
+    /// Prints an emergency-level message (level 0) prefixed with device information.
+    ///
+    /// More details are available from [`dev_emerg`].
+    fn pr_emerg(&self, args: fmt::Arguments<'_>) {
+        // SAFETY: `klevel` is null-terminated, uses one of the kernel constants.
+        unsafe { self.printk(bindings::KERN_EMERG, args) };
+    }
+
+    /// Prints an alert-level message (level 1) prefixed with device information.
+    ///
+    /// More details are available from [`dev_alert`].
+    fn pr_alert(&self, args: fmt::Arguments<'_>) {
+        // SAFETY: `klevel` is null-terminated, uses one of the kernel constants.
+        unsafe { self.printk(bindings::KERN_ALERT, args) };
+    }
+
+    /// Prints a critical-level message (level 2) prefixed with device information.
+    ///
+    /// More details are available from [`dev_crit`].
+    fn pr_crit(&self, args: fmt::Arguments<'_>) {
+        // SAFETY: `klevel` is null-terminated, uses one of the kernel constants.
+        unsafe { self.printk(bindings::KERN_CRIT, args) };
+    }
+
+    /// Prints an error-level message (level 3) prefixed with device information.
+    ///
+    /// More details are available from [`dev_err`].
+    fn pr_err(&self, args: fmt::Arguments<'_>) {
+        // SAFETY: `klevel` is null-terminated, uses one of the kernel constants.
+        unsafe { self.printk(bindings::KERN_ERR, args) };
+    }
+
+    /// Prints a warning-level message (level 4) prefixed with device information.
+    ///
+    /// More details are available from [`dev_warn`].
+    fn pr_warn(&self, args: fmt::Arguments<'_>) {
+        // SAFETY: `klevel` is null-terminated, uses one of the kernel constants.
+        unsafe { self.printk(bindings::KERN_WARNING, args) };
+    }
+
+    /// Prints a notice-level message (level 5) prefixed with device information.
+    ///
+    /// More details are available from [`dev_notice`].
+    fn pr_notice(&self, args: fmt::Arguments<'_>) {
+        // SAFETY: `klevel` is null-terminated, uses one of the kernel constants.
+        unsafe { self.printk(bindings::KERN_NOTICE, args) };
+    }
+
+    /// Prints an info-level message (level 6) prefixed with device information.
+    ///
+    /// More details are available from [`dev_info`].
+    fn pr_info(&self, args: fmt::Arguments<'_>) {
+        // SAFETY: `klevel` is null-terminated, uses one of the kernel constants.
+        unsafe { self.printk(bindings::KERN_INFO, args) };
+    }
+
+    /// Prints a debug-level message (level 7) prefixed with device information.
+    ///
+    /// More details are available from [`dev_dbg`].
+    fn pr_dbg(&self, args: fmt::Arguments<'_>) {
+        if cfg!(debug_assertions) {
+            // SAFETY: `klevel` is null-terminated, uses one of the kernel constants.
+            unsafe { self.printk(bindings::KERN_DEBUG, args) };
+        }
+    }
+
+    /// Prints the provided message to the console.
+    ///
+    /// # Safety
+    ///
+    /// Callers must ensure that `klevel` is null-terminated; in particular, one of the
+    /// `KERN_*`constants, for example, `KERN_CRIT`, `KERN_ALERT`, etc.
+    #[cfg_attr(not(CONFIG_PRINTK), allow(unused_variables))]
+    unsafe fn printk(&self, klevel: &[u8], msg: fmt::Arguments<'_>) {
+        // SAFETY: `klevel` is null-terminated and one of the kernel constants. `self.raw_device`
+        // is valid because `self` is valid. The "%pA" format string expects a pointer to
+        // `fmt::Arguments`, which is what we're passing as the last argument.
+        #[cfg(CONFIG_PRINTK)]
+        unsafe {
+            bindings::_dev_printk(
+                klevel as *const _ as *const c_types::c_char,
+                self.raw_device(),
+                c_str!("%pA").as_char_ptr(),
+                &msg as *const _ as *const c_types::c_void,
+            )
+        };
+    }
+}
+
+/// A ref-counted device.
+///
+/// # Invariants
+///
+/// `ptr` is valid, non-null, and has a non-zero reference count. One of the references is owned by
+/// `self`, and will be decremented when `self` is dropped.
+pub struct Device {
+    pub(crate) ptr: *mut bindings::device,
+}
+
+// SAFETY: `Device` only holds a pointer to a C device, which is safe to be used from any thread.
+unsafe impl Send for Device {}
+
+// SAFETY: `Device` only holds a pointer to a C device, references to which are safe to be used
+// from any thread.
+unsafe impl Sync for Device {}
+
+impl Device {
+    /// Creates a new device instance.
+    ///
+    /// # Safety
+    ///
+    /// Callers must ensure that `ptr` is valid, non-null, and has a non-zero reference count.
+    pub unsafe fn new(ptr: *mut bindings::device) -> Self {
+        // SAFETY: By the safety requirements, ptr is valid and its refcounted will be incremented.
+        unsafe { bindings::get_device(ptr) };
+        // INVARIANT: The safety requirements satisfy all but one invariant, which is that `self`
+        // owns a reference. This is satisfied by the call to `get_device` above.
+        Self { ptr }
+    }
+
+    /// Creates a new device instance from an existing [`RawDevice`] instance.
+    pub fn from_dev(dev: &dyn RawDevice) -> Self {
+        // SAFETY: The requirements are satisfied by the existence of `RawDevice` and its safety
+        // requirements.
+        unsafe { Self::new(dev.raw_device()) }
+    }
+}
+
+// SAFETY: The device returned by `raw_device` is the one for which we hold a reference.
+unsafe impl RawDevice for Device {
+    fn raw_device(&self) -> *mut bindings::device {
+        self.ptr
+    }
+}
+
+impl Drop for Device {
+    fn drop(&mut self) {
+        // SAFETY: By the type invariants, we know that `self` owns a reference, so it is safe to
+        // relinquish it now.
+        unsafe { bindings::put_device(self.ptr) };
+    }
+}
+
+/// Device data.
+///
+/// When a device is removed (for whatever reason, for example, because the device was unplugged or
+/// because the user decided to unbind the driver), the driver is given a chance to clean its state
+/// up, and all io resources should ideally not be used anymore.
+///
+/// However, the device data is reference-counted because other subsystems hold pointers to it. So
+/// some device state must be freed and not used anymore, while others must remain accessible.
+///
+/// This struct separates the device data into three categories:
+///   1. Registrations: are destroyed when the device is removed, but before the io resources
+///      become inaccessible.
+///   2. Io resources: are available until the device is removed.
+///   3. General data: remain available as long as the ref count is nonzero.
+///
+/// This struct implements the `DeviceRemoval` trait so that it can clean resources up even if not
+/// explicitly called by the device drivers.
+pub struct Data<T, U, V> {
+    registrations: RevocableMutex<T>,
+    resources: Revocable<U>,
+    general: V,
+}
+
+/// Safely creates an new reference-counted instance of [`Data`].
+#[doc(hidden)]
+#[macro_export]
+macro_rules! new_device_data {
+    ($reg:expr, $res:expr, $gen:expr, $name:literal) => {{
+        static mut CLASS1: core::mem::MaybeUninit<$crate::bindings::lock_class_key> =
+            core::mem::MaybeUninit::uninit();
+        static mut CLASS2: core::mem::MaybeUninit<$crate::bindings::lock_class_key> =
+            core::mem::MaybeUninit::uninit();
+        let regs = $reg;
+        let res = $res;
+        let gen = $gen;
+        let name = $crate::c_str!($name);
+        // SAFETY: `CLASS1` and `CLASS2` are never used by Rust code directly; the C portion of the
+        // kernel may change it though.
+        unsafe {
+            $crate::device::Data::try_new(
+                regs,
+                res,
+                gen,
+                name,
+                CLASS1.as_mut_ptr(),
+                CLASS2.as_mut_ptr(),
+            )
+        }
+    }};
+}
+
+impl<T, U, V> Data<T, U, V> {
+    /// Creates a new instance of `Data`.
+    ///
+    /// It is recommended that the [`new_device_data`] macro be used as it automatically creates
+    /// the lock classes.
+    ///
+    /// # Safety
+    ///
+    /// `key1` and `key2` must point to valid memory locations and remain valid until `self` is
+    /// dropped.
+    pub unsafe fn try_new(
+        registrations: T,
+        resources: U,
+        general: V,
+        name: &'static CStr,
+        key1: *mut bindings::lock_class_key,
+        key2: *mut bindings::lock_class_key,
+    ) -> Result<Pin<UniqueRef<Self>>> {
+        let mut ret = Pin::from(UniqueRef::try_new(Self {
+            // SAFETY: We call `RevocableMutex::init` below.
+            registrations: unsafe { RevocableMutex::new(registrations) },
+            resources: Revocable::new(resources),
+            general,
+        })?);
+
+        // SAFETY: `Data::registrations` is pinned when `Data` is.
+        let pinned = unsafe { ret.as_mut().map_unchecked_mut(|d| &mut d.registrations) };
+
+        // SAFETY: The safety requirements of this function satisfy those of `RevocableMutex::init`.
+        unsafe { pinned.init(name, key1, key2) };
+        Ok(ret)
+    }
+
+    /// Returns the resources if they're still available.
+    pub fn resources(&self) -> Option<RevocableGuard<'_, U>> {
+        self.resources.try_access()
+    }
+
+    /// Returns the locked registrations if they're still available.
+    pub fn registrations(&self) -> Option<RevocableMutexGuard<'_, T>> {
+        self.registrations.try_write()
+    }
+}
+
+impl<T, U, V> crate::driver::DeviceRemoval for Data<T, U, V> {
+    fn device_remove(&self) {
+        // We revoke the registrations first so that resources are still available to them during
+        // unregistration.
+        self.registrations.revoke();
+
+        // Release resources now. General data remains available.
+        self.resources.revoke();
+    }
+}
+
+impl<T, U, V> Deref for Data<T, U, V> {
+    type Target = V;
+
+    fn deref(&self) -> &V {
+        &self.general
+    }
+}
+
+impl<T, U, V> DerefMut for Data<T, U, V> {
+    fn deref_mut(&mut self) -> &mut V {
+        &mut self.general
+    }
+}
+
+#[doc(hidden)]
+#[macro_export]
+macro_rules! dev_printk {
+    ($method:ident, $dev:expr, $($f:tt)*) => {
+        {
+            // We have an explicity `use` statement here so that callers of this macro are not
+            // required to explicitly use the `RawDevice` trait to use its functions.
+            use $crate::device::RawDevice;
+            ($dev).$method(core::format_args!($($f)*));
+        }
+    }
+}
+
+/// Prints an emergency-level message (level 0) prefixed with device information.
+///
+/// This level should be used if the system is unusable.
+///
+/// Equivalent to the kernel's `dev_emerg` macro.
+///
+/// Mimics the interface of [`std::print!`]. More information about the syntax is available from
+/// [`core::fmt`] and [`alloc::format!`].
+///
+/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::device::Device;
+///
+/// fn example(dev: &Device) {
+///     dev_emerg!(dev, "hello {}\n", "there");
+/// }
+/// ```
+#[macro_export]
+macro_rules! dev_emerg {
+    ($($f:tt)*) => { $crate::dev_printk!(pr_emerg, $($f)*); }
+}
+
+/// Prints an alert-level message (level 1) prefixed with device information.
+///
+/// This level should be used if action must be taken immediately.
+///
+/// Equivalent to the kernel's `dev_alert` macro.
+///
+/// Mimics the interface of [`std::print!`]. More information about the syntax is available from
+/// [`core::fmt`] and [`alloc::format!`].
+///
+/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::device::Device;
+///
+/// fn example(dev: &Device) {
+///     dev_alert!(dev, "hello {}\n", "there");
+/// }
+/// ```
+#[macro_export]
+macro_rules! dev_alert {
+    ($($f:tt)*) => { $crate::dev_printk!(pr_alert, $($f)*); }
+}
+
+/// Prints a critical-level message (level 2) prefixed with device information.
+///
+/// This level should be used in critical conditions.
+///
+/// Equivalent to the kernel's `dev_crit` macro.
+///
+/// Mimics the interface of [`std::print!`]. More information about the syntax is available from
+/// [`core::fmt`] and [`alloc::format!`].
+///
+/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::device::Device;
+///
+/// fn example(dev: &Device) {
+///     dev_crit!(dev, "hello {}\n", "there");
+/// }
+/// ```
+#[macro_export]
+macro_rules! dev_crit {
+    ($($f:tt)*) => { $crate::dev_printk!(pr_crit, $($f)*); }
+}
+
+/// Prints an error-level message (level 3) prefixed with device information.
+///
+/// This level should be used in error conditions.
+///
+/// Equivalent to the kernel's `dev_err` macro.
+///
+/// Mimics the interface of [`std::print!`]. More information about the syntax is available from
+/// [`core::fmt`] and [`alloc::format!`].
+///
+/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::device::Device;
+///
+/// fn example(dev: &Device) {
+///     dev_err!(dev, "hello {}\n", "there");
+/// }
+/// ```
+#[macro_export]
+macro_rules! dev_err {
+    ($($f:tt)*) => { $crate::dev_printk!(pr_err, $($f)*); }
+}
+
+/// Prints a warning-level message (level 4) prefixed with device information.
+///
+/// This level should be used in warning conditions.
+///
+/// Equivalent to the kernel's `dev_warn` macro.
+///
+/// Mimics the interface of [`std::print!`]. More information about the syntax is available from
+/// [`core::fmt`] and [`alloc::format!`].
+///
+/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::device::Device;
+///
+/// fn example(dev: &Device) {
+///     dev_warn!(dev, "hello {}\n", "there");
+/// }
+/// ```
+#[macro_export]
+macro_rules! dev_warn {
+    ($($f:tt)*) => { $crate::dev_printk!(pr_warn, $($f)*); }
+}
+
+/// Prints a notice-level message (level 5) prefixed with device information.
+///
+/// This level should be used in normal but significant conditions.
+///
+/// Equivalent to the kernel's `dev_notice` macro.
+///
+/// Mimics the interface of [`std::print!`]. More information about the syntax is available from
+/// [`core::fmt`] and [`alloc::format!`].
+///
+/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::device::Device;
+///
+/// fn example(dev: &Device) {
+///     dev_notice!(dev, "hello {}\n", "there");
+/// }
+/// ```
+#[macro_export]
+macro_rules! dev_notice {
+    ($($f:tt)*) => { $crate::dev_printk!(pr_notice, $($f)*); }
+}
+
+/// Prints an info-level message (level 6) prefixed with device information.
+///
+/// This level should be used for informational messages.
+///
+/// Equivalent to the kernel's `dev_info` macro.
+///
+/// Mimics the interface of [`std::print!`]. More information about the syntax is available from
+/// [`core::fmt`] and [`alloc::format!`].
+///
+/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::device::Device;
+///
+/// fn example(dev: &Device) {
+///     dev_info!(dev, "hello {}\n", "there");
+/// }
+/// ```
+#[macro_export]
+macro_rules! dev_info {
+    ($($f:tt)*) => { $crate::dev_printk!(pr_info, $($f)*); }
+}
+
+/// Prints a debug-level message (level 7) prefixed with device information.
+///
+/// This level should be used for debug messages.
+///
+/// Equivalent to the kernel's `dev_dbg` macro, except that it doesn't support dynamic debug yet.
+///
+/// Mimics the interface of [`std::print!`]. More information about the syntax is available from
+/// [`core::fmt`] and [`alloc::format!`].
+///
+/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::device::Device;
+///
+/// fn example(dev: &Device) {
+///     dev_dbg!(dev, "hello {}\n", "there");
+/// }
+/// ```
+#[macro_export]
+macro_rules! dev_dbg {
+    ($($f:tt)*) => { $crate::dev_printk!(pr_dbg, $($f)*); }
+}
diff --git a/rust/kernel/driver.rs b/rust/kernel/driver.rs
new file mode 100644
index 000000000000..0ae9f4d3dbc5
--- /dev/null
+++ b/rust/kernel/driver.rs
@@ -0,0 +1,442 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Generic support for drivers of different buses (e.g., PCI, Platform, Amba, etc.).
+//!
+//! Each bus/subsystem is expected to implement [`DriverOps`], which allows drivers to register
+//! using the [`Registration`] class.
+
+use crate::{error::code::*, str::CStr, sync::Ref, Result, ThisModule};
+use alloc::boxed::Box;
+use core::{cell::UnsafeCell, marker::PhantomData, ops::Deref, pin::Pin};
+
+/// A subsystem (e.g., PCI, Platform, Amba, etc.) that allows drivers to be written for it.
+pub trait DriverOps {
+    /// The type that holds information about the registration. This is typically a struct defined
+    /// by the C portion of the kernel.
+    type RegType: Default;
+
+    /// Registers a driver.
+    ///
+    /// # Safety
+    ///
+    /// `reg` must point to valid, initialised, and writable memory. It may be modified by this
+    /// function to hold registration state.
+    ///
+    /// On success, `reg` must remain pinned and valid until the matching call to
+    /// [`DriverOps::unregister`].
+    unsafe fn register(
+        reg: *mut Self::RegType,
+        name: &'static CStr,
+        module: &'static ThisModule,
+    ) -> Result;
+
+    /// Unregisters a driver previously registered with [`DriverOps::register`].
+    ///
+    /// # Safety
+    ///
+    /// `reg` must point to valid writable memory, initialised by a previous successful call to
+    /// [`DriverOps::register`].
+    unsafe fn unregister(reg: *mut Self::RegType);
+}
+
+/// The registration of a driver.
+pub struct Registration<T: DriverOps> {
+    is_registered: bool,
+    concrete_reg: UnsafeCell<T::RegType>,
+}
+
+// SAFETY: `Registration` has no fields or methods accessible via `&Registration`, so it is safe to
+// share references to it with multiple threads as nothing can be done.
+unsafe impl<T: DriverOps> Sync for Registration<T> {}
+
+impl<T: DriverOps> Registration<T> {
+    /// Creates a new instance of the registration object.
+    pub fn new() -> Self {
+        Self {
+            is_registered: false,
+            concrete_reg: UnsafeCell::new(T::RegType::default()),
+        }
+    }
+
+    /// Allocates a pinned registration object and registers it.
+    ///
+    /// Returns a pinned heap-allocated representation of the registration.
+    pub fn new_pinned(name: &'static CStr, module: &'static ThisModule) -> Result<Pin<Box<Self>>> {
+        let mut reg = Pin::from(Box::try_new(Self::new())?);
+        reg.as_mut().register(name, module)?;
+        Ok(reg)
+    }
+
+    /// Registers a driver with its subsystem.
+    ///
+    /// It must be pinned because the memory block that represents the registration is potentially
+    /// self-referential.
+    pub fn register(
+        self: Pin<&mut Self>,
+        name: &'static CStr,
+        module: &'static ThisModule,
+    ) -> Result {
+        // SAFETY: We never move out of `this`.
+        let this = unsafe { self.get_unchecked_mut() };
+        if this.is_registered {
+            // Already registered.
+            return Err(EINVAL);
+        }
+
+        // SAFETY: `concrete_reg` was initialised via its default constructor. It is only freed
+        // after `Self::drop` is called, which first calls `T::unregister`.
+        unsafe { T::register(this.concrete_reg.get(), name, module) }?;
+
+        this.is_registered = true;
+        Ok(())
+    }
+}
+
+impl<T: DriverOps> Default for Registration<T> {
+    fn default() -> Self {
+        Self::new()
+    }
+}
+
+impl<T: DriverOps> Drop for Registration<T> {
+    fn drop(&mut self) {
+        if self.is_registered {
+            // SAFETY: This path only runs if a previous call to `T::register` completed
+            // successfully.
+            unsafe { T::unregister(self.concrete_reg.get()) };
+        }
+    }
+}
+
+/// Conversion from a device id to a raw device id.
+///
+/// This is meant to be implemented by buses/subsystems so that they can use [`IdTable`] to
+/// guarantee (at compile-time) zero-termination of device id tables provided by drivers.
+///
+/// # Safety
+///
+/// Implementers must ensure that:
+///   - [`RawDeviceId::ZERO`] is actually a zeroed-out version of the raw device id.
+///   - [`RawDeviceId::to_rawid`] stores `offset` in the context/data field of the raw device id so
+///     that buses can recover the pointer to the data.
+pub unsafe trait RawDeviceId {
+    /// The raw type that holds the device id.
+    ///
+    /// Id tables created from [`Self`] are going to hold this type in its zero-terminated array.
+    type RawType: Copy;
+
+    /// A zeroed-out representation of the raw device id.
+    ///
+    /// Id tables created from [`Self`] use [`Self::ZERO`] as the sentinel to indicate the end of
+    /// the table.
+    const ZERO: Self::RawType;
+
+    /// Converts an id into a raw id.
+    ///
+    /// `offset` is the offset from the memory location where the raw device id is stored to the
+    /// location where its associated context information is stored. Implementations must store
+    /// this in the appropriate context/data field of the raw type.
+    fn to_rawid(&self, offset: isize) -> Self::RawType;
+}
+
+/// A zero-terminated device id array, followed by context data.
+#[repr(C)]
+pub struct IdArray<T: RawDeviceId, U, const N: usize> {
+    ids: [T::RawType; N],
+    sentinel: T::RawType,
+    id_infos: [Option<U>; N],
+}
+
+impl<T: RawDeviceId, U, const N: usize> IdArray<T, U, N> {
+    /// Creates a new instance of the array.
+    ///
+    /// The contents are derived from the given identifiers and context information.
+    pub const fn new(ids: [T; N], infos: [Option<U>; N]) -> Self
+    where
+        T: ~const RawDeviceId + Copy,
+    {
+        let mut array = Self {
+            ids: [T::ZERO; N],
+            sentinel: T::ZERO,
+            id_infos: infos,
+        };
+        let mut i = 0usize;
+        while i < N {
+            // SAFETY: Both pointers are within `array` (or one byte beyond), consequently they are
+            // derived from the same allocated object. We are using a `u8` pointer, whose size 1,
+            // so the pointers are necessarily 1-byte aligned.
+            let offset = unsafe {
+                (&array.id_infos[i] as *const _ as *const u8)
+                    .offset_from(&array.ids[i] as *const _ as _)
+            };
+            array.ids[i] = ids[i].to_rawid(offset);
+            i += 1;
+        }
+        array
+    }
+
+    /// Returns an `IdTable` backed by `self`.
+    ///
+    /// This is used to essentially erase the array size.
+    pub const fn as_table(&self) -> IdTable<'_, T, U> {
+        IdTable {
+            first: &self.ids[0],
+            _p: PhantomData,
+        }
+    }
+}
+
+/// A device id table.
+///
+/// The table is guaranteed to be zero-terminated and to be followed by an array of context data of
+/// type `Option<U>`.
+pub struct IdTable<'a, T: RawDeviceId, U> {
+    first: &'a T::RawType,
+    _p: PhantomData<&'a U>,
+}
+
+impl<T: RawDeviceId, U> const AsRef<T::RawType> for IdTable<'_, T, U> {
+    fn as_ref(&self) -> &T::RawType {
+        self.first
+    }
+}
+
+/// Counts the number of parenthesis-delimited, comma-separated items.
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::count_paren_items;
+///
+/// assert_eq!(0, count_paren_items!());
+/// assert_eq!(1, count_paren_items!((A)));
+/// assert_eq!(1, count_paren_items!((A),));
+/// assert_eq!(2, count_paren_items!((A), (B)));
+/// assert_eq!(2, count_paren_items!((A), (B),));
+/// assert_eq!(3, count_paren_items!((A), (B), (C)));
+/// assert_eq!(3, count_paren_items!((A), (B), (C),));
+/// ```
+#[macro_export]
+macro_rules! count_paren_items {
+    (($($item:tt)*), $($remaining:tt)*) => { 1 + $crate::count_paren_items!($($remaining)*) };
+    (($($item:tt)*)) => { 1 };
+    () => { 0 };
+}
+
+/// Converts a comma-separated list of pairs into an array with the first element. That is, it
+/// discards the second element of the pair.
+///
+/// Additionally, it automatically introduces a type if the first element is warpped in curly
+/// braces, for example, if it's `{v: 10}`, it becomes `X { v: 10 }`; this is to avoid repeating
+/// the type.
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::first_item;
+///
+/// #[derive(PartialEq, Debug)]
+/// struct X {
+///     v: u32,
+/// }
+///
+/// assert_eq!([] as [X; 0], first_item!(X, ));
+/// assert_eq!([X { v: 10 }], first_item!(X, ({ v: 10 }, Y)));
+/// assert_eq!([X { v: 10 }], first_item!(X, ({ v: 10 }, Y),));
+/// assert_eq!([X { v: 10 }], first_item!(X, (X { v: 10 }, Y)));
+/// assert_eq!([X { v: 10 }], first_item!(X, (X { v: 10 }, Y),));
+/// assert_eq!([X { v: 10 }, X { v: 20 }], first_item!(X, ({ v: 10 }, Y), ({ v: 20 }, Y)));
+/// assert_eq!([X { v: 10 }, X { v: 20 }], first_item!(X, ({ v: 10 }, Y), ({ v: 20 }, Y),));
+/// assert_eq!([X { v: 10 }, X { v: 20 }], first_item!(X, (X { v: 10 }, Y), (X { v: 20 }, Y)));
+/// assert_eq!([X { v: 10 }, X { v: 20 }], first_item!(X, (X { v: 10 }, Y), (X { v: 20 }, Y),));
+/// assert_eq!([X { v: 10 }, X { v: 20 }, X { v: 30 }],
+///            first_item!(X, ({ v: 10 }, Y), ({ v: 20 }, Y), ({v: 30}, Y)));
+/// assert_eq!([X { v: 10 }, X { v: 20 }, X { v: 30 }],
+///            first_item!(X, ({ v: 10 }, Y), ({ v: 20 }, Y), ({v: 30}, Y),));
+/// assert_eq!([X { v: 10 }, X { v: 20 }, X { v: 30 }],
+///            first_item!(X, (X { v: 10 }, Y), (X { v: 20 }, Y), (X {v: 30}, Y)));
+/// assert_eq!([X { v: 10 }, X { v: 20 }, X { v: 30 }],
+///            first_item!(X, (X { v: 10 }, Y), (X { v: 20 }, Y), (X {v: 30}, Y),));
+/// ```
+#[macro_export]
+macro_rules! first_item {
+    ($id_type:ty, $(({$($first:tt)*}, $second:expr)),* $(,)?) => {
+        {
+            type IdType = $id_type;
+            [$(IdType{$($first)*},)*]
+        }
+    };
+    ($id_type:ty, $(($first:expr, $second:expr)),* $(,)?) => { [$($first,)*] };
+}
+
+/// Converts a comma-separated list of pairs into an array with the second element. That is, it
+/// discards the first element of the pair.
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::second_item;
+///
+/// assert_eq!([] as [u32; 0], second_item!());
+/// assert_eq!([10u32], second_item!((X, 10u32)));
+/// assert_eq!([10u32], second_item!((X, 10u32),));
+/// assert_eq!([10u32], second_item!(({X}, 10u32)));
+/// assert_eq!([10u32], second_item!(({X}, 10u32),));
+/// assert_eq!([10u32, 20], second_item!((X, 10u32), (X, 20)));
+/// assert_eq!([10u32, 20], second_item!((X, 10u32), (X, 20),));
+/// assert_eq!([10u32, 20], second_item!(({X}, 10u32), ({X}, 20)));
+/// assert_eq!([10u32, 20], second_item!(({X}, 10u32), ({X}, 20),));
+/// assert_eq!([10u32, 20, 30], second_item!((X, 10u32), (X, 20), (X, 30)));
+/// assert_eq!([10u32, 20, 30], second_item!((X, 10u32), (X, 20), (X, 30),));
+/// assert_eq!([10u32, 20, 30], second_item!(({X}, 10u32), ({X}, 20), ({X}, 30)));
+/// assert_eq!([10u32, 20, 30], second_item!(({X}, 10u32), ({X}, 20), ({X}, 30),));
+/// ```
+#[macro_export]
+macro_rules! second_item {
+    ($(({$($first:tt)*}, $second:expr)),* $(,)?) => { [$($second,)*] };
+    ($(($first:expr, $second:expr)),* $(,)?) => { [$($second,)*] };
+}
+
+/// Defines a new constant [`IdArray`] with a concise syntax.
+///
+/// It is meant to be used by buses and subsystems to create a similar macro with their device id
+/// type already specified, i.e., with fewer parameters to the end user.
+///
+/// # Examples
+///
+// TODO: Exported but not usable by kernel modules (requires `const_trait_impl`).
+/// ```ignore
+/// #![feature(const_trait_impl)]
+/// # use kernel::{define_id_array, driver::RawDeviceId};
+///
+/// #[derive(Copy, Clone)]
+/// struct Id(u32);
+///
+/// // SAFETY: `ZERO` is all zeroes and `to_rawid` stores `offset` as the second element of the raw
+/// // device id pair.
+/// unsafe impl const RawDeviceId for Id {
+///     type RawType = (u64, isize);
+///     const ZERO: Self::RawType = (0, 0);
+///     fn to_rawid(&self, offset: isize) -> Self::RawType {
+///         (self.0 as u64 + 1, offset)
+///     }
+/// }
+///
+/// define_id_array!(A1, Id, (), []);
+/// define_id_array!(A2, Id, &'static [u8], [(Id(10), None)]);
+/// define_id_array!(A3, Id, &'static [u8], [(Id(10), Some(b"id1")), ]);
+/// define_id_array!(A4, Id, &'static [u8], [(Id(10), Some(b"id1")), (Id(20), Some(b"id2"))]);
+/// define_id_array!(A5, Id, &'static [u8], [(Id(10), Some(b"id1")), (Id(20), Some(b"id2")), ]);
+/// define_id_array!(A6, Id, &'static [u8], [(Id(10), None), (Id(20), Some(b"id2")), ]);
+/// define_id_array!(A7, Id, &'static [u8], [(Id(10), Some(b"id1")), (Id(20), None), ]);
+/// define_id_array!(A8, Id, &'static [u8], [(Id(10), None), (Id(20), None), ]);
+/// ```
+#[macro_export]
+macro_rules! define_id_array {
+    ($table_name:ident, $id_type:ty, $data_type:ty, [ $($t:tt)* ]) => {
+        const $table_name:
+            $crate::driver::IdArray<$id_type, $data_type, { $crate::count_paren_items!($($t)*) }> =
+                $crate::driver::IdArray::new(
+                    $crate::first_item!($id_type, $($t)*), $crate::second_item!($($t)*));
+    };
+}
+
+/// Defines a new constant [`IdTable`] with a concise syntax.
+///
+/// It is meant to be used by buses and subsystems to create a similar macro with their device id
+/// type already specified, i.e., with fewer parameters to the end user.
+///
+/// # Examples
+///
+// TODO: Exported but not usable by kernel modules (requires `const_trait_impl`).
+/// ```ignore
+/// #![feature(const_trait_impl)]
+/// # use kernel::{define_id_table, driver::RawDeviceId};
+///
+/// #[derive(Copy, Clone)]
+/// struct Id(u32);
+///
+/// // SAFETY: `ZERO` is all zeroes and `to_rawid` stores `offset` as the second element of the raw
+/// // device id pair.
+/// unsafe impl const RawDeviceId for Id {
+///     type RawType = (u64, isize);
+///     const ZERO: Self::RawType = (0, 0);
+///     fn to_rawid(&self, offset: isize) -> Self::RawType {
+///         (self.0 as u64 + 1, offset)
+///     }
+/// }
+///
+/// define_id_table!(T1, Id, &'static [u8], [(Id(10), None)]);
+/// define_id_table!(T2, Id, &'static [u8], [(Id(10), Some(b"id1")), ]);
+/// define_id_table!(T3, Id, &'static [u8], [(Id(10), Some(b"id1")), (Id(20), Some(b"id2"))]);
+/// define_id_table!(T4, Id, &'static [u8], [(Id(10), Some(b"id1")), (Id(20), Some(b"id2")), ]);
+/// define_id_table!(T5, Id, &'static [u8], [(Id(10), None), (Id(20), Some(b"id2")), ]);
+/// define_id_table!(T6, Id, &'static [u8], [(Id(10), Some(b"id1")), (Id(20), None), ]);
+/// define_id_table!(T7, Id, &'static [u8], [(Id(10), None), (Id(20), None), ]);
+/// ```
+#[macro_export]
+macro_rules! define_id_table {
+    ($table_name:ident, $id_type:ty, $data_type:ty, [ $($t:tt)* ]) => {
+        const $table_name: Option<$crate::driver::IdTable<'static, $id_type, $data_type>> = {
+            $crate::define_id_array!(ARRAY, $id_type, $data_type, [ $($t)* ]);
+            Some(ARRAY.as_table())
+        };
+    };
+}
+
+/// Custom code within device removal.
+pub trait DeviceRemoval {
+    /// Cleans resources up when the device is removed.
+    ///
+    /// This is called when a device is removed and offers implementers the chance to run some code
+    /// that cleans state up.
+    fn device_remove(&self);
+}
+
+impl DeviceRemoval for () {
+    fn device_remove(&self) {}
+}
+
+impl<T: DeviceRemoval> DeviceRemoval for Ref<T> {
+    fn device_remove(&self) {
+        self.deref().device_remove();
+    }
+}
+
+impl<T: DeviceRemoval> DeviceRemoval for Box<T> {
+    fn device_remove(&self) {
+        self.deref().device_remove();
+    }
+}
+
+/// A kernel module that only registers the given driver on init.
+///
+/// This is a helper struct to make it easier to define single-functionality modules, in this case,
+/// modules that offer a single driver.
+pub struct Module<T: DriverOps> {
+    _driver: Pin<Box<Registration<T>>>,
+}
+
+impl<T: DriverOps> crate::Module for Module<T> {
+    fn init(name: &'static CStr, module: &'static ThisModule) -> Result<Self> {
+        Ok(Self {
+            _driver: Registration::new_pinned(name, module)?,
+        })
+    }
+}
+
+/// Declares a kernel module that exposes a single driver.
+///
+/// It is meant to be used as a helper by other subsystems so they can more easily expose their own
+/// macros.
+#[macro_export]
+macro_rules! module_driver {
+    (<$gen_type:ident>, $driver_ops:ty, { type: $type:ty, $($f:tt)* }) => {
+        type Ops<$gen_type> = $driver_ops;
+        type ModuleType = $crate::driver::Module<Ops<$type>>;
+        $crate::prelude::module! {
+            type: ModuleType,
+            $($f)*
+        }
+    }
+}
diff --git a/rust/kernel/error.rs b/rust/kernel/error.rs
new file mode 100644
index 000000000000..55029cf09a91
--- /dev/null
+++ b/rust/kernel/error.rs
@@ -0,0 +1,565 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Kernel errors.
+//!
+//! C header: [`include/uapi/asm-generic/errno-base.h`](../../../include/uapi/asm-generic/errno-base.h)
+
+use crate::str::CStr;
+use crate::{bindings, c_types};
+use alloc::{
+    alloc::{AllocError, LayoutError},
+    collections::TryReserveError,
+};
+use core::convert::From;
+use core::fmt;
+use core::num::TryFromIntError;
+use core::str::{self, Utf8Error};
+
+/// Contains the C-compatible error codes.
+pub mod code {
+    macro_rules! declare_err {
+        ($err:tt $(,)? $($doc:expr),+) => {
+            $(
+            #[doc = $doc]
+            )*
+            pub const $err: super::Error = super::Error(-(crate::bindings::$err as i32));
+        };
+    }
+
+    declare_err!(EPERM, "Operation not permitted.");
+
+    declare_err!(ENOENT, "No such file or directory.");
+
+    declare_err!(ESRCH, "No such process.");
+
+    declare_err!(EINTR, "Interrupted system call.");
+
+    declare_err!(EIO, "I/O error.");
+
+    declare_err!(ENXIO, "No such device or address.");
+
+    declare_err!(E2BIG, "Argument list too long.");
+
+    declare_err!(ENOEXEC, "Exec format error.");
+
+    declare_err!(EBADF, "Bad file number.");
+
+    declare_err!(ECHILD, "Exec format error.");
+
+    declare_err!(EAGAIN, "Try again.");
+
+    declare_err!(ENOMEM, "Out of memory.");
+
+    declare_err!(EACCES, "Permission denied.");
+
+    declare_err!(EFAULT, "Bad address.");
+
+    declare_err!(ENOTBLK, "Block device required.");
+
+    declare_err!(EBUSY, "Device or resource busy.");
+
+    declare_err!(EEXIST, "File exists.");
+
+    declare_err!(EXDEV, "Cross-device link.");
+
+    declare_err!(ENODEV, "No such device.");
+
+    declare_err!(ENOTDIR, "Not a directory.");
+
+    declare_err!(EISDIR, "Is a directory.");
+
+    declare_err!(EINVAL, "Invalid argument.");
+
+    declare_err!(ENFILE, "File table overflow.");
+
+    declare_err!(EMFILE, "Too many open files.");
+
+    declare_err!(ENOTTY, "Not a typewriter.");
+
+    declare_err!(ETXTBSY, "Text file busy.");
+
+    declare_err!(EFBIG, "File too large.");
+
+    declare_err!(ENOSPC, "No space left on device.");
+
+    declare_err!(ESPIPE, "Illegal seek.");
+
+    declare_err!(EROFS, "Read-only file system.");
+
+    declare_err!(EMLINK, "Too many links.");
+
+    declare_err!(EPIPE, "Broken pipe.");
+
+    declare_err!(EDOM, "Math argument out of domain of func.");
+
+    declare_err!(ERANGE, "Math result not representable.");
+
+    declare_err!(EDEADLK, "Resource deadlock would occur");
+
+    declare_err!(ENAMETOOLONG, "File name too long");
+
+    declare_err!(ENOLCK, "No record locks available");
+
+    declare_err!(
+        ENOSYS,
+        "Invalid system call number.",
+        "",
+        "This error code is special: arch syscall entry code will return",
+        "[`ENOSYS`] if users try to call a syscall that doesn't exist.",
+        "To keep failures of syscalls that really do exist distinguishable from",
+        "failures due to attempts to use a nonexistent syscall, syscall",
+        "implementations should refrain from returning [`ENOSYS`]."
+    );
+
+    declare_err!(ENOTEMPTY, "Directory not empty.");
+
+    declare_err!(ELOOP, "Too many symbolic links encountered.");
+
+    declare_err!(EWOULDBLOCK, "Operation would block.");
+
+    declare_err!(ENOMSG, "No message of desired type.");
+
+    declare_err!(EIDRM, "Identifier removed.");
+
+    declare_err!(ECHRNG, "Channel number out of range.");
+
+    declare_err!(EL2NSYNC, "Level 2 not synchronized.");
+
+    declare_err!(EL3HLT, "Level 3 halted.");
+
+    declare_err!(EL3RST, "Level 3 reset.");
+
+    declare_err!(ELNRNG, "Link number out of range.");
+
+    declare_err!(EUNATCH, "Protocol driver not attached.");
+
+    declare_err!(ENOCSI, "No CSI structure available.");
+
+    declare_err!(EL2HLT, "Level 2 halted.");
+
+    declare_err!(EBADE, "Invalid exchange.");
+
+    declare_err!(EBADR, "Invalid request descriptor.");
+
+    declare_err!(EXFULL, "Exchange full.");
+
+    declare_err!(ENOANO, "No anode.");
+
+    declare_err!(EBADRQC, "Invalid request code.");
+
+    declare_err!(EBADSLT, "Invalid slot.");
+
+    declare_err!(EDEADLOCK, "Resource deadlock would occur.");
+
+    declare_err!(EBFONT, "Bad font file format.");
+
+    declare_err!(ENOSTR, "Device not a stream.");
+
+    declare_err!(ENODATA, "No data available.");
+
+    declare_err!(ETIME, "Timer expired.");
+
+    declare_err!(ENOSR, "Out of streams resources.");
+
+    declare_err!(ENONET, "Machine is not on the network.");
+
+    declare_err!(ENOPKG, "Package not installed.");
+
+    declare_err!(EREMOTE, "Object is remote.");
+
+    declare_err!(ENOLINK, "Link has been severed.");
+
+    declare_err!(EADV, "Advertise error.");
+
+    declare_err!(ESRMNT, "Srmount error.");
+
+    declare_err!(ECOMM, "Communication error on send.");
+
+    declare_err!(EPROTO, "Protocol error.");
+
+    declare_err!(EMULTIHOP, "Multihop attempted.");
+
+    declare_err!(EDOTDOT, "RFS specific error.");
+
+    declare_err!(EBADMSG, "Not a data message.");
+
+    declare_err!(EOVERFLOW, "Value too large for defined data type.");
+
+    declare_err!(ENOTUNIQ, "Name not unique on network.");
+
+    declare_err!(EBADFD, "File descriptor in bad state.");
+
+    declare_err!(EREMCHG, "Remote address changed.");
+
+    declare_err!(ELIBACC, "Can not access a needed shared library.");
+
+    declare_err!(ELIBBAD, "Accessing a corrupted shared library.");
+
+    declare_err!(ELIBSCN, ".lib section in a.out corrupted.");
+
+    declare_err!(ELIBMAX, "Attempting to link in too many shared libraries.");
+
+    declare_err!(ELIBEXEC, "Cannot exec a shared library directly.");
+
+    declare_err!(EILSEQ, "Illegal byte sequence.");
+
+    declare_err!(ERESTART, "Interrupted system call should be restarted.");
+
+    declare_err!(ESTRPIPE, "Streams pipe error.");
+
+    declare_err!(EUSERS, "Too many users.");
+
+    declare_err!(ENOTSOCK, "Socket operation on non-socket.");
+
+    declare_err!(EDESTADDRREQ, "Destination address required.");
+
+    declare_err!(EMSGSIZE, "Message too long.");
+
+    declare_err!(EPROTOTYPE, "Protocol wrong type for socket.");
+
+    declare_err!(ENOPROTOOPT, "Protocol not available.");
+
+    declare_err!(EPROTONOSUPPORT, "Protocol not supported.");
+
+    declare_err!(ESOCKTNOSUPPORT, "Socket type not supported.");
+
+    declare_err!(EOPNOTSUPP, "Operation not supported on transport endpoint.");
+
+    declare_err!(EPFNOSUPPORT, "Protocol family not supported.");
+
+    declare_err!(EAFNOSUPPORT, "Address family not supported by protocol.");
+
+    declare_err!(EADDRINUSE, "Address already in use.");
+
+    declare_err!(EADDRNOTAVAIL, "Cannot assign requested address.");
+
+    declare_err!(ENETDOWN, "Network is down.");
+
+    declare_err!(ENETUNREACH, "Network is unreachable.");
+
+    declare_err!(ENETRESET, "Network dropped connection because of reset.");
+
+    declare_err!(ECONNABORTED, "Software caused connection abort.");
+
+    declare_err!(ECONNRESET, "Connection reset by peer.");
+
+    declare_err!(ENOBUFS, "No buffer space available.");
+
+    declare_err!(EISCONN, "Transport endpoint is already connected.");
+
+    declare_err!(ENOTCONN, "Transport endpoint is not connected.");
+
+    declare_err!(ESHUTDOWN, "Cannot send after transport endpoint shutdown.");
+
+    declare_err!(ETOOMANYREFS, "Too many references: cannot splice.");
+
+    declare_err!(ETIMEDOUT, "Connection timed out.");
+
+    declare_err!(ECONNREFUSED, "Connection refused.");
+
+    declare_err!(EHOSTDOWN, "Host is down.");
+
+    declare_err!(EHOSTUNREACH, "No route to host.");
+
+    declare_err!(EALREADY, "Operation already in progress.");
+
+    declare_err!(EINPROGRESS, "Operation now in progress.");
+
+    declare_err!(ESTALE, "Stale file handle.");
+
+    declare_err!(EUCLEAN, "Structure needs cleaning.");
+
+    declare_err!(ENOTNAM, "Not a XENIX named type file.");
+
+    declare_err!(ENAVAIL, "No XENIX semaphores available.");
+
+    declare_err!(EISNAM, "Is a named type file.");
+
+    declare_err!(EREMOTEIO, "Remote I/O error.");
+
+    declare_err!(EDQUOT, "Quota exceeded.");
+
+    declare_err!(ENOMEDIUM, "No medium found.");
+
+    declare_err!(EMEDIUMTYPE, "Wrong medium type.");
+
+    declare_err!(ECANCELED, "Operation Canceled.");
+
+    declare_err!(ENOKEY, "Required key not available.");
+
+    declare_err!(EKEYEXPIRED, "Key has expired.");
+
+    declare_err!(EKEYREVOKED, "Key has been revoked.");
+
+    declare_err!(EKEYREJECTED, "Key was rejected by service.");
+
+    declare_err!(EOWNERDEAD, "Owner died.", "", "For robust mutexes.");
+
+    declare_err!(ENOTRECOVERABLE, "State not recoverable.");
+
+    declare_err!(ERFKILL, "Operation not possible due to RF-kill.");
+
+    declare_err!(EHWPOISON, "Memory page has hardware error.");
+
+    declare_err!(ERESTARTSYS, "Restart the system call.");
+
+    declare_err!(ENOTSUPP, "Operation is not supported.");
+}
+
+/// Generic integer kernel error.
+///
+/// The kernel defines a set of integer generic error codes based on C and
+/// POSIX ones. These codes may have a more specific meaning in some contexts.
+///
+/// # Invariants
+///
+/// The value is a valid `errno` (i.e. `>= -MAX_ERRNO && < 0`).
+#[derive(Clone, Copy, PartialEq, Eq)]
+pub struct Error(c_types::c_int);
+
+impl Error {
+    /// Creates an [`Error`] from a kernel error code.
+    ///
+    /// It is a bug to pass an out-of-range `errno`. `EINVAL` would
+    /// be returned in such a case.
+    pub(crate) fn from_kernel_errno(errno: c_types::c_int) -> Error {
+        if errno < -(bindings::MAX_ERRNO as i32) || errno >= 0 {
+            // TODO: Make it a `WARN_ONCE` once available.
+            crate::pr_warn!(
+                "attempted to create `Error` with out of range `errno`: {}",
+                errno
+            );
+            return code::EINVAL;
+        }
+
+        // INVARIANT: The check above ensures the type invariant
+        // will hold.
+        Error(errno)
+    }
+
+    /// Creates an [`Error`] from a kernel error code.
+    ///
+    /// # Safety
+    ///
+    /// `errno` must be within error code range (i.e. `>= -MAX_ERRNO && < 0`).
+    pub(crate) unsafe fn from_kernel_errno_unchecked(errno: c_types::c_int) -> Error {
+        // INVARIANT: The contract ensures the type invariant
+        // will hold.
+        Error(errno)
+    }
+
+    /// Returns the kernel error code.
+    pub fn to_kernel_errno(self) -> c_types::c_int {
+        self.0
+    }
+
+    /// Returns a string representing the error, if one exists.
+    #[cfg(not(testlib))]
+    pub fn name(&self) -> Option<&'static CStr> {
+        // SAFETY: Just an FFI call, there are no extra safety requirements.
+        let ptr = unsafe { bindings::errname(-self.0) };
+        if ptr.is_null() {
+            None
+        } else {
+            // SAFETY: The string returned by `errname` is static and `NUL`-terminated.
+            Some(unsafe { CStr::from_char_ptr(ptr) })
+        }
+    }
+
+    /// Returns a string representing the error, if one exists.
+    ///
+    /// When `testlib` is configured, this always returns `None` to avoid the dependency on a
+    /// kernel function so that tests that use this (e.g., by calling [`Result::unwrap`]) can still
+    /// run in userspace.
+    #[cfg(testlib)]
+    pub fn name(&self) -> Option<&'static CStr> {
+        None
+    }
+}
+
+impl fmt::Debug for Error {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match self.name() {
+            // Print out number if no name can be found.
+            None => f.debug_tuple("Error").field(&-self.0).finish(),
+            // SAFETY: These strings are ASCII-only.
+            Some(name) => f
+                .debug_tuple(unsafe { str::from_utf8_unchecked(name) })
+                .finish(),
+        }
+    }
+}
+
+impl From<TryFromIntError> for Error {
+    fn from(_: TryFromIntError) -> Error {
+        code::EINVAL
+    }
+}
+
+impl From<Utf8Error> for Error {
+    fn from(_: Utf8Error) -> Error {
+        code::EINVAL
+    }
+}
+
+impl From<TryReserveError> for Error {
+    fn from(_: TryReserveError) -> Error {
+        code::ENOMEM
+    }
+}
+
+impl From<LayoutError> for Error {
+    fn from(_: LayoutError) -> Error {
+        code::ENOMEM
+    }
+}
+
+impl From<core::fmt::Error> for Error {
+    fn from(_: core::fmt::Error) -> Error {
+        code::EINVAL
+    }
+}
+
+impl From<core::convert::Infallible> for Error {
+    fn from(e: core::convert::Infallible) -> Error {
+        match e {}
+    }
+}
+
+/// A [`Result`] with an [`Error`] error type.
+///
+/// To be used as the return type for functions that may fail.
+///
+/// # Error codes in C and Rust
+///
+/// In C, it is common that functions indicate success or failure through
+/// their return value; modifying or returning extra data through non-`const`
+/// pointer parameters. In particular, in the kernel, functions that may fail
+/// typically return an `int` that represents a generic error code. We model
+/// those as [`Error`].
+///
+/// In Rust, it is idiomatic to model functions that may fail as returning
+/// a [`Result`]. Since in the kernel many functions return an error code,
+/// [`Result`] is a type alias for a [`core::result::Result`] that uses
+/// [`Error`] as its error type.
+///
+/// Note that even if a function does not return anything when it succeeds,
+/// it should still be modeled as returning a `Result` rather than
+/// just an [`Error`].
+pub type Result<T = ()> = core::result::Result<T, Error>;
+
+impl From<AllocError> for Error {
+    fn from(_: AllocError) -> Error {
+        code::ENOMEM
+    }
+}
+
+// # Invariant: `-bindings::MAX_ERRNO` fits in an `i16`.
+crate::static_assert!(bindings::MAX_ERRNO <= -(i16::MIN as i32) as u32);
+
+pub(crate) fn from_kernel_result_helper<T>(r: Result<T>) -> T
+where
+    T: From<i16>,
+{
+    match r {
+        Ok(v) => v,
+        // NO-OVERFLOW: negative `errno`s are no smaller than `-bindings::MAX_ERRNO`,
+        // `-bindings::MAX_ERRNO` fits in an `i16` as per invariant above,
+        // therefore a negative `errno` always fits in an `i16` and will not overflow.
+        Err(e) => T::from(e.to_kernel_errno() as i16),
+    }
+}
+
+/// Transforms a [`crate::error::Result<T>`] to a kernel C integer result.
+///
+/// This is useful when calling Rust functions that return [`crate::error::Result<T>`]
+/// from inside `extern "C"` functions that need to return an integer
+/// error result.
+///
+/// `T` should be convertible to an `i16` via `From<i16>`.
+///
+/// # Examples
+///
+/// ```ignore
+/// # use kernel::from_kernel_result;
+/// # use kernel::c_types;
+/// # use kernel::bindings;
+/// unsafe extern "C" fn probe_callback(
+///     pdev: *mut bindings::platform_device,
+/// ) -> c_types::c_int {
+///     from_kernel_result! {
+///         let ptr = devm_alloc(pdev)?;
+///         bindings::platform_set_drvdata(pdev, ptr);
+///         Ok(0)
+///     }
+/// }
+/// ```
+macro_rules! from_kernel_result {
+    ($($tt:tt)*) => {{
+        $crate::error::from_kernel_result_helper((|| {
+            $($tt)*
+        })())
+    }};
+}
+
+pub(crate) use from_kernel_result;
+
+/// Transform a kernel "error pointer" to a normal pointer.
+///
+/// Some kernel C API functions return an "error pointer" which optionally
+/// embeds an `errno`. Callers are supposed to check the returned pointer
+/// for errors. This function performs the check and converts the "error pointer"
+/// to a normal pointer in an idiomatic fashion.
+///
+/// # Examples
+///
+/// ```ignore
+/// # use kernel::from_kernel_err_ptr;
+/// # use kernel::c_types;
+/// # use kernel::bindings;
+/// fn devm_platform_ioremap_resource(
+///     pdev: &mut PlatformDevice,
+///     index: u32,
+/// ) -> Result<*mut c_types::c_void> {
+///     // SAFETY: FFI call.
+///     unsafe {
+///         from_kernel_err_ptr(bindings::devm_platform_ioremap_resource(
+///             pdev.to_ptr(),
+///             index,
+///         ))
+///     }
+/// }
+/// ```
+// TODO: Remove `dead_code` marker once an in-kernel client is available.
+#[allow(dead_code)]
+pub(crate) fn from_kernel_err_ptr<T>(ptr: *mut T) -> Result<*mut T> {
+    // CAST: Casting a pointer to `*const c_types::c_void` is always valid.
+    let const_ptr: *const c_types::c_void = ptr.cast();
+    // SAFETY: The FFI function does not deref the pointer.
+    if unsafe { bindings::IS_ERR(const_ptr) } {
+        // SAFETY: The FFI function does not deref the pointer.
+        let err = unsafe { bindings::PTR_ERR(const_ptr) };
+        // CAST: If `IS_ERR()` returns `true`,
+        // then `PTR_ERR()` is guaranteed to return a
+        // negative value greater-or-equal to `-bindings::MAX_ERRNO`,
+        // which always fits in an `i16`, as per the invariant above.
+        // And an `i16` always fits in an `i32`. So casting `err` to
+        // an `i32` can never overflow, and is always valid.
+        //
+        // SAFETY: `IS_ERR()` ensures `err` is a
+        // negative value greater-or-equal to `-bindings::MAX_ERRNO`.
+        return Err(unsafe { Error::from_kernel_errno_unchecked(err as i32) });
+    }
+    Ok(ptr)
+}
+
+/// Calls a kernel function that returns an integer error code on failure and converts the result
+/// to a [`Result`].
+pub fn to_result(func: impl FnOnce() -> c_types::c_int) -> Result {
+    let err = func();
+    if err < 0 {
+        Err(Error::from_kernel_errno(err))
+    } else {
+        Ok(())
+    }
+}
diff --git a/rust/kernel/file.rs b/rust/kernel/file.rs
new file mode 100644
index 000000000000..e1b3b324bb3d
--- /dev/null
+++ b/rust/kernel/file.rs
@@ -0,0 +1,860 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Files and file descriptors.
+//!
+//! C headers: [`include/linux/fs.h`](../../../../include/linux/fs.h) and
+//! [`include/linux/file.h`](../../../../include/linux/file.h)
+
+use crate::{
+    bindings, c_types,
+    cred::Credential,
+    error::{code::*, from_kernel_result, Error, Result},
+    io_buffer::{IoBufferReader, IoBufferWriter},
+    iov_iter::IovIter,
+    mm,
+    sync::CondVar,
+    types::PointerWrapper,
+    user_ptr::{UserSlicePtr, UserSlicePtrReader, UserSlicePtrWriter},
+    ARef, AlwaysRefCounted,
+};
+use core::convert::{TryFrom, TryInto};
+use core::{cell::UnsafeCell, marker, mem, ptr};
+
+/// Wraps the kernel's `struct file`.
+///
+/// # Invariants
+///
+/// Instances of this type are always ref-counted, that is, a call to `get_file` ensures that the
+/// allocation remains valid at least until the matching call to `fput`.
+#[repr(transparent)]
+pub struct File(pub(crate) UnsafeCell<bindings::file>);
+
+// TODO: Accessing fields of `struct file` through the pointer is UB because other threads may be
+// writing to them. However, this is how the C code currently operates: naked reads and writes to
+// fields. Even if we used relaxed atomics on the Rust side, we can't force this on the C side.
+impl File {
+    /// Constructs a new [`struct file`] wrapper from a file descriptor.
+    ///
+    /// The file descriptor belongs to the current process.
+    pub fn from_fd(fd: u32) -> Result<ARef<Self>> {
+        // SAFETY: FFI call, there are no requirements on `fd`.
+        let ptr = ptr::NonNull::new(unsafe { bindings::fget(fd) }).ok_or(EBADF)?;
+
+        // SAFETY: `fget` increments the refcount before returning.
+        Ok(unsafe { ARef::from_raw(ptr.cast()) })
+    }
+
+    /// Creates a reference to a [`File`] from a valid pointer.
+    ///
+    /// # Safety
+    ///
+    /// The caller must ensure that `ptr` is valid and remains valid for the lifetime of the
+    /// returned [`File`] instance.
+    pub(crate) unsafe fn from_ptr<'a>(ptr: *const bindings::file) -> &'a File {
+        // SAFETY: The safety requirements guarantee the validity of the dereference, while the
+        // `File` type being transparent makes the cast ok.
+        unsafe { &*ptr.cast() }
+    }
+
+    /// Returns the current seek/cursor/pointer position (`struct file::f_pos`).
+    pub fn pos(&self) -> u64 {
+        // SAFETY: The file is valid because the shared reference guarantees a nonzero refcount.
+        unsafe { core::ptr::addr_of!((*self.0.get()).f_pos).read() as _ }
+    }
+
+    /// Returns whether the file is in blocking mode.
+    pub fn is_blocking(&self) -> bool {
+        self.flags() & bindings::O_NONBLOCK == 0
+    }
+
+    /// Returns the credentials of the task that originally opened the file.
+    pub fn cred(&self) -> &Credential {
+        // SAFETY: The file is valid because the shared reference guarantees a nonzero refcount.
+        let ptr = unsafe { core::ptr::addr_of!((*self.0.get()).f_cred).read() };
+        // SAFETY: The lifetimes of `self` and `Credential` are tied, so it is guaranteed that
+        // the credential pointer remains valid (because the file is still alive, and it doesn't
+        // change over the lifetime of a file).
+        unsafe { Credential::from_ptr(ptr) }
+    }
+
+    /// Returns the flags associated with the file.
+    pub fn flags(&self) -> u32 {
+        // SAFETY: The file is valid because the shared reference guarantees a nonzero refcount.
+        unsafe { core::ptr::addr_of!((*self.0.get()).f_flags).read() }
+    }
+}
+
+// SAFETY: The type invariants guarantee that `File` is always ref-counted.
+unsafe impl AlwaysRefCounted for File {
+    fn inc_ref(&self) {
+        // SAFETY: The existence of a shared reference means that the refcount is nonzero.
+        unsafe { bindings::get_file(self.0.get()) };
+    }
+
+    unsafe fn dec_ref(obj: ptr::NonNull<Self>) {
+        // SAFETY: The safety requirements guarantee that the refcount is nonzero.
+        unsafe { bindings::fput(obj.cast().as_ptr()) }
+    }
+}
+
+/// A file descriptor reservation.
+///
+/// This allows the creation of a file descriptor in two steps: first, we reserve a slot for it,
+/// then we commit or drop the reservation. The first step may fail (e.g., the current process ran
+/// out of available slots), but commit and drop never fail (and are mutually exclusive).
+pub struct FileDescriptorReservation {
+    fd: u32,
+}
+
+impl FileDescriptorReservation {
+    /// Creates a new file descriptor reservation.
+    pub fn new(flags: u32) -> Result<Self> {
+        // SAFETY: FFI call, there are no safety requirements on `flags`.
+        let fd = unsafe { bindings::get_unused_fd_flags(flags) };
+        if fd < 0 {
+            return Err(Error::from_kernel_errno(fd));
+        }
+        Ok(Self { fd: fd as _ })
+    }
+
+    /// Returns the file descriptor number that was reserved.
+    pub fn reserved_fd(&self) -> u32 {
+        self.fd
+    }
+
+    /// Commits the reservation.
+    ///
+    /// The previously reserved file descriptor is bound to `file`.
+    pub fn commit(self, file: ARef<File>) {
+        // SAFETY: `self.fd` was previously returned by `get_unused_fd_flags`, and `file.ptr` is
+        // guaranteed to have an owned ref count by its type invariants.
+        unsafe { bindings::fd_install(self.fd, file.0.get()) };
+
+        // `fd_install` consumes both the file descriptor and the file reference, so we cannot run
+        // the destructors.
+        core::mem::forget(self);
+        core::mem::forget(file);
+    }
+}
+
+impl Drop for FileDescriptorReservation {
+    fn drop(&mut self) {
+        // SAFETY: `self.fd` was returned by a previous call to `get_unused_fd_flags`.
+        unsafe { bindings::put_unused_fd(self.fd) };
+    }
+}
+
+/// Wraps the kernel's `struct poll_table_struct`.
+///
+/// # Invariants
+///
+/// The pointer `PollTable::ptr` is null or valid.
+pub struct PollTable {
+    ptr: *mut bindings::poll_table_struct,
+}
+
+impl PollTable {
+    /// Constructors a new `struct poll_table_struct` wrapper.
+    ///
+    /// # Safety
+    ///
+    /// The pointer `ptr` must be either null or a valid pointer for the lifetime of the object.
+    unsafe fn from_ptr(ptr: *mut bindings::poll_table_struct) -> Self {
+        Self { ptr }
+    }
+
+    /// Associates the given file and condition variable to this poll table. It means notifying the
+    /// condition variable will notify the poll table as well; additionally, the association
+    /// between the condition variable and the file will automatically be undone by the kernel when
+    /// the file is destructed. To unilaterally remove the association before then, one can call
+    /// [`CondVar::free_waiters`].
+    ///
+    /// # Safety
+    ///
+    /// If the condition variable is destroyed before the file, then [`CondVar::free_waiters`] must
+    /// be called to ensure that all waiters are flushed out.
+    pub unsafe fn register_wait<'a>(&self, file: &'a File, cv: &'a CondVar) {
+        if self.ptr.is_null() {
+            return;
+        }
+
+        // SAFETY: `PollTable::ptr` is guaranteed to be valid by the type invariants and the null
+        // check above.
+        let table = unsafe { &*self.ptr };
+        if let Some(proc) = table._qproc {
+            // SAFETY: All pointers are known to be valid.
+            unsafe { proc(file.0.get() as _, cv.wait_list.get(), self.ptr) }
+        }
+    }
+}
+
+/// Equivalent to [`std::io::SeekFrom`].
+///
+/// [`std::io::SeekFrom`]: https://doc.rust-lang.org/std/io/enum.SeekFrom.html
+pub enum SeekFrom {
+    /// Equivalent to C's `SEEK_SET`.
+    Start(u64),
+
+    /// Equivalent to C's `SEEK_END`.
+    End(i64),
+
+    /// Equivalent to C's `SEEK_CUR`.
+    Current(i64),
+}
+
+pub(crate) struct OperationsVtable<A, T>(marker::PhantomData<A>, marker::PhantomData<T>);
+
+impl<A: OpenAdapter<T::OpenData>, T: Operations> OperationsVtable<A, T> {
+    /// Called by the VFS when an inode should be opened.
+    ///
+    /// Calls `T::open` on the returned value of `A::convert`.
+    ///
+    /// # Safety
+    ///
+    /// The returned value of `A::convert` must be a valid non-null pointer and
+    /// `T:open` must return a valid non-null pointer on an `Ok` result.
+    unsafe extern "C" fn open_callback(
+        inode: *mut bindings::inode,
+        file: *mut bindings::file,
+    ) -> c_types::c_int {
+        from_kernel_result! {
+            // SAFETY: `A::convert` must return a valid non-null pointer that
+            // should point to data in the inode or file that lives longer
+            // than the following use of `T::open`.
+            let arg = unsafe { A::convert(inode, file) };
+            // SAFETY: The C contract guarantees that `file` is valid. Additionally,
+            // `fileref` never outlives this function, so it is guaranteed to be
+            // valid.
+            let fileref = unsafe { File::from_ptr(file) };
+            // SAFETY: `arg` was previously returned by `A::convert` and must
+            // be a valid non-null pointer.
+            let ptr = T::open(unsafe { &*arg }, fileref)?.into_pointer();
+            // SAFETY: The C contract guarantees that `private_data` is available
+            // for implementers of the file operations (no other C code accesses
+            // it), so we know that there are no concurrent threads/CPUs accessing
+            // it (it's not visible to any other Rust code).
+            unsafe { (*file).private_data = ptr as *mut c_types::c_void };
+            Ok(0)
+        }
+    }
+
+    unsafe extern "C" fn read_callback(
+        file: *mut bindings::file,
+        buf: *mut c_types::c_char,
+        len: c_types::c_size_t,
+        offset: *mut bindings::loff_t,
+    ) -> c_types::c_ssize_t {
+        from_kernel_result! {
+            let mut data = unsafe { UserSlicePtr::new(buf as *mut c_types::c_void, len).writer() };
+            // SAFETY: `private_data` was initialised by `open_callback` with a value returned by
+            // `T::Data::into_pointer`. `T::Data::from_pointer` is only called by the
+            // `release` callback, which the C API guarantees that will be called only when all
+            // references to `file` have been released, so we know it can't be called while this
+            // function is running.
+            let f = unsafe { T::Data::borrow((*file).private_data) };
+            // No `FMODE_UNSIGNED_OFFSET` support, so `offset` must be in [0, 2^63).
+            // See discussion in https://github.com/fishinabarrel/linux-kernel-module-rust/pull/113
+            let read = T::read(
+                f,
+                unsafe { File::from_ptr(file) },
+                &mut data,
+                unsafe { *offset }.try_into()?,
+            )?;
+            unsafe { (*offset) += bindings::loff_t::try_from(read).unwrap() };
+            Ok(read as _)
+        }
+    }
+
+    unsafe extern "C" fn read_iter_callback(
+        iocb: *mut bindings::kiocb,
+        raw_iter: *mut bindings::iov_iter,
+    ) -> isize {
+        from_kernel_result! {
+            let mut iter = unsafe { IovIter::from_ptr(raw_iter) };
+            let file = unsafe { (*iocb).ki_filp };
+            let offset = unsafe { (*iocb).ki_pos };
+            // SAFETY: `private_data` was initialised by `open_callback` with a value returned by
+            // `T::Data::into_pointer`. `T::Data::from_pointer` is only called by the
+            // `release` callback, which the C API guarantees that will be called only when all
+            // references to `file` have been released, so we know it can't be called while this
+            // function is running.
+            let f = unsafe { T::Data::borrow((*file).private_data) };
+            let read =
+                T::read(f, unsafe { File::from_ptr(file) }, &mut iter, offset.try_into()?)?;
+            unsafe { (*iocb).ki_pos += bindings::loff_t::try_from(read).unwrap() };
+            Ok(read as _)
+        }
+    }
+
+    unsafe extern "C" fn write_callback(
+        file: *mut bindings::file,
+        buf: *const c_types::c_char,
+        len: c_types::c_size_t,
+        offset: *mut bindings::loff_t,
+    ) -> c_types::c_ssize_t {
+        from_kernel_result! {
+            let mut data = unsafe { UserSlicePtr::new(buf as *mut c_types::c_void, len).reader() };
+            // SAFETY: `private_data` was initialised by `open_callback` with a value returned by
+            // `T::Data::into_pointer`. `T::Data::from_pointer` is only called by the
+            // `release` callback, which the C API guarantees that will be called only when all
+            // references to `file` have been released, so we know it can't be called while this
+            // function is running.
+            let f = unsafe { T::Data::borrow((*file).private_data) };
+            // No `FMODE_UNSIGNED_OFFSET` support, so `offset` must be in [0, 2^63).
+            // See discussion in https://github.com/fishinabarrel/linux-kernel-module-rust/pull/113
+            let written = T::write(
+                f,
+                unsafe { File::from_ptr(file) },
+                &mut data,
+                unsafe { *offset }.try_into()?
+            )?;
+            unsafe { (*offset) += bindings::loff_t::try_from(written).unwrap() };
+            Ok(written as _)
+        }
+    }
+
+    unsafe extern "C" fn write_iter_callback(
+        iocb: *mut bindings::kiocb,
+        raw_iter: *mut bindings::iov_iter,
+    ) -> isize {
+        from_kernel_result! {
+            let mut iter = unsafe { IovIter::from_ptr(raw_iter) };
+            let file = unsafe { (*iocb).ki_filp };
+            let offset = unsafe { (*iocb).ki_pos };
+            // SAFETY: `private_data` was initialised by `open_callback` with a value returned by
+            // `T::Data::into_pointer`. `T::Data::from_pointer` is only called by the
+            // `release` callback, which the C API guarantees that will be called only when all
+            // references to `file` have been released, so we know it can't be called while this
+            // function is running.
+            let f = unsafe { T::Data::borrow((*file).private_data) };
+            let written =
+                T::write(f, unsafe { File::from_ptr(file) }, &mut iter, offset.try_into()?)?;
+            unsafe { (*iocb).ki_pos += bindings::loff_t::try_from(written).unwrap() };
+            Ok(written as _)
+        }
+    }
+
+    unsafe extern "C" fn release_callback(
+        _inode: *mut bindings::inode,
+        file: *mut bindings::file,
+    ) -> c_types::c_int {
+        let ptr = mem::replace(unsafe { &mut (*file).private_data }, ptr::null_mut());
+        T::release(unsafe { T::Data::from_pointer(ptr as _) }, unsafe {
+            File::from_ptr(file)
+        });
+        0
+    }
+
+    unsafe extern "C" fn llseek_callback(
+        file: *mut bindings::file,
+        offset: bindings::loff_t,
+        whence: c_types::c_int,
+    ) -> bindings::loff_t {
+        from_kernel_result! {
+            let off = match whence as u32 {
+                bindings::SEEK_SET => SeekFrom::Start(offset.try_into()?),
+                bindings::SEEK_CUR => SeekFrom::Current(offset),
+                bindings::SEEK_END => SeekFrom::End(offset),
+                _ => return Err(EINVAL),
+            };
+            // SAFETY: `private_data` was initialised by `open_callback` with a value returned by
+            // `T::Data::into_pointer`. `T::Data::from_pointer` is only called by the
+            // `release` callback, which the C API guarantees that will be called only when all
+            // references to `file` have been released, so we know it can't be called while this
+            // function is running.
+            let f = unsafe { T::Data::borrow((*file).private_data) };
+            let off = T::seek(f, unsafe { File::from_ptr(file) }, off)?;
+            Ok(off as bindings::loff_t)
+        }
+    }
+
+    unsafe extern "C" fn unlocked_ioctl_callback(
+        file: *mut bindings::file,
+        cmd: c_types::c_uint,
+        arg: c_types::c_ulong,
+    ) -> c_types::c_long {
+        from_kernel_result! {
+            // SAFETY: `private_data` was initialised by `open_callback` with a value returned by
+            // `T::Data::into_pointer`. `T::Data::from_pointer` is only called by the
+            // `release` callback, which the C API guarantees that will be called only when all
+            // references to `file` have been released, so we know it can't be called while this
+            // function is running.
+            let f = unsafe { T::Data::borrow((*file).private_data) };
+            let mut cmd = IoctlCommand::new(cmd as _, arg as _);
+            let ret = T::ioctl(f, unsafe { File::from_ptr(file) }, &mut cmd)?;
+            Ok(ret as _)
+        }
+    }
+
+    unsafe extern "C" fn compat_ioctl_callback(
+        file: *mut bindings::file,
+        cmd: c_types::c_uint,
+        arg: c_types::c_ulong,
+    ) -> c_types::c_long {
+        from_kernel_result! {
+            // SAFETY: `private_data` was initialised by `open_callback` with a value returned by
+            // `T::Data::into_pointer`. `T::Data::from_pointer` is only called by the
+            // `release` callback, which the C API guarantees that will be called only when all
+            // references to `file` have been released, so we know it can't be called while this
+            // function is running.
+            let f = unsafe { T::Data::borrow((*file).private_data) };
+            let mut cmd = IoctlCommand::new(cmd as _, arg as _);
+            let ret = T::compat_ioctl(f, unsafe { File::from_ptr(file) }, &mut cmd)?;
+            Ok(ret as _)
+        }
+    }
+
+    unsafe extern "C" fn mmap_callback(
+        file: *mut bindings::file,
+        vma: *mut bindings::vm_area_struct,
+    ) -> c_types::c_int {
+        from_kernel_result! {
+            // SAFETY: `private_data` was initialised by `open_callback` with a value returned by
+            // `T::Data::into_pointer`. `T::Data::from_pointer` is only called by the
+            // `release` callback, which the C API guarantees that will be called only when all
+            // references to `file` have been released, so we know it can't be called while this
+            // function is running.
+            let f = unsafe { T::Data::borrow((*file).private_data) };
+
+            // SAFETY: The C API guarantees that `vma` is valid for the duration of this call.
+            // `area` only lives within this call, so it is guaranteed to be valid.
+            let mut area = unsafe { mm::virt::Area::from_ptr(vma) };
+
+            // SAFETY: The C API guarantees that `file` is valid for the duration of this call,
+            // which is longer than the lifetime of the file reference.
+            T::mmap(f, unsafe { File::from_ptr(file) }, &mut area)?;
+            Ok(0)
+        }
+    }
+
+    unsafe extern "C" fn fsync_callback(
+        file: *mut bindings::file,
+        start: bindings::loff_t,
+        end: bindings::loff_t,
+        datasync: c_types::c_int,
+    ) -> c_types::c_int {
+        from_kernel_result! {
+            let start = start.try_into()?;
+            let end = end.try_into()?;
+            let datasync = datasync != 0;
+            // SAFETY: `private_data` was initialised by `open_callback` with a value returned by
+            // `T::Data::into_pointer`. `T::Data::from_pointer` is only called by the
+            // `release` callback, which the C API guarantees that will be called only when all
+            // references to `file` have been released, so we know it can't be called while this
+            // function is running.
+            let f = unsafe { T::Data::borrow((*file).private_data) };
+            let res = T::fsync(f, unsafe { File::from_ptr(file) }, start, end, datasync)?;
+            Ok(res.try_into().unwrap())
+        }
+    }
+
+    unsafe extern "C" fn poll_callback(
+        file: *mut bindings::file,
+        wait: *mut bindings::poll_table_struct,
+    ) -> bindings::__poll_t {
+        // SAFETY: `private_data` was initialised by `open_callback` with a value returned by
+        // `T::Data::into_pointer`. `T::Data::from_pointer` is only called by the `release`
+        // callback, which the C API guarantees that will be called only when all references to
+        // `file` have been released, so we know it can't be called while this function is running.
+        let f = unsafe { T::Data::borrow((*file).private_data) };
+        match T::poll(f, unsafe { File::from_ptr(file) }, unsafe {
+            &PollTable::from_ptr(wait)
+        }) {
+            Ok(v) => v,
+            Err(_) => bindings::POLLERR,
+        }
+    }
+
+    const VTABLE: bindings::file_operations = bindings::file_operations {
+        open: Some(Self::open_callback),
+        release: Some(Self::release_callback),
+        read: if T::TO_USE.read {
+            Some(Self::read_callback)
+        } else {
+            None
+        },
+        write: if T::TO_USE.write {
+            Some(Self::write_callback)
+        } else {
+            None
+        },
+        llseek: if T::TO_USE.seek {
+            Some(Self::llseek_callback)
+        } else {
+            None
+        },
+
+        check_flags: None,
+        compat_ioctl: if T::TO_USE.compat_ioctl {
+            Some(Self::compat_ioctl_callback)
+        } else {
+            None
+        },
+        copy_file_range: None,
+        fallocate: None,
+        fadvise: None,
+        fasync: None,
+        flock: None,
+        flush: None,
+        fsync: if T::TO_USE.fsync {
+            Some(Self::fsync_callback)
+        } else {
+            None
+        },
+        get_unmapped_area: None,
+        iterate: None,
+        iterate_shared: None,
+        iopoll: None,
+        lock: None,
+        mmap: if T::TO_USE.mmap {
+            Some(Self::mmap_callback)
+        } else {
+            None
+        },
+        mmap_supported_flags: 0,
+        owner: ptr::null_mut(),
+        poll: if T::TO_USE.poll {
+            Some(Self::poll_callback)
+        } else {
+            None
+        },
+        read_iter: if T::TO_USE.read_iter {
+            Some(Self::read_iter_callback)
+        } else {
+            None
+        },
+        remap_file_range: None,
+        sendpage: None,
+        setlease: None,
+        show_fdinfo: None,
+        splice_read: None,
+        splice_write: None,
+        unlocked_ioctl: if T::TO_USE.ioctl {
+            Some(Self::unlocked_ioctl_callback)
+        } else {
+            None
+        },
+        write_iter: if T::TO_USE.write_iter {
+            Some(Self::write_iter_callback)
+        } else {
+            None
+        },
+    };
+
+    /// Builds an instance of [`struct file_operations`].
+    ///
+    /// # Safety
+    ///
+    /// The caller must ensure that the adapter is compatible with the way the device is registered.
+    pub(crate) const unsafe fn build() -> &'static bindings::file_operations {
+        &Self::VTABLE
+    }
+}
+
+/// Represents which fields of [`struct file_operations`] should be populated with pointers.
+pub struct ToUse {
+    /// The `read` field of [`struct file_operations`].
+    pub read: bool,
+
+    /// The `read_iter` field of [`struct file_operations`].
+    pub read_iter: bool,
+
+    /// The `write` field of [`struct file_operations`].
+    pub write: bool,
+
+    /// The `write_iter` field of [`struct file_operations`].
+    pub write_iter: bool,
+
+    /// The `llseek` field of [`struct file_operations`].
+    pub seek: bool,
+
+    /// The `unlocked_ioctl` field of [`struct file_operations`].
+    pub ioctl: bool,
+
+    /// The `compat_ioctl` field of [`struct file_operations`].
+    pub compat_ioctl: bool,
+
+    /// The `fsync` field of [`struct file_operations`].
+    pub fsync: bool,
+
+    /// The `mmap` field of [`struct file_operations`].
+    pub mmap: bool,
+
+    /// The `poll` field of [`struct file_operations`].
+    pub poll: bool,
+}
+
+/// A constant version where all values are to set to `false`, that is, all supported fields will
+/// be set to null pointers.
+pub const USE_NONE: ToUse = ToUse {
+    read: false,
+    read_iter: false,
+    write: false,
+    write_iter: false,
+    seek: false,
+    ioctl: false,
+    compat_ioctl: false,
+    fsync: false,
+    mmap: false,
+    poll: false,
+};
+
+/// Defines the [`Operations::TO_USE`] field based on a list of fields to be populated.
+#[macro_export]
+macro_rules! declare_file_operations {
+    () => {
+        const TO_USE: $crate::file::ToUse = $crate::file::USE_NONE;
+    };
+    ($($i:ident),+) => {
+        const TO_USE: kernel::file::ToUse =
+            $crate::file::ToUse {
+                $($i: true),+ ,
+                ..$crate::file::USE_NONE
+            };
+    };
+}
+
+/// Allows the handling of ioctls defined with the `_IO`, `_IOR`, `_IOW`, and `_IOWR` macros.
+///
+/// For each macro, there is a handler function that takes the appropriate types as arguments.
+pub trait IoctlHandler: Sync {
+    /// The type of the first argument to each associated function.
+    type Target<'a>;
+
+    /// Handles ioctls defined with the `_IO` macro, that is, with no buffer as argument.
+    fn pure(_this: Self::Target<'_>, _file: &File, _cmd: u32, _arg: usize) -> Result<i32> {
+        Err(EINVAL)
+    }
+
+    /// Handles ioctls defined with the `_IOR` macro, that is, with an output buffer provided as
+    /// argument.
+    fn read(
+        _this: Self::Target<'_>,
+        _file: &File,
+        _cmd: u32,
+        _writer: &mut UserSlicePtrWriter,
+    ) -> Result<i32> {
+        Err(EINVAL)
+    }
+
+    /// Handles ioctls defined with the `_IOW` macro, that is, with an input buffer provided as
+    /// argument.
+    fn write(
+        _this: Self::Target<'_>,
+        _file: &File,
+        _cmd: u32,
+        _reader: &mut UserSlicePtrReader,
+    ) -> Result<i32> {
+        Err(EINVAL)
+    }
+
+    /// Handles ioctls defined with the `_IOWR` macro, that is, with a buffer for both input and
+    /// output provided as argument.
+    fn read_write(
+        _this: Self::Target<'_>,
+        _file: &File,
+        _cmd: u32,
+        _data: UserSlicePtr,
+    ) -> Result<i32> {
+        Err(EINVAL)
+    }
+}
+
+/// Represents an ioctl command.
+///
+/// It can use the components of an ioctl command to dispatch ioctls using
+/// [`IoctlCommand::dispatch`].
+pub struct IoctlCommand {
+    cmd: u32,
+    arg: usize,
+    user_slice: Option<UserSlicePtr>,
+}
+
+impl IoctlCommand {
+    /// Constructs a new [`IoctlCommand`].
+    fn new(cmd: u32, arg: usize) -> Self {
+        let size = (cmd >> bindings::_IOC_SIZESHIFT) & bindings::_IOC_SIZEMASK;
+
+        // SAFETY: We only create one instance of the user slice per ioctl call, so TOCTOU issues
+        // are not possible.
+        let user_slice = Some(unsafe { UserSlicePtr::new(arg as _, size as _) });
+        Self {
+            cmd,
+            arg,
+            user_slice,
+        }
+    }
+
+    /// Dispatches the given ioctl to the appropriate handler based on the value of the command. It
+    /// also creates a [`UserSlicePtr`], [`UserSlicePtrReader`], or [`UserSlicePtrWriter`]
+    /// depending on the direction of the buffer of the command.
+    ///
+    /// It is meant to be used in implementations of [`Operations::ioctl`] and
+    /// [`Operations::compat_ioctl`].
+    pub fn dispatch<T: IoctlHandler>(
+        &mut self,
+        handler: T::Target<'_>,
+        file: &File,
+    ) -> Result<i32> {
+        let dir = (self.cmd >> bindings::_IOC_DIRSHIFT) & bindings::_IOC_DIRMASK;
+        if dir == bindings::_IOC_NONE {
+            return T::pure(handler, file, self.cmd, self.arg);
+        }
+
+        let data = self.user_slice.take().ok_or(EINVAL)?;
+        const READ_WRITE: u32 = bindings::_IOC_READ | bindings::_IOC_WRITE;
+        match dir {
+            bindings::_IOC_WRITE => T::write(handler, file, self.cmd, &mut data.reader()),
+            bindings::_IOC_READ => T::read(handler, file, self.cmd, &mut data.writer()),
+            READ_WRITE => T::read_write(handler, file, self.cmd, data),
+            _ => Err(EINVAL),
+        }
+    }
+
+    /// Returns the raw 32-bit value of the command and the ptr-sized argument.
+    pub fn raw(&self) -> (u32, usize) {
+        (self.cmd, self.arg)
+    }
+}
+
+/// Trait for extracting file open arguments from kernel data structures.
+///
+/// This is meant to be implemented by registration managers.
+pub trait OpenAdapter<T: Sync> {
+    /// Converts untyped data stored in [`struct inode`] and [`struct file`] (when [`struct
+    /// file_operations::open`] is called) into the given type. For example, for `miscdev`
+    /// devices, a pointer to the registered [`struct miscdev`] is stored in [`struct
+    /// file::private_data`].
+    ///
+    /// # Safety
+    ///
+    /// This function must be called only when [`struct file_operations::open`] is being called for
+    /// a file that was registered by the implementer. The returned pointer must be valid and
+    /// not-null.
+    unsafe fn convert(_inode: *mut bindings::inode, _file: *mut bindings::file) -> *const T;
+}
+
+/// Corresponds to the kernel's `struct file_operations`.
+///
+/// You implement this trait whenever you would create a `struct file_operations`.
+///
+/// File descriptors may be used from multiple threads/processes concurrently, so your type must be
+/// [`Sync`]. It must also be [`Send`] because [`Operations::release`] will be called from the
+/// thread that decrements that associated file's refcount to zero.
+pub trait Operations {
+    /// The methods to use to populate [`struct file_operations`].
+    const TO_USE: ToUse;
+
+    /// The type of the context data returned by [`Operations::open`] and made available to
+    /// other methods.
+    type Data: PointerWrapper + Send + Sync = ();
+
+    /// The type of the context data passed to [`Operations::open`].
+    type OpenData: Sync = ();
+
+    /// Creates a new instance of this file.
+    ///
+    /// Corresponds to the `open` function pointer in `struct file_operations`.
+    fn open(context: &Self::OpenData, file: &File) -> Result<Self::Data>;
+
+    /// Cleans up after the last reference to the file goes away.
+    ///
+    /// Note that context data is moved, so it will be freed automatically unless the
+    /// implementation moves it elsewhere.
+    ///
+    /// Corresponds to the `release` function pointer in `struct file_operations`.
+    fn release(_data: Self::Data, _file: &File) {}
+
+    /// Reads data from this file to the caller's buffer.
+    ///
+    /// Corresponds to the `read` and `read_iter` function pointers in `struct file_operations`.
+    fn read(
+        _data: <Self::Data as PointerWrapper>::Borrowed<'_>,
+        _file: &File,
+        _writer: &mut impl IoBufferWriter,
+        _offset: u64,
+    ) -> Result<usize> {
+        Err(EINVAL)
+    }
+
+    /// Writes data from the caller's buffer to this file.
+    ///
+    /// Corresponds to the `write` and `write_iter` function pointers in `struct file_operations`.
+    fn write(
+        _data: <Self::Data as PointerWrapper>::Borrowed<'_>,
+        _file: &File,
+        _reader: &mut impl IoBufferReader,
+        _offset: u64,
+    ) -> Result<usize> {
+        Err(EINVAL)
+    }
+
+    /// Changes the position of the file.
+    ///
+    /// Corresponds to the `llseek` function pointer in `struct file_operations`.
+    fn seek(
+        _data: <Self::Data as PointerWrapper>::Borrowed<'_>,
+        _file: &File,
+        _offset: SeekFrom,
+    ) -> Result<u64> {
+        Err(EINVAL)
+    }
+
+    /// Performs IO control operations that are specific to the file.
+    ///
+    /// Corresponds to the `unlocked_ioctl` function pointer in `struct file_operations`.
+    fn ioctl(
+        _data: <Self::Data as PointerWrapper>::Borrowed<'_>,
+        _file: &File,
+        _cmd: &mut IoctlCommand,
+    ) -> Result<i32> {
+        Err(ENOTTY)
+    }
+
+    /// Performs 32-bit IO control operations on that are specific to the file on 64-bit kernels.
+    ///
+    /// Corresponds to the `compat_ioctl` function pointer in `struct file_operations`.
+    fn compat_ioctl(
+        _data: <Self::Data as PointerWrapper>::Borrowed<'_>,
+        _file: &File,
+        _cmd: &mut IoctlCommand,
+    ) -> Result<i32> {
+        Err(ENOTTY)
+    }
+
+    /// Syncs pending changes to this file.
+    ///
+    /// Corresponds to the `fsync` function pointer in `struct file_operations`.
+    fn fsync(
+        _data: <Self::Data as PointerWrapper>::Borrowed<'_>,
+        _file: &File,
+        _start: u64,
+        _end: u64,
+        _datasync: bool,
+    ) -> Result<u32> {
+        Err(EINVAL)
+    }
+
+    /// Maps areas of the caller's virtual memory with device/file memory.
+    ///
+    /// Corresponds to the `mmap` function pointer in `struct file_operations`.
+    fn mmap(
+        _data: <Self::Data as PointerWrapper>::Borrowed<'_>,
+        _file: &File,
+        _vma: &mut mm::virt::Area,
+    ) -> Result {
+        Err(EINVAL)
+    }
+
+    /// Checks the state of the file and optionally registers for notification when the state
+    /// changes.
+    ///
+    /// Corresponds to the `poll` function pointer in `struct file_operations`.
+    fn poll(
+        _data: <Self::Data as PointerWrapper>::Borrowed<'_>,
+        _file: &File,
+        _table: &PollTable,
+    ) -> Result<u32> {
+        Ok(bindings::POLLIN | bindings::POLLOUT | bindings::POLLRDNORM | bindings::POLLWRNORM)
+    }
+}
diff --git a/rust/kernel/gpio.rs b/rust/kernel/gpio.rs
new file mode 100644
index 000000000000..2e4365dfcf74
--- /dev/null
+++ b/rust/kernel/gpio.rs
@@ -0,0 +1,478 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Support for gpio device drivers.
+//!
+//! C header: [`include/linux/gpio/driver.h`](../../../../include/linux/gpio/driver.h)
+
+use crate::{
+    bindings, c_types, device, error::code::*, error::from_kernel_result, types::PointerWrapper,
+    Error, Result,
+};
+use core::{
+    cell::UnsafeCell,
+    marker::{PhantomData, PhantomPinned},
+    pin::Pin,
+};
+
+#[cfg(CONFIG_GPIOLIB_IRQCHIP)]
+pub use irqchip::{ChipWithIrqChip, RegistrationWithIrqChip};
+
+/// The direction of a gpio line.
+pub enum LineDirection {
+    /// Direction is input.
+    In = bindings::GPIO_LINE_DIRECTION_IN as _,
+
+    /// Direction is output.
+    Out = bindings::GPIO_LINE_DIRECTION_OUT as _,
+}
+
+/// A gpio chip.
+pub trait Chip {
+    /// Context data associated with the gpio chip.
+    ///
+    /// It determines the type of the context data passed to each of the methods of the trait.
+    type Data: PointerWrapper + Sync + Send;
+
+    /// The methods to use to populate [`struct gpio_chip`]. This is typically populated with
+    /// [`declare_gpio_chip_operations`].
+    const TO_USE: ToUse;
+
+    /// Returns the direction of the given gpio line.
+    fn get_direction(
+        _data: <Self::Data as PointerWrapper>::Borrowed<'_>,
+        _offset: u32,
+    ) -> Result<LineDirection> {
+        Err(ENOTSUPP)
+    }
+
+    /// Configures the direction as input of the given gpio line.
+    fn direction_input(
+        _data: <Self::Data as PointerWrapper>::Borrowed<'_>,
+        _offset: u32,
+    ) -> Result {
+        Err(EIO)
+    }
+
+    /// Configures the direction as output of the given gpio line.
+    ///
+    /// The value that will be initially output is also specified.
+    fn direction_output(
+        _data: <Self::Data as PointerWrapper>::Borrowed<'_>,
+        _offset: u32,
+        _value: bool,
+    ) -> Result {
+        Err(ENOTSUPP)
+    }
+
+    /// Returns the current value of the given gpio line.
+    fn get(_data: <Self::Data as PointerWrapper>::Borrowed<'_>, _offset: u32) -> Result<bool> {
+        Err(EIO)
+    }
+
+    /// Sets the value of the given gpio line.
+    fn set(_data: <Self::Data as PointerWrapper>::Borrowed<'_>, _offset: u32, _value: bool) {}
+}
+
+/// Represents which fields of [`struct gpio_chip`] should be populated with pointers.
+///
+/// This is typically populated with the [`declare_gpio_chip_operations`] macro.
+pub struct ToUse {
+    /// The `get_direction` field of [`struct gpio_chip`].
+    pub get_direction: bool,
+
+    /// The `direction_input` field of [`struct gpio_chip`].
+    pub direction_input: bool,
+
+    /// The `direction_output` field of [`struct gpio_chip`].
+    pub direction_output: bool,
+
+    /// The `get` field of [`struct gpio_chip`].
+    pub get: bool,
+
+    /// The `set` field of [`struct gpio_chip`].
+    pub set: bool,
+}
+
+/// A constant version where all values are set to `false`, that is, all supported fields will be
+/// set to null pointers.
+pub const USE_NONE: ToUse = ToUse {
+    get_direction: false,
+    direction_input: false,
+    direction_output: false,
+    get: false,
+    set: false,
+};
+
+/// Defines the [`Chip::TO_USE`] field based on a list of fields to be populated.
+#[macro_export]
+macro_rules! declare_gpio_chip_operations {
+    () => {
+        const TO_USE: $crate::gpio::ToUse = $crate::gpio::USE_NONE;
+    };
+    ($($i:ident),+) => {
+        #[allow(clippy::needless_update)]
+        const TO_USE: $crate::gpio::ToUse =
+            $crate::gpio::ToUse {
+                $($i: true),+ ,
+                ..$crate::gpio::USE_NONE
+            };
+    };
+}
+
+/// A registration of a gpio chip.
+pub struct Registration<T: Chip> {
+    gc: UnsafeCell<bindings::gpio_chip>,
+    parent: Option<device::Device>,
+    _p: PhantomData<T>,
+    _pin: PhantomPinned,
+}
+
+impl<T: Chip> Registration<T> {
+    /// Creates a new [`Registration`] but does not register it yet.
+    ///
+    /// It is allowed to move.
+    pub fn new() -> Self {
+        Self {
+            parent: None,
+            gc: UnsafeCell::new(bindings::gpio_chip::default()),
+            _pin: PhantomPinned,
+            _p: PhantomData,
+        }
+    }
+
+    /// Registers a gpio chip with the rest of the kernel.
+    pub fn register(
+        self: Pin<&mut Self>,
+        gpio_count: u16,
+        base: Option<i32>,
+        parent: &dyn device::RawDevice,
+        data: T::Data,
+    ) -> Result {
+        if self.parent.is_some() {
+            // Already registered.
+            return Err(EINVAL);
+        }
+
+        // SAFETY: We never move out of `this`.
+        let this = unsafe { self.get_unchecked_mut() };
+        {
+            let gc = this.gc.get_mut();
+
+            // Set up the callbacks.
+            gc.request = Some(bindings::gpiochip_generic_request);
+            gc.free = Some(bindings::gpiochip_generic_free);
+            if T::TO_USE.get_direction {
+                gc.get_direction = Some(get_direction_callback::<T>);
+            }
+            if T::TO_USE.direction_input {
+                gc.direction_input = Some(direction_input_callback::<T>);
+            }
+            if T::TO_USE.direction_output {
+                gc.direction_output = Some(direction_output_callback::<T>);
+            }
+            if T::TO_USE.get {
+                gc.get = Some(get_callback::<T>);
+            }
+            if T::TO_USE.set {
+                gc.set = Some(set_callback::<T>);
+            }
+
+            // When a base is not explicitly given, use -1 for one to be picked.
+            if let Some(b) = base {
+                gc.base = b;
+            } else {
+                gc.base = -1;
+            }
+
+            gc.ngpio = gpio_count;
+            gc.parent = parent.raw_device();
+            gc.label = parent.name().as_char_ptr();
+
+            // TODO: Define `gc.owner` as well.
+        }
+
+        let data_pointer = <T::Data as PointerWrapper>::into_pointer(data);
+        // SAFETY: `gc` was initilised above, so it is valid.
+        let ret = unsafe {
+            bindings::gpiochip_add_data_with_key(
+                this.gc.get(),
+                data_pointer as _,
+                core::ptr::null_mut(),
+                core::ptr::null_mut(),
+            )
+        };
+        if ret < 0 {
+            // SAFETY: `data_pointer` was returned by `into_pointer` above.
+            unsafe { T::Data::from_pointer(data_pointer) };
+            return Err(Error::from_kernel_errno(ret));
+        }
+
+        this.parent = Some(device::Device::from_dev(parent));
+        Ok(())
+    }
+}
+
+// SAFETY: `Registration` doesn't offer any methods or access to fields when shared between threads
+// or CPUs, so it is safe to share it.
+unsafe impl<T: Chip> Sync for Registration<T> {}
+
+// SAFETY: Registration with and unregistration from the gpio subsystem can happen from any thread.
+// Additionally, `T::Data` (which is dropped during unregistration) is `Send`, so it is ok to move
+// `Registration` to different threads.
+#[allow(clippy::non_send_fields_in_send_ty)]
+unsafe impl<T: Chip> Send for Registration<T> {}
+
+impl<T: Chip> Default for Registration<T> {
+    fn default() -> Self {
+        Self::new()
+    }
+}
+
+impl<T: Chip> Drop for Registration<T> {
+    /// Removes the registration from the kernel if it has completed successfully before.
+    fn drop(&mut self) {
+        if self.parent.is_some() {
+            // Get a pointer to the data stored in chip before destroying it.
+            // SAFETY: `gc` was during registration, which is guaranteed to have succeeded (because
+            // `parent` is `Some(_)`, so it remains valid.
+            let data_pointer = unsafe { bindings::gpiochip_get_data(self.gc.get()) };
+
+            // SAFETY: By the same argument above, `gc` is still valid.
+            unsafe { bindings::gpiochip_remove(self.gc.get()) };
+
+            // Free data as well.
+            // SAFETY: `data_pointer` was returned by `into_pointer` during registration.
+            unsafe { <T::Data as PointerWrapper>::from_pointer(data_pointer) };
+        }
+    }
+}
+
+unsafe extern "C" fn get_direction_callback<T: Chip>(
+    gc: *mut bindings::gpio_chip,
+    offset: c_types::c_uint,
+) -> c_types::c_int {
+    from_kernel_result! {
+        // SAFETY: The value stored as chip data was returned by `into_pointer` during registration.
+        let data = unsafe { T::Data::borrow(bindings::gpiochip_get_data(gc)) };
+        Ok(T::get_direction(data, offset)? as i32)
+    }
+}
+
+unsafe extern "C" fn direction_input_callback<T: Chip>(
+    gc: *mut bindings::gpio_chip,
+    offset: c_types::c_uint,
+) -> c_types::c_int {
+    from_kernel_result! {
+        // SAFETY: The value stored as chip data was returned by `into_pointer` during registration.
+        let data = unsafe { T::Data::borrow(bindings::gpiochip_get_data(gc)) };
+        T::direction_input(data, offset)?;
+        Ok(0)
+    }
+}
+
+unsafe extern "C" fn direction_output_callback<T: Chip>(
+    gc: *mut bindings::gpio_chip,
+    offset: c_types::c_uint,
+    value: c_types::c_int,
+) -> c_types::c_int {
+    from_kernel_result! {
+        // SAFETY: The value stored as chip data was returned by `into_pointer` during registration.
+        let data = unsafe { T::Data::borrow(bindings::gpiochip_get_data(gc)) };
+        T::direction_output(data, offset, value != 0)?;
+        Ok(0)
+    }
+}
+
+unsafe extern "C" fn get_callback<T: Chip>(
+    gc: *mut bindings::gpio_chip,
+    offset: c_types::c_uint,
+) -> c_types::c_int {
+    from_kernel_result! {
+        // SAFETY: The value stored as chip data was returned by `into_pointer` during registration.
+        let data = unsafe { T::Data::borrow(bindings::gpiochip_get_data(gc)) };
+        let v = T::get(data, offset)?;
+        Ok(v as _)
+    }
+}
+
+unsafe extern "C" fn set_callback<T: Chip>(
+    gc: *mut bindings::gpio_chip,
+    offset: c_types::c_uint,
+    value: c_types::c_int,
+) {
+    // SAFETY: The value stored as chip data was returned by `into_pointer` during registration.
+    let data = unsafe { T::Data::borrow(bindings::gpiochip_get_data(gc)) };
+    T::set(data, offset, value != 0);
+}
+
+#[cfg(CONFIG_GPIOLIB_IRQCHIP)]
+mod irqchip {
+    use super::*;
+    use crate::irq;
+
+    /// A gpio chip that includes an irq chip.
+    pub trait ChipWithIrqChip: Chip {
+        /// Implements the irq flow for the gpio chip.
+        fn handle_irq_flow(
+            _data: <Self::Data as PointerWrapper>::Borrowed<'_>,
+            _desc: &irq::Descriptor,
+            _domain: &irq::Domain,
+        );
+    }
+
+    /// A registration of a gpio chip that includes an irq chip.
+    pub struct RegistrationWithIrqChip<T: ChipWithIrqChip> {
+        reg: Registration<T>,
+        irq_chip: UnsafeCell<bindings::irq_chip>,
+        parent_irq: u32,
+    }
+
+    impl<T: ChipWithIrqChip> RegistrationWithIrqChip<T> {
+        /// Creates a new [`RegistrationWithIrqChip`] but does not register it yet.
+        ///
+        /// It is allowed to move.
+        pub fn new() -> Self {
+            Self {
+                reg: Registration::new(),
+                irq_chip: UnsafeCell::new(bindings::irq_chip::default()),
+                parent_irq: 0,
+            }
+        }
+
+        /// Registers a gpio chip and its irq chip with the rest of the kernel.
+        pub fn register<U: irq::Chip<Data = T::Data>>(
+            mut self: Pin<&mut Self>,
+            gpio_count: u16,
+            base: Option<i32>,
+            parent: &dyn device::RawDevice,
+            data: T::Data,
+            parent_irq: u32,
+        ) -> Result {
+            if self.reg.parent.is_some() {
+                // Already registered.
+                return Err(EINVAL);
+            }
+
+            // SAFETY: We never move out of `this`.
+            let this = unsafe { self.as_mut().get_unchecked_mut() };
+
+            // Initialise the irq_chip.
+            {
+                let irq_chip = this.irq_chip.get_mut();
+                irq_chip.name = parent.name().as_char_ptr();
+
+                // SAFETY: The gpio subsystem configures a pointer to `gpio_chip` as the irq chip
+                // data, so we use `IrqChipAdapter` to convert to the `T::Data`, which is the same
+                // as `irq::Chip::Data` per the bound above.
+                unsafe { irq::init_chip::<IrqChipAdapter<U>>(irq_chip) };
+            }
+
+            // Initialise gc irq state.
+            {
+                let girq = &mut this.reg.gc.get_mut().irq;
+                girq.chip = this.irq_chip.get();
+                // SAFETY: By leaving `parent_handler_data` set to `null`, the gpio subsystem
+                // initialises it to a pointer to the gpio chip, which is what `FlowHandler<T>`
+                // expects.
+                girq.parent_handler = unsafe { irq::new_flow_handler::<FlowHandler<T>>() };
+                girq.num_parents = 1;
+                girq.parents = &mut this.parent_irq;
+                this.parent_irq = parent_irq;
+                girq.default_type = bindings::IRQ_TYPE_NONE;
+                girq.handler = Some(bindings::handle_bad_irq);
+            }
+
+            // SAFETY: `reg` is pinned when `self` is.
+            let pinned = unsafe { self.map_unchecked_mut(|r| &mut r.reg) };
+            pinned.register(gpio_count, base, parent, data)
+        }
+    }
+
+    impl<T: ChipWithIrqChip> Default for RegistrationWithIrqChip<T> {
+        fn default() -> Self {
+            Self::new()
+        }
+    }
+
+    // SAFETY: `RegistrationWithIrqChip` doesn't offer any methods or access to fields when shared
+    // between threads or CPUs, so it is safe to share it.
+    unsafe impl<T: ChipWithIrqChip> Sync for RegistrationWithIrqChip<T> {}
+
+    // SAFETY: Registration with and unregistration from the gpio subsystem (including irq chips for
+    // them) can happen from any thread. Additionally, `T::Data` (which is dropped during
+    // unregistration) is `Send`, so it is ok to move `Registration` to different threads.
+    #[allow(clippy::non_send_fields_in_send_ty)]
+    unsafe impl<T: ChipWithIrqChip> Send for RegistrationWithIrqChip<T> where T::Data: Send {}
+
+    struct FlowHandler<T: ChipWithIrqChip>(PhantomData<T>);
+
+    impl<T: ChipWithIrqChip> irq::FlowHandler for FlowHandler<T> {
+        type Data = *mut bindings::gpio_chip;
+
+        fn handle_irq_flow(gc: *mut bindings::gpio_chip, desc: &irq::Descriptor) {
+            // SAFETY: `FlowHandler` is only used in gpio chips, and it is removed when the gpio is
+            // unregistered, so we know that `gc` must still be valid. We also know that the value
+            // stored as gpio data was returned by `T::Data::into_pointer` again because
+            // `FlowHandler` is a private structure only used in this way.
+            let data = unsafe { T::Data::borrow(bindings::gpiochip_get_data(gc)) };
+
+            // SAFETY: `gc` is valid (see comment above), so we can dereference it.
+            let domain = unsafe { irq::Domain::from_ptr((*gc).irq.domain) };
+
+            T::handle_irq_flow(data, desc, &domain);
+        }
+    }
+
+    /// Adapter from an irq chip with `gpio_chip` pointer as context to one where the gpio chip
+    /// data is passed as context.
+    struct IrqChipAdapter<T: irq::Chip>(PhantomData<T>);
+
+    impl<T: irq::Chip> irq::Chip for IrqChipAdapter<T> {
+        type Data = *mut bindings::gpio_chip;
+        const TO_USE: irq::ToUse = T::TO_USE;
+
+        fn ack(gc: *mut bindings::gpio_chip, irq_data: &irq::IrqData) {
+            // SAFETY: `IrqChipAdapter` is a private struct, only used when the data stored in the
+            // gpio chip is known to come from `T::Data`, and only valid while the gpio chip is
+            // registered, so `gc` is valid.
+            let data = unsafe { T::Data::borrow(bindings::gpiochip_get_data(gc as _)) };
+            T::ack(data, irq_data);
+        }
+
+        fn mask(gc: *mut bindings::gpio_chip, irq_data: &irq::IrqData) {
+            // SAFETY: `IrqChipAdapter` is a private struct, only used when the data stored in the
+            // gpio chip is known to come from `T::Data`, and only valid while the gpio chip is
+            // registered, so `gc` is valid.
+            let data = unsafe { T::Data::borrow(bindings::gpiochip_get_data(gc as _)) };
+            T::mask(data, irq_data);
+        }
+
+        fn unmask(gc: *mut bindings::gpio_chip, irq_data: &irq::IrqData) {
+            // SAFETY: `IrqChipAdapter` is a private struct, only used when the data stored in the
+            // gpio chip is known to come from `T::Data`, and only valid while the gpio chip is
+            // registered, so `gc` is valid.
+            let data = unsafe { T::Data::borrow(bindings::gpiochip_get_data(gc as _)) };
+            T::unmask(data, irq_data);
+        }
+
+        fn set_type(
+            gc: *mut bindings::gpio_chip,
+            irq_data: &mut irq::LockedIrqData,
+            flow_type: u32,
+        ) -> Result<irq::ExtraResult> {
+            // SAFETY: `IrqChipAdapter` is a private struct, only used when the data stored in the
+            // gpio chip is known to come from `T::Data`, and only valid while the gpio chip is
+            // registered, so `gc` is valid.
+            let data = unsafe { T::Data::borrow(bindings::gpiochip_get_data(gc as _)) };
+            T::set_type(data, irq_data, flow_type)
+        }
+
+        fn set_wake(gc: *mut bindings::gpio_chip, irq_data: &irq::IrqData, on: bool) -> Result {
+            // SAFETY: `IrqChipAdapter` is a private struct, only used when the data stored in the
+            // gpio chip is known to come from `T::Data`, and only valid while the gpio chip is
+            // registered, so `gc` is valid.
+            let data = unsafe { T::Data::borrow(bindings::gpiochip_get_data(gc as _)) };
+            T::set_wake(data, irq_data, on)
+        }
+    }
+}
diff --git a/rust/kernel/hwrng.rs b/rust/kernel/hwrng.rs
new file mode 100644
index 000000000000..a50de9510631
--- /dev/null
+++ b/rust/kernel/hwrng.rs
@@ -0,0 +1,242 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Hardware Random Number Generator.
+//!
+//! C header: [`include/linux/hw_random.h`](../../../../include/linux/hw_random.h)
+
+use alloc::{boxed::Box, slice::from_raw_parts_mut};
+
+use crate::{
+    bindings, c_types, error::code::*, error::from_kernel_result, str::CString, to_result,
+    types::PointerWrapper, Result, ScopeGuard,
+};
+
+use core::{cell::UnsafeCell, fmt, marker::PhantomData, pin::Pin};
+
+/// This trait is implemented in order to provide callbacks to `struct hwrng`.
+pub trait Operations {
+    /// The methods to use to populate [`struct hwrng`].
+    const TO_USE: ToUse;
+
+    /// The pointer type that will be used to hold user-defined data type.
+    type Data: PointerWrapper + Send + Sync = ();
+
+    /// Initialization callback, can be left undefined.
+    fn init(_data: <Self::Data as PointerWrapper>::Borrowed<'_>) -> Result {
+        Err(EINVAL)
+    }
+
+    /// Cleanup callback, can be left undefined.
+    fn cleanup(_data: Self::Data) {}
+
+    /// Read data into the provided buffer.
+    /// Drivers can fill up to max bytes of data into the buffer.
+    /// The buffer is aligned for any type and its size is a multiple of 4 and >= 32 bytes.
+    fn read(
+        data: <Self::Data as PointerWrapper>::Borrowed<'_>,
+        buffer: &mut [u8],
+        wait: bool,
+    ) -> Result<u32>;
+}
+
+/// Registration structure for Hardware Random Number Generator driver.
+pub struct Registration<T: Operations> {
+    hwrng: UnsafeCell<bindings::hwrng>,
+    name: Option<CString>,
+    registered: bool,
+    _p: PhantomData<T>,
+}
+
+impl<T: Operations> Registration<T> {
+    /// Creates new instance of registration.
+    ///
+    /// The data must be registered.
+    pub fn new() -> Self {
+        Self {
+            hwrng: UnsafeCell::new(bindings::hwrng::default()),
+            name: None,
+            registered: false,
+            _p: PhantomData,
+        }
+    }
+
+    /// Returns a registered and pinned, heap-allocated representation of the registration.
+    pub fn new_pinned(
+        name: fmt::Arguments<'_>,
+        quality: u16,
+        data: T::Data,
+    ) -> Result<Pin<Box<Self>>> {
+        let mut reg = Pin::from(Box::try_new(Self::new())?);
+        reg.as_mut().register(name, quality, data)?;
+        Ok(reg)
+    }
+
+    /// Registers a hwrng device within the rest of the kernel.
+    ///
+    /// It must be pinned because the memory block that represents
+    /// the registration may be self-referential.
+    pub fn register(
+        self: Pin<&mut Self>,
+        name: fmt::Arguments<'_>,
+        quality: u16,
+        data: T::Data,
+    ) -> Result {
+        // SAFETY: We never move out of `this`.
+        let this = unsafe { self.get_unchecked_mut() };
+
+        if this.registered {
+            return Err(EINVAL);
+        }
+
+        let data_pointer = data.into_pointer();
+
+        // SAFETY: `data_pointer` comes from the call to `data.into_pointer()` above.
+        let guard = ScopeGuard::new(|| unsafe {
+            T::Data::from_pointer(data_pointer);
+        });
+
+        let name = CString::try_from_fmt(name)?;
+
+        // SAFETY: Registration is pinned and contains allocated and set to zero `bindings::hwrng` structure.
+        Self::init_hwrng(
+            unsafe { &mut *this.hwrng.get() },
+            &name,
+            quality,
+            data_pointer,
+        );
+
+        // SAFETY: `bindings::hwrng` is initialized above which guarantees safety.
+        to_result(|| unsafe { bindings::hwrng_register(this.hwrng.get()) })?;
+
+        this.registered = true;
+        this.name = Some(name);
+        guard.dismiss();
+        Ok(())
+    }
+
+    fn init_hwrng(
+        hwrng: &mut bindings::hwrng,
+        name: &CString,
+        quality: u16,
+        data: *const c_types::c_void,
+    ) {
+        hwrng.name = name.as_char_ptr();
+
+        hwrng.init = if T::TO_USE.init {
+            Some(Self::init_callback)
+        } else {
+            None
+        };
+        hwrng.cleanup = if T::TO_USE.cleanup {
+            Some(Self::cleanup_callback)
+        } else {
+            None
+        };
+        hwrng.data_present = None;
+        hwrng.data_read = None;
+        hwrng.read = Some(Self::read_callback);
+
+        hwrng.priv_ = data as _;
+        hwrng.quality = quality;
+
+        // SAFETY: All fields are properly initialized as
+        // remaining fields `list`, `ref` and `cleanup_done` are already
+        // zeroed by `bindings::hwrng::default()` call.
+    }
+
+    unsafe extern "C" fn init_callback(rng: *mut bindings::hwrng) -> c_types::c_int {
+        from_kernel_result! {
+            // SAFETY: `priv` private data field was initialized during creation of
+            // the `bindings::hwrng` in `Self::init_hwrng` method. This callback is only
+            // called once the driver is registered.
+            let data = unsafe { T::Data::borrow((*rng).priv_ as *const _) };
+            T::init(data)?;
+            Ok(0)
+        }
+    }
+
+    unsafe extern "C" fn cleanup_callback(rng: *mut bindings::hwrng) {
+        // SAFETY: `priv` private data field was initialized during creation of
+        // the `bindings::hwrng` in `Self::init_hwrng` method. This callback is only
+        // called once the driver is registered.
+        let data = unsafe { T::Data::from_pointer((*rng).priv_ as *const _) };
+        T::cleanup(data);
+    }
+
+    unsafe extern "C" fn read_callback(
+        rng: *mut bindings::hwrng,
+        data: *mut c_types::c_void,
+        max: usize,
+        wait: bindings::bool_,
+    ) -> c_types::c_int {
+        from_kernel_result! {
+            // SAFETY: `priv` private data field was initialized during creation of
+            // the `bindings::hwrng` in `Self::init_hwrng` method. This callback is only
+            // called once the driver is registered.
+            let drv_data = unsafe { T::Data::borrow((*rng).priv_ as *const _) };
+
+            // SAFETY: Slice is created from `data` and `max` arguments that are C's buffer
+            // along with its size in bytes that are safe for this conversion.
+            let buffer = unsafe { from_raw_parts_mut(data as *mut u8, max) };
+            let ret = T::read(drv_data, buffer, wait)?;
+            Ok(ret as _)
+        }
+    }
+}
+
+impl<T: Operations> Default for Registration<T> {
+    fn default() -> Self {
+        Self::new()
+    }
+}
+
+/// Represents which callbacks of [`struct hwrng`] should be populated with pointers.
+pub struct ToUse {
+    /// The `init` field of [`struct hwrng`].
+    pub init: bool,
+
+    /// The `cleanup` field of [`struct hwrng`].
+    pub cleanup: bool,
+}
+
+/// A constant version where all values are to set to `false`, that is, all supported fields will
+/// be set to null pointers.
+pub const USE_NONE: ToUse = ToUse {
+    init: false,
+    cleanup: false,
+};
+
+/// Defines the [`Operations::TO_USE`] field based on a list of fields to be populated.
+#[macro_export]
+macro_rules! declare_hwrng_operations {
+    () => {
+        const TO_USE: $crate::hwrng::ToUse = $crate::hwrng::USE_NONE;
+    };
+    ($($i:ident),+) => {
+        #[allow(clippy::needless_update)]
+        const TO_USE: kernel::hwrng::ToUse =
+            $crate::hwrng::ToUse {
+                $($i: true),+ ,
+                ..$crate::hwrng::USE_NONE
+            };
+    };
+}
+
+// SAFETY: `Registration` does not expose any of its state across threads.
+unsafe impl<T: Operations> Sync for Registration<T> {}
+
+// SAFETY: `Registration` is not restricted to a single thread,
+// its `T::Data` is also `Send` so it may be moved to different threads.
+#[allow(clippy::non_send_fields_in_send_ty)]
+unsafe impl<T: Operations> Send for Registration<T> {}
+
+impl<T: Operations> Drop for Registration<T> {
+    /// Removes the registration from the kernel if it has completed successfully before.
+    fn drop(&mut self) {
+        // SAFETY: The instance of Registration<T> is unregistered only
+        // after being initialized and registered before.
+        if self.registered {
+            unsafe { bindings::hwrng_unregister(self.hwrng.get()) };
+        }
+    }
+}
diff --git a/rust/kernel/io_buffer.rs b/rust/kernel/io_buffer.rs
new file mode 100644
index 000000000000..ccecc4763aca
--- /dev/null
+++ b/rust/kernel/io_buffer.rs
@@ -0,0 +1,153 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Buffers used in IO.
+
+use crate::Result;
+use alloc::vec::Vec;
+use core::mem::{size_of, MaybeUninit};
+
+/// Represents a buffer to be read from during IO.
+pub trait IoBufferReader {
+    /// Returns the number of bytes left to be read from the io buffer.
+    ///
+    /// Note that even reading less than this number of bytes may fail.
+    fn len(&self) -> usize;
+
+    /// Returns `true` if no data is available in the io buffer.
+    fn is_empty(&self) -> bool {
+        self.len() == 0
+    }
+
+    /// Reads raw data from the io buffer into a raw kernel buffer.
+    ///
+    /// # Safety
+    ///
+    /// The output buffer must be valid.
+    unsafe fn read_raw(&mut self, out: *mut u8, len: usize) -> Result;
+
+    /// Reads all data remaining in the io buffer.
+    ///
+    /// Returns `EFAULT` if the address does not currently point to mapped, readable memory.
+    fn read_all(&mut self) -> Result<Vec<u8>> {
+        let mut data = Vec::<u8>::new();
+        data.try_resize(self.len(), 0)?;
+
+        // SAFETY: The output buffer is valid as we just allocated it.
+        unsafe { self.read_raw(data.as_mut_ptr(), data.len())? };
+        Ok(data)
+    }
+
+    /// Reads a byte slice from the io buffer.
+    ///
+    /// Returns `EFAULT` if the byte slice is bigger than the remaining size of the user slice or
+    /// if the address does not currently point to mapped, readable memory.
+    fn read_slice(&mut self, data: &mut [u8]) -> Result {
+        // SAFETY: The output buffer is valid as it's coming from a live reference.
+        unsafe { self.read_raw(data.as_mut_ptr(), data.len()) }
+    }
+
+    /// Reads the contents of a plain old data (POD) type from the io buffer.
+    fn read<T: ReadableFromBytes>(&mut self) -> Result<T> {
+        let mut out = MaybeUninit::<T>::uninit();
+        // SAFETY: The buffer is valid as it was just allocated.
+        unsafe { self.read_raw(out.as_mut_ptr() as _, size_of::<T>()) }?;
+        // SAFETY: We just initialised the data.
+        Ok(unsafe { out.assume_init() })
+    }
+}
+
+/// Represents a buffer to be written to during IO.
+pub trait IoBufferWriter {
+    /// Returns the number of bytes left to be written into the io buffer.
+    ///
+    /// Note that even writing less than this number of bytes may fail.
+    fn len(&self) -> usize;
+
+    /// Returns `true` if the io buffer cannot hold any additional data.
+    fn is_empty(&self) -> bool {
+        self.len() == 0
+    }
+
+    /// Writes zeroes to the io buffer.
+    ///
+    /// Differently from the other write functions, `clear` will zero as much as it can and update
+    /// the writer internal state to reflect this. It will, however, return an error if it cannot
+    /// clear `len` bytes.
+    ///
+    /// For example, if a caller requests that 100 bytes be cleared but a segfault happens after
+    /// 20 bytes, then EFAULT is returned and the writer is advanced by 20 bytes.
+    fn clear(&mut self, len: usize) -> Result;
+
+    /// Writes a byte slice into the io buffer.
+    ///
+    /// Returns `EFAULT` if the byte slice is bigger than the remaining size of the io buffer or if
+    /// the address does not currently point to mapped, writable memory.
+    fn write_slice(&mut self, data: &[u8]) -> Result {
+        // SAFETY: The input buffer is valid as it's coming from a live reference.
+        unsafe { self.write_raw(data.as_ptr(), data.len()) }
+    }
+
+    /// Writes raw data to the io buffer from a raw kernel buffer.
+    ///
+    /// # Safety
+    ///
+    /// The input buffer must be valid.
+    unsafe fn write_raw(&mut self, data: *const u8, len: usize) -> Result;
+
+    /// Writes the contents of the given data into the io buffer.
+    fn write<T: WritableToBytes>(&mut self, data: &T) -> Result {
+        // SAFETY: The input buffer is valid as it's coming from a live
+        // reference to a type that implements `WritableToBytes`.
+        unsafe { self.write_raw(data as *const T as _, size_of::<T>()) }
+    }
+}
+
+/// Specifies that a type is safely readable from byte slices.
+///
+/// Not all types can be safely read from byte slices; examples from
+/// <https://doc.rust-lang.org/reference/behavior-considered-undefined.html> include `bool`
+/// that must be either `0` or `1`, and `char` that cannot be a surrogate or above `char::MAX`.
+///
+/// # Safety
+///
+/// Implementers must ensure that the type is made up only of types that can be safely read from
+/// arbitrary byte sequences (e.g., `u32`, `u64`, etc.).
+pub unsafe trait ReadableFromBytes {}
+
+// SAFETY: All bit patterns are acceptable values of the types below.
+unsafe impl ReadableFromBytes for u8 {}
+unsafe impl ReadableFromBytes for u16 {}
+unsafe impl ReadableFromBytes for u32 {}
+unsafe impl ReadableFromBytes for u64 {}
+unsafe impl ReadableFromBytes for usize {}
+unsafe impl ReadableFromBytes for i8 {}
+unsafe impl ReadableFromBytes for i16 {}
+unsafe impl ReadableFromBytes for i32 {}
+unsafe impl ReadableFromBytes for i64 {}
+unsafe impl ReadableFromBytes for isize {}
+
+/// Specifies that a type is safely writable to byte slices.
+///
+/// This means that we don't read undefined values (which leads to UB) in preparation for writing
+/// to the byte slice. It also ensures that no potentially sensitive information is leaked into the
+/// byte slices.
+///
+/// # Safety
+///
+/// A type must not include padding bytes and must be fully initialised to safely implement
+/// [`WritableToBytes`] (i.e., it doesn't contain [`MaybeUninit`] fields). A composition of
+/// writable types in a structure is not necessarily writable because it may result in padding
+/// bytes.
+pub unsafe trait WritableToBytes {}
+
+// SAFETY: Initialised instances of the following types have no uninitialised portions.
+unsafe impl WritableToBytes for u8 {}
+unsafe impl WritableToBytes for u16 {}
+unsafe impl WritableToBytes for u32 {}
+unsafe impl WritableToBytes for u64 {}
+unsafe impl WritableToBytes for usize {}
+unsafe impl WritableToBytes for i8 {}
+unsafe impl WritableToBytes for i16 {}
+unsafe impl WritableToBytes for i32 {}
+unsafe impl WritableToBytes for i64 {}
+unsafe impl WritableToBytes for isize {}
diff --git a/rust/kernel/io_mem.rs b/rust/kernel/io_mem.rs
new file mode 100644
index 000000000000..25096fe43675
--- /dev/null
+++ b/rust/kernel/io_mem.rs
@@ -0,0 +1,275 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Memory-mapped IO.
+//!
+//! C header: [`include/asm-generic/io.h`](../../../../include/asm-generic/io.h)
+
+#![allow(dead_code)]
+
+use crate::{bindings, error::code::*, Result};
+use core::convert::TryInto;
+
+/// Represents a memory resource.
+pub struct Resource {
+    offset: bindings::resource_size_t,
+    size: bindings::resource_size_t,
+}
+
+impl Resource {
+    pub(crate) fn new(
+        start: bindings::resource_size_t,
+        end: bindings::resource_size_t,
+    ) -> Option<Self> {
+        if start == 0 {
+            return None;
+        }
+        Some(Self {
+            offset: start,
+            size: end.checked_sub(start)?.checked_add(1)?,
+        })
+    }
+}
+
+/// Represents a memory block of at least `SIZE` bytes.
+///
+/// # Invariants
+///
+/// `ptr` is a non-null and valid address of at least `SIZE` bytes and returned by an `ioremap`
+/// variant. `ptr` is also 8-byte aligned.
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::prelude::*;
+/// use kernel::io_mem::{IoMem, Resource};
+///
+/// fn test(res: Resource) -> Result {
+///     // Create an io mem block of at least 100 bytes.
+///     // SAFETY: No DMA operations are initiated through `mem`.
+///     let mem = unsafe { IoMem::<100>::try_new(res) }?;
+///
+///     // Read one byte from offset 10.
+///     let v = mem.readb(10);
+///
+///     // Write value to offset 20.
+///     mem.writeb(v, 20);
+///
+///     Ok(())
+/// }
+///
+/// ```
+pub struct IoMem<const SIZE: usize> {
+    ptr: usize,
+}
+
+macro_rules! define_read {
+    ($(#[$attr:meta])* $name:ident, $try_name:ident, $type_name:ty) => {
+        /// Reads IO data from the given offset known, at compile time.
+        ///
+        /// If the offset is not known at compile time, the build will fail.
+        $(#[$attr])*
+        pub fn $name(&self, offset: usize) -> $type_name {
+            Self::check_offset::<$type_name>(offset);
+            let ptr = self.ptr.wrapping_add(offset);
+            // SAFETY: The type invariants guarantee that `ptr` is a valid pointer. The check above
+            // guarantees that the code won't build if `offset` makes the read go out of bounds
+            // (including the type size).
+            unsafe { bindings::$name(ptr as _) }
+        }
+
+        /// Reads IO data from the given offset.
+        ///
+        /// It fails if/when the offset (plus the type size) is out of bounds.
+        $(#[$attr])*
+        pub fn $try_name(&self, offset: usize) -> Result<$type_name> {
+            if !Self::offset_ok::<$type_name>(offset) {
+                return Err(EINVAL);
+            }
+            let ptr = self.ptr.wrapping_add(offset);
+            // SAFETY: The type invariants guarantee that `ptr` is a valid pointer. The check above
+            // returns an error if `offset` would make the read go out of bounds (including the
+            // type size).
+            Ok(unsafe { bindings::$name(ptr as _) })
+        }
+    };
+}
+
+macro_rules! define_write {
+    ($(#[$attr:meta])* $name:ident, $try_name:ident, $type_name:ty) => {
+        /// Writes IO data to the given offset, known at compile time.
+        ///
+        /// If the offset is not known at compile time, the build will fail.
+        $(#[$attr])*
+        pub fn $name(&self, value: $type_name, offset: usize) {
+            Self::check_offset::<$type_name>(offset);
+            let ptr = self.ptr.wrapping_add(offset);
+            // SAFETY: The type invariants guarantee that `ptr` is a valid pointer. The check above
+            // guarantees that the code won't link if `offset` makes the write go out of bounds
+            // (including the type size).
+            unsafe { bindings::$name(value, ptr as _) }
+        }
+
+        /// Writes IO data to the given offset.
+        ///
+        /// It fails if/when the offset (plus the type size) is out of bounds.
+        $(#[$attr])*
+        pub fn $try_name(&self, value: $type_name, offset: usize) -> Result {
+            if !Self::offset_ok::<$type_name>(offset) {
+                return Err(EINVAL);
+            }
+            let ptr = self.ptr.wrapping_add(offset);
+            // SAFETY: The type invariants guarantee that `ptr` is a valid pointer. The check above
+            // returns an error if `offset` would make the write go out of bounds (including the
+            // type size).
+            unsafe { bindings::$name(value, ptr as _) };
+            Ok(())
+        }
+    };
+}
+
+impl<const SIZE: usize> IoMem<SIZE> {
+    /// Tries to create a new instance of a memory block.
+    ///
+    /// The resource described by `res` is mapped into the CPU's address space so that it can be
+    /// accessed directly. It is also consumed by this function so that it can't be mapped again
+    /// to a different address.
+    ///
+    /// # Safety
+    ///
+    /// Callers must ensure that either (a) the resulting interface cannot be used to initiate DMA
+    /// operations, or (b) that DMA operations initiated via the returned interface use DMA handles
+    /// allocated through the `dma` module.
+    pub unsafe fn try_new(res: Resource) -> Result<Self> {
+        // Check that the resource has at least `SIZE` bytes in it.
+        if res.size < SIZE.try_into()? {
+            return Err(EINVAL);
+        }
+
+        // To be able to check pointers at compile time based only on offsets, we need to guarantee
+        // that the base pointer is minimally aligned. So we conservatively expect at least 8 bytes.
+        if res.offset % 8 != 0 {
+            crate::pr_err!("Physical address is not 64-bit aligned: {:x}", res.offset);
+            return Err(EDOM);
+        }
+
+        // Try to map the resource.
+        // SAFETY: Just mapping the memory range.
+        let addr = unsafe { bindings::ioremap(res.offset, res.size as _) };
+        if addr.is_null() {
+            Err(ENOMEM)
+        } else {
+            // INVARIANT: `addr` is non-null and was returned by `ioremap`, so it is valid. It is
+            // also 8-byte aligned because we checked it above.
+            Ok(Self { ptr: addr as usize })
+        }
+    }
+
+    const fn offset_ok<T>(offset: usize) -> bool {
+        let type_size = core::mem::size_of::<T>();
+        if let Some(end) = offset.checked_add(type_size) {
+            end <= SIZE && offset % type_size == 0
+        } else {
+            false
+        }
+    }
+
+    fn offset_ok_of_val<T: ?Sized>(offset: usize, value: &T) -> bool {
+        let value_size = core::mem::size_of_val(value);
+        let value_alignment = core::mem::align_of_val(value);
+        if let Some(end) = offset.checked_add(value_size) {
+            end <= SIZE && offset % value_alignment == 0
+        } else {
+            false
+        }
+    }
+
+    const fn check_offset<T>(offset: usize) {
+        crate::build_assert!(Self::offset_ok::<T>(offset), "IoMem offset overflow");
+    }
+
+    /// Copy memory block from an i/o memory by filling the specified buffer with it.
+    ///
+    /// # Examples
+    /// ```
+    /// use kernel::io_mem::{self, IoMem, Resource};
+    ///
+    /// fn test(res: Resource) -> Result {
+    ///     // Create an i/o memory block of at least 100 bytes.
+    ///     let mem = unsafe { IoMem::<100>::try_new(res) }?;
+    ///
+    ///     let mut buffer: [u8; 32] = [0; 32];
+    ///
+    ///     // Memcpy 16 bytes from an offset 10 of i/o memory block into the buffer.
+    ///     mem.try_memcpy_fromio(&mut buffer[..16], 10)?;
+    ///
+    ///     Ok(())
+    /// }
+    /// ```
+    pub fn try_memcpy_fromio(&self, buffer: &mut [u8], offset: usize) -> Result {
+        if !Self::offset_ok_of_val(offset, buffer) {
+            return Err(EINVAL);
+        }
+
+        let ptr = self.ptr.wrapping_add(offset);
+
+        // SAFETY:
+        //   - The type invariants guarantee that `ptr` is a valid pointer.
+        //   - The bounds of `buffer` are checked with a call to `offset_ok_of_val()`.
+        unsafe {
+            bindings::memcpy_fromio(
+                buffer.as_mut_ptr() as *mut _,
+                ptr as *const _,
+                buffer.len() as _,
+            )
+        };
+        Ok(())
+    }
+
+    define_read!(readb, try_readb, u8);
+    define_read!(readw, try_readw, u16);
+    define_read!(readl, try_readl, u32);
+    define_read!(
+        #[cfg(CONFIG_64BIT)]
+        readq,
+        try_readq,
+        u64
+    );
+
+    define_read!(readb_relaxed, try_readb_relaxed, u8);
+    define_read!(readw_relaxed, try_readw_relaxed, u16);
+    define_read!(readl_relaxed, try_readl_relaxed, u32);
+    define_read!(
+        #[cfg(CONFIG_64BIT)]
+        readq_relaxed,
+        try_readq_relaxed,
+        u64
+    );
+
+    define_write!(writeb, try_writeb, u8);
+    define_write!(writew, try_writew, u16);
+    define_write!(writel, try_writel, u32);
+    define_write!(
+        #[cfg(CONFIG_64BIT)]
+        writeq,
+        try_writeq,
+        u64
+    );
+
+    define_write!(writeb_relaxed, try_writeb_relaxed, u8);
+    define_write!(writew_relaxed, try_writew_relaxed, u16);
+    define_write!(writel_relaxed, try_writel_relaxed, u32);
+    define_write!(
+        #[cfg(CONFIG_64BIT)]
+        writeq_relaxed,
+        try_writeq_relaxed,
+        u64
+    );
+}
+
+impl<const SIZE: usize> Drop for IoMem<SIZE> {
+    fn drop(&mut self) {
+        // SAFETY: By the type invariant, `self.ptr` is a value returned by a previous successful
+        // call to `ioremap`.
+        unsafe { bindings::iounmap(self.ptr as _) };
+    }
+}
diff --git a/rust/kernel/iov_iter.rs b/rust/kernel/iov_iter.rs
new file mode 100644
index 000000000000..b9b8dc882bd0
--- /dev/null
+++ b/rust/kernel/iov_iter.rs
@@ -0,0 +1,81 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! IO vector iterators.
+//!
+//! C header: [`include/linux/uio.h`](../../../../include/linux/uio.h)
+
+use crate::{
+    bindings,
+    error::code::*,
+    io_buffer::{IoBufferReader, IoBufferWriter},
+    Result,
+};
+
+/// Wraps the kernel's `struct iov_iter`.
+///
+/// # Invariants
+///
+/// The pointer `IovIter::ptr` is non-null and valid.
+pub struct IovIter {
+    ptr: *mut bindings::iov_iter,
+}
+
+impl IovIter {
+    fn common_len(&self) -> usize {
+        // SAFETY: `IovIter::ptr` is guaranteed to be valid by the type invariants.
+        unsafe { (*self.ptr).count }
+    }
+
+    /// Constructs a new [`struct iov_iter`] wrapper.
+    ///
+    /// # Safety
+    ///
+    /// The pointer `ptr` must be non-null and valid for the lifetime of the object.
+    pub(crate) unsafe fn from_ptr(ptr: *mut bindings::iov_iter) -> Self {
+        // INVARIANTS: the safety contract ensures the type invariant will hold.
+        Self { ptr }
+    }
+}
+
+impl IoBufferWriter for IovIter {
+    fn len(&self) -> usize {
+        self.common_len()
+    }
+
+    fn clear(&mut self, mut len: usize) -> Result {
+        while len > 0 {
+            // SAFETY: `IovIter::ptr` is guaranteed to be valid by the type invariants.
+            let written = unsafe { bindings::iov_iter_zero(len, self.ptr) };
+            if written == 0 {
+                return Err(EFAULT);
+            }
+
+            len -= written;
+        }
+        Ok(())
+    }
+
+    unsafe fn write_raw(&mut self, data: *const u8, len: usize) -> Result {
+        let res = unsafe { bindings::copy_to_iter(data as _, len, self.ptr) };
+        if res != len {
+            Err(EFAULT)
+        } else {
+            Ok(())
+        }
+    }
+}
+
+impl IoBufferReader for IovIter {
+    fn len(&self) -> usize {
+        self.common_len()
+    }
+
+    unsafe fn read_raw(&mut self, out: *mut u8, len: usize) -> Result {
+        let res = unsafe { bindings::copy_from_iter(out as _, len, self.ptr) };
+        if res != len {
+            Err(EFAULT)
+        } else {
+            Ok(())
+        }
+    }
+}
diff --git a/rust/kernel/irq.rs b/rust/kernel/irq.rs
new file mode 100644
index 000000000000..ca62849a5dc0
--- /dev/null
+++ b/rust/kernel/irq.rs
@@ -0,0 +1,409 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Interrupts and interrupt chips.
+//!
+//! See <https://www.kernel.org/doc/Documentation/core-api/genericirq.rst>.
+//!
+//! C headers: [`include/linux/irq.h`](../../../../include/linux/irq.h) and
+//! [`include/linux/interrupt.h`](../../../../include/linux/interrupt.h).
+
+#![allow(dead_code)]
+
+use crate::{bindings, c_types, error::from_kernel_result, types::PointerWrapper, Error, Result};
+use core::ops::Deref;
+
+/// The type of irq hardware numbers.
+pub type HwNumber = bindings::irq_hw_number_t;
+
+/// Wraps the kernel's `struct irq_data`.
+///
+/// # Invariants
+///
+/// The pointer `IrqData::ptr` is non-null and valid.
+pub struct IrqData {
+    ptr: *mut bindings::irq_data,
+}
+
+impl IrqData {
+    /// Creates a new `IrqData` instance from a raw pointer.
+    ///
+    /// # Safety
+    ///
+    /// Callers must ensure that `ptr` is non-null and valid when the function is called, and that
+    /// it remains valid for the lifetime of the return [`IrqData`] instance.
+    unsafe fn from_ptr(ptr: *mut bindings::irq_data) -> Self {
+        // INVARIANTS: By the safety requirements, the instance we're creating satisfies the type
+        // invariants.
+        Self { ptr }
+    }
+
+    /// Returns the hardware irq number.
+    pub fn hwirq(&self) -> HwNumber {
+        // SAFETY: By the type invariants, it's ok to dereference `ptr`.
+        unsafe { (*self.ptr).hwirq }
+    }
+}
+
+/// Wraps the kernel's `struct irq_data` when it is locked.
+///
+/// Being locked allows additional operations to be performed on the data.
+pub struct LockedIrqData(IrqData);
+
+impl LockedIrqData {
+    /// Sets the high-level irq flow handler to the builtin one for level-triggered irqs.
+    pub fn set_level_handler(&mut self) {
+        // SAFETY: By the type invariants of `self.0`, we know `self.0.ptr` is valid.
+        unsafe { bindings::irq_set_handler_locked(self.0.ptr, Some(bindings::handle_level_irq)) };
+    }
+
+    /// Sets the high-level irq flow handler to the builtin one for edge-triggered irqs.
+    pub fn set_edge_handler(&mut self) {
+        // SAFETY: By the type invariants of `self.0`, we know `self.0.ptr` is valid.
+        unsafe { bindings::irq_set_handler_locked(self.0.ptr, Some(bindings::handle_edge_irq)) };
+    }
+
+    /// Sets the high-level irq flow handler to the builtin one for bad irqs.
+    pub fn set_bad_handler(&mut self) {
+        // SAFETY: By the type invariants of `self.0`, we know `self.0.ptr` is valid.
+        unsafe { bindings::irq_set_handler_locked(self.0.ptr, Some(bindings::handle_bad_irq)) };
+    }
+}
+
+impl Deref for LockedIrqData {
+    type Target = IrqData;
+
+    fn deref(&self) -> &Self::Target {
+        &self.0
+    }
+}
+
+/// Extra information returned by some of the [`Chip`] methods on success.
+pub enum ExtraResult {
+    /// Indicates that the caller (irq core) will update the descriptor state.
+    None = bindings::IRQ_SET_MASK_OK as _,
+
+    /// Indicates that the callee (irq chip implementation) already updated the descriptor state.
+    NoCopy = bindings::IRQ_SET_MASK_OK_NOCOPY as _,
+
+    /// Same as [`ExtraResult::None`] in terms of updating descriptor state. It is used in stacked
+    /// irq chips to indicate that descendant chips should be skipped.
+    Done = bindings::IRQ_SET_MASK_OK_DONE as _,
+}
+
+/// An irq chip.
+///
+/// It is a trait for the functions defined in [`struct irq_chip`].
+///
+/// [`struct irq_chip`]: ../../../include/linux/irq.h
+pub trait Chip: Sized {
+    /// The type of the context data stored in the irq chip and made available on each callback.
+    type Data: PointerWrapper;
+
+    /// The methods to use to populate [`struct irq_chip`]. This is typically populated with
+    /// [`declare_irq_chip_operations`].
+    const TO_USE: ToUse;
+
+    /// Called at the start of a new interrupt.
+    fn ack(data: <Self::Data as PointerWrapper>::Borrowed<'_>, irq_data: &IrqData);
+
+    /// Masks an interrupt source.
+    fn mask(data: <Self::Data as PointerWrapper>::Borrowed<'_>, irq_data: &IrqData);
+
+    /// Unmasks an interrupt source.
+    fn unmask(_data: <Self::Data as PointerWrapper>::Borrowed<'_>, irq_data: &IrqData);
+
+    /// Sets the flow type of an interrupt.
+    ///
+    /// The flow type is a combination of the constants in [`Type`].
+    fn set_type(
+        _data: <Self::Data as PointerWrapper>::Borrowed<'_>,
+        _irq_data: &mut LockedIrqData,
+        _flow_type: u32,
+    ) -> Result<ExtraResult> {
+        Ok(ExtraResult::None)
+    }
+
+    /// Enables or disables power-management wake-on of an interrupt.
+    fn set_wake(
+        _data: <Self::Data as PointerWrapper>::Borrowed<'_>,
+        _irq_data: &IrqData,
+        _on: bool,
+    ) -> Result {
+        Ok(())
+    }
+}
+
+/// Initialises `chip` with the callbacks defined in `T`.
+///
+/// # Safety
+///
+/// The caller must ensure that the value stored in the irq chip data is the result of calling
+/// [`PointerWrapper::into_pointer] for the [`T::Data`] type.
+pub(crate) unsafe fn init_chip<T: Chip>(chip: &mut bindings::irq_chip) {
+    chip.irq_ack = Some(irq_ack_callback::<T>);
+    chip.irq_mask = Some(irq_mask_callback::<T>);
+    chip.irq_unmask = Some(irq_unmask_callback::<T>);
+
+    if T::TO_USE.set_type {
+        chip.irq_set_type = Some(irq_set_type_callback::<T>);
+    }
+
+    if T::TO_USE.set_wake {
+        chip.irq_set_wake = Some(irq_set_wake_callback::<T>);
+    }
+}
+
+/// Represents which fields of [`struct irq_chip`] should be populated with pointers.
+///
+/// This is typically populated with the [`declare_irq_chip_operations`] macro.
+pub struct ToUse {
+    /// The `irq_set_type` field of [`struct irq_chip`].
+    pub set_type: bool,
+
+    /// The `irq_set_wake` field of [`struct irq_chip`].
+    pub set_wake: bool,
+}
+
+/// A constant version where all values are to set to `false`, that is, all supported fields will
+/// be set to null pointers.
+pub const USE_NONE: ToUse = ToUse {
+    set_type: false,
+    set_wake: false,
+};
+
+/// Defines the [`Chip::TO_USE`] field based on a list of fields to be populated.
+#[macro_export]
+macro_rules! declare_irq_chip_operations {
+    () => {
+        const TO_USE: $crate::irq::ToUse = $crate::irq::USE_NONE;
+    };
+    ($($i:ident),+) => {
+        #[allow(clippy::needless_update)]
+        const TO_USE: $crate::irq::ToUse =
+            $crate::irq::ToUse {
+                $($i: true),+ ,
+                ..$crate::irq::USE_NONE
+            };
+    };
+}
+
+/// Enables or disables power-management wake-on for the given irq number.
+pub fn set_wake(irq: u32, on: bool) -> Result {
+    // SAFETY: Just an FFI call, there are no extra requirements for safety.
+    let ret = unsafe { bindings::irq_set_irq_wake(irq, on as _) };
+    if ret < 0 {
+        Err(Error::from_kernel_errno(ret))
+    } else {
+        Ok(())
+    }
+}
+
+unsafe extern "C" fn irq_ack_callback<T: Chip>(irq_data: *mut bindings::irq_data) {
+    // SAFETY: The safety requirements of `init_chip`, which is the only place that uses this
+    // callback, ensure that the value stored as irq chip data comes from a previous call to
+    // `PointerWrapper::into_pointer`.
+    let data = unsafe { T::Data::borrow(bindings::irq_data_get_irq_chip_data(irq_data)) };
+
+    // SAFETY: The value returned by `IrqData` is only valid until the end of this function, and
+    // `irq_data` is guaranteed to be valid until then (by the contract with C code).
+    T::ack(data, unsafe { &IrqData::from_ptr(irq_data) })
+}
+
+unsafe extern "C" fn irq_mask_callback<T: Chip>(irq_data: *mut bindings::irq_data) {
+    // SAFETY: The safety requirements of `init_chip`, which is the only place that uses this
+    // callback, ensure that the value stored as irq chip data comes from a previous call to
+    // `PointerWrapper::into_pointer`.
+    let data = unsafe { T::Data::borrow(bindings::irq_data_get_irq_chip_data(irq_data)) };
+
+    // SAFETY: The value returned by `IrqData` is only valid until the end of this function, and
+    // `irq_data` is guaranteed to be valid until then (by the contract with C code).
+    T::mask(data, unsafe { &IrqData::from_ptr(irq_data) })
+}
+
+unsafe extern "C" fn irq_unmask_callback<T: Chip>(irq_data: *mut bindings::irq_data) {
+    // SAFETY: The safety requirements of `init_chip`, which is the only place that uses this
+    // callback, ensure that the value stored as irq chip data comes from a previous call to
+    // `PointerWrapper::into_pointer`.
+    let data = unsafe { T::Data::borrow(bindings::irq_data_get_irq_chip_data(irq_data)) };
+
+    // SAFETY: The value returned by `IrqData` is only valid until the end of this function, and
+    // `irq_data` is guaranteed to be valid until then (by the contract with C code).
+    T::unmask(data, unsafe { &IrqData::from_ptr(irq_data) })
+}
+
+unsafe extern "C" fn irq_set_type_callback<T: Chip>(
+    irq_data: *mut bindings::irq_data,
+    flow_type: c_types::c_uint,
+) -> c_types::c_int {
+    from_kernel_result! {
+        // SAFETY: The safety requirements of `init_chip`, which is the only place that uses this
+        // callback, ensure that the value stored as irq chip data comes from a previous call to
+        // `PointerWrapper::into_pointer`.
+        let data = unsafe { T::Data::borrow(bindings::irq_data_get_irq_chip_data(irq_data)) };
+
+        // SAFETY: The value returned by `IrqData` is only valid until the end of this function, and
+        // `irq_data` is guaranteed to be valid until then (by the contract with C code).
+        let ret = T::set_type(data, &mut LockedIrqData(unsafe { IrqData::from_ptr(irq_data) }), flow_type)?;
+        Ok(ret as _)
+    }
+}
+
+unsafe extern "C" fn irq_set_wake_callback<T: Chip>(
+    irq_data: *mut bindings::irq_data,
+    on: c_types::c_uint,
+) -> c_types::c_int {
+    from_kernel_result! {
+        // SAFETY: The safety requirements of `init_chip`, which is the only place that uses this
+        // callback, ensure that the value stored as irq chip data comes from a previous call to
+        // `PointerWrapper::into_pointer`.
+        let data = unsafe { T::Data::borrow(bindings::irq_data_get_irq_chip_data(irq_data)) };
+
+        // SAFETY: The value returned by `IrqData` is only valid until the end of this function, and
+        // `irq_data` is guaranteed to be valid until then (by the contract with C code).
+        T::set_wake(data, unsafe { &IrqData::from_ptr(irq_data) }, on != 0)?;
+        Ok(0)
+    }
+}
+
+/// Contains constants that describes how an interrupt can be triggered.
+///
+/// It is tagged with `non_exhaustive` to prevent users from instantiating it.
+#[non_exhaustive]
+pub struct Type;
+
+impl Type {
+    /// The interrupt cannot be triggered.
+    pub const NONE: u32 = bindings::IRQ_TYPE_NONE;
+
+    /// The interrupt is triggered when the signal goes from low to high.
+    pub const EDGE_RISING: u32 = bindings::IRQ_TYPE_EDGE_RISING;
+
+    /// The interrupt is triggered when the signal goes from high to low.
+    pub const EDGE_FALLING: u32 = bindings::IRQ_TYPE_EDGE_FALLING;
+
+    /// The interrupt is triggered when the signal goes from low to high and when it goes to high
+    /// to low.
+    pub const EDGE_BOTH: u32 = bindings::IRQ_TYPE_EDGE_BOTH;
+
+    /// The interrupt is triggered while the signal is held high.
+    pub const LEVEL_HIGH: u32 = bindings::IRQ_TYPE_LEVEL_HIGH;
+
+    /// The interrupt is triggered while the signal is held low.
+    pub const LEVEL_LOW: u32 = bindings::IRQ_TYPE_LEVEL_LOW;
+}
+
+/// Wraps the kernel's `struct irq_desc`.
+///
+/// # Invariants
+///
+/// The pointer `Descriptor::ptr` is non-null and valid.
+pub struct Descriptor {
+    pub(crate) ptr: *mut bindings::irq_desc,
+}
+
+impl Descriptor {
+    /// Constructs a new `struct irq_desc` wrapper.
+    ///
+    /// # Safety
+    ///
+    /// The pointer `ptr` must be non-null and valid for the lifetime of the returned object.
+    unsafe fn from_ptr(ptr: *mut bindings::irq_desc) -> Self {
+        // INVARIANT: The safety requirements ensure the invariant.
+        Self { ptr }
+    }
+
+    /// Calls `chained_irq_enter` and returns a guard that calls `chained_irq_exit` once dropped.
+    ///
+    /// It is meant to be used by chained irq handlers to dispatch irqs to the next handlers.
+    pub fn enter_chained(&self) -> ChainedGuard<'_> {
+        // SAFETY: By the type invariants, `ptr` is always non-null and valid.
+        let irq_chip = unsafe { bindings::irq_desc_get_chip(self.ptr) };
+
+        // SAFETY: By the type invariants, `ptr` is always non-null and valid. `irq_chip` was just
+        // returned from `ptr`, so it is still valid too.
+        unsafe { bindings::chained_irq_enter(irq_chip, self.ptr) };
+        ChainedGuard {
+            desc: self,
+            irq_chip,
+        }
+    }
+}
+
+/// A guard to call `chained_irq_exit` after `chained_irq_enter` was called.
+///
+/// It is also used as evidence that a previous `chained_irq_enter` was called. So there are no
+/// public constructors and it is only created after indeed calling `chained_irq_enter`.
+pub struct ChainedGuard<'a> {
+    desc: &'a Descriptor,
+    irq_chip: *mut bindings::irq_chip,
+}
+
+impl Drop for ChainedGuard<'_> {
+    fn drop(&mut self) {
+        // SAFETY: The lifetime of `ChainedGuard` guarantees that `self.desc` remains valid, so it
+        // also guarantess `irq_chip` (which was returned from it) and `self.desc.ptr` (guaranteed
+        // by the type invariants).
+        unsafe { bindings::chained_irq_exit(self.irq_chip, self.desc.ptr) };
+    }
+}
+
+/// Wraps the kernel's `struct irq_domain`.
+///
+/// # Invariants
+///
+/// The pointer `Domain::ptr` is non-null and valid.
+pub struct Domain {
+    ptr: *mut bindings::irq_domain,
+}
+
+impl Domain {
+    /// Constructs a new `struct irq_domain` wrapper.
+    ///
+    /// # Safety
+    ///
+    /// The pointer `ptr` must be non-null and valid for the lifetime of the returned object.
+    pub(crate) unsafe fn from_ptr(ptr: *mut bindings::irq_domain) -> Self {
+        // INVARIANT: The safety requirements ensure the invariant.
+        Self { ptr }
+    }
+
+    /// Invokes the chained handler of the given hw irq of the given domain.
+    ///
+    /// It requires evidence that `chained_irq_enter` was called, which is done by passing a
+    /// `ChainedGuard` instance.
+    pub fn generic_handle_chained(&self, hwirq: u32, _guard: &ChainedGuard<'_>) {
+        // SAFETY: `ptr` is valid by the type invariants.
+        unsafe { bindings::generic_handle_domain_irq(self.ptr, hwirq) };
+    }
+}
+
+/// A high-level irq flow handler.
+pub trait FlowHandler {
+    /// The data associated with the handler.
+    type Data: PointerWrapper;
+
+    /// Implements the irq flow for the given descriptor.
+    fn handle_irq_flow(data: <Self::Data as PointerWrapper>::Borrowed<'_>, desc: &Descriptor);
+}
+
+/// Returns the raw irq flow handler corresponding to the (high-level) one defined in `T`.
+///
+/// # Safety
+///
+/// The caller must ensure that the value stored in the irq handler data (as returned by
+/// `irq_desc_get_handler_data`) is the result of calling [`PointerWrapper::into_pointer] for the
+/// [`T::Data`] type.
+pub(crate) unsafe fn new_flow_handler<T: FlowHandler>() -> bindings::irq_flow_handler_t {
+    Some(irq_flow_handler::<T>)
+}
+
+unsafe extern "C" fn irq_flow_handler<T: FlowHandler>(desc: *mut bindings::irq_desc) {
+    // SAFETY: By the safety requirements of `new_flow_handler`, we know that the value returned by
+    // `irq_desc_get_handler_data` comes from calling `T::Data::into_pointer`. `desc` is valid by
+    // the C API contract.
+    let data = unsafe { T::Data::borrow(bindings::irq_desc_get_handler_data(desc)) };
+
+    // SAFETY: The C API guarantees that `desc` is valid for the duration of this call, which
+    // outlives the lifetime returned by `from_desc`.
+    T::handle_irq_flow(data, &unsafe { Descriptor::from_ptr(desc) });
+}
diff --git a/rust/kernel/kasync.rs b/rust/kernel/kasync.rs
new file mode 100644
index 000000000000..4b57116bebc5
--- /dev/null
+++ b/rust/kernel/kasync.rs
@@ -0,0 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Kernel async functionality.
+
+#[cfg(CONFIG_NET)]
+pub mod net;
diff --git a/rust/kernel/kasync/net.rs b/rust/kernel/kasync/net.rs
new file mode 100644
index 000000000000..f7d15559e738
--- /dev/null
+++ b/rust/kernel/kasync/net.rs
@@ -0,0 +1,322 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Async networking.
+
+use crate::{bindings, c_types, error::code::*, net, sync::NoWaitLock, types::Opaque, Result};
+use core::{
+    future::Future,
+    marker::{PhantomData, PhantomPinned},
+    ops::Deref,
+    pin::Pin,
+    task::{Context, Poll, Waker},
+};
+
+/// A socket listening on a TCP port.
+///
+/// The [`TcpListener::accept`] method is meant to be used in async contexts.
+pub struct TcpListener {
+    listener: net::TcpListener,
+}
+
+impl TcpListener {
+    /// Creates a new TCP listener.
+    ///
+    /// It is configured to listen on the given socket address for the given namespace.
+    pub fn try_new(ns: &net::Namespace, addr: &net::SocketAddr) -> Result<Self> {
+        Ok(Self {
+            listener: net::TcpListener::try_new(ns, addr)?,
+        })
+    }
+
+    /// Accepts a new connection.
+    ///
+    /// Returns a future that when ready indicates the result of the accept operation; on success,
+    /// it contains the newly-accepted tcp stream.
+    pub fn accept(&self) -> impl Future<Output = Result<TcpStream>> + '_ {
+        SocketFuture::from_listener(
+            self,
+            bindings::BINDINGS_EPOLLIN | bindings::BINDINGS_EPOLLERR,
+            || {
+                Ok(TcpStream {
+                    stream: self.listener.accept(false)?,
+                })
+            },
+        )
+    }
+}
+
+impl Deref for TcpListener {
+    type Target = net::TcpListener;
+
+    fn deref(&self) -> &Self::Target {
+        &self.listener
+    }
+}
+
+/// A connected TCP socket.
+///
+/// The potentially blocking methods (e.g., [`TcpStream::read`], [`TcpStream::write`]) are meant
+/// to be used in async contexts.
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::prelude::*;
+/// # use kernel::kasync::net::TcpStream;
+/// async fn echo_server(stream: TcpStream) -> Result {
+///     let mut buf = [0u8; 1024];
+///     loop {
+///         let n = stream.read(&mut buf).await?;
+///         if n == 0 {
+///             return Ok(());
+///         }
+///         stream.write_all(&buf[..n]).await?;
+///     }
+/// }
+/// ```
+pub struct TcpStream {
+    stream: net::TcpStream,
+}
+
+impl TcpStream {
+    /// Reads data from a connected socket.
+    ///
+    /// Returns a future that when ready indicates the result of the read operation; on success, it
+    /// contains the number of bytes read, which will be zero if the connection is closed.
+    pub fn read<'a>(&'a self, buf: &'a mut [u8]) -> impl Future<Output = Result<usize>> + 'a {
+        SocketFuture::from_stream(
+            self,
+            bindings::BINDINGS_EPOLLIN | bindings::BINDINGS_EPOLLHUP | bindings::BINDINGS_EPOLLERR,
+            || self.stream.read(buf, false),
+        )
+    }
+
+    /// Writes data to the connected socket.
+    ///
+    /// Returns a future that when ready indicates the result of the write operation; on success, it
+    /// contains the number of bytes written.
+    pub fn write<'a>(&'a self, buf: &'a [u8]) -> impl Future<Output = Result<usize>> + 'a {
+        SocketFuture::from_stream(
+            self,
+            bindings::BINDINGS_EPOLLOUT | bindings::BINDINGS_EPOLLHUP | bindings::BINDINGS_EPOLLERR,
+            || self.stream.write(buf, false),
+        )
+    }
+
+    /// Writes all the data to the connected socket.
+    ///
+    /// Returns a future that when ready indicates the result of the write operation; on success, it
+    /// has written all the data.
+    pub async fn write_all<'a>(&'a self, buf: &'a [u8]) -> Result {
+        let mut rem = buf;
+
+        while !rem.is_empty() {
+            let n = self.write(rem).await?;
+            rem = &rem[n..];
+        }
+
+        Ok(())
+    }
+}
+
+impl Deref for TcpStream {
+    type Target = net::TcpStream;
+
+    fn deref(&self) -> &Self::Target {
+        &self.stream
+    }
+}
+
+/// A future for a socket operation.
+///
+/// # Invariants
+///
+/// `sock` is always non-null and valid for the duration of the lifetime of the instance.
+struct SocketFuture<'a, Out, F: FnMut() -> Result<Out> + Send + 'a> {
+    sock: *mut bindings::socket,
+    mask: u32,
+    is_queued: bool,
+    wq_entry: Opaque<bindings::wait_queue_entry>,
+    waker: NoWaitLock<Option<Waker>>,
+    _p: PhantomData<&'a ()>,
+    _pin: PhantomPinned,
+    operation: F,
+}
+
+// SAFETY: A kernel socket can be used from any thread, `wq_entry` is only used on drop and when
+// `is_queued` is initially `false`.
+unsafe impl<Out, F: FnMut() -> Result<Out> + Send> Send for SocketFuture<'_, Out, F> {}
+
+impl<'a, Out, F: FnMut() -> Result<Out> + Send + 'a> SocketFuture<'a, Out, F> {
+    /// Creates a new socket future.
+    ///
+    /// # Safety
+    ///
+    /// Callers must ensure that `sock` is non-null, valid, and remains valid for the lifetime
+    /// (`'a`) of the returned instance.
+    unsafe fn new(sock: *mut bindings::socket, mask: u32, operation: F) -> Self {
+        Self {
+            sock,
+            mask,
+            is_queued: false,
+            wq_entry: Opaque::uninit(),
+            waker: NoWaitLock::new(None),
+            operation,
+            _p: PhantomData,
+            _pin: PhantomPinned,
+        }
+    }
+
+    /// Creates a new socket future for a tcp listener.
+    fn from_listener(listener: &'a TcpListener, mask: u32, operation: F) -> Self {
+        // SAFETY: The socket is guaranteed to remain valid because it is bound to the reference to
+        // the listener (whose existence guarantees the socket remains valid).
+        unsafe { Self::new(listener.listener.sock, mask, operation) }
+    }
+
+    /// Creates a new socket future for a tcp stream.
+    fn from_stream(stream: &'a TcpStream, mask: u32, operation: F) -> Self {
+        // SAFETY: The socket is guaranteed to remain valid because it is bound to the reference to
+        // the stream (whose existence guarantees the socket remains valid).
+        unsafe { Self::new(stream.stream.sock, mask, operation) }
+    }
+
+    /// Callback called when the socket changes state.
+    ///
+    /// If the state matches the one we're waiting on, we wake up the task so that the future can be
+    /// polled again.
+    unsafe extern "C" fn wake_callback(
+        wq_entry: *mut bindings::wait_queue_entry,
+        _mode: c_types::c_uint,
+        _flags: c_types::c_int,
+        key: *mut c_types::c_void,
+    ) -> c_types::c_int {
+        let mask = key as u32;
+
+        // SAFETY: The future is valid while this callback is called because we remove from the
+        // queue on drop.
+        //
+        // There is a potential soundness issue here because we're generating a shared reference to
+        // `Self` while `Self::poll` has a mutable (unique) reference. However, for `!Unpin` types
+        // (like `Self`), `&mut T` is treated as `*mut T` per
+        // https://github.com/rust-lang/rust/issues/63818 -- so we avoid the unsoundness. Once a
+        // more definitive solution is available, we can change this to use it.
+        let s = unsafe { &*crate::container_of!(wq_entry, Self, wq_entry) };
+        if mask & s.mask == 0 {
+            // Nothing to do as this notification doesn't interest us.
+            return 0;
+        }
+
+        // If we can't acquire the waker lock, the waker is in the process of being modified. Our
+        // attempt to acquire the lock will be reported to the lock owner, so it will trigger the
+        // wake up.
+        if let Some(guard) = s.waker.try_lock() {
+            if let Some(ref w) = *guard {
+                let cloned = w.clone();
+                drop(guard);
+                cloned.wake();
+                return 1;
+            }
+        }
+        0
+    }
+
+    /// Poll the future once.
+    ///
+    /// It calls the operation and converts `EAGAIN` errors into a pending state.
+    fn poll_once(self: Pin<&mut Self>) -> Poll<Result<Out>> {
+        // SAFETY: We never move out of `this`.
+        let this = unsafe { self.get_unchecked_mut() };
+        match (this.operation)() {
+            Ok(s) => Poll::Ready(Ok(s)),
+            Err(e) => {
+                if e == EAGAIN {
+                    Poll::Pending
+                } else {
+                    Poll::Ready(Err(e))
+                }
+            }
+        }
+    }
+
+    /// Updates the waker stored in the future.
+    ///
+    /// It automatically triggers a wake up on races with the reactor.
+    fn set_waker(&self, waker: &Waker) {
+        if let Some(mut guard) = self.waker.try_lock() {
+            let old = core::mem::replace(&mut *guard, Some(waker.clone()));
+            let contention = guard.unlock();
+            drop(old);
+            if !contention {
+                return;
+            }
+        }
+
+        // We either couldn't store the waker because the existing one is being awakened, or the
+        // reactor tried to acquire the lock while we held it (contention). In either case, we just
+        // wake it up to ensure we don't miss any notification.
+        waker.wake_by_ref();
+    }
+}
+
+impl<Out, F: FnMut() -> Result<Out> + Send> Future for SocketFuture<'_, Out, F> {
+    type Output = Result<Out>;
+
+    fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
+        match self.as_mut().poll_once() {
+            Poll::Ready(r) => Poll::Ready(r),
+            Poll::Pending => {
+                // Store away the latest waker every time we may `Pending`.
+                self.set_waker(cx.waker());
+                if self.is_queued {
+                    // Nothing else to do was the waiter is already queued.
+                    return Poll::Pending;
+                }
+
+                // SAFETY: We never move out of `this`.
+                let this = unsafe { self.as_mut().get_unchecked_mut() };
+
+                this.is_queued = true;
+
+                // SAFETY: `wq_entry` is valid for write.
+                unsafe {
+                    bindings::init_waitqueue_func_entry(
+                        this.wq_entry.get(),
+                        Some(Self::wake_callback),
+                    )
+                };
+
+                // SAFETY: `wq_entry` was just initialised above and is valid for read/write.
+                // By the type invariants, the socket is always valid.
+                unsafe {
+                    bindings::add_wait_queue(
+                        core::ptr::addr_of_mut!((*this.sock).wq.wait),
+                        this.wq_entry.get(),
+                    )
+                };
+
+                // If the future wasn't queued yet, we need to poll again in case it reached
+                // the desired state between the last poll and being queued (in which case we
+                // would have missed the notification).
+                self.poll_once()
+            }
+        }
+    }
+}
+
+impl<Out, F: FnMut() -> Result<Out> + Send> Drop for SocketFuture<'_, Out, F> {
+    fn drop(&mut self) {
+        if !self.is_queued {
+            return;
+        }
+
+        // SAFETY: `wq_entry` is initialised because `is_queued` is set to `true`, so it is valid
+        // for read/write. By the type invariants, the socket is always valid.
+        unsafe {
+            bindings::remove_wait_queue(
+                core::ptr::addr_of_mut!((*self.sock).wq.wait),
+                self.wq_entry.get(),
+            )
+        };
+    }
+}
diff --git a/rust/kernel/kunit.rs b/rust/kernel/kunit.rs
new file mode 100644
index 000000000000..5f3e102962c3
--- /dev/null
+++ b/rust/kernel/kunit.rs
@@ -0,0 +1,91 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! KUnit-based macros for Rust unit tests.
+//!
+//! C header: [`include/kunit/test.h`](../../../../../include/kunit/test.h)
+//!
+//! Reference: <https://www.kernel.org/doc/html/latest/dev-tools/kunit/index.html>
+
+/// Asserts that a boolean expression is `true` at runtime.
+///
+/// Public but hidden since it should only be used from generated tests.
+///
+/// Unlike the one in `core`, this one does not panic; instead, it is mapped to the KUnit
+/// facilities. See [`assert!`] for more details.
+#[doc(hidden)]
+#[macro_export]
+macro_rules! kunit_assert {
+    ($test:expr, $cond:expr $(,)?) => {{
+        if !$cond {
+            #[repr(transparent)]
+            struct Location($crate::bindings::kunit_loc);
+
+            #[repr(transparent)]
+            struct UnaryAssert($crate::bindings::kunit_unary_assert);
+
+            // SAFETY: There is only a static instance and in that one the pointer field
+            // points to an immutable C string.
+            unsafe impl Sync for Location {}
+
+            // SAFETY: There is only a static instance and in that one the pointer field
+            // points to an immutable C string.
+            unsafe impl Sync for UnaryAssert {}
+
+            static FILE: &'static $crate::str::CStr = $crate::c_str!(core::file!());
+            static LOCATION: Location = Location($crate::bindings::kunit_loc {
+                file: FILE.as_char_ptr(),
+                line: core::line!() as i32,
+            });
+            static CONDITION: &'static $crate::str::CStr = $crate::c_str!(stringify!($cond));
+            static ASSERTION: UnaryAssert = UnaryAssert($crate::bindings::kunit_unary_assert {
+                assert: $crate::bindings::kunit_assert {
+                    format: Some($crate::bindings::kunit_unary_assert_format),
+                },
+                condition: CONDITION.as_char_ptr(),
+                expected_true: true,
+            });
+
+            // SAFETY:
+            //   - FFI call.
+            //   - The `test` pointer is valid because this hidden macro should only be called by
+            //     the generated documentation tests which forward the test pointer given by KUnit.
+            //   - The string pointers (`file` and `condition`) point to null-terminated ones.
+            //   - The function pointer (`format`) points to the proper function.
+            //   - The pointers passed will remain valid since they point to statics.
+            //   - The format string is allowed to be null.
+            //   - There are, however, problems with this: first of all, this will end up stopping
+            //     the thread, without running destructors. While that is problematic in itself,
+            //     it is considered UB to have what is effectively an forced foreign unwind
+            //     with `extern "C"` ABI. One could observe the stack that is now gone from
+            //     another thread. We should avoid pinning stack variables to prevent library UB,
+            //     too. For the moment, given test failures are reported immediately before the
+            //     next test runs, that test failures should be fixed and that KUnit is explicitly
+            //     documented as not suitable for production environments, we feel it is reasonable.
+            unsafe {
+                $crate::bindings::kunit_do_failed_assertion(
+                    $test,
+                    core::ptr::addr_of!(LOCATION.0),
+                    $crate::bindings::kunit_assert_type_KUNIT_ASSERTION,
+                    core::ptr::addr_of!(ASSERTION.0.assert),
+                    core::ptr::null(),
+                );
+            }
+        }
+    }};
+}
+
+/// Asserts that two expressions are equal to each other (using [`PartialEq`]).
+///
+/// Public but hidden since it should only be used from generated tests.
+///
+/// Unlike the one in `core`, this one does not panic; instead, it is mapped to the KUnit
+/// facilities. See [`assert!`] for more details.
+#[doc(hidden)]
+#[macro_export]
+macro_rules! kunit_assert_eq {
+    ($test:expr, $left:expr, $right:expr $(,)?) => {{
+        // For the moment, we just forward to the expression assert because,
+        // for binary asserts, KUnit supports only a few types (e.g. integers).
+        $crate::kunit_assert!($test, $left == $right);
+    }};
+}
diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs
new file mode 100644
index 000000000000..99c70d984396
--- /dev/null
+++ b/rust/kernel/lib.rs
@@ -0,0 +1,260 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! The `kernel` crate.
+//!
+//! This crate contains the kernel APIs that have been ported or wrapped for
+//! usage by Rust code in the kernel and is shared by all of them.
+//!
+//! In other words, all the rest of the Rust code in the kernel (e.g. kernel
+//! modules written in Rust) depends on [`core`], [`alloc`] and this crate.
+//!
+//! If you need a kernel C API that is not ported or wrapped yet here, then
+//! do so first instead of bypassing this crate.
+
+#![no_std]
+#![feature(allocator_api)]
+#![feature(associated_type_defaults)]
+#![feature(concat_idents)]
+#![feature(const_fn_trait_bound)]
+#![feature(const_mut_refs)]
+#![feature(const_ptr_offset_from)]
+#![feature(const_refs_to_cell)]
+#![feature(const_trait_impl)]
+#![feature(doc_cfg)]
+#![feature(generic_associated_types)]
+#![feature(ptr_metadata)]
+#![feature(receiver_trait)]
+#![feature(coerce_unsized)]
+#![feature(dispatch_from_dyn)]
+#![feature(unsize)]
+
+// Ensure conditional compilation based on the kernel configuration works;
+// otherwise we may silently break things like initcall handling.
+#[cfg(not(CONFIG_RUST))]
+compile_error!("Missing kernel configuration for conditional compilation");
+
+#[cfg(not(test))]
+#[cfg(not(testlib))]
+mod allocator;
+
+#[doc(hidden)]
+pub mod bindings;
+
+#[cfg(CONFIG_ARM_AMBA)]
+pub mod amba;
+pub mod c_types;
+pub mod chrdev;
+#[cfg(CONFIG_COMMON_CLK)]
+pub mod clk;
+pub mod cred;
+pub mod device;
+pub mod driver;
+pub mod error;
+pub mod file;
+pub mod gpio;
+pub mod hwrng;
+pub mod irq;
+pub mod kasync;
+pub mod miscdev;
+pub mod mm;
+#[cfg(CONFIG_NET)]
+pub mod net;
+pub mod pages;
+pub mod power;
+pub mod revocable;
+pub mod security;
+pub mod str;
+pub mod task;
+
+pub mod linked_list;
+mod raw_list;
+pub mod rbtree;
+
+#[doc(hidden)]
+pub mod module_param;
+
+mod build_assert;
+pub mod prelude;
+pub mod print;
+pub mod random;
+mod static_assert;
+#[doc(hidden)]
+pub mod std_vendor;
+pub mod sync;
+
+#[cfg(any(CONFIG_SYSCTL, doc))]
+#[doc(cfg(CONFIG_SYSCTL))]
+pub mod sysctl;
+
+pub mod io_buffer;
+pub mod io_mem;
+pub mod iov_iter;
+pub mod of;
+pub mod platform;
+mod types;
+pub mod user_ptr;
+
+#[cfg(CONFIG_KUNIT)]
+pub mod kunit;
+
+#[doc(hidden)]
+pub use build_error::build_error;
+
+pub use crate::error::{to_result, Error, Result};
+pub use crate::types::{
+    bit, bits_iter, ARef, AlwaysRefCounted, Bool, False, Mode, Opaque, ScopeGuard, True,
+};
+
+use core::marker::PhantomData;
+
+/// Page size defined in terms of the `PAGE_SHIFT` macro from C.
+///
+/// [`PAGE_SHIFT`]: ../../../include/asm-generic/page.h
+pub const PAGE_SIZE: usize = 1 << bindings::PAGE_SHIFT;
+
+/// Prefix to appear before log messages printed from within the kernel crate.
+const __LOG_PREFIX: &[u8] = b"rust_kernel\0";
+
+/// The top level entrypoint to implementing a kernel module.
+///
+/// For any teardown or cleanup operations, your type may implement [`Drop`].
+pub trait Module: Sized + Sync {
+    /// Called at module initialization time.
+    ///
+    /// Use this method to perform whatever setup or registration your module
+    /// should do.
+    ///
+    /// Equivalent to the `module_init` macro in the C API.
+    fn init(name: &'static str::CStr, module: &'static ThisModule) -> Result<Self>;
+}
+
+/// Equivalent to `THIS_MODULE` in the C API.
+///
+/// C header: `include/linux/export.h`
+pub struct ThisModule(*mut bindings::module);
+
+// SAFETY: `THIS_MODULE` may be used from all threads within a module.
+unsafe impl Sync for ThisModule {}
+
+impl ThisModule {
+    /// Creates a [`ThisModule`] given the `THIS_MODULE` pointer.
+    ///
+    /// # Safety
+    ///
+    /// The pointer must be equal to the right `THIS_MODULE`.
+    pub const unsafe fn from_ptr(ptr: *mut bindings::module) -> ThisModule {
+        ThisModule(ptr)
+    }
+
+    /// Locks the module parameters to access them.
+    ///
+    /// Returns a [`KParamGuard`] that will release the lock when dropped.
+    pub fn kernel_param_lock(&self) -> KParamGuard<'_> {
+        // SAFETY: `kernel_param_lock` will check if the pointer is null and
+        // use the built-in mutex in that case.
+        #[cfg(CONFIG_SYSFS)]
+        unsafe {
+            bindings::kernel_param_lock(self.0)
+        }
+
+        KParamGuard {
+            #[cfg(CONFIG_SYSFS)]
+            this_module: self,
+            phantom: PhantomData,
+        }
+    }
+}
+
+/// Scoped lock on the kernel parameters of [`ThisModule`].
+///
+/// Lock will be released when this struct is dropped.
+pub struct KParamGuard<'a> {
+    #[cfg(CONFIG_SYSFS)]
+    this_module: &'a ThisModule,
+    phantom: PhantomData<&'a ()>,
+}
+
+#[cfg(CONFIG_SYSFS)]
+impl<'a> Drop for KParamGuard<'a> {
+    fn drop(&mut self) {
+        // SAFETY: `kernel_param_lock` will check if the pointer is null and
+        // use the built-in mutex in that case. The existance of `self`
+        // guarantees that the lock is held.
+        unsafe { bindings::kernel_param_unlock(self.this_module.0) }
+    }
+}
+
+/// Calculates the offset of a field from the beginning of the struct it belongs to.
+///
+/// # Example
+///
+/// ```
+/// # use kernel::prelude::*;
+/// # use kernel::offset_of;
+/// struct Test {
+///     a: u64,
+///     b: u32,
+/// }
+///
+/// assert_eq!(offset_of!(Test, b), 8);
+/// ```
+#[macro_export]
+macro_rules! offset_of {
+    ($type:ty, $($f:tt)*) => {{
+        let tmp = core::mem::MaybeUninit::<$type>::uninit();
+        let outer = tmp.as_ptr();
+        // To avoid warnings when nesting `unsafe` blocks.
+        #[allow(unused_unsafe)]
+        // SAFETY: The pointer is valid and aligned, just not initialised; `addr_of` ensures that
+        // we don't actually read from `outer` (which would be UB) nor create an intermediate
+        // reference.
+        let inner = unsafe { core::ptr::addr_of!((*outer).$($f)*) } as *const u8;
+        // To avoid warnings when nesting `unsafe` blocks.
+        #[allow(unused_unsafe)]
+        // SAFETY: The two pointers are within the same allocation block.
+        unsafe { inner.offset_from(outer as *const u8) }
+    }}
+}
+
+/// Produces a pointer to an object from a pointer to one of its fields.
+///
+/// # Safety
+///
+/// Callers must ensure that the pointer to the field is in fact a pointer to the specified field,
+/// as opposed to a pointer to another object of the same type. If this condition is not met,
+/// any dereference of the resulting pointer is UB.
+///
+/// # Example
+///
+/// ```
+/// # use kernel::container_of;
+/// struct Test {
+///     a: u64,
+///     b: u32,
+/// }
+///
+/// let test = Test { a: 10, b: 20 };
+/// let b_ptr = &test.b;
+/// let test_alias = container_of!(b_ptr, Test, b);
+/// assert!(core::ptr::eq(&test, test_alias));
+/// ```
+#[macro_export]
+macro_rules! container_of {
+    ($ptr:expr, $type:ty, $($f:tt)*) => {{
+        let ptr = $ptr as *const _ as *const u8;
+        let offset = $crate::offset_of!($type, $($f)*);
+        ptr.wrapping_offset(-offset) as *const $type
+    }}
+}
+
+#[cfg(not(any(testlib, test)))]
+#[panic_handler]
+fn panic(info: &core::panic::PanicInfo<'_>) -> ! {
+    pr_emerg!("{}\n", info);
+    // SAFETY: FFI call.
+    unsafe { bindings::BUG() };
+    // Bindgen currently does not recognize `__noreturn` so `BUG` returns `()`
+    // instead of `!`.
+    // https://github.com/rust-lang/rust-bindgen/issues/2094
+    loop {}
+}
diff --git a/rust/kernel/linked_list.rs b/rust/kernel/linked_list.rs
new file mode 100644
index 000000000000..3330edcc7ca8
--- /dev/null
+++ b/rust/kernel/linked_list.rs
@@ -0,0 +1,247 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Linked lists.
+//!
+//! TODO: This module is a work in progress.
+
+use alloc::boxed::Box;
+use core::ptr::NonNull;
+
+pub use crate::raw_list::{Cursor, GetLinks, Links};
+use crate::{raw_list, raw_list::RawList, sync::Ref};
+
+// TODO: Use the one from `kernel::file_operations::PointerWrapper` instead.
+/// Wraps an object to be inserted in a linked list.
+pub trait Wrapper<T: ?Sized> {
+    /// Converts the wrapped object into a pointer that represents it.
+    fn into_pointer(self) -> NonNull<T>;
+
+    /// Converts the object back from the pointer representation.
+    ///
+    /// # Safety
+    ///
+    /// The passed pointer must come from a previous call to [`Wrapper::into_pointer()`].
+    unsafe fn from_pointer(ptr: NonNull<T>) -> Self;
+
+    /// Returns a reference to the wrapped object.
+    fn as_ref(&self) -> &T;
+}
+
+impl<T: ?Sized> Wrapper<T> for Box<T> {
+    fn into_pointer(self) -> NonNull<T> {
+        NonNull::new(Box::into_raw(self)).unwrap()
+    }
+
+    unsafe fn from_pointer(ptr: NonNull<T>) -> Self {
+        unsafe { Box::from_raw(ptr.as_ptr()) }
+    }
+
+    fn as_ref(&self) -> &T {
+        AsRef::as_ref(self)
+    }
+}
+
+impl<T: ?Sized> Wrapper<T> for Ref<T> {
+    fn into_pointer(self) -> NonNull<T> {
+        NonNull::new(Ref::into_raw(self) as _).unwrap()
+    }
+
+    unsafe fn from_pointer(ptr: NonNull<T>) -> Self {
+        // SAFETY: The safety requirements of `from_pointer` satisfy the ones from `Ref::from_raw`.
+        unsafe { Ref::from_raw(ptr.as_ptr() as _) }
+    }
+
+    fn as_ref(&self) -> &T {
+        AsRef::as_ref(self)
+    }
+}
+
+impl<T: ?Sized> Wrapper<T> for &T {
+    fn into_pointer(self) -> NonNull<T> {
+        NonNull::from(self)
+    }
+
+    unsafe fn from_pointer(ptr: NonNull<T>) -> Self {
+        unsafe { &*ptr.as_ptr() }
+    }
+
+    fn as_ref(&self) -> &T {
+        self
+    }
+}
+
+/// A descriptor of wrapped list elements.
+pub trait GetLinksWrapped: GetLinks {
+    /// Specifies which wrapper (e.g., `Box` and `Arc`) wraps the list entries.
+    type Wrapped: Wrapper<Self::EntryType>;
+}
+
+impl<T: ?Sized> GetLinksWrapped for Box<T>
+where
+    Box<T>: GetLinks,
+{
+    type Wrapped = Box<<Box<T> as GetLinks>::EntryType>;
+}
+
+impl<T: GetLinks + ?Sized> GetLinks for Box<T> {
+    type EntryType = T::EntryType;
+    fn get_links(data: &Self::EntryType) -> &Links<Self::EntryType> {
+        <T as GetLinks>::get_links(data)
+    }
+}
+
+impl<T: ?Sized> GetLinksWrapped for Ref<T>
+where
+    Ref<T>: GetLinks,
+{
+    type Wrapped = Ref<<Ref<T> as GetLinks>::EntryType>;
+}
+
+impl<T: GetLinks + ?Sized> GetLinks for Ref<T> {
+    type EntryType = T::EntryType;
+
+    fn get_links(data: &Self::EntryType) -> &Links<Self::EntryType> {
+        <T as GetLinks>::get_links(data)
+    }
+}
+
+/// A linked list.
+///
+/// Elements in the list are wrapped and ownership is transferred to the list while the element is
+/// in the list.
+pub struct List<G: GetLinksWrapped> {
+    list: RawList<G>,
+}
+
+impl<G: GetLinksWrapped> List<G> {
+    /// Constructs a new empty linked list.
+    pub fn new() -> Self {
+        Self {
+            list: RawList::new(),
+        }
+    }
+
+    /// Returns whether the list is empty.
+    pub fn is_empty(&self) -> bool {
+        self.list.is_empty()
+    }
+
+    /// Adds the given object to the end (back) of the list.
+    ///
+    /// It is dropped if it's already on this (or another) list; this can happen for
+    /// reference-counted objects, so dropping means decrementing the reference count.
+    pub fn push_back(&mut self, data: G::Wrapped) {
+        let ptr = data.into_pointer();
+
+        // SAFETY: We took ownership of the entry, so it is safe to insert it.
+        if !unsafe { self.list.push_back(ptr.as_ref()) } {
+            // If insertion failed, rebuild object so that it can be freed.
+            // SAFETY: We just called `into_pointer` above.
+            unsafe { G::Wrapped::from_pointer(ptr) };
+        }
+    }
+
+    /// Inserts the given object after `existing`.
+    ///
+    /// It is dropped if it's already on this (or another) list; this can happen for
+    /// reference-counted objects, so dropping means decrementing the reference count.
+    ///
+    /// # Safety
+    ///
+    /// Callers must ensure that `existing` points to a valid entry that is on the list.
+    pub unsafe fn insert_after(&mut self, existing: NonNull<G::EntryType>, data: G::Wrapped) {
+        let ptr = data.into_pointer();
+        let entry = unsafe { &*existing.as_ptr() };
+        if unsafe { !self.list.insert_after(entry, ptr.as_ref()) } {
+            // If insertion failed, rebuild object so that it can be freed.
+            unsafe { G::Wrapped::from_pointer(ptr) };
+        }
+    }
+
+    /// Removes the given entry.
+    ///
+    /// # Safety
+    ///
+    /// Callers must ensure that `data` is either on this list or in no list. It being on another
+    /// list leads to memory unsafety.
+    pub unsafe fn remove(&mut self, data: &G::Wrapped) -> Option<G::Wrapped> {
+        let entry_ref = Wrapper::as_ref(data);
+        if unsafe { self.list.remove(entry_ref) } {
+            Some(unsafe { G::Wrapped::from_pointer(NonNull::from(entry_ref)) })
+        } else {
+            None
+        }
+    }
+
+    /// Removes the element currently at the front of the list and returns it.
+    ///
+    /// Returns `None` if the list is empty.
+    pub fn pop_front(&mut self) -> Option<G::Wrapped> {
+        let front = self.list.pop_front()?;
+        // SAFETY: Elements on the list were inserted after a call to `into_pointer `.
+        Some(unsafe { G::Wrapped::from_pointer(front) })
+    }
+
+    /// Returns a cursor starting on the first (front) element of the list.
+    pub fn cursor_front(&self) -> Cursor<'_, G> {
+        self.list.cursor_front()
+    }
+
+    /// Returns a mutable cursor starting on the first (front) element of the list.
+    pub fn cursor_front_mut(&mut self) -> CursorMut<'_, G> {
+        CursorMut::new(self.list.cursor_front_mut())
+    }
+}
+
+impl<G: GetLinksWrapped> Default for List<G> {
+    fn default() -> Self {
+        Self::new()
+    }
+}
+
+impl<G: GetLinksWrapped> Drop for List<G> {
+    fn drop(&mut self) {
+        while self.pop_front().is_some() {}
+    }
+}
+
+/// A list cursor that allows traversing a linked list and inspecting & mutating elements.
+pub struct CursorMut<'a, G: GetLinksWrapped> {
+    cursor: raw_list::CursorMut<'a, G>,
+}
+
+impl<'a, G: GetLinksWrapped> CursorMut<'a, G> {
+    fn new(cursor: raw_list::CursorMut<'a, G>) -> Self {
+        Self { cursor }
+    }
+
+    /// Returns the element the cursor is currently positioned on.
+    pub fn current(&mut self) -> Option<&mut G::EntryType> {
+        self.cursor.current()
+    }
+
+    /// Removes the element the cursor is currently positioned on.
+    ///
+    /// After removal, it advances the cursor to the next element.
+    pub fn remove_current(&mut self) -> Option<G::Wrapped> {
+        let ptr = self.cursor.remove_current()?;
+
+        // SAFETY: Elements on the list were inserted after a call to `into_pointer `.
+        Some(unsafe { G::Wrapped::from_pointer(ptr) })
+    }
+
+    /// Returns the element immediately after the one the cursor is positioned on.
+    pub fn peek_next(&mut self) -> Option<&mut G::EntryType> {
+        self.cursor.peek_next()
+    }
+
+    /// Returns the element immediately before the one the cursor is positioned on.
+    pub fn peek_prev(&mut self) -> Option<&mut G::EntryType> {
+        self.cursor.peek_prev()
+    }
+
+    /// Moves the cursor to the next element.
+    pub fn move_next(&mut self) {
+        self.cursor.move_next();
+    }
+}
diff --git a/rust/kernel/miscdev.rs b/rust/kernel/miscdev.rs
new file mode 100644
index 000000000000..e551e48ccdbc
--- /dev/null
+++ b/rust/kernel/miscdev.rs
@@ -0,0 +1,291 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Miscellaneous devices.
+//!
+//! C header: [`include/linux/miscdevice.h`](../../../../include/linux/miscdevice.h)
+//!
+//! Reference: <https://www.kernel.org/doc/html/latest/driver-api/misc_devices.html>
+
+use crate::bindings;
+use crate::error::{code::*, Error, Result};
+use crate::file;
+use crate::{device, str::CStr, str::CString, ThisModule};
+use alloc::boxed::Box;
+use core::marker::PhantomPinned;
+use core::{fmt, mem::MaybeUninit, pin::Pin};
+
+/// Options which can be used to configure how a misc device is registered.
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::{c_str, device::RawDevice, file, miscdev, prelude::*};
+/// fn example(
+///     reg: Pin<&mut miscdev::Registration<impl file::Operations<OpenData = ()>>>,
+///     parent: &dyn RawDevice,
+/// ) -> Result {
+///     miscdev::Options::new()
+///         .mode(0o600)
+///         .minor(10)
+///         .parent(parent)
+///         .register(reg, fmt!("sample"), ())
+/// }
+/// ```
+#[derive(Default)]
+pub struct Options<'a> {
+    minor: Option<i32>,
+    mode: Option<u16>,
+    parent: Option<&'a dyn device::RawDevice>,
+}
+
+impl<'a> Options<'a> {
+    /// Creates new [`Options`] instance with the required fields.
+    pub const fn new() -> Self {
+        Self {
+            minor: None,
+            mode: None,
+            parent: None,
+        }
+    }
+
+    /// Sets the minor device number.
+    pub const fn minor(&mut self, v: i32) -> &mut Self {
+        self.minor = Some(v);
+        self
+    }
+
+    /// Sets the device mode.
+    ///
+    /// This is usually an octal number and describes who can perform read/write/execute operations
+    /// on the device.
+    pub const fn mode(&mut self, m: u16) -> &mut Self {
+        self.mode = Some(m);
+        self
+    }
+
+    /// Sets the device parent.
+    pub const fn parent(&mut self, p: &'a dyn device::RawDevice) -> &mut Self {
+        self.parent = Some(p);
+        self
+    }
+
+    /// Registers a misc device using the configured options.
+    pub fn register<T: file::Operations>(
+        &self,
+        reg: Pin<&mut Registration<T>>,
+        name: fmt::Arguments<'_>,
+        open_data: T::OpenData,
+    ) -> Result {
+        reg.register_with_options(name, open_data, self)
+    }
+
+    /// Allocates a new registration of a misc device and completes the registration with the
+    /// configured options.
+    pub fn register_new<T: file::Operations>(
+        &self,
+        name: fmt::Arguments<'_>,
+        open_data: T::OpenData,
+    ) -> Result<Pin<Box<Registration<T>>>> {
+        let mut r = Pin::from(Box::try_new(Registration::new())?);
+        self.register(r.as_mut(), name, open_data)?;
+        Ok(r)
+    }
+}
+
+/// A registration of a miscellaneous device.
+///
+/// # Invariants
+///
+/// `Context` is always initialised when `registered` is `true`, and not initialised otherwise.
+pub struct Registration<T: file::Operations> {
+    registered: bool,
+    mdev: bindings::miscdevice,
+    name: Option<CString>,
+    _pin: PhantomPinned,
+
+    /// Context initialised on construction and made available to all file instances on
+    /// [`file::Operations::open`].
+    open_data: MaybeUninit<T::OpenData>,
+}
+
+impl<T: file::Operations> Registration<T> {
+    /// Creates a new [`Registration`] but does not register it yet.
+    ///
+    /// It is allowed to move.
+    pub fn new() -> Self {
+        // INVARIANT: `registered` is `false` and `open_data` is not initialised.
+        Self {
+            registered: false,
+            mdev: bindings::miscdevice::default(),
+            name: None,
+            _pin: PhantomPinned,
+            open_data: MaybeUninit::uninit(),
+        }
+    }
+
+    /// Registers a miscellaneous device.
+    ///
+    /// Returns a pinned heap-allocated representation of the registration.
+    pub fn new_pinned(name: fmt::Arguments<'_>, open_data: T::OpenData) -> Result<Pin<Box<Self>>> {
+        Options::new().register_new(name, open_data)
+    }
+
+    /// Registers a miscellaneous device with the rest of the kernel.
+    ///
+    /// It must be pinned because the memory block that represents the registration is
+    /// self-referential.
+    pub fn register(
+        self: Pin<&mut Self>,
+        name: fmt::Arguments<'_>,
+        open_data: T::OpenData,
+    ) -> Result {
+        Options::new().register(self, name, open_data)
+    }
+
+    /// Registers a miscellaneous device with the rest of the kernel. Additional optional settings
+    /// are provided via the `opts` parameter.
+    ///
+    /// It must be pinned because the memory block that represents the registration is
+    /// self-referential.
+    pub fn register_with_options(
+        self: Pin<&mut Self>,
+        name: fmt::Arguments<'_>,
+        open_data: T::OpenData,
+        opts: &Options<'_>,
+    ) -> Result {
+        // SAFETY: We must ensure that we never move out of `this`.
+        let this = unsafe { self.get_unchecked_mut() };
+        if this.registered {
+            // Already registered.
+            return Err(EINVAL);
+        }
+
+        let name = CString::try_from_fmt(name)?;
+
+        // SAFETY: The adapter is compatible with `misc_register`.
+        this.mdev.fops = unsafe { file::OperationsVtable::<Self, T>::build() };
+        this.mdev.name = name.as_char_ptr();
+        this.mdev.minor = opts.minor.unwrap_or(bindings::MISC_DYNAMIC_MINOR as i32);
+        this.mdev.mode = opts.mode.unwrap_or(0);
+        this.mdev.parent = opts
+            .parent
+            .map_or(core::ptr::null_mut(), |p| p.raw_device());
+
+        // We write to `open_data` here because as soon as `misc_register` succeeds, the file can be
+        // opened, so we need `open_data` configured ahead of time.
+        //
+        // INVARIANT: `registered` is set to `true`, but `open_data` is also initialised.
+        this.registered = true;
+        this.open_data.write(open_data);
+
+        let ret = unsafe { bindings::misc_register(&mut this.mdev) };
+        if ret < 0 {
+            // INVARIANT: `registered` is set back to `false` and the `open_data` is destructued.
+            this.registered = false;
+            // SAFETY: `open_data` was initialised a few lines above.
+            unsafe { this.open_data.assume_init_drop() };
+            return Err(Error::from_kernel_errno(ret));
+        }
+
+        this.name = Some(name);
+
+        Ok(())
+    }
+}
+
+impl<T: file::Operations> Default for Registration<T> {
+    fn default() -> Self {
+        Self::new()
+    }
+}
+
+impl<T: file::Operations> file::OpenAdapter<T::OpenData> for Registration<T> {
+    unsafe fn convert(
+        _inode: *mut bindings::inode,
+        file: *mut bindings::file,
+    ) -> *const T::OpenData {
+        // SAFETY: The caller must guarantee that `file` is valid.
+        let reg = crate::container_of!(unsafe { (*file).private_data }, Self, mdev);
+
+        // SAFETY: This function is only called while the misc device is still registered, so the
+        // registration must be valid. Additionally, the type invariants guarantee that while the
+        // miscdev is registered, `open_data` is initialised.
+        unsafe { (*reg).open_data.as_ptr() }
+    }
+}
+
+// SAFETY: The only method is `register()`, which requires a (pinned) mutable `Registration`, so it
+// is safe to pass `&Registration` to multiple threads because it offers no interior mutability.
+unsafe impl<T: file::Operations> Sync for Registration<T> {}
+
+// SAFETY: All functions work from any thread. So as long as the `Registration::open_data` is
+// `Send`, so is `Registration<T>`.
+unsafe impl<T: file::Operations> Send for Registration<T> where T::OpenData: Send {}
+
+impl<T: file::Operations> Drop for Registration<T> {
+    /// Removes the registration from the kernel if it has completed successfully before.
+    fn drop(&mut self) {
+        if self.registered {
+            // SAFETY: `registered` being `true` indicates that a previous call to  `misc_register`
+            // succeeded.
+            unsafe { bindings::misc_deregister(&mut self.mdev) };
+
+            // SAFETY: The type invariant guarantees that `open_data` is initialised when
+            // `registered` is `true`.
+            unsafe { self.open_data.assume_init_drop() };
+        }
+    }
+}
+
+/// Kernel module that exposes a single miscdev device implemented by `T`.
+pub struct Module<T: file::Operations<OpenData = ()>> {
+    _dev: Pin<Box<Registration<T>>>,
+}
+
+impl<T: file::Operations<OpenData = ()>> crate::Module for Module<T> {
+    fn init(name: &'static CStr, _module: &'static ThisModule) -> Result<Self> {
+        Ok(Self {
+            _dev: Registration::new_pinned(crate::fmt!("{name}"), ())?,
+        })
+    }
+}
+
+/// Declares a kernel module that exposes a single misc device.
+///
+/// The `type` argument should be a type which implements the [`FileOpener`] trait. Also accepts
+/// various forms of kernel metadata.
+///
+/// C header: [`include/linux/moduleparam.h`](../../../include/linux/moduleparam.h)
+///
+/// [`FileOpener`]: ../kernel/file_operations/trait.FileOpener.html
+///
+/// # Examples
+///
+/// ```ignore
+/// use kernel::prelude::*;
+///
+/// module_misc_device! {
+///     type: MyFile,
+///     name: b"my_miscdev_kernel_module",
+///     author: b"Rust for Linux Contributors",
+///     description: b"My very own misc device kernel module!",
+///     license: b"GPL v2",
+/// }
+///
+/// #[derive(Default)]
+/// struct MyFile;
+///
+/// impl kernel::file::Operations for MyFile {
+///     kernel::declare_file_operations!();
+/// }
+/// ```
+#[macro_export]
+macro_rules! module_misc_device {
+    (type: $type:ty, $($f:tt)*) => {
+        type ModuleType = kernel::miscdev::Module<$type>;
+        module! {
+            type: ModuleType,
+            $($f)*
+        }
+    }
+}
diff --git a/rust/kernel/mm.rs b/rust/kernel/mm.rs
new file mode 100644
index 000000000000..322f94f501e0
--- /dev/null
+++ b/rust/kernel/mm.rs
@@ -0,0 +1,149 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Memory management.
+//!
+//! C header: [`include/linux/mm.h`](../../../../include/linux/mm.h)
+
+use crate::{bindings, pages, to_result, Result};
+
+/// Virtual memory.
+pub mod virt {
+    use super::*;
+
+    /// A wrapper for the kernel's `struct vm_area_struct`.
+    ///
+    /// It represents an area of virtual memory.
+    ///
+    /// # Invariants
+    ///
+    /// `vma` is always non-null and valid.
+    pub struct Area {
+        vma: *mut bindings::vm_area_struct,
+    }
+
+    impl Area {
+        /// Creates a new instance of a virtual memory area.
+        ///
+        /// # Safety
+        ///
+        /// Callers must ensure that `vma` is non-null and valid for the duration of the new area's
+        /// lifetime.
+        pub(crate) unsafe fn from_ptr(vma: *mut bindings::vm_area_struct) -> Self {
+            // INVARIANTS: The safety requirements guarantee the invariants.
+            Self { vma }
+        }
+
+        /// Returns the flags associated with the virtual memory area.
+        ///
+        /// The possible flags are a combination of the constants in [`flags`].
+        pub fn flags(&self) -> usize {
+            // SAFETY: `self.vma` is valid by the type invariants.
+            unsafe { (*self.vma).vm_flags as _ }
+        }
+
+        /// Sets the flags associated with the virtual memory area.
+        ///
+        /// The possible flags are a combination of the constants in [`flags`].
+        pub fn set_flags(&mut self, flags: usize) {
+            // SAFETY: `self.vma` is valid by the type invariants.
+            unsafe { (*self.vma).vm_flags = flags as _ };
+        }
+
+        /// Returns the start address of the virtual memory area.
+        pub fn start(&self) -> usize {
+            // SAFETY: `self.vma` is valid by the type invariants.
+            unsafe { (*self.vma).vm_start as _ }
+        }
+
+        /// Returns the end address of the virtual memory area.
+        pub fn end(&self) -> usize {
+            // SAFETY: `self.vma` is valid by the type invariants.
+            unsafe { (*self.vma).vm_end as _ }
+        }
+
+        /// Maps a single page at the given address within the virtual memory area.
+        pub fn insert_page(&mut self, address: usize, page: &pages::Pages<0>) -> Result {
+            // SAFETY: The page is guaranteed to be order 0 by the type system. The range of
+            // `address` is already checked by `vm_insert_page`. `self.vma` and `page.pages` are
+            // guaranteed by their repective type invariants to be valid.
+            to_result(|| unsafe { bindings::vm_insert_page(self.vma, address as _, page.pages) })
+        }
+    }
+
+    /// Container for [`Area`] flags.
+    pub mod flags {
+        use crate::bindings;
+
+        /// No flags are set.
+        pub const NONE: usize = bindings::VM_NONE as _;
+
+        /// Mapping allows reads.
+        pub const READ: usize = bindings::VM_READ as _;
+
+        /// Mapping allows writes.
+        pub const WRITE: usize = bindings::VM_WRITE as _;
+
+        /// Mapping allows execution.
+        pub const EXEC: usize = bindings::VM_EXEC as _;
+
+        /// Mapping is shared.
+        pub const SHARED: usize = bindings::VM_SHARED as _;
+
+        /// Mapping may be updated to allow reads.
+        pub const MAYREAD: usize = bindings::VM_MAYREAD as _;
+
+        /// Mapping may be updated to allow writes.
+        pub const MAYWRITE: usize = bindings::VM_MAYWRITE as _;
+
+        /// Mapping may be updated to allow execution.
+        pub const MAYEXEC: usize = bindings::VM_MAYEXEC as _;
+
+        /// Mapping may be updated to be shared.
+        pub const MAYSHARE: usize = bindings::VM_MAYSHARE as _;
+
+        /// Do not copy this vma on fork.
+        pub const DONTCOPY: usize = bindings::VM_DONTCOPY as _;
+
+        /// Cannot expand with mremap().
+        pub const DONTEXPAND: usize = bindings::VM_DONTEXPAND as _;
+
+        /// Lock the pages covered when they are faulted in.
+        pub const LOCKONFAULT: usize = bindings::VM_LOCKONFAULT as _;
+
+        /// Is a VM accounted object.
+        pub const ACCOUNT: usize = bindings::VM_ACCOUNT as _;
+
+        /// should the VM suppress accounting.
+        pub const NORESERVE: usize = bindings::VM_NORESERVE as _;
+
+        /// Huge TLB Page VM.
+        pub const HUGETLB: usize = bindings::VM_HUGETLB as _;
+
+        /// Synchronous page faults.
+        pub const SYNC: usize = bindings::VM_SYNC as _;
+
+        /// Architecture-specific flag.
+        pub const ARCH_1: usize = bindings::VM_ARCH_1 as _;
+
+        /// Wipe VMA contents in child..
+        pub const WIPEONFORK: usize = bindings::VM_WIPEONFORK as _;
+
+        /// Do not include in the core dump.
+        pub const DONTDUMP: usize = bindings::VM_DONTDUMP as _;
+
+        /// Not soft dirty clean area.
+        pub const SOFTDIRTY: usize = bindings::VM_SOFTDIRTY as _;
+
+        /// Can contain "struct page" and pure PFN pages.
+        pub const MIXEDMAP: usize = bindings::VM_MIXEDMAP as _;
+
+        /// MADV_HUGEPAGE marked this vma.
+        pub const HUGEPAGE: usize = bindings::VM_HUGEPAGE as _;
+
+        /// MADV_NOHUGEPAGE marked this vma.
+        pub const NOHUGEPAGE: usize = bindings::VM_NOHUGEPAGE as _;
+
+        /// KSM may merge identical pages.
+        pub const MERGEABLE: usize = bindings::VM_MERGEABLE as _;
+    }
+}
diff --git a/rust/kernel/module_param.rs b/rust/kernel/module_param.rs
new file mode 100644
index 000000000000..5065dffa817e
--- /dev/null
+++ b/rust/kernel/module_param.rs
@@ -0,0 +1,498 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Types for module parameters.
+//!
+//! C header: [`include/linux/moduleparam.h`](../../../include/linux/moduleparam.h)
+
+use crate::error::{code::*, from_kernel_result};
+use crate::str::{CStr, Formatter};
+use core::fmt::Write;
+
+/// Types that can be used for module parameters.
+///
+/// Note that displaying the type in `sysfs` will fail if
+/// [`alloc::string::ToString::to_string`] (as implemented through the
+/// [`core::fmt::Display`] trait) writes more than [`PAGE_SIZE`]
+/// bytes (including an additional null terminator).
+///
+/// [`PAGE_SIZE`]: `crate::PAGE_SIZE`
+pub trait ModuleParam: core::fmt::Display + core::marker::Sized {
+    /// The `ModuleParam` will be used by the kernel module through this type.
+    ///
+    /// This may differ from `Self` if, for example, `Self` needs to track
+    /// ownership without exposing it or allocate extra space for other possible
+    /// parameter values. See [`StringParam`] or [`ArrayParam`] for examples.
+    type Value: ?Sized;
+
+    /// Whether the parameter is allowed to be set without an argument.
+    ///
+    /// Setting this to `true` allows the parameter to be passed without an
+    /// argument (e.g. just `module.param` instead of `module.param=foo`).
+    const NOARG_ALLOWED: bool;
+
+    /// Convert a parameter argument into the parameter value.
+    ///
+    /// `None` should be returned when parsing of the argument fails.
+    /// `arg == None` indicates that the parameter was passed without an
+    /// argument. If `NOARG_ALLOWED` is set to `false` then `arg` is guaranteed
+    /// to always be `Some(_)`.
+    ///
+    /// Parameters passed at boot time will be set before [`kmalloc`] is
+    /// available (even if the module is loaded at a later time). However, in
+    /// this case, the argument buffer will be valid for the entire lifetime of
+    /// the kernel. So implementations of this method which need to allocate
+    /// should first check that the allocator is available (with
+    /// [`crate::bindings::slab_is_available`]) and when it is not available
+    /// provide an alternative implementation which doesn't allocate. In cases
+    /// where the allocator is not available it is safe to save references to
+    /// `arg` in `Self`, but in other cases a copy should be made.
+    ///
+    /// [`kmalloc`]: ../../../include/linux/slab.h
+    fn try_from_param_arg(arg: Option<&'static [u8]>) -> Option<Self>;
+
+    /// Get the current value of the parameter for use in the kernel module.
+    ///
+    /// This function should not be used directly. Instead use the wrapper
+    /// `read` which will be generated by [`macros::module`].
+    fn value(&self) -> &Self::Value;
+
+    /// Set the module parameter from a string.
+    ///
+    /// Used to set the parameter value when loading the module or when set
+    /// through `sysfs`.
+    ///
+    /// # Safety
+    ///
+    /// If `val` is non-null then it must point to a valid null-terminated
+    /// string. The `arg` field of `param` must be an instance of `Self`.
+    unsafe extern "C" fn set_param(
+        val: *const crate::c_types::c_char,
+        param: *const crate::bindings::kernel_param,
+    ) -> crate::c_types::c_int {
+        let arg = if val.is_null() {
+            None
+        } else {
+            Some(unsafe { CStr::from_char_ptr(val).as_bytes() })
+        };
+        match Self::try_from_param_arg(arg) {
+            Some(new_value) => {
+                let old_value = unsafe { (*param).__bindgen_anon_1.arg as *mut Self };
+                let _ = unsafe { core::ptr::replace(old_value, new_value) };
+                0
+            }
+            None => EINVAL.to_kernel_errno(),
+        }
+    }
+
+    /// Write a string representation of the current parameter value to `buf`.
+    ///
+    /// Used for displaying the current parameter value in `sysfs`.
+    ///
+    /// # Safety
+    ///
+    /// `buf` must be a buffer of length at least `kernel::PAGE_SIZE` that is
+    /// writeable. The `arg` field of `param` must be an instance of `Self`.
+    unsafe extern "C" fn get_param(
+        buf: *mut crate::c_types::c_char,
+        param: *const crate::bindings::kernel_param,
+    ) -> crate::c_types::c_int {
+        from_kernel_result! {
+            // SAFETY: The C contracts guarantees that the buffer is at least `PAGE_SIZE` bytes.
+            let mut f = unsafe { Formatter::from_buffer(buf.cast(), crate::PAGE_SIZE) };
+            unsafe { write!(f, "{}\0", *((*param).__bindgen_anon_1.arg as *mut Self)) }?;
+            Ok(f.bytes_written().try_into()?)
+        }
+    }
+
+    /// Drop the parameter.
+    ///
+    /// Called when unloading a module.
+    ///
+    /// # Safety
+    ///
+    /// The `arg` field of `param` must be an instance of `Self`.
+    unsafe extern "C" fn free(arg: *mut crate::c_types::c_void) {
+        unsafe { core::ptr::drop_in_place(arg as *mut Self) };
+    }
+}
+
+/// Trait for parsing integers.
+///
+/// Strings begining with `0x`, `0o`, or `0b` are parsed as hex, octal, or
+/// binary respectively. Strings beginning with `0` otherwise are parsed as
+/// octal. Anything else is parsed as decimal. A leading `+` or `-` is also
+/// permitted. Any string parsed by [`kstrtol()`] or [`kstrtoul()`] will be
+/// successfully parsed.
+///
+/// [`kstrtol()`]: https://www.kernel.org/doc/html/latest/core-api/kernel-api.html#c.kstrtol
+/// [`kstrtoul()`]: https://www.kernel.org/doc/html/latest/core-api/kernel-api.html#c.kstrtoul
+trait ParseInt: Sized {
+    fn from_str_radix(src: &str, radix: u32) -> Result<Self, core::num::ParseIntError>;
+    fn checked_neg(self) -> Option<Self>;
+
+    fn from_str_unsigned(src: &str) -> Result<Self, core::num::ParseIntError> {
+        let (radix, digits) = if let Some(n) = src.strip_prefix("0x") {
+            (16, n)
+        } else if let Some(n) = src.strip_prefix("0X") {
+            (16, n)
+        } else if let Some(n) = src.strip_prefix("0o") {
+            (8, n)
+        } else if let Some(n) = src.strip_prefix("0O") {
+            (8, n)
+        } else if let Some(n) = src.strip_prefix("0b") {
+            (2, n)
+        } else if let Some(n) = src.strip_prefix("0B") {
+            (2, n)
+        } else if src.starts_with('0') {
+            (8, src)
+        } else {
+            (10, src)
+        };
+        Self::from_str_radix(digits, radix)
+    }
+
+    fn from_str(src: &str) -> Option<Self> {
+        match src.bytes().next() {
+            None => None,
+            Some(b'-') => Self::from_str_unsigned(&src[1..]).ok()?.checked_neg(),
+            Some(b'+') => Some(Self::from_str_unsigned(&src[1..]).ok()?),
+            Some(_) => Some(Self::from_str_unsigned(src).ok()?),
+        }
+    }
+}
+
+macro_rules! impl_parse_int {
+    ($ty:ident) => {
+        impl ParseInt for $ty {
+            fn from_str_radix(src: &str, radix: u32) -> Result<Self, core::num::ParseIntError> {
+                $ty::from_str_radix(src, radix)
+            }
+
+            fn checked_neg(self) -> Option<Self> {
+                self.checked_neg()
+            }
+        }
+    };
+}
+
+impl_parse_int!(i8);
+impl_parse_int!(u8);
+impl_parse_int!(i16);
+impl_parse_int!(u16);
+impl_parse_int!(i32);
+impl_parse_int!(u32);
+impl_parse_int!(i64);
+impl_parse_int!(u64);
+impl_parse_int!(isize);
+impl_parse_int!(usize);
+
+macro_rules! impl_module_param {
+    ($ty:ident) => {
+        impl ModuleParam for $ty {
+            type Value = $ty;
+
+            const NOARG_ALLOWED: bool = false;
+
+            fn try_from_param_arg(arg: Option<&'static [u8]>) -> Option<Self> {
+                let bytes = arg?;
+                let utf8 = core::str::from_utf8(bytes).ok()?;
+                <$ty as crate::module_param::ParseInt>::from_str(utf8)
+            }
+
+            fn value(&self) -> &Self::Value {
+                self
+            }
+        }
+    };
+}
+
+#[doc(hidden)]
+#[macro_export]
+/// Generate a static [`kernel_param_ops`](../../../include/linux/moduleparam.h) struct.
+///
+/// # Example
+/// ```ignore
+/// make_param_ops!(
+///     /// Documentation for new param ops.
+///     PARAM_OPS_MYTYPE, // Name for the static.
+///     MyType // A type which implements [`ModuleParam`].
+/// );
+/// ```
+macro_rules! make_param_ops {
+    ($ops:ident, $ty:ty) => {
+        $crate::make_param_ops!(
+            #[doc=""]
+            $ops,
+            $ty
+        );
+    };
+    ($(#[$meta:meta])* $ops:ident, $ty:ty) => {
+        $(#[$meta])*
+        ///
+        /// Static [`kernel_param_ops`](../../../include/linux/moduleparam.h)
+        /// struct generated by [`make_param_ops`].
+        pub static $ops: $crate::bindings::kernel_param_ops = $crate::bindings::kernel_param_ops {
+            flags: if <$ty as $crate::module_param::ModuleParam>::NOARG_ALLOWED {
+                $crate::bindings::KERNEL_PARAM_OPS_FL_NOARG
+            } else {
+                0
+            },
+            set: Some(<$ty as $crate::module_param::ModuleParam>::set_param),
+            get: Some(<$ty as $crate::module_param::ModuleParam>::get_param),
+            free: Some(<$ty as $crate::module_param::ModuleParam>::free),
+        };
+    };
+}
+
+impl_module_param!(i8);
+impl_module_param!(u8);
+impl_module_param!(i16);
+impl_module_param!(u16);
+impl_module_param!(i32);
+impl_module_param!(u32);
+impl_module_param!(i64);
+impl_module_param!(u64);
+impl_module_param!(isize);
+impl_module_param!(usize);
+
+make_param_ops!(
+    /// Rust implementation of [`kernel_param_ops`](../../../include/linux/moduleparam.h)
+    /// for [`i8`].
+    PARAM_OPS_I8,
+    i8
+);
+make_param_ops!(
+    /// Rust implementation of [`kernel_param_ops`](../../../include/linux/moduleparam.h)
+    /// for [`u8`].
+    PARAM_OPS_U8,
+    u8
+);
+make_param_ops!(
+    /// Rust implementation of [`kernel_param_ops`](../../../include/linux/moduleparam.h)
+    /// for [`i16`].
+    PARAM_OPS_I16,
+    i16
+);
+make_param_ops!(
+    /// Rust implementation of [`kernel_param_ops`](../../../include/linux/moduleparam.h)
+    /// for [`u16`].
+    PARAM_OPS_U16,
+    u16
+);
+make_param_ops!(
+    /// Rust implementation of [`kernel_param_ops`](../../../include/linux/moduleparam.h)
+    /// for [`i32`].
+    PARAM_OPS_I32,
+    i32
+);
+make_param_ops!(
+    /// Rust implementation of [`kernel_param_ops`](../../../include/linux/moduleparam.h)
+    /// for [`u32`].
+    PARAM_OPS_U32,
+    u32
+);
+make_param_ops!(
+    /// Rust implementation of [`kernel_param_ops`](../../../include/linux/moduleparam.h)
+    /// for [`i64`].
+    PARAM_OPS_I64,
+    i64
+);
+make_param_ops!(
+    /// Rust implementation of [`kernel_param_ops`](../../../include/linux/moduleparam.h)
+    /// for [`u64`].
+    PARAM_OPS_U64,
+    u64
+);
+make_param_ops!(
+    /// Rust implementation of [`kernel_param_ops`](../../../include/linux/moduleparam.h)
+    /// for [`isize`].
+    PARAM_OPS_ISIZE,
+    isize
+);
+make_param_ops!(
+    /// Rust implementation of [`kernel_param_ops`](../../../include/linux/moduleparam.h)
+    /// for [`usize`].
+    PARAM_OPS_USIZE,
+    usize
+);
+
+impl ModuleParam for bool {
+    type Value = bool;
+
+    const NOARG_ALLOWED: bool = true;
+
+    fn try_from_param_arg(arg: Option<&'static [u8]>) -> Option<Self> {
+        match arg {
+            None => Some(true),
+            Some(b"y") | Some(b"Y") | Some(b"1") | Some(b"true") => Some(true),
+            Some(b"n") | Some(b"N") | Some(b"0") | Some(b"false") => Some(false),
+            _ => None,
+        }
+    }
+
+    fn value(&self) -> &Self::Value {
+        self
+    }
+}
+
+make_param_ops!(
+    /// Rust implementation of [`kernel_param_ops`](../../../include/linux/moduleparam.h)
+    /// for [`bool`].
+    PARAM_OPS_BOOL,
+    bool
+);
+
+/// An array of at __most__ `N` values.
+///
+/// # Invariant
+///
+/// The first `self.used` elements of `self.values` are initialized.
+pub struct ArrayParam<T, const N: usize> {
+    values: [core::mem::MaybeUninit<T>; N],
+    used: usize,
+}
+
+impl<T, const N: usize> ArrayParam<T, { N }> {
+    fn values(&self) -> &[T] {
+        // SAFETY: The invariant maintained by `ArrayParam` allows us to cast
+        // the first `self.used` elements to `T`.
+        unsafe {
+            &*(&self.values[0..self.used] as *const [core::mem::MaybeUninit<T>] as *const [T])
+        }
+    }
+}
+
+impl<T: Copy, const N: usize> ArrayParam<T, { N }> {
+    const fn new() -> Self {
+        // INVARIANT: The first `self.used` elements of `self.values` are
+        // initialized.
+        ArrayParam {
+            values: [core::mem::MaybeUninit::uninit(); N],
+            used: 0,
+        }
+    }
+
+    const fn push(&mut self, val: T) {
+        if self.used < N {
+            // INVARIANT: The first `self.used` elements of `self.values` are
+            // initialized.
+            self.values[self.used] = core::mem::MaybeUninit::new(val);
+            self.used += 1;
+        }
+    }
+
+    /// Create an instance of `ArrayParam` initialized with `vals`.
+    ///
+    /// This function is only meant to be used in the [`module::module`] macro.
+    pub const fn create(vals: &[T]) -> Self {
+        let mut result = ArrayParam::new();
+        let mut i = 0;
+        while i < vals.len() {
+            result.push(vals[i]);
+            i += 1;
+        }
+        result
+    }
+}
+
+impl<T: core::fmt::Display, const N: usize> core::fmt::Display for ArrayParam<T, { N }> {
+    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
+        for val in self.values() {
+            write!(f, "{},", val)?;
+        }
+        Ok(())
+    }
+}
+
+impl<T: Copy + core::fmt::Display + ModuleParam, const N: usize> ModuleParam
+    for ArrayParam<T, { N }>
+{
+    type Value = [T];
+
+    const NOARG_ALLOWED: bool = false;
+
+    fn try_from_param_arg(arg: Option<&'static [u8]>) -> Option<Self> {
+        arg.and_then(|args| {
+            let mut result = Self::new();
+            for arg in args.split(|b| *b == b',') {
+                result.push(T::try_from_param_arg(Some(arg))?);
+            }
+            Some(result)
+        })
+    }
+
+    fn value(&self) -> &Self::Value {
+        self.values()
+    }
+}
+
+/// A C-style string parameter.
+///
+/// The Rust version of the [`charp`] parameter. This type is meant to be
+/// used by the [`macros::module`] macro, not handled directly. Instead use the
+/// `read` method generated by that macro.
+///
+/// [`charp`]: ../../../include/linux/moduleparam.h
+pub enum StringParam {
+    /// A borrowed parameter value.
+    ///
+    /// Either the default value (which is static in the module) or borrowed
+    /// from the original argument buffer used to set the value.
+    Ref(&'static [u8]),
+
+    /// A value that was allocated when the parameter was set.
+    ///
+    /// The value needs to be freed when the parameter is reset or the module is
+    /// unloaded.
+    Owned(alloc::vec::Vec<u8>),
+}
+
+impl StringParam {
+    fn bytes(&self) -> &[u8] {
+        match self {
+            StringParam::Ref(bytes) => *bytes,
+            StringParam::Owned(vec) => &vec[..],
+        }
+    }
+}
+
+impl core::fmt::Display for StringParam {
+    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
+        let bytes = self.bytes();
+        match core::str::from_utf8(bytes) {
+            Ok(utf8) => write!(f, "{}", utf8),
+            Err(_) => write!(f, "{:?}", bytes),
+        }
+    }
+}
+
+impl ModuleParam for StringParam {
+    type Value = [u8];
+
+    const NOARG_ALLOWED: bool = false;
+
+    fn try_from_param_arg(arg: Option<&'static [u8]>) -> Option<Self> {
+        // SAFETY: It is always safe to call [`slab_is_available`](../../../include/linux/slab.h).
+        let slab_available = unsafe { crate::bindings::slab_is_available() };
+        arg.and_then(|arg| {
+            if slab_available {
+                let mut vec = alloc::vec::Vec::new();
+                vec.try_extend_from_slice(arg).ok()?;
+                Some(StringParam::Owned(vec))
+            } else {
+                Some(StringParam::Ref(arg))
+            }
+        })
+    }
+
+    fn value(&self) -> &Self::Value {
+        self.bytes()
+    }
+}
+
+make_param_ops!(
+    /// Rust implementation of [`kernel_param_ops`](../../../include/linux/moduleparam.h)
+    /// for [`StringParam`].
+    PARAM_OPS_STR,
+    StringParam
+);
diff --git a/rust/kernel/net.rs b/rust/kernel/net.rs
new file mode 100644
index 000000000000..0495ab778144
--- /dev/null
+++ b/rust/kernel/net.rs
@@ -0,0 +1,392 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Networking core.
+//!
+//! C headers: [`include/net/net_namespace.h`](../../../../include/linux/net/net_namespace.h),
+//! [`include/linux/netdevice.h`](../../../../include/linux/netdevice.h),
+//! [`include/linux/skbuff.h`](../../../../include/linux/skbuff.h).
+
+use crate::{bindings, str::CStr, to_result, ARef, AlwaysRefCounted, Error, Result};
+use core::{cell::UnsafeCell, ptr::NonNull};
+
+#[cfg(CONFIG_NETFILTER)]
+pub mod filter;
+
+/// Wraps the kernel's `struct net_device`.
+#[repr(transparent)]
+pub struct Device(UnsafeCell<bindings::net_device>);
+
+// SAFETY: Instances of `Device` are created on the C side. They are always refcounted.
+unsafe impl AlwaysRefCounted for Device {
+    fn inc_ref(&self) {
+        // SAFETY: The existence of a shared reference means that the refcount is nonzero.
+        unsafe { bindings::dev_hold(self.0.get()) };
+    }
+
+    unsafe fn dec_ref(obj: core::ptr::NonNull<Self>) {
+        // SAFETY: The safety requirements guarantee that the refcount is nonzero.
+        unsafe { bindings::dev_put(obj.cast().as_ptr()) };
+    }
+}
+
+/// Wraps the kernel's `struct net`.
+#[repr(transparent)]
+pub struct Namespace(UnsafeCell<bindings::net>);
+
+impl Namespace {
+    /// Finds a network device with the given name in the namespace.
+    pub fn dev_get_by_name(&self, name: &CStr) -> Option<ARef<Device>> {
+        // SAFETY: The existence of a shared reference guarantees the refcount is nonzero.
+        let ptr =
+            NonNull::new(unsafe { bindings::dev_get_by_name(self.0.get(), name.as_char_ptr()) })?;
+        Some(unsafe { ARef::from_raw(ptr.cast()) })
+    }
+}
+
+// SAFETY: Instances of `Namespace` are created on the C side. They are always refcounted.
+unsafe impl AlwaysRefCounted for Namespace {
+    fn inc_ref(&self) {
+        // SAFETY: The existence of a shared reference means that the refcount is nonzero.
+        unsafe { bindings::get_net(self.0.get()) };
+    }
+
+    unsafe fn dec_ref(obj: core::ptr::NonNull<Self>) {
+        // SAFETY: The safety requirements guarantee that the refcount is nonzero.
+        unsafe { bindings::put_net(obj.cast().as_ptr()) };
+    }
+}
+
+/// Returns the network namespace for the `init` process.
+pub fn init_ns() -> &'static Namespace {
+    unsafe { &*core::ptr::addr_of!(bindings::init_net).cast() }
+}
+
+/// Wraps the kernel's `struct sk_buff`.
+#[repr(transparent)]
+pub struct SkBuff(UnsafeCell<bindings::sk_buff>);
+
+impl SkBuff {
+    /// Creates a reference to an [`SkBuff`] from a valid pointer.
+    ///
+    /// # Safety
+    ///
+    /// The caller must ensure that `ptr` is valid and remains valid for the lifetime of the
+    /// returned [`SkBuff`] instance.
+    pub unsafe fn from_ptr<'a>(ptr: *const bindings::sk_buff) -> &'a SkBuff {
+        // SAFETY: The safety requirements guarantee the validity of the dereference, while the
+        // `SkBuff` type being transparent makes the cast ok.
+        unsafe { &*ptr.cast() }
+    }
+
+    /// Returns the remaining data in the buffer's first segment.
+    pub fn head_data(&self) -> &[u8] {
+        // SAFETY: The existence of a shared reference means that the refcount is nonzero.
+        let headlen = unsafe { bindings::skb_headlen(self.0.get()) };
+        let len = headlen.try_into().unwrap_or(usize::MAX);
+        // SAFETY: The existence of a shared reference means `self.0` is valid.
+        let data = unsafe { core::ptr::addr_of!((*self.0.get()).data).read() };
+        // SAFETY: The `struct sk_buff` conventions guarantee that at least `skb_headlen(skb)` bytes
+        // are valid from `skb->data`.
+        unsafe { core::slice::from_raw_parts(data, len) }
+    }
+
+    /// Returns the total length of the data (in all segments) in the skb.
+    #[allow(clippy::len_without_is_empty)]
+    pub fn len(&self) -> u32 {
+        // SAFETY: The existence of a shared reference means `self.0` is valid.
+        unsafe { core::ptr::addr_of!((*self.0.get()).len).read() }
+    }
+}
+
+// SAFETY: Instances of `SkBuff` are created on the C side. They are always refcounted.
+unsafe impl AlwaysRefCounted for SkBuff {
+    fn inc_ref(&self) {
+        // SAFETY: The existence of a shared reference means that the refcount is nonzero.
+        unsafe { bindings::skb_get(self.0.get()) };
+    }
+
+    unsafe fn dec_ref(obj: core::ptr::NonNull<Self>) {
+        // SAFETY: The safety requirements guarantee that the refcount is nonzero.
+        unsafe {
+            bindings::kfree_skb_reason(
+                obj.cast().as_ptr(),
+                bindings::skb_drop_reason_SKB_DROP_REASON_NOT_SPECIFIED,
+            )
+        };
+    }
+}
+
+/// An IPv4 address.
+///
+/// This is equivalent to C's `in_addr`.
+#[repr(transparent)]
+pub struct Ipv4Addr(bindings::in_addr);
+
+impl Ipv4Addr {
+    /// A wildcard IPv4 address.
+    ///
+    /// Binding to this address means binding to all IPv4 addresses.
+    pub const ANY: Self = Self::new(0, 0, 0, 0);
+
+    /// The IPv4 loopback address.
+    pub const LOOPBACK: Self = Self::new(127, 0, 0, 1);
+
+    /// The IPv4 broadcast address.
+    pub const BROADCAST: Self = Self::new(255, 255, 255, 255);
+
+    /// Creates a new IPv4 address with the given components.
+    pub const fn new(a: u8, b: u8, c: u8, d: u8) -> Self {
+        Self(bindings::in_addr {
+            s_addr: u32::from_be_bytes([a, b, c, d]).to_be(),
+        })
+    }
+}
+
+/// An IPv6 address.
+///
+/// This is equivalent to C's `in6_addr`.
+#[repr(transparent)]
+pub struct Ipv6Addr(bindings::in6_addr);
+
+impl Ipv6Addr {
+    /// A wildcard IPv6 address.
+    ///
+    /// Binding to this address means binding to all IPv6 addresses.
+    pub const ANY: Self = Self::new(0, 0, 0, 0, 0, 0, 0, 0);
+
+    /// The IPv6 loopback address.
+    pub const LOOPBACK: Self = Self::new(0, 0, 0, 0, 0, 0, 0, 1);
+
+    /// Creates a new IPv6 address with the given components.
+    #[allow(clippy::too_many_arguments)]
+    pub const fn new(a: u16, b: u16, c: u16, d: u16, e: u16, f: u16, g: u16, h: u16) -> Self {
+        Self(bindings::in6_addr {
+            in6_u: bindings::in6_addr__bindgen_ty_1 {
+                u6_addr16: [
+                    a.to_be(),
+                    b.to_be(),
+                    c.to_be(),
+                    d.to_be(),
+                    e.to_be(),
+                    f.to_be(),
+                    g.to_be(),
+                    h.to_be(),
+                ],
+            },
+        })
+    }
+}
+
+/// A socket address.
+///
+/// It's an enum with either an IPv4 or IPv6 socket address.
+pub enum SocketAddr {
+    /// An IPv4 socket address.
+    V4(SocketAddrV4),
+
+    /// An IPv6 socket address.
+    V6(SocketAddrV6),
+}
+
+/// An IPv4 socket address.
+///
+/// This is equivalent to C's `sockaddr_in`.
+#[repr(transparent)]
+pub struct SocketAddrV4(bindings::sockaddr_in);
+
+impl SocketAddrV4 {
+    /// Creates a new IPv4 socket address.
+    pub const fn new(addr: Ipv4Addr, port: u16) -> Self {
+        Self(bindings::sockaddr_in {
+            sin_family: bindings::AF_INET as _,
+            sin_port: port.to_be(),
+            sin_addr: addr.0,
+            __pad: [0; 8],
+        })
+    }
+}
+
+/// An IPv6 socket address.
+///
+/// This is equivalent to C's `sockaddr_in6`.
+#[repr(transparent)]
+pub struct SocketAddrV6(bindings::sockaddr_in6);
+
+impl SocketAddrV6 {
+    /// Creates a new IPv6 socket address.
+    pub const fn new(addr: Ipv6Addr, port: u16, flowinfo: u32, scopeid: u32) -> Self {
+        Self(bindings::sockaddr_in6 {
+            sin6_family: bindings::AF_INET6 as _,
+            sin6_port: port.to_be(),
+            sin6_addr: addr.0,
+            sin6_flowinfo: flowinfo,
+            sin6_scope_id: scopeid,
+        })
+    }
+}
+
+/// A socket listening on a TCP port.
+///
+/// # Invariants
+///
+/// The socket pointer is always non-null and valid.
+pub struct TcpListener {
+    pub(crate) sock: *mut bindings::socket,
+}
+
+// SAFETY: `TcpListener` is just a wrapper for a kernel socket, which can be used from any thread.
+unsafe impl Send for TcpListener {}
+
+// SAFETY: `TcpListener` is just a wrapper for a kernel socket, which can be used from any thread.
+unsafe impl Sync for TcpListener {}
+
+impl TcpListener {
+    /// Creates a new TCP listener.
+    ///
+    /// It is configured to listen on the given socket address for the given namespace.
+    pub fn try_new(ns: &Namespace, addr: &SocketAddr) -> Result<Self> {
+        let mut socket = core::ptr::null_mut();
+        let (pf, addr, addrlen) = match addr {
+            SocketAddr::V4(addr) => (
+                bindings::PF_INET,
+                addr as *const _ as _,
+                core::mem::size_of::<bindings::sockaddr_in>(),
+            ),
+            SocketAddr::V6(addr) => (
+                bindings::PF_INET6,
+                addr as *const _ as _,
+                core::mem::size_of::<bindings::sockaddr_in6>(),
+            ),
+        };
+
+        // SAFETY: The namespace is valid and the output socket pointer is valid for write.
+        to_result(|| unsafe {
+            bindings::sock_create_kern(
+                ns.0.get(),
+                pf as _,
+                bindings::sock_type_SOCK_STREAM as _,
+                bindings::IPPROTO_TCP as _,
+                &mut socket,
+            )
+        })?;
+
+        // INVARIANT: The socket was just created, so it is valid.
+        let listener = Self { sock: socket };
+
+        // SAFETY: The type invariant guarantees that the socket is valid, and `addr` and `addrlen`
+        // were initialised based on valid values provided in the address enum.
+        to_result(|| unsafe { bindings::kernel_bind(socket, addr, addrlen as _) })?;
+
+        // SAFETY: The socket is valid per the type invariant.
+        to_result(|| unsafe { bindings::kernel_listen(socket, bindings::SOMAXCONN as _) })?;
+
+        Ok(listener)
+    }
+
+    /// Accepts a new connection.
+    ///
+    /// On success, returns the newly-accepted socket stream.
+    ///
+    /// If no connection is available to be accepted, one of two behaviours will occur:
+    /// - If `block` is `false`, returns [`crate::error::code::EAGAIN`];
+    /// - If `block` is `true`, blocks until an error occurs or some connection can be accepted.
+    pub fn accept(&self, block: bool) -> Result<TcpStream> {
+        let mut new = core::ptr::null_mut();
+        let flags = if block { 0 } else { bindings::O_NONBLOCK };
+        // SAFETY: The type invariant guarantees that the socket is valid, and the output argument
+        // is also valid for write.
+        to_result(|| unsafe { bindings::kernel_accept(self.sock, &mut new, flags as _) })?;
+        Ok(TcpStream { sock: new })
+    }
+}
+
+impl Drop for TcpListener {
+    fn drop(&mut self) {
+        // SAFETY: The type invariant guarantees that the socket is valid.
+        unsafe { bindings::sock_release(self.sock) };
+    }
+}
+
+/// A connected TCP socket.
+///
+/// # Invariants
+///
+/// The socket pointer is always non-null and valid.
+pub struct TcpStream {
+    pub(crate) sock: *mut bindings::socket,
+}
+
+// SAFETY: `TcpStream` is just a wrapper for a kernel socket, which can be used from any thread.
+unsafe impl Send for TcpStream {}
+
+// SAFETY: `TcpStream` is just a wrapper for a kernel socket, which can be used from any thread.
+unsafe impl Sync for TcpStream {}
+
+impl TcpStream {
+    /// Reads data from a connected socket.
+    ///
+    /// On success, returns the number of bytes read, which will be zero if the connection is
+    /// closed.
+    ///
+    /// If no data is immediately available for reading, one of two behaviours will occur:
+    /// - If `block` is `false`, returns [`crate::error::code::EAGAIN`];
+    /// - If `block` is `true`, blocks until an error occurs, the connection is closed, or some
+    ///   becomes readable.
+    pub fn read(&self, buf: &mut [u8], block: bool) -> Result<usize> {
+        let mut msg = bindings::msghdr::default();
+        let mut vec = bindings::kvec {
+            iov_base: buf.as_mut_ptr().cast(),
+            iov_len: buf.len(),
+        };
+        // SAFETY: The type invariant guarantees that the socket is valid, and `vec` was
+        // initialised with the output buffer.
+        let r = unsafe {
+            bindings::kernel_recvmsg(
+                self.sock,
+                &mut msg,
+                &mut vec,
+                1,
+                vec.iov_len,
+                if block { 0 } else { bindings::MSG_DONTWAIT } as _,
+            )
+        };
+        if r < 0 {
+            Err(Error::from_kernel_errno(r))
+        } else {
+            Ok(r as _)
+        }
+    }
+
+    /// Writes data to the connected socket.
+    ///
+    /// On success, returns the number of bytes written.
+    ///
+    /// If the send buffer of the socket is full, one of two behaviours will occur:
+    /// - If `block` is `false`, returns [`crate::error::code::EAGAIN`];
+    /// - If `block` is `true`, blocks until an error occurs or some data is written.
+    pub fn write(&self, buf: &[u8], block: bool) -> Result<usize> {
+        let mut msg = bindings::msghdr {
+            msg_flags: if block { 0 } else { bindings::MSG_DONTWAIT },
+            ..bindings::msghdr::default()
+        };
+        let mut vec = bindings::kvec {
+            iov_base: buf.as_ptr() as *mut u8 as _,
+            iov_len: buf.len(),
+        };
+        // SAFETY: The type invariant guarantees that the socket is valid, and `vec` was
+        // initialised with the input  buffer.
+        let r = unsafe { bindings::kernel_sendmsg(self.sock, &mut msg, &mut vec, 1, vec.iov_len) };
+        if r < 0 {
+            Err(Error::from_kernel_errno(r))
+        } else {
+            Ok(r as _)
+        }
+    }
+}
+
+impl Drop for TcpStream {
+    fn drop(&mut self) {
+        // SAFETY: The type invariant guarantees that the socket is valid.
+        unsafe { bindings::sock_release(self.sock) };
+    }
+}
diff --git a/rust/kernel/net/filter.rs b/rust/kernel/net/filter.rs
new file mode 100644
index 000000000000..3241100a1561
--- /dev/null
+++ b/rust/kernel/net/filter.rs
@@ -0,0 +1,447 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Networking filters.
+//!
+//! C header: [`include/linux/netfilter.h`](../../../../../include/linux/netfilter.h)
+
+use crate::{
+    bindings, c_types,
+    error::{code::*, to_result},
+    net,
+    types::PointerWrapper,
+    ARef, AlwaysRefCounted, Result, ScopeGuard,
+};
+use alloc::boxed::Box;
+use core::{
+    marker::{PhantomData, PhantomPinned},
+    pin::Pin,
+};
+
+/// A network filter.
+pub trait Filter {
+    /// The type of the context data stored on registration and made available to the
+    /// [`Filter::filter`] function.
+    type Data: PointerWrapper + Sync = ();
+
+    /// Filters the packet stored in the given buffer.
+    ///
+    /// It dictates to the netfilter core what the fate of the packet should be.
+    fn filter(
+        _data: <Self::Data as PointerWrapper>::Borrowed<'_>,
+        _skb: &net::SkBuff,
+    ) -> Disposition;
+}
+
+/// Specifies the action to be taken by the netfilter core.
+pub enum Disposition {
+    /// Drop the packet.
+    Drop,
+
+    /// Accept the packet.
+    Accept,
+
+    /// The packet was stolen by the filter and must be treated as if it didn't exist.
+    Stolen,
+
+    /// Queue the packet to the given user-space queue.
+    Queue {
+        /// The identifier of the queue to which the packet should be added.
+        queue_id: u16,
+
+        /// Specifies the behaviour if a queue with the given identifier doesn't exist: if `true`,
+        /// the packet is accepted, otherwise it is rejected.
+        accept_if_queue_non_existent: bool,
+    },
+}
+
+/// The filter hook families.
+pub enum Family {
+    ///  IPv4 and IPv6 packets.
+    INet(inet::Hook),
+
+    /// IPv4 packets.
+    Ipv4(ipv4::Hook, ipv4::PriorityBase),
+
+    /// All packets through a device.
+    ///
+    /// When this family is used, a device _must_ be specified.
+    NetDev(netdev::Hook),
+
+    /// IPv6 packets.
+    Ipv6(ipv6::Hook, ipv6::PriorityBase),
+
+    /// Address resolution protocol (ARP) packets.
+    Arp(arp::Hook),
+}
+
+/// A registration of a networking filter.
+///
+/// # Examples
+///
+/// The following is an example of a function that attaches an inbound filter (that always accepts
+/// all packets after printing their lengths) on the specified device (in the `init` ns).
+///
+/// ```
+/// use kernel::net::{self, filter as netfilter};
+///
+/// struct MyFilter;
+/// impl netfilter::Filter for MyFilter {
+///     fn filter(_data: (), skb: &net::SkBuff) -> netfilter::Disposition {
+///         pr_info!("Packet of length {}\n", skb.len());
+///         netfilter::Disposition::Accept
+///     }
+/// }
+///
+/// fn register(name: &CStr) -> Result<Pin<Box<netfilter::Registration<MyFilter>>>> {
+///     let ns = net::init_ns();
+///     let dev = ns.dev_get_by_name(name).ok_or(ENOENT)?;
+///     netfilter::Registration::new_pinned(
+///         netfilter::Family::NetDev(netfilter::netdev::Hook::Ingress),
+///         0,
+///         ns.into(),
+///         Some(dev),
+///         (),
+///     )
+/// }
+/// ```
+#[derive(Default)]
+pub struct Registration<T: Filter> {
+    hook: bindings::nf_hook_ops,
+    // When `ns` is `Some(_)`, the hook is registered.
+    ns: Option<ARef<net::Namespace>>,
+    dev: Option<ARef<net::Device>>,
+    _p: PhantomData<T>,
+    _pinned: PhantomPinned,
+}
+
+// SAFETY: `Registration` does not expose any of its state across threads.
+unsafe impl<T: Filter> Sync for Registration<T> {}
+
+impl<T: Filter> Registration<T> {
+    /// Creates a new [`Registration`] but does not register it yet.
+    ///
+    /// It is allowed to move.
+    pub fn new() -> Self {
+        Self {
+            hook: bindings::nf_hook_ops::default(),
+            dev: None,
+            ns: None,
+            _p: PhantomData,
+            _pinned: PhantomPinned,
+        }
+    }
+
+    /// Creates a new filter registration and registers it.
+    ///
+    /// Returns a pinned heap-allocated representation of the registration.
+    pub fn new_pinned(
+        family: Family,
+        priority: i32,
+        ns: ARef<net::Namespace>,
+        dev: Option<ARef<net::Device>>,
+        data: T::Data,
+    ) -> Result<Pin<Box<Self>>> {
+        let mut filter = Pin::from(Box::try_new(Self::new())?);
+        filter.as_mut().register(family, priority, ns, dev, data)?;
+        Ok(filter)
+    }
+
+    /// Registers a network filter.
+    ///
+    /// It must be pinned because the C portion of the kernel stores a pointer to it while it is
+    /// registered.
+    ///
+    /// The priority is relative to the family's base priority. For example, if the base priority
+    /// is `100` and `priority` is `-1`, the actual priority will be `99`. If a family doesn't
+    /// explicitly allow a base to be specified, `0` is assumed.
+    pub fn register(
+        self: Pin<&mut Self>,
+        family: Family,
+        priority: i32,
+        ns: ARef<net::Namespace>,
+        dev: Option<ARef<net::Device>>,
+        data: T::Data,
+    ) -> Result {
+        // SAFETY: We must ensure that we never move out of `this`.
+        let this = unsafe { self.get_unchecked_mut() };
+        if this.ns.is_some() {
+            // Already registered.
+            return Err(EINVAL);
+        }
+
+        let data_pointer = data.into_pointer();
+
+        // SAFETY: `data_pointer` comes from the call to `data.into_pointer()` above.
+        let guard = ScopeGuard::new(|| unsafe {
+            T::Data::from_pointer(data_pointer);
+        });
+
+        let mut pri_base = 0i32;
+        match family {
+            Family::INet(hook) => {
+                this.hook.pf = bindings::NFPROTO_INET as _;
+                this.hook.hooknum = hook as _;
+            }
+            Family::Ipv4(hook, pbase) => {
+                this.hook.pf = bindings::NFPROTO_IPV4 as _;
+                this.hook.hooknum = hook as _;
+                pri_base = pbase as _;
+            }
+            Family::Ipv6(hook, pbase) => {
+                this.hook.pf = bindings::NFPROTO_IPV6 as _;
+                this.hook.hooknum = hook as _;
+                pri_base = pbase as _;
+            }
+            Family::NetDev(hook) => {
+                this.hook.pf = bindings::NFPROTO_NETDEV as _;
+                this.hook.hooknum = hook as _;
+            }
+            Family::Arp(hook) => {
+                this.hook.pf = bindings::NFPROTO_ARP as _;
+                this.hook.hooknum = hook as _;
+            }
+        }
+
+        this.hook.priority = pri_base.saturating_add(priority);
+        this.hook.priv_ = data_pointer as _;
+        this.hook.hook = Some(Self::hook_callback);
+        crate::static_assert!(bindings::nf_hook_ops_type_NF_HOOK_OP_UNDEFINED == 0);
+
+        if let Some(ref device) = dev {
+            this.hook.dev = device.0.get();
+        }
+
+        // SAFETY: `ns` has a valid reference to the namespace, and `this.hook` was just
+        // initialised above, so they're both valid.
+        to_result(|| unsafe { bindings::nf_register_net_hook(ns.0.get(), &this.hook) })?;
+
+        this.dev = dev;
+        this.ns = Some(ns);
+        guard.dismiss();
+        Ok(())
+    }
+
+    unsafe extern "C" fn hook_callback(
+        priv_: *mut c_types::c_void,
+        skb: *mut bindings::sk_buff,
+        _state: *const bindings::nf_hook_state,
+    ) -> c_types::c_uint {
+        // SAFETY: `priv_` was initialised on registration by a value returned from
+        // `T::Data::into_pointer`, and it remains valid until the hook is unregistered.
+        let data = unsafe { T::Data::borrow(priv_) };
+
+        // SAFETY: The C contract guarantees that `skb` remains valid for the duration of this
+        // function call.
+        match T::filter(data, unsafe { net::SkBuff::from_ptr(skb) }) {
+            Disposition::Drop => bindings::NF_DROP,
+            Disposition::Accept => bindings::NF_ACCEPT,
+            Disposition::Stolen => {
+                // SAFETY: This function takes over ownership of `skb` when it returns `NF_STOLEN`,
+                // so we decrement the refcount here to avoid a leak.
+                unsafe { net::SkBuff::dec_ref(core::ptr::NonNull::new(skb).unwrap().cast()) };
+                bindings::NF_STOLEN
+            }
+            Disposition::Queue {
+                queue_id,
+                accept_if_queue_non_existent,
+            } => {
+                // SAFETY: Just an FFI call, no additional safety requirements.
+                let verdict = unsafe { bindings::NF_QUEUE_NR(queue_id as _) };
+                if accept_if_queue_non_existent {
+                    verdict | bindings::NF_VERDICT_FLAG_QUEUE_BYPASS
+                } else {
+                    verdict
+                }
+            }
+        }
+    }
+}
+
+impl<T: Filter> Drop for Registration<T> {
+    fn drop(&mut self) {
+        if let Some(ref ns) = self.ns {
+            // SAFETY: `self.ns` is `Some(_)` only when a previous call to `nf_register_net_hook`
+            // succeeded. And the arguments are the same.
+            unsafe { bindings::nf_unregister_net_hook(ns.0.get(), &self.hook) };
+
+            // `self.hook.priv_` was initialised during registration to a value returned from
+            // `T::Data::into_pointer`, so it is ok to convert back here.
+            unsafe { T::Data::from_pointer(self.hook.priv_) };
+        }
+    }
+}
+
+/// Definitions used when defining hooks for the [`Family::NetDev`] family.
+pub mod netdev {
+    use crate::bindings;
+
+    /// Hooks allowed in the [`super::Family::NetDev`] family.
+    #[repr(u32)]
+    pub enum Hook {
+        /// All inbound packets through the given device.
+        Ingress = bindings::nf_dev_hooks_NF_NETDEV_INGRESS,
+
+        /// All outbound packets through the given device.
+        Egress = bindings::nf_dev_hooks_NF_NETDEV_EGRESS,
+    }
+}
+
+/// Definitions used when defining hooks for the [`Family::Ipv4`] family.
+pub mod ipv4 {
+    use crate::bindings;
+
+    /// Hooks allowed in [`super::Family::Ipv4`] family.
+    pub type Hook = super::inet::Hook;
+
+    /// The base priority for [`super::Family::Ipv4`] hooks.
+    ///
+    /// The actual priority is the base priority plus the priority specified when registering.
+    #[repr(i32)]
+    pub enum PriorityBase {
+        /// Same as the `NF_IP_PRI_FIRST` C constant.
+        First = bindings::nf_ip_hook_priorities_NF_IP_PRI_FIRST,
+
+        /// Same as the `NF_IP_PRI_RAW_BEFORE_DEFRAG` C constant.
+        RawBeforeDefrag = bindings::nf_ip_hook_priorities_NF_IP_PRI_RAW_BEFORE_DEFRAG,
+
+        /// Same as the `NF_IP_PRI_CONNTRACK_DEFRAG` C constant.
+        ConnTrackDefrag = bindings::nf_ip_hook_priorities_NF_IP_PRI_CONNTRACK_DEFRAG,
+
+        /// Same as the `NF_IP_PRI_RAW` C constant.
+        Raw = bindings::nf_ip_hook_priorities_NF_IP_PRI_RAW,
+
+        /// Same as the `NF_IP_PRI_SELINUX_FIRST` C constant.
+        SeLinuxFirst = bindings::nf_ip_hook_priorities_NF_IP_PRI_SELINUX_FIRST,
+
+        /// Same as the `NF_IP_PRI_CONNTRACK` C constant.
+        ConnTrack = bindings::nf_ip_hook_priorities_NF_IP_PRI_CONNTRACK,
+
+        /// Same as the `NF_IP_PRI_MANGLE` C constant.
+        Mangle = bindings::nf_ip_hook_priorities_NF_IP_PRI_MANGLE,
+
+        /// Same as the `NF_IP_PRI_NAT_DST` C constant.
+        NatDst = bindings::nf_ip_hook_priorities_NF_IP_PRI_NAT_DST,
+
+        /// Same as the `NF_IP_PRI_FILTER` C constant.
+        Filter = bindings::nf_ip_hook_priorities_NF_IP_PRI_FILTER,
+
+        /// Same as the `NF_IP_PRI_SECURITY` C constant.
+        Security = bindings::nf_ip_hook_priorities_NF_IP_PRI_SECURITY,
+
+        /// Same as the `NF_IP_PRI_NAT_SRC` C constant.
+        NatSrc = bindings::nf_ip_hook_priorities_NF_IP_PRI_NAT_SRC,
+
+        /// Same as the `NF_IP_PRI_SELINUX_LAST` C constant.
+        SeLinuxLast = bindings::nf_ip_hook_priorities_NF_IP_PRI_SELINUX_LAST,
+
+        /// Same as the `NF_IP_PRI_CONNTRACK_HELPER` C constant.
+        ConnTrackHelper = bindings::nf_ip_hook_priorities_NF_IP_PRI_CONNTRACK_HELPER,
+
+        /// Same as the `NF_IP_PRI_LAST` and `NF_IP_PRI_CONNTRACK_CONFIRM` C constants.
+        Last = bindings::nf_ip_hook_priorities_NF_IP_PRI_LAST,
+    }
+}
+
+/// Definitions used when defining hooks for the [`Family::Ipv6`] family.
+pub mod ipv6 {
+    use crate::bindings;
+
+    /// Hooks allowed in [`super::Family::Ipv6`] family.
+    pub type Hook = super::inet::Hook;
+
+    /// The base priority for [`super::Family::Ipv6`] hooks.
+    ///
+    /// The actual priority is the base priority plus the priority specified when registering.
+    #[repr(i32)]
+    pub enum PriorityBase {
+        /// Same as the `NF_IP6_PRI_FIRST` C constant.
+        First = bindings::nf_ip6_hook_priorities_NF_IP6_PRI_FIRST,
+
+        /// Same as the `NF_IP6_PRI_RAW_BEFORE_DEFRAG` C constant.
+        RawBeforeDefrag = bindings::nf_ip6_hook_priorities_NF_IP6_PRI_RAW_BEFORE_DEFRAG,
+
+        /// Same as the `NF_IP6_PRI_CONNTRACK_DEFRAG` C constant.
+        ConnTrackDefrag = bindings::nf_ip6_hook_priorities_NF_IP6_PRI_CONNTRACK_DEFRAG,
+
+        /// Same as the `NF_IP6_PRI_RAW` C constant.
+        Raw = bindings::nf_ip6_hook_priorities_NF_IP6_PRI_RAW,
+
+        /// Same as the `NF_IP6_PRI_SELINUX_FIRST` C constant.
+        SeLinuxFirst = bindings::nf_ip6_hook_priorities_NF_IP6_PRI_SELINUX_FIRST,
+
+        /// Same as the `NF_IP6_PRI_CONNTRACK` C constant.
+        ConnTrack = bindings::nf_ip6_hook_priorities_NF_IP6_PRI_CONNTRACK,
+
+        /// Same as the `NF_IP6_PRI_MANGLE` C constant.
+        Mangle = bindings::nf_ip6_hook_priorities_NF_IP6_PRI_MANGLE,
+
+        /// Same as the `NF_IP6_PRI_NAT_DST` C constant.
+        NatDst = bindings::nf_ip6_hook_priorities_NF_IP6_PRI_NAT_DST,
+
+        /// Same as the `NF_IP6_PRI_FILTER` C constant.
+        Filter = bindings::nf_ip6_hook_priorities_NF_IP6_PRI_FILTER,
+
+        /// Same as the `NF_IP6_PRI_SECURITY` C constant.
+        Security = bindings::nf_ip6_hook_priorities_NF_IP6_PRI_SECURITY,
+
+        /// Same as the `NF_IP6_PRI_NAT_SRC` C constant.
+        NatSrc = bindings::nf_ip6_hook_priorities_NF_IP6_PRI_NAT_SRC,
+
+        /// Same as the `NF_IP6_PRI_SELINUX_LAST` C constant.
+        SeLinuxLast = bindings::nf_ip6_hook_priorities_NF_IP6_PRI_SELINUX_LAST,
+
+        /// Same as the `NF_IP6_PRI_CONNTRACK_HELPER` C constant.
+        ConnTrackHelper = bindings::nf_ip6_hook_priorities_NF_IP6_PRI_CONNTRACK_HELPER,
+
+        /// Same as the `NF_IP6_PRI_LAST` C constant.
+        Last = bindings::nf_ip6_hook_priorities_NF_IP6_PRI_LAST,
+    }
+}
+
+/// Definitions used when defining hooks for the [`Family::Arp`] family.
+pub mod arp {
+    use crate::bindings;
+
+    /// Hooks allowed in the [`super::Family::Arp`] family.
+    #[repr(u32)]
+    pub enum Hook {
+        /// Inbound ARP packets.
+        In = bindings::NF_ARP_IN,
+
+        /// Outbound ARP packets.
+        Out = bindings::NF_ARP_OUT,
+
+        /// Forwarded ARP packets.
+        Forward = bindings::NF_ARP_FORWARD,
+    }
+}
+
+/// Definitions used when defining hooks for the [`Family::INet`] family.
+pub mod inet {
+    use crate::bindings;
+
+    /// Hooks allowed in the [`super::Family::INet`], [`super::Family::Ipv4`], and
+    /// [`super::Family::Ipv6`] families.
+    #[repr(u32)]
+    pub enum Hook {
+        /// Inbound packets before routing decisions are made (i.e., before it's determined if the
+        /// packet is to be delivered locally or forwarded to another host).
+        PreRouting = bindings::nf_inet_hooks_NF_INET_PRE_ROUTING as _,
+
+        /// Inbound packets that are meant to be delivered locally.
+        LocalIn = bindings::nf_inet_hooks_NF_INET_LOCAL_IN as _,
+
+        /// Inbound packets that are meant to be forwarded to another host.
+        Forward = bindings::nf_inet_hooks_NF_INET_FORWARD as _,
+
+        /// Outbound packet created by the local networking stack.
+        LocalOut = bindings::nf_inet_hooks_NF_INET_LOCAL_OUT as _,
+
+        /// All outbound packets (i.e., generated locally or being forwarded to another host).
+        PostRouting = bindings::nf_inet_hooks_NF_INET_POST_ROUTING as _,
+
+        /// Equivalent to [`super::netdev::Hook::Ingress`], so a device must be specified. Packets
+        /// of all types (not just ipv4/ipv6) will be delivered to the filter.
+        Ingress = bindings::nf_inet_hooks_NF_INET_INGRESS as _,
+    }
+}
diff --git a/rust/kernel/of.rs b/rust/kernel/of.rs
new file mode 100644
index 000000000000..cdcd83244337
--- /dev/null
+++ b/rust/kernel/of.rs
@@ -0,0 +1,63 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Devicetree and Open Firmware abstractions.
+//!
+//! C header: [`include/linux/of_*.h`](../../../../include/linux/of_*.h)
+
+use crate::{bindings, driver, str::BStr};
+
+/// An open firmware device id.
+#[derive(Clone, Copy)]
+pub enum DeviceId {
+    /// An open firmware device id where only a compatible string is specified.
+    Compatible(&'static BStr),
+}
+
+/// Defines a const open firmware device id table that also carries per-entry data/context/info.
+///
+/// The name of the const is `OF_DEVICE_ID_TABLE`, which is what buses are expected to name their
+/// open firmware tables.
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::define_of_id_table;
+/// use kernel::of;
+///
+/// define_of_id_table! {u32, [
+///     (of::DeviceId::Compatible(b"test-device1,test-device2"), Some(0xff)),
+///     (of::DeviceId::Compatible(b"test-device3"), None),
+/// ]};
+/// ```
+#[macro_export]
+macro_rules! define_of_id_table {
+    ($data_type:ty, $($t:tt)*) => {
+        $crate::define_id_table!(OF_DEVICE_ID_TABLE, $crate::of::DeviceId, $data_type, $($t)*);
+    };
+}
+
+// SAFETY: `ZERO` is all zeroed-out and `to_rawid` stores `offset` in `of_device_id::data`.
+unsafe impl const driver::RawDeviceId for DeviceId {
+    type RawType = bindings::of_device_id;
+    const ZERO: Self::RawType = bindings::of_device_id {
+        name: [0; 32],
+        type_: [0; 32],
+        compatible: [0; 128],
+        data: core::ptr::null(),
+    };
+
+    fn to_rawid(&self, offset: isize) -> Self::RawType {
+        let DeviceId::Compatible(compatible) = self;
+        let mut id = Self::ZERO;
+        let mut i = 0;
+        while i < compatible.len() {
+            // If `compatible` does not fit in `id.compatible`, an "index out of bounds" build time
+            // error will be triggered.
+            id.compatible[i] = compatible[i] as _;
+            i += 1;
+        }
+        id.compatible[i] = b'\0' as _;
+        id.data = offset as _;
+        id
+    }
+}
diff --git a/rust/kernel/pages.rs b/rust/kernel/pages.rs
new file mode 100644
index 000000000000..02c0d500fae4
--- /dev/null
+++ b/rust/kernel/pages.rs
@@ -0,0 +1,144 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Kernel page allocation and management.
+//!
+//! TODO: This module is a work in progress.
+
+use crate::{
+    bindings, c_types, error::code::*, io_buffer::IoBufferReader, user_ptr::UserSlicePtrReader,
+    Result, PAGE_SIZE,
+};
+use core::{marker::PhantomData, ptr};
+
+/// A set of physical pages.
+///
+/// `Pages` holds a reference to a set of pages of order `ORDER`. Having the order as a generic
+/// const allows the struct to have the same size as a pointer.
+///
+/// # Invariants
+///
+/// The pointer `Pages::pages` is valid and points to 2^ORDER pages.
+pub struct Pages<const ORDER: u32> {
+    pub(crate) pages: *mut bindings::page,
+}
+
+impl<const ORDER: u32> Pages<ORDER> {
+    /// Allocates a new set of contiguous pages.
+    pub fn new() -> Result<Self> {
+        // TODO: Consider whether we want to allow callers to specify flags.
+        // SAFETY: This only allocates pages. We check that it succeeds in the next statement.
+        let pages = unsafe {
+            bindings::alloc_pages(
+                bindings::GFP_KERNEL | bindings::__GFP_ZERO | bindings::__GFP_HIGHMEM,
+                ORDER,
+            )
+        };
+        if pages.is_null() {
+            return Err(ENOMEM);
+        }
+        // INVARIANTS: We checked that the allocation above succeeded>
+        Ok(Self { pages })
+    }
+
+    /// Copies data from the given [`UserSlicePtrReader`] into the pages.
+    pub fn copy_into_page(
+        &self,
+        reader: &mut UserSlicePtrReader,
+        offset: usize,
+        len: usize,
+    ) -> Result {
+        // TODO: For now this only works on the first page.
+        let end = offset.checked_add(len).ok_or(EINVAL)?;
+        if end > PAGE_SIZE {
+            return Err(EINVAL);
+        }
+
+        let mapping = self.kmap(0).ok_or(EINVAL)?;
+
+        // SAFETY: We ensured that the buffer was valid with the check above.
+        unsafe { reader.read_raw((mapping.ptr as usize + offset) as _, len) }?;
+        Ok(())
+    }
+
+    /// Maps the pages and reads from them into the given buffer.
+    ///
+    /// # Safety
+    ///
+    /// Callers must ensure that the destination buffer is valid for the given length.
+    /// Additionally, if the raw buffer is intended to be recast, they must ensure that the data
+    /// can be safely cast; [`crate::io_buffer::ReadableFromBytes`] has more details about it.
+    pub unsafe fn read(&self, dest: *mut u8, offset: usize, len: usize) -> Result {
+        // TODO: For now this only works on the first page.
+        let end = offset.checked_add(len).ok_or(EINVAL)?;
+        if end > PAGE_SIZE {
+            return Err(EINVAL);
+        }
+
+        let mapping = self.kmap(0).ok_or(EINVAL)?;
+        unsafe { ptr::copy((mapping.ptr as *mut u8).add(offset), dest, len) };
+        Ok(())
+    }
+
+    /// Maps the pages and writes into them from the given bufer.
+    ///
+    /// # Safety
+    ///
+    /// Callers must ensure that the buffer is valid for the given length. Additionally, if the
+    /// page is (or will be) mapped by userspace, they must ensure that no kernel data is leaked
+    /// through padding if it was cast from another type; [`crate::io_buffer::WritableToBytes`] has
+    /// more details about it.
+    pub unsafe fn write(&self, src: *const u8, offset: usize, len: usize) -> Result {
+        // TODO: For now this only works on the first page.
+        let end = offset.checked_add(len).ok_or(EINVAL)?;
+        if end > PAGE_SIZE {
+            return Err(EINVAL);
+        }
+
+        let mapping = self.kmap(0).ok_or(EINVAL)?;
+        unsafe { ptr::copy(src, (mapping.ptr as *mut u8).add(offset), len) };
+        Ok(())
+    }
+
+    /// Maps the page at index `index`.
+    fn kmap(&self, index: usize) -> Option<PageMapping<'_>> {
+        if index >= 1usize << ORDER {
+            return None;
+        }
+
+        // SAFETY: We checked above that `index` is within range.
+        let page = unsafe { self.pages.add(index) };
+
+        // SAFETY: `page` is valid based on the checks above.
+        let ptr = unsafe { bindings::kmap(page) };
+        if ptr.is_null() {
+            return None;
+        }
+
+        Some(PageMapping {
+            page,
+            ptr,
+            _phantom: PhantomData,
+        })
+    }
+}
+
+impl<const ORDER: u32> Drop for Pages<ORDER> {
+    fn drop(&mut self) {
+        // SAFETY: By the type invariants, we know the pages are allocated with the given order.
+        unsafe { bindings::__free_pages(self.pages, ORDER) };
+    }
+}
+
+struct PageMapping<'a> {
+    page: *mut bindings::page,
+    ptr: *mut c_types::c_void,
+    _phantom: PhantomData<&'a i32>,
+}
+
+impl Drop for PageMapping<'_> {
+    fn drop(&mut self) {
+        // SAFETY: An instance of `PageMapping` is created only when `kmap` succeeded for the given
+        // page, so it is safe to unmap it here.
+        unsafe { bindings::kunmap(self.page) };
+    }
+}
diff --git a/rust/kernel/platform.rs b/rust/kernel/platform.rs
new file mode 100644
index 000000000000..f597796974f1
--- /dev/null
+++ b/rust/kernel/platform.rs
@@ -0,0 +1,223 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Platform devices and drivers.
+//!
+//! Also called `platdev`, `pdev`.
+//!
+//! C header: [`include/linux/platform_device.h`](../../../../include/linux/platform_device.h)
+
+use crate::{
+    bindings, c_types,
+    device::{self, RawDevice},
+    driver,
+    error::{from_kernel_result, Result},
+    of,
+    str::CStr,
+    to_result,
+    types::PointerWrapper,
+    ThisModule,
+};
+
+/// A registration of a platform driver.
+pub type Registration<T> = driver::Registration<Adapter<T>>;
+
+/// An adapter for the registration of platform drivers.
+pub struct Adapter<T: Driver>(T);
+
+impl<T: Driver> driver::DriverOps for Adapter<T> {
+    type RegType = bindings::platform_driver;
+
+    unsafe fn register(
+        reg: *mut bindings::platform_driver,
+        name: &'static CStr,
+        module: &'static ThisModule,
+    ) -> Result {
+        // SAFETY: By the safety requirements of this function (defined in the trait defintion),
+        // `reg` is non-null and valid.
+        let pdrv = unsafe { &mut *reg };
+
+        pdrv.driver.name = name.as_char_ptr();
+        pdrv.probe = Some(Self::probe_callback);
+        pdrv.remove = Some(Self::remove_callback);
+        if let Some(t) = T::OF_DEVICE_ID_TABLE {
+            pdrv.driver.of_match_table = t.as_ref();
+        }
+        // SAFETY:
+        //   - `pdrv` lives at least until the call to `platform_driver_unregister()` returns.
+        //   - `name` pointer has static lifetime.
+        //   - `module.0` lives at least as long as the module.
+        //   - `probe()` and `remove()` are static functions.
+        //   - `of_match_table` is either a raw pointer with static lifetime,
+        //      as guaranteed by the [`driver::IdTable`] type, or null.
+        to_result(|| unsafe { bindings::__platform_driver_register(reg, module.0) })
+    }
+
+    unsafe fn unregister(reg: *mut bindings::platform_driver) {
+        // SAFETY: By the safety requirements of this function (defined in the trait definition),
+        // `reg` was passed (and updated) by a previous successful call to
+        // `platform_driver_register`.
+        unsafe { bindings::platform_driver_unregister(reg) };
+    }
+}
+
+impl<T: Driver> Adapter<T> {
+    fn get_id_info(dev: &Device) -> Option<&'static T::IdInfo> {
+        let table = T::OF_DEVICE_ID_TABLE?;
+
+        // SAFETY: `table` has static lifetime, so it is valid for read. `dev` is guaranteed to be
+        // valid while it's alive, so is the raw device returned by it.
+        let id = unsafe { bindings::of_match_device(table.as_ref(), dev.raw_device()) };
+        if id.is_null() {
+            return None;
+        }
+
+        // SAFETY: `id` is a pointer within the static table, so it's always valid.
+        let offset = unsafe { (*id).data };
+        if offset.is_null() {
+            return None;
+        }
+
+        // SAFETY: The offset comes from a previous call to `offset_from` in `IdArray::new`, which
+        // guarantees that the resulting pointer is within the table.
+        let ptr = unsafe {
+            id.cast::<u8>()
+                .offset(offset as _)
+                .cast::<Option<T::IdInfo>>()
+        };
+
+        // SAFETY: The id table has a static lifetime, so `ptr` is guaranteed to be valid for read.
+        unsafe { (&*ptr).as_ref() }
+    }
+
+    extern "C" fn probe_callback(pdev: *mut bindings::platform_device) -> c_types::c_int {
+        from_kernel_result! {
+            // SAFETY: `pdev` is valid by the contract with the C code. `dev` is alive only for the
+            // duration of this call, so it is guaranteed to remain alive for the lifetime of
+            // `pdev`.
+            let mut dev = unsafe { Device::from_ptr(pdev) };
+            let info = Self::get_id_info(&dev);
+            let data = T::probe(&mut dev, info)?;
+            // SAFETY: `pdev` is guaranteed to be a valid, non-null pointer.
+            unsafe { bindings::platform_set_drvdata(pdev, data.into_pointer() as _) };
+            Ok(0)
+        }
+    }
+
+    extern "C" fn remove_callback(pdev: *mut bindings::platform_device) -> c_types::c_int {
+        from_kernel_result! {
+            // SAFETY: `pdev` is guaranteed to be a valid, non-null pointer.
+            let ptr = unsafe { bindings::platform_get_drvdata(pdev) };
+            // SAFETY:
+            //   - we allocated this pointer using `T::Data::into_pointer`,
+            //     so it is safe to turn back into a `T::Data`.
+            //   - the allocation happened in `probe`, no-one freed the memory,
+            //     `remove` is the canonical kernel location to free driver data. so OK
+            //     to convert the pointer back to a Rust structure here.
+            let data = unsafe { T::Data::from_pointer(ptr) };
+            let ret = T::remove(&data);
+            <T::Data as driver::DeviceRemoval>::device_remove(&data);
+            ret?;
+            Ok(0)
+        }
+    }
+}
+
+/// A platform driver.
+pub trait Driver {
+    /// Data stored on device by driver.
+    ///
+    /// Corresponds to the data set or retrieved via the kernel's
+    /// `platform_{set,get}_drvdata()` functions.
+    ///
+    /// Require that `Data` implements `PointerWrapper`. We guarantee to
+    /// never move the underlying wrapped data structure. This allows
+    type Data: PointerWrapper + Send + Sync + driver::DeviceRemoval = ();
+
+    /// The type holding information about each device id supported by the driver.
+    type IdInfo: 'static = ();
+
+    /// The table of device ids supported by the driver.
+    const OF_DEVICE_ID_TABLE: Option<driver::IdTable<'static, of::DeviceId, Self::IdInfo>> = None;
+
+    /// Platform driver probe.
+    ///
+    /// Called when a new platform device is added or discovered.
+    /// Implementers should attempt to initialize the device here.
+    fn probe(dev: &mut Device, id_info: Option<&Self::IdInfo>) -> Result<Self::Data>;
+
+    /// Platform driver remove.
+    ///
+    /// Called when a platform device is removed.
+    /// Implementers should prepare the device for complete removal here.
+    fn remove(_data: &Self::Data) -> Result {
+        Ok(())
+    }
+}
+
+/// A platform device.
+///
+/// # Invariants
+///
+/// The field `ptr` is non-null and valid for the lifetime of the object.
+pub struct Device {
+    ptr: *mut bindings::platform_device,
+}
+
+impl Device {
+    /// Creates a new device from the given pointer.
+    ///
+    /// # Safety
+    ///
+    /// `ptr` must be non-null and valid. It must remain valid for the lifetime of the returned
+    /// instance.
+    unsafe fn from_ptr(ptr: *mut bindings::platform_device) -> Self {
+        // INVARIANT: The safety requirements of the function ensure the lifetime invariant.
+        Self { ptr }
+    }
+
+    /// Returns id of the platform device.
+    pub fn id(&self) -> i32 {
+        // SAFETY: By the type invariants, we know that `self.ptr` is non-null and valid.
+        unsafe { (*self.ptr).id }
+    }
+}
+
+// SAFETY: The device returned by `raw_device` is the raw platform device.
+unsafe impl device::RawDevice for Device {
+    fn raw_device(&self) -> *mut bindings::device {
+        // SAFETY: By the type invariants, we know that `self.ptr` is non-null and valid.
+        unsafe { &mut (*self.ptr).dev }
+    }
+}
+
+/// Declares a kernel module that exposes a single platform driver.
+///
+/// # Examples
+///
+/// ```ignore
+/// # use kernel::{platform, define_of_id_table, module_platform_driver};
+/// #
+/// struct MyDriver;
+/// impl platform::Driver for MyDriver {
+///     // [...]
+/// #   fn probe(_dev: &mut platform::Device, _id_info: Option<&Self::IdInfo>) -> Result {
+/// #       Ok(())
+/// #   }
+/// #   define_of_id_table! {(), [
+/// #       (of::DeviceId::Compatible(b"brcm,bcm2835-rng"), None),
+/// #   ]}
+/// }
+///
+/// module_platform_driver! {
+///     type: MyDriver,
+///     name: b"module_name",
+///     author: b"Author name",
+///     license: b"GPL v2",
+/// }
+/// ```
+#[macro_export]
+macro_rules! module_platform_driver {
+    ($($f:tt)*) => {
+        $crate::module_driver!(<T>, $crate::platform::Adapter<T>, { $($f)* });
+    };
+}
diff --git a/rust/kernel/power.rs b/rust/kernel/power.rs
new file mode 100644
index 000000000000..e318b5d9f0c0
--- /dev/null
+++ b/rust/kernel/power.rs
@@ -0,0 +1,118 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Power management interfaces.
+//!
+//! C header: [`include/linux/pm.h`](../../../../include/linux/pm.h)
+
+#![allow(dead_code)]
+
+use crate::{bindings, c_types, error::from_kernel_result, types::PointerWrapper, Result};
+use core::marker::PhantomData;
+
+/// Corresponds to the kernel's `struct dev_pm_ops`.
+///
+/// It is meant to be implemented by drivers that support power-management operations.
+pub trait Operations {
+    /// The type of the context data stored by the driver on each device.
+    type Data: PointerWrapper + Sync + Send;
+
+    /// Called before the system goes into a sleep state.
+    fn suspend(_data: <Self::Data as PointerWrapper>::Borrowed<'_>) -> Result {
+        Ok(())
+    }
+
+    /// Called after the system comes back from a sleep state.
+    fn resume(_data: <Self::Data as PointerWrapper>::Borrowed<'_>) -> Result {
+        Ok(())
+    }
+
+    /// Called before creating a hibernation image.
+    fn freeze(_data: <Self::Data as PointerWrapper>::Borrowed<'_>) -> Result {
+        Ok(())
+    }
+
+    /// Called after the system is restored from a hibernation image.
+    fn restore(_data: <Self::Data as PointerWrapper>::Borrowed<'_>) -> Result {
+        Ok(())
+    }
+}
+
+macro_rules! pm_callback {
+    ($callback:ident, $method:ident) => {
+        unsafe extern "C" fn $callback<T: Operations>(
+            dev: *mut bindings::device,
+        ) -> c_types::c_int {
+            from_kernel_result! {
+                // SAFETY: `dev` is valid as it was passed in by the C portion.
+                let ptr = unsafe { bindings::dev_get_drvdata(dev) };
+                // SAFETY: By the safety requirements of `OpsTable::build`, we know that `ptr` came
+                // from a previous call to `T::Data::into_pointer`.
+                let data = unsafe { T::Data::borrow(ptr) };
+                T::$method(data)?;
+                Ok(0)
+            }
+        }
+    };
+}
+
+pm_callback!(suspend_callback, suspend);
+pm_callback!(resume_callback, resume);
+pm_callback!(freeze_callback, freeze);
+pm_callback!(restore_callback, restore);
+
+pub(crate) struct OpsTable<T: Operations>(PhantomData<*const T>);
+
+impl<T: Operations> OpsTable<T> {
+    const VTABLE: bindings::dev_pm_ops = bindings::dev_pm_ops {
+        prepare: None,
+        complete: None,
+        suspend: Some(suspend_callback::<T>),
+        resume: Some(resume_callback::<T>),
+        freeze: Some(freeze_callback::<T>),
+        thaw: None,
+        poweroff: None,
+        restore: Some(restore_callback::<T>),
+        suspend_late: None,
+        resume_early: None,
+        freeze_late: None,
+        thaw_early: None,
+        poweroff_late: None,
+        restore_early: None,
+        suspend_noirq: None,
+        resume_noirq: None,
+        freeze_noirq: None,
+        thaw_noirq: None,
+        poweroff_noirq: None,
+        restore_noirq: None,
+        runtime_suspend: None,
+        runtime_resume: None,
+        runtime_idle: None,
+    };
+
+    /// Builds an instance of `struct dev_pm_ops`.
+    ///
+    /// # Safety
+    ///
+    /// The caller must ensure that `dev_get_drvdata` will result in a value returned by
+    /// [`T::Data::into_pointer`].
+    pub(crate) const unsafe fn build() -> &'static bindings::dev_pm_ops {
+        &Self::VTABLE
+    }
+}
+
+/// Implements the [`Operations`] trait as no-ops.
+///
+/// This is useful when one doesn't want to provide the implementation of any power-manager related
+/// operation.
+pub struct NoOperations<T: PointerWrapper>(PhantomData<T>);
+
+impl<T: PointerWrapper + Send + Sync> Operations for NoOperations<T> {
+    type Data = T;
+}
+
+// SAFETY: `NoOperation` provides no functionality, it is safe to send a reference to it to
+// different threads.
+unsafe impl<T: PointerWrapper> Sync for NoOperations<T> {}
+
+// SAFETY: `NoOperation` provides no functionality, it is safe to send it to different threads.
+unsafe impl<T: PointerWrapper> Send for NoOperations<T> {}
diff --git a/rust/kernel/prelude.rs b/rust/kernel/prelude.rs
new file mode 100644
index 000000000000..a02b9a9d1937
--- /dev/null
+++ b/rust/kernel/prelude.rs
@@ -0,0 +1,36 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! The `kernel` prelude.
+//!
+//! These are the most common items used by Rust code in the kernel,
+//! intended to be imported by all Rust code, for convenience.
+//!
+//! # Examples
+//!
+//! ```
+//! use kernel::prelude::*;
+//! ```
+
+pub use core::pin::Pin;
+
+pub use alloc::{boxed::Box, string::String, vec::Vec};
+
+pub use macros::module;
+
+pub use super::build_assert;
+
+pub use super::{
+    dbg, dev_alert, dev_crit, dev_dbg, dev_emerg, dev_err, dev_info, dev_notice, dev_warn, fmt,
+    pr_alert, pr_crit, pr_debug, pr_emerg, pr_err, pr_info, pr_notice, pr_warn,
+};
+
+pub use super::module_misc_device;
+
+#[cfg(CONFIG_ARM_AMBA)]
+pub use super::module_amba_driver;
+
+pub use super::static_assert;
+
+pub use super::{error::code::*, Error, Result};
+
+pub use super::{str::CStr, ARef, ThisModule};
diff --git a/rust/kernel/print.rs b/rust/kernel/print.rs
new file mode 100644
index 000000000000..9846bd13eab6
--- /dev/null
+++ b/rust/kernel/print.rs
@@ -0,0 +1,405 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Printing facilities.
+//!
+//! C header: [`include/linux/printk.h`](../../../../include/linux/printk.h)
+//!
+//! Reference: <https://www.kernel.org/doc/html/latest/core-api/printk-basics.html>
+
+use core::fmt;
+
+use crate::{
+    c_types::{c_char, c_void},
+    str::RawFormatter,
+};
+
+#[cfg(CONFIG_PRINTK)]
+use crate::bindings;
+
+// Called from `vsprintf` with format specifier `%pA`.
+#[no_mangle]
+unsafe fn rust_fmt_argument(buf: *mut c_char, end: *mut c_char, ptr: *const c_void) -> *mut c_char {
+    use fmt::Write;
+    // SAFETY: The C contract guarantees that `buf` is valid if it's less than `end`.
+    let mut w = unsafe { RawFormatter::from_ptrs(buf.cast(), end.cast()) };
+    let _ = w.write_fmt(unsafe { *(ptr as *const fmt::Arguments<'_>) });
+    w.pos().cast()
+}
+
+/// Format strings.
+///
+/// Public but hidden since it should only be used from public macros.
+#[doc(hidden)]
+pub mod format_strings {
+    use crate::bindings;
+
+    /// The length we copy from the `KERN_*` kernel prefixes.
+    const LENGTH_PREFIX: usize = 2;
+
+    /// The length of the fixed format strings.
+    pub const LENGTH: usize = 10;
+
+    /// Generates a fixed format string for the kernel's [`_printk`].
+    ///
+    /// The format string is always the same for a given level, i.e. for a
+    /// given `prefix`, which are the kernel's `KERN_*` constants.
+    ///
+    /// [`_printk`]: ../../../../include/linux/printk.h
+    const fn generate(is_cont: bool, prefix: &[u8; 3]) -> [u8; LENGTH] {
+        // Ensure the `KERN_*` macros are what we expect.
+        assert!(prefix[0] == b'\x01');
+        if is_cont {
+            assert!(prefix[1] == b'c');
+        } else {
+            assert!(prefix[1] >= b'0' && prefix[1] <= b'7');
+        }
+        assert!(prefix[2] == b'\x00');
+
+        let suffix: &[u8; LENGTH - LENGTH_PREFIX] = if is_cont {
+            b"%pA\0\0\0\0\0"
+        } else {
+            b"%s: %pA\0"
+        };
+
+        [
+            prefix[0], prefix[1], suffix[0], suffix[1], suffix[2], suffix[3], suffix[4], suffix[5],
+            suffix[6], suffix[7],
+        ]
+    }
+
+    // Generate the format strings at compile-time.
+    //
+    // This avoids the compiler generating the contents on the fly in the stack.
+    //
+    // Furthermore, `static` instead of `const` is used to share the strings
+    // for all the kernel.
+    pub static EMERG: [u8; LENGTH] = generate(false, bindings::KERN_EMERG);
+    pub static ALERT: [u8; LENGTH] = generate(false, bindings::KERN_ALERT);
+    pub static CRIT: [u8; LENGTH] = generate(false, bindings::KERN_CRIT);
+    pub static ERR: [u8; LENGTH] = generate(false, bindings::KERN_ERR);
+    pub static WARNING: [u8; LENGTH] = generate(false, bindings::KERN_WARNING);
+    pub static NOTICE: [u8; LENGTH] = generate(false, bindings::KERN_NOTICE);
+    pub static INFO: [u8; LENGTH] = generate(false, bindings::KERN_INFO);
+    pub static DEBUG: [u8; LENGTH] = generate(false, bindings::KERN_DEBUG);
+    pub static CONT: [u8; LENGTH] = generate(true, bindings::KERN_CONT);
+}
+
+/// Prints a message via the kernel's [`_printk`].
+///
+/// Public but hidden since it should only be used from public macros.
+///
+/// # Safety
+///
+/// The format string must be one of the ones in [`format_strings`], and
+/// the module name must be null-terminated.
+///
+/// [`_printk`]: ../../../../include/linux/_printk.h
+#[doc(hidden)]
+#[cfg_attr(not(CONFIG_PRINTK), allow(unused_variables))]
+pub unsafe fn call_printk(
+    format_string: &[u8; format_strings::LENGTH],
+    module_name: &[u8],
+    args: fmt::Arguments<'_>,
+) {
+    // `_printk` does not seem to fail in any path.
+    #[cfg(CONFIG_PRINTK)]
+    unsafe {
+        bindings::_printk(
+            format_string.as_ptr() as _,
+            module_name.as_ptr(),
+            &args as *const _ as *const c_void,
+        );
+    }
+}
+
+/// Prints a message via the kernel's [`_printk`] for the `CONT` level.
+///
+/// Public but hidden since it should only be used from public macros.
+///
+/// [`_printk`]: ../../../../include/linux/printk.h
+#[doc(hidden)]
+#[cfg_attr(not(CONFIG_PRINTK), allow(unused_variables))]
+pub fn call_printk_cont(args: fmt::Arguments<'_>) {
+    // `_printk` does not seem to fail in any path.
+    //
+    // SAFETY: The format string is fixed.
+    #[cfg(CONFIG_PRINTK)]
+    unsafe {
+        bindings::_printk(
+            format_strings::CONT.as_ptr() as _,
+            &args as *const _ as *const c_void,
+        );
+    }
+}
+
+/// Performs formatting and forwards the string to [`call_printk`].
+///
+/// Public but hidden since it should only be used from public macros.
+#[doc(hidden)]
+#[cfg(not(testlib))]
+#[macro_export]
+macro_rules! print_macro (
+    // The non-continuation cases (most of them, e.g. `INFO`).
+    ($format_string:path, false, $($arg:tt)+) => (
+        // SAFETY: This hidden macro should only be called by the documented
+        // printing macros which ensure the format string is one of the fixed
+        // ones. All `__LOG_PREFIX`s are null-terminated as they are generated
+        // by the `module!` proc macro or fixed values defined in a kernel
+        // crate.
+        unsafe {
+            $crate::print::call_printk(
+                &$format_string,
+                crate::__LOG_PREFIX,
+                format_args!($($arg)+),
+            );
+        }
+    );
+
+    // The `CONT` case.
+    ($format_string:path, true, $($arg:tt)+) => (
+        $crate::print::call_printk_cont(
+            format_args!($($arg)+),
+        );
+    );
+);
+
+/// Stub for doctests
+#[cfg(testlib)]
+#[macro_export]
+macro_rules! print_macro (
+    ($format_string:path, $e:expr, $($arg:tt)+) => (
+        ()
+    );
+);
+
+// We could use a macro to generate these macros. However, doing so ends
+// up being a bit ugly: it requires the dollar token trick to escape `$` as
+// well as playing with the `doc` attribute. Furthermore, they cannot be easily
+// imported in the prelude due to [1]. So, for the moment, we just write them
+// manually, like in the C side; while keeping most of the logic in another
+// macro, i.e. [`print_macro`].
+//
+// [1]: https://github.com/rust-lang/rust/issues/52234
+
+/// Prints an emergency-level message (level 0).
+///
+/// Use this level if the system is unusable.
+///
+/// Equivalent to the kernel's [`pr_emerg`] macro.
+///
+/// Mimics the interface of [`std::print!`]. See [`core::fmt`] and
+/// [`alloc::format!`] for information about the formatting syntax.
+///
+/// [`pr_emerg`]: https://www.kernel.org/doc/html/latest/core-api/printk-basics.html#c.pr_emerg
+/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html
+///
+/// # Examples
+///
+/// ```
+/// pr_emerg!("hello {}\n", "there");
+/// ```
+#[macro_export]
+macro_rules! pr_emerg (
+    ($($arg:tt)*) => (
+        $crate::print_macro!($crate::print::format_strings::EMERG, false, $($arg)*)
+    )
+);
+
+/// Prints an alert-level message (level 1).
+///
+/// Use this level if action must be taken immediately.
+///
+/// Equivalent to the kernel's [`pr_alert`] macro.
+///
+/// Mimics the interface of [`std::print!`]. See [`core::fmt`] and
+/// [`alloc::format!`] for information about the formatting syntax.
+///
+/// [`pr_alert`]: https://www.kernel.org/doc/html/latest/core-api/printk-basics.html#c.pr_alert
+/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html
+///
+/// # Examples
+///
+/// ```
+/// pr_alert!("hello {}\n", "there");
+/// ```
+#[macro_export]
+macro_rules! pr_alert (
+    ($($arg:tt)*) => (
+        $crate::print_macro!($crate::print::format_strings::ALERT, false, $($arg)*)
+    )
+);
+
+/// Prints a critical-level message (level 2).
+///
+/// Use this level for critical conditions.
+///
+/// Equivalent to the kernel's [`pr_crit`] macro.
+///
+/// Mimics the interface of [`std::print!`]. See [`core::fmt`] and
+/// [`alloc::format!`] for information about the formatting syntax.
+///
+/// [`pr_crit`]: https://www.kernel.org/doc/html/latest/core-api/printk-basics.html#c.pr_crit
+/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html
+///
+/// # Examples
+///
+/// ```
+/// pr_crit!("hello {}\n", "there");
+/// ```
+#[macro_export]
+macro_rules! pr_crit (
+    ($($arg:tt)*) => (
+        $crate::print_macro!($crate::print::format_strings::CRIT, false, $($arg)*)
+    )
+);
+
+/// Prints an error-level message (level 3).
+///
+/// Use this level for error conditions.
+///
+/// Equivalent to the kernel's [`pr_err`] macro.
+///
+/// Mimics the interface of [`std::print!`]. See [`core::fmt`] and
+/// [`alloc::format!`] for information about the formatting syntax.
+///
+/// [`pr_err`]: https://www.kernel.org/doc/html/latest/core-api/printk-basics.html#c.pr_err
+/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html
+///
+/// # Examples
+///
+/// ```
+/// pr_err!("hello {}\n", "there");
+/// ```
+#[macro_export]
+macro_rules! pr_err (
+    ($($arg:tt)*) => (
+        $crate::print_macro!($crate::print::format_strings::ERR, false, $($arg)*)
+    )
+);
+
+/// Prints a warning-level message (level 4).
+///
+/// Use this level for warning conditions.
+///
+/// Equivalent to the kernel's [`pr_warn`] macro.
+///
+/// Mimics the interface of [`std::print!`]. See [`core::fmt`] and
+/// [`alloc::format!`] for information about the formatting syntax.
+///
+/// [`pr_warn`]: https://www.kernel.org/doc/html/latest/core-api/printk-basics.html#c.pr_warn
+/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html
+///
+/// # Examples
+///
+/// ```
+/// pr_warn!("hello {}\n", "there");
+/// ```
+#[macro_export]
+macro_rules! pr_warn (
+    ($($arg:tt)*) => (
+        $crate::print_macro!($crate::print::format_strings::WARNING, false, $($arg)*)
+    )
+);
+
+/// Prints a notice-level message (level 5).
+///
+/// Use this level for normal but significant conditions.
+///
+/// Equivalent to the kernel's [`pr_notice`] macro.
+///
+/// Mimics the interface of [`std::print!`]. See [`core::fmt`] and
+/// [`alloc::format!`] for information about the formatting syntax.
+///
+/// [`pr_notice`]: https://www.kernel.org/doc/html/latest/core-api/printk-basics.html#c.pr_notice
+/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html
+///
+/// # Examples
+///
+/// ```
+/// pr_notice!("hello {}\n", "there");
+/// ```
+#[macro_export]
+macro_rules! pr_notice (
+    ($($arg:tt)*) => (
+        $crate::print_macro!($crate::print::format_strings::NOTICE, false, $($arg)*)
+    )
+);
+
+/// Prints an info-level message (level 6).
+///
+/// Use this level for informational messages.
+///
+/// Equivalent to the kernel's [`pr_info`] macro.
+///
+/// Mimics the interface of [`std::print!`]. See [`core::fmt`] and
+/// [`alloc::format!`] for information about the formatting syntax.
+///
+/// [`pr_info`]: https://www.kernel.org/doc/html/latest/core-api/printk-basics.html#c.pr_info
+/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html
+///
+/// # Examples
+///
+/// ```
+/// pr_info!("hello {}\n", "there");
+/// ```
+#[macro_export]
+#[doc(alias = "print")]
+macro_rules! pr_info (
+    ($($arg:tt)*) => (
+        $crate::print_macro!($crate::print::format_strings::INFO, false, $($arg)*)
+    )
+);
+
+/// Prints a debug-level message (level 7).
+///
+/// Use this level for debug messages.
+///
+/// Equivalent to the kernel's [`pr_debug`] macro, except that it doesn't support dynamic debug
+/// yet.
+///
+/// Mimics the interface of [`std::print!`]. See [`core::fmt`] and
+/// [`alloc::format!`] for information about the formatting syntax.
+///
+/// [`pr_debug`]: https://www.kernel.org/doc/html/latest/core-api/printk-basics.html#c.pr_debug
+/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html
+///
+/// # Examples
+///
+/// ```
+/// pr_debug!("hello {}\n", "there");
+/// ```
+#[macro_export]
+#[doc(alias = "print")]
+macro_rules! pr_debug (
+    ($($arg:tt)*) => (
+        if cfg!(debug_assertions) {
+            $crate::print_macro!($crate::print::format_strings::DEBUG, false, $($arg)*)
+        }
+    )
+);
+
+/// Continues a previous log message in the same line.
+///
+/// Use only when continuing a previous `pr_*!` macro (e.g. [`pr_info!`]).
+///
+/// Equivalent to the kernel's [`pr_cont`] macro.
+///
+/// Mimics the interface of [`std::print!`]. See [`core::fmt`] and
+/// [`alloc::format!`] for information about the formatting syntax.
+///
+/// [`pr_cont`]: https://www.kernel.org/doc/html/latest/core-api/printk-basics.html#c.pr_cont
+/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::pr_cont;
+/// pr_info!("hello");
+/// pr_cont!(" {}\n", "there");
+/// ```
+#[macro_export]
+macro_rules! pr_cont (
+    ($($arg:tt)*) => (
+        $crate::print_macro!($crate::print::format_strings::CONT, true, $($arg)*)
+    )
+);
diff --git a/rust/kernel/random.rs b/rust/kernel/random.rs
new file mode 100644
index 000000000000..a0926cb68a75
--- /dev/null
+++ b/rust/kernel/random.rs
@@ -0,0 +1,42 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Random numbers.
+//!
+//! C header: [`include/linux/random.h`](../../../../include/linux/random.h)
+
+use crate::{bindings, c_types, error::code::*, Error, Result};
+
+/// Fills a byte slice with random bytes generated from the kernel's CSPRNG.
+///
+/// Ensures that the CSPRNG has been seeded before generating any random bytes,
+/// and will block until it is ready.
+pub fn getrandom(dest: &mut [u8]) -> Result {
+    let res = unsafe { bindings::wait_for_random_bytes() };
+    if res != 0 {
+        return Err(Error::from_kernel_errno(res));
+    }
+
+    unsafe {
+        bindings::get_random_bytes(dest.as_mut_ptr() as *mut c_types::c_void, dest.len());
+    }
+    Ok(())
+}
+
+/// Fills a byte slice with random bytes generated from the kernel's CSPRNG.
+///
+/// If the CSPRNG is not yet seeded, returns an `Err(EAGAIN)` immediately.
+pub fn getrandom_nonblock(dest: &mut [u8]) -> Result {
+    if !unsafe { bindings::rng_is_initialized() } {
+        return Err(EAGAIN);
+    }
+    getrandom(dest)
+}
+
+/// Contributes the contents of a byte slice to the kernel's entropy pool.
+///
+/// Does *not* credit the kernel entropy counter though.
+pub fn add_randomness(data: &[u8]) {
+    unsafe {
+        bindings::add_device_randomness(data.as_ptr() as *const c_types::c_void, data.len());
+    }
+}
diff --git a/rust/kernel/raw_list.rs b/rust/kernel/raw_list.rs
new file mode 100644
index 000000000000..267b21709c29
--- /dev/null
+++ b/rust/kernel/raw_list.rs
@@ -0,0 +1,361 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Raw lists.
+//!
+//! TODO: This module is a work in progress.
+
+use core::{
+    cell::UnsafeCell,
+    ptr,
+    ptr::NonNull,
+    sync::atomic::{AtomicBool, Ordering},
+};
+
+/// A descriptor of list elements.
+///
+/// It describes the type of list elements and provides a function to determine how to get the
+/// links to be used on a list.
+///
+/// A type that may be in multiple lists simultaneously needs to implement one of these for each
+/// simultaneous list.
+pub trait GetLinks {
+    /// The type of the entries in the list.
+    type EntryType: ?Sized;
+
+    /// Returns the links to be used when linking an entry within a list.
+    fn get_links(data: &Self::EntryType) -> &Links<Self::EntryType>;
+}
+
+/// The links used to link an object on a linked list.
+///
+/// Instances of this type are usually embedded in structures and returned in calls to
+/// [`GetLinks::get_links`].
+pub struct Links<T: ?Sized> {
+    inserted: AtomicBool,
+    entry: UnsafeCell<ListEntry<T>>,
+}
+
+impl<T: ?Sized> Links<T> {
+    /// Constructs a new [`Links`] instance that isn't inserted on any lists yet.
+    pub fn new() -> Self {
+        Self {
+            inserted: AtomicBool::new(false),
+            entry: UnsafeCell::new(ListEntry::new()),
+        }
+    }
+
+    fn acquire_for_insertion(&self) -> bool {
+        self.inserted
+            .compare_exchange(false, true, Ordering::Acquire, Ordering::Relaxed)
+            .is_ok()
+    }
+
+    fn release_after_removal(&self) {
+        self.inserted.store(false, Ordering::Release);
+    }
+}
+
+impl<T: ?Sized> Default for Links<T> {
+    fn default() -> Self {
+        Self::new()
+    }
+}
+
+struct ListEntry<T: ?Sized> {
+    next: Option<NonNull<T>>,
+    prev: Option<NonNull<T>>,
+}
+
+impl<T: ?Sized> ListEntry<T> {
+    fn new() -> Self {
+        Self {
+            next: None,
+            prev: None,
+        }
+    }
+}
+
+/// A linked list.
+///
+/// # Invariants
+///
+/// The links of objects added to a list are owned by the list.
+pub(crate) struct RawList<G: GetLinks> {
+    head: Option<NonNull<G::EntryType>>,
+}
+
+impl<G: GetLinks> RawList<G> {
+    pub(crate) fn new() -> Self {
+        Self { head: None }
+    }
+
+    pub(crate) fn is_empty(&self) -> bool {
+        self.head.is_none()
+    }
+
+    fn insert_after_priv(
+        &mut self,
+        existing: &G::EntryType,
+        new_entry: &mut ListEntry<G::EntryType>,
+        new_ptr: Option<NonNull<G::EntryType>>,
+    ) {
+        {
+            // SAFETY: It's safe to get the previous entry of `existing` because the list cannot
+            // change.
+            let existing_links = unsafe { &mut *G::get_links(existing).entry.get() };
+            new_entry.next = existing_links.next;
+            existing_links.next = new_ptr;
+        }
+
+        new_entry.prev = Some(NonNull::from(existing));
+
+        // SAFETY: It's safe to get the next entry of `existing` because the list cannot change.
+        let next_links =
+            unsafe { &mut *G::get_links(new_entry.next.unwrap().as_ref()).entry.get() };
+        next_links.prev = new_ptr;
+    }
+
+    /// Inserts the given object after `existing`.
+    ///
+    /// # Safety
+    ///
+    /// Callers must ensure that `existing` points to a valid entry that is on the list.
+    pub(crate) unsafe fn insert_after(
+        &mut self,
+        existing: &G::EntryType,
+        new: &G::EntryType,
+    ) -> bool {
+        let links = G::get_links(new);
+        if !links.acquire_for_insertion() {
+            // Nothing to do if already inserted.
+            return false;
+        }
+
+        // SAFETY: The links are now owned by the list, so it is safe to get a mutable reference.
+        let new_entry = unsafe { &mut *links.entry.get() };
+        self.insert_after_priv(existing, new_entry, Some(NonNull::from(new)));
+        true
+    }
+
+    fn push_back_internal(&mut self, new: &G::EntryType) -> bool {
+        let links = G::get_links(new);
+        if !links.acquire_for_insertion() {
+            // Nothing to do if already inserted.
+            return false;
+        }
+
+        // SAFETY: The links are now owned by the list, so it is safe to get a mutable reference.
+        let new_entry = unsafe { &mut *links.entry.get() };
+        let new_ptr = Some(NonNull::from(new));
+        match self.back() {
+            // SAFETY: `back` is valid as the list cannot change.
+            Some(back) => self.insert_after_priv(unsafe { back.as_ref() }, new_entry, new_ptr),
+            None => {
+                self.head = new_ptr;
+                new_entry.next = new_ptr;
+                new_entry.prev = new_ptr;
+            }
+        }
+        true
+    }
+
+    pub(crate) unsafe fn push_back(&mut self, new: &G::EntryType) -> bool {
+        self.push_back_internal(new)
+    }
+
+    fn remove_internal(&mut self, data: &G::EntryType) -> bool {
+        let links = G::get_links(data);
+
+        // SAFETY: The links are now owned by the list, so it is safe to get a mutable reference.
+        let entry = unsafe { &mut *links.entry.get() };
+        let next = if let Some(next) = entry.next {
+            next
+        } else {
+            // Nothing to do if the entry is not on the list.
+            return false;
+        };
+
+        if ptr::eq(data, next.as_ptr()) {
+            // We're removing the only element.
+            self.head = None
+        } else {
+            // Update the head if we're removing it.
+            if let Some(raw_head) = self.head {
+                if ptr::eq(data, raw_head.as_ptr()) {
+                    self.head = Some(next);
+                }
+            }
+
+            // SAFETY: It's safe to get the previous entry because the list cannot change.
+            unsafe { &mut *G::get_links(entry.prev.unwrap().as_ref()).entry.get() }.next =
+                entry.next;
+
+            // SAFETY: It's safe to get the next entry because the list cannot change.
+            unsafe { &mut *G::get_links(next.as_ref()).entry.get() }.prev = entry.prev;
+        }
+
+        // Reset the links of the element we're removing so that we know it's not on any list.
+        entry.next = None;
+        entry.prev = None;
+        links.release_after_removal();
+        true
+    }
+
+    /// Removes the given entry.
+    ///
+    /// # Safety
+    ///
+    /// Callers must ensure that `data` is either on this list or in no list. It being on another
+    /// list leads to memory unsafety.
+    pub(crate) unsafe fn remove(&mut self, data: &G::EntryType) -> bool {
+        self.remove_internal(data)
+    }
+
+    fn pop_front_internal(&mut self) -> Option<NonNull<G::EntryType>> {
+        let head = self.head?;
+        // SAFETY: The head is on the list as we just got it from there and it cannot change.
+        unsafe { self.remove(head.as_ref()) };
+        Some(head)
+    }
+
+    pub(crate) fn pop_front(&mut self) -> Option<NonNull<G::EntryType>> {
+        self.pop_front_internal()
+    }
+
+    pub(crate) fn front(&self) -> Option<NonNull<G::EntryType>> {
+        self.head
+    }
+
+    pub(crate) fn back(&self) -> Option<NonNull<G::EntryType>> {
+        // SAFETY: The links of head are owned by the list, so it is safe to get a reference.
+        unsafe { &*G::get_links(self.head?.as_ref()).entry.get() }.prev
+    }
+
+    pub(crate) fn cursor_front(&self) -> Cursor<'_, G> {
+        Cursor::new(self, self.front())
+    }
+
+    pub(crate) fn cursor_front_mut(&mut self) -> CursorMut<'_, G> {
+        CursorMut::new(self, self.front())
+    }
+}
+
+struct CommonCursor<G: GetLinks> {
+    cur: Option<NonNull<G::EntryType>>,
+}
+
+impl<G: GetLinks> CommonCursor<G> {
+    fn new(cur: Option<NonNull<G::EntryType>>) -> Self {
+        Self { cur }
+    }
+
+    fn move_next(&mut self, list: &RawList<G>) {
+        match self.cur.take() {
+            None => self.cur = list.head,
+            Some(cur) => {
+                if let Some(head) = list.head {
+                    // SAFETY: We have a shared ref to the linked list, so the links can't change.
+                    let links = unsafe { &*G::get_links(cur.as_ref()).entry.get() };
+                    if links.next.unwrap() != head {
+                        self.cur = links.next;
+                    }
+                }
+            }
+        }
+    }
+
+    fn move_prev(&mut self, list: &RawList<G>) {
+        match list.head {
+            None => self.cur = None,
+            Some(head) => {
+                let next = match self.cur.take() {
+                    None => head,
+                    Some(cur) => {
+                        if cur == head {
+                            return;
+                        }
+                        cur
+                    }
+                };
+                // SAFETY: There's a shared ref to the list, so the links can't change.
+                let links = unsafe { &*G::get_links(next.as_ref()).entry.get() };
+                self.cur = links.prev;
+            }
+        }
+    }
+}
+
+/// A list cursor that allows traversing a linked list and inspecting elements.
+pub struct Cursor<'a, G: GetLinks> {
+    cursor: CommonCursor<G>,
+    list: &'a RawList<G>,
+}
+
+impl<'a, G: GetLinks> Cursor<'a, G> {
+    fn new(list: &'a RawList<G>, cur: Option<NonNull<G::EntryType>>) -> Self {
+        Self {
+            list,
+            cursor: CommonCursor::new(cur),
+        }
+    }
+
+    /// Returns the element the cursor is currently positioned on.
+    pub fn current(&self) -> Option<&'a G::EntryType> {
+        let cur = self.cursor.cur?;
+        // SAFETY: Objects must be kept alive while on the list.
+        Some(unsafe { &*cur.as_ptr() })
+    }
+
+    /// Moves the cursor to the next element.
+    pub fn move_next(&mut self) {
+        self.cursor.move_next(self.list);
+    }
+}
+
+pub(crate) struct CursorMut<'a, G: GetLinks> {
+    cursor: CommonCursor<G>,
+    list: &'a mut RawList<G>,
+}
+
+impl<'a, G: GetLinks> CursorMut<'a, G> {
+    fn new(list: &'a mut RawList<G>, cur: Option<NonNull<G::EntryType>>) -> Self {
+        Self {
+            list,
+            cursor: CommonCursor::new(cur),
+        }
+    }
+
+    pub(crate) fn current(&mut self) -> Option<&mut G::EntryType> {
+        let cur = self.cursor.cur?;
+        // SAFETY: Objects must be kept alive while on the list.
+        Some(unsafe { &mut *cur.as_ptr() })
+    }
+
+    /// Removes the entry the cursor is pointing to and advances the cursor to the next entry. It
+    /// returns a raw pointer to the removed element (if one is removed).
+    pub(crate) fn remove_current(&mut self) -> Option<NonNull<G::EntryType>> {
+        let entry = self.cursor.cur?;
+        self.cursor.move_next(self.list);
+        // SAFETY: The entry is on the list as we just got it from there and it cannot change.
+        unsafe { self.list.remove(entry.as_ref()) };
+        Some(entry)
+    }
+
+    pub(crate) fn peek_next(&mut self) -> Option<&mut G::EntryType> {
+        let mut new = CommonCursor::new(self.cursor.cur);
+        new.move_next(self.list);
+        // SAFETY: Objects must be kept alive while on the list.
+        Some(unsafe { &mut *new.cur?.as_ptr() })
+    }
+
+    pub(crate) fn peek_prev(&mut self) -> Option<&mut G::EntryType> {
+        let mut new = CommonCursor::new(self.cursor.cur);
+        new.move_prev(self.list);
+        // SAFETY: Objects must be kept alive while on the list.
+        Some(unsafe { &mut *new.cur?.as_ptr() })
+    }
+
+    pub(crate) fn move_next(&mut self) {
+        self.cursor.move_next(self.list);
+    }
+}
diff --git a/rust/kernel/rbtree.rs b/rust/kernel/rbtree.rs
new file mode 100644
index 000000000000..a30739cc6839
--- /dev/null
+++ b/rust/kernel/rbtree.rs
@@ -0,0 +1,563 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Red-black trees.
+//!
+//! C header: [`include/linux/rbtree.h`](../../../../include/linux/rbtree.h)
+//!
+//! Reference: <https://www.kernel.org/doc/html/latest/core-api/rbtree.html>
+
+use crate::{bindings, Result};
+use alloc::boxed::Box;
+use core::{
+    cmp::{Ord, Ordering},
+    iter::{IntoIterator, Iterator},
+    marker::PhantomData,
+    mem::MaybeUninit,
+    ptr::{addr_of_mut, NonNull},
+};
+
+struct Node<K, V> {
+    links: bindings::rb_node,
+    key: K,
+    value: V,
+}
+
+/// A red-black tree with owned nodes.
+///
+/// It is backed by the kernel C red-black trees.
+///
+/// # Invariants
+///
+/// Non-null parent/children pointers stored in instances of the `rb_node` C struct are always
+/// valid, and pointing to a field of our internal representation of a node.
+///
+/// # Examples
+///
+/// In the example below we do several operations on a tree. We note that insertions may fail if
+/// the system is out of memory.
+///
+/// ```
+/// use kernel::rbtree::RBTree;
+///
+/// # fn test() -> Result {
+/// // Create a new tree.
+/// let mut tree = RBTree::new();
+///
+/// // Insert three elements.
+/// tree.try_insert(20, 200)?;
+/// tree.try_insert(10, 100)?;
+/// tree.try_insert(30, 300)?;
+///
+/// // Check the nodes we just inserted.
+/// {
+///     let mut iter = tree.iter();
+///     assert_eq!(iter.next().unwrap(), (&10, &100));
+///     assert_eq!(iter.next().unwrap(), (&20, &200));
+///     assert_eq!(iter.next().unwrap(), (&30, &300));
+///     assert!(iter.next().is_none());
+/// }
+///
+/// // Print all elements.
+/// for (key, value) in &tree {
+///     pr_info!("{} = {}\n", key, value);
+/// }
+///
+/// // Replace one of the elements.
+/// tree.try_insert(10, 1000)?;
+///
+/// // Check that the tree reflects the replacement.
+/// {
+///     let mut iter = tree.iter();
+///     assert_eq!(iter.next().unwrap(), (&10, &1000));
+///     assert_eq!(iter.next().unwrap(), (&20, &200));
+///     assert_eq!(iter.next().unwrap(), (&30, &300));
+///     assert!(iter.next().is_none());
+/// }
+///
+/// // Change the value of one of the elements.
+/// *tree.get_mut(&30).unwrap() = 3000;
+///
+/// // Check that the tree reflects the update.
+/// {
+///     let mut iter = tree.iter();
+///     assert_eq!(iter.next().unwrap(), (&10, &1000));
+///     assert_eq!(iter.next().unwrap(), (&20, &200));
+///     assert_eq!(iter.next().unwrap(), (&30, &3000));
+///     assert!(iter.next().is_none());
+/// }
+///
+/// // Remove an element.
+/// tree.remove(&10);
+///
+/// // Check that the tree reflects the removal.
+/// {
+///     let mut iter = tree.iter();
+///     assert_eq!(iter.next().unwrap(), (&20, &200));
+///     assert_eq!(iter.next().unwrap(), (&30, &3000));
+///     assert!(iter.next().is_none());
+/// }
+///
+/// // Update all values.
+/// for value in tree.values_mut() {
+///     *value *= 10;
+/// }
+///
+/// // Check that the tree reflects the changes to values.
+/// {
+///     let mut iter = tree.iter();
+///     assert_eq!(iter.next().unwrap(), (&20, &2000));
+///     assert_eq!(iter.next().unwrap(), (&30, &30000));
+///     assert!(iter.next().is_none());
+/// }
+///
+/// # Ok(())
+/// # }
+/// #
+/// # assert_eq!(test(), Ok(()));
+/// ```
+///
+/// In the example below, we first allocate a node, acquire a spinlock, then insert the node into
+/// the tree. This is useful when the insertion context does not allow sleeping, for example, when
+/// holding a spinlock.
+///
+/// ```
+/// use kernel::{rbtree::RBTree, sync::SpinLock};
+///
+/// fn insert_test(tree: &SpinLock<RBTree<u32, u32>>) -> Result {
+///     // Pre-allocate node. This may fail (as it allocates memory).
+///     let node = RBTree::try_allocate_node(10, 100)?;
+///
+///     // Insert node while holding the lock. It is guaranteed to succeed with no allocation
+///     // attempts.
+///     let mut guard = tree.lock();
+///     guard.insert(node);
+///     Ok(())
+/// }
+/// ```
+///
+/// In the example below, we reuse an existing node allocation from an element we removed.
+///
+/// ```
+/// use kernel::rbtree::RBTree;
+///
+/// # fn test() -> Result {
+/// // Create a new tree.
+/// let mut tree = RBTree::new();
+///
+/// // Insert three elements.
+/// tree.try_insert(20, 200)?;
+/// tree.try_insert(10, 100)?;
+/// tree.try_insert(30, 300)?;
+///
+/// // Check the nodes we just inserted.
+/// {
+///     let mut iter = tree.iter();
+///     assert_eq!(iter.next().unwrap(), (&10, &100));
+///     assert_eq!(iter.next().unwrap(), (&20, &200));
+///     assert_eq!(iter.next().unwrap(), (&30, &300));
+///     assert!(iter.next().is_none());
+/// }
+///
+/// // Remove a node, getting back ownership of it.
+/// let existing = tree.remove_node(&30).unwrap();
+///
+/// // Check that the tree reflects the removal.
+/// {
+///     let mut iter = tree.iter();
+///     assert_eq!(iter.next().unwrap(), (&10, &100));
+///     assert_eq!(iter.next().unwrap(), (&20, &200));
+///     assert!(iter.next().is_none());
+/// }
+///
+/// // Turn the node into a reservation so that we can reuse it with a different key/value.
+/// let reservation = existing.into_reservation();
+///
+/// // Insert a new node into the tree, reusing the previous allocation. This is guaranteed to
+/// // succeed (no memory allocations).
+/// tree.insert(reservation.into_node(15, 150));
+///
+/// // Check that the tree reflect the new insertion.
+/// {
+///     let mut iter = tree.iter();
+///     assert_eq!(iter.next().unwrap(), (&10, &100));
+///     assert_eq!(iter.next().unwrap(), (&15, &150));
+///     assert_eq!(iter.next().unwrap(), (&20, &200));
+///     assert!(iter.next().is_none());
+/// }
+///
+/// # Ok(())
+/// # }
+/// #
+/// # assert_eq!(test(), Ok(()));
+/// ```
+pub struct RBTree<K, V> {
+    root: bindings::rb_root,
+    _p: PhantomData<Node<K, V>>,
+}
+
+impl<K, V> RBTree<K, V> {
+    /// Creates a new and empty tree.
+    pub fn new() -> Self {
+        Self {
+            // INVARIANT: There are no nodes in the tree, so the invariant holds vacuously.
+            root: bindings::rb_root::default(),
+            _p: PhantomData,
+        }
+    }
+
+    /// Tries to insert a new value into the tree.
+    ///
+    /// It overwrites a node if one already exists with the same key and returns it (containing the
+    /// key/value pair). Returns [`None`] if a node with the same key didn't already exist.
+    ///
+    /// Returns an error if it cannot allocate memory for the new node.
+    pub fn try_insert(&mut self, key: K, value: V) -> Result<Option<RBTreeNode<K, V>>>
+    where
+        K: Ord,
+    {
+        Ok(self.insert(Self::try_allocate_node(key, value)?))
+    }
+
+    /// Allocates memory for a node to be eventually initialised and inserted into the tree via a
+    /// call to [`RBTree::insert`].
+    pub fn try_reserve_node() -> Result<RBTreeNodeReservation<K, V>> {
+        Ok(RBTreeNodeReservation {
+            node: Box::try_new(MaybeUninit::uninit())?,
+        })
+    }
+
+    /// Allocates and initialiases a node that can be inserted into the tree via
+    /// [`RBTree::insert`].
+    pub fn try_allocate_node(key: K, value: V) -> Result<RBTreeNode<K, V>> {
+        Ok(Self::try_reserve_node()?.into_node(key, value))
+    }
+
+    /// Inserts a new node into the tree.
+    ///
+    /// It overwrites a node if one already exists with the same key and returns it (containing the
+    /// key/value pair). Returns [`None`] if a node with the same key didn't already exist.
+    ///
+    /// This function always succeeds.
+    pub fn insert(&mut self, node: RBTreeNode<K, V>) -> Option<RBTreeNode<K, V>>
+    where
+        K: Ord,
+    {
+        let RBTreeNode { node } = node;
+        let node = Box::into_raw(node);
+        // SAFETY: `node` is valid at least until we call `Box::from_raw`, which only happens when
+        // the node is removed or replaced.
+        let node_links = unsafe { addr_of_mut!((*node).links) };
+        let mut new_link: &mut *mut bindings::rb_node = &mut self.root.rb_node;
+        let mut parent = core::ptr::null_mut();
+        while !new_link.is_null() {
+            let this = crate::container_of!(*new_link, Node<K, V>, links);
+
+            parent = *new_link;
+
+            // SAFETY: `this` is a non-null node so it is valid by the type invariants. `node` is
+            // valid until the node is removed.
+            match unsafe { (*node).key.cmp(&(*this).key) } {
+                // SAFETY: `parent` is a non-null node so it is valid by the type invariants.
+                Ordering::Less => new_link = unsafe { &mut (*parent).rb_left },
+                // SAFETY: `parent` is a non-null node so it is valid by the type invariants.
+                Ordering::Greater => new_link = unsafe { &mut (*parent).rb_right },
+                Ordering::Equal => {
+                    // INVARIANT: We are replacing an existing node with a new one, which is valid.
+                    // It remains valid because we "forgot" it with `Box::into_raw`.
+                    // SAFETY: All pointers are non-null and valid (parent, despite the name, really
+                    // is the node we're replacing).
+                    unsafe { bindings::rb_replace_node(parent, node_links, &mut self.root) };
+
+                    // INVARIANT: The node is being returned and the caller may free it, however,
+                    // it was removed from the tree. So the invariants still hold.
+                    return Some(RBTreeNode {
+                        // SAFETY: `this` was a node in the tree, so it is valid.
+                        node: unsafe { Box::from_raw(this as _) },
+                    });
+                }
+            }
+        }
+
+        // INVARIANT: We are linking in a new node, which is valid. It remains valid because we
+        // "forgot" it with `Box::into_raw`.
+        // SAFETY: All pointers are non-null and valid (`*new_link` is null, but `new_link` is a
+        // mutable reference).
+        unsafe { bindings::rb_link_node(node_links, parent, new_link) };
+
+        // SAFETY: All pointers are valid. `node` has just been inserted into the tree.
+        unsafe { bindings::rb_insert_color(node_links, &mut self.root) };
+        None
+    }
+
+    /// Returns a node with the given key, if one exists.
+    fn find(&self, key: &K) -> Option<NonNull<Node<K, V>>>
+    where
+        K: Ord,
+    {
+        let mut node = self.root.rb_node;
+        while !node.is_null() {
+            let this = crate::container_of!(node, Node<K, V>, links);
+            // SAFETY: `this` is a non-null node so it is valid by the type invariants.
+            node = match key.cmp(unsafe { &(*this).key }) {
+                // SAFETY: `node` is a non-null node so it is valid by the type invariants.
+                Ordering::Less => unsafe { (*node).rb_left },
+                // SAFETY: `node` is a non-null node so it is valid by the type invariants.
+                Ordering::Greater => unsafe { (*node).rb_right },
+                Ordering::Equal => return NonNull::new(this as _),
+            }
+        }
+        None
+    }
+
+    /// Returns a reference to the value corresponding to the key.
+    pub fn get(&self, key: &K) -> Option<&V>
+    where
+        K: Ord,
+    {
+        // SAFETY: The `find` return value is a node in the tree, so it is valid.
+        self.find(key).map(|node| unsafe { &node.as_ref().value })
+    }
+
+    /// Returns a mutable reference to the value corresponding to the key.
+    pub fn get_mut(&mut self, key: &K) -> Option<&mut V>
+    where
+        K: Ord,
+    {
+        // SAFETY: The `find` return value is a node in the tree, so it is valid.
+        self.find(key)
+            .map(|mut node| unsafe { &mut node.as_mut().value })
+    }
+
+    /// Removes the node with the given key from the tree.
+    ///
+    /// It returns the node that was removed if one exists, or [`None`] otherwise.
+    pub fn remove_node(&mut self, key: &K) -> Option<RBTreeNode<K, V>>
+    where
+        K: Ord,
+    {
+        let mut node = self.find(key)?;
+
+        // SAFETY: The `find` return value is a node in the tree, so it is valid.
+        unsafe { bindings::rb_erase(&mut node.as_mut().links, &mut self.root) };
+
+        // INVARIANT: The node is being returned and the caller may free it, however, it was
+        // removed from the tree. So the invariants still hold.
+        Some(RBTreeNode {
+            // SAFETY: The `find` return value was a node in the tree, so it is valid.
+            node: unsafe { Box::from_raw(node.as_ptr()) },
+        })
+    }
+
+    /// Removes the node with the given key from the tree.
+    ///
+    /// It returns the value that was removed if one exists, or [`None`] otherwise.
+    pub fn remove(&mut self, key: &K) -> Option<V>
+    where
+        K: Ord,
+    {
+        let node = self.remove_node(key)?;
+        let RBTreeNode { node } = node;
+        let Node {
+            links: _,
+            key: _,
+            value,
+        } = *node;
+        Some(value)
+    }
+
+    /// Returns an iterator over the tree nodes, sorted by key.
+    pub fn iter(&self) -> RBTreeIterator<'_, K, V> {
+        RBTreeIterator {
+            _tree: PhantomData,
+            // SAFETY: `root` is valid as it's embedded in `self` and we have a valid `self`.
+            next: unsafe { bindings::rb_first(&self.root) },
+        }
+    }
+
+    /// Returns a mutable iterator over the tree nodes, sorted by key.
+    pub fn iter_mut(&mut self) -> RBTreeIteratorMut<'_, K, V> {
+        RBTreeIteratorMut {
+            _tree: PhantomData,
+            // SAFETY: `root` is valid as it's embedded in `self` and we have a valid `self`.
+            next: unsafe { bindings::rb_first(&self.root) },
+        }
+    }
+
+    /// Returns an iterator over the keys of the nodes in the tree, in sorted order.
+    pub fn keys(&self) -> impl Iterator<Item = &'_ K> {
+        self.iter().map(|(k, _)| k)
+    }
+
+    /// Returns an iterator over the values of the nodes in the tree, sorted by key.
+    pub fn values(&self) -> impl Iterator<Item = &'_ V> {
+        self.iter().map(|(_, v)| v)
+    }
+
+    /// Returns a mutable iterator over the values of the nodes in the tree, sorted by key.
+    pub fn values_mut(&mut self) -> impl Iterator<Item = &'_ mut V> {
+        self.iter_mut().map(|(_, v)| v)
+    }
+}
+
+impl<K, V> Default for RBTree<K, V> {
+    fn default() -> Self {
+        Self::new()
+    }
+}
+
+impl<K, V> Drop for RBTree<K, V> {
+    fn drop(&mut self) {
+        // SAFETY: `root` is valid as it's embedded in `self` and we have a valid `self`.
+        let mut next = unsafe { bindings::rb_first_postorder(&self.root) };
+
+        // INVARIANT: The loop invariant is that all tree nodes from `next` in postorder are valid.
+        while !next.is_null() {
+            let this = crate::container_of!(next, Node<K, V>, links);
+
+            // Find out what the next node is before disposing of the current one.
+            // SAFETY: `next` and all nodes in postorder are still valid.
+            next = unsafe { bindings::rb_next_postorder(next) };
+
+            // INVARIANT: This is the destructor, so we break the type invariant during clean-up,
+            // but it is not observable. The loop invariant is still maintained.
+            // SAFETY: `this` is valid per the loop invariant.
+            unsafe { Box::from_raw(this as *mut Node<K, V>) };
+        }
+    }
+}
+
+impl<'a, K, V> IntoIterator for &'a RBTree<K, V> {
+    type Item = (&'a K, &'a V);
+    type IntoIter = RBTreeIterator<'a, K, V>;
+
+    fn into_iter(self) -> Self::IntoIter {
+        self.iter()
+    }
+}
+
+/// An iterator over the nodes of a [`RBTree`].
+///
+/// Instances are created by calling [`RBTree::iter`].
+pub struct RBTreeIterator<'a, K, V> {
+    _tree: PhantomData<&'a RBTree<K, V>>,
+    next: *mut bindings::rb_node,
+}
+
+impl<'a, K, V> Iterator for RBTreeIterator<'a, K, V> {
+    type Item = (&'a K, &'a V);
+
+    fn next(&mut self) -> Option<Self::Item> {
+        if self.next.is_null() {
+            return None;
+        }
+
+        let cur = crate::container_of!(self.next, Node<K, V>, links);
+
+        // SAFETY: The reference to the tree used to create the iterator outlives the iterator, so
+        // the tree cannot change. By the tree invariant, all nodes are valid.
+        self.next = unsafe { bindings::rb_next(self.next) };
+
+        // SAFETY: By the same reasoning above, it is safe to dereference the node. Additionally,
+        // it is ok to return a reference to members because the iterator must outlive it.
+        Some(unsafe { (&(*cur).key, &(*cur).value) })
+    }
+}
+
+impl<'a, K, V> IntoIterator for &'a mut RBTree<K, V> {
+    type Item = (&'a K, &'a mut V);
+    type IntoIter = RBTreeIteratorMut<'a, K, V>;
+
+    fn into_iter(self) -> Self::IntoIter {
+        self.iter_mut()
+    }
+}
+
+/// A mutable iterator over the nodes of a [`RBTree`].
+///
+/// Instances are created by calling [`RBTree::iter_mut`].
+pub struct RBTreeIteratorMut<'a, K, V> {
+    _tree: PhantomData<&'a RBTree<K, V>>,
+    next: *mut bindings::rb_node,
+}
+
+impl<'a, K, V> Iterator for RBTreeIteratorMut<'a, K, V> {
+    type Item = (&'a K, &'a mut V);
+
+    fn next(&mut self) -> Option<Self::Item> {
+        if self.next.is_null() {
+            return None;
+        }
+
+        let cur = crate::container_of!(self.next, Node<K, V>, links) as *mut Node<K, V>;
+
+        // SAFETY: The reference to the tree used to create the iterator outlives the iterator, so
+        // the tree cannot change (except for the value of previous nodes, but those don't affect
+        // the iteration process). By the tree invariant, all nodes are valid.
+        self.next = unsafe { bindings::rb_next(self.next) };
+
+        // SAFETY: By the same reasoning above, it is safe to dereference the node. Additionally,
+        // it is ok to return a reference to members because the iterator must outlive it.
+        Some(unsafe { (&(*cur).key, &mut (*cur).value) })
+    }
+}
+
+/// A memory reservation for a red-black tree node.
+///
+/// It contains the memory needed to hold a node that can be inserted into a red-black tree. One
+/// can be obtained by directly allocating it ([`RBTree::try_reserve_node`]) or by "uninitialising"
+/// ([`RBTreeNode::into_reservation`]) an actual node (usually returned by some operation like
+/// removal from a tree).
+pub struct RBTreeNodeReservation<K, V> {
+    node: Box<MaybeUninit<Node<K, V>>>,
+}
+
+impl<K, V> RBTreeNodeReservation<K, V> {
+    /// Initialises a node reservation.
+    ///
+    /// It then becomes an [`RBTreeNode`] that can be inserted into a tree.
+    pub fn into_node(mut self, key: K, value: V) -> RBTreeNode<K, V> {
+        let node_ptr = self.node.as_mut_ptr();
+        // SAFETY: `node_ptr` is valid, and so are its fields.
+        unsafe { addr_of_mut!((*node_ptr).links).write(bindings::rb_node::default()) };
+        // SAFETY: `node_ptr` is valid, and so are its fields.
+        unsafe { addr_of_mut!((*node_ptr).key).write(key) };
+        // SAFETY: `node_ptr` is valid, and so are its fields.
+        unsafe { addr_of_mut!((*node_ptr).value).write(value) };
+        let raw = Box::into_raw(self.node);
+        RBTreeNode {
+            // SAFETY: The pointer came from a `MaybeUninit<Node>` whose fields have all been
+            // initialised. Additionally, it has the same layout as `Node`.
+            node: unsafe { Box::from_raw(raw as _) },
+        }
+    }
+}
+
+/// A red-black tree node.
+///
+/// The node is fully initialised (with key and value) and can be inserted into a tree without any
+/// extra allocations or failure paths.
+pub struct RBTreeNode<K, V> {
+    node: Box<Node<K, V>>,
+}
+
+impl<K, V> RBTreeNode<K, V> {
+    /// "Uninitialises" a node.
+    ///
+    /// It then becomes a reservation that can be re-initialised into a different node (i.e., with
+    /// a different key and/or value).
+    ///
+    /// The existing key and value are dropped in-place as part of this operation, that is, memory
+    /// may be freed (but only for the key/value; memory for the node itself is kept for reuse).
+    pub fn into_reservation(self) -> RBTreeNodeReservation<K, V> {
+        let raw = Box::into_raw(self.node);
+        let mut ret = RBTreeNodeReservation {
+            // SAFETY: The pointer came from a valid `Node`, which has the same layout as
+            // `MaybeUninit<Node>`.
+            node: unsafe { Box::from_raw(raw as _) },
+        };
+        // SAFETY: Although the type is `MaybeUninit<Node>`, we know it has been initialised
+        // because it came from a `Node`. So it is safe to drop it.
+        unsafe { core::ptr::drop_in_place(ret.node.as_mut_ptr()) };
+        ret
+    }
+}
diff --git a/rust/kernel/revocable.rs b/rust/kernel/revocable.rs
new file mode 100644
index 000000000000..cc49ccaa7a6d
--- /dev/null
+++ b/rust/kernel/revocable.rs
@@ -0,0 +1,161 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Revocable objects.
+//!
+//! The [`Revocable`] type wraps other types and allows access to them to be revoked. The existence
+//! of a [`RevocableGuard`] ensures that objects remain valid.
+
+use crate::bindings;
+use core::{
+    cell::UnsafeCell,
+    marker::PhantomData,
+    mem::ManuallyDrop,
+    ops::Deref,
+    ptr::drop_in_place,
+    sync::atomic::{AtomicBool, Ordering},
+};
+
+/// An object that can become inaccessible at runtime.
+///
+/// Once access is revoked and all concurrent users complete (i.e., all existing instances of
+/// [`RevocableGuard`] are dropped), the wrapped object is also dropped.
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::revocable::Revocable;
+///
+/// struct Example {
+///     a: u32,
+///     b: u32,
+/// }
+///
+/// fn add_two(v: &Revocable<Example>) -> Option<u32> {
+///     let guard = v.try_access()?;
+///     Some(guard.a + guard.b)
+/// }
+///
+/// let v = Revocable::new(Example { a: 10, b: 20 });
+/// assert_eq!(add_two(&v), Some(30));
+/// v.revoke();
+/// assert_eq!(add_two(&v), None);
+/// ```
+pub struct Revocable<T: ?Sized> {
+    is_available: AtomicBool,
+    data: ManuallyDrop<UnsafeCell<T>>,
+}
+
+// SAFETY: `Revocable` is `Send` if the wrapped object is also `Send`. This is because while the
+// functionality exposed by `Revocable` can be accessed from any thread/CPU, it is possible that
+// this isn't supported by the wrapped object.
+unsafe impl<T: ?Sized + Send> Send for Revocable<T> {}
+
+// SAFETY: `Revocable` is `Sync` if the wrapped object is both `Send` and `Sync`. We require `Send`
+// from the wrapped object as well because  of `Revocable::revoke`, which can trigger the `Drop`
+// implementation of the wrapped object from an arbitrary thread.
+unsafe impl<T: ?Sized + Sync + Send> Sync for Revocable<T> {}
+
+impl<T> Revocable<T> {
+    /// Creates a new revocable instance of the given data.
+    pub fn new(data: T) -> Self {
+        Self {
+            is_available: AtomicBool::new(true),
+            data: ManuallyDrop::new(UnsafeCell::new(data)),
+        }
+    }
+}
+
+impl<T: ?Sized> Revocable<T> {
+    /// Tries to access the \[revocable\] wrapped object.
+    ///
+    /// Returns `None` if the object has been revoked and is therefore no longer accessible.
+    ///
+    /// Returns a guard that gives access to the object otherwise; the object is guaranteed to
+    /// remain accessible while the guard is alive. In such cases, callers are not allowed to sleep
+    /// because another CPU may be waiting to complete the revocation of this object.
+    pub fn try_access(&self) -> Option<RevocableGuard<'_, T>> {
+        let guard = RevocableGuard::new(self.data.get());
+        if self.is_available.load(Ordering::Relaxed) {
+            Some(guard)
+        } else {
+            None
+        }
+    }
+
+    /// Revokes access to and drops the wrapped object.
+    ///
+    /// Access to the object is revoked immediately to new callers of [`Revocable::try_access`]. If
+    /// there are concurrent users of the object (i.e., ones that called [`Revocable::try_access`]
+    /// beforehand and still haven't dropped the returned guard), this function waits for the
+    /// concurrent access to complete before dropping the wrapped object.
+    pub fn revoke(&self) {
+        if self
+            .is_available
+            .compare_exchange(true, false, Ordering::Relaxed, Ordering::Relaxed)
+            .is_ok()
+        {
+            // SAFETY: Just an FFI call, there are no further requirements.
+            unsafe { bindings::synchronize_rcu() };
+
+            // SAFETY: We know `self.data` is valid because only one CPU can succeed the
+            // `compare_exchange` above that takes `is_available` from `true` to `false`.
+            unsafe { drop_in_place(self.data.get()) };
+        }
+    }
+}
+
+impl<T: ?Sized> Drop for Revocable<T> {
+    fn drop(&mut self) {
+        // Drop only if the data hasn't been revoked yet (in which case it has already been
+        // dropped).
+        if *self.is_available.get_mut() {
+            // SAFETY: We know `self.data` is valid because no other CPU has changed
+            // `is_available` to `false` yet, and no other CPU can do it anymore because this CPU
+            // holds the only reference (mutable) to `self` now.
+            unsafe { drop_in_place(self.data.get()) };
+        }
+    }
+}
+
+/// A guard that allows access to a revocable object and keeps it alive.
+///
+/// CPUs may not sleep while holding on to [`RevocableGuard`] because it's in atomic context
+/// holding the RCU read-side lock.
+///
+/// # Invariants
+///
+/// The RCU read-side lock is held while the guard is alive.
+pub struct RevocableGuard<'a, T: ?Sized> {
+    data_ref: *const T,
+    _p: PhantomData<&'a ()>,
+}
+
+impl<T: ?Sized> RevocableGuard<'_, T> {
+    fn new(data_ref: *const T) -> Self {
+        // SAFETY: Just an FFI call, there are no further requirements.
+        unsafe { bindings::rcu_read_lock() };
+
+        // INVARIANTS: The RCU read-side lock was just acquired.
+        Self {
+            data_ref,
+            _p: PhantomData,
+        }
+    }
+}
+
+impl<T: ?Sized> Drop for RevocableGuard<'_, T> {
+    fn drop(&mut self) {
+        // SAFETY: By the type invariants, we know that we hold the RCU read-side lock.
+        unsafe { bindings::rcu_read_unlock() };
+    }
+}
+
+impl<T: ?Sized> Deref for RevocableGuard<'_, T> {
+    type Target = T;
+
+    fn deref(&self) -> &Self::Target {
+        // SAFETY: By the type invariants, we hold the rcu read-side lock, so the object is
+        // guaranteed to remain valid.
+        unsafe { &*self.data_ref }
+    }
+}
diff --git a/rust/kernel/security.rs b/rust/kernel/security.rs
new file mode 100644
index 000000000000..eecf6dbf7851
--- /dev/null
+++ b/rust/kernel/security.rs
@@ -0,0 +1,38 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Linux Security Modules (LSM).
+//!
+//! C header: [`include/linux/security.h`](../../../../include/linux/security.h).
+
+use crate::{bindings, cred::Credential, file::File, to_result, Result};
+
+/// Calls the security modules to determine if the given task can become the manager of a binder
+/// context.
+pub fn binder_set_context_mgr(mgr: &Credential) -> Result {
+    // SAFETY: `mrg.0` is valid because the shared reference guarantees a nonzero refcount.
+    to_result(|| unsafe { bindings::security_binder_set_context_mgr(mgr.0.get()) })
+}
+
+/// Calls the security modules to determine if binder transactions are allowed from task `from` to
+/// task `to`.
+pub fn binder_transaction(from: &Credential, to: &Credential) -> Result {
+    // SAFETY: `from` and `to` are valid because the shared references guarantee nonzero refcounts.
+    to_result(|| unsafe { bindings::security_binder_transaction(from.0.get(), to.0.get()) })
+}
+
+/// Calls the security modules to determine if task `from` is allowed to send binder objects
+/// (owned by itself or other processes) to task `to` through a binder transaction.
+pub fn binder_transfer_binder(from: &Credential, to: &Credential) -> Result {
+    // SAFETY: `from` and `to` are valid because the shared references guarantee nonzero refcounts.
+    to_result(|| unsafe { bindings::security_binder_transfer_binder(from.0.get(), to.0.get()) })
+}
+
+/// Calls the security modules to determine if task `from` is allowed to send the given file to
+/// task `to` (which would get its own file descriptor) through a binder transaction.
+pub fn binder_transfer_file(from: &Credential, to: &Credential, file: &File) -> Result {
+    // SAFETY: `from`, `to` and `file` are valid because the shared references guarantee nonzero
+    // refcounts.
+    to_result(|| unsafe {
+        bindings::security_binder_transfer_file(from.0.get(), to.0.get(), file.0.get())
+    })
+}
diff --git a/rust/kernel/static_assert.rs b/rust/kernel/static_assert.rs
new file mode 100644
index 000000000000..c4424218b0ce
--- /dev/null
+++ b/rust/kernel/static_assert.rs
@@ -0,0 +1,38 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Static assert.
+
+/// Static assert (i.e. compile-time assert).
+///
+/// Similar to C11 [`_Static_assert`] and C++11 [`static_assert`].
+///
+/// The feature may be added to Rust in the future: see [RFC 2790].
+///
+/// [`_Static_assert`]: https://en.cppreference.com/w/c/language/_Static_assert
+/// [`static_assert`]: https://en.cppreference.com/w/cpp/language/static_assert
+/// [RFC 2790]: https://github.com/rust-lang/rfcs/issues/2790
+///
+/// # Examples
+///
+/// ```
+/// static_assert!(42 > 24);
+/// static_assert!(core::mem::size_of::<u8>() == 1);
+///
+/// const X: &[u8] = b"bar";
+/// static_assert!(X[1] == b'a');
+///
+/// const fn f(x: i32) -> i32 {
+///     x + 2
+/// }
+/// static_assert!(f(40) == 42);
+/// ```
+#[macro_export]
+macro_rules! static_assert {
+    ($condition:expr) => {
+        // Based on the latest one in `rustc`'s one before it was [removed].
+        //
+        // [removed]: https://github.com/rust-lang/rust/commit/c2dad1c6b9f9636198d7c561b47a2974f5103f6d
+        #[allow(dead_code)]
+        const _: () = [()][!($condition) as usize];
+    };
+}
diff --git a/rust/kernel/std_vendor.rs b/rust/kernel/std_vendor.rs
new file mode 100644
index 000000000000..d64f30ce78dc
--- /dev/null
+++ b/rust/kernel/std_vendor.rs
@@ -0,0 +1,160 @@
+// SPDX-License-Identifier: Apache-2.0 OR MIT
+
+//! The contents of this file come from the Rust standard library, hosted in the
+//! <https://github.com/rust-lang/rust> repository. For copyright details, see
+//! <https://github.com/rust-lang/rust/blob/master/COPYRIGHT>.
+
+/// [`std::dbg`], but using [`pr_info`] instead of [`eprintln`].
+///
+/// Prints and returns the value of a given expression for quick and dirty
+/// debugging.
+///
+/// An example:
+///
+/// ```rust
+/// let a = 2;
+/// # #[allow(clippy::dbg_macro)]
+/// let b = dbg!(a * 2) + 1;
+/// //      ^-- prints: [src/main.rs:2] a * 2 = 4
+/// assert_eq!(b, 5);
+/// ```
+///
+/// The macro works by using the `Debug` implementation of the type of
+/// the given expression to print the value with [`printk`] along with the
+/// source location of the macro invocation as well as the source code
+/// of the expression.
+///
+/// Invoking the macro on an expression moves and takes ownership of it
+/// before returning the evaluated expression unchanged. If the type
+/// of the expression does not implement `Copy` and you don't want
+/// to give up ownership, you can instead borrow with `dbg!(&expr)`
+/// for some expression `expr`.
+///
+/// The `dbg!` macro works exactly the same in release builds.
+/// This is useful when debugging issues that only occur in release
+/// builds or when debugging in release mode is significantly faster.
+///
+/// Note that the macro is intended as a debugging tool and therefore you
+/// should avoid having uses of it in version control for long periods
+/// (other than in tests and similar).
+///
+/// # Stability
+///
+/// The exact output printed by this macro should not be relied upon
+/// and is subject to future changes.
+///
+/// # Further examples
+///
+/// With a method call:
+///
+/// ```rust
+/// # #[allow(clippy::dbg_macro)]
+/// fn foo(n: usize) {
+///     if dbg!(n.checked_sub(4)).is_some() {
+///         // ...
+///     }
+/// }
+///
+/// foo(3)
+/// ```
+///
+/// This prints to the kernel log:
+///
+/// ```text,ignore
+/// [src/main.rs:4] n.checked_sub(4) = None
+/// ```
+///
+/// Naive factorial implementation:
+///
+/// ```rust
+/// # #[allow(clippy::dbg_macro)]
+/// # {
+/// fn factorial(n: u32) -> u32 {
+///     if dbg!(n <= 1) {
+///         dbg!(1)
+///     } else {
+///         dbg!(n * factorial(n - 1))
+///     }
+/// }
+///
+/// dbg!(factorial(4));
+/// # }
+/// ```
+///
+/// This prints to the kernel log:
+///
+/// ```text,ignore
+/// [src/main.rs:3] n <= 1 = false
+/// [src/main.rs:3] n <= 1 = false
+/// [src/main.rs:3] n <= 1 = false
+/// [src/main.rs:3] n <= 1 = true
+/// [src/main.rs:4] 1 = 1
+/// [src/main.rs:5] n * factorial(n - 1) = 2
+/// [src/main.rs:5] n * factorial(n - 1) = 6
+/// [src/main.rs:5] n * factorial(n - 1) = 24
+/// [src/main.rs:11] factorial(4) = 24
+/// ```
+///
+/// The `dbg!(..)` macro moves the input:
+///
+// TODO: Could be `compile_fail` when supported.
+/// ```ignore
+/// /// A wrapper around `usize` which importantly is not Copyable.
+/// #[derive(Debug)]
+/// struct NoCopy(usize);
+///
+/// let a = NoCopy(42);
+/// let _ = dbg!(a); // <-- `a` is moved here.
+/// let _ = dbg!(a); // <-- `a` is moved again; error!
+/// ```
+///
+/// You can also use `dbg!()` without a value to just print the
+/// file and line whenever it's reached.
+///
+/// Finally, if you want to `dbg!(..)` multiple values, it will treat them as
+/// a tuple (and return it, too):
+///
+/// ```
+/// # #[allow(clippy::dbg_macro)]
+/// assert_eq!(dbg!(1usize, 2u32), (1, 2));
+/// ```
+///
+/// However, a single argument with a trailing comma will still not be treated
+/// as a tuple, following the convention of ignoring trailing commas in macro
+/// invocations. You can use a 1-tuple directly if you need one:
+///
+/// ```
+/// # #[allow(clippy::dbg_macro)]
+/// # {
+/// assert_eq!(1, dbg!(1u32,)); // trailing comma ignored
+/// assert_eq!((1,), dbg!((1u32,))); // 1-tuple
+/// # }
+/// ```
+///
+/// [`std::dbg`]: https://doc.rust-lang.org/std/macro.dbg.html
+/// [`eprintln`]: https://doc.rust-lang.org/std/macro.eprintln.html
+/// [`printk`]: https://www.kernel.org/doc/html/latest/core-api/printk-basics.html
+#[macro_export]
+macro_rules! dbg {
+    // NOTE: We cannot use `concat!` to make a static string as a format argument
+    // of `pr_info!` because `file!` could contain a `{` or
+    // `$val` expression could be a block (`{ .. }`), in which case the `pr_info!`
+    // will be malformed.
+    () => {
+        $crate::pr_info!("[{}:{}]\n", ::core::file!(), ::core::line!())
+    };
+    ($val:expr $(,)?) => {
+        // Use of `match` here is intentional because it affects the lifetimes
+        // of temporaries - https://stackoverflow.com/a/48732525/1063961
+        match $val {
+            tmp => {
+                $crate::pr_info!("[{}:{}] {} = {:#?}\n",
+                    ::core::file!(), ::core::line!(), ::core::stringify!($val), &tmp);
+                tmp
+            }
+        }
+    };
+    ($($val:expr),+ $(,)?) => {
+        ($($crate::dbg!($val)),+,)
+    };
+}
diff --git a/rust/kernel/str.rs b/rust/kernel/str.rs
new file mode 100644
index 000000000000..1a72e2f0206d
--- /dev/null
+++ b/rust/kernel/str.rs
@@ -0,0 +1,597 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! String representations.
+
+use alloc::vec::Vec;
+use core::fmt::{self, Write};
+use core::ops::{self, Deref, Index};
+
+use crate::{bindings, c_types, error::code::*, Error};
+
+/// Byte string without UTF-8 validity guarantee.
+///
+/// `BStr` is simply an alias to `[u8]`, but has a more evident semantical meaning.
+pub type BStr = [u8];
+
+/// Creates a new [`BStr`] from a string literal.
+///
+/// `b_str!` converts the supplied string literal to byte string, so non-ASCII
+/// characters can be included.
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::b_str;
+/// # use kernel::str::BStr;
+/// const MY_BSTR: &BStr = b_str!("My awesome BStr!");
+/// ```
+#[macro_export]
+macro_rules! b_str {
+    ($str:literal) => {{
+        const S: &'static str = $str;
+        const C: &'static $crate::str::BStr = S.as_bytes();
+        C
+    }};
+}
+
+/// Possible errors when using conversion functions in [`CStr`].
+#[derive(Debug, Clone, Copy)]
+pub enum CStrConvertError {
+    /// Supplied bytes contain an interior `NUL`.
+    InteriorNul,
+
+    /// Supplied bytes are not terminated by `NUL`.
+    NotNulTerminated,
+}
+
+impl From<CStrConvertError> for Error {
+    #[inline]
+    fn from(_: CStrConvertError) -> Error {
+        EINVAL
+    }
+}
+
+/// A string that is guaranteed to have exactly one `NUL` byte, which is at the
+/// end.
+///
+/// Used for interoperability with kernel APIs that take C strings.
+#[repr(transparent)]
+pub struct CStr([u8]);
+
+impl CStr {
+    /// Returns the length of this string excluding `NUL`.
+    #[inline]
+    pub const fn len(&self) -> usize {
+        self.len_with_nul() - 1
+    }
+
+    /// Returns the length of this string with `NUL`.
+    #[inline]
+    pub const fn len_with_nul(&self) -> usize {
+        // SAFETY: This is one of the invariant of `CStr`.
+        // We add a `unreachable_unchecked` here to hint the optimizer that
+        // the value returned from this function is non-zero.
+        if self.0.is_empty() {
+            unsafe { core::hint::unreachable_unchecked() };
+        }
+        self.0.len()
+    }
+
+    /// Returns `true` if the string only includes `NUL`.
+    #[inline]
+    pub const fn is_empty(&self) -> bool {
+        self.len() == 0
+    }
+
+    /// Wraps a raw C string pointer.
+    ///
+    /// # Safety
+    ///
+    /// `ptr` must be a valid pointer to a `NUL`-terminated C string, and it must
+    /// last at least `'a`. When `CStr` is alive, the memory pointed by `ptr`
+    /// must not be mutated.
+    #[inline]
+    pub unsafe fn from_char_ptr<'a>(ptr: *const c_types::c_char) -> &'a Self {
+        // SAFETY: The safety precondition guarantees `ptr` is a valid pointer
+        // to a `NUL`-terminated C string.
+        let len = unsafe { bindings::strlen(ptr) } + 1;
+        // SAFETY: Lifetime guaranteed by the safety precondition.
+        let bytes = unsafe { core::slice::from_raw_parts(ptr as _, len as _) };
+        // SAFETY: As `len` is returned by `strlen`, `bytes` does not contain interior `NUL`.
+        // As we have added 1 to `len`, the last byte is known to be `NUL`.
+        unsafe { Self::from_bytes_with_nul_unchecked(bytes) }
+    }
+
+    /// Creates a [`CStr`] from a `[u8]`.
+    ///
+    /// The provided slice must be `NUL`-terminated, does not contain any
+    /// interior `NUL` bytes.
+    pub const fn from_bytes_with_nul(bytes: &[u8]) -> Result<&Self, CStrConvertError> {
+        if bytes.is_empty() {
+            return Err(CStrConvertError::NotNulTerminated);
+        }
+        if bytes[bytes.len() - 1] != 0 {
+            return Err(CStrConvertError::NotNulTerminated);
+        }
+        let mut i = 0;
+        // `i + 1 < bytes.len()` allows LLVM to optimize away bounds checking,
+        // while it couldn't optimize away bounds checks for `i < bytes.len() - 1`.
+        while i + 1 < bytes.len() {
+            if bytes[i] == 0 {
+                return Err(CStrConvertError::InteriorNul);
+            }
+            i += 1;
+        }
+        // SAFETY: We just checked that all properties hold.
+        Ok(unsafe { Self::from_bytes_with_nul_unchecked(bytes) })
+    }
+
+    /// Creates a [`CStr`] from a `[u8]`, panic if input is not valid.
+    ///
+    /// This function is only meant to be used by `c_str!` macro, so
+    /// crates using `c_str!` macro don't have to enable `const_panic` feature.
+    #[doc(hidden)]
+    pub const fn from_bytes_with_nul_unwrap(bytes: &[u8]) -> &Self {
+        match Self::from_bytes_with_nul(bytes) {
+            Ok(v) => v,
+            Err(_) => panic!("string contains interior NUL"),
+        }
+    }
+
+    /// Creates a [`CStr`] from a `[u8]` without performing any additional
+    /// checks.
+    ///
+    /// # Safety
+    ///
+    /// `bytes` *must* end with a `NUL` byte, and should only have a single
+    /// `NUL` byte (or the string will be truncated).
+    #[inline]
+    pub const unsafe fn from_bytes_with_nul_unchecked(bytes: &[u8]) -> &CStr {
+        // SAFETY: Properties of `bytes` guaranteed by the safety precondition.
+        unsafe { core::mem::transmute(bytes) }
+    }
+
+    /// Returns a C pointer to the string.
+    #[inline]
+    pub const fn as_char_ptr(&self) -> *const c_types::c_char {
+        self.0.as_ptr() as _
+    }
+
+    /// Convert the string to a byte slice without the trailing 0 byte.
+    #[inline]
+    pub fn as_bytes(&self) -> &[u8] {
+        &self.0[..self.len()]
+    }
+
+    /// Convert the string to a byte slice containing the trailing 0 byte.
+    #[inline]
+    pub const fn as_bytes_with_nul(&self) -> &[u8] {
+        &self.0
+    }
+
+    /// Yields a [`&str`] slice if the [`CStr`] contains valid UTF-8.
+    ///
+    /// If the contents of the [`CStr`] are valid UTF-8 data, this
+    /// function will return the corresponding [`&str`] slice. Otherwise,
+    /// it will return an error with details of where UTF-8 validation failed.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # use kernel::str::CStr;
+    /// let cstr = CStr::from_bytes_with_nul(b"foo\0").unwrap();
+    /// assert_eq!(cstr.to_str(), Ok("foo"));
+    /// ```
+    #[inline]
+    pub fn to_str(&self) -> Result<&str, core::str::Utf8Error> {
+        core::str::from_utf8(self.as_bytes())
+    }
+
+    /// Unsafely convert this [`CStr`] into a [`&str`], without checking for
+    /// valid UTF-8.
+    ///
+    /// # Safety
+    ///
+    /// The contents must be valid UTF-8.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # use kernel::c_str;
+    /// # use kernel::str::CStr;
+    /// // SAFETY: String literals are guaranteed to be valid UTF-8
+    /// // by the Rust compiler.
+    /// let bar = c_str!("ツ");
+    /// assert_eq!(unsafe { bar.as_str_unchecked() }, "ツ");
+    /// ```
+    #[inline]
+    pub unsafe fn as_str_unchecked(&self) -> &str {
+        unsafe { core::str::from_utf8_unchecked(self.as_bytes()) }
+    }
+}
+
+impl fmt::Display for CStr {
+    /// Formats printable ASCII characters, escaping the rest.
+    ///
+    /// ```
+    /// # use kernel::c_str;
+    /// # use kernel::str::CStr;
+    /// # use kernel::str::CString;
+    /// let penguin = c_str!("🐧");
+    /// let s = CString::try_from_fmt(fmt!("{}", penguin)).unwrap();
+    /// assert_eq!(s.as_bytes_with_nul(), "\\xf0\\x9f\\x90\\xa7\0".as_bytes());
+    ///
+    /// let ascii = c_str!("so \"cool\"");
+    /// let s = CString::try_from_fmt(fmt!("{}", ascii)).unwrap();
+    /// assert_eq!(s.as_bytes_with_nul(), "so \"cool\"\0".as_bytes());
+    /// ```
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        for &c in self.as_bytes() {
+            if (0x20..0x7f).contains(&c) {
+                // Printable character
+                f.write_char(c as char)?;
+            } else {
+                write!(f, "\\x{:02x}", c)?;
+            }
+        }
+        Ok(())
+    }
+}
+
+impl fmt::Debug for CStr {
+    /// Formats printable ASCII characters with a double quote on either end, escaping the rest.
+    ///
+    /// ```
+    /// # use kernel::c_str;
+    /// # use kernel::str::CStr;
+    /// # use kernel::str::CString;
+    /// let penguin = c_str!("🐧");
+    /// let s = CString::try_from_fmt(fmt!("{:?}", penguin)).unwrap();
+    /// assert_eq!(s.as_bytes_with_nul(), "\"\\xf0\\x9f\\x90\\xa7\"\0".as_bytes());
+    ///
+    /// // Embedded double quotes are escaped.
+    /// let ascii = c_str!("so \"cool\"");
+    /// let s = CString::try_from_fmt(fmt!("{:?}", ascii)).unwrap();
+    /// assert_eq!(s.as_bytes_with_nul(), "\"so \\\"cool\\\"\"\0".as_bytes());
+    /// ```
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.write_str("\"")?;
+        for &c in self.as_bytes() {
+            match c {
+                // Printable characters
+                b'\"' => f.write_str("\\\"")?,
+                0x20..=0x7e => f.write_char(c as char)?,
+                _ => write!(f, "\\x{:02x}", c)?,
+            }
+        }
+        f.write_str("\"")
+    }
+}
+
+impl AsRef<BStr> for CStr {
+    #[inline]
+    fn as_ref(&self) -> &BStr {
+        self.as_bytes()
+    }
+}
+
+impl Deref for CStr {
+    type Target = BStr;
+
+    #[inline]
+    fn deref(&self) -> &Self::Target {
+        self.as_bytes()
+    }
+}
+
+impl Index<ops::RangeFrom<usize>> for CStr {
+    type Output = CStr;
+
+    #[inline]
+    fn index(&self, index: ops::RangeFrom<usize>) -> &Self::Output {
+        // Delegate bounds checking to slice.
+        // Assign to _ to mute clippy's unnecessary operation warning.
+        let _ = &self.as_bytes()[index.start..];
+        // SAFETY: We just checked the bounds.
+        unsafe { Self::from_bytes_with_nul_unchecked(&self.0[index.start..]) }
+    }
+}
+
+impl Index<ops::RangeFull> for CStr {
+    type Output = CStr;
+
+    #[inline]
+    fn index(&self, _index: ops::RangeFull) -> &Self::Output {
+        self
+    }
+}
+
+mod private {
+    use core::ops;
+
+    // Marker trait for index types that can be forward to `BStr`.
+    pub trait CStrIndex {}
+
+    impl CStrIndex for usize {}
+    impl CStrIndex for ops::Range<usize> {}
+    impl CStrIndex for ops::RangeInclusive<usize> {}
+    impl CStrIndex for ops::RangeToInclusive<usize> {}
+}
+
+impl<Idx> Index<Idx> for CStr
+where
+    Idx: private::CStrIndex,
+    BStr: Index<Idx>,
+{
+    type Output = <BStr as Index<Idx>>::Output;
+
+    #[inline]
+    fn index(&self, index: Idx) -> &Self::Output {
+        &self.as_bytes()[index]
+    }
+}
+
+/// Creates a new [`CStr`] from a string literal.
+///
+/// The string literal should not contain any `NUL` bytes.
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::c_str;
+/// # use kernel::str::CStr;
+/// const MY_CSTR: &CStr = c_str!("My awesome CStr!");
+/// ```
+#[macro_export]
+macro_rules! c_str {
+    ($str:expr) => {{
+        const S: &str = concat!($str, "\0");
+        const C: &$crate::str::CStr = $crate::str::CStr::from_bytes_with_nul_unwrap(S.as_bytes());
+        C
+    }};
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn test_cstr_to_str() {
+        let good_bytes = b"\xf0\x9f\xa6\x80\0";
+        let checked_cstr = CStr::from_bytes_with_nul(good_bytes).unwrap();
+        let checked_str = checked_cstr.to_str().unwrap();
+        assert_eq!(checked_str, "🦀");
+    }
+
+    #[test]
+    #[should_panic]
+    fn test_cstr_to_str_panic() {
+        let bad_bytes = b"\xc3\x28\0";
+        let checked_cstr = CStr::from_bytes_with_nul(bad_bytes).unwrap();
+        checked_cstr.to_str().unwrap();
+    }
+
+    #[test]
+    fn test_cstr_as_str_unchecked() {
+        let good_bytes = b"\xf0\x9f\x90\xA7\0";
+        let checked_cstr = CStr::from_bytes_with_nul(good_bytes).unwrap();
+        let unchecked_str = unsafe { checked_cstr.as_str_unchecked() };
+        assert_eq!(unchecked_str, "🐧");
+    }
+}
+
+/// Allows formatting of [`fmt::Arguments`] into a raw buffer.
+///
+/// It does not fail if callers write past the end of the buffer so that they can calculate the
+/// size required to fit everything.
+///
+/// # Invariants
+///
+/// The memory region between `pos` (inclusive) and `end` (exclusive) is valid for writes if `pos`
+/// is less than `end`.
+pub(crate) struct RawFormatter {
+    // Use `usize` to use `saturating_*` functions.
+    beg: usize,
+    pos: usize,
+    end: usize,
+}
+
+impl RawFormatter {
+    /// Creates a new instance of [`RawFormatter`] with an empty buffer.
+    fn new() -> Self {
+        // INVARIANT: The buffer is empty, so the region that needs to be writable is empty.
+        Self {
+            beg: 0,
+            pos: 0,
+            end: 0,
+        }
+    }
+
+    /// Creates a new instance of [`RawFormatter`] with the given buffer pointers.
+    ///
+    /// # Safety
+    ///
+    /// If `pos` is less than `end`, then the region between `pos` (inclusive) and `end`
+    /// (exclusive) must be valid for writes for the lifetime of the returned [`RawFormatter`].
+    pub(crate) unsafe fn from_ptrs(pos: *mut u8, end: *mut u8) -> Self {
+        // INVARIANT: The safety requierments guarantee the type invariants.
+        Self {
+            beg: pos as _,
+            pos: pos as _,
+            end: end as _,
+        }
+    }
+
+    /// Creates a new instance of [`RawFormatter`] with the given buffer.
+    ///
+    /// # Safety
+    ///
+    /// The memory region starting at `buf` and extending for `len` bytes must be valid for writes
+    /// for the lifetime of the returned [`RawFormatter`].
+    pub(crate) unsafe fn from_buffer(buf: *mut u8, len: usize) -> Self {
+        let pos = buf as usize;
+        // INVARIANT: We ensure that `end` is never less then `buf`, and the safety requirements
+        // guarantees that the memory region is valid for writes.
+        Self {
+            pos,
+            beg: pos,
+            end: pos.saturating_add(len),
+        }
+    }
+
+    /// Returns the current insert position.
+    ///
+    /// N.B. It may point to invalid memory.
+    pub(crate) fn pos(&self) -> *mut u8 {
+        self.pos as _
+    }
+
+    /// Return the number of bytes written to the formatter.
+    pub(crate) fn bytes_written(&self) -> usize {
+        self.pos - self.beg
+    }
+}
+
+impl fmt::Write for RawFormatter {
+    fn write_str(&mut self, s: &str) -> fmt::Result {
+        // `pos` value after writing `len` bytes. This does not have to be bounded by `end`, but we
+        // don't want it to wrap around to 0.
+        let pos_new = self.pos.saturating_add(s.len());
+
+        // Amount that we can copy. `saturating_sub` ensures we get 0 if `pos` goes past `end`.
+        let len_to_copy = core::cmp::min(pos_new, self.end).saturating_sub(self.pos);
+
+        if len_to_copy > 0 {
+            // SAFETY: If `len_to_copy` is non-zero, then we know `pos` has not gone past `end`
+            // yet, so it is valid for write per the type invariants.
+            unsafe {
+                core::ptr::copy_nonoverlapping(
+                    s.as_bytes().as_ptr(),
+                    self.pos as *mut u8,
+                    len_to_copy,
+                )
+            };
+        }
+
+        self.pos = pos_new;
+        Ok(())
+    }
+}
+
+/// Allows formatting of [`fmt::Arguments`] into a raw buffer.
+///
+/// Fails if callers attempt to write more than will fit in the buffer.
+pub(crate) struct Formatter(RawFormatter);
+
+impl Formatter {
+    /// Creates a new instance of [`Formatter`] with the given buffer.
+    ///
+    /// # Safety
+    ///
+    /// The memory region starting at `buf` and extending for `len` bytes must be valid for writes
+    /// for the lifetime of the returned [`Formatter`].
+    pub(crate) unsafe fn from_buffer(buf: *mut u8, len: usize) -> Self {
+        // SAFETY: The safety requirements of this function satisfy those of the callee.
+        Self(unsafe { RawFormatter::from_buffer(buf, len) })
+    }
+}
+
+impl Deref for Formatter {
+    type Target = RawFormatter;
+
+    fn deref(&self) -> &Self::Target {
+        &self.0
+    }
+}
+
+impl fmt::Write for Formatter {
+    fn write_str(&mut self, s: &str) -> fmt::Result {
+        self.0.write_str(s)?;
+
+        // Fail the request if we go past the end of the buffer.
+        if self.0.pos > self.0.end {
+            Err(fmt::Error)
+        } else {
+            Ok(())
+        }
+    }
+}
+
+/// An owned string that is guaranteed to have exactly one `NUL` byte, which is at the end.
+///
+/// Used for interoperability with kernel APIs that take C strings.
+///
+/// # Invariants
+///
+/// The string is always `NUL`-terminated and contains no other `NUL` bytes.
+///
+/// # Examples
+///
+/// ```
+/// use kernel::str::CString;
+///
+/// let s = CString::try_from_fmt(fmt!("{}{}{}", "abc", 10, 20)).unwrap();
+/// assert_eq!(s.as_bytes_with_nul(), "abc1020\0".as_bytes());
+///
+/// let tmp = "testing";
+/// let s = CString::try_from_fmt(fmt!("{tmp}{}", 123)).unwrap();
+/// assert_eq!(s.as_bytes_with_nul(), "testing123\0".as_bytes());
+///
+/// // This fails because it has an embedded `NUL` byte.
+/// let s = CString::try_from_fmt(fmt!("a\0b{}", 123));
+/// assert_eq!(s.is_ok(), false);
+/// ```
+pub struct CString {
+    buf: Vec<u8>,
+}
+
+impl CString {
+    /// Creates an instance of [`CString`] from the given formatted arguments.
+    pub fn try_from_fmt(args: fmt::Arguments<'_>) -> Result<Self, Error> {
+        // Calculate the size needed (formatted string plus `NUL` terminator).
+        let mut f = RawFormatter::new();
+        f.write_fmt(args)?;
+        f.write_str("\0")?;
+        let size = f.bytes_written();
+
+        // Allocate a vector with the required number of bytes, and write to it.
+        let mut buf = Vec::try_with_capacity(size)?;
+        // SAFETY: The buffer stored in `buf` is at least of size `size` and is valid for writes.
+        let mut f = unsafe { Formatter::from_buffer(buf.as_mut_ptr(), size) };
+        f.write_fmt(args)?;
+        f.write_str("\0")?;
+
+        // SAFETY: The number of bytes that can be written to `f` is bounded by `size`, which is
+        // `buf`'s capacity. The contents of the buffer have been initialised by writes to `f`.
+        unsafe { buf.set_len(f.bytes_written()) };
+
+        // Check that there are no `NUL` bytes before the end.
+        // SAFETY: The buffer is valid for read because `f.bytes_written()` is bounded by `size`
+        // (which the minimum buffer size) and is non-zero (we wrote at least the `NUL` terminator)
+        // so `f.bytes_written() - 1` doesn't underflow.
+        let ptr = unsafe { bindings::memchr(buf.as_ptr().cast(), 0, (f.bytes_written() - 1) as _) };
+        if !ptr.is_null() {
+            return Err(EINVAL);
+        }
+
+        // INVARIANT: We wrote the `NUL` terminator and checked above that no other `NUL` bytes
+        // exist in the buffer.
+        Ok(Self { buf })
+    }
+}
+
+impl Deref for CString {
+    type Target = CStr;
+
+    fn deref(&self) -> &Self::Target {
+        // SAFETY: The type invariants guarantee that the string is `NUL`-terminated and that no
+        // other `NUL` bytes exist.
+        unsafe { CStr::from_bytes_with_nul_unchecked(self.buf.as_slice()) }
+    }
+}
+
+/// A convenience alias for [`core::format_args`].
+#[macro_export]
+macro_rules! fmt {
+    ($($f:tt)*) => ( core::format_args!($($f)*) )
+}
diff --git a/rust/kernel/sysctl.rs b/rust/kernel/sysctl.rs
new file mode 100644
index 000000000000..63bf76d03d93
--- /dev/null
+++ b/rust/kernel/sysctl.rs
@@ -0,0 +1,199 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! System control.
+//!
+//! C header: [`include/linux/sysctl.h`](../../../../include/linux/sysctl.h)
+//!
+//! Reference: <https://www.kernel.org/doc/Documentation/sysctl/README>
+
+use alloc::boxed::Box;
+use alloc::vec::Vec;
+use core::mem;
+use core::ptr;
+use core::sync::atomic;
+
+use crate::{
+    bindings, c_types,
+    error::code::*,
+    io_buffer::IoBufferWriter,
+    str::CStr,
+    types,
+    user_ptr::{UserSlicePtr, UserSlicePtrWriter},
+    Result,
+};
+
+/// Sysctl storage.
+pub trait SysctlStorage: Sync {
+    /// Writes a byte slice.
+    fn store_value(&self, data: &[u8]) -> (usize, Result);
+
+    /// Reads via a [`UserSlicePtrWriter`].
+    fn read_value(&self, data: &mut UserSlicePtrWriter) -> (usize, Result);
+}
+
+fn trim_whitespace(mut data: &[u8]) -> &[u8] {
+    while !data.is_empty() && (data[0] == b' ' || data[0] == b'\t' || data[0] == b'\n') {
+        data = &data[1..];
+    }
+    while !data.is_empty()
+        && (data[data.len() - 1] == b' '
+            || data[data.len() - 1] == b'\t'
+            || data[data.len() - 1] == b'\n')
+    {
+        data = &data[..data.len() - 1];
+    }
+    data
+}
+
+impl<T> SysctlStorage for &T
+where
+    T: SysctlStorage,
+{
+    fn store_value(&self, data: &[u8]) -> (usize, Result) {
+        (*self).store_value(data)
+    }
+
+    fn read_value(&self, data: &mut UserSlicePtrWriter) -> (usize, Result) {
+        (*self).read_value(data)
+    }
+}
+
+impl SysctlStorage for atomic::AtomicBool {
+    fn store_value(&self, data: &[u8]) -> (usize, Result) {
+        let result = match trim_whitespace(data) {
+            b"0" => {
+                self.store(false, atomic::Ordering::Relaxed);
+                Ok(())
+            }
+            b"1" => {
+                self.store(true, atomic::Ordering::Relaxed);
+                Ok(())
+            }
+            _ => Err(EINVAL),
+        };
+        (data.len(), result)
+    }
+
+    fn read_value(&self, data: &mut UserSlicePtrWriter) -> (usize, Result) {
+        let value = if self.load(atomic::Ordering::Relaxed) {
+            b"1\n"
+        } else {
+            b"0\n"
+        };
+        (value.len(), data.write_slice(value))
+    }
+}
+
+/// Holds a single `sysctl` entry (and its table).
+pub struct Sysctl<T: SysctlStorage> {
+    inner: Box<T>,
+    // Responsible for keeping the `ctl_table` alive.
+    _table: Box<[bindings::ctl_table]>,
+    header: *mut bindings::ctl_table_header,
+}
+
+// SAFETY: The only public method we have is `get()`, which returns `&T`, and
+// `T: Sync`. Any new methods must adhere to this requirement.
+unsafe impl<T: SysctlStorage> Sync for Sysctl<T> {}
+
+unsafe extern "C" fn proc_handler<T: SysctlStorage>(
+    ctl: *mut bindings::ctl_table,
+    write: c_types::c_int,
+    buffer: *mut c_types::c_void,
+    len: *mut usize,
+    ppos: *mut bindings::loff_t,
+) -> c_types::c_int {
+    // If we are reading from some offset other than the beginning of the file,
+    // return an empty read to signal EOF.
+    if unsafe { *ppos } != 0 && write == 0 {
+        unsafe { *len = 0 };
+        return 0;
+    }
+
+    let data = unsafe { UserSlicePtr::new(buffer, *len) };
+    let storage = unsafe { &*((*ctl).data as *const T) };
+    let (bytes_processed, result) = if write != 0 {
+        let data = match data.read_all() {
+            Ok(r) => r,
+            Err(e) => return e.to_kernel_errno(),
+        };
+        storage.store_value(&data)
+    } else {
+        let mut writer = data.writer();
+        storage.read_value(&mut writer)
+    };
+    unsafe { *len = bytes_processed };
+    unsafe { *ppos += *len as bindings::loff_t };
+    match result {
+        Ok(()) => 0,
+        Err(e) => e.to_kernel_errno(),
+    }
+}
+
+impl<T: SysctlStorage> Sysctl<T> {
+    /// Registers a single entry in `sysctl`.
+    pub fn register(
+        path: &'static CStr,
+        name: &'static CStr,
+        storage: T,
+        mode: types::Mode,
+    ) -> Result<Sysctl<T>> {
+        if name.contains(&b'/') {
+            return Err(EINVAL);
+        }
+
+        let storage = Box::try_new(storage)?;
+        let mut table = Vec::try_with_capacity(2)?;
+        table.try_push(bindings::ctl_table {
+            procname: name.as_char_ptr(),
+            mode: mode.as_int(),
+            data: &*storage as *const T as *mut c_types::c_void,
+            proc_handler: Some(proc_handler::<T>),
+
+            maxlen: 0,
+            child: ptr::null_mut(),
+            poll: ptr::null_mut(),
+            extra1: ptr::null_mut(),
+            extra2: ptr::null_mut(),
+        })?;
+        table.try_push(unsafe { mem::zeroed() })?;
+        let mut table = table.try_into_boxed_slice()?;
+
+        let result = unsafe { bindings::register_sysctl(path.as_char_ptr(), table.as_mut_ptr()) };
+        if result.is_null() {
+            return Err(ENOMEM);
+        }
+
+        Ok(Sysctl {
+            inner: storage,
+            _table: table,
+            header: result,
+        })
+    }
+
+    /// Gets the storage.
+    pub fn get(&self) -> &T {
+        &self.inner
+    }
+}
+
+impl<T: SysctlStorage> Drop for Sysctl<T> {
+    fn drop(&mut self) {
+        unsafe {
+            bindings::unregister_sysctl_table(self.header);
+        }
+        self.header = ptr::null_mut();
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn test_trim_whitespace() {
+        assert_eq!(trim_whitespace(b"foo    "), b"foo");
+        assert_eq!(trim_whitespace(b"    foo"), b"foo");
+        assert_eq!(trim_whitespace(b"  foo  "), b"foo");
+    }
+}
diff --git a/rust/kernel/task.rs b/rust/kernel/task.rs
new file mode 100644
index 000000000000..52dfc8db3d35
--- /dev/null
+++ b/rust/kernel/task.rs
@@ -0,0 +1,175 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Tasks (threads and processes).
+//!
+//! C header: [`include/linux/sched.h`](../../../../include/linux/sched.h).
+
+use crate::bindings;
+use core::{marker::PhantomData, mem::ManuallyDrop, ops::Deref};
+
+/// Wraps the kernel's `struct task_struct`.
+///
+/// # Invariants
+///
+/// The pointer `Task::ptr` is non-null and valid. Its reference count is also non-zero.
+///
+/// # Examples
+///
+/// The following is an example of getting the PID of the current thread with zero additional cost
+/// when compared to the C version:
+///
+/// ```
+/// use kernel::task::Task;
+///
+/// let pid = Task::current().pid();
+/// ```
+///
+/// Getting the PID of the current process, also zero additional cost:
+///
+/// ```
+/// use kernel::task::Task;
+///
+/// let pid = Task::current().group_leader().pid();
+/// ```
+///
+/// Getting the current task and storing it in some struct. The reference count is automatically
+/// incremented when creating `State` and decremented when it is dropped:
+///
+/// ```
+/// use kernel::task::Task;
+///
+/// struct State {
+///     creator: Task,
+///     index: u32,
+/// }
+///
+/// impl State {
+///     fn new() -> Self {
+///         Self {
+///             creator: Task::current().clone(),
+///             index: 0,
+///         }
+///     }
+/// }
+/// ```
+pub struct Task {
+    pub(crate) ptr: *mut bindings::task_struct,
+}
+
+// SAFETY: Given that the task is referenced, it is OK to send it to another thread.
+unsafe impl Send for Task {}
+
+// SAFETY: It's OK to access `Task` through references from other threads because we're either
+// accessing properties that don't change (e.g., `pid`, `group_leader`) or that are properly
+// synchronised by C code (e.g., `signal_pending`).
+unsafe impl Sync for Task {}
+
+/// The type of process identifiers (PIDs).
+type Pid = bindings::pid_t;
+
+impl Task {
+    /// Returns a task reference for the currently executing task/thread.
+    pub fn current<'a>() -> TaskRef<'a> {
+        // SAFETY: Just an FFI call.
+        let ptr = unsafe { bindings::get_current() };
+
+        // SAFETY: If the current thread is still running, the current task is valid. Given
+        // that `TaskRef` is not `Send`, we know it cannot be transferred to another thread (where
+        // it could potentially outlive the caller).
+        unsafe { TaskRef::from_ptr(ptr) }
+    }
+
+    /// Returns the group leader of the given task.
+    pub fn group_leader(&self) -> TaskRef<'_> {
+        // SAFETY: By the type invariant, we know that `self.ptr` is non-null and valid.
+        let ptr = unsafe { (*self.ptr).group_leader };
+
+        // SAFETY: The lifetime of the returned task reference is tied to the lifetime of `self`,
+        // and given that a task has a reference to its group leader, we know it must be valid for
+        // the lifetime of the returned task reference.
+        unsafe { TaskRef::from_ptr(ptr) }
+    }
+
+    /// Returns the PID of the given task.
+    pub fn pid(&self) -> Pid {
+        // SAFETY: By the type invariant, we know that `self.ptr` is non-null and valid.
+        unsafe { (*self.ptr).pid }
+    }
+
+    /// Determines whether the given task has pending signals.
+    pub fn signal_pending(&self) -> bool {
+        // SAFETY: By the type invariant, we know that `self.ptr` is non-null and valid.
+        unsafe { bindings::signal_pending(self.ptr) != 0 }
+    }
+}
+
+impl PartialEq for Task {
+    fn eq(&self, other: &Self) -> bool {
+        self.ptr == other.ptr
+    }
+}
+
+impl Eq for Task {}
+
+impl Clone for Task {
+    fn clone(&self) -> Self {
+        // SAFETY: The type invariants guarantee that `self.ptr` has a non-zero reference count.
+        unsafe { bindings::get_task_struct(self.ptr) };
+
+        // INVARIANT: We incremented the reference count to account for the new `Task` being
+        // created.
+        Self { ptr: self.ptr }
+    }
+}
+
+impl Drop for Task {
+    fn drop(&mut self) {
+        // INVARIANT: We may decrement the refcount to zero, but the `Task` is being dropped, so
+        // this is not observable.
+        // SAFETY: The type invariants guarantee that `Task::ptr` has a non-zero reference count.
+        unsafe { bindings::put_task_struct(self.ptr) };
+    }
+}
+
+/// A wrapper for [`Task`] that doesn't automatically decrement the refcount when dropped.
+///
+/// We need the wrapper because [`ManuallyDrop`] alone would allow callers to call
+/// [`ManuallyDrop::into_inner`]. This would allow an unsafe sequence to be triggered without
+/// `unsafe` blocks because it would trigger an unbalanced call to `put_task_struct`.
+///
+/// We make this explicitly not [`Send`] so that we can use it to represent the current thread
+/// without having to increment/decrement its reference count.
+///
+/// # Invariants
+///
+/// The wrapped [`Task`] remains valid for the lifetime of the object.
+pub struct TaskRef<'a> {
+    task: ManuallyDrop<Task>,
+    _not_send: PhantomData<(&'a (), *mut ())>,
+}
+
+impl TaskRef<'_> {
+    /// Constructs a new `struct task_struct` wrapper that doesn't change its reference count.
+    ///
+    /// # Safety
+    ///
+    /// The pointer `ptr` must be non-null and valid for the lifetime of the object.
+    pub(crate) unsafe fn from_ptr(ptr: *mut bindings::task_struct) -> Self {
+        Self {
+            task: ManuallyDrop::new(Task { ptr }),
+            _not_send: PhantomData,
+        }
+    }
+}
+
+// SAFETY: It is OK to share a reference to the current thread with another thread because we know
+// the owner cannot go away while the shared reference exists (and `Task` itself is `Sync`).
+unsafe impl Sync for TaskRef<'_> {}
+
+impl Deref for TaskRef<'_> {
+    type Target = Task;
+
+    fn deref(&self) -> &Self::Target {
+        self.task.deref()
+    }
+}
diff --git a/rust/kernel/types.rs b/rust/kernel/types.rs
new file mode 100644
index 000000000000..42a83f4390d3
--- /dev/null
+++ b/rust/kernel/types.rs
@@ -0,0 +1,679 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Kernel types.
+//!
+//! C header: [`include/linux/types.h`](../../../../include/linux/types.h)
+
+use crate::{
+    bindings, c_types,
+    sync::{Ref, RefBorrow},
+};
+use alloc::boxed::Box;
+use core::{
+    cell::UnsafeCell,
+    marker::PhantomData,
+    mem::MaybeUninit,
+    ops::{self, Deref, DerefMut},
+    pin::Pin,
+    ptr::NonNull,
+};
+
+/// Permissions.
+///
+/// C header: [`include/uapi/linux/stat.h`](../../../../include/uapi/linux/stat.h)
+///
+/// C header: [`include/linux/stat.h`](../../../../include/linux/stat.h)
+pub struct Mode(bindings::umode_t);
+
+impl Mode {
+    /// Creates a [`Mode`] from an integer.
+    pub fn from_int(m: u16) -> Mode {
+        Mode(m)
+    }
+
+    /// Returns the mode as an integer.
+    pub fn as_int(&self) -> u16 {
+        self.0
+    }
+}
+
+/// Used to convert an object into a raw pointer that represents it.
+///
+/// It can eventually be converted back into the object. This is used to store objects as pointers
+/// in kernel data structures, for example, an implementation of [`FileOperations`] in `struct
+/// file::private_data`.
+pub trait PointerWrapper {
+    /// Type of values borrowed between calls to [`PointerWrapper::into_pointer`] and
+    /// [`PointerWrapper::from_pointer`].
+    type Borrowed<'a>;
+
+    /// Returns the raw pointer.
+    fn into_pointer(self) -> *const c_types::c_void;
+
+    /// Returns a borrowed value.
+    ///
+    /// # Safety
+    ///
+    /// `ptr` must have been returned by a previous call to [`PointerWrapper::into_pointer`].
+    /// Additionally, [`PointerWrapper::from_pointer`] can only be called after *all* values
+    /// returned by [`PointerWrapper::borrow`] have been dropped.
+    unsafe fn borrow<'a>(ptr: *const c_types::c_void) -> Self::Borrowed<'a>;
+
+    /// Returns the instance back from the raw pointer.
+    ///
+    /// # Safety
+    ///
+    /// The passed pointer must come from a previous call to [`PointerWrapper::into_pointer()`].
+    unsafe fn from_pointer(ptr: *const c_types::c_void) -> Self;
+}
+
+impl<T: 'static> PointerWrapper for Box<T> {
+    type Borrowed<'a> = &'a T;
+
+    fn into_pointer(self) -> *const c_types::c_void {
+        Box::into_raw(self) as _
+    }
+
+    unsafe fn borrow<'a>(ptr: *const c_types::c_void) -> &'a T {
+        // SAFETY: The safety requirements for this function ensure that the object is still alive,
+        // so it is safe to dereference the raw pointer.
+        // The safety requirements also ensure that the object remains alive for the lifetime of
+        // the returned value.
+        unsafe { &*ptr.cast() }
+    }
+
+    unsafe fn from_pointer(ptr: *const c_types::c_void) -> Self {
+        // SAFETY: The passed pointer comes from a previous call to [`Self::into_pointer()`].
+        unsafe { Box::from_raw(ptr as _) }
+    }
+}
+
+impl<T: 'static> PointerWrapper for Ref<T> {
+    type Borrowed<'a> = RefBorrow<'a, T>;
+
+    fn into_pointer(self) -> *const c_types::c_void {
+        Ref::into_usize(self) as _
+    }
+
+    unsafe fn borrow<'a>(ptr: *const c_types::c_void) -> RefBorrow<'a, T> {
+        // SAFETY: The safety requirements for this function ensure that the underlying object
+        // remains valid for the lifetime of the returned value.
+        unsafe { Ref::borrow_usize(ptr as _) }
+    }
+
+    unsafe fn from_pointer(ptr: *const c_types::c_void) -> Self {
+        // SAFETY: The passed pointer comes from a previous call to [`Self::into_pointer()`].
+        unsafe { Ref::from_usize(ptr as _) }
+    }
+}
+
+impl<T: PointerWrapper + Deref> PointerWrapper for Pin<T> {
+    type Borrowed<'a> = T::Borrowed<'a>;
+
+    fn into_pointer(self) -> *const c_types::c_void {
+        // SAFETY: We continue to treat the pointer as pinned by returning just a pointer to it to
+        // the caller.
+        let inner = unsafe { Pin::into_inner_unchecked(self) };
+        inner.into_pointer()
+    }
+
+    unsafe fn borrow<'a>(ptr: *const c_types::c_void) -> Self::Borrowed<'a> {
+        // SAFETY: The safety requirements for this function are the same as the ones for
+        // `T::borrow`.
+        unsafe { T::borrow(ptr) }
+    }
+
+    unsafe fn from_pointer(p: *const c_types::c_void) -> Self {
+        // SAFETY: The object was originally pinned.
+        // The passed pointer comes from a previous call to `inner::into_pointer()`.
+        unsafe { Pin::new_unchecked(T::from_pointer(p)) }
+    }
+}
+
+impl<T> PointerWrapper for *mut T {
+    type Borrowed<'a> = *mut T;
+
+    fn into_pointer(self) -> *const c_types::c_void {
+        self as _
+    }
+
+    unsafe fn borrow<'a>(ptr: *const c_types::c_void) -> Self::Borrowed<'a> {
+        ptr as _
+    }
+
+    unsafe fn from_pointer(ptr: *const c_types::c_void) -> Self {
+        ptr as _
+    }
+}
+
+impl PointerWrapper for () {
+    type Borrowed<'a> = ();
+
+    fn into_pointer(self) -> *const c_types::c_void {
+        // We use 1 to be different from a null pointer.
+        1usize as _
+    }
+
+    unsafe fn borrow<'a>(_: *const c_types::c_void) -> Self::Borrowed<'a> {}
+
+    unsafe fn from_pointer(_: *const c_types::c_void) -> Self {}
+}
+
+/// Runs a cleanup function/closure when dropped.
+///
+/// The [`ScopeGuard::dismiss`] function prevents the cleanup function from running.
+///
+/// # Examples
+///
+/// In the example below, we have multiple exit paths and we want to log regardless of which one is
+/// taken:
+/// ```
+/// # use kernel::ScopeGuard;
+/// fn example1(arg: bool) {
+///     let _log = ScopeGuard::new(|| pr_info!("example1 completed\n"));
+///
+///     if arg {
+///         return;
+///     }
+///
+///     pr_info!("Do something...\n");
+/// }
+///
+/// # example1(false);
+/// # example1(true);
+/// ```
+///
+/// In the example below, we want to log the same message on all early exits but a different one on
+/// the main exit path:
+/// ```
+/// # use kernel::ScopeGuard;
+/// fn example2(arg: bool) {
+///     let log = ScopeGuard::new(|| pr_info!("example2 returned early\n"));
+///
+///     if arg {
+///         return;
+///     }
+///
+///     // (Other early returns...)
+///
+///     log.dismiss();
+///     pr_info!("example2 no early return\n");
+/// }
+///
+/// # example2(false);
+/// # example2(true);
+/// ```
+///
+/// In the example below, we need a mutable object (the vector) to be accessible within the log
+/// function, so we wrap it in the [`ScopeGuard`]:
+/// ```
+/// # use kernel::ScopeGuard;
+/// fn example3(arg: bool) -> Result {
+///     let mut vec =
+///         ScopeGuard::new_with_data(Vec::new(), |v| pr_info!("vec had {} elements\n", v.len()));
+///
+///     vec.try_push(10u8)?;
+///     if arg {
+///         return Ok(());
+///     }
+///     vec.try_push(20u8)?;
+///     Ok(())
+/// }
+///
+/// # assert_eq!(example3(false), Ok(()));
+/// # assert_eq!(example3(true), Ok(()));
+/// ```
+///
+/// # Invariants
+///
+/// The value stored in the struct is nearly always `Some(_)`, except between
+/// [`ScopeGuard::dismiss`] and [`ScopeGuard::drop`]: in this case, it will be `None` as the value
+/// will have been returned to the caller. Since  [`ScopeGuard::dismiss`] consumes the guard,
+/// callers won't be able to use it anymore.
+pub struct ScopeGuard<T, F: FnOnce(T)>(Option<(T, F)>);
+
+impl<T, F: FnOnce(T)> ScopeGuard<T, F> {
+    /// Creates a new guarded object wrapping the given data and with the given cleanup function.
+    pub fn new_with_data(data: T, cleanup_func: F) -> Self {
+        // INVARIANT: The struct is being initialised with `Some(_)`.
+        Self(Some((data, cleanup_func)))
+    }
+
+    /// Prevents the cleanup function from running and returns the guarded data.
+    pub fn dismiss(mut self) -> T {
+        // INVARIANT: This is the exception case in the invariant; it is not visible to callers
+        // because this function consumes `self`.
+        self.0.take().unwrap().0
+    }
+}
+
+impl ScopeGuard<(), Box<dyn FnOnce(())>> {
+    /// Creates a new guarded object with the given cleanup function.
+    pub fn new(cleanup: impl FnOnce()) -> ScopeGuard<(), impl FnOnce(())> {
+        ScopeGuard::new_with_data((), move |_| cleanup())
+    }
+}
+
+impl<T, F: FnOnce(T)> Deref for ScopeGuard<T, F> {
+    type Target = T;
+
+    fn deref(&self) -> &T {
+        // The type invariants guarantee that `unwrap` will succeed.
+        &self.0.as_ref().unwrap().0
+    }
+}
+
+impl<T, F: FnOnce(T)> DerefMut for ScopeGuard<T, F> {
+    fn deref_mut(&mut self) -> &mut T {
+        // The type invariants guarantee that `unwrap` will succeed.
+        &mut self.0.as_mut().unwrap().0
+    }
+}
+
+impl<T, F: FnOnce(T)> Drop for ScopeGuard<T, F> {
+    fn drop(&mut self) {
+        // Run the cleanup function if one is still present.
+        if let Some((data, cleanup)) = self.0.take() {
+            cleanup(data)
+        }
+    }
+}
+
+/// Stores an opaque value.
+///
+/// This is meant to be used with FFI objects that are never interpreted by Rust code.
+pub struct Opaque<T>(MaybeUninit<UnsafeCell<T>>);
+
+impl<T> Opaque<T> {
+    /// Creates a new opaque value.
+    pub fn new(value: T) -> Self {
+        Self(MaybeUninit::new(UnsafeCell::new(value)))
+    }
+
+    /// Creates an uninitialised value.
+    pub const fn uninit() -> Self {
+        Self(MaybeUninit::uninit())
+    }
+
+    /// Returns a raw pointer to the opaque data.
+    pub fn get(&self) -> *mut T {
+        UnsafeCell::raw_get(self.0.as_ptr())
+    }
+}
+
+/// A bitmask.
+///
+/// It has a restriction that all bits must be the same, except one. For example, `0b1110111` and
+/// `0b1000` are acceptable masks.
+#[derive(Clone, Copy)]
+pub struct Bit<T> {
+    index: T,
+    inverted: bool,
+}
+
+/// Creates a bit mask with a single bit set.
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::bit;
+/// let mut x = 0xfeu32;
+///
+/// assert_eq!(x & bit(0), 0);
+/// assert_eq!(x & bit(1), 2);
+/// assert_eq!(x & bit(2), 4);
+/// assert_eq!(x & bit(3), 8);
+///
+/// x |= bit(0);
+/// assert_eq!(x, 0xff);
+///
+/// x &= !bit(1);
+/// assert_eq!(x, 0xfd);
+///
+/// x &= !bit(7);
+/// assert_eq!(x, 0x7d);
+///
+/// let y: u64 = bit(34).into();
+/// assert_eq!(y, 0x400000000);
+///
+/// assert_eq!(y | bit(35), 0xc00000000);
+/// ```
+pub fn bit<T: Copy>(index: T) -> Bit<T> {
+    Bit {
+        index,
+        inverted: false,
+    }
+}
+
+impl<T: Copy> ops::Not for Bit<T> {
+    type Output = Self;
+    fn not(self) -> Self {
+        Self {
+            index: self.index,
+            inverted: !self.inverted,
+        }
+    }
+}
+
+/// Implemented by integer types that allow counting the number of trailing zeroes.
+pub trait TrailingZeros {
+    /// Returns the number of trailing zeroes in the binary representation of `self`.
+    fn trailing_zeros(&self) -> u32;
+}
+
+macro_rules! define_unsigned_number_traits {
+    ($type_name:ty) => {
+        impl TrailingZeros for $type_name {
+            fn trailing_zeros(&self) -> u32 {
+                <$type_name>::trailing_zeros(*self)
+            }
+        }
+
+        impl<T: Copy> core::convert::From<Bit<T>> for $type_name
+        where
+            Self: ops::Shl<T, Output = Self> + core::convert::From<u8> + ops::Not<Output = Self>,
+        {
+            fn from(v: Bit<T>) -> Self {
+                let c = Self::from(1u8) << v.index;
+                if v.inverted {
+                    !c
+                } else {
+                    c
+                }
+            }
+        }
+
+        impl<T: Copy> ops::BitAnd<Bit<T>> for $type_name
+        where
+            Self: ops::Shl<T, Output = Self> + core::convert::From<u8>,
+        {
+            type Output = Self;
+            fn bitand(self, rhs: Bit<T>) -> Self::Output {
+                self & Self::from(rhs)
+            }
+        }
+
+        impl<T: Copy> ops::BitOr<Bit<T>> for $type_name
+        where
+            Self: ops::Shl<T, Output = Self> + core::convert::From<u8>,
+        {
+            type Output = Self;
+            fn bitor(self, rhs: Bit<T>) -> Self::Output {
+                self | Self::from(rhs)
+            }
+        }
+
+        impl<T: Copy> ops::BitAndAssign<Bit<T>> for $type_name
+        where
+            Self: ops::Shl<T, Output = Self> + core::convert::From<u8>,
+        {
+            fn bitand_assign(&mut self, rhs: Bit<T>) {
+                *self &= Self::from(rhs)
+            }
+        }
+
+        impl<T: Copy> ops::BitOrAssign<Bit<T>> for $type_name
+        where
+            Self: ops::Shl<T, Output = Self> + core::convert::From<u8>,
+        {
+            fn bitor_assign(&mut self, rhs: Bit<T>) {
+                *self |= Self::from(rhs)
+            }
+        }
+    };
+}
+
+define_unsigned_number_traits!(u8);
+define_unsigned_number_traits!(u16);
+define_unsigned_number_traits!(u32);
+define_unsigned_number_traits!(u64);
+define_unsigned_number_traits!(usize);
+
+/// Returns an iterator over the set bits of `value`.
+///
+/// # Examples
+///
+/// ```
+/// use kernel::bits_iter;
+///
+/// let mut iter = bits_iter(5usize);
+/// assert_eq!(iter.next().unwrap(), 0);
+/// assert_eq!(iter.next().unwrap(), 2);
+/// assert!(iter.next().is_none());
+/// ```
+///
+/// ```
+/// use kernel::bits_iter;
+///
+/// fn print_bits(x: usize) {
+///     for bit in bits_iter(x) {
+///         pr_info!("{}\n", bit);
+///     }
+/// }
+///
+/// # print_bits(42);
+/// ```
+#[inline]
+pub fn bits_iter<T>(value: T) -> impl Iterator<Item = u32>
+where
+    T: core::cmp::PartialEq
+        + From<u8>
+        + ops::Shl<u32, Output = T>
+        + ops::Not<Output = T>
+        + ops::BitAndAssign
+        + TrailingZeros,
+{
+    struct BitIterator<U> {
+        value: U,
+    }
+
+    impl<U> Iterator for BitIterator<U>
+    where
+        U: core::cmp::PartialEq
+            + From<u8>
+            + ops::Shl<u32, Output = U>
+            + ops::Not<Output = U>
+            + ops::BitAndAssign
+            + TrailingZeros,
+    {
+        type Item = u32;
+
+        #[inline]
+        fn next(&mut self) -> Option<u32> {
+            if self.value == U::from(0u8) {
+                return None;
+            }
+            let ret = self.value.trailing_zeros();
+            self.value &= !(U::from(1u8) << ret);
+            Some(ret)
+        }
+    }
+
+    BitIterator { value }
+}
+
+/// A trait for boolean types.
+///
+/// This is meant to be used in type states to allow boolean constraints in implementation blocks.
+/// In the example below, the implementation containing `MyType::set_value` could _not_ be
+/// constrained to type states containing `Writable = true` if `Writable` were a constant instead
+/// of a type.
+///
+/// # Safety
+///
+/// No additional implementations of [`Bool`] should be provided, as [`True`] and [`False`] are
+/// already provided.
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::{Bool, False, True};
+/// use core::marker::PhantomData;
+///
+/// // Type state specifies whether the type is writable.
+/// trait MyTypeState {
+///     type Writable: Bool;
+/// }
+///
+/// // In state S1, the type is writable.
+/// struct S1;
+/// impl MyTypeState for S1 {
+///     type Writable = True;
+/// }
+///
+/// // In state S2, the type is not writable.
+/// struct S2;
+/// impl MyTypeState for S2 {
+///     type Writable = False;
+/// }
+///
+/// struct MyType<T: MyTypeState> {
+///     value: u32,
+///     _p: PhantomData<T>,
+/// }
+///
+/// impl<T: MyTypeState> MyType<T> {
+///     fn new(value: u32) -> Self {
+///         Self {
+///             value,
+///             _p: PhantomData,
+///         }
+///     }
+/// }
+///
+/// // This implementation block only applies if the type state is writable.
+/// impl<T> MyType<T>
+/// where
+///     T: MyTypeState<Writable = True>,
+/// {
+///     fn set_value(&mut self, v: u32) {
+///         self.value = v;
+///     }
+/// }
+///
+/// let mut x = MyType::<S1>::new(10);
+/// let mut y = MyType::<S2>::new(20);
+///
+/// x.set_value(30);
+///
+/// // The code below fails to compile because `S2` is not writable.
+/// // y.set_value(40);
+/// ```
+pub unsafe trait Bool {}
+
+/// Represents the `true` value for types with [`Bool`] bound.
+pub struct True;
+
+// SAFETY: This is one of the only two implementations of `Bool`.
+unsafe impl Bool for True {}
+
+/// Represents the `false` value for types wth [`Bool`] bound.
+pub struct False;
+
+// SAFETY: This is one of the only two implementations of `Bool`.
+unsafe impl Bool for False {}
+
+/// Types that are _always_ reference counted.
+///
+/// It allows such types to define their own custom ref increment and decrement functions.
+/// Additionally, it allows users to convert from a shared reference `&T` to an owned reference
+/// [`ARef<T>`].
+///
+/// This is usually implemented by wrappers to existing structures on the C side of the code. For
+/// Rust code, the recommendation is to use [`Ref`] to create reference-counted instances of a
+/// type.
+///
+/// # Safety
+///
+/// Implementers must ensure that increments to the reference count keeps the object alive in
+/// memory at least until a matching decrement performed.
+///
+/// Implementers must also ensure that all instances are reference-counted. (Otherwise they
+/// won't be able to honour the requirement that [`AlwaysRefCounted::inc_ref`] keep the object
+/// alive.)
+pub unsafe trait AlwaysRefCounted {
+    /// Increments the reference count on the object.
+    fn inc_ref(&self);
+
+    /// Decrements the reference count on the object.
+    ///
+    /// Frees the object when the count reaches zero.
+    ///
+    /// # Safety
+    ///
+    /// Callers must ensure that there was a previous matching increment to the reference count,
+    /// and that the object is no longer used after its reference count is decremented (as it may
+    /// result in the object being freed), unless the caller owns another increment on the refcount
+    /// (e.g., it calls [`AlwaysRefCounted::inc_ref`] twice, then calls
+    /// [`AlwaysRefCounted::dec_ref`] once).
+    unsafe fn dec_ref(obj: NonNull<Self>);
+}
+
+/// An owned reference to an always-reference-counted object.
+///
+/// The object's reference count is automatically decremented when an instance of [`ARef`] is
+/// dropped. It is also automatically incremented when a new instance is created via
+/// [`ARef::clone`].
+///
+/// # Invariants
+///
+/// The pointer stored in `ptr` is non-null and valid for the lifetime of the [`ARef`] instance. In
+/// particular, the [`ARef`] instance owns an increment on underlying object's reference count.
+pub struct ARef<T: AlwaysRefCounted> {
+    ptr: NonNull<T>,
+    _p: PhantomData<T>,
+}
+
+impl<T: AlwaysRefCounted> ARef<T> {
+    /// Creates a new instance of [`ARef`].
+    ///
+    /// It takes over an increment of the reference count on the underlying object.
+    ///
+    /// # Safety
+    ///
+    /// Callers must ensure that the reference count was incremented at least once, and that they
+    /// are properly relinquishing one increment. That is, if there is only one increment, callers
+    /// must not use the underlying object anymore -- it is only safe to do so via the newly
+    /// created [`ARef`].
+    pub unsafe fn from_raw(ptr: NonNull<T>) -> Self {
+        // INVARIANT: The safety requirements guarantee that the new instance now owns the
+        // increment on the refcount.
+        Self {
+            ptr,
+            _p: PhantomData,
+        }
+    }
+}
+
+impl<T: AlwaysRefCounted> Clone for ARef<T> {
+    fn clone(&self) -> Self {
+        self.inc_ref();
+        // SAFETY: We just incremented the refcount above.
+        unsafe { Self::from_raw(self.ptr) }
+    }
+}
+
+impl<T: AlwaysRefCounted> Deref for ARef<T> {
+    type Target = T;
+
+    fn deref(&self) -> &Self::Target {
+        // SAFETY: The type invariants guarantee that the object is valid.
+        unsafe { self.ptr.as_ref() }
+    }
+}
+
+impl<T: AlwaysRefCounted> From<&T> for ARef<T> {
+    fn from(b: &T) -> Self {
+        b.inc_ref();
+        // SAFETY: We just incremented the refcount above.
+        unsafe { Self::from_raw(NonNull::from(b)) }
+    }
+}
+
+impl<T: AlwaysRefCounted> Drop for ARef<T> {
+    fn drop(&mut self) {
+        // SAFETY: The type invariants guarantee that the `ARef` owns the reference we're about to
+        // decrement.
+        unsafe { T::dec_ref(self.ptr) };
+    }
+}
diff --git a/rust/kernel/user_ptr.rs b/rust/kernel/user_ptr.rs
new file mode 100644
index 000000000000..8489e80923c7
--- /dev/null
+++ b/rust/kernel/user_ptr.rs
@@ -0,0 +1,175 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! User pointers.
+//!
+//! C header: [`include/linux/uaccess.h`](../../../../include/linux/uaccess.h)
+
+use crate::{
+    bindings, c_types,
+    error::code::*,
+    io_buffer::{IoBufferReader, IoBufferWriter},
+    Result,
+};
+use alloc::vec::Vec;
+
+/// A reference to an area in userspace memory, which can be either
+/// read-only or read-write.
+///
+/// All methods on this struct are safe: invalid pointers return
+/// `EFAULT`. Concurrent access, *including data races to/from userspace
+/// memory*, is permitted, because fundamentally another userspace
+/// thread/process could always be modifying memory at the same time
+/// (in the same way that userspace Rust's [`std::io`] permits data races
+/// with the contents of files on disk). In the presence of a race, the
+/// exact byte values read/written are unspecified but the operation is
+/// well-defined. Kernelspace code should validate its copy of data
+/// after completing a read, and not expect that multiple reads of the
+/// same address will return the same value.
+///
+/// All APIs enforce the invariant that a given byte of memory from userspace
+/// may only be read once. By preventing double-fetches we avoid TOCTOU
+/// vulnerabilities. This is accomplished by taking `self` by value to prevent
+/// obtaining multiple readers on a given [`UserSlicePtr`], and the readers
+/// only permitting forward reads.
+///
+/// Constructing a [`UserSlicePtr`] performs no checks on the provided
+/// address and length, it can safely be constructed inside a kernel thread
+/// with no current userspace process. Reads and writes wrap the kernel APIs
+/// `copy_from_user` and `copy_to_user`, which check the memory map of the
+/// current process and enforce that the address range is within the user
+/// range (no additional calls to `access_ok` are needed).
+///
+/// [`std::io`]: https://doc.rust-lang.org/std/io/index.html
+pub struct UserSlicePtr(*mut c_types::c_void, usize);
+
+impl UserSlicePtr {
+    /// Constructs a user slice from a raw pointer and a length in bytes.
+    ///
+    /// # Safety
+    ///
+    /// Callers must be careful to avoid time-of-check-time-of-use
+    /// (TOCTOU) issues. The simplest way is to create a single instance of
+    /// [`UserSlicePtr`] per user memory block as it reads each byte at
+    /// most once.
+    pub unsafe fn new(ptr: *mut c_types::c_void, length: usize) -> Self {
+        UserSlicePtr(ptr, length)
+    }
+
+    /// Reads the entirety of the user slice.
+    ///
+    /// Returns `EFAULT` if the address does not currently point to
+    /// mapped, readable memory.
+    pub fn read_all(self) -> Result<Vec<u8>> {
+        self.reader().read_all()
+    }
+
+    /// Constructs a [`UserSlicePtrReader`].
+    pub fn reader(self) -> UserSlicePtrReader {
+        UserSlicePtrReader(self.0, self.1)
+    }
+
+    /// Writes the provided slice into the user slice.
+    ///
+    /// Returns `EFAULT` if the address does not currently point to
+    /// mapped, writable memory (in which case some data from before the
+    /// fault may be written), or `data` is larger than the user slice
+    /// (in which case no data is written).
+    pub fn write_all(self, data: &[u8]) -> Result {
+        self.writer().write_slice(data)
+    }
+
+    /// Constructs a [`UserSlicePtrWriter`].
+    pub fn writer(self) -> UserSlicePtrWriter {
+        UserSlicePtrWriter(self.0, self.1)
+    }
+
+    /// Constructs both a [`UserSlicePtrReader`] and a [`UserSlicePtrWriter`].
+    pub fn reader_writer(self) -> (UserSlicePtrReader, UserSlicePtrWriter) {
+        (
+            UserSlicePtrReader(self.0, self.1),
+            UserSlicePtrWriter(self.0, self.1),
+        )
+    }
+}
+
+/// A reader for [`UserSlicePtr`].
+///
+/// Used to incrementally read from the user slice.
+pub struct UserSlicePtrReader(*mut c_types::c_void, usize);
+
+impl IoBufferReader for UserSlicePtrReader {
+    /// Returns the number of bytes left to be read from this.
+    ///
+    /// Note that even reading less than this number of bytes may fail.
+    fn len(&self) -> usize {
+        self.1
+    }
+
+    /// Reads raw data from the user slice into a raw kernel buffer.
+    ///
+    /// # Safety
+    ///
+    /// The output buffer must be valid.
+    unsafe fn read_raw(&mut self, out: *mut u8, len: usize) -> Result {
+        if len > self.1 || len > u32::MAX as usize {
+            return Err(EFAULT);
+        }
+        let res = unsafe { bindings::copy_from_user(out as _, self.0, len as _) };
+        if res != 0 {
+            return Err(EFAULT);
+        }
+        // Since this is not a pointer to a valid object in our program,
+        // we cannot use `add`, which has C-style rules for defined
+        // behavior.
+        self.0 = self.0.wrapping_add(len);
+        self.1 -= len;
+        Ok(())
+    }
+}
+
+/// A writer for [`UserSlicePtr`].
+///
+/// Used to incrementally write into the user slice.
+pub struct UserSlicePtrWriter(*mut c_types::c_void, usize);
+
+impl IoBufferWriter for UserSlicePtrWriter {
+    fn len(&self) -> usize {
+        self.1
+    }
+
+    fn clear(&mut self, mut len: usize) -> Result {
+        let mut ret = Ok(());
+        if len > self.1 {
+            ret = Err(EFAULT);
+            len = self.1;
+        }
+
+        // SAFETY: The buffer will be validated by `clear_user`. We ensure that `len` is within
+        // bounds in the check above.
+        let left = unsafe { bindings::clear_user(self.0, len as _) } as usize;
+        if left != 0 {
+            ret = Err(EFAULT);
+            len -= left;
+        }
+
+        self.0 = self.0.wrapping_add(len);
+        self.1 -= len;
+        ret
+    }
+
+    unsafe fn write_raw(&mut self, data: *const u8, len: usize) -> Result {
+        if len > self.1 || len > u32::MAX as usize {
+            return Err(EFAULT);
+        }
+        let res = unsafe { bindings::copy_to_user(self.0, data as _, len as _) };
+        if res != 0 {
+            return Err(EFAULT);
+        }
+        // Since this is not a pointer to a valid object in our program,
+        // we cannot use `add`, which has C-style rules for defined
+        // behavior.
+        self.0 = self.0.wrapping_add(len);
+        self.1 -= len;
+        Ok(())
+    }
+}
-- 
2.35.3


^ permalink raw reply related	[relevance 1%]

* [PATCH v6 20/23] samples: add Rust examples
    2022-05-07  5:24  1% ` [PATCH v6 12/23] rust: add `kernel` crate Miguel Ojeda
@ 2022-05-07  5:24  3% ` Miguel Ojeda
  1 sibling, 0 replies; 77+ results
From: Miguel Ojeda @ 2022-05-07  5:24 UTC (permalink / raw)
  To: Linus Torvalds, Greg Kroah-Hartman
  Cc: rust-for-linux, linux-kernel, Jarkko Sakkinen, Miguel Ojeda,
	Alex Gaynor, Finn Behrens, Wedson Almeida Filho,
	Sven Van Asbroeck, Gary Guo, Boris-Chengbiao Zhou, Ayaan Zaidi,
	Milan Landaverde

A set of Rust modules that showcase how Rust modules look like
and how to use the abstracted kernel features, as well as
an example of a Rust host program with several modules.

These samples also double as tests in the CI.

The semaphore sample comes with a C version for comparison.

Co-developed-by: Alex Gaynor <alex.gaynor@gmail.com>
Signed-off-by: Alex Gaynor <alex.gaynor@gmail.com>
Co-developed-by: Finn Behrens <me@kloenk.de>
Signed-off-by: Finn Behrens <me@kloenk.de>
Co-developed-by: Wedson Almeida Filho <wedsonaf@google.com>
Signed-off-by: Wedson Almeida Filho <wedsonaf@google.com>
Co-developed-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Co-developed-by: Sven Van Asbroeck <thesven73@gmail.com>
Signed-off-by: Sven Van Asbroeck <thesven73@gmail.com>
Co-developed-by: Gary Guo <gary@garyguo.net>
Signed-off-by: Gary Guo <gary@garyguo.net>
Co-developed-by: Boris-Chengbiao Zhou <bobo1239@web.de>
Signed-off-by: Boris-Chengbiao Zhou <bobo1239@web.de>
Co-developed-by: Ayaan Zaidi <zaidi.ayaan@gmail.com>
Signed-off-by: Ayaan Zaidi <zaidi.ayaan@gmail.com>
Co-developed-by: Milan Landaverde <milan@mdaverde.com>
Signed-off-by: Milan Landaverde <milan@mdaverde.com>
Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
---
 samples/Kconfig                        |   2 +
 samples/Makefile                       |   1 +
 samples/rust/Kconfig                   | 140 ++++++++++++++++
 samples/rust/Makefile                  |  16 ++
 samples/rust/hostprogs/.gitignore      |   3 +
 samples/rust/hostprogs/Makefile        |   5 +
 samples/rust/hostprogs/a.rs            |   7 +
 samples/rust/hostprogs/b.rs            |   5 +
 samples/rust/hostprogs/single.rs       |  12 ++
 samples/rust/rust_chrdev.rs            |  50 ++++++
 samples/rust/rust_minimal.rs           |  35 ++++
 samples/rust/rust_miscdev.rs           | 143 +++++++++++++++++
 samples/rust/rust_module_parameters.rs |  69 ++++++++
 samples/rust/rust_netfilter.rs         |  54 +++++++
 samples/rust/rust_platform.rs          |  22 +++
 samples/rust/rust_print.rs             |  54 +++++++
 samples/rust/rust_random.rs            |  60 +++++++
 samples/rust/rust_semaphore.rs         | 171 ++++++++++++++++++++
 samples/rust/rust_semaphore_c.c        | 212 +++++++++++++++++++++++++
 samples/rust/rust_stack_probing.rs     |  36 +++++
 samples/rust/rust_sync.rs              |  93 +++++++++++
 21 files changed, 1190 insertions(+)
 create mode 100644 samples/rust/Kconfig
 create mode 100644 samples/rust/Makefile
 create mode 100644 samples/rust/hostprogs/.gitignore
 create mode 100644 samples/rust/hostprogs/Makefile
 create mode 100644 samples/rust/hostprogs/a.rs
 create mode 100644 samples/rust/hostprogs/b.rs
 create mode 100644 samples/rust/hostprogs/single.rs
 create mode 100644 samples/rust/rust_chrdev.rs
 create mode 100644 samples/rust/rust_minimal.rs
 create mode 100644 samples/rust/rust_miscdev.rs
 create mode 100644 samples/rust/rust_module_parameters.rs
 create mode 100644 samples/rust/rust_netfilter.rs
 create mode 100644 samples/rust/rust_platform.rs
 create mode 100644 samples/rust/rust_print.rs
 create mode 100644 samples/rust/rust_random.rs
 create mode 100644 samples/rust/rust_semaphore.rs
 create mode 100644 samples/rust/rust_semaphore_c.c
 create mode 100644 samples/rust/rust_stack_probing.rs
 create mode 100644 samples/rust/rust_sync.rs

diff --git a/samples/Kconfig b/samples/Kconfig
index 470ee3baf2e1..0d81c00289ee 100644
--- a/samples/Kconfig
+++ b/samples/Kconfig
@@ -263,6 +263,8 @@ config SAMPLE_CORESIGHT_SYSCFG
 	  This demonstrates how a user may create their own CoreSight
 	  configurations and easily load them into the system at runtime.
 
+source "samples/rust/Kconfig"
+
 endif # SAMPLES
 
 config HAVE_SAMPLE_FTRACE_DIRECT
diff --git a/samples/Makefile b/samples/Makefile
index 701e912ab5af..9832ef3f8fcb 100644
--- a/samples/Makefile
+++ b/samples/Makefile
@@ -35,3 +35,4 @@ subdir-$(CONFIG_SAMPLE_WATCH_QUEUE)	+= watch_queue
 obj-$(CONFIG_DEBUG_KMEMLEAK_TEST)	+= kmemleak/
 obj-$(CONFIG_SAMPLE_CORESIGHT_SYSCFG)	+= coresight/
 obj-$(CONFIG_SAMPLE_FPROBE)		+= fprobe/
+obj-$(CONFIG_SAMPLES_RUST)		+= rust/
diff --git a/samples/rust/Kconfig b/samples/rust/Kconfig
new file mode 100644
index 000000000000..4f90f8d69351
--- /dev/null
+++ b/samples/rust/Kconfig
@@ -0,0 +1,140 @@
+# SPDX-License-Identifier: GPL-2.0
+
+menuconfig SAMPLES_RUST
+	bool "Rust samples"
+	depends on RUST
+	help
+	  You can build sample Rust kernel code here.
+
+	  If unsure, say N.
+
+if SAMPLES_RUST
+
+config SAMPLE_RUST_MINIMAL
+	tristate "Minimal"
+	help
+	  This option builds the Rust minimal module sample.
+
+	  To compile this as a module, choose M here:
+	  the module will be called rust_minimal.
+
+	  If unsure, say N.
+
+config SAMPLE_RUST_PRINT
+	tristate "Printing macros"
+	help
+	  This option builds the Rust printing macros sample.
+
+	  To compile this as a module, choose M here:
+	  the module will be called rust_print.
+
+	  If unsure, say N.
+
+config SAMPLE_RUST_MODULE_PARAMETERS
+	tristate "Module parameters"
+	help
+	  This option builds the Rust module parameters sample.
+
+	  To compile this as a module, choose M here:
+	  the module will be called rust_module_parameters.
+
+	  If unsure, say N.
+
+config SAMPLE_RUST_SYNC
+	tristate "Synchronisation primitives"
+	help
+	  This option builds the Rust synchronisation primitives sample.
+
+	  To compile this as a module, choose M here:
+	  the module will be called rust_sync.
+
+	  If unsure, say N.
+
+config SAMPLE_RUST_CHRDEV
+	tristate "Character device"
+	help
+	  This option builds the Rust character device sample.
+
+	  To compile this as a module, choose M here:
+	  the module will be called rust_chrdev.
+
+	  If unsure, say N.
+
+config SAMPLE_RUST_MISCDEV
+	tristate "Miscellaneous device"
+	help
+	  This option builds the Rust miscellaneous device sample.
+
+	  To compile this as a module, choose M here:
+	  the module will be called rust_miscdev.
+
+	  If unsure, say N.
+
+config SAMPLE_RUST_STACK_PROBING
+	tristate "Stack probing"
+	help
+	  This option builds the Rust stack probing sample.
+
+	  To compile this as a module, choose M here:
+	  the module will be called rust_stack_probing.
+
+	  If unsure, say N.
+
+config SAMPLE_RUST_SEMAPHORE
+	tristate "Semaphore"
+	help
+	  This option builds the Rust semaphore sample.
+
+	  To compile this as a module, choose M here:
+	  the module will be called rust_semaphore.
+
+	  If unsure, say N.
+
+config SAMPLE_RUST_SEMAPHORE_C
+	tristate "Semaphore (in C, for comparison)"
+	help
+	  This option builds the Rust semaphore sample (in C, for comparison).
+
+	  To compile this as a module, choose M here:
+	  the module will be called rust_semaphore_c.
+
+	  If unsure, say N.
+
+config SAMPLE_RUST_RANDOM
+	tristate "Random"
+	help
+	  This option builds the Rust random sample.
+
+	  To compile this as a module, choose M here:
+	  the module will be called rust_random.
+
+	  If unsure, say N.
+
+config SAMPLE_RUST_PLATFORM
+	tristate "Platform device driver"
+	help
+	  This option builds the Rust platform device driver sample.
+
+	  To compile this as a module, choose M here:
+	  the module will be called rust_platform.
+
+	  If unsure, say N.
+
+config SAMPLE_RUST_NETFILTER
+	tristate "Network filter module"
+	help
+	  This option builds the Rust netfilter module sample.
+
+	  To compile this as a module, choose M here:
+	  the module will be called rust_netfilter.
+
+	  If unsure, say N.
+
+config SAMPLE_RUST_HOSTPROGS
+	bool "Host programs"
+	help
+	  This option builds the Rust host program samples.
+
+	  If unsure, say N.
+
+endif # SAMPLES_RUST
diff --git a/samples/rust/Makefile b/samples/rust/Makefile
new file mode 100644
index 000000000000..fb5a205ebb8c
--- /dev/null
+++ b/samples/rust/Makefile
@@ -0,0 +1,16 @@
+# SPDX-License-Identifier: GPL-2.0
+
+obj-$(CONFIG_SAMPLE_RUST_MINIMAL)		+= rust_minimal.o
+obj-$(CONFIG_SAMPLE_RUST_PRINT)			+= rust_print.o
+obj-$(CONFIG_SAMPLE_RUST_MODULE_PARAMETERS)	+= rust_module_parameters.o
+obj-$(CONFIG_SAMPLE_RUST_SYNC)			+= rust_sync.o
+obj-$(CONFIG_SAMPLE_RUST_CHRDEV)		+= rust_chrdev.o
+obj-$(CONFIG_SAMPLE_RUST_MISCDEV)		+= rust_miscdev.o
+obj-$(CONFIG_SAMPLE_RUST_STACK_PROBING)		+= rust_stack_probing.o
+obj-$(CONFIG_SAMPLE_RUST_SEMAPHORE)		+= rust_semaphore.o
+obj-$(CONFIG_SAMPLE_RUST_SEMAPHORE_C)		+= rust_semaphore_c.o
+obj-$(CONFIG_SAMPLE_RUST_RANDOM)		+= rust_random.o
+obj-$(CONFIG_SAMPLE_RUST_PLATFORM)		+= rust_platform.o
+obj-$(CONFIG_SAMPLE_RUST_NETFILTER)		+= rust_netfilter.o
+
+subdir-$(CONFIG_SAMPLE_RUST_HOSTPROGS)		+= hostprogs
diff --git a/samples/rust/hostprogs/.gitignore b/samples/rust/hostprogs/.gitignore
new file mode 100644
index 000000000000..a6c173da5048
--- /dev/null
+++ b/samples/rust/hostprogs/.gitignore
@@ -0,0 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0
+
+single
diff --git a/samples/rust/hostprogs/Makefile b/samples/rust/hostprogs/Makefile
new file mode 100644
index 000000000000..8ddcbd7416db
--- /dev/null
+++ b/samples/rust/hostprogs/Makefile
@@ -0,0 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0
+
+hostprogs-always-y := single
+
+single-rust := y
diff --git a/samples/rust/hostprogs/a.rs b/samples/rust/hostprogs/a.rs
new file mode 100644
index 000000000000..f7a4a3d0f4e0
--- /dev/null
+++ b/samples/rust/hostprogs/a.rs
@@ -0,0 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Rust single host program sample: module `a`.
+
+pub(crate) fn f(x: i32) {
+    println!("The number is {}.", x);
+}
diff --git a/samples/rust/hostprogs/b.rs b/samples/rust/hostprogs/b.rs
new file mode 100644
index 000000000000..c1675890648f
--- /dev/null
+++ b/samples/rust/hostprogs/b.rs
@@ -0,0 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Rust single host program sample: module `b`.
+
+pub(crate) const CONSTANT: i32 = 42;
diff --git a/samples/rust/hostprogs/single.rs b/samples/rust/hostprogs/single.rs
new file mode 100644
index 000000000000..8c48a119339a
--- /dev/null
+++ b/samples/rust/hostprogs/single.rs
@@ -0,0 +1,12 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Rust single host program sample.
+
+mod a;
+mod b;
+
+fn main() {
+    println!("Hello world!");
+
+    a::f(b::CONSTANT);
+}
diff --git a/samples/rust/rust_chrdev.rs b/samples/rust/rust_chrdev.rs
new file mode 100644
index 000000000000..2e49c0056f59
--- /dev/null
+++ b/samples/rust/rust_chrdev.rs
@@ -0,0 +1,50 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Rust character device sample.
+
+use kernel::prelude::*;
+use kernel::{chrdev, file};
+
+module! {
+    type: RustChrdev,
+    name: b"rust_chrdev",
+    author: b"Rust for Linux Contributors",
+    description: b"Rust character device sample",
+    license: b"GPL v2",
+}
+
+struct RustFile;
+
+impl file::Operations for RustFile {
+    kernel::declare_file_operations!();
+
+    fn open(_shared: &(), _file: &file::File) -> Result {
+        Ok(())
+    }
+}
+
+struct RustChrdev {
+    _dev: Pin<Box<chrdev::Registration<2>>>,
+}
+
+impl kernel::Module for RustChrdev {
+    fn init(name: &'static CStr, module: &'static ThisModule) -> Result<Self> {
+        pr_info!("Rust character device sample (init)\n");
+
+        let mut chrdev_reg = chrdev::Registration::new_pinned(name, 0, module)?;
+
+        // Register the same kind of device twice, we're just demonstrating
+        // that you can use multiple minors. There are two minors in this case
+        // because its type is `chrdev::Registration<2>`
+        chrdev_reg.as_mut().register::<RustFile>()?;
+        chrdev_reg.as_mut().register::<RustFile>()?;
+
+        Ok(RustChrdev { _dev: chrdev_reg })
+    }
+}
+
+impl Drop for RustChrdev {
+    fn drop(&mut self) {
+        pr_info!("Rust character device sample (exit)\n");
+    }
+}
diff --git a/samples/rust/rust_minimal.rs b/samples/rust/rust_minimal.rs
new file mode 100644
index 000000000000..83524f05bc35
--- /dev/null
+++ b/samples/rust/rust_minimal.rs
@@ -0,0 +1,35 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Rust minimal sample.
+
+use kernel::prelude::*;
+
+module! {
+    type: RustMinimal,
+    name: b"rust_minimal",
+    author: b"Rust for Linux Contributors",
+    description: b"Rust minimal sample",
+    license: b"GPL v2",
+}
+
+struct RustMinimal {
+    message: String,
+}
+
+impl kernel::Module for RustMinimal {
+    fn init(_name: &'static CStr, _module: &'static ThisModule) -> Result<Self> {
+        pr_info!("Rust minimal sample (init)\n");
+        pr_info!("Am I built-in? {}\n", !cfg!(MODULE));
+
+        Ok(RustMinimal {
+            message: "on the heap!".try_to_owned()?,
+        })
+    }
+}
+
+impl Drop for RustMinimal {
+    fn drop(&mut self) {
+        pr_info!("My message is {}\n", self.message);
+        pr_info!("Rust minimal sample (exit)\n");
+    }
+}
diff --git a/samples/rust/rust_miscdev.rs b/samples/rust/rust_miscdev.rs
new file mode 100644
index 000000000000..079dc61b193f
--- /dev/null
+++ b/samples/rust/rust_miscdev.rs
@@ -0,0 +1,143 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Rust miscellaneous device sample.
+
+use kernel::prelude::*;
+use kernel::{
+    file::{self, File},
+    io_buffer::{IoBufferReader, IoBufferWriter},
+    miscdev,
+    sync::{CondVar, Mutex, Ref, RefBorrow, UniqueRef},
+};
+
+module! {
+    type: RustMiscdev,
+    name: b"rust_miscdev",
+    author: b"Rust for Linux Contributors",
+    description: b"Rust miscellaneous device sample",
+    license: b"GPL v2",
+}
+
+const MAX_TOKENS: usize = 3;
+
+struct SharedStateInner {
+    token_count: usize,
+}
+
+struct SharedState {
+    state_changed: CondVar,
+    inner: Mutex<SharedStateInner>,
+}
+
+impl SharedState {
+    fn try_new() -> Result<Ref<Self>> {
+        let mut state = Pin::from(UniqueRef::try_new(Self {
+            // SAFETY: `condvar_init!` is called below.
+            state_changed: unsafe { CondVar::new() },
+            // SAFETY: `mutex_init!` is called below.
+            inner: unsafe { Mutex::new(SharedStateInner { token_count: 0 }) },
+        })?);
+
+        // SAFETY: `state_changed` is pinned when `state` is.
+        let pinned = unsafe { state.as_mut().map_unchecked_mut(|s| &mut s.state_changed) };
+        kernel::condvar_init!(pinned, "SharedState::state_changed");
+
+        // SAFETY: `inner` is pinned when `state` is.
+        let pinned = unsafe { state.as_mut().map_unchecked_mut(|s| &mut s.inner) };
+        kernel::mutex_init!(pinned, "SharedState::inner");
+
+        Ok(state.into())
+    }
+}
+
+struct Token;
+impl file::Operations for Token {
+    type Data = Ref<SharedState>;
+    type OpenData = Ref<SharedState>;
+
+    kernel::declare_file_operations!(read, write);
+
+    fn open(shared: &Ref<SharedState>, _file: &File) -> Result<Self::Data> {
+        Ok(shared.clone())
+    }
+
+    fn read(
+        shared: RefBorrow<'_, SharedState>,
+        _: &File,
+        data: &mut impl IoBufferWriter,
+        offset: u64,
+    ) -> Result<usize> {
+        // Succeed if the caller doesn't provide a buffer or if not at the start.
+        if data.is_empty() || offset != 0 {
+            return Ok(0);
+        }
+
+        {
+            let mut inner = shared.inner.lock();
+
+            // Wait until we are allowed to decrement the token count or a signal arrives.
+            while inner.token_count == 0 {
+                if shared.state_changed.wait(&mut inner) {
+                    return Err(EINTR);
+                }
+            }
+
+            // Consume a token.
+            inner.token_count -= 1;
+        }
+
+        // Notify a possible writer waiting.
+        shared.state_changed.notify_all();
+
+        // Write a one-byte 1 to the reader.
+        data.write_slice(&[1u8; 1])?;
+        Ok(1)
+    }
+
+    fn write(
+        shared: RefBorrow<'_, SharedState>,
+        _: &File,
+        data: &mut impl IoBufferReader,
+        _offset: u64,
+    ) -> Result<usize> {
+        {
+            let mut inner = shared.inner.lock();
+
+            // Wait until we are allowed to increment the token count or a signal arrives.
+            while inner.token_count == MAX_TOKENS {
+                if shared.state_changed.wait(&mut inner) {
+                    return Err(EINTR);
+                }
+            }
+
+            // Increment the number of token so that a reader can be released.
+            inner.token_count += 1;
+        }
+
+        // Notify a possible reader waiting.
+        shared.state_changed.notify_all();
+        Ok(data.len())
+    }
+}
+
+struct RustMiscdev {
+    _dev: Pin<Box<miscdev::Registration<Token>>>,
+}
+
+impl kernel::Module for RustMiscdev {
+    fn init(name: &'static CStr, _module: &'static ThisModule) -> Result<Self> {
+        pr_info!("Rust miscellaneous device sample (init)\n");
+
+        let state = SharedState::try_new()?;
+
+        Ok(RustMiscdev {
+            _dev: miscdev::Registration::new_pinned(fmt!("{name}"), state)?,
+        })
+    }
+}
+
+impl Drop for RustMiscdev {
+    fn drop(&mut self) {
+        pr_info!("Rust miscellaneous device sample (exit)\n");
+    }
+}
diff --git a/samples/rust/rust_module_parameters.rs b/samples/rust/rust_module_parameters.rs
new file mode 100644
index 000000000000..6ccb1be7700f
--- /dev/null
+++ b/samples/rust/rust_module_parameters.rs
@@ -0,0 +1,69 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Rust module parameters sample.
+
+use kernel::prelude::*;
+
+module! {
+    type: RustModuleParameters,
+    name: b"rust_module_parameters",
+    author: b"Rust for Linux Contributors",
+    description: b"Rust module parameters sample",
+    license: b"GPL v2",
+    params: {
+        my_bool: bool {
+            default: true,
+            permissions: 0,
+            description: b"Example of bool",
+        },
+        my_i32: i32 {
+            default: 42,
+            permissions: 0o644,
+            description: b"Example of i32",
+        },
+        my_str: str {
+            default: b"default str val",
+            permissions: 0o644,
+            description: b"Example of a string param",
+        },
+        my_usize: usize {
+            default: 42,
+            permissions: 0o644,
+            description: b"Example of usize",
+        },
+        my_array: ArrayParam<i32, 3> {
+            default: [0, 1],
+            permissions: 0,
+            description: b"Example of array",
+        },
+    },
+}
+
+struct RustModuleParameters;
+
+impl kernel::Module for RustModuleParameters {
+    fn init(_name: &'static CStr, module: &'static ThisModule) -> Result<Self> {
+        pr_info!("Rust module parameters sample (init)\n");
+
+        {
+            let lock = module.kernel_param_lock();
+            pr_info!("Parameters:\n");
+            pr_info!("  my_bool:    {}\n", my_bool.read());
+            pr_info!("  my_i32:     {}\n", my_i32.read(&lock));
+            pr_info!(
+                "  my_str:     {}\n",
+                core::str::from_utf8(my_str.read(&lock))?
+            );
+            pr_info!("  my_usize:   {}\n", my_usize.read(&lock));
+            pr_info!("  my_array:   {:?}\n", my_array.read());
+        }
+
+        Ok(RustModuleParameters)
+    }
+}
+
+impl Drop for RustModuleParameters {
+    fn drop(&mut self) {
+        pr_info!("Rust module parameters sample (exit)\n");
+    }
+}
diff --git a/samples/rust/rust_netfilter.rs b/samples/rust/rust_netfilter.rs
new file mode 100644
index 000000000000..363a65bfee20
--- /dev/null
+++ b/samples/rust/rust_netfilter.rs
@@ -0,0 +1,54 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Rust netfilter sample.
+
+use kernel::net;
+use kernel::net::filter::{self as netfilter, inet, Disposition, Family};
+use kernel::prelude::*;
+
+module! {
+    type: RustNetfilter,
+    name: b"rust_netfilter",
+    author: b"Rust for Linux Contributors",
+    description: b"Rust netfilter sample",
+    license: b"GPL v2",
+}
+
+struct RustNetfilter {
+    _in: Pin<Box<netfilter::Registration<Self>>>,
+    _out: Pin<Box<netfilter::Registration<Self>>>,
+}
+
+impl netfilter::Filter for RustNetfilter {
+    fn filter(_: (), skb: &net::SkBuff) -> Disposition {
+        let data = skb.head_data();
+        pr_info!(
+            "packet headlen={}, len={}, first bytes={:02x?}\n",
+            data.len(),
+            skb.len(),
+            &data[..core::cmp::min(10, data.len())]
+        );
+        Disposition::Accept
+    }
+}
+
+impl kernel::Module for RustNetfilter {
+    fn init(_name: &'static CStr, _module: &'static ThisModule) -> Result<Self> {
+        Ok(Self {
+            _in: netfilter::Registration::new_pinned(
+                Family::INet(inet::Hook::PreRouting),
+                0,
+                net::init_ns().into(),
+                None,
+                (),
+            )?,
+            _out: netfilter::Registration::new_pinned(
+                Family::INet(inet::Hook::PostRouting),
+                0,
+                net::init_ns().into(),
+                None,
+                (),
+            )?,
+        })
+    }
+}
diff --git a/samples/rust/rust_platform.rs b/samples/rust/rust_platform.rs
new file mode 100644
index 000000000000..c0b740094c59
--- /dev/null
+++ b/samples/rust/rust_platform.rs
@@ -0,0 +1,22 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Rust platform device driver sample.
+
+use kernel::{module_platform_driver, of, platform, prelude::*};
+
+module_platform_driver! {
+    type: Driver,
+    name: b"rust_platform",
+    license: b"GPL v2",
+}
+
+struct Driver;
+impl platform::Driver for Driver {
+    kernel::define_of_id_table! {(), [
+        (of::DeviceId::Compatible(b"rust,sample"), None),
+    ]}
+
+    fn probe(_dev: &mut platform::Device, _id_info: Option<&Self::IdInfo>) -> Result {
+        Ok(())
+    }
+}
diff --git a/samples/rust/rust_print.rs b/samples/rust/rust_print.rs
new file mode 100644
index 000000000000..dcc3ca9b84d4
--- /dev/null
+++ b/samples/rust/rust_print.rs
@@ -0,0 +1,54 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Rust printing macros sample.
+
+use kernel::prelude::*;
+use kernel::{pr_cont, str::CStr, ThisModule};
+
+module! {
+    type: RustPrint,
+    name: b"rust_print",
+    author: b"Rust for Linux Contributors",
+    description: b"Rust printing macros sample",
+    license: b"GPL v2",
+}
+
+struct RustPrint;
+
+impl kernel::Module for RustPrint {
+    fn init(_name: &'static CStr, _module: &'static ThisModule) -> Result<Self> {
+        pr_info!("Rust printing macros sample (init)\n");
+
+        pr_emerg!("Emergency message (level 0) without args\n");
+        pr_alert!("Alert message (level 1) without args\n");
+        pr_crit!("Critical message (level 2) without args\n");
+        pr_err!("Error message (level 3) without args\n");
+        pr_warn!("Warning message (level 4) without args\n");
+        pr_notice!("Notice message (level 5) without args\n");
+        pr_info!("Info message (level 6) without args\n");
+
+        pr_info!("A line that");
+        pr_cont!(" is continued");
+        pr_cont!(" without args\n");
+
+        pr_emerg!("{} message (level {}) with args\n", "Emergency", 0);
+        pr_alert!("{} message (level {}) with args\n", "Alert", 1);
+        pr_crit!("{} message (level {}) with args\n", "Critical", 2);
+        pr_err!("{} message (level {}) with args\n", "Error", 3);
+        pr_warn!("{} message (level {}) with args\n", "Warning", 4);
+        pr_notice!("{} message (level {}) with args\n", "Notice", 5);
+        pr_info!("{} message (level {}) with args\n", "Info", 6);
+
+        pr_info!("A {} that", "line");
+        pr_cont!(" is {}", "continued");
+        pr_cont!(" with {}\n", "args");
+
+        Ok(RustPrint)
+    }
+}
+
+impl Drop for RustPrint {
+    fn drop(&mut self) {
+        pr_info!("Rust printing macros sample (exit)\n");
+    }
+}
diff --git a/samples/rust/rust_random.rs b/samples/rust/rust_random.rs
new file mode 100644
index 000000000000..241fbbfb8673
--- /dev/null
+++ b/samples/rust/rust_random.rs
@@ -0,0 +1,60 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Rust random device.
+//!
+//! Adapted from Alex Gaynor's original available at
+//! <https://github.com/alex/just-use/blob/master/src/lib.rs>.
+
+use kernel::{
+    file::{self, File},
+    io_buffer::{IoBufferReader, IoBufferWriter},
+    prelude::*,
+};
+
+struct RandomFile;
+
+impl file::Operations for RandomFile {
+    kernel::declare_file_operations!(read, write, read_iter, write_iter);
+
+    fn open(_data: &(), _file: &File) -> Result {
+        Ok(())
+    }
+
+    fn read(_this: (), file: &File, buf: &mut impl IoBufferWriter, _: u64) -> Result<usize> {
+        let total_len = buf.len();
+        let mut chunkbuf = [0; 256];
+
+        while !buf.is_empty() {
+            let len = chunkbuf.len().min(buf.len());
+            let chunk = &mut chunkbuf[0..len];
+
+            if file.is_blocking() {
+                kernel::random::getrandom(chunk)?;
+            } else {
+                kernel::random::getrandom_nonblock(chunk)?;
+            }
+            buf.write_slice(chunk)?;
+        }
+        Ok(total_len)
+    }
+
+    fn write(_this: (), _file: &File, buf: &mut impl IoBufferReader, _: u64) -> Result<usize> {
+        let total_len = buf.len();
+        let mut chunkbuf = [0; 256];
+        while !buf.is_empty() {
+            let len = chunkbuf.len().min(buf.len());
+            let chunk = &mut chunkbuf[0..len];
+            buf.read_slice(chunk)?;
+            kernel::random::add_randomness(chunk);
+        }
+        Ok(total_len)
+    }
+}
+
+module_misc_device! {
+    type: RandomFile,
+    name: b"rust_random",
+    author: b"Rust for Linux Contributors",
+    description: b"Just use /dev/urandom: Now with early-boot safety",
+    license: b"GPL v2",
+}
diff --git a/samples/rust/rust_semaphore.rs b/samples/rust/rust_semaphore.rs
new file mode 100644
index 000000000000..01230cd45961
--- /dev/null
+++ b/samples/rust/rust_semaphore.rs
@@ -0,0 +1,171 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Rust semaphore sample.
+//!
+//! A counting semaphore that can be used by userspace.
+//!
+//! The count is incremented by writes to the device. A write of `n` bytes results in an increment
+//! of `n`. It is decremented by reads; each read results in the count being decremented by 1. If
+//! the count is already zero, a read will block until another write increments it.
+//!
+//! This can be used in user space from the shell for example  as follows (assuming a node called
+//! `semaphore`): `cat semaphore` decrements the count by 1 (waiting for it to become non-zero
+//! before decrementing); `echo -n 123 > semaphore` increments the semaphore by 3, potentially
+//! unblocking up to 3 blocked readers.
+
+use core::sync::atomic::{AtomicU64, Ordering};
+use kernel::{
+    condvar_init, declare_file_operations,
+    file::{self, File, IoctlCommand, IoctlHandler},
+    io_buffer::{IoBufferReader, IoBufferWriter},
+    miscdev::Registration,
+    mutex_init,
+    prelude::*,
+    sync::{CondVar, Mutex, Ref, UniqueRef},
+    user_ptr::{UserSlicePtrReader, UserSlicePtrWriter},
+};
+
+module! {
+    type: RustSemaphore,
+    name: b"rust_semaphore",
+    author: b"Rust for Linux Contributors",
+    description: b"Rust semaphore sample",
+    license: b"GPL v2",
+}
+
+struct SemaphoreInner {
+    count: usize,
+    max_seen: usize,
+}
+
+struct Semaphore {
+    changed: CondVar,
+    inner: Mutex<SemaphoreInner>,
+}
+
+struct FileState {
+    read_count: AtomicU64,
+    shared: Ref<Semaphore>,
+}
+
+impl FileState {
+    fn consume(&self) -> Result {
+        let mut inner = self.shared.inner.lock();
+        while inner.count == 0 {
+            if self.shared.changed.wait(&mut inner) {
+                return Err(EINTR);
+            }
+        }
+        inner.count -= 1;
+        Ok(())
+    }
+}
+
+impl file::Operations for FileState {
+    type Data = Box<Self>;
+    type OpenData = Ref<Semaphore>;
+
+    declare_file_operations!(read, write, ioctl);
+
+    fn open(shared: &Ref<Semaphore>, _file: &File) -> Result<Box<Self>> {
+        Ok(Box::try_new(Self {
+            read_count: AtomicU64::new(0),
+            shared: shared.clone(),
+        })?)
+    }
+
+    fn read(this: &Self, _: &File, data: &mut impl IoBufferWriter, offset: u64) -> Result<usize> {
+        if data.is_empty() || offset > 0 {
+            return Ok(0);
+        }
+        this.consume()?;
+        data.write_slice(&[0u8; 1])?;
+        this.read_count.fetch_add(1, Ordering::Relaxed);
+        Ok(1)
+    }
+
+    fn write(this: &Self, _: &File, data: &mut impl IoBufferReader, _offs: u64) -> Result<usize> {
+        {
+            let mut inner = this.shared.inner.lock();
+            inner.count = inner.count.saturating_add(data.len());
+            if inner.count > inner.max_seen {
+                inner.max_seen = inner.count;
+            }
+        }
+
+        this.shared.changed.notify_all();
+        Ok(data.len())
+    }
+
+    fn ioctl(this: &Self, file: &File, cmd: &mut IoctlCommand) -> Result<i32> {
+        cmd.dispatch::<Self>(this, file)
+    }
+}
+
+struct RustSemaphore {
+    _dev: Pin<Box<Registration<FileState>>>,
+}
+
+impl kernel::Module for RustSemaphore {
+    fn init(name: &'static CStr, _module: &'static ThisModule) -> Result<Self> {
+        pr_info!("Rust semaphore sample (init)\n");
+
+        let mut sema = Pin::from(UniqueRef::try_new(Semaphore {
+            // SAFETY: `condvar_init!` is called below.
+            changed: unsafe { CondVar::new() },
+
+            // SAFETY: `mutex_init!` is called below.
+            inner: unsafe {
+                Mutex::new(SemaphoreInner {
+                    count: 0,
+                    max_seen: 0,
+                })
+            },
+        })?);
+
+        // SAFETY: `changed` is pinned when `sema` is.
+        let pinned = unsafe { sema.as_mut().map_unchecked_mut(|s| &mut s.changed) };
+        condvar_init!(pinned, "Semaphore::changed");
+
+        // SAFETY: `inner` is pinned when `sema` is.
+        let pinned = unsafe { sema.as_mut().map_unchecked_mut(|s| &mut s.inner) };
+        mutex_init!(pinned, "Semaphore::inner");
+
+        Ok(Self {
+            _dev: Registration::new_pinned(fmt!("{name}"), sema.into())?,
+        })
+    }
+}
+
+impl Drop for RustSemaphore {
+    fn drop(&mut self) {
+        pr_info!("Rust semaphore sample (exit)\n");
+    }
+}
+
+const IOCTL_GET_READ_COUNT: u32 = 0x80086301;
+const IOCTL_SET_READ_COUNT: u32 = 0x40086301;
+
+impl IoctlHandler for FileState {
+    type Target<'a> = &'a Self;
+
+    fn read(this: &Self, _: &File, cmd: u32, writer: &mut UserSlicePtrWriter) -> Result<i32> {
+        match cmd {
+            IOCTL_GET_READ_COUNT => {
+                writer.write(&this.read_count.load(Ordering::Relaxed))?;
+                Ok(0)
+            }
+            _ => Err(EINVAL),
+        }
+    }
+
+    fn write(this: &Self, _: &File, cmd: u32, reader: &mut UserSlicePtrReader) -> Result<i32> {
+        match cmd {
+            IOCTL_SET_READ_COUNT => {
+                this.read_count.store(reader.read()?, Ordering::Relaxed);
+                Ok(0)
+            }
+            _ => Err(EINVAL),
+        }
+    }
+}
diff --git a/samples/rust/rust_semaphore_c.c b/samples/rust/rust_semaphore_c.c
new file mode 100644
index 000000000000..cdc121d4030d
--- /dev/null
+++ b/samples/rust/rust_semaphore_c.c
@@ -0,0 +1,212 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Rust semaphore sample (in C, for comparison)
+ *
+ * This is a C implementation of `rust_semaphore.rs`. Refer to the description
+ * in that file for details on the device.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/miscdevice.h>
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/slab.h>
+#include <linux/refcount.h>
+#include <linux/wait.h>
+
+#define IOCTL_GET_READ_COUNT _IOR('c', 1, u64)
+#define IOCTL_SET_READ_COUNT _IOW('c', 1, u64)
+
+struct semaphore_state {
+	struct kref ref;
+	struct miscdevice miscdev;
+	wait_queue_head_t changed;
+	struct mutex mutex;
+	size_t count;
+	size_t max_seen;
+};
+
+struct file_state {
+	atomic64_t read_count;
+	struct semaphore_state *shared;
+};
+
+static int semaphore_consume(struct semaphore_state *state)
+{
+	DEFINE_WAIT(wait);
+
+	mutex_lock(&state->mutex);
+	while (state->count == 0) {
+		prepare_to_wait(&state->changed, &wait, TASK_INTERRUPTIBLE);
+		mutex_unlock(&state->mutex);
+		schedule();
+		finish_wait(&state->changed, &wait);
+		if (signal_pending(current))
+			return -EINTR;
+		mutex_lock(&state->mutex);
+	}
+
+	state->count--;
+	mutex_unlock(&state->mutex);
+
+	return 0;
+}
+
+static int semaphore_open(struct inode *nodp, struct file *filp)
+{
+	struct semaphore_state *shared =
+		container_of(filp->private_data, struct semaphore_state, miscdev);
+	struct file_state *state;
+
+	state = kzalloc(sizeof(*state), GFP_KERNEL);
+	if (!state)
+		return -ENOMEM;
+
+	kref_get(&shared->ref);
+	state->shared = shared;
+	atomic64_set(&state->read_count, 0);
+
+	filp->private_data = state;
+
+	return 0;
+}
+
+static ssize_t semaphore_write(struct file *filp, const char __user *buffer, size_t count,
+			       loff_t *ppos)
+{
+	struct file_state *state = filp->private_data;
+	struct semaphore_state *shared = state->shared;
+
+	mutex_lock(&shared->mutex);
+
+	shared->count += count;
+	if (shared->count < count)
+		shared->count = SIZE_MAX;
+
+	if (shared->count > shared->max_seen)
+		shared->max_seen = shared->count;
+
+	mutex_unlock(&shared->mutex);
+
+	wake_up_all(&shared->changed);
+
+	return count;
+}
+
+static ssize_t semaphore_read(struct file *filp, char __user *buffer,
+			      size_t count, loff_t *ppos)
+{
+	struct file_state *state = filp->private_data;
+	char c = 0;
+	int ret;
+
+	if (count == 0 || *ppos > 0)
+		return 0;
+
+	ret = semaphore_consume(state->shared);
+	if (ret)
+		return ret;
+
+	if (copy_to_user(buffer, &c, sizeof(c)))
+		return -EFAULT;
+
+	atomic64_add(1, &state->read_count);
+	*ppos += 1;
+	return 1;
+}
+
+static long semaphore_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
+{
+	struct file_state *state = filp->private_data;
+	void __user *buffer = (void __user *)arg;
+	u64 value;
+
+	switch (cmd) {
+	case IOCTL_GET_READ_COUNT:
+		value = atomic64_read(&state->read_count);
+		if (copy_to_user(buffer, &value, sizeof(value)))
+			return -EFAULT;
+		return 0;
+	case IOCTL_SET_READ_COUNT:
+		if (copy_from_user(&value, buffer, sizeof(value)))
+			return -EFAULT;
+		atomic64_set(&state->read_count, value);
+		return 0;
+	default:
+		return -EINVAL;
+	}
+}
+
+static void semaphore_free(struct kref *kref)
+{
+	struct semaphore_state *device;
+
+	device = container_of(kref, struct semaphore_state, ref);
+	kfree(device);
+}
+
+static int semaphore_release(struct inode *nodp, struct file *filp)
+{
+	struct file_state *state = filp->private_data;
+
+	kref_put(&state->shared->ref, semaphore_free);
+	kfree(state);
+	return 0;
+}
+
+static const struct file_operations semaphore_fops = {
+	.owner = THIS_MODULE,
+	.open = semaphore_open,
+	.read = semaphore_read,
+	.write = semaphore_write,
+	.compat_ioctl = semaphore_ioctl,
+	.release = semaphore_release,
+};
+
+static struct semaphore_state *device;
+
+static int __init semaphore_init(void)
+{
+	int ret;
+	struct semaphore_state *state;
+
+	pr_info("Rust semaphore sample (in C, for comparison) (init)\n");
+
+	state = kzalloc(sizeof(*state), GFP_KERNEL);
+	if (!state)
+		return -ENOMEM;
+
+	mutex_init(&state->mutex);
+	kref_init(&state->ref);
+	init_waitqueue_head(&state->changed);
+
+	state->miscdev.fops = &semaphore_fops;
+	state->miscdev.minor = MISC_DYNAMIC_MINOR;
+	state->miscdev.name = "semaphore";
+
+	ret = misc_register(&state->miscdev);
+	if (ret < 0) {
+		kfree(state);
+		return ret;
+	}
+
+	device = state;
+
+	return 0;
+}
+
+static void __exit semaphore_exit(void)
+{
+	pr_info("Rust semaphore sample (in C, for comparison) (exit)\n");
+
+	misc_deregister(&device->miscdev);
+	kref_put(&device->ref, semaphore_free);
+}
+
+module_init(semaphore_init);
+module_exit(semaphore_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Rust for Linux Contributors");
+MODULE_DESCRIPTION("Rust semaphore sample (in C, for comparison)");
diff --git a/samples/rust/rust_stack_probing.rs b/samples/rust/rust_stack_probing.rs
new file mode 100644
index 000000000000..725755f42314
--- /dev/null
+++ b/samples/rust/rust_stack_probing.rs
@@ -0,0 +1,36 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Rust stack probing sample.
+
+use kernel::prelude::*;
+
+module! {
+    type: RustStackProbing,
+    name: b"rust_stack_probing",
+    author: b"Rust for Linux Contributors",
+    description: b"Rust stack probing sample",
+    license: b"GPL v2",
+}
+
+struct RustStackProbing;
+
+impl kernel::Module for RustStackProbing {
+    fn init(_name: &'static CStr, _module: &'static ThisModule) -> Result<Self> {
+        pr_info!("Rust stack probing sample (init)\n");
+
+        // Including this large variable on the stack will trigger
+        // stack probing on the supported archs.
+        // This will verify that stack probing does not lead to
+        // any errors if we need to link `__rust_probestack`.
+        let x: [u64; 514] = core::hint::black_box([5; 514]);
+        pr_info!("Large array has length: {}\n", x.len());
+
+        Ok(RustStackProbing)
+    }
+}
+
+impl Drop for RustStackProbing {
+    fn drop(&mut self) {
+        pr_info!("Rust stack probing sample (exit)\n");
+    }
+}
diff --git a/samples/rust/rust_sync.rs b/samples/rust/rust_sync.rs
new file mode 100644
index 000000000000..d87d72cf6d9a
--- /dev/null
+++ b/samples/rust/rust_sync.rs
@@ -0,0 +1,93 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Rust synchronisation primitives sample.
+
+use kernel::prelude::*;
+use kernel::{
+    condvar_init, mutex_init, spinlock_init,
+    sync::{CondVar, Mutex, SpinLock},
+};
+
+module! {
+    type: RustSync,
+    name: b"rust_sync",
+    author: b"Rust for Linux Contributors",
+    description: b"Rust synchronisation primitives sample",
+    license: b"GPL v2",
+}
+
+kernel::init_static_sync! {
+    static SAMPLE_MUTEX: Mutex<u32> = 10;
+    static SAMPLE_CONDVAR: CondVar;
+}
+
+struct RustSync;
+
+impl kernel::Module for RustSync {
+    fn init(_name: &'static CStr, _module: &'static ThisModule) -> Result<Self> {
+        pr_info!("Rust synchronisation primitives sample (init)\n");
+
+        // Test mutexes.
+        {
+            // SAFETY: `init` is called below.
+            let mut data = Pin::from(Box::try_new(unsafe { Mutex::new(0) })?);
+            mutex_init!(data.as_mut(), "RustSync::init::data1");
+            *data.lock() = 10;
+            pr_info!("Value: {}\n", *data.lock());
+
+            // SAFETY: `init` is called below.
+            let mut cv = Pin::from(Box::try_new(unsafe { CondVar::new() })?);
+            condvar_init!(cv.as_mut(), "RustSync::init::cv1");
+
+            {
+                let mut guard = data.lock();
+                while *guard != 10 {
+                    let _ = cv.wait(&mut guard);
+                }
+            }
+            cv.notify_one();
+            cv.notify_all();
+            cv.free_waiters();
+        }
+
+        // Test static mutex + condvar.
+        *SAMPLE_MUTEX.lock() = 20;
+
+        {
+            let mut guard = SAMPLE_MUTEX.lock();
+            while *guard != 20 {
+                let _ = SAMPLE_CONDVAR.wait(&mut guard);
+            }
+        }
+
+        // Test spinlocks.
+        {
+            // SAFETY: `init` is called below.
+            let mut data = Pin::from(Box::try_new(unsafe { SpinLock::new(0) })?);
+            spinlock_init!(data.as_mut(), "RustSync::init::data2");
+            *data.lock() = 10;
+            pr_info!("Value: {}\n", *data.lock());
+
+            // SAFETY: `init` is called below.
+            let mut cv = Pin::from(Box::try_new(unsafe { CondVar::new() })?);
+            condvar_init!(cv.as_mut(), "RustSync::init::cv2");
+            {
+                let mut guard = data.lock();
+                while *guard != 10 {
+                    let _ = cv.wait(&mut guard);
+                }
+            }
+            cv.notify_one();
+            cv.notify_all();
+            cv.free_waiters();
+        }
+
+        Ok(RustSync)
+    }
+}
+
+impl Drop for RustSync {
+    fn drop(&mut self) {
+        pr_info!("Rust synchronisation primitives sample (exit)\n");
+    }
+}
-- 
2.35.3


^ permalink raw reply related	[relevance 3%]

* [PATCH v7 12/25] rust: add `kernel` crate
  @ 2022-05-23  2:01  1% ` Miguel Ojeda
  2022-05-23  2:01  3% ` [PATCH v7 22/25] samples: add Rust examples Miguel Ojeda
  1 sibling, 0 replies; 77+ results
From: Miguel Ojeda @ 2022-05-23  2:01 UTC (permalink / raw)
  To: Linus Torvalds, Greg Kroah-Hartman
  Cc: rust-for-linux, linux-kernel, Jarkko Sakkinen, Miguel Ojeda,
	Wedson Almeida Filho, Alex Gaynor, Geoffrey Thomas, Finn Behrens,
	Adam Bratschi-Kaye, Michael Ellerman, Sumera Priyadarsini,
	Sven Van Asbroeck, Gary Guo, Boris-Chengbiao Zhou, Boqun Feng,
	Fox Chen, Dan Robertson, Viktor Garske, Dariusz Sosnowski,
	Léo Lanteri Thauvin, Niklas Mohrin, Gioh Kim, Daniel Xu,
	Milan Landaverde, Morgan Bartlett, Maciej Falkowski,
	Jiapeng Chong, Nándor István Krácser, David Gow

From: Wedson Almeida Filho <wedsonaf@google.com>

The `kernel` crate currently includes all the abstractions that wrap
kernel features written in C.

These abstractions call the C side of the kernel via the generated
bindings with the `bindgen` tool. Modules developed in Rust should
never call the bindings themselves.

In the future, as the abstractions grow in number, we may need
to split this crate into several, possibly following a similar
subdivision in subsystems as the kernel itself and/or moving
the code to the actual subsystems.

Co-developed-by: Alex Gaynor <alex.gaynor@gmail.com>
Signed-off-by: Alex Gaynor <alex.gaynor@gmail.com>
Co-developed-by: Geoffrey Thomas <geofft@ldpreload.com>
Signed-off-by: Geoffrey Thomas <geofft@ldpreload.com>
Co-developed-by: Finn Behrens <me@kloenk.de>
Signed-off-by: Finn Behrens <me@kloenk.de>
Co-developed-by: Adam Bratschi-Kaye <ark.email@gmail.com>
Signed-off-by: Adam Bratschi-Kaye <ark.email@gmail.com>
Co-developed-by: Michael Ellerman <mpe@ellerman.id.au>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Co-developed-by: Sumera Priyadarsini <sylphrenadin@gmail.com>
Signed-off-by: Sumera Priyadarsini <sylphrenadin@gmail.com>
Co-developed-by: Sven Van Asbroeck <thesven73@gmail.com>
Signed-off-by: Sven Van Asbroeck <thesven73@gmail.com>
Co-developed-by: Gary Guo <gary@garyguo.net>
Signed-off-by: Gary Guo <gary@garyguo.net>
Co-developed-by: Boris-Chengbiao Zhou <bobo1239@web.de>
Signed-off-by: Boris-Chengbiao Zhou <bobo1239@web.de>
Co-developed-by: Boqun Feng <boqun.feng@gmail.com>
Signed-off-by: Boqun Feng <boqun.feng@gmail.com>
Co-developed-by: Fox Chen <foxhlchen@gmail.com>
Signed-off-by: Fox Chen <foxhlchen@gmail.com>
Co-developed-by: Dan Robertson <daniel.robertson@starlab.io>
Signed-off-by: Dan Robertson <daniel.robertson@starlab.io>
Co-developed-by: Viktor Garske <viktor@v-gar.de>
Signed-off-by: Viktor Garske <viktor@v-gar.de>
Co-developed-by: Dariusz Sosnowski <dsosnowski@dsosnowski.pl>
Signed-off-by: Dariusz Sosnowski <dsosnowski@dsosnowski.pl>
Co-developed-by: Léo Lanteri Thauvin <leseulartichaut@gmail.com>
Signed-off-by: Léo Lanteri Thauvin <leseulartichaut@gmail.com>
Co-developed-by: Niklas Mohrin <dev@niklasmohrin.de>
Signed-off-by: Niklas Mohrin <dev@niklasmohrin.de>
Co-developed-by: Gioh Kim <gurugio@gmail.com>
Signed-off-by: Gioh Kim <gurugio@gmail.com>
Co-developed-by: Daniel Xu <dxu@dxuuu.xyz>
Signed-off-by: Daniel Xu <dxu@dxuuu.xyz>
Co-developed-by: Milan Landaverde <milan@mdaverde.com>
Signed-off-by: Milan Landaverde <milan@mdaverde.com>
Co-developed-by: Morgan Bartlett <mjmouse9999@gmail.com>
Signed-off-by: Morgan Bartlett <mjmouse9999@gmail.com>
Co-developed-by: Maciej Falkowski <m.falkowski@samsung.com>
Signed-off-by: Maciej Falkowski <m.falkowski@samsung.com>
Co-developed-by: Jiapeng Chong <jiapeng.chong@linux.alibaba.com>
Signed-off-by: Jiapeng Chong <jiapeng.chong@linux.alibaba.com>
Co-developed-by: Nándor István Krácser <bonifaido@gmail.com>
Signed-off-by: Nándor István Krácser <bonifaido@gmail.com>
Co-developed-by: David Gow <davidgow@google.com>
Signed-off-by: David Gow <davidgow@google.com>
Signed-off-by: Wedson Almeida Filho <wedsonaf@google.com>
Co-developed-by: Miguel Ojeda <ojeda@kernel.org>
Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
---
 rust/kernel/allocator.rs      |  65 +++
 rust/kernel/amba.rs           | 257 ++++++++++
 rust/kernel/bindings.rs       |  47 ++
 rust/kernel/bindings_helper.h |  46 ++
 rust/kernel/build_assert.rs   |  82 ++++
 rust/kernel/c_types.rs        | 119 +++++
 rust/kernel/chrdev.rs         | 207 ++++++++
 rust/kernel/clk.rs            |  79 ++++
 rust/kernel/cred.rs           |  46 ++
 rust/kernel/device.rs         | 546 +++++++++++++++++++++
 rust/kernel/driver.rs         | 442 +++++++++++++++++
 rust/kernel/error.rs          | 565 ++++++++++++++++++++++
 rust/kernel/file.rs           | 860 ++++++++++++++++++++++++++++++++++
 rust/kernel/gpio.rs           | 478 +++++++++++++++++++
 rust/kernel/hwrng.rs          | 242 ++++++++++
 rust/kernel/io_buffer.rs      | 153 ++++++
 rust/kernel/io_mem.rs         | 275 +++++++++++
 rust/kernel/iov_iter.rs       |  81 ++++
 rust/kernel/irq.rs            | 411 ++++++++++++++++
 rust/kernel/kasync.rs         |   6 +
 rust/kernel/kasync/net.rs     | 322 +++++++++++++
 rust/kernel/kunit.rs          |  91 ++++
 rust/kernel/lib.rs            | 261 +++++++++++
 rust/kernel/linked_list.rs    | 247 ++++++++++
 rust/kernel/miscdev.rs        | 291 ++++++++++++
 rust/kernel/mm.rs             | 149 ++++++
 rust/kernel/module_param.rs   | 498 ++++++++++++++++++++
 rust/kernel/net.rs            | 392 ++++++++++++++++
 rust/kernel/net/filter.rs     | 447 ++++++++++++++++++
 rust/kernel/of.rs             |  63 +++
 rust/kernel/pages.rs          | 144 ++++++
 rust/kernel/platform.rs       | 223 +++++++++
 rust/kernel/power.rs          | 118 +++++
 rust/kernel/prelude.rs        |  36 ++
 rust/kernel/print.rs          | 405 ++++++++++++++++
 rust/kernel/random.rs         |  42 ++
 rust/kernel/raw_list.rs       | 361 ++++++++++++++
 rust/kernel/rbtree.rs         | 563 ++++++++++++++++++++++
 rust/kernel/revocable.rs      | 161 +++++++
 rust/kernel/security.rs       |  38 ++
 rust/kernel/static_assert.rs  |  38 ++
 rust/kernel/std_vendor.rs     | 160 +++++++
 rust/kernel/str.rs            | 597 +++++++++++++++++++++++
 rust/kernel/sysctl.rs         | 199 ++++++++
 rust/kernel/task.rs           | 175 +++++++
 rust/kernel/types.rs          | 679 +++++++++++++++++++++++++++
 rust/kernel/user_ptr.rs       | 175 +++++++
 47 files changed, 11882 insertions(+)
 create mode 100644 rust/kernel/allocator.rs
 create mode 100644 rust/kernel/amba.rs
 create mode 100644 rust/kernel/bindings.rs
 create mode 100644 rust/kernel/bindings_helper.h
 create mode 100644 rust/kernel/build_assert.rs
 create mode 100644 rust/kernel/c_types.rs
 create mode 100644 rust/kernel/chrdev.rs
 create mode 100644 rust/kernel/clk.rs
 create mode 100644 rust/kernel/cred.rs
 create mode 100644 rust/kernel/device.rs
 create mode 100644 rust/kernel/driver.rs
 create mode 100644 rust/kernel/error.rs
 create mode 100644 rust/kernel/file.rs
 create mode 100644 rust/kernel/gpio.rs
 create mode 100644 rust/kernel/hwrng.rs
 create mode 100644 rust/kernel/io_buffer.rs
 create mode 100644 rust/kernel/io_mem.rs
 create mode 100644 rust/kernel/iov_iter.rs
 create mode 100644 rust/kernel/irq.rs
 create mode 100644 rust/kernel/kasync.rs
 create mode 100644 rust/kernel/kasync/net.rs
 create mode 100644 rust/kernel/kunit.rs
 create mode 100644 rust/kernel/lib.rs
 create mode 100644 rust/kernel/linked_list.rs
 create mode 100644 rust/kernel/miscdev.rs
 create mode 100644 rust/kernel/mm.rs
 create mode 100644 rust/kernel/module_param.rs
 create mode 100644 rust/kernel/net.rs
 create mode 100644 rust/kernel/net/filter.rs
 create mode 100644 rust/kernel/of.rs
 create mode 100644 rust/kernel/pages.rs
 create mode 100644 rust/kernel/platform.rs
 create mode 100644 rust/kernel/power.rs
 create mode 100644 rust/kernel/prelude.rs
 create mode 100644 rust/kernel/print.rs
 create mode 100644 rust/kernel/random.rs
 create mode 100644 rust/kernel/raw_list.rs
 create mode 100644 rust/kernel/rbtree.rs
 create mode 100644 rust/kernel/revocable.rs
 create mode 100644 rust/kernel/security.rs
 create mode 100644 rust/kernel/static_assert.rs
 create mode 100644 rust/kernel/std_vendor.rs
 create mode 100644 rust/kernel/str.rs
 create mode 100644 rust/kernel/sysctl.rs
 create mode 100644 rust/kernel/task.rs
 create mode 100644 rust/kernel/types.rs
 create mode 100644 rust/kernel/user_ptr.rs

diff --git a/rust/kernel/allocator.rs b/rust/kernel/allocator.rs
new file mode 100644
index 000000000000..4c5d2fc6f206
--- /dev/null
+++ b/rust/kernel/allocator.rs
@@ -0,0 +1,65 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Allocator support.
+
+use core::alloc::{GlobalAlloc, Layout};
+use core::ptr;
+
+use crate::bindings;
+use crate::c_types;
+
+struct KernelAllocator;
+
+unsafe impl GlobalAlloc for KernelAllocator {
+    unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
+        // `krealloc()` is used instead of `kmalloc()` because the latter is
+        // an inline function and cannot be bound to as a result.
+        unsafe { bindings::krealloc(ptr::null(), layout.size(), bindings::GFP_KERNEL) as *mut u8 }
+    }
+
+    unsafe fn dealloc(&self, ptr: *mut u8, _layout: Layout) {
+        unsafe {
+            bindings::kfree(ptr as *const c_types::c_void);
+        }
+    }
+}
+
+#[global_allocator]
+static ALLOCATOR: KernelAllocator = KernelAllocator;
+
+// `rustc` only generates these for some crate types. Even then, we would need
+// to extract the object file that has them from the archive. For the moment,
+// let's generate them ourselves instead.
+//
+// Note that `#[no_mangle]` implies exported too, nowadays.
+#[no_mangle]
+fn __rust_alloc(size: usize, _align: usize) -> *mut u8 {
+    unsafe { bindings::krealloc(core::ptr::null(), size, bindings::GFP_KERNEL) as *mut u8 }
+}
+
+#[no_mangle]
+fn __rust_dealloc(ptr: *mut u8, _size: usize, _align: usize) {
+    unsafe { bindings::kfree(ptr as *const c_types::c_void) };
+}
+
+#[no_mangle]
+fn __rust_realloc(ptr: *mut u8, _old_size: usize, _align: usize, new_size: usize) -> *mut u8 {
+    unsafe {
+        bindings::krealloc(
+            ptr as *const c_types::c_void,
+            new_size,
+            bindings::GFP_KERNEL,
+        ) as *mut u8
+    }
+}
+
+#[no_mangle]
+fn __rust_alloc_zeroed(size: usize, _align: usize) -> *mut u8 {
+    unsafe {
+        bindings::krealloc(
+            core::ptr::null(),
+            size,
+            bindings::GFP_KERNEL | bindings::__GFP_ZERO,
+        ) as *mut u8
+    }
+}
diff --git a/rust/kernel/amba.rs b/rust/kernel/amba.rs
new file mode 100644
index 000000000000..7ca5358d2580
--- /dev/null
+++ b/rust/kernel/amba.rs
@@ -0,0 +1,257 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Amba devices and drivers.
+//!
+//! C header: [`include/linux/amba/bus.h`](../../../../include/linux/amba/bus.h)
+
+use crate::{
+    bindings, c_types, device, driver, error::from_kernel_result, io_mem::Resource, power,
+    str::CStr, to_result, types::PointerWrapper, Result, ThisModule,
+};
+
+/// A registration of an amba driver.
+pub type Registration<T> = driver::Registration<Adapter<T>>;
+
+/// Id of an Amba device.
+#[derive(Clone, Copy)]
+pub struct DeviceId {
+    /// Device id.
+    pub id: u32,
+
+    /// Mask that identifies which bits are valid in the device id.
+    pub mask: u32,
+}
+
+// SAFETY: `ZERO` is all zeroed-out and `to_rawid` stores `offset` in `amba_id::data`.
+unsafe impl const driver::RawDeviceId for DeviceId {
+    type RawType = bindings::amba_id;
+    const ZERO: Self::RawType = bindings::amba_id {
+        id: 0,
+        mask: 0,
+        data: core::ptr::null_mut(),
+    };
+
+    fn to_rawid(&self, offset: isize) -> Self::RawType {
+        bindings::amba_id {
+            id: self.id,
+            mask: self.mask,
+            data: offset as _,
+        }
+    }
+}
+
+/// An amba driver.
+pub trait Driver {
+    /// Data stored on device by driver.
+    type Data: PointerWrapper + Send + Sync + driver::DeviceRemoval = ();
+
+    /// The type that implements the power-management operations.
+    ///
+    /// The default is a type that implements no power-management operations. Drivers that do
+    /// implement them need to specify the type (commonly [`Self`]).
+    type PowerOps: power::Operations<Data = Self::Data> = power::NoOperations<Self::Data>;
+
+    /// The type holding information about each device id supported by the driver.
+    type IdInfo: 'static = ();
+
+    /// The table of device ids supported by the driver.
+    const ID_TABLE: Option<driver::IdTable<'static, DeviceId, Self::IdInfo>> = None;
+
+    /// Probes for the device with the given id.
+    fn probe(dev: &mut Device, id_info: Option<&Self::IdInfo>) -> Result<Self::Data>;
+
+    /// Cleans any resources up that are associated with the device.
+    ///
+    /// This is called when the driver is detached from the device.
+    fn remove(_data: &Self::Data) {}
+}
+
+/// An adapter for the registration of Amba drivers.
+pub struct Adapter<T: Driver>(T);
+
+impl<T: Driver> driver::DriverOps for Adapter<T> {
+    type RegType = bindings::amba_driver;
+
+    unsafe fn register(
+        reg: *mut bindings::amba_driver,
+        name: &'static CStr,
+        module: &'static ThisModule,
+    ) -> Result {
+        // SAFETY: By the safety requirements of this function (defined in the trait definition),
+        // `reg` is non-null and valid.
+        let amba = unsafe { &mut *reg };
+        amba.drv.name = name.as_char_ptr();
+        amba.drv.owner = module.0;
+        amba.probe = Some(probe_callback::<T>);
+        amba.remove = Some(remove_callback::<T>);
+        if let Some(t) = T::ID_TABLE {
+            amba.id_table = t.as_ref();
+        }
+        if cfg!(CONFIG_PM) {
+            // SAFETY: `probe_callback` sets the driver data after calling `T::Data::into_pointer`,
+            // and we guarantee that `T::Data` is the same as `T::PowerOps::Data` by a constraint
+            // in the type declaration.
+            amba.drv.pm = unsafe { power::OpsTable::<T::PowerOps>::build() };
+        }
+        // SAFETY: By the safety requirements of this function, `reg` is valid and fully
+        // initialised.
+        to_result(|| unsafe { bindings::amba_driver_register(reg) })
+    }
+
+    unsafe fn unregister(reg: *mut bindings::amba_driver) {
+        // SAFETY: By the safety requirements of this function (defined in the trait definition),
+        // `reg` was passed (and updated) by a previous successful call to `amba_driver_register`.
+        unsafe { bindings::amba_driver_unregister(reg) };
+    }
+}
+
+unsafe extern "C" fn probe_callback<T: Driver>(
+    adev: *mut bindings::amba_device,
+    aid: *const bindings::amba_id,
+) -> c_types::c_int {
+    from_kernel_result! {
+        // SAFETY: `adev` is valid by the contract with the C code. `dev` is alive only for the
+        // duration of this call, so it is guaranteed to remain alive for the lifetime of `dev`.
+        let mut dev = unsafe { Device::from_ptr(adev) };
+        // SAFETY: `aid` is valid by the requirements the contract with the C code.
+        let offset = unsafe { (*aid).data };
+        let info = if offset.is_null() {
+            None
+        } else {
+            // SAFETY: The offset comes from a previous call to `offset_from` in `IdArray::new`,
+            // which guarantees that the resulting pointer is within the table.
+            let ptr = unsafe { aid.cast::<u8>().offset(offset as _).cast::<Option<T::IdInfo>>() };
+            // SAFETY: The id table has a static lifetime, so `ptr` is guaranteed to be valid for
+            // read.
+            unsafe { (&*ptr).as_ref() }
+        };
+        let data = T::probe(&mut dev, info)?;
+        let ptr = T::Data::into_pointer(data);
+        // SAFETY: `adev` is valid for write by the contract with the C code.
+        unsafe { bindings::amba_set_drvdata(adev, ptr as _) };
+        Ok(0)
+    }
+}
+
+unsafe extern "C" fn remove_callback<T: Driver>(adev: *mut bindings::amba_device) {
+    // SAFETY: `adev` is valid by the contract with the C code.
+    let ptr = unsafe { bindings::amba_get_drvdata(adev) };
+    // SAFETY: The value returned by `amba_get_drvdata` was stored by a previous call to
+    // `amba_set_drvdata` in `probe_callback` above; the value comes from a call to
+    // `T::Data::into_pointer`.
+    let data = unsafe { T::Data::from_pointer(ptr) };
+    T::remove(&data);
+    <T::Data as driver::DeviceRemoval>::device_remove(&data);
+}
+
+/// An Amba device.
+///
+/// # Invariants
+///
+/// The field `ptr` is non-null and valid for the lifetime of the object.
+pub struct Device {
+    ptr: *mut bindings::amba_device,
+    res: Option<Resource>,
+}
+
+impl Device {
+    /// Creates a new device from the given pointer.
+    ///
+    /// # Safety
+    ///
+    /// `ptr` must be non-null and valid. It must remain valid for the lifetime of the returned
+    /// instance.
+    unsafe fn from_ptr(ptr: *mut bindings::amba_device) -> Self {
+        // SAFETY: The safety requirements of the function ensure that `ptr` is valid.
+        let dev = unsafe { &mut *ptr };
+        // INVARIANT: The safety requirements of the function ensure the lifetime invariant.
+        Self {
+            ptr,
+            res: Resource::new(dev.res.start, dev.res.end),
+        }
+    }
+
+    /// Returns the io mem resource associated with the device, if there is one.
+    ///
+    /// Ownership of the resource is transferred to the caller, so subsequent calls to this
+    /// function will return [`None`].
+    pub fn take_resource(&mut self) -> Option<Resource> {
+        self.res.take()
+    }
+
+    /// Returns the index-th irq associated with the device, if one exists.
+    pub fn irq(&self, index: usize) -> Option<u32> {
+        // SAFETY: By the type invariants, `self.ptr` is valid for read.
+        let dev = unsafe { &*self.ptr };
+        if index >= dev.irq.len() || dev.irq[index] == 0 {
+            None
+        } else {
+            Some(dev.irq[index])
+        }
+    }
+}
+
+// SAFETY: The device returned by `raw_device` is the raw Amba device.
+unsafe impl device::RawDevice for Device {
+    fn raw_device(&self) -> *mut bindings::device {
+        // SAFETY: By the type invariants, we know that `self.ptr` is non-null and valid.
+        unsafe { &mut (*self.ptr).dev }
+    }
+}
+
+/// Declares a kernel module that exposes a single amba driver.
+///
+/// # Examples
+///
+/// ```ignore
+/// # use kernel::{amba, define_amba_id_table, module_amba_driver};
+/// #
+/// struct MyDriver;
+/// impl amba::Driver for MyDriver {
+///     // [...]
+/// #   fn probe(_dev: &mut amba::Device, _id: Option<&Self::IdInfo>) -> Result {
+/// #       Ok(())
+/// #   }
+/// #   define_amba_id_table! {(), [
+/// #       ({ id: 0x00041061, mask: 0x000fffff }, None),
+/// #   ]}
+/// }
+///
+/// module_amba_driver! {
+///     type: MyDriver,
+///     name: b"module_name",
+///     author: b"Author name",
+///     license: b"GPL",
+/// }
+/// ```
+#[macro_export]
+macro_rules! module_amba_driver {
+    ($($f:tt)*) => {
+        $crate::module_driver!(<T>, $crate::amba::Adapter<T>, { $($f)* });
+    };
+}
+
+/// Defines the id table for amba devices.
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::{amba, define_amba_id_table};
+/// #
+/// # struct Sample;
+/// # impl kernel::amba::Driver for Sample {
+/// #   fn probe(_dev: &mut amba::Device, _id: Option<&Self::IdInfo>) -> Result {
+/// #       Ok(())
+/// #   }
+///     define_amba_id_table! {(), [
+///         ({ id: 0x00041061, mask: 0x000fffff }, None),
+///     ]}
+/// # }
+/// ```
+#[macro_export]
+macro_rules! define_amba_id_table {
+    ($data_type:ty, $($t:tt)*) => {
+        type IdInfo = $data_type;
+        $crate::define_id_table!(ID_TABLE, $crate::amba::DeviceId, $data_type, $($t)*);
+    };
+}
diff --git a/rust/kernel/bindings.rs b/rust/kernel/bindings.rs
new file mode 100644
index 000000000000..29a21030688e
--- /dev/null
+++ b/rust/kernel/bindings.rs
@@ -0,0 +1,47 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Bindings.
+//!
+//! Imports the generated bindings by `bindgen`.
+
+// See https://github.com/rust-lang/rust-bindgen/issues/1651.
+#![cfg_attr(test, allow(deref_nullptr))]
+#![cfg_attr(test, allow(unaligned_references))]
+#![cfg_attr(test, allow(unsafe_op_in_unsafe_fn))]
+#![allow(
+    clippy::all,
+    non_camel_case_types,
+    non_upper_case_globals,
+    non_snake_case,
+    improper_ctypes,
+    unreachable_pub,
+    unsafe_op_in_unsafe_fn
+)]
+
+mod bindings_raw {
+    // Use glob import here to expose all helpers.
+    // Symbols defined within the module will take precedence to the glob import.
+    pub use super::bindings_helper::*;
+    use crate::c_types;
+    include!(concat!(env!("OBJTREE"), "/rust/bindings_generated.rs"));
+}
+
+// When both a directly exposed symbol and a helper exists for the same function,
+// the directly exposed symbol is preferred and the helper becomes dead code, so
+// ignore the warning here.
+#[allow(dead_code)]
+mod bindings_helper {
+    // Import the generated bindings for types.
+    use super::bindings_raw::*;
+    use crate::c_types;
+    include!(concat!(
+        env!("OBJTREE"),
+        "/rust/bindings_helpers_generated.rs"
+    ));
+}
+
+pub use bindings_raw::*;
+
+pub const GFP_KERNEL: gfp_t = BINDINGS_GFP_KERNEL;
+pub const __GFP_ZERO: gfp_t = BINDINGS___GFP_ZERO;
+pub const __GFP_HIGHMEM: gfp_t = ___GFP_HIGHMEM;
diff --git a/rust/kernel/bindings_helper.h b/rust/kernel/bindings_helper.h
new file mode 100644
index 000000000000..73100fa139eb
--- /dev/null
+++ b/rust/kernel/bindings_helper.h
@@ -0,0 +1,46 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Header that contains the code (mostly headers) for which Rust bindings
+ * will be automatically generated by `bindgen`.
+ *
+ * Sorted alphabetically.
+ */
+
+#include <kunit/test.h>
+#include <linux/amba/bus.h>
+#include <linux/cdev.h>
+#include <linux/clk.h>
+#include <linux/errname.h>
+#include <linux/file.h>
+#include <linux/fs.h>
+#include <linux/gpio/driver.h>
+#include <linux/hw_random.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/irqdomain.h>
+#include <linux/irq.h>
+#include <linux/miscdevice.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/netfilter_arp.h>
+#include <linux/netfilter.h>
+#include <linux/netfilter_ipv4.h>
+#include <linux/netfilter_ipv6.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/poll.h>
+#include <linux/random.h>
+#include <linux/security.h>
+#include <linux/slab.h>
+#include <linux/sysctl.h>
+#include <linux/uaccess.h>
+#include <linux/uio.h>
+#include <uapi/linux/android/binder.h>
+
+/* `bindgen` gets confused at certain things. */
+const gfp_t BINDINGS_GFP_KERNEL = GFP_KERNEL;
+const gfp_t BINDINGS___GFP_ZERO = __GFP_ZERO;
+const __poll_t BINDINGS_EPOLLIN = EPOLLIN;
+const __poll_t BINDINGS_EPOLLOUT = EPOLLOUT;
+const __poll_t BINDINGS_EPOLLERR = EPOLLERR;
+const __poll_t BINDINGS_EPOLLHUP = EPOLLHUP;
diff --git a/rust/kernel/build_assert.rs b/rust/kernel/build_assert.rs
new file mode 100644
index 000000000000..18cffec7d037
--- /dev/null
+++ b/rust/kernel/build_assert.rs
@@ -0,0 +1,82 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Build-time assert.
+
+/// Fails the build if the code path calling `build_error!` can possibly be executed.
+///
+/// If the macro is executed in const context, `build_error!` will panic.
+/// If the compiler or optimizer cannot guarantee that `build_error!` can never
+/// be called, a build error will be triggered.
+///
+/// # Examples
+/// ```
+/// # use kernel::build_error;
+/// #[inline]
+/// fn foo(a: usize) -> usize {
+///     a.checked_add(1).unwrap_or_else(|| build_error!("overflow"))
+/// }
+///
+/// assert_eq!(foo(usize::MAX - 1), usize::MAX); // OK.
+/// // foo(usize::MAX); // Fails to compile.
+/// ```
+#[macro_export]
+macro_rules! build_error {
+    () => {{
+        $crate::build_error("")
+    }};
+    ($msg:expr) => {{
+        $crate::build_error($msg)
+    }};
+}
+
+/// Asserts that a boolean expression is `true` at compile time.
+///
+/// If the condition is evaluated to `false` in const context, `build_assert!`
+/// will panic. If the compiler or optimizer cannot guarantee the condition will
+/// be evaluated to `true`, a build error will be triggered.
+///
+/// [`static_assert!`] should be preferred to `build_assert!` whenever possible.
+///
+/// # Examples
+///
+/// These examples show that different types of [`assert!`] will trigger errors
+/// at different stage of compilation. It is preferred to err as early as
+/// possible, so [`static_assert!`] should be used whenever possible.
+// TODO: Could be `compile_fail` when supported.
+/// ```ignore
+/// fn foo() {
+///     static_assert!(1 > 1); // Compile-time error
+///     build_assert!(1 > 1); // Build-time error
+///     assert!(1 > 1); // Run-time error
+/// }
+/// ```
+///
+/// When the condition refers to generic parameters or parameters of an inline function,
+/// [`static_assert!`] cannot be used. Use `build_assert!` in this scenario.
+/// ```
+/// fn foo<const N: usize>() {
+///     // `static_assert!(N > 1);` is not allowed
+///     build_assert!(N > 1); // Build-time check
+///     assert!(N > 1); // Run-time check
+/// }
+///
+/// #[inline]
+/// fn bar(n: usize) {
+///     // `static_assert!(n > 1);` is not allowed
+///     build_assert!(n > 1); // Build-time check
+///     assert!(n > 1); // Run-time check
+/// }
+/// ```
+#[macro_export]
+macro_rules! build_assert {
+    ($cond:expr $(,)?) => {{
+        if !$cond {
+            $crate::build_error(concat!("assertion failed: ", stringify!($cond)));
+        }
+    }};
+    ($cond:expr, $msg:expr) => {{
+        if !$cond {
+            $crate::build_error($msg);
+        }
+    }};
+}
diff --git a/rust/kernel/c_types.rs b/rust/kernel/c_types.rs
new file mode 100644
index 000000000000..07593a3ba8be
--- /dev/null
+++ b/rust/kernel/c_types.rs
@@ -0,0 +1,119 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! C types for the bindings.
+//!
+//! The bindings generated by `bindgen` use these types to map to the C ones.
+//!
+//! C's standard integer types may differ in width depending on
+//! the architecture, thus we need to conditionally compile those.
+
+#![allow(non_camel_case_types)]
+
+#[cfg(any(target_arch = "arm", target_arch = "x86", target_arch = "riscv32",))]
+mod c {
+    /// C `void` type.
+    pub type c_void = core::ffi::c_void;
+
+    /// C `char` type.
+    pub type c_char = i8;
+
+    /// C `signed char` type.
+    pub type c_schar = i8;
+
+    /// C `unsigned char` type.
+    pub type c_uchar = u8;
+
+    /// C `short` type.
+    pub type c_short = i16;
+
+    /// C `unsigned short` type.
+    pub type c_ushort = u16;
+
+    /// C `int` type.
+    pub type c_int = i32;
+
+    /// C `unsigned int` type.
+    pub type c_uint = u32;
+
+    /// C `long` type.
+    pub type c_long = i32;
+
+    /// C `unsigned long` type.
+    pub type c_ulong = u32;
+
+    /// C `long long` type.
+    pub type c_longlong = i64;
+
+    /// C `unsigned long long` type.
+    pub type c_ulonglong = u64;
+
+    /// C `ssize_t` type (typically defined in `<sys/types.h>` by POSIX).
+    ///
+    /// For some 32-bit architectures like this one, the kernel defines it as
+    /// `int`, i.e. it is an [`i32`].
+    pub type c_ssize_t = isize;
+
+    /// C `size_t` type (typically defined in `<stddef.h>`).
+    ///
+    /// For some 32-bit architectures like this one, the kernel defines it as
+    /// `unsigned int`, i.e. it is an [`u32`].
+    pub type c_size_t = usize;
+}
+
+#[cfg(any(
+    target_arch = "aarch64",
+    target_arch = "x86_64",
+    target_arch = "powerpc64",
+    target_arch = "riscv64",
+))]
+mod c {
+    /// C `void` type.
+    pub type c_void = core::ffi::c_void;
+
+    /// C `char` type.
+    pub type c_char = i8;
+
+    /// C `signed char` type.
+    pub type c_schar = i8;
+
+    /// C `unsigned char` type.
+    pub type c_uchar = u8;
+
+    /// C `short` type.
+    pub type c_short = i16;
+
+    /// C `unsigned short` type.
+    pub type c_ushort = u16;
+
+    /// C `int` type.
+    pub type c_int = i32;
+
+    /// C `unsigned int` type.
+    pub type c_uint = u32;
+
+    /// C `long` type.
+    pub type c_long = i64;
+
+    /// C `unsigned long` type.
+    pub type c_ulong = u64;
+
+    /// C `long long` type.
+    pub type c_longlong = i64;
+
+    /// C `unsigned long long` type.
+    pub type c_ulonglong = u64;
+
+    /// C `ssize_t` type (typically defined in `<sys/types.h>` by POSIX).
+    ///
+    /// For 64-bit architectures like this one, the kernel defines it as
+    /// `long`, i.e. it is an [`i64`].
+    pub type c_ssize_t = isize;
+
+    /// C `size_t` type (typically defined in `<stddef.h>`).
+    ///
+    /// For 64-bit architectures like this one, the kernel defines it as
+    /// `unsigned long`, i.e. it is an [`u64`].
+    pub type c_size_t = usize;
+}
+
+pub use c::*;
diff --git a/rust/kernel/chrdev.rs b/rust/kernel/chrdev.rs
new file mode 100644
index 000000000000..85a52c2d0b8a
--- /dev/null
+++ b/rust/kernel/chrdev.rs
@@ -0,0 +1,207 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Character devices.
+//!
+//! Also called "char devices", `chrdev`, `cdev`.
+//!
+//! C header: [`include/linux/cdev.h`](../../../../include/linux/cdev.h)
+//!
+//! Reference: <https://www.kernel.org/doc/html/latest/core-api/kernel-api.html#char-devices>
+
+use alloc::boxed::Box;
+use core::convert::TryInto;
+use core::marker::PhantomPinned;
+use core::pin::Pin;
+
+use crate::bindings;
+use crate::c_types;
+use crate::error::{code::*, Error, Result};
+use crate::file;
+use crate::str::CStr;
+
+/// Character device.
+///
+/// # Invariants
+///
+///   - [`self.0`] is valid and non-null.
+///   - [`(*self.0).ops`] is valid, non-null and has static lifetime.
+///   - [`(*self.0).owner`] is valid and, if non-null, has module lifetime.
+struct Cdev(*mut bindings::cdev);
+
+impl Cdev {
+    fn alloc(
+        fops: &'static bindings::file_operations,
+        module: &'static crate::ThisModule,
+    ) -> Result<Self> {
+        // SAFETY: FFI call.
+        let cdev = unsafe { bindings::cdev_alloc() };
+        if cdev.is_null() {
+            return Err(ENOMEM);
+        }
+        // SAFETY: `cdev` is valid and non-null since `cdev_alloc()`
+        // returned a valid pointer which was null-checked.
+        unsafe {
+            (*cdev).ops = fops;
+            (*cdev).owner = module.0;
+        }
+        // INVARIANTS:
+        //   - [`self.0`] is valid and non-null.
+        //   - [`(*self.0).ops`] is valid, non-null and has static lifetime,
+        //     because it was coerced from a reference with static lifetime.
+        //   - [`(*self.0).owner`] is valid and, if non-null, has module lifetime,
+        //     guaranteed by the [`ThisModule`] invariant.
+        Ok(Self(cdev))
+    }
+
+    fn add(&mut self, dev: bindings::dev_t, count: c_types::c_uint) -> Result {
+        // SAFETY: According to the type invariants:
+        //   - [`self.0`] can be safely passed to [`bindings::cdev_add`].
+        //   - [`(*self.0).ops`] will live at least as long as [`self.0`].
+        //   - [`(*self.0).owner`] will live at least as long as the
+        //     module, which is an implicit requirement.
+        let rc = unsafe { bindings::cdev_add(self.0, dev, count) };
+        if rc != 0 {
+            return Err(Error::from_kernel_errno(rc));
+        }
+        Ok(())
+    }
+}
+
+impl Drop for Cdev {
+    fn drop(&mut self) {
+        // SAFETY: [`self.0`] is valid and non-null by the type invariants.
+        unsafe {
+            bindings::cdev_del(self.0);
+        }
+    }
+}
+
+struct RegistrationInner<const N: usize> {
+    dev: bindings::dev_t,
+    used: usize,
+    cdevs: [Option<Cdev>; N],
+    _pin: PhantomPinned,
+}
+
+/// Character device registration.
+///
+/// May contain up to a fixed number (`N`) of devices. Must be pinned.
+pub struct Registration<const N: usize> {
+    name: &'static CStr,
+    minors_start: u16,
+    this_module: &'static crate::ThisModule,
+    inner: Option<RegistrationInner<N>>,
+}
+
+impl<const N: usize> Registration<{ N }> {
+    /// Creates a [`Registration`] object for a character device.
+    ///
+    /// This does *not* register the device: see [`Self::register()`].
+    ///
+    /// This associated function is intended to be used when you need to avoid
+    /// a memory allocation, e.g. when the [`Registration`] is a member of
+    /// a bigger structure inside your [`crate::Module`] instance. If you
+    /// are going to pin the registration right away, call
+    /// [`Self::new_pinned()`] instead.
+    pub fn new(
+        name: &'static CStr,
+        minors_start: u16,
+        this_module: &'static crate::ThisModule,
+    ) -> Self {
+        Registration {
+            name,
+            minors_start,
+            this_module,
+            inner: None,
+        }
+    }
+
+    /// Creates a pinned [`Registration`] object for a character device.
+    ///
+    /// This does *not* register the device: see [`Self::register()`].
+    pub fn new_pinned(
+        name: &'static CStr,
+        minors_start: u16,
+        this_module: &'static crate::ThisModule,
+    ) -> Result<Pin<Box<Self>>> {
+        Ok(Pin::from(Box::try_new(Self::new(
+            name,
+            minors_start,
+            this_module,
+        ))?))
+    }
+
+    /// Registers a character device.
+    ///
+    /// You may call this once per device type, up to `N` times.
+    pub fn register<T: file::Operations<OpenData = ()>>(self: Pin<&mut Self>) -> Result {
+        // SAFETY: We must ensure that we never move out of `this`.
+        let this = unsafe { self.get_unchecked_mut() };
+        if this.inner.is_none() {
+            let mut dev: bindings::dev_t = 0;
+            // SAFETY: Calling unsafe function. `this.name` has `'static`
+            // lifetime.
+            let res = unsafe {
+                bindings::alloc_chrdev_region(
+                    &mut dev,
+                    this.minors_start.into(),
+                    N.try_into()?,
+                    this.name.as_char_ptr(),
+                )
+            };
+            if res != 0 {
+                return Err(Error::from_kernel_errno(res));
+            }
+            const NONE: Option<Cdev> = None;
+            this.inner = Some(RegistrationInner {
+                dev,
+                used: 0,
+                cdevs: [NONE; N],
+                _pin: PhantomPinned,
+            });
+        }
+
+        let mut inner = this.inner.as_mut().unwrap();
+        if inner.used == N {
+            return Err(EINVAL);
+        }
+
+        // SAFETY: The adapter doesn't retrieve any state yet, so it's compatible with any
+        // registration.
+        let fops = unsafe { file::OperationsVtable::<Self, T>::build() };
+        let mut cdev = Cdev::alloc(fops, this.this_module)?;
+        cdev.add(inner.dev + inner.used as bindings::dev_t, 1)?;
+        inner.cdevs[inner.used].replace(cdev);
+        inner.used += 1;
+        Ok(())
+    }
+}
+
+impl<const N: usize> file::OpenAdapter<()> for Registration<{ N }> {
+    unsafe fn convert(_inode: *mut bindings::inode, _file: *mut bindings::file) -> *const () {
+        // TODO: Update the SAFETY comment on the call to `FileOperationsVTable::build` above once
+        // this is updated to retrieve state.
+        &()
+    }
+}
+
+// SAFETY: `Registration` does not expose any of its state across threads
+// (it is fine for multiple threads to have a shared reference to it).
+unsafe impl<const N: usize> Sync for Registration<{ N }> {}
+
+impl<const N: usize> Drop for Registration<{ N }> {
+    fn drop(&mut self) {
+        if let Some(inner) = self.inner.as_mut() {
+            // Replicate kernel C behaviour: drop [`Cdev`]s before calling
+            // [`bindings::unregister_chrdev_region`].
+            for i in 0..inner.used {
+                inner.cdevs[i].take();
+            }
+            // SAFETY: [`self.inner`] is Some, so [`inner.dev`] was previously
+            // created using [`bindings::alloc_chrdev_region`].
+            unsafe {
+                bindings::unregister_chrdev_region(inner.dev, N.try_into().unwrap());
+            }
+        }
+    }
+}
diff --git a/rust/kernel/clk.rs b/rust/kernel/clk.rs
new file mode 100644
index 000000000000..465462b9bc85
--- /dev/null
+++ b/rust/kernel/clk.rs
@@ -0,0 +1,79 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Common clock framework.
+//!
+//! C header: [`include/linux/clk.h`](../../../../include/linux/clk.h)
+
+use crate::{bindings, error::Result, to_result};
+use core::mem::ManuallyDrop;
+
+/// Represents `struct clk *`.
+///
+/// # Invariants
+///
+/// The pointer is valid.
+pub struct Clk(*mut bindings::clk);
+
+impl Clk {
+    /// Creates new clock structure from a raw pointer.
+    ///
+    /// # Safety
+    ///
+    /// The pointer must be valid.
+    pub unsafe fn new(clk: *mut bindings::clk) -> Self {
+        Self(clk)
+    }
+
+    /// Returns value of the rate field of `struct clk`.
+    pub fn get_rate(&self) -> usize {
+        // SAFETY: The pointer is valid by the type invariant.
+        unsafe { bindings::clk_get_rate(self.0) as usize }
+    }
+
+    /// Prepares and enables the underlying hardware clock.
+    ///
+    /// This function should not be called in atomic context.
+    pub fn prepare_enable(self) -> Result<EnabledClk> {
+        // SAFETY: The pointer is valid by the type invariant.
+        to_result(|| unsafe { bindings::clk_prepare_enable(self.0) })?;
+        Ok(EnabledClk(self))
+    }
+}
+
+impl Drop for Clk {
+    fn drop(&mut self) {
+        // SAFETY: The pointer is valid by the type invariant.
+        unsafe { bindings::clk_put(self.0) };
+    }
+}
+
+// SAFETY: `Clk` is not restricted to a single thread so it is safe
+// to move it between threads.
+unsafe impl Send for Clk {}
+
+/// A clock variant that is prepared and enabled.
+pub struct EnabledClk(Clk);
+
+impl EnabledClk {
+    /// Returns value of the rate field of `struct clk`.
+    pub fn get_rate(&self) -> usize {
+        self.0.get_rate()
+    }
+
+    /// Disables and later unprepares the underlying hardware clock prematurely.
+    ///
+    /// This function should not be called in atomic context.
+    pub fn disable_unprepare(self) -> Clk {
+        let mut clk = ManuallyDrop::new(self);
+        // SAFETY: The pointer is valid by the type invariant.
+        unsafe { bindings::clk_disable_unprepare(clk.0 .0) };
+        core::mem::replace(&mut clk.0, Clk(core::ptr::null_mut()))
+    }
+}
+
+impl Drop for EnabledClk {
+    fn drop(&mut self) {
+        // SAFETY: The pointer is valid by the type invariant.
+        unsafe { bindings::clk_disable_unprepare(self.0 .0) };
+    }
+}
diff --git a/rust/kernel/cred.rs b/rust/kernel/cred.rs
new file mode 100644
index 000000000000..beacc71d92ac
--- /dev/null
+++ b/rust/kernel/cred.rs
@@ -0,0 +1,46 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Credentials management.
+//!
+//! C header: [`include/linux/cred.h`](../../../../include/linux/cred.h)
+//!
+//! Reference: <https://www.kernel.org/doc/html/latest/security/credentials.html>
+
+use crate::{bindings, AlwaysRefCounted};
+use core::cell::UnsafeCell;
+
+/// Wraps the kernel's `struct cred`.
+///
+/// # Invariants
+///
+/// Instances of this type are always ref-counted, that is, a call to `get_cred` ensures that the
+/// allocation remains valid at least until the matching call to `put_cred`.
+#[repr(transparent)]
+pub struct Credential(pub(crate) UnsafeCell<bindings::cred>);
+
+impl Credential {
+    /// Creates a reference to a [`Credential`] from a valid pointer.
+    ///
+    /// # Safety
+    ///
+    /// The caller must ensure that `ptr` is valid and remains valid for the lifetime of the
+    /// returned [`Credential`] reference.
+    pub(crate) unsafe fn from_ptr<'a>(ptr: *const bindings::cred) -> &'a Self {
+        // SAFETY: The safety requirements guarantee the validity of the dereference, while the
+        // `Credential` type being transparent makes the cast ok.
+        unsafe { &*ptr.cast() }
+    }
+}
+
+// SAFETY: The type invariants guarantee that `Credential` is always ref-counted.
+unsafe impl AlwaysRefCounted for Credential {
+    fn inc_ref(&self) {
+        // SAFETY: The existence of a shared reference means that the refcount is nonzero.
+        unsafe { bindings::get_cred(self.0.get()) };
+    }
+
+    unsafe fn dec_ref(obj: core::ptr::NonNull<Self>) {
+        // SAFETY: The safety requirements guarantee that the refcount is nonzero.
+        unsafe { bindings::put_cred(obj.cast().as_ptr()) };
+    }
+}
diff --git a/rust/kernel/device.rs b/rust/kernel/device.rs
new file mode 100644
index 000000000000..236d278f5576
--- /dev/null
+++ b/rust/kernel/device.rs
@@ -0,0 +1,546 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Generic devices that are part of the kernel's driver model.
+//!
+//! C header: [`include/linux/device.h`](../../../../include/linux/device.h)
+
+#[cfg(CONFIG_COMMON_CLK)]
+use crate::{clk::Clk, error::from_kernel_err_ptr};
+
+use crate::{
+    bindings,
+    revocable::{Revocable, RevocableGuard},
+    str::CStr,
+    sync::{NeedsLockClass, RevocableMutex, RevocableMutexGuard, UniqueRef},
+    Result,
+};
+use core::{
+    fmt,
+    ops::{Deref, DerefMut},
+    pin::Pin,
+};
+
+#[cfg(CONFIG_PRINTK)]
+use crate::{c_str, c_types};
+
+/// A raw device.
+///
+/// # Safety
+///
+/// Implementers must ensure that the `*mut device` returned by [`RawDevice::raw_device`] is
+/// related to `self`, that is, actions on it will affect `self`. For example, if one calls
+/// `get_device`, then the refcount on the device represented by `self` will be incremented.
+///
+/// Additionally, implementers must ensure that the device is never renamed. Commit a5462516aa994
+/// has details on why `device_rename` should not be used.
+pub unsafe trait RawDevice {
+    /// Returns the raw `struct device` related to `self`.
+    fn raw_device(&self) -> *mut bindings::device;
+
+    /// Returns the name of the device.
+    fn name(&self) -> &CStr {
+        let ptr = self.raw_device();
+
+        // SAFETY: `ptr` is valid because `self` keeps it alive.
+        let name = unsafe { bindings::dev_name(ptr) };
+
+        // SAFETY: The name of the device remains valid while it is alive (because the device is
+        // never renamed, per the safety requirement of this trait). This is guaranteed to be the
+        // case because the reference to `self` outlives the one of the returned `CStr` (enforced
+        // by the compiler because of their lifetimes).
+        unsafe { CStr::from_char_ptr(name) }
+    }
+
+    /// Lookups a clock producer consumed by this device.
+    ///
+    /// Returns a managed reference to the clock producer.
+    #[cfg(CONFIG_COMMON_CLK)]
+    fn clk_get(&self, id: Option<&CStr>) -> Result<Clk> {
+        let id_ptr = match id {
+            Some(cstr) => cstr.as_char_ptr(),
+            None => core::ptr::null(),
+        };
+
+        // SAFETY: `id_ptr` is optional and may be either a valid pointer
+        // from the type invariant or NULL otherwise.
+        let clk_ptr = unsafe { from_kernel_err_ptr(bindings::clk_get(self.raw_device(), id_ptr)) }?;
+
+        // SAFETY: Clock is initialized with valid pointer returned from `bindings::clk_get` call.
+        unsafe { Ok(Clk::new(clk_ptr)) }
+    }
+
+    /// Prints an emergency-level message (level 0) prefixed with device information.
+    ///
+    /// More details are available from [`dev_emerg`].
+    fn pr_emerg(&self, args: fmt::Arguments<'_>) {
+        // SAFETY: `klevel` is null-terminated, uses one of the kernel constants.
+        unsafe { self.printk(bindings::KERN_EMERG, args) };
+    }
+
+    /// Prints an alert-level message (level 1) prefixed with device information.
+    ///
+    /// More details are available from [`dev_alert`].
+    fn pr_alert(&self, args: fmt::Arguments<'_>) {
+        // SAFETY: `klevel` is null-terminated, uses one of the kernel constants.
+        unsafe { self.printk(bindings::KERN_ALERT, args) };
+    }
+
+    /// Prints a critical-level message (level 2) prefixed with device information.
+    ///
+    /// More details are available from [`dev_crit`].
+    fn pr_crit(&self, args: fmt::Arguments<'_>) {
+        // SAFETY: `klevel` is null-terminated, uses one of the kernel constants.
+        unsafe { self.printk(bindings::KERN_CRIT, args) };
+    }
+
+    /// Prints an error-level message (level 3) prefixed with device information.
+    ///
+    /// More details are available from [`dev_err`].
+    fn pr_err(&self, args: fmt::Arguments<'_>) {
+        // SAFETY: `klevel` is null-terminated, uses one of the kernel constants.
+        unsafe { self.printk(bindings::KERN_ERR, args) };
+    }
+
+    /// Prints a warning-level message (level 4) prefixed with device information.
+    ///
+    /// More details are available from [`dev_warn`].
+    fn pr_warn(&self, args: fmt::Arguments<'_>) {
+        // SAFETY: `klevel` is null-terminated, uses one of the kernel constants.
+        unsafe { self.printk(bindings::KERN_WARNING, args) };
+    }
+
+    /// Prints a notice-level message (level 5) prefixed with device information.
+    ///
+    /// More details are available from [`dev_notice`].
+    fn pr_notice(&self, args: fmt::Arguments<'_>) {
+        // SAFETY: `klevel` is null-terminated, uses one of the kernel constants.
+        unsafe { self.printk(bindings::KERN_NOTICE, args) };
+    }
+
+    /// Prints an info-level message (level 6) prefixed with device information.
+    ///
+    /// More details are available from [`dev_info`].
+    fn pr_info(&self, args: fmt::Arguments<'_>) {
+        // SAFETY: `klevel` is null-terminated, uses one of the kernel constants.
+        unsafe { self.printk(bindings::KERN_INFO, args) };
+    }
+
+    /// Prints a debug-level message (level 7) prefixed with device information.
+    ///
+    /// More details are available from [`dev_dbg`].
+    fn pr_dbg(&self, args: fmt::Arguments<'_>) {
+        if cfg!(debug_assertions) {
+            // SAFETY: `klevel` is null-terminated, uses one of the kernel constants.
+            unsafe { self.printk(bindings::KERN_DEBUG, args) };
+        }
+    }
+
+    /// Prints the provided message to the console.
+    ///
+    /// # Safety
+    ///
+    /// Callers must ensure that `klevel` is null-terminated; in particular, one of the
+    /// `KERN_*`constants, for example, `KERN_CRIT`, `KERN_ALERT`, etc.
+    #[cfg_attr(not(CONFIG_PRINTK), allow(unused_variables))]
+    unsafe fn printk(&self, klevel: &[u8], msg: fmt::Arguments<'_>) {
+        // SAFETY: `klevel` is null-terminated and one of the kernel constants. `self.raw_device`
+        // is valid because `self` is valid. The "%pA" format string expects a pointer to
+        // `fmt::Arguments`, which is what we're passing as the last argument.
+        #[cfg(CONFIG_PRINTK)]
+        unsafe {
+            bindings::_dev_printk(
+                klevel as *const _ as *const c_types::c_char,
+                self.raw_device(),
+                c_str!("%pA").as_char_ptr(),
+                &msg as *const _ as *const c_types::c_void,
+            )
+        };
+    }
+}
+
+/// A ref-counted device.
+///
+/// # Invariants
+///
+/// `ptr` is valid, non-null, and has a non-zero reference count. One of the references is owned by
+/// `self`, and will be decremented when `self` is dropped.
+pub struct Device {
+    pub(crate) ptr: *mut bindings::device,
+}
+
+// SAFETY: `Device` only holds a pointer to a C device, which is safe to be used from any thread.
+unsafe impl Send for Device {}
+
+// SAFETY: `Device` only holds a pointer to a C device, references to which are safe to be used
+// from any thread.
+unsafe impl Sync for Device {}
+
+impl Device {
+    /// Creates a new device instance.
+    ///
+    /// # Safety
+    ///
+    /// Callers must ensure that `ptr` is valid, non-null, and has a non-zero reference count.
+    pub unsafe fn new(ptr: *mut bindings::device) -> Self {
+        // SAFETY: By the safety requirements, ptr is valid and its refcounted will be incremented.
+        unsafe { bindings::get_device(ptr) };
+        // INVARIANT: The safety requirements satisfy all but one invariant, which is that `self`
+        // owns a reference. This is satisfied by the call to `get_device` above.
+        Self { ptr }
+    }
+
+    /// Creates a new device instance from an existing [`RawDevice`] instance.
+    pub fn from_dev(dev: &dyn RawDevice) -> Self {
+        // SAFETY: The requirements are satisfied by the existence of `RawDevice` and its safety
+        // requirements.
+        unsafe { Self::new(dev.raw_device()) }
+    }
+}
+
+// SAFETY: The device returned by `raw_device` is the one for which we hold a reference.
+unsafe impl RawDevice for Device {
+    fn raw_device(&self) -> *mut bindings::device {
+        self.ptr
+    }
+}
+
+impl Drop for Device {
+    fn drop(&mut self) {
+        // SAFETY: By the type invariants, we know that `self` owns a reference, so it is safe to
+        // relinquish it now.
+        unsafe { bindings::put_device(self.ptr) };
+    }
+}
+
+/// Device data.
+///
+/// When a device is removed (for whatever reason, for example, because the device was unplugged or
+/// because the user decided to unbind the driver), the driver is given a chance to clean its state
+/// up, and all io resources should ideally not be used anymore.
+///
+/// However, the device data is reference-counted because other subsystems hold pointers to it. So
+/// some device state must be freed and not used anymore, while others must remain accessible.
+///
+/// This struct separates the device data into three categories:
+///   1. Registrations: are destroyed when the device is removed, but before the io resources
+///      become inaccessible.
+///   2. Io resources: are available until the device is removed.
+///   3. General data: remain available as long as the ref count is nonzero.
+///
+/// This struct implements the `DeviceRemoval` trait so that it can clean resources up even if not
+/// explicitly called by the device drivers.
+pub struct Data<T, U, V> {
+    registrations: RevocableMutex<T>,
+    resources: Revocable<U>,
+    general: V,
+}
+
+/// Safely creates an new reference-counted instance of [`Data`].
+#[doc(hidden)]
+#[macro_export]
+macro_rules! new_device_data {
+    ($reg:expr, $res:expr, $gen:expr, $name:literal) => {{
+        static mut CLASS1: core::mem::MaybeUninit<$crate::bindings::lock_class_key> =
+            core::mem::MaybeUninit::uninit();
+        static mut CLASS2: core::mem::MaybeUninit<$crate::bindings::lock_class_key> =
+            core::mem::MaybeUninit::uninit();
+        let regs = $reg;
+        let res = $res;
+        let gen = $gen;
+        let name = $crate::c_str!($name);
+        // SAFETY: `CLASS1` and `CLASS2` are never used by Rust code directly; the C portion of the
+        // kernel may change it though.
+        unsafe {
+            $crate::device::Data::try_new(
+                regs,
+                res,
+                gen,
+                name,
+                CLASS1.as_mut_ptr(),
+                CLASS2.as_mut_ptr(),
+            )
+        }
+    }};
+}
+
+impl<T, U, V> Data<T, U, V> {
+    /// Creates a new instance of `Data`.
+    ///
+    /// It is recommended that the [`new_device_data`] macro be used as it automatically creates
+    /// the lock classes.
+    ///
+    /// # Safety
+    ///
+    /// `key1` and `key2` must point to valid memory locations and remain valid until `self` is
+    /// dropped.
+    pub unsafe fn try_new(
+        registrations: T,
+        resources: U,
+        general: V,
+        name: &'static CStr,
+        key1: *mut bindings::lock_class_key,
+        key2: *mut bindings::lock_class_key,
+    ) -> Result<Pin<UniqueRef<Self>>> {
+        let mut ret = Pin::from(UniqueRef::try_new(Self {
+            // SAFETY: We call `RevocableMutex::init` below.
+            registrations: unsafe { RevocableMutex::new(registrations) },
+            resources: Revocable::new(resources),
+            general,
+        })?);
+
+        // SAFETY: `Data::registrations` is pinned when `Data` is.
+        let pinned = unsafe { ret.as_mut().map_unchecked_mut(|d| &mut d.registrations) };
+
+        // SAFETY: The safety requirements of this function satisfy those of `RevocableMutex::init`.
+        unsafe { pinned.init(name, key1, key2) };
+        Ok(ret)
+    }
+
+    /// Returns the resources if they're still available.
+    pub fn resources(&self) -> Option<RevocableGuard<'_, U>> {
+        self.resources.try_access()
+    }
+
+    /// Returns the locked registrations if they're still available.
+    pub fn registrations(&self) -> Option<RevocableMutexGuard<'_, T>> {
+        self.registrations.try_write()
+    }
+}
+
+impl<T, U, V> crate::driver::DeviceRemoval for Data<T, U, V> {
+    fn device_remove(&self) {
+        // We revoke the registrations first so that resources are still available to them during
+        // unregistration.
+        self.registrations.revoke();
+
+        // Release resources now. General data remains available.
+        self.resources.revoke();
+    }
+}
+
+impl<T, U, V> Deref for Data<T, U, V> {
+    type Target = V;
+
+    fn deref(&self) -> &V {
+        &self.general
+    }
+}
+
+impl<T, U, V> DerefMut for Data<T, U, V> {
+    fn deref_mut(&mut self) -> &mut V {
+        &mut self.general
+    }
+}
+
+#[doc(hidden)]
+#[macro_export]
+macro_rules! dev_printk {
+    ($method:ident, $dev:expr, $($f:tt)*) => {
+        {
+            // We have an explicity `use` statement here so that callers of this macro are not
+            // required to explicitly use the `RawDevice` trait to use its functions.
+            use $crate::device::RawDevice;
+            ($dev).$method(core::format_args!($($f)*));
+        }
+    }
+}
+
+/// Prints an emergency-level message (level 0) prefixed with device information.
+///
+/// This level should be used if the system is unusable.
+///
+/// Equivalent to the kernel's `dev_emerg` macro.
+///
+/// Mimics the interface of [`std::print!`]. More information about the syntax is available from
+/// [`core::fmt`] and [`alloc::format!`].
+///
+/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::device::Device;
+///
+/// fn example(dev: &Device) {
+///     dev_emerg!(dev, "hello {}\n", "there");
+/// }
+/// ```
+#[macro_export]
+macro_rules! dev_emerg {
+    ($($f:tt)*) => { $crate::dev_printk!(pr_emerg, $($f)*); }
+}
+
+/// Prints an alert-level message (level 1) prefixed with device information.
+///
+/// This level should be used if action must be taken immediately.
+///
+/// Equivalent to the kernel's `dev_alert` macro.
+///
+/// Mimics the interface of [`std::print!`]. More information about the syntax is available from
+/// [`core::fmt`] and [`alloc::format!`].
+///
+/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::device::Device;
+///
+/// fn example(dev: &Device) {
+///     dev_alert!(dev, "hello {}\n", "there");
+/// }
+/// ```
+#[macro_export]
+macro_rules! dev_alert {
+    ($($f:tt)*) => { $crate::dev_printk!(pr_alert, $($f)*); }
+}
+
+/// Prints a critical-level message (level 2) prefixed with device information.
+///
+/// This level should be used in critical conditions.
+///
+/// Equivalent to the kernel's `dev_crit` macro.
+///
+/// Mimics the interface of [`std::print!`]. More information about the syntax is available from
+/// [`core::fmt`] and [`alloc::format!`].
+///
+/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::device::Device;
+///
+/// fn example(dev: &Device) {
+///     dev_crit!(dev, "hello {}\n", "there");
+/// }
+/// ```
+#[macro_export]
+macro_rules! dev_crit {
+    ($($f:tt)*) => { $crate::dev_printk!(pr_crit, $($f)*); }
+}
+
+/// Prints an error-level message (level 3) prefixed with device information.
+///
+/// This level should be used in error conditions.
+///
+/// Equivalent to the kernel's `dev_err` macro.
+///
+/// Mimics the interface of [`std::print!`]. More information about the syntax is available from
+/// [`core::fmt`] and [`alloc::format!`].
+///
+/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::device::Device;
+///
+/// fn example(dev: &Device) {
+///     dev_err!(dev, "hello {}\n", "there");
+/// }
+/// ```
+#[macro_export]
+macro_rules! dev_err {
+    ($($f:tt)*) => { $crate::dev_printk!(pr_err, $($f)*); }
+}
+
+/// Prints a warning-level message (level 4) prefixed with device information.
+///
+/// This level should be used in warning conditions.
+///
+/// Equivalent to the kernel's `dev_warn` macro.
+///
+/// Mimics the interface of [`std::print!`]. More information about the syntax is available from
+/// [`core::fmt`] and [`alloc::format!`].
+///
+/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::device::Device;
+///
+/// fn example(dev: &Device) {
+///     dev_warn!(dev, "hello {}\n", "there");
+/// }
+/// ```
+#[macro_export]
+macro_rules! dev_warn {
+    ($($f:tt)*) => { $crate::dev_printk!(pr_warn, $($f)*); }
+}
+
+/// Prints a notice-level message (level 5) prefixed with device information.
+///
+/// This level should be used in normal but significant conditions.
+///
+/// Equivalent to the kernel's `dev_notice` macro.
+///
+/// Mimics the interface of [`std::print!`]. More information about the syntax is available from
+/// [`core::fmt`] and [`alloc::format!`].
+///
+/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::device::Device;
+///
+/// fn example(dev: &Device) {
+///     dev_notice!(dev, "hello {}\n", "there");
+/// }
+/// ```
+#[macro_export]
+macro_rules! dev_notice {
+    ($($f:tt)*) => { $crate::dev_printk!(pr_notice, $($f)*); }
+}
+
+/// Prints an info-level message (level 6) prefixed with device information.
+///
+/// This level should be used for informational messages.
+///
+/// Equivalent to the kernel's `dev_info` macro.
+///
+/// Mimics the interface of [`std::print!`]. More information about the syntax is available from
+/// [`core::fmt`] and [`alloc::format!`].
+///
+/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::device::Device;
+///
+/// fn example(dev: &Device) {
+///     dev_info!(dev, "hello {}\n", "there");
+/// }
+/// ```
+#[macro_export]
+macro_rules! dev_info {
+    ($($f:tt)*) => { $crate::dev_printk!(pr_info, $($f)*); }
+}
+
+/// Prints a debug-level message (level 7) prefixed with device information.
+///
+/// This level should be used for debug messages.
+///
+/// Equivalent to the kernel's `dev_dbg` macro, except that it doesn't support dynamic debug yet.
+///
+/// Mimics the interface of [`std::print!`]. More information about the syntax is available from
+/// [`core::fmt`] and [`alloc::format!`].
+///
+/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::device::Device;
+///
+/// fn example(dev: &Device) {
+///     dev_dbg!(dev, "hello {}\n", "there");
+/// }
+/// ```
+#[macro_export]
+macro_rules! dev_dbg {
+    ($($f:tt)*) => { $crate::dev_printk!(pr_dbg, $($f)*); }
+}
diff --git a/rust/kernel/driver.rs b/rust/kernel/driver.rs
new file mode 100644
index 000000000000..0ae9f4d3dbc5
--- /dev/null
+++ b/rust/kernel/driver.rs
@@ -0,0 +1,442 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Generic support for drivers of different buses (e.g., PCI, Platform, Amba, etc.).
+//!
+//! Each bus/subsystem is expected to implement [`DriverOps`], which allows drivers to register
+//! using the [`Registration`] class.
+
+use crate::{error::code::*, str::CStr, sync::Ref, Result, ThisModule};
+use alloc::boxed::Box;
+use core::{cell::UnsafeCell, marker::PhantomData, ops::Deref, pin::Pin};
+
+/// A subsystem (e.g., PCI, Platform, Amba, etc.) that allows drivers to be written for it.
+pub trait DriverOps {
+    /// The type that holds information about the registration. This is typically a struct defined
+    /// by the C portion of the kernel.
+    type RegType: Default;
+
+    /// Registers a driver.
+    ///
+    /// # Safety
+    ///
+    /// `reg` must point to valid, initialised, and writable memory. It may be modified by this
+    /// function to hold registration state.
+    ///
+    /// On success, `reg` must remain pinned and valid until the matching call to
+    /// [`DriverOps::unregister`].
+    unsafe fn register(
+        reg: *mut Self::RegType,
+        name: &'static CStr,
+        module: &'static ThisModule,
+    ) -> Result;
+
+    /// Unregisters a driver previously registered with [`DriverOps::register`].
+    ///
+    /// # Safety
+    ///
+    /// `reg` must point to valid writable memory, initialised by a previous successful call to
+    /// [`DriverOps::register`].
+    unsafe fn unregister(reg: *mut Self::RegType);
+}
+
+/// The registration of a driver.
+pub struct Registration<T: DriverOps> {
+    is_registered: bool,
+    concrete_reg: UnsafeCell<T::RegType>,
+}
+
+// SAFETY: `Registration` has no fields or methods accessible via `&Registration`, so it is safe to
+// share references to it with multiple threads as nothing can be done.
+unsafe impl<T: DriverOps> Sync for Registration<T> {}
+
+impl<T: DriverOps> Registration<T> {
+    /// Creates a new instance of the registration object.
+    pub fn new() -> Self {
+        Self {
+            is_registered: false,
+            concrete_reg: UnsafeCell::new(T::RegType::default()),
+        }
+    }
+
+    /// Allocates a pinned registration object and registers it.
+    ///
+    /// Returns a pinned heap-allocated representation of the registration.
+    pub fn new_pinned(name: &'static CStr, module: &'static ThisModule) -> Result<Pin<Box<Self>>> {
+        let mut reg = Pin::from(Box::try_new(Self::new())?);
+        reg.as_mut().register(name, module)?;
+        Ok(reg)
+    }
+
+    /// Registers a driver with its subsystem.
+    ///
+    /// It must be pinned because the memory block that represents the registration is potentially
+    /// self-referential.
+    pub fn register(
+        self: Pin<&mut Self>,
+        name: &'static CStr,
+        module: &'static ThisModule,
+    ) -> Result {
+        // SAFETY: We never move out of `this`.
+        let this = unsafe { self.get_unchecked_mut() };
+        if this.is_registered {
+            // Already registered.
+            return Err(EINVAL);
+        }
+
+        // SAFETY: `concrete_reg` was initialised via its default constructor. It is only freed
+        // after `Self::drop` is called, which first calls `T::unregister`.
+        unsafe { T::register(this.concrete_reg.get(), name, module) }?;
+
+        this.is_registered = true;
+        Ok(())
+    }
+}
+
+impl<T: DriverOps> Default for Registration<T> {
+    fn default() -> Self {
+        Self::new()
+    }
+}
+
+impl<T: DriverOps> Drop for Registration<T> {
+    fn drop(&mut self) {
+        if self.is_registered {
+            // SAFETY: This path only runs if a previous call to `T::register` completed
+            // successfully.
+            unsafe { T::unregister(self.concrete_reg.get()) };
+        }
+    }
+}
+
+/// Conversion from a device id to a raw device id.
+///
+/// This is meant to be implemented by buses/subsystems so that they can use [`IdTable`] to
+/// guarantee (at compile-time) zero-termination of device id tables provided by drivers.
+///
+/// # Safety
+///
+/// Implementers must ensure that:
+///   - [`RawDeviceId::ZERO`] is actually a zeroed-out version of the raw device id.
+///   - [`RawDeviceId::to_rawid`] stores `offset` in the context/data field of the raw device id so
+///     that buses can recover the pointer to the data.
+pub unsafe trait RawDeviceId {
+    /// The raw type that holds the device id.
+    ///
+    /// Id tables created from [`Self`] are going to hold this type in its zero-terminated array.
+    type RawType: Copy;
+
+    /// A zeroed-out representation of the raw device id.
+    ///
+    /// Id tables created from [`Self`] use [`Self::ZERO`] as the sentinel to indicate the end of
+    /// the table.
+    const ZERO: Self::RawType;
+
+    /// Converts an id into a raw id.
+    ///
+    /// `offset` is the offset from the memory location where the raw device id is stored to the
+    /// location where its associated context information is stored. Implementations must store
+    /// this in the appropriate context/data field of the raw type.
+    fn to_rawid(&self, offset: isize) -> Self::RawType;
+}
+
+/// A zero-terminated device id array, followed by context data.
+#[repr(C)]
+pub struct IdArray<T: RawDeviceId, U, const N: usize> {
+    ids: [T::RawType; N],
+    sentinel: T::RawType,
+    id_infos: [Option<U>; N],
+}
+
+impl<T: RawDeviceId, U, const N: usize> IdArray<T, U, N> {
+    /// Creates a new instance of the array.
+    ///
+    /// The contents are derived from the given identifiers and context information.
+    pub const fn new(ids: [T; N], infos: [Option<U>; N]) -> Self
+    where
+        T: ~const RawDeviceId + Copy,
+    {
+        let mut array = Self {
+            ids: [T::ZERO; N],
+            sentinel: T::ZERO,
+            id_infos: infos,
+        };
+        let mut i = 0usize;
+        while i < N {
+            // SAFETY: Both pointers are within `array` (or one byte beyond), consequently they are
+            // derived from the same allocated object. We are using a `u8` pointer, whose size 1,
+            // so the pointers are necessarily 1-byte aligned.
+            let offset = unsafe {
+                (&array.id_infos[i] as *const _ as *const u8)
+                    .offset_from(&array.ids[i] as *const _ as _)
+            };
+            array.ids[i] = ids[i].to_rawid(offset);
+            i += 1;
+        }
+        array
+    }
+
+    /// Returns an `IdTable` backed by `self`.
+    ///
+    /// This is used to essentially erase the array size.
+    pub const fn as_table(&self) -> IdTable<'_, T, U> {
+        IdTable {
+            first: &self.ids[0],
+            _p: PhantomData,
+        }
+    }
+}
+
+/// A device id table.
+///
+/// The table is guaranteed to be zero-terminated and to be followed by an array of context data of
+/// type `Option<U>`.
+pub struct IdTable<'a, T: RawDeviceId, U> {
+    first: &'a T::RawType,
+    _p: PhantomData<&'a U>,
+}
+
+impl<T: RawDeviceId, U> const AsRef<T::RawType> for IdTable<'_, T, U> {
+    fn as_ref(&self) -> &T::RawType {
+        self.first
+    }
+}
+
+/// Counts the number of parenthesis-delimited, comma-separated items.
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::count_paren_items;
+///
+/// assert_eq!(0, count_paren_items!());
+/// assert_eq!(1, count_paren_items!((A)));
+/// assert_eq!(1, count_paren_items!((A),));
+/// assert_eq!(2, count_paren_items!((A), (B)));
+/// assert_eq!(2, count_paren_items!((A), (B),));
+/// assert_eq!(3, count_paren_items!((A), (B), (C)));
+/// assert_eq!(3, count_paren_items!((A), (B), (C),));
+/// ```
+#[macro_export]
+macro_rules! count_paren_items {
+    (($($item:tt)*), $($remaining:tt)*) => { 1 + $crate::count_paren_items!($($remaining)*) };
+    (($($item:tt)*)) => { 1 };
+    () => { 0 };
+}
+
+/// Converts a comma-separated list of pairs into an array with the first element. That is, it
+/// discards the second element of the pair.
+///
+/// Additionally, it automatically introduces a type if the first element is warpped in curly
+/// braces, for example, if it's `{v: 10}`, it becomes `X { v: 10 }`; this is to avoid repeating
+/// the type.
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::first_item;
+///
+/// #[derive(PartialEq, Debug)]
+/// struct X {
+///     v: u32,
+/// }
+///
+/// assert_eq!([] as [X; 0], first_item!(X, ));
+/// assert_eq!([X { v: 10 }], first_item!(X, ({ v: 10 }, Y)));
+/// assert_eq!([X { v: 10 }], first_item!(X, ({ v: 10 }, Y),));
+/// assert_eq!([X { v: 10 }], first_item!(X, (X { v: 10 }, Y)));
+/// assert_eq!([X { v: 10 }], first_item!(X, (X { v: 10 }, Y),));
+/// assert_eq!([X { v: 10 }, X { v: 20 }], first_item!(X, ({ v: 10 }, Y), ({ v: 20 }, Y)));
+/// assert_eq!([X { v: 10 }, X { v: 20 }], first_item!(X, ({ v: 10 }, Y), ({ v: 20 }, Y),));
+/// assert_eq!([X { v: 10 }, X { v: 20 }], first_item!(X, (X { v: 10 }, Y), (X { v: 20 }, Y)));
+/// assert_eq!([X { v: 10 }, X { v: 20 }], first_item!(X, (X { v: 10 }, Y), (X { v: 20 }, Y),));
+/// assert_eq!([X { v: 10 }, X { v: 20 }, X { v: 30 }],
+///            first_item!(X, ({ v: 10 }, Y), ({ v: 20 }, Y), ({v: 30}, Y)));
+/// assert_eq!([X { v: 10 }, X { v: 20 }, X { v: 30 }],
+///            first_item!(X, ({ v: 10 }, Y), ({ v: 20 }, Y), ({v: 30}, Y),));
+/// assert_eq!([X { v: 10 }, X { v: 20 }, X { v: 30 }],
+///            first_item!(X, (X { v: 10 }, Y), (X { v: 20 }, Y), (X {v: 30}, Y)));
+/// assert_eq!([X { v: 10 }, X { v: 20 }, X { v: 30 }],
+///            first_item!(X, (X { v: 10 }, Y), (X { v: 20 }, Y), (X {v: 30}, Y),));
+/// ```
+#[macro_export]
+macro_rules! first_item {
+    ($id_type:ty, $(({$($first:tt)*}, $second:expr)),* $(,)?) => {
+        {
+            type IdType = $id_type;
+            [$(IdType{$($first)*},)*]
+        }
+    };
+    ($id_type:ty, $(($first:expr, $second:expr)),* $(,)?) => { [$($first,)*] };
+}
+
+/// Converts a comma-separated list of pairs into an array with the second element. That is, it
+/// discards the first element of the pair.
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::second_item;
+///
+/// assert_eq!([] as [u32; 0], second_item!());
+/// assert_eq!([10u32], second_item!((X, 10u32)));
+/// assert_eq!([10u32], second_item!((X, 10u32),));
+/// assert_eq!([10u32], second_item!(({X}, 10u32)));
+/// assert_eq!([10u32], second_item!(({X}, 10u32),));
+/// assert_eq!([10u32, 20], second_item!((X, 10u32), (X, 20)));
+/// assert_eq!([10u32, 20], second_item!((X, 10u32), (X, 20),));
+/// assert_eq!([10u32, 20], second_item!(({X}, 10u32), ({X}, 20)));
+/// assert_eq!([10u32, 20], second_item!(({X}, 10u32), ({X}, 20),));
+/// assert_eq!([10u32, 20, 30], second_item!((X, 10u32), (X, 20), (X, 30)));
+/// assert_eq!([10u32, 20, 30], second_item!((X, 10u32), (X, 20), (X, 30),));
+/// assert_eq!([10u32, 20, 30], second_item!(({X}, 10u32), ({X}, 20), ({X}, 30)));
+/// assert_eq!([10u32, 20, 30], second_item!(({X}, 10u32), ({X}, 20), ({X}, 30),));
+/// ```
+#[macro_export]
+macro_rules! second_item {
+    ($(({$($first:tt)*}, $second:expr)),* $(,)?) => { [$($second,)*] };
+    ($(($first:expr, $second:expr)),* $(,)?) => { [$($second,)*] };
+}
+
+/// Defines a new constant [`IdArray`] with a concise syntax.
+///
+/// It is meant to be used by buses and subsystems to create a similar macro with their device id
+/// type already specified, i.e., with fewer parameters to the end user.
+///
+/// # Examples
+///
+// TODO: Exported but not usable by kernel modules (requires `const_trait_impl`).
+/// ```ignore
+/// #![feature(const_trait_impl)]
+/// # use kernel::{define_id_array, driver::RawDeviceId};
+///
+/// #[derive(Copy, Clone)]
+/// struct Id(u32);
+///
+/// // SAFETY: `ZERO` is all zeroes and `to_rawid` stores `offset` as the second element of the raw
+/// // device id pair.
+/// unsafe impl const RawDeviceId for Id {
+///     type RawType = (u64, isize);
+///     const ZERO: Self::RawType = (0, 0);
+///     fn to_rawid(&self, offset: isize) -> Self::RawType {
+///         (self.0 as u64 + 1, offset)
+///     }
+/// }
+///
+/// define_id_array!(A1, Id, (), []);
+/// define_id_array!(A2, Id, &'static [u8], [(Id(10), None)]);
+/// define_id_array!(A3, Id, &'static [u8], [(Id(10), Some(b"id1")), ]);
+/// define_id_array!(A4, Id, &'static [u8], [(Id(10), Some(b"id1")), (Id(20), Some(b"id2"))]);
+/// define_id_array!(A5, Id, &'static [u8], [(Id(10), Some(b"id1")), (Id(20), Some(b"id2")), ]);
+/// define_id_array!(A6, Id, &'static [u8], [(Id(10), None), (Id(20), Some(b"id2")), ]);
+/// define_id_array!(A7, Id, &'static [u8], [(Id(10), Some(b"id1")), (Id(20), None), ]);
+/// define_id_array!(A8, Id, &'static [u8], [(Id(10), None), (Id(20), None), ]);
+/// ```
+#[macro_export]
+macro_rules! define_id_array {
+    ($table_name:ident, $id_type:ty, $data_type:ty, [ $($t:tt)* ]) => {
+        const $table_name:
+            $crate::driver::IdArray<$id_type, $data_type, { $crate::count_paren_items!($($t)*) }> =
+                $crate::driver::IdArray::new(
+                    $crate::first_item!($id_type, $($t)*), $crate::second_item!($($t)*));
+    };
+}
+
+/// Defines a new constant [`IdTable`] with a concise syntax.
+///
+/// It is meant to be used by buses and subsystems to create a similar macro with their device id
+/// type already specified, i.e., with fewer parameters to the end user.
+///
+/// # Examples
+///
+// TODO: Exported but not usable by kernel modules (requires `const_trait_impl`).
+/// ```ignore
+/// #![feature(const_trait_impl)]
+/// # use kernel::{define_id_table, driver::RawDeviceId};
+///
+/// #[derive(Copy, Clone)]
+/// struct Id(u32);
+///
+/// // SAFETY: `ZERO` is all zeroes and `to_rawid` stores `offset` as the second element of the raw
+/// // device id pair.
+/// unsafe impl const RawDeviceId for Id {
+///     type RawType = (u64, isize);
+///     const ZERO: Self::RawType = (0, 0);
+///     fn to_rawid(&self, offset: isize) -> Self::RawType {
+///         (self.0 as u64 + 1, offset)
+///     }
+/// }
+///
+/// define_id_table!(T1, Id, &'static [u8], [(Id(10), None)]);
+/// define_id_table!(T2, Id, &'static [u8], [(Id(10), Some(b"id1")), ]);
+/// define_id_table!(T3, Id, &'static [u8], [(Id(10), Some(b"id1")), (Id(20), Some(b"id2"))]);
+/// define_id_table!(T4, Id, &'static [u8], [(Id(10), Some(b"id1")), (Id(20), Some(b"id2")), ]);
+/// define_id_table!(T5, Id, &'static [u8], [(Id(10), None), (Id(20), Some(b"id2")), ]);
+/// define_id_table!(T6, Id, &'static [u8], [(Id(10), Some(b"id1")), (Id(20), None), ]);
+/// define_id_table!(T7, Id, &'static [u8], [(Id(10), None), (Id(20), None), ]);
+/// ```
+#[macro_export]
+macro_rules! define_id_table {
+    ($table_name:ident, $id_type:ty, $data_type:ty, [ $($t:tt)* ]) => {
+        const $table_name: Option<$crate::driver::IdTable<'static, $id_type, $data_type>> = {
+            $crate::define_id_array!(ARRAY, $id_type, $data_type, [ $($t)* ]);
+            Some(ARRAY.as_table())
+        };
+    };
+}
+
+/// Custom code within device removal.
+pub trait DeviceRemoval {
+    /// Cleans resources up when the device is removed.
+    ///
+    /// This is called when a device is removed and offers implementers the chance to run some code
+    /// that cleans state up.
+    fn device_remove(&self);
+}
+
+impl DeviceRemoval for () {
+    fn device_remove(&self) {}
+}
+
+impl<T: DeviceRemoval> DeviceRemoval for Ref<T> {
+    fn device_remove(&self) {
+        self.deref().device_remove();
+    }
+}
+
+impl<T: DeviceRemoval> DeviceRemoval for Box<T> {
+    fn device_remove(&self) {
+        self.deref().device_remove();
+    }
+}
+
+/// A kernel module that only registers the given driver on init.
+///
+/// This is a helper struct to make it easier to define single-functionality modules, in this case,
+/// modules that offer a single driver.
+pub struct Module<T: DriverOps> {
+    _driver: Pin<Box<Registration<T>>>,
+}
+
+impl<T: DriverOps> crate::Module for Module<T> {
+    fn init(name: &'static CStr, module: &'static ThisModule) -> Result<Self> {
+        Ok(Self {
+            _driver: Registration::new_pinned(name, module)?,
+        })
+    }
+}
+
+/// Declares a kernel module that exposes a single driver.
+///
+/// It is meant to be used as a helper by other subsystems so they can more easily expose their own
+/// macros.
+#[macro_export]
+macro_rules! module_driver {
+    (<$gen_type:ident>, $driver_ops:ty, { type: $type:ty, $($f:tt)* }) => {
+        type Ops<$gen_type> = $driver_ops;
+        type ModuleType = $crate::driver::Module<Ops<$type>>;
+        $crate::prelude::module! {
+            type: ModuleType,
+            $($f)*
+        }
+    }
+}
diff --git a/rust/kernel/error.rs b/rust/kernel/error.rs
new file mode 100644
index 000000000000..55029cf09a91
--- /dev/null
+++ b/rust/kernel/error.rs
@@ -0,0 +1,565 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Kernel errors.
+//!
+//! C header: [`include/uapi/asm-generic/errno-base.h`](../../../include/uapi/asm-generic/errno-base.h)
+
+use crate::str::CStr;
+use crate::{bindings, c_types};
+use alloc::{
+    alloc::{AllocError, LayoutError},
+    collections::TryReserveError,
+};
+use core::convert::From;
+use core::fmt;
+use core::num::TryFromIntError;
+use core::str::{self, Utf8Error};
+
+/// Contains the C-compatible error codes.
+pub mod code {
+    macro_rules! declare_err {
+        ($err:tt $(,)? $($doc:expr),+) => {
+            $(
+            #[doc = $doc]
+            )*
+            pub const $err: super::Error = super::Error(-(crate::bindings::$err as i32));
+        };
+    }
+
+    declare_err!(EPERM, "Operation not permitted.");
+
+    declare_err!(ENOENT, "No such file or directory.");
+
+    declare_err!(ESRCH, "No such process.");
+
+    declare_err!(EINTR, "Interrupted system call.");
+
+    declare_err!(EIO, "I/O error.");
+
+    declare_err!(ENXIO, "No such device or address.");
+
+    declare_err!(E2BIG, "Argument list too long.");
+
+    declare_err!(ENOEXEC, "Exec format error.");
+
+    declare_err!(EBADF, "Bad file number.");
+
+    declare_err!(ECHILD, "Exec format error.");
+
+    declare_err!(EAGAIN, "Try again.");
+
+    declare_err!(ENOMEM, "Out of memory.");
+
+    declare_err!(EACCES, "Permission denied.");
+
+    declare_err!(EFAULT, "Bad address.");
+
+    declare_err!(ENOTBLK, "Block device required.");
+
+    declare_err!(EBUSY, "Device or resource busy.");
+
+    declare_err!(EEXIST, "File exists.");
+
+    declare_err!(EXDEV, "Cross-device link.");
+
+    declare_err!(ENODEV, "No such device.");
+
+    declare_err!(ENOTDIR, "Not a directory.");
+
+    declare_err!(EISDIR, "Is a directory.");
+
+    declare_err!(EINVAL, "Invalid argument.");
+
+    declare_err!(ENFILE, "File table overflow.");
+
+    declare_err!(EMFILE, "Too many open files.");
+
+    declare_err!(ENOTTY, "Not a typewriter.");
+
+    declare_err!(ETXTBSY, "Text file busy.");
+
+    declare_err!(EFBIG, "File too large.");
+
+    declare_err!(ENOSPC, "No space left on device.");
+
+    declare_err!(ESPIPE, "Illegal seek.");
+
+    declare_err!(EROFS, "Read-only file system.");
+
+    declare_err!(EMLINK, "Too many links.");
+
+    declare_err!(EPIPE, "Broken pipe.");
+
+    declare_err!(EDOM, "Math argument out of domain of func.");
+
+    declare_err!(ERANGE, "Math result not representable.");
+
+    declare_err!(EDEADLK, "Resource deadlock would occur");
+
+    declare_err!(ENAMETOOLONG, "File name too long");
+
+    declare_err!(ENOLCK, "No record locks available");
+
+    declare_err!(
+        ENOSYS,
+        "Invalid system call number.",
+        "",
+        "This error code is special: arch syscall entry code will return",
+        "[`ENOSYS`] if users try to call a syscall that doesn't exist.",
+        "To keep failures of syscalls that really do exist distinguishable from",
+        "failures due to attempts to use a nonexistent syscall, syscall",
+        "implementations should refrain from returning [`ENOSYS`]."
+    );
+
+    declare_err!(ENOTEMPTY, "Directory not empty.");
+
+    declare_err!(ELOOP, "Too many symbolic links encountered.");
+
+    declare_err!(EWOULDBLOCK, "Operation would block.");
+
+    declare_err!(ENOMSG, "No message of desired type.");
+
+    declare_err!(EIDRM, "Identifier removed.");
+
+    declare_err!(ECHRNG, "Channel number out of range.");
+
+    declare_err!(EL2NSYNC, "Level 2 not synchronized.");
+
+    declare_err!(EL3HLT, "Level 3 halted.");
+
+    declare_err!(EL3RST, "Level 3 reset.");
+
+    declare_err!(ELNRNG, "Link number out of range.");
+
+    declare_err!(EUNATCH, "Protocol driver not attached.");
+
+    declare_err!(ENOCSI, "No CSI structure available.");
+
+    declare_err!(EL2HLT, "Level 2 halted.");
+
+    declare_err!(EBADE, "Invalid exchange.");
+
+    declare_err!(EBADR, "Invalid request descriptor.");
+
+    declare_err!(EXFULL, "Exchange full.");
+
+    declare_err!(ENOANO, "No anode.");
+
+    declare_err!(EBADRQC, "Invalid request code.");
+
+    declare_err!(EBADSLT, "Invalid slot.");
+
+    declare_err!(EDEADLOCK, "Resource deadlock would occur.");
+
+    declare_err!(EBFONT, "Bad font file format.");
+
+    declare_err!(ENOSTR, "Device not a stream.");
+
+    declare_err!(ENODATA, "No data available.");
+
+    declare_err!(ETIME, "Timer expired.");
+
+    declare_err!(ENOSR, "Out of streams resources.");
+
+    declare_err!(ENONET, "Machine is not on the network.");
+
+    declare_err!(ENOPKG, "Package not installed.");
+
+    declare_err!(EREMOTE, "Object is remote.");
+
+    declare_err!(ENOLINK, "Link has been severed.");
+
+    declare_err!(EADV, "Advertise error.");
+
+    declare_err!(ESRMNT, "Srmount error.");
+
+    declare_err!(ECOMM, "Communication error on send.");
+
+    declare_err!(EPROTO, "Protocol error.");
+
+    declare_err!(EMULTIHOP, "Multihop attempted.");
+
+    declare_err!(EDOTDOT, "RFS specific error.");
+
+    declare_err!(EBADMSG, "Not a data message.");
+
+    declare_err!(EOVERFLOW, "Value too large for defined data type.");
+
+    declare_err!(ENOTUNIQ, "Name not unique on network.");
+
+    declare_err!(EBADFD, "File descriptor in bad state.");
+
+    declare_err!(EREMCHG, "Remote address changed.");
+
+    declare_err!(ELIBACC, "Can not access a needed shared library.");
+
+    declare_err!(ELIBBAD, "Accessing a corrupted shared library.");
+
+    declare_err!(ELIBSCN, ".lib section in a.out corrupted.");
+
+    declare_err!(ELIBMAX, "Attempting to link in too many shared libraries.");
+
+    declare_err!(ELIBEXEC, "Cannot exec a shared library directly.");
+
+    declare_err!(EILSEQ, "Illegal byte sequence.");
+
+    declare_err!(ERESTART, "Interrupted system call should be restarted.");
+
+    declare_err!(ESTRPIPE, "Streams pipe error.");
+
+    declare_err!(EUSERS, "Too many users.");
+
+    declare_err!(ENOTSOCK, "Socket operation on non-socket.");
+
+    declare_err!(EDESTADDRREQ, "Destination address required.");
+
+    declare_err!(EMSGSIZE, "Message too long.");
+
+    declare_err!(EPROTOTYPE, "Protocol wrong type for socket.");
+
+    declare_err!(ENOPROTOOPT, "Protocol not available.");
+
+    declare_err!(EPROTONOSUPPORT, "Protocol not supported.");
+
+    declare_err!(ESOCKTNOSUPPORT, "Socket type not supported.");
+
+    declare_err!(EOPNOTSUPP, "Operation not supported on transport endpoint.");
+
+    declare_err!(EPFNOSUPPORT, "Protocol family not supported.");
+
+    declare_err!(EAFNOSUPPORT, "Address family not supported by protocol.");
+
+    declare_err!(EADDRINUSE, "Address already in use.");
+
+    declare_err!(EADDRNOTAVAIL, "Cannot assign requested address.");
+
+    declare_err!(ENETDOWN, "Network is down.");
+
+    declare_err!(ENETUNREACH, "Network is unreachable.");
+
+    declare_err!(ENETRESET, "Network dropped connection because of reset.");
+
+    declare_err!(ECONNABORTED, "Software caused connection abort.");
+
+    declare_err!(ECONNRESET, "Connection reset by peer.");
+
+    declare_err!(ENOBUFS, "No buffer space available.");
+
+    declare_err!(EISCONN, "Transport endpoint is already connected.");
+
+    declare_err!(ENOTCONN, "Transport endpoint is not connected.");
+
+    declare_err!(ESHUTDOWN, "Cannot send after transport endpoint shutdown.");
+
+    declare_err!(ETOOMANYREFS, "Too many references: cannot splice.");
+
+    declare_err!(ETIMEDOUT, "Connection timed out.");
+
+    declare_err!(ECONNREFUSED, "Connection refused.");
+
+    declare_err!(EHOSTDOWN, "Host is down.");
+
+    declare_err!(EHOSTUNREACH, "No route to host.");
+
+    declare_err!(EALREADY, "Operation already in progress.");
+
+    declare_err!(EINPROGRESS, "Operation now in progress.");
+
+    declare_err!(ESTALE, "Stale file handle.");
+
+    declare_err!(EUCLEAN, "Structure needs cleaning.");
+
+    declare_err!(ENOTNAM, "Not a XENIX named type file.");
+
+    declare_err!(ENAVAIL, "No XENIX semaphores available.");
+
+    declare_err!(EISNAM, "Is a named type file.");
+
+    declare_err!(EREMOTEIO, "Remote I/O error.");
+
+    declare_err!(EDQUOT, "Quota exceeded.");
+
+    declare_err!(ENOMEDIUM, "No medium found.");
+
+    declare_err!(EMEDIUMTYPE, "Wrong medium type.");
+
+    declare_err!(ECANCELED, "Operation Canceled.");
+
+    declare_err!(ENOKEY, "Required key not available.");
+
+    declare_err!(EKEYEXPIRED, "Key has expired.");
+
+    declare_err!(EKEYREVOKED, "Key has been revoked.");
+
+    declare_err!(EKEYREJECTED, "Key was rejected by service.");
+
+    declare_err!(EOWNERDEAD, "Owner died.", "", "For robust mutexes.");
+
+    declare_err!(ENOTRECOVERABLE, "State not recoverable.");
+
+    declare_err!(ERFKILL, "Operation not possible due to RF-kill.");
+
+    declare_err!(EHWPOISON, "Memory page has hardware error.");
+
+    declare_err!(ERESTARTSYS, "Restart the system call.");
+
+    declare_err!(ENOTSUPP, "Operation is not supported.");
+}
+
+/// Generic integer kernel error.
+///
+/// The kernel defines a set of integer generic error codes based on C and
+/// POSIX ones. These codes may have a more specific meaning in some contexts.
+///
+/// # Invariants
+///
+/// The value is a valid `errno` (i.e. `>= -MAX_ERRNO && < 0`).
+#[derive(Clone, Copy, PartialEq, Eq)]
+pub struct Error(c_types::c_int);
+
+impl Error {
+    /// Creates an [`Error`] from a kernel error code.
+    ///
+    /// It is a bug to pass an out-of-range `errno`. `EINVAL` would
+    /// be returned in such a case.
+    pub(crate) fn from_kernel_errno(errno: c_types::c_int) -> Error {
+        if errno < -(bindings::MAX_ERRNO as i32) || errno >= 0 {
+            // TODO: Make it a `WARN_ONCE` once available.
+            crate::pr_warn!(
+                "attempted to create `Error` with out of range `errno`: {}",
+                errno
+            );
+            return code::EINVAL;
+        }
+
+        // INVARIANT: The check above ensures the type invariant
+        // will hold.
+        Error(errno)
+    }
+
+    /// Creates an [`Error`] from a kernel error code.
+    ///
+    /// # Safety
+    ///
+    /// `errno` must be within error code range (i.e. `>= -MAX_ERRNO && < 0`).
+    pub(crate) unsafe fn from_kernel_errno_unchecked(errno: c_types::c_int) -> Error {
+        // INVARIANT: The contract ensures the type invariant
+        // will hold.
+        Error(errno)
+    }
+
+    /// Returns the kernel error code.
+    pub fn to_kernel_errno(self) -> c_types::c_int {
+        self.0
+    }
+
+    /// Returns a string representing the error, if one exists.
+    #[cfg(not(testlib))]
+    pub fn name(&self) -> Option<&'static CStr> {
+        // SAFETY: Just an FFI call, there are no extra safety requirements.
+        let ptr = unsafe { bindings::errname(-self.0) };
+        if ptr.is_null() {
+            None
+        } else {
+            // SAFETY: The string returned by `errname` is static and `NUL`-terminated.
+            Some(unsafe { CStr::from_char_ptr(ptr) })
+        }
+    }
+
+    /// Returns a string representing the error, if one exists.
+    ///
+    /// When `testlib` is configured, this always returns `None` to avoid the dependency on a
+    /// kernel function so that tests that use this (e.g., by calling [`Result::unwrap`]) can still
+    /// run in userspace.
+    #[cfg(testlib)]
+    pub fn name(&self) -> Option<&'static CStr> {
+        None
+    }
+}
+
+impl fmt::Debug for Error {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match self.name() {
+            // Print out number if no name can be found.
+            None => f.debug_tuple("Error").field(&-self.0).finish(),
+            // SAFETY: These strings are ASCII-only.
+            Some(name) => f
+                .debug_tuple(unsafe { str::from_utf8_unchecked(name) })
+                .finish(),
+        }
+    }
+}
+
+impl From<TryFromIntError> for Error {
+    fn from(_: TryFromIntError) -> Error {
+        code::EINVAL
+    }
+}
+
+impl From<Utf8Error> for Error {
+    fn from(_: Utf8Error) -> Error {
+        code::EINVAL
+    }
+}
+
+impl From<TryReserveError> for Error {
+    fn from(_: TryReserveError) -> Error {
+        code::ENOMEM
+    }
+}
+
+impl From<LayoutError> for Error {
+    fn from(_: LayoutError) -> Error {
+        code::ENOMEM
+    }
+}
+
+impl From<core::fmt::Error> for Error {
+    fn from(_: core::fmt::Error) -> Error {
+        code::EINVAL
+    }
+}
+
+impl From<core::convert::Infallible> for Error {
+    fn from(e: core::convert::Infallible) -> Error {
+        match e {}
+    }
+}
+
+/// A [`Result`] with an [`Error`] error type.
+///
+/// To be used as the return type for functions that may fail.
+///
+/// # Error codes in C and Rust
+///
+/// In C, it is common that functions indicate success or failure through
+/// their return value; modifying or returning extra data through non-`const`
+/// pointer parameters. In particular, in the kernel, functions that may fail
+/// typically return an `int` that represents a generic error code. We model
+/// those as [`Error`].
+///
+/// In Rust, it is idiomatic to model functions that may fail as returning
+/// a [`Result`]. Since in the kernel many functions return an error code,
+/// [`Result`] is a type alias for a [`core::result::Result`] that uses
+/// [`Error`] as its error type.
+///
+/// Note that even if a function does not return anything when it succeeds,
+/// it should still be modeled as returning a `Result` rather than
+/// just an [`Error`].
+pub type Result<T = ()> = core::result::Result<T, Error>;
+
+impl From<AllocError> for Error {
+    fn from(_: AllocError) -> Error {
+        code::ENOMEM
+    }
+}
+
+// # Invariant: `-bindings::MAX_ERRNO` fits in an `i16`.
+crate::static_assert!(bindings::MAX_ERRNO <= -(i16::MIN as i32) as u32);
+
+pub(crate) fn from_kernel_result_helper<T>(r: Result<T>) -> T
+where
+    T: From<i16>,
+{
+    match r {
+        Ok(v) => v,
+        // NO-OVERFLOW: negative `errno`s are no smaller than `-bindings::MAX_ERRNO`,
+        // `-bindings::MAX_ERRNO` fits in an `i16` as per invariant above,
+        // therefore a negative `errno` always fits in an `i16` and will not overflow.
+        Err(e) => T::from(e.to_kernel_errno() as i16),
+    }
+}
+
+/// Transforms a [`crate::error::Result<T>`] to a kernel C integer result.
+///
+/// This is useful when calling Rust functions that return [`crate::error::Result<T>`]
+/// from inside `extern "C"` functions that need to return an integer
+/// error result.
+///
+/// `T` should be convertible to an `i16` via `From<i16>`.
+///
+/// # Examples
+///
+/// ```ignore
+/// # use kernel::from_kernel_result;
+/// # use kernel::c_types;
+/// # use kernel::bindings;
+/// unsafe extern "C" fn probe_callback(
+///     pdev: *mut bindings::platform_device,
+/// ) -> c_types::c_int {
+///     from_kernel_result! {
+///         let ptr = devm_alloc(pdev)?;
+///         bindings::platform_set_drvdata(pdev, ptr);
+///         Ok(0)
+///     }
+/// }
+/// ```
+macro_rules! from_kernel_result {
+    ($($tt:tt)*) => {{
+        $crate::error::from_kernel_result_helper((|| {
+            $($tt)*
+        })())
+    }};
+}
+
+pub(crate) use from_kernel_result;
+
+/// Transform a kernel "error pointer" to a normal pointer.
+///
+/// Some kernel C API functions return an "error pointer" which optionally
+/// embeds an `errno`. Callers are supposed to check the returned pointer
+/// for errors. This function performs the check and converts the "error pointer"
+/// to a normal pointer in an idiomatic fashion.
+///
+/// # Examples
+///
+/// ```ignore
+/// # use kernel::from_kernel_err_ptr;
+/// # use kernel::c_types;
+/// # use kernel::bindings;
+/// fn devm_platform_ioremap_resource(
+///     pdev: &mut PlatformDevice,
+///     index: u32,
+/// ) -> Result<*mut c_types::c_void> {
+///     // SAFETY: FFI call.
+///     unsafe {
+///         from_kernel_err_ptr(bindings::devm_platform_ioremap_resource(
+///             pdev.to_ptr(),
+///             index,
+///         ))
+///     }
+/// }
+/// ```
+// TODO: Remove `dead_code` marker once an in-kernel client is available.
+#[allow(dead_code)]
+pub(crate) fn from_kernel_err_ptr<T>(ptr: *mut T) -> Result<*mut T> {
+    // CAST: Casting a pointer to `*const c_types::c_void` is always valid.
+    let const_ptr: *const c_types::c_void = ptr.cast();
+    // SAFETY: The FFI function does not deref the pointer.
+    if unsafe { bindings::IS_ERR(const_ptr) } {
+        // SAFETY: The FFI function does not deref the pointer.
+        let err = unsafe { bindings::PTR_ERR(const_ptr) };
+        // CAST: If `IS_ERR()` returns `true`,
+        // then `PTR_ERR()` is guaranteed to return a
+        // negative value greater-or-equal to `-bindings::MAX_ERRNO`,
+        // which always fits in an `i16`, as per the invariant above.
+        // And an `i16` always fits in an `i32`. So casting `err` to
+        // an `i32` can never overflow, and is always valid.
+        //
+        // SAFETY: `IS_ERR()` ensures `err` is a
+        // negative value greater-or-equal to `-bindings::MAX_ERRNO`.
+        return Err(unsafe { Error::from_kernel_errno_unchecked(err as i32) });
+    }
+    Ok(ptr)
+}
+
+/// Calls a kernel function that returns an integer error code on failure and converts the result
+/// to a [`Result`].
+pub fn to_result(func: impl FnOnce() -> c_types::c_int) -> Result {
+    let err = func();
+    if err < 0 {
+        Err(Error::from_kernel_errno(err))
+    } else {
+        Ok(())
+    }
+}
diff --git a/rust/kernel/file.rs b/rust/kernel/file.rs
new file mode 100644
index 000000000000..e1b3b324bb3d
--- /dev/null
+++ b/rust/kernel/file.rs
@@ -0,0 +1,860 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Files and file descriptors.
+//!
+//! C headers: [`include/linux/fs.h`](../../../../include/linux/fs.h) and
+//! [`include/linux/file.h`](../../../../include/linux/file.h)
+
+use crate::{
+    bindings, c_types,
+    cred::Credential,
+    error::{code::*, from_kernel_result, Error, Result},
+    io_buffer::{IoBufferReader, IoBufferWriter},
+    iov_iter::IovIter,
+    mm,
+    sync::CondVar,
+    types::PointerWrapper,
+    user_ptr::{UserSlicePtr, UserSlicePtrReader, UserSlicePtrWriter},
+    ARef, AlwaysRefCounted,
+};
+use core::convert::{TryFrom, TryInto};
+use core::{cell::UnsafeCell, marker, mem, ptr};
+
+/// Wraps the kernel's `struct file`.
+///
+/// # Invariants
+///
+/// Instances of this type are always ref-counted, that is, a call to `get_file` ensures that the
+/// allocation remains valid at least until the matching call to `fput`.
+#[repr(transparent)]
+pub struct File(pub(crate) UnsafeCell<bindings::file>);
+
+// TODO: Accessing fields of `struct file` through the pointer is UB because other threads may be
+// writing to them. However, this is how the C code currently operates: naked reads and writes to
+// fields. Even if we used relaxed atomics on the Rust side, we can't force this on the C side.
+impl File {
+    /// Constructs a new [`struct file`] wrapper from a file descriptor.
+    ///
+    /// The file descriptor belongs to the current process.
+    pub fn from_fd(fd: u32) -> Result<ARef<Self>> {
+        // SAFETY: FFI call, there are no requirements on `fd`.
+        let ptr = ptr::NonNull::new(unsafe { bindings::fget(fd) }).ok_or(EBADF)?;
+
+        // SAFETY: `fget` increments the refcount before returning.
+        Ok(unsafe { ARef::from_raw(ptr.cast()) })
+    }
+
+    /// Creates a reference to a [`File`] from a valid pointer.
+    ///
+    /// # Safety
+    ///
+    /// The caller must ensure that `ptr` is valid and remains valid for the lifetime of the
+    /// returned [`File`] instance.
+    pub(crate) unsafe fn from_ptr<'a>(ptr: *const bindings::file) -> &'a File {
+        // SAFETY: The safety requirements guarantee the validity of the dereference, while the
+        // `File` type being transparent makes the cast ok.
+        unsafe { &*ptr.cast() }
+    }
+
+    /// Returns the current seek/cursor/pointer position (`struct file::f_pos`).
+    pub fn pos(&self) -> u64 {
+        // SAFETY: The file is valid because the shared reference guarantees a nonzero refcount.
+        unsafe { core::ptr::addr_of!((*self.0.get()).f_pos).read() as _ }
+    }
+
+    /// Returns whether the file is in blocking mode.
+    pub fn is_blocking(&self) -> bool {
+        self.flags() & bindings::O_NONBLOCK == 0
+    }
+
+    /// Returns the credentials of the task that originally opened the file.
+    pub fn cred(&self) -> &Credential {
+        // SAFETY: The file is valid because the shared reference guarantees a nonzero refcount.
+        let ptr = unsafe { core::ptr::addr_of!((*self.0.get()).f_cred).read() };
+        // SAFETY: The lifetimes of `self` and `Credential` are tied, so it is guaranteed that
+        // the credential pointer remains valid (because the file is still alive, and it doesn't
+        // change over the lifetime of a file).
+        unsafe { Credential::from_ptr(ptr) }
+    }
+
+    /// Returns the flags associated with the file.
+    pub fn flags(&self) -> u32 {
+        // SAFETY: The file is valid because the shared reference guarantees a nonzero refcount.
+        unsafe { core::ptr::addr_of!((*self.0.get()).f_flags).read() }
+    }
+}
+
+// SAFETY: The type invariants guarantee that `File` is always ref-counted.
+unsafe impl AlwaysRefCounted for File {
+    fn inc_ref(&self) {
+        // SAFETY: The existence of a shared reference means that the refcount is nonzero.
+        unsafe { bindings::get_file(self.0.get()) };
+    }
+
+    unsafe fn dec_ref(obj: ptr::NonNull<Self>) {
+        // SAFETY: The safety requirements guarantee that the refcount is nonzero.
+        unsafe { bindings::fput(obj.cast().as_ptr()) }
+    }
+}
+
+/// A file descriptor reservation.
+///
+/// This allows the creation of a file descriptor in two steps: first, we reserve a slot for it,
+/// then we commit or drop the reservation. The first step may fail (e.g., the current process ran
+/// out of available slots), but commit and drop never fail (and are mutually exclusive).
+pub struct FileDescriptorReservation {
+    fd: u32,
+}
+
+impl FileDescriptorReservation {
+    /// Creates a new file descriptor reservation.
+    pub fn new(flags: u32) -> Result<Self> {
+        // SAFETY: FFI call, there are no safety requirements on `flags`.
+        let fd = unsafe { bindings::get_unused_fd_flags(flags) };
+        if fd < 0 {
+            return Err(Error::from_kernel_errno(fd));
+        }
+        Ok(Self { fd: fd as _ })
+    }
+
+    /// Returns the file descriptor number that was reserved.
+    pub fn reserved_fd(&self) -> u32 {
+        self.fd
+    }
+
+    /// Commits the reservation.
+    ///
+    /// The previously reserved file descriptor is bound to `file`.
+    pub fn commit(self, file: ARef<File>) {
+        // SAFETY: `self.fd` was previously returned by `get_unused_fd_flags`, and `file.ptr` is
+        // guaranteed to have an owned ref count by its type invariants.
+        unsafe { bindings::fd_install(self.fd, file.0.get()) };
+
+        // `fd_install` consumes both the file descriptor and the file reference, so we cannot run
+        // the destructors.
+        core::mem::forget(self);
+        core::mem::forget(file);
+    }
+}
+
+impl Drop for FileDescriptorReservation {
+    fn drop(&mut self) {
+        // SAFETY: `self.fd` was returned by a previous call to `get_unused_fd_flags`.
+        unsafe { bindings::put_unused_fd(self.fd) };
+    }
+}
+
+/// Wraps the kernel's `struct poll_table_struct`.
+///
+/// # Invariants
+///
+/// The pointer `PollTable::ptr` is null or valid.
+pub struct PollTable {
+    ptr: *mut bindings::poll_table_struct,
+}
+
+impl PollTable {
+    /// Constructors a new `struct poll_table_struct` wrapper.
+    ///
+    /// # Safety
+    ///
+    /// The pointer `ptr` must be either null or a valid pointer for the lifetime of the object.
+    unsafe fn from_ptr(ptr: *mut bindings::poll_table_struct) -> Self {
+        Self { ptr }
+    }
+
+    /// Associates the given file and condition variable to this poll table. It means notifying the
+    /// condition variable will notify the poll table as well; additionally, the association
+    /// between the condition variable and the file will automatically be undone by the kernel when
+    /// the file is destructed. To unilaterally remove the association before then, one can call
+    /// [`CondVar::free_waiters`].
+    ///
+    /// # Safety
+    ///
+    /// If the condition variable is destroyed before the file, then [`CondVar::free_waiters`] must
+    /// be called to ensure that all waiters are flushed out.
+    pub unsafe fn register_wait<'a>(&self, file: &'a File, cv: &'a CondVar) {
+        if self.ptr.is_null() {
+            return;
+        }
+
+        // SAFETY: `PollTable::ptr` is guaranteed to be valid by the type invariants and the null
+        // check above.
+        let table = unsafe { &*self.ptr };
+        if let Some(proc) = table._qproc {
+            // SAFETY: All pointers are known to be valid.
+            unsafe { proc(file.0.get() as _, cv.wait_list.get(), self.ptr) }
+        }
+    }
+}
+
+/// Equivalent to [`std::io::SeekFrom`].
+///
+/// [`std::io::SeekFrom`]: https://doc.rust-lang.org/std/io/enum.SeekFrom.html
+pub enum SeekFrom {
+    /// Equivalent to C's `SEEK_SET`.
+    Start(u64),
+
+    /// Equivalent to C's `SEEK_END`.
+    End(i64),
+
+    /// Equivalent to C's `SEEK_CUR`.
+    Current(i64),
+}
+
+pub(crate) struct OperationsVtable<A, T>(marker::PhantomData<A>, marker::PhantomData<T>);
+
+impl<A: OpenAdapter<T::OpenData>, T: Operations> OperationsVtable<A, T> {
+    /// Called by the VFS when an inode should be opened.
+    ///
+    /// Calls `T::open` on the returned value of `A::convert`.
+    ///
+    /// # Safety
+    ///
+    /// The returned value of `A::convert` must be a valid non-null pointer and
+    /// `T:open` must return a valid non-null pointer on an `Ok` result.
+    unsafe extern "C" fn open_callback(
+        inode: *mut bindings::inode,
+        file: *mut bindings::file,
+    ) -> c_types::c_int {
+        from_kernel_result! {
+            // SAFETY: `A::convert` must return a valid non-null pointer that
+            // should point to data in the inode or file that lives longer
+            // than the following use of `T::open`.
+            let arg = unsafe { A::convert(inode, file) };
+            // SAFETY: The C contract guarantees that `file` is valid. Additionally,
+            // `fileref` never outlives this function, so it is guaranteed to be
+            // valid.
+            let fileref = unsafe { File::from_ptr(file) };
+            // SAFETY: `arg` was previously returned by `A::convert` and must
+            // be a valid non-null pointer.
+            let ptr = T::open(unsafe { &*arg }, fileref)?.into_pointer();
+            // SAFETY: The C contract guarantees that `private_data` is available
+            // for implementers of the file operations (no other C code accesses
+            // it), so we know that there are no concurrent threads/CPUs accessing
+            // it (it's not visible to any other Rust code).
+            unsafe { (*file).private_data = ptr as *mut c_types::c_void };
+            Ok(0)
+        }
+    }
+
+    unsafe extern "C" fn read_callback(
+        file: *mut bindings::file,
+        buf: *mut c_types::c_char,
+        len: c_types::c_size_t,
+        offset: *mut bindings::loff_t,
+    ) -> c_types::c_ssize_t {
+        from_kernel_result! {
+            let mut data = unsafe { UserSlicePtr::new(buf as *mut c_types::c_void, len).writer() };
+            // SAFETY: `private_data` was initialised by `open_callback` with a value returned by
+            // `T::Data::into_pointer`. `T::Data::from_pointer` is only called by the
+            // `release` callback, which the C API guarantees that will be called only when all
+            // references to `file` have been released, so we know it can't be called while this
+            // function is running.
+            let f = unsafe { T::Data::borrow((*file).private_data) };
+            // No `FMODE_UNSIGNED_OFFSET` support, so `offset` must be in [0, 2^63).
+            // See discussion in https://github.com/fishinabarrel/linux-kernel-module-rust/pull/113
+            let read = T::read(
+                f,
+                unsafe { File::from_ptr(file) },
+                &mut data,
+                unsafe { *offset }.try_into()?,
+            )?;
+            unsafe { (*offset) += bindings::loff_t::try_from(read).unwrap() };
+            Ok(read as _)
+        }
+    }
+
+    unsafe extern "C" fn read_iter_callback(
+        iocb: *mut bindings::kiocb,
+        raw_iter: *mut bindings::iov_iter,
+    ) -> isize {
+        from_kernel_result! {
+            let mut iter = unsafe { IovIter::from_ptr(raw_iter) };
+            let file = unsafe { (*iocb).ki_filp };
+            let offset = unsafe { (*iocb).ki_pos };
+            // SAFETY: `private_data` was initialised by `open_callback` with a value returned by
+            // `T::Data::into_pointer`. `T::Data::from_pointer` is only called by the
+            // `release` callback, which the C API guarantees that will be called only when all
+            // references to `file` have been released, so we know it can't be called while this
+            // function is running.
+            let f = unsafe { T::Data::borrow((*file).private_data) };
+            let read =
+                T::read(f, unsafe { File::from_ptr(file) }, &mut iter, offset.try_into()?)?;
+            unsafe { (*iocb).ki_pos += bindings::loff_t::try_from(read).unwrap() };
+            Ok(read as _)
+        }
+    }
+
+    unsafe extern "C" fn write_callback(
+        file: *mut bindings::file,
+        buf: *const c_types::c_char,
+        len: c_types::c_size_t,
+        offset: *mut bindings::loff_t,
+    ) -> c_types::c_ssize_t {
+        from_kernel_result! {
+            let mut data = unsafe { UserSlicePtr::new(buf as *mut c_types::c_void, len).reader() };
+            // SAFETY: `private_data` was initialised by `open_callback` with a value returned by
+            // `T::Data::into_pointer`. `T::Data::from_pointer` is only called by the
+            // `release` callback, which the C API guarantees that will be called only when all
+            // references to `file` have been released, so we know it can't be called while this
+            // function is running.
+            let f = unsafe { T::Data::borrow((*file).private_data) };
+            // No `FMODE_UNSIGNED_OFFSET` support, so `offset` must be in [0, 2^63).
+            // See discussion in https://github.com/fishinabarrel/linux-kernel-module-rust/pull/113
+            let written = T::write(
+                f,
+                unsafe { File::from_ptr(file) },
+                &mut data,
+                unsafe { *offset }.try_into()?
+            )?;
+            unsafe { (*offset) += bindings::loff_t::try_from(written).unwrap() };
+            Ok(written as _)
+        }
+    }
+
+    unsafe extern "C" fn write_iter_callback(
+        iocb: *mut bindings::kiocb,
+        raw_iter: *mut bindings::iov_iter,
+    ) -> isize {
+        from_kernel_result! {
+            let mut iter = unsafe { IovIter::from_ptr(raw_iter) };
+            let file = unsafe { (*iocb).ki_filp };
+            let offset = unsafe { (*iocb).ki_pos };
+            // SAFETY: `private_data` was initialised by `open_callback` with a value returned by
+            // `T::Data::into_pointer`. `T::Data::from_pointer` is only called by the
+            // `release` callback, which the C API guarantees that will be called only when all
+            // references to `file` have been released, so we know it can't be called while this
+            // function is running.
+            let f = unsafe { T::Data::borrow((*file).private_data) };
+            let written =
+                T::write(f, unsafe { File::from_ptr(file) }, &mut iter, offset.try_into()?)?;
+            unsafe { (*iocb).ki_pos += bindings::loff_t::try_from(written).unwrap() };
+            Ok(written as _)
+        }
+    }
+
+    unsafe extern "C" fn release_callback(
+        _inode: *mut bindings::inode,
+        file: *mut bindings::file,
+    ) -> c_types::c_int {
+        let ptr = mem::replace(unsafe { &mut (*file).private_data }, ptr::null_mut());
+        T::release(unsafe { T::Data::from_pointer(ptr as _) }, unsafe {
+            File::from_ptr(file)
+        });
+        0
+    }
+
+    unsafe extern "C" fn llseek_callback(
+        file: *mut bindings::file,
+        offset: bindings::loff_t,
+        whence: c_types::c_int,
+    ) -> bindings::loff_t {
+        from_kernel_result! {
+            let off = match whence as u32 {
+                bindings::SEEK_SET => SeekFrom::Start(offset.try_into()?),
+                bindings::SEEK_CUR => SeekFrom::Current(offset),
+                bindings::SEEK_END => SeekFrom::End(offset),
+                _ => return Err(EINVAL),
+            };
+            // SAFETY: `private_data` was initialised by `open_callback` with a value returned by
+            // `T::Data::into_pointer`. `T::Data::from_pointer` is only called by the
+            // `release` callback, which the C API guarantees that will be called only when all
+            // references to `file` have been released, so we know it can't be called while this
+            // function is running.
+            let f = unsafe { T::Data::borrow((*file).private_data) };
+            let off = T::seek(f, unsafe { File::from_ptr(file) }, off)?;
+            Ok(off as bindings::loff_t)
+        }
+    }
+
+    unsafe extern "C" fn unlocked_ioctl_callback(
+        file: *mut bindings::file,
+        cmd: c_types::c_uint,
+        arg: c_types::c_ulong,
+    ) -> c_types::c_long {
+        from_kernel_result! {
+            // SAFETY: `private_data` was initialised by `open_callback` with a value returned by
+            // `T::Data::into_pointer`. `T::Data::from_pointer` is only called by the
+            // `release` callback, which the C API guarantees that will be called only when all
+            // references to `file` have been released, so we know it can't be called while this
+            // function is running.
+            let f = unsafe { T::Data::borrow((*file).private_data) };
+            let mut cmd = IoctlCommand::new(cmd as _, arg as _);
+            let ret = T::ioctl(f, unsafe { File::from_ptr(file) }, &mut cmd)?;
+            Ok(ret as _)
+        }
+    }
+
+    unsafe extern "C" fn compat_ioctl_callback(
+        file: *mut bindings::file,
+        cmd: c_types::c_uint,
+        arg: c_types::c_ulong,
+    ) -> c_types::c_long {
+        from_kernel_result! {
+            // SAFETY: `private_data` was initialised by `open_callback` with a value returned by
+            // `T::Data::into_pointer`. `T::Data::from_pointer` is only called by the
+            // `release` callback, which the C API guarantees that will be called only when all
+            // references to `file` have been released, so we know it can't be called while this
+            // function is running.
+            let f = unsafe { T::Data::borrow((*file).private_data) };
+            let mut cmd = IoctlCommand::new(cmd as _, arg as _);
+            let ret = T::compat_ioctl(f, unsafe { File::from_ptr(file) }, &mut cmd)?;
+            Ok(ret as _)
+        }
+    }
+
+    unsafe extern "C" fn mmap_callback(
+        file: *mut bindings::file,
+        vma: *mut bindings::vm_area_struct,
+    ) -> c_types::c_int {
+        from_kernel_result! {
+            // SAFETY: `private_data` was initialised by `open_callback` with a value returned by
+            // `T::Data::into_pointer`. `T::Data::from_pointer` is only called by the
+            // `release` callback, which the C API guarantees that will be called only when all
+            // references to `file` have been released, so we know it can't be called while this
+            // function is running.
+            let f = unsafe { T::Data::borrow((*file).private_data) };
+
+            // SAFETY: The C API guarantees that `vma` is valid for the duration of this call.
+            // `area` only lives within this call, so it is guaranteed to be valid.
+            let mut area = unsafe { mm::virt::Area::from_ptr(vma) };
+
+            // SAFETY: The C API guarantees that `file` is valid for the duration of this call,
+            // which is longer than the lifetime of the file reference.
+            T::mmap(f, unsafe { File::from_ptr(file) }, &mut area)?;
+            Ok(0)
+        }
+    }
+
+    unsafe extern "C" fn fsync_callback(
+        file: *mut bindings::file,
+        start: bindings::loff_t,
+        end: bindings::loff_t,
+        datasync: c_types::c_int,
+    ) -> c_types::c_int {
+        from_kernel_result! {
+            let start = start.try_into()?;
+            let end = end.try_into()?;
+            let datasync = datasync != 0;
+            // SAFETY: `private_data` was initialised by `open_callback` with a value returned by
+            // `T::Data::into_pointer`. `T::Data::from_pointer` is only called by the
+            // `release` callback, which the C API guarantees that will be called only when all
+            // references to `file` have been released, so we know it can't be called while this
+            // function is running.
+            let f = unsafe { T::Data::borrow((*file).private_data) };
+            let res = T::fsync(f, unsafe { File::from_ptr(file) }, start, end, datasync)?;
+            Ok(res.try_into().unwrap())
+        }
+    }
+
+    unsafe extern "C" fn poll_callback(
+        file: *mut bindings::file,
+        wait: *mut bindings::poll_table_struct,
+    ) -> bindings::__poll_t {
+        // SAFETY: `private_data` was initialised by `open_callback` with a value returned by
+        // `T::Data::into_pointer`. `T::Data::from_pointer` is only called by the `release`
+        // callback, which the C API guarantees that will be called only when all references to
+        // `file` have been released, so we know it can't be called while this function is running.
+        let f = unsafe { T::Data::borrow((*file).private_data) };
+        match T::poll(f, unsafe { File::from_ptr(file) }, unsafe {
+            &PollTable::from_ptr(wait)
+        }) {
+            Ok(v) => v,
+            Err(_) => bindings::POLLERR,
+        }
+    }
+
+    const VTABLE: bindings::file_operations = bindings::file_operations {
+        open: Some(Self::open_callback),
+        release: Some(Self::release_callback),
+        read: if T::TO_USE.read {
+            Some(Self::read_callback)
+        } else {
+            None
+        },
+        write: if T::TO_USE.write {
+            Some(Self::write_callback)
+        } else {
+            None
+        },
+        llseek: if T::TO_USE.seek {
+            Some(Self::llseek_callback)
+        } else {
+            None
+        },
+
+        check_flags: None,
+        compat_ioctl: if T::TO_USE.compat_ioctl {
+            Some(Self::compat_ioctl_callback)
+        } else {
+            None
+        },
+        copy_file_range: None,
+        fallocate: None,
+        fadvise: None,
+        fasync: None,
+        flock: None,
+        flush: None,
+        fsync: if T::TO_USE.fsync {
+            Some(Self::fsync_callback)
+        } else {
+            None
+        },
+        get_unmapped_area: None,
+        iterate: None,
+        iterate_shared: None,
+        iopoll: None,
+        lock: None,
+        mmap: if T::TO_USE.mmap {
+            Some(Self::mmap_callback)
+        } else {
+            None
+        },
+        mmap_supported_flags: 0,
+        owner: ptr::null_mut(),
+        poll: if T::TO_USE.poll {
+            Some(Self::poll_callback)
+        } else {
+            None
+        },
+        read_iter: if T::TO_USE.read_iter {
+            Some(Self::read_iter_callback)
+        } else {
+            None
+        },
+        remap_file_range: None,
+        sendpage: None,
+        setlease: None,
+        show_fdinfo: None,
+        splice_read: None,
+        splice_write: None,
+        unlocked_ioctl: if T::TO_USE.ioctl {
+            Some(Self::unlocked_ioctl_callback)
+        } else {
+            None
+        },
+        write_iter: if T::TO_USE.write_iter {
+            Some(Self::write_iter_callback)
+        } else {
+            None
+        },
+    };
+
+    /// Builds an instance of [`struct file_operations`].
+    ///
+    /// # Safety
+    ///
+    /// The caller must ensure that the adapter is compatible with the way the device is registered.
+    pub(crate) const unsafe fn build() -> &'static bindings::file_operations {
+        &Self::VTABLE
+    }
+}
+
+/// Represents which fields of [`struct file_operations`] should be populated with pointers.
+pub struct ToUse {
+    /// The `read` field of [`struct file_operations`].
+    pub read: bool,
+
+    /// The `read_iter` field of [`struct file_operations`].
+    pub read_iter: bool,
+
+    /// The `write` field of [`struct file_operations`].
+    pub write: bool,
+
+    /// The `write_iter` field of [`struct file_operations`].
+    pub write_iter: bool,
+
+    /// The `llseek` field of [`struct file_operations`].
+    pub seek: bool,
+
+    /// The `unlocked_ioctl` field of [`struct file_operations`].
+    pub ioctl: bool,
+
+    /// The `compat_ioctl` field of [`struct file_operations`].
+    pub compat_ioctl: bool,
+
+    /// The `fsync` field of [`struct file_operations`].
+    pub fsync: bool,
+
+    /// The `mmap` field of [`struct file_operations`].
+    pub mmap: bool,
+
+    /// The `poll` field of [`struct file_operations`].
+    pub poll: bool,
+}
+
+/// A constant version where all values are to set to `false`, that is, all supported fields will
+/// be set to null pointers.
+pub const USE_NONE: ToUse = ToUse {
+    read: false,
+    read_iter: false,
+    write: false,
+    write_iter: false,
+    seek: false,
+    ioctl: false,
+    compat_ioctl: false,
+    fsync: false,
+    mmap: false,
+    poll: false,
+};
+
+/// Defines the [`Operations::TO_USE`] field based on a list of fields to be populated.
+#[macro_export]
+macro_rules! declare_file_operations {
+    () => {
+        const TO_USE: $crate::file::ToUse = $crate::file::USE_NONE;
+    };
+    ($($i:ident),+) => {
+        const TO_USE: kernel::file::ToUse =
+            $crate::file::ToUse {
+                $($i: true),+ ,
+                ..$crate::file::USE_NONE
+            };
+    };
+}
+
+/// Allows the handling of ioctls defined with the `_IO`, `_IOR`, `_IOW`, and `_IOWR` macros.
+///
+/// For each macro, there is a handler function that takes the appropriate types as arguments.
+pub trait IoctlHandler: Sync {
+    /// The type of the first argument to each associated function.
+    type Target<'a>;
+
+    /// Handles ioctls defined with the `_IO` macro, that is, with no buffer as argument.
+    fn pure(_this: Self::Target<'_>, _file: &File, _cmd: u32, _arg: usize) -> Result<i32> {
+        Err(EINVAL)
+    }
+
+    /// Handles ioctls defined with the `_IOR` macro, that is, with an output buffer provided as
+    /// argument.
+    fn read(
+        _this: Self::Target<'_>,
+        _file: &File,
+        _cmd: u32,
+        _writer: &mut UserSlicePtrWriter,
+    ) -> Result<i32> {
+        Err(EINVAL)
+    }
+
+    /// Handles ioctls defined with the `_IOW` macro, that is, with an input buffer provided as
+    /// argument.
+    fn write(
+        _this: Self::Target<'_>,
+        _file: &File,
+        _cmd: u32,
+        _reader: &mut UserSlicePtrReader,
+    ) -> Result<i32> {
+        Err(EINVAL)
+    }
+
+    /// Handles ioctls defined with the `_IOWR` macro, that is, with a buffer for both input and
+    /// output provided as argument.
+    fn read_write(
+        _this: Self::Target<'_>,
+        _file: &File,
+        _cmd: u32,
+        _data: UserSlicePtr,
+    ) -> Result<i32> {
+        Err(EINVAL)
+    }
+}
+
+/// Represents an ioctl command.
+///
+/// It can use the components of an ioctl command to dispatch ioctls using
+/// [`IoctlCommand::dispatch`].
+pub struct IoctlCommand {
+    cmd: u32,
+    arg: usize,
+    user_slice: Option<UserSlicePtr>,
+}
+
+impl IoctlCommand {
+    /// Constructs a new [`IoctlCommand`].
+    fn new(cmd: u32, arg: usize) -> Self {
+        let size = (cmd >> bindings::_IOC_SIZESHIFT) & bindings::_IOC_SIZEMASK;
+
+        // SAFETY: We only create one instance of the user slice per ioctl call, so TOCTOU issues
+        // are not possible.
+        let user_slice = Some(unsafe { UserSlicePtr::new(arg as _, size as _) });
+        Self {
+            cmd,
+            arg,
+            user_slice,
+        }
+    }
+
+    /// Dispatches the given ioctl to the appropriate handler based on the value of the command. It
+    /// also creates a [`UserSlicePtr`], [`UserSlicePtrReader`], or [`UserSlicePtrWriter`]
+    /// depending on the direction of the buffer of the command.
+    ///
+    /// It is meant to be used in implementations of [`Operations::ioctl`] and
+    /// [`Operations::compat_ioctl`].
+    pub fn dispatch<T: IoctlHandler>(
+        &mut self,
+        handler: T::Target<'_>,
+        file: &File,
+    ) -> Result<i32> {
+        let dir = (self.cmd >> bindings::_IOC_DIRSHIFT) & bindings::_IOC_DIRMASK;
+        if dir == bindings::_IOC_NONE {
+            return T::pure(handler, file, self.cmd, self.arg);
+        }
+
+        let data = self.user_slice.take().ok_or(EINVAL)?;
+        const READ_WRITE: u32 = bindings::_IOC_READ | bindings::_IOC_WRITE;
+        match dir {
+            bindings::_IOC_WRITE => T::write(handler, file, self.cmd, &mut data.reader()),
+            bindings::_IOC_READ => T::read(handler, file, self.cmd, &mut data.writer()),
+            READ_WRITE => T::read_write(handler, file, self.cmd, data),
+            _ => Err(EINVAL),
+        }
+    }
+
+    /// Returns the raw 32-bit value of the command and the ptr-sized argument.
+    pub fn raw(&self) -> (u32, usize) {
+        (self.cmd, self.arg)
+    }
+}
+
+/// Trait for extracting file open arguments from kernel data structures.
+///
+/// This is meant to be implemented by registration managers.
+pub trait OpenAdapter<T: Sync> {
+    /// Converts untyped data stored in [`struct inode`] and [`struct file`] (when [`struct
+    /// file_operations::open`] is called) into the given type. For example, for `miscdev`
+    /// devices, a pointer to the registered [`struct miscdev`] is stored in [`struct
+    /// file::private_data`].
+    ///
+    /// # Safety
+    ///
+    /// This function must be called only when [`struct file_operations::open`] is being called for
+    /// a file that was registered by the implementer. The returned pointer must be valid and
+    /// not-null.
+    unsafe fn convert(_inode: *mut bindings::inode, _file: *mut bindings::file) -> *const T;
+}
+
+/// Corresponds to the kernel's `struct file_operations`.
+///
+/// You implement this trait whenever you would create a `struct file_operations`.
+///
+/// File descriptors may be used from multiple threads/processes concurrently, so your type must be
+/// [`Sync`]. It must also be [`Send`] because [`Operations::release`] will be called from the
+/// thread that decrements that associated file's refcount to zero.
+pub trait Operations {
+    /// The methods to use to populate [`struct file_operations`].
+    const TO_USE: ToUse;
+
+    /// The type of the context data returned by [`Operations::open`] and made available to
+    /// other methods.
+    type Data: PointerWrapper + Send + Sync = ();
+
+    /// The type of the context data passed to [`Operations::open`].
+    type OpenData: Sync = ();
+
+    /// Creates a new instance of this file.
+    ///
+    /// Corresponds to the `open` function pointer in `struct file_operations`.
+    fn open(context: &Self::OpenData, file: &File) -> Result<Self::Data>;
+
+    /// Cleans up after the last reference to the file goes away.
+    ///
+    /// Note that context data is moved, so it will be freed automatically unless the
+    /// implementation moves it elsewhere.
+    ///
+    /// Corresponds to the `release` function pointer in `struct file_operations`.
+    fn release(_data: Self::Data, _file: &File) {}
+
+    /// Reads data from this file to the caller's buffer.
+    ///
+    /// Corresponds to the `read` and `read_iter` function pointers in `struct file_operations`.
+    fn read(
+        _data: <Self::Data as PointerWrapper>::Borrowed<'_>,
+        _file: &File,
+        _writer: &mut impl IoBufferWriter,
+        _offset: u64,
+    ) -> Result<usize> {
+        Err(EINVAL)
+    }
+
+    /// Writes data from the caller's buffer to this file.
+    ///
+    /// Corresponds to the `write` and `write_iter` function pointers in `struct file_operations`.
+    fn write(
+        _data: <Self::Data as PointerWrapper>::Borrowed<'_>,
+        _file: &File,
+        _reader: &mut impl IoBufferReader,
+        _offset: u64,
+    ) -> Result<usize> {
+        Err(EINVAL)
+    }
+
+    /// Changes the position of the file.
+    ///
+    /// Corresponds to the `llseek` function pointer in `struct file_operations`.
+    fn seek(
+        _data: <Self::Data as PointerWrapper>::Borrowed<'_>,
+        _file: &File,
+        _offset: SeekFrom,
+    ) -> Result<u64> {
+        Err(EINVAL)
+    }
+
+    /// Performs IO control operations that are specific to the file.
+    ///
+    /// Corresponds to the `unlocked_ioctl` function pointer in `struct file_operations`.
+    fn ioctl(
+        _data: <Self::Data as PointerWrapper>::Borrowed<'_>,
+        _file: &File,
+        _cmd: &mut IoctlCommand,
+    ) -> Result<i32> {
+        Err(ENOTTY)
+    }
+
+    /// Performs 32-bit IO control operations on that are specific to the file on 64-bit kernels.
+    ///
+    /// Corresponds to the `compat_ioctl` function pointer in `struct file_operations`.
+    fn compat_ioctl(
+        _data: <Self::Data as PointerWrapper>::Borrowed<'_>,
+        _file: &File,
+        _cmd: &mut IoctlCommand,
+    ) -> Result<i32> {
+        Err(ENOTTY)
+    }
+
+    /// Syncs pending changes to this file.
+    ///
+    /// Corresponds to the `fsync` function pointer in `struct file_operations`.
+    fn fsync(
+        _data: <Self::Data as PointerWrapper>::Borrowed<'_>,
+        _file: &File,
+        _start: u64,
+        _end: u64,
+        _datasync: bool,
+    ) -> Result<u32> {
+        Err(EINVAL)
+    }
+
+    /// Maps areas of the caller's virtual memory with device/file memory.
+    ///
+    /// Corresponds to the `mmap` function pointer in `struct file_operations`.
+    fn mmap(
+        _data: <Self::Data as PointerWrapper>::Borrowed<'_>,
+        _file: &File,
+        _vma: &mut mm::virt::Area,
+    ) -> Result {
+        Err(EINVAL)
+    }
+
+    /// Checks the state of the file and optionally registers for notification when the state
+    /// changes.
+    ///
+    /// Corresponds to the `poll` function pointer in `struct file_operations`.
+    fn poll(
+        _data: <Self::Data as PointerWrapper>::Borrowed<'_>,
+        _file: &File,
+        _table: &PollTable,
+    ) -> Result<u32> {
+        Ok(bindings::POLLIN | bindings::POLLOUT | bindings::POLLRDNORM | bindings::POLLWRNORM)
+    }
+}
diff --git a/rust/kernel/gpio.rs b/rust/kernel/gpio.rs
new file mode 100644
index 000000000000..2e4365dfcf74
--- /dev/null
+++ b/rust/kernel/gpio.rs
@@ -0,0 +1,478 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Support for gpio device drivers.
+//!
+//! C header: [`include/linux/gpio/driver.h`](../../../../include/linux/gpio/driver.h)
+
+use crate::{
+    bindings, c_types, device, error::code::*, error::from_kernel_result, types::PointerWrapper,
+    Error, Result,
+};
+use core::{
+    cell::UnsafeCell,
+    marker::{PhantomData, PhantomPinned},
+    pin::Pin,
+};
+
+#[cfg(CONFIG_GPIOLIB_IRQCHIP)]
+pub use irqchip::{ChipWithIrqChip, RegistrationWithIrqChip};
+
+/// The direction of a gpio line.
+pub enum LineDirection {
+    /// Direction is input.
+    In = bindings::GPIO_LINE_DIRECTION_IN as _,
+
+    /// Direction is output.
+    Out = bindings::GPIO_LINE_DIRECTION_OUT as _,
+}
+
+/// A gpio chip.
+pub trait Chip {
+    /// Context data associated with the gpio chip.
+    ///
+    /// It determines the type of the context data passed to each of the methods of the trait.
+    type Data: PointerWrapper + Sync + Send;
+
+    /// The methods to use to populate [`struct gpio_chip`]. This is typically populated with
+    /// [`declare_gpio_chip_operations`].
+    const TO_USE: ToUse;
+
+    /// Returns the direction of the given gpio line.
+    fn get_direction(
+        _data: <Self::Data as PointerWrapper>::Borrowed<'_>,
+        _offset: u32,
+    ) -> Result<LineDirection> {
+        Err(ENOTSUPP)
+    }
+
+    /// Configures the direction as input of the given gpio line.
+    fn direction_input(
+        _data: <Self::Data as PointerWrapper>::Borrowed<'_>,
+        _offset: u32,
+    ) -> Result {
+        Err(EIO)
+    }
+
+    /// Configures the direction as output of the given gpio line.
+    ///
+    /// The value that will be initially output is also specified.
+    fn direction_output(
+        _data: <Self::Data as PointerWrapper>::Borrowed<'_>,
+        _offset: u32,
+        _value: bool,
+    ) -> Result {
+        Err(ENOTSUPP)
+    }
+
+    /// Returns the current value of the given gpio line.
+    fn get(_data: <Self::Data as PointerWrapper>::Borrowed<'_>, _offset: u32) -> Result<bool> {
+        Err(EIO)
+    }
+
+    /// Sets the value of the given gpio line.
+    fn set(_data: <Self::Data as PointerWrapper>::Borrowed<'_>, _offset: u32, _value: bool) {}
+}
+
+/// Represents which fields of [`struct gpio_chip`] should be populated with pointers.
+///
+/// This is typically populated with the [`declare_gpio_chip_operations`] macro.
+pub struct ToUse {
+    /// The `get_direction` field of [`struct gpio_chip`].
+    pub get_direction: bool,
+
+    /// The `direction_input` field of [`struct gpio_chip`].
+    pub direction_input: bool,
+
+    /// The `direction_output` field of [`struct gpio_chip`].
+    pub direction_output: bool,
+
+    /// The `get` field of [`struct gpio_chip`].
+    pub get: bool,
+
+    /// The `set` field of [`struct gpio_chip`].
+    pub set: bool,
+}
+
+/// A constant version where all values are set to `false`, that is, all supported fields will be
+/// set to null pointers.
+pub const USE_NONE: ToUse = ToUse {
+    get_direction: false,
+    direction_input: false,
+    direction_output: false,
+    get: false,
+    set: false,
+};
+
+/// Defines the [`Chip::TO_USE`] field based on a list of fields to be populated.
+#[macro_export]
+macro_rules! declare_gpio_chip_operations {
+    () => {
+        const TO_USE: $crate::gpio::ToUse = $crate::gpio::USE_NONE;
+    };
+    ($($i:ident),+) => {
+        #[allow(clippy::needless_update)]
+        const TO_USE: $crate::gpio::ToUse =
+            $crate::gpio::ToUse {
+                $($i: true),+ ,
+                ..$crate::gpio::USE_NONE
+            };
+    };
+}
+
+/// A registration of a gpio chip.
+pub struct Registration<T: Chip> {
+    gc: UnsafeCell<bindings::gpio_chip>,
+    parent: Option<device::Device>,
+    _p: PhantomData<T>,
+    _pin: PhantomPinned,
+}
+
+impl<T: Chip> Registration<T> {
+    /// Creates a new [`Registration`] but does not register it yet.
+    ///
+    /// It is allowed to move.
+    pub fn new() -> Self {
+        Self {
+            parent: None,
+            gc: UnsafeCell::new(bindings::gpio_chip::default()),
+            _pin: PhantomPinned,
+            _p: PhantomData,
+        }
+    }
+
+    /// Registers a gpio chip with the rest of the kernel.
+    pub fn register(
+        self: Pin<&mut Self>,
+        gpio_count: u16,
+        base: Option<i32>,
+        parent: &dyn device::RawDevice,
+        data: T::Data,
+    ) -> Result {
+        if self.parent.is_some() {
+            // Already registered.
+            return Err(EINVAL);
+        }
+
+        // SAFETY: We never move out of `this`.
+        let this = unsafe { self.get_unchecked_mut() };
+        {
+            let gc = this.gc.get_mut();
+
+            // Set up the callbacks.
+            gc.request = Some(bindings::gpiochip_generic_request);
+            gc.free = Some(bindings::gpiochip_generic_free);
+            if T::TO_USE.get_direction {
+                gc.get_direction = Some(get_direction_callback::<T>);
+            }
+            if T::TO_USE.direction_input {
+                gc.direction_input = Some(direction_input_callback::<T>);
+            }
+            if T::TO_USE.direction_output {
+                gc.direction_output = Some(direction_output_callback::<T>);
+            }
+            if T::TO_USE.get {
+                gc.get = Some(get_callback::<T>);
+            }
+            if T::TO_USE.set {
+                gc.set = Some(set_callback::<T>);
+            }
+
+            // When a base is not explicitly given, use -1 for one to be picked.
+            if let Some(b) = base {
+                gc.base = b;
+            } else {
+                gc.base = -1;
+            }
+
+            gc.ngpio = gpio_count;
+            gc.parent = parent.raw_device();
+            gc.label = parent.name().as_char_ptr();
+
+            // TODO: Define `gc.owner` as well.
+        }
+
+        let data_pointer = <T::Data as PointerWrapper>::into_pointer(data);
+        // SAFETY: `gc` was initilised above, so it is valid.
+        let ret = unsafe {
+            bindings::gpiochip_add_data_with_key(
+                this.gc.get(),
+                data_pointer as _,
+                core::ptr::null_mut(),
+                core::ptr::null_mut(),
+            )
+        };
+        if ret < 0 {
+            // SAFETY: `data_pointer` was returned by `into_pointer` above.
+            unsafe { T::Data::from_pointer(data_pointer) };
+            return Err(Error::from_kernel_errno(ret));
+        }
+
+        this.parent = Some(device::Device::from_dev(parent));
+        Ok(())
+    }
+}
+
+// SAFETY: `Registration` doesn't offer any methods or access to fields when shared between threads
+// or CPUs, so it is safe to share it.
+unsafe impl<T: Chip> Sync for Registration<T> {}
+
+// SAFETY: Registration with and unregistration from the gpio subsystem can happen from any thread.
+// Additionally, `T::Data` (which is dropped during unregistration) is `Send`, so it is ok to move
+// `Registration` to different threads.
+#[allow(clippy::non_send_fields_in_send_ty)]
+unsafe impl<T: Chip> Send for Registration<T> {}
+
+impl<T: Chip> Default for Registration<T> {
+    fn default() -> Self {
+        Self::new()
+    }
+}
+
+impl<T: Chip> Drop for Registration<T> {
+    /// Removes the registration from the kernel if it has completed successfully before.
+    fn drop(&mut self) {
+        if self.parent.is_some() {
+            // Get a pointer to the data stored in chip before destroying it.
+            // SAFETY: `gc` was during registration, which is guaranteed to have succeeded (because
+            // `parent` is `Some(_)`, so it remains valid.
+            let data_pointer = unsafe { bindings::gpiochip_get_data(self.gc.get()) };
+
+            // SAFETY: By the same argument above, `gc` is still valid.
+            unsafe { bindings::gpiochip_remove(self.gc.get()) };
+
+            // Free data as well.
+            // SAFETY: `data_pointer` was returned by `into_pointer` during registration.
+            unsafe { <T::Data as PointerWrapper>::from_pointer(data_pointer) };
+        }
+    }
+}
+
+unsafe extern "C" fn get_direction_callback<T: Chip>(
+    gc: *mut bindings::gpio_chip,
+    offset: c_types::c_uint,
+) -> c_types::c_int {
+    from_kernel_result! {
+        // SAFETY: The value stored as chip data was returned by `into_pointer` during registration.
+        let data = unsafe { T::Data::borrow(bindings::gpiochip_get_data(gc)) };
+        Ok(T::get_direction(data, offset)? as i32)
+    }
+}
+
+unsafe extern "C" fn direction_input_callback<T: Chip>(
+    gc: *mut bindings::gpio_chip,
+    offset: c_types::c_uint,
+) -> c_types::c_int {
+    from_kernel_result! {
+        // SAFETY: The value stored as chip data was returned by `into_pointer` during registration.
+        let data = unsafe { T::Data::borrow(bindings::gpiochip_get_data(gc)) };
+        T::direction_input(data, offset)?;
+        Ok(0)
+    }
+}
+
+unsafe extern "C" fn direction_output_callback<T: Chip>(
+    gc: *mut bindings::gpio_chip,
+    offset: c_types::c_uint,
+    value: c_types::c_int,
+) -> c_types::c_int {
+    from_kernel_result! {
+        // SAFETY: The value stored as chip data was returned by `into_pointer` during registration.
+        let data = unsafe { T::Data::borrow(bindings::gpiochip_get_data(gc)) };
+        T::direction_output(data, offset, value != 0)?;
+        Ok(0)
+    }
+}
+
+unsafe extern "C" fn get_callback<T: Chip>(
+    gc: *mut bindings::gpio_chip,
+    offset: c_types::c_uint,
+) -> c_types::c_int {
+    from_kernel_result! {
+        // SAFETY: The value stored as chip data was returned by `into_pointer` during registration.
+        let data = unsafe { T::Data::borrow(bindings::gpiochip_get_data(gc)) };
+        let v = T::get(data, offset)?;
+        Ok(v as _)
+    }
+}
+
+unsafe extern "C" fn set_callback<T: Chip>(
+    gc: *mut bindings::gpio_chip,
+    offset: c_types::c_uint,
+    value: c_types::c_int,
+) {
+    // SAFETY: The value stored as chip data was returned by `into_pointer` during registration.
+    let data = unsafe { T::Data::borrow(bindings::gpiochip_get_data(gc)) };
+    T::set(data, offset, value != 0);
+}
+
+#[cfg(CONFIG_GPIOLIB_IRQCHIP)]
+mod irqchip {
+    use super::*;
+    use crate::irq;
+
+    /// A gpio chip that includes an irq chip.
+    pub trait ChipWithIrqChip: Chip {
+        /// Implements the irq flow for the gpio chip.
+        fn handle_irq_flow(
+            _data: <Self::Data as PointerWrapper>::Borrowed<'_>,
+            _desc: &irq::Descriptor,
+            _domain: &irq::Domain,
+        );
+    }
+
+    /// A registration of a gpio chip that includes an irq chip.
+    pub struct RegistrationWithIrqChip<T: ChipWithIrqChip> {
+        reg: Registration<T>,
+        irq_chip: UnsafeCell<bindings::irq_chip>,
+        parent_irq: u32,
+    }
+
+    impl<T: ChipWithIrqChip> RegistrationWithIrqChip<T> {
+        /// Creates a new [`RegistrationWithIrqChip`] but does not register it yet.
+        ///
+        /// It is allowed to move.
+        pub fn new() -> Self {
+            Self {
+                reg: Registration::new(),
+                irq_chip: UnsafeCell::new(bindings::irq_chip::default()),
+                parent_irq: 0,
+            }
+        }
+
+        /// Registers a gpio chip and its irq chip with the rest of the kernel.
+        pub fn register<U: irq::Chip<Data = T::Data>>(
+            mut self: Pin<&mut Self>,
+            gpio_count: u16,
+            base: Option<i32>,
+            parent: &dyn device::RawDevice,
+            data: T::Data,
+            parent_irq: u32,
+        ) -> Result {
+            if self.reg.parent.is_some() {
+                // Already registered.
+                return Err(EINVAL);
+            }
+
+            // SAFETY: We never move out of `this`.
+            let this = unsafe { self.as_mut().get_unchecked_mut() };
+
+            // Initialise the irq_chip.
+            {
+                let irq_chip = this.irq_chip.get_mut();
+                irq_chip.name = parent.name().as_char_ptr();
+
+                // SAFETY: The gpio subsystem configures a pointer to `gpio_chip` as the irq chip
+                // data, so we use `IrqChipAdapter` to convert to the `T::Data`, which is the same
+                // as `irq::Chip::Data` per the bound above.
+                unsafe { irq::init_chip::<IrqChipAdapter<U>>(irq_chip) };
+            }
+
+            // Initialise gc irq state.
+            {
+                let girq = &mut this.reg.gc.get_mut().irq;
+                girq.chip = this.irq_chip.get();
+                // SAFETY: By leaving `parent_handler_data` set to `null`, the gpio subsystem
+                // initialises it to a pointer to the gpio chip, which is what `FlowHandler<T>`
+                // expects.
+                girq.parent_handler = unsafe { irq::new_flow_handler::<FlowHandler<T>>() };
+                girq.num_parents = 1;
+                girq.parents = &mut this.parent_irq;
+                this.parent_irq = parent_irq;
+                girq.default_type = bindings::IRQ_TYPE_NONE;
+                girq.handler = Some(bindings::handle_bad_irq);
+            }
+
+            // SAFETY: `reg` is pinned when `self` is.
+            let pinned = unsafe { self.map_unchecked_mut(|r| &mut r.reg) };
+            pinned.register(gpio_count, base, parent, data)
+        }
+    }
+
+    impl<T: ChipWithIrqChip> Default for RegistrationWithIrqChip<T> {
+        fn default() -> Self {
+            Self::new()
+        }
+    }
+
+    // SAFETY: `RegistrationWithIrqChip` doesn't offer any methods or access to fields when shared
+    // between threads or CPUs, so it is safe to share it.
+    unsafe impl<T: ChipWithIrqChip> Sync for RegistrationWithIrqChip<T> {}
+
+    // SAFETY: Registration with and unregistration from the gpio subsystem (including irq chips for
+    // them) can happen from any thread. Additionally, `T::Data` (which is dropped during
+    // unregistration) is `Send`, so it is ok to move `Registration` to different threads.
+    #[allow(clippy::non_send_fields_in_send_ty)]
+    unsafe impl<T: ChipWithIrqChip> Send for RegistrationWithIrqChip<T> where T::Data: Send {}
+
+    struct FlowHandler<T: ChipWithIrqChip>(PhantomData<T>);
+
+    impl<T: ChipWithIrqChip> irq::FlowHandler for FlowHandler<T> {
+        type Data = *mut bindings::gpio_chip;
+
+        fn handle_irq_flow(gc: *mut bindings::gpio_chip, desc: &irq::Descriptor) {
+            // SAFETY: `FlowHandler` is only used in gpio chips, and it is removed when the gpio is
+            // unregistered, so we know that `gc` must still be valid. We also know that the value
+            // stored as gpio data was returned by `T::Data::into_pointer` again because
+            // `FlowHandler` is a private structure only used in this way.
+            let data = unsafe { T::Data::borrow(bindings::gpiochip_get_data(gc)) };
+
+            // SAFETY: `gc` is valid (see comment above), so we can dereference it.
+            let domain = unsafe { irq::Domain::from_ptr((*gc).irq.domain) };
+
+            T::handle_irq_flow(data, desc, &domain);
+        }
+    }
+
+    /// Adapter from an irq chip with `gpio_chip` pointer as context to one where the gpio chip
+    /// data is passed as context.
+    struct IrqChipAdapter<T: irq::Chip>(PhantomData<T>);
+
+    impl<T: irq::Chip> irq::Chip for IrqChipAdapter<T> {
+        type Data = *mut bindings::gpio_chip;
+        const TO_USE: irq::ToUse = T::TO_USE;
+
+        fn ack(gc: *mut bindings::gpio_chip, irq_data: &irq::IrqData) {
+            // SAFETY: `IrqChipAdapter` is a private struct, only used when the data stored in the
+            // gpio chip is known to come from `T::Data`, and only valid while the gpio chip is
+            // registered, so `gc` is valid.
+            let data = unsafe { T::Data::borrow(bindings::gpiochip_get_data(gc as _)) };
+            T::ack(data, irq_data);
+        }
+
+        fn mask(gc: *mut bindings::gpio_chip, irq_data: &irq::IrqData) {
+            // SAFETY: `IrqChipAdapter` is a private struct, only used when the data stored in the
+            // gpio chip is known to come from `T::Data`, and only valid while the gpio chip is
+            // registered, so `gc` is valid.
+            let data = unsafe { T::Data::borrow(bindings::gpiochip_get_data(gc as _)) };
+            T::mask(data, irq_data);
+        }
+
+        fn unmask(gc: *mut bindings::gpio_chip, irq_data: &irq::IrqData) {
+            // SAFETY: `IrqChipAdapter` is a private struct, only used when the data stored in the
+            // gpio chip is known to come from `T::Data`, and only valid while the gpio chip is
+            // registered, so `gc` is valid.
+            let data = unsafe { T::Data::borrow(bindings::gpiochip_get_data(gc as _)) };
+            T::unmask(data, irq_data);
+        }
+
+        fn set_type(
+            gc: *mut bindings::gpio_chip,
+            irq_data: &mut irq::LockedIrqData,
+            flow_type: u32,
+        ) -> Result<irq::ExtraResult> {
+            // SAFETY: `IrqChipAdapter` is a private struct, only used when the data stored in the
+            // gpio chip is known to come from `T::Data`, and only valid while the gpio chip is
+            // registered, so `gc` is valid.
+            let data = unsafe { T::Data::borrow(bindings::gpiochip_get_data(gc as _)) };
+            T::set_type(data, irq_data, flow_type)
+        }
+
+        fn set_wake(gc: *mut bindings::gpio_chip, irq_data: &irq::IrqData, on: bool) -> Result {
+            // SAFETY: `IrqChipAdapter` is a private struct, only used when the data stored in the
+            // gpio chip is known to come from `T::Data`, and only valid while the gpio chip is
+            // registered, so `gc` is valid.
+            let data = unsafe { T::Data::borrow(bindings::gpiochip_get_data(gc as _)) };
+            T::set_wake(data, irq_data, on)
+        }
+    }
+}
diff --git a/rust/kernel/hwrng.rs b/rust/kernel/hwrng.rs
new file mode 100644
index 000000000000..a50de9510631
--- /dev/null
+++ b/rust/kernel/hwrng.rs
@@ -0,0 +1,242 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Hardware Random Number Generator.
+//!
+//! C header: [`include/linux/hw_random.h`](../../../../include/linux/hw_random.h)
+
+use alloc::{boxed::Box, slice::from_raw_parts_mut};
+
+use crate::{
+    bindings, c_types, error::code::*, error::from_kernel_result, str::CString, to_result,
+    types::PointerWrapper, Result, ScopeGuard,
+};
+
+use core::{cell::UnsafeCell, fmt, marker::PhantomData, pin::Pin};
+
+/// This trait is implemented in order to provide callbacks to `struct hwrng`.
+pub trait Operations {
+    /// The methods to use to populate [`struct hwrng`].
+    const TO_USE: ToUse;
+
+    /// The pointer type that will be used to hold user-defined data type.
+    type Data: PointerWrapper + Send + Sync = ();
+
+    /// Initialization callback, can be left undefined.
+    fn init(_data: <Self::Data as PointerWrapper>::Borrowed<'_>) -> Result {
+        Err(EINVAL)
+    }
+
+    /// Cleanup callback, can be left undefined.
+    fn cleanup(_data: Self::Data) {}
+
+    /// Read data into the provided buffer.
+    /// Drivers can fill up to max bytes of data into the buffer.
+    /// The buffer is aligned for any type and its size is a multiple of 4 and >= 32 bytes.
+    fn read(
+        data: <Self::Data as PointerWrapper>::Borrowed<'_>,
+        buffer: &mut [u8],
+        wait: bool,
+    ) -> Result<u32>;
+}
+
+/// Registration structure for Hardware Random Number Generator driver.
+pub struct Registration<T: Operations> {
+    hwrng: UnsafeCell<bindings::hwrng>,
+    name: Option<CString>,
+    registered: bool,
+    _p: PhantomData<T>,
+}
+
+impl<T: Operations> Registration<T> {
+    /// Creates new instance of registration.
+    ///
+    /// The data must be registered.
+    pub fn new() -> Self {
+        Self {
+            hwrng: UnsafeCell::new(bindings::hwrng::default()),
+            name: None,
+            registered: false,
+            _p: PhantomData,
+        }
+    }
+
+    /// Returns a registered and pinned, heap-allocated representation of the registration.
+    pub fn new_pinned(
+        name: fmt::Arguments<'_>,
+        quality: u16,
+        data: T::Data,
+    ) -> Result<Pin<Box<Self>>> {
+        let mut reg = Pin::from(Box::try_new(Self::new())?);
+        reg.as_mut().register(name, quality, data)?;
+        Ok(reg)
+    }
+
+    /// Registers a hwrng device within the rest of the kernel.
+    ///
+    /// It must be pinned because the memory block that represents
+    /// the registration may be self-referential.
+    pub fn register(
+        self: Pin<&mut Self>,
+        name: fmt::Arguments<'_>,
+        quality: u16,
+        data: T::Data,
+    ) -> Result {
+        // SAFETY: We never move out of `this`.
+        let this = unsafe { self.get_unchecked_mut() };
+
+        if this.registered {
+            return Err(EINVAL);
+        }
+
+        let data_pointer = data.into_pointer();
+
+        // SAFETY: `data_pointer` comes from the call to `data.into_pointer()` above.
+        let guard = ScopeGuard::new(|| unsafe {
+            T::Data::from_pointer(data_pointer);
+        });
+
+        let name = CString::try_from_fmt(name)?;
+
+        // SAFETY: Registration is pinned and contains allocated and set to zero `bindings::hwrng` structure.
+        Self::init_hwrng(
+            unsafe { &mut *this.hwrng.get() },
+            &name,
+            quality,
+            data_pointer,
+        );
+
+        // SAFETY: `bindings::hwrng` is initialized above which guarantees safety.
+        to_result(|| unsafe { bindings::hwrng_register(this.hwrng.get()) })?;
+
+        this.registered = true;
+        this.name = Some(name);
+        guard.dismiss();
+        Ok(())
+    }
+
+    fn init_hwrng(
+        hwrng: &mut bindings::hwrng,
+        name: &CString,
+        quality: u16,
+        data: *const c_types::c_void,
+    ) {
+        hwrng.name = name.as_char_ptr();
+
+        hwrng.init = if T::TO_USE.init {
+            Some(Self::init_callback)
+        } else {
+            None
+        };
+        hwrng.cleanup = if T::TO_USE.cleanup {
+            Some(Self::cleanup_callback)
+        } else {
+            None
+        };
+        hwrng.data_present = None;
+        hwrng.data_read = None;
+        hwrng.read = Some(Self::read_callback);
+
+        hwrng.priv_ = data as _;
+        hwrng.quality = quality;
+
+        // SAFETY: All fields are properly initialized as
+        // remaining fields `list`, `ref` and `cleanup_done` are already
+        // zeroed by `bindings::hwrng::default()` call.
+    }
+
+    unsafe extern "C" fn init_callback(rng: *mut bindings::hwrng) -> c_types::c_int {
+        from_kernel_result! {
+            // SAFETY: `priv` private data field was initialized during creation of
+            // the `bindings::hwrng` in `Self::init_hwrng` method. This callback is only
+            // called once the driver is registered.
+            let data = unsafe { T::Data::borrow((*rng).priv_ as *const _) };
+            T::init(data)?;
+            Ok(0)
+        }
+    }
+
+    unsafe extern "C" fn cleanup_callback(rng: *mut bindings::hwrng) {
+        // SAFETY: `priv` private data field was initialized during creation of
+        // the `bindings::hwrng` in `Self::init_hwrng` method. This callback is only
+        // called once the driver is registered.
+        let data = unsafe { T::Data::from_pointer((*rng).priv_ as *const _) };
+        T::cleanup(data);
+    }
+
+    unsafe extern "C" fn read_callback(
+        rng: *mut bindings::hwrng,
+        data: *mut c_types::c_void,
+        max: usize,
+        wait: bindings::bool_,
+    ) -> c_types::c_int {
+        from_kernel_result! {
+            // SAFETY: `priv` private data field was initialized during creation of
+            // the `bindings::hwrng` in `Self::init_hwrng` method. This callback is only
+            // called once the driver is registered.
+            let drv_data = unsafe { T::Data::borrow((*rng).priv_ as *const _) };
+
+            // SAFETY: Slice is created from `data` and `max` arguments that are C's buffer
+            // along with its size in bytes that are safe for this conversion.
+            let buffer = unsafe { from_raw_parts_mut(data as *mut u8, max) };
+            let ret = T::read(drv_data, buffer, wait)?;
+            Ok(ret as _)
+        }
+    }
+}
+
+impl<T: Operations> Default for Registration<T> {
+    fn default() -> Self {
+        Self::new()
+    }
+}
+
+/// Represents which callbacks of [`struct hwrng`] should be populated with pointers.
+pub struct ToUse {
+    /// The `init` field of [`struct hwrng`].
+    pub init: bool,
+
+    /// The `cleanup` field of [`struct hwrng`].
+    pub cleanup: bool,
+}
+
+/// A constant version where all values are to set to `false`, that is, all supported fields will
+/// be set to null pointers.
+pub const USE_NONE: ToUse = ToUse {
+    init: false,
+    cleanup: false,
+};
+
+/// Defines the [`Operations::TO_USE`] field based on a list of fields to be populated.
+#[macro_export]
+macro_rules! declare_hwrng_operations {
+    () => {
+        const TO_USE: $crate::hwrng::ToUse = $crate::hwrng::USE_NONE;
+    };
+    ($($i:ident),+) => {
+        #[allow(clippy::needless_update)]
+        const TO_USE: kernel::hwrng::ToUse =
+            $crate::hwrng::ToUse {
+                $($i: true),+ ,
+                ..$crate::hwrng::USE_NONE
+            };
+    };
+}
+
+// SAFETY: `Registration` does not expose any of its state across threads.
+unsafe impl<T: Operations> Sync for Registration<T> {}
+
+// SAFETY: `Registration` is not restricted to a single thread,
+// its `T::Data` is also `Send` so it may be moved to different threads.
+#[allow(clippy::non_send_fields_in_send_ty)]
+unsafe impl<T: Operations> Send for Registration<T> {}
+
+impl<T: Operations> Drop for Registration<T> {
+    /// Removes the registration from the kernel if it has completed successfully before.
+    fn drop(&mut self) {
+        // SAFETY: The instance of Registration<T> is unregistered only
+        // after being initialized and registered before.
+        if self.registered {
+            unsafe { bindings::hwrng_unregister(self.hwrng.get()) };
+        }
+    }
+}
diff --git a/rust/kernel/io_buffer.rs b/rust/kernel/io_buffer.rs
new file mode 100644
index 000000000000..ccecc4763aca
--- /dev/null
+++ b/rust/kernel/io_buffer.rs
@@ -0,0 +1,153 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Buffers used in IO.
+
+use crate::Result;
+use alloc::vec::Vec;
+use core::mem::{size_of, MaybeUninit};
+
+/// Represents a buffer to be read from during IO.
+pub trait IoBufferReader {
+    /// Returns the number of bytes left to be read from the io buffer.
+    ///
+    /// Note that even reading less than this number of bytes may fail.
+    fn len(&self) -> usize;
+
+    /// Returns `true` if no data is available in the io buffer.
+    fn is_empty(&self) -> bool {
+        self.len() == 0
+    }
+
+    /// Reads raw data from the io buffer into a raw kernel buffer.
+    ///
+    /// # Safety
+    ///
+    /// The output buffer must be valid.
+    unsafe fn read_raw(&mut self, out: *mut u8, len: usize) -> Result;
+
+    /// Reads all data remaining in the io buffer.
+    ///
+    /// Returns `EFAULT` if the address does not currently point to mapped, readable memory.
+    fn read_all(&mut self) -> Result<Vec<u8>> {
+        let mut data = Vec::<u8>::new();
+        data.try_resize(self.len(), 0)?;
+
+        // SAFETY: The output buffer is valid as we just allocated it.
+        unsafe { self.read_raw(data.as_mut_ptr(), data.len())? };
+        Ok(data)
+    }
+
+    /// Reads a byte slice from the io buffer.
+    ///
+    /// Returns `EFAULT` if the byte slice is bigger than the remaining size of the user slice or
+    /// if the address does not currently point to mapped, readable memory.
+    fn read_slice(&mut self, data: &mut [u8]) -> Result {
+        // SAFETY: The output buffer is valid as it's coming from a live reference.
+        unsafe { self.read_raw(data.as_mut_ptr(), data.len()) }
+    }
+
+    /// Reads the contents of a plain old data (POD) type from the io buffer.
+    fn read<T: ReadableFromBytes>(&mut self) -> Result<T> {
+        let mut out = MaybeUninit::<T>::uninit();
+        // SAFETY: The buffer is valid as it was just allocated.
+        unsafe { self.read_raw(out.as_mut_ptr() as _, size_of::<T>()) }?;
+        // SAFETY: We just initialised the data.
+        Ok(unsafe { out.assume_init() })
+    }
+}
+
+/// Represents a buffer to be written to during IO.
+pub trait IoBufferWriter {
+    /// Returns the number of bytes left to be written into the io buffer.
+    ///
+    /// Note that even writing less than this number of bytes may fail.
+    fn len(&self) -> usize;
+
+    /// Returns `true` if the io buffer cannot hold any additional data.
+    fn is_empty(&self) -> bool {
+        self.len() == 0
+    }
+
+    /// Writes zeroes to the io buffer.
+    ///
+    /// Differently from the other write functions, `clear` will zero as much as it can and update
+    /// the writer internal state to reflect this. It will, however, return an error if it cannot
+    /// clear `len` bytes.
+    ///
+    /// For example, if a caller requests that 100 bytes be cleared but a segfault happens after
+    /// 20 bytes, then EFAULT is returned and the writer is advanced by 20 bytes.
+    fn clear(&mut self, len: usize) -> Result;
+
+    /// Writes a byte slice into the io buffer.
+    ///
+    /// Returns `EFAULT` if the byte slice is bigger than the remaining size of the io buffer or if
+    /// the address does not currently point to mapped, writable memory.
+    fn write_slice(&mut self, data: &[u8]) -> Result {
+        // SAFETY: The input buffer is valid as it's coming from a live reference.
+        unsafe { self.write_raw(data.as_ptr(), data.len()) }
+    }
+
+    /// Writes raw data to the io buffer from a raw kernel buffer.
+    ///
+    /// # Safety
+    ///
+    /// The input buffer must be valid.
+    unsafe fn write_raw(&mut self, data: *const u8, len: usize) -> Result;
+
+    /// Writes the contents of the given data into the io buffer.
+    fn write<T: WritableToBytes>(&mut self, data: &T) -> Result {
+        // SAFETY: The input buffer is valid as it's coming from a live
+        // reference to a type that implements `WritableToBytes`.
+        unsafe { self.write_raw(data as *const T as _, size_of::<T>()) }
+    }
+}
+
+/// Specifies that a type is safely readable from byte slices.
+///
+/// Not all types can be safely read from byte slices; examples from
+/// <https://doc.rust-lang.org/reference/behavior-considered-undefined.html> include `bool`
+/// that must be either `0` or `1`, and `char` that cannot be a surrogate or above `char::MAX`.
+///
+/// # Safety
+///
+/// Implementers must ensure that the type is made up only of types that can be safely read from
+/// arbitrary byte sequences (e.g., `u32`, `u64`, etc.).
+pub unsafe trait ReadableFromBytes {}
+
+// SAFETY: All bit patterns are acceptable values of the types below.
+unsafe impl ReadableFromBytes for u8 {}
+unsafe impl ReadableFromBytes for u16 {}
+unsafe impl ReadableFromBytes for u32 {}
+unsafe impl ReadableFromBytes for u64 {}
+unsafe impl ReadableFromBytes for usize {}
+unsafe impl ReadableFromBytes for i8 {}
+unsafe impl ReadableFromBytes for i16 {}
+unsafe impl ReadableFromBytes for i32 {}
+unsafe impl ReadableFromBytes for i64 {}
+unsafe impl ReadableFromBytes for isize {}
+
+/// Specifies that a type is safely writable to byte slices.
+///
+/// This means that we don't read undefined values (which leads to UB) in preparation for writing
+/// to the byte slice. It also ensures that no potentially sensitive information is leaked into the
+/// byte slices.
+///
+/// # Safety
+///
+/// A type must not include padding bytes and must be fully initialised to safely implement
+/// [`WritableToBytes`] (i.e., it doesn't contain [`MaybeUninit`] fields). A composition of
+/// writable types in a structure is not necessarily writable because it may result in padding
+/// bytes.
+pub unsafe trait WritableToBytes {}
+
+// SAFETY: Initialised instances of the following types have no uninitialised portions.
+unsafe impl WritableToBytes for u8 {}
+unsafe impl WritableToBytes for u16 {}
+unsafe impl WritableToBytes for u32 {}
+unsafe impl WritableToBytes for u64 {}
+unsafe impl WritableToBytes for usize {}
+unsafe impl WritableToBytes for i8 {}
+unsafe impl WritableToBytes for i16 {}
+unsafe impl WritableToBytes for i32 {}
+unsafe impl WritableToBytes for i64 {}
+unsafe impl WritableToBytes for isize {}
diff --git a/rust/kernel/io_mem.rs b/rust/kernel/io_mem.rs
new file mode 100644
index 000000000000..25096fe43675
--- /dev/null
+++ b/rust/kernel/io_mem.rs
@@ -0,0 +1,275 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Memory-mapped IO.
+//!
+//! C header: [`include/asm-generic/io.h`](../../../../include/asm-generic/io.h)
+
+#![allow(dead_code)]
+
+use crate::{bindings, error::code::*, Result};
+use core::convert::TryInto;
+
+/// Represents a memory resource.
+pub struct Resource {
+    offset: bindings::resource_size_t,
+    size: bindings::resource_size_t,
+}
+
+impl Resource {
+    pub(crate) fn new(
+        start: bindings::resource_size_t,
+        end: bindings::resource_size_t,
+    ) -> Option<Self> {
+        if start == 0 {
+            return None;
+        }
+        Some(Self {
+            offset: start,
+            size: end.checked_sub(start)?.checked_add(1)?,
+        })
+    }
+}
+
+/// Represents a memory block of at least `SIZE` bytes.
+///
+/// # Invariants
+///
+/// `ptr` is a non-null and valid address of at least `SIZE` bytes and returned by an `ioremap`
+/// variant. `ptr` is also 8-byte aligned.
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::prelude::*;
+/// use kernel::io_mem::{IoMem, Resource};
+///
+/// fn test(res: Resource) -> Result {
+///     // Create an io mem block of at least 100 bytes.
+///     // SAFETY: No DMA operations are initiated through `mem`.
+///     let mem = unsafe { IoMem::<100>::try_new(res) }?;
+///
+///     // Read one byte from offset 10.
+///     let v = mem.readb(10);
+///
+///     // Write value to offset 20.
+///     mem.writeb(v, 20);
+///
+///     Ok(())
+/// }
+///
+/// ```
+pub struct IoMem<const SIZE: usize> {
+    ptr: usize,
+}
+
+macro_rules! define_read {
+    ($(#[$attr:meta])* $name:ident, $try_name:ident, $type_name:ty) => {
+        /// Reads IO data from the given offset known, at compile time.
+        ///
+        /// If the offset is not known at compile time, the build will fail.
+        $(#[$attr])*
+        pub fn $name(&self, offset: usize) -> $type_name {
+            Self::check_offset::<$type_name>(offset);
+            let ptr = self.ptr.wrapping_add(offset);
+            // SAFETY: The type invariants guarantee that `ptr` is a valid pointer. The check above
+            // guarantees that the code won't build if `offset` makes the read go out of bounds
+            // (including the type size).
+            unsafe { bindings::$name(ptr as _) }
+        }
+
+        /// Reads IO data from the given offset.
+        ///
+        /// It fails if/when the offset (plus the type size) is out of bounds.
+        $(#[$attr])*
+        pub fn $try_name(&self, offset: usize) -> Result<$type_name> {
+            if !Self::offset_ok::<$type_name>(offset) {
+                return Err(EINVAL);
+            }
+            let ptr = self.ptr.wrapping_add(offset);
+            // SAFETY: The type invariants guarantee that `ptr` is a valid pointer. The check above
+            // returns an error if `offset` would make the read go out of bounds (including the
+            // type size).
+            Ok(unsafe { bindings::$name(ptr as _) })
+        }
+    };
+}
+
+macro_rules! define_write {
+    ($(#[$attr:meta])* $name:ident, $try_name:ident, $type_name:ty) => {
+        /// Writes IO data to the given offset, known at compile time.
+        ///
+        /// If the offset is not known at compile time, the build will fail.
+        $(#[$attr])*
+        pub fn $name(&self, value: $type_name, offset: usize) {
+            Self::check_offset::<$type_name>(offset);
+            let ptr = self.ptr.wrapping_add(offset);
+            // SAFETY: The type invariants guarantee that `ptr` is a valid pointer. The check above
+            // guarantees that the code won't link if `offset` makes the write go out of bounds
+            // (including the type size).
+            unsafe { bindings::$name(value, ptr as _) }
+        }
+
+        /// Writes IO data to the given offset.
+        ///
+        /// It fails if/when the offset (plus the type size) is out of bounds.
+        $(#[$attr])*
+        pub fn $try_name(&self, value: $type_name, offset: usize) -> Result {
+            if !Self::offset_ok::<$type_name>(offset) {
+                return Err(EINVAL);
+            }
+            let ptr = self.ptr.wrapping_add(offset);
+            // SAFETY: The type invariants guarantee that `ptr` is a valid pointer. The check above
+            // returns an error if `offset` would make the write go out of bounds (including the
+            // type size).
+            unsafe { bindings::$name(value, ptr as _) };
+            Ok(())
+        }
+    };
+}
+
+impl<const SIZE: usize> IoMem<SIZE> {
+    /// Tries to create a new instance of a memory block.
+    ///
+    /// The resource described by `res` is mapped into the CPU's address space so that it can be
+    /// accessed directly. It is also consumed by this function so that it can't be mapped again
+    /// to a different address.
+    ///
+    /// # Safety
+    ///
+    /// Callers must ensure that either (a) the resulting interface cannot be used to initiate DMA
+    /// operations, or (b) that DMA operations initiated via the returned interface use DMA handles
+    /// allocated through the `dma` module.
+    pub unsafe fn try_new(res: Resource) -> Result<Self> {
+        // Check that the resource has at least `SIZE` bytes in it.
+        if res.size < SIZE.try_into()? {
+            return Err(EINVAL);
+        }
+
+        // To be able to check pointers at compile time based only on offsets, we need to guarantee
+        // that the base pointer is minimally aligned. So we conservatively expect at least 8 bytes.
+        if res.offset % 8 != 0 {
+            crate::pr_err!("Physical address is not 64-bit aligned: {:x}", res.offset);
+            return Err(EDOM);
+        }
+
+        // Try to map the resource.
+        // SAFETY: Just mapping the memory range.
+        let addr = unsafe { bindings::ioremap(res.offset, res.size as _) };
+        if addr.is_null() {
+            Err(ENOMEM)
+        } else {
+            // INVARIANT: `addr` is non-null and was returned by `ioremap`, so it is valid. It is
+            // also 8-byte aligned because we checked it above.
+            Ok(Self { ptr: addr as usize })
+        }
+    }
+
+    const fn offset_ok<T>(offset: usize) -> bool {
+        let type_size = core::mem::size_of::<T>();
+        if let Some(end) = offset.checked_add(type_size) {
+            end <= SIZE && offset % type_size == 0
+        } else {
+            false
+        }
+    }
+
+    fn offset_ok_of_val<T: ?Sized>(offset: usize, value: &T) -> bool {
+        let value_size = core::mem::size_of_val(value);
+        let value_alignment = core::mem::align_of_val(value);
+        if let Some(end) = offset.checked_add(value_size) {
+            end <= SIZE && offset % value_alignment == 0
+        } else {
+            false
+        }
+    }
+
+    const fn check_offset<T>(offset: usize) {
+        crate::build_assert!(Self::offset_ok::<T>(offset), "IoMem offset overflow");
+    }
+
+    /// Copy memory block from an i/o memory by filling the specified buffer with it.
+    ///
+    /// # Examples
+    /// ```
+    /// use kernel::io_mem::{self, IoMem, Resource};
+    ///
+    /// fn test(res: Resource) -> Result {
+    ///     // Create an i/o memory block of at least 100 bytes.
+    ///     let mem = unsafe { IoMem::<100>::try_new(res) }?;
+    ///
+    ///     let mut buffer: [u8; 32] = [0; 32];
+    ///
+    ///     // Memcpy 16 bytes from an offset 10 of i/o memory block into the buffer.
+    ///     mem.try_memcpy_fromio(&mut buffer[..16], 10)?;
+    ///
+    ///     Ok(())
+    /// }
+    /// ```
+    pub fn try_memcpy_fromio(&self, buffer: &mut [u8], offset: usize) -> Result {
+        if !Self::offset_ok_of_val(offset, buffer) {
+            return Err(EINVAL);
+        }
+
+        let ptr = self.ptr.wrapping_add(offset);
+
+        // SAFETY:
+        //   - The type invariants guarantee that `ptr` is a valid pointer.
+        //   - The bounds of `buffer` are checked with a call to `offset_ok_of_val()`.
+        unsafe {
+            bindings::memcpy_fromio(
+                buffer.as_mut_ptr() as *mut _,
+                ptr as *const _,
+                buffer.len() as _,
+            )
+        };
+        Ok(())
+    }
+
+    define_read!(readb, try_readb, u8);
+    define_read!(readw, try_readw, u16);
+    define_read!(readl, try_readl, u32);
+    define_read!(
+        #[cfg(CONFIG_64BIT)]
+        readq,
+        try_readq,
+        u64
+    );
+
+    define_read!(readb_relaxed, try_readb_relaxed, u8);
+    define_read!(readw_relaxed, try_readw_relaxed, u16);
+    define_read!(readl_relaxed, try_readl_relaxed, u32);
+    define_read!(
+        #[cfg(CONFIG_64BIT)]
+        readq_relaxed,
+        try_readq_relaxed,
+        u64
+    );
+
+    define_write!(writeb, try_writeb, u8);
+    define_write!(writew, try_writew, u16);
+    define_write!(writel, try_writel, u32);
+    define_write!(
+        #[cfg(CONFIG_64BIT)]
+        writeq,
+        try_writeq,
+        u64
+    );
+
+    define_write!(writeb_relaxed, try_writeb_relaxed, u8);
+    define_write!(writew_relaxed, try_writew_relaxed, u16);
+    define_write!(writel_relaxed, try_writel_relaxed, u32);
+    define_write!(
+        #[cfg(CONFIG_64BIT)]
+        writeq_relaxed,
+        try_writeq_relaxed,
+        u64
+    );
+}
+
+impl<const SIZE: usize> Drop for IoMem<SIZE> {
+    fn drop(&mut self) {
+        // SAFETY: By the type invariant, `self.ptr` is a value returned by a previous successful
+        // call to `ioremap`.
+        unsafe { bindings::iounmap(self.ptr as _) };
+    }
+}
diff --git a/rust/kernel/iov_iter.rs b/rust/kernel/iov_iter.rs
new file mode 100644
index 000000000000..b9b8dc882bd0
--- /dev/null
+++ b/rust/kernel/iov_iter.rs
@@ -0,0 +1,81 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! IO vector iterators.
+//!
+//! C header: [`include/linux/uio.h`](../../../../include/linux/uio.h)
+
+use crate::{
+    bindings,
+    error::code::*,
+    io_buffer::{IoBufferReader, IoBufferWriter},
+    Result,
+};
+
+/// Wraps the kernel's `struct iov_iter`.
+///
+/// # Invariants
+///
+/// The pointer `IovIter::ptr` is non-null and valid.
+pub struct IovIter {
+    ptr: *mut bindings::iov_iter,
+}
+
+impl IovIter {
+    fn common_len(&self) -> usize {
+        // SAFETY: `IovIter::ptr` is guaranteed to be valid by the type invariants.
+        unsafe { (*self.ptr).count }
+    }
+
+    /// Constructs a new [`struct iov_iter`] wrapper.
+    ///
+    /// # Safety
+    ///
+    /// The pointer `ptr` must be non-null and valid for the lifetime of the object.
+    pub(crate) unsafe fn from_ptr(ptr: *mut bindings::iov_iter) -> Self {
+        // INVARIANTS: the safety contract ensures the type invariant will hold.
+        Self { ptr }
+    }
+}
+
+impl IoBufferWriter for IovIter {
+    fn len(&self) -> usize {
+        self.common_len()
+    }
+
+    fn clear(&mut self, mut len: usize) -> Result {
+        while len > 0 {
+            // SAFETY: `IovIter::ptr` is guaranteed to be valid by the type invariants.
+            let written = unsafe { bindings::iov_iter_zero(len, self.ptr) };
+            if written == 0 {
+                return Err(EFAULT);
+            }
+
+            len -= written;
+        }
+        Ok(())
+    }
+
+    unsafe fn write_raw(&mut self, data: *const u8, len: usize) -> Result {
+        let res = unsafe { bindings::copy_to_iter(data as _, len, self.ptr) };
+        if res != len {
+            Err(EFAULT)
+        } else {
+            Ok(())
+        }
+    }
+}
+
+impl IoBufferReader for IovIter {
+    fn len(&self) -> usize {
+        self.common_len()
+    }
+
+    unsafe fn read_raw(&mut self, out: *mut u8, len: usize) -> Result {
+        let res = unsafe { bindings::copy_from_iter(out as _, len, self.ptr) };
+        if res != len {
+            Err(EFAULT)
+        } else {
+            Ok(())
+        }
+    }
+}
diff --git a/rust/kernel/irq.rs b/rust/kernel/irq.rs
new file mode 100644
index 000000000000..b1d067de6925
--- /dev/null
+++ b/rust/kernel/irq.rs
@@ -0,0 +1,411 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Interrupts and interrupt chips.
+//!
+//! See <https://www.kernel.org/doc/Documentation/core-api/genericirq.rst>.
+//!
+//! C headers: [`include/linux/irq.h`](../../../../include/linux/irq.h) and
+//! [`include/linux/interrupt.h`](../../../../include/linux/interrupt.h).
+
+#![allow(dead_code)]
+
+use crate::{bindings, c_types, error::from_kernel_result, types::PointerWrapper, Error, Result};
+use core::ops::Deref;
+
+/// The type of irq hardware numbers.
+pub type HwNumber = bindings::irq_hw_number_t;
+
+/// Wraps the kernel's `struct irq_data`.
+///
+/// # Invariants
+///
+/// The pointer `IrqData::ptr` is non-null and valid.
+pub struct IrqData {
+    ptr: *mut bindings::irq_data,
+}
+
+impl IrqData {
+    /// Creates a new `IrqData` instance from a raw pointer.
+    ///
+    /// # Safety
+    ///
+    /// Callers must ensure that `ptr` is non-null and valid when the function is called, and that
+    /// it remains valid for the lifetime of the return [`IrqData`] instance.
+    unsafe fn from_ptr(ptr: *mut bindings::irq_data) -> Self {
+        // INVARIANTS: By the safety requirements, the instance we're creating satisfies the type
+        // invariants.
+        Self { ptr }
+    }
+
+    /// Returns the hardware irq number.
+    pub fn hwirq(&self) -> HwNumber {
+        // SAFETY: By the type invariants, it's ok to dereference `ptr`.
+        unsafe { (*self.ptr).hwirq }
+    }
+}
+
+/// Wraps the kernel's `struct irq_data` when it is locked.
+///
+/// Being locked allows additional operations to be performed on the data.
+pub struct LockedIrqData(IrqData);
+
+impl LockedIrqData {
+    /// Sets the high-level irq flow handler to the builtin one for level-triggered irqs.
+    pub fn set_level_handler(&mut self) {
+        // SAFETY: By the type invariants of `self.0`, we know `self.0.ptr` is valid.
+        unsafe { bindings::irq_set_handler_locked(self.0.ptr, Some(bindings::handle_level_irq)) };
+    }
+
+    /// Sets the high-level irq flow handler to the builtin one for edge-triggered irqs.
+    pub fn set_edge_handler(&mut self) {
+        // SAFETY: By the type invariants of `self.0`, we know `self.0.ptr` is valid.
+        unsafe { bindings::irq_set_handler_locked(self.0.ptr, Some(bindings::handle_edge_irq)) };
+    }
+
+    /// Sets the high-level irq flow handler to the builtin one for bad irqs.
+    pub fn set_bad_handler(&mut self) {
+        // SAFETY: By the type invariants of `self.0`, we know `self.0.ptr` is valid.
+        unsafe { bindings::irq_set_handler_locked(self.0.ptr, Some(bindings::handle_bad_irq)) };
+    }
+}
+
+impl Deref for LockedIrqData {
+    type Target = IrqData;
+
+    fn deref(&self) -> &Self::Target {
+        &self.0
+    }
+}
+
+/// Extra information returned by some of the [`Chip`] methods on success.
+pub enum ExtraResult {
+    /// Indicates that the caller (irq core) will update the descriptor state.
+    None = bindings::IRQ_SET_MASK_OK as _,
+
+    /// Indicates that the callee (irq chip implementation) already updated the descriptor state.
+    NoCopy = bindings::IRQ_SET_MASK_OK_NOCOPY as _,
+
+    /// Same as [`ExtraResult::None`] in terms of updating descriptor state. It is used in stacked
+    /// irq chips to indicate that descendant chips should be skipped.
+    Done = bindings::IRQ_SET_MASK_OK_DONE as _,
+}
+
+/// An irq chip.
+///
+/// It is a trait for the functions defined in [`struct irq_chip`].
+///
+/// [`struct irq_chip`]: ../../../include/linux/irq.h
+pub trait Chip: Sized {
+    /// The type of the context data stored in the irq chip and made available on each callback.
+    type Data: PointerWrapper;
+
+    /// The methods to use to populate [`struct irq_chip`]. This is typically populated with
+    /// [`declare_irq_chip_operations`].
+    const TO_USE: ToUse;
+
+    /// Called at the start of a new interrupt.
+    fn ack(data: <Self::Data as PointerWrapper>::Borrowed<'_>, irq_data: &IrqData);
+
+    /// Masks an interrupt source.
+    fn mask(data: <Self::Data as PointerWrapper>::Borrowed<'_>, irq_data: &IrqData);
+
+    /// Unmasks an interrupt source.
+    fn unmask(_data: <Self::Data as PointerWrapper>::Borrowed<'_>, irq_data: &IrqData);
+
+    /// Sets the flow type of an interrupt.
+    ///
+    /// The flow type is a combination of the constants in [`Type`].
+    fn set_type(
+        _data: <Self::Data as PointerWrapper>::Borrowed<'_>,
+        _irq_data: &mut LockedIrqData,
+        _flow_type: u32,
+    ) -> Result<ExtraResult> {
+        Ok(ExtraResult::None)
+    }
+
+    /// Enables or disables power-management wake-on of an interrupt.
+    fn set_wake(
+        _data: <Self::Data as PointerWrapper>::Borrowed<'_>,
+        _irq_data: &IrqData,
+        _on: bool,
+    ) -> Result {
+        Ok(())
+    }
+}
+
+/// Initialises `chip` with the callbacks defined in `T`.
+///
+/// # Safety
+///
+/// The caller must ensure that the value stored in the irq chip data is the result of calling
+/// [`PointerWrapper::into_pointer] for the [`T::Data`] type.
+pub(crate) unsafe fn init_chip<T: Chip>(chip: &mut bindings::irq_chip) {
+    chip.irq_ack = Some(irq_ack_callback::<T>);
+    chip.irq_mask = Some(irq_mask_callback::<T>);
+    chip.irq_unmask = Some(irq_unmask_callback::<T>);
+
+    if T::TO_USE.set_type {
+        chip.irq_set_type = Some(irq_set_type_callback::<T>);
+    }
+
+    if T::TO_USE.set_wake {
+        chip.irq_set_wake = Some(irq_set_wake_callback::<T>);
+    }
+}
+
+/// Represents which fields of [`struct irq_chip`] should be populated with pointers.
+///
+/// This is typically populated with the [`declare_irq_chip_operations`] macro.
+pub struct ToUse {
+    /// The `irq_set_type` field of [`struct irq_chip`].
+    pub set_type: bool,
+
+    /// The `irq_set_wake` field of [`struct irq_chip`].
+    pub set_wake: bool,
+}
+
+/// A constant version where all values are to set to `false`, that is, all supported fields will
+/// be set to null pointers.
+pub const USE_NONE: ToUse = ToUse {
+    set_type: false,
+    set_wake: false,
+};
+
+/// Defines the [`Chip::TO_USE`] field based on a list of fields to be populated.
+#[macro_export]
+macro_rules! declare_irq_chip_operations {
+    () => {
+        const TO_USE: $crate::irq::ToUse = $crate::irq::USE_NONE;
+    };
+    ($($i:ident),+) => {
+        #[allow(clippy::needless_update)]
+        const TO_USE: $crate::irq::ToUse =
+            $crate::irq::ToUse {
+                $($i: true),+ ,
+                ..$crate::irq::USE_NONE
+            };
+    };
+}
+
+/// Enables or disables power-management wake-on for the given irq number.
+pub fn set_wake(irq: u32, on: bool) -> Result {
+    // SAFETY: Just an FFI call, there are no extra requirements for safety.
+    let ret = unsafe { bindings::irq_set_irq_wake(irq, on as _) };
+    if ret < 0 {
+        Err(Error::from_kernel_errno(ret))
+    } else {
+        Ok(())
+    }
+}
+
+unsafe extern "C" fn irq_ack_callback<T: Chip>(irq_data: *mut bindings::irq_data) {
+    // SAFETY: The safety requirements of `init_chip`, which is the only place that uses this
+    // callback, ensure that the value stored as irq chip data comes from a previous call to
+    // `PointerWrapper::into_pointer`.
+    let data = unsafe { T::Data::borrow(bindings::irq_data_get_irq_chip_data(irq_data)) };
+
+    // SAFETY: The value returned by `IrqData` is only valid until the end of this function, and
+    // `irq_data` is guaranteed to be valid until then (by the contract with C code).
+    T::ack(data, unsafe { &IrqData::from_ptr(irq_data) })
+}
+
+unsafe extern "C" fn irq_mask_callback<T: Chip>(irq_data: *mut bindings::irq_data) {
+    // SAFETY: The safety requirements of `init_chip`, which is the only place that uses this
+    // callback, ensure that the value stored as irq chip data comes from a previous call to
+    // `PointerWrapper::into_pointer`.
+    let data = unsafe { T::Data::borrow(bindings::irq_data_get_irq_chip_data(irq_data)) };
+
+    // SAFETY: The value returned by `IrqData` is only valid until the end of this function, and
+    // `irq_data` is guaranteed to be valid until then (by the contract with C code).
+    T::mask(data, unsafe { &IrqData::from_ptr(irq_data) })
+}
+
+unsafe extern "C" fn irq_unmask_callback<T: Chip>(irq_data: *mut bindings::irq_data) {
+    // SAFETY: The safety requirements of `init_chip`, which is the only place that uses this
+    // callback, ensure that the value stored as irq chip data comes from a previous call to
+    // `PointerWrapper::into_pointer`.
+    let data = unsafe { T::Data::borrow(bindings::irq_data_get_irq_chip_data(irq_data)) };
+
+    // SAFETY: The value returned by `IrqData` is only valid until the end of this function, and
+    // `irq_data` is guaranteed to be valid until then (by the contract with C code).
+    T::unmask(data, unsafe { &IrqData::from_ptr(irq_data) })
+}
+
+unsafe extern "C" fn irq_set_type_callback<T: Chip>(
+    irq_data: *mut bindings::irq_data,
+    flow_type: c_types::c_uint,
+) -> c_types::c_int {
+    from_kernel_result! {
+        // SAFETY: The safety requirements of `init_chip`, which is the only place that uses this
+        // callback, ensure that the value stored as irq chip data comes from a previous call to
+        // `PointerWrapper::into_pointer`.
+        let data = unsafe { T::Data::borrow(bindings::irq_data_get_irq_chip_data(irq_data)) };
+
+        // SAFETY: The value returned by `IrqData` is only valid until the end of this function, and
+        // `irq_data` is guaranteed to be valid until then (by the contract with C code).
+        let ret = T::set_type(data, &mut LockedIrqData(unsafe { IrqData::from_ptr(irq_data) }), flow_type)?;
+        Ok(ret as _)
+    }
+}
+
+unsafe extern "C" fn irq_set_wake_callback<T: Chip>(
+    irq_data: *mut bindings::irq_data,
+    on: c_types::c_uint,
+) -> c_types::c_int {
+    from_kernel_result! {
+        // SAFETY: The safety requirements of `init_chip`, which is the only place that uses this
+        // callback, ensure that the value stored as irq chip data comes from a previous call to
+        // `PointerWrapper::into_pointer`.
+        let data = unsafe { T::Data::borrow(bindings::irq_data_get_irq_chip_data(irq_data)) };
+
+        // SAFETY: The value returned by `IrqData` is only valid until the end of this function, and
+        // `irq_data` is guaranteed to be valid until then (by the contract with C code).
+        T::set_wake(data, unsafe { &IrqData::from_ptr(irq_data) }, on != 0)?;
+        Ok(0)
+    }
+}
+
+/// Contains constants that describes how an interrupt can be triggered.
+///
+/// It is tagged with `non_exhaustive` to prevent users from instantiating it.
+#[non_exhaustive]
+pub struct Type;
+
+impl Type {
+    /// The interrupt cannot be triggered.
+    pub const NONE: u32 = bindings::IRQ_TYPE_NONE;
+
+    /// The interrupt is triggered when the signal goes from low to high.
+    pub const EDGE_RISING: u32 = bindings::IRQ_TYPE_EDGE_RISING;
+
+    /// The interrupt is triggered when the signal goes from high to low.
+    pub const EDGE_FALLING: u32 = bindings::IRQ_TYPE_EDGE_FALLING;
+
+    /// The interrupt is triggered when the signal goes from low to high and when it goes to high
+    /// to low.
+    pub const EDGE_BOTH: u32 = bindings::IRQ_TYPE_EDGE_BOTH;
+
+    /// The interrupt is triggered while the signal is held high.
+    pub const LEVEL_HIGH: u32 = bindings::IRQ_TYPE_LEVEL_HIGH;
+
+    /// The interrupt is triggered while the signal is held low.
+    pub const LEVEL_LOW: u32 = bindings::IRQ_TYPE_LEVEL_LOW;
+}
+
+/// Wraps the kernel's `struct irq_desc`.
+///
+/// # Invariants
+///
+/// The pointer `Descriptor::ptr` is non-null and valid.
+pub struct Descriptor {
+    pub(crate) ptr: *mut bindings::irq_desc,
+}
+
+impl Descriptor {
+    /// Constructs a new `struct irq_desc` wrapper.
+    ///
+    /// # Safety
+    ///
+    /// The pointer `ptr` must be non-null and valid for the lifetime of the returned object.
+    unsafe fn from_ptr(ptr: *mut bindings::irq_desc) -> Self {
+        // INVARIANT: The safety requirements ensure the invariant.
+        Self { ptr }
+    }
+
+    /// Calls `chained_irq_enter` and returns a guard that calls `chained_irq_exit` once dropped.
+    ///
+    /// It is meant to be used by chained irq handlers to dispatch irqs to the next handlers.
+    pub fn enter_chained(&self) -> ChainedGuard<'_> {
+        // SAFETY: By the type invariants, `ptr` is always non-null and valid.
+        let irq_chip = unsafe { bindings::irq_desc_get_chip(self.ptr) };
+
+        // SAFETY: By the type invariants, `ptr` is always non-null and valid. `irq_chip` was just
+        // returned from `ptr`, so it is still valid too.
+        unsafe { bindings::chained_irq_enter(irq_chip, self.ptr) };
+        ChainedGuard {
+            desc: self,
+            irq_chip,
+        }
+    }
+}
+
+/// A guard to call `chained_irq_exit` after `chained_irq_enter` was called.
+///
+/// It is also used as evidence that a previous `chained_irq_enter` was called. So there are no
+/// public constructors and it is only created after indeed calling `chained_irq_enter`.
+pub struct ChainedGuard<'a> {
+    desc: &'a Descriptor,
+    irq_chip: *mut bindings::irq_chip,
+}
+
+impl Drop for ChainedGuard<'_> {
+    fn drop(&mut self) {
+        // SAFETY: The lifetime of `ChainedGuard` guarantees that `self.desc` remains valid, so it
+        // also guarantess `irq_chip` (which was returned from it) and `self.desc.ptr` (guaranteed
+        // by the type invariants).
+        unsafe { bindings::chained_irq_exit(self.irq_chip, self.desc.ptr) };
+    }
+}
+
+/// Wraps the kernel's `struct irq_domain`.
+///
+/// # Invariants
+///
+/// The pointer `Domain::ptr` is non-null and valid.
+#[cfg(CONFIG_IRQ_DOMAIN)]
+pub struct Domain {
+    ptr: *mut bindings::irq_domain,
+}
+
+#[cfg(CONFIG_IRQ_DOMAIN)]
+impl Domain {
+    /// Constructs a new `struct irq_domain` wrapper.
+    ///
+    /// # Safety
+    ///
+    /// The pointer `ptr` must be non-null and valid for the lifetime of the returned object.
+    pub(crate) unsafe fn from_ptr(ptr: *mut bindings::irq_domain) -> Self {
+        // INVARIANT: The safety requirements ensure the invariant.
+        Self { ptr }
+    }
+
+    /// Invokes the chained handler of the given hw irq of the given domain.
+    ///
+    /// It requires evidence that `chained_irq_enter` was called, which is done by passing a
+    /// `ChainedGuard` instance.
+    pub fn generic_handle_chained(&self, hwirq: u32, _guard: &ChainedGuard<'_>) {
+        // SAFETY: `ptr` is valid by the type invariants.
+        unsafe { bindings::generic_handle_domain_irq(self.ptr, hwirq) };
+    }
+}
+
+/// A high-level irq flow handler.
+pub trait FlowHandler {
+    /// The data associated with the handler.
+    type Data: PointerWrapper;
+
+    /// Implements the irq flow for the given descriptor.
+    fn handle_irq_flow(data: <Self::Data as PointerWrapper>::Borrowed<'_>, desc: &Descriptor);
+}
+
+/// Returns the raw irq flow handler corresponding to the (high-level) one defined in `T`.
+///
+/// # Safety
+///
+/// The caller must ensure that the value stored in the irq handler data (as returned by
+/// `irq_desc_get_handler_data`) is the result of calling [`PointerWrapper::into_pointer] for the
+/// [`T::Data`] type.
+pub(crate) unsafe fn new_flow_handler<T: FlowHandler>() -> bindings::irq_flow_handler_t {
+    Some(irq_flow_handler::<T>)
+}
+
+unsafe extern "C" fn irq_flow_handler<T: FlowHandler>(desc: *mut bindings::irq_desc) {
+    // SAFETY: By the safety requirements of `new_flow_handler`, we know that the value returned by
+    // `irq_desc_get_handler_data` comes from calling `T::Data::into_pointer`. `desc` is valid by
+    // the C API contract.
+    let data = unsafe { T::Data::borrow(bindings::irq_desc_get_handler_data(desc)) };
+
+    // SAFETY: The C API guarantees that `desc` is valid for the duration of this call, which
+    // outlives the lifetime returned by `from_desc`.
+    T::handle_irq_flow(data, &unsafe { Descriptor::from_ptr(desc) });
+}
diff --git a/rust/kernel/kasync.rs b/rust/kernel/kasync.rs
new file mode 100644
index 000000000000..4b57116bebc5
--- /dev/null
+++ b/rust/kernel/kasync.rs
@@ -0,0 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Kernel async functionality.
+
+#[cfg(CONFIG_NET)]
+pub mod net;
diff --git a/rust/kernel/kasync/net.rs b/rust/kernel/kasync/net.rs
new file mode 100644
index 000000000000..f7d15559e738
--- /dev/null
+++ b/rust/kernel/kasync/net.rs
@@ -0,0 +1,322 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Async networking.
+
+use crate::{bindings, c_types, error::code::*, net, sync::NoWaitLock, types::Opaque, Result};
+use core::{
+    future::Future,
+    marker::{PhantomData, PhantomPinned},
+    ops::Deref,
+    pin::Pin,
+    task::{Context, Poll, Waker},
+};
+
+/// A socket listening on a TCP port.
+///
+/// The [`TcpListener::accept`] method is meant to be used in async contexts.
+pub struct TcpListener {
+    listener: net::TcpListener,
+}
+
+impl TcpListener {
+    /// Creates a new TCP listener.
+    ///
+    /// It is configured to listen on the given socket address for the given namespace.
+    pub fn try_new(ns: &net::Namespace, addr: &net::SocketAddr) -> Result<Self> {
+        Ok(Self {
+            listener: net::TcpListener::try_new(ns, addr)?,
+        })
+    }
+
+    /// Accepts a new connection.
+    ///
+    /// Returns a future that when ready indicates the result of the accept operation; on success,
+    /// it contains the newly-accepted tcp stream.
+    pub fn accept(&self) -> impl Future<Output = Result<TcpStream>> + '_ {
+        SocketFuture::from_listener(
+            self,
+            bindings::BINDINGS_EPOLLIN | bindings::BINDINGS_EPOLLERR,
+            || {
+                Ok(TcpStream {
+                    stream: self.listener.accept(false)?,
+                })
+            },
+        )
+    }
+}
+
+impl Deref for TcpListener {
+    type Target = net::TcpListener;
+
+    fn deref(&self) -> &Self::Target {
+        &self.listener
+    }
+}
+
+/// A connected TCP socket.
+///
+/// The potentially blocking methods (e.g., [`TcpStream::read`], [`TcpStream::write`]) are meant
+/// to be used in async contexts.
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::prelude::*;
+/// # use kernel::kasync::net::TcpStream;
+/// async fn echo_server(stream: TcpStream) -> Result {
+///     let mut buf = [0u8; 1024];
+///     loop {
+///         let n = stream.read(&mut buf).await?;
+///         if n == 0 {
+///             return Ok(());
+///         }
+///         stream.write_all(&buf[..n]).await?;
+///     }
+/// }
+/// ```
+pub struct TcpStream {
+    stream: net::TcpStream,
+}
+
+impl TcpStream {
+    /// Reads data from a connected socket.
+    ///
+    /// Returns a future that when ready indicates the result of the read operation; on success, it
+    /// contains the number of bytes read, which will be zero if the connection is closed.
+    pub fn read<'a>(&'a self, buf: &'a mut [u8]) -> impl Future<Output = Result<usize>> + 'a {
+        SocketFuture::from_stream(
+            self,
+            bindings::BINDINGS_EPOLLIN | bindings::BINDINGS_EPOLLHUP | bindings::BINDINGS_EPOLLERR,
+            || self.stream.read(buf, false),
+        )
+    }
+
+    /// Writes data to the connected socket.
+    ///
+    /// Returns a future that when ready indicates the result of the write operation; on success, it
+    /// contains the number of bytes written.
+    pub fn write<'a>(&'a self, buf: &'a [u8]) -> impl Future<Output = Result<usize>> + 'a {
+        SocketFuture::from_stream(
+            self,
+            bindings::BINDINGS_EPOLLOUT | bindings::BINDINGS_EPOLLHUP | bindings::BINDINGS_EPOLLERR,
+            || self.stream.write(buf, false),
+        )
+    }
+
+    /// Writes all the data to the connected socket.
+    ///
+    /// Returns a future that when ready indicates the result of the write operation; on success, it
+    /// has written all the data.
+    pub async fn write_all<'a>(&'a self, buf: &'a [u8]) -> Result {
+        let mut rem = buf;
+
+        while !rem.is_empty() {
+            let n = self.write(rem).await?;
+            rem = &rem[n..];
+        }
+
+        Ok(())
+    }
+}
+
+impl Deref for TcpStream {
+    type Target = net::TcpStream;
+
+    fn deref(&self) -> &Self::Target {
+        &self.stream
+    }
+}
+
+/// A future for a socket operation.
+///
+/// # Invariants
+///
+/// `sock` is always non-null and valid for the duration of the lifetime of the instance.
+struct SocketFuture<'a, Out, F: FnMut() -> Result<Out> + Send + 'a> {
+    sock: *mut bindings::socket,
+    mask: u32,
+    is_queued: bool,
+    wq_entry: Opaque<bindings::wait_queue_entry>,
+    waker: NoWaitLock<Option<Waker>>,
+    _p: PhantomData<&'a ()>,
+    _pin: PhantomPinned,
+    operation: F,
+}
+
+// SAFETY: A kernel socket can be used from any thread, `wq_entry` is only used on drop and when
+// `is_queued` is initially `false`.
+unsafe impl<Out, F: FnMut() -> Result<Out> + Send> Send for SocketFuture<'_, Out, F> {}
+
+impl<'a, Out, F: FnMut() -> Result<Out> + Send + 'a> SocketFuture<'a, Out, F> {
+    /// Creates a new socket future.
+    ///
+    /// # Safety
+    ///
+    /// Callers must ensure that `sock` is non-null, valid, and remains valid for the lifetime
+    /// (`'a`) of the returned instance.
+    unsafe fn new(sock: *mut bindings::socket, mask: u32, operation: F) -> Self {
+        Self {
+            sock,
+            mask,
+            is_queued: false,
+            wq_entry: Opaque::uninit(),
+            waker: NoWaitLock::new(None),
+            operation,
+            _p: PhantomData,
+            _pin: PhantomPinned,
+        }
+    }
+
+    /// Creates a new socket future for a tcp listener.
+    fn from_listener(listener: &'a TcpListener, mask: u32, operation: F) -> Self {
+        // SAFETY: The socket is guaranteed to remain valid because it is bound to the reference to
+        // the listener (whose existence guarantees the socket remains valid).
+        unsafe { Self::new(listener.listener.sock, mask, operation) }
+    }
+
+    /// Creates a new socket future for a tcp stream.
+    fn from_stream(stream: &'a TcpStream, mask: u32, operation: F) -> Self {
+        // SAFETY: The socket is guaranteed to remain valid because it is bound to the reference to
+        // the stream (whose existence guarantees the socket remains valid).
+        unsafe { Self::new(stream.stream.sock, mask, operation) }
+    }
+
+    /// Callback called when the socket changes state.
+    ///
+    /// If the state matches the one we're waiting on, we wake up the task so that the future can be
+    /// polled again.
+    unsafe extern "C" fn wake_callback(
+        wq_entry: *mut bindings::wait_queue_entry,
+        _mode: c_types::c_uint,
+        _flags: c_types::c_int,
+        key: *mut c_types::c_void,
+    ) -> c_types::c_int {
+        let mask = key as u32;
+
+        // SAFETY: The future is valid while this callback is called because we remove from the
+        // queue on drop.
+        //
+        // There is a potential soundness issue here because we're generating a shared reference to
+        // `Self` while `Self::poll` has a mutable (unique) reference. However, for `!Unpin` types
+        // (like `Self`), `&mut T` is treated as `*mut T` per
+        // https://github.com/rust-lang/rust/issues/63818 -- so we avoid the unsoundness. Once a
+        // more definitive solution is available, we can change this to use it.
+        let s = unsafe { &*crate::container_of!(wq_entry, Self, wq_entry) };
+        if mask & s.mask == 0 {
+            // Nothing to do as this notification doesn't interest us.
+            return 0;
+        }
+
+        // If we can't acquire the waker lock, the waker is in the process of being modified. Our
+        // attempt to acquire the lock will be reported to the lock owner, so it will trigger the
+        // wake up.
+        if let Some(guard) = s.waker.try_lock() {
+            if let Some(ref w) = *guard {
+                let cloned = w.clone();
+                drop(guard);
+                cloned.wake();
+                return 1;
+            }
+        }
+        0
+    }
+
+    /// Poll the future once.
+    ///
+    /// It calls the operation and converts `EAGAIN` errors into a pending state.
+    fn poll_once(self: Pin<&mut Self>) -> Poll<Result<Out>> {
+        // SAFETY: We never move out of `this`.
+        let this = unsafe { self.get_unchecked_mut() };
+        match (this.operation)() {
+            Ok(s) => Poll::Ready(Ok(s)),
+            Err(e) => {
+                if e == EAGAIN {
+                    Poll::Pending
+                } else {
+                    Poll::Ready(Err(e))
+                }
+            }
+        }
+    }
+
+    /// Updates the waker stored in the future.
+    ///
+    /// It automatically triggers a wake up on races with the reactor.
+    fn set_waker(&self, waker: &Waker) {
+        if let Some(mut guard) = self.waker.try_lock() {
+            let old = core::mem::replace(&mut *guard, Some(waker.clone()));
+            let contention = guard.unlock();
+            drop(old);
+            if !contention {
+                return;
+            }
+        }
+
+        // We either couldn't store the waker because the existing one is being awakened, or the
+        // reactor tried to acquire the lock while we held it (contention). In either case, we just
+        // wake it up to ensure we don't miss any notification.
+        waker.wake_by_ref();
+    }
+}
+
+impl<Out, F: FnMut() -> Result<Out> + Send> Future for SocketFuture<'_, Out, F> {
+    type Output = Result<Out>;
+
+    fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
+        match self.as_mut().poll_once() {
+            Poll::Ready(r) => Poll::Ready(r),
+            Poll::Pending => {
+                // Store away the latest waker every time we may `Pending`.
+                self.set_waker(cx.waker());
+                if self.is_queued {
+                    // Nothing else to do was the waiter is already queued.
+                    return Poll::Pending;
+                }
+
+                // SAFETY: We never move out of `this`.
+                let this = unsafe { self.as_mut().get_unchecked_mut() };
+
+                this.is_queued = true;
+
+                // SAFETY: `wq_entry` is valid for write.
+                unsafe {
+                    bindings::init_waitqueue_func_entry(
+                        this.wq_entry.get(),
+                        Some(Self::wake_callback),
+                    )
+                };
+
+                // SAFETY: `wq_entry` was just initialised above and is valid for read/write.
+                // By the type invariants, the socket is always valid.
+                unsafe {
+                    bindings::add_wait_queue(
+                        core::ptr::addr_of_mut!((*this.sock).wq.wait),
+                        this.wq_entry.get(),
+                    )
+                };
+
+                // If the future wasn't queued yet, we need to poll again in case it reached
+                // the desired state between the last poll and being queued (in which case we
+                // would have missed the notification).
+                self.poll_once()
+            }
+        }
+    }
+}
+
+impl<Out, F: FnMut() -> Result<Out> + Send> Drop for SocketFuture<'_, Out, F> {
+    fn drop(&mut self) {
+        if !self.is_queued {
+            return;
+        }
+
+        // SAFETY: `wq_entry` is initialised because `is_queued` is set to `true`, so it is valid
+        // for read/write. By the type invariants, the socket is always valid.
+        unsafe {
+            bindings::remove_wait_queue(
+                core::ptr::addr_of_mut!((*self.sock).wq.wait),
+                self.wq_entry.get(),
+            )
+        };
+    }
+}
diff --git a/rust/kernel/kunit.rs b/rust/kernel/kunit.rs
new file mode 100644
index 000000000000..5f3e102962c3
--- /dev/null
+++ b/rust/kernel/kunit.rs
@@ -0,0 +1,91 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! KUnit-based macros for Rust unit tests.
+//!
+//! C header: [`include/kunit/test.h`](../../../../../include/kunit/test.h)
+//!
+//! Reference: <https://www.kernel.org/doc/html/latest/dev-tools/kunit/index.html>
+
+/// Asserts that a boolean expression is `true` at runtime.
+///
+/// Public but hidden since it should only be used from generated tests.
+///
+/// Unlike the one in `core`, this one does not panic; instead, it is mapped to the KUnit
+/// facilities. See [`assert!`] for more details.
+#[doc(hidden)]
+#[macro_export]
+macro_rules! kunit_assert {
+    ($test:expr, $cond:expr $(,)?) => {{
+        if !$cond {
+            #[repr(transparent)]
+            struct Location($crate::bindings::kunit_loc);
+
+            #[repr(transparent)]
+            struct UnaryAssert($crate::bindings::kunit_unary_assert);
+
+            // SAFETY: There is only a static instance and in that one the pointer field
+            // points to an immutable C string.
+            unsafe impl Sync for Location {}
+
+            // SAFETY: There is only a static instance and in that one the pointer field
+            // points to an immutable C string.
+            unsafe impl Sync for UnaryAssert {}
+
+            static FILE: &'static $crate::str::CStr = $crate::c_str!(core::file!());
+            static LOCATION: Location = Location($crate::bindings::kunit_loc {
+                file: FILE.as_char_ptr(),
+                line: core::line!() as i32,
+            });
+            static CONDITION: &'static $crate::str::CStr = $crate::c_str!(stringify!($cond));
+            static ASSERTION: UnaryAssert = UnaryAssert($crate::bindings::kunit_unary_assert {
+                assert: $crate::bindings::kunit_assert {
+                    format: Some($crate::bindings::kunit_unary_assert_format),
+                },
+                condition: CONDITION.as_char_ptr(),
+                expected_true: true,
+            });
+
+            // SAFETY:
+            //   - FFI call.
+            //   - The `test` pointer is valid because this hidden macro should only be called by
+            //     the generated documentation tests which forward the test pointer given by KUnit.
+            //   - The string pointers (`file` and `condition`) point to null-terminated ones.
+            //   - The function pointer (`format`) points to the proper function.
+            //   - The pointers passed will remain valid since they point to statics.
+            //   - The format string is allowed to be null.
+            //   - There are, however, problems with this: first of all, this will end up stopping
+            //     the thread, without running destructors. While that is problematic in itself,
+            //     it is considered UB to have what is effectively an forced foreign unwind
+            //     with `extern "C"` ABI. One could observe the stack that is now gone from
+            //     another thread. We should avoid pinning stack variables to prevent library UB,
+            //     too. For the moment, given test failures are reported immediately before the
+            //     next test runs, that test failures should be fixed and that KUnit is explicitly
+            //     documented as not suitable for production environments, we feel it is reasonable.
+            unsafe {
+                $crate::bindings::kunit_do_failed_assertion(
+                    $test,
+                    core::ptr::addr_of!(LOCATION.0),
+                    $crate::bindings::kunit_assert_type_KUNIT_ASSERTION,
+                    core::ptr::addr_of!(ASSERTION.0.assert),
+                    core::ptr::null(),
+                );
+            }
+        }
+    }};
+}
+
+/// Asserts that two expressions are equal to each other (using [`PartialEq`]).
+///
+/// Public but hidden since it should only be used from generated tests.
+///
+/// Unlike the one in `core`, this one does not panic; instead, it is mapped to the KUnit
+/// facilities. See [`assert!`] for more details.
+#[doc(hidden)]
+#[macro_export]
+macro_rules! kunit_assert_eq {
+    ($test:expr, $left:expr, $right:expr $(,)?) => {{
+        // For the moment, we just forward to the expression assert because,
+        // for binary asserts, KUnit supports only a few types (e.g. integers).
+        $crate::kunit_assert!($test, $left == $right);
+    }};
+}
diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs
new file mode 100644
index 000000000000..3e01c30de670
--- /dev/null
+++ b/rust/kernel/lib.rs
@@ -0,0 +1,261 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! The `kernel` crate.
+//!
+//! This crate contains the kernel APIs that have been ported or wrapped for
+//! usage by Rust code in the kernel and is shared by all of them.
+//!
+//! In other words, all the rest of the Rust code in the kernel (e.g. kernel
+//! modules written in Rust) depends on [`core`], [`alloc`] and this crate.
+//!
+//! If you need a kernel C API that is not ported or wrapped yet here, then
+//! do so first instead of bypassing this crate.
+
+#![no_std]
+#![feature(allocator_api)]
+#![feature(associated_type_defaults)]
+#![feature(concat_idents)]
+#![feature(const_fn_trait_bound)]
+#![feature(const_mut_refs)]
+#![feature(const_ptr_offset_from)]
+#![feature(const_refs_to_cell)]
+#![feature(const_trait_impl)]
+#![feature(doc_cfg)]
+#![feature(generic_associated_types)]
+#![feature(ptr_metadata)]
+#![feature(receiver_trait)]
+#![feature(coerce_unsized)]
+#![feature(dispatch_from_dyn)]
+#![feature(unsize)]
+
+// Ensure conditional compilation based on the kernel configuration works;
+// otherwise we may silently break things like initcall handling.
+#[cfg(not(CONFIG_RUST))]
+compile_error!("Missing kernel configuration for conditional compilation");
+
+#[cfg(not(test))]
+#[cfg(not(testlib))]
+mod allocator;
+
+#[doc(hidden)]
+pub mod bindings;
+
+#[cfg(CONFIG_ARM_AMBA)]
+pub mod amba;
+pub mod c_types;
+pub mod chrdev;
+#[cfg(CONFIG_COMMON_CLK)]
+pub mod clk;
+pub mod cred;
+pub mod device;
+pub mod driver;
+pub mod error;
+pub mod file;
+pub mod gpio;
+pub mod hwrng;
+pub mod irq;
+pub mod kasync;
+pub mod miscdev;
+pub mod mm;
+#[cfg(CONFIG_NET)]
+pub mod net;
+pub mod pages;
+pub mod power;
+pub mod revocable;
+pub mod security;
+pub mod str;
+pub mod task;
+
+pub mod linked_list;
+mod raw_list;
+pub mod rbtree;
+
+#[doc(hidden)]
+pub mod module_param;
+
+mod build_assert;
+pub mod prelude;
+pub mod print;
+pub mod random;
+mod static_assert;
+#[doc(hidden)]
+pub mod std_vendor;
+pub mod sync;
+
+#[cfg(any(CONFIG_SYSCTL, doc))]
+#[doc(cfg(CONFIG_SYSCTL))]
+pub mod sysctl;
+
+pub mod io_buffer;
+#[cfg(CONFIG_HAS_IOMEM)]
+pub mod io_mem;
+pub mod iov_iter;
+pub mod of;
+pub mod platform;
+mod types;
+pub mod user_ptr;
+
+#[cfg(CONFIG_KUNIT)]
+pub mod kunit;
+
+#[doc(hidden)]
+pub use build_error::build_error;
+
+pub use crate::error::{to_result, Error, Result};
+pub use crate::types::{
+    bit, bits_iter, ARef, AlwaysRefCounted, Bool, False, Mode, Opaque, ScopeGuard, True,
+};
+
+use core::marker::PhantomData;
+
+/// Page size defined in terms of the `PAGE_SHIFT` macro from C.
+///
+/// [`PAGE_SHIFT`]: ../../../include/asm-generic/page.h
+pub const PAGE_SIZE: usize = 1 << bindings::PAGE_SHIFT;
+
+/// Prefix to appear before log messages printed from within the kernel crate.
+const __LOG_PREFIX: &[u8] = b"rust_kernel\0";
+
+/// The top level entrypoint to implementing a kernel module.
+///
+/// For any teardown or cleanup operations, your type may implement [`Drop`].
+pub trait Module: Sized + Sync {
+    /// Called at module initialization time.
+    ///
+    /// Use this method to perform whatever setup or registration your module
+    /// should do.
+    ///
+    /// Equivalent to the `module_init` macro in the C API.
+    fn init(name: &'static str::CStr, module: &'static ThisModule) -> Result<Self>;
+}
+
+/// Equivalent to `THIS_MODULE` in the C API.
+///
+/// C header: `include/linux/export.h`
+pub struct ThisModule(*mut bindings::module);
+
+// SAFETY: `THIS_MODULE` may be used from all threads within a module.
+unsafe impl Sync for ThisModule {}
+
+impl ThisModule {
+    /// Creates a [`ThisModule`] given the `THIS_MODULE` pointer.
+    ///
+    /// # Safety
+    ///
+    /// The pointer must be equal to the right `THIS_MODULE`.
+    pub const unsafe fn from_ptr(ptr: *mut bindings::module) -> ThisModule {
+        ThisModule(ptr)
+    }
+
+    /// Locks the module parameters to access them.
+    ///
+    /// Returns a [`KParamGuard`] that will release the lock when dropped.
+    pub fn kernel_param_lock(&self) -> KParamGuard<'_> {
+        // SAFETY: `kernel_param_lock` will check if the pointer is null and
+        // use the built-in mutex in that case.
+        #[cfg(CONFIG_SYSFS)]
+        unsafe {
+            bindings::kernel_param_lock(self.0)
+        }
+
+        KParamGuard {
+            #[cfg(CONFIG_SYSFS)]
+            this_module: self,
+            phantom: PhantomData,
+        }
+    }
+}
+
+/// Scoped lock on the kernel parameters of [`ThisModule`].
+///
+/// Lock will be released when this struct is dropped.
+pub struct KParamGuard<'a> {
+    #[cfg(CONFIG_SYSFS)]
+    this_module: &'a ThisModule,
+    phantom: PhantomData<&'a ()>,
+}
+
+#[cfg(CONFIG_SYSFS)]
+impl<'a> Drop for KParamGuard<'a> {
+    fn drop(&mut self) {
+        // SAFETY: `kernel_param_lock` will check if the pointer is null and
+        // use the built-in mutex in that case. The existence of `self`
+        // guarantees that the lock is held.
+        unsafe { bindings::kernel_param_unlock(self.this_module.0) }
+    }
+}
+
+/// Calculates the offset of a field from the beginning of the struct it belongs to.
+///
+/// # Example
+///
+/// ```
+/// # use kernel::prelude::*;
+/// # use kernel::offset_of;
+/// struct Test {
+///     a: u64,
+///     b: u32,
+/// }
+///
+/// assert_eq!(offset_of!(Test, b), 8);
+/// ```
+#[macro_export]
+macro_rules! offset_of {
+    ($type:ty, $($f:tt)*) => {{
+        let tmp = core::mem::MaybeUninit::<$type>::uninit();
+        let outer = tmp.as_ptr();
+        // To avoid warnings when nesting `unsafe` blocks.
+        #[allow(unused_unsafe)]
+        // SAFETY: The pointer is valid and aligned, just not initialised; `addr_of` ensures that
+        // we don't actually read from `outer` (which would be UB) nor create an intermediate
+        // reference.
+        let inner = unsafe { core::ptr::addr_of!((*outer).$($f)*) } as *const u8;
+        // To avoid warnings when nesting `unsafe` blocks.
+        #[allow(unused_unsafe)]
+        // SAFETY: The two pointers are within the same allocation block.
+        unsafe { inner.offset_from(outer as *const u8) }
+    }}
+}
+
+/// Produces a pointer to an object from a pointer to one of its fields.
+///
+/// # Safety
+///
+/// Callers must ensure that the pointer to the field is in fact a pointer to the specified field,
+/// as opposed to a pointer to another object of the same type. If this condition is not met,
+/// any dereference of the resulting pointer is UB.
+///
+/// # Example
+///
+/// ```
+/// # use kernel::container_of;
+/// struct Test {
+///     a: u64,
+///     b: u32,
+/// }
+///
+/// let test = Test { a: 10, b: 20 };
+/// let b_ptr = &test.b;
+/// let test_alias = container_of!(b_ptr, Test, b);
+/// assert!(core::ptr::eq(&test, test_alias));
+/// ```
+#[macro_export]
+macro_rules! container_of {
+    ($ptr:expr, $type:ty, $($f:tt)*) => {{
+        let ptr = $ptr as *const _ as *const u8;
+        let offset = $crate::offset_of!($type, $($f)*);
+        ptr.wrapping_offset(-offset) as *const $type
+    }}
+}
+
+#[cfg(not(any(testlib, test)))]
+#[panic_handler]
+fn panic(info: &core::panic::PanicInfo<'_>) -> ! {
+    pr_emerg!("{}\n", info);
+    // SAFETY: FFI call.
+    unsafe { bindings::BUG() };
+    // Bindgen currently does not recognize `__noreturn` so `BUG` returns `()`
+    // instead of `!`.
+    // https://github.com/rust-lang/rust-bindgen/issues/2094
+    loop {}
+}
diff --git a/rust/kernel/linked_list.rs b/rust/kernel/linked_list.rs
new file mode 100644
index 000000000000..3330edcc7ca8
--- /dev/null
+++ b/rust/kernel/linked_list.rs
@@ -0,0 +1,247 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Linked lists.
+//!
+//! TODO: This module is a work in progress.
+
+use alloc::boxed::Box;
+use core::ptr::NonNull;
+
+pub use crate::raw_list::{Cursor, GetLinks, Links};
+use crate::{raw_list, raw_list::RawList, sync::Ref};
+
+// TODO: Use the one from `kernel::file_operations::PointerWrapper` instead.
+/// Wraps an object to be inserted in a linked list.
+pub trait Wrapper<T: ?Sized> {
+    /// Converts the wrapped object into a pointer that represents it.
+    fn into_pointer(self) -> NonNull<T>;
+
+    /// Converts the object back from the pointer representation.
+    ///
+    /// # Safety
+    ///
+    /// The passed pointer must come from a previous call to [`Wrapper::into_pointer()`].
+    unsafe fn from_pointer(ptr: NonNull<T>) -> Self;
+
+    /// Returns a reference to the wrapped object.
+    fn as_ref(&self) -> &T;
+}
+
+impl<T: ?Sized> Wrapper<T> for Box<T> {
+    fn into_pointer(self) -> NonNull<T> {
+        NonNull::new(Box::into_raw(self)).unwrap()
+    }
+
+    unsafe fn from_pointer(ptr: NonNull<T>) -> Self {
+        unsafe { Box::from_raw(ptr.as_ptr()) }
+    }
+
+    fn as_ref(&self) -> &T {
+        AsRef::as_ref(self)
+    }
+}
+
+impl<T: ?Sized> Wrapper<T> for Ref<T> {
+    fn into_pointer(self) -> NonNull<T> {
+        NonNull::new(Ref::into_raw(self) as _).unwrap()
+    }
+
+    unsafe fn from_pointer(ptr: NonNull<T>) -> Self {
+        // SAFETY: The safety requirements of `from_pointer` satisfy the ones from `Ref::from_raw`.
+        unsafe { Ref::from_raw(ptr.as_ptr() as _) }
+    }
+
+    fn as_ref(&self) -> &T {
+        AsRef::as_ref(self)
+    }
+}
+
+impl<T: ?Sized> Wrapper<T> for &T {
+    fn into_pointer(self) -> NonNull<T> {
+        NonNull::from(self)
+    }
+
+    unsafe fn from_pointer(ptr: NonNull<T>) -> Self {
+        unsafe { &*ptr.as_ptr() }
+    }
+
+    fn as_ref(&self) -> &T {
+        self
+    }
+}
+
+/// A descriptor of wrapped list elements.
+pub trait GetLinksWrapped: GetLinks {
+    /// Specifies which wrapper (e.g., `Box` and `Arc`) wraps the list entries.
+    type Wrapped: Wrapper<Self::EntryType>;
+}
+
+impl<T: ?Sized> GetLinksWrapped for Box<T>
+where
+    Box<T>: GetLinks,
+{
+    type Wrapped = Box<<Box<T> as GetLinks>::EntryType>;
+}
+
+impl<T: GetLinks + ?Sized> GetLinks for Box<T> {
+    type EntryType = T::EntryType;
+    fn get_links(data: &Self::EntryType) -> &Links<Self::EntryType> {
+        <T as GetLinks>::get_links(data)
+    }
+}
+
+impl<T: ?Sized> GetLinksWrapped for Ref<T>
+where
+    Ref<T>: GetLinks,
+{
+    type Wrapped = Ref<<Ref<T> as GetLinks>::EntryType>;
+}
+
+impl<T: GetLinks + ?Sized> GetLinks for Ref<T> {
+    type EntryType = T::EntryType;
+
+    fn get_links(data: &Self::EntryType) -> &Links<Self::EntryType> {
+        <T as GetLinks>::get_links(data)
+    }
+}
+
+/// A linked list.
+///
+/// Elements in the list are wrapped and ownership is transferred to the list while the element is
+/// in the list.
+pub struct List<G: GetLinksWrapped> {
+    list: RawList<G>,
+}
+
+impl<G: GetLinksWrapped> List<G> {
+    /// Constructs a new empty linked list.
+    pub fn new() -> Self {
+        Self {
+            list: RawList::new(),
+        }
+    }
+
+    /// Returns whether the list is empty.
+    pub fn is_empty(&self) -> bool {
+        self.list.is_empty()
+    }
+
+    /// Adds the given object to the end (back) of the list.
+    ///
+    /// It is dropped if it's already on this (or another) list; this can happen for
+    /// reference-counted objects, so dropping means decrementing the reference count.
+    pub fn push_back(&mut self, data: G::Wrapped) {
+        let ptr = data.into_pointer();
+
+        // SAFETY: We took ownership of the entry, so it is safe to insert it.
+        if !unsafe { self.list.push_back(ptr.as_ref()) } {
+            // If insertion failed, rebuild object so that it can be freed.
+            // SAFETY: We just called `into_pointer` above.
+            unsafe { G::Wrapped::from_pointer(ptr) };
+        }
+    }
+
+    /// Inserts the given object after `existing`.
+    ///
+    /// It is dropped if it's already on this (or another) list; this can happen for
+    /// reference-counted objects, so dropping means decrementing the reference count.
+    ///
+    /// # Safety
+    ///
+    /// Callers must ensure that `existing` points to a valid entry that is on the list.
+    pub unsafe fn insert_after(&mut self, existing: NonNull<G::EntryType>, data: G::Wrapped) {
+        let ptr = data.into_pointer();
+        let entry = unsafe { &*existing.as_ptr() };
+        if unsafe { !self.list.insert_after(entry, ptr.as_ref()) } {
+            // If insertion failed, rebuild object so that it can be freed.
+            unsafe { G::Wrapped::from_pointer(ptr) };
+        }
+    }
+
+    /// Removes the given entry.
+    ///
+    /// # Safety
+    ///
+    /// Callers must ensure that `data` is either on this list or in no list. It being on another
+    /// list leads to memory unsafety.
+    pub unsafe fn remove(&mut self, data: &G::Wrapped) -> Option<G::Wrapped> {
+        let entry_ref = Wrapper::as_ref(data);
+        if unsafe { self.list.remove(entry_ref) } {
+            Some(unsafe { G::Wrapped::from_pointer(NonNull::from(entry_ref)) })
+        } else {
+            None
+        }
+    }
+
+    /// Removes the element currently at the front of the list and returns it.
+    ///
+    /// Returns `None` if the list is empty.
+    pub fn pop_front(&mut self) -> Option<G::Wrapped> {
+        let front = self.list.pop_front()?;
+        // SAFETY: Elements on the list were inserted after a call to `into_pointer `.
+        Some(unsafe { G::Wrapped::from_pointer(front) })
+    }
+
+    /// Returns a cursor starting on the first (front) element of the list.
+    pub fn cursor_front(&self) -> Cursor<'_, G> {
+        self.list.cursor_front()
+    }
+
+    /// Returns a mutable cursor starting on the first (front) element of the list.
+    pub fn cursor_front_mut(&mut self) -> CursorMut<'_, G> {
+        CursorMut::new(self.list.cursor_front_mut())
+    }
+}
+
+impl<G: GetLinksWrapped> Default for List<G> {
+    fn default() -> Self {
+        Self::new()
+    }
+}
+
+impl<G: GetLinksWrapped> Drop for List<G> {
+    fn drop(&mut self) {
+        while self.pop_front().is_some() {}
+    }
+}
+
+/// A list cursor that allows traversing a linked list and inspecting & mutating elements.
+pub struct CursorMut<'a, G: GetLinksWrapped> {
+    cursor: raw_list::CursorMut<'a, G>,
+}
+
+impl<'a, G: GetLinksWrapped> CursorMut<'a, G> {
+    fn new(cursor: raw_list::CursorMut<'a, G>) -> Self {
+        Self { cursor }
+    }
+
+    /// Returns the element the cursor is currently positioned on.
+    pub fn current(&mut self) -> Option<&mut G::EntryType> {
+        self.cursor.current()
+    }
+
+    /// Removes the element the cursor is currently positioned on.
+    ///
+    /// After removal, it advances the cursor to the next element.
+    pub fn remove_current(&mut self) -> Option<G::Wrapped> {
+        let ptr = self.cursor.remove_current()?;
+
+        // SAFETY: Elements on the list were inserted after a call to `into_pointer `.
+        Some(unsafe { G::Wrapped::from_pointer(ptr) })
+    }
+
+    /// Returns the element immediately after the one the cursor is positioned on.
+    pub fn peek_next(&mut self) -> Option<&mut G::EntryType> {
+        self.cursor.peek_next()
+    }
+
+    /// Returns the element immediately before the one the cursor is positioned on.
+    pub fn peek_prev(&mut self) -> Option<&mut G::EntryType> {
+        self.cursor.peek_prev()
+    }
+
+    /// Moves the cursor to the next element.
+    pub fn move_next(&mut self) {
+        self.cursor.move_next();
+    }
+}
diff --git a/rust/kernel/miscdev.rs b/rust/kernel/miscdev.rs
new file mode 100644
index 000000000000..8b1110b0143c
--- /dev/null
+++ b/rust/kernel/miscdev.rs
@@ -0,0 +1,291 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Miscellaneous devices.
+//!
+//! C header: [`include/linux/miscdevice.h`](../../../../include/linux/miscdevice.h)
+//!
+//! Reference: <https://www.kernel.org/doc/html/latest/driver-api/misc_devices.html>
+
+use crate::bindings;
+use crate::error::{code::*, Error, Result};
+use crate::file;
+use crate::{device, str::CStr, str::CString, ThisModule};
+use alloc::boxed::Box;
+use core::marker::PhantomPinned;
+use core::{fmt, mem::MaybeUninit, pin::Pin};
+
+/// Options which can be used to configure how a misc device is registered.
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::{c_str, device::RawDevice, file, miscdev, prelude::*};
+/// fn example(
+///     reg: Pin<&mut miscdev::Registration<impl file::Operations<OpenData = ()>>>,
+///     parent: &dyn RawDevice,
+/// ) -> Result {
+///     miscdev::Options::new()
+///         .mode(0o600)
+///         .minor(10)
+///         .parent(parent)
+///         .register(reg, fmt!("sample"), ())
+/// }
+/// ```
+#[derive(Default)]
+pub struct Options<'a> {
+    minor: Option<i32>,
+    mode: Option<u16>,
+    parent: Option<&'a dyn device::RawDevice>,
+}
+
+impl<'a> Options<'a> {
+    /// Creates new [`Options`] instance with the required fields.
+    pub const fn new() -> Self {
+        Self {
+            minor: None,
+            mode: None,
+            parent: None,
+        }
+    }
+
+    /// Sets the minor device number.
+    pub const fn minor(&mut self, v: i32) -> &mut Self {
+        self.minor = Some(v);
+        self
+    }
+
+    /// Sets the device mode.
+    ///
+    /// This is usually an octal number and describes who can perform read/write/execute operations
+    /// on the device.
+    pub const fn mode(&mut self, m: u16) -> &mut Self {
+        self.mode = Some(m);
+        self
+    }
+
+    /// Sets the device parent.
+    pub const fn parent(&mut self, p: &'a dyn device::RawDevice) -> &mut Self {
+        self.parent = Some(p);
+        self
+    }
+
+    /// Registers a misc device using the configured options.
+    pub fn register<T: file::Operations>(
+        &self,
+        reg: Pin<&mut Registration<T>>,
+        name: fmt::Arguments<'_>,
+        open_data: T::OpenData,
+    ) -> Result {
+        reg.register_with_options(name, open_data, self)
+    }
+
+    /// Allocates a new registration of a misc device and completes the registration with the
+    /// configured options.
+    pub fn register_new<T: file::Operations>(
+        &self,
+        name: fmt::Arguments<'_>,
+        open_data: T::OpenData,
+    ) -> Result<Pin<Box<Registration<T>>>> {
+        let mut r = Pin::from(Box::try_new(Registration::new())?);
+        self.register(r.as_mut(), name, open_data)?;
+        Ok(r)
+    }
+}
+
+/// A registration of a miscellaneous device.
+///
+/// # Invariants
+///
+/// `Context` is always initialised when `registered` is `true`, and not initialised otherwise.
+pub struct Registration<T: file::Operations> {
+    registered: bool,
+    mdev: bindings::miscdevice,
+    name: Option<CString>,
+    _pin: PhantomPinned,
+
+    /// Context initialised on construction and made available to all file instances on
+    /// [`file::Operations::open`].
+    open_data: MaybeUninit<T::OpenData>,
+}
+
+impl<T: file::Operations> Registration<T> {
+    /// Creates a new [`Registration`] but does not register it yet.
+    ///
+    /// It is allowed to move.
+    pub fn new() -> Self {
+        // INVARIANT: `registered` is `false` and `open_data` is not initialised.
+        Self {
+            registered: false,
+            mdev: bindings::miscdevice::default(),
+            name: None,
+            _pin: PhantomPinned,
+            open_data: MaybeUninit::uninit(),
+        }
+    }
+
+    /// Registers a miscellaneous device.
+    ///
+    /// Returns a pinned heap-allocated representation of the registration.
+    pub fn new_pinned(name: fmt::Arguments<'_>, open_data: T::OpenData) -> Result<Pin<Box<Self>>> {
+        Options::new().register_new(name, open_data)
+    }
+
+    /// Registers a miscellaneous device with the rest of the kernel.
+    ///
+    /// It must be pinned because the memory block that represents the registration is
+    /// self-referential.
+    pub fn register(
+        self: Pin<&mut Self>,
+        name: fmt::Arguments<'_>,
+        open_data: T::OpenData,
+    ) -> Result {
+        Options::new().register(self, name, open_data)
+    }
+
+    /// Registers a miscellaneous device with the rest of the kernel. Additional optional settings
+    /// are provided via the `opts` parameter.
+    ///
+    /// It must be pinned because the memory block that represents the registration is
+    /// self-referential.
+    pub fn register_with_options(
+        self: Pin<&mut Self>,
+        name: fmt::Arguments<'_>,
+        open_data: T::OpenData,
+        opts: &Options<'_>,
+    ) -> Result {
+        // SAFETY: We must ensure that we never move out of `this`.
+        let this = unsafe { self.get_unchecked_mut() };
+        if this.registered {
+            // Already registered.
+            return Err(EINVAL);
+        }
+
+        let name = CString::try_from_fmt(name)?;
+
+        // SAFETY: The adapter is compatible with `misc_register`.
+        this.mdev.fops = unsafe { file::OperationsVtable::<Self, T>::build() };
+        this.mdev.name = name.as_char_ptr();
+        this.mdev.minor = opts.minor.unwrap_or(bindings::MISC_DYNAMIC_MINOR as i32);
+        this.mdev.mode = opts.mode.unwrap_or(0);
+        this.mdev.parent = opts
+            .parent
+            .map_or(core::ptr::null_mut(), |p| p.raw_device());
+
+        // We write to `open_data` here because as soon as `misc_register` succeeds, the file can be
+        // opened, so we need `open_data` configured ahead of time.
+        //
+        // INVARIANT: `registered` is set to `true`, but `open_data` is also initialised.
+        this.registered = true;
+        this.open_data.write(open_data);
+
+        let ret = unsafe { bindings::misc_register(&mut this.mdev) };
+        if ret < 0 {
+            // INVARIANT: `registered` is set back to `false` and the `open_data` is destructued.
+            this.registered = false;
+            // SAFETY: `open_data` was initialised a few lines above.
+            unsafe { this.open_data.assume_init_drop() };
+            return Err(Error::from_kernel_errno(ret));
+        }
+
+        this.name = Some(name);
+
+        Ok(())
+    }
+}
+
+impl<T: file::Operations> Default for Registration<T> {
+    fn default() -> Self {
+        Self::new()
+    }
+}
+
+impl<T: file::Operations> file::OpenAdapter<T::OpenData> for Registration<T> {
+    unsafe fn convert(
+        _inode: *mut bindings::inode,
+        file: *mut bindings::file,
+    ) -> *const T::OpenData {
+        // SAFETY: The caller must guarantee that `file` is valid.
+        let reg = crate::container_of!(unsafe { (*file).private_data }, Self, mdev);
+
+        // SAFETY: This function is only called while the misc device is still registered, so the
+        // registration must be valid. Additionally, the type invariants guarantee that while the
+        // miscdev is registered, `open_data` is initialised.
+        unsafe { (*reg).open_data.as_ptr() }
+    }
+}
+
+// SAFETY: The only method is `register()`, which requires a (pinned) mutable `Registration`, so it
+// is safe to pass `&Registration` to multiple threads because it offers no interior mutability.
+unsafe impl<T: file::Operations> Sync for Registration<T> {}
+
+// SAFETY: All functions work from any thread. So as long as the `Registration::open_data` is
+// `Send`, so is `Registration<T>`.
+unsafe impl<T: file::Operations> Send for Registration<T> where T::OpenData: Send {}
+
+impl<T: file::Operations> Drop for Registration<T> {
+    /// Removes the registration from the kernel if it has completed successfully before.
+    fn drop(&mut self) {
+        if self.registered {
+            // SAFETY: `registered` being `true` indicates that a previous call to  `misc_register`
+            // succeeded.
+            unsafe { bindings::misc_deregister(&mut self.mdev) };
+
+            // SAFETY: The type invariant guarantees that `open_data` is initialised when
+            // `registered` is `true`.
+            unsafe { self.open_data.assume_init_drop() };
+        }
+    }
+}
+
+/// Kernel module that exposes a single miscdev device implemented by `T`.
+pub struct Module<T: file::Operations<OpenData = ()>> {
+    _dev: Pin<Box<Registration<T>>>,
+}
+
+impl<T: file::Operations<OpenData = ()>> crate::Module for Module<T> {
+    fn init(name: &'static CStr, _module: &'static ThisModule) -> Result<Self> {
+        Ok(Self {
+            _dev: Registration::new_pinned(crate::fmt!("{name}"), ())?,
+        })
+    }
+}
+
+/// Declares a kernel module that exposes a single misc device.
+///
+/// The `type` argument should be a type which implements the [`FileOpener`] trait. Also accepts
+/// various forms of kernel metadata.
+///
+/// C header: [`include/linux/moduleparam.h`](../../../include/linux/moduleparam.h)
+///
+/// [`FileOpener`]: ../kernel/file_operations/trait.FileOpener.html
+///
+/// # Examples
+///
+/// ```ignore
+/// use kernel::prelude::*;
+///
+/// module_misc_device! {
+///     type: MyFile,
+///     name: b"my_miscdev_kernel_module",
+///     author: b"Rust for Linux Contributors",
+///     description: b"My very own misc device kernel module!",
+///     license: b"GPL",
+/// }
+///
+/// #[derive(Default)]
+/// struct MyFile;
+///
+/// impl kernel::file::Operations for MyFile {
+///     kernel::declare_file_operations!();
+/// }
+/// ```
+#[macro_export]
+macro_rules! module_misc_device {
+    (type: $type:ty, $($f:tt)*) => {
+        type ModuleType = kernel::miscdev::Module<$type>;
+        module! {
+            type: ModuleType,
+            $($f)*
+        }
+    }
+}
diff --git a/rust/kernel/mm.rs b/rust/kernel/mm.rs
new file mode 100644
index 000000000000..322f94f501e0
--- /dev/null
+++ b/rust/kernel/mm.rs
@@ -0,0 +1,149 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Memory management.
+//!
+//! C header: [`include/linux/mm.h`](../../../../include/linux/mm.h)
+
+use crate::{bindings, pages, to_result, Result};
+
+/// Virtual memory.
+pub mod virt {
+    use super::*;
+
+    /// A wrapper for the kernel's `struct vm_area_struct`.
+    ///
+    /// It represents an area of virtual memory.
+    ///
+    /// # Invariants
+    ///
+    /// `vma` is always non-null and valid.
+    pub struct Area {
+        vma: *mut bindings::vm_area_struct,
+    }
+
+    impl Area {
+        /// Creates a new instance of a virtual memory area.
+        ///
+        /// # Safety
+        ///
+        /// Callers must ensure that `vma` is non-null and valid for the duration of the new area's
+        /// lifetime.
+        pub(crate) unsafe fn from_ptr(vma: *mut bindings::vm_area_struct) -> Self {
+            // INVARIANTS: The safety requirements guarantee the invariants.
+            Self { vma }
+        }
+
+        /// Returns the flags associated with the virtual memory area.
+        ///
+        /// The possible flags are a combination of the constants in [`flags`].
+        pub fn flags(&self) -> usize {
+            // SAFETY: `self.vma` is valid by the type invariants.
+            unsafe { (*self.vma).vm_flags as _ }
+        }
+
+        /// Sets the flags associated with the virtual memory area.
+        ///
+        /// The possible flags are a combination of the constants in [`flags`].
+        pub fn set_flags(&mut self, flags: usize) {
+            // SAFETY: `self.vma` is valid by the type invariants.
+            unsafe { (*self.vma).vm_flags = flags as _ };
+        }
+
+        /// Returns the start address of the virtual memory area.
+        pub fn start(&self) -> usize {
+            // SAFETY: `self.vma` is valid by the type invariants.
+            unsafe { (*self.vma).vm_start as _ }
+        }
+
+        /// Returns the end address of the virtual memory area.
+        pub fn end(&self) -> usize {
+            // SAFETY: `self.vma` is valid by the type invariants.
+            unsafe { (*self.vma).vm_end as _ }
+        }
+
+        /// Maps a single page at the given address within the virtual memory area.
+        pub fn insert_page(&mut self, address: usize, page: &pages::Pages<0>) -> Result {
+            // SAFETY: The page is guaranteed to be order 0 by the type system. The range of
+            // `address` is already checked by `vm_insert_page`. `self.vma` and `page.pages` are
+            // guaranteed by their repective type invariants to be valid.
+            to_result(|| unsafe { bindings::vm_insert_page(self.vma, address as _, page.pages) })
+        }
+    }
+
+    /// Container for [`Area`] flags.
+    pub mod flags {
+        use crate::bindings;
+
+        /// No flags are set.
+        pub const NONE: usize = bindings::VM_NONE as _;
+
+        /// Mapping allows reads.
+        pub const READ: usize = bindings::VM_READ as _;
+
+        /// Mapping allows writes.
+        pub const WRITE: usize = bindings::VM_WRITE as _;
+
+        /// Mapping allows execution.
+        pub const EXEC: usize = bindings::VM_EXEC as _;
+
+        /// Mapping is shared.
+        pub const SHARED: usize = bindings::VM_SHARED as _;
+
+        /// Mapping may be updated to allow reads.
+        pub const MAYREAD: usize = bindings::VM_MAYREAD as _;
+
+        /// Mapping may be updated to allow writes.
+        pub const MAYWRITE: usize = bindings::VM_MAYWRITE as _;
+
+        /// Mapping may be updated to allow execution.
+        pub const MAYEXEC: usize = bindings::VM_MAYEXEC as _;
+
+        /// Mapping may be updated to be shared.
+        pub const MAYSHARE: usize = bindings::VM_MAYSHARE as _;
+
+        /// Do not copy this vma on fork.
+        pub const DONTCOPY: usize = bindings::VM_DONTCOPY as _;
+
+        /// Cannot expand with mremap().
+        pub const DONTEXPAND: usize = bindings::VM_DONTEXPAND as _;
+
+        /// Lock the pages covered when they are faulted in.
+        pub const LOCKONFAULT: usize = bindings::VM_LOCKONFAULT as _;
+
+        /// Is a VM accounted object.
+        pub const ACCOUNT: usize = bindings::VM_ACCOUNT as _;
+
+        /// should the VM suppress accounting.
+        pub const NORESERVE: usize = bindings::VM_NORESERVE as _;
+
+        /// Huge TLB Page VM.
+        pub const HUGETLB: usize = bindings::VM_HUGETLB as _;
+
+        /// Synchronous page faults.
+        pub const SYNC: usize = bindings::VM_SYNC as _;
+
+        /// Architecture-specific flag.
+        pub const ARCH_1: usize = bindings::VM_ARCH_1 as _;
+
+        /// Wipe VMA contents in child..
+        pub const WIPEONFORK: usize = bindings::VM_WIPEONFORK as _;
+
+        /// Do not include in the core dump.
+        pub const DONTDUMP: usize = bindings::VM_DONTDUMP as _;
+
+        /// Not soft dirty clean area.
+        pub const SOFTDIRTY: usize = bindings::VM_SOFTDIRTY as _;
+
+        /// Can contain "struct page" and pure PFN pages.
+        pub const MIXEDMAP: usize = bindings::VM_MIXEDMAP as _;
+
+        /// MADV_HUGEPAGE marked this vma.
+        pub const HUGEPAGE: usize = bindings::VM_HUGEPAGE as _;
+
+        /// MADV_NOHUGEPAGE marked this vma.
+        pub const NOHUGEPAGE: usize = bindings::VM_NOHUGEPAGE as _;
+
+        /// KSM may merge identical pages.
+        pub const MERGEABLE: usize = bindings::VM_MERGEABLE as _;
+    }
+}
diff --git a/rust/kernel/module_param.rs b/rust/kernel/module_param.rs
new file mode 100644
index 000000000000..3aee16e5efc7
--- /dev/null
+++ b/rust/kernel/module_param.rs
@@ -0,0 +1,498 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Types for module parameters.
+//!
+//! C header: [`include/linux/moduleparam.h`](../../../include/linux/moduleparam.h)
+
+use crate::error::{code::*, from_kernel_result};
+use crate::str::{CStr, Formatter};
+use core::fmt::Write;
+
+/// Types that can be used for module parameters.
+///
+/// Note that displaying the type in `sysfs` will fail if
+/// [`alloc::string::ToString::to_string`] (as implemented through the
+/// [`core::fmt::Display`] trait) writes more than [`PAGE_SIZE`]
+/// bytes (including an additional null terminator).
+///
+/// [`PAGE_SIZE`]: `crate::PAGE_SIZE`
+pub trait ModuleParam: core::fmt::Display + core::marker::Sized {
+    /// The `ModuleParam` will be used by the kernel module through this type.
+    ///
+    /// This may differ from `Self` if, for example, `Self` needs to track
+    /// ownership without exposing it or allocate extra space for other possible
+    /// parameter values. See [`StringParam`] or [`ArrayParam`] for examples.
+    type Value: ?Sized;
+
+    /// Whether the parameter is allowed to be set without an argument.
+    ///
+    /// Setting this to `true` allows the parameter to be passed without an
+    /// argument (e.g. just `module.param` instead of `module.param=foo`).
+    const NOARG_ALLOWED: bool;
+
+    /// Convert a parameter argument into the parameter value.
+    ///
+    /// `None` should be returned when parsing of the argument fails.
+    /// `arg == None` indicates that the parameter was passed without an
+    /// argument. If `NOARG_ALLOWED` is set to `false` then `arg` is guaranteed
+    /// to always be `Some(_)`.
+    ///
+    /// Parameters passed at boot time will be set before [`kmalloc`] is
+    /// available (even if the module is loaded at a later time). However, in
+    /// this case, the argument buffer will be valid for the entire lifetime of
+    /// the kernel. So implementations of this method which need to allocate
+    /// should first check that the allocator is available (with
+    /// [`crate::bindings::slab_is_available`]) and when it is not available
+    /// provide an alternative implementation which doesn't allocate. In cases
+    /// where the allocator is not available it is safe to save references to
+    /// `arg` in `Self`, but in other cases a copy should be made.
+    ///
+    /// [`kmalloc`]: ../../../include/linux/slab.h
+    fn try_from_param_arg(arg: Option<&'static [u8]>) -> Option<Self>;
+
+    /// Get the current value of the parameter for use in the kernel module.
+    ///
+    /// This function should not be used directly. Instead use the wrapper
+    /// `read` which will be generated by [`macros::module`].
+    fn value(&self) -> &Self::Value;
+
+    /// Set the module parameter from a string.
+    ///
+    /// Used to set the parameter value when loading the module or when set
+    /// through `sysfs`.
+    ///
+    /// # Safety
+    ///
+    /// If `val` is non-null then it must point to a valid null-terminated
+    /// string. The `arg` field of `param` must be an instance of `Self`.
+    unsafe extern "C" fn set_param(
+        val: *const crate::c_types::c_char,
+        param: *const crate::bindings::kernel_param,
+    ) -> crate::c_types::c_int {
+        let arg = if val.is_null() {
+            None
+        } else {
+            Some(unsafe { CStr::from_char_ptr(val).as_bytes() })
+        };
+        match Self::try_from_param_arg(arg) {
+            Some(new_value) => {
+                let old_value = unsafe { (*param).__bindgen_anon_1.arg as *mut Self };
+                let _ = unsafe { core::ptr::replace(old_value, new_value) };
+                0
+            }
+            None => EINVAL.to_kernel_errno(),
+        }
+    }
+
+    /// Write a string representation of the current parameter value to `buf`.
+    ///
+    /// Used for displaying the current parameter value in `sysfs`.
+    ///
+    /// # Safety
+    ///
+    /// `buf` must be a buffer of length at least `kernel::PAGE_SIZE` that is
+    /// writeable. The `arg` field of `param` must be an instance of `Self`.
+    unsafe extern "C" fn get_param(
+        buf: *mut crate::c_types::c_char,
+        param: *const crate::bindings::kernel_param,
+    ) -> crate::c_types::c_int {
+        from_kernel_result! {
+            // SAFETY: The C contracts guarantees that the buffer is at least `PAGE_SIZE` bytes.
+            let mut f = unsafe { Formatter::from_buffer(buf.cast(), crate::PAGE_SIZE) };
+            unsafe { write!(f, "{}\0", *((*param).__bindgen_anon_1.arg as *mut Self)) }?;
+            Ok(f.bytes_written().try_into()?)
+        }
+    }
+
+    /// Drop the parameter.
+    ///
+    /// Called when unloading a module.
+    ///
+    /// # Safety
+    ///
+    /// The `arg` field of `param` must be an instance of `Self`.
+    unsafe extern "C" fn free(arg: *mut crate::c_types::c_void) {
+        unsafe { core::ptr::drop_in_place(arg as *mut Self) };
+    }
+}
+
+/// Trait for parsing integers.
+///
+/// Strings beginning with `0x`, `0o`, or `0b` are parsed as hex, octal, or
+/// binary respectively. Strings beginning with `0` otherwise are parsed as
+/// octal. Anything else is parsed as decimal. A leading `+` or `-` is also
+/// permitted. Any string parsed by [`kstrtol()`] or [`kstrtoul()`] will be
+/// successfully parsed.
+///
+/// [`kstrtol()`]: https://www.kernel.org/doc/html/latest/core-api/kernel-api.html#c.kstrtol
+/// [`kstrtoul()`]: https://www.kernel.org/doc/html/latest/core-api/kernel-api.html#c.kstrtoul
+trait ParseInt: Sized {
+    fn from_str_radix(src: &str, radix: u32) -> Result<Self, core::num::ParseIntError>;
+    fn checked_neg(self) -> Option<Self>;
+
+    fn from_str_unsigned(src: &str) -> Result<Self, core::num::ParseIntError> {
+        let (radix, digits) = if let Some(n) = src.strip_prefix("0x") {
+            (16, n)
+        } else if let Some(n) = src.strip_prefix("0X") {
+            (16, n)
+        } else if let Some(n) = src.strip_prefix("0o") {
+            (8, n)
+        } else if let Some(n) = src.strip_prefix("0O") {
+            (8, n)
+        } else if let Some(n) = src.strip_prefix("0b") {
+            (2, n)
+        } else if let Some(n) = src.strip_prefix("0B") {
+            (2, n)
+        } else if src.starts_with('0') {
+            (8, src)
+        } else {
+            (10, src)
+        };
+        Self::from_str_radix(digits, radix)
+    }
+
+    fn from_str(src: &str) -> Option<Self> {
+        match src.bytes().next() {
+            None => None,
+            Some(b'-') => Self::from_str_unsigned(&src[1..]).ok()?.checked_neg(),
+            Some(b'+') => Some(Self::from_str_unsigned(&src[1..]).ok()?),
+            Some(_) => Some(Self::from_str_unsigned(src).ok()?),
+        }
+    }
+}
+
+macro_rules! impl_parse_int {
+    ($ty:ident) => {
+        impl ParseInt for $ty {
+            fn from_str_radix(src: &str, radix: u32) -> Result<Self, core::num::ParseIntError> {
+                $ty::from_str_radix(src, radix)
+            }
+
+            fn checked_neg(self) -> Option<Self> {
+                self.checked_neg()
+            }
+        }
+    };
+}
+
+impl_parse_int!(i8);
+impl_parse_int!(u8);
+impl_parse_int!(i16);
+impl_parse_int!(u16);
+impl_parse_int!(i32);
+impl_parse_int!(u32);
+impl_parse_int!(i64);
+impl_parse_int!(u64);
+impl_parse_int!(isize);
+impl_parse_int!(usize);
+
+macro_rules! impl_module_param {
+    ($ty:ident) => {
+        impl ModuleParam for $ty {
+            type Value = $ty;
+
+            const NOARG_ALLOWED: bool = false;
+
+            fn try_from_param_arg(arg: Option<&'static [u8]>) -> Option<Self> {
+                let bytes = arg?;
+                let utf8 = core::str::from_utf8(bytes).ok()?;
+                <$ty as crate::module_param::ParseInt>::from_str(utf8)
+            }
+
+            fn value(&self) -> &Self::Value {
+                self
+            }
+        }
+    };
+}
+
+#[doc(hidden)]
+#[macro_export]
+/// Generate a static [`kernel_param_ops`](../../../include/linux/moduleparam.h) struct.
+///
+/// # Example
+/// ```ignore
+/// make_param_ops!(
+///     /// Documentation for new param ops.
+///     PARAM_OPS_MYTYPE, // Name for the static.
+///     MyType // A type which implements [`ModuleParam`].
+/// );
+/// ```
+macro_rules! make_param_ops {
+    ($ops:ident, $ty:ty) => {
+        $crate::make_param_ops!(
+            #[doc=""]
+            $ops,
+            $ty
+        );
+    };
+    ($(#[$meta:meta])* $ops:ident, $ty:ty) => {
+        $(#[$meta])*
+        ///
+        /// Static [`kernel_param_ops`](../../../include/linux/moduleparam.h)
+        /// struct generated by [`make_param_ops`].
+        pub static $ops: $crate::bindings::kernel_param_ops = $crate::bindings::kernel_param_ops {
+            flags: if <$ty as $crate::module_param::ModuleParam>::NOARG_ALLOWED {
+                $crate::bindings::KERNEL_PARAM_OPS_FL_NOARG
+            } else {
+                0
+            },
+            set: Some(<$ty as $crate::module_param::ModuleParam>::set_param),
+            get: Some(<$ty as $crate::module_param::ModuleParam>::get_param),
+            free: Some(<$ty as $crate::module_param::ModuleParam>::free),
+        };
+    };
+}
+
+impl_module_param!(i8);
+impl_module_param!(u8);
+impl_module_param!(i16);
+impl_module_param!(u16);
+impl_module_param!(i32);
+impl_module_param!(u32);
+impl_module_param!(i64);
+impl_module_param!(u64);
+impl_module_param!(isize);
+impl_module_param!(usize);
+
+make_param_ops!(
+    /// Rust implementation of [`kernel_param_ops`](../../../include/linux/moduleparam.h)
+    /// for [`i8`].
+    PARAM_OPS_I8,
+    i8
+);
+make_param_ops!(
+    /// Rust implementation of [`kernel_param_ops`](../../../include/linux/moduleparam.h)
+    /// for [`u8`].
+    PARAM_OPS_U8,
+    u8
+);
+make_param_ops!(
+    /// Rust implementation of [`kernel_param_ops`](../../../include/linux/moduleparam.h)
+    /// for [`i16`].
+    PARAM_OPS_I16,
+    i16
+);
+make_param_ops!(
+    /// Rust implementation of [`kernel_param_ops`](../../../include/linux/moduleparam.h)
+    /// for [`u16`].
+    PARAM_OPS_U16,
+    u16
+);
+make_param_ops!(
+    /// Rust implementation of [`kernel_param_ops`](../../../include/linux/moduleparam.h)
+    /// for [`i32`].
+    PARAM_OPS_I32,
+    i32
+);
+make_param_ops!(
+    /// Rust implementation of [`kernel_param_ops`](../../../include/linux/moduleparam.h)
+    /// for [`u32`].
+    PARAM_OPS_U32,
+    u32
+);
+make_param_ops!(
+    /// Rust implementation of [`kernel_param_ops`](../../../include/linux/moduleparam.h)
+    /// for [`i64`].
+    PARAM_OPS_I64,
+    i64
+);
+make_param_ops!(
+    /// Rust implementation of [`kernel_param_ops`](../../../include/linux/moduleparam.h)
+    /// for [`u64`].
+    PARAM_OPS_U64,
+    u64
+);
+make_param_ops!(
+    /// Rust implementation of [`kernel_param_ops`](../../../include/linux/moduleparam.h)
+    /// for [`isize`].
+    PARAM_OPS_ISIZE,
+    isize
+);
+make_param_ops!(
+    /// Rust implementation of [`kernel_param_ops`](../../../include/linux/moduleparam.h)
+    /// for [`usize`].
+    PARAM_OPS_USIZE,
+    usize
+);
+
+impl ModuleParam for bool {
+    type Value = bool;
+
+    const NOARG_ALLOWED: bool = true;
+
+    fn try_from_param_arg(arg: Option<&'static [u8]>) -> Option<Self> {
+        match arg {
+            None => Some(true),
+            Some(b"y") | Some(b"Y") | Some(b"1") | Some(b"true") => Some(true),
+            Some(b"n") | Some(b"N") | Some(b"0") | Some(b"false") => Some(false),
+            _ => None,
+        }
+    }
+
+    fn value(&self) -> &Self::Value {
+        self
+    }
+}
+
+make_param_ops!(
+    /// Rust implementation of [`kernel_param_ops`](../../../include/linux/moduleparam.h)
+    /// for [`bool`].
+    PARAM_OPS_BOOL,
+    bool
+);
+
+/// An array of at __most__ `N` values.
+///
+/// # Invariant
+///
+/// The first `self.used` elements of `self.values` are initialized.
+pub struct ArrayParam<T, const N: usize> {
+    values: [core::mem::MaybeUninit<T>; N],
+    used: usize,
+}
+
+impl<T, const N: usize> ArrayParam<T, { N }> {
+    fn values(&self) -> &[T] {
+        // SAFETY: The invariant maintained by `ArrayParam` allows us to cast
+        // the first `self.used` elements to `T`.
+        unsafe {
+            &*(&self.values[0..self.used] as *const [core::mem::MaybeUninit<T>] as *const [T])
+        }
+    }
+}
+
+impl<T: Copy, const N: usize> ArrayParam<T, { N }> {
+    const fn new() -> Self {
+        // INVARIANT: The first `self.used` elements of `self.values` are
+        // initialized.
+        ArrayParam {
+            values: [core::mem::MaybeUninit::uninit(); N],
+            used: 0,
+        }
+    }
+
+    const fn push(&mut self, val: T) {
+        if self.used < N {
+            // INVARIANT: The first `self.used` elements of `self.values` are
+            // initialized.
+            self.values[self.used] = core::mem::MaybeUninit::new(val);
+            self.used += 1;
+        }
+    }
+
+    /// Create an instance of `ArrayParam` initialized with `vals`.
+    ///
+    /// This function is only meant to be used in the [`module::module`] macro.
+    pub const fn create(vals: &[T]) -> Self {
+        let mut result = ArrayParam::new();
+        let mut i = 0;
+        while i < vals.len() {
+            result.push(vals[i]);
+            i += 1;
+        }
+        result
+    }
+}
+
+impl<T: core::fmt::Display, const N: usize> core::fmt::Display for ArrayParam<T, { N }> {
+    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
+        for val in self.values() {
+            write!(f, "{},", val)?;
+        }
+        Ok(())
+    }
+}
+
+impl<T: Copy + core::fmt::Display + ModuleParam, const N: usize> ModuleParam
+    for ArrayParam<T, { N }>
+{
+    type Value = [T];
+
+    const NOARG_ALLOWED: bool = false;
+
+    fn try_from_param_arg(arg: Option<&'static [u8]>) -> Option<Self> {
+        arg.and_then(|args| {
+            let mut result = Self::new();
+            for arg in args.split(|b| *b == b',') {
+                result.push(T::try_from_param_arg(Some(arg))?);
+            }
+            Some(result)
+        })
+    }
+
+    fn value(&self) -> &Self::Value {
+        self.values()
+    }
+}
+
+/// A C-style string parameter.
+///
+/// The Rust version of the [`charp`] parameter. This type is meant to be
+/// used by the [`macros::module`] macro, not handled directly. Instead use the
+/// `read` method generated by that macro.
+///
+/// [`charp`]: ../../../include/linux/moduleparam.h
+pub enum StringParam {
+    /// A borrowed parameter value.
+    ///
+    /// Either the default value (which is static in the module) or borrowed
+    /// from the original argument buffer used to set the value.
+    Ref(&'static [u8]),
+
+    /// A value that was allocated when the parameter was set.
+    ///
+    /// The value needs to be freed when the parameter is reset or the module is
+    /// unloaded.
+    Owned(alloc::vec::Vec<u8>),
+}
+
+impl StringParam {
+    fn bytes(&self) -> &[u8] {
+        match self {
+            StringParam::Ref(bytes) => *bytes,
+            StringParam::Owned(vec) => &vec[..],
+        }
+    }
+}
+
+impl core::fmt::Display for StringParam {
+    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
+        let bytes = self.bytes();
+        match core::str::from_utf8(bytes) {
+            Ok(utf8) => write!(f, "{}", utf8),
+            Err(_) => write!(f, "{:?}", bytes),
+        }
+    }
+}
+
+impl ModuleParam for StringParam {
+    type Value = [u8];
+
+    const NOARG_ALLOWED: bool = false;
+
+    fn try_from_param_arg(arg: Option<&'static [u8]>) -> Option<Self> {
+        // SAFETY: It is always safe to call [`slab_is_available`](../../../include/linux/slab.h).
+        let slab_available = unsafe { crate::bindings::slab_is_available() };
+        arg.and_then(|arg| {
+            if slab_available {
+                let mut vec = alloc::vec::Vec::new();
+                vec.try_extend_from_slice(arg).ok()?;
+                Some(StringParam::Owned(vec))
+            } else {
+                Some(StringParam::Ref(arg))
+            }
+        })
+    }
+
+    fn value(&self) -> &Self::Value {
+        self.bytes()
+    }
+}
+
+make_param_ops!(
+    /// Rust implementation of [`kernel_param_ops`](../../../include/linux/moduleparam.h)
+    /// for [`StringParam`].
+    PARAM_OPS_STR,
+    StringParam
+);
diff --git a/rust/kernel/net.rs b/rust/kernel/net.rs
new file mode 100644
index 000000000000..0495ab778144
--- /dev/null
+++ b/rust/kernel/net.rs
@@ -0,0 +1,392 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Networking core.
+//!
+//! C headers: [`include/net/net_namespace.h`](../../../../include/linux/net/net_namespace.h),
+//! [`include/linux/netdevice.h`](../../../../include/linux/netdevice.h),
+//! [`include/linux/skbuff.h`](../../../../include/linux/skbuff.h).
+
+use crate::{bindings, str::CStr, to_result, ARef, AlwaysRefCounted, Error, Result};
+use core::{cell::UnsafeCell, ptr::NonNull};
+
+#[cfg(CONFIG_NETFILTER)]
+pub mod filter;
+
+/// Wraps the kernel's `struct net_device`.
+#[repr(transparent)]
+pub struct Device(UnsafeCell<bindings::net_device>);
+
+// SAFETY: Instances of `Device` are created on the C side. They are always refcounted.
+unsafe impl AlwaysRefCounted for Device {
+    fn inc_ref(&self) {
+        // SAFETY: The existence of a shared reference means that the refcount is nonzero.
+        unsafe { bindings::dev_hold(self.0.get()) };
+    }
+
+    unsafe fn dec_ref(obj: core::ptr::NonNull<Self>) {
+        // SAFETY: The safety requirements guarantee that the refcount is nonzero.
+        unsafe { bindings::dev_put(obj.cast().as_ptr()) };
+    }
+}
+
+/// Wraps the kernel's `struct net`.
+#[repr(transparent)]
+pub struct Namespace(UnsafeCell<bindings::net>);
+
+impl Namespace {
+    /// Finds a network device with the given name in the namespace.
+    pub fn dev_get_by_name(&self, name: &CStr) -> Option<ARef<Device>> {
+        // SAFETY: The existence of a shared reference guarantees the refcount is nonzero.
+        let ptr =
+            NonNull::new(unsafe { bindings::dev_get_by_name(self.0.get(), name.as_char_ptr()) })?;
+        Some(unsafe { ARef::from_raw(ptr.cast()) })
+    }
+}
+
+// SAFETY: Instances of `Namespace` are created on the C side. They are always refcounted.
+unsafe impl AlwaysRefCounted for Namespace {
+    fn inc_ref(&self) {
+        // SAFETY: The existence of a shared reference means that the refcount is nonzero.
+        unsafe { bindings::get_net(self.0.get()) };
+    }
+
+    unsafe fn dec_ref(obj: core::ptr::NonNull<Self>) {
+        // SAFETY: The safety requirements guarantee that the refcount is nonzero.
+        unsafe { bindings::put_net(obj.cast().as_ptr()) };
+    }
+}
+
+/// Returns the network namespace for the `init` process.
+pub fn init_ns() -> &'static Namespace {
+    unsafe { &*core::ptr::addr_of!(bindings::init_net).cast() }
+}
+
+/// Wraps the kernel's `struct sk_buff`.
+#[repr(transparent)]
+pub struct SkBuff(UnsafeCell<bindings::sk_buff>);
+
+impl SkBuff {
+    /// Creates a reference to an [`SkBuff`] from a valid pointer.
+    ///
+    /// # Safety
+    ///
+    /// The caller must ensure that `ptr` is valid and remains valid for the lifetime of the
+    /// returned [`SkBuff`] instance.
+    pub unsafe fn from_ptr<'a>(ptr: *const bindings::sk_buff) -> &'a SkBuff {
+        // SAFETY: The safety requirements guarantee the validity of the dereference, while the
+        // `SkBuff` type being transparent makes the cast ok.
+        unsafe { &*ptr.cast() }
+    }
+
+    /// Returns the remaining data in the buffer's first segment.
+    pub fn head_data(&self) -> &[u8] {
+        // SAFETY: The existence of a shared reference means that the refcount is nonzero.
+        let headlen = unsafe { bindings::skb_headlen(self.0.get()) };
+        let len = headlen.try_into().unwrap_or(usize::MAX);
+        // SAFETY: The existence of a shared reference means `self.0` is valid.
+        let data = unsafe { core::ptr::addr_of!((*self.0.get()).data).read() };
+        // SAFETY: The `struct sk_buff` conventions guarantee that at least `skb_headlen(skb)` bytes
+        // are valid from `skb->data`.
+        unsafe { core::slice::from_raw_parts(data, len) }
+    }
+
+    /// Returns the total length of the data (in all segments) in the skb.
+    #[allow(clippy::len_without_is_empty)]
+    pub fn len(&self) -> u32 {
+        // SAFETY: The existence of a shared reference means `self.0` is valid.
+        unsafe { core::ptr::addr_of!((*self.0.get()).len).read() }
+    }
+}
+
+// SAFETY: Instances of `SkBuff` are created on the C side. They are always refcounted.
+unsafe impl AlwaysRefCounted for SkBuff {
+    fn inc_ref(&self) {
+        // SAFETY: The existence of a shared reference means that the refcount is nonzero.
+        unsafe { bindings::skb_get(self.0.get()) };
+    }
+
+    unsafe fn dec_ref(obj: core::ptr::NonNull<Self>) {
+        // SAFETY: The safety requirements guarantee that the refcount is nonzero.
+        unsafe {
+            bindings::kfree_skb_reason(
+                obj.cast().as_ptr(),
+                bindings::skb_drop_reason_SKB_DROP_REASON_NOT_SPECIFIED,
+            )
+        };
+    }
+}
+
+/// An IPv4 address.
+///
+/// This is equivalent to C's `in_addr`.
+#[repr(transparent)]
+pub struct Ipv4Addr(bindings::in_addr);
+
+impl Ipv4Addr {
+    /// A wildcard IPv4 address.
+    ///
+    /// Binding to this address means binding to all IPv4 addresses.
+    pub const ANY: Self = Self::new(0, 0, 0, 0);
+
+    /// The IPv4 loopback address.
+    pub const LOOPBACK: Self = Self::new(127, 0, 0, 1);
+
+    /// The IPv4 broadcast address.
+    pub const BROADCAST: Self = Self::new(255, 255, 255, 255);
+
+    /// Creates a new IPv4 address with the given components.
+    pub const fn new(a: u8, b: u8, c: u8, d: u8) -> Self {
+        Self(bindings::in_addr {
+            s_addr: u32::from_be_bytes([a, b, c, d]).to_be(),
+        })
+    }
+}
+
+/// An IPv6 address.
+///
+/// This is equivalent to C's `in6_addr`.
+#[repr(transparent)]
+pub struct Ipv6Addr(bindings::in6_addr);
+
+impl Ipv6Addr {
+    /// A wildcard IPv6 address.
+    ///
+    /// Binding to this address means binding to all IPv6 addresses.
+    pub const ANY: Self = Self::new(0, 0, 0, 0, 0, 0, 0, 0);
+
+    /// The IPv6 loopback address.
+    pub const LOOPBACK: Self = Self::new(0, 0, 0, 0, 0, 0, 0, 1);
+
+    /// Creates a new IPv6 address with the given components.
+    #[allow(clippy::too_many_arguments)]
+    pub const fn new(a: u16, b: u16, c: u16, d: u16, e: u16, f: u16, g: u16, h: u16) -> Self {
+        Self(bindings::in6_addr {
+            in6_u: bindings::in6_addr__bindgen_ty_1 {
+                u6_addr16: [
+                    a.to_be(),
+                    b.to_be(),
+                    c.to_be(),
+                    d.to_be(),
+                    e.to_be(),
+                    f.to_be(),
+                    g.to_be(),
+                    h.to_be(),
+                ],
+            },
+        })
+    }
+}
+
+/// A socket address.
+///
+/// It's an enum with either an IPv4 or IPv6 socket address.
+pub enum SocketAddr {
+    /// An IPv4 socket address.
+    V4(SocketAddrV4),
+
+    /// An IPv6 socket address.
+    V6(SocketAddrV6),
+}
+
+/// An IPv4 socket address.
+///
+/// This is equivalent to C's `sockaddr_in`.
+#[repr(transparent)]
+pub struct SocketAddrV4(bindings::sockaddr_in);
+
+impl SocketAddrV4 {
+    /// Creates a new IPv4 socket address.
+    pub const fn new(addr: Ipv4Addr, port: u16) -> Self {
+        Self(bindings::sockaddr_in {
+            sin_family: bindings::AF_INET as _,
+            sin_port: port.to_be(),
+            sin_addr: addr.0,
+            __pad: [0; 8],
+        })
+    }
+}
+
+/// An IPv6 socket address.
+///
+/// This is equivalent to C's `sockaddr_in6`.
+#[repr(transparent)]
+pub struct SocketAddrV6(bindings::sockaddr_in6);
+
+impl SocketAddrV6 {
+    /// Creates a new IPv6 socket address.
+    pub const fn new(addr: Ipv6Addr, port: u16, flowinfo: u32, scopeid: u32) -> Self {
+        Self(bindings::sockaddr_in6 {
+            sin6_family: bindings::AF_INET6 as _,
+            sin6_port: port.to_be(),
+            sin6_addr: addr.0,
+            sin6_flowinfo: flowinfo,
+            sin6_scope_id: scopeid,
+        })
+    }
+}
+
+/// A socket listening on a TCP port.
+///
+/// # Invariants
+///
+/// The socket pointer is always non-null and valid.
+pub struct TcpListener {
+    pub(crate) sock: *mut bindings::socket,
+}
+
+// SAFETY: `TcpListener` is just a wrapper for a kernel socket, which can be used from any thread.
+unsafe impl Send for TcpListener {}
+
+// SAFETY: `TcpListener` is just a wrapper for a kernel socket, which can be used from any thread.
+unsafe impl Sync for TcpListener {}
+
+impl TcpListener {
+    /// Creates a new TCP listener.
+    ///
+    /// It is configured to listen on the given socket address for the given namespace.
+    pub fn try_new(ns: &Namespace, addr: &SocketAddr) -> Result<Self> {
+        let mut socket = core::ptr::null_mut();
+        let (pf, addr, addrlen) = match addr {
+            SocketAddr::V4(addr) => (
+                bindings::PF_INET,
+                addr as *const _ as _,
+                core::mem::size_of::<bindings::sockaddr_in>(),
+            ),
+            SocketAddr::V6(addr) => (
+                bindings::PF_INET6,
+                addr as *const _ as _,
+                core::mem::size_of::<bindings::sockaddr_in6>(),
+            ),
+        };
+
+        // SAFETY: The namespace is valid and the output socket pointer is valid for write.
+        to_result(|| unsafe {
+            bindings::sock_create_kern(
+                ns.0.get(),
+                pf as _,
+                bindings::sock_type_SOCK_STREAM as _,
+                bindings::IPPROTO_TCP as _,
+                &mut socket,
+            )
+        })?;
+
+        // INVARIANT: The socket was just created, so it is valid.
+        let listener = Self { sock: socket };
+
+        // SAFETY: The type invariant guarantees that the socket is valid, and `addr` and `addrlen`
+        // were initialised based on valid values provided in the address enum.
+        to_result(|| unsafe { bindings::kernel_bind(socket, addr, addrlen as _) })?;
+
+        // SAFETY: The socket is valid per the type invariant.
+        to_result(|| unsafe { bindings::kernel_listen(socket, bindings::SOMAXCONN as _) })?;
+
+        Ok(listener)
+    }
+
+    /// Accepts a new connection.
+    ///
+    /// On success, returns the newly-accepted socket stream.
+    ///
+    /// If no connection is available to be accepted, one of two behaviours will occur:
+    /// - If `block` is `false`, returns [`crate::error::code::EAGAIN`];
+    /// - If `block` is `true`, blocks until an error occurs or some connection can be accepted.
+    pub fn accept(&self, block: bool) -> Result<TcpStream> {
+        let mut new = core::ptr::null_mut();
+        let flags = if block { 0 } else { bindings::O_NONBLOCK };
+        // SAFETY: The type invariant guarantees that the socket is valid, and the output argument
+        // is also valid for write.
+        to_result(|| unsafe { bindings::kernel_accept(self.sock, &mut new, flags as _) })?;
+        Ok(TcpStream { sock: new })
+    }
+}
+
+impl Drop for TcpListener {
+    fn drop(&mut self) {
+        // SAFETY: The type invariant guarantees that the socket is valid.
+        unsafe { bindings::sock_release(self.sock) };
+    }
+}
+
+/// A connected TCP socket.
+///
+/// # Invariants
+///
+/// The socket pointer is always non-null and valid.
+pub struct TcpStream {
+    pub(crate) sock: *mut bindings::socket,
+}
+
+// SAFETY: `TcpStream` is just a wrapper for a kernel socket, which can be used from any thread.
+unsafe impl Send for TcpStream {}
+
+// SAFETY: `TcpStream` is just a wrapper for a kernel socket, which can be used from any thread.
+unsafe impl Sync for TcpStream {}
+
+impl TcpStream {
+    /// Reads data from a connected socket.
+    ///
+    /// On success, returns the number of bytes read, which will be zero if the connection is
+    /// closed.
+    ///
+    /// If no data is immediately available for reading, one of two behaviours will occur:
+    /// - If `block` is `false`, returns [`crate::error::code::EAGAIN`];
+    /// - If `block` is `true`, blocks until an error occurs, the connection is closed, or some
+    ///   becomes readable.
+    pub fn read(&self, buf: &mut [u8], block: bool) -> Result<usize> {
+        let mut msg = bindings::msghdr::default();
+        let mut vec = bindings::kvec {
+            iov_base: buf.as_mut_ptr().cast(),
+            iov_len: buf.len(),
+        };
+        // SAFETY: The type invariant guarantees that the socket is valid, and `vec` was
+        // initialised with the output buffer.
+        let r = unsafe {
+            bindings::kernel_recvmsg(
+                self.sock,
+                &mut msg,
+                &mut vec,
+                1,
+                vec.iov_len,
+                if block { 0 } else { bindings::MSG_DONTWAIT } as _,
+            )
+        };
+        if r < 0 {
+            Err(Error::from_kernel_errno(r))
+        } else {
+            Ok(r as _)
+        }
+    }
+
+    /// Writes data to the connected socket.
+    ///
+    /// On success, returns the number of bytes written.
+    ///
+    /// If the send buffer of the socket is full, one of two behaviours will occur:
+    /// - If `block` is `false`, returns [`crate::error::code::EAGAIN`];
+    /// - If `block` is `true`, blocks until an error occurs or some data is written.
+    pub fn write(&self, buf: &[u8], block: bool) -> Result<usize> {
+        let mut msg = bindings::msghdr {
+            msg_flags: if block { 0 } else { bindings::MSG_DONTWAIT },
+            ..bindings::msghdr::default()
+        };
+        let mut vec = bindings::kvec {
+            iov_base: buf.as_ptr() as *mut u8 as _,
+            iov_len: buf.len(),
+        };
+        // SAFETY: The type invariant guarantees that the socket is valid, and `vec` was
+        // initialised with the input  buffer.
+        let r = unsafe { bindings::kernel_sendmsg(self.sock, &mut msg, &mut vec, 1, vec.iov_len) };
+        if r < 0 {
+            Err(Error::from_kernel_errno(r))
+        } else {
+            Ok(r as _)
+        }
+    }
+}
+
+impl Drop for TcpStream {
+    fn drop(&mut self) {
+        // SAFETY: The type invariant guarantees that the socket is valid.
+        unsafe { bindings::sock_release(self.sock) };
+    }
+}
diff --git a/rust/kernel/net/filter.rs b/rust/kernel/net/filter.rs
new file mode 100644
index 000000000000..3241100a1561
--- /dev/null
+++ b/rust/kernel/net/filter.rs
@@ -0,0 +1,447 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Networking filters.
+//!
+//! C header: [`include/linux/netfilter.h`](../../../../../include/linux/netfilter.h)
+
+use crate::{
+    bindings, c_types,
+    error::{code::*, to_result},
+    net,
+    types::PointerWrapper,
+    ARef, AlwaysRefCounted, Result, ScopeGuard,
+};
+use alloc::boxed::Box;
+use core::{
+    marker::{PhantomData, PhantomPinned},
+    pin::Pin,
+};
+
+/// A network filter.
+pub trait Filter {
+    /// The type of the context data stored on registration and made available to the
+    /// [`Filter::filter`] function.
+    type Data: PointerWrapper + Sync = ();
+
+    /// Filters the packet stored in the given buffer.
+    ///
+    /// It dictates to the netfilter core what the fate of the packet should be.
+    fn filter(
+        _data: <Self::Data as PointerWrapper>::Borrowed<'_>,
+        _skb: &net::SkBuff,
+    ) -> Disposition;
+}
+
+/// Specifies the action to be taken by the netfilter core.
+pub enum Disposition {
+    /// Drop the packet.
+    Drop,
+
+    /// Accept the packet.
+    Accept,
+
+    /// The packet was stolen by the filter and must be treated as if it didn't exist.
+    Stolen,
+
+    /// Queue the packet to the given user-space queue.
+    Queue {
+        /// The identifier of the queue to which the packet should be added.
+        queue_id: u16,
+
+        /// Specifies the behaviour if a queue with the given identifier doesn't exist: if `true`,
+        /// the packet is accepted, otherwise it is rejected.
+        accept_if_queue_non_existent: bool,
+    },
+}
+
+/// The filter hook families.
+pub enum Family {
+    ///  IPv4 and IPv6 packets.
+    INet(inet::Hook),
+
+    /// IPv4 packets.
+    Ipv4(ipv4::Hook, ipv4::PriorityBase),
+
+    /// All packets through a device.
+    ///
+    /// When this family is used, a device _must_ be specified.
+    NetDev(netdev::Hook),
+
+    /// IPv6 packets.
+    Ipv6(ipv6::Hook, ipv6::PriorityBase),
+
+    /// Address resolution protocol (ARP) packets.
+    Arp(arp::Hook),
+}
+
+/// A registration of a networking filter.
+///
+/// # Examples
+///
+/// The following is an example of a function that attaches an inbound filter (that always accepts
+/// all packets after printing their lengths) on the specified device (in the `init` ns).
+///
+/// ```
+/// use kernel::net::{self, filter as netfilter};
+///
+/// struct MyFilter;
+/// impl netfilter::Filter for MyFilter {
+///     fn filter(_data: (), skb: &net::SkBuff) -> netfilter::Disposition {
+///         pr_info!("Packet of length {}\n", skb.len());
+///         netfilter::Disposition::Accept
+///     }
+/// }
+///
+/// fn register(name: &CStr) -> Result<Pin<Box<netfilter::Registration<MyFilter>>>> {
+///     let ns = net::init_ns();
+///     let dev = ns.dev_get_by_name(name).ok_or(ENOENT)?;
+///     netfilter::Registration::new_pinned(
+///         netfilter::Family::NetDev(netfilter::netdev::Hook::Ingress),
+///         0,
+///         ns.into(),
+///         Some(dev),
+///         (),
+///     )
+/// }
+/// ```
+#[derive(Default)]
+pub struct Registration<T: Filter> {
+    hook: bindings::nf_hook_ops,
+    // When `ns` is `Some(_)`, the hook is registered.
+    ns: Option<ARef<net::Namespace>>,
+    dev: Option<ARef<net::Device>>,
+    _p: PhantomData<T>,
+    _pinned: PhantomPinned,
+}
+
+// SAFETY: `Registration` does not expose any of its state across threads.
+unsafe impl<T: Filter> Sync for Registration<T> {}
+
+impl<T: Filter> Registration<T> {
+    /// Creates a new [`Registration`] but does not register it yet.
+    ///
+    /// It is allowed to move.
+    pub fn new() -> Self {
+        Self {
+            hook: bindings::nf_hook_ops::default(),
+            dev: None,
+            ns: None,
+            _p: PhantomData,
+            _pinned: PhantomPinned,
+        }
+    }
+
+    /// Creates a new filter registration and registers it.
+    ///
+    /// Returns a pinned heap-allocated representation of the registration.
+    pub fn new_pinned(
+        family: Family,
+        priority: i32,
+        ns: ARef<net::Namespace>,
+        dev: Option<ARef<net::Device>>,
+        data: T::Data,
+    ) -> Result<Pin<Box<Self>>> {
+        let mut filter = Pin::from(Box::try_new(Self::new())?);
+        filter.as_mut().register(family, priority, ns, dev, data)?;
+        Ok(filter)
+    }
+
+    /// Registers a network filter.
+    ///
+    /// It must be pinned because the C portion of the kernel stores a pointer to it while it is
+    /// registered.
+    ///
+    /// The priority is relative to the family's base priority. For example, if the base priority
+    /// is `100` and `priority` is `-1`, the actual priority will be `99`. If a family doesn't
+    /// explicitly allow a base to be specified, `0` is assumed.
+    pub fn register(
+        self: Pin<&mut Self>,
+        family: Family,
+        priority: i32,
+        ns: ARef<net::Namespace>,
+        dev: Option<ARef<net::Device>>,
+        data: T::Data,
+    ) -> Result {
+        // SAFETY: We must ensure that we never move out of `this`.
+        let this = unsafe { self.get_unchecked_mut() };
+        if this.ns.is_some() {
+            // Already registered.
+            return Err(EINVAL);
+        }
+
+        let data_pointer = data.into_pointer();
+
+        // SAFETY: `data_pointer` comes from the call to `data.into_pointer()` above.
+        let guard = ScopeGuard::new(|| unsafe {
+            T::Data::from_pointer(data_pointer);
+        });
+
+        let mut pri_base = 0i32;
+        match family {
+            Family::INet(hook) => {
+                this.hook.pf = bindings::NFPROTO_INET as _;
+                this.hook.hooknum = hook as _;
+            }
+            Family::Ipv4(hook, pbase) => {
+                this.hook.pf = bindings::NFPROTO_IPV4 as _;
+                this.hook.hooknum = hook as _;
+                pri_base = pbase as _;
+            }
+            Family::Ipv6(hook, pbase) => {
+                this.hook.pf = bindings::NFPROTO_IPV6 as _;
+                this.hook.hooknum = hook as _;
+                pri_base = pbase as _;
+            }
+            Family::NetDev(hook) => {
+                this.hook.pf = bindings::NFPROTO_NETDEV as _;
+                this.hook.hooknum = hook as _;
+            }
+            Family::Arp(hook) => {
+                this.hook.pf = bindings::NFPROTO_ARP as _;
+                this.hook.hooknum = hook as _;
+            }
+        }
+
+        this.hook.priority = pri_base.saturating_add(priority);
+        this.hook.priv_ = data_pointer as _;
+        this.hook.hook = Some(Self::hook_callback);
+        crate::static_assert!(bindings::nf_hook_ops_type_NF_HOOK_OP_UNDEFINED == 0);
+
+        if let Some(ref device) = dev {
+            this.hook.dev = device.0.get();
+        }
+
+        // SAFETY: `ns` has a valid reference to the namespace, and `this.hook` was just
+        // initialised above, so they're both valid.
+        to_result(|| unsafe { bindings::nf_register_net_hook(ns.0.get(), &this.hook) })?;
+
+        this.dev = dev;
+        this.ns = Some(ns);
+        guard.dismiss();
+        Ok(())
+    }
+
+    unsafe extern "C" fn hook_callback(
+        priv_: *mut c_types::c_void,
+        skb: *mut bindings::sk_buff,
+        _state: *const bindings::nf_hook_state,
+    ) -> c_types::c_uint {
+        // SAFETY: `priv_` was initialised on registration by a value returned from
+        // `T::Data::into_pointer`, and it remains valid until the hook is unregistered.
+        let data = unsafe { T::Data::borrow(priv_) };
+
+        // SAFETY: The C contract guarantees that `skb` remains valid for the duration of this
+        // function call.
+        match T::filter(data, unsafe { net::SkBuff::from_ptr(skb) }) {
+            Disposition::Drop => bindings::NF_DROP,
+            Disposition::Accept => bindings::NF_ACCEPT,
+            Disposition::Stolen => {
+                // SAFETY: This function takes over ownership of `skb` when it returns `NF_STOLEN`,
+                // so we decrement the refcount here to avoid a leak.
+                unsafe { net::SkBuff::dec_ref(core::ptr::NonNull::new(skb).unwrap().cast()) };
+                bindings::NF_STOLEN
+            }
+            Disposition::Queue {
+                queue_id,
+                accept_if_queue_non_existent,
+            } => {
+                // SAFETY: Just an FFI call, no additional safety requirements.
+                let verdict = unsafe { bindings::NF_QUEUE_NR(queue_id as _) };
+                if accept_if_queue_non_existent {
+                    verdict | bindings::NF_VERDICT_FLAG_QUEUE_BYPASS
+                } else {
+                    verdict
+                }
+            }
+        }
+    }
+}
+
+impl<T: Filter> Drop for Registration<T> {
+    fn drop(&mut self) {
+        if let Some(ref ns) = self.ns {
+            // SAFETY: `self.ns` is `Some(_)` only when a previous call to `nf_register_net_hook`
+            // succeeded. And the arguments are the same.
+            unsafe { bindings::nf_unregister_net_hook(ns.0.get(), &self.hook) };
+
+            // `self.hook.priv_` was initialised during registration to a value returned from
+            // `T::Data::into_pointer`, so it is ok to convert back here.
+            unsafe { T::Data::from_pointer(self.hook.priv_) };
+        }
+    }
+}
+
+/// Definitions used when defining hooks for the [`Family::NetDev`] family.
+pub mod netdev {
+    use crate::bindings;
+
+    /// Hooks allowed in the [`super::Family::NetDev`] family.
+    #[repr(u32)]
+    pub enum Hook {
+        /// All inbound packets through the given device.
+        Ingress = bindings::nf_dev_hooks_NF_NETDEV_INGRESS,
+
+        /// All outbound packets through the given device.
+        Egress = bindings::nf_dev_hooks_NF_NETDEV_EGRESS,
+    }
+}
+
+/// Definitions used when defining hooks for the [`Family::Ipv4`] family.
+pub mod ipv4 {
+    use crate::bindings;
+
+    /// Hooks allowed in [`super::Family::Ipv4`] family.
+    pub type Hook = super::inet::Hook;
+
+    /// The base priority for [`super::Family::Ipv4`] hooks.
+    ///
+    /// The actual priority is the base priority plus the priority specified when registering.
+    #[repr(i32)]
+    pub enum PriorityBase {
+        /// Same as the `NF_IP_PRI_FIRST` C constant.
+        First = bindings::nf_ip_hook_priorities_NF_IP_PRI_FIRST,
+
+        /// Same as the `NF_IP_PRI_RAW_BEFORE_DEFRAG` C constant.
+        RawBeforeDefrag = bindings::nf_ip_hook_priorities_NF_IP_PRI_RAW_BEFORE_DEFRAG,
+
+        /// Same as the `NF_IP_PRI_CONNTRACK_DEFRAG` C constant.
+        ConnTrackDefrag = bindings::nf_ip_hook_priorities_NF_IP_PRI_CONNTRACK_DEFRAG,
+
+        /// Same as the `NF_IP_PRI_RAW` C constant.
+        Raw = bindings::nf_ip_hook_priorities_NF_IP_PRI_RAW,
+
+        /// Same as the `NF_IP_PRI_SELINUX_FIRST` C constant.
+        SeLinuxFirst = bindings::nf_ip_hook_priorities_NF_IP_PRI_SELINUX_FIRST,
+
+        /// Same as the `NF_IP_PRI_CONNTRACK` C constant.
+        ConnTrack = bindings::nf_ip_hook_priorities_NF_IP_PRI_CONNTRACK,
+
+        /// Same as the `NF_IP_PRI_MANGLE` C constant.
+        Mangle = bindings::nf_ip_hook_priorities_NF_IP_PRI_MANGLE,
+
+        /// Same as the `NF_IP_PRI_NAT_DST` C constant.
+        NatDst = bindings::nf_ip_hook_priorities_NF_IP_PRI_NAT_DST,
+
+        /// Same as the `NF_IP_PRI_FILTER` C constant.
+        Filter = bindings::nf_ip_hook_priorities_NF_IP_PRI_FILTER,
+
+        /// Same as the `NF_IP_PRI_SECURITY` C constant.
+        Security = bindings::nf_ip_hook_priorities_NF_IP_PRI_SECURITY,
+
+        /// Same as the `NF_IP_PRI_NAT_SRC` C constant.
+        NatSrc = bindings::nf_ip_hook_priorities_NF_IP_PRI_NAT_SRC,
+
+        /// Same as the `NF_IP_PRI_SELINUX_LAST` C constant.
+        SeLinuxLast = bindings::nf_ip_hook_priorities_NF_IP_PRI_SELINUX_LAST,
+
+        /// Same as the `NF_IP_PRI_CONNTRACK_HELPER` C constant.
+        ConnTrackHelper = bindings::nf_ip_hook_priorities_NF_IP_PRI_CONNTRACK_HELPER,
+
+        /// Same as the `NF_IP_PRI_LAST` and `NF_IP_PRI_CONNTRACK_CONFIRM` C constants.
+        Last = bindings::nf_ip_hook_priorities_NF_IP_PRI_LAST,
+    }
+}
+
+/// Definitions used when defining hooks for the [`Family::Ipv6`] family.
+pub mod ipv6 {
+    use crate::bindings;
+
+    /// Hooks allowed in [`super::Family::Ipv6`] family.
+    pub type Hook = super::inet::Hook;
+
+    /// The base priority for [`super::Family::Ipv6`] hooks.
+    ///
+    /// The actual priority is the base priority plus the priority specified when registering.
+    #[repr(i32)]
+    pub enum PriorityBase {
+        /// Same as the `NF_IP6_PRI_FIRST` C constant.
+        First = bindings::nf_ip6_hook_priorities_NF_IP6_PRI_FIRST,
+
+        /// Same as the `NF_IP6_PRI_RAW_BEFORE_DEFRAG` C constant.
+        RawBeforeDefrag = bindings::nf_ip6_hook_priorities_NF_IP6_PRI_RAW_BEFORE_DEFRAG,
+
+        /// Same as the `NF_IP6_PRI_CONNTRACK_DEFRAG` C constant.
+        ConnTrackDefrag = bindings::nf_ip6_hook_priorities_NF_IP6_PRI_CONNTRACK_DEFRAG,
+
+        /// Same as the `NF_IP6_PRI_RAW` C constant.
+        Raw = bindings::nf_ip6_hook_priorities_NF_IP6_PRI_RAW,
+
+        /// Same as the `NF_IP6_PRI_SELINUX_FIRST` C constant.
+        SeLinuxFirst = bindings::nf_ip6_hook_priorities_NF_IP6_PRI_SELINUX_FIRST,
+
+        /// Same as the `NF_IP6_PRI_CONNTRACK` C constant.
+        ConnTrack = bindings::nf_ip6_hook_priorities_NF_IP6_PRI_CONNTRACK,
+
+        /// Same as the `NF_IP6_PRI_MANGLE` C constant.
+        Mangle = bindings::nf_ip6_hook_priorities_NF_IP6_PRI_MANGLE,
+
+        /// Same as the `NF_IP6_PRI_NAT_DST` C constant.
+        NatDst = bindings::nf_ip6_hook_priorities_NF_IP6_PRI_NAT_DST,
+
+        /// Same as the `NF_IP6_PRI_FILTER` C constant.
+        Filter = bindings::nf_ip6_hook_priorities_NF_IP6_PRI_FILTER,
+
+        /// Same as the `NF_IP6_PRI_SECURITY` C constant.
+        Security = bindings::nf_ip6_hook_priorities_NF_IP6_PRI_SECURITY,
+
+        /// Same as the `NF_IP6_PRI_NAT_SRC` C constant.
+        NatSrc = bindings::nf_ip6_hook_priorities_NF_IP6_PRI_NAT_SRC,
+
+        /// Same as the `NF_IP6_PRI_SELINUX_LAST` C constant.
+        SeLinuxLast = bindings::nf_ip6_hook_priorities_NF_IP6_PRI_SELINUX_LAST,
+
+        /// Same as the `NF_IP6_PRI_CONNTRACK_HELPER` C constant.
+        ConnTrackHelper = bindings::nf_ip6_hook_priorities_NF_IP6_PRI_CONNTRACK_HELPER,
+
+        /// Same as the `NF_IP6_PRI_LAST` C constant.
+        Last = bindings::nf_ip6_hook_priorities_NF_IP6_PRI_LAST,
+    }
+}
+
+/// Definitions used when defining hooks for the [`Family::Arp`] family.
+pub mod arp {
+    use crate::bindings;
+
+    /// Hooks allowed in the [`super::Family::Arp`] family.
+    #[repr(u32)]
+    pub enum Hook {
+        /// Inbound ARP packets.
+        In = bindings::NF_ARP_IN,
+
+        /// Outbound ARP packets.
+        Out = bindings::NF_ARP_OUT,
+
+        /// Forwarded ARP packets.
+        Forward = bindings::NF_ARP_FORWARD,
+    }
+}
+
+/// Definitions used when defining hooks for the [`Family::INet`] family.
+pub mod inet {
+    use crate::bindings;
+
+    /// Hooks allowed in the [`super::Family::INet`], [`super::Family::Ipv4`], and
+    /// [`super::Family::Ipv6`] families.
+    #[repr(u32)]
+    pub enum Hook {
+        /// Inbound packets before routing decisions are made (i.e., before it's determined if the
+        /// packet is to be delivered locally or forwarded to another host).
+        PreRouting = bindings::nf_inet_hooks_NF_INET_PRE_ROUTING as _,
+
+        /// Inbound packets that are meant to be delivered locally.
+        LocalIn = bindings::nf_inet_hooks_NF_INET_LOCAL_IN as _,
+
+        /// Inbound packets that are meant to be forwarded to another host.
+        Forward = bindings::nf_inet_hooks_NF_INET_FORWARD as _,
+
+        /// Outbound packet created by the local networking stack.
+        LocalOut = bindings::nf_inet_hooks_NF_INET_LOCAL_OUT as _,
+
+        /// All outbound packets (i.e., generated locally or being forwarded to another host).
+        PostRouting = bindings::nf_inet_hooks_NF_INET_POST_ROUTING as _,
+
+        /// Equivalent to [`super::netdev::Hook::Ingress`], so a device must be specified. Packets
+        /// of all types (not just ipv4/ipv6) will be delivered to the filter.
+        Ingress = bindings::nf_inet_hooks_NF_INET_INGRESS as _,
+    }
+}
diff --git a/rust/kernel/of.rs b/rust/kernel/of.rs
new file mode 100644
index 000000000000..cdcd83244337
--- /dev/null
+++ b/rust/kernel/of.rs
@@ -0,0 +1,63 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Devicetree and Open Firmware abstractions.
+//!
+//! C header: [`include/linux/of_*.h`](../../../../include/linux/of_*.h)
+
+use crate::{bindings, driver, str::BStr};
+
+/// An open firmware device id.
+#[derive(Clone, Copy)]
+pub enum DeviceId {
+    /// An open firmware device id where only a compatible string is specified.
+    Compatible(&'static BStr),
+}
+
+/// Defines a const open firmware device id table that also carries per-entry data/context/info.
+///
+/// The name of the const is `OF_DEVICE_ID_TABLE`, which is what buses are expected to name their
+/// open firmware tables.
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::define_of_id_table;
+/// use kernel::of;
+///
+/// define_of_id_table! {u32, [
+///     (of::DeviceId::Compatible(b"test-device1,test-device2"), Some(0xff)),
+///     (of::DeviceId::Compatible(b"test-device3"), None),
+/// ]};
+/// ```
+#[macro_export]
+macro_rules! define_of_id_table {
+    ($data_type:ty, $($t:tt)*) => {
+        $crate::define_id_table!(OF_DEVICE_ID_TABLE, $crate::of::DeviceId, $data_type, $($t)*);
+    };
+}
+
+// SAFETY: `ZERO` is all zeroed-out and `to_rawid` stores `offset` in `of_device_id::data`.
+unsafe impl const driver::RawDeviceId for DeviceId {
+    type RawType = bindings::of_device_id;
+    const ZERO: Self::RawType = bindings::of_device_id {
+        name: [0; 32],
+        type_: [0; 32],
+        compatible: [0; 128],
+        data: core::ptr::null(),
+    };
+
+    fn to_rawid(&self, offset: isize) -> Self::RawType {
+        let DeviceId::Compatible(compatible) = self;
+        let mut id = Self::ZERO;
+        let mut i = 0;
+        while i < compatible.len() {
+            // If `compatible` does not fit in `id.compatible`, an "index out of bounds" build time
+            // error will be triggered.
+            id.compatible[i] = compatible[i] as _;
+            i += 1;
+        }
+        id.compatible[i] = b'\0' as _;
+        id.data = offset as _;
+        id
+    }
+}
diff --git a/rust/kernel/pages.rs b/rust/kernel/pages.rs
new file mode 100644
index 000000000000..91def8ed062a
--- /dev/null
+++ b/rust/kernel/pages.rs
@@ -0,0 +1,144 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Kernel page allocation and management.
+//!
+//! TODO: This module is a work in progress.
+
+use crate::{
+    bindings, c_types, error::code::*, io_buffer::IoBufferReader, user_ptr::UserSlicePtrReader,
+    Result, PAGE_SIZE,
+};
+use core::{marker::PhantomData, ptr};
+
+/// A set of physical pages.
+///
+/// `Pages` holds a reference to a set of pages of order `ORDER`. Having the order as a generic
+/// const allows the struct to have the same size as a pointer.
+///
+/// # Invariants
+///
+/// The pointer `Pages::pages` is valid and points to 2^ORDER pages.
+pub struct Pages<const ORDER: u32> {
+    pub(crate) pages: *mut bindings::page,
+}
+
+impl<const ORDER: u32> Pages<ORDER> {
+    /// Allocates a new set of contiguous pages.
+    pub fn new() -> Result<Self> {
+        // TODO: Consider whether we want to allow callers to specify flags.
+        // SAFETY: This only allocates pages. We check that it succeeds in the next statement.
+        let pages = unsafe {
+            bindings::alloc_pages(
+                bindings::GFP_KERNEL | bindings::__GFP_ZERO | bindings::__GFP_HIGHMEM,
+                ORDER,
+            )
+        };
+        if pages.is_null() {
+            return Err(ENOMEM);
+        }
+        // INVARIANTS: We checked that the allocation above succeeded>
+        Ok(Self { pages })
+    }
+
+    /// Copies data from the given [`UserSlicePtrReader`] into the pages.
+    pub fn copy_into_page(
+        &self,
+        reader: &mut UserSlicePtrReader,
+        offset: usize,
+        len: usize,
+    ) -> Result {
+        // TODO: For now this only works on the first page.
+        let end = offset.checked_add(len).ok_or(EINVAL)?;
+        if end > PAGE_SIZE {
+            return Err(EINVAL);
+        }
+
+        let mapping = self.kmap(0).ok_or(EINVAL)?;
+
+        // SAFETY: We ensured that the buffer was valid with the check above.
+        unsafe { reader.read_raw((mapping.ptr as usize + offset) as _, len) }?;
+        Ok(())
+    }
+
+    /// Maps the pages and reads from them into the given buffer.
+    ///
+    /// # Safety
+    ///
+    /// Callers must ensure that the destination buffer is valid for the given length.
+    /// Additionally, if the raw buffer is intended to be recast, they must ensure that the data
+    /// can be safely cast; [`crate::io_buffer::ReadableFromBytes`] has more details about it.
+    pub unsafe fn read(&self, dest: *mut u8, offset: usize, len: usize) -> Result {
+        // TODO: For now this only works on the first page.
+        let end = offset.checked_add(len).ok_or(EINVAL)?;
+        if end > PAGE_SIZE {
+            return Err(EINVAL);
+        }
+
+        let mapping = self.kmap(0).ok_or(EINVAL)?;
+        unsafe { ptr::copy((mapping.ptr as *mut u8).add(offset), dest, len) };
+        Ok(())
+    }
+
+    /// Maps the pages and writes into them from the given buffer.
+    ///
+    /// # Safety
+    ///
+    /// Callers must ensure that the buffer is valid for the given length. Additionally, if the
+    /// page is (or will be) mapped by userspace, they must ensure that no kernel data is leaked
+    /// through padding if it was cast from another type; [`crate::io_buffer::WritableToBytes`] has
+    /// more details about it.
+    pub unsafe fn write(&self, src: *const u8, offset: usize, len: usize) -> Result {
+        // TODO: For now this only works on the first page.
+        let end = offset.checked_add(len).ok_or(EINVAL)?;
+        if end > PAGE_SIZE {
+            return Err(EINVAL);
+        }
+
+        let mapping = self.kmap(0).ok_or(EINVAL)?;
+        unsafe { ptr::copy(src, (mapping.ptr as *mut u8).add(offset), len) };
+        Ok(())
+    }
+
+    /// Maps the page at index `index`.
+    fn kmap(&self, index: usize) -> Option<PageMapping<'_>> {
+        if index >= 1usize << ORDER {
+            return None;
+        }
+
+        // SAFETY: We checked above that `index` is within range.
+        let page = unsafe { self.pages.add(index) };
+
+        // SAFETY: `page` is valid based on the checks above.
+        let ptr = unsafe { bindings::kmap(page) };
+        if ptr.is_null() {
+            return None;
+        }
+
+        Some(PageMapping {
+            page,
+            ptr,
+            _phantom: PhantomData,
+        })
+    }
+}
+
+impl<const ORDER: u32> Drop for Pages<ORDER> {
+    fn drop(&mut self) {
+        // SAFETY: By the type invariants, we know the pages are allocated with the given order.
+        unsafe { bindings::__free_pages(self.pages, ORDER) };
+    }
+}
+
+struct PageMapping<'a> {
+    page: *mut bindings::page,
+    ptr: *mut c_types::c_void,
+    _phantom: PhantomData<&'a i32>,
+}
+
+impl Drop for PageMapping<'_> {
+    fn drop(&mut self) {
+        // SAFETY: An instance of `PageMapping` is created only when `kmap` succeeded for the given
+        // page, so it is safe to unmap it here.
+        unsafe { bindings::kunmap(self.page) };
+    }
+}
diff --git a/rust/kernel/platform.rs b/rust/kernel/platform.rs
new file mode 100644
index 000000000000..586cb8f27c3f
--- /dev/null
+++ b/rust/kernel/platform.rs
@@ -0,0 +1,223 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Platform devices and drivers.
+//!
+//! Also called `platdev`, `pdev`.
+//!
+//! C header: [`include/linux/platform_device.h`](../../../../include/linux/platform_device.h)
+
+use crate::{
+    bindings, c_types,
+    device::{self, RawDevice},
+    driver,
+    error::{from_kernel_result, Result},
+    of,
+    str::CStr,
+    to_result,
+    types::PointerWrapper,
+    ThisModule,
+};
+
+/// A registration of a platform driver.
+pub type Registration<T> = driver::Registration<Adapter<T>>;
+
+/// An adapter for the registration of platform drivers.
+pub struct Adapter<T: Driver>(T);
+
+impl<T: Driver> driver::DriverOps for Adapter<T> {
+    type RegType = bindings::platform_driver;
+
+    unsafe fn register(
+        reg: *mut bindings::platform_driver,
+        name: &'static CStr,
+        module: &'static ThisModule,
+    ) -> Result {
+        // SAFETY: By the safety requirements of this function (defined in the trait definition),
+        // `reg` is non-null and valid.
+        let pdrv = unsafe { &mut *reg };
+
+        pdrv.driver.name = name.as_char_ptr();
+        pdrv.probe = Some(Self::probe_callback);
+        pdrv.remove = Some(Self::remove_callback);
+        if let Some(t) = T::OF_DEVICE_ID_TABLE {
+            pdrv.driver.of_match_table = t.as_ref();
+        }
+        // SAFETY:
+        //   - `pdrv` lives at least until the call to `platform_driver_unregister()` returns.
+        //   - `name` pointer has static lifetime.
+        //   - `module.0` lives at least as long as the module.
+        //   - `probe()` and `remove()` are static functions.
+        //   - `of_match_table` is either a raw pointer with static lifetime,
+        //      as guaranteed by the [`driver::IdTable`] type, or null.
+        to_result(|| unsafe { bindings::__platform_driver_register(reg, module.0) })
+    }
+
+    unsafe fn unregister(reg: *mut bindings::platform_driver) {
+        // SAFETY: By the safety requirements of this function (defined in the trait definition),
+        // `reg` was passed (and updated) by a previous successful call to
+        // `platform_driver_register`.
+        unsafe { bindings::platform_driver_unregister(reg) };
+    }
+}
+
+impl<T: Driver> Adapter<T> {
+    fn get_id_info(dev: &Device) -> Option<&'static T::IdInfo> {
+        let table = T::OF_DEVICE_ID_TABLE?;
+
+        // SAFETY: `table` has static lifetime, so it is valid for read. `dev` is guaranteed to be
+        // valid while it's alive, so is the raw device returned by it.
+        let id = unsafe { bindings::of_match_device(table.as_ref(), dev.raw_device()) };
+        if id.is_null() {
+            return None;
+        }
+
+        // SAFETY: `id` is a pointer within the static table, so it's always valid.
+        let offset = unsafe { (*id).data };
+        if offset.is_null() {
+            return None;
+        }
+
+        // SAFETY: The offset comes from a previous call to `offset_from` in `IdArray::new`, which
+        // guarantees that the resulting pointer is within the table.
+        let ptr = unsafe {
+            id.cast::<u8>()
+                .offset(offset as _)
+                .cast::<Option<T::IdInfo>>()
+        };
+
+        // SAFETY: The id table has a static lifetime, so `ptr` is guaranteed to be valid for read.
+        unsafe { (&*ptr).as_ref() }
+    }
+
+    extern "C" fn probe_callback(pdev: *mut bindings::platform_device) -> c_types::c_int {
+        from_kernel_result! {
+            // SAFETY: `pdev` is valid by the contract with the C code. `dev` is alive only for the
+            // duration of this call, so it is guaranteed to remain alive for the lifetime of
+            // `pdev`.
+            let mut dev = unsafe { Device::from_ptr(pdev) };
+            let info = Self::get_id_info(&dev);
+            let data = T::probe(&mut dev, info)?;
+            // SAFETY: `pdev` is guaranteed to be a valid, non-null pointer.
+            unsafe { bindings::platform_set_drvdata(pdev, data.into_pointer() as _) };
+            Ok(0)
+        }
+    }
+
+    extern "C" fn remove_callback(pdev: *mut bindings::platform_device) -> c_types::c_int {
+        from_kernel_result! {
+            // SAFETY: `pdev` is guaranteed to be a valid, non-null pointer.
+            let ptr = unsafe { bindings::platform_get_drvdata(pdev) };
+            // SAFETY:
+            //   - we allocated this pointer using `T::Data::into_pointer`,
+            //     so it is safe to turn back into a `T::Data`.
+            //   - the allocation happened in `probe`, no-one freed the memory,
+            //     `remove` is the canonical kernel location to free driver data. so OK
+            //     to convert the pointer back to a Rust structure here.
+            let data = unsafe { T::Data::from_pointer(ptr) };
+            let ret = T::remove(&data);
+            <T::Data as driver::DeviceRemoval>::device_remove(&data);
+            ret?;
+            Ok(0)
+        }
+    }
+}
+
+/// A platform driver.
+pub trait Driver {
+    /// Data stored on device by driver.
+    ///
+    /// Corresponds to the data set or retrieved via the kernel's
+    /// `platform_{set,get}_drvdata()` functions.
+    ///
+    /// Require that `Data` implements `PointerWrapper`. We guarantee to
+    /// never move the underlying wrapped data structure. This allows
+    type Data: PointerWrapper + Send + Sync + driver::DeviceRemoval = ();
+
+    /// The type holding information about each device id supported by the driver.
+    type IdInfo: 'static = ();
+
+    /// The table of device ids supported by the driver.
+    const OF_DEVICE_ID_TABLE: Option<driver::IdTable<'static, of::DeviceId, Self::IdInfo>> = None;
+
+    /// Platform driver probe.
+    ///
+    /// Called when a new platform device is added or discovered.
+    /// Implementers should attempt to initialize the device here.
+    fn probe(dev: &mut Device, id_info: Option<&Self::IdInfo>) -> Result<Self::Data>;
+
+    /// Platform driver remove.
+    ///
+    /// Called when a platform device is removed.
+    /// Implementers should prepare the device for complete removal here.
+    fn remove(_data: &Self::Data) -> Result {
+        Ok(())
+    }
+}
+
+/// A platform device.
+///
+/// # Invariants
+///
+/// The field `ptr` is non-null and valid for the lifetime of the object.
+pub struct Device {
+    ptr: *mut bindings::platform_device,
+}
+
+impl Device {
+    /// Creates a new device from the given pointer.
+    ///
+    /// # Safety
+    ///
+    /// `ptr` must be non-null and valid. It must remain valid for the lifetime of the returned
+    /// instance.
+    unsafe fn from_ptr(ptr: *mut bindings::platform_device) -> Self {
+        // INVARIANT: The safety requirements of the function ensure the lifetime invariant.
+        Self { ptr }
+    }
+
+    /// Returns id of the platform device.
+    pub fn id(&self) -> i32 {
+        // SAFETY: By the type invariants, we know that `self.ptr` is non-null and valid.
+        unsafe { (*self.ptr).id }
+    }
+}
+
+// SAFETY: The device returned by `raw_device` is the raw platform device.
+unsafe impl device::RawDevice for Device {
+    fn raw_device(&self) -> *mut bindings::device {
+        // SAFETY: By the type invariants, we know that `self.ptr` is non-null and valid.
+        unsafe { &mut (*self.ptr).dev }
+    }
+}
+
+/// Declares a kernel module that exposes a single platform driver.
+///
+/// # Examples
+///
+/// ```ignore
+/// # use kernel::{platform, define_of_id_table, module_platform_driver};
+/// #
+/// struct MyDriver;
+/// impl platform::Driver for MyDriver {
+///     // [...]
+/// #   fn probe(_dev: &mut platform::Device, _id_info: Option<&Self::IdInfo>) -> Result {
+/// #       Ok(())
+/// #   }
+/// #   define_of_id_table! {(), [
+/// #       (of::DeviceId::Compatible(b"brcm,bcm2835-rng"), None),
+/// #   ]}
+/// }
+///
+/// module_platform_driver! {
+///     type: MyDriver,
+///     name: b"module_name",
+///     author: b"Author name",
+///     license: b"GPL",
+/// }
+/// ```
+#[macro_export]
+macro_rules! module_platform_driver {
+    ($($f:tt)*) => {
+        $crate::module_driver!(<T>, $crate::platform::Adapter<T>, { $($f)* });
+    };
+}
diff --git a/rust/kernel/power.rs b/rust/kernel/power.rs
new file mode 100644
index 000000000000..e318b5d9f0c0
--- /dev/null
+++ b/rust/kernel/power.rs
@@ -0,0 +1,118 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Power management interfaces.
+//!
+//! C header: [`include/linux/pm.h`](../../../../include/linux/pm.h)
+
+#![allow(dead_code)]
+
+use crate::{bindings, c_types, error::from_kernel_result, types::PointerWrapper, Result};
+use core::marker::PhantomData;
+
+/// Corresponds to the kernel's `struct dev_pm_ops`.
+///
+/// It is meant to be implemented by drivers that support power-management operations.
+pub trait Operations {
+    /// The type of the context data stored by the driver on each device.
+    type Data: PointerWrapper + Sync + Send;
+
+    /// Called before the system goes into a sleep state.
+    fn suspend(_data: <Self::Data as PointerWrapper>::Borrowed<'_>) -> Result {
+        Ok(())
+    }
+
+    /// Called after the system comes back from a sleep state.
+    fn resume(_data: <Self::Data as PointerWrapper>::Borrowed<'_>) -> Result {
+        Ok(())
+    }
+
+    /// Called before creating a hibernation image.
+    fn freeze(_data: <Self::Data as PointerWrapper>::Borrowed<'_>) -> Result {
+        Ok(())
+    }
+
+    /// Called after the system is restored from a hibernation image.
+    fn restore(_data: <Self::Data as PointerWrapper>::Borrowed<'_>) -> Result {
+        Ok(())
+    }
+}
+
+macro_rules! pm_callback {
+    ($callback:ident, $method:ident) => {
+        unsafe extern "C" fn $callback<T: Operations>(
+            dev: *mut bindings::device,
+        ) -> c_types::c_int {
+            from_kernel_result! {
+                // SAFETY: `dev` is valid as it was passed in by the C portion.
+                let ptr = unsafe { bindings::dev_get_drvdata(dev) };
+                // SAFETY: By the safety requirements of `OpsTable::build`, we know that `ptr` came
+                // from a previous call to `T::Data::into_pointer`.
+                let data = unsafe { T::Data::borrow(ptr) };
+                T::$method(data)?;
+                Ok(0)
+            }
+        }
+    };
+}
+
+pm_callback!(suspend_callback, suspend);
+pm_callback!(resume_callback, resume);
+pm_callback!(freeze_callback, freeze);
+pm_callback!(restore_callback, restore);
+
+pub(crate) struct OpsTable<T: Operations>(PhantomData<*const T>);
+
+impl<T: Operations> OpsTable<T> {
+    const VTABLE: bindings::dev_pm_ops = bindings::dev_pm_ops {
+        prepare: None,
+        complete: None,
+        suspend: Some(suspend_callback::<T>),
+        resume: Some(resume_callback::<T>),
+        freeze: Some(freeze_callback::<T>),
+        thaw: None,
+        poweroff: None,
+        restore: Some(restore_callback::<T>),
+        suspend_late: None,
+        resume_early: None,
+        freeze_late: None,
+        thaw_early: None,
+        poweroff_late: None,
+        restore_early: None,
+        suspend_noirq: None,
+        resume_noirq: None,
+        freeze_noirq: None,
+        thaw_noirq: None,
+        poweroff_noirq: None,
+        restore_noirq: None,
+        runtime_suspend: None,
+        runtime_resume: None,
+        runtime_idle: None,
+    };
+
+    /// Builds an instance of `struct dev_pm_ops`.
+    ///
+    /// # Safety
+    ///
+    /// The caller must ensure that `dev_get_drvdata` will result in a value returned by
+    /// [`T::Data::into_pointer`].
+    pub(crate) const unsafe fn build() -> &'static bindings::dev_pm_ops {
+        &Self::VTABLE
+    }
+}
+
+/// Implements the [`Operations`] trait as no-ops.
+///
+/// This is useful when one doesn't want to provide the implementation of any power-manager related
+/// operation.
+pub struct NoOperations<T: PointerWrapper>(PhantomData<T>);
+
+impl<T: PointerWrapper + Send + Sync> Operations for NoOperations<T> {
+    type Data = T;
+}
+
+// SAFETY: `NoOperation` provides no functionality, it is safe to send a reference to it to
+// different threads.
+unsafe impl<T: PointerWrapper> Sync for NoOperations<T> {}
+
+// SAFETY: `NoOperation` provides no functionality, it is safe to send it to different threads.
+unsafe impl<T: PointerWrapper> Send for NoOperations<T> {}
diff --git a/rust/kernel/prelude.rs b/rust/kernel/prelude.rs
new file mode 100644
index 000000000000..a02b9a9d1937
--- /dev/null
+++ b/rust/kernel/prelude.rs
@@ -0,0 +1,36 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! The `kernel` prelude.
+//!
+//! These are the most common items used by Rust code in the kernel,
+//! intended to be imported by all Rust code, for convenience.
+//!
+//! # Examples
+//!
+//! ```
+//! use kernel::prelude::*;
+//! ```
+
+pub use core::pin::Pin;
+
+pub use alloc::{boxed::Box, string::String, vec::Vec};
+
+pub use macros::module;
+
+pub use super::build_assert;
+
+pub use super::{
+    dbg, dev_alert, dev_crit, dev_dbg, dev_emerg, dev_err, dev_info, dev_notice, dev_warn, fmt,
+    pr_alert, pr_crit, pr_debug, pr_emerg, pr_err, pr_info, pr_notice, pr_warn,
+};
+
+pub use super::module_misc_device;
+
+#[cfg(CONFIG_ARM_AMBA)]
+pub use super::module_amba_driver;
+
+pub use super::static_assert;
+
+pub use super::{error::code::*, Error, Result};
+
+pub use super::{str::CStr, ARef, ThisModule};
diff --git a/rust/kernel/print.rs b/rust/kernel/print.rs
new file mode 100644
index 000000000000..9846bd13eab6
--- /dev/null
+++ b/rust/kernel/print.rs
@@ -0,0 +1,405 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Printing facilities.
+//!
+//! C header: [`include/linux/printk.h`](../../../../include/linux/printk.h)
+//!
+//! Reference: <https://www.kernel.org/doc/html/latest/core-api/printk-basics.html>
+
+use core::fmt;
+
+use crate::{
+    c_types::{c_char, c_void},
+    str::RawFormatter,
+};
+
+#[cfg(CONFIG_PRINTK)]
+use crate::bindings;
+
+// Called from `vsprintf` with format specifier `%pA`.
+#[no_mangle]
+unsafe fn rust_fmt_argument(buf: *mut c_char, end: *mut c_char, ptr: *const c_void) -> *mut c_char {
+    use fmt::Write;
+    // SAFETY: The C contract guarantees that `buf` is valid if it's less than `end`.
+    let mut w = unsafe { RawFormatter::from_ptrs(buf.cast(), end.cast()) };
+    let _ = w.write_fmt(unsafe { *(ptr as *const fmt::Arguments<'_>) });
+    w.pos().cast()
+}
+
+/// Format strings.
+///
+/// Public but hidden since it should only be used from public macros.
+#[doc(hidden)]
+pub mod format_strings {
+    use crate::bindings;
+
+    /// The length we copy from the `KERN_*` kernel prefixes.
+    const LENGTH_PREFIX: usize = 2;
+
+    /// The length of the fixed format strings.
+    pub const LENGTH: usize = 10;
+
+    /// Generates a fixed format string for the kernel's [`_printk`].
+    ///
+    /// The format string is always the same for a given level, i.e. for a
+    /// given `prefix`, which are the kernel's `KERN_*` constants.
+    ///
+    /// [`_printk`]: ../../../../include/linux/printk.h
+    const fn generate(is_cont: bool, prefix: &[u8; 3]) -> [u8; LENGTH] {
+        // Ensure the `KERN_*` macros are what we expect.
+        assert!(prefix[0] == b'\x01');
+        if is_cont {
+            assert!(prefix[1] == b'c');
+        } else {
+            assert!(prefix[1] >= b'0' && prefix[1] <= b'7');
+        }
+        assert!(prefix[2] == b'\x00');
+
+        let suffix: &[u8; LENGTH - LENGTH_PREFIX] = if is_cont {
+            b"%pA\0\0\0\0\0"
+        } else {
+            b"%s: %pA\0"
+        };
+
+        [
+            prefix[0], prefix[1], suffix[0], suffix[1], suffix[2], suffix[3], suffix[4], suffix[5],
+            suffix[6], suffix[7],
+        ]
+    }
+
+    // Generate the format strings at compile-time.
+    //
+    // This avoids the compiler generating the contents on the fly in the stack.
+    //
+    // Furthermore, `static` instead of `const` is used to share the strings
+    // for all the kernel.
+    pub static EMERG: [u8; LENGTH] = generate(false, bindings::KERN_EMERG);
+    pub static ALERT: [u8; LENGTH] = generate(false, bindings::KERN_ALERT);
+    pub static CRIT: [u8; LENGTH] = generate(false, bindings::KERN_CRIT);
+    pub static ERR: [u8; LENGTH] = generate(false, bindings::KERN_ERR);
+    pub static WARNING: [u8; LENGTH] = generate(false, bindings::KERN_WARNING);
+    pub static NOTICE: [u8; LENGTH] = generate(false, bindings::KERN_NOTICE);
+    pub static INFO: [u8; LENGTH] = generate(false, bindings::KERN_INFO);
+    pub static DEBUG: [u8; LENGTH] = generate(false, bindings::KERN_DEBUG);
+    pub static CONT: [u8; LENGTH] = generate(true, bindings::KERN_CONT);
+}
+
+/// Prints a message via the kernel's [`_printk`].
+///
+/// Public but hidden since it should only be used from public macros.
+///
+/// # Safety
+///
+/// The format string must be one of the ones in [`format_strings`], and
+/// the module name must be null-terminated.
+///
+/// [`_printk`]: ../../../../include/linux/_printk.h
+#[doc(hidden)]
+#[cfg_attr(not(CONFIG_PRINTK), allow(unused_variables))]
+pub unsafe fn call_printk(
+    format_string: &[u8; format_strings::LENGTH],
+    module_name: &[u8],
+    args: fmt::Arguments<'_>,
+) {
+    // `_printk` does not seem to fail in any path.
+    #[cfg(CONFIG_PRINTK)]
+    unsafe {
+        bindings::_printk(
+            format_string.as_ptr() as _,
+            module_name.as_ptr(),
+            &args as *const _ as *const c_void,
+        );
+    }
+}
+
+/// Prints a message via the kernel's [`_printk`] for the `CONT` level.
+///
+/// Public but hidden since it should only be used from public macros.
+///
+/// [`_printk`]: ../../../../include/linux/printk.h
+#[doc(hidden)]
+#[cfg_attr(not(CONFIG_PRINTK), allow(unused_variables))]
+pub fn call_printk_cont(args: fmt::Arguments<'_>) {
+    // `_printk` does not seem to fail in any path.
+    //
+    // SAFETY: The format string is fixed.
+    #[cfg(CONFIG_PRINTK)]
+    unsafe {
+        bindings::_printk(
+            format_strings::CONT.as_ptr() as _,
+            &args as *const _ as *const c_void,
+        );
+    }
+}
+
+/// Performs formatting and forwards the string to [`call_printk`].
+///
+/// Public but hidden since it should only be used from public macros.
+#[doc(hidden)]
+#[cfg(not(testlib))]
+#[macro_export]
+macro_rules! print_macro (
+    // The non-continuation cases (most of them, e.g. `INFO`).
+    ($format_string:path, false, $($arg:tt)+) => (
+        // SAFETY: This hidden macro should only be called by the documented
+        // printing macros which ensure the format string is one of the fixed
+        // ones. All `__LOG_PREFIX`s are null-terminated as they are generated
+        // by the `module!` proc macro or fixed values defined in a kernel
+        // crate.
+        unsafe {
+            $crate::print::call_printk(
+                &$format_string,
+                crate::__LOG_PREFIX,
+                format_args!($($arg)+),
+            );
+        }
+    );
+
+    // The `CONT` case.
+    ($format_string:path, true, $($arg:tt)+) => (
+        $crate::print::call_printk_cont(
+            format_args!($($arg)+),
+        );
+    );
+);
+
+/// Stub for doctests
+#[cfg(testlib)]
+#[macro_export]
+macro_rules! print_macro (
+    ($format_string:path, $e:expr, $($arg:tt)+) => (
+        ()
+    );
+);
+
+// We could use a macro to generate these macros. However, doing so ends
+// up being a bit ugly: it requires the dollar token trick to escape `$` as
+// well as playing with the `doc` attribute. Furthermore, they cannot be easily
+// imported in the prelude due to [1]. So, for the moment, we just write them
+// manually, like in the C side; while keeping most of the logic in another
+// macro, i.e. [`print_macro`].
+//
+// [1]: https://github.com/rust-lang/rust/issues/52234
+
+/// Prints an emergency-level message (level 0).
+///
+/// Use this level if the system is unusable.
+///
+/// Equivalent to the kernel's [`pr_emerg`] macro.
+///
+/// Mimics the interface of [`std::print!`]. See [`core::fmt`] and
+/// [`alloc::format!`] for information about the formatting syntax.
+///
+/// [`pr_emerg`]: https://www.kernel.org/doc/html/latest/core-api/printk-basics.html#c.pr_emerg
+/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html
+///
+/// # Examples
+///
+/// ```
+/// pr_emerg!("hello {}\n", "there");
+/// ```
+#[macro_export]
+macro_rules! pr_emerg (
+    ($($arg:tt)*) => (
+        $crate::print_macro!($crate::print::format_strings::EMERG, false, $($arg)*)
+    )
+);
+
+/// Prints an alert-level message (level 1).
+///
+/// Use this level if action must be taken immediately.
+///
+/// Equivalent to the kernel's [`pr_alert`] macro.
+///
+/// Mimics the interface of [`std::print!`]. See [`core::fmt`] and
+/// [`alloc::format!`] for information about the formatting syntax.
+///
+/// [`pr_alert`]: https://www.kernel.org/doc/html/latest/core-api/printk-basics.html#c.pr_alert
+/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html
+///
+/// # Examples
+///
+/// ```
+/// pr_alert!("hello {}\n", "there");
+/// ```
+#[macro_export]
+macro_rules! pr_alert (
+    ($($arg:tt)*) => (
+        $crate::print_macro!($crate::print::format_strings::ALERT, false, $($arg)*)
+    )
+);
+
+/// Prints a critical-level message (level 2).
+///
+/// Use this level for critical conditions.
+///
+/// Equivalent to the kernel's [`pr_crit`] macro.
+///
+/// Mimics the interface of [`std::print!`]. See [`core::fmt`] and
+/// [`alloc::format!`] for information about the formatting syntax.
+///
+/// [`pr_crit`]: https://www.kernel.org/doc/html/latest/core-api/printk-basics.html#c.pr_crit
+/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html
+///
+/// # Examples
+///
+/// ```
+/// pr_crit!("hello {}\n", "there");
+/// ```
+#[macro_export]
+macro_rules! pr_crit (
+    ($($arg:tt)*) => (
+        $crate::print_macro!($crate::print::format_strings::CRIT, false, $($arg)*)
+    )
+);
+
+/// Prints an error-level message (level 3).
+///
+/// Use this level for error conditions.
+///
+/// Equivalent to the kernel's [`pr_err`] macro.
+///
+/// Mimics the interface of [`std::print!`]. See [`core::fmt`] and
+/// [`alloc::format!`] for information about the formatting syntax.
+///
+/// [`pr_err`]: https://www.kernel.org/doc/html/latest/core-api/printk-basics.html#c.pr_err
+/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html
+///
+/// # Examples
+///
+/// ```
+/// pr_err!("hello {}\n", "there");
+/// ```
+#[macro_export]
+macro_rules! pr_err (
+    ($($arg:tt)*) => (
+        $crate::print_macro!($crate::print::format_strings::ERR, false, $($arg)*)
+    )
+);
+
+/// Prints a warning-level message (level 4).
+///
+/// Use this level for warning conditions.
+///
+/// Equivalent to the kernel's [`pr_warn`] macro.
+///
+/// Mimics the interface of [`std::print!`]. See [`core::fmt`] and
+/// [`alloc::format!`] for information about the formatting syntax.
+///
+/// [`pr_warn`]: https://www.kernel.org/doc/html/latest/core-api/printk-basics.html#c.pr_warn
+/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html
+///
+/// # Examples
+///
+/// ```
+/// pr_warn!("hello {}\n", "there");
+/// ```
+#[macro_export]
+macro_rules! pr_warn (
+    ($($arg:tt)*) => (
+        $crate::print_macro!($crate::print::format_strings::WARNING, false, $($arg)*)
+    )
+);
+
+/// Prints a notice-level message (level 5).
+///
+/// Use this level for normal but significant conditions.
+///
+/// Equivalent to the kernel's [`pr_notice`] macro.
+///
+/// Mimics the interface of [`std::print!`]. See [`core::fmt`] and
+/// [`alloc::format!`] for information about the formatting syntax.
+///
+/// [`pr_notice`]: https://www.kernel.org/doc/html/latest/core-api/printk-basics.html#c.pr_notice
+/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html
+///
+/// # Examples
+///
+/// ```
+/// pr_notice!("hello {}\n", "there");
+/// ```
+#[macro_export]
+macro_rules! pr_notice (
+    ($($arg:tt)*) => (
+        $crate::print_macro!($crate::print::format_strings::NOTICE, false, $($arg)*)
+    )
+);
+
+/// Prints an info-level message (level 6).
+///
+/// Use this level for informational messages.
+///
+/// Equivalent to the kernel's [`pr_info`] macro.
+///
+/// Mimics the interface of [`std::print!`]. See [`core::fmt`] and
+/// [`alloc::format!`] for information about the formatting syntax.
+///
+/// [`pr_info`]: https://www.kernel.org/doc/html/latest/core-api/printk-basics.html#c.pr_info
+/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html
+///
+/// # Examples
+///
+/// ```
+/// pr_info!("hello {}\n", "there");
+/// ```
+#[macro_export]
+#[doc(alias = "print")]
+macro_rules! pr_info (
+    ($($arg:tt)*) => (
+        $crate::print_macro!($crate::print::format_strings::INFO, false, $($arg)*)
+    )
+);
+
+/// Prints a debug-level message (level 7).
+///
+/// Use this level for debug messages.
+///
+/// Equivalent to the kernel's [`pr_debug`] macro, except that it doesn't support dynamic debug
+/// yet.
+///
+/// Mimics the interface of [`std::print!`]. See [`core::fmt`] and
+/// [`alloc::format!`] for information about the formatting syntax.
+///
+/// [`pr_debug`]: https://www.kernel.org/doc/html/latest/core-api/printk-basics.html#c.pr_debug
+/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html
+///
+/// # Examples
+///
+/// ```
+/// pr_debug!("hello {}\n", "there");
+/// ```
+#[macro_export]
+#[doc(alias = "print")]
+macro_rules! pr_debug (
+    ($($arg:tt)*) => (
+        if cfg!(debug_assertions) {
+            $crate::print_macro!($crate::print::format_strings::DEBUG, false, $($arg)*)
+        }
+    )
+);
+
+/// Continues a previous log message in the same line.
+///
+/// Use only when continuing a previous `pr_*!` macro (e.g. [`pr_info!`]).
+///
+/// Equivalent to the kernel's [`pr_cont`] macro.
+///
+/// Mimics the interface of [`std::print!`]. See [`core::fmt`] and
+/// [`alloc::format!`] for information about the formatting syntax.
+///
+/// [`pr_cont`]: https://www.kernel.org/doc/html/latest/core-api/printk-basics.html#c.pr_cont
+/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::pr_cont;
+/// pr_info!("hello");
+/// pr_cont!(" {}\n", "there");
+/// ```
+#[macro_export]
+macro_rules! pr_cont (
+    ($($arg:tt)*) => (
+        $crate::print_macro!($crate::print::format_strings::CONT, true, $($arg)*)
+    )
+);
diff --git a/rust/kernel/random.rs b/rust/kernel/random.rs
new file mode 100644
index 000000000000..a0926cb68a75
--- /dev/null
+++ b/rust/kernel/random.rs
@@ -0,0 +1,42 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Random numbers.
+//!
+//! C header: [`include/linux/random.h`](../../../../include/linux/random.h)
+
+use crate::{bindings, c_types, error::code::*, Error, Result};
+
+/// Fills a byte slice with random bytes generated from the kernel's CSPRNG.
+///
+/// Ensures that the CSPRNG has been seeded before generating any random bytes,
+/// and will block until it is ready.
+pub fn getrandom(dest: &mut [u8]) -> Result {
+    let res = unsafe { bindings::wait_for_random_bytes() };
+    if res != 0 {
+        return Err(Error::from_kernel_errno(res));
+    }
+
+    unsafe {
+        bindings::get_random_bytes(dest.as_mut_ptr() as *mut c_types::c_void, dest.len());
+    }
+    Ok(())
+}
+
+/// Fills a byte slice with random bytes generated from the kernel's CSPRNG.
+///
+/// If the CSPRNG is not yet seeded, returns an `Err(EAGAIN)` immediately.
+pub fn getrandom_nonblock(dest: &mut [u8]) -> Result {
+    if !unsafe { bindings::rng_is_initialized() } {
+        return Err(EAGAIN);
+    }
+    getrandom(dest)
+}
+
+/// Contributes the contents of a byte slice to the kernel's entropy pool.
+///
+/// Does *not* credit the kernel entropy counter though.
+pub fn add_randomness(data: &[u8]) {
+    unsafe {
+        bindings::add_device_randomness(data.as_ptr() as *const c_types::c_void, data.len());
+    }
+}
diff --git a/rust/kernel/raw_list.rs b/rust/kernel/raw_list.rs
new file mode 100644
index 000000000000..267b21709c29
--- /dev/null
+++ b/rust/kernel/raw_list.rs
@@ -0,0 +1,361 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Raw lists.
+//!
+//! TODO: This module is a work in progress.
+
+use core::{
+    cell::UnsafeCell,
+    ptr,
+    ptr::NonNull,
+    sync::atomic::{AtomicBool, Ordering},
+};
+
+/// A descriptor of list elements.
+///
+/// It describes the type of list elements and provides a function to determine how to get the
+/// links to be used on a list.
+///
+/// A type that may be in multiple lists simultaneously needs to implement one of these for each
+/// simultaneous list.
+pub trait GetLinks {
+    /// The type of the entries in the list.
+    type EntryType: ?Sized;
+
+    /// Returns the links to be used when linking an entry within a list.
+    fn get_links(data: &Self::EntryType) -> &Links<Self::EntryType>;
+}
+
+/// The links used to link an object on a linked list.
+///
+/// Instances of this type are usually embedded in structures and returned in calls to
+/// [`GetLinks::get_links`].
+pub struct Links<T: ?Sized> {
+    inserted: AtomicBool,
+    entry: UnsafeCell<ListEntry<T>>,
+}
+
+impl<T: ?Sized> Links<T> {
+    /// Constructs a new [`Links`] instance that isn't inserted on any lists yet.
+    pub fn new() -> Self {
+        Self {
+            inserted: AtomicBool::new(false),
+            entry: UnsafeCell::new(ListEntry::new()),
+        }
+    }
+
+    fn acquire_for_insertion(&self) -> bool {
+        self.inserted
+            .compare_exchange(false, true, Ordering::Acquire, Ordering::Relaxed)
+            .is_ok()
+    }
+
+    fn release_after_removal(&self) {
+        self.inserted.store(false, Ordering::Release);
+    }
+}
+
+impl<T: ?Sized> Default for Links<T> {
+    fn default() -> Self {
+        Self::new()
+    }
+}
+
+struct ListEntry<T: ?Sized> {
+    next: Option<NonNull<T>>,
+    prev: Option<NonNull<T>>,
+}
+
+impl<T: ?Sized> ListEntry<T> {
+    fn new() -> Self {
+        Self {
+            next: None,
+            prev: None,
+        }
+    }
+}
+
+/// A linked list.
+///
+/// # Invariants
+///
+/// The links of objects added to a list are owned by the list.
+pub(crate) struct RawList<G: GetLinks> {
+    head: Option<NonNull<G::EntryType>>,
+}
+
+impl<G: GetLinks> RawList<G> {
+    pub(crate) fn new() -> Self {
+        Self { head: None }
+    }
+
+    pub(crate) fn is_empty(&self) -> bool {
+        self.head.is_none()
+    }
+
+    fn insert_after_priv(
+        &mut self,
+        existing: &G::EntryType,
+        new_entry: &mut ListEntry<G::EntryType>,
+        new_ptr: Option<NonNull<G::EntryType>>,
+    ) {
+        {
+            // SAFETY: It's safe to get the previous entry of `existing` because the list cannot
+            // change.
+            let existing_links = unsafe { &mut *G::get_links(existing).entry.get() };
+            new_entry.next = existing_links.next;
+            existing_links.next = new_ptr;
+        }
+
+        new_entry.prev = Some(NonNull::from(existing));
+
+        // SAFETY: It's safe to get the next entry of `existing` because the list cannot change.
+        let next_links =
+            unsafe { &mut *G::get_links(new_entry.next.unwrap().as_ref()).entry.get() };
+        next_links.prev = new_ptr;
+    }
+
+    /// Inserts the given object after `existing`.
+    ///
+    /// # Safety
+    ///
+    /// Callers must ensure that `existing` points to a valid entry that is on the list.
+    pub(crate) unsafe fn insert_after(
+        &mut self,
+        existing: &G::EntryType,
+        new: &G::EntryType,
+    ) -> bool {
+        let links = G::get_links(new);
+        if !links.acquire_for_insertion() {
+            // Nothing to do if already inserted.
+            return false;
+        }
+
+        // SAFETY: The links are now owned by the list, so it is safe to get a mutable reference.
+        let new_entry = unsafe { &mut *links.entry.get() };
+        self.insert_after_priv(existing, new_entry, Some(NonNull::from(new)));
+        true
+    }
+
+    fn push_back_internal(&mut self, new: &G::EntryType) -> bool {
+        let links = G::get_links(new);
+        if !links.acquire_for_insertion() {
+            // Nothing to do if already inserted.
+            return false;
+        }
+
+        // SAFETY: The links are now owned by the list, so it is safe to get a mutable reference.
+        let new_entry = unsafe { &mut *links.entry.get() };
+        let new_ptr = Some(NonNull::from(new));
+        match self.back() {
+            // SAFETY: `back` is valid as the list cannot change.
+            Some(back) => self.insert_after_priv(unsafe { back.as_ref() }, new_entry, new_ptr),
+            None => {
+                self.head = new_ptr;
+                new_entry.next = new_ptr;
+                new_entry.prev = new_ptr;
+            }
+        }
+        true
+    }
+
+    pub(crate) unsafe fn push_back(&mut self, new: &G::EntryType) -> bool {
+        self.push_back_internal(new)
+    }
+
+    fn remove_internal(&mut self, data: &G::EntryType) -> bool {
+        let links = G::get_links(data);
+
+        // SAFETY: The links are now owned by the list, so it is safe to get a mutable reference.
+        let entry = unsafe { &mut *links.entry.get() };
+        let next = if let Some(next) = entry.next {
+            next
+        } else {
+            // Nothing to do if the entry is not on the list.
+            return false;
+        };
+
+        if ptr::eq(data, next.as_ptr()) {
+            // We're removing the only element.
+            self.head = None
+        } else {
+            // Update the head if we're removing it.
+            if let Some(raw_head) = self.head {
+                if ptr::eq(data, raw_head.as_ptr()) {
+                    self.head = Some(next);
+                }
+            }
+
+            // SAFETY: It's safe to get the previous entry because the list cannot change.
+            unsafe { &mut *G::get_links(entry.prev.unwrap().as_ref()).entry.get() }.next =
+                entry.next;
+
+            // SAFETY: It's safe to get the next entry because the list cannot change.
+            unsafe { &mut *G::get_links(next.as_ref()).entry.get() }.prev = entry.prev;
+        }
+
+        // Reset the links of the element we're removing so that we know it's not on any list.
+        entry.next = None;
+        entry.prev = None;
+        links.release_after_removal();
+        true
+    }
+
+    /// Removes the given entry.
+    ///
+    /// # Safety
+    ///
+    /// Callers must ensure that `data` is either on this list or in no list. It being on another
+    /// list leads to memory unsafety.
+    pub(crate) unsafe fn remove(&mut self, data: &G::EntryType) -> bool {
+        self.remove_internal(data)
+    }
+
+    fn pop_front_internal(&mut self) -> Option<NonNull<G::EntryType>> {
+        let head = self.head?;
+        // SAFETY: The head is on the list as we just got it from there and it cannot change.
+        unsafe { self.remove(head.as_ref()) };
+        Some(head)
+    }
+
+    pub(crate) fn pop_front(&mut self) -> Option<NonNull<G::EntryType>> {
+        self.pop_front_internal()
+    }
+
+    pub(crate) fn front(&self) -> Option<NonNull<G::EntryType>> {
+        self.head
+    }
+
+    pub(crate) fn back(&self) -> Option<NonNull<G::EntryType>> {
+        // SAFETY: The links of head are owned by the list, so it is safe to get a reference.
+        unsafe { &*G::get_links(self.head?.as_ref()).entry.get() }.prev
+    }
+
+    pub(crate) fn cursor_front(&self) -> Cursor<'_, G> {
+        Cursor::new(self, self.front())
+    }
+
+    pub(crate) fn cursor_front_mut(&mut self) -> CursorMut<'_, G> {
+        CursorMut::new(self, self.front())
+    }
+}
+
+struct CommonCursor<G: GetLinks> {
+    cur: Option<NonNull<G::EntryType>>,
+}
+
+impl<G: GetLinks> CommonCursor<G> {
+    fn new(cur: Option<NonNull<G::EntryType>>) -> Self {
+        Self { cur }
+    }
+
+    fn move_next(&mut self, list: &RawList<G>) {
+        match self.cur.take() {
+            None => self.cur = list.head,
+            Some(cur) => {
+                if let Some(head) = list.head {
+                    // SAFETY: We have a shared ref to the linked list, so the links can't change.
+                    let links = unsafe { &*G::get_links(cur.as_ref()).entry.get() };
+                    if links.next.unwrap() != head {
+                        self.cur = links.next;
+                    }
+                }
+            }
+        }
+    }
+
+    fn move_prev(&mut self, list: &RawList<G>) {
+        match list.head {
+            None => self.cur = None,
+            Some(head) => {
+                let next = match self.cur.take() {
+                    None => head,
+                    Some(cur) => {
+                        if cur == head {
+                            return;
+                        }
+                        cur
+                    }
+                };
+                // SAFETY: There's a shared ref to the list, so the links can't change.
+                let links = unsafe { &*G::get_links(next.as_ref()).entry.get() };
+                self.cur = links.prev;
+            }
+        }
+    }
+}
+
+/// A list cursor that allows traversing a linked list and inspecting elements.
+pub struct Cursor<'a, G: GetLinks> {
+    cursor: CommonCursor<G>,
+    list: &'a RawList<G>,
+}
+
+impl<'a, G: GetLinks> Cursor<'a, G> {
+    fn new(list: &'a RawList<G>, cur: Option<NonNull<G::EntryType>>) -> Self {
+        Self {
+            list,
+            cursor: CommonCursor::new(cur),
+        }
+    }
+
+    /// Returns the element the cursor is currently positioned on.
+    pub fn current(&self) -> Option<&'a G::EntryType> {
+        let cur = self.cursor.cur?;
+        // SAFETY: Objects must be kept alive while on the list.
+        Some(unsafe { &*cur.as_ptr() })
+    }
+
+    /// Moves the cursor to the next element.
+    pub fn move_next(&mut self) {
+        self.cursor.move_next(self.list);
+    }
+}
+
+pub(crate) struct CursorMut<'a, G: GetLinks> {
+    cursor: CommonCursor<G>,
+    list: &'a mut RawList<G>,
+}
+
+impl<'a, G: GetLinks> CursorMut<'a, G> {
+    fn new(list: &'a mut RawList<G>, cur: Option<NonNull<G::EntryType>>) -> Self {
+        Self {
+            list,
+            cursor: CommonCursor::new(cur),
+        }
+    }
+
+    pub(crate) fn current(&mut self) -> Option<&mut G::EntryType> {
+        let cur = self.cursor.cur?;
+        // SAFETY: Objects must be kept alive while on the list.
+        Some(unsafe { &mut *cur.as_ptr() })
+    }
+
+    /// Removes the entry the cursor is pointing to and advances the cursor to the next entry. It
+    /// returns a raw pointer to the removed element (if one is removed).
+    pub(crate) fn remove_current(&mut self) -> Option<NonNull<G::EntryType>> {
+        let entry = self.cursor.cur?;
+        self.cursor.move_next(self.list);
+        // SAFETY: The entry is on the list as we just got it from there and it cannot change.
+        unsafe { self.list.remove(entry.as_ref()) };
+        Some(entry)
+    }
+
+    pub(crate) fn peek_next(&mut self) -> Option<&mut G::EntryType> {
+        let mut new = CommonCursor::new(self.cursor.cur);
+        new.move_next(self.list);
+        // SAFETY: Objects must be kept alive while on the list.
+        Some(unsafe { &mut *new.cur?.as_ptr() })
+    }
+
+    pub(crate) fn peek_prev(&mut self) -> Option<&mut G::EntryType> {
+        let mut new = CommonCursor::new(self.cursor.cur);
+        new.move_prev(self.list);
+        // SAFETY: Objects must be kept alive while on the list.
+        Some(unsafe { &mut *new.cur?.as_ptr() })
+    }
+
+    pub(crate) fn move_next(&mut self) {
+        self.cursor.move_next(self.list);
+    }
+}
diff --git a/rust/kernel/rbtree.rs b/rust/kernel/rbtree.rs
new file mode 100644
index 000000000000..a30739cc6839
--- /dev/null
+++ b/rust/kernel/rbtree.rs
@@ -0,0 +1,563 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Red-black trees.
+//!
+//! C header: [`include/linux/rbtree.h`](../../../../include/linux/rbtree.h)
+//!
+//! Reference: <https://www.kernel.org/doc/html/latest/core-api/rbtree.html>
+
+use crate::{bindings, Result};
+use alloc::boxed::Box;
+use core::{
+    cmp::{Ord, Ordering},
+    iter::{IntoIterator, Iterator},
+    marker::PhantomData,
+    mem::MaybeUninit,
+    ptr::{addr_of_mut, NonNull},
+};
+
+struct Node<K, V> {
+    links: bindings::rb_node,
+    key: K,
+    value: V,
+}
+
+/// A red-black tree with owned nodes.
+///
+/// It is backed by the kernel C red-black trees.
+///
+/// # Invariants
+///
+/// Non-null parent/children pointers stored in instances of the `rb_node` C struct are always
+/// valid, and pointing to a field of our internal representation of a node.
+///
+/// # Examples
+///
+/// In the example below we do several operations on a tree. We note that insertions may fail if
+/// the system is out of memory.
+///
+/// ```
+/// use kernel::rbtree::RBTree;
+///
+/// # fn test() -> Result {
+/// // Create a new tree.
+/// let mut tree = RBTree::new();
+///
+/// // Insert three elements.
+/// tree.try_insert(20, 200)?;
+/// tree.try_insert(10, 100)?;
+/// tree.try_insert(30, 300)?;
+///
+/// // Check the nodes we just inserted.
+/// {
+///     let mut iter = tree.iter();
+///     assert_eq!(iter.next().unwrap(), (&10, &100));
+///     assert_eq!(iter.next().unwrap(), (&20, &200));
+///     assert_eq!(iter.next().unwrap(), (&30, &300));
+///     assert!(iter.next().is_none());
+/// }
+///
+/// // Print all elements.
+/// for (key, value) in &tree {
+///     pr_info!("{} = {}\n", key, value);
+/// }
+///
+/// // Replace one of the elements.
+/// tree.try_insert(10, 1000)?;
+///
+/// // Check that the tree reflects the replacement.
+/// {
+///     let mut iter = tree.iter();
+///     assert_eq!(iter.next().unwrap(), (&10, &1000));
+///     assert_eq!(iter.next().unwrap(), (&20, &200));
+///     assert_eq!(iter.next().unwrap(), (&30, &300));
+///     assert!(iter.next().is_none());
+/// }
+///
+/// // Change the value of one of the elements.
+/// *tree.get_mut(&30).unwrap() = 3000;
+///
+/// // Check that the tree reflects the update.
+/// {
+///     let mut iter = tree.iter();
+///     assert_eq!(iter.next().unwrap(), (&10, &1000));
+///     assert_eq!(iter.next().unwrap(), (&20, &200));
+///     assert_eq!(iter.next().unwrap(), (&30, &3000));
+///     assert!(iter.next().is_none());
+/// }
+///
+/// // Remove an element.
+/// tree.remove(&10);
+///
+/// // Check that the tree reflects the removal.
+/// {
+///     let mut iter = tree.iter();
+///     assert_eq!(iter.next().unwrap(), (&20, &200));
+///     assert_eq!(iter.next().unwrap(), (&30, &3000));
+///     assert!(iter.next().is_none());
+/// }
+///
+/// // Update all values.
+/// for value in tree.values_mut() {
+///     *value *= 10;
+/// }
+///
+/// // Check that the tree reflects the changes to values.
+/// {
+///     let mut iter = tree.iter();
+///     assert_eq!(iter.next().unwrap(), (&20, &2000));
+///     assert_eq!(iter.next().unwrap(), (&30, &30000));
+///     assert!(iter.next().is_none());
+/// }
+///
+/// # Ok(())
+/// # }
+/// #
+/// # assert_eq!(test(), Ok(()));
+/// ```
+///
+/// In the example below, we first allocate a node, acquire a spinlock, then insert the node into
+/// the tree. This is useful when the insertion context does not allow sleeping, for example, when
+/// holding a spinlock.
+///
+/// ```
+/// use kernel::{rbtree::RBTree, sync::SpinLock};
+///
+/// fn insert_test(tree: &SpinLock<RBTree<u32, u32>>) -> Result {
+///     // Pre-allocate node. This may fail (as it allocates memory).
+///     let node = RBTree::try_allocate_node(10, 100)?;
+///
+///     // Insert node while holding the lock. It is guaranteed to succeed with no allocation
+///     // attempts.
+///     let mut guard = tree.lock();
+///     guard.insert(node);
+///     Ok(())
+/// }
+/// ```
+///
+/// In the example below, we reuse an existing node allocation from an element we removed.
+///
+/// ```
+/// use kernel::rbtree::RBTree;
+///
+/// # fn test() -> Result {
+/// // Create a new tree.
+/// let mut tree = RBTree::new();
+///
+/// // Insert three elements.
+/// tree.try_insert(20, 200)?;
+/// tree.try_insert(10, 100)?;
+/// tree.try_insert(30, 300)?;
+///
+/// // Check the nodes we just inserted.
+/// {
+///     let mut iter = tree.iter();
+///     assert_eq!(iter.next().unwrap(), (&10, &100));
+///     assert_eq!(iter.next().unwrap(), (&20, &200));
+///     assert_eq!(iter.next().unwrap(), (&30, &300));
+///     assert!(iter.next().is_none());
+/// }
+///
+/// // Remove a node, getting back ownership of it.
+/// let existing = tree.remove_node(&30).unwrap();
+///
+/// // Check that the tree reflects the removal.
+/// {
+///     let mut iter = tree.iter();
+///     assert_eq!(iter.next().unwrap(), (&10, &100));
+///     assert_eq!(iter.next().unwrap(), (&20, &200));
+///     assert!(iter.next().is_none());
+/// }
+///
+/// // Turn the node into a reservation so that we can reuse it with a different key/value.
+/// let reservation = existing.into_reservation();
+///
+/// // Insert a new node into the tree, reusing the previous allocation. This is guaranteed to
+/// // succeed (no memory allocations).
+/// tree.insert(reservation.into_node(15, 150));
+///
+/// // Check that the tree reflect the new insertion.
+/// {
+///     let mut iter = tree.iter();
+///     assert_eq!(iter.next().unwrap(), (&10, &100));
+///     assert_eq!(iter.next().unwrap(), (&15, &150));
+///     assert_eq!(iter.next().unwrap(), (&20, &200));
+///     assert!(iter.next().is_none());
+/// }
+///
+/// # Ok(())
+/// # }
+/// #
+/// # assert_eq!(test(), Ok(()));
+/// ```
+pub struct RBTree<K, V> {
+    root: bindings::rb_root,
+    _p: PhantomData<Node<K, V>>,
+}
+
+impl<K, V> RBTree<K, V> {
+    /// Creates a new and empty tree.
+    pub fn new() -> Self {
+        Self {
+            // INVARIANT: There are no nodes in the tree, so the invariant holds vacuously.
+            root: bindings::rb_root::default(),
+            _p: PhantomData,
+        }
+    }
+
+    /// Tries to insert a new value into the tree.
+    ///
+    /// It overwrites a node if one already exists with the same key and returns it (containing the
+    /// key/value pair). Returns [`None`] if a node with the same key didn't already exist.
+    ///
+    /// Returns an error if it cannot allocate memory for the new node.
+    pub fn try_insert(&mut self, key: K, value: V) -> Result<Option<RBTreeNode<K, V>>>
+    where
+        K: Ord,
+    {
+        Ok(self.insert(Self::try_allocate_node(key, value)?))
+    }
+
+    /// Allocates memory for a node to be eventually initialised and inserted into the tree via a
+    /// call to [`RBTree::insert`].
+    pub fn try_reserve_node() -> Result<RBTreeNodeReservation<K, V>> {
+        Ok(RBTreeNodeReservation {
+            node: Box::try_new(MaybeUninit::uninit())?,
+        })
+    }
+
+    /// Allocates and initialiases a node that can be inserted into the tree via
+    /// [`RBTree::insert`].
+    pub fn try_allocate_node(key: K, value: V) -> Result<RBTreeNode<K, V>> {
+        Ok(Self::try_reserve_node()?.into_node(key, value))
+    }
+
+    /// Inserts a new node into the tree.
+    ///
+    /// It overwrites a node if one already exists with the same key and returns it (containing the
+    /// key/value pair). Returns [`None`] if a node with the same key didn't already exist.
+    ///
+    /// This function always succeeds.
+    pub fn insert(&mut self, node: RBTreeNode<K, V>) -> Option<RBTreeNode<K, V>>
+    where
+        K: Ord,
+    {
+        let RBTreeNode { node } = node;
+        let node = Box::into_raw(node);
+        // SAFETY: `node` is valid at least until we call `Box::from_raw`, which only happens when
+        // the node is removed or replaced.
+        let node_links = unsafe { addr_of_mut!((*node).links) };
+        let mut new_link: &mut *mut bindings::rb_node = &mut self.root.rb_node;
+        let mut parent = core::ptr::null_mut();
+        while !new_link.is_null() {
+            let this = crate::container_of!(*new_link, Node<K, V>, links);
+
+            parent = *new_link;
+
+            // SAFETY: `this` is a non-null node so it is valid by the type invariants. `node` is
+            // valid until the node is removed.
+            match unsafe { (*node).key.cmp(&(*this).key) } {
+                // SAFETY: `parent` is a non-null node so it is valid by the type invariants.
+                Ordering::Less => new_link = unsafe { &mut (*parent).rb_left },
+                // SAFETY: `parent` is a non-null node so it is valid by the type invariants.
+                Ordering::Greater => new_link = unsafe { &mut (*parent).rb_right },
+                Ordering::Equal => {
+                    // INVARIANT: We are replacing an existing node with a new one, which is valid.
+                    // It remains valid because we "forgot" it with `Box::into_raw`.
+                    // SAFETY: All pointers are non-null and valid (parent, despite the name, really
+                    // is the node we're replacing).
+                    unsafe { bindings::rb_replace_node(parent, node_links, &mut self.root) };
+
+                    // INVARIANT: The node is being returned and the caller may free it, however,
+                    // it was removed from the tree. So the invariants still hold.
+                    return Some(RBTreeNode {
+                        // SAFETY: `this` was a node in the tree, so it is valid.
+                        node: unsafe { Box::from_raw(this as _) },
+                    });
+                }
+            }
+        }
+
+        // INVARIANT: We are linking in a new node, which is valid. It remains valid because we
+        // "forgot" it with `Box::into_raw`.
+        // SAFETY: All pointers are non-null and valid (`*new_link` is null, but `new_link` is a
+        // mutable reference).
+        unsafe { bindings::rb_link_node(node_links, parent, new_link) };
+
+        // SAFETY: All pointers are valid. `node` has just been inserted into the tree.
+        unsafe { bindings::rb_insert_color(node_links, &mut self.root) };
+        None
+    }
+
+    /// Returns a node with the given key, if one exists.
+    fn find(&self, key: &K) -> Option<NonNull<Node<K, V>>>
+    where
+        K: Ord,
+    {
+        let mut node = self.root.rb_node;
+        while !node.is_null() {
+            let this = crate::container_of!(node, Node<K, V>, links);
+            // SAFETY: `this` is a non-null node so it is valid by the type invariants.
+            node = match key.cmp(unsafe { &(*this).key }) {
+                // SAFETY: `node` is a non-null node so it is valid by the type invariants.
+                Ordering::Less => unsafe { (*node).rb_left },
+                // SAFETY: `node` is a non-null node so it is valid by the type invariants.
+                Ordering::Greater => unsafe { (*node).rb_right },
+                Ordering::Equal => return NonNull::new(this as _),
+            }
+        }
+        None
+    }
+
+    /// Returns a reference to the value corresponding to the key.
+    pub fn get(&self, key: &K) -> Option<&V>
+    where
+        K: Ord,
+    {
+        // SAFETY: The `find` return value is a node in the tree, so it is valid.
+        self.find(key).map(|node| unsafe { &node.as_ref().value })
+    }
+
+    /// Returns a mutable reference to the value corresponding to the key.
+    pub fn get_mut(&mut self, key: &K) -> Option<&mut V>
+    where
+        K: Ord,
+    {
+        // SAFETY: The `find` return value is a node in the tree, so it is valid.
+        self.find(key)
+            .map(|mut node| unsafe { &mut node.as_mut().value })
+    }
+
+    /// Removes the node with the given key from the tree.
+    ///
+    /// It returns the node that was removed if one exists, or [`None`] otherwise.
+    pub fn remove_node(&mut self, key: &K) -> Option<RBTreeNode<K, V>>
+    where
+        K: Ord,
+    {
+        let mut node = self.find(key)?;
+
+        // SAFETY: The `find` return value is a node in the tree, so it is valid.
+        unsafe { bindings::rb_erase(&mut node.as_mut().links, &mut self.root) };
+
+        // INVARIANT: The node is being returned and the caller may free it, however, it was
+        // removed from the tree. So the invariants still hold.
+        Some(RBTreeNode {
+            // SAFETY: The `find` return value was a node in the tree, so it is valid.
+            node: unsafe { Box::from_raw(node.as_ptr()) },
+        })
+    }
+
+    /// Removes the node with the given key from the tree.
+    ///
+    /// It returns the value that was removed if one exists, or [`None`] otherwise.
+    pub fn remove(&mut self, key: &K) -> Option<V>
+    where
+        K: Ord,
+    {
+        let node = self.remove_node(key)?;
+        let RBTreeNode { node } = node;
+        let Node {
+            links: _,
+            key: _,
+            value,
+        } = *node;
+        Some(value)
+    }
+
+    /// Returns an iterator over the tree nodes, sorted by key.
+    pub fn iter(&self) -> RBTreeIterator<'_, K, V> {
+        RBTreeIterator {
+            _tree: PhantomData,
+            // SAFETY: `root` is valid as it's embedded in `self` and we have a valid `self`.
+            next: unsafe { bindings::rb_first(&self.root) },
+        }
+    }
+
+    /// Returns a mutable iterator over the tree nodes, sorted by key.
+    pub fn iter_mut(&mut self) -> RBTreeIteratorMut<'_, K, V> {
+        RBTreeIteratorMut {
+            _tree: PhantomData,
+            // SAFETY: `root` is valid as it's embedded in `self` and we have a valid `self`.
+            next: unsafe { bindings::rb_first(&self.root) },
+        }
+    }
+
+    /// Returns an iterator over the keys of the nodes in the tree, in sorted order.
+    pub fn keys(&self) -> impl Iterator<Item = &'_ K> {
+        self.iter().map(|(k, _)| k)
+    }
+
+    /// Returns an iterator over the values of the nodes in the tree, sorted by key.
+    pub fn values(&self) -> impl Iterator<Item = &'_ V> {
+        self.iter().map(|(_, v)| v)
+    }
+
+    /// Returns a mutable iterator over the values of the nodes in the tree, sorted by key.
+    pub fn values_mut(&mut self) -> impl Iterator<Item = &'_ mut V> {
+        self.iter_mut().map(|(_, v)| v)
+    }
+}
+
+impl<K, V> Default for RBTree<K, V> {
+    fn default() -> Self {
+        Self::new()
+    }
+}
+
+impl<K, V> Drop for RBTree<K, V> {
+    fn drop(&mut self) {
+        // SAFETY: `root` is valid as it's embedded in `self` and we have a valid `self`.
+        let mut next = unsafe { bindings::rb_first_postorder(&self.root) };
+
+        // INVARIANT: The loop invariant is that all tree nodes from `next` in postorder are valid.
+        while !next.is_null() {
+            let this = crate::container_of!(next, Node<K, V>, links);
+
+            // Find out what the next node is before disposing of the current one.
+            // SAFETY: `next` and all nodes in postorder are still valid.
+            next = unsafe { bindings::rb_next_postorder(next) };
+
+            // INVARIANT: This is the destructor, so we break the type invariant during clean-up,
+            // but it is not observable. The loop invariant is still maintained.
+            // SAFETY: `this` is valid per the loop invariant.
+            unsafe { Box::from_raw(this as *mut Node<K, V>) };
+        }
+    }
+}
+
+impl<'a, K, V> IntoIterator for &'a RBTree<K, V> {
+    type Item = (&'a K, &'a V);
+    type IntoIter = RBTreeIterator<'a, K, V>;
+
+    fn into_iter(self) -> Self::IntoIter {
+        self.iter()
+    }
+}
+
+/// An iterator over the nodes of a [`RBTree`].
+///
+/// Instances are created by calling [`RBTree::iter`].
+pub struct RBTreeIterator<'a, K, V> {
+    _tree: PhantomData<&'a RBTree<K, V>>,
+    next: *mut bindings::rb_node,
+}
+
+impl<'a, K, V> Iterator for RBTreeIterator<'a, K, V> {
+    type Item = (&'a K, &'a V);
+
+    fn next(&mut self) -> Option<Self::Item> {
+        if self.next.is_null() {
+            return None;
+        }
+
+        let cur = crate::container_of!(self.next, Node<K, V>, links);
+
+        // SAFETY: The reference to the tree used to create the iterator outlives the iterator, so
+        // the tree cannot change. By the tree invariant, all nodes are valid.
+        self.next = unsafe { bindings::rb_next(self.next) };
+
+        // SAFETY: By the same reasoning above, it is safe to dereference the node. Additionally,
+        // it is ok to return a reference to members because the iterator must outlive it.
+        Some(unsafe { (&(*cur).key, &(*cur).value) })
+    }
+}
+
+impl<'a, K, V> IntoIterator for &'a mut RBTree<K, V> {
+    type Item = (&'a K, &'a mut V);
+    type IntoIter = RBTreeIteratorMut<'a, K, V>;
+
+    fn into_iter(self) -> Self::IntoIter {
+        self.iter_mut()
+    }
+}
+
+/// A mutable iterator over the nodes of a [`RBTree`].
+///
+/// Instances are created by calling [`RBTree::iter_mut`].
+pub struct RBTreeIteratorMut<'a, K, V> {
+    _tree: PhantomData<&'a RBTree<K, V>>,
+    next: *mut bindings::rb_node,
+}
+
+impl<'a, K, V> Iterator for RBTreeIteratorMut<'a, K, V> {
+    type Item = (&'a K, &'a mut V);
+
+    fn next(&mut self) -> Option<Self::Item> {
+        if self.next.is_null() {
+            return None;
+        }
+
+        let cur = crate::container_of!(self.next, Node<K, V>, links) as *mut Node<K, V>;
+
+        // SAFETY: The reference to the tree used to create the iterator outlives the iterator, so
+        // the tree cannot change (except for the value of previous nodes, but those don't affect
+        // the iteration process). By the tree invariant, all nodes are valid.
+        self.next = unsafe { bindings::rb_next(self.next) };
+
+        // SAFETY: By the same reasoning above, it is safe to dereference the node. Additionally,
+        // it is ok to return a reference to members because the iterator must outlive it.
+        Some(unsafe { (&(*cur).key, &mut (*cur).value) })
+    }
+}
+
+/// A memory reservation for a red-black tree node.
+///
+/// It contains the memory needed to hold a node that can be inserted into a red-black tree. One
+/// can be obtained by directly allocating it ([`RBTree::try_reserve_node`]) or by "uninitialising"
+/// ([`RBTreeNode::into_reservation`]) an actual node (usually returned by some operation like
+/// removal from a tree).
+pub struct RBTreeNodeReservation<K, V> {
+    node: Box<MaybeUninit<Node<K, V>>>,
+}
+
+impl<K, V> RBTreeNodeReservation<K, V> {
+    /// Initialises a node reservation.
+    ///
+    /// It then becomes an [`RBTreeNode`] that can be inserted into a tree.
+    pub fn into_node(mut self, key: K, value: V) -> RBTreeNode<K, V> {
+        let node_ptr = self.node.as_mut_ptr();
+        // SAFETY: `node_ptr` is valid, and so are its fields.
+        unsafe { addr_of_mut!((*node_ptr).links).write(bindings::rb_node::default()) };
+        // SAFETY: `node_ptr` is valid, and so are its fields.
+        unsafe { addr_of_mut!((*node_ptr).key).write(key) };
+        // SAFETY: `node_ptr` is valid, and so are its fields.
+        unsafe { addr_of_mut!((*node_ptr).value).write(value) };
+        let raw = Box::into_raw(self.node);
+        RBTreeNode {
+            // SAFETY: The pointer came from a `MaybeUninit<Node>` whose fields have all been
+            // initialised. Additionally, it has the same layout as `Node`.
+            node: unsafe { Box::from_raw(raw as _) },
+        }
+    }
+}
+
+/// A red-black tree node.
+///
+/// The node is fully initialised (with key and value) and can be inserted into a tree without any
+/// extra allocations or failure paths.
+pub struct RBTreeNode<K, V> {
+    node: Box<Node<K, V>>,
+}
+
+impl<K, V> RBTreeNode<K, V> {
+    /// "Uninitialises" a node.
+    ///
+    /// It then becomes a reservation that can be re-initialised into a different node (i.e., with
+    /// a different key and/or value).
+    ///
+    /// The existing key and value are dropped in-place as part of this operation, that is, memory
+    /// may be freed (but only for the key/value; memory for the node itself is kept for reuse).
+    pub fn into_reservation(self) -> RBTreeNodeReservation<K, V> {
+        let raw = Box::into_raw(self.node);
+        let mut ret = RBTreeNodeReservation {
+            // SAFETY: The pointer came from a valid `Node`, which has the same layout as
+            // `MaybeUninit<Node>`.
+            node: unsafe { Box::from_raw(raw as _) },
+        };
+        // SAFETY: Although the type is `MaybeUninit<Node>`, we know it has been initialised
+        // because it came from a `Node`. So it is safe to drop it.
+        unsafe { core::ptr::drop_in_place(ret.node.as_mut_ptr()) };
+        ret
+    }
+}
diff --git a/rust/kernel/revocable.rs b/rust/kernel/revocable.rs
new file mode 100644
index 000000000000..cc49ccaa7a6d
--- /dev/null
+++ b/rust/kernel/revocable.rs
@@ -0,0 +1,161 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Revocable objects.
+//!
+//! The [`Revocable`] type wraps other types and allows access to them to be revoked. The existence
+//! of a [`RevocableGuard`] ensures that objects remain valid.
+
+use crate::bindings;
+use core::{
+    cell::UnsafeCell,
+    marker::PhantomData,
+    mem::ManuallyDrop,
+    ops::Deref,
+    ptr::drop_in_place,
+    sync::atomic::{AtomicBool, Ordering},
+};
+
+/// An object that can become inaccessible at runtime.
+///
+/// Once access is revoked and all concurrent users complete (i.e., all existing instances of
+/// [`RevocableGuard`] are dropped), the wrapped object is also dropped.
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::revocable::Revocable;
+///
+/// struct Example {
+///     a: u32,
+///     b: u32,
+/// }
+///
+/// fn add_two(v: &Revocable<Example>) -> Option<u32> {
+///     let guard = v.try_access()?;
+///     Some(guard.a + guard.b)
+/// }
+///
+/// let v = Revocable::new(Example { a: 10, b: 20 });
+/// assert_eq!(add_two(&v), Some(30));
+/// v.revoke();
+/// assert_eq!(add_two(&v), None);
+/// ```
+pub struct Revocable<T: ?Sized> {
+    is_available: AtomicBool,
+    data: ManuallyDrop<UnsafeCell<T>>,
+}
+
+// SAFETY: `Revocable` is `Send` if the wrapped object is also `Send`. This is because while the
+// functionality exposed by `Revocable` can be accessed from any thread/CPU, it is possible that
+// this isn't supported by the wrapped object.
+unsafe impl<T: ?Sized + Send> Send for Revocable<T> {}
+
+// SAFETY: `Revocable` is `Sync` if the wrapped object is both `Send` and `Sync`. We require `Send`
+// from the wrapped object as well because  of `Revocable::revoke`, which can trigger the `Drop`
+// implementation of the wrapped object from an arbitrary thread.
+unsafe impl<T: ?Sized + Sync + Send> Sync for Revocable<T> {}
+
+impl<T> Revocable<T> {
+    /// Creates a new revocable instance of the given data.
+    pub fn new(data: T) -> Self {
+        Self {
+            is_available: AtomicBool::new(true),
+            data: ManuallyDrop::new(UnsafeCell::new(data)),
+        }
+    }
+}
+
+impl<T: ?Sized> Revocable<T> {
+    /// Tries to access the \[revocable\] wrapped object.
+    ///
+    /// Returns `None` if the object has been revoked and is therefore no longer accessible.
+    ///
+    /// Returns a guard that gives access to the object otherwise; the object is guaranteed to
+    /// remain accessible while the guard is alive. In such cases, callers are not allowed to sleep
+    /// because another CPU may be waiting to complete the revocation of this object.
+    pub fn try_access(&self) -> Option<RevocableGuard<'_, T>> {
+        let guard = RevocableGuard::new(self.data.get());
+        if self.is_available.load(Ordering::Relaxed) {
+            Some(guard)
+        } else {
+            None
+        }
+    }
+
+    /// Revokes access to and drops the wrapped object.
+    ///
+    /// Access to the object is revoked immediately to new callers of [`Revocable::try_access`]. If
+    /// there are concurrent users of the object (i.e., ones that called [`Revocable::try_access`]
+    /// beforehand and still haven't dropped the returned guard), this function waits for the
+    /// concurrent access to complete before dropping the wrapped object.
+    pub fn revoke(&self) {
+        if self
+            .is_available
+            .compare_exchange(true, false, Ordering::Relaxed, Ordering::Relaxed)
+            .is_ok()
+        {
+            // SAFETY: Just an FFI call, there are no further requirements.
+            unsafe { bindings::synchronize_rcu() };
+
+            // SAFETY: We know `self.data` is valid because only one CPU can succeed the
+            // `compare_exchange` above that takes `is_available` from `true` to `false`.
+            unsafe { drop_in_place(self.data.get()) };
+        }
+    }
+}
+
+impl<T: ?Sized> Drop for Revocable<T> {
+    fn drop(&mut self) {
+        // Drop only if the data hasn't been revoked yet (in which case it has already been
+        // dropped).
+        if *self.is_available.get_mut() {
+            // SAFETY: We know `self.data` is valid because no other CPU has changed
+            // `is_available` to `false` yet, and no other CPU can do it anymore because this CPU
+            // holds the only reference (mutable) to `self` now.
+            unsafe { drop_in_place(self.data.get()) };
+        }
+    }
+}
+
+/// A guard that allows access to a revocable object and keeps it alive.
+///
+/// CPUs may not sleep while holding on to [`RevocableGuard`] because it's in atomic context
+/// holding the RCU read-side lock.
+///
+/// # Invariants
+///
+/// The RCU read-side lock is held while the guard is alive.
+pub struct RevocableGuard<'a, T: ?Sized> {
+    data_ref: *const T,
+    _p: PhantomData<&'a ()>,
+}
+
+impl<T: ?Sized> RevocableGuard<'_, T> {
+    fn new(data_ref: *const T) -> Self {
+        // SAFETY: Just an FFI call, there are no further requirements.
+        unsafe { bindings::rcu_read_lock() };
+
+        // INVARIANTS: The RCU read-side lock was just acquired.
+        Self {
+            data_ref,
+            _p: PhantomData,
+        }
+    }
+}
+
+impl<T: ?Sized> Drop for RevocableGuard<'_, T> {
+    fn drop(&mut self) {
+        // SAFETY: By the type invariants, we know that we hold the RCU read-side lock.
+        unsafe { bindings::rcu_read_unlock() };
+    }
+}
+
+impl<T: ?Sized> Deref for RevocableGuard<'_, T> {
+    type Target = T;
+
+    fn deref(&self) -> &Self::Target {
+        // SAFETY: By the type invariants, we hold the rcu read-side lock, so the object is
+        // guaranteed to remain valid.
+        unsafe { &*self.data_ref }
+    }
+}
diff --git a/rust/kernel/security.rs b/rust/kernel/security.rs
new file mode 100644
index 000000000000..eecf6dbf7851
--- /dev/null
+++ b/rust/kernel/security.rs
@@ -0,0 +1,38 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Linux Security Modules (LSM).
+//!
+//! C header: [`include/linux/security.h`](../../../../include/linux/security.h).
+
+use crate::{bindings, cred::Credential, file::File, to_result, Result};
+
+/// Calls the security modules to determine if the given task can become the manager of a binder
+/// context.
+pub fn binder_set_context_mgr(mgr: &Credential) -> Result {
+    // SAFETY: `mrg.0` is valid because the shared reference guarantees a nonzero refcount.
+    to_result(|| unsafe { bindings::security_binder_set_context_mgr(mgr.0.get()) })
+}
+
+/// Calls the security modules to determine if binder transactions are allowed from task `from` to
+/// task `to`.
+pub fn binder_transaction(from: &Credential, to: &Credential) -> Result {
+    // SAFETY: `from` and `to` are valid because the shared references guarantee nonzero refcounts.
+    to_result(|| unsafe { bindings::security_binder_transaction(from.0.get(), to.0.get()) })
+}
+
+/// Calls the security modules to determine if task `from` is allowed to send binder objects
+/// (owned by itself or other processes) to task `to` through a binder transaction.
+pub fn binder_transfer_binder(from: &Credential, to: &Credential) -> Result {
+    // SAFETY: `from` and `to` are valid because the shared references guarantee nonzero refcounts.
+    to_result(|| unsafe { bindings::security_binder_transfer_binder(from.0.get(), to.0.get()) })
+}
+
+/// Calls the security modules to determine if task `from` is allowed to send the given file to
+/// task `to` (which would get its own file descriptor) through a binder transaction.
+pub fn binder_transfer_file(from: &Credential, to: &Credential, file: &File) -> Result {
+    // SAFETY: `from`, `to` and `file` are valid because the shared references guarantee nonzero
+    // refcounts.
+    to_result(|| unsafe {
+        bindings::security_binder_transfer_file(from.0.get(), to.0.get(), file.0.get())
+    })
+}
diff --git a/rust/kernel/static_assert.rs b/rust/kernel/static_assert.rs
new file mode 100644
index 000000000000..c4424218b0ce
--- /dev/null
+++ b/rust/kernel/static_assert.rs
@@ -0,0 +1,38 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Static assert.
+
+/// Static assert (i.e. compile-time assert).
+///
+/// Similar to C11 [`_Static_assert`] and C++11 [`static_assert`].
+///
+/// The feature may be added to Rust in the future: see [RFC 2790].
+///
+/// [`_Static_assert`]: https://en.cppreference.com/w/c/language/_Static_assert
+/// [`static_assert`]: https://en.cppreference.com/w/cpp/language/static_assert
+/// [RFC 2790]: https://github.com/rust-lang/rfcs/issues/2790
+///
+/// # Examples
+///
+/// ```
+/// static_assert!(42 > 24);
+/// static_assert!(core::mem::size_of::<u8>() == 1);
+///
+/// const X: &[u8] = b"bar";
+/// static_assert!(X[1] == b'a');
+///
+/// const fn f(x: i32) -> i32 {
+///     x + 2
+/// }
+/// static_assert!(f(40) == 42);
+/// ```
+#[macro_export]
+macro_rules! static_assert {
+    ($condition:expr) => {
+        // Based on the latest one in `rustc`'s one before it was [removed].
+        //
+        // [removed]: https://github.com/rust-lang/rust/commit/c2dad1c6b9f9636198d7c561b47a2974f5103f6d
+        #[allow(dead_code)]
+        const _: () = [()][!($condition) as usize];
+    };
+}
diff --git a/rust/kernel/std_vendor.rs b/rust/kernel/std_vendor.rs
new file mode 100644
index 000000000000..d64f30ce78dc
--- /dev/null
+++ b/rust/kernel/std_vendor.rs
@@ -0,0 +1,160 @@
+// SPDX-License-Identifier: Apache-2.0 OR MIT
+
+//! The contents of this file come from the Rust standard library, hosted in the
+//! <https://github.com/rust-lang/rust> repository. For copyright details, see
+//! <https://github.com/rust-lang/rust/blob/master/COPYRIGHT>.
+
+/// [`std::dbg`], but using [`pr_info`] instead of [`eprintln`].
+///
+/// Prints and returns the value of a given expression for quick and dirty
+/// debugging.
+///
+/// An example:
+///
+/// ```rust
+/// let a = 2;
+/// # #[allow(clippy::dbg_macro)]
+/// let b = dbg!(a * 2) + 1;
+/// //      ^-- prints: [src/main.rs:2] a * 2 = 4
+/// assert_eq!(b, 5);
+/// ```
+///
+/// The macro works by using the `Debug` implementation of the type of
+/// the given expression to print the value with [`printk`] along with the
+/// source location of the macro invocation as well as the source code
+/// of the expression.
+///
+/// Invoking the macro on an expression moves and takes ownership of it
+/// before returning the evaluated expression unchanged. If the type
+/// of the expression does not implement `Copy` and you don't want
+/// to give up ownership, you can instead borrow with `dbg!(&expr)`
+/// for some expression `expr`.
+///
+/// The `dbg!` macro works exactly the same in release builds.
+/// This is useful when debugging issues that only occur in release
+/// builds or when debugging in release mode is significantly faster.
+///
+/// Note that the macro is intended as a debugging tool and therefore you
+/// should avoid having uses of it in version control for long periods
+/// (other than in tests and similar).
+///
+/// # Stability
+///
+/// The exact output printed by this macro should not be relied upon
+/// and is subject to future changes.
+///
+/// # Further examples
+///
+/// With a method call:
+///
+/// ```rust
+/// # #[allow(clippy::dbg_macro)]
+/// fn foo(n: usize) {
+///     if dbg!(n.checked_sub(4)).is_some() {
+///         // ...
+///     }
+/// }
+///
+/// foo(3)
+/// ```
+///
+/// This prints to the kernel log:
+///
+/// ```text,ignore
+/// [src/main.rs:4] n.checked_sub(4) = None
+/// ```
+///
+/// Naive factorial implementation:
+///
+/// ```rust
+/// # #[allow(clippy::dbg_macro)]
+/// # {
+/// fn factorial(n: u32) -> u32 {
+///     if dbg!(n <= 1) {
+///         dbg!(1)
+///     } else {
+///         dbg!(n * factorial(n - 1))
+///     }
+/// }
+///
+/// dbg!(factorial(4));
+/// # }
+/// ```
+///
+/// This prints to the kernel log:
+///
+/// ```text,ignore
+/// [src/main.rs:3] n <= 1 = false
+/// [src/main.rs:3] n <= 1 = false
+/// [src/main.rs:3] n <= 1 = false
+/// [src/main.rs:3] n <= 1 = true
+/// [src/main.rs:4] 1 = 1
+/// [src/main.rs:5] n * factorial(n - 1) = 2
+/// [src/main.rs:5] n * factorial(n - 1) = 6
+/// [src/main.rs:5] n * factorial(n - 1) = 24
+/// [src/main.rs:11] factorial(4) = 24
+/// ```
+///
+/// The `dbg!(..)` macro moves the input:
+///
+// TODO: Could be `compile_fail` when supported.
+/// ```ignore
+/// /// A wrapper around `usize` which importantly is not Copyable.
+/// #[derive(Debug)]
+/// struct NoCopy(usize);
+///
+/// let a = NoCopy(42);
+/// let _ = dbg!(a); // <-- `a` is moved here.
+/// let _ = dbg!(a); // <-- `a` is moved again; error!
+/// ```
+///
+/// You can also use `dbg!()` without a value to just print the
+/// file and line whenever it's reached.
+///
+/// Finally, if you want to `dbg!(..)` multiple values, it will treat them as
+/// a tuple (and return it, too):
+///
+/// ```
+/// # #[allow(clippy::dbg_macro)]
+/// assert_eq!(dbg!(1usize, 2u32), (1, 2));
+/// ```
+///
+/// However, a single argument with a trailing comma will still not be treated
+/// as a tuple, following the convention of ignoring trailing commas in macro
+/// invocations. You can use a 1-tuple directly if you need one:
+///
+/// ```
+/// # #[allow(clippy::dbg_macro)]
+/// # {
+/// assert_eq!(1, dbg!(1u32,)); // trailing comma ignored
+/// assert_eq!((1,), dbg!((1u32,))); // 1-tuple
+/// # }
+/// ```
+///
+/// [`std::dbg`]: https://doc.rust-lang.org/std/macro.dbg.html
+/// [`eprintln`]: https://doc.rust-lang.org/std/macro.eprintln.html
+/// [`printk`]: https://www.kernel.org/doc/html/latest/core-api/printk-basics.html
+#[macro_export]
+macro_rules! dbg {
+    // NOTE: We cannot use `concat!` to make a static string as a format argument
+    // of `pr_info!` because `file!` could contain a `{` or
+    // `$val` expression could be a block (`{ .. }`), in which case the `pr_info!`
+    // will be malformed.
+    () => {
+        $crate::pr_info!("[{}:{}]\n", ::core::file!(), ::core::line!())
+    };
+    ($val:expr $(,)?) => {
+        // Use of `match` here is intentional because it affects the lifetimes
+        // of temporaries - https://stackoverflow.com/a/48732525/1063961
+        match $val {
+            tmp => {
+                $crate::pr_info!("[{}:{}] {} = {:#?}\n",
+                    ::core::file!(), ::core::line!(), ::core::stringify!($val), &tmp);
+                tmp
+            }
+        }
+    };
+    ($($val:expr),+ $(,)?) => {
+        ($($crate::dbg!($val)),+,)
+    };
+}
diff --git a/rust/kernel/str.rs b/rust/kernel/str.rs
new file mode 100644
index 000000000000..1a72e2f0206d
--- /dev/null
+++ b/rust/kernel/str.rs
@@ -0,0 +1,597 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! String representations.
+
+use alloc::vec::Vec;
+use core::fmt::{self, Write};
+use core::ops::{self, Deref, Index};
+
+use crate::{bindings, c_types, error::code::*, Error};
+
+/// Byte string without UTF-8 validity guarantee.
+///
+/// `BStr` is simply an alias to `[u8]`, but has a more evident semantical meaning.
+pub type BStr = [u8];
+
+/// Creates a new [`BStr`] from a string literal.
+///
+/// `b_str!` converts the supplied string literal to byte string, so non-ASCII
+/// characters can be included.
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::b_str;
+/// # use kernel::str::BStr;
+/// const MY_BSTR: &BStr = b_str!("My awesome BStr!");
+/// ```
+#[macro_export]
+macro_rules! b_str {
+    ($str:literal) => {{
+        const S: &'static str = $str;
+        const C: &'static $crate::str::BStr = S.as_bytes();
+        C
+    }};
+}
+
+/// Possible errors when using conversion functions in [`CStr`].
+#[derive(Debug, Clone, Copy)]
+pub enum CStrConvertError {
+    /// Supplied bytes contain an interior `NUL`.
+    InteriorNul,
+
+    /// Supplied bytes are not terminated by `NUL`.
+    NotNulTerminated,
+}
+
+impl From<CStrConvertError> for Error {
+    #[inline]
+    fn from(_: CStrConvertError) -> Error {
+        EINVAL
+    }
+}
+
+/// A string that is guaranteed to have exactly one `NUL` byte, which is at the
+/// end.
+///
+/// Used for interoperability with kernel APIs that take C strings.
+#[repr(transparent)]
+pub struct CStr([u8]);
+
+impl CStr {
+    /// Returns the length of this string excluding `NUL`.
+    #[inline]
+    pub const fn len(&self) -> usize {
+        self.len_with_nul() - 1
+    }
+
+    /// Returns the length of this string with `NUL`.
+    #[inline]
+    pub const fn len_with_nul(&self) -> usize {
+        // SAFETY: This is one of the invariant of `CStr`.
+        // We add a `unreachable_unchecked` here to hint the optimizer that
+        // the value returned from this function is non-zero.
+        if self.0.is_empty() {
+            unsafe { core::hint::unreachable_unchecked() };
+        }
+        self.0.len()
+    }
+
+    /// Returns `true` if the string only includes `NUL`.
+    #[inline]
+    pub const fn is_empty(&self) -> bool {
+        self.len() == 0
+    }
+
+    /// Wraps a raw C string pointer.
+    ///
+    /// # Safety
+    ///
+    /// `ptr` must be a valid pointer to a `NUL`-terminated C string, and it must
+    /// last at least `'a`. When `CStr` is alive, the memory pointed by `ptr`
+    /// must not be mutated.
+    #[inline]
+    pub unsafe fn from_char_ptr<'a>(ptr: *const c_types::c_char) -> &'a Self {
+        // SAFETY: The safety precondition guarantees `ptr` is a valid pointer
+        // to a `NUL`-terminated C string.
+        let len = unsafe { bindings::strlen(ptr) } + 1;
+        // SAFETY: Lifetime guaranteed by the safety precondition.
+        let bytes = unsafe { core::slice::from_raw_parts(ptr as _, len as _) };
+        // SAFETY: As `len` is returned by `strlen`, `bytes` does not contain interior `NUL`.
+        // As we have added 1 to `len`, the last byte is known to be `NUL`.
+        unsafe { Self::from_bytes_with_nul_unchecked(bytes) }
+    }
+
+    /// Creates a [`CStr`] from a `[u8]`.
+    ///
+    /// The provided slice must be `NUL`-terminated, does not contain any
+    /// interior `NUL` bytes.
+    pub const fn from_bytes_with_nul(bytes: &[u8]) -> Result<&Self, CStrConvertError> {
+        if bytes.is_empty() {
+            return Err(CStrConvertError::NotNulTerminated);
+        }
+        if bytes[bytes.len() - 1] != 0 {
+            return Err(CStrConvertError::NotNulTerminated);
+        }
+        let mut i = 0;
+        // `i + 1 < bytes.len()` allows LLVM to optimize away bounds checking,
+        // while it couldn't optimize away bounds checks for `i < bytes.len() - 1`.
+        while i + 1 < bytes.len() {
+            if bytes[i] == 0 {
+                return Err(CStrConvertError::InteriorNul);
+            }
+            i += 1;
+        }
+        // SAFETY: We just checked that all properties hold.
+        Ok(unsafe { Self::from_bytes_with_nul_unchecked(bytes) })
+    }
+
+    /// Creates a [`CStr`] from a `[u8]`, panic if input is not valid.
+    ///
+    /// This function is only meant to be used by `c_str!` macro, so
+    /// crates using `c_str!` macro don't have to enable `const_panic` feature.
+    #[doc(hidden)]
+    pub const fn from_bytes_with_nul_unwrap(bytes: &[u8]) -> &Self {
+        match Self::from_bytes_with_nul(bytes) {
+            Ok(v) => v,
+            Err(_) => panic!("string contains interior NUL"),
+        }
+    }
+
+    /// Creates a [`CStr`] from a `[u8]` without performing any additional
+    /// checks.
+    ///
+    /// # Safety
+    ///
+    /// `bytes` *must* end with a `NUL` byte, and should only have a single
+    /// `NUL` byte (or the string will be truncated).
+    #[inline]
+    pub const unsafe fn from_bytes_with_nul_unchecked(bytes: &[u8]) -> &CStr {
+        // SAFETY: Properties of `bytes` guaranteed by the safety precondition.
+        unsafe { core::mem::transmute(bytes) }
+    }
+
+    /// Returns a C pointer to the string.
+    #[inline]
+    pub const fn as_char_ptr(&self) -> *const c_types::c_char {
+        self.0.as_ptr() as _
+    }
+
+    /// Convert the string to a byte slice without the trailing 0 byte.
+    #[inline]
+    pub fn as_bytes(&self) -> &[u8] {
+        &self.0[..self.len()]
+    }
+
+    /// Convert the string to a byte slice containing the trailing 0 byte.
+    #[inline]
+    pub const fn as_bytes_with_nul(&self) -> &[u8] {
+        &self.0
+    }
+
+    /// Yields a [`&str`] slice if the [`CStr`] contains valid UTF-8.
+    ///
+    /// If the contents of the [`CStr`] are valid UTF-8 data, this
+    /// function will return the corresponding [`&str`] slice. Otherwise,
+    /// it will return an error with details of where UTF-8 validation failed.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # use kernel::str::CStr;
+    /// let cstr = CStr::from_bytes_with_nul(b"foo\0").unwrap();
+    /// assert_eq!(cstr.to_str(), Ok("foo"));
+    /// ```
+    #[inline]
+    pub fn to_str(&self) -> Result<&str, core::str::Utf8Error> {
+        core::str::from_utf8(self.as_bytes())
+    }
+
+    /// Unsafely convert this [`CStr`] into a [`&str`], without checking for
+    /// valid UTF-8.
+    ///
+    /// # Safety
+    ///
+    /// The contents must be valid UTF-8.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # use kernel::c_str;
+    /// # use kernel::str::CStr;
+    /// // SAFETY: String literals are guaranteed to be valid UTF-8
+    /// // by the Rust compiler.
+    /// let bar = c_str!("ツ");
+    /// assert_eq!(unsafe { bar.as_str_unchecked() }, "ツ");
+    /// ```
+    #[inline]
+    pub unsafe fn as_str_unchecked(&self) -> &str {
+        unsafe { core::str::from_utf8_unchecked(self.as_bytes()) }
+    }
+}
+
+impl fmt::Display for CStr {
+    /// Formats printable ASCII characters, escaping the rest.
+    ///
+    /// ```
+    /// # use kernel::c_str;
+    /// # use kernel::str::CStr;
+    /// # use kernel::str::CString;
+    /// let penguin = c_str!("🐧");
+    /// let s = CString::try_from_fmt(fmt!("{}", penguin)).unwrap();
+    /// assert_eq!(s.as_bytes_with_nul(), "\\xf0\\x9f\\x90\\xa7\0".as_bytes());
+    ///
+    /// let ascii = c_str!("so \"cool\"");
+    /// let s = CString::try_from_fmt(fmt!("{}", ascii)).unwrap();
+    /// assert_eq!(s.as_bytes_with_nul(), "so \"cool\"\0".as_bytes());
+    /// ```
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        for &c in self.as_bytes() {
+            if (0x20..0x7f).contains(&c) {
+                // Printable character
+                f.write_char(c as char)?;
+            } else {
+                write!(f, "\\x{:02x}", c)?;
+            }
+        }
+        Ok(())
+    }
+}
+
+impl fmt::Debug for CStr {
+    /// Formats printable ASCII characters with a double quote on either end, escaping the rest.
+    ///
+    /// ```
+    /// # use kernel::c_str;
+    /// # use kernel::str::CStr;
+    /// # use kernel::str::CString;
+    /// let penguin = c_str!("🐧");
+    /// let s = CString::try_from_fmt(fmt!("{:?}", penguin)).unwrap();
+    /// assert_eq!(s.as_bytes_with_nul(), "\"\\xf0\\x9f\\x90\\xa7\"\0".as_bytes());
+    ///
+    /// // Embedded double quotes are escaped.
+    /// let ascii = c_str!("so \"cool\"");
+    /// let s = CString::try_from_fmt(fmt!("{:?}", ascii)).unwrap();
+    /// assert_eq!(s.as_bytes_with_nul(), "\"so \\\"cool\\\"\"\0".as_bytes());
+    /// ```
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.write_str("\"")?;
+        for &c in self.as_bytes() {
+            match c {
+                // Printable characters
+                b'\"' => f.write_str("\\\"")?,
+                0x20..=0x7e => f.write_char(c as char)?,
+                _ => write!(f, "\\x{:02x}", c)?,
+            }
+        }
+        f.write_str("\"")
+    }
+}
+
+impl AsRef<BStr> for CStr {
+    #[inline]
+    fn as_ref(&self) -> &BStr {
+        self.as_bytes()
+    }
+}
+
+impl Deref for CStr {
+    type Target = BStr;
+
+    #[inline]
+    fn deref(&self) -> &Self::Target {
+        self.as_bytes()
+    }
+}
+
+impl Index<ops::RangeFrom<usize>> for CStr {
+    type Output = CStr;
+
+    #[inline]
+    fn index(&self, index: ops::RangeFrom<usize>) -> &Self::Output {
+        // Delegate bounds checking to slice.
+        // Assign to _ to mute clippy's unnecessary operation warning.
+        let _ = &self.as_bytes()[index.start..];
+        // SAFETY: We just checked the bounds.
+        unsafe { Self::from_bytes_with_nul_unchecked(&self.0[index.start..]) }
+    }
+}
+
+impl Index<ops::RangeFull> for CStr {
+    type Output = CStr;
+
+    #[inline]
+    fn index(&self, _index: ops::RangeFull) -> &Self::Output {
+        self
+    }
+}
+
+mod private {
+    use core::ops;
+
+    // Marker trait for index types that can be forward to `BStr`.
+    pub trait CStrIndex {}
+
+    impl CStrIndex for usize {}
+    impl CStrIndex for ops::Range<usize> {}
+    impl CStrIndex for ops::RangeInclusive<usize> {}
+    impl CStrIndex for ops::RangeToInclusive<usize> {}
+}
+
+impl<Idx> Index<Idx> for CStr
+where
+    Idx: private::CStrIndex,
+    BStr: Index<Idx>,
+{
+    type Output = <BStr as Index<Idx>>::Output;
+
+    #[inline]
+    fn index(&self, index: Idx) -> &Self::Output {
+        &self.as_bytes()[index]
+    }
+}
+
+/// Creates a new [`CStr`] from a string literal.
+///
+/// The string literal should not contain any `NUL` bytes.
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::c_str;
+/// # use kernel::str::CStr;
+/// const MY_CSTR: &CStr = c_str!("My awesome CStr!");
+/// ```
+#[macro_export]
+macro_rules! c_str {
+    ($str:expr) => {{
+        const S: &str = concat!($str, "\0");
+        const C: &$crate::str::CStr = $crate::str::CStr::from_bytes_with_nul_unwrap(S.as_bytes());
+        C
+    }};
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn test_cstr_to_str() {
+        let good_bytes = b"\xf0\x9f\xa6\x80\0";
+        let checked_cstr = CStr::from_bytes_with_nul(good_bytes).unwrap();
+        let checked_str = checked_cstr.to_str().unwrap();
+        assert_eq!(checked_str, "🦀");
+    }
+
+    #[test]
+    #[should_panic]
+    fn test_cstr_to_str_panic() {
+        let bad_bytes = b"\xc3\x28\0";
+        let checked_cstr = CStr::from_bytes_with_nul(bad_bytes).unwrap();
+        checked_cstr.to_str().unwrap();
+    }
+
+    #[test]
+    fn test_cstr_as_str_unchecked() {
+        let good_bytes = b"\xf0\x9f\x90\xA7\0";
+        let checked_cstr = CStr::from_bytes_with_nul(good_bytes).unwrap();
+        let unchecked_str = unsafe { checked_cstr.as_str_unchecked() };
+        assert_eq!(unchecked_str, "🐧");
+    }
+}
+
+/// Allows formatting of [`fmt::Arguments`] into a raw buffer.
+///
+/// It does not fail if callers write past the end of the buffer so that they can calculate the
+/// size required to fit everything.
+///
+/// # Invariants
+///
+/// The memory region between `pos` (inclusive) and `end` (exclusive) is valid for writes if `pos`
+/// is less than `end`.
+pub(crate) struct RawFormatter {
+    // Use `usize` to use `saturating_*` functions.
+    beg: usize,
+    pos: usize,
+    end: usize,
+}
+
+impl RawFormatter {
+    /// Creates a new instance of [`RawFormatter`] with an empty buffer.
+    fn new() -> Self {
+        // INVARIANT: The buffer is empty, so the region that needs to be writable is empty.
+        Self {
+            beg: 0,
+            pos: 0,
+            end: 0,
+        }
+    }
+
+    /// Creates a new instance of [`RawFormatter`] with the given buffer pointers.
+    ///
+    /// # Safety
+    ///
+    /// If `pos` is less than `end`, then the region between `pos` (inclusive) and `end`
+    /// (exclusive) must be valid for writes for the lifetime of the returned [`RawFormatter`].
+    pub(crate) unsafe fn from_ptrs(pos: *mut u8, end: *mut u8) -> Self {
+        // INVARIANT: The safety requierments guarantee the type invariants.
+        Self {
+            beg: pos as _,
+            pos: pos as _,
+            end: end as _,
+        }
+    }
+
+    /// Creates a new instance of [`RawFormatter`] with the given buffer.
+    ///
+    /// # Safety
+    ///
+    /// The memory region starting at `buf` and extending for `len` bytes must be valid for writes
+    /// for the lifetime of the returned [`RawFormatter`].
+    pub(crate) unsafe fn from_buffer(buf: *mut u8, len: usize) -> Self {
+        let pos = buf as usize;
+        // INVARIANT: We ensure that `end` is never less then `buf`, and the safety requirements
+        // guarantees that the memory region is valid for writes.
+        Self {
+            pos,
+            beg: pos,
+            end: pos.saturating_add(len),
+        }
+    }
+
+    /// Returns the current insert position.
+    ///
+    /// N.B. It may point to invalid memory.
+    pub(crate) fn pos(&self) -> *mut u8 {
+        self.pos as _
+    }
+
+    /// Return the number of bytes written to the formatter.
+    pub(crate) fn bytes_written(&self) -> usize {
+        self.pos - self.beg
+    }
+}
+
+impl fmt::Write for RawFormatter {
+    fn write_str(&mut self, s: &str) -> fmt::Result {
+        // `pos` value after writing `len` bytes. This does not have to be bounded by `end`, but we
+        // don't want it to wrap around to 0.
+        let pos_new = self.pos.saturating_add(s.len());
+
+        // Amount that we can copy. `saturating_sub` ensures we get 0 if `pos` goes past `end`.
+        let len_to_copy = core::cmp::min(pos_new, self.end).saturating_sub(self.pos);
+
+        if len_to_copy > 0 {
+            // SAFETY: If `len_to_copy` is non-zero, then we know `pos` has not gone past `end`
+            // yet, so it is valid for write per the type invariants.
+            unsafe {
+                core::ptr::copy_nonoverlapping(
+                    s.as_bytes().as_ptr(),
+                    self.pos as *mut u8,
+                    len_to_copy,
+                )
+            };
+        }
+
+        self.pos = pos_new;
+        Ok(())
+    }
+}
+
+/// Allows formatting of [`fmt::Arguments`] into a raw buffer.
+///
+/// Fails if callers attempt to write more than will fit in the buffer.
+pub(crate) struct Formatter(RawFormatter);
+
+impl Formatter {
+    /// Creates a new instance of [`Formatter`] with the given buffer.
+    ///
+    /// # Safety
+    ///
+    /// The memory region starting at `buf` and extending for `len` bytes must be valid for writes
+    /// for the lifetime of the returned [`Formatter`].
+    pub(crate) unsafe fn from_buffer(buf: *mut u8, len: usize) -> Self {
+        // SAFETY: The safety requirements of this function satisfy those of the callee.
+        Self(unsafe { RawFormatter::from_buffer(buf, len) })
+    }
+}
+
+impl Deref for Formatter {
+    type Target = RawFormatter;
+
+    fn deref(&self) -> &Self::Target {
+        &self.0
+    }
+}
+
+impl fmt::Write for Formatter {
+    fn write_str(&mut self, s: &str) -> fmt::Result {
+        self.0.write_str(s)?;
+
+        // Fail the request if we go past the end of the buffer.
+        if self.0.pos > self.0.end {
+            Err(fmt::Error)
+        } else {
+            Ok(())
+        }
+    }
+}
+
+/// An owned string that is guaranteed to have exactly one `NUL` byte, which is at the end.
+///
+/// Used for interoperability with kernel APIs that take C strings.
+///
+/// # Invariants
+///
+/// The string is always `NUL`-terminated and contains no other `NUL` bytes.
+///
+/// # Examples
+///
+/// ```
+/// use kernel::str::CString;
+///
+/// let s = CString::try_from_fmt(fmt!("{}{}{}", "abc", 10, 20)).unwrap();
+/// assert_eq!(s.as_bytes_with_nul(), "abc1020\0".as_bytes());
+///
+/// let tmp = "testing";
+/// let s = CString::try_from_fmt(fmt!("{tmp}{}", 123)).unwrap();
+/// assert_eq!(s.as_bytes_with_nul(), "testing123\0".as_bytes());
+///
+/// // This fails because it has an embedded `NUL` byte.
+/// let s = CString::try_from_fmt(fmt!("a\0b{}", 123));
+/// assert_eq!(s.is_ok(), false);
+/// ```
+pub struct CString {
+    buf: Vec<u8>,
+}
+
+impl CString {
+    /// Creates an instance of [`CString`] from the given formatted arguments.
+    pub fn try_from_fmt(args: fmt::Arguments<'_>) -> Result<Self, Error> {
+        // Calculate the size needed (formatted string plus `NUL` terminator).
+        let mut f = RawFormatter::new();
+        f.write_fmt(args)?;
+        f.write_str("\0")?;
+        let size = f.bytes_written();
+
+        // Allocate a vector with the required number of bytes, and write to it.
+        let mut buf = Vec::try_with_capacity(size)?;
+        // SAFETY: The buffer stored in `buf` is at least of size `size` and is valid for writes.
+        let mut f = unsafe { Formatter::from_buffer(buf.as_mut_ptr(), size) };
+        f.write_fmt(args)?;
+        f.write_str("\0")?;
+
+        // SAFETY: The number of bytes that can be written to `f` is bounded by `size`, which is
+        // `buf`'s capacity. The contents of the buffer have been initialised by writes to `f`.
+        unsafe { buf.set_len(f.bytes_written()) };
+
+        // Check that there are no `NUL` bytes before the end.
+        // SAFETY: The buffer is valid for read because `f.bytes_written()` is bounded by `size`
+        // (which the minimum buffer size) and is non-zero (we wrote at least the `NUL` terminator)
+        // so `f.bytes_written() - 1` doesn't underflow.
+        let ptr = unsafe { bindings::memchr(buf.as_ptr().cast(), 0, (f.bytes_written() - 1) as _) };
+        if !ptr.is_null() {
+            return Err(EINVAL);
+        }
+
+        // INVARIANT: We wrote the `NUL` terminator and checked above that no other `NUL` bytes
+        // exist in the buffer.
+        Ok(Self { buf })
+    }
+}
+
+impl Deref for CString {
+    type Target = CStr;
+
+    fn deref(&self) -> &Self::Target {
+        // SAFETY: The type invariants guarantee that the string is `NUL`-terminated and that no
+        // other `NUL` bytes exist.
+        unsafe { CStr::from_bytes_with_nul_unchecked(self.buf.as_slice()) }
+    }
+}
+
+/// A convenience alias for [`core::format_args`].
+#[macro_export]
+macro_rules! fmt {
+    ($($f:tt)*) => ( core::format_args!($($f)*) )
+}
diff --git a/rust/kernel/sysctl.rs b/rust/kernel/sysctl.rs
new file mode 100644
index 000000000000..63bf76d03d93
--- /dev/null
+++ b/rust/kernel/sysctl.rs
@@ -0,0 +1,199 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! System control.
+//!
+//! C header: [`include/linux/sysctl.h`](../../../../include/linux/sysctl.h)
+//!
+//! Reference: <https://www.kernel.org/doc/Documentation/sysctl/README>
+
+use alloc::boxed::Box;
+use alloc::vec::Vec;
+use core::mem;
+use core::ptr;
+use core::sync::atomic;
+
+use crate::{
+    bindings, c_types,
+    error::code::*,
+    io_buffer::IoBufferWriter,
+    str::CStr,
+    types,
+    user_ptr::{UserSlicePtr, UserSlicePtrWriter},
+    Result,
+};
+
+/// Sysctl storage.
+pub trait SysctlStorage: Sync {
+    /// Writes a byte slice.
+    fn store_value(&self, data: &[u8]) -> (usize, Result);
+
+    /// Reads via a [`UserSlicePtrWriter`].
+    fn read_value(&self, data: &mut UserSlicePtrWriter) -> (usize, Result);
+}
+
+fn trim_whitespace(mut data: &[u8]) -> &[u8] {
+    while !data.is_empty() && (data[0] == b' ' || data[0] == b'\t' || data[0] == b'\n') {
+        data = &data[1..];
+    }
+    while !data.is_empty()
+        && (data[data.len() - 1] == b' '
+            || data[data.len() - 1] == b'\t'
+            || data[data.len() - 1] == b'\n')
+    {
+        data = &data[..data.len() - 1];
+    }
+    data
+}
+
+impl<T> SysctlStorage for &T
+where
+    T: SysctlStorage,
+{
+    fn store_value(&self, data: &[u8]) -> (usize, Result) {
+        (*self).store_value(data)
+    }
+
+    fn read_value(&self, data: &mut UserSlicePtrWriter) -> (usize, Result) {
+        (*self).read_value(data)
+    }
+}
+
+impl SysctlStorage for atomic::AtomicBool {
+    fn store_value(&self, data: &[u8]) -> (usize, Result) {
+        let result = match trim_whitespace(data) {
+            b"0" => {
+                self.store(false, atomic::Ordering::Relaxed);
+                Ok(())
+            }
+            b"1" => {
+                self.store(true, atomic::Ordering::Relaxed);
+                Ok(())
+            }
+            _ => Err(EINVAL),
+        };
+        (data.len(), result)
+    }
+
+    fn read_value(&self, data: &mut UserSlicePtrWriter) -> (usize, Result) {
+        let value = if self.load(atomic::Ordering::Relaxed) {
+            b"1\n"
+        } else {
+            b"0\n"
+        };
+        (value.len(), data.write_slice(value))
+    }
+}
+
+/// Holds a single `sysctl` entry (and its table).
+pub struct Sysctl<T: SysctlStorage> {
+    inner: Box<T>,
+    // Responsible for keeping the `ctl_table` alive.
+    _table: Box<[bindings::ctl_table]>,
+    header: *mut bindings::ctl_table_header,
+}
+
+// SAFETY: The only public method we have is `get()`, which returns `&T`, and
+// `T: Sync`. Any new methods must adhere to this requirement.
+unsafe impl<T: SysctlStorage> Sync for Sysctl<T> {}
+
+unsafe extern "C" fn proc_handler<T: SysctlStorage>(
+    ctl: *mut bindings::ctl_table,
+    write: c_types::c_int,
+    buffer: *mut c_types::c_void,
+    len: *mut usize,
+    ppos: *mut bindings::loff_t,
+) -> c_types::c_int {
+    // If we are reading from some offset other than the beginning of the file,
+    // return an empty read to signal EOF.
+    if unsafe { *ppos } != 0 && write == 0 {
+        unsafe { *len = 0 };
+        return 0;
+    }
+
+    let data = unsafe { UserSlicePtr::new(buffer, *len) };
+    let storage = unsafe { &*((*ctl).data as *const T) };
+    let (bytes_processed, result) = if write != 0 {
+        let data = match data.read_all() {
+            Ok(r) => r,
+            Err(e) => return e.to_kernel_errno(),
+        };
+        storage.store_value(&data)
+    } else {
+        let mut writer = data.writer();
+        storage.read_value(&mut writer)
+    };
+    unsafe { *len = bytes_processed };
+    unsafe { *ppos += *len as bindings::loff_t };
+    match result {
+        Ok(()) => 0,
+        Err(e) => e.to_kernel_errno(),
+    }
+}
+
+impl<T: SysctlStorage> Sysctl<T> {
+    /// Registers a single entry in `sysctl`.
+    pub fn register(
+        path: &'static CStr,
+        name: &'static CStr,
+        storage: T,
+        mode: types::Mode,
+    ) -> Result<Sysctl<T>> {
+        if name.contains(&b'/') {
+            return Err(EINVAL);
+        }
+
+        let storage = Box::try_new(storage)?;
+        let mut table = Vec::try_with_capacity(2)?;
+        table.try_push(bindings::ctl_table {
+            procname: name.as_char_ptr(),
+            mode: mode.as_int(),
+            data: &*storage as *const T as *mut c_types::c_void,
+            proc_handler: Some(proc_handler::<T>),
+
+            maxlen: 0,
+            child: ptr::null_mut(),
+            poll: ptr::null_mut(),
+            extra1: ptr::null_mut(),
+            extra2: ptr::null_mut(),
+        })?;
+        table.try_push(unsafe { mem::zeroed() })?;
+        let mut table = table.try_into_boxed_slice()?;
+
+        let result = unsafe { bindings::register_sysctl(path.as_char_ptr(), table.as_mut_ptr()) };
+        if result.is_null() {
+            return Err(ENOMEM);
+        }
+
+        Ok(Sysctl {
+            inner: storage,
+            _table: table,
+            header: result,
+        })
+    }
+
+    /// Gets the storage.
+    pub fn get(&self) -> &T {
+        &self.inner
+    }
+}
+
+impl<T: SysctlStorage> Drop for Sysctl<T> {
+    fn drop(&mut self) {
+        unsafe {
+            bindings::unregister_sysctl_table(self.header);
+        }
+        self.header = ptr::null_mut();
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn test_trim_whitespace() {
+        assert_eq!(trim_whitespace(b"foo    "), b"foo");
+        assert_eq!(trim_whitespace(b"    foo"), b"foo");
+        assert_eq!(trim_whitespace(b"  foo  "), b"foo");
+    }
+}
diff --git a/rust/kernel/task.rs b/rust/kernel/task.rs
new file mode 100644
index 000000000000..52dfc8db3d35
--- /dev/null
+++ b/rust/kernel/task.rs
@@ -0,0 +1,175 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Tasks (threads and processes).
+//!
+//! C header: [`include/linux/sched.h`](../../../../include/linux/sched.h).
+
+use crate::bindings;
+use core::{marker::PhantomData, mem::ManuallyDrop, ops::Deref};
+
+/// Wraps the kernel's `struct task_struct`.
+///
+/// # Invariants
+///
+/// The pointer `Task::ptr` is non-null and valid. Its reference count is also non-zero.
+///
+/// # Examples
+///
+/// The following is an example of getting the PID of the current thread with zero additional cost
+/// when compared to the C version:
+///
+/// ```
+/// use kernel::task::Task;
+///
+/// let pid = Task::current().pid();
+/// ```
+///
+/// Getting the PID of the current process, also zero additional cost:
+///
+/// ```
+/// use kernel::task::Task;
+///
+/// let pid = Task::current().group_leader().pid();
+/// ```
+///
+/// Getting the current task and storing it in some struct. The reference count is automatically
+/// incremented when creating `State` and decremented when it is dropped:
+///
+/// ```
+/// use kernel::task::Task;
+///
+/// struct State {
+///     creator: Task,
+///     index: u32,
+/// }
+///
+/// impl State {
+///     fn new() -> Self {
+///         Self {
+///             creator: Task::current().clone(),
+///             index: 0,
+///         }
+///     }
+/// }
+/// ```
+pub struct Task {
+    pub(crate) ptr: *mut bindings::task_struct,
+}
+
+// SAFETY: Given that the task is referenced, it is OK to send it to another thread.
+unsafe impl Send for Task {}
+
+// SAFETY: It's OK to access `Task` through references from other threads because we're either
+// accessing properties that don't change (e.g., `pid`, `group_leader`) or that are properly
+// synchronised by C code (e.g., `signal_pending`).
+unsafe impl Sync for Task {}
+
+/// The type of process identifiers (PIDs).
+type Pid = bindings::pid_t;
+
+impl Task {
+    /// Returns a task reference for the currently executing task/thread.
+    pub fn current<'a>() -> TaskRef<'a> {
+        // SAFETY: Just an FFI call.
+        let ptr = unsafe { bindings::get_current() };
+
+        // SAFETY: If the current thread is still running, the current task is valid. Given
+        // that `TaskRef` is not `Send`, we know it cannot be transferred to another thread (where
+        // it could potentially outlive the caller).
+        unsafe { TaskRef::from_ptr(ptr) }
+    }
+
+    /// Returns the group leader of the given task.
+    pub fn group_leader(&self) -> TaskRef<'_> {
+        // SAFETY: By the type invariant, we know that `self.ptr` is non-null and valid.
+        let ptr = unsafe { (*self.ptr).group_leader };
+
+        // SAFETY: The lifetime of the returned task reference is tied to the lifetime of `self`,
+        // and given that a task has a reference to its group leader, we know it must be valid for
+        // the lifetime of the returned task reference.
+        unsafe { TaskRef::from_ptr(ptr) }
+    }
+
+    /// Returns the PID of the given task.
+    pub fn pid(&self) -> Pid {
+        // SAFETY: By the type invariant, we know that `self.ptr` is non-null and valid.
+        unsafe { (*self.ptr).pid }
+    }
+
+    /// Determines whether the given task has pending signals.
+    pub fn signal_pending(&self) -> bool {
+        // SAFETY: By the type invariant, we know that `self.ptr` is non-null and valid.
+        unsafe { bindings::signal_pending(self.ptr) != 0 }
+    }
+}
+
+impl PartialEq for Task {
+    fn eq(&self, other: &Self) -> bool {
+        self.ptr == other.ptr
+    }
+}
+
+impl Eq for Task {}
+
+impl Clone for Task {
+    fn clone(&self) -> Self {
+        // SAFETY: The type invariants guarantee that `self.ptr` has a non-zero reference count.
+        unsafe { bindings::get_task_struct(self.ptr) };
+
+        // INVARIANT: We incremented the reference count to account for the new `Task` being
+        // created.
+        Self { ptr: self.ptr }
+    }
+}
+
+impl Drop for Task {
+    fn drop(&mut self) {
+        // INVARIANT: We may decrement the refcount to zero, but the `Task` is being dropped, so
+        // this is not observable.
+        // SAFETY: The type invariants guarantee that `Task::ptr` has a non-zero reference count.
+        unsafe { bindings::put_task_struct(self.ptr) };
+    }
+}
+
+/// A wrapper for [`Task`] that doesn't automatically decrement the refcount when dropped.
+///
+/// We need the wrapper because [`ManuallyDrop`] alone would allow callers to call
+/// [`ManuallyDrop::into_inner`]. This would allow an unsafe sequence to be triggered without
+/// `unsafe` blocks because it would trigger an unbalanced call to `put_task_struct`.
+///
+/// We make this explicitly not [`Send`] so that we can use it to represent the current thread
+/// without having to increment/decrement its reference count.
+///
+/// # Invariants
+///
+/// The wrapped [`Task`] remains valid for the lifetime of the object.
+pub struct TaskRef<'a> {
+    task: ManuallyDrop<Task>,
+    _not_send: PhantomData<(&'a (), *mut ())>,
+}
+
+impl TaskRef<'_> {
+    /// Constructs a new `struct task_struct` wrapper that doesn't change its reference count.
+    ///
+    /// # Safety
+    ///
+    /// The pointer `ptr` must be non-null and valid for the lifetime of the object.
+    pub(crate) unsafe fn from_ptr(ptr: *mut bindings::task_struct) -> Self {
+        Self {
+            task: ManuallyDrop::new(Task { ptr }),
+            _not_send: PhantomData,
+        }
+    }
+}
+
+// SAFETY: It is OK to share a reference to the current thread with another thread because we know
+// the owner cannot go away while the shared reference exists (and `Task` itself is `Sync`).
+unsafe impl Sync for TaskRef<'_> {}
+
+impl Deref for TaskRef<'_> {
+    type Target = Task;
+
+    fn deref(&self) -> &Self::Target {
+        self.task.deref()
+    }
+}
diff --git a/rust/kernel/types.rs b/rust/kernel/types.rs
new file mode 100644
index 000000000000..42a83f4390d3
--- /dev/null
+++ b/rust/kernel/types.rs
@@ -0,0 +1,679 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Kernel types.
+//!
+//! C header: [`include/linux/types.h`](../../../../include/linux/types.h)
+
+use crate::{
+    bindings, c_types,
+    sync::{Ref, RefBorrow},
+};
+use alloc::boxed::Box;
+use core::{
+    cell::UnsafeCell,
+    marker::PhantomData,
+    mem::MaybeUninit,
+    ops::{self, Deref, DerefMut},
+    pin::Pin,
+    ptr::NonNull,
+};
+
+/// Permissions.
+///
+/// C header: [`include/uapi/linux/stat.h`](../../../../include/uapi/linux/stat.h)
+///
+/// C header: [`include/linux/stat.h`](../../../../include/linux/stat.h)
+pub struct Mode(bindings::umode_t);
+
+impl Mode {
+    /// Creates a [`Mode`] from an integer.
+    pub fn from_int(m: u16) -> Mode {
+        Mode(m)
+    }
+
+    /// Returns the mode as an integer.
+    pub fn as_int(&self) -> u16 {
+        self.0
+    }
+}
+
+/// Used to convert an object into a raw pointer that represents it.
+///
+/// It can eventually be converted back into the object. This is used to store objects as pointers
+/// in kernel data structures, for example, an implementation of [`FileOperations`] in `struct
+/// file::private_data`.
+pub trait PointerWrapper {
+    /// Type of values borrowed between calls to [`PointerWrapper::into_pointer`] and
+    /// [`PointerWrapper::from_pointer`].
+    type Borrowed<'a>;
+
+    /// Returns the raw pointer.
+    fn into_pointer(self) -> *const c_types::c_void;
+
+    /// Returns a borrowed value.
+    ///
+    /// # Safety
+    ///
+    /// `ptr` must have been returned by a previous call to [`PointerWrapper::into_pointer`].
+    /// Additionally, [`PointerWrapper::from_pointer`] can only be called after *all* values
+    /// returned by [`PointerWrapper::borrow`] have been dropped.
+    unsafe fn borrow<'a>(ptr: *const c_types::c_void) -> Self::Borrowed<'a>;
+
+    /// Returns the instance back from the raw pointer.
+    ///
+    /// # Safety
+    ///
+    /// The passed pointer must come from a previous call to [`PointerWrapper::into_pointer()`].
+    unsafe fn from_pointer(ptr: *const c_types::c_void) -> Self;
+}
+
+impl<T: 'static> PointerWrapper for Box<T> {
+    type Borrowed<'a> = &'a T;
+
+    fn into_pointer(self) -> *const c_types::c_void {
+        Box::into_raw(self) as _
+    }
+
+    unsafe fn borrow<'a>(ptr: *const c_types::c_void) -> &'a T {
+        // SAFETY: The safety requirements for this function ensure that the object is still alive,
+        // so it is safe to dereference the raw pointer.
+        // The safety requirements also ensure that the object remains alive for the lifetime of
+        // the returned value.
+        unsafe { &*ptr.cast() }
+    }
+
+    unsafe fn from_pointer(ptr: *const c_types::c_void) -> Self {
+        // SAFETY: The passed pointer comes from a previous call to [`Self::into_pointer()`].
+        unsafe { Box::from_raw(ptr as _) }
+    }
+}
+
+impl<T: 'static> PointerWrapper for Ref<T> {
+    type Borrowed<'a> = RefBorrow<'a, T>;
+
+    fn into_pointer(self) -> *const c_types::c_void {
+        Ref::into_usize(self) as _
+    }
+
+    unsafe fn borrow<'a>(ptr: *const c_types::c_void) -> RefBorrow<'a, T> {
+        // SAFETY: The safety requirements for this function ensure that the underlying object
+        // remains valid for the lifetime of the returned value.
+        unsafe { Ref::borrow_usize(ptr as _) }
+    }
+
+    unsafe fn from_pointer(ptr: *const c_types::c_void) -> Self {
+        // SAFETY: The passed pointer comes from a previous call to [`Self::into_pointer()`].
+        unsafe { Ref::from_usize(ptr as _) }
+    }
+}
+
+impl<T: PointerWrapper + Deref> PointerWrapper for Pin<T> {
+    type Borrowed<'a> = T::Borrowed<'a>;
+
+    fn into_pointer(self) -> *const c_types::c_void {
+        // SAFETY: We continue to treat the pointer as pinned by returning just a pointer to it to
+        // the caller.
+        let inner = unsafe { Pin::into_inner_unchecked(self) };
+        inner.into_pointer()
+    }
+
+    unsafe fn borrow<'a>(ptr: *const c_types::c_void) -> Self::Borrowed<'a> {
+        // SAFETY: The safety requirements for this function are the same as the ones for
+        // `T::borrow`.
+        unsafe { T::borrow(ptr) }
+    }
+
+    unsafe fn from_pointer(p: *const c_types::c_void) -> Self {
+        // SAFETY: The object was originally pinned.
+        // The passed pointer comes from a previous call to `inner::into_pointer()`.
+        unsafe { Pin::new_unchecked(T::from_pointer(p)) }
+    }
+}
+
+impl<T> PointerWrapper for *mut T {
+    type Borrowed<'a> = *mut T;
+
+    fn into_pointer(self) -> *const c_types::c_void {
+        self as _
+    }
+
+    unsafe fn borrow<'a>(ptr: *const c_types::c_void) -> Self::Borrowed<'a> {
+        ptr as _
+    }
+
+    unsafe fn from_pointer(ptr: *const c_types::c_void) -> Self {
+        ptr as _
+    }
+}
+
+impl PointerWrapper for () {
+    type Borrowed<'a> = ();
+
+    fn into_pointer(self) -> *const c_types::c_void {
+        // We use 1 to be different from a null pointer.
+        1usize as _
+    }
+
+    unsafe fn borrow<'a>(_: *const c_types::c_void) -> Self::Borrowed<'a> {}
+
+    unsafe fn from_pointer(_: *const c_types::c_void) -> Self {}
+}
+
+/// Runs a cleanup function/closure when dropped.
+///
+/// The [`ScopeGuard::dismiss`] function prevents the cleanup function from running.
+///
+/// # Examples
+///
+/// In the example below, we have multiple exit paths and we want to log regardless of which one is
+/// taken:
+/// ```
+/// # use kernel::ScopeGuard;
+/// fn example1(arg: bool) {
+///     let _log = ScopeGuard::new(|| pr_info!("example1 completed\n"));
+///
+///     if arg {
+///         return;
+///     }
+///
+///     pr_info!("Do something...\n");
+/// }
+///
+/// # example1(false);
+/// # example1(true);
+/// ```
+///
+/// In the example below, we want to log the same message on all early exits but a different one on
+/// the main exit path:
+/// ```
+/// # use kernel::ScopeGuard;
+/// fn example2(arg: bool) {
+///     let log = ScopeGuard::new(|| pr_info!("example2 returned early\n"));
+///
+///     if arg {
+///         return;
+///     }
+///
+///     // (Other early returns...)
+///
+///     log.dismiss();
+///     pr_info!("example2 no early return\n");
+/// }
+///
+/// # example2(false);
+/// # example2(true);
+/// ```
+///
+/// In the example below, we need a mutable object (the vector) to be accessible within the log
+/// function, so we wrap it in the [`ScopeGuard`]:
+/// ```
+/// # use kernel::ScopeGuard;
+/// fn example3(arg: bool) -> Result {
+///     let mut vec =
+///         ScopeGuard::new_with_data(Vec::new(), |v| pr_info!("vec had {} elements\n", v.len()));
+///
+///     vec.try_push(10u8)?;
+///     if arg {
+///         return Ok(());
+///     }
+///     vec.try_push(20u8)?;
+///     Ok(())
+/// }
+///
+/// # assert_eq!(example3(false), Ok(()));
+/// # assert_eq!(example3(true), Ok(()));
+/// ```
+///
+/// # Invariants
+///
+/// The value stored in the struct is nearly always `Some(_)`, except between
+/// [`ScopeGuard::dismiss`] and [`ScopeGuard::drop`]: in this case, it will be `None` as the value
+/// will have been returned to the caller. Since  [`ScopeGuard::dismiss`] consumes the guard,
+/// callers won't be able to use it anymore.
+pub struct ScopeGuard<T, F: FnOnce(T)>(Option<(T, F)>);
+
+impl<T, F: FnOnce(T)> ScopeGuard<T, F> {
+    /// Creates a new guarded object wrapping the given data and with the given cleanup function.
+    pub fn new_with_data(data: T, cleanup_func: F) -> Self {
+        // INVARIANT: The struct is being initialised with `Some(_)`.
+        Self(Some((data, cleanup_func)))
+    }
+
+    /// Prevents the cleanup function from running and returns the guarded data.
+    pub fn dismiss(mut self) -> T {
+        // INVARIANT: This is the exception case in the invariant; it is not visible to callers
+        // because this function consumes `self`.
+        self.0.take().unwrap().0
+    }
+}
+
+impl ScopeGuard<(), Box<dyn FnOnce(())>> {
+    /// Creates a new guarded object with the given cleanup function.
+    pub fn new(cleanup: impl FnOnce()) -> ScopeGuard<(), impl FnOnce(())> {
+        ScopeGuard::new_with_data((), move |_| cleanup())
+    }
+}
+
+impl<T, F: FnOnce(T)> Deref for ScopeGuard<T, F> {
+    type Target = T;
+
+    fn deref(&self) -> &T {
+        // The type invariants guarantee that `unwrap` will succeed.
+        &self.0.as_ref().unwrap().0
+    }
+}
+
+impl<T, F: FnOnce(T)> DerefMut for ScopeGuard<T, F> {
+    fn deref_mut(&mut self) -> &mut T {
+        // The type invariants guarantee that `unwrap` will succeed.
+        &mut self.0.as_mut().unwrap().0
+    }
+}
+
+impl<T, F: FnOnce(T)> Drop for ScopeGuard<T, F> {
+    fn drop(&mut self) {
+        // Run the cleanup function if one is still present.
+        if let Some((data, cleanup)) = self.0.take() {
+            cleanup(data)
+        }
+    }
+}
+
+/// Stores an opaque value.
+///
+/// This is meant to be used with FFI objects that are never interpreted by Rust code.
+pub struct Opaque<T>(MaybeUninit<UnsafeCell<T>>);
+
+impl<T> Opaque<T> {
+    /// Creates a new opaque value.
+    pub fn new(value: T) -> Self {
+        Self(MaybeUninit::new(UnsafeCell::new(value)))
+    }
+
+    /// Creates an uninitialised value.
+    pub const fn uninit() -> Self {
+        Self(MaybeUninit::uninit())
+    }
+
+    /// Returns a raw pointer to the opaque data.
+    pub fn get(&self) -> *mut T {
+        UnsafeCell::raw_get(self.0.as_ptr())
+    }
+}
+
+/// A bitmask.
+///
+/// It has a restriction that all bits must be the same, except one. For example, `0b1110111` and
+/// `0b1000` are acceptable masks.
+#[derive(Clone, Copy)]
+pub struct Bit<T> {
+    index: T,
+    inverted: bool,
+}
+
+/// Creates a bit mask with a single bit set.
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::bit;
+/// let mut x = 0xfeu32;
+///
+/// assert_eq!(x & bit(0), 0);
+/// assert_eq!(x & bit(1), 2);
+/// assert_eq!(x & bit(2), 4);
+/// assert_eq!(x & bit(3), 8);
+///
+/// x |= bit(0);
+/// assert_eq!(x, 0xff);
+///
+/// x &= !bit(1);
+/// assert_eq!(x, 0xfd);
+///
+/// x &= !bit(7);
+/// assert_eq!(x, 0x7d);
+///
+/// let y: u64 = bit(34).into();
+/// assert_eq!(y, 0x400000000);
+///
+/// assert_eq!(y | bit(35), 0xc00000000);
+/// ```
+pub fn bit<T: Copy>(index: T) -> Bit<T> {
+    Bit {
+        index,
+        inverted: false,
+    }
+}
+
+impl<T: Copy> ops::Not for Bit<T> {
+    type Output = Self;
+    fn not(self) -> Self {
+        Self {
+            index: self.index,
+            inverted: !self.inverted,
+        }
+    }
+}
+
+/// Implemented by integer types that allow counting the number of trailing zeroes.
+pub trait TrailingZeros {
+    /// Returns the number of trailing zeroes in the binary representation of `self`.
+    fn trailing_zeros(&self) -> u32;
+}
+
+macro_rules! define_unsigned_number_traits {
+    ($type_name:ty) => {
+        impl TrailingZeros for $type_name {
+            fn trailing_zeros(&self) -> u32 {
+                <$type_name>::trailing_zeros(*self)
+            }
+        }
+
+        impl<T: Copy> core::convert::From<Bit<T>> for $type_name
+        where
+            Self: ops::Shl<T, Output = Self> + core::convert::From<u8> + ops::Not<Output = Self>,
+        {
+            fn from(v: Bit<T>) -> Self {
+                let c = Self::from(1u8) << v.index;
+                if v.inverted {
+                    !c
+                } else {
+                    c
+                }
+            }
+        }
+
+        impl<T: Copy> ops::BitAnd<Bit<T>> for $type_name
+        where
+            Self: ops::Shl<T, Output = Self> + core::convert::From<u8>,
+        {
+            type Output = Self;
+            fn bitand(self, rhs: Bit<T>) -> Self::Output {
+                self & Self::from(rhs)
+            }
+        }
+
+        impl<T: Copy> ops::BitOr<Bit<T>> for $type_name
+        where
+            Self: ops::Shl<T, Output = Self> + core::convert::From<u8>,
+        {
+            type Output = Self;
+            fn bitor(self, rhs: Bit<T>) -> Self::Output {
+                self | Self::from(rhs)
+            }
+        }
+
+        impl<T: Copy> ops::BitAndAssign<Bit<T>> for $type_name
+        where
+            Self: ops::Shl<T, Output = Self> + core::convert::From<u8>,
+        {
+            fn bitand_assign(&mut self, rhs: Bit<T>) {
+                *self &= Self::from(rhs)
+            }
+        }
+
+        impl<T: Copy> ops::BitOrAssign<Bit<T>> for $type_name
+        where
+            Self: ops::Shl<T, Output = Self> + core::convert::From<u8>,
+        {
+            fn bitor_assign(&mut self, rhs: Bit<T>) {
+                *self |= Self::from(rhs)
+            }
+        }
+    };
+}
+
+define_unsigned_number_traits!(u8);
+define_unsigned_number_traits!(u16);
+define_unsigned_number_traits!(u32);
+define_unsigned_number_traits!(u64);
+define_unsigned_number_traits!(usize);
+
+/// Returns an iterator over the set bits of `value`.
+///
+/// # Examples
+///
+/// ```
+/// use kernel::bits_iter;
+///
+/// let mut iter = bits_iter(5usize);
+/// assert_eq!(iter.next().unwrap(), 0);
+/// assert_eq!(iter.next().unwrap(), 2);
+/// assert!(iter.next().is_none());
+/// ```
+///
+/// ```
+/// use kernel::bits_iter;
+///
+/// fn print_bits(x: usize) {
+///     for bit in bits_iter(x) {
+///         pr_info!("{}\n", bit);
+///     }
+/// }
+///
+/// # print_bits(42);
+/// ```
+#[inline]
+pub fn bits_iter<T>(value: T) -> impl Iterator<Item = u32>
+where
+    T: core::cmp::PartialEq
+        + From<u8>
+        + ops::Shl<u32, Output = T>
+        + ops::Not<Output = T>
+        + ops::BitAndAssign
+        + TrailingZeros,
+{
+    struct BitIterator<U> {
+        value: U,
+    }
+
+    impl<U> Iterator for BitIterator<U>
+    where
+        U: core::cmp::PartialEq
+            + From<u8>
+            + ops::Shl<u32, Output = U>
+            + ops::Not<Output = U>
+            + ops::BitAndAssign
+            + TrailingZeros,
+    {
+        type Item = u32;
+
+        #[inline]
+        fn next(&mut self) -> Option<u32> {
+            if self.value == U::from(0u8) {
+                return None;
+            }
+            let ret = self.value.trailing_zeros();
+            self.value &= !(U::from(1u8) << ret);
+            Some(ret)
+        }
+    }
+
+    BitIterator { value }
+}
+
+/// A trait for boolean types.
+///
+/// This is meant to be used in type states to allow boolean constraints in implementation blocks.
+/// In the example below, the implementation containing `MyType::set_value` could _not_ be
+/// constrained to type states containing `Writable = true` if `Writable` were a constant instead
+/// of a type.
+///
+/// # Safety
+///
+/// No additional implementations of [`Bool`] should be provided, as [`True`] and [`False`] are
+/// already provided.
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::{Bool, False, True};
+/// use core::marker::PhantomData;
+///
+/// // Type state specifies whether the type is writable.
+/// trait MyTypeState {
+///     type Writable: Bool;
+/// }
+///
+/// // In state S1, the type is writable.
+/// struct S1;
+/// impl MyTypeState for S1 {
+///     type Writable = True;
+/// }
+///
+/// // In state S2, the type is not writable.
+/// struct S2;
+/// impl MyTypeState for S2 {
+///     type Writable = False;
+/// }
+///
+/// struct MyType<T: MyTypeState> {
+///     value: u32,
+///     _p: PhantomData<T>,
+/// }
+///
+/// impl<T: MyTypeState> MyType<T> {
+///     fn new(value: u32) -> Self {
+///         Self {
+///             value,
+///             _p: PhantomData,
+///         }
+///     }
+/// }
+///
+/// // This implementation block only applies if the type state is writable.
+/// impl<T> MyType<T>
+/// where
+///     T: MyTypeState<Writable = True>,
+/// {
+///     fn set_value(&mut self, v: u32) {
+///         self.value = v;
+///     }
+/// }
+///
+/// let mut x = MyType::<S1>::new(10);
+/// let mut y = MyType::<S2>::new(20);
+///
+/// x.set_value(30);
+///
+/// // The code below fails to compile because `S2` is not writable.
+/// // y.set_value(40);
+/// ```
+pub unsafe trait Bool {}
+
+/// Represents the `true` value for types with [`Bool`] bound.
+pub struct True;
+
+// SAFETY: This is one of the only two implementations of `Bool`.
+unsafe impl Bool for True {}
+
+/// Represents the `false` value for types wth [`Bool`] bound.
+pub struct False;
+
+// SAFETY: This is one of the only two implementations of `Bool`.
+unsafe impl Bool for False {}
+
+/// Types that are _always_ reference counted.
+///
+/// It allows such types to define their own custom ref increment and decrement functions.
+/// Additionally, it allows users to convert from a shared reference `&T` to an owned reference
+/// [`ARef<T>`].
+///
+/// This is usually implemented by wrappers to existing structures on the C side of the code. For
+/// Rust code, the recommendation is to use [`Ref`] to create reference-counted instances of a
+/// type.
+///
+/// # Safety
+///
+/// Implementers must ensure that increments to the reference count keeps the object alive in
+/// memory at least until a matching decrement performed.
+///
+/// Implementers must also ensure that all instances are reference-counted. (Otherwise they
+/// won't be able to honour the requirement that [`AlwaysRefCounted::inc_ref`] keep the object
+/// alive.)
+pub unsafe trait AlwaysRefCounted {
+    /// Increments the reference count on the object.
+    fn inc_ref(&self);
+
+    /// Decrements the reference count on the object.
+    ///
+    /// Frees the object when the count reaches zero.
+    ///
+    /// # Safety
+    ///
+    /// Callers must ensure that there was a previous matching increment to the reference count,
+    /// and that the object is no longer used after its reference count is decremented (as it may
+    /// result in the object being freed), unless the caller owns another increment on the refcount
+    /// (e.g., it calls [`AlwaysRefCounted::inc_ref`] twice, then calls
+    /// [`AlwaysRefCounted::dec_ref`] once).
+    unsafe fn dec_ref(obj: NonNull<Self>);
+}
+
+/// An owned reference to an always-reference-counted object.
+///
+/// The object's reference count is automatically decremented when an instance of [`ARef`] is
+/// dropped. It is also automatically incremented when a new instance is created via
+/// [`ARef::clone`].
+///
+/// # Invariants
+///
+/// The pointer stored in `ptr` is non-null and valid for the lifetime of the [`ARef`] instance. In
+/// particular, the [`ARef`] instance owns an increment on underlying object's reference count.
+pub struct ARef<T: AlwaysRefCounted> {
+    ptr: NonNull<T>,
+    _p: PhantomData<T>,
+}
+
+impl<T: AlwaysRefCounted> ARef<T> {
+    /// Creates a new instance of [`ARef`].
+    ///
+    /// It takes over an increment of the reference count on the underlying object.
+    ///
+    /// # Safety
+    ///
+    /// Callers must ensure that the reference count was incremented at least once, and that they
+    /// are properly relinquishing one increment. That is, if there is only one increment, callers
+    /// must not use the underlying object anymore -- it is only safe to do so via the newly
+    /// created [`ARef`].
+    pub unsafe fn from_raw(ptr: NonNull<T>) -> Self {
+        // INVARIANT: The safety requirements guarantee that the new instance now owns the
+        // increment on the refcount.
+        Self {
+            ptr,
+            _p: PhantomData,
+        }
+    }
+}
+
+impl<T: AlwaysRefCounted> Clone for ARef<T> {
+    fn clone(&self) -> Self {
+        self.inc_ref();
+        // SAFETY: We just incremented the refcount above.
+        unsafe { Self::from_raw(self.ptr) }
+    }
+}
+
+impl<T: AlwaysRefCounted> Deref for ARef<T> {
+    type Target = T;
+
+    fn deref(&self) -> &Self::Target {
+        // SAFETY: The type invariants guarantee that the object is valid.
+        unsafe { self.ptr.as_ref() }
+    }
+}
+
+impl<T: AlwaysRefCounted> From<&T> for ARef<T> {
+    fn from(b: &T) -> Self {
+        b.inc_ref();
+        // SAFETY: We just incremented the refcount above.
+        unsafe { Self::from_raw(NonNull::from(b)) }
+    }
+}
+
+impl<T: AlwaysRefCounted> Drop for ARef<T> {
+    fn drop(&mut self) {
+        // SAFETY: The type invariants guarantee that the `ARef` owns the reference we're about to
+        // decrement.
+        unsafe { T::dec_ref(self.ptr) };
+    }
+}
diff --git a/rust/kernel/user_ptr.rs b/rust/kernel/user_ptr.rs
new file mode 100644
index 000000000000..8489e80923c7
--- /dev/null
+++ b/rust/kernel/user_ptr.rs
@@ -0,0 +1,175 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! User pointers.
+//!
+//! C header: [`include/linux/uaccess.h`](../../../../include/linux/uaccess.h)
+
+use crate::{
+    bindings, c_types,
+    error::code::*,
+    io_buffer::{IoBufferReader, IoBufferWriter},
+    Result,
+};
+use alloc::vec::Vec;
+
+/// A reference to an area in userspace memory, which can be either
+/// read-only or read-write.
+///
+/// All methods on this struct are safe: invalid pointers return
+/// `EFAULT`. Concurrent access, *including data races to/from userspace
+/// memory*, is permitted, because fundamentally another userspace
+/// thread/process could always be modifying memory at the same time
+/// (in the same way that userspace Rust's [`std::io`] permits data races
+/// with the contents of files on disk). In the presence of a race, the
+/// exact byte values read/written are unspecified but the operation is
+/// well-defined. Kernelspace code should validate its copy of data
+/// after completing a read, and not expect that multiple reads of the
+/// same address will return the same value.
+///
+/// All APIs enforce the invariant that a given byte of memory from userspace
+/// may only be read once. By preventing double-fetches we avoid TOCTOU
+/// vulnerabilities. This is accomplished by taking `self` by value to prevent
+/// obtaining multiple readers on a given [`UserSlicePtr`], and the readers
+/// only permitting forward reads.
+///
+/// Constructing a [`UserSlicePtr`] performs no checks on the provided
+/// address and length, it can safely be constructed inside a kernel thread
+/// with no current userspace process. Reads and writes wrap the kernel APIs
+/// `copy_from_user` and `copy_to_user`, which check the memory map of the
+/// current process and enforce that the address range is within the user
+/// range (no additional calls to `access_ok` are needed).
+///
+/// [`std::io`]: https://doc.rust-lang.org/std/io/index.html
+pub struct UserSlicePtr(*mut c_types::c_void, usize);
+
+impl UserSlicePtr {
+    /// Constructs a user slice from a raw pointer and a length in bytes.
+    ///
+    /// # Safety
+    ///
+    /// Callers must be careful to avoid time-of-check-time-of-use
+    /// (TOCTOU) issues. The simplest way is to create a single instance of
+    /// [`UserSlicePtr`] per user memory block as it reads each byte at
+    /// most once.
+    pub unsafe fn new(ptr: *mut c_types::c_void, length: usize) -> Self {
+        UserSlicePtr(ptr, length)
+    }
+
+    /// Reads the entirety of the user slice.
+    ///
+    /// Returns `EFAULT` if the address does not currently point to
+    /// mapped, readable memory.
+    pub fn read_all(self) -> Result<Vec<u8>> {
+        self.reader().read_all()
+    }
+
+    /// Constructs a [`UserSlicePtrReader`].
+    pub fn reader(self) -> UserSlicePtrReader {
+        UserSlicePtrReader(self.0, self.1)
+    }
+
+    /// Writes the provided slice into the user slice.
+    ///
+    /// Returns `EFAULT` if the address does not currently point to
+    /// mapped, writable memory (in which case some data from before the
+    /// fault may be written), or `data` is larger than the user slice
+    /// (in which case no data is written).
+    pub fn write_all(self, data: &[u8]) -> Result {
+        self.writer().write_slice(data)
+    }
+
+    /// Constructs a [`UserSlicePtrWriter`].
+    pub fn writer(self) -> UserSlicePtrWriter {
+        UserSlicePtrWriter(self.0, self.1)
+    }
+
+    /// Constructs both a [`UserSlicePtrReader`] and a [`UserSlicePtrWriter`].
+    pub fn reader_writer(self) -> (UserSlicePtrReader, UserSlicePtrWriter) {
+        (
+            UserSlicePtrReader(self.0, self.1),
+            UserSlicePtrWriter(self.0, self.1),
+        )
+    }
+}
+
+/// A reader for [`UserSlicePtr`].
+///
+/// Used to incrementally read from the user slice.
+pub struct UserSlicePtrReader(*mut c_types::c_void, usize);
+
+impl IoBufferReader for UserSlicePtrReader {
+    /// Returns the number of bytes left to be read from this.
+    ///
+    /// Note that even reading less than this number of bytes may fail.
+    fn len(&self) -> usize {
+        self.1
+    }
+
+    /// Reads raw data from the user slice into a raw kernel buffer.
+    ///
+    /// # Safety
+    ///
+    /// The output buffer must be valid.
+    unsafe fn read_raw(&mut self, out: *mut u8, len: usize) -> Result {
+        if len > self.1 || len > u32::MAX as usize {
+            return Err(EFAULT);
+        }
+        let res = unsafe { bindings::copy_from_user(out as _, self.0, len as _) };
+        if res != 0 {
+            return Err(EFAULT);
+        }
+        // Since this is not a pointer to a valid object in our program,
+        // we cannot use `add`, which has C-style rules for defined
+        // behavior.
+        self.0 = self.0.wrapping_add(len);
+        self.1 -= len;
+        Ok(())
+    }
+}
+
+/// A writer for [`UserSlicePtr`].
+///
+/// Used to incrementally write into the user slice.
+pub struct UserSlicePtrWriter(*mut c_types::c_void, usize);
+
+impl IoBufferWriter for UserSlicePtrWriter {
+    fn len(&self) -> usize {
+        self.1
+    }
+
+    fn clear(&mut self, mut len: usize) -> Result {
+        let mut ret = Ok(());
+        if len > self.1 {
+            ret = Err(EFAULT);
+            len = self.1;
+        }
+
+        // SAFETY: The buffer will be validated by `clear_user`. We ensure that `len` is within
+        // bounds in the check above.
+        let left = unsafe { bindings::clear_user(self.0, len as _) } as usize;
+        if left != 0 {
+            ret = Err(EFAULT);
+            len -= left;
+        }
+
+        self.0 = self.0.wrapping_add(len);
+        self.1 -= len;
+        ret
+    }
+
+    unsafe fn write_raw(&mut self, data: *const u8, len: usize) -> Result {
+        if len > self.1 || len > u32::MAX as usize {
+            return Err(EFAULT);
+        }
+        let res = unsafe { bindings::copy_to_user(self.0, data as _, len as _) };
+        if res != 0 {
+            return Err(EFAULT);
+        }
+        // Since this is not a pointer to a valid object in our program,
+        // we cannot use `add`, which has C-style rules for defined
+        // behavior.
+        self.0 = self.0.wrapping_add(len);
+        self.1 -= len;
+        Ok(())
+    }
+}
-- 
2.36.1


^ permalink raw reply related	[relevance 1%]

* [PATCH v7 22/25] samples: add Rust examples
    2022-05-23  2:01  1% ` [PATCH v7 12/25] rust: add `kernel` crate Miguel Ojeda
@ 2022-05-23  2:01  3% ` Miguel Ojeda
  1 sibling, 0 replies; 77+ results
From: Miguel Ojeda @ 2022-05-23  2:01 UTC (permalink / raw)
  To: Linus Torvalds, Greg Kroah-Hartman
  Cc: rust-for-linux, linux-kernel, Jarkko Sakkinen, Miguel Ojeda,
	Alex Gaynor, Finn Behrens, Wedson Almeida Filho,
	Sven Van Asbroeck, Gary Guo, Boris-Chengbiao Zhou, Ayaan Zaidi,
	Milan Landaverde

A set of Rust modules that showcase how Rust modules look like
and how to use the abstracted kernel features, as well as
an example of a Rust host program with several modules.

These samples also double as tests in the CI.

The semaphore sample comes with a C version for comparison.

Co-developed-by: Alex Gaynor <alex.gaynor@gmail.com>
Signed-off-by: Alex Gaynor <alex.gaynor@gmail.com>
Co-developed-by: Finn Behrens <me@kloenk.de>
Signed-off-by: Finn Behrens <me@kloenk.de>
Co-developed-by: Wedson Almeida Filho <wedsonaf@google.com>
Signed-off-by: Wedson Almeida Filho <wedsonaf@google.com>
Co-developed-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Co-developed-by: Sven Van Asbroeck <thesven73@gmail.com>
Signed-off-by: Sven Van Asbroeck <thesven73@gmail.com>
Co-developed-by: Gary Guo <gary@garyguo.net>
Signed-off-by: Gary Guo <gary@garyguo.net>
Co-developed-by: Boris-Chengbiao Zhou <bobo1239@web.de>
Signed-off-by: Boris-Chengbiao Zhou <bobo1239@web.de>
Co-developed-by: Ayaan Zaidi <zaidi.ayaan@gmail.com>
Signed-off-by: Ayaan Zaidi <zaidi.ayaan@gmail.com>
Co-developed-by: Milan Landaverde <milan@mdaverde.com>
Signed-off-by: Milan Landaverde <milan@mdaverde.com>
Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
---
 samples/Kconfig                        |   2 +
 samples/Makefile                       |   1 +
 samples/rust/Kconfig                   | 140 ++++++++++++++++
 samples/rust/Makefile                  |  16 ++
 samples/rust/hostprogs/.gitignore      |   3 +
 samples/rust/hostprogs/Makefile        |   5 +
 samples/rust/hostprogs/a.rs            |   7 +
 samples/rust/hostprogs/b.rs            |   5 +
 samples/rust/hostprogs/single.rs       |  12 ++
 samples/rust/rust_chrdev.rs            |  50 ++++++
 samples/rust/rust_minimal.rs           |  35 ++++
 samples/rust/rust_miscdev.rs           | 143 +++++++++++++++++
 samples/rust/rust_module_parameters.rs |  69 ++++++++
 samples/rust/rust_netfilter.rs         |  54 +++++++
 samples/rust/rust_platform.rs          |  22 +++
 samples/rust/rust_print.rs             |  54 +++++++
 samples/rust/rust_random.rs            |  60 +++++++
 samples/rust/rust_semaphore.rs         | 171 ++++++++++++++++++++
 samples/rust/rust_semaphore_c.c        | 212 +++++++++++++++++++++++++
 samples/rust/rust_stack_probing.rs     |  36 +++++
 samples/rust/rust_sync.rs              |  93 +++++++++++
 21 files changed, 1190 insertions(+)
 create mode 100644 samples/rust/Kconfig
 create mode 100644 samples/rust/Makefile
 create mode 100644 samples/rust/hostprogs/.gitignore
 create mode 100644 samples/rust/hostprogs/Makefile
 create mode 100644 samples/rust/hostprogs/a.rs
 create mode 100644 samples/rust/hostprogs/b.rs
 create mode 100644 samples/rust/hostprogs/single.rs
 create mode 100644 samples/rust/rust_chrdev.rs
 create mode 100644 samples/rust/rust_minimal.rs
 create mode 100644 samples/rust/rust_miscdev.rs
 create mode 100644 samples/rust/rust_module_parameters.rs
 create mode 100644 samples/rust/rust_netfilter.rs
 create mode 100644 samples/rust/rust_platform.rs
 create mode 100644 samples/rust/rust_print.rs
 create mode 100644 samples/rust/rust_random.rs
 create mode 100644 samples/rust/rust_semaphore.rs
 create mode 100644 samples/rust/rust_semaphore_c.c
 create mode 100644 samples/rust/rust_stack_probing.rs
 create mode 100644 samples/rust/rust_sync.rs

diff --git a/samples/Kconfig b/samples/Kconfig
index 470ee3baf2e1..0d81c00289ee 100644
--- a/samples/Kconfig
+++ b/samples/Kconfig
@@ -263,6 +263,8 @@ config SAMPLE_CORESIGHT_SYSCFG
 	  This demonstrates how a user may create their own CoreSight
 	  configurations and easily load them into the system at runtime.
 
+source "samples/rust/Kconfig"
+
 endif # SAMPLES
 
 config HAVE_SAMPLE_FTRACE_DIRECT
diff --git a/samples/Makefile b/samples/Makefile
index 701e912ab5af..9832ef3f8fcb 100644
--- a/samples/Makefile
+++ b/samples/Makefile
@@ -35,3 +35,4 @@ subdir-$(CONFIG_SAMPLE_WATCH_QUEUE)	+= watch_queue
 obj-$(CONFIG_DEBUG_KMEMLEAK_TEST)	+= kmemleak/
 obj-$(CONFIG_SAMPLE_CORESIGHT_SYSCFG)	+= coresight/
 obj-$(CONFIG_SAMPLE_FPROBE)		+= fprobe/
+obj-$(CONFIG_SAMPLES_RUST)		+= rust/
diff --git a/samples/rust/Kconfig b/samples/rust/Kconfig
new file mode 100644
index 000000000000..4f90f8d69351
--- /dev/null
+++ b/samples/rust/Kconfig
@@ -0,0 +1,140 @@
+# SPDX-License-Identifier: GPL-2.0
+
+menuconfig SAMPLES_RUST
+	bool "Rust samples"
+	depends on RUST
+	help
+	  You can build sample Rust kernel code here.
+
+	  If unsure, say N.
+
+if SAMPLES_RUST
+
+config SAMPLE_RUST_MINIMAL
+	tristate "Minimal"
+	help
+	  This option builds the Rust minimal module sample.
+
+	  To compile this as a module, choose M here:
+	  the module will be called rust_minimal.
+
+	  If unsure, say N.
+
+config SAMPLE_RUST_PRINT
+	tristate "Printing macros"
+	help
+	  This option builds the Rust printing macros sample.
+
+	  To compile this as a module, choose M here:
+	  the module will be called rust_print.
+
+	  If unsure, say N.
+
+config SAMPLE_RUST_MODULE_PARAMETERS
+	tristate "Module parameters"
+	help
+	  This option builds the Rust module parameters sample.
+
+	  To compile this as a module, choose M here:
+	  the module will be called rust_module_parameters.
+
+	  If unsure, say N.
+
+config SAMPLE_RUST_SYNC
+	tristate "Synchronisation primitives"
+	help
+	  This option builds the Rust synchronisation primitives sample.
+
+	  To compile this as a module, choose M here:
+	  the module will be called rust_sync.
+
+	  If unsure, say N.
+
+config SAMPLE_RUST_CHRDEV
+	tristate "Character device"
+	help
+	  This option builds the Rust character device sample.
+
+	  To compile this as a module, choose M here:
+	  the module will be called rust_chrdev.
+
+	  If unsure, say N.
+
+config SAMPLE_RUST_MISCDEV
+	tristate "Miscellaneous device"
+	help
+	  This option builds the Rust miscellaneous device sample.
+
+	  To compile this as a module, choose M here:
+	  the module will be called rust_miscdev.
+
+	  If unsure, say N.
+
+config SAMPLE_RUST_STACK_PROBING
+	tristate "Stack probing"
+	help
+	  This option builds the Rust stack probing sample.
+
+	  To compile this as a module, choose M here:
+	  the module will be called rust_stack_probing.
+
+	  If unsure, say N.
+
+config SAMPLE_RUST_SEMAPHORE
+	tristate "Semaphore"
+	help
+	  This option builds the Rust semaphore sample.
+
+	  To compile this as a module, choose M here:
+	  the module will be called rust_semaphore.
+
+	  If unsure, say N.
+
+config SAMPLE_RUST_SEMAPHORE_C
+	tristate "Semaphore (in C, for comparison)"
+	help
+	  This option builds the Rust semaphore sample (in C, for comparison).
+
+	  To compile this as a module, choose M here:
+	  the module will be called rust_semaphore_c.
+
+	  If unsure, say N.
+
+config SAMPLE_RUST_RANDOM
+	tristate "Random"
+	help
+	  This option builds the Rust random sample.
+
+	  To compile this as a module, choose M here:
+	  the module will be called rust_random.
+
+	  If unsure, say N.
+
+config SAMPLE_RUST_PLATFORM
+	tristate "Platform device driver"
+	help
+	  This option builds the Rust platform device driver sample.
+
+	  To compile this as a module, choose M here:
+	  the module will be called rust_platform.
+
+	  If unsure, say N.
+
+config SAMPLE_RUST_NETFILTER
+	tristate "Network filter module"
+	help
+	  This option builds the Rust netfilter module sample.
+
+	  To compile this as a module, choose M here:
+	  the module will be called rust_netfilter.
+
+	  If unsure, say N.
+
+config SAMPLE_RUST_HOSTPROGS
+	bool "Host programs"
+	help
+	  This option builds the Rust host program samples.
+
+	  If unsure, say N.
+
+endif # SAMPLES_RUST
diff --git a/samples/rust/Makefile b/samples/rust/Makefile
new file mode 100644
index 000000000000..fb5a205ebb8c
--- /dev/null
+++ b/samples/rust/Makefile
@@ -0,0 +1,16 @@
+# SPDX-License-Identifier: GPL-2.0
+
+obj-$(CONFIG_SAMPLE_RUST_MINIMAL)		+= rust_minimal.o
+obj-$(CONFIG_SAMPLE_RUST_PRINT)			+= rust_print.o
+obj-$(CONFIG_SAMPLE_RUST_MODULE_PARAMETERS)	+= rust_module_parameters.o
+obj-$(CONFIG_SAMPLE_RUST_SYNC)			+= rust_sync.o
+obj-$(CONFIG_SAMPLE_RUST_CHRDEV)		+= rust_chrdev.o
+obj-$(CONFIG_SAMPLE_RUST_MISCDEV)		+= rust_miscdev.o
+obj-$(CONFIG_SAMPLE_RUST_STACK_PROBING)		+= rust_stack_probing.o
+obj-$(CONFIG_SAMPLE_RUST_SEMAPHORE)		+= rust_semaphore.o
+obj-$(CONFIG_SAMPLE_RUST_SEMAPHORE_C)		+= rust_semaphore_c.o
+obj-$(CONFIG_SAMPLE_RUST_RANDOM)		+= rust_random.o
+obj-$(CONFIG_SAMPLE_RUST_PLATFORM)		+= rust_platform.o
+obj-$(CONFIG_SAMPLE_RUST_NETFILTER)		+= rust_netfilter.o
+
+subdir-$(CONFIG_SAMPLE_RUST_HOSTPROGS)		+= hostprogs
diff --git a/samples/rust/hostprogs/.gitignore b/samples/rust/hostprogs/.gitignore
new file mode 100644
index 000000000000..a6c173da5048
--- /dev/null
+++ b/samples/rust/hostprogs/.gitignore
@@ -0,0 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0
+
+single
diff --git a/samples/rust/hostprogs/Makefile b/samples/rust/hostprogs/Makefile
new file mode 100644
index 000000000000..8ddcbd7416db
--- /dev/null
+++ b/samples/rust/hostprogs/Makefile
@@ -0,0 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0
+
+hostprogs-always-y := single
+
+single-rust := y
diff --git a/samples/rust/hostprogs/a.rs b/samples/rust/hostprogs/a.rs
new file mode 100644
index 000000000000..f7a4a3d0f4e0
--- /dev/null
+++ b/samples/rust/hostprogs/a.rs
@@ -0,0 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Rust single host program sample: module `a`.
+
+pub(crate) fn f(x: i32) {
+    println!("The number is {}.", x);
+}
diff --git a/samples/rust/hostprogs/b.rs b/samples/rust/hostprogs/b.rs
new file mode 100644
index 000000000000..c1675890648f
--- /dev/null
+++ b/samples/rust/hostprogs/b.rs
@@ -0,0 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Rust single host program sample: module `b`.
+
+pub(crate) const CONSTANT: i32 = 42;
diff --git a/samples/rust/hostprogs/single.rs b/samples/rust/hostprogs/single.rs
new file mode 100644
index 000000000000..8c48a119339a
--- /dev/null
+++ b/samples/rust/hostprogs/single.rs
@@ -0,0 +1,12 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Rust single host program sample.
+
+mod a;
+mod b;
+
+fn main() {
+    println!("Hello world!");
+
+    a::f(b::CONSTANT);
+}
diff --git a/samples/rust/rust_chrdev.rs b/samples/rust/rust_chrdev.rs
new file mode 100644
index 000000000000..9f5d564671ea
--- /dev/null
+++ b/samples/rust/rust_chrdev.rs
@@ -0,0 +1,50 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Rust character device sample.
+
+use kernel::prelude::*;
+use kernel::{chrdev, file};
+
+module! {
+    type: RustChrdev,
+    name: b"rust_chrdev",
+    author: b"Rust for Linux Contributors",
+    description: b"Rust character device sample",
+    license: b"GPL",
+}
+
+struct RustFile;
+
+impl file::Operations for RustFile {
+    kernel::declare_file_operations!();
+
+    fn open(_shared: &(), _file: &file::File) -> Result {
+        Ok(())
+    }
+}
+
+struct RustChrdev {
+    _dev: Pin<Box<chrdev::Registration<2>>>,
+}
+
+impl kernel::Module for RustChrdev {
+    fn init(name: &'static CStr, module: &'static ThisModule) -> Result<Self> {
+        pr_info!("Rust character device sample (init)\n");
+
+        let mut chrdev_reg = chrdev::Registration::new_pinned(name, 0, module)?;
+
+        // Register the same kind of device twice, we're just demonstrating
+        // that you can use multiple minors. There are two minors in this case
+        // because its type is `chrdev::Registration<2>`
+        chrdev_reg.as_mut().register::<RustFile>()?;
+        chrdev_reg.as_mut().register::<RustFile>()?;
+
+        Ok(RustChrdev { _dev: chrdev_reg })
+    }
+}
+
+impl Drop for RustChrdev {
+    fn drop(&mut self) {
+        pr_info!("Rust character device sample (exit)\n");
+    }
+}
diff --git a/samples/rust/rust_minimal.rs b/samples/rust/rust_minimal.rs
new file mode 100644
index 000000000000..6e1a926c6f62
--- /dev/null
+++ b/samples/rust/rust_minimal.rs
@@ -0,0 +1,35 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Rust minimal sample.
+
+use kernel::prelude::*;
+
+module! {
+    type: RustMinimal,
+    name: b"rust_minimal",
+    author: b"Rust for Linux Contributors",
+    description: b"Rust minimal sample",
+    license: b"GPL",
+}
+
+struct RustMinimal {
+    message: String,
+}
+
+impl kernel::Module for RustMinimal {
+    fn init(_name: &'static CStr, _module: &'static ThisModule) -> Result<Self> {
+        pr_info!("Rust minimal sample (init)\n");
+        pr_info!("Am I built-in? {}\n", !cfg!(MODULE));
+
+        Ok(RustMinimal {
+            message: "on the heap!".try_to_owned()?,
+        })
+    }
+}
+
+impl Drop for RustMinimal {
+    fn drop(&mut self) {
+        pr_info!("My message is {}\n", self.message);
+        pr_info!("Rust minimal sample (exit)\n");
+    }
+}
diff --git a/samples/rust/rust_miscdev.rs b/samples/rust/rust_miscdev.rs
new file mode 100644
index 000000000000..d1bf3c61f5ce
--- /dev/null
+++ b/samples/rust/rust_miscdev.rs
@@ -0,0 +1,143 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Rust miscellaneous device sample.
+
+use kernel::prelude::*;
+use kernel::{
+    file::{self, File},
+    io_buffer::{IoBufferReader, IoBufferWriter},
+    miscdev,
+    sync::{CondVar, Mutex, Ref, RefBorrow, UniqueRef},
+};
+
+module! {
+    type: RustMiscdev,
+    name: b"rust_miscdev",
+    author: b"Rust for Linux Contributors",
+    description: b"Rust miscellaneous device sample",
+    license: b"GPL",
+}
+
+const MAX_TOKENS: usize = 3;
+
+struct SharedStateInner {
+    token_count: usize,
+}
+
+struct SharedState {
+    state_changed: CondVar,
+    inner: Mutex<SharedStateInner>,
+}
+
+impl SharedState {
+    fn try_new() -> Result<Ref<Self>> {
+        let mut state = Pin::from(UniqueRef::try_new(Self {
+            // SAFETY: `condvar_init!` is called below.
+            state_changed: unsafe { CondVar::new() },
+            // SAFETY: `mutex_init!` is called below.
+            inner: unsafe { Mutex::new(SharedStateInner { token_count: 0 }) },
+        })?);
+
+        // SAFETY: `state_changed` is pinned when `state` is.
+        let pinned = unsafe { state.as_mut().map_unchecked_mut(|s| &mut s.state_changed) };
+        kernel::condvar_init!(pinned, "SharedState::state_changed");
+
+        // SAFETY: `inner` is pinned when `state` is.
+        let pinned = unsafe { state.as_mut().map_unchecked_mut(|s| &mut s.inner) };
+        kernel::mutex_init!(pinned, "SharedState::inner");
+
+        Ok(state.into())
+    }
+}
+
+struct Token;
+impl file::Operations for Token {
+    type Data = Ref<SharedState>;
+    type OpenData = Ref<SharedState>;
+
+    kernel::declare_file_operations!(read, write);
+
+    fn open(shared: &Ref<SharedState>, _file: &File) -> Result<Self::Data> {
+        Ok(shared.clone())
+    }
+
+    fn read(
+        shared: RefBorrow<'_, SharedState>,
+        _: &File,
+        data: &mut impl IoBufferWriter,
+        offset: u64,
+    ) -> Result<usize> {
+        // Succeed if the caller doesn't provide a buffer or if not at the start.
+        if data.is_empty() || offset != 0 {
+            return Ok(0);
+        }
+
+        {
+            let mut inner = shared.inner.lock();
+
+            // Wait until we are allowed to decrement the token count or a signal arrives.
+            while inner.token_count == 0 {
+                if shared.state_changed.wait(&mut inner) {
+                    return Err(EINTR);
+                }
+            }
+
+            // Consume a token.
+            inner.token_count -= 1;
+        }
+
+        // Notify a possible writer waiting.
+        shared.state_changed.notify_all();
+
+        // Write a one-byte 1 to the reader.
+        data.write_slice(&[1u8; 1])?;
+        Ok(1)
+    }
+
+    fn write(
+        shared: RefBorrow<'_, SharedState>,
+        _: &File,
+        data: &mut impl IoBufferReader,
+        _offset: u64,
+    ) -> Result<usize> {
+        {
+            let mut inner = shared.inner.lock();
+
+            // Wait until we are allowed to increment the token count or a signal arrives.
+            while inner.token_count == MAX_TOKENS {
+                if shared.state_changed.wait(&mut inner) {
+                    return Err(EINTR);
+                }
+            }
+
+            // Increment the number of token so that a reader can be released.
+            inner.token_count += 1;
+        }
+
+        // Notify a possible reader waiting.
+        shared.state_changed.notify_all();
+        Ok(data.len())
+    }
+}
+
+struct RustMiscdev {
+    _dev: Pin<Box<miscdev::Registration<Token>>>,
+}
+
+impl kernel::Module for RustMiscdev {
+    fn init(name: &'static CStr, _module: &'static ThisModule) -> Result<Self> {
+        pr_info!("Rust miscellaneous device sample (init)\n");
+
+        let state = SharedState::try_new()?;
+
+        Ok(RustMiscdev {
+            _dev: miscdev::Registration::new_pinned(fmt!("{name}"), state)?,
+        })
+    }
+}
+
+impl Drop for RustMiscdev {
+    fn drop(&mut self) {
+        pr_info!("Rust miscellaneous device sample (exit)\n");
+    }
+}
diff --git a/samples/rust/rust_module_parameters.rs b/samples/rust/rust_module_parameters.rs
new file mode 100644
index 000000000000..12fe5e738e83
--- /dev/null
+++ b/samples/rust/rust_module_parameters.rs
@@ -0,0 +1,69 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Rust module parameters sample.
+
+use kernel::prelude::*;
+
+module! {
+    type: RustModuleParameters,
+    name: b"rust_module_parameters",
+    author: b"Rust for Linux Contributors",
+    description: b"Rust module parameters sample",
+    license: b"GPL",
+    params: {
+        my_bool: bool {
+            default: true,
+            permissions: 0,
+            description: b"Example of bool",
+        },
+        my_i32: i32 {
+            default: 42,
+            permissions: 0o644,
+            description: b"Example of i32",
+        },
+        my_str: str {
+            default: b"default str val",
+            permissions: 0o644,
+            description: b"Example of a string param",
+        },
+        my_usize: usize {
+            default: 42,
+            permissions: 0o644,
+            description: b"Example of usize",
+        },
+        my_array: ArrayParam<i32, 3> {
+            default: [0, 1],
+            permissions: 0,
+            description: b"Example of array",
+        },
+    },
+}
+
+struct RustModuleParameters;
+
+impl kernel::Module for RustModuleParameters {
+    fn init(_name: &'static CStr, module: &'static ThisModule) -> Result<Self> {
+        pr_info!("Rust module parameters sample (init)\n");
+
+        {
+            let lock = module.kernel_param_lock();
+            pr_info!("Parameters:\n");
+            pr_info!("  my_bool:    {}\n", my_bool.read());
+            pr_info!("  my_i32:     {}\n", my_i32.read(&lock));
+            pr_info!(
+                "  my_str:     {}\n",
+                core::str::from_utf8(my_str.read(&lock))?
+            );
+            pr_info!("  my_usize:   {}\n", my_usize.read(&lock));
+            pr_info!("  my_array:   {:?}\n", my_array.read());
+        }
+
+        Ok(RustModuleParameters)
+    }
+}
+
+impl Drop for RustModuleParameters {
+    fn drop(&mut self) {
+        pr_info!("Rust module parameters sample (exit)\n");
+    }
+}
diff --git a/samples/rust/rust_netfilter.rs b/samples/rust/rust_netfilter.rs
new file mode 100644
index 000000000000..4bd5c07fee8c
--- /dev/null
+++ b/samples/rust/rust_netfilter.rs
@@ -0,0 +1,54 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Rust netfilter sample.
+
+use kernel::net;
+use kernel::net::filter::{self as netfilter, inet, Disposition, Family};
+use kernel::prelude::*;
+
+module! {
+    type: RustNetfilter,
+    name: b"rust_netfilter",
+    author: b"Rust for Linux Contributors",
+    description: b"Rust netfilter sample",
+    license: b"GPL",
+}
+
+struct RustNetfilter {
+    _in: Pin<Box<netfilter::Registration<Self>>>,
+    _out: Pin<Box<netfilter::Registration<Self>>>,
+}
+
+impl netfilter::Filter for RustNetfilter {
+    fn filter(_: (), skb: &net::SkBuff) -> Disposition {
+        let data = skb.head_data();
+        pr_info!(
+            "packet headlen={}, len={}, first bytes={:02x?}\n",
+            data.len(),
+            skb.len(),
+            &data[..core::cmp::min(10, data.len())]
+        );
+        Disposition::Accept
+    }
+}
+
+impl kernel::Module for RustNetfilter {
+    fn init(_name: &'static CStr, _module: &'static ThisModule) -> Result<Self> {
+        Ok(Self {
+            _in: netfilter::Registration::new_pinned(
+                Family::INet(inet::Hook::PreRouting),
+                0,
+                net::init_ns().into(),
+                None,
+                (),
+            )?,
+            _out: netfilter::Registration::new_pinned(
+                Family::INet(inet::Hook::PostRouting),
+                0,
+                net::init_ns().into(),
+                None,
+                (),
+            )?,
+        })
+    }
+}
diff --git a/samples/rust/rust_platform.rs b/samples/rust/rust_platform.rs
new file mode 100644
index 000000000000..f62784676919
--- /dev/null
+++ b/samples/rust/rust_platform.rs
@@ -0,0 +1,22 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Rust platform device driver sample.
+
+use kernel::{module_platform_driver, of, platform, prelude::*};
+
+module_platform_driver! {
+    type: Driver,
+    name: b"rust_platform",
+    license: b"GPL",
+}
+
+struct Driver;
+impl platform::Driver for Driver {
+    kernel::define_of_id_table! {(), [
+        (of::DeviceId::Compatible(b"rust,sample"), None),
+    ]}
+
+    fn probe(_dev: &mut platform::Device, _id_info: Option<&Self::IdInfo>) -> Result {
+        Ok(())
+    }
+}
diff --git a/samples/rust/rust_print.rs b/samples/rust/rust_print.rs
new file mode 100644
index 000000000000..30d96e025d89
--- /dev/null
+++ b/samples/rust/rust_print.rs
@@ -0,0 +1,54 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Rust printing macros sample.
+
+use kernel::prelude::*;
+use kernel::{pr_cont, str::CStr, ThisModule};
+
+module! {
+    type: RustPrint,
+    name: b"rust_print",
+    author: b"Rust for Linux Contributors",
+    description: b"Rust printing macros sample",
+    license: b"GPL",
+}
+
+struct RustPrint;
+
+impl kernel::Module for RustPrint {
+    fn init(_name: &'static CStr, _module: &'static ThisModule) -> Result<Self> {
+        pr_info!("Rust printing macros sample (init)\n");
+
+        pr_emerg!("Emergency message (level 0) without args\n");
+        pr_alert!("Alert message (level 1) without args\n");
+        pr_crit!("Critical message (level 2) without args\n");
+        pr_err!("Error message (level 3) without args\n");
+        pr_warn!("Warning message (level 4) without args\n");
+        pr_notice!("Notice message (level 5) without args\n");
+        pr_info!("Info message (level 6) without args\n");
+
+        pr_info!("A line that");
+        pr_cont!(" is continued");
+        pr_cont!(" without args\n");
+
+        pr_emerg!("{} message (level {}) with args\n", "Emergency", 0);
+        pr_alert!("{} message (level {}) with args\n", "Alert", 1);
+        pr_crit!("{} message (level {}) with args\n", "Critical", 2);
+        pr_err!("{} message (level {}) with args\n", "Error", 3);
+        pr_warn!("{} message (level {}) with args\n", "Warning", 4);
+        pr_notice!("{} message (level {}) with args\n", "Notice", 5);
+        pr_info!("{} message (level {}) with args\n", "Info", 6);
+
+        pr_info!("A {} that", "line");
+        pr_cont!(" is {}", "continued");
+        pr_cont!(" with {}\n", "args");
+
+        Ok(RustPrint)
+    }
+}
+
+impl Drop for RustPrint {
+    fn drop(&mut self) {
+        pr_info!("Rust printing macros sample (exit)\n");
+    }
+}
diff --git a/samples/rust/rust_random.rs b/samples/rust/rust_random.rs
new file mode 100644
index 000000000000..8ec87119aa9b
--- /dev/null
+++ b/samples/rust/rust_random.rs
@@ -0,0 +1,60 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Rust random device.
+//!
+//! Adapted from Alex Gaynor's original available at
+//! <https://github.com/alex/just-use/blob/master/src/lib.rs>.
+
+use kernel::{
+    file::{self, File},
+    io_buffer::{IoBufferReader, IoBufferWriter},
+    prelude::*,
+};
+
+module_misc_device! {
+    type: RandomFile,
+    name: b"rust_random",
+    author: b"Rust for Linux Contributors",
+    description: b"Just use /dev/urandom: Now with early-boot safety",
+    license: b"GPL",
+}
+
+struct RandomFile;
+
+impl file::Operations for RandomFile {
+    kernel::declare_file_operations!(read, write, read_iter, write_iter);
+
+    fn open(_data: &(), _file: &File) -> Result {
+        Ok(())
+    }
+
+    fn read(_this: (), file: &File, buf: &mut impl IoBufferWriter, _: u64) -> Result<usize> {
+        let total_len = buf.len();
+        let mut chunkbuf = [0; 256];
+
+        while !buf.is_empty() {
+            let len = chunkbuf.len().min(buf.len());
+            let chunk = &mut chunkbuf[0..len];
+
+            if file.is_blocking() {
+                kernel::random::getrandom(chunk)?;
+            } else {
+                kernel::random::getrandom_nonblock(chunk)?;
+            }
+            buf.write_slice(chunk)?;
+        }
+        Ok(total_len)
+    }
+
+    fn write(_this: (), _file: &File, buf: &mut impl IoBufferReader, _: u64) -> Result<usize> {
+        let total_len = buf.len();
+        let mut chunkbuf = [0; 256];
+        while !buf.is_empty() {
+            let len = chunkbuf.len().min(buf.len());
+            let chunk = &mut chunkbuf[0..len];
+            buf.read_slice(chunk)?;
+            kernel::random::add_randomness(chunk);
+        }
+        Ok(total_len)
+    }
+}
diff --git a/samples/rust/rust_semaphore.rs b/samples/rust/rust_semaphore.rs
new file mode 100644
index 000000000000..702ac1fcb48a
--- /dev/null
+++ b/samples/rust/rust_semaphore.rs
@@ -0,0 +1,171 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Rust semaphore sample.
+//!
+//! A counting semaphore that can be used by userspace.
+//!
+//! The count is incremented by writes to the device. A write of `n` bytes results in an increment
+//! of `n`. It is decremented by reads; each read results in the count being decremented by 1. If
+//! the count is already zero, a read will block until another write increments it.
+//!
+//! This can be used in user space from the shell for example  as follows (assuming a node called
+//! `semaphore`): `cat semaphore` decrements the count by 1 (waiting for it to become non-zero
+//! before decrementing); `echo -n 123 > semaphore` increments the semaphore by 3, potentially
+//! unblocking up to 3 blocked readers.
+
+use core::sync::atomic::{AtomicU64, Ordering};
+use kernel::{
+    condvar_init, declare_file_operations,
+    file::{self, File, IoctlCommand, IoctlHandler},
+    io_buffer::{IoBufferReader, IoBufferWriter},
+    miscdev::Registration,
+    mutex_init,
+    prelude::*,
+    sync::{CondVar, Mutex, Ref, UniqueRef},
+    user_ptr::{UserSlicePtrReader, UserSlicePtrWriter},
+};
+
+module! {
+    type: RustSemaphore,
+    name: b"rust_semaphore",
+    author: b"Rust for Linux Contributors",
+    description: b"Rust semaphore sample",
+    license: b"GPL",
+}
+
+struct SemaphoreInner {
+    count: usize,
+    max_seen: usize,
+}
+
+struct Semaphore {
+    changed: CondVar,
+    inner: Mutex<SemaphoreInner>,
+}
+
+struct FileState {
+    read_count: AtomicU64,
+    shared: Ref<Semaphore>,
+}
+
+impl FileState {
+    fn consume(&self) -> Result {
+        let mut inner = self.shared.inner.lock();
+        while inner.count == 0 {
+            if self.shared.changed.wait(&mut inner) {
+                return Err(EINTR);
+            }
+        }
+        inner.count -= 1;
+        Ok(())
+    }
+}
+
+impl file::Operations for FileState {
+    type Data = Box<Self>;
+    type OpenData = Ref<Semaphore>;
+
+    declare_file_operations!(read, write, ioctl);
+
+    fn open(shared: &Ref<Semaphore>, _file: &File) -> Result<Box<Self>> {
+        Ok(Box::try_new(Self {
+            read_count: AtomicU64::new(0),
+            shared: shared.clone(),
+        })?)
+    }
+
+    fn read(this: &Self, _: &File, data: &mut impl IoBufferWriter, offset: u64) -> Result<usize> {
+        if data.is_empty() || offset > 0 {
+            return Ok(0);
+        }
+        this.consume()?;
+        data.write_slice(&[0u8; 1])?;
+        this.read_count.fetch_add(1, Ordering::Relaxed);
+        Ok(1)
+    }
+
+    fn write(this: &Self, _: &File, data: &mut impl IoBufferReader, _offs: u64) -> Result<usize> {
+        {
+            let mut inner = this.shared.inner.lock();
+            inner.count = inner.count.saturating_add(data.len());
+            if inner.count > inner.max_seen {
+                inner.max_seen = inner.count;
+            }
+        }
+
+        this.shared.changed.notify_all();
+        Ok(data.len())
+    }
+
+    fn ioctl(this: &Self, file: &File, cmd: &mut IoctlCommand) -> Result<i32> {
+        cmd.dispatch::<Self>(this, file)
+    }
+}
+
+struct RustSemaphore {
+    _dev: Pin<Box<Registration<FileState>>>,
+}
+
+impl kernel::Module for RustSemaphore {
+    fn init(name: &'static CStr, _module: &'static ThisModule) -> Result<Self> {
+        pr_info!("Rust semaphore sample (init)\n");
+
+        let mut sema = Pin::from(UniqueRef::try_new(Semaphore {
+            // SAFETY: `condvar_init!` is called below.
+            changed: unsafe { CondVar::new() },
+
+            // SAFETY: `mutex_init!` is called below.
+            inner: unsafe {
+                Mutex::new(SemaphoreInner {
+                    count: 0,
+                    max_seen: 0,
+                })
+            },
+        })?);
+
+        // SAFETY: `changed` is pinned when `sema` is.
+        let pinned = unsafe { sema.as_mut().map_unchecked_mut(|s| &mut s.changed) };
+        condvar_init!(pinned, "Semaphore::changed");
+
+        // SAFETY: `inner` is pinned when `sema` is.
+        let pinned = unsafe { sema.as_mut().map_unchecked_mut(|s| &mut s.inner) };
+        mutex_init!(pinned, "Semaphore::inner");
+
+        Ok(Self {
+            _dev: Registration::new_pinned(fmt!("{name}"), sema.into())?,
+        })
+    }
+}
+
+impl Drop for RustSemaphore {
+    fn drop(&mut self) {
+        pr_info!("Rust semaphore sample (exit)\n");
+    }
+}
+
+const IOCTL_GET_READ_COUNT: u32 = 0x80086301;
+const IOCTL_SET_READ_COUNT: u32 = 0x40086301;
+
+impl IoctlHandler for FileState {
+    type Target<'a> = &'a Self;
+
+    fn read(this: &Self, _: &File, cmd: u32, writer: &mut UserSlicePtrWriter) -> Result<i32> {
+        match cmd {
+            IOCTL_GET_READ_COUNT => {
+                writer.write(&this.read_count.load(Ordering::Relaxed))?;
+                Ok(0)
+            }
+            _ => Err(EINVAL),
+        }
+    }
+
+    fn write(this: &Self, _: &File, cmd: u32, reader: &mut UserSlicePtrReader) -> Result<i32> {
+        match cmd {
+            IOCTL_SET_READ_COUNT => {
+                this.read_count.store(reader.read()?, Ordering::Relaxed);
+                Ok(0)
+            }
+            _ => Err(EINVAL),
+        }
+    }
+}
diff --git a/samples/rust/rust_semaphore_c.c b/samples/rust/rust_semaphore_c.c
new file mode 100644
index 000000000000..7672b0b4c105
--- /dev/null
+++ b/samples/rust/rust_semaphore_c.c
@@ -0,0 +1,212 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Rust semaphore sample (in C, for comparison)
+ *
+ * This is a C implementation of `rust_semaphore.rs`. Refer to the description
+ * in that file for details on the device.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/miscdevice.h>
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/slab.h>
+#include <linux/refcount.h>
+#include <linux/wait.h>
+
+#define IOCTL_GET_READ_COUNT _IOR('c', 1, u64)
+#define IOCTL_SET_READ_COUNT _IOW('c', 1, u64)
+
+struct semaphore_state {
+	struct kref ref;
+	struct miscdevice miscdev;
+	wait_queue_head_t changed;
+	struct mutex mutex;
+	size_t count;
+	size_t max_seen;
+};
+
+struct file_state {
+	atomic64_t read_count;
+	struct semaphore_state *shared;
+};
+
+static int semaphore_consume(struct semaphore_state *state)
+{
+	DEFINE_WAIT(wait);
+
+	mutex_lock(&state->mutex);
+	while (state->count == 0) {
+		prepare_to_wait(&state->changed, &wait, TASK_INTERRUPTIBLE);
+		mutex_unlock(&state->mutex);
+		schedule();
+		finish_wait(&state->changed, &wait);
+		if (signal_pending(current))
+			return -EINTR;
+		mutex_lock(&state->mutex);
+	}
+
+	state->count--;
+	mutex_unlock(&state->mutex);
+
+	return 0;
+}
+
+static int semaphore_open(struct inode *nodp, struct file *filp)
+{
+	struct semaphore_state *shared =
+		container_of(filp->private_data, struct semaphore_state, miscdev);
+	struct file_state *state;
+
+	state = kzalloc(sizeof(*state), GFP_KERNEL);
+	if (!state)
+		return -ENOMEM;
+
+	kref_get(&shared->ref);
+	state->shared = shared;
+	atomic64_set(&state->read_count, 0);
+
+	filp->private_data = state;
+
+	return 0;
+}
+
+static ssize_t semaphore_write(struct file *filp, const char __user *buffer, size_t count,
+			       loff_t *ppos)
+{
+	struct file_state *state = filp->private_data;
+	struct semaphore_state *shared = state->shared;
+
+	mutex_lock(&shared->mutex);
+
+	shared->count += count;
+	if (shared->count < count)
+		shared->count = SIZE_MAX;
+
+	if (shared->count > shared->max_seen)
+		shared->max_seen = shared->count;
+
+	mutex_unlock(&shared->mutex);
+
+	wake_up_all(&shared->changed);
+
+	return count;
+}
+
+static ssize_t semaphore_read(struct file *filp, char __user *buffer,
+			      size_t count, loff_t *ppos)
+{
+	struct file_state *state = filp->private_data;
+	char c = 0;
+	int ret;
+
+	if (count == 0 || *ppos > 0)
+		return 0;
+
+	ret = semaphore_consume(state->shared);
+	if (ret)
+		return ret;
+
+	if (copy_to_user(buffer, &c, sizeof(c)))
+		return -EFAULT;
+
+	atomic64_add(1, &state->read_count);
+	*ppos += 1;
+	return 1;
+}
+
+static long semaphore_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
+{
+	struct file_state *state = filp->private_data;
+	void __user *buffer = (void __user *)arg;
+	u64 value;
+
+	switch (cmd) {
+	case IOCTL_GET_READ_COUNT:
+		value = atomic64_read(&state->read_count);
+		if (copy_to_user(buffer, &value, sizeof(value)))
+			return -EFAULT;
+		return 0;
+	case IOCTL_SET_READ_COUNT:
+		if (copy_from_user(&value, buffer, sizeof(value)))
+			return -EFAULT;
+		atomic64_set(&state->read_count, value);
+		return 0;
+	default:
+		return -EINVAL;
+	}
+}
+
+static void semaphore_free(struct kref *kref)
+{
+	struct semaphore_state *device;
+
+	device = container_of(kref, struct semaphore_state, ref);
+	kfree(device);
+}
+
+static int semaphore_release(struct inode *nodp, struct file *filp)
+{
+	struct file_state *state = filp->private_data;
+
+	kref_put(&state->shared->ref, semaphore_free);
+	kfree(state);
+	return 0;
+}
+
+static const struct file_operations semaphore_fops = {
+	.owner = THIS_MODULE,
+	.open = semaphore_open,
+	.read = semaphore_read,
+	.write = semaphore_write,
+	.compat_ioctl = semaphore_ioctl,
+	.release = semaphore_release,
+};
+
+static struct semaphore_state *device;
+
+static int __init semaphore_init(void)
+{
+	int ret;
+	struct semaphore_state *state;
+
+	pr_info("Rust semaphore sample (in C, for comparison) (init)\n");
+
+	state = kzalloc(sizeof(*state), GFP_KERNEL);
+	if (!state)
+		return -ENOMEM;
+
+	mutex_init(&state->mutex);
+	kref_init(&state->ref);
+	init_waitqueue_head(&state->changed);
+
+	state->miscdev.fops = &semaphore_fops;
+	state->miscdev.minor = MISC_DYNAMIC_MINOR;
+	state->miscdev.name = "semaphore";
+
+	ret = misc_register(&state->miscdev);
+	if (ret < 0) {
+		kfree(state);
+		return ret;
+	}
+
+	device = state;
+
+	return 0;
+}
+
+static void __exit semaphore_exit(void)
+{
+	pr_info("Rust semaphore sample (in C, for comparison) (exit)\n");
+
+	misc_deregister(&device->miscdev);
+	kref_put(&device->ref, semaphore_free);
+}
+
+module_init(semaphore_init);
+module_exit(semaphore_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Rust for Linux Contributors");
+MODULE_DESCRIPTION("Rust semaphore sample (in C, for comparison)");
diff --git a/samples/rust/rust_stack_probing.rs b/samples/rust/rust_stack_probing.rs
new file mode 100644
index 000000000000..1448fe8e1b56
--- /dev/null
+++ b/samples/rust/rust_stack_probing.rs
@@ -0,0 +1,36 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Rust stack probing sample.
+
+use kernel::prelude::*;
+
+module! {
+    type: RustStackProbing,
+    name: b"rust_stack_probing",
+    author: b"Rust for Linux Contributors",
+    description: b"Rust stack probing sample",
+    license: b"GPL",
+}
+
+struct RustStackProbing;
+
+impl kernel::Module for RustStackProbing {
+    fn init(_name: &'static CStr, _module: &'static ThisModule) -> Result<Self> {
+        pr_info!("Rust stack probing sample (init)\n");
+
+        // Including this large variable on the stack will trigger
+        // stack probing on the supported archs.
+        // This will verify that stack probing does not lead to
+        // any errors if we need to link `__rust_probestack`.
+        let x: [u64; 514] = core::hint::black_box([5; 514]);
+        pr_info!("Large array has length: {}\n", x.len());
+
+        Ok(RustStackProbing)
+    }
+}
+
+impl Drop for RustStackProbing {
+    fn drop(&mut self) {
+        pr_info!("Rust stack probing sample (exit)\n");
+    }
+}
diff --git a/samples/rust/rust_sync.rs b/samples/rust/rust_sync.rs
new file mode 100644
index 000000000000..46637ace2f7f
--- /dev/null
+++ b/samples/rust/rust_sync.rs
@@ -0,0 +1,93 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Rust synchronisation primitives sample.
+
+use kernel::prelude::*;
+use kernel::{
+    condvar_init, mutex_init, spinlock_init,
+    sync::{CondVar, Mutex, SpinLock},
+};
+
+module! {
+    type: RustSync,
+    name: b"rust_sync",
+    author: b"Rust for Linux Contributors",
+    description: b"Rust synchronisation primitives sample",
+    license: b"GPL",
+}
+
+kernel::init_static_sync! {
+    static SAMPLE_MUTEX: Mutex<u32> = 10;
+    static SAMPLE_CONDVAR: CondVar;
+}
+
+struct RustSync;
+
+impl kernel::Module for RustSync {
+    fn init(_name: &'static CStr, _module: &'static ThisModule) -> Result<Self> {
+        pr_info!("Rust synchronisation primitives sample (init)\n");
+
+        // Test mutexes.
+        {
+            // SAFETY: `init` is called below.
+            let mut data = Pin::from(Box::try_new(unsafe { Mutex::new(0) })?);
+            mutex_init!(data.as_mut(), "RustSync::init::data1");
+            *data.lock() = 10;
+            pr_info!("Value: {}\n", *data.lock());
+
+            // SAFETY: `init` is called below.
+            let mut cv = Pin::from(Box::try_new(unsafe { CondVar::new() })?);
+            condvar_init!(cv.as_mut(), "RustSync::init::cv1");
+
+            {
+                let mut guard = data.lock();
+                while *guard != 10 {
+                    let _ = cv.wait(&mut guard);
+                }
+            }
+            cv.notify_one();
+            cv.notify_all();
+            cv.free_waiters();
+        }
+
+        // Test static mutex + condvar.
+        *SAMPLE_MUTEX.lock() = 20;
+
+        {
+            let mut guard = SAMPLE_MUTEX.lock();
+            while *guard != 20 {
+                let _ = SAMPLE_CONDVAR.wait(&mut guard);
+            }
+        }
+
+        // Test spinlocks.
+        {
+            // SAFETY: `init` is called below.
+            let mut data = Pin::from(Box::try_new(unsafe { SpinLock::new(0) })?);
+            spinlock_init!(data.as_mut(), "RustSync::init::data2");
+            *data.lock() = 10;
+            pr_info!("Value: {}\n", *data.lock());
+
+            // SAFETY: `init` is called below.
+            let mut cv = Pin::from(Box::try_new(unsafe { CondVar::new() })?);
+            condvar_init!(cv.as_mut(), "RustSync::init::cv2");
+            {
+                let mut guard = data.lock();
+                while *guard != 10 {
+                    let _ = cv.wait(&mut guard);
+                }
+            }
+            cv.notify_one();
+            cv.notify_all();
+            cv.free_waiters();
+        }
+
+        Ok(RustSync)
+    }
+}
+
+impl Drop for RustSync {
+    fn drop(&mut self) {
+        pr_info!("Rust synchronisation primitives sample (exit)\n");
+    }
+}
-- 
2.36.1


^ permalink raw reply related	[relevance 3%]

* pull-request: bpf-next 2022-05-23
@ 2022-05-23 22:38  2% Daniel Borkmann
  0 siblings, 0 replies; 77+ results
From: Daniel Borkmann @ 2022-05-23 22:38 UTC (permalink / raw)
  To: davem; +Cc: kuba, pabeni, edumazet, daniel, ast, andrii, netdev, bpf

Hi David, hi Jakub, hi Paolo, hi Eric,

The following pull-request contains BPF updates for your *net-next* tree.

We've added 113 non-merge commits during the last 26 day(s) which contain
a total of 121 files changed, 7425 insertions(+), 1586 deletions(-).

There is a trivial merge conflict in net/core/sysctl_net_core.c between
commits 4c7f24f857c7 ("net: sysctl: introduce sysctl SYSCTL_THREE") from
net-next and f922c8972fb5 ("net: sysctl: Use SYSCTL_TWO instead of &two")
from bpf-next. To resolve it, just remove the 'static int three = 3;'.

The main changes are:

1) Speed up symbol resolution for kprobes multi-link attachments, from Jiri Olsa.

2) Add BPF dynamic pointer infrastructure e.g. to allow for dynamically sized ringbuf
   reservations without extra memory copies, from Joanne Koong.

3) Big batch of libbpf improvements towards libbpf 1.0 release, from Andrii Nakryiko.

4) Add BPF link iterator to traverse links via seq_file ops, from Dmitrii Dolgov.

5) Add source IP address to BPF tunnel key infrastructure, from Kaixi Fan.

6) Refine unprivileged BPF to disable only object-creating commands, from Alan Maguire.

7) Fix JIT blinding of ld_imm64 when they point to subprogs, from Alexei Starovoitov.

8) Add BPF access to mptcp_sock structures and their meta data, from Geliang Tang.

9) Add new BPF helper for access to remote CPU's BPF map elements, from Feng Zhou.

10) Allow attaching 64-bit cookie to BPF link of fentry/fexit/fmod_ret, from Kui-Feng Lee.

11) Follow-ups to typed pointer support in BPF maps, from Kumar Kartikeya Dwivedi.

12) Add busy-poll test cases to the XSK selftest suite, from Magnus Karlsson.

13) Improvements in BPF selftest test_progs subtest output, from Mykola Lysenko.

14) Fill bpf_prog_pack allocator areas with illegal instructions, from Song Liu.

15) Add generic batch operations for BPF map-in-map cases, from Takshak Chahande.

16) Make bpf_jit_enable more user friendly when permanently on 1, from Tiezhu Yang.

17) Fix an array overflow in bpf_trampoline_get_progs(), from Yuntao Wang.

Please consider pulling these changes from:

  git://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next.git

Thanks a lot!

Also thanks to reporters, reviewers and testers of commits in this pull-request:

Alexander Lobakin, Andrii Nakryiko, Björn Töpel, CKI Project, Daniel 
Müller, David Vernet, Ilya Leoshkevich, John Fastabend, kernel test 
robot, KP Singh, Kumar Kartikeya Dwivedi, Linus Torvalds, Maciej 
Fijalkowski, Martin KaFai Lau, Masami Hiramatsu, Matthieu Baerts, Mykola 
Lysenko, Nathan Chancellor, Peter Zijlstra (Intel), Shung-Hsi Yu, Song 
Liu, Veronika Kabatova, Yonghong Song

----------------------------------------------------------------

The following changes since commit 50c6afabfd2ae91a4ff0e2feb14fe702b0688ec5:

  Merge https://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next (2022-04-27 17:09:32 -0700)

are available in the Git repository at:

  https://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next.git 

for you to fetch changes up to 608b638ebf368f18431f47bbbd0d93828cbbdf83:

  Merge branch 'Dynamic pointers' (2022-05-23 14:31:29 -0700)

----------------------------------------------------------------
Alan Maguire (2):
      bpf: refine kernel.unprivileged_bpf_disabled behaviour
      selftests/bpf: add tests verifying unprivileged bpf behaviour

Alexei Starovoitov (11):
      Merge branch 'libbpf: allow to opt-out from BPF map creation'
      Merge branch 'Add source ip in bpf tunnel key'
      Merge branch 'bpf: bpf link iterator'
      Merge branch 'bpf: Speed up symbol resolving in kprobe multi link'
      Merge branch 'selftests: xsk: add busy-poll testing plus various fixes'
      Merge branch 'Follow ups for kptr series'
      Merge branch 'Introduce access remote cpu elem support in BPF percpu map'
      bpf: Fix combination of jit blinding and pointers to bpf subprogs.
      selftests/bpf: Check combination of jit blinding and pointers to bpf subprogs.
      Merge branch 'Start libbpf 1.0 dev cycle'
      Merge branch 'bpf: refine kernel.unprivileged_bpf_disabled behaviour'

Andrii Nakryiko (29):
      libbpf: Allow "incomplete" basic tracing SEC() definitions
      libbpf: Support target-less SEC() definitions for BTF-backed programs
      selftests/bpf: Use target-less SEC() definitions in various tests
      libbpf: Append "..." in fixed up log if CO-RE spec is truncated
      libbpf: Use libbpf_mem_ensure() when allocating new map
      libbpf: Allow to opt-out from creating BPF maps
      selftests/bpf: Test bpf_map__set_autocreate() and related log fixup logic
      selftests/bpf: Prevent skeleton generation race
      libbpf: Make __kptr and __kptr_ref unconditionally use btf_type_tag() attr
      libbpf: Improve usability of field-based CO-RE helpers
      selftests/bpf: Use both syntaxes for field-based CO-RE helpers
      libbpf: Complete field-based CO-RE helpers with field offset helper
      selftests/bpf: Add bpf_core_field_offset() tests
      libbpf: Provide barrier() and barrier_var() in bpf_helpers.h
      libbpf: Automatically fix up BPF_MAP_TYPE_RINGBUF size, if necessary
      selftests/bpf: Test libbpf's ringbuf size fix up logic
      Merge branch 'bpftool: fix feature output when helper probes fail'
      Merge branch 'Attach a cookie to a tracing program.'
      libbpf: Clean up ringbuf size adjustment implementation
      selftests/bpf: make fexit_stress test run in serial mode
      libbpf: Add safer high-level wrappers for map operations
      selftests/bpf: Convert some selftests to high-level BPF map APIs
      selftests/bpf: Fix usdt_400 test case
      libbpf: fix memory leak in attach_tp for target-less tracepoint program
      libbpf: fix up global symbol counting logic
      libbpf: start 1.0 development cycle
      libbpf: remove bpf_create_map*() APIs
      Merge branch 'bpf: mptcp: Support for mptcp_sock'
      Merge branch 'Dynamic pointers'

Benjamin Tissoires (1):
      bpf: Allow kfunc in tracing and syscall programs.

Colin Ian King (1):
      selftests/bpf: Fix spelling mistake: "unpriviliged" -> "unprivileged"

Daniel Müller (1):
      selftests/bpf: Enable CONFIG_FPROBE for self tests

Dmitrii Dolgov (4):
      bpf: Add bpf_link iterator
      selftests/bpf: Fix result check for test_bpf_hash_map
      selftests/bpf: Use ASSERT_* instead of CHECK
      selftests/bpf: Add bpf link iter test

Feng Zhou (3):
      bpf: add bpf_map_lookup_percpu_elem for percpu map
      selftests/bpf: add test case for bpf_map_lookup_percpu_elem
      selftests/bpf: Fix some bugs in map_lookup_percpu_elem testcase

Geliang Tang (6):
      bpf: Add bpf_skc_to_mptcp_sock_proto
      selftests/bpf: Enable CONFIG_IKCONFIG_PROC in config
      selftests/bpf: Test bpf_skc_to_mptcp_sock
      selftests/bpf: Verify token of struct mptcp_sock
      selftests/bpf: Verify ca_name of struct mptcp_sock
      selftests/bpf: Verify first of struct mptcp_sock

Hangbin Liu (1):
      selftests/bpf: Add missed ima_setup.sh in Makefile

Jason Wang (1):
      bpftool: Declare generator name

Jerome Marchand (1):
      samples: bpf: Don't fail for a missing VMLINUX_BTF when VMLINUX_H is provided

Jiri Olsa (6):
      kallsyms: Make kallsyms_on_each_symbol generally available
      ftrace: Add ftrace_lookup_symbols function
      fprobe: Resolve symbols with ftrace_lookup_symbols
      bpf: Resolve symbols with ftrace_lookup_symbols for kprobe multi link
      selftests/bpf: Add attach bench test
      libbpf: Add bpf_program__set_insns function

Joanne Koong (7):
      bpf: Add MEM_UNINIT as a bpf_type_flag
      bpf: Add verifier support for dynptrs
      bpf: Add bpf_dynptr_from_mem for local dynptrs
      bpf: Dynptr support for ring buffers
      bpf: Add bpf_dynptr_read and bpf_dynptr_write
      bpf: Add dynptr data slices
      selftests/bpf: Dynptr tests

Julia Lawall (2):
      libbpf: Fix typo in comment
      s390/bpf: Fix typo in comment

KP Singh (1):
      bpftool: bpf_link_get_from_fd support for LSM programs in lskel

Kaixi Fan (3):
      bpf: Add source ip in "struct bpf_tunnel_key"
      selftests/bpf: Move vxlan tunnel testcases to test_progs
      selftests/bpf: Replace bpf_trace_printk in tunnel kernel code

Kui-Feng Lee (5):
      bpf, x86: Generate trampolines from bpf_tramp_links
      bpf, x86: Create bpf_tramp_run_ctx on the caller thread's stack
      bpf, x86: Attach a cookie to fentry/fexit/fmod_ret/lsm.
      libbpf: Assign cookies to links in libbpf.
      selftest/bpf: The test cases of BPF cookie for fentry/fexit/fmod_ret/lsm.

Kumar Kartikeya Dwivedi (5):
      bpf: Fix sparse warning for bpf_kptr_xchg_proto
      bpf: Prepare prog_test_struct kfuncs for runtime tests
      selftests/bpf: Add negative C tests for kptrs
      selftests/bpf: Add tests for kptr_ref refcounting
      bpf: Suppress 'passing zero to PTR_ERR' warning

Larysa Zaremba (1):
      bpftool: Use sysfs vmlinux when dumping BTF by ID

Liu Jian (1):
      bpf, sockmap: Call skb_linearize only when required in sk_psock_skb_ingress_enqueue

Magnus Karlsson (10):
      selftests: xsk: cleanup bash scripts
      selftests: xsk: do not send zero-length packets
      selftests: xsk: run all tests for busy-poll
      selftests: xsk: fix reporting of failed tests
      selftests: xsk: add timeout to tests
      selftests: xsk: cleanup veth pair at ctrl-c
      selftests: xsk: introduce validation functions
      selftests: xsk: make the stats tests normal tests
      selftests: xsk: make stat tests not spin on getsockopt
      MAINTAINERS: Add maintainer to AF_XDP

Milan Landaverde (2):
      bpftool: Adjust for error codes from libbpf probes
      bpftool: Output message if no helpers found in feature probing

Mykola Lysenko (4):
      bpf/selftests: Add granular subtest output for prog_test
      selftests/bpf: Fix two memory leaks in prog_tests
      selftests/bpf: Fix subtest number formatting in test_progs
      selftests/bpf: Remove filtered subtests from output

Nicolas Rybowski (1):
      selftests/bpf: Add MPTCP test base

Song Liu (3):
      bpf: Fill new bpf_prog_pack with illegal instructions
      x86/alternative: Introduce text_poke_set
      bpf: Introduce bpf_arch_text_invalidate for bpf_prog_pack

Takshak Chahande (2):
      bpf: Extend batch operations for map-in-map bpf-maps
      selftests/bpf: Handle batch operations for map-in-map bpf-maps

Tiezhu Yang (5):
      bpf, docs: Remove duplicated word "instructions"
      bpf, docs: BPF_FROM_BE exists as alias for BPF_TO_BE
      bpf, docs: Fix typo "respetively" to "respectively"
      net: sysctl: Use SYSCTL_TWO instead of &two
      bpf: Print some info if disable bpf_jit_enable failed

Yonghong Song (2):
      selftests/bpf: fix a few clang compilation errors
      selftests/bpf: fix btf_dump/btf_dump due to recent clang change

Yosry Ahmed (1):
      selftests/bpf: Fix building bpf selftests statically

Yuntao Wang (3):
      bpf: Remove unused parameter from find_kfunc_desc_btf()
      bpf: Fix potential array overflow in bpf_trampoline_get_progs()
      selftests/bpf: Add missing trampoline program type to trampoline_count test

Zhengchao Shao (1):
      samples/bpf: Detach xdp prog when program exits unexpectedly in xdp_rxq_info_user

 Documentation/bpf/instruction-set.rst              |   4 +-
 MAINTAINERS                                        |   2 +
 arch/s390/net/bpf_jit_comp.c                       |   2 +-
 arch/x86/include/asm/text-patching.h               |   1 +
 arch/x86/kernel/alternative.c                      |  67 ++-
 arch/x86/net/bpf_jit_comp.c                        |  79 ++-
 include/linux/bpf.h                                | 122 +++-
 include/linux/bpf_types.h                          |   1 +
 include/linux/bpf_verifier.h                       |  20 +
 include/linux/btf_ids.h                            |   3 +-
 include/linux/ftrace.h                             |   6 +
 include/linux/kallsyms.h                           |   7 +-
 include/net/mptcp.h                                |   6 +
 include/uapi/linux/bpf.h                           | 113 ++++
 kernel/bpf/Makefile                                |   2 +-
 kernel/bpf/arraymap.c                              |  17 +
 kernel/bpf/bpf_lsm.c                               |  17 +
 kernel/bpf/bpf_struct_ops.c                        |  71 ++-
 kernel/bpf/btf.c                                   |   6 +
 kernel/bpf/core.c                                  |  29 +-
 kernel/bpf/hashtab.c                               |  45 +-
 kernel/bpf/helpers.c                               | 199 ++++++-
 kernel/bpf/link_iter.c                             | 107 ++++
 kernel/bpf/ringbuf.c                               |  78 +++
 kernel/bpf/syscall.c                               |  75 ++-
 kernel/bpf/trampoline.c                            | 118 ++--
 kernel/bpf/verifier.c                              | 324 +++++++++--
 kernel/kallsyms.c                                  |   3 +-
 kernel/trace/bpf_trace.c                           | 133 +++--
 kernel/trace/fprobe.c                              |  32 +-
 kernel/trace/ftrace.c                              |  62 ++
 net/bpf/bpf_dummy_struct_ops.c                     |  24 +-
 net/bpf/test_run.c                                 |  23 +-
 net/core/filter.c                                  |  27 +
 net/core/skmsg.c                                   |  22 +-
 net/core/sysctl_net_core.c                         |  13 +-
 net/mptcp/Makefile                                 |   2 +
 net/mptcp/bpf.c                                    |  21 +
 samples/bpf/Makefile                               |   9 +-
 samples/bpf/xdp_rxq_info_user.c                    |  22 +-
 scripts/bpf_doc.py                                 |   4 +
 tools/bpf/bpftool/btf.c                            |  62 +-
 tools/bpf/bpftool/feature.c                        |  22 +-
 tools/bpf/bpftool/gen.c                            |   5 +-
 tools/bpf/bpftool/link.c                           |   1 +
 tools/include/uapi/linux/bpf.h                     | 113 ++++
 tools/lib/bpf/Makefile                             |   2 +-
 tools/lib/bpf/bpf.c                                | 102 +---
 tools/lib/bpf/bpf.h                                |  46 +-
 tools/lib/bpf/bpf_core_read.h                      |  37 +-
 tools/lib/bpf/bpf_helpers.h                        |  29 +-
 tools/lib/bpf/libbpf.c                             | 475 ++++++++++++---
 tools/lib/bpf/libbpf.h                             | 156 +++++
 tools/lib/bpf/libbpf.map                           |  16 +-
 tools/lib/bpf/libbpf_version.h                     |   4 +-
 tools/testing/selftests/bpf/Makefile               |  18 +-
 tools/testing/selftests/bpf/bpf_tcp_helpers.h      |  13 +
 tools/testing/selftests/bpf/config                 |   4 +
 .../selftests/bpf/map_tests/map_in_map_batch_ops.c | 252 ++++++++
 tools/testing/selftests/bpf/network_helpers.c      |  40 +-
 tools/testing/selftests/bpf/network_helpers.h      |   2 +
 .../selftests/bpf/prog_tests/attach_probe.c        |  10 +
 .../testing/selftests/bpf/prog_tests/bpf_cookie.c  |  89 +++
 tools/testing/selftests/bpf/prog_tests/bpf_iter.c  | 261 ++++-----
 .../selftests/bpf/prog_tests/core_autosize.c       |   2 +-
 .../testing/selftests/bpf/prog_tests/core_reloc.c  |  13 +-
 .../testing/selftests/bpf/prog_tests/core_retro.c  |  17 +-
 tools/testing/selftests/bpf/prog_tests/dynptr.c    | 137 +++++
 .../selftests/bpf/prog_tests/fexit_stress.c        |   2 +-
 tools/testing/selftests/bpf/prog_tests/for_each.c  |  30 +-
 .../selftests/bpf/prog_tests/kprobe_multi_test.c   | 159 ++++-
 tools/testing/selftests/bpf/prog_tests/log_fixup.c |  37 +-
 .../selftests/bpf/prog_tests/lookup_and_delete.c   |  15 +-
 tools/testing/selftests/bpf/prog_tests/map_kptr.c  | 131 ++++-
 .../bpf/prog_tests/map_lookup_percpu_elem.c        |  58 ++
 tools/testing/selftests/bpf/prog_tests/mptcp.c     | 174 ++++++
 .../selftests/bpf/prog_tests/ringbuf_multi.c       |  12 -
 .../selftests/bpf/prog_tests/stacktrace_build_id.c |   8 +-
 .../bpf/prog_tests/stacktrace_build_id_nmi.c       |  11 +-
 .../testing/selftests/bpf/prog_tests/test_tunnel.c | 423 ++++++++++++++
 tools/testing/selftests/bpf/prog_tests/timer_mim.c |   2 +-
 .../selftests/bpf/prog_tests/trampoline_count.c    | 134 ++---
 .../selftests/bpf/prog_tests/unpriv_bpf_disabled.c | 312 ++++++++++
 tools/testing/selftests/bpf/prog_tests/usdt.c      |   6 +-
 tools/testing/selftests/bpf/progs/bpf_iter.h       |   7 +
 .../selftests/bpf/progs/bpf_iter_bpf_link.c        |  21 +
 .../bpf/progs/btf__core_reloc_size___diff_offs.c   |   3 +
 .../bpf/progs/btf_dump_test_case_syntax.c          |   2 +-
 .../testing/selftests/bpf/progs/core_reloc_types.h |  18 +
 tools/testing/selftests/bpf/progs/dynptr_fail.c    | 588 +++++++++++++++++++
 tools/testing/selftests/bpf/progs/dynptr_success.c | 164 ++++++
 tools/testing/selftests/bpf/progs/exhandler_kern.c |   2 -
 tools/testing/selftests/bpf/progs/kprobe_multi.c   |  14 +
 .../selftests/bpf/progs/kprobe_multi_empty.c       |  12 +
 tools/testing/selftests/bpf/progs/loop5.c          |   1 -
 tools/testing/selftests/bpf/progs/map_kptr.c       | 106 +++-
 tools/testing/selftests/bpf/progs/map_kptr_fail.c  | 418 +++++++++++++
 tools/testing/selftests/bpf/progs/mptcp_sock.c     |  88 +++
 tools/testing/selftests/bpf/progs/profiler1.c      |   1 -
 tools/testing/selftests/bpf/progs/pyperf.h         |   2 -
 .../selftests/bpf/progs/test_attach_probe.c        |  23 +-
 .../testing/selftests/bpf/progs/test_bpf_cookie.c  |  52 +-
 .../bpf/progs/test_core_reloc_existence.c          |  11 +-
 .../selftests/bpf/progs/test_core_reloc_size.c     |  31 +-
 tools/testing/selftests/bpf/progs/test_log_fixup.c |  26 +
 .../bpf/progs/test_map_lookup_percpu_elem.c        |  76 +++
 .../selftests/bpf/progs/test_module_attach.c       |   2 +-
 .../testing/selftests/bpf/progs/test_pkt_access.c  |   2 -
 .../selftests/bpf/progs/test_ringbuf_multi.c       |   2 +
 tools/testing/selftests/bpf/progs/test_subprogs.c  |   8 +
 .../selftests/bpf/progs/test_trampoline_count.c    |  16 +-
 .../testing/selftests/bpf/progs/test_tunnel_kern.c | 371 +++++++-----
 .../selftests/bpf/progs/test_unpriv_bpf_disabled.c |  83 +++
 tools/testing/selftests/bpf/test_progs.c           | 647 +++++++++++++++------
 tools/testing/selftests/bpf/test_progs.h           |  37 +-
 tools/testing/selftests/bpf/test_tunnel.sh         | 124 +---
 tools/testing/selftests/bpf/test_xsk.sh            |  53 +-
 tools/testing/selftests/bpf/verifier/map_kptr.c    |   4 +-
 tools/testing/selftests/bpf/xdpxceiver.c           | 547 +++++++++++------
 tools/testing/selftests/bpf/xdpxceiver.h           |  42 +-
 tools/testing/selftests/bpf/xsk_prereqs.sh         |  47 +-
 121 files changed, 7425 insertions(+), 1586 deletions(-)
 create mode 100644 kernel/bpf/link_iter.c
 create mode 100644 net/mptcp/bpf.c
 create mode 100644 tools/testing/selftests/bpf/map_tests/map_in_map_batch_ops.c
 create mode 100644 tools/testing/selftests/bpf/prog_tests/dynptr.c
 create mode 100644 tools/testing/selftests/bpf/prog_tests/map_lookup_percpu_elem.c
 create mode 100644 tools/testing/selftests/bpf/prog_tests/mptcp.c
 create mode 100644 tools/testing/selftests/bpf/prog_tests/test_tunnel.c
 create mode 100644 tools/testing/selftests/bpf/prog_tests/unpriv_bpf_disabled.c
 create mode 100644 tools/testing/selftests/bpf/progs/bpf_iter_bpf_link.c
 create mode 100644 tools/testing/selftests/bpf/progs/btf__core_reloc_size___diff_offs.c
 create mode 100644 tools/testing/selftests/bpf/progs/dynptr_fail.c
 create mode 100644 tools/testing/selftests/bpf/progs/dynptr_success.c
 create mode 100644 tools/testing/selftests/bpf/progs/kprobe_multi_empty.c
 create mode 100644 tools/testing/selftests/bpf/progs/map_kptr_fail.c
 create mode 100644 tools/testing/selftests/bpf/progs/mptcp_sock.c
 create mode 100644 tools/testing/selftests/bpf/progs/test_map_lookup_percpu_elem.c
 create mode 100644 tools/testing/selftests/bpf/progs/test_unpriv_bpf_disabled.c

^ permalink raw reply	[relevance 2%]

* [GIT PULL] Networking for 5.19
@ 2022-05-24 20:31  1% Jakub Kicinski
  0 siblings, 0 replies; 77+ results
From: Jakub Kicinski @ 2022-05-24 20:31 UTC (permalink / raw)
  To: torvalds; +Cc: kuba, davem, netdev, linux-kernel

Hi Linus!

We have a conflict with the sysctl changes, delete both sides:
https://lore.kernel.org/all/20220414112812.652190b5@canb.auug.org.au/
(the resolution from Stephen is a bit hard to read, but just delete).

There may be a warning if you pull after the bitmap tree PR, too:
https://lore.kernel.org/all/20220524082256.3b8033a9@canb.auug.org.au/

The following changes since commit d904c8cc0302393640bc29ee62193f88ddc53126:

  Merge tag 'net-5.18-rc8' of git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net (2022-05-19 05:50:29 -1000)

are available in the Git repository at:

  git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net-next.git tags/net-next-5.19

for you to fetch changes up to 57d7becda9c9e612e6b00676f2eecfac3e719e88:

  Merge branch 'ptp-ocp-various-updates' (2022-05-24 11:40:01 -0700)

----------------------------------------------------------------
Networking changes for 5.19.

Core
----

 - Support TCPv6 segmentation offload with super-segments larger than
   64k bytes using the IPv6 Jumbogram extension header (AKA BIG TCP).

 - Generalize skb freeing deferral to per-cpu lists, instead of
   per-socket lists.

 - Add a netdev statistic for packets dropped due to L2 address
   mismatch (rx_otherhost_dropped).

 - Continue work annotating skb drop reasons.

 - Accept alternative netdev names (ALT_IFNAME) in more netlink
   requests.

 - Add VLAN support for AF_PACKET SOCK_RAW GSO.

 - Allow receiving skb mark from the socket as a cmsg.

 - Enable memcg accounting for veth queues, sysctl tables and IPv6.

BPF
---

 - Add libbpf support for User Statically-Defined Tracing (USDTs).

 - Speed up symbol resolution for kprobes multi-link attachments.

 - Support storing typed pointers to referenced and unreferenced
   objects in BPF maps.

 - Add support for BPF link iterator.

 - Introduce access to remote CPU map elements in BPF per-cpu map.

 - Allow middle-of-the-road settings for the
   kernel.unprivileged_bpf_disabled sysctl.

 - Implement basic types of dynamic pointers e.g. to allow for
   dynamically sized ringbuf reservations without extra memory copies.

Protocols
---------

 - Retire port only listening_hash table, add a second bind table
   hashed by port and address. Avoid linear list walk when binding
   to very popular ports (e.g. 443).

 - Add bridge FDB bulk flush filtering support allowing user space
   to remove all FDB entries matching a condition.

 - Introduce accept_unsolicited_na sysctl for IPv6 to implement
   router-side changes for RFC9131.

 - Support for MPTCP path manager in user space.

 - Add MPTCP support for fallback to regular TCP for connections
   that have never connected additional subflows or transmitted
   out-of-sequence data (partial support for RFC8684 fallback).

 - Avoid races in MPTCP-level window tracking, stabilize and improve
   throughput.

 - Support lockless operation of GRE tunnels with seq numbers enabled.

 - WiFi support for host based BSS color collision detection.

 - Add support for SO_TXTIME/SCM_TXTIME on CAN sockets.

 - Support transmission w/o flow control in CAN ISOTP (ISO 15765-2).

 - Support zero-copy Tx with TLS 1.2 crypto offload (sendfile).

 - Allow matching on the number of VLAN tags via tc-flower.

 - Add tracepoint for tcp_set_ca_state().

Driver API
----------

 - Improve error reporting from classifier and action offload.

 - Add support for listing line cards in switches (devlink).

 - Add helpers for reporting page pool statistics with ethtool -S.

 - Add support for reading clock cycles when using PTP virtual clocks,
   instead of having the driver convert to time before reporting.
   This makes it possible to report time from different vclocks.

 - Support configuring low-latency Tx descriptor push via ethtool.

 - Separate Clause 22 and Clause 45 MDIO accesses more explicitly.

New hardware / drivers
----------------------

 - Ethernet:
   - Marvell's Octeon NIC PCI Endpoint support (octeon_ep)
   - Sunplus SP7021 SoC (sp7021_emac)
   - Add support for Renesas RZ/V2M (in ravb)
   - Add support for MediaTek mt7986 switches (in mtk_eth_soc)

 - Ethernet PHYs:
   - ADIN1100 industrial PHYs (w/ 10BASE-T1L and SQI reporting)
   - TI DP83TD510 PHY
   - Microchip LAN8742/LAN88xx PHYs

 - WiFi:
   - Driver for pureLiFi X, XL, XC devices (plfxlc)
   - Driver for Silicon Labs devices (wfx)
   - Support for WCN6750 (in ath11k)
   - Support Realtek 8852ce devices (in rtw89)

 - Mobile:
   - MediaTek T700 modems (Intel 5G 5000 M.2 cards)

 - CAN:
  - ctucanfd: add support for CTU CAN FD open-source IP core
    from Czech Technical University in Prague

Drivers
-------

 - Delete a number of old drivers still using virt_to_bus().

 - Ethernet NICs:
   - intel: support TSO on tunnels MPLS
   - broadcom: support multi-buffer XDP
   - nfp: support VF rate limiting
   - sfc: use hardware tx timestamps for more than PTP
   - mlx5: multi-port eswitch support
   - hyper-v: add support for XDP_REDIRECT
   - atlantic: XDP support (including multi-buffer)
   - macb: improve real-time perf by deferring Tx processing to NAPI

 - High-speed Ethernet switches:
   - mlxsw: implement basic line card information querying
   - prestera: add support for traffic policing on ingress and egress

 - Embedded Ethernet switches:
   - lan966x: add support for packet DMA (FDMA)
   - lan966x: add support for PTP programmable pins
   - ti: cpsw_new: enable bc/mc storm prevention

 - Qualcomm 802.11ax WiFi (ath11k):
   - Wake-on-WLAN support for QCA6390 and WCN6855
   - device recovery (firmware restart) support
   - support setting Specific Absorption Rate (SAR) for WCN6855
   - read country code from SMBIOS for WCN6855/QCA6390
   - enable keep-alive during WoWLAN suspend
   - implement remain-on-channel support

 - MediaTek WiFi (mt76):
   - support Wireless Ethernet Dispatch offloading packet movement
     between the Ethernet switch and WiFi interfaces
   - non-standard VHT MCS10-11 support
   - mt7921 AP mode support
   - mt7921 IPv6 NS offload support

 - Ethernet PHYs:
   - micrel: ksz9031/ksz9131: cabletest support
   - lan87xx: SQI support for T1 PHYs
   - lan937x: add interrupt support for link detection

Signed-off-by: Jakub Kicinski <kuba@kernel.org>

----------------------------------------------------------------
Abhishek Kumar (1):
      ath10k: skip ath10k_halt during suspend for driver state RESTARTING

Ahmad Fatoum (1):
      Bluetooth: hci_sync: use hci_skb_event() helper

Ajay Singh (5):
      wilc1000: increase firmware version array size
      wilc1000: use fixed function base register value to access SDIO_FBR_ENABLE_CSA
      wilc1000: fix crash observed in AP mode with cfg80211_register_netdevice()
      wilc1000: use 'u64' datatype for cookie variable
      wilc1000: add valid vmm_entry check before fetching from TX queue

Akira Yokosawa (1):
      docs: ctucanfd: Use 'kernel-figure' directive instead of 'figure'

Alaa Mohamed (6):
      selftests: net: fib_rule_tests: add support to select a test to run
      igb: Convert kmap() to kmap_local_page()
      rtnetlink: add extack support in fdb del handlers
      net: vxlan: Add extack support to vxlan_fdb_delete
      net: vxlan: Fix kernel coding style
      net: mscc: fix the alignment in ocelot_port_fdb_del()

Alan Maguire (11):
      libbpf: auto-resolve programs/libraries when necessary for uprobes
      libbpf: Support function name-based attach uprobes
      libbpf: Add auto-attach for uprobes based on section name
      selftests/bpf: Add tests for u[ret]probe attach by name
      selftests/bpf: Add tests for uprobe auto-attach via skeleton
      libbpf: Improve library identification for uprobe binary path resolution
      libbpf: Improve string parsing for uprobe auto-attach
      selftests/bpf: Uprobe tests should verify param/return values
      libbpf: Usdt aarch64 arg parsing support
      bpf: refine kernel.unprivileged_bpf_disabled behaviour
      selftests/bpf: add tests verifying unprivileged bpf behaviour

Alex Elder (17):
      net: ipa: compute proper aggregation limit
      net: ipa: drop an unneeded transaction reference
      net: ipa: rename a GSI error code
      net: ipa: ignore endianness if there is no header
      net: ipa: open-code ether_setup()
      net: ipa: move endpoint configuration data definitions
      net: ipa: rename a few endpoint config data types
      net: ipa: save a copy of endpoint default config
      net: ipa: make endpoint HOLB drop configurable
      net: ipa: support hard aggregation limits
      net: ipa: specify RX aggregation time limit in config data
      net: ipa: kill gsi_trans_commit_wait_timeout()
      net: ipa: count the number of modem TX endpoints
      net: ipa: get rid of ipa_cmd_info->direction
      net: ipa: remove command direction argument
      net: ipa: remove command info pool
      net: ipa: use data space for command opcodes

Alexander Duyck (2):
      net: allow gso_max_size to exceed 65536
      net: allow gro_max_size to exceed 65536

Alexander Lobakin (6):
      samples: bpf: Fix linking xdp_router_ipv4 after migration
      ice: switch: add and use u16[] aliases to ice_adv_lkup_elem::{h, m}_u
      ice: switch: unobscurify bitops loop in ice_fill_adv_dummy_packet()
      ice: switch: use a struct to pass packet template params
      ice: switch: use convenience macros to declare dummy pkt templates
      ice: switch: convert packet template match code to rodata

Alexander Wetzel (1):
      rtl818x: Prevent using not initialized queues

Alexandru Ardelean (1):
      net: phy: adin1100: Add initial support for ADIN1100 industrial PHY

Alexandru Tachici (6):
      ethtool: Add 10base-T1L link mode entry
      net: phy: Add 10-BaseT1L registers
      net: phy: Add BaseT1 auto-negotiation registers
      net: phy: Add 10BASE-T1L support in phy-c45
      net: phy: adin1100: Add SQI support
      dt-bindings: net: phy: Add 10-baseT1L 2.4 Vpp

Alexei Starovoitov (15):
      Merge branch 'Add libbpf support for USDTs'
      Merge branch 'Ensure type tags are always ordered first in BTF'
      Merge branch 'Introduce typed pointer support in BPF maps'
      Merge branch 'Teach libbpf to "fix up" BPF verifier log'
      Merge branch 'libbpf: allow to opt-out from BPF map creation'
      Merge branch 'Add source ip in bpf tunnel key'
      Merge branch 'bpf: bpf link iterator'
      Merge branch 'bpf: Speed up symbol resolving in kprobe multi link'
      Merge branch 'selftests: xsk: add busy-poll testing plus various fixes'
      Merge branch 'Follow ups for kptr series'
      Merge branch 'Introduce access remote cpu elem support in BPF percpu map'
      bpf: Fix combination of jit blinding and pointers to bpf subprogs.
      selftests/bpf: Check combination of jit blinding and pointers to bpf subprogs.
      Merge branch 'Start libbpf 1.0 dev cycle'
      Merge branch 'bpf: refine kernel.unprivileged_bpf_disabled behaviour'

Alvin Šipraga (1):
      net: dsa: realtek: rtl8366rb: Serialize indirect PHY register access

Amit Cohen (2):
      selftests: fib_nexthops: Make the test more robust
      selftests: fib_nexthops: Make ping timeout configurable

Andrea Parri (Microsoft) (1):
      hv_netvsc: Print value of invalid ID in netvsc_send_{completion,tx_complete}()

Andrejs Cainikovs (2):
      mwifiex: Select firmware based on strapping
      mwifiex: Add SD8997 SDIO-UART firmware

Andrew Lunn (5):
      net: phylink: Convert to mdiobus_c45_{read|write}
      net: phy: Convert to mdiobus_c45_{read|write}
      net: phy: bcm87xx: Use mmd helpers
      net: dsa: sja1105: Convert to mdiobus_c45_read
      net: pcs: pcs-xpcs: Convert to mdiobus_c45_read

Andrii Nakryiko (63):
      Merge branch 'libbpf: name-based u[ret]probe attach'
      Merge branch 'bpf/bpftool: add program & link type names'
      libbpf: Add BPF-side of USDT support
      libbpf: Wire up USDT API and bpf_link integration
      libbpf: Add USDT notes parsing and resolution logic
      libbpf: Wire up spec management and other arch-independent USDT logic
      libbpf: Add x86-specific USDT arg spec parsing logic
      selftests/bpf: Add basic USDT selftests
      selftests/bpf: Add urandom_read shared lib and USDTs
      Merge branch 'libbpf: uprobe name-based attach followups'
      libbpf: Fix use #ifdef instead of #if to avoid compiler warning
      Merge branch 'Add USDT support for s390'
      libbpf: Use strlcpy() in path resolution fallback logic
      libbpf: Allow WEAK and GLOBAL bindings during BTF fixup
      libbpf: Don't error out on CO-RE relos for overriden weak subprogs
      libbpf: Use weak hidden modifier for USDT BPF-side API functions
      selftests/bpf: Add CO-RE relos into linked_funcs selftests
      Merge branch 'bpf: RLIMIT_MEMLOCK cleanups'
      libbpf: Support opting out from autoloading BPF programs declaratively
      selftests/bpf: Use non-autoloaded programs in few tests
      Merge branch 'Support riscv libbpf USDT arg parsing logic'
      bpf: Allow attach TRACING programs through LINK_CREATE command
      libbpf: Teach bpf_link_create() to fallback to bpf_raw_tracepoint_open()
      selftests/bpf: Switch fexit_stress to bpf_link_create() API
      libbpf: Fix anonymous type check in CO-RE logic
      libbpf: Drop unhelpful "program too large" guess
      libbpf: Fix logic for finding matching program for CO-RE relocation
      libbpf: Avoid joining .BTF.ext data with BPF programs by section name
      selftests/bpf: Add CO-RE relos and SEC("?...") to linked_funcs selftests
      libbpf: Record subprog-resolved CO-RE relocations unconditionally
      libbpf: Refactor CO-RE relo human description formatting routine
      libbpf: Simplify bpf_core_parse_spec() signature
      libbpf: Fix up verifier log for unguarded failed CO-RE relos
      selftests/bpf: Add libbpf's log fixup logic selftests
      libbpf: Allow "incomplete" basic tracing SEC() definitions
      libbpf: Support target-less SEC() definitions for BTF-backed programs
      selftests/bpf: Use target-less SEC() definitions in various tests
      libbpf: Append "..." in fixed up log if CO-RE spec is truncated
      libbpf: Use libbpf_mem_ensure() when allocating new map
      libbpf: Allow to opt-out from creating BPF maps
      selftests/bpf: Test bpf_map__set_autocreate() and related log fixup logic
      selftests/bpf: Prevent skeleton generation race
      libbpf: Make __kptr and __kptr_ref unconditionally use btf_type_tag() attr
      libbpf: Improve usability of field-based CO-RE helpers
      selftests/bpf: Use both syntaxes for field-based CO-RE helpers
      libbpf: Complete field-based CO-RE helpers with field offset helper
      selftests/bpf: Add bpf_core_field_offset() tests
      libbpf: Provide barrier() and barrier_var() in bpf_helpers.h
      libbpf: Automatically fix up BPF_MAP_TYPE_RINGBUF size, if necessary
      selftests/bpf: Test libbpf's ringbuf size fix up logic
      Merge branch 'bpftool: fix feature output when helper probes fail'
      Merge branch 'Attach a cookie to a tracing program.'
      libbpf: Clean up ringbuf size adjustment implementation
      selftests/bpf: make fexit_stress test run in serial mode
      libbpf: Add safer high-level wrappers for map operations
      selftests/bpf: Convert some selftests to high-level BPF map APIs
      selftests/bpf: Fix usdt_400 test case
      libbpf: fix memory leak in attach_tp for target-less tracepoint program
      libbpf: fix up global symbol counting logic
      libbpf: start 1.0 development cycle
      libbpf: remove bpf_create_map*() APIs
      Merge branch 'bpf: mptcp: Support for mptcp_sock'
      Merge branch 'Dynamic pointers'

Andy Gospodarek (11):
      bnxt: refactor bnxt_rx_xdp to separate xdp_init_buff/xdp_prepare_buff
      bnxt: add flag to denote that an xdp program is currently attached
      bnxt: refactor bnxt_rx_pages operate on skb_shared_info
      bnxt: rename bnxt_rx_pages to bnxt_rx_agg_pages_skb
      bnxt: adding bnxt_rx_agg_pages_xdp for aggregated xdp
      bnxt: set xdp_buff pfmemalloc flag if needed
      bnxt: change receive ring space parameters
      bnxt: add page_pool support for aggregation ring when using xdp
      bnxt: adding bnxt_xdp_build_skb to build skb from multibuffer xdp_buff
      bnxt: support transmit and free of aggregation buffers
      bnxt: XDP multibuffer enablement

Andy Shevchenko (2):
      firmware: tee_bnxt: Use UUID API for exporting the UUID
      bcma: gpio: Switch to use fwnode instead of of_node

Anilkumar Kolli (1):
      ath11k: Reuse the available memory after firmware reload

Ansuel Smith (6):
      net: dsa: qca8k: drop MTU tracking from qca8k_priv
      net: dsa: qca8k: drop port_sts from qca8k_priv
      net: dsa: qca8k: rework and simplify mdiobus logic
      net: dsa: qca8k: drop dsa_switch_ops from qca8k_priv
      net: dsa: qca8k: correctly handle mdio read error
      net: dsa: qca8k: unify bus id naming with legacy and OF mdio bus

Artem Savkov (4):
      selftests/bpf: Use bpf_num_possible_cpus() in per-cpu map allocations
      selftests/bpf: Fix attach tests retcode checks
      selftests/bpf: Fix prog_tests uprobe_autoattach compilation error
      selftests/bpf: Fix map tests errno checks

Arun Ajith S (2):
      net/ipv6: Introduce accept_unsolicited_na knob to implement router-side changes for RFC9131
      net/ipv6: Enforce limits for accept_unsolicited_na sysctl

Arun Ramadoss (13):
      net: phy: LAN87xx: add ethtool SQI support
      MAINTAINERS: Add maintainers for Microchip T1 Phy driver
      net: phy: LAN937x: add interrupt support for link detection
      net: dsa: ksz: added the generic port_stp_state_set function
      net: dsa: ksz9477: move get_stats64 to ksz_common.c
      net: dsa: microchip: ksz8795: update the port_cnt value in ksz_chip_data
      net: dsa: microchip: move ksz_chip_data to ksz_common
      net: dsa: microchip: perform the compatibility check for dev probed
      net: dsa: microchip: move struct mib_names to ksz_chip_data
      net: dsa: microchip: move port memory allocation to ksz_common
      net: dsa: microchip: move get_strings to ksz_common
      net: dsa: microchip: add the phylink get_caps
      net: dsa: microchip: remove unused members in ksz_device

Arınç ÜNAL (1):
      net: bridge: offload BR_HAIRPIN_MODE, BR_ISOLATED, BR_MULTICAST_TO_UNICAST

Avraham Stern (1):
      iwlwifi: mei: clear the sap data header before sending

Aya Levin (1):
      net/mlx5e: Allow relaxed ordering over VFs

Baochen Qiang (8):
      ath11k: enable PLATFORM_CAP_PCIE_GLOBAL_RESET QMI host capability
      ath11k: Remove unnecessary delay in ath11k_core_suspend
      ath11k: Add support for SAR
      ath11k: Don't use GFP_KERNEL in atomic context
      ath11k: Handle keepalive during WoWLAN suspend and resume
      ath11k: Implement remain-on-channel support
      ath11k: Don't check arvif->is_started before sending management frames
      ath11k: Designating channel frequency when sending management frames

Baowen Zheng (1):
      nfp: support 802.1ad VLAN assingment to VF

Benjamin Stürz (1):
      wcn36xx: Improve readability of wcn36xx_caps_name

Benjamin Tissoires (1):
      bpf: Allow kfunc in tracing and syscall programs.

Bernard Zhao (1):
      ethernet/ti: delete if NULL check befort devm_kfree

Bert Kenward (1):
      sfc: use hardware tx timestamps for more than PTP

Biju Das (1):
      dt-bindings: can: renesas,rcar-canfd: Document RZ/G2UL support

Bin Chen (2):
      rtnetlink: verify rate parameters for calls to ndo_set_vf_rate
      nfp: VF rate limit support

Bjorn Helgaas (2):
      net: wan: atp: remove unused eeprom_delay()
      net: remove comments that mention obsolete __SLOW_DOWN_IO

Björn Töpel (1):
      xsk: Improve xdp_do_redirect() error codes

Bo Jiao (2):
      mt76: mt7915: disable RX_HDR_TRANS_SHORT
      mt76: mt7615/mt7915: do reset_work with mt76's work queue

Boris Pismenny (1):
      tls: Add opt-in zerocopy mode of sendfile()

Boris Sukholitko (5):
      net/sched: flower: Helper function for vlan ethtype checks
      net/sched: flower: Reduce identation after is_key_vlan refactoring
      flow_dissector: Add number of vlan tags dissector
      net/sched: flower: Add number of vlan tags filter
      net/sched: flower: Consider the number of tags for vlan filters

Borislav Petkov (2):
      IB/mlx5: Fix undefined behavior due to shift overflowing the constant
      bnx2x: Fix undefined behavior due to shift overflowing the constant

Brian Gix (1):
      Bluetooth: Keep MGMT pending queue ordered FIFO

Carl Huang (6):
      ath11k: Add basic WoW functionalities
      ath11k: Add WoW net-detect functionality
      ath11k: implement hardware data filter
      ath11k: purge rx pktlog when entering WoW
      ath11k: support ARP and NS offload
      ath11k: support GTK rekey offload

Casper Andersson (1):
      net: sparx5: Add handling of host MDB entries

Chandrashekar Devegowda (1):
      net: wwan: t7xx: Add AT and MBIM WWAN ports

Chia-Yuan Li (5):
      rtw89: pci: refine pci pre_init function
      rtw89: ser: configure D-MAC interrupt mask
      rtw89: ser: configure C-MAC interrupt mask
      rtw89: 8852c: disable firmware watchdog if CPU disabled
      rtw89: 8852c: add 8852c specific BT-coexistence initial function

Chih-Kang Chang (3):
      rtw88: add HT MPDU density value for each chip
      rtw88: fix not disabling beacon filter after disconnection
      rtw88: fix hw scan may cause disconnect issue

Chin-Yen Lee (1):
      rtw88: adjust adaptivity option to 1

Ching-Te Ku (1):
      rtw89: coex: Add case for scan offload

Chris Chiu (2):
      rtl8xxxu: feed antenna information for cfg80211
      rtl8xxxu: fill up txrate info for gen1 chips

Chris Packham (3):
      dt-bindings: net: orion-mdio: Convert to JSON schema
      arm64: dts: armada-3720-turris-mox: Correct reg property for mdio devices
      dt-bindings: net: marvell,orion-mdio: Set unevaluatedProperties to false

Christophe JAILLET (4):
      mt76: mt7921: Fix the error handling path of mt7921_pci_probe()
      octeon_ep: Fix a memory leak in the error handling path of octep_request_irqs()
      octeon_ep: Fix irq releasing in the error handling path of octep_request_irqs()
      hinic: Avoid some over memory allocation

Christophe Leroy (4):
      orinoco: Prepare cleanup of powerpc's asm/prom.h
      can: mscan: mpc5xxx_can: Prepare cleanup of powerpc's asm/prom.h
      sungem: Prepare cleanup of powerpc's asm/prom.h
      net: ethernet: Prepare cleanup of powerpc's asm/prom.h

Coco Li (2):
      fou: Remove XRFM from NET_FOU Kconfig
      ipv6: Add hop-by-hop header to jumbograms in ip6_output

Colin Foster (4):
      net: mdio: mscc-miim: add local dev variable to cleanup probe function
      net: ethernet: ocelot: remove the need for num_stats initializer
      net: mscc: ocelot: remove unnecessary variable
      net: mscc: ocelot: add missed parentheses around macro argument

Colin Ian King (11):
      libbpf: Fix spelling mistake "libaries" -> "libraries"
      ath11k: Fix spelling mistake "reseting" -> "resetting"
      octeon_ep: Fix spelling mistake "inerrupts" -> "interrupts"
      myri10ge: remove redundant assignment to variable status
      net: hns3: Fix spelling mistake "actvie" -> "active"
      x25: remove redundant pointer dev
      ath11k: remove redundant assignment to variables vht_mcs and he_mcs
      net: ethernet: SP7021: Fix spelling mistake "Interrput" -> "Interrupt"
      mt76: mt7915: make read-only array ppet16_ppet8_ru3_ru0 static const
      mt76: mt7921: make read-only array ppet16_ppet8_ru3_ru0 static const
      selftests/bpf: Fix spelling mistake: "unpriviliged" -> "unprivileged"

Dan Carpenter (5):
      net: ethernet: mtk_eth_soc: use after free in __mtk_ppe_check_skb()
      ath9k_htc: fix potential out of bounds access with invalid rxstatus->rs_keyix
      net: ethernet: mtk_eth_soc: add check for allocation failure
      net: ethernet: SP7021: fix a use after free of skb->len
      net: ethernet: mtk_eth_soc: fix error code in mtk_flow_offload_replace()

Daniel Borkmann (1):
      Merge branch 'pr/bpf-sysctl' into bpf-next

Daniel Müller (1):
      selftests/bpf: Enable CONFIG_FPROBE for self tests

Daniele Palmas (1):
      net: usb: qmi_wwan: add Telit 0x1057 composition

Danielle Ratson (1):
      selftests: netdevsim: Increase sleep time in hw_stats_l3.sh test

David Ahern (1):
      net: Make msg_zerocopy_alloc static

David Bentham (1):
      net: ethernet: mtk_eth_soc: add ipv6 flow offload support

David Howells (12):
      rxrpc: Allow list of in-use local UDP endpoints to be viewed in /proc
      rxrpc: Use refcount_t rather than atomic_t
      rxrpc: Fix locking issue
      rxrpc: Automatically generate trace tag enums
      rxrpc: Return an error to sendmsg if call failed
      rxrpc, afs: Fix selection of abort codes
      afs: Adjust ACK interpretation to try and cope with NAT
      rxrpc: Fix listen() setting the bar too high for the prealloc rings
      rxrpc: Don't try to resend the request if we're receiving the reply
      rxrpc: Fix overlapping ACK accounting
      rxrpc: Don't let ack.previousPacket regress
      rxrpc: Fix decision on when to generate an IDLE ACK

David Ober (1):
      net: usb: r8152: Add in new Devices that are supported for Mac-Passthru

David S. Miller (80):
      Merge branch 'mscc-miim'
      Merge branch 'mtk_eth_soc-flo-offload-plus-wireless'
      Merge branch 'tls-rx-refactor-part-1'
      Merge branch 'bnxt-xdp-multi-buffer'
      Merge branch 'aspeed-mdio-c45'
      Merge branch '100GbE' of git://git.kernel.org/pub/scm/linux/kernel/git/tnguy/nex t-queue
      Merge branch 'net-sched-offload-failure-error-reporting'
      Merge branch 'tls-rx-refactoring-part-2'
      Merge branch 'icmp-skb-reason'
      Merge git://git.kernel.org/pub/scm/linux/kernel/git/netfilter/nf-next
      Merge branch 'mptcp-next'
      Merge branch 'tls-rx-refactor-part-3'
      Merge branch '40GbE' of git://git.kernel.org/pub/scm/linux/kernel/git/tnguy/next-queue
      Merge branch 'net-ti-storm-prevention-support'
      Merge branch 'br-flush-filtering'
      Merge branch 'octeon_ep-driver'
      Merge branch 'ip-ingress-skb-reason'
      Merge branch 'mneta-page_pool_get_stats'
      Merge branch 'mlxsw-line-card-prep'
      Merge branch 'emaclite-cleanups'
      Merge branch 'qca8k_preiv-shrink'
      Merge branch 'tcp-drop-reason-additions'
      Merge branch 'mlxsw-line-card'
      Merge branch 'dsa-cross-chip-notifier-cleanup'
      Merge branch 'atlantic-xdp-multi-buffer'
      Merge branch 'hns3-next'
      Merge branch 'net-sched-flower-num-vlan-tags'
      Merge tag 'linux-can-next-for-5.19-20220419' of git://git.kernel.org/pub/scm/linux/kernel/git/mkl/linux-can-next
      Merge branch 'mlxsw-line-card-status-tracking'
      Merge branch 'ipv6-only-sock'
      Merge branch 'zynqmp-phy-config-optional'
      Merge branch 'ipv6-RT_ONLINK-remove-prep'
      Merge branch 'mptcp-tcp-fallback'
      Merge branch 'dsa-selftests'
      Merge branch 'mlxsw-line-card-model'
      Merge branch 'mptcp-MP_FAIL-timeout'
      Merge branch 'lan966x-ptp-programmable-pins'
      Merge branch 'remove-virt_to_bus-drivers'
      Merge branch 'remove-NAPI_POLL_WEIGHT-copies'
      Merge branch 'ipv6-net-opts'
      Merge branch 'lan966x-phy-reset-remove'
      Merge branch 'UDP-sock_wfree-opts'
      Merge branch 'adin1100-industrial-PHY-support'
      Merge branch 'mptcp-pathmanager-api'
      Merge tag 'mlx5-updates-2022-05-03' of git://git.kernel.org/pub/scm/linux/kernel/git/saeed/linux
      Merge branch 'sfc-Siena-subdir'
      Merge branch 'mlxsw-updates'
      Merge branch '100GbE' of git://git.kernel.org/pub/scm/linux/kernel/git/tnguy/next-queue
      Merge branch 'nfp-flower-rework'
      Merge branch 'tso-gso-limit-split'
      Merge branch 'switch-drivers-to-netif_napi_add_weight'
      Merge branch 'mlxsw-dedicated-router-notification-block'
      Merge tag 'batadv-next-pullrequest-20220508' of git://git.open-mesh.org/linux-merge
      Merge branch 'wwan-t7xx'
      Merge branch 'vxlan_fdb_delete-extack'
      Merge branch 'add-ti-dp83td510-support'
      Merge branch 'lan8742-phy'
      Merge branch 'hns3-next'
      Merge tag 'mlx5-updates-2022-05-09' of git://git.kernel.org/pub/scm/linux/kernel/git/saeed/linux
      Merge branch 'debug-net'
      Merge branch 'lan95xx-no-polling'
      Merge branch 'bnxt_en-next'
      Merge git://git.kernel.org/pub/scm/linux/kernel/git/netfilter/nf-next
      Merge branch 'Renesas-RSZ-V2M-support'
      Merge branch 'big-tcp'
      Merge branch 'sk_bound_dev_if-annotations'
      Merge branch 'skb-drop-reason-boundary'
      Merge branch 'net-skb-defer-freeing-polish'
      Merge tag 'mlx5-updates-2022-05-17' of git://git.kernel.org/pub/scm/linux/kernel/git/saeed/linux
      Merge branch 'dsa-microchip-ksz_switch-refactor'
      Merge branch 'armada-3720-turris-mox-and-orion-mdio'
      Merge branch 'net-ipa-next'
      Merge branch 'ipa-next'
      Merge branch 'rxrpc-misc'
      Merge branch 'rxrpc-fixes'
      Merge branch 'ocelot-selftests'
      Merge branch 'dpaa2-swtso-fixes'
      Merge branch 'net-gcc12-warnings'
      Merge branch 'mt7986-support'
      Merge branch 'dsa-multi-cpu-port-part-two'

David Thompson (2):
      mlxbf_gige: increase MDIO polling rate to 5us
      mlxbf_gige: remove driver-managed interrupt counts

Deren Wu (2):
      mt76: fix antenna config missing in 6G cap
      mt76: mt7921: add ipv6 NS offload support

Dimitri John Ledkov (1):
      cfg80211: declare MODULE_FIRMWARE for regulatory.db

Dmitrii Dolgov (4):
      bpf: Add bpf_link iterator
      selftests/bpf: Fix result check for test_bpf_hash_map
      selftests/bpf: Use ASSERT_* instead of CHECK
      selftests/bpf: Add bpf link iter test

Dominique Martinet (2):
      bpftool, musl compat: Replace nftw with FTW_ACTIONRETVAL
      bpftool, musl compat: Replace sys/fcntl.h by fcntl.h

Dongliang Mu (1):
      rtlwifi: Use pr_warn instead of WARN_ONCE

Duoming Zhou (1):
      NFC: hci: fix sleep in atomic context bugs in nfc_hci_hcp_message_tx

Dylan Hung (3):
      dt-bindings: net: add reset property for aspeed, ast2600-mdio binding
      net: mdio: add reset control for Aspeed MDIO
      ARM: dts: aspeed: add reset properties into MDIO nodes

Dylan Muller (1):
      nfp: update nfp_X logging definitions

Edmond Gagnon (1):
      wcn36xx: Implement tx_rate reporting

Eli Cohen (3):
      net/mlx5: Lag, refactor lag state machine
      net/mlx5: Remove unused argument
      net/mlx5: Support multiport eswitch mode

Emmanuel Grumbach (2):
      iwlwifi: mvm: fix assert 1F04 upon reconfig
      iwlwifi: mvm: always tell the firmware to accept MCAST frames in BSS

Eric Dumazet (47):
      tcp: add accessors to read/set tp->snd_cwnd
      net_sched: make qdisc_reset() smaller
      ipv6: fix NULL deref in ip6_rcv_core()
      tcp: consume incoming skb leading to a reset
      tcp: get rid of rst_seq_match
      tcp: add drop reason support to tcp_validate_incoming()
      tcp: make tcp_rcv_state_process() drop monitor friendly
      tcp: add drop reasons to tcp_rcv_state_process()
      tcp: add two drop reasons for tcp_ack()
      tcp: add drop reason support to tcp_prune_ofo_queue()
      tcp: make tcp_rcv_synsent_state_process() drop monitor friend
      tcp: add drop reasons to tcp_rcv_synsent_state_process()
      tcp: add drop reason support to tcp_ofo_queue()
      tcp: fix signed/unsigned comparison
      net: generalize skb freeing deferral to per-cpu lists
      net: make sure net_rx_action() calls skb_defer_free_flush()
      tcp: drop skb dst in tcp_rcv_established()
      net: add include/net/net_debug.h
      net: add CONFIG_DEBUG_NET
      net: warn if transport header was not set
      net: remove two BUG() from skb_checksum_help()
      net: add more debug info in skb_checksum_help()
      inet: add READ_ONCE(sk->sk_bound_dev_if) in INET_MATCH()
      net: add IFLA_TSO_{MAX_SIZE|SEGS} attributes
      net: limit GSO_MAX_SIZE to 524280 bytes
      tcp_cubic: make hystart_ack_delay() aware of BIG TCP
      ipv6: add struct hop_jumbo_hdr definition
      ipv6/gso: remove temporary HBH/jumbo header
      ipv6/gro: insert temporary HBH/jumbo header
      net: loopback: enable BIG TCP packets
      veth: enable BIG TCP packets
      mlx4: support BIG TCP packets
      mlx5: support BIG TCP packets
      net: annotate races around sk->sk_bound_dev_if
      sctp: read sk->sk_bound_dev_if once in sctp_rcv()
      tcp: sk->sk_bound_dev_if once in inet_request_bound_dev_if()
      net: core: add READ_ONCE/WRITE_ONCE annotations for sk->sk_bound_dev_if
      dccp: use READ_ONCE() to read sk->sk_bound_dev_if
      inet: add READ_ONCE(sk->sk_bound_dev_if) in inet_csk_bind_conflict()
      net_sched: em_meta: add READ_ONCE() in var_sk_bound_if()
      l2tp: use add READ_ONCE() to fetch sk->sk_bound_dev_if
      ipv6: add READ_ONCE(sk->sk_bound_dev_if) in INET6_MATCH()
      inet: rename INET_MATCH()
      net: fix possible race in skb_attempt_defer_free()
      net: use napi_consume_skb() in skb_defer_free_flush()
      net: add skb_defer_max sysctl
      net: call skb_defer_free_flush() before each napi_poll()

Erik Stromdahl (2):
      ath10k: add support for MSDU IDs for USB devices
      ath10k: enable napi on RX path for usb

Erin MacNeil (1):
      net: SO_RCVMARK socket option for SO_MARK with recvmsg()

Ethan Yang (1):
      net: usb: qmi_wwan: add support for Sierra Wireless EM7590

Evelyn Tsai (1):
      mt76: fix MBSS index condition in DBDC mode

Eyal Birger (2):
      selftests/bpf: Remove unused variable from bpf_sk_assign test
      net: align SO_RCVMARK required privileges with SO_MARK

Fabio Estevam (2):
      net: phy: micrel: Allow probing without .driver_data
      net: phy: micrel: Use the kszphy probe/suspend/resume

Fei Qin (1):
      nfp: support VxLAN inner TSO with GSO_PARTIAL offload

Felix Fietkau (27):
      net: ethernet: mtk_eth_soc: add support for coherent DMA
      arm64: dts: mediatek: mt7622: add support for coherent DMA
      net: ethernet: mtk_eth_soc: add support for Wireless Ethernet Dispatch (WED)
      net: ethernet: mtk_eth_soc: implement flow offloading to WED devices
      arm64: dts: mediatek: mt7622: introduce nodes for Wireless Ethernet Dispatch
      net: ethernet: mtk_eth_soc: support TC_SETUP_BLOCK for PPE offload
      net: ethernet: mtk_eth_soc: allocate struct mtk_ppe separately
      net: ethernet: mtk_eth_soc: rework hardware flow table management
      net: ethernet: mtk_eth_soc: remove bridge flow offload type entry support
      net: ethernet: mtk_eth_soc: support creating mac address based offload entries
      net: ethernet: mtk_eth_soc/wed: fix sparse endian warnings
      mac80211: upgrade passive scan to active scan on DFS channels after beacon rx
      mt76: mt7915: fix DBDC default band selection on MT7915D
      mt76: mt7915: rework hardware/phy initialization
      mt76: reduce tx queue lock hold time
      mt76: dma: use kzalloc instead of devm_kzalloc for txwi
      mt76: mt7915: accept rx frames with non-standard VHT MCS10-11
      mt76: mt7921: accept rx frames with non-standard VHT MCS10-11
      mt76: fix use-after-free by removing a non-RCU wcid pointer
      mt76: fix rx reordering with non explicit / psmp ack policy
      mt76: do not attempt to reorder received 802.3 packets without agg session
      mt76: fix encap offload ethernet type check
      mt76: fix tx status related use-after-free race on station removal
      mt76: dma: add wrapper macro for accessing queue registers
      mt76: add support for overriding the device used for DMA mapping
      mt76: make number of tokens configurable dynamically
      mt76: mt7915: add Wireless Ethernet Dispatch support

Feng Zhou (3):
      bpf: add bpf_map_lookup_percpu_elem for percpu map
      selftests/bpf: add test case for bpf_map_lookup_percpu_elem
      selftests/bpf: Fix some bugs in map_lookup_percpu_elem testcase

Florent Fourcot (5):
      rtnetlink: return ENODEV when ifname does not exist and group is given
      rtnetlink: enable alt_ifname for setlink/newlink
      rtnetlink: return ENODEV when IFLA_ALT_IFNAME is used in dellink
      rtnetlink: return EINVAL when request cannot succeed
      Revert "rtnetlink: return EINVAL when request cannot succeed"

Florian Westphal (26):
      netfilter: ecache: move to separate structure
      netfilter: conntrack: split inner loop of list dumping to own function
      netfilter: cttimeout: inc/dec module refcount per object, not per use refcount
      selftests: netfilter: add fib expression forward test case
      mptcp: diag: switch to context structure
      mptcp: remove locking in mptcp_diag_fill_info
      mptcp: listen diag dump support
      selftests/mptcp: add diag listen tests
      mptcp: netlink: split mptcp_pm_parse_addr into two functions
      mptcp: netlink: allow userspace-driven subflow establishment
      netfilter: ecache: use dedicated list for event redelivery
      netfilter: conntrack: include ecache dying list in dumps
      netfilter: conntrack: remove the percpu dying list
      netfilter: cttimeout: decouple unlink and free on netns destruction
      netfilter: remove nf_ct_unconfirmed_destroy helper
      netfilter: extensions: introduce extension genid count
      netfilter: cttimeout: decouple unlink and free on netns destruction
      netfilter: conntrack: remove __nf_ct_unconfirmed_destroy
      netfilter: conntrack: remove unconfirmed list
      netfilter: conntrack: avoid unconditional local_bh_disable
      netfilter: nfnetlink: allow to detect if ctnetlink listeners exist
      netfilter: conntrack: un-inline nf_ct_ecache_ext_add
      netfilter: conntrack: add nf_conntrack_events autodetect mode
      netfilter: prefer extension check to pointer check
      netfilter: conntrack: remove pr_debug callsites from tcp tracker
      mptcp: sockopt: add TCP_DEFER_ACCEPT support

GONG, Ruiqi (1):
      net: mpls: fix memdup.cocci warning

Gal Pressman (4):
      net/mlx5e: Remove unused mlx5e_dcbnl_build_rep_netdev function
      net/mlx5e: IPoIB, Improve ethtool rxnfc callback structure in IPoIB
      net/mlx5e: Support partial GSO for tunnels over vlans
      net/mlx5e: Add XDP SQs to uplink representors steering tables

Gaosheng Cui (1):
      libbpf: Remove redundant non-null checks on obj_elf

Gavin Li (2):
      net/mlx5: Add exit route when waiting for FW
      net/mlx5: Increase FW pre-init timeout for health recovery

Geert Uytterhoeven (3):
      can: ctucanfd: Let users select instead of depend on CAN_CTUCANFD
      dt-bindings: can: renesas,rcar-canfd: Make interrupt-names required
      net: smc911x: Fix min() use in debug code

Geliang Tang (25):
      mptcp: add pm_nl_pernet helpers
      selftests/bpf: Drop duplicate max/min definitions
      mptcp: don't send RST for single subflow
      mptcp: add the fallback check
      mptcp: track and update contiguous data status
      mptcp: infinite mapping sending
      mptcp: infinite mapping receiving
      mptcp: add mib for infinite map sending
      mptcp: dump infinite_map field in mptcp_dump_mpext
      selftests: mptcp: add infinite map mibs check
      selftests: mptcp: add infinite map testcase
      mptcp: use mptcp_stop_timer
      mptcp: add data lock for sk timers
      mptcp: add MP_FAIL response support
      mptcp: reset subflow when MP_FAIL doesn't respond
      selftests: mptcp: check MP_FAIL response mibs
      selftests: mptcp: print extra msg in chk_csum_nr
      selftests: mptcp: fix a mp_fail test warning
      selftests: mptcp: add MP_FAIL reset testcase
      bpf: Add bpf_skc_to_mptcp_sock_proto
      selftests/bpf: Enable CONFIG_IKCONFIG_PROC in config
      selftests/bpf: Test bpf_skc_to_mptcp_sock
      selftests/bpf: Verify token of struct mptcp_sock
      selftests/bpf: Verify ca_name of struct mptcp_sock
      selftests/bpf: Verify first of struct mptcp_sock

Gerhard Engleder (6):
      ptp: Add cycles support for virtual clocks
      ptp: Request cycles for TX timestamp
      ptp: Pass hwtstamp to ptp_convert_timestamp()
      ptp: Support late timestamp determination
      ptp: Speed up vclock lookup
      tsnep: Add free running cycle counter support

Grant Seltzer (4):
      libbpf: Add error returns to two API functions
      libbpf: Update API functions usage to check error
      libbpf: Add documentation to API functions
      libbpf: Improve libbpf API documentation link position

Grygorii Strashko (4):
      net: ethernet: ti: cpsw: drop CPSW_HEADROOM define
      drivers: net: cpsw: ale: add broadcast/multicast rate limit support
      net: ethernet: ti: am65-cpsw: enable bc/mc storm prevention support
      net: ethernet: ti: cpsw_new: enable bc/mc storm prevention support

Guangbin Huang (2):
      net: hns3: add query vf ring and vector map relation
      net: hns3: fix incorrect type of argument in declaration of function hclge_comm_get_rss_indir_tbl

Guangguan Wang (3):
      net/smc: align the connect behaviour with TCP
      net/smc: send cdc msg inline if qp has sufficient inline space
      net/smc: rdma write inline if qp has sufficient inline space

Guillaume Nault (9):
      ipv4: Use dscp_t in struct fib_rt_info
      ipv4: Use dscp_t in struct fib_entry_notifier_info
      netdevsim: Use dscp_t in struct nsim_fib4_rt
      mlxsw: Use dscp_t in struct mlxsw_sp_fib4_entry
      net: marvell: prestera: Use dscp_t in struct prestera_kern_fib_cache
      ipv4: Don't reset ->flowi4_scope in ip_rt_fix_tos().
      ipv4: Avoid using RTO_ONLINK with ip_route_connect().
      ipv4: Initialise ->flowi4_scope properly in ICMP handlers.
      qed: Remove IP services API.

Guo Zhengkui (3):
      ipv6: exthdrs: use swap() instead of open coding it
      rtlwifi: btcoex: fix if == else warning
      net: smc911x: replace ternary operator with min()

Gustavo A. R. Silva (2):
      iwlwifi: fw: Replace zero-length arrays with flexible-array members
      iwlwifi: mei: Replace zero-length array with flexible-array member

H. Nikolaus Schaller (1):
      wl1251: dynamically allocate memory used for DMA

Haijun Liu (10):
      net: wwan: t7xx: Add control DMA interface
      net: wwan: t7xx: Add core components
      net: wwan: t7xx: Add port proxy infrastructure
      net: wwan: t7xx: Add control port
      net: wwan: t7xx: Data path HW layer
      net: wwan: t7xx: Add data path interface
      net: wwan: t7xx: Add WWAN network interface
      net: wwan: t7xx: Introduce power management
      net: wwan: t7xx: Runtime PM
      net: wwan: t7xx: Device deep sleep lock/unlock

Haim Dreyfuss (1):
      iwlwifi: mvm: use NULL instead of ERR_PTR when parsing wowlan status

Haiyang Zhang (1):
      hv_netvsc: Add support for XDP_REDIRECT

Haiyue Wang (1):
      bpf: Correct the comment for BTF kind bitfield

Hamid Zamani (1):
      brcmfmac: use ISO3166 country code and 0 rev as fallback on brcmfmac43602 chips

Hangbin Liu (3):
      net/af_packet: add VLAN support for AF_PACKET SOCK_RAW GSO
      selftests/bpf: Add missed ima_setup.sh in Makefile
      bonding: fix missed rcu protection

Hangyu Hua (1):
      mac80211: tx: delete a redundant if statement in ieee80211_check_fast_xmit()

Hao Chen (4):
      net: hns3: refactor hns3_set_ringparam()
      net: hns3: add log for setting tx spare buf size
      net: hns3: remove unnecessary line wrap for hns3_set_tunable
      net: hns3: fix access null pointer issue when set tx-buf-size as 0

Haowen Bai (12):
      selftests/bpf: Return true/false (not 1/0) from bool functions
      b43legacy: Fix assigning negative value to unsigned variable
      b43: Fix assigning negative value to unsigned variable
      ipw2x00: Fix potential NULL dereference in libipw_xmit()
      libbpf: Potential NULL dereference in usdt_manager_attach_usdt()
      sfc: ef10: Fix assigning negative value to unsigned variable
      ar5523: Use kzalloc instead of kmalloc/memset
      net: eql: Use kzalloc instead of kmalloc/memset
      tsnep: Remove useless null check before call of_node_put()
      net: mscc: ocelot: Remove useless code
      net/mlx5: Remove useless kfree
      net: thunderx: remove null check after call container_of()

Hari Chandrakanthan (2):
      ath11k: change fw build id format in driver init log
      ath11k: disable spectral scan during spectral deinit

Harini Katakam (1):
      net: macb: Fix PTP one step sync support

Hongbin Wang (1):
      ip6_tunnel: Remove duplicate assignments

Horatiu Vultur (11):
      net: lan966x: Add registers that are used for FDMA.
      net: lan966x: Expose functions that are needed by FDMA
      net: lan966x: Add FDMA functionality
      net: lan966x: Update FDMA to change MTU.
      dt-bindings: net: lan966x: Extend with the ptp external interrupt.
      net: lan966x: Change the PTP pin used to read/write the PHC.
      net: lan966x: Add registers used to configure the PTP pin
      net: lan966x: Add support for PTP_PF_PEROUT
      net: lan966x: Add support for PTP_PF_EXTTS
      net: lan966x: Fix compilation error
      net: lan966x: Fix use of pointer after being freed

Hsuan Hung (1):
      rtw89: 8852c: add settings to decrease the effect of DC

Ian Wienand (1):
      net: ethernet: set default assignment identifier to NET_NAME_ENUM

Ido Schimmel (17):
      net/sched: matchall: Take verbose flag into account when logging error messages
      net/sched: flower: Take verbose flag into account when logging error messages
      net/sched: act_api: Add extack to offload_act_setup() callback
      net/sched: act_gact: Add extack messages for offload failure
      net/sched: act_mirred: Add extack message for offload failure
      net/sched: act_mpls: Add extack messages for offload failure
      net/sched: act_pedit: Add extack message for offload failure
      net/sched: act_police: Add extack messages for offload failure
      net/sched: act_skbedit: Add extack messages for offload failure
      net/sched: act_tunnel_key: Add extack message for offload failure
      net/sched: act_vlan: Add extack message for offload failure
      net/sched: cls_api: Add extack message for unsupported action offload
      net/sched: matchall: Avoid overwriting error messages
      net/sched: flower: Avoid overwriting error messages
      mlxsw: spectrum_acl: Do not report activity for multicast routes
      mlxsw: spectrum_switchdev: Only query FDB notifications when necessary
      mlxsw: spectrum_router: Only query neighbour activity when necessary

Ilya Leoshkevich (5):
      selftests/bpf: Define SYS_NANOSLEEP_KPROBE_NAME for aarch64
      libbpf: Support Debian in resolve_full_path()
      libbpf: Minor style improvements in USDT code
      libbpf: Make BPF-side of USDT support work on big-endian machines
      libbpf: Add s390-specific USDT arg spec parsing logic

Ioana Ciornei (3):
      dpaa2-eth: retrieve the virtual address before dma_unmap
      dpaa2-eth: use the correct software annotation field
      dpaa2-eth: unmap the SGT buffer before accessing its contents

Ismael Luceno (1):
      Bluetooth: btusb: Add 0x0bda:0x8771 Realtek 8761BUV devices

Jacob Keller (6):
      ice: add newline to dev_dbg in ice_vf_fdir_dump_info
      ice: always check VF VSI pointer values
      ice: remove return value comment for ice_reset_all_vfs
      ice: fix wording in comment for ice_reset_vf
      ice: add a function comment for ice_cfg_mac_antispoof
      ice: remove period on argument description in ice_for_each_vf

Jaehee Park (2):
      selftests: net: vrf_strict_mode_test: add support to select a test to run
      wfx: use container_of() to get vif

Jakob Koschel (3):
      bpf: Replace usage of supported with dedicated list iterator variable
      netfilter: nf_tables: replace unnecessary use of list_for_each_entry_continue()
      rtlwifi: replace usage of found with dedicated list iterator variable

Jakub Kicinski (180):
      net: wan: remove the lanmedia (lmc) driver
      net: hyperv: remove use of bpf_op_t
      net: unexport a handful of dev_* functions
      net: extract a few internals from netdevice.h
      Merge branch 'net-create-a-net-core-internal-header'
      Merge git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net
      tls: rx: jump to a more appropriate label
      tls: rx: drop pointless else after goto
      tls: rx: don't store the record type in socket context
      tls: rx: don't store the decryption status in socket context
      tls: rx: init decrypted status in tls_read_size()
      tls: rx: use a define for tag length
      tls: rx: replace 'back' with 'offset'
      tls: rx: don't issue wake ups when data is decrypted
      tls: rx: refactor decrypt_skb_update()
      tls: hw: rx: use return value of tls_device_decrypted() to carry status
      net: atm: remove the ambassador driver
      Merge https://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next
      tls: rx: drop unnecessary arguments from tls_setup_from_iter()
      tls: rx: don't report text length from the bowels of decrypt
      tls: rx: wrap decryption arguments in a structure
      tls: rx: simplify async wait
      tls: rx: factor out writing ContentType to cmsg
      tls: rx: don't handle async in tls_sw_advance_skb()
      tls: rx: don't track the async count
      tls: rx: pull most of zc check out of the loop
      tls: rx: inline consuming the skb at the end of the loop
      tls: rx: clear ctx->recv_pkt earlier
      tls: rx: jump out for cases which need to leave skb on list
      Merge branch 'ipv4-convert-several-tos-fields-to-dscp_t'
      Merge branch 'mlx5-next' of https://git.kernel.org/pub/scm/linux/kernel/git/mellanox/linux
      Merge branch 'net-lan966x-add-support-for-fdma'
      Merge branch 'mlxsw-extend-device-registers-for-line-cards-support'
      tls: rx: consistently use unlocked accessors for rx_list
      tls: rx: reuse leave_on_list label for psock
      tls: rx: move counting TlsDecryptErrors for sync
      tls: rx: don't handle TLS 1.3 in the async crypto callback
      tls: rx: assume crypto always calls our callback
      tls: rx: treat process_rx_list() errors as transient
      tls: rx: return the already-copied data on crypto error
      tls: rx: use async as an in-out argument
      tls: rx: use MAX_IV_SIZE for allocations
      tls: rx: only copy IV from the packet for TLS 1.2
      Merge branch 'net-ethool-add-support-to-get-set-tx-push-by-ethtool-g-g'
      Merge branch 'ibmvnic-use-a-set-of-ltbs-per-pool'
      Merge branch 'add-ethtool-sqi-support-for-lan87xx-t1-phy'
      net: tls: fix async vs NIC crypto offload
      net: atm: remove support for Fujitsu FireStream ATM devices
      net: atm: remove support for Madge Horizon ATM devices
      net: atm: remove support for ZeitNet ZN122x ATM devices
      net: wan: remove support for COSA and SRP synchronous serial boards
      net: wan: remove support for Z85230-based devices
      net: hamradio: remove support for DMA SCC devices
      Merge https://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next
      Merge git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net
      eth: remove copies of the NAPI_POLL_WEIGHT define
      eth: smsc: remove a copy of the NAPI_POLL_WEIGHT define
      eth: cpsw: remove a copy of the NAPI_POLL_WEIGHT define
      eth: pch_gbe: remove a copy of the NAPI_POLL_WEIGHT define
      eth: mtk_eth_soc: remove a copy of the NAPI_POLL_WEIGHT define
      usb: lan78xx: remove a copy of the NAPI_POLL_WEIGHT define
      slic: remove a copy of the NAPI_POLL_WEIGHT define
      net: bgmac: remove a copy of the NAPI_POLL_WEIGHT define
      eth: atlantic: remove a copy of the NAPI_POLL_WEIGHT define
      eth: benet: remove a copy of the NAPI_POLL_WEIGHT define
      eth: gfar: remove a copy of the NAPI_POLL_WEIGHT define
      eth: vxge: remove a copy of the NAPI_POLL_WEIGHT define
      eth: spider: remove a copy of the NAPI_POLL_WEIGHT define
      eth: velocity: remove a copy of the NAPI_POLL_WEIGHT define
      qeth: remove a copy of the NAPI_POLL_WEIGHT define
      Merge branch 'net-phy-micrel-add-coma-mode-support'
      Merge branch 'mptcp-path-manager-mode-selection'
      Merge branch 'tcp-pass-back-data-left-in-socket-after-receive' of git://git.kernel.org/pub/scm/linux/kernel/git/kuba/linux
      eth: remove remaining copies of the NAPI_POLL_WEIGHT define
      can: m_can: remove a copy of the NAPI_POLL_WEIGHT define
      rtnl: allocate more attr tables on the heap
      rtnl: split __rtnl_newlink() into two functions
      rtnl: move rtnl_newlink_create()
      ath10k: remove a copy of the NAPI_POLL_WEIGHT define
      wil6210: use NAPI_POLL_WEIGHT for napi budget
      rtw88: remove a copy of the NAPI_POLL_WEIGHT define
      Stefan Schmidt says:
      Merge branch 'ocelot-stats-improvement'
      Merge branch 'vsock-virtio-add-support-for-device-suspend-resume'
      Merge branch 'mptcp-userspace-path-manager-prerequisites'
      netdev: reshuffle netif_napi_add() APIs to allow dropping weight
      Merge tag 'wireless-next-2022-05-03' of git://git.kernel.org/pub/scm/linux/kernel/git/wireless/wireless-next
      Merge branch 'ocelot-vcap-cleanups'
      Merge git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net
      Revert "Merge branch 'mlxsw-line-card-model'"
      jme: remove an unnecessary indirection
      net: switch to netif_napi_add_tx()
      net: move snowflake callers to netif_napi_add_tx_weight()
      Merge branch 'mptcp-improve-mptcp-level-window-tracking'
      wil6210: switch to netif_napi_add_tx()
      mt76: switch to netif_napi_add_tx()
      qtnfmac: switch to netif_napi_add_weight()
      net: add netif_inherit_tso_max()
      net: don't allow user space to lift the device limits
      net: make drivers set the TSO limit not the GSO limit
      net: move netif_set_gso_max helpers
      Merge branch '10GbE' of git://git.kernel.org/pub/scm/linux/kernel/git/tnguy/next-queue
      Merge branch 'simplify-migration-of-host-filtered-addresses-in-felix-driver'
      um: vector: switch to netif_napi_add_weight()
      caif_virtio: switch to netif_napi_add_weight()
      eth: switch to netif_napi_add_weight()
      r8152: switch to netif_napi_add_weight()
      net: virtio: switch to netif_napi_add_weight()
      net: wan: switch to netif_napi_add_weight()
      Merge branch '100GbE' of git://git.kernel.org/pub/scm/linux/kernel/git/tnguy/next-queue
      Merge branch 'nfp-support-corigine-pcie-vendor-id'
      eth: dpaa2-mac: remove a dead-code NULL check on fwnode parent
      Merge branch 'move-siena-into-a-separate-subdirectory'
      net: fix kdoc on __dev_queue_xmit()
      skbuff: add a basic intro doc
      skbuff: rewrite the doc for data-only skbs
      skbuff: render the checksum comment to documentation
      Merge branch 'docs-document-some-aspects-of-struct-sk_buff'
      Merge branch 'net-phy-add-comments-for-lan8742-phy-support'
      net: appletalk: remove Apple/Farallon LocalTalk PC support
      eth: amd: remove NI6510 support (ni65)
      Merge branch '1GbE' of git://git.kernel.org/pub/scm/linux/kernel/git/tnguy/next-queue
      Merge branch 'macb-napi-improvements'
      Merge branch 'count-tc-taprio-window-drops-in-enetc-driver'
      Merge git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net
      skbuff: replace a BUG_ON() with the new DEBUG_NET_WARN_ON_ONCE()
      net: update the register_netdevice() kdoc
      Merge branch 'dsa-changes-for-multiple-cpu-ports-part-1'
      Merge branch 'restructure-struct-ocelot_port'
      Merge branch 'make-sfc-siena-ko-specific-to-siena'
      Merge branch 'net-inet-retire-port-only-listening_hash'
      Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/klassert/ipsec-next
      eth: sfc: remove remnants of the out-of-tree napi_weight module param
      Merge branch 'mptcp-updates-for-net-next'
      Merge branch 'net-skb-remove-skb_data_area_size'
      Merge tag 'linux-can-next-for-5.19-20220516' of git://git.kernel.org/pub/scm/linux/kernel/git/mkl/linux-can-next
      Merge branch 'net-smc-send-and-write-inline-optimization-for-smc'
      Merge branch 'adin-add-support-for-clock-output'
      Merge branch 'octeon_ep-fix-the-error-handling-path-of-octep_request_irqs'
      net/mlx5: fix multiple definitions of mlx5_lag_mpesw_init / mlx5_lag_mpesw_cleanup
      Merge git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net
      Merge tag 'wireless-next-2022-05-19' of git://git.kernel.org/pub/scm/linux/kernel/git/wireless/wireless-next
      can: can-dev: move to netif_napi_add_weight()
      Merge tag 'linux-can-next-for-5.19-20220519' of git://git.kernel.org/pub/scm/linux/kernel/git/mkl/linux-can-next
      net: tls: fix messing up lists when bpf enabled
      Merge branch 'mtk_eth_soc-phylink-updates'
      Merge branch 'lantiq_gswip-two-small-fixes'
      net: wwan: iosm: remove pointless null check
      net: ipa: don't proceed to out-of-bound write
      docs: change the title of networking docs
      Merge branch 'mptcp-miscellaneous-fixes-and-a-new-test-case'
      eth: mtk_ppe: fix up after merge
      Merge git://git.kernel.org/pub/scm/linux/kernel/git/netfilter/nf-next
      tcp_ipv6: set the drop_reason in the right place
      net: stmmac: fix out-of-bounds access in a selftest
      net: avoid strange behavior with skb_defer_max == 1
      Merge branch 'amt-fix-several-bugs-in-gateway-mode'
      eth: bnxt: make ulp_id unsigned to make GCC 12 happy
      wwan: iosm: use a flexible array rather than allocate short objects
      Merge branch 'add-a-bhash2-table-hashed-by-port-address'
      net: wrap the wireless pointers in struct net_device in an ifdef
      eth: mtk_eth_soc: silence the GCC 12 array-bounds warning
      eth: ice: silence the GCC 12 array-bounds warning
      eth: tg3: silence the GCC 12 array-bounds warning
      wifi: plfxlc: remove redundant NULL-check for GCC 12
      wifi: ath9k: silence array-bounds warning on GCC 12
      wifi: rtlwifi: remove always-true condition pointed out by GCC 12
      wifi: ath6k: silence false positive -Wno-dangling-pointer warning on GCC 12
      wifi: iwlwifi: use unsigned to silence a GCC 12 warning
      wifi: brcmfmac: work around a GCC 12 -Warray-bounds warning
      wifi: carl9170: silence a GCC 12 -Warray-bounds warning
      Merge branch 'fix-silence-gcc-12-warnings-in-drivers-net-wireless'
      eth: de4x5: remove support for Generic DECchip & DIGITAL EtherWORKS PCI/EISA
      can: kvaser_usb: silence a GCC 12 -Warray-bounds warning
      Merge tag 'for-net-2022-05-23' of git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth
      Merge tag 'for-net-next-2022-05-23' of git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth-next
      Merge tag 'linux-can-next-for-5.19-20220523' of git://git.kernel.org/pub/scm/linux/kernel/git/mkl/linux-can-next
      Merge https://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next
      Merge git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net
      Merge branch 'ptp-ocp-various-updates'

Jason Wang (1):
      bpftool: Declare generator name

Jeff Daly (1):
      ixgbe: Fix module_param allow_unsupported_sfp type

Jeffrey Ji (1):
      net-core: rx_otherhost_dropped to core_stats

Jeremy Sowden (2):
      netfilter: bitwise: replace hard-coded size with `sizeof` expression
      netfilter: bitwise: improve error goto labels

Jerome Marchand (1):
      samples: bpf: Don't fail for a missing VMLINUX_BTF when VMLINUX_H is provided

Jian Shen (1):
      net: hns3: refine the definition for struct hclge_pf_to_vf_msg

Jiapeng Chong (7):
      bpf: Use swap() instead of open coding it
      plfxlc: Remove unused include <linux/version.h>
      can: ctucanfd: remove unused including <linux/version.h>
      can: ctucanfd: ctucan_platform_probe(): remove unnecessary print function dev_err()
      ROSE: Remove unused code and clean up some inconsistent indenting
      ssb: remove unreachable code
      net: ethernet: Use swap() instead of open coding it

Jie Wang (7):
      net: ethtool: extend ringparam set/get APIs for tx_push
      net: ethtool: move checks before rtnl_lock() in ethnl_set_rings
      net: hns3: add tx push support in hns3 ring param process
      net: hns3: add failure logs in hclge_set_vport_mtu
      net: hns3: add byte order conversion for PF to VF mailbox message
      net: hns3: add byte order conversion for VF to PF mailbox message
      net: page_pool: add page allocation stats for two fast page allocate path

Jimmy Hon (2):
      rtw88: 8821ce: add support for device ID 0xb821
      rtw88: 8821ce: Disable PCIe ASPM L1 for 8821CE using chip ID

Jiri Olsa (6):
      kallsyms: Make kallsyms_on_each_symbol generally available
      ftrace: Add ftrace_lookup_symbols function
      fprobe: Resolve symbols with ftrace_lookup_symbols
      bpf: Resolve symbols with ftrace_lookup_symbols for kprobe multi link
      selftests/bpf: Add attach bench test
      libbpf: Add bpf_program__set_insns function

Jiri Pirko (30):
      devlink: add support to create line card and expose to user
      devlink: implement line card provisioning
      devlink: implement line card active state
      devlink: add port to line card relationship set
      mlxsw: spectrum: Allow lane to start from non-zero index
      mlxsw: spectrum: Allocate port mapping array of structs instead of pointers
      mlxsw: reg: Add Ports Mapping Event Configuration Register
      mlxsw: Narrow the critical section of devl_lock during ports creation/removal
      mlxsw: spectrum: Introduce port mapping change event processing
      mlxsw: reg: Add Management DownStream Device Query Register
      mlxsw: reg: Add Management DownStream Device Control Register
      mlxsw: reg: Add Management Binary Code Transfer Register
      mlxsw: core_linecards: Add line card objects and implement provisioning
      mlxsw: core_linecards: Implement line card activation process
      mlxsw: core: Extend driver ops by remove selected ports op
      mlxsw: spectrum: Add port to linecard mapping
      selftests: mlxsw: Introduce devlink line card provision/unprovision/activation tests
      mlxsw: core_linecards: Introduce ops for linecards status change tracking
      mlxsw: core_linecards: Fix size of array element during ini_files allocation
      devlink: introduce line card devices support
      devlink: introduce line card info get message
      devlink: introduce line card device info infrastructure
      mlxsw: reg: Extend MDDQ by device_info
      mlxsw: core_linecards: Probe provisioned line cards for devices and attach them
      selftests: mlxsw: Check devices on provisioned line card
      mlxsw: core_linecards: Expose HW revision and INI version
      selftests: mlxsw: Check line card info on provisioned line card
      mlxsw: reg: Extend MDDQ device_info by FW version fields
      mlxsw: core_linecards: Expose device FW version over device info
      selftests: mlxsw: Check device info on activated line card

Joachim Wiberg (4):
      net: bridge: add support for host l2 mdb entries
      selftests: forwarding: new test, verify host mdb entries
      selftests: forwarding: add TCPDUMP_EXTRA_FLAGS to lib.sh
      selftests: forwarding: multiple instances in tcpdump helper

Joanne Koong (9):
      bpf: Add MEM_UNINIT as a bpf_type_flag
      net: Add a second bind table hashed by port and address
      selftests: Add test for timing a bind request to a port with a populated bhash entry
      bpf: Add verifier support for dynptrs
      bpf: Add bpf_dynptr_from_mem for local dynptrs
      bpf: Dynptr support for ring buffers
      bpf: Add bpf_dynptr_read and bpf_dynptr_write
      bpf: Add dynptr data slices
      selftests/bpf: Dynptr tests

Joe Damato (3):
      i40e: Add support for MPLS + TSO
      ice: Add mpls+tso support
      i40e: Add tx_stopped stat

Joe Perches (1):
      rtw89: rtw89_ser: add const to struct state_ent and event_ent

Johannes Berg (21):
      net: ensure net_todo_list is processed quickly
      nl80211: show SSID for P2P_GO interfaces
      cfg80211: remove cfg80211_get_chan_state()
      nl80211: don't hold RTNL in color change request
      nl80211: rework internal_flags usage
      wil6210: remove 'freq' debugfs
      mac80211: unify CCMP/GCMP AAD construction
      mac80211: fix typo in documentation
      mac80211: remove stray multi_sta_back_32bit docs
      mac80211: mlme: move in RSSI reporting code
      mac80211: use ifmgd->bssid instead of ifmgd->associated->bssid
      mac80211: mlme: use local SSID copy
      mac80211: remove unused argument to ieee80211_sta_connection_lost()
      mac80211: remove useless bssid copy
      mac80211: mlme: track assoc_bss/associated separately
      cfg80211: fix kernel-doc for cfg80211_beacon_data
      mac80211: refactor freeing the next_beacon
      iwlwifi: pcie: simplify MSI-X cause mapping
      iwlwifi: mvm: clean up authorized condition
      iwlwifi: fw: init SAR GEO table only if data is present
      iwlwifi: mei: fix potential NULL-ptr deref

Johnson Lin (3):
      rtw89: packed IGI configuration flow into function for DIG feature
      rtw89: disabled IGI configuration for unsupported hardware
      rtw89: Skip useless dig gain and igi related settings for 8852C

Jonas Jelonek (2):
      mac80211: extend current rate control tx status API
      mac80211: minstrel_ht: support ieee80211_rate_status

Jonathan Lemon (8):
      ptp: ocp: 32-bit fixups for pci start address
      ptp: ocp: Remove #ifdefs around PCI IDs
      ptp: ocp: revise firmware display
      ptp: ocp: parameterize input/output sma selectors
      ptp: ocp: constify selectors
      ptp: ocp: vectorize the sma accessor functions
      ptp: ocp: add .init function for sma_op vector
      ptp: ocp: fix PPS source selector debugfs reporting

Jonathan Neuschäfer (1):
      net: calxedaxgmac: Fix typo (doubled "the")

Josua Mayer (3):
      dt-bindings: net: adin: document phy clock output properties
      net: phy: adin: add support for clock output
      ARM: dts: imx6qdl-sr-som: update phy configuration for som revision 1.9

Julia Lawall (12):
      ath6kl: fix typos in comments
      net: sparx5: switchdev: fix typo in comment
      net: mvpp2: fix typo in comment
      net/mlx5: fix typo in comment
      net: qed: fix typos in comments
      cirrus: cs89x0: fix typo in comment
      net: marvell: prestera: fix typo in comment
      nfp: flower: fix typo in comment
      qed: fix typos in comments
      libbpf: Fix typo in comment
      s390/bpf: Fix typo in comment
      can: peak_usb: fix typo in comment

Jérôme Pouiller (1):
      wfx: get out from the staging area

KP Singh (2):
      bpf: Fix usage of trace RCU in local storage.
      bpftool: bpf_link_get_from_fd support for LSM programs in lskel

Kaixi Fan (3):
      bpf: Add source ip in "struct bpf_tunnel_key"
      selftests/bpf: Move vxlan tunnel testcases to test_progs
      selftests/bpf: Replace bpf_trace_printk in tunnel kernel code

Kalesh AP (1):
      bnxt_en: parse and report result field when NVRAM package install fails

Kalle Valo (10):
      ath11k: mhi: remove state machine
      ath11k: mhi: add error handling for suspend and resume
      ath11k: mhi: remove unnecessary goto from ath11k_mhi_start()
      Merge ath-next from git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/ath.git
      Merge branch 'wfx-move-out-of-staging'
      Merge ath-next from git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/ath.git
      ath11k: mac: fix too long line
      ath10k: mac: fix too long lines
      Merge tag 'mt76-for-kvalo-2022-05-12' of https://github.com/nbd168/wireless
      Merge ath-next from git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/ath.git

Karthikeyan Kathirvel (1):
      ath11k: Change max no of active probe SSID and BSSID to fw capability

Karthikeyan Periyasamy (2):
      ath11k: Refactor the peer delete
      ath11k: Add peer rhash table support

Kees Cook (1):
      fortify: Provide a memcpy trap door for sharp corners

Kevin Lo (1):
      rtw88: use the correct bit in the REG_HCI_OPT_CTRL register

Kevin Mitchell (1):
      netfilter: conntrack: skip verification of zero UDP checksum

Kishen Maloor (17):
      mptcp: bypass in-kernel PM restrictions for non-kernel PMs
      mptcp: store remote id from MP_JOIN SYN/ACK in local ctx
      mptcp: reflect remote port (not 0) in ANNOUNCED events
      mptcp: establish subflows from either end of connection
      mptcp: expose server_side attribute in MPTCP netlink events
      mptcp: allow ADD_ADDR reissuance by userspace PMs
      mptcp: handle local addrs announced by userspace PMs
      mptcp: read attributes of addr entries managed by userspace PMs
      mptcp: netlink: Add MPTCP_PM_CMD_ANNOUNCE
      selftests: mptcp: support MPTCP_PM_CMD_ANNOUNCE
      mptcp: netlink: Add MPTCP_PM_CMD_REMOVE
      selftests: mptcp: support MPTCP_PM_CMD_REMOVE
      selftests: mptcp: support MPTCP_PM_CMD_SUBFLOW_CREATE
      selftests: mptcp: support MPTCP_PM_CMD_SUBFLOW_DESTROY
      selftests: mptcp: capture netlink events
      selftests: mptcp: create listeners to receive MPJs
      selftests: mptcp: functional tests for the userspace PM type

Kris Bahnsen (1):
      can: Fix Links to Technologic Systems web resources

Kui-Feng Lee (5):
      bpf, x86: Generate trampolines from bpf_tramp_links
      bpf, x86: Create bpf_tramp_run_ctx on the caller thread's stack
      bpf, x86: Attach a cookie to fentry/fexit/fmod_ret/lsm.
      libbpf: Assign cookies to links in libbpf.
      selftest/bpf: The test cases of BPF cookie for fentry/fexit/fmod_ret/lsm.

Kumar Kartikeya Dwivedi (27):
      bpf: Do write access check for kfunc and global func
      bpf: Check PTR_TO_MEM | MEM_RDONLY in check_helper_mem_access
      bpf: Reject writes for PTR_TO_MAP_KEY in check_helper_mem_access
      selftests/bpf: Test passing rdonly mem to global func
      selftests/bpf: Test for writes to map key from BPF helpers
      bpf: Ensure type tags precede modifiers in BTF
      selftests/bpf: Add tests for type tag order validation
      bpf: Make btf_find_field more generic
      bpf: Move check_ptr_off_reg before check_map_access
      bpf: Allow storing unreferenced kptr in map
      bpf: Tag argument to be released in bpf_func_proto
      bpf: Allow storing referenced kptr in map
      bpf: Prevent escaping of kptr loaded from maps
      bpf: Adapt copy_map_value for multiple offset case
      bpf: Populate pairs of btf_id and destructor kfunc in btf
      bpf: Wire up freeing of referenced kptr
      bpf: Teach verifier about kptr_get kfunc helpers
      bpf: Make BTF type match stricter for release arguments
      libbpf: Add kptr type tag macros to bpf_helpers.h
      selftests/bpf: Add C tests for kptr
      selftests/bpf: Add verifier tests for kptr
      selftests/bpf: Add test for strict BTF type check
      bpf: Fix sparse warning for bpf_kptr_xchg_proto
      bpf: Prepare prog_test_struct kfuncs for runtime tests
      selftests/bpf: Add negative C tests for kptrs
      selftests/bpf: Add tests for kptr_ref refcounting
      bpf: Suppress 'passing zero to PTR_ERR' warning

Kuniyuki Iwashima (2):
      ipv6: Remove __ipv6_only_sock().
      ipv6: Use ipv6_only_sock() helper in condition.

Larysa Zaremba (1):
      bpftool: Use sysfs vmlinux when dumping BTF by ID

Lavanya Suresh (1):
      mac80211: disable BSS color collision detection in case of no free colors

Lech Perczak (3):
      cdc_ether: export usbnet_cdc_zte_rx_fixup
      rndis_host: enable the bogus MAC fixup for ZTE devices from cdc_ether
      rndis_host: limit scope of bogus MAC address detection to ZTE devices

Leon Romanovsky (48):
      net/mlx5_fpga: Drop INNOVA TLS support
      net/mlx5: Reliably return TLS device capabilities
      net/mlx5: Remove indirection in TLS build
      net/mlx5: Remove tls vs. ktls separation as it is the same
      net/mlx5: Cleanup kTLS function names and their exposure
      net/mlx5_fpga: Drop INNOVA IPsec support
      net/mlx5: Delete metadata handling logic
      net/mlx5: Remove not-used IDA field from IPsec struct
      net/mlx5: Remove XFRM no_trailer flag
      net/mlx5: Remove FPGA ipsec specific statistics
      RDMA/mlx5: Delete never supported IPsec flow action
      RDMA/mlx5: Drop crypto flow steering API
      RDMA/core: Delete IPsec flow action logic from the core
      net/mlx5: Remove ipsec vs. ipsec offload file separation
      net/mlx5: Remove useless IPsec device checks
      net/mlx5: Unify device IPsec capabilities check
      net/mlx5: Align flow steering allocation namespace to common style
      net/mlx5: Remove not-needed IPsec config
      net/mlx5: Move IPsec file to relevant directory
      net/mlx5: Reduce kconfig complexity while building crypto support
      net/mlx5: Remove ipsec_ops function table
      net/mlx5: Remove not-implemented IPsec capabilities
      octeon_ep: Remove custom driver version
      net/mlx5: Simplify IPsec flow steering init/cleanup functions
      net/mlx5: Check IPsec TX flow steering namespace in advance
      net/mlx5: Don't hide fallback to software IPsec in FS code
      net/mlx5: Reduce useless indirection in IPsec FS add/delete flows
      net/mlx5: Store IPsec ESN update work in XFRM state
      net/mlx5: Remove useless validity check
      net/mlx5: Merge various control path IPsec headers into one file
      net/mlx5: Remove indirections from esp functions
      net/mlx5: Simplify HW context interfaces by using SA entry
      net/mlx5: Clean IPsec FS add/delete rules
      net/mlx5: Make sure that no dangling IPsec FS pointers exist
      net/mlx5: Don't advertise IPsec netdev support for non-IPsec device
      net/mlx5: Simplify IPsec capabilities logic
      net/mlx5: Remove not-supported ICV length
      net/mlx5: Cleanup XFRM attributes struct
      net/mlx5: Don't perform lookup after already known sec_path
      net/mlx5: Allow future addition of IPsec object modifiers
      xfrm: free not used XFRM_ESP_NO_TRAILER flag
      xfrm: delete not used number of external headers
      xfrm: rename xfrm_state_offload struct to allow reuse
      xfrm: store and rely on direction to construct offload flags
      ixgbe: propagate XFRM offload state direction instead of flags
      netdevsim: rely on XFRM state direction instead of flags
      net/mlx5e: Use XFRM state direction instead of flags
      xfrm: drop not needed flags variable in XFRM offload struct

Leszek Polak (1):
      net: phy: marvell: Add errata section 5.1 for Alaska PHY

Lin Ma (1):
      NFC: NULL out the dev->rfkill to prevent UAF

Linus Walleij (1):
      Bluetooth: btbcm: Support per-board firmware variants

Liu Jian (4):
      bpf: Enlarge offset check value to INT_MAX in bpf_skb_{load,store}_bytes
      net: Change skb_ensure_writable()'s write_len param to unsigned int type
      selftests/bpf: Add test for skb_load_bytes
      bpf, sockmap: Call skb_linearize only when required in sk_psock_skb_ingress_enqueue

Lorenzo Bianconi (41):
      samples: bpf: Convert xdp_router_ipv4 to XDP samples helper
      dt-bindings: net: mediatek: add optional properties for the SoC ethernet core
      dt-bindings: arm: mediatek: document WED binding for MT7622
      dt-bindings: arm: mediatek: document the pcie mirror node on MT7622
      net: netfilter: Reports ct direction in CT lookup helpers for XDP and TC-BPF
      samples, bpf: Move routes monitor in xdp_router_ipv4 in a dedicated thread
      mac80211: protect ieee80211_assign_beacon with next_beacon check
      mac80211: introduce BSS color collision detection
      page_pool: Add recycle stats to page_pool_put_page_bulk
      net: ethernet: mtk_eth_soc: use standard property for cci-control-port
      net: page_pool: introduce ethtool stats
      net: mvneta: add support for page_pool_get_stats
      dt-bindings: net: mediatek,net: convert to the json-schema
      mt76: mt7921u: add suspend/resume support
      mt76: mt7921: rely on mt76_dev rxfilter in mt7921_configure_filter
      mt76: mt7921: honor pm user configuration in mt7921_sniffer_interface_iter
      mt76: mt7915: fix unbounded shift in mt7915_mcu_beacon_mbss
      mt76: mt7915: fix possible uninitialized pointer dereference in mt7986_wmac_gpio_setup
      mt76: mt7915: fix possible NULL pointer dereference in mt7915_mac_fill_rx_vector
      mt76: mt7915: do not pass data pointer to mt7915_mcu_muru_debug_set
      mt76: mt7915: report rx mode value in mt7915_mac_fill_rx_rate
      mt76: mt7915: use 0xff to initialize bitrate_mask in mt7915_init_bitrate_mask
      mt76: mt7915: configure soc clocks in mt7986_wmac_init
      mt76: add gfp to mt76_mcu_msg_alloc signature
      ixgbe: add xdp frags support to ndo_xdp_xmit
      arm64: dts: mediatek: mt7986: introduce ethernet nodes
      dt-bindings: net: mediatek,net: add mt7986-eth binding
      net: ethernet: mtk_eth_soc: rely on GFP_KERNEL for dma_alloc_coherent whenever possible
      net: ethernet: mtk_eth_soc: move tx dma desc configuration in mtk_tx_set_dma_desc
      net: ethernet: mtk_eth_soc: add txd_size to mtk_soc_data
      net: ethernet: mtk_eth_soc: rely on txd_size in mtk_tx_alloc/mtk_tx_clean
      net: ethernet: mtk_eth_soc: rely on txd_size in mtk_desc_to_tx_buf
      net: ethernet: mtk_eth_soc: rely on txd_size in txd_to_idx
      net: ethernet: mtk_eth_soc: add rxd_size to mtk_soc_data
      net: ethernet: mtk_eth_soc: rely on txd_size field in mtk_poll_tx/mtk_poll_rx
      net: ethernet: mtk_eth_soc: rely on rxd_size field in mtk_rx_alloc/mtk_rx_clean
      net: ethernet: mtk_eth_soc: introduce device register map
      net: ethernet: mtk_eth_soc: introduce MTK_NETSYS_V2 support
      net: ethernet: mtk_eth_soc: convert ring dma pointer to void
      net: ethernet: mtk_eth_soc: convert scratch_ring pointer to void
      net: ethernet: mtk_eth_soc: introduce support for mt7986 chipset

Louis Peens (10):
      nfp: flower: add infrastructure for pre_tun rework
      nfp: flower: add/remove predt_list entries
      nfp: flower: enforce more strict pre_tun checks
      nfp: flower: fixup ipv6/ipv4 route lookup for neigh events
      nfp: flower: update nfp_tun_neigh structs
      nfp: flower: rework tunnel neighbour configuration
      nfp: flower: link pre_tun flow rules with neigh entries
      nfp: flower: remove unused neighbour cache
      nfp: flower: enable decap_v2 bit
      nfp: flower: fix 'variable 'flow6' set but not used'

Lu Wei (2):
      net/mlxbf_gige: use eth_zero_addr() to clear mac address
      ax25: merge repeat codes in ax25_dev_device_down()

Luiz Angelo Daros de Luca (4):
      docs: net: dsa: describe issues with checksum offload
      dt-bindings: net: dsa: realtek: cleanup compatible strings
      net: dsa: realtek: remove realtek,rtl8367s string
      net: dsa: OF-ware slave_mii_bus

Luiz Augusto von Dentz (7):
      Bluetooth: HCI: Add HCI_QUIRK_BROKEN_ENHANCED_SETUP_SYNC_CONN quirk
      Bluetooth: Print broken quirks
      Bluetooth: btusb: Set HCI_QUIRK_BROKEN_ENHANCED_SETUP_SYNC_CONN for QCA
      Bluetooth: MGMT: Add conditions for setting HCI_CONN_FLAG_REMOTE_WAKEUP
      Bluetooth: hci_sync: Fix attempting to suspend with unfiltered passive scan
      Bluetooth: eir: Add helpers for managing service data
      Bluetooth: hci_conn: Fix hci_connect_le_sync

Lukas Bulwahn (1):
      MAINTAINERS: rectify entry for XILINX CAN DRIVER

Lukas Wunner (8):
      net: phy: Deduplicate interrupt disablement on PHY attach
      usbnet: Run unregister_netdev() before unbind() again
      usbnet: smsc95xx: Don't clear read-only PHY interrupt
      usbnet: smsc95xx: Don't reset PHY behind PHY driver's back
      usbnet: smsc95xx: Avoid link settings race on interrupt reception
      usbnet: smsc95xx: Forward PHY interrupts to PHY driver to avoid polling
      net: phy: smsc: Cache interrupt mask
      net: phy: smsc: Cope with hot-removal in interrupt handler

Lv Ruyi (5):
      bnx2x: Fix spelling mistake "regiser" -> "register"
      sfc: Fix spelling mistake "writting" -> "writing"
      rtlwifi: Fix spelling mistake "cacluated" -> "calculated"
      rtlwifi: rtl8192cu: Fix spelling mistake "writting" -> "writing"
      ixp4xx_eth: fix error check return value of platform_get_irq()

Maciej Fijalkowski (16):
      xsk: Diversify return codes in xsk_rcv_check()
      ice, xsk: Decorate ICE_XDP_REDIR with likely()
      ixgbe, xsk: Decorate IXGBE_XDP_REDIR with likely()
      ice, xsk: Terminate Rx side of NAPI when XSK Rx queue gets full
      i40e, xsk: Terminate Rx side of NAPI when XSK Rx queue gets full
      ixgbe, xsk: Terminate Rx side of NAPI when XSK Rx queue gets full
      ice, xsk: Diversify return values from xsk_wakeup call paths
      i40e, xsk: Diversify return values from xsk_wakeup call paths
      ixgbe, xsk: Diversify return values from xsk_wakeup call paths
      mlx5, xsk: Diversify return values from xsk_wakeup call paths
      stmmac, xsk: Diversify return values from xsk_wakeup call paths
      ice, xsk: Avoid refilling single Rx descriptors
      xsk: Drop ternary operator from xskq_cons_has_entries
      ixgbe, xsk: Get rid of redundant 'fallthrough'
      i40e, xsk: Get rid of redundant 'fallthrough'
      ice: introduce common helper for retrieving VSI by vsi_num

Magnus Karlsson (10):
      selftests: xsk: cleanup bash scripts
      selftests: xsk: do not send zero-length packets
      selftests: xsk: run all tests for busy-poll
      selftests: xsk: fix reporting of failed tests
      selftests: xsk: add timeout to tests
      selftests: xsk: cleanup veth pair at ctrl-c
      selftests: xsk: introduce validation functions
      selftests: xsk: make the stats tests normal tests
      selftests: xsk: make stat tests not spin on getsockopt
      MAINTAINERS: Add maintainer to AF_XDP

Manikanta Pubbisetty (19):
      ath11k: PCI changes to support WCN6750
      ath11k: Refactor PCI code to support WCN6750
      ath11k: Choose MSI config based on HW revision
      ath11k: Refactor MSI logic to support WCN6750
      ath11k: Remove core PCI references from PCI common code
      ath11k: Do not put HW in DBS mode for WCN6750
      ath11k: WMI changes to support WCN6750
      ath11k: Update WBM idle ring HP after FW mode on
      dt: bindings: net: add bindings of WCN6750 for ath11k
      ath11k: Move parameters in bus_params to hw_params
      ath11k: Add HW params for WCN6750
      ath11k: Add register access logic for WCN6750
      ath11k: Fetch device information via QMI for WCN6750
      ath11k: Add QMI changes for WCN6750
      ath11k: HAL changes to support WCN6750
      ath11k: Datapath changes to support WCN6750
      ath11k: Add support for WCN6750 device
      ath11k: Add support for targets without trustzone
      ath11k: Fix RX de-fragmentation issue on WCN6750

Marc Kleine-Budde (9):
      can: rx-offload: rename can_rx_offload_queue_sorted() -> can_rx_offload_queue_timestamp()
      can: bittiming: can_calc_bittiming(): prefer small bit rate pre-scalers over larger ones
      can: xilinx_can: mark bit timing constants as const
      dt-binding: can: mcp251xfd: add binding information for mcp251863
      can: mcp251xfd: add support for mcp251863
      can: raw: raw_sendmsg(): remove not needed setting of skb->sk
      can: raw: add support for SO_TXTIME/SCM_TXTIME
      dt-bindings: can: ctucanfd: include common CAN controller bindings
      can: ctucanfd: platform: add missing dependency to HAS_IOMEM

Marcel Ziswiler (1):
      net: stmmac: dwmac-imx: comment spelling fix

Marcin Szycik (1):
      Revert "ice: Hide bus-info in ethtool for PRs in switchdev mode"

Marcin Wojtas (1):
      net: dsa: remove unused headers

Marek Behún (1):
      net: dsa: mv88e6xxx: Cosmetic change spaces to tabs in dsa_switch_ops

Marek Vasut (1):
      net: phy: micrel: ksz9031/ksz9131: add cabletest support

Mark Bloch (22):
      net/mlx5e: TC, set proper dest type
      net/mlx5: fs, split software and IFC flow destination definitions
      net/mlx5: fs, refactor software deletion rule
      net/mlx5: fs, jump to exit point and don't fall through
      net/mlx5: fs, add unused destination type
      net/mlx5: fs, do proper bookkeeping for forward destinations
      net/mlx5: fs, delete the FTE when there are no rules attached to it
      net/mlx5: fs, call the deletion function of the node
      net/mlx5: fs, an FTE should have no dests when deleted
      net/mlx5: Lag, expose number of lag ports
      net/mlx5: devcom only supports 2 ports
      net/mlx5: Lag, move E-Switch prerequisite check into lag code
      net/mlx5: Lag, use lag lock
      net/mlx5: Lag, filter non compatible devices
      net/mlx5: Lag, store number of ports inside lag object
      net/mlx5: Lag, support single FDB only on 2 ports
      net/mlx5: Lag, use hash when in roce lag on 4 ports
      net/mlx5: Lag, use actual number of lag ports
      net/mlx5: Support devices with more than 2 ports
      net/mlx5: Lag, refactor dmesg print
      net/mlx5: Lag, use buckets in hash mode
      net/mlx5: Lag, add debugfs to query hardware lag state

Martin Blumenstingl (2):
      net: dsa: lantiq_gswip: Fix start index in gswip_port_fdb()
      net: dsa: lantiq_gswip: Fix typo in gswip_port_fdb_dump() error print

Martin Habets (23):
      sfc: efx_default_channel_type APIs can be static
      sfc: Remove duplicate definition of efx_xmit_done
      sfc: Remove global definition of efx_reset_type_names
      sfc: Disable Siena support
      sfc: Copy a subset of mcdi_pcol.h to siena
      sfc: Move Siena specific files
      sfc: Copy shared files needed for Siena (part 1)
      sfc: Copy shared files needed for Siena (part 2)
      sfc/siena: Remove build references to missing functionality
      sfc/siena: Rename functions in efx headers to avoid conflicts with sfc
      sfc/siena: Rename RX/TX functions to avoid conflicts with sfc
      sfc/siena: Rename peripheral functions to avoid conflicts with sfc
      sfc/siena: Rename functions in mcdi headers to avoid conflicts with sfc
      sfc/siena: Rename functions in nic_common.h to avoid conflicts with sfc
      sfc/siena: Inline functions in sriov.h to avoid conflicts with sfc
      sfc: Add a basic Siena module
      siena: Make MTD support specific for Siena
      siena: Make SRIOV support specific for Siena
      siena: Make HWMON support specific for Siena
      sfc/siena: Make MCDI logging support specific for Siena
      sfc/siena: Make PTP and reset support specific for Siena
      sfc/siena: Reinstate SRIOV init/fini function calls
      sfc/siena: Remove duplicate check on segments

Martin Jerabek (1):
      can: ctucanfd: add support for CTU CAN FD open-source IP core - bus independent part.

Martin KaFai Lau (4):
      net: inet: Remove count from inet_listen_hashbucket
      net: inet: Open code inet_hash2 and inet_unhash2
      net: inet: Retire port only listening_hash
      net: selftests: Stress reuseport listen

Martin Liška (1):
      eth: sun: cassini: remove dead code

Martin Willi (1):
      netfilter: Use l3mdev flow key when re-routing mangled packets

Mat Martineau (9):
      mptcp: Remove redundant assignments in path manager init
      mptcp: Add a member to mptcp_pm_data to track kernel vs userspace mode
      mptcp: Bypass kernel PM when userspace PM is enabled
      mptcp: Make kernel path manager check for userspace-managed sockets
      mptcp: Add a per-namespace sysctl to set the default path manager type
      selftests: mptcp: Add tests for userspace PM type
      selftests: mptcp: ADD_ADDR echo test with missing userspace daemon
      mptcp: Check for orphaned subflow before handling MP_FAIL timer
      mptcp: Do not traverse the subflow connection list without lock

Mateusz Palczewski (1):
      i40e: Add Ethernet Connection X722 for 10GbE SFP+ support

Max Chou (1):
      Bluetooth: btrtl: Add support for RTL8852C

Maxim Mikityanskiy (1):
      net/mlx5e: Drop error CQE handling from the XSK RX handler

MeiChia Chiu (1):
      mt76: mt7915: add support for 6G in-band discovery

Meng Tang (2):
      ath10k: Use of_device_get_match_data() helper
      ipw2x00: use DEVICE_ATTR_*() macro

Menglong Dong (18):
      net: sock: introduce sock_queue_rcv_skb_reason()
      net: skb: rename SKB_DROP_REASON_PTYPE_ABSENT
      net: icmp: introduce __ping_queue_rcv_skb() to report drop reasons
      net: icmp: add skb drop reasons to icmp protocol
      skb: add some helpers for skb drop reasons
      net: ipv4: add skb drop reasons to ip_error()
      net: ipv6: add skb drop reasons to ip6_pkt_drop()
      net: ip: add skb drop reasons to ip forwarding
      net: icmp: introduce function icmpv6_param_prob_reason()
      net: ipv6: remove redundant statistics in ipv6_hop_jumbo()
      net: ipv6: add skb drop reasons to TLV parse
      net: ipv6: add skb drop reasons to ip6_rcv_core()
      net: ipv6: add skb drop reasons to ip6_protocol_deliver_rcu()
      bpf: Compute map_btf_id during build time
      net: dm: check the boundary of skb drop reasons
      net: skb: check the boundrary of drop reason in kfree_skb_reason()
      net: skb: change the definition SKB_DR_SET()
      net: tcp: reset 'drop_reason' to NOT_SPCIFIED in tcp_v{4,6}_rcv()

Michael Chan (1):
      bnxt_en: Update firmware interface to 1.10.2.95

Michael Trimarchi (1):
      net: fec: Avoid allocating rx buffer using ATOMIC in ndo_open

Michael Walle (9):
      dt-bindings: net: convert mscc-miim to YAML format
      dt-bindings: net: mscc-miim: add clock and clock-frequency
      net: phy: mscc-miim: add support to set MDIO bus frequency
      dt-bindings: net: micrel: add coma-mode-gpios property
      net: phy: micrel: move the PHY timestamping check
      net: phy: micrel: add coma mode GPIO
      dt-bindings: net: lan966x: remove PHY reset
      net: lan966x: remove PHY reset support
      dt-bindings: net: lan966x: fix example

Michal Simek (1):
      net: emaclite: Update copyright text to correct format

Michal Swiatkowski (2):
      ice: get switch id on switchdev devices
      ice: link representors to PCI device

Milan Landaverde (5):
      bpftool: Add syscall prog type
      bpftool: Add missing link types
      bpftool: Handle libbpf_probe_prog_type errors
      bpftool: Adjust for error codes from libbpf probes
      bpftool: Output message if no helpers found in feature probing

Min Li (2):
      ptp: ptp_clockmatrix: Add PTP_CLK_REQ_EXTTS support
      ptp: ptp_clockmatrix: return -EBUSY if phase pull-in is in progress

Minghao Chi (28):
      ath9k: Use platform_get_irq() to get the interrupt
      net: stmmac: using pm_runtime_resume_and_get instead of pm_runtime_get_sync
      net/cadence: using pm_runtime_resume_and_get instead of pm_runtime_get_sync
      wlcore: debugfs: use pm_runtime_resume_and_get() instead of pm_runtime_get_sync()
      net: ethernet: ti: cpsw: using pm_runtime_resume_and_get instead of pm_runtime_get_sync
      net: ethernet: ti: am65-cpsw-nuss: using pm_runtime_resume_and_get instead of pm_runtime_get_sync
      net: ethernet: ti: cpsw_new: use pm_runtime_resume_and_get() instead of pm_runtime_get_sync()
      net: stmmac: stmmac_main: using pm_runtime_resume_and_get instead of pm_runtime_get_sync
      net: ethernet: ti: cpsw_priv: using pm_runtime_resume_and_get instead of pm_runtime_get_sync
      net: ethernet: ti: davinci_emac: using pm_runtime_resume_and_get instead of pm_runtime_get_sync
      can: flexcan: using pm_runtime_resume_and_get instead of pm_runtime_get_sync
      drivers: net: davinci_mdio: using pm_runtime_resume_and_get instead of pm_runtime_get_sync
      net: ethernet: ti: am65-cpsw-ethtool: use pm_runtime_resume_and_get
      wlcore: main: use pm_runtime_resume_and_get() instead of pm_runtime_get_sync()
      wlcore: sysfs: use pm_runtime_resume_and_get() instead of pm_runtime_get_sync()
      wlcore: testmode: use pm_runtime_resume_and_get() instead of pm_runtime_get_sync()
      wlcore: vendor_cmd: use pm_runtime_resume_and_get() instead of pm_runtime_get_sync()
      wlcore: sdio: using pm_runtime_resume_and_get() instead of pm_runtime_get_sync()
      wlcore: cmd: using pm_runtime_resume_and_get() instead of pm_runtime_get_sync()
      wil6210: use pm_runtime_resume_and_get() instead of pm_runtime_get_sync()
      wl18xx: debugfs: use pm_runtime_resume_and_get() instead of pm_runtime_get_sync()
      wl12xx: use pm_runtime_resume_and_get() instead of pm_runtime_get_sync()
      wl12xx: scan: use pm_runtime_resume_and_get() instead of pm_runtime_get_sync()
      net/funeth: simplify the return expression of fun_dl_info_get()
      octeontx2-pf: Remove unnecessary synchronize_irq() before free_irq()
      qed: Remove unnecessary synchronize_irq() before free_irq()
      net: vxge: Remove unnecessary synchronize_irq() before free_irq()
      net: qede: Remove unnecessary synchronize_irq() before free_irq()

Miquel Raynal (15):
      net: ieee802154: ca8210: Fix lifs/sifs periods
      net: mac802154: Convert the symbol duration into nanoseconds
      net: mac802154: Set durations automatically
      net: ieee802154: Drop duration settings when the core does it already
      net: ieee802154: Enhance/fix the names of the MLME return codes
      net: ieee802154: Fill the list of MLME return codes
      net: mac802154: Save a global error code on transmissions
      net: mac802154: Create an offloaded transmission error helper
      net: mac802154: Create an error helper for asynchronous offloading errors
      net: ieee802154: at86rf230: Call _xmit_hw_error() when failing to offload frames
      net: ieee802154: at86rf230: Forward Tx trac errors
      net: ieee802154: atusb: Call _xmit_hw_error() upon transmission error
      net: ieee802154: ca8210: Use core return codes instead of hardcoding them
      net: ieee802154: ca8210: Call _xmit_error() when a transmission fails
      net: mac802154: Fix symbol durations

Miri Korenblit (1):
      iwlwifi: mvm: remove vif_count

Mordechay Goodstein (1):
      iwlwifi: mvm: add OTP info in case of init failure

Moshe Shemesh (1):
      net/mlx5: Add last command failure syndrome to debugfs

Moshe Tal (1):
      net/mlx5e: Correct the calculation of max channels for rep

Muhammad Usama Anjum (1):
      net: selftests: Add stress_reuseport_listen to .gitignore

Muna Sinada (2):
      cfg80211: support disabling EHT mode
      mac80211: support disabling EHT mode

Mykola Lysenko (6):
      selftests/bpf: Improve by-name subtest selection logic in prog_tests
      selftests/bpf: Refactor prog_tests logging and test execution
      bpf/selftests: Add granular subtest output for prog_test
      selftests/bpf: Fix two memory leaks in prog_tests
      selftests/bpf: Fix subtest number formatting in test_progs
      selftests/bpf: Remove filtered subtests from output

Nabil S. Alramli (1):
      i40e: Add vsi.tx_restart to i40e ethtool stats

Nagarajan Maran (1):
      ath11k: fix driver initialization failure with WoW unsupported hw

Nathan Chancellor (1):
      ath6kl: Use cc-disable-warning to disable -Wdangling-pointer

Nathan Rossi (1):
      net: dsa: mv88e6xxx: Single chip mode detection for MV88E6*41

Nick Desaulniers (1):
      net, uapi: remove inclusion of arpa/inet.h

Nicolas Rybowski (1):
      selftests/bpf: Add MPTCP test base

Niels Dossche (7):
      ath11k: acquire ab->base_lock in unassign when finding the peer by addr
      mwifiex: add mutex lock for call in mwifiex_dfs_chan_sw_work_queue
      ipv6: fix locking issues with loops over idev->addr_list
      octeontx2-af: debugfs: fix error return of allocations
      Bluetooth: use hdev lock in activate_scan for hci_is_adv_monitoring
      Bluetooth: use hdev lock for accept_list and reject_list in conn req
      Bluetooth: protect le accept and resolv lists with hdev->lock

Nikolay Aleksandrov (12):
      net: rtnetlink: add msg kind names
      net: rtnetlink: add helper to extract msg type's kind
      net: rtnetlink: use BIT for flag values
      net: netlink: add NLM_F_BULK delete request modifier
      net: rtnetlink: add bulk delete support flag
      net: add ndo_fdb_del_bulk
      net: rtnetlink: add NLM_F_BULK support to rtnl_fdb_del
      net: bridge: fdb: add ndo_fdb_del_bulk
      net: bridge: fdb: add support for fine-grained flushing
      net: rtnetlink: add ndm flags and state mask attributes
      net: bridge: fdb: add support for flush filtering based on ndm flags and state
      net: bridge: fdb: add support for flush filtering based on ifindex and vlan

Nikolay Borisov (1):
      selftests/bpf: Fix vfs_link kprobe definition

Nobuhiro Iwamatsu (1):
      dt-bindings: net: toshiba,visconti-dwmac: Update the common clock properties

Oleksij Rempel (7):
      net: phy: genphy_c45_baset1_an_config_aneg: do no set unknown configuration
      net: phy: introduce genphy_c45_pma_baset1_setup_master_slave()
      net: phy: genphy_c45_pma_baset1_setup_master_slave: do no set unknown configuration
      net: phy: introduce genphy_c45_pma_baset1_read_master_slave()
      net: phy: genphy_c45_pma_baset1_read_master_slave: read actual configuration
      net: phy: export genphy_c45_baset1_read_status()
      net: phy: dp83td510: Add support for the DP83TD510 Ethernet PHY

Oliver Hartkopp (6):
      net: remove noblock parameter from skb_recv_datagram()
      net: remove noblock parameter from recvmsg() entities
      can: isotp: add support for transmission without flow control
      can: isotp: isotp_bind(): return -EINVAL on incorrect CAN ID formatting
      can: isotp: isotp_bind(): do not validate unused address information
      can: can-dev: remove obsolete CAN LED support

Pablo Neira Ayuso (2):
      netfilter: nft_fib: reverse path filter for policy-based routing on iif
      netfilter: conntrack: add nf_ct_iter_data object for nf_ct_iterate_cleanup*()

Paolo Abeni (30):
      mptcp: optimize release_cb for the common case
      mptcp: reset the packet scheduler on incoming MP_PRIO
      mptcp: reset the packet scheduler on PRIO change
      Merge branch 'net-bridge-add-support-for-host-l2-mdb-entries'
      Merge branch 'net-dsa-mt7530-updates-for-phylink-changes'
      Merge branch 'sfc-remove-some-global-definitions'
      Merge branch 'rndis_host-handle-bogus-mac-addresses-in-zte-rndis-devices'
      Merge git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net
      geneve: avoid indirect calls in GRO path, when possible
      Merge branch 'net-sched-allow-user-to-select-txqueue'
      Merge branch 'rtnetlink-improve-alt_ifname-config-and-fix-dangerous-group-usage'
      Merge git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net
      Merge branch 'add-reset-deassertion-for-aspeed-mdio'
      Merge branch 'devices-always-netif_f_lltx'
      Merge tag 'linux-can-next-for-5.19-20220502' of git://git.kernel.org/pub/scm/linux/kernel/git/mkl/linux-can-next
      Merge branch 'use-mmd-c45-helpers'
      Merge branch 'net-more-heap-allocation-and-split-of-rtnl_newlink'
      Merge branch 'use-standard-sysctl-macro'
      Merge branch 'mlxsw-remove-size-limitations-on-egress-descriptor-buffer'
      Merge tag 'mlx5-updates-2022-05-02' of git://git.kernel.org/pub/scm/linux/kernel/git/saeed/linux
      mptcp: really share subflow snd_wnd
      mptcp: add mib for xmit window sharing
      tcp: allow MPTCP to update the announced window
      mptcp: never shrink offered window
      mptcp: add more offered MIBs counter
      Merge branch 'ptp-support-hardware-clocks-with-additional-free-running-cycle-counter'
      Merge branch 'this-is-a-patch-series-for-ethernet-driver-of-sunplus-sp7021-soc'
      Merge branch 'nfp-vf-rate-limit-support'
      Revert "mptcp: add data lock for sk timers"
      mptcp: stop using the mptcp_has_another_subflow() helper

Pavan Chebbi (2):
      bnxt_en: Configure ptp filters during bnxt open
      bnxt_en: Enable packet timestamping for all RX packets

Pavel Begunkov (9):
      net: inline sock_alloc_send_skb
      net: inline skb_zerocopy_iter_dgram
      net: inline dev_queue_xmit()
      ipv6: help __ip6_finish_output() inlining
      ipv6: refactor ip6_finish_output2()
      sock: dedup sock_def_write_space wmem_alloc checks
      sock: optimise UDP sock_wfree() refcounting
      sock: optimise sock_def_write_space barriers
      tcp: optimise skb_zerocopy_iter_stream()

Pavel Löbl (1):
      brcmfmac: allow setting wlan MAC address using device tree

Pavel Pisa (11):
      dt-bindings: vendor-prefix: add prefix for the Czech Technical University in Prague.
      dt-bindings: net: can: binding for CTU CAN FD open-source IP core.
      can: ctucanfd: CTU CAN FD open-source IP core - PCI bus support.
      can: ctucanfd: CTU CAN FD open-source IP core - platform/SoC support.
      docs: ctucanfd: CTU CAN FD open-source IP core documentation.
      MAINTAINERS: Add maintainers for CTU CAN FD IP core driver
      docs: networking: device drivers: can: add ctucanfd to index
      docs: networking: device drivers: can: ctucanfd: update author e-mail
      can: ctucanfd: remove inline keyword from local static functions
      can: ctucanfd: remove debug statements
      can: ctucanfd: remove PCI module debug parameters

Peilin Ye (2):
      ip_gre: Make GRE and GRETAP devices always NETIF_F_LLTX
      ip6_gre: Make IP6GRE and IP6GRETAP devices always NETIF_F_LLTX

Peng Li (3):
      net: hns3: update the comment of function hclgevf_get_mbx_resp
      net: hns3: fix the wrong words in comments
      net: hns3: replace magic value by HCLGE_RING_REG_OFFSET

Pengcheng Yang (1):
      tcp: use tcp_skb_sent_after() instead in RACK

Peter Chiu (4):
      mt76: mt7915: update mt7986 patch in mt7986_wmac_adie_patch_7976()
      mt76: mt7915: fix twt table_mask to u16 in mt7915_dev
      mt76: mt7915: reject duplicated twt flows
      mt76: mt7915: limit minimum twt duration

Peter Seiderer (3):
      mac80211: minstrel_ht: fix where rate stats are stored (fixes debugfs output)
      ath9k: fix ath_get_rate_txpower() to respect the rate list end tag
      mac80211: minstrel_ht: fill all requested rates

Petr Machata (19):
      mlxsw: reg: Add "desc" field to SBPR
      mlxsw: Configure descriptor buffers
      selftests: forwarding: lib: Add start_traffic_pktsize() helpers
      selftests: mlxsw: Add a test for soaking up a burst of traffic
      selftests: mlxsw: bail_on_lldpad before installing the cleanup trap
      selftests: router_vid_1: Add a diagram, fix coding style
      selftests: router.sh: Add a diagram
      mlxsw: spectrum_dcb: Do not warn about priority changes
      mlxsw: Treat LLDP packets as control
      mlxsw: spectrum: Tolerate enslaving of various devices to VRF
      mlxsw: spectrum_router: Add a dedicated notifier block
      mlxsw: spectrum: Move handling of VRF events to router code
      mlxsw: spectrum: Move handling of HW stats events to router code
      mlxsw: spectrum: Move handling of router events to router code
      mlxsw: spectrum: Move handling of tunnel events to router code
      mlxsw: spectrum: Update a comment
      mlxsw: spectrum_router: Take router lock in router notifier handler
      selftests: lib: Add a generic helper for obtaining HW stats
      selftests: forwarding: Add a tunnel-based test for L3 HW stats

Phil Edworthy (5):
      dt-bindings: net: renesas,etheravb: Document RZ/V2M SoC
      ravb: Separate handling of irq enable/disable regs into feature
      ravb: Support separate Line0 (Desc), Line1 (Err) and Line2 (Mgmt) irqs
      ravb: Use separate clock for gPTP
      ravb: Add support for RZ/V2M

Phil Sutter (3):
      netfilter: nf_log_syslog: Merge MAC header dumpers
      netfilter: nf_log_syslog: Don't ignore unknown protocols
      netfilter: nf_log_syslog: Consolidate entry checks

Pieter Jansen van Vuuren (1):
      sfc: add EF100 VF support via a write to sriov_numvfs

Ping Gan (1):
      tcp: Add tracepoint for tcp_set_ca_state

Ping-Ke Shih (79):
      rtw89: reduce export symbol number of mac size and quota
      rtw89: add chip_info::h2c_desc_size/fill_txdesc_fwcmd to support new chips
      rtw89: pci: support variant of fill_txaddr_info
      rtw89: support variant of fill_txdesc
      rtw89: support hardware generate security header
      rtw89: read RX bandwidth from v1 type RX descriptor
      rtw89: handle potential uninitialized variable
      rtw89: pci: add register definition to rtw89_pci_info to generalize pci code
      rtw89: pci: add pci attributes to configure operating mode
      rtw89: pci: add LTR setting for v1 chip
      rtw89: pci: set address info registers depends on chips
      rtw89: pci: add deglitch setting
      rtw89: pci: add L1 settings
      rtw89: extend dmac_pre_init to support 8852C
      rtw89: update STA scheduler parameters for v1 chip
      rtw89: add chip_ops::{enable,disable}_bb_rf to support v1 chip
      rtw89: Turn on CR protection of CMAC
      rtw89: 8852c: update security engine setting
      rtw89: update scheduler setting
      rtw89: initialize NAV control
      rtw89: update TMAC parameters
      rtw89: update ptcl_init
      rtw89: ser: configure top ERR IMR for firmware to recover
      rtw89: change station scheduler setting for hardware TX mode
      rtw89: reset BA CAM
      rtw88: do PHY calibration while starting AP
      rtw89: extend H2C of CMAC control info
      rtw89: add new H2C to configure security CAM via DCTL for V1 chip
      rtw89: configure security CAM for V1 chip
      rtw89: pci: correct return value handling of rtw89_write16_mdio_mask()
      rtw89: 8852c: add BB and RF parameters tables
      rtw89: 8852c: add TX power by rate and limit tables
      rtw89: 8852c: phy: configure TSSI bandedge
      rtw89: 8852c: add BB initial and reset functions
      rtw89: 8852c: add efuse gain offset parser
      rtw89: 8852c: add HFC parameters
      rtw89: 8852c: add set channel function of RF part
      rtw89: 8852c: set channel of MAC part
      rtw89: 8852c: add set channel of BB part
      rtw89: 8852c: add help function of set channel
      rtw89: pci: add variant IMR/ISR and configure functions
      rtw89: pci: add variant RPWM/CPWM to enter low power mode
      rtw89: pci: reclaim TX BD only if it really need
      rtw89: pci: add a separate interrupt handler for low power mode
      rtw89: ser: re-enable interrupt in threadfn if under_recovery
      rtw89: ps: access TX/RX rings via another registers in low power mode
      rtw89: pci: allow to process RPP prior to TX BD
      rtw89: don't flush hci queues and send h2c if power is off
      rtw89: add RF H2C to notify firmware
      rtw89: 8852c: configure default BB TX/RX path
      rtw89: 8852c: implement chip_ops related to TX power
      rtw89: 8852c: implement chip_ops::get_thermal
      rtw89: 8852c: fill freq and band of RX status by PPDU report
      rtw89: 8852c: add chip_ops related to BTC
      rtw89: 8852c: rfk: add RFK tables
      rtw89: 8852c: rfk: add DACK
      rtw89: 8852c: rfk: add LCK
      rtw89: 8852c: rfk: add TSSI
      rtw89: 8852c: rfk: add RCK
      rtw89: 8852c: rfk: add RX DCK
      rtw89: 8852c: rfk: add IQK
      rtw89: 8852c: rfk: add DPK
      rtw89: 8852c: rfk: get calibrated channels to notify firmware
      rtw89: 8852c: add chip_ops::bb_ctrl_btc_preagc
      rtw89: 8852c: add basic and remaining chip_info
      rtw89: ps: fine tune polling interval while changing low power mode
      rtw89: correct AID settings of beamformee
      rtw89: 8852c: correct register definitions used by 8852c
      rtw89: 8852c: fix warning of FIELD_PREP() mask type
      rtw89: 8852c: add 8852ce to Makefile and Kconfig
      mac80211: consider Order bit to fill CCMP AAD
      rtw89: correct setting of RX MPDU length
      rtw89: correct CCA control
      rtw89: add debug select to dump MAC pages 0x30 to 0x33
      rtw89: add debug entry to dump BSSID CAM
      rtw89: add ieee80211::sta_rc_update ops
      rtw89: 8852c: set TX antenna path
      rtw89: cfo: check mac_id to avoid out-of-bounds
      rtw89: pci: only mask out INT indicator register for disable interrupt v1

Po Hao Huang (3):
      rtw89: change idle mode condition during hw_scan
      rtw89: packet offload handler to avoid warning
      rtw89: fix misconfiguration on hw_scan channel time

Po Liu (1):
      net: enetc: count the tc-taprio window drops

Po-Hao Huang (8):
      rtw88: change idle mode condition during hw_scan
      rtw88: add ieee80211:sta_rc_update ops
      rtw88: fix incorrect frequency reported
      rtw88: Add update beacon flow for AP mode
      rtw88: 8821c: Enable TX report for management frames
      rtw88: 8821c: fix debugfs rssi value
      rtw88: fix uninitialized 'tim_offset' warning
      rtw88: pci: 8821c: Disable 21ce completion timeout

Potin Lai (3):
      net: mdio: aspeed: move reg accessing part into separate functions
      net: mdio: aspeed: Introduce read write function for c22 and c45
      net: mdio: aspeed: Add c45 support

Prabhakar Kushwaha (1):
      qede: Reduce verbosity of ptp tx timestamp

Prasanna Vengateshan (1):
      net: dsa: move mib->cnt_ptr reset code to ksz_common.c

Pu Lehui (3):
      riscv, bpf: Implement more atomic operations for RV64
      libbpf: Fix usdt_cookie being cast to 32 bits
      libbpf: Support riscv USDT argument parsing logic

Quentin Monnet (1):
      selftests/bpf: Fix parsing of prog types in UAPI hdr for bpftool sync

Radhey Shyam Pandey (3):
      net: emaclite: Fix coding style
      dt-bindings: net: cdns,macb: Drop phy-names property for ZynqMP SGMII PHY
      net: macb: In ZynqMP initialization make SGMII phy configuration optional

Rameshkumar Sundaram (1):
      nl80211: Parse NL80211_ATTR_HE_BSS_COLOR as a part of nl80211_parse_beacon

Randy Dunlap (1):
      net: dsa: restrict SMSC_LAN9303_I2C kconfig

Ren Zhijie (1):
      sfc: siena: Fix Kconfig dependencies

Ricardo Martinez (6):
      list: Add list_next_entry_circular() and list_prev_entry_circular()
      net: skb: introduce skb_data_area_size()
      net: wwan: t7xx: Add maintainers and documentation
      net: wwan: t7xx: Avoid calls to skb_data_area_size()
      net: skb: Remove skb_data_area_size()
      net: wwan: t7xx: Fix smatch errors

Rikard Falkeborn (1):
      Bluetooth: btintel: Constify static struct regmap_bus

Robert Hancock (5):
      net: phy: marvell: update abilities and advertising when switching to SGMII
      net: macb: simplify/cleanup NAPI reschedule checking
      net: macb: use NAPI for TX completion path
      net: axienet: Be more careful about updating tx_bd_tail
      net: axienet: Use NAPI for TX completion path

Robert Marko (1):
      ath10k: support bus and device specific API 1 BDF selection

Robin Murphy (1):
      sfc: Stop using iommu_present()

Rolf Eike Beer (2):
      net: tulip: convert to devres
      net: tulip: fix build with CONFIG_GSC

Runqing Yang (1):
      libbpf: Fix a bug with checking bpf_probe_read_kernel() support in old kernels

Russell King (1):
      net: mtk_eth_soc: correct 802.3z duplex setting

Russell King (Oracle) (22):
      net: dsa: mt7530: 1G can also support 1000BASE-X link mode
      net: dsa: mt7530: populate supported_interfaces and mac_capabilities
      net: dsa: mt7530: remove interface checks
      net: dsa: mt7530: drop use of phylink_helper_basex_speed()
      net: dsa: mt7530: only indicate linkmodes that can be supported
      net: dsa: mt7530: switch to use phylink_get_linkmodes()
      net: dsa: mt7530: partially convert to phylink_pcs
      net: dsa: mt7530: move autoneg handling to PCS validation
      net: dsa: mt7530: mark as non-legacy
      net: phylink: remove phylink_helper_basex_speed()
      net: dsa: mt753x: fix pcs conversion regression
      net: mtk_eth_soc: remove unused mac->mode
      net: mtk_eth_soc: remove unused sgmii flags
      net: mtk_eth_soc: add mask and update PCS speed definitions
      net: mtk_eth_soc: correct 802.3z speed setting
      net: mtk_eth_soc: stop passing phylink state to sgmii setup
      net: mtk_eth_soc: provide mtk_sgmii_config()
      net: mtk_eth_soc: add fixme comment for state->speed use
      net: mtk_eth_soc: move MAC_MCR setting to mac_finish()
      net: mtk_eth_soc: move restoration of SYSCFG0 to mac_finish()
      net: mtk_eth_soc: convert code structure to suit split PCS support
      net: mtk_eth_soc: partially convert to phylink_pcs

Ryder Lee (7):
      mt76: mt7915: always call mt7915_wfsys_reset() during init
      mt76: mt7915: remove SCS feature
      mt76: mt7915: rework SER debugfs knob
      mt76: mt7915: introduce mt7915_mac_severe_check()
      mt76: mt7915: move MT_INT_MASK_CSR to init.c
      mt76: mt7915: improve error handling for fw_debug knobs
      mt76: mt7915: add more statistics from fw_util debugfs knobs

Saeed Mahameed (3):
      net/mlx5: sparse: error: context imbalance in 'mlx5_vf_get_core_dev'
      net/mlx5e: CT: Add ct driver counters
      sfc: siena: Have a unique wrapper ifndef for efx channels header

Sasha Neftin (3):
      igc: Remove igc_set_spd_dplx method
      igc: Remove unused phy_type enum
      igc: Change type of the 'igc_check_downshift' method

Sean Wang (8):
      mt76: mt7921: Add AP mode support
      mt76: mt7921: fix kernel crash at mt7921_pci_remove
      mt76: connac: use skb_put_data instead of open coding
      Bluetooth: mt7921s: Fix the incorrect pointer check
      Bluetooth: btusb: Add a new PID/VID 0489/e0c8 for MT7921
      Bluetooth: btmtksdio: fix use-after-free at btmtksdio_recv_event
      Bluetooth: btmtksdio: fix possible FW initialization failure
      Bluetooth: btmtksdio: fix the reset takes too long

Shay Drory (2):
      net/mlx5: Delete redundant default assignment of runtime devlink params
      net/mlx5: Print initializing field in case of timeout

Shayne Chen (1):
      mt76: mt7915: add debugfs knob for RF registers read/write

Shravya Kumbham (1):
      net: emaclite: Remove custom BUFFER_ALIGN macro

Simon Wunderlich (1):
      batman-adv: Start new development cycle

Song Chen (1):
      sample: bpf: syscall_tp_user: Print result of verify_map

Song Liu (3):
      bpf: Fill new bpf_prog_pack with illegal instructions
      x86/alternative: Introduce text_poke_set
      bpf: Introduce bpf_arch_text_invalidate for bpf_prog_pack

Sridhar Samudrala (1):
      ice: Expose RSS indirection tables for queue groups via ethtool

Srinivasan R (1):
      wireless: Fix Makefile to be in alphabetical order

Srinivasan Raju (2):
      wireless: add plfxlc driver for pureLiFi X, XL, XC devices
      plfxlc: fix le16_to_cpu warning for beacon_interval

Sriram R (1):
      mac80211: prepare sta handling for MLO support

Stanislav Fomichev (2):
      bpf: Move rcu lock management out of BPF_PROG_RUN routines
      bpf: Use bpf_prog_run_array_cg_flags everywhere

Stefano Garzarella (2):
      vsock/virtio: factor our the code to initialize and delete VQs
      vsock/virtio: add support for device suspend/resume

Steffen Klassert (1):
      Merge  branch 'Be explicit with XFRM offload direction'

Stephen Rothwell (1):
      netfilter: ctnetlink: fix up for "netfilter: conntrack: remove unconfirmed list"

Steven Rostedt (1):
      Bluetooth: hci_qca: Use del_timer_sync() before freeing

Sukadev Bhattiprolu (6):
      ibmvnic: rename local variable index to bufidx
      ibmvnic: define map_rxpool_buf_to_ltb()
      ibmvnic: define map_txpool_buf_to_ltb()
      ibmvnic: convert rxpool ltb to a set of ltbs
      ibmvnic: Allow multiple ltbs in rxpool ltb_set
      ibmvnic: Allow multiple ltbs in txpool ltb_set

Suman Ghosh (1):
      octeontx2-pf: Add support for adaptive interrupt coalescing

Sven Auhagen (1):
      netfilter: flowtable: nft_flow_route use more data for reverse route

Taehee Yoo (5):
      net: atlantic: Implement xdp control plane
      net: atlantic: Implement xdp data plane
      net: atlantic: Implement .ndo_xdp_xmit handler
      amt: fix gateway mode stuck
      amt: fix memory leak for advertisement message

Takshak Chahande (2):
      bpf: Extend batch operations for map-in-map bpf-maps
      selftests/bpf: Handle batch operations for map-in-map bpf-maps

Tariq Toukan (5):
      net/mlx5: Inline db alloc API function
      net/mlx5: Allocate virtually contiguous memory in vport.c
      net/mlx5: Allocate virtually contiguous memory in pci_irq.c
      net/mlx5e: Allocate virtually contiguous memory for VLANs list
      net/mlx5e: Allocate virtually contiguous memory for reps structures

Tetsuo Handa (2):
      wwan_hwsim: Avoid flush_scheduled_work() usage
      wfx: avoid flush_workqueue(system_highpri_wq) usage

Thibaut VARÈNE (1):
      ath9k: fix QCA9561 PA bias level

Tiezhu Yang (5):
      bpf, docs: Remove duplicated word "instructions"
      bpf, docs: BPF_FROM_BE exists as alias for BPF_TO_BE
      bpf, docs: Fix typo "respetively" to "respectively"
      net: sysctl: Use SYSCTL_TWO instead of &two
      bpf: Print some info if disable bpf_jit_enable failed

Tim Harvey (1):
      Bluetooth: btbcm: Add entry for BCM4373A0 UART Bluetooth

Toke Høiland-Jørgensen (1):
      mac80211: Improve confusing comment around tx_info clearing

Tom Rix (3):
      mlxsw: spectrum_router: simplify list unwinding
      USB2NET : SR9800 : change SR9800_BULKIN_SIZE from global to static
      net: fddi: skfp: smt: Remove extra parameters to vararg macro

Tommaso Merciai (1):
      net: phy: DP83822: enable rgmii mode if phy_interface_is_rgmii

Tonghao Zhang (5):
      net: sched: use queue_mapping to pick tx queue
      net: sched: support hash selecting tx queue
      net: sysctl: use shared sysctl macro
      net: sysctl: introduce sysctl SYSCTL_THREE
      selftests/sysctl: add sysctl macro test

Ulf Hansson (1):
      brcmfmac: Avoid keeping power to SDIO card unless WOWL is used

Uwe Kleine-König (2):
      net: fec: Do proper error checking for optional clks
      net: fec: Do proper error checking for enet_out clk

Vadim Fedorenko (2):
      ptp: ocp: add Celestica timecard PCI ids
      ptp: ocp: Add firmware header checks

Vadim Pasternak (22):
      mlxsw: reg: Extend MTMP register with new slot number field
      mlxsw: reg: Extend MTBR register with new slot number field
      mlxsw: reg: Extend MCIA register with new slot number field
      mlxsw: reg: Extend MCION register with new slot number field
      mlxsw: reg: Extend PMMP register with new slot number field
      mlxsw: reg: Extend MGPIR register with new slot fields
      mlxsw: core_env: Pass slot index during PMAOS register write call
      mlxsw: reg: Add new field to Management General Peripheral Information Register
      mlxsw: core: Extend interfaces for cable info access with slot argument
      mlxsw: core: Extend port module data structures for line cards
      mlxsw: core: Move port module events enablement to a separate function
      mlxsw: core_hwmon: Extend internal structures to support multi hwmon objects
      mlxsw: core_hwmon: Introduce slot parameter in hwmon interfaces
      mlxsw: core_thermal: Extend internal structures to support multi thermal areas
      mlxsw: core_thermal: Add line card id prefix to line card thermal zone name
      mlxsw: core_thermal: Use exact name of cooling devices for binding
      mlxsw: core_thermal: Use common define for thermal zone name length
      mlxsw: core: Add bus argument to environment init API
      mlxsw: core_env: Split module power mode setting to a separate function
      mlxsw: core_env: Add interfaces for line card initialization and de-initialization
      mlxsw: core_thermal: Add interfaces for line card initialization and de-initialization
      mlxsw: core_hwmon: Add interfaces for line card initialization and de-initialization

Vasily Averin (2):
      net: enable memcg accounting for veth queues
      memcg: accounting for objects allocated for new netdevice

Vasyl Vavrychuk (1):
      Bluetooth: core: Fix missing power_on work cancel on HCI close

Veerasenareddy Burru (7):
      octeon_ep: Add driver framework and device initialization
      octeon_ep: add hardware configuration APIs
      octeon_ep: Add mailbox for control commands
      octeon_ep: add Tx/Rx ring resource setup and cleanup
      octeon_ep: add support for ndo ops
      octeon_ep: add Tx/Rx processing and interrupt support
      octeon_ep: add ethtool support for Octeon PCI Endpoint NIC

Vincent Mailhol (2):
      can: slcan: slc_xmit(): use can_dropped_invalid_skb() instead of manual check
      can: mcp251xfd: silence clang's -Wunaligned-access warning

Vincent Whitchurch (1):
      net: stmmac: remove unused get_addr() callback

Vladimir Isaev (1):
      libbpf: Add ARC support to bpf_tracing.h

Vladimir Oltean (48):
      net: dsa: move reset of VLAN filtering to dsa_port_switchdev_unsync_attrs
      net: dsa: make cross-chip notifiers more efficient for host events
      net: dsa: use dsa_tree_for_each_user_port in dsa_slave_change_mtu
      net: dsa: avoid one dsa_to_port() in dsa_slave_change_mtu
      net: dsa: drop dsa_slave_priv from dsa_slave_change_mtu
      net: dsa: don't emit targeted cross-chip notifiers for MTU change
      selftests: forwarding: add option to run tests with stable MAC addresses
      selftests: forwarding: add helpers for IP multicast group joins/leaves
      selftests: forwarding: add helper for retrieving IPv6 link-local address of interface
      selftests: forwarding: add a no_forwarding.sh test
      selftests: forwarding: add a test for local_termination.sh
      selftests: drivers: dsa: add a subset of forwarding selftests
      selftests: forwarding: add Per-Stream Filtering and Policing test for Ocelot
      selftests: forwarding: add basic QoS classification test for Ocelot switches
      net: mscc: ocelot: use list_add_tail in ocelot_vcap_filter_add_to_block()
      net: mscc: ocelot: add to tail of empty list in ocelot_vcap_filter_add_to_block
      net: mscc: ocelot: use list_for_each_entry in ocelot_vcap_filter_add_to_block
      net: mscc: ocelot: drop port argument from qos_policer_conf_set
      net: mscc: ocelot: don't use magic numbers for OCELOT_POLICER_DISCARD
      net: dsa: felix: use PGID_CPU for FDB entry migration on NPI port
      net: dsa: felix: stop migrating FDBs back and forth on tag proto change
      net: dsa: felix: perform MDB migration based on ocelot->multicast list
      net: dsa: delete dsa_port_walk_{fdbs,mdbs}
      selftests: forwarding: tc_actions: allow mirred egress test to run on non-offloaded h2
      net: dsa: ocelot: accept 1000base-X for VSC9959 and VSC9953
      net: enetc: manage ENETC_F_QBV in priv->active_offloads only when enabled
      net: enetc: kill PHY-less mode for PFs
      net: dsa: felix: program host FDB entries towards PGID_CPU for tag_8021q too
      net: dsa: felix: bring the NPI port indirection for host MDBs to surface
      net: dsa: felix: bring the NPI port indirection for host flooding to surface
      net: dsa: introduce the dsa_cpu_ports() helper
      net: dsa: felix: manage host flooding using a specific driver callback
      net: dsa: remove port argument from ->change_tag_protocol()
      net: dsa: felix: dynamically determine tag_8021q CPU port for traps
      net: dsa: felix: reimplement tagging protocol change with function pointers
      net: mscc: ocelot: delete ocelot_port :: xmit_template
      net: mscc: ocelot: minimize holes in struct ocelot_port
      net: mscc: ocelot: move ocelot_port_private :: chip_port to ocelot_port :: index
      selftests: ocelot: tc_flower_chains: streamline test output
      selftests: ocelot: tc_flower_chains: use conventional interface names
      selftests: ocelot: tc_flower_chains: reorder interfaces
      net: mscc: ocelot: offload tc action "ok" using an empty action vector
      net: dsa: fix missing adjustment of host broadcast flooding
      net: dsa: felix: move the updating of PGID_CPU to the ocelot lib
      net: dsa: felix: update bridge fwd mask from ocelot lib when changing tag_8021q CPU
      net: dsa: felix: directly call ocelot_port_{set,unset}_dsa_8021q_cpu
      net: mscc: ocelot: switch from {,un}set to {,un}assign for tag_8021q CPU ports
      net: dsa: felix: tag_8021q preparation for multiple CPU ports

Volodymyr Mytnyk (2):
      prestera: acl: add action hw_stats support
      net: prestera: add police action support

Wan Jiabing (4):
      ath10k: simplify if-if to if-else
      wil6210: simplify if-if to if-else
      ath9k: hif_usb: simplify if-if to if-else
      ice: use min_t() to make code cleaner in ice_gnss

Wang Qing (2):
      net: ethernet: xilinx: use of_property_read_bool() instead of of_get_property
      net: usb: remove duplicate assignment

Wells Lu (3):
      devicetree: bindings: net: Add bindings doc for Sunplus SP7021.
      net: ethernet: Add driver for Sunplus SP7021
      net: ethernet: Fix unmet direct dependencies detected for NVMEM_SUNPLUS_OCOTP

Wen Gong (16):
      ath11k: remove unused ATH11K_BD_IE_BOARD_EXT
      ath11k: disable regdb support for QCA6390
      ath11k: add support for device recovery for QCA6390/WCN6855
      ath11k: add synchronization operation between reconfigure of mac80211 and ath11k_base
      ath11k: Add hw-restart option to simulate_fw_crash
      ath11k: fix the warning of dev_wake in mhi_pm_disable_transition()
      ath11k: add fallback board name without variant while searching board-2.bin
      ath11k: add read variant from SMBIOS for download board data
      ath11k: store and send country code to firmware after recovery
      ath11k: add support to search regdb data in board-2.bin for WCN6855
      ath11k: reduce the wait time of 11d scan and hw scan while add interface
      ath11k: add support for extended wmi service bit
      ath11k: read country code from SMBIOS for WCN6855/QCA6390
      ath11k: fix warning of not found station for bssid in message
      ath11k: change management tx queue to avoid connection timed out
      ath11k: reset 11d state in process of recovery

Wenli Looi (7):
      ath9k: make ATH_SREV macros more consistent
      ath9k: split set11nRateFlags and set11nChainSel
      ath9k: use AR9300_MAX_CHAINS when appropriate
      ath9k: fix ar9003_get_eepmisc
      ath9k: refactor ar9003_hw_spur_mitigate_ofdm
      ath9k: add functions to get paprd rate mask
      ath9k: make is2ghz consistent in ar9003_eeprom

William Tu (1):
      netfilter: nf_conncount: reduce unnecessary GC

Wojciech Drewek (1):
      ice: return ENOSPC when exceeding ICE_MAX_CHAIN_WORDS

Wolfram Sang (1):
      dt-bindings: can: renesas,rcar-canfd: document r8a77961 support

Xiaomeng Tong (2):
      qed: remove an unneed NULL check on list iterator
      carl9170: tx: fix an incorrect use of list iterator

Xin Long (2):
      dn_route: set rt neigh to blackhole_netdev instead of loopback_dev in ifdown
      Documentation: add description for net.core.gro_normal_batch

Xiu Jianfeng (2):
      octeontx2-pf: Use memset_startat() helper in otx2_stop()
      stcp: Use memset_after() to zero sctp_stream_out_ext

Xu Kuohai (6):
      arm64, insn: Add ldr/str with immediate offset
      bpf, arm64: Optimize BPF store/load using arm64 str/ldr(immediate offset)
      bpf, arm64: Adjust the offset of str/ldr(immediate) to positive number
      bpf, tests: Add tests for BPF_LDX/BPF_STX with different offsets
      bpf, tests: Add load store test case for tail call
      bpf, arm64: Sign return address for JITed code

Yafang Shao (4):
      samples/bpf: Use libbpf 1.0 API mode instead of RLIMIT_MEMLOCK
      selftests/bpf: Use libbpf 1.0 API mode instead of RLIMIT_MEMLOCK
      bpftool: Use libbpf 1.0 API mode instead of RLIMIT_MEMLOCK
      tools/runqslower: Use libbpf 1.0 API mode instead of RLIMIT_MEMLOCK

Yajun Deng (1):
      arp: fix unused variable warnning when CONFIG_PROC_FS=n

Yan Zhu (1):
      bpf: Move BPF sysctls from kernel/sysctl.c to BPF core

Yang Li (4):
      wcn36xx: clean up some inconsistent indenting
      ath9k: Remove unnecessary print function dev_err()
      rtw89: remove unneeded semicolon
      net: ethernet: fix platform_no_drv_owner.cocci warning

Yang Yingliang (6):
      net: ethernet: mtk_eth_soc: fix return value check in mtk_wed_add_hw()
      octeon_ep: fix error return code in octep_probe()
      ath11k: fix missing unlock on error in ath11k_wow_op_resume()
      ethernet: broadcom/sb1250-mac: remove BUG_ON in sbmac_probe()
      net: ethernet: sunplus: add missing of_node_put() in spl2sw_mdio_init()
      net: wwan: t7xx: use GFP_ATOMIC under spin lock in t7xx_cldma_gpd_set_next_ptr()

Yauheni Kaliuta (1):
      bpf, test_offload.py: Skip base maps without names

Ying Hsu (1):
      Bluetooth: fix dangling sco_conn and use-after-free in sco_sock_timeout

Yinjun Zhang (2):
      nfp: flower: utilize the tuple iifidx in offloading ct flows
      nfp: flower: support ct merging when mangle action exists

Yonghong Song (4):
      selftests/bpf: Limit unroll_count for pyperf600 test
      selftests/bpf: Workaround a verifier issue for test exhandler
      selftests/bpf: fix a few clang compilation errors
      selftests/bpf: fix btf_dump/btf_dump due to recent clang change

Yongzhi Liu (1):
      hv_netvsc: Fix potential dereference of NULL pointer

Yosry Ahmed (1):
      selftests/bpf: Fix building bpf selftests statically

Youghandhar Chintala (1):
      ath10k: Trigger sta disconnect on hardware restart

Yu Xiao (2):
      nfp: vendor neutral strings for chip and Corigne in strings for driver
      nfp: support Corigine PCIE vendor ID

Yu Zhe (3):
      bpf: Remove unnecessary type castings
      batman-adv: remove unnecessary type castings
      ipv4: remove unnecessary type castings

Yuchung Cheng (1):
      tcp: improve PRR loss recovery

YueHaibing (3):
      net: ethernet: ti: am65-cpsw: Fix build error without PHYLINK
      ath11k: Fix build warning without CONFIG_IPV6
      net: wwan: t7xx: Fix return type of t7xx_dl_add_timedout()

Yufeng Mo (2):
      net: hns3: add ethtool parameter check for CQE/EQE mode
      net: hns3: remove the affinity settings of vector0

Yuiko Oshino (4):
      net: phy: microchip: update LAN88xx phy ID and phy ID mask.
      net: phy: smsc: add LAN8742 phy support.
      net: phy: microchip: add comments for the modified LAN88xx phy ID mask.
      net: phy: smsc: add comments for the LAN8742 phy ID mask.

Yunbo Yu (2):
      net: cdc-ncm: Move spin_lock_bh() to spin_lock()
      mt76: mt7603: move spin_lock_bh() to spin_lock()

Yuntao Wang (12):
      bpf: Remove redundant assignment to smap->map.value_size
      selftests/bpf: Fix cd_flavor_subdir() of test_progs
      libbpf: Don't return -EINVAL if hdr_len < offsetofend(core_relo_len)
      selftests/bpf: Fix file descriptor leak in load_kallsyms()
      selftests/bpf: Fix issues in parse_num_list()
      selftests/bpf: Fix return value checks in perf_event_stackmap test
      bpf: Fix excessive memory allocation in stack_map_alloc()
      bpf: Remove redundant assignment to meta.seq in __task_seq_show()
      libbpf: Remove unnecessary type cast
      bpf: Remove unused parameter from find_kfunc_desc_btf()
      bpf: Fix potential array overflow in bpf_trampoline_get_progs()
      selftests/bpf: Add missing trampoline program type to trampoline_count test

Zheng Bin (2):
      net: hinic: add missing destroy_workqueue in hinic_pf_to_mgmt_init
      octeon_ep: add missing destroy_workqueue in octep_init_module

Zhengchao Shao (2):
      samples/bpf: Reduce the sampling interval in xdp1_user
      samples/bpf: Detach xdp prog when program exits unexpectedly in xdp_rxq_info_user

Zijun Hu (2):
      Bluetooth: btusb: add support for Qualcomm WCN785x
      Bluetooth: btusb: Set HCI_QUIRK_BROKEN_ERR_DATA_REPORTING for QCA

Ziyang Xuan (2):
      net/mlx5: use kvfree() for kvzalloc() in mlx5_ct_fs_smfs_matcher_create
      octeon_ep: delete unnecessary NULL check

Zong-Zhe Yang (17):
      rtw89: ser: fix CAM leaks occurring in L2 reset
      rtw89: mac: move table of mem base addr to common
      rtw89: mac: correct decision on error status by scenario
      rtw89: ser: control hci interrupts on/off by state
      rtw89: ser: dump memory for fw payload engine while L2 reset
      rtw89: ser: dump fw backtrace while L2 reset
      rtw89: reconstruct fw feature
      rtw89: support FW crash simulation
      rtw89: add UK to regulation type
      rtw89: 8852a: update txpwr tables to HALRF_027_00_038
      rtw89: regd: consider 6G band
      rtw89: regd: update mapping table to R59-R32
      rtw89: ser: fix unannotated fall-through
      rtw89: 8852c: add TX power track tables
      rtw89: 8852c: support bb gain info
      rtw89: 8852c: update txpwr tables to HALRF_027_00_052
      rtw89: convert rtw89_band to nl80211_band precisely

jianghaoran (1):
      ipv6: Don't send rs packets to the interface of ARPHRD_TUNNEL

liuyacan (3):
      net/smc: postpone sk_refcnt increment in connect()
      net/smc: fix listen processing for SMC-Rv2
      Revert "net/smc: fix listen processing for SMC-Rv2"

 Documentation/admin-guide/devices.txt              |     2 +-
 Documentation/admin-guide/sysctl/net.rst           |    17 +
 Documentation/bpf/instruction-set.rst              |     4 +-
 Documentation/bpf/libbpf/index.rst                 |     3 +-
 .../arm/mediatek/mediatek,mt7622-pcie-mirror.yaml  |    42 +
 .../bindings/arm/mediatek/mediatek,mt7622-wed.yaml |    50 +
 .../devicetree/bindings/net/adi,adin.yaml          |    15 +
 .../bindings/net/aspeed,ast2600-mdio.yaml          |     6 +
 .../devicetree/bindings/net/can/ctu,ctucanfd.yaml  |    66 +
 .../bindings/net/can/microchip,mcp251xfd.yaml      |    19 +-
 .../bindings/net/can/renesas,rcar-canfd.yaml       |     5 +-
 .../devicetree/bindings/net/cdns,macb.yaml         |     8 -
 .../devicetree/bindings/net/ethernet-phy.yaml      |     9 +
 .../bindings/net/marvell,orion-mdio.yaml           |    60 +
 .../devicetree/bindings/net/marvell-orion-mdio.txt |    54 -
 .../devicetree/bindings/net/mediatek,net.yaml      |   434 +
 .../devicetree/bindings/net/mediatek-net.txt       |    98 -
 Documentation/devicetree/bindings/net/micrel.txt   |     9 +
 .../bindings/net/microchip,lan966x-switch.yaml     |     8 +-
 .../devicetree/bindings/net/mscc,miim.yaml         |    61 +
 .../devicetree/bindings/net/mscc-miim.txt          |    26 -
 .../devicetree/bindings/net/renesas,etheravb.yaml  |    82 +-
 .../bindings/net/sunplus,sp7021-emac.yaml          |   141 +
 .../bindings/net/toshiba,visconti-dwmac.yaml       |     3 +-
 .../bindings/net/wireless/qcom,ath11k.yaml         |   361 +-
 .../{staging => }/net/wireless/silabs,wfx.yaml     |     2 +-
 .../devicetree/bindings/vendor-prefixes.yaml       |     2 +
 .../networking/device_drivers/appletalk/index.rst  |     1 -
 .../networking/device_drivers/appletalk/ltpc.rst   |   144 -
 .../device_drivers/can/ctu/ctucanfd-driver.rst     |   639 +
 .../device_drivers/can/ctu/fsm_txt_buffer_user.svg |   151 +
 .../networking/device_drivers/can/index.rst        |     1 +
 .../device_drivers/ethernet/dec/de4x5.rst          |   189 -
 .../networking/device_drivers/ethernet/index.rst   |     2 +-
 .../device_drivers/ethernet/marvell/octeon_ep.rst  |    35 +
 Documentation/networking/device_drivers/index.rst  |     1 -
 .../networking/device_drivers/wan/index.rst        |    18 -
 .../networking/device_drivers/wan/z8530book.rst    |   256 -
 .../networking/device_drivers/wwan/index.rst       |     1 +
 .../networking/device_drivers/wwan/t7xx.rst        |   120 +
 .../networking/devlink/devlink-linecard.rst        |   122 +
 Documentation/networking/devlink/index.rst         |     1 +
 Documentation/networking/dsa/dsa.rst               |    17 +
 Documentation/networking/ethtool-netlink.rst       |     8 +
 Documentation/networking/index.rst                 |     5 +-
 Documentation/networking/ip-sysctl.rst             |    27 +
 Documentation/networking/mptcp-sysctl.rst          |    18 +
 Documentation/networking/nf_conntrack-sysctl.rst   |     5 +-
 Documentation/networking/skbuff.rst                |    37 +
 MAINTAINERS                                        |    63 +-
 arch/alpha/include/uapi/asm/socket.h               |     2 +
 arch/arm/boot/dts/aspeed-g6.dtsi                   |     4 +
 arch/arm/boot/dts/imx6qdl-sr-som.dtsi              |    10 +
 .../boot/dts/marvell/armada-3720-turris-mox.dts    |    12 +-
 arch/arm64/boot/dts/mediatek/mt7622.dtsi           |    32 +-
 arch/arm64/boot/dts/mediatek/mt7986a-rfb.dts       |    74 +
 arch/arm64/boot/dts/mediatek/mt7986a.dtsi          |    39 +
 arch/arm64/boot/dts/mediatek/mt7986b-rfb.dts       |    70 +
 arch/arm64/include/asm/insn.h                      |     9 +
 arch/arm64/lib/insn.c                              |    67 +-
 arch/arm64/net/bpf_jit.h                           |    17 +
 arch/arm64/net/bpf_jit_comp.c                      |   255 +-
 arch/mips/configs/gpr_defconfig                    |     5 -
 arch/mips/configs/mtx1_defconfig                   |     6 -
 arch/mips/include/uapi/asm/socket.h                |     2 +
 arch/parisc/include/uapi/asm/socket.h              |     2 +
 arch/powerpc/configs/chrp32_defconfig              |     1 -
 arch/powerpc/configs/ppc6xx_defconfig              |     1 -
 arch/riscv/net/bpf_jit.h                           |    67 +
 arch/riscv/net/bpf_jit_comp64.c                    |   110 +-
 arch/s390/net/bpf_jit_comp.c                       |     2 +-
 arch/sparc/include/uapi/asm/socket.h               |     1 +
 arch/um/drivers/vector_kern.c                      |     3 +-
 arch/x86/include/asm/text-patching.h               |     1 +
 arch/x86/kernel/alternative.c                      |    67 +-
 arch/x86/net/bpf_jit_comp.c                        |    79 +-
 drivers/atm/Kconfig                                |    79 -
 drivers/atm/Makefile                               |     4 -
 drivers/atm/ambassador.c                           |  2400 ---
 drivers/atm/ambassador.h                           |   648 -
 drivers/atm/firestream.c                           |  2057 --
 drivers/atm/firestream.h                           |   502 -
 drivers/atm/horizon.c                              |  2853 ---
 drivers/atm/horizon.h                              |   492 -
 drivers/atm/nicstarmac.c                           |     5 -
 drivers/atm/uPD98401.h                             |   293 -
 drivers/atm/uPD98402.c                             |   266 -
 drivers/atm/uPD98402.h                             |   107 -
 drivers/atm/zatm.c                                 |  1652 --
 drivers/atm/zatm.h                                 |   104 -
 drivers/bcma/driver_gpio.c                         |     7 +-
 drivers/bluetooth/btbcm.c                          |    53 +-
 drivers/bluetooth/btintel.c                        |     2 +-
 drivers/bluetooth/btmtksdio.c                      |    26 +-
 drivers/bluetooth/btrtl.c                          |    13 +
 drivers/bluetooth/btusb.c                          |    23 +-
 drivers/bluetooth/hci_qca.c                        |     4 +-
 drivers/firmware/broadcom/tee_bnxt_fw.c            |     2 +-
 drivers/infiniband/core/device.c                   |     2 -
 .../infiniband/core/uverbs_std_types_flow_action.c |   383 +-
 drivers/infiniband/hw/mlx5/fs.c                    |   223 +-
 drivers/infiniband/hw/mlx5/gsi.c                   |     2 +-
 drivers/infiniband/hw/mlx5/main.c                  |    32 +-
 drivers/infiniband/hw/mlx5/mlx5_ib.h               |     1 +
 drivers/infiniband/hw/mlx5/qp.c                    |     2 +-
 drivers/isdn/mISDN/socket.c                        |     2 +-
 drivers/media/rc/bpf-lirc.c                        |     8 +-
 drivers/net/Space.c                                |     3 -
 drivers/net/amt.c                                  |    11 +-
 drivers/net/appletalk/Kconfig                      |    11 -
 drivers/net/appletalk/Makefile                     |     1 -
 drivers/net/appletalk/ltpc.c                       |  1277 --
 drivers/net/appletalk/ltpc.h                       |    74 -
 drivers/net/bonding/bond_main.c                    |    29 +-
 drivers/net/caif/caif_virtio.c                     |     3 +-
 drivers/net/can/Kconfig                            |    18 +-
 drivers/net/can/Makefile                           |     1 +
 drivers/net/can/at91_can.c                         |    12 +-
 drivers/net/can/c_can/c_can_main.c                 |    19 +-
 drivers/net/can/ctucanfd/Kconfig                   |    34 +
 drivers/net/can/ctucanfd/Makefile                  |    10 +
 drivers/net/can/ctucanfd/ctucanfd.h                |    82 +
 drivers/net/can/ctucanfd/ctucanfd_base.c           |  1452 ++
 drivers/net/can/ctucanfd/ctucanfd_kframe.h         |    77 +
 drivers/net/can/ctucanfd/ctucanfd_kregs.h          |   325 +
 drivers/net/can/ctucanfd/ctucanfd_pci.c            |   294 +
 drivers/net/can/ctucanfd/ctucanfd_platform.c       |   131 +
 drivers/net/can/dev/Makefile                       |     2 -
 drivers/net/can/dev/bittiming.c                    |     2 +-
 drivers/net/can/dev/dev.c                          |     5 -
 drivers/net/can/dev/rx-offload.c                   |    11 +-
 drivers/net/can/flexcan/flexcan-core.c             |    23 +-
 drivers/net/can/grcan.c                            |     2 +-
 drivers/net/can/ifi_canfd/ifi_canfd.c              |     9 -
 drivers/net/can/janz-ican3.c                       |     2 +-
 drivers/net/can/led.c                              |   140 -
 drivers/net/can/m_can/m_can.c                      |    22 +-
 drivers/net/can/m_can/m_can.h                      |     1 -
 drivers/net/can/mscan/mpc5xxx_can.c                |     2 +
 drivers/net/can/mscan/mscan.c                      |     2 +-
 drivers/net/can/pch_can.c                          |     2 +-
 drivers/net/can/rcar/rcar_can.c                    |    12 +-
 drivers/net/can/rcar/rcar_canfd.c                  |    11 +-
 drivers/net/can/sja1000/Kconfig                    |     2 +-
 drivers/net/can/sja1000/sja1000.c                  |    11 -
 drivers/net/can/sja1000/tscan1.c                   |     7 +-
 drivers/net/can/slcan.c                            |     4 +-
 drivers/net/can/spi/hi311x.c                       |     8 -
 drivers/net/can/spi/mcp251x.c                      |    10 -
 drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c     |    25 +-
 drivers/net/can/spi/mcp251xfd/mcp251xfd-rx.c       |     2 +-
 drivers/net/can/spi/mcp251xfd/mcp251xfd.h          |    14 +-
 drivers/net/can/sun4i_can.c                        |     7 -
 drivers/net/can/ti_hecc.c                          |    12 +-
 drivers/net/can/usb/kvaser_usb/Makefile            |     5 +
 drivers/net/can/usb/mcba_usb.c                     |     8 -
 drivers/net/can/usb/peak_usb/pcan_usb.c            |     2 +-
 drivers/net/can/usb/usb_8dev.c                     |    11 -
 drivers/net/can/xilinx_can.c                       |    16 +-
 drivers/net/dsa/Kconfig                            |     3 +-
 drivers/net/dsa/lantiq_gswip.c                     |     9 +-
 drivers/net/dsa/microchip/ksz8795.c                |   287 +-
 drivers/net/dsa/microchip/ksz8795_reg.h            |     3 -
 drivers/net/dsa/microchip/ksz8795_spi.c            |    35 +-
 drivers/net/dsa/microchip/ksz8863_smi.c            |    10 +-
 drivers/net/dsa/microchip/ksz9477.c                |   331 +-
 drivers/net/dsa/microchip/ksz9477_i2c.c            |    30 +-
 drivers/net/dsa/microchip/ksz9477_reg.h            |     4 -
 drivers/net/dsa/microchip/ksz9477_spi.c            |    30 +-
 drivers/net/dsa/microchip/ksz_common.c             |   621 +-
 drivers/net/dsa/microchip/ksz_common.h             |    89 +-
 drivers/net/dsa/mt7530.c                           |   332 +-
 drivers/net/dsa/mt7530.h                           |    26 +-
 drivers/net/dsa/mv88e6xxx/chip.c                   |    78 +-
 drivers/net/dsa/ocelot/felix.c                     |   695 +-
 drivers/net/dsa/ocelot/felix.h                     |    18 +-
 drivers/net/dsa/ocelot/felix_vsc9959.c             |     7 +-
 drivers/net/dsa/ocelot/seville_vsc9953.c           |     6 +-
 drivers/net/dsa/qca8k.c                            |   145 +-
 drivers/net/dsa/qca8k.h                            |    12 +-
 drivers/net/dsa/realtek/rtl8365mb.c                |     2 +-
 drivers/net/dsa/realtek/rtl8366rb.c                |    37 +-
 drivers/net/dsa/sja1105/sja1105_main.c             |     5 +-
 drivers/net/eql.c                                  |     3 +-
 drivers/net/ethernet/3com/typhoon.c                |     2 +-
 drivers/net/ethernet/Kconfig                       |     1 +
 drivers/net/ethernet/Makefile                      |     1 +
 drivers/net/ethernet/adaptec/starfire.c            |     2 +-
 drivers/net/ethernet/alacritech/slic.h             |     2 -
 drivers/net/ethernet/alacritech/slicoss.c          |     2 +-
 drivers/net/ethernet/amazon/ena/ena_netdev.c       |     4 +-
 drivers/net/ethernet/amd/Kconfig                   |    10 -
 drivers/net/ethernet/amd/Makefile                  |     1 -
 drivers/net/ethernet/amd/amd8111e.c                |     2 +-
 drivers/net/ethernet/amd/ni65.c                    |  1251 --
 drivers/net/ethernet/amd/ni65.h                    |   121 -
 drivers/net/ethernet/amd/pcnet32.c                 |     3 +-
 drivers/net/ethernet/amd/xgbe/xgbe.h               |     3 +-
 drivers/net/ethernet/apple/bmac.c                  |     1 -
 drivers/net/ethernet/apple/mace.c                  |     1 -
 drivers/net/ethernet/aquantia/atlantic/aq_cfg.h    |     3 +-
 .../net/ethernet/aquantia/atlantic/aq_ethtool.c    |     9 +
 drivers/net/ethernet/aquantia/atlantic/aq_main.c   |    87 +
 drivers/net/ethernet/aquantia/atlantic/aq_main.h   |     2 +
 drivers/net/ethernet/aquantia/atlantic/aq_nic.c    |   136 +
 drivers/net/ethernet/aquantia/atlantic/aq_nic.h    |     5 +
 drivers/net/ethernet/aquantia/atlantic/aq_ptp.c    |     2 +-
 drivers/net/ethernet/aquantia/atlantic/aq_ring.c   |   409 +-
 drivers/net/ethernet/aquantia/atlantic/aq_ring.h   |    21 +-
 drivers/net/ethernet/aquantia/atlantic/aq_vec.c    |    25 +-
 drivers/net/ethernet/aquantia/atlantic/aq_vec.h    |     6 +
 .../ethernet/aquantia/atlantic/hw_atl/hw_atl_a0.c  |     6 +-
 .../ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c  |    10 +-
 drivers/net/ethernet/arc/emac_main.c               |     3 +-
 drivers/net/ethernet/atheros/ag71xx.c              |     3 +-
 drivers/net/ethernet/atheros/atl1e/atl1e_main.c    |     2 +-
 drivers/net/ethernet/broadcom/Makefile             |     5 +
 drivers/net/ethernet/broadcom/bcm4908_enet.c       |     2 +-
 drivers/net/ethernet/broadcom/bcm63xx_enet.c       |     4 +-
 drivers/net/ethernet/broadcom/bcmsysport.c         |     2 +-
 drivers/net/ethernet/broadcom/bgmac.c              |     2 +-
 drivers/net/ethernet/broadcom/bgmac.h              |     2 -
 drivers/net/ethernet/broadcom/bnx2x/bnx2x_reg.h    |    10 +-
 drivers/net/ethernet/broadcom/bnxt/bnxt.c          |   313 +-
 drivers/net/ethernet/broadcom/bnxt/bnxt.h          |    18 +-
 drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.c  |     2 +-
 drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c  |    86 +-
 drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.h  |     2 +-
 drivers/net/ethernet/broadcom/bnxt/bnxt_hsi.h      |   415 +-
 drivers/net/ethernet/broadcom/bnxt/bnxt_ptp.c      |    80 +-
 drivers/net/ethernet/broadcom/bnxt/bnxt_ptp.h      |     2 +
 drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.c      |    12 +-
 drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.h      |    12 +-
 drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.c      |   191 +-
 drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.h      |    16 +-
 drivers/net/ethernet/broadcom/genet/bcmgenet.c     |     3 +-
 drivers/net/ethernet/broadcom/sb1250-mac.c         |     9 +-
 drivers/net/ethernet/brocade/bna/bnad.c            |     3 +-
 drivers/net/ethernet/cadence/macb.h                |     6 +-
 drivers/net/ethernet/cadence/macb_main.c           |   353 +-
 drivers/net/ethernet/cadence/macb_ptp.c            |     4 +-
 drivers/net/ethernet/calxeda/xgmac.c               |     2 +-
 drivers/net/ethernet/cavium/liquidio/lio_main.c    |     2 +-
 drivers/net/ethernet/cavium/liquidio/lio_vf_main.c |     2 +-
 drivers/net/ethernet/cavium/thunder/nicvf_main.c   |     3 -
 .../chelsio/inline_crypto/ch_ktls/chcr_ktls.c      |     2 +-
 .../ethernet/chelsio/inline_crypto/chtls/chtls.h   |     2 +-
 .../chelsio/inline_crypto/chtls/chtls_io.c         |    22 +-
 drivers/net/ethernet/cirrus/cs89x0.c               |     2 +-
 drivers/net/ethernet/cortina/gemini.c              |     4 +-
 drivers/net/ethernet/dec/tulip/Kconfig             |    15 -
 drivers/net/ethernet/dec/tulip/Makefile            |     1 -
 drivers/net/ethernet/dec/tulip/de4x5.c             |  5591 ------
 drivers/net/ethernet/dec/tulip/de4x5.h             |  1017 -
 drivers/net/ethernet/dec/tulip/eeprom.c            |     7 +-
 drivers/net/ethernet/dec/tulip/tulip_core.c        |    66 +-
 drivers/net/ethernet/dec/tulip/winbond-840.c       |     2 -
 drivers/net/ethernet/emulex/benet/be.h             |     3 +-
 drivers/net/ethernet/emulex/benet/be_main.c        |     4 +-
 drivers/net/ethernet/engleder/tsnep_hw.h           |     9 +-
 drivers/net/ethernet/engleder/tsnep_main.c         |    36 +-
 drivers/net/ethernet/engleder/tsnep_ptp.c          |    28 +
 drivers/net/ethernet/ezchip/nps_enet.c             |     4 +-
 drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c   |    12 +-
 drivers/net/ethernet/freescale/dpaa2/dpaa2-mac.c   |     3 -
 drivers/net/ethernet/freescale/enetc/enetc.c       |    13 +-
 drivers/net/ethernet/freescale/enetc/enetc.h       |     2 +
 .../net/ethernet/freescale/enetc/enetc_ethtool.c   |     2 +
 drivers/net/ethernet/freescale/enetc/enetc_hw.h    |     1 +
 drivers/net/ethernet/freescale/enetc/enetc_pf.c    |    30 +-
 drivers/net/ethernet/freescale/enetc/enetc_qos.c   |     6 +
 drivers/net/ethernet/freescale/fec_main.c          |    20 +-
 drivers/net/ethernet/freescale/fec_mpc52xx.c       |     2 +
 drivers/net/ethernet/freescale/fec_mpc52xx_phy.c   |     1 +
 .../net/ethernet/freescale/fs_enet/fs_enet-main.c  |     3 +-
 drivers/net/ethernet/freescale/gianfar.c           |     6 +-
 drivers/net/ethernet/freescale/gianfar.h           |     3 -
 .../net/ethernet/fungible/funeth/funeth_devlink.c  |     8 +-
 drivers/net/ethernet/fungible/funeth/funeth_main.c |     3 +-
 drivers/net/ethernet/hisilicon/hisi_femac.c        |     3 +-
 drivers/net/ethernet/hisilicon/hns/hns_enet.c      |     4 +-
 drivers/net/ethernet/hisilicon/hns3/hclge_mbx.h    |    73 +-
 drivers/net/ethernet/hisilicon/hns3/hnae3.h        |     4 +
 .../hisilicon/hns3/hns3_common/hclge_comm_cmd.c    |     2 +
 .../hisilicon/hns3/hns3_common/hclge_comm_cmd.h    |     1 +
 .../hisilicon/hns3/hns3_common/hclge_comm_rss.h    |     2 +-
 drivers/net/ethernet/hisilicon/hns3/hns3_enet.c    |     5 +-
 drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c |   144 +-
 drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.h |     6 +
 .../net/ethernet/hisilicon/hns3/hns3pf/hclge_err.c |     2 +-
 .../ethernet/hisilicon/hns3/hns3pf/hclge_main.c    |    30 +-
 .../ethernet/hisilicon/hns3/hns3pf/hclge_main.h    |     6 +-
 .../net/ethernet/hisilicon/hns3/hns3pf/hclge_mbx.c |   195 +-
 .../ethernet/hisilicon/hns3/hns3pf/hclge_trace.h   |     2 +-
 .../ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c  |    62 +-
 .../ethernet/hisilicon/hns3/hns3vf/hclgevf_main.h  |     2 +-
 .../ethernet/hisilicon/hns3/hns3vf/hclgevf_mbx.c   |    88 +-
 .../ethernet/hisilicon/hns3/hns3vf/hclgevf_trace.h |     2 +-
 drivers/net/ethernet/huawei/hinic/hinic_hw_mgmt.c  |     2 +
 drivers/net/ethernet/huawei/hinic/hinic_hw_wq.c    |     2 +-
 drivers/net/ethernet/huawei/hinic/hinic_rx.c       |     3 +-
 drivers/net/ethernet/huawei/hinic/hinic_tx.c       |     3 +-
 drivers/net/ethernet/ibm/ehea/ehea.h               |     1 +
 drivers/net/ethernet/ibm/ehea/ehea_main.c          |     2 +
 drivers/net/ethernet/ibm/emac/mal.c                |     4 +-
 drivers/net/ethernet/ibm/ibmveth.c                 |     2 +-
 drivers/net/ethernet/ibm/ibmvnic.c                 |   311 +-
 drivers/net/ethernet/ibm/ibmvnic.h                 |    54 +-
 drivers/net/ethernet/intel/e100.c                  |     2 +-
 drivers/net/ethernet/intel/i40e/i40e.h             |     1 +
 drivers/net/ethernet/intel/i40e/i40e_common.c      |     1 +
 drivers/net/ethernet/intel/i40e/i40e_debugfs.c     |     5 +-
 drivers/net/ethernet/intel/i40e/i40e_devids.h      |     1 +
 drivers/net/ethernet/intel/i40e/i40e_ethtool.c     |     2 +
 drivers/net/ethernet/intel/i40e/i40e_main.c        |    25 +-
 drivers/net/ethernet/intel/i40e/i40e_txrx.c        |    49 +-
 drivers/net/ethernet/intel/i40e/i40e_txrx.h        |     1 +
 drivers/net/ethernet/intel/i40e/i40e_txrx_common.h |     1 +
 drivers/net/ethernet/intel/i40e/i40e_xsk.c         |    39 +-
 drivers/net/ethernet/intel/ice/Makefile            |     5 +
 drivers/net/ethernet/intel/ice/ice.h               |    15 +
 drivers/net/ethernet/intel/ice/ice_devlink.c       |    27 +-
 drivers/net/ethernet/intel/ice/ice_ethtool.c       |    77 +-
 drivers/net/ethernet/intel/ice/ice_gnss.c          |     3 +-
 drivers/net/ethernet/intel/ice/ice_idc.c           |    15 -
 drivers/net/ethernet/intel/ice/ice_main.c          |    22 +-
 drivers/net/ethernet/intel/ice/ice_repr.c          |     8 +-
 drivers/net/ethernet/intel/ice/ice_sriov.c         |    32 +-
 drivers/net/ethernet/intel/ice/ice_switch.c        |   494 +-
 drivers/net/ethernet/intel/ice/ice_switch.h        |    12 +-
 drivers/net/ethernet/intel/ice/ice_tc_lib.c        |     1 -
 drivers/net/ethernet/intel/ice/ice_txrx.c          |    29 +-
 drivers/net/ethernet/intel/ice/ice_txrx.h          |     1 +
 drivers/net/ethernet/intel/ice/ice_vf_lib.c        |    43 +-
 drivers/net/ethernet/intel/ice/ice_vf_lib.h        |     4 +-
 drivers/net/ethernet/intel/ice/ice_virtchnl.c      |    27 +-
 drivers/net/ethernet/intel/ice/ice_virtchnl_fdir.c |     9 +-
 drivers/net/ethernet/intel/ice/ice_xsk.c           |    53 +-
 drivers/net/ethernet/intel/igb/igb_ethtool.c       |     4 +-
 drivers/net/ethernet/intel/igc/igc.h               |     1 -
 drivers/net/ethernet/intel/igc/igc_base.c          |     2 -
 drivers/net/ethernet/intel/igc/igc_hw.h            |     7 -
 drivers/net/ethernet/intel/igc/igc_main.c          |    50 -
 drivers/net/ethernet/intel/igc/igc_phy.c           |    16 +-
 drivers/net/ethernet/intel/igc/igc_phy.h           |     2 +-
 drivers/net/ethernet/intel/ixgbe/ixgbe_ipsec.c     |     9 +-
 drivers/net/ethernet/intel/ixgbe/ixgbe_ipsec.h     |     2 +-
 drivers/net/ethernet/intel/ixgbe/ixgbe_main.c      |   107 +-
 .../net/ethernet/intel/ixgbe/ixgbe_txrx_common.h   |     1 +
 drivers/net/ethernet/intel/ixgbe/ixgbe_xsk.c       |    53 +-
 drivers/net/ethernet/intel/ixgbevf/ipsec.c         |     6 +-
 drivers/net/ethernet/intel/ixgbevf/ipsec.h         |     2 +-
 drivers/net/ethernet/jme.c                         |     2 +-
 drivers/net/ethernet/jme.h                         |     2 -
 drivers/net/ethernet/lantiq_etop.c                 |     8 +-
 drivers/net/ethernet/lantiq_xrx200.c               |     4 +-
 drivers/net/ethernet/marvell/Kconfig               |     2 +
 drivers/net/ethernet/marvell/Makefile              |     1 +
 drivers/net/ethernet/marvell/mv643xx_eth.c         |     2 +-
 drivers/net/ethernet/marvell/mvneta.c              |    22 +-
 drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c    |     4 +-
 drivers/net/ethernet/marvell/octeon_ep/Kconfig     |    20 +
 drivers/net/ethernet/marvell/octeon_ep/Makefile    |     9 +
 .../net/ethernet/marvell/octeon_ep/octep_cn9k_pf.c |   737 +
 .../net/ethernet/marvell/octeon_ep/octep_config.h  |   204 +
 .../ethernet/marvell/octeon_ep/octep_ctrl_mbox.c   |   245 +
 .../ethernet/marvell/octeon_ep/octep_ctrl_mbox.h   |   170 +
 .../ethernet/marvell/octeon_ep/octep_ctrl_net.c    |   194 +
 .../ethernet/marvell/octeon_ep/octep_ctrl_net.h    |   299 +
 .../net/ethernet/marvell/octeon_ep/octep_ethtool.c |   463 +
 .../net/ethernet/marvell/octeon_ep/octep_main.c    |  1181 ++
 .../net/ethernet/marvell/octeon_ep/octep_main.h    |   357 +
 .../marvell/octeon_ep/octep_regs_cn9k_pf.h         |   367 +
 drivers/net/ethernet/marvell/octeon_ep/octep_rx.c  |   507 +
 drivers/net/ethernet/marvell/octeon_ep/octep_rx.h  |   199 +
 drivers/net/ethernet/marvell/octeon_ep/octep_tx.c  |   334 +
 drivers/net/ethernet/marvell/octeon_ep/octep_tx.h  |   284 +
 drivers/net/ethernet/marvell/octeontx2/Kconfig     |     1 +
 .../ethernet/marvell/octeontx2/af/rvu_debugfs.c    |     4 +-
 .../ethernet/marvell/octeontx2/nic/otx2_common.c   |     5 -
 .../ethernet/marvell/octeontx2/nic/otx2_common.h   |    10 +
 .../ethernet/marvell/octeontx2/nic/otx2_ethtool.c  |    45 +-
 .../net/ethernet/marvell/octeontx2/nic/otx2_pf.c   |    29 +-
 .../net/ethernet/marvell/octeontx2/nic/otx2_txrx.c |    23 +
 .../net/ethernet/marvell/octeontx2/nic/otx2_txrx.h |     1 +
 .../net/ethernet/marvell/octeontx2/nic/otx2_vf.c   |     2 +-
 .../net/ethernet/marvell/prestera/prestera_acl.c   |    42 +-
 .../net/ethernet/marvell/prestera/prestera_acl.h   |    12 +
 .../ethernet/marvell/prestera/prestera_flower.c    |    28 +
 .../net/ethernet/marvell/prestera/prestera_hw.c    |    81 +
 .../net/ethernet/marvell/prestera/prestera_hw.h    |    13 +
 .../ethernet/marvell/prestera/prestera_router.c    |    11 +-
 .../net/ethernet/marvell/prestera/prestera_rxtx.c  |     2 +-
 drivers/net/ethernet/marvell/pxa168_eth.c          |     3 +-
 drivers/net/ethernet/marvell/skge.c                |     3 +-
 drivers/net/ethernet/marvell/sky2.c                |     3 +-
 drivers/net/ethernet/mediatek/Kconfig              |     4 +
 drivers/net/ethernet/mediatek/Makefile             |    10 +
 drivers/net/ethernet/mediatek/mtk_eth_soc.c        |  1062 +-
 drivers/net/ethernet/mediatek/mtk_eth_soc.h        |   360 +-
 drivers/net/ethernet/mediatek/mtk_ppe.c            |   369 +-
 drivers/net/ethernet/mediatek/mtk_ppe.h            |    89 +-
 drivers/net/ethernet/mediatek/mtk_ppe_debugfs.c    |     1 -
 drivers/net/ethernet/mediatek/mtk_ppe_offload.c    |   191 +-
 drivers/net/ethernet/mediatek/mtk_sgmii.c          |   176 +-
 drivers/net/ethernet/mediatek/mtk_star_emac.c      |     3 +-
 drivers/net/ethernet/mediatek/mtk_wed.c            |   880 +
 drivers/net/ethernet/mediatek/mtk_wed.h            |   135 +
 drivers/net/ethernet/mediatek/mtk_wed_debugfs.c    |   175 +
 drivers/net/ethernet/mediatek/mtk_wed_ops.c        |     8 +
 drivers/net/ethernet/mediatek/mtk_wed_regs.h       |   251 +
 drivers/net/ethernet/mellanox/mlx4/en_cq.c         |     3 +-
 drivers/net/ethernet/mellanox/mlx4/en_netdev.c     |     3 +
 drivers/net/ethernet/mellanox/mlx4/en_tx.c         |    47 +-
 drivers/net/ethernet/mellanox/mlx5/core/Kconfig    |    58 +-
 drivers/net/ethernet/mellanox/mlx5/core/Makefile   |    16 +-
 .../net/ethernet/mellanox/mlx5/core/accel/accel.h  |    36 -
 .../net/ethernet/mellanox/mlx5/core/accel/ipsec.c  |   179 -
 .../net/ethernet/mellanox/mlx5/core/accel/ipsec.h  |    96 -
 .../mellanox/mlx5/core/accel/ipsec_offload.c       |   385 -
 .../mellanox/mlx5/core/accel/ipsec_offload.h       |    38 -
 .../net/ethernet/mellanox/mlx5/core/accel/tls.c    |   125 -
 .../net/ethernet/mellanox/mlx5/core/accel/tls.h    |   156 -
 drivers/net/ethernet/mellanox/mlx5/core/alloc.c    |     6 -
 drivers/net/ethernet/mellanox/mlx5/core/cmd.c      |     7 +-
 drivers/net/ethernet/mellanox/mlx5/core/debugfs.c  |     2 +
 drivers/net/ethernet/mellanox/mlx5/core/dev.c      |    49 +-
 drivers/net/ethernet/mellanox/mlx5/core/devlink.c  |    24 +-
 .../mellanox/mlx5/core/diag/fs_tracepoint.c        |     3 +
 drivers/net/ethernet/mellanox/mlx5/core/en.h       |     6 +-
 drivers/net/ethernet/mellanox/mlx5/core/en/dcbnl.h |     2 -
 drivers/net/ethernet/mellanox/mlx5/core/en/fs.h    |     1 -
 .../net/ethernet/mellanox/mlx5/core/en/params.c    |    22 +-
 .../ethernet/mellanox/mlx5/core/en/tc/act/mirred.c |    14 +
 .../ethernet/mellanox/mlx5/core/en/tc/ct_fs_smfs.c |     2 +-
 .../net/ethernet/mellanox/mlx5/core/en/tc/sample.c |     1 +
 drivers/net/ethernet/mellanox/mlx5/core/en/tc_ct.c |    53 +-
 .../net/ethernet/mellanox/mlx5/core/en/xsk/rx.c    |     6 -
 .../net/ethernet/mellanox/mlx5/core/en/xsk/rx.h    |     1 -
 .../net/ethernet/mellanox/mlx5/core/en/xsk/tx.c    |     2 +-
 .../mellanox/mlx5/core/en_accel/en_accel.h         |    11 +-
 .../ethernet/mellanox/mlx5/core/en_accel/fs_tcp.c  |     2 +-
 .../ethernet/mellanox/mlx5/core/en_accel/ipsec.c   |   204 +-
 .../ethernet/mellanox/mlx5/core/en_accel/ipsec.h   |   110 +-
 .../mellanox/mlx5/core/en_accel/ipsec_fs.c         |   365 +-
 .../mellanox/mlx5/core/en_accel/ipsec_fs.h         |    11 +-
 .../mellanox/mlx5/core/en_accel/ipsec_offload.c    |   205 +
 .../mellanox/mlx5/core/en_accel/ipsec_rxtx.c       |   249 +-
 .../mellanox/mlx5/core/en_accel/ipsec_rxtx.h       |     3 -
 .../mellanox/mlx5/core/en_accel/ipsec_stats.c      |    65 +-
 .../ethernet/mellanox/mlx5/core/en_accel/ktls.c    |    71 +-
 .../ethernet/mellanox/mlx5/core/en_accel/ktls.h    |    86 +-
 .../ethernet/mellanox/mlx5/core/en_accel/ktls_rx.c |     2 +-
 .../core/en_accel/{tls_stats.c => ktls_stats.c}    |    51 +-
 .../ethernet/mellanox/mlx5/core/en_accel/ktls_tx.c |    20 +-
 .../mellanox/mlx5/core/en_accel/ktls_txrx.h        |    28 +-
 .../mellanox/mlx5/core/en_accel/ktls_utils.h       |     1 -
 .../net/ethernet/mellanox/mlx5/core/en_accel/tls.c |   247 -
 .../net/ethernet/mellanox/mlx5/core/en_accel/tls.h |   132 -
 .../mellanox/mlx5/core/en_accel/tls_rxtx.c         |   390 -
 .../mellanox/mlx5/core/en_accel/tls_rxtx.h         |    91 -
 .../net/ethernet/mellanox/mlx5/core/en_common.c    |     5 +-
 drivers/net/ethernet/mellanox/mlx5/core/en_dcbnl.c |     9 -
 drivers/net/ethernet/mellanox/mlx5/core/en_fs.c    |     4 +-
 drivers/net/ethernet/mellanox/mlx5/core/en_main.c  |    35 +-
 drivers/net/ethernet/mellanox/mlx5/core/en_rep.c   |    36 +-
 drivers/net/ethernet/mellanox/mlx5/core/en_rx.c    |    79 +-
 drivers/net/ethernet/mellanox/mlx5/core/en_stats.c |     9 +-
 drivers/net/ethernet/mellanox/mlx5/core/en_stats.h |     1 -
 drivers/net/ethernet/mellanox/mlx5/core/en_tc.c    |    28 +-
 drivers/net/ethernet/mellanox/mlx5/core/en_tc.h    |     7 +
 drivers/net/ethernet/mellanox/mlx5/core/en_tx.c    |   105 +-
 drivers/net/ethernet/mellanox/mlx5/core/eswitch.c  |    28 +-
 drivers/net/ethernet/mellanox/mlx5/core/eswitch.h  |     8 -
 .../ethernet/mellanox/mlx5/core/eswitch_offloads.c |     3 +
 .../net/ethernet/mellanox/mlx5/core/fpga/core.h    |     3 -
 .../net/ethernet/mellanox/mlx5/core/fpga/ipsec.c   |  1582 --
 .../net/ethernet/mellanox/mlx5/core/fpga/ipsec.h   |    62 -
 drivers/net/ethernet/mellanox/mlx5/core/fpga/tls.c |   622 -
 drivers/net/ethernet/mellanox/mlx5/core/fpga/tls.h |    74 -
 drivers/net/ethernet/mellanox/mlx5/core/fs_cmd.c   |    20 +-
 drivers/net/ethernet/mellanox/mlx5/core/fs_core.c  |    61 +-
 drivers/net/ethernet/mellanox/mlx5/core/fs_core.h  |     1 +
 drivers/net/ethernet/mellanox/mlx5/core/fw.c       |     3 +-
 drivers/net/ethernet/mellanox/mlx5/core/fw_reset.c |     2 +-
 .../ethernet/mellanox/mlx5/core/ipoib/ethtool.c    |    14 +-
 .../net/ethernet/mellanox/mlx5/core/lag/debugfs.c  |   174 +
 drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c  |   681 +-
 drivers/net/ethernet/mellanox/mlx5/core/lag/lag.h  |    55 +-
 drivers/net/ethernet/mellanox/mlx5/core/lag/mp.c   |     4 +-
 .../net/ethernet/mellanox/mlx5/core/lag/mpesw.c    |   101 +
 .../net/ethernet/mellanox/mlx5/core/lag/mpesw.h    |    26 +
 .../net/ethernet/mellanox/mlx5/core/lag/port_sel.c |   129 +-
 .../net/ethernet/mellanox/mlx5/core/lag/port_sel.h |    15 +-
 .../net/ethernet/mellanox/mlx5/core/lib/devcom.c   |    16 +-
 .../net/ethernet/mellanox/mlx5/core/lib/devcom.h   |     2 +
 drivers/net/ethernet/mellanox/mlx5/core/lib/tout.c |     1 +
 drivers/net/ethernet/mellanox/mlx5/core/lib/tout.h |     1 +
 drivers/net/ethernet/mellanox/mlx5/core/main.c     |    67 +-
 .../net/ethernet/mellanox/mlx5/core/mlx5_core.h    |     3 +-
 drivers/net/ethernet/mellanox/mlx5/core/pci_irq.c  |     8 +-
 .../ethernet/mellanox/mlx5/core/steering/dr_cmd.c  |    21 +-
 drivers/net/ethernet/mellanox/mlx5/core/vport.c    |    52 +-
 .../net/ethernet/mellanox/mlxbf_gige/mlxbf_gige.h  |     3 -
 .../mellanox/mlxbf_gige/mlxbf_gige_ethtool.c       |     8 +-
 .../ethernet/mellanox/mlxbf_gige/mlxbf_gige_intr.c |     9 -
 .../ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c |     2 +-
 .../ethernet/mellanox/mlxbf_gige/mlxbf_gige_mdio.c |     6 +-
 drivers/net/ethernet/mellanox/mlxsw/Makefile       |     3 +-
 drivers/net/ethernet/mellanox/mlxsw/core.c         |    58 +-
 drivers/net/ethernet/mellanox/mlxsw/core.h         |    79 +-
 drivers/net/ethernet/mellanox/mlxsw/core_env.c     |   681 +-
 drivers/net/ethernet/mellanox/mlxsw/core_env.h     |    47 +-
 drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c   |   311 +-
 .../net/ethernet/mellanox/mlxsw/core_linecards.c   |  1142 ++
 drivers/net/ethernet/mellanox/mlxsw/core_thermal.c |   250 +-
 drivers/net/ethernet/mellanox/mlxsw/minimal.c      |    39 +-
 drivers/net/ethernet/mellanox/mlxsw/reg.h          |   465 +-
 drivers/net/ethernet/mellanox/mlxsw/spectrum.c     |   348 +-
 drivers/net/ethernet/mellanox/mlxsw/spectrum.h     |    27 +-
 .../ethernet/mellanox/mlxsw/spectrum_acl_tcam.c    |     5 +-
 .../net/ethernet/mellanox/mlxsw/spectrum_buffers.c |    26 +
 drivers/net/ethernet/mellanox/mlxsw/spectrum_dcb.c |    13 -
 .../net/ethernet/mellanox/mlxsw/spectrum_ethtool.c |    35 +-
 .../net/ethernet/mellanox/mlxsw/spectrum_router.c  |   201 +-
 .../net/ethernet/mellanox/mlxsw/spectrum_router.h  |     2 +
 .../ethernet/mellanox/mlxsw/spectrum_switchdev.c   |    31 +-
 .../net/ethernet/mellanox/mlxsw/spectrum_trap.c    |     2 +-
 drivers/net/ethernet/mellanox/mlxsw/trap.h         |     6 +
 drivers/net/ethernet/microchip/lan743x_main.c      |     6 +-
 drivers/net/ethernet/microchip/lan966x/Makefile    |     2 +-
 .../net/ethernet/microchip/lan966x/lan966x_fdma.c  |   842 +
 .../net/ethernet/microchip/lan966x/lan966x_main.c  |    84 +-
 .../net/ethernet/microchip/lan966x/lan966x_main.h  |   121 +
 .../net/ethernet/microchip/lan966x/lan966x_port.c  |     3 +
 .../net/ethernet/microchip/lan966x/lan966x_ptp.c   |   276 +-
 .../net/ethernet/microchip/lan966x/lan966x_regs.h  |   146 +
 .../net/ethernet/microchip/sparx5/sparx5_fdma.c    |     3 +-
 .../net/ethernet/microchip/sparx5/sparx5_port.c    |     2 +-
 .../ethernet/microchip/sparx5/sparx5_switchdev.c   |    12 +
 drivers/net/ethernet/microsoft/mana/mana_en.c      |     4 +-
 drivers/net/ethernet/moxa/moxart_ether.c           |     2 +-
 drivers/net/ethernet/mscc/ocelot.c                 |   244 +-
 drivers/net/ethernet/mscc/ocelot.h                 |     1 -
 drivers/net/ethernet/mscc/ocelot_fdma.c            |     4 +-
 drivers/net/ethernet/mscc/ocelot_flower.c          |    16 +
 drivers/net/ethernet/mscc/ocelot_net.c             |    79 +-
 drivers/net/ethernet/mscc/ocelot_police.c          |    26 +-
 drivers/net/ethernet/mscc/ocelot_police.h          |     2 +-
 drivers/net/ethernet/mscc/ocelot_vcap.c            |    42 +-
 drivers/net/ethernet/mscc/ocelot_vsc7514.c         |     2 +-
 drivers/net/ethernet/myricom/myri10ge/myri10ge.c   |     6 +-
 drivers/net/ethernet/natsemi/natsemi.c             |     2 -
 drivers/net/ethernet/neterion/vxge/vxge-main.c     |    13 +-
 drivers/net/ethernet/neterion/vxge/vxge-main.h     |     2 -
 drivers/net/ethernet/netronome/nfp/crypto/tls.c    |     2 +-
 drivers/net/ethernet/netronome/nfp/flower/action.c |     3 +-
 .../net/ethernet/netronome/nfp/flower/conntrack.c  |   268 +-
 .../net/ethernet/netronome/nfp/flower/lag_conf.c   |     2 +-
 drivers/net/ethernet/netronome/nfp/flower/main.h   |   110 +-
 drivers/net/ethernet/netronome/nfp/flower/match.c  |    51 +-
 .../net/ethernet/netronome/nfp/flower/metadata.c   |    19 +-
 .../net/ethernet/netronome/nfp/flower/offload.c    |    86 +-
 .../ethernet/netronome/nfp/flower/tunnel_conf.c    |   515 +-
 drivers/net/ethernet/netronome/nfp/nfp_main.c      |    38 +-
 .../net/ethernet/netronome/nfp/nfp_net_common.c    |    13 +-
 drivers/net/ethernet/netronome/nfp/nfp_net_repr.c  |     5 +-
 drivers/net/ethernet/netronome/nfp/nfp_net_sriov.c |    91 +-
 drivers/net/ethernet/netronome/nfp/nfp_net_sriov.h |    12 +
 .../net/ethernet/netronome/nfp/nfp_netvf_main.c    |    12 +-
 .../ethernet/netronome/nfp/nfpcore/nfp6000_pcie.c  |    18 +-
 .../net/ethernet/netronome/nfp/nfpcore/nfp_cpp.h   |    26 +-
 .../net/ethernet/netronome/nfp/nfpcore/nfp_dev.h   |     8 +
 drivers/net/ethernet/nvidia/forcedeth.c            |     6 +-
 drivers/net/ethernet/nxp/lpc_eth.c                 |     2 +-
 .../net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c   |    12 +-
 drivers/net/ethernet/qlogic/qed/Makefile           |     3 +-
 drivers/net/ethernet/qlogic/qed/qed_dbg_hsi.h      |     2 +-
 drivers/net/ethernet/qlogic/qed/qed_main.c         |     1 -
 .../ethernet/qlogic/qed/qed_nvmetcp_ip_services.c  |   238 -
 drivers/net/ethernet/qlogic/qed/qed_vf.h           |     2 +-
 drivers/net/ethernet/qlogic/qede/qede_main.c       |     1 -
 drivers/net/ethernet/qlogic/qede/qede_ptp.c        |    10 +-
 drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c     |     9 +-
 drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c   |     3 +-
 drivers/net/ethernet/realtek/8139cp.c              |     2 +-
 drivers/net/ethernet/realtek/atp.h                 |     4 -
 drivers/net/ethernet/realtek/r8169_main.c          |     8 +-
 drivers/net/ethernet/renesas/ravb.h                |     6 +
 drivers/net/ethernet/renesas/ravb_main.c           |   109 +-
 drivers/net/ethernet/renesas/ravb_ptp.c            |     6 +-
 drivers/net/ethernet/rocker/rocker_main.c          |     3 +-
 drivers/net/ethernet/sfc/Kconfig                   |    15 +-
 drivers/net/ethernet/sfc/Makefile                  |     5 +-
 drivers/net/ethernet/sfc/ef10.c                    |     2 +-
 drivers/net/ethernet/sfc/ef100.c                   |    27 +-
 drivers/net/ethernet/sfc/ef100_nic.c               |    18 +-
 drivers/net/ethernet/sfc/ef100_sriov.c             |    56 +
 drivers/net/ethernet/sfc/ef100_sriov.h             |    14 +
 drivers/net/ethernet/sfc/efx.c                     |    19 +-
 drivers/net/ethernet/sfc/efx.h                     |     1 -
 drivers/net/ethernet/sfc/efx_channels.c            |    59 +-
 drivers/net/ethernet/sfc/efx_channels.h            |     3 -
 drivers/net/ethernet/sfc/efx_common.c              |     4 +-
 drivers/net/ethernet/sfc/falcon/efx.c              |    10 +-
 drivers/net/ethernet/sfc/falcon/rx.c               |     4 +-
 drivers/net/ethernet/sfc/falcon/tx.c               |     3 +-
 drivers/net/ethernet/sfc/mcdi_pcol.h               |     4 +-
 drivers/net/ethernet/sfc/net_driver.h              |     5 -
 drivers/net/ethernet/sfc/nic.h                     |     4 -
 drivers/net/ethernet/sfc/siena/Kconfig             |    46 +
 drivers/net/ethernet/sfc/siena/Makefile            |    11 +
 drivers/net/ethernet/sfc/siena/bitfield.h          |   614 +
 drivers/net/ethernet/sfc/siena/efx.c               |  1325 ++
 drivers/net/ethernet/sfc/siena/efx.h               |   218 +
 drivers/net/ethernet/sfc/siena/efx_channels.c      |  1370 ++
 drivers/net/ethernet/sfc/siena/efx_channels.h      |    45 +
 drivers/net/ethernet/sfc/siena/efx_common.c        |  1408 ++
 drivers/net/ethernet/sfc/siena/efx_common.h        |   118 +
 drivers/net/ethernet/sfc/siena/enum.h              |   176 +
 drivers/net/ethernet/sfc/siena/ethtool.c           |   282 +
 drivers/net/ethernet/sfc/siena/ethtool_common.c    |  1340 ++
 drivers/net/ethernet/sfc/siena/ethtool_common.h    |    60 +
 drivers/net/ethernet/sfc/{ => siena}/farch.c       |    77 +-
 drivers/net/ethernet/sfc/siena/farch_regs.h        |  2929 +++
 drivers/net/ethernet/sfc/siena/filter.h            |   309 +
 drivers/net/ethernet/sfc/siena/io.h                |   310 +
 drivers/net/ethernet/sfc/siena/mcdi.c              |  2260 +++
 drivers/net/ethernet/sfc/siena/mcdi.h              |   386 +
 drivers/net/ethernet/sfc/siena/mcdi_mon.c          |   531 +
 drivers/net/ethernet/sfc/siena/mcdi_pcol.h         | 17204 ++++++++++++++++
 drivers/net/ethernet/sfc/siena/mcdi_port.c         |   110 +
 drivers/net/ethernet/sfc/siena/mcdi_port.h         |    17 +
 drivers/net/ethernet/sfc/siena/mcdi_port_common.c  |  1282 ++
 drivers/net/ethernet/sfc/siena/mcdi_port_common.h  |    58 +
 drivers/net/ethernet/sfc/siena/mtd.c               |   124 +
 drivers/net/ethernet/sfc/siena/net_driver.h        |  1715 ++
 drivers/net/ethernet/sfc/siena/nic.c               |   530 +
 drivers/net/ethernet/sfc/siena/nic.h               |   206 +
 drivers/net/ethernet/sfc/siena/nic_common.h        |   251 +
 drivers/net/ethernet/sfc/siena/ptp.c               |  2201 +++
 drivers/net/ethernet/sfc/siena/ptp.h               |    45 +
 drivers/net/ethernet/sfc/siena/rx.c                |   400 +
 drivers/net/ethernet/sfc/siena/rx_common.c         |  1094 ++
 drivers/net/ethernet/sfc/siena/rx_common.h         |   110 +
 drivers/net/ethernet/sfc/siena/selftest.c          |   807 +
 drivers/net/ethernet/sfc/siena/selftest.h          |    52 +
 drivers/net/ethernet/sfc/{ => siena}/siena.c       |   168 +-
 drivers/net/ethernet/sfc/{ => siena}/siena_sriov.c |    35 +-
 drivers/net/ethernet/sfc/{ => siena}/siena_sriov.h |     9 +-
 drivers/net/ethernet/sfc/siena/sriov.h             |    83 +
 drivers/net/ethernet/sfc/siena/tx.c                |   392 +
 drivers/net/ethernet/sfc/siena/tx.h                |    40 +
 drivers/net/ethernet/sfc/siena/tx_common.c         |   448 +
 drivers/net/ethernet/sfc/siena/tx_common.h         |    39 +
 drivers/net/ethernet/sfc/siena/vfdi.h              |   252 +
 drivers/net/ethernet/sfc/siena/workarounds.h       |    28 +
 drivers/net/ethernet/sfc/tx.c                      |     3 +-
 drivers/net/ethernet/sfc/tx_common.c               |     3 +-
 drivers/net/ethernet/smsc/smc911x.c                |     6 +-
 drivers/net/ethernet/smsc/smsc911x.c               |     3 +-
 drivers/net/ethernet/smsc/smsc9420.c               |     2 +-
 drivers/net/ethernet/smsc/smsc9420.h               |     1 -
 drivers/net/ethernet/socionext/sni_ave.c           |     3 +-
 drivers/net/ethernet/stmicro/stmmac/dwmac-imx.c    |     4 +-
 drivers/net/ethernet/stmicro/stmmac/dwmac4_descs.c |     6 -
 .../net/ethernet/stmicro/stmmac/dwxgmac2_descs.c   |     6 -
 drivers/net/ethernet/stmicro/stmmac/enh_desc.c     |     6 -
 drivers/net/ethernet/stmicro/stmmac/hwif.h         |     4 -
 drivers/net/ethernet/stmicro/stmmac/norm_desc.c    |     6 -
 drivers/net/ethernet/stmicro/stmmac/stmmac_main.c  |    27 +-
 drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c  |    24 +-
 .../net/ethernet/stmicro/stmmac/stmmac_selftests.c |    13 +-
 drivers/net/ethernet/sun/cassini.c                 |     4 +-
 drivers/net/ethernet/sun/sungem.c                  |     1 -
 drivers/net/ethernet/sunplus/Kconfig               |    32 +
 drivers/net/ethernet/sunplus/Makefile              |     6 +
 drivers/net/ethernet/sunplus/spl2sw_define.h       |   270 +
 drivers/net/ethernet/sunplus/spl2sw_desc.c         |   228 +
 drivers/net/ethernet/sunplus/spl2sw_desc.h         |    19 +
 drivers/net/ethernet/sunplus/spl2sw_driver.c       |   565 +
 drivers/net/ethernet/sunplus/spl2sw_int.c          |   273 +
 drivers/net/ethernet/sunplus/spl2sw_int.h          |    13 +
 drivers/net/ethernet/sunplus/spl2sw_mac.c          |   274 +
 drivers/net/ethernet/sunplus/spl2sw_mac.h          |    18 +
 drivers/net/ethernet/sunplus/spl2sw_mdio.c         |   131 +
 drivers/net/ethernet/sunplus/spl2sw_mdio.h         |    12 +
 drivers/net/ethernet/sunplus/spl2sw_phy.c          |    92 +
 drivers/net/ethernet/sunplus/spl2sw_phy.h          |    12 +
 drivers/net/ethernet/sunplus/spl2sw_register.h     |    86 +
 drivers/net/ethernet/synopsys/dwc-xlgmac.h         |     3 +-
 drivers/net/ethernet/ti/Kconfig                    |     1 +
 drivers/net/ethernet/ti/am65-cpsw-ethtool.c        |     6 +-
 drivers/net/ethernet/ti/am65-cpsw-nuss.c           |    37 +-
 drivers/net/ethernet/ti/am65-cpsw-qos.c            |   193 +-
 drivers/net/ethernet/ti/am65-cpsw-qos.h            |     8 +
 drivers/net/ethernet/ti/cpsw.c                     |    45 +-
 drivers/net/ethernet/ti/cpsw_ale.c                 |    66 +
 drivers/net/ethernet/ti/cpsw_ale.h                 |     2 +
 drivers/net/ethernet/ti/cpsw_new.c                 |    46 +-
 drivers/net/ethernet/ti/cpsw_priv.c                |   235 +-
 drivers/net/ethernet/ti/cpsw_priv.h                |    10 +-
 drivers/net/ethernet/ti/davinci_emac.c             |    12 +-
 drivers/net/ethernet/ti/davinci_mdio.c             |    18 +-
 drivers/net/ethernet/ti/netcp_core.c               |     5 +-
 drivers/net/ethernet/toshiba/spider_net.c          |     3 +-
 drivers/net/ethernet/toshiba/spider_net.h          |     1 -
 drivers/net/ethernet/toshiba/tc35815.c             |     2 +-
 drivers/net/ethernet/via/via-velocity.c            |     3 +-
 drivers/net/ethernet/via/via-velocity.h            |     1 -
 drivers/net/ethernet/wiznet/w5100.c                |     2 +-
 drivers/net/ethernet/wiznet/w5300.c                |     2 +-
 drivers/net/ethernet/xilinx/ll_temac_main.c        |     2 +-
 drivers/net/ethernet/xilinx/xilinx_axienet.h       |    54 +-
 drivers/net/ethernet/xilinx/xilinx_axienet_main.c  |   168 +-
 drivers/net/ethernet/xilinx/xilinx_emaclite.c      |    55 +-
 drivers/net/ethernet/xscale/ixp4xx_eth.c           |     2 +-
 drivers/net/ethernet/xscale/ptp_ixp46x.c           |     2 +-
 drivers/net/fddi/skfp/smt.c                        |     2 +-
 drivers/net/geneve.c                               |    10 +-
 drivers/net/hamradio/Kconfig                       |    34 -
 drivers/net/hamradio/Makefile                      |     1 -
 drivers/net/hamradio/dmascc.c                      |  1450 --
 drivers/net/hyperv/hyperv_net.h                    |    69 +-
 drivers/net/hyperv/netvsc.c                        |    16 +-
 drivers/net/hyperv/netvsc_bpf.c                    |   101 +-
 drivers/net/hyperv/netvsc_drv.c                    |   155 +-
 drivers/net/hyperv/rndis_filter.c                  |     4 +-
 drivers/net/ieee802154/Kconfig                     |     7 -
 drivers/net/ieee802154/at86rf230.c                 |   163 +-
 drivers/net/ieee802154/atusb.c                     |    37 +-
 drivers/net/ieee802154/ca8210.c                    |   181 +-
 drivers/net/ieee802154/mcr20a.c                    |     5 -
 drivers/net/ipa/gsi.c                              |    20 +-
 drivers/net/ipa/gsi.h                              |     1 -
 drivers/net/ipa/gsi_reg.h                          |     2 +-
 drivers/net/ipa/gsi_trans.c                        |    38 +-
 drivers/net/ipa/gsi_trans.h                        |    24 +-
 drivers/net/ipa/ipa.h                              |     2 +
 drivers/net/ipa/ipa_cmd.c                          |    78 +-
 drivers/net/ipa/ipa_cmd.h                          |    11 -
 drivers/net/ipa/ipa_data-v3.1.c                    |     2 +
 drivers/net/ipa/ipa_data-v3.5.1.c                  |     2 +
 drivers/net/ipa/ipa_data-v4.11.c                   |     2 +
 drivers/net/ipa/ipa_data-v4.2.c                    |     2 +
 drivers/net/ipa/ipa_data-v4.5.c                    |     2 +
 drivers/net/ipa/ipa_data-v4.9.c                    |     2 +
 drivers/net/ipa/ipa_data.h                         |    70 +-
 drivers/net/ipa/ipa_endpoint.c                     |   214 +-
 drivers/net/ipa/ipa_endpoint.h                     |    85 +-
 drivers/net/ipa/ipa_interrupt.c                    |     6 +-
 drivers/net/ipa/ipa_modem.c                        |    13 +-
 drivers/net/ipvlan/ipvlan_main.c                   |     6 +-
 drivers/net/loopback.c                             |     2 +
 drivers/net/macvlan.c                              |     9 +-
 drivers/net/mdio/mdio-aspeed.c                     |   138 +-
 drivers/net/mdio/mdio-mscc-miim.c                  |    81 +-
 drivers/net/netdevsim/fib.c                        |     9 +-
 drivers/net/netdevsim/ipsec.c                      |     2 +-
 drivers/net/pcs/pcs-xpcs.c                         |     6 +-
 drivers/net/phy/Kconfig                            |    13 +
 drivers/net/phy/Makefile                           |     2 +
 drivers/net/phy/adin.c                             |    40 +
 drivers/net/phy/adin1100.c                         |   292 +
 drivers/net/phy/bcm87xx.c                          |    36 +-
 drivers/net/phy/dp83822.c                          |     9 +-
 drivers/net/phy/dp83td510.c                        |   209 +
 drivers/net/phy/marvell.c                          |    53 +-
 drivers/net/phy/micrel.c                           |   269 +-
 drivers/net/phy/microchip.c                        |    10 +-
 drivers/net/phy/microchip_t1.c                     |    50 +
 drivers/net/phy/phy-c45.c                          |   297 +-
 drivers/net/phy/phy-core.c                         |     3 +-
 drivers/net/phy/phy.c                              |    18 +-
 drivers/net/phy/phy_device.c                       |    10 +-
 drivers/net/phy/phylink.c                          |    64 +-
 drivers/net/phy/smsc.c                             |    59 +-
 drivers/net/ppp/pppoe.c                            |     3 +-
 drivers/net/sungem_phy.c                           |     6 +-
 drivers/net/tun.c                                  |     3 +-
 drivers/net/usb/aqc111.c                           |     2 +-
 drivers/net/usb/asix_devices.c                     |     6 +-
 drivers/net/usb/ax88179_178a.c                     |     2 +-
 drivers/net/usb/cdc_ether.c                        |     3 +-
 drivers/net/usb/cdc_ncm.c                          |     8 +-
 drivers/net/usb/lan78xx.c                          |     6 +-
 drivers/net/usb/qmi_wwan.c                         |     3 +-
 drivers/net/usb/r8152.c                            |    41 +-
 drivers/net/usb/rndis_host.c                       |    47 +-
 drivers/net/usb/smsc95xx.c                         |   152 +-
 drivers/net/usb/sr9800.h                           |     2 +-
 drivers/net/usb/usbnet.c                           |     6 +-
 drivers/net/veth.c                                 |     6 +-
 drivers/net/virtio_net.c                           |     9 +-
 drivers/net/vxlan/vxlan_core.c                     |    43 +-
 drivers/net/wan/Kconfig                            |    72 -
 drivers/net/wan/Makefile                           |     5 -
 drivers/net/wan/cosa.c                             |  2052 --
 drivers/net/wan/cosa.h                             |   104 -
 drivers/net/wan/fsl_ucc_hdlc.c                     |     2 +-
 drivers/net/wan/hd64572.c                          |     3 +-
 drivers/net/wan/hostess_sv11.c                     |   336 -
 drivers/net/wan/ixp4xx_hss.c                       |     2 +-
 drivers/net/wan/lapbether.c                        |     2 +-
 drivers/net/wan/lmc/Makefile                       |    18 -
 drivers/net/wan/lmc/lmc.h                          |    33 -
 drivers/net/wan/lmc/lmc_debug.c                    |    65 -
 drivers/net/wan/lmc/lmc_debug.h                    |    52 -
 drivers/net/wan/lmc/lmc_ioctl.h                    |   255 -
 drivers/net/wan/lmc/lmc_main.c                     |  2009 --
 drivers/net/wan/lmc/lmc_media.c                    |  1206 --
 drivers/net/wan/lmc/lmc_proto.c                    |   106 -
 drivers/net/wan/lmc/lmc_proto.h                    |    18 -
 drivers/net/wan/lmc/lmc_var.h                      |   468 -
 drivers/net/wan/sealevel.c                         |   352 -
 drivers/net/wan/z85230.c                           |  1641 --
 drivers/net/wan/z85230.h                           |   407 -
 drivers/net/wireless/Kconfig                       |     2 +
 drivers/net/wireless/Makefile                      |     4 +-
 drivers/net/wireless/ath/ar5523/ar5523.c           |     7 +-
 drivers/net/wireless/ath/ath10k/ahb.c              |     9 +-
 drivers/net/wireless/ath/ath10k/core.c             |    38 +-
 drivers/net/wireless/ath/ath10k/core.h             |     3 -
 drivers/net/wireless/ath/ath10k/hw.h               |     2 +
 drivers/net/wireless/ath/ath10k/mac.c              |   106 +-
 drivers/net/wireless/ath/ath10k/pci.c              |     2 +-
 drivers/net/wireless/ath/ath10k/sdio.c             |     2 +-
 drivers/net/wireless/ath/ath10k/snoc.c             |     2 +-
 drivers/net/wireless/ath/ath10k/usb.c              |    27 +
 drivers/net/wireless/ath/ath11k/Makefile           |     3 +-
 drivers/net/wireless/ath/ath11k/ahb.c              |   331 +-
 drivers/net/wireless/ath/ath11k/ahb.h              |     9 +
 drivers/net/wireless/ath/ath11k/ce.c               |     4 +-
 drivers/net/wireless/ath/ath11k/core.c             |   579 +-
 drivers/net/wireless/ath/ath11k/core.h             |   155 +-
 drivers/net/wireless/ath/ath11k/debugfs.c          |     4 +
 drivers/net/wireless/ath/ath11k/dp_tx.c            |     8 +-
 drivers/net/wireless/ath/ath11k/hal.c              |    15 +-
 drivers/net/wireless/ath/ath11k/hal.h              |    17 +-
 drivers/net/wireless/ath/ath11k/htc.c              |     6 +
 drivers/net/wireless/ath/ath11k/hw.c               |   209 +-
 drivers/net/wireless/ath/ath11k/hw.h               |    45 +-
 drivers/net/wireless/ath/ath11k/mac.c              |   722 +-
 drivers/net/wireless/ath/ath11k/mac.h              |     5 +
 drivers/net/wireless/ath/ath11k/mhi.c              |   285 +-
 drivers/net/wireless/ath/ath11k/mhi.h              |    17 +-
 drivers/net/wireless/ath/ath11k/pci.c              |   984 +-
 drivers/net/wireless/ath/ath11k/pci.h              |    28 +-
 drivers/net/wireless/ath/ath11k/pcic.c             |   748 +
 drivers/net/wireless/ath/ath11k/pcic.h             |    46 +
 drivers/net/wireless/ath/ath11k/peer.c             |   373 +-
 drivers/net/wireless/ath/ath11k/peer.h             |    10 +-
 drivers/net/wireless/ath/ath11k/qmi.c              |   286 +-
 drivers/net/wireless/ath/ath11k/qmi.h              |    28 +-
 drivers/net/wireless/ath/ath11k/reg.c              |     4 +
 drivers/net/wireless/ath/ath11k/spectral.c         |    17 +-
 drivers/net/wireless/ath/ath11k/wmi.c              |   856 +-
 drivers/net/wireless/ath/ath11k/wmi.h              |   448 +-
 drivers/net/wireless/ath/ath11k/wow.c              |   797 +
 drivers/net/wireless/ath/ath11k/wow.h              |    45 +
 drivers/net/wireless/ath/ath6kl/Makefile           |     5 +
 drivers/net/wireless/ath/ath6kl/htc_mbox.c         |     2 +-
 drivers/net/wireless/ath/ath9k/Makefile            |     5 +
 drivers/net/wireless/ath/ath9k/ahb.c               |    10 +-
 drivers/net/wireless/ath/ath9k/ar9002_mac.c        |     9 +-
 drivers/net/wireless/ath/ath9k/ar9003_calib.c      |     2 +-
 drivers/net/wireless/ath/ath9k/ar9003_eeprom.c     |    85 +-
 drivers/net/wireless/ath/ath9k/ar9003_eeprom.h     |     2 +
 drivers/net/wireless/ath/ath9k/ar9003_mac.c        |     9 +-
 drivers/net/wireless/ath/ath9k/ar9003_paprd.c      |    10 +-
 drivers/net/wireless/ath/ath9k/ar9003_phy.c        |    25 +-
 drivers/net/wireless/ath/ath9k/ar9003_phy.h        |     2 +-
 drivers/net/wireless/ath/ath9k/debug_sta.c         |     4 +-
 drivers/net/wireless/ath/ath9k/hif_usb.c           |     5 +-
 drivers/net/wireless/ath/ath9k/htc_drv_main.c      |    20 +-
 drivers/net/wireless/ath/ath9k/htc_drv_txrx.c      |     8 +
 drivers/net/wireless/ath/ath9k/mac.h               |     6 +-
 drivers/net/wireless/ath/ath9k/main.c              |     2 +-
 drivers/net/wireless/ath/ath9k/reg.h               |    10 +-
 drivers/net/wireless/ath/ath9k/xmit.c              |     8 +-
 drivers/net/wireless/ath/carl9170/Makefile         |     5 +
 drivers/net/wireless/ath/carl9170/main.c           |     8 +-
 drivers/net/wireless/ath/carl9170/tx.c             |     8 +-
 drivers/net/wireless/ath/wcn36xx/hal.h             |     7 +-
 drivers/net/wireless/ath/wcn36xx/main.c            |   160 +-
 drivers/net/wireless/ath/wcn36xx/smd.c             |    98 +-
 drivers/net/wireless/ath/wcn36xx/smd.h             |     2 +
 drivers/net/wireless/ath/wcn36xx/txrx.c            |    29 +
 drivers/net/wireless/ath/wcn36xx/txrx.h            |     1 +
 drivers/net/wireless/ath/wil6210/cfg80211.c        |     5 +-
 drivers/net/wireless/ath/wil6210/debugfs.c         |    14 -
 drivers/net/wireless/ath/wil6210/netdev.c          |    14 +-
 drivers/net/wireless/ath/wil6210/pm.c              |     5 +-
 drivers/net/wireless/ath/wil6210/wil6210.h         |     1 -
 drivers/net/wireless/broadcom/b43/phy_n.c          |     2 +-
 drivers/net/wireless/broadcom/b43legacy/phy.c      |     2 +-
 .../wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c  |    39 +-
 .../broadcom/brcm80211/brcmfmac/cfg80211.c         |     3 +-
 .../wireless/broadcom/brcm80211/brcmfmac/common.c  |    23 +-
 .../wireless/broadcom/brcm80211/brcmfmac/common.h  |     1 +
 .../wireless/broadcom/brcm80211/brcmfmac/core.c    |     4 +-
 .../net/wireless/broadcom/brcm80211/brcmfmac/of.c  |     3 +
 .../broadcom/brcm80211/brcmsmac/mac80211_if.c      |     2 +-
 drivers/net/wireless/intel/ipw2x00/ipw2100.c       |    64 +-
 drivers/net/wireless/intel/ipw2x00/ipw2200.c       |   119 +-
 drivers/net/wireless/intel/ipw2x00/libipw_tx.c     |     2 +-
 drivers/net/wireless/intel/iwlegacy/3945-rs.c      |     6 +-
 drivers/net/wireless/intel/iwlegacy/4965-rs.c      |    22 +-
 drivers/net/wireless/intel/iwlegacy/common.c       |     6 +-
 drivers/net/wireless/intel/iwlwifi/dvm/rs.c        |    22 +-
 drivers/net/wireless/intel/iwlwifi/dvm/rxon.c      |     2 +-
 drivers/net/wireless/intel/iwlwifi/dvm/sta.c       |     4 +-
 drivers/net/wireless/intel/iwlwifi/fw/acpi.c       |     3 +
 .../net/wireless/intel/iwlwifi/fw/api/dbg-tlv.h    |     4 +-
 drivers/net/wireless/intel/iwlwifi/fw/api/debug.h  |     4 +-
 drivers/net/wireless/intel/iwlwifi/fw/api/filter.h |     2 +-
 drivers/net/wireless/intel/iwlwifi/fw/api/scan.h   |     4 +-
 drivers/net/wireless/intel/iwlwifi/fw/api/sta.h    |     2 +-
 drivers/net/wireless/intel/iwlwifi/fw/api/tdls.h   |     2 +-
 drivers/net/wireless/intel/iwlwifi/fw/error-dump.h |     2 +-
 drivers/net/wireless/intel/iwlwifi/fw/file.h       |    10 +-
 drivers/net/wireless/intel/iwlwifi/iwl-prph.h      |     2 +
 drivers/net/wireless/intel/iwlwifi/mei/main.c      |     3 +
 drivers/net/wireless/intel/iwlwifi/mei/sap.h       |     2 +-
 drivers/net/wireless/intel/iwlwifi/mvm/d3.c        |    24 +-
 drivers/net/wireless/intel/iwlwifi/mvm/fw.c        |    15 +-
 drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c  |    32 +-
 drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c  |    55 +-
 drivers/net/wireless/intel/iwlwifi/mvm/mvm.h       |     1 -
 drivers/net/wireless/intel/iwlwifi/mvm/power.c     |     3 +
 drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c     |    38 +-
 drivers/net/wireless/intel/iwlwifi/mvm/rs.c        |    35 +-
 drivers/net/wireless/intel/iwlwifi/mvm/rx.c        |    44 +-
 drivers/net/wireless/intel/iwlwifi/mvm/sf.c        |     8 +-
 drivers/net/wireless/intel/iwlwifi/mvm/sta.c       |    33 +-
 drivers/net/wireless/intel/iwlwifi/mvm/tx.c        |     6 +-
 drivers/net/wireless/intel/iwlwifi/pcie/trans.c    |    48 +-
 drivers/net/wireless/intersil/orinoco/airport.c    |     1 +
 drivers/net/wireless/mac80211_hwsim.c              |     4 +-
 drivers/net/wireless/marvell/mwifiex/11h.c         |     2 +
 drivers/net/wireless/marvell/mwifiex/sdio.c        |    23 +-
 drivers/net/wireless/marvell/mwifiex/sdio.h        |     6 +
 drivers/net/wireless/marvell/mwl8k.c               |    48 +-
 drivers/net/wireless/mediatek/mt76/agg-rx.c        |     8 +-
 drivers/net/wireless/mediatek/mt76/dma.c           |   215 +-
 drivers/net/wireless/mediatek/mt76/mac80211.c      |    14 +-
 drivers/net/wireless/mediatek/mt76/mcu.c           |     8 +-
 drivers/net/wireless/mediatek/mt76/mmio.c          |     9 +-
 drivers/net/wireless/mediatek/mt76/mt76.h          |    50 +-
 drivers/net/wireless/mediatek/mt76/mt7603/beacon.c |     8 +-
 drivers/net/wireless/mediatek/mt76/mt7603/dma.c    |    12 +-
 drivers/net/wireless/mediatek/mt76/mt7603/mac.c    |    16 +-
 drivers/net/wireless/mediatek/mt76/mt7603/main.c   |     8 +-
 drivers/net/wireless/mediatek/mt76/mt7615/dma.c    |    10 +-
 drivers/net/wireless/mediatek/mt76/mt7615/main.c   |     8 +-
 drivers/net/wireless/mediatek/mt76/mt7615/mmio.c   |     2 +-
 .../net/wireless/mediatek/mt76/mt76_connac_mcu.c   |    90 +-
 .../net/wireless/mediatek/mt76/mt76_connac_mcu.h   |     1 -
 drivers/net/wireless/mediatek/mt76/mt76x02_mac.c   |     4 +-
 drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c  |     8 +-
 drivers/net/wireless/mediatek/mt76/mt76x02_util.c  |    10 +-
 .../net/wireless/mediatek/mt76/mt7915/debugfs.c    |   205 +-
 drivers/net/wireless/mediatek/mt76/mt7915/dma.c    |    61 +-
 drivers/net/wireless/mediatek/mt76/mt7915/eeprom.c |     2 +
 drivers/net/wireless/mediatek/mt76/mt7915/init.c   |   129 +-
 drivers/net/wireless/mediatek/mt76/mt7915/mac.c    |   251 +-
 drivers/net/wireless/mediatek/mt76/mt7915/mac.h    |     2 +
 drivers/net/wireless/mediatek/mt76/mt7915/main.c   |    72 +-
 drivers/net/wireless/mediatek/mt76/mt7915/mcu.c    |   288 +-
 drivers/net/wireless/mediatek/mt76/mt7915/mcu.h    |    39 +-
 drivers/net/wireless/mediatek/mt76/mt7915/mmio.c   |    39 +-
 drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h |    26 +-
 drivers/net/wireless/mediatek/mt76/mt7915/pci.c    |    99 +-
 drivers/net/wireless/mediatek/mt76/mt7915/regs.h   |    61 +-
 drivers/net/wireless/mediatek/mt76/mt7915/soc.c    |    41 +-
 drivers/net/wireless/mediatek/mt76/mt7921/dma.c    |     6 +-
 drivers/net/wireless/mediatek/mt76/mt7921/init.c   |    15 +-
 drivers/net/wireless/mediatek/mt76/mt7921/mac.c    |    43 +-
 drivers/net/wireless/mediatek/mt76/mt7921/main.c   |   155 +-
 drivers/net/wireless/mediatek/mt76/mt7921/mcu.c    |   122 +-
 drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h |    15 +-
 drivers/net/wireless/mediatek/mt76/mt7921/pci.c    |    10 +-
 drivers/net/wireless/mediatek/mt76/mt7921/regs.h   |     5 +
 drivers/net/wireless/mediatek/mt76/mt7921/usb.c    |    62 +-
 .../net/wireless/mediatek/mt76/mt7921/usb_mac.c    |     7 +-
 drivers/net/wireless/mediatek/mt76/tx.c            |    53 +-
 drivers/net/wireless/mediatek/mt7601u/mac.c        |     2 +-
 drivers/net/wireless/mediatek/mt7601u/tx.c         |     4 +-
 drivers/net/wireless/microchip/wilc1000/hif.h      |     2 +-
 drivers/net/wireless/microchip/wilc1000/mon.c      |     4 +-
 drivers/net/wireless/microchip/wilc1000/netdev.c   |     3 +-
 drivers/net/wireless/microchip/wilc1000/sdio.c     |     2 +-
 drivers/net/wireless/microchip/wilc1000/wlan.c     |     7 +-
 drivers/net/wireless/purelifi/Kconfig              |    17 +
 drivers/net/wireless/purelifi/Makefile             |     2 +
 drivers/net/wireless/purelifi/plfxlc/Kconfig       |    14 +
 drivers/net/wireless/purelifi/plfxlc/Makefile      |     3 +
 drivers/net/wireless/purelifi/plfxlc/chip.c        |    98 +
 drivers/net/wireless/purelifi/plfxlc/chip.h        |    70 +
 drivers/net/wireless/purelifi/plfxlc/firmware.c    |   276 +
 drivers/net/wireless/purelifi/plfxlc/intf.h        |    52 +
 drivers/net/wireless/purelifi/plfxlc/mac.c         |   754 +
 drivers/net/wireless/purelifi/plfxlc/mac.h         |   184 +
 drivers/net/wireless/purelifi/plfxlc/usb.c         |   891 +
 drivers/net/wireless/purelifi/plfxlc/usb.h         |   198 +
 .../wireless/quantenna/qtnfmac/pcie/pearl_pcie.c   |     4 +-
 .../wireless/quantenna/qtnfmac/pcie/topaz_pcie.c   |     4 +-
 drivers/net/wireless/ralink/rt2x00/rt2800lib.c     |     8 +-
 drivers/net/wireless/ralink/rt2x00/rt2x00queue.c   |     2 +-
 drivers/net/wireless/realtek/rtl818x/rtl8180/dev.c |     8 +-
 .../net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c  |   146 +-
 drivers/net/wireless/realtek/rtlwifi/base.c        |    44 +-
 .../realtek/rtlwifi/btcoexist/halbtc8821a1ant.c    |    16 +-
 drivers/net/wireless/realtek/rtlwifi/core.c        |    40 +-
 drivers/net/wireless/realtek/rtlwifi/pci.c         |    15 +-
 drivers/net/wireless/realtek/rtlwifi/rc.c          |    20 +-
 .../net/wireless/realtek/rtlwifi/rtl8188ee/hw.c    |    26 +-
 .../net/wireless/realtek/rtlwifi/rtl8188ee/trx.c   |     8 +-
 .../net/wireless/realtek/rtlwifi/rtl8192ce/hw.c    |    26 +-
 .../net/wireless/realtek/rtlwifi/rtl8192ce/trx.c   |     6 +-
 .../net/wireless/realtek/rtlwifi/rtl8192cu/hw.c    |    30 +-
 .../net/wireless/realtek/rtlwifi/rtl8192cu/trx.c   |     2 +-
 .../net/wireless/realtek/rtlwifi/rtl8192de/hw.c    |    26 +-
 .../net/wireless/realtek/rtlwifi/rtl8192de/phy.c   |     5 +-
 .../net/wireless/realtek/rtlwifi/rtl8192de/trx.c   |     4 +-
 .../net/wireless/realtek/rtlwifi/rtl8192ee/hw.c    |    12 +-
 .../net/wireless/realtek/rtlwifi/rtl8192ee/trx.c   |     8 +-
 .../net/wireless/realtek/rtlwifi/rtl8192se/hw.c    |    26 +-
 .../net/wireless/realtek/rtlwifi/rtl8192se/trx.c   |     2 +-
 .../net/wireless/realtek/rtlwifi/rtl8723ae/hw.c    |    26 +-
 .../net/wireless/realtek/rtlwifi/rtl8723ae/trx.c   |     8 +-
 .../net/wireless/realtek/rtlwifi/rtl8723be/hw.c    |    12 +-
 .../net/wireless/realtek/rtlwifi/rtl8723be/trx.c   |     8 +-
 .../net/wireless/realtek/rtlwifi/rtl8821ae/hw.c    |    30 +-
 .../net/wireless/realtek/rtlwifi/rtl8821ae/trx.c   |     6 +-
 drivers/net/wireless/realtek/rtlwifi/usb.c         |     2 +-
 drivers/net/wireless/realtek/rtw88/bf.c            |     2 +-
 drivers/net/wireless/realtek/rtw88/fw.c            |    31 +-
 drivers/net/wireless/realtek/rtw88/fw.h            |     4 +-
 drivers/net/wireless/realtek/rtw88/mac.c           |     2 +-
 drivers/net/wireless/realtek/rtw88/mac80211.c      |    44 +-
 drivers/net/wireless/realtek/rtw88/main.c          |    73 +-
 drivers/net/wireless/realtek/rtw88/main.h          |     8 +-
 drivers/net/wireless/realtek/rtw88/pci.c           |    19 +-
 drivers/net/wireless/realtek/rtw88/phy.c           |     2 +-
 drivers/net/wireless/realtek/rtw88/reg.h           |     2 +
 drivers/net/wireless/realtek/rtw88/rtw8723d.c      |     1 +
 drivers/net/wireless/realtek/rtw88/rtw8821c.c      |     5 +
 .../net/wireless/realtek/rtw88/rtw8821c_table.c    |     2 +-
 drivers/net/wireless/realtek/rtw88/rtw8821ce.c     |     4 +
 drivers/net/wireless/realtek/rtw88/rtw8822b.c      |     1 +
 drivers/net/wireless/realtek/rtw88/rtw8822c.c      |     1 +
 drivers/net/wireless/realtek/rtw88/rx.c            |     3 +-
 drivers/net/wireless/realtek/rtw88/tx.c            |    31 +-
 drivers/net/wireless/realtek/rtw88/tx.h            |     4 +
 drivers/net/wireless/realtek/rtw89/Kconfig         |    18 +-
 drivers/net/wireless/realtek/rtw89/Makefile        |     9 +
 drivers/net/wireless/realtek/rtw89/cam.c           |    57 +-
 drivers/net/wireless/realtek/rtw89/cam.h           |     4 +
 drivers/net/wireless/realtek/rtw89/coex.c          |    24 +-
 drivers/net/wireless/realtek/rtw89/core.c          |   193 +-
 drivers/net/wireless/realtek/rtw89/core.h          |   295 +-
 drivers/net/wireless/realtek/rtw89/debug.c         |    75 +-
 drivers/net/wireless/realtek/rtw89/debug.h         |     1 +
 drivers/net/wireless/realtek/rtw89/fw.c            |   301 +-
 drivers/net/wireless/realtek/rtw89/fw.h            |   388 +-
 drivers/net/wireless/realtek/rtw89/mac.c           |   736 +-
 drivers/net/wireless/realtek/rtw89/mac.h           |    82 +-
 drivers/net/wireless/realtek/rtw89/mac80211.c      |    16 +-
 drivers/net/wireless/realtek/rtw89/pci.c           |   954 +-
 drivers/net/wireless/realtek/rtw89/pci.h           |   389 +
 drivers/net/wireless/realtek/rtw89/phy.c           |   481 +-
 drivers/net/wireless/realtek/rtw89/phy.h           |    76 +-
 drivers/net/wireless/realtek/rtw89/ps.c            |    34 +-
 drivers/net/wireless/realtek/rtw89/reg.h           |  1907 +-
 drivers/net/wireless/realtek/rtw89/regd.c          |   513 +-
 drivers/net/wireless/realtek/rtw89/rtw8852a.c      |    81 +-
 drivers/net/wireless/realtek/rtw89/rtw8852a_rfk.c  |    16 +-
 .../net/wireless/realtek/rtw89/rtw8852a_table.c    |   605 +-
 drivers/net/wireless/realtek/rtw89/rtw8852ae.c     |    40 +
 drivers/net/wireless/realtek/rtw89/rtw8852c.c      |  2561 ++-
 drivers/net/wireless/realtek/rtw89/rtw8852c.h      |    20 +-
 drivers/net/wireless/realtek/rtw89/rtw8852c_rfk.c  |  4041 ++++
 drivers/net/wireless/realtek/rtw89/rtw8852c_rfk.h  |    28 +
 .../wireless/realtek/rtw89/rtw8852c_rfk_table.c    |   781 +
 .../wireless/realtek/rtw89/rtw8852c_rfk_table.h    |    67 +
 .../net/wireless/realtek/rtw89/rtw8852c_table.c    | 19470 +++++++++++++++++++
 .../net/wireless/realtek/rtw89/rtw8852c_table.h    |    36 +
 drivers/net/wireless/realtek/rtw89/rtw8852ce.c     |    48 +
 drivers/net/wireless/realtek/rtw89/ser.c           |   250 +-
 drivers/net/wireless/realtek/rtw89/txrx.h          |   107 +
 drivers/net/wireless/realtek/rtw89/util.h          |    30 +
 drivers/net/wireless/rsi/rsi_91x_mac80211.c        |    12 +-
 drivers/net/wireless/rsi/rsi_91x_mgmt.c            |     8 +-
 drivers/net/wireless/silabs/Kconfig                |    18 +
 drivers/net/wireless/silabs/Makefile               |     3 +
 .../{staging => net/wireless/silabs}/wfx/Kconfig   |     0
 .../{staging => net/wireless/silabs}/wfx/Makefile  |     0
 drivers/{staging => net/wireless/silabs}/wfx/bh.c  |     6 +-
 drivers/{staging => net/wireless/silabs}/wfx/bh.h  |     0
 drivers/{staging => net/wireless/silabs}/wfx/bus.h |     0
 .../wireless/silabs}/wfx/bus_sdio.c                |     0
 .../{staging => net/wireless/silabs}/wfx/bus_spi.c |     0
 .../{staging => net/wireless/silabs}/wfx/data_rx.c |     5 +-
 .../{staging => net/wireless/silabs}/wfx/data_rx.h |     0
 .../{staging => net/wireless/silabs}/wfx/data_tx.c |     3 +-
 .../{staging => net/wireless/silabs}/wfx/data_tx.h |     0
 .../{staging => net/wireless/silabs}/wfx/debug.c   |     0
 .../{staging => net/wireless/silabs}/wfx/debug.h   |     0
 .../{staging => net/wireless/silabs}/wfx/fwio.c    |     0
 .../{staging => net/wireless/silabs}/wfx/fwio.h    |     0
 .../wireless/silabs}/wfx/hif_api_cmd.h             |     0
 .../wireless/silabs}/wfx/hif_api_general.h         |     0
 .../wireless/silabs}/wfx/hif_api_mib.h             |     0
 .../{staging => net/wireless/silabs}/wfx/hif_rx.c  |     0
 .../{staging => net/wireless/silabs}/wfx/hif_rx.h  |     0
 .../{staging => net/wireless/silabs}/wfx/hif_tx.c  |     2 +-
 .../{staging => net/wireless/silabs}/wfx/hif_tx.h  |     0
 .../wireless/silabs}/wfx/hif_tx_mib.c              |     0
 .../wireless/silabs}/wfx/hif_tx_mib.h              |     0
 .../{staging => net/wireless/silabs}/wfx/hwio.c    |     0
 .../{staging => net/wireless/silabs}/wfx/hwio.h    |     0
 drivers/{staging => net/wireless/silabs}/wfx/key.c |     4 +-
 drivers/{staging => net/wireless/silabs}/wfx/key.h |     0
 .../{staging => net/wireless/silabs}/wfx/main.c    |     6 +
 .../{staging => net/wireless/silabs}/wfx/main.h    |     0
 .../{staging => net/wireless/silabs}/wfx/queue.c   |     3 +-
 .../{staging => net/wireless/silabs}/wfx/queue.h   |     0
 .../{staging => net/wireless/silabs}/wfx/scan.c    |    11 +-
 .../{staging => net/wireless/silabs}/wfx/scan.h    |     0
 drivers/{staging => net/wireless/silabs}/wfx/sta.c |    84 +-
 drivers/{staging => net/wireless/silabs}/wfx/sta.h |     0
 .../{staging => net/wireless/silabs}/wfx/traces.h  |     0
 drivers/{staging => net/wireless/silabs}/wfx/wfx.h |     7 +-
 drivers/net/wireless/st/cw1200/sta.c               |     4 +-
 drivers/net/wireless/ti/wl1251/event.c             |    22 +-
 drivers/net/wireless/ti/wl1251/io.c                |    20 +-
 drivers/net/wireless/ti/wl1251/tx.c                |    15 +-
 drivers/net/wireless/ti/wl18xx/debugfs.c           |    18 +-
 drivers/net/wireless/ti/wlcore/cmd.c               |    14 +-
 drivers/net/wireless/ti/wlcore/debugfs.c           |    52 +-
 drivers/net/wireless/ti/wlcore/main.c              |   241 +-
 drivers/net/wireless/ti/wlcore/scan.c              |     6 +-
 drivers/net/wireless/ti/wlcore/sdio.c              |     3 +-
 drivers/net/wireless/ti/wlcore/sysfs.c             |     6 +-
 drivers/net/wireless/ti/wlcore/testmode.c          |    12 +-
 drivers/net/wireless/ti/wlcore/tx.c                |     6 +-
 drivers/net/wireless/ti/wlcore/vendor_cmd.c        |    18 +-
 drivers/net/wwan/Kconfig                           |    14 +
 drivers/net/wwan/Makefile                          |     1 +
 drivers/net/wwan/iosm/iosm_ipc_coredump.h          |     5 +-
 drivers/net/wwan/iosm/iosm_ipc_protocol_ops.c      |    10 -
 drivers/net/wwan/t7xx/Makefile                     |    20 +
 drivers/net/wwan/t7xx/t7xx_cldma.c                 |   281 +
 drivers/net/wwan/t7xx/t7xx_cldma.h                 |   180 +
 drivers/net/wwan/t7xx/t7xx_dpmaif.c                |  1281 ++
 drivers/net/wwan/t7xx/t7xx_dpmaif.h                |   179 +
 drivers/net/wwan/t7xx/t7xx_hif_cldma.c             |  1339 ++
 drivers/net/wwan/t7xx/t7xx_hif_cldma.h             |   127 +
 drivers/net/wwan/t7xx/t7xx_hif_dpmaif.c            |   574 +
 drivers/net/wwan/t7xx/t7xx_hif_dpmaif.h            |   206 +
 drivers/net/wwan/t7xx/t7xx_hif_dpmaif_rx.c         |  1243 ++
 drivers/net/wwan/t7xx/t7xx_hif_dpmaif_rx.h         |   116 +
 drivers/net/wwan/t7xx/t7xx_hif_dpmaif_tx.c         |   683 +
 drivers/net/wwan/t7xx/t7xx_hif_dpmaif_tx.h         |    78 +
 drivers/net/wwan/t7xx/t7xx_mhccif.c                |   122 +
 drivers/net/wwan/t7xx/t7xx_mhccif.h                |    37 +
 drivers/net/wwan/t7xx/t7xx_modem_ops.c             |   727 +
 drivers/net/wwan/t7xx/t7xx_modem_ops.h             |    88 +
 drivers/net/wwan/t7xx/t7xx_netdev.c                |   423 +
 drivers/net/wwan/t7xx/t7xx_netdev.h                |    55 +
 drivers/net/wwan/t7xx/t7xx_pci.c                   |   761 +
 drivers/net/wwan/t7xx/t7xx_pci.h                   |   120 +
 drivers/net/wwan/t7xx/t7xx_pcie_mac.c              |   262 +
 drivers/net/wwan/t7xx/t7xx_pcie_mac.h              |    31 +
 drivers/net/wwan/t7xx/t7xx_port.h                  |   135 +
 drivers/net/wwan/t7xx/t7xx_port_ctrl_msg.c         |   273 +
 drivers/net/wwan/t7xx/t7xx_port_proxy.c            |   509 +
 drivers/net/wwan/t7xx/t7xx_port_proxy.h            |    98 +
 drivers/net/wwan/t7xx/t7xx_port_wwan.c             |   176 +
 drivers/net/wwan/t7xx/t7xx_reg.h                   |   350 +
 drivers/net/wwan/t7xx/t7xx_state_monitor.c         |   550 +
 drivers/net/wwan/t7xx/t7xx_state_monitor.h         |   135 +
 drivers/net/wwan/wwan_hwsim.c                      |    22 +-
 drivers/net/xen-netback/interface.c                |     3 +-
 drivers/nfc/st21nfca/se.c                          |    17 +-
 drivers/nfc/st21nfca/st21nfca.h                    |     1 +
 drivers/ptp/ptp_clock.c                            |    31 +-
 drivers/ptp/ptp_clockmatrix.c                      |   321 +-
 drivers/ptp/ptp_clockmatrix.h                      |     7 +-
 drivers/ptp/ptp_ocp.c                              |   559 +-
 drivers/ptp/ptp_private.h                          |    11 +
 drivers/ptp/ptp_sysfs.c                            |    11 +-
 drivers/ptp/ptp_vclock.c                           |    82 +-
 drivers/s390/net/qeth_core.h                       |     2 -
 drivers/s390/net/qeth_core_main.c                  |     3 +-
 drivers/s390/net/qeth_l2_main.c                    |     4 +-
 drivers/s390/net/qeth_l3_main.c                    |     4 +-
 drivers/scsi/fcoe/fcoe.c                           |     2 +-
 drivers/ssb/pci.c                                  |     1 -
 drivers/staging/Kconfig                            |     1 -
 drivers/staging/Makefile                           |     1 -
 drivers/staging/wfx/TODO                           |     6 -
 fs/afs/misc.c                                      |     5 +-
 fs/afs/rotate.c                                    |     4 +
 fs/afs/rxrpc.c                                     |     8 +-
 fs/afs/write.c                                     |     1 +
 fs/proc/proc_sysctl.c                              |     4 +-
 fs/seq_file.c                                      |    32 +
 include/linux/bpf-cgroup.h                         |     8 +-
 include/linux/bpf.h                                |   351 +-
 include/linux/bpf_local_storage.h                  |     4 +-
 include/linux/bpf_types.h                          |     1 +
 include/linux/bpf_verifier.h                       |    23 +-
 include/linux/btf.h                                |    23 +
 include/linux/btf_ids.h                            |     3 +-
 include/linux/can/dev.h                            |    10 -
 include/linux/can/led.h                            |    51 -
 include/linux/can/rx-offload.h                     |     4 +-
 include/linux/ethtool.h                            |     4 +
 include/linux/fortify-string.h                     |    16 +
 include/linux/ftrace.h                             |     6 +
 include/linux/icmpv6.h                             |    11 +-
 include/linux/ieee802154.h                         |    81 +-
 include/linux/ipv6.h                               |     6 +-
 include/linux/kallsyms.h                           |     7 +-
 include/linux/list.h                               |    36 +
 include/linux/mdio.h                               |    70 +
 include/linux/mfd/idt8a340_reg.h                   |    12 +-
 include/linux/mlx5/accel.h                         |   156 -
 include/linux/mlx5/driver.h                        |    17 +-
 include/linux/mlx5/fs.h                            |    12 +
 include/linux/mlx5/mlx5_ifc.h                      |    23 +-
 include/linux/mlx5/mlx5_ifc_fpga.h                 |   211 -
 include/linux/mlx5/port.h                          |     2 +-
 include/linux/netdevice.h                          |   378 +-
 include/linux/phy.h                                |     8 +-
 include/linux/phylink.h                            |     6 -
 include/linux/ptp_classify.h                       |     3 +
 include/linux/ptp_clock_kernel.h                   |    42 +-
 include/linux/qed/qed_fcoe_if.h                    |     4 +-
 include/linux/qed/qed_iscsi_if.h                   |     4 +-
 include/linux/qed/qed_nvmetcp_if.h                 |     2 +-
 include/linux/qed/qed_nvmetcp_ip_services_if.h     |    29 -
 include/linux/rtnetlink.h                          |     1 +
 include/linux/seq_file.h                           |     4 +
 include/linux/skbuff.h                             |   419 +-
 include/linux/soc/mediatek/mtk_wed.h               |   131 +
 include/linux/socket.h                             |     6 +-
 include/linux/string.h                             |     4 +
 include/linux/sysctl.h                             |     9 +-
 include/linux/usb/rndis_host.h                     |     1 +
 include/linux/usb/usbnet.h                         |     1 +
 include/net/act_api.h                              |     3 +-
 include/net/bluetooth/hci.h                        |    10 +
 include/net/bluetooth/hci_core.h                   |     8 +-
 include/net/cfg80211.h                             |    16 +-
 include/net/cfg802154.h                            |     8 +-
 include/net/devlink.h                              |    48 +
 include/net/dsa.h                                  |    25 +-
 include/net/flow_dissector.h                       |     9 +
 include/net/if_inet6.h                             |     8 +
 include/net/inet6_hashtables.h                     |    28 +-
 include/net/inet_connection_sock.h                 |     5 +-
 include/net/inet_hashtables.h                      |   145 +-
 include/net/inet_sock.h                            |     5 +-
 include/net/ip.h                                   |     2 +-
 include/net/ip_fib.h                               |     4 +-
 include/net/ipv6.h                                 |    44 +
 include/net/mac80211.h                             |   126 +-
 include/net/mac802154.h                            |    19 +
 include/net/mptcp.h                                |    11 +-
 include/net/net_debug.h                            |   157 +
 include/net/netfilter/nf_conntrack.h               |    23 +-
 include/net/netfilter/nf_conntrack_core.h          |     2 +-
 include/net/netfilter/nf_conntrack_count.h         |     1 +
 include/net/netfilter/nf_conntrack_ecache.h        |    53 +-
 include/net/netfilter/nf_conntrack_extend.h        |    31 +-
 include/net/netfilter/nf_conntrack_labels.h        |    10 +-
 include/net/netfilter/nf_conntrack_timeout.h       |     8 -
 include/net/netfilter/nf_reject.h                  |    21 +-
 include/net/netns/conntrack.h                      |     8 +-
 include/net/page_pool.h                            |    21 +
 include/net/ping.h                                 |     4 +-
 include/net/pkt_cls.h                              |     6 +-
 include/net/route.h                                |    36 +-
 include/net/rtnetlink.h                            |    16 +-
 include/net/sctp/sctp.h                            |     2 +-
 include/net/sock.h                                 |    64 +-
 include/net/strparser.h                            |     4 +
 include/net/tc_act/tc_gact.h                       |    15 +
 include/net/tc_act/tc_skbedit.h                    |    13 +
 include/net/tcp.h                                  |    45 +-
 include/net/tls.h                                  |    16 +-
 include/net/udp.h                                  |     8 +-
 include/net/xfrm.h                                 |    20 +-
 include/rdma/ib_verbs.h                            |     8 -
 include/soc/mscc/ocelot.h                          |    42 +-
 include/soc/mscc/ocelot_vcap.h                     |     2 +-
 include/trace/events/mptcp.h                       |     6 +-
 include/trace/events/rxrpc.h                       |   265 +-
 include/trace/events/skb.h                         |    21 +-
 include/trace/events/tcp.h                         |    47 +-
 include/uapi/asm-generic/socket.h                  |     2 +
 include/uapi/linux/atm_zatm.h                      |    47 -
 include/uapi/linux/bpf.h                           |   125 +
 include/uapi/linux/btf.h                           |     4 +-
 include/uapi/linux/can/isotp.h                     |    25 +-
 include/uapi/linux/devlink.h                       |    23 +
 include/uapi/linux/ethtool.h                       |     1 +
 include/uapi/linux/ethtool_netlink.h               |     1 +
 include/uapi/linux/if_link.h                       |     7 +
 include/uapi/linux/ipv6.h                          |     1 +
 include/uapi/linux/mdio.h                          |    75 +
 include/uapi/linux/mptcp.h                         |     8 +
 include/uapi/linux/neighbour.h                     |     2 +
 include/uapi/linux/netlink.h                       |     1 +
 include/uapi/linux/nl80211.h                       |     2 +
 include/uapi/linux/pkt_cls.h                       |     2 +
 include/uapi/linux/tc_act/tc_skbedit.h             |     2 +
 include/uapi/linux/tipc_config.h                   |    28 +-
 include/uapi/linux/tls.h                           |     2 +
 kernel/bpf/Makefile                                |     2 +-
 kernel/bpf/arraymap.c                              |    61 +-
 kernel/bpf/bloom_filter.c                          |     6 +-
 kernel/bpf/bpf_inode_storage.c                     |    10 +-
 kernel/bpf/bpf_iter.c                              |    32 +-
 kernel/bpf/bpf_local_storage.c                     |    29 +-
 kernel/bpf/bpf_lsm.c                               |    17 +
 kernel/bpf/bpf_struct_ops.c                        |    81 +-
 kernel/bpf/bpf_task_storage.c                      |     9 +-
 kernel/bpf/btf.c                                   |   640 +-
 kernel/bpf/cgroup.c                                |   106 +-
 kernel/bpf/core.c                                  |    29 +-
 kernel/bpf/cpumap.c                                |     6 +-
 kernel/bpf/devmap.c                                |    10 +-
 kernel/bpf/hashtab.c                               |   133 +-
 kernel/bpf/helpers.c                               |   223 +-
 kernel/bpf/link_iter.c                             |   107 +
 kernel/bpf/local_storage.c                         |     7 +-
 kernel/bpf/lpm_trie.c                              |     6 +-
 kernel/bpf/map_in_map.c                            |     5 +-
 kernel/bpf/queue_stack_maps.c                      |    10 +-
 kernel/bpf/reuseport_array.c                       |     6 +-
 kernel/bpf/ringbuf.c                               |    88 +-
 kernel/bpf/stackmap.c                              |     7 +-
 kernel/bpf/syscall.c                               |   500 +-
 kernel/bpf/task_iter.c                             |     1 -
 kernel/bpf/trampoline.c                            |   118 +-
 kernel/bpf/verifier.c                              |   819 +-
 kernel/kallsyms.c                                  |     3 +-
 kernel/sysctl.c                                    |    79 -
 kernel/trace/bpf_trace.c                           |   144 +-
 kernel/trace/fprobe.c                              |    32 +-
 kernel/trace/ftrace.c                              |    62 +
 lib/test_bpf.c                                     |   315 +-
 lib/test_sysctl.c                                  |    32 +
 net/8021q/vlan.c                                   |     3 +-
 net/8021q/vlan_dev.c                               |     3 +-
 net/Kconfig.debug                                  |     7 +
 net/appletalk/ddp.c                                |     3 +-
 net/atm/common.c                                   |     4 +-
 net/ax25/af_ax25.c                                 |     3 +-
 net/ax25/ax25_dev.c                                |    22 +-
 net/batman-adv/bridge_loop_avoidance.c             |     4 +-
 net/batman-adv/hard-interface.c                    |     2 +
 net/batman-adv/main.h                              |     2 +-
 net/batman-adv/translation-table.c                 |    12 +-
 net/bluetooth/af_bluetooth.c                       |     7 +-
 net/bluetooth/eir.c                                |    31 +
 net/bluetooth/eir.h                                |     4 +
 net/bluetooth/hci_conn.c                           |     7 +-
 net/bluetooth/hci_core.c                           |     2 -
 net/bluetooth/hci_event.c                          |    35 +-
 net/bluetooth/hci_request.c                        |     4 +-
 net/bluetooth/hci_sock.c                           |     3 +-
 net/bluetooth/hci_sync.c                           |    90 +-
 net/bluetooth/mgmt.c                               |    18 +
 net/bluetooth/mgmt_util.c                          |     2 +-
 net/bluetooth/sco.c                                |    23 +-
 net/bpf/bpf_dummy_struct_ops.c                     |    24 +-
 net/bpf/test_run.c                                 |    86 +-
 net/bridge/br_device.c                             |     1 +
 net/bridge/br_fdb.c                                |   160 +-
 net/bridge/br_if.c                                 |    12 +-
 net/bridge/br_mdb.c                                |    12 +-
 net/bridge/br_netlink.c                            |     9 +-
 net/bridge/br_private.h                            |    21 +-
 net/bridge/br_switchdev.c                          |     3 +-
 net/bridge/br_sysfs_br.c                           |     6 +-
 net/caif/caif_socket.c                             |     2 +-
 net/can/bcm.c                                      |     7 +-
 net/can/isotp.c                                    |   130 +-
 net/can/j1939/socket.c                             |     4 +-
 net/can/raw.c                                      |    20 +-
 net/core/bpf_sk_storage.c                          |    11 +-
 net/core/datagram.c                                |     7 +-
 net/core/datagram.h                                |    15 -
 net/core/dev.c                                     |   232 +-
 net/core/dev.h                                     |   112 +
 net/core/dev_addr_lists.c                          |     2 +
 net/core/dev_ioctl.c                               |     2 +
 net/core/devlink.c                                 |   653 +-
 net/core/drop_monitor.c                            |     2 +-
 net/core/filter.c                                  |    37 +-
 net/core/flow_dissector.c                          |    20 +
 net/core/gro.c                                     |     8 +
 net/core/link_watch.c                              |     1 +
 net/core/neighbour.c                               |     2 +-
 net/core/net-procfs.c                              |     2 +
 net/core/net-sysfs.c                               |    22 +-
 net/core/page_pool.c                               |    83 +-
 net/core/rtnetlink.c                               |   449 +-
 net/core/skbuff.c                                  |    67 +-
 net/core/skmsg.c                                   |    22 +-
 net/core/sock.c                                    |   126 +-
 net/core/sock_map.c                                |    10 +-
 net/core/sysctl_net_core.c                         |    29 +-
 net/dccp/dccp.h                                    |     4 +-
 net/dccp/ipv4.c                                    |     7 +-
 net/dccp/ipv6.c                                    |     6 +-
 net/dccp/proto.c                                   |    40 +-
 net/decnet/dn_route.c                              |     2 +-
 net/dsa/dsa.c                                      |    49 -
 net/dsa/dsa2.c                                     |    25 +-
 net/dsa/dsa_priv.h                                 |    29 +-
 net/dsa/port.c                                     |   136 +-
 net/dsa/slave.c                                    |    67 +-
 net/dsa/switch.c                                   |   198 +-
 net/dsa/tag_8021q.c                                |    10 +-
 net/ethernet/eth.c                                 |     2 +-
 net/ethtool/common.c                               |     3 +
 net/ethtool/netlink.h                              |     2 +-
 net/ethtool/rings.c                                |    54 +-
 net/ieee802154/socket.c                            |    12 +-
 net/ipv4/Kconfig                                   |     1 -
 net/ipv4/af_inet.c                                 |    11 +-
 net/ipv4/arp.c                                     |     7 +-
 net/ipv4/datagram.c                                |     7 +-
 net/ipv4/devinet.c                                 |     2 +-
 net/ipv4/esp4.c                                    |     6 -
 net/ipv4/fib_frontend.c                            |     4 +-
 net/ipv4/fib_rules.c                               |     2 +-
 net/ipv4/fib_semantics.c                           |     4 +-
 net/ipv4/fib_trie.c                                |    12 +-
 net/ipv4/fou.c                                     |     1 -
 net/ipv4/icmp.c                                    |    77 +-
 net/ipv4/igmp.c                                    |     4 +-
 net/ipv4/inet_connection_sock.c                    |   245 +-
 net/ipv4/inet_diag.c                               |     5 +-
 net/ipv4/inet_fragment.c                           |     2 +-
 net/ipv4/inet_hashtables.c                         |   329 +-
 net/ipv4/ip_forward.c                              |    13 +-
 net/ipv4/ip_gre.c                                  |    50 +-
 net/ipv4/ip_input.c                                |     1 +
 net/ipv4/ipmr.c                                    |     2 +-
 net/ipv4/netfilter.c                               |     3 +-
 net/ipv4/netfilter/nf_reject_ipv4.c                |    10 +-
 net/ipv4/netfilter/nft_fib_ipv4.c                  |     4 +
 net/ipv4/ping.c                                    |    40 +-
 net/ipv4/raw.c                                     |     6 +-
 net/ipv4/route.c                                   |    51 +-
 net/ipv4/sysctl_net_ipv4.c                         |    16 +-
 net/ipv4/tcp.c                                     |    83 +-
 net/ipv4/tcp_bbr.c                                 |    22 +-
 net/ipv4/tcp_bic.c                                 |    14 +-
 net/ipv4/tcp_bpf.c                                 |    15 +-
 net/ipv4/tcp_cdg.c                                 |    30 +-
 net/ipv4/tcp_cong.c                                |    30 +-
 net/ipv4/tcp_cubic.c                               |    26 +-
 net/ipv4/tcp_dctcp.c                               |    11 +-
 net/ipv4/tcp_highspeed.c                           |    18 +-
 net/ipv4/tcp_htcp.c                                |    10 +-
 net/ipv4/tcp_hybla.c                               |    18 +-
 net/ipv4/tcp_illinois.c                            |    12 +-
 net/ipv4/tcp_input.c                               |   177 +-
 net/ipv4/tcp_ipv4.c                                |    30 +-
 net/ipv4/tcp_lp.c                                  |     6 +-
 net/ipv4/tcp_metrics.c                             |    12 +-
 net/ipv4/tcp_nv.c                                  |    24 +-
 net/ipv4/tcp_output.c                              |    46 +-
 net/ipv4/tcp_rate.c                                |     2 +-
 net/ipv4/tcp_recovery.c                            |    15 +-
 net/ipv4/tcp_scalable.c                            |     4 +-
 net/ipv4/tcp_vegas.c                               |    21 +-
 net/ipv4/tcp_veno.c                                |    24 +-
 net/ipv4/tcp_westwood.c                            |     3 +-
 net/ipv4/tcp_yeah.c                                |    30 +-
 net/ipv4/udp.c                                     |    16 +-
 net/ipv4/udp_bpf.c                                 |    17 +-
 net/ipv4/udp_impl.h                                |     4 +-
 net/ipv6/addrconf.c                                |    51 +-
 net/ipv6/af_inet6.c                                |     7 +-
 net/ipv6/datagram.c                                |    10 +-
 net/ipv6/esp6.c                                    |     6 -
 net/ipv6/exthdrs.c                                 |    44 +-
 net/ipv6/icmp.c                                    |    31 +-
 net/ipv6/inet6_hashtables.c                        |    11 +-
 net/ipv6/ip6_gre.c                                 |    34 +-
 net/ipv6/ip6_input.c                               |    41 +-
 net/ipv6/ip6_offload.c                             |    56 +-
 net/ipv6/ip6_output.c                              |    56 +-
 net/ipv6/ip6_tunnel.c                              |     2 -
 net/ipv6/ndisc.c                                   |    20 +-
 net/ipv6/netfilter.c                               |     3 +-
 net/ipv6/netfilter/nf_reject_ipv6.c                |     4 +-
 net/ipv6/netfilter/nft_fib_ipv6.c                  |     4 +
 net/ipv6/raw.c                                     |     6 +-
 net/ipv6/route.c                                   |     6 +-
 net/ipv6/sysctl_net_ipv6.c                         |     6 +-
 net/ipv6/tcp_ipv6.c                                |     6 +-
 net/ipv6/udp.c                                     |    23 +-
 net/ipv6/udp_impl.h                                |     4 +-
 net/iucv/af_iucv.c                                 |     3 +-
 net/key/af_key.c                                   |     4 +-
 net/l2tp/l2tp_ip.c                                 |     8 +-
 net/l2tp/l2tp_ip6.c                                |    12 +-
 net/l2tp/l2tp_ppp.c                                |     3 +-
 net/mac80211/agg-rx.c                              |    12 +-
 net/mac80211/agg-tx.c                              |     6 +-
 net/mac80211/airtime.c                             |     4 +-
 net/mac80211/cfg.c                                 |    81 +-
 net/mac80211/chan.c                                |     8 +-
 net/mac80211/debugfs.c                             |     1 +
 net/mac80211/debugfs_netdev.c                      |     2 +-
 net/mac80211/debugfs_sta.c                         |    12 +-
 net/mac80211/eht.c                                 |     6 +-
 net/mac80211/ethtool.c                             |     4 +-
 net/mac80211/he.c                                  |     8 +-
 net/mac80211/ht.c                                  |     8 +-
 net/mac80211/ibss.c                                |    26 +-
 net/mac80211/ieee80211_i.h                         |    12 +-
 net/mac80211/key.c                                 |     9 +-
 net/mac80211/main.c                                |     4 +-
 net/mac80211/mesh_hwmp.c                           |     2 +-
 net/mac80211/mesh_plink.c                          |    24 +-
 net/mac80211/mlme.c                                |   135 +-
 net/mac80211/ocb.c                                 |     2 +-
 net/mac80211/offchannel.c                          |     2 +-
 net/mac80211/rate.c                                |     8 +-
 net/mac80211/rc80211_minstrel_ht.c                 |   177 +-
 net/mac80211/rc80211_minstrel_ht.h                 |     2 +-
 net/mac80211/rx.c                                  |   131 +-
 net/mac80211/s1g.c                                 |     4 +-
 net/mac80211/scan.c                                |    20 +
 net/mac80211/sta_info.c                            |   110 +-
 net/mac80211/sta_info.h                            |   155 +-
 net/mac80211/status.c                              |   130 +-
 net/mac80211/tdls.c                                |    26 +-
 net/mac80211/trace.h                               |     4 +-
 net/mac80211/tx.c                                  |    28 +-
 net/mac80211/util.c                                |    40 -
 net/mac80211/vht.c                                 |    78 +-
 net/mac80211/wpa.c                                 |   103 +-
 net/mac802154/cfg.c                                |     1 +
 net/mac802154/ieee802154_i.h                       |     2 +
 net/mac802154/main.c                               |    54 +-
 net/mac802154/util.c                               |    22 +-
 net/mctp/af_mctp.c                                 |     4 +-
 net/mctp/test/route-test.c                         |     8 +-
 net/mpls/af_mpls.c                                 |     3 +-
 net/mptcp/Makefile                                 |     4 +-
 net/mptcp/bpf.c                                    |    21 +
 net/mptcp/ctrl.c                                   |    21 +
 net/mptcp/mib.c                                    |     5 +
 net/mptcp/mib.h                                    |     7 +
 net/mptcp/mptcp_diag.c                             |   105 +-
 net/mptcp/options.c                                |    69 +-
 net/mptcp/pm.c                                     |   108 +-
 net/mptcp/pm_netlink.c                             |   266 +-
 net/mptcp/pm_userspace.c                           |   429 +
 net/mptcp/protocol.c                               |   123 +-
 net/mptcp/protocol.h                               |   101 +-
 net/mptcp/sockopt.c                                |    21 +-
 net/mptcp/subflow.c                                |    72 +-
 net/netfilter/ipvs/ip_vs_ctl.c                     |     4 +-
 net/netfilter/nf_conncount.c                       |    11 +
 net/netfilter/nf_conntrack_bpf.c                   |    22 +-
 net/netfilter/nf_conntrack_core.c                  |   304 +-
 net/netfilter/nf_conntrack_ecache.c                |   178 +-
 net/netfilter/nf_conntrack_extend.c                |    32 +-
 net/netfilter/nf_conntrack_helper.c                |     5 -
 net/netfilter/nf_conntrack_netlink.c               |   152 +-
 net/netfilter/nf_conntrack_proto.c                 |    10 +-
 net/netfilter/nf_conntrack_proto_tcp.c             |    52 +-
 net/netfilter/nf_conntrack_standalone.c            |     2 +-
 net/netfilter/nf_conntrack_timeout.c               |     7 +-
 net/netfilter/nf_log_syslog.c                      |   136 +-
 net/netfilter/nf_nat_masquerade.c                  |     5 +-
 net/netfilter/nf_tables_api.c                      |     6 +-
 net/netfilter/nfnetlink.c                          |    40 +-
 net/netfilter/nfnetlink_cttimeout.c                |    61 +-
 net/netfilter/nft_bitwise.c                        |    13 +-
 net/netfilter/nft_fib.c                            |     4 +
 net/netfilter/nft_flow_offload.c                   |     8 +
 net/netlink/af_netlink.c                           |     3 +-
 net/netrom/af_netrom.c                             |     3 +-
 net/nfc/core.c                                     |     1 +
 net/nfc/llcp_sock.c                                |     3 +-
 net/nfc/rawsock.c                                  |     3 +-
 net/packet/af_packet.c                             |    22 +-
 net/phonet/datagram.c                              |     4 +-
 net/phonet/pep.c                                   |     7 +-
 net/qrtr/af_qrtr.c                                 |     3 +-
 net/rose/af_rose.c                                 |     3 +-
 net/rose/rose_route.c                              |    25 +-
 net/rxrpc/af_rxrpc.c                               |     2 +-
 net/rxrpc/ar-internal.h                            |    38 +-
 net/rxrpc/call_accept.c                            |    10 +-
 net/rxrpc/call_event.c                             |     7 +-
 net/rxrpc/call_object.c                            |    62 +-
 net/rxrpc/conn_client.c                            |    30 +-
 net/rxrpc/conn_object.c                            |    51 +-
 net/rxrpc/conn_service.c                           |     8 +-
 net/rxrpc/input.c                                  |    62 +-
 net/rxrpc/local_object.c                           |    68 +-
 net/rxrpc/net_ns.c                                 |     7 +-
 net/rxrpc/output.c                                 |    20 +-
 net/rxrpc/peer_object.c                            |    40 +-
 net/rxrpc/proc.c                                   |    85 +-
 net/rxrpc/recvmsg.c                                |     8 +-
 net/rxrpc/sendmsg.c                                |     6 +
 net/rxrpc/skbuff.c                                 |     1 -
 net/rxrpc/sysctl.c                                 |     4 +-
 net/sched/act_api.c                                |     4 +-
 net/sched/act_csum.c                               |     3 +-
 net/sched/act_ct.c                                 |     3 +-
 net/sched/act_gact.c                               |    13 +-
 net/sched/act_gate.c                               |     3 +-
 net/sched/act_mirred.c                             |     4 +-
 net/sched/act_mpls.c                               |    10 +-
 net/sched/act_pedit.c                              |     4 +-
 net/sched/act_police.c                             |    20 +-
 net/sched/act_sample.c                             |     3 +-
 net/sched/act_skbedit.c                            |    65 +-
 net/sched/act_tunnel_key.c                         |     4 +-
 net/sched/act_vlan.c                               |     4 +-
 net/sched/cls_api.c                                |    22 +-
 net/sched/cls_flower.c                             |   104 +-
 net/sched/cls_matchall.c                           |    19 +-
 net/sched/em_meta.c                                |     7 +-
 net/sched/sch_generic.c                            |    12 +-
 net/sctp/input.c                                   |     4 +-
 net/sctp/ipv6.c                                    |     4 +-
 net/sctp/output.c                                  |     3 +-
 net/sctp/socket.c                                  |    18 +-
 net/sctp/stream_sched.c                            |     9 +-
 net/sctp/ulpevent.c                                |     2 +-
 net/smc/af_smc.c                                   |    52 +-
 net/smc/smc_ib.c                                   |     1 +
 net/smc/smc_tx.c                                   |    17 +-
 net/smc/smc_wr.c                                   |     5 +-
 net/socket.c                                       |    75 +-
 net/sunrpc/svcsock.c                               |     2 +-
 net/sunrpc/xprtsock.c                              |     2 +-
 net/tls/tls_device.c                               |    59 +-
 net/tls/tls_main.c                                 |    55 +
 net/tls/tls_sw.c                                   |   491 +-
 net/unix/af_unix.c                                 |    11 +-
 net/unix/unix_bpf.c                                |     5 +-
 net/vmw_vsock/virtio_transport.c                   |   197 +-
 net/vmw_vsock/vmci_transport.c                     |     5 +-
 net/wireless/chan.c                                |    93 +-
 net/wireless/core.h                                |    14 +-
 net/wireless/ibss.c                                |     4 +-
 net/wireless/nl80211.c                             |   417 +-
 net/wireless/reg.c                                 |     4 +
 net/x25/af_x25.c                                   |     3 +-
 net/x25/x25_proc.c                                 |     3 +-
 net/xdp/xsk.c                                      |     4 +-
 net/xdp/xsk_queue.h                                |     4 +-
 net/xdp/xskmap.c                                   |     6 +-
 net/xfrm/espintcp.c                                |     4 +-
 net/xfrm/xfrm_device.c                             |    15 +-
 net/xfrm/xfrm_state.c                              |     4 +-
 net/xfrm/xfrm_user.c                               |     5 +-
 samples/bpf/Makefile                               |    19 +-
 samples/bpf/cpustat_user.c                         |     1 -
 samples/bpf/hbm.c                                  |     5 +-
 samples/bpf/ibumad_user.c                          |     1 -
 samples/bpf/map_perf_test_user.c                   |     1 -
 samples/bpf/offwaketime_user.c                     |     1 -
 samples/bpf/sockex2_user.c                         |     1 -
 samples/bpf/sockex3_user.c                         |     1 -
 samples/bpf/spintest_user.c                        |     1 -
 samples/bpf/syscall_tp_user.c                      |     4 +-
 samples/bpf/task_fd_query_user.c                   |     1 -
 samples/bpf/test_lru_dist.c                        |     1 -
 samples/bpf/test_map_in_map_user.c                 |     1 -
 samples/bpf/test_overhead_user.c                   |     1 -
 samples/bpf/tracex2_user.c                         |     1 -
 samples/bpf/tracex3_user.c                         |     1 -
 samples/bpf/tracex4_user.c                         |     1 -
 samples/bpf/tracex5_user.c                         |     1 -
 samples/bpf/tracex6_user.c                         |     1 -
 samples/bpf/xdp1_user.c                            |     3 +-
 samples/bpf/xdp_adjust_tail_user.c                 |     1 -
 samples/bpf/xdp_monitor_user.c                     |     1 -
 samples/bpf/xdp_redirect_cpu_user.c                |     1 -
 samples/bpf/xdp_redirect_map_multi_user.c          |     1 -
 samples/bpf/xdp_redirect_user.c                    |     1 -
 samples/bpf/xdp_router_ipv4.bpf.c                  |   180 +
 samples/bpf/xdp_router_ipv4_kern.c                 |   186 -
 samples/bpf/xdp_router_ipv4_user.c                 |   456 +-
 samples/bpf/xdp_rxq_info_user.c                    |    23 +-
 samples/bpf/xdp_sample_pkts_user.c                 |     1 -
 samples/bpf/xdp_sample_user.c                      |     1 -
 samples/bpf/xdp_tx_iptunnel_user.c                 |     1 -
 samples/bpf/xdpsock_user.c                         |     9 +-
 samples/bpf/xsk_fwd.c                              |     7 +-
 scripts/bpf_doc.py                                 |     4 +
 tools/bpf/bpftool/btf.c                            |    62 +-
 tools/bpf/bpftool/common.c                         |     8 -
 tools/bpf/bpftool/feature.c                        |    26 +-
 tools/bpf/bpftool/gen.c                            |     5 +-
 tools/bpf/bpftool/link.c                           |     4 +
 tools/bpf/bpftool/main.c                           |     6 +-
 tools/bpf/bpftool/main.h                           |     2 -
 tools/bpf/bpftool/map.c                            |     2 -
 tools/bpf/bpftool/perf.c                           |   112 +-
 tools/bpf/bpftool/pids.c                           |     1 -
 tools/bpf/bpftool/prog.c                           |     4 +-
 tools/bpf/bpftool/struct_ops.c                     |     2 -
 tools/bpf/bpftool/tracelog.c                       |     2 +-
 tools/bpf/runqslower/runqslower.c                  |    18 +-
 tools/include/uapi/asm-generic/socket.h            |     2 +
 tools/include/uapi/asm/bpf_perf_event.h            |     2 +
 tools/include/uapi/linux/bpf.h                     |   125 +
 tools/include/uapi/linux/btf.h                     |     4 +-
 tools/include/uapi/linux/if_link.h                 |     2 +
 tools/lib/bpf/Build                                |     3 +-
 tools/lib/bpf/Makefile                             |     4 +-
 tools/lib/bpf/bpf.c                                |   136 +-
 tools/lib/bpf/bpf.h                                |    46 +-
 tools/lib/bpf/bpf_core_read.h                      |    37 +-
 tools/lib/bpf/bpf_helpers.h                        |    26 +
 tools/lib/bpf/bpf_tracing.h                        |    23 +
 tools/lib/bpf/btf.c                                |    15 +-
 tools/lib/bpf/libbpf.c                             |  1273 +-
 tools/lib/bpf/libbpf.h                             |   279 +-
 tools/lib/bpf/libbpf.map                           |    17 +-
 tools/lib/bpf/libbpf_internal.h                    |    37 +
 tools/lib/bpf/libbpf_version.h                     |     4 +-
 tools/lib/bpf/relo_core.c                          |   104 +-
 tools/lib/bpf/relo_core.h                          |     6 +
 tools/lib/bpf/usdt.bpf.h                           |   259 +
 tools/lib/bpf/usdt.c                               |  1518 ++
 tools/testing/selftests/bpf/Makefile               |    39 +-
 tools/testing/selftests/bpf/bench.c                |     1 -
 tools/testing/selftests/bpf/bpf_rlimit.h           |    28 -
 tools/testing/selftests/bpf/bpf_tcp_helpers.h      |    13 +
 tools/testing/selftests/bpf/config                 |     4 +
 tools/testing/selftests/bpf/flow_dissector_load.c  |     6 +-
 tools/testing/selftests/bpf/get_cgroup_id_user.c   |     4 +-
 .../selftests/bpf/map_tests/map_in_map_batch_ops.c |   252 +
 tools/testing/selftests/bpf/network_helpers.c      |    40 +-
 tools/testing/selftests/bpf/network_helpers.h      |     2 +
 .../testing/selftests/bpf/prog_tests/arg_parsing.c |   107 +
 .../selftests/bpf/prog_tests/attach_probe.c        |    95 +-
 .../testing/selftests/bpf/prog_tests/bpf_cookie.c  |    89 +
 tools/testing/selftests/bpf/prog_tests/bpf_iter.c  |   265 +-
 .../selftests/bpf/prog_tests/bpf_mod_race.c        |     4 +-
 .../testing/selftests/bpf/prog_tests/bpf_tcp_ca.c  |     6 +-
 tools/testing/selftests/bpf/prog_tests/btf.c       |   100 +-
 .../selftests/bpf/prog_tests/core_autosize.c       |     2 +-
 .../testing/selftests/bpf/prog_tests/core_reloc.c  |    13 +-
 .../testing/selftests/bpf/prog_tests/core_retro.c  |    17 +-
 tools/testing/selftests/bpf/prog_tests/dynptr.c    |   137 +
 .../selftests/bpf/prog_tests/fexit_stress.c        |     4 +-
 tools/testing/selftests/bpf/prog_tests/for_each.c  |    42 +-
 .../selftests/bpf/prog_tests/helper_restricted.c   |    10 +-
 .../selftests/bpf/prog_tests/kprobe_multi_test.c   |   159 +-
 tools/testing/selftests/bpf/prog_tests/ksyms_btf.c |    17 +-
 .../selftests/bpf/prog_tests/linked_funcs.c        |     6 +
 tools/testing/selftests/bpf/prog_tests/log_fixup.c |   149 +
 .../selftests/bpf/prog_tests/lookup_and_delete.c   |    15 +-
 tools/testing/selftests/bpf/prog_tests/map_kptr.c  |   148 +
 .../bpf/prog_tests/map_lookup_percpu_elem.c        |    58 +
 tools/testing/selftests/bpf/prog_tests/mptcp.c     |   174 +
 tools/testing/selftests/bpf/prog_tests/netcnt.c    |     2 +-
 .../bpf/prog_tests/prog_tests_framework.c          |    56 +
 .../selftests/bpf/prog_tests/reference_tracking.c  |    23 +-
 .../selftests/bpf/prog_tests/ringbuf_multi.c       |    12 -
 .../selftests/bpf/prog_tests/skb_load_bytes.c      |    45 +
 tools/testing/selftests/bpf/prog_tests/snprintf.c  |     4 +-
 .../selftests/bpf/prog_tests/stacktrace_build_id.c |     8 +-
 .../bpf/prog_tests/stacktrace_build_id_nmi.c       |    11 +-
 .../testing/selftests/bpf/prog_tests/tc_redirect.c |     1 -
 .../selftests/bpf/prog_tests/test_global_funcs.c   |     1 +
 .../selftests/bpf/prog_tests/test_strncmp.c        |    25 +-
 .../testing/selftests/bpf/prog_tests/test_tunnel.c |   423 +
 tools/testing/selftests/bpf/prog_tests/timer_mim.c |     2 +-
 .../selftests/bpf/prog_tests/trampoline_count.c    |   134 +-
 .../selftests/bpf/prog_tests/unpriv_bpf_disabled.c |   312 +
 .../selftests/bpf/prog_tests/uprobe_autoattach.c   |    50 +
 tools/testing/selftests/bpf/prog_tests/usdt.c      |   419 +
 tools/testing/selftests/bpf/progs/bpf_iter.h       |     7 +
 .../selftests/bpf/progs/bpf_iter_bpf_link.c        |    21 +
 .../bpf/progs/btf__core_reloc_size___diff_offs.c   |     3 +
 .../bpf/progs/btf_dump_test_case_syntax.c          |     2 +-
 .../testing/selftests/bpf/progs/core_reloc_types.h |    18 +
 tools/testing/selftests/bpf/progs/dynptr_fail.c    |   588 +
 tools/testing/selftests/bpf/progs/dynptr_success.c |   164 +
 tools/testing/selftests/bpf/progs/exhandler_kern.c |    13 +-
 .../bpf/progs/for_each_map_elem_write_key.c        |    27 +
 tools/testing/selftests/bpf/progs/kprobe_multi.c   |    14 +
 .../selftests/bpf/progs/kprobe_multi_empty.c       |    12 +
 tools/testing/selftests/bpf/progs/linked_funcs1.c  |    15 +-
 tools/testing/selftests/bpf/progs/linked_funcs2.c  |    15 +-
 tools/testing/selftests/bpf/progs/loop5.c          |     1 -
 tools/testing/selftests/bpf/progs/map_kptr.c       |   292 +
 tools/testing/selftests/bpf/progs/map_kptr_fail.c  |   418 +
 tools/testing/selftests/bpf/progs/mptcp_sock.c     |    88 +
 .../selftests/bpf/progs/perf_event_stackmap.c      |     4 +-
 tools/testing/selftests/bpf/progs/profiler.inc.h   |     5 +-
 tools/testing/selftests/bpf/progs/profiler1.c      |     1 -
 tools/testing/selftests/bpf/progs/pyperf.h         |     6 +-
 tools/testing/selftests/bpf/progs/pyperf600.c      |    11 +-
 tools/testing/selftests/bpf/progs/skb_load_bytes.c |    19 +
 tools/testing/selftests/bpf/progs/strncmp_test.c   |     8 +-
 .../selftests/bpf/progs/test_attach_probe.c        |    64 +-
 .../testing/selftests/bpf/progs/test_bpf_cookie.c  |    56 +-
 .../bpf/progs/test_core_reloc_existence.c          |    11 +-
 .../selftests/bpf/progs/test_core_reloc_size.c     |    31 +-
 .../selftests/bpf/progs/test_global_func17.c       |    16 +
 .../selftests/bpf/progs/test_helper_restricted.c   |    16 +-
 .../bpf/progs/test_ksyms_btf_write_check.c         |    18 +-
 .../selftests/bpf/progs/test_l4lb_noinline.c       |     2 +-
 tools/testing/selftests/bpf/progs/test_log_fixup.c |    64 +
 .../bpf/progs/test_map_lookup_percpu_elem.c        |    76 +
 .../selftests/bpf/progs/test_module_attach.c       |     2 +-
 .../testing/selftests/bpf/progs/test_pkt_access.c  |     2 -
 .../selftests/bpf/progs/test_ringbuf_multi.c       |     2 +
 tools/testing/selftests/bpf/progs/test_sk_assign.c |     4 +-
 .../selftests/bpf/progs/test_sk_lookup_kern.c      |    18 +-
 tools/testing/selftests/bpf/progs/test_subprogs.c  |     8 +
 .../selftests/bpf/progs/test_task_pt_regs.c        |     2 +-
 .../selftests/bpf/progs/test_trampoline_count.c    |    16 +-
 .../testing/selftests/bpf/progs/test_tunnel_kern.c |   371 +-
 .../selftests/bpf/progs/test_unpriv_bpf_disabled.c |    83 +
 .../selftests/bpf/progs/test_uprobe_autoattach.c   |    73 +
 .../selftests/bpf/progs/test_urandom_usdt.c        |    70 +
 tools/testing/selftests/bpf/progs/test_usdt.c      |    96 +
 .../selftests/bpf/progs/test_usdt_multispec.c      |    32 +
 .../selftests/bpf/progs/test_xdp_noinline.c        |    12 +-
 tools/testing/selftests/bpf/progs/trigger_bench.c  |     2 +-
 tools/testing/selftests/bpf/sdt-config.h           |     6 +
 tools/testing/selftests/bpf/sdt.h                  |   513 +
 .../selftests/bpf/test_bpftool_synctypes.py        |     2 +-
 tools/testing/selftests/bpf/test_cgroup_storage.c  |     7 +-
 tools/testing/selftests/bpf/test_dev_cgroup.c      |     4 +-
 tools/testing/selftests/bpf/test_lpm_map.c         |    43 +-
 tools/testing/selftests/bpf/test_lru_map.c         |    70 +-
 tools/testing/selftests/bpf/test_offload.py        |     2 +-
 tools/testing/selftests/bpf/test_progs.c           |  1006 +-
 tools/testing/selftests/bpf/test_progs.h           |    89 +-
 .../selftests/bpf/test_skb_cgroup_id_user.c        |     4 +-
 tools/testing/selftests/bpf/test_sock.c            |     6 +-
 tools/testing/selftests/bpf/test_sock_addr.c       |     4 +-
 tools/testing/selftests/bpf/test_sockmap.c         |     5 +-
 tools/testing/selftests/bpf/test_sysctl.c          |     6 +-
 tools/testing/selftests/bpf/test_tag.c             |     4 +-
 .../selftests/bpf/test_tcp_check_syncookie_user.c  |     4 +-
 tools/testing/selftests/bpf/test_tcpnotify_user.c  |     1 -
 tools/testing/selftests/bpf/test_tunnel.sh         |   124 +-
 tools/testing/selftests/bpf/test_verifier.c        |    55 +-
 tools/testing/selftests/bpf/test_verifier_log.c    |     5 +-
 tools/testing/selftests/bpf/test_xsk.sh            |    53 +-
 tools/testing/selftests/bpf/testing_helpers.c      |    91 +-
 tools/testing/selftests/bpf/testing_helpers.h      |     8 +
 tools/testing/selftests/bpf/trace_helpers.c        |     9 +-
 tools/testing/selftests/bpf/urandom_read.c         |    63 +-
 tools/testing/selftests/bpf/urandom_read_aux.c     |     9 +
 tools/testing/selftests/bpf/urandom_read_lib1.c    |    13 +
 tools/testing/selftests/bpf/urandom_read_lib2.c    |     8 +
 tools/testing/selftests/bpf/verifier/calls.c       |    20 +
 tools/testing/selftests/bpf/verifier/map_kptr.c    |   469 +
 .../testing/selftests/bpf/verifier/ref_tracking.c  |     2 +-
 tools/testing/selftests/bpf/verifier/sock.c        |     6 +-
 tools/testing/selftests/bpf/xdp_redirect_multi.c   |     1 -
 tools/testing/selftests/bpf/xdping.c               |     8 +-
 tools/testing/selftests/bpf/xdpxceiver.c           |   553 +-
 tools/testing/selftests/bpf/xdpxceiver.h           |    42 +-
 tools/testing/selftests/bpf/xsk_prereqs.sh         |    47 +-
 .../drivers/net/dsa/bridge_locked_port.sh          |     1 +
 .../selftests/drivers/net/dsa/bridge_mdb.sh        |     1 +
 .../selftests/drivers/net/dsa/bridge_mld.sh        |     1 +
 .../selftests/drivers/net/dsa/bridge_vlan_aware.sh |     1 +
 .../selftests/drivers/net/dsa/bridge_vlan_mcast.sh |     1 +
 .../drivers/net/dsa/bridge_vlan_unaware.sh         |     1 +
 .../selftests/drivers/net/dsa/forwarding.config    |     2 +
 tools/testing/selftests/drivers/net/dsa/lib.sh     |     1 +
 .../selftests/drivers/net/dsa/local_termination.sh |     1 +
 .../selftests/drivers/net/dsa/no_forwarding.sh     |     1 +
 .../drivers/net/mlxsw/devlink_linecard.sh          |   280 +
 .../selftests/drivers/net/mlxsw/qos_burst.sh       |   480 +
 .../selftests/drivers/net/mlxsw/qos_headroom.sh    |     4 +-
 .../testing/selftests/drivers/net/mlxsw/qos_pfc.sh |     4 +-
 .../selftests/drivers/net/mlxsw/sch_red_ets.sh     |     5 +-
 .../selftests/drivers/net/mlxsw/sch_red_root.sh    |     5 +-
 .../selftests/drivers/net/netdevsim/hw_stats_l3.sh |     4 +-
 .../selftests/drivers/net/ocelot/basic_qos.sh      |   253 +
 tools/testing/selftests/drivers/net/ocelot/psfp.sh |   327 +
 .../drivers/net/ocelot/tc_flower_chains.sh         |   202 +-
 tools/testing/selftests/net/.gitignore             |     2 +
 tools/testing/selftests/net/Makefile               |     5 +
 tools/testing/selftests/net/bind_bhash_test.c      |   119 +
 tools/testing/selftests/net/fib_nexthops.sh        |    53 +-
 tools/testing/selftests/net/fib_rule_tests.sh      |    12 +-
 tools/testing/selftests/net/forwarding/Makefile    |     2 +
 .../testing/selftests/net/forwarding/bridge_mdb.sh |   103 +
 .../selftests/net/forwarding/hw_stats_l3.sh        |    16 +-
 .../selftests/net/forwarding/hw_stats_l3_gre.sh    |   109 +
 tools/testing/selftests/net/forwarding/lib.sh      |   144 +-
 .../selftests/net/forwarding/local_termination.sh  |   299 +
 .../selftests/net/forwarding/no_forwarding.sh      |   261 +
 tools/testing/selftests/net/forwarding/router.sh   |    18 +
 .../selftests/net/forwarding/router_vid_1.sh       |    27 +-
 .../testing/selftests/net/forwarding/tc_actions.sh |     2 +-
 tools/testing/selftests/net/forwarding/tsn_lib.sh  |   235 +
 tools/testing/selftests/net/mptcp/config           |     8 +
 tools/testing/selftests/net/mptcp/diag.sh          |    38 +
 tools/testing/selftests/net/mptcp/mptcp_join.sh    |   243 +-
 tools/testing/selftests/net/mptcp/pm_nl_ctl.c      |   645 +-
 tools/testing/selftests/net/mptcp/userspace_pm.sh  |   779 +
 .../selftests/net/ndisc_unsolicited_na_test.sh     |   255 +
 .../selftests/net/stress_reuseport_listen.c        |   105 +
 .../selftests/net/stress_reuseport_listen.sh       |    25 +
 .../testing/selftests/net/vrf_strict_mode_test.sh  |    48 +-
 tools/testing/selftests/netfilter/nft_fib.sh       |    50 +
 tools/testing/selftests/sysctl/sysctl.sh           |    23 +
 1931 files changed, 162345 insertions(+), 59902 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/arm/mediatek/mediatek,mt7622-pcie-mirror.yaml
 create mode 100644 Documentation/devicetree/bindings/arm/mediatek/mediatek,mt7622-wed.yaml
 create mode 100644 Documentation/devicetree/bindings/net/can/ctu,ctucanfd.yaml
 create mode 100644 Documentation/devicetree/bindings/net/marvell,orion-mdio.yaml
 delete mode 100644 Documentation/devicetree/bindings/net/marvell-orion-mdio.txt
 create mode 100644 Documentation/devicetree/bindings/net/mediatek,net.yaml
 delete mode 100644 Documentation/devicetree/bindings/net/mediatek-net.txt
 create mode 100644 Documentation/devicetree/bindings/net/mscc,miim.yaml
 delete mode 100644 Documentation/devicetree/bindings/net/mscc-miim.txt
 create mode 100644 Documentation/devicetree/bindings/net/sunplus,sp7021-emac.yaml
 rename Documentation/devicetree/bindings/{staging => }/net/wireless/silabs,wfx.yaml (98%)
 delete mode 100644 Documentation/networking/device_drivers/appletalk/ltpc.rst
 create mode 100644 Documentation/networking/device_drivers/can/ctu/ctucanfd-driver.rst
 create mode 100644 Documentation/networking/device_drivers/can/ctu/fsm_txt_buffer_user.svg
 delete mode 100644 Documentation/networking/device_drivers/ethernet/dec/de4x5.rst
 create mode 100644 Documentation/networking/device_drivers/ethernet/marvell/octeon_ep.rst
 delete mode 100644 Documentation/networking/device_drivers/wan/index.rst
 delete mode 100644 Documentation/networking/device_drivers/wan/z8530book.rst
 create mode 100644 Documentation/networking/device_drivers/wwan/t7xx.rst
 create mode 100644 Documentation/networking/devlink/devlink-linecard.rst
 create mode 100644 Documentation/networking/skbuff.rst
 delete mode 100644 drivers/atm/ambassador.c
 delete mode 100644 drivers/atm/ambassador.h
 delete mode 100644 drivers/atm/firestream.c
 delete mode 100644 drivers/atm/firestream.h
 delete mode 100644 drivers/atm/horizon.c
 delete mode 100644 drivers/atm/horizon.h
 delete mode 100644 drivers/atm/uPD98401.h
 delete mode 100644 drivers/atm/uPD98402.c
 delete mode 100644 drivers/atm/uPD98402.h
 delete mode 100644 drivers/atm/zatm.c
 delete mode 100644 drivers/atm/zatm.h
 delete mode 100644 drivers/net/appletalk/ltpc.c
 delete mode 100644 drivers/net/appletalk/ltpc.h
 create mode 100644 drivers/net/can/ctucanfd/Kconfig
 create mode 100644 drivers/net/can/ctucanfd/Makefile
 create mode 100644 drivers/net/can/ctucanfd/ctucanfd.h
 create mode 100644 drivers/net/can/ctucanfd/ctucanfd_base.c
 create mode 100644 drivers/net/can/ctucanfd/ctucanfd_kframe.h
 create mode 100644 drivers/net/can/ctucanfd/ctucanfd_kregs.h
 create mode 100644 drivers/net/can/ctucanfd/ctucanfd_pci.c
 create mode 100644 drivers/net/can/ctucanfd/ctucanfd_platform.c
 delete mode 100644 drivers/net/can/led.c
 delete mode 100644 drivers/net/ethernet/amd/ni65.c
 delete mode 100644 drivers/net/ethernet/amd/ni65.h
 delete mode 100644 drivers/net/ethernet/dec/tulip/de4x5.c
 delete mode 100644 drivers/net/ethernet/dec/tulip/de4x5.h
 create mode 100644 drivers/net/ethernet/marvell/octeon_ep/Kconfig
 create mode 100644 drivers/net/ethernet/marvell/octeon_ep/Makefile
 create mode 100644 drivers/net/ethernet/marvell/octeon_ep/octep_cn9k_pf.c
 create mode 100644 drivers/net/ethernet/marvell/octeon_ep/octep_config.h
 create mode 100644 drivers/net/ethernet/marvell/octeon_ep/octep_ctrl_mbox.c
 create mode 100644 drivers/net/ethernet/marvell/octeon_ep/octep_ctrl_mbox.h
 create mode 100644 drivers/net/ethernet/marvell/octeon_ep/octep_ctrl_net.c
 create mode 100644 drivers/net/ethernet/marvell/octeon_ep/octep_ctrl_net.h
 create mode 100644 drivers/net/ethernet/marvell/octeon_ep/octep_ethtool.c
 create mode 100644 drivers/net/ethernet/marvell/octeon_ep/octep_main.c
 create mode 100644 drivers/net/ethernet/marvell/octeon_ep/octep_main.h
 create mode 100644 drivers/net/ethernet/marvell/octeon_ep/octep_regs_cn9k_pf.h
 create mode 100644 drivers/net/ethernet/marvell/octeon_ep/octep_rx.c
 create mode 100644 drivers/net/ethernet/marvell/octeon_ep/octep_rx.h
 create mode 100644 drivers/net/ethernet/marvell/octeon_ep/octep_tx.c
 create mode 100644 drivers/net/ethernet/marvell/octeon_ep/octep_tx.h
 create mode 100644 drivers/net/ethernet/mediatek/mtk_wed.c
 create mode 100644 drivers/net/ethernet/mediatek/mtk_wed.h
 create mode 100644 drivers/net/ethernet/mediatek/mtk_wed_debugfs.c
 create mode 100644 drivers/net/ethernet/mediatek/mtk_wed_ops.c
 create mode 100644 drivers/net/ethernet/mediatek/mtk_wed_regs.h
 delete mode 100644 drivers/net/ethernet/mellanox/mlx5/core/accel/accel.h
 delete mode 100644 drivers/net/ethernet/mellanox/mlx5/core/accel/ipsec.c
 delete mode 100644 drivers/net/ethernet/mellanox/mlx5/core/accel/ipsec.h
 delete mode 100644 drivers/net/ethernet/mellanox/mlx5/core/accel/ipsec_offload.c
 delete mode 100644 drivers/net/ethernet/mellanox/mlx5/core/accel/ipsec_offload.h
 delete mode 100644 drivers/net/ethernet/mellanox/mlx5/core/accel/tls.c
 delete mode 100644 drivers/net/ethernet/mellanox/mlx5/core/accel/tls.h
 create mode 100644 drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_offload.c
 rename drivers/net/ethernet/mellanox/mlx5/core/en_accel/{tls_stats.c => ktls_stats.c} (63%)
 delete mode 100644 drivers/net/ethernet/mellanox/mlx5/core/en_accel/tls.c
 delete mode 100644 drivers/net/ethernet/mellanox/mlx5/core/en_accel/tls.h
 delete mode 100644 drivers/net/ethernet/mellanox/mlx5/core/en_accel/tls_rxtx.c
 delete mode 100644 drivers/net/ethernet/mellanox/mlx5/core/en_accel/tls_rxtx.h
 delete mode 100644 drivers/net/ethernet/mellanox/mlx5/core/fpga/ipsec.c
 delete mode 100644 drivers/net/ethernet/mellanox/mlx5/core/fpga/ipsec.h
 delete mode 100644 drivers/net/ethernet/mellanox/mlx5/core/fpga/tls.c
 delete mode 100644 drivers/net/ethernet/mellanox/mlx5/core/fpga/tls.h
 create mode 100644 drivers/net/ethernet/mellanox/mlx5/core/lag/debugfs.c
 create mode 100644 drivers/net/ethernet/mellanox/mlx5/core/lag/mpesw.c
 create mode 100644 drivers/net/ethernet/mellanox/mlx5/core/lag/mpesw.h
 create mode 100644 drivers/net/ethernet/mellanox/mlxsw/core_linecards.c
 create mode 100644 drivers/net/ethernet/microchip/lan966x/lan966x_fdma.c
 delete mode 100644 drivers/net/ethernet/qlogic/qed/qed_nvmetcp_ip_services.c
 create mode 100644 drivers/net/ethernet/sfc/ef100_sriov.c
 create mode 100644 drivers/net/ethernet/sfc/ef100_sriov.h
 create mode 100644 drivers/net/ethernet/sfc/siena/Kconfig
 create mode 100644 drivers/net/ethernet/sfc/siena/Makefile
 create mode 100644 drivers/net/ethernet/sfc/siena/bitfield.h
 create mode 100644 drivers/net/ethernet/sfc/siena/efx.c
 create mode 100644 drivers/net/ethernet/sfc/siena/efx.h
 create mode 100644 drivers/net/ethernet/sfc/siena/efx_channels.c
 create mode 100644 drivers/net/ethernet/sfc/siena/efx_channels.h
 create mode 100644 drivers/net/ethernet/sfc/siena/efx_common.c
 create mode 100644 drivers/net/ethernet/sfc/siena/efx_common.h
 create mode 100644 drivers/net/ethernet/sfc/siena/enum.h
 create mode 100644 drivers/net/ethernet/sfc/siena/ethtool.c
 create mode 100644 drivers/net/ethernet/sfc/siena/ethtool_common.c
 create mode 100644 drivers/net/ethernet/sfc/siena/ethtool_common.h
 rename drivers/net/ethernet/sfc/{ => siena}/farch.c (97%)
 create mode 100644 drivers/net/ethernet/sfc/siena/farch_regs.h
 create mode 100644 drivers/net/ethernet/sfc/siena/filter.h
 create mode 100644 drivers/net/ethernet/sfc/siena/io.h
 create mode 100644 drivers/net/ethernet/sfc/siena/mcdi.c
 create mode 100644 drivers/net/ethernet/sfc/siena/mcdi.h
 create mode 100644 drivers/net/ethernet/sfc/siena/mcdi_mon.c
 create mode 100644 drivers/net/ethernet/sfc/siena/mcdi_pcol.h
 create mode 100644 drivers/net/ethernet/sfc/siena/mcdi_port.c
 create mode 100644 drivers/net/ethernet/sfc/siena/mcdi_port.h
 create mode 100644 drivers/net/ethernet/sfc/siena/mcdi_port_common.c
 create mode 100644 drivers/net/ethernet/sfc/siena/mcdi_port_common.h
 create mode 100644 drivers/net/ethernet/sfc/siena/mtd.c
 create mode 100644 drivers/net/ethernet/sfc/siena/net_driver.h
 create mode 100644 drivers/net/ethernet/sfc/siena/nic.c
 create mode 100644 drivers/net/ethernet/sfc/siena/nic.h
 create mode 100644 drivers/net/ethernet/sfc/siena/nic_common.h
 create mode 100644 drivers/net/ethernet/sfc/siena/ptp.c
 create mode 100644 drivers/net/ethernet/sfc/siena/ptp.h
 create mode 100644 drivers/net/ethernet/sfc/siena/rx.c
 create mode 100644 drivers/net/ethernet/sfc/siena/rx_common.c
 create mode 100644 drivers/net/ethernet/sfc/siena/rx_common.h
 create mode 100644 drivers/net/ethernet/sfc/siena/selftest.c
 create mode 100644 drivers/net/ethernet/sfc/siena/selftest.h
 rename drivers/net/ethernet/sfc/{ => siena}/siena.c (89%)
 rename drivers/net/ethernet/sfc/{ => siena}/siena_sriov.c (98%)
 rename drivers/net/ethernet/sfc/{ => siena}/siena_sriov.h (94%)
 create mode 100644 drivers/net/ethernet/sfc/siena/sriov.h
 create mode 100644 drivers/net/ethernet/sfc/siena/tx.c
 create mode 100644 drivers/net/ethernet/sfc/siena/tx.h
 create mode 100644 drivers/net/ethernet/sfc/siena/tx_common.c
 create mode 100644 drivers/net/ethernet/sfc/siena/tx_common.h
 create mode 100644 drivers/net/ethernet/sfc/siena/vfdi.h
 create mode 100644 drivers/net/ethernet/sfc/siena/workarounds.h
 create mode 100644 drivers/net/ethernet/sunplus/Kconfig
 create mode 100644 drivers/net/ethernet/sunplus/Makefile
 create mode 100644 drivers/net/ethernet/sunplus/spl2sw_define.h
 create mode 100644 drivers/net/ethernet/sunplus/spl2sw_desc.c
 create mode 100644 drivers/net/ethernet/sunplus/spl2sw_desc.h
 create mode 100644 drivers/net/ethernet/sunplus/spl2sw_driver.c
 create mode 100644 drivers/net/ethernet/sunplus/spl2sw_int.c
 create mode 100644 drivers/net/ethernet/sunplus/spl2sw_int.h
 create mode 100644 drivers/net/ethernet/sunplus/spl2sw_mac.c
 create mode 100644 drivers/net/ethernet/sunplus/spl2sw_mac.h
 create mode 100644 drivers/net/ethernet/sunplus/spl2sw_mdio.c
 create mode 100644 drivers/net/ethernet/sunplus/spl2sw_mdio.h
 create mode 100644 drivers/net/ethernet/sunplus/spl2sw_phy.c
 create mode 100644 drivers/net/ethernet/sunplus/spl2sw_phy.h
 create mode 100644 drivers/net/ethernet/sunplus/spl2sw_register.h
 delete mode 100644 drivers/net/hamradio/dmascc.c
 create mode 100644 drivers/net/phy/adin1100.c
 create mode 100644 drivers/net/phy/dp83td510.c
 delete mode 100644 drivers/net/wan/cosa.c
 delete mode 100644 drivers/net/wan/cosa.h
 delete mode 100644 drivers/net/wan/hostess_sv11.c
 delete mode 100644 drivers/net/wan/lmc/Makefile
 delete mode 100644 drivers/net/wan/lmc/lmc.h
 delete mode 100644 drivers/net/wan/lmc/lmc_debug.c
 delete mode 100644 drivers/net/wan/lmc/lmc_debug.h
 delete mode 100644 drivers/net/wan/lmc/lmc_ioctl.h
 delete mode 100644 drivers/net/wan/lmc/lmc_main.c
 delete mode 100644 drivers/net/wan/lmc/lmc_media.c
 delete mode 100644 drivers/net/wan/lmc/lmc_proto.c
 delete mode 100644 drivers/net/wan/lmc/lmc_proto.h
 delete mode 100644 drivers/net/wan/lmc/lmc_var.h
 delete mode 100644 drivers/net/wan/sealevel.c
 delete mode 100644 drivers/net/wan/z85230.c
 delete mode 100644 drivers/net/wan/z85230.h
 create mode 100644 drivers/net/wireless/ath/ath11k/pcic.c
 create mode 100644 drivers/net/wireless/ath/ath11k/pcic.h
 create mode 100644 drivers/net/wireless/purelifi/Kconfig
 create mode 100644 drivers/net/wireless/purelifi/Makefile
 create mode 100644 drivers/net/wireless/purelifi/plfxlc/Kconfig
 create mode 100644 drivers/net/wireless/purelifi/plfxlc/Makefile
 create mode 100644 drivers/net/wireless/purelifi/plfxlc/chip.c
 create mode 100644 drivers/net/wireless/purelifi/plfxlc/chip.h
 create mode 100644 drivers/net/wireless/purelifi/plfxlc/firmware.c
 create mode 100644 drivers/net/wireless/purelifi/plfxlc/intf.h
 create mode 100644 drivers/net/wireless/purelifi/plfxlc/mac.c
 create mode 100644 drivers/net/wireless/purelifi/plfxlc/mac.h
 create mode 100644 drivers/net/wireless/purelifi/plfxlc/usb.c
 create mode 100644 drivers/net/wireless/purelifi/plfxlc/usb.h
 create mode 100644 drivers/net/wireless/realtek/rtw89/rtw8852c_rfk.c
 create mode 100644 drivers/net/wireless/realtek/rtw89/rtw8852c_rfk.h
 create mode 100644 drivers/net/wireless/realtek/rtw89/rtw8852c_rfk_table.c
 create mode 100644 drivers/net/wireless/realtek/rtw89/rtw8852c_rfk_table.h
 create mode 100644 drivers/net/wireless/realtek/rtw89/rtw8852c_table.c
 create mode 100644 drivers/net/wireless/realtek/rtw89/rtw8852c_table.h
 create mode 100644 drivers/net/wireless/silabs/Kconfig
 create mode 100644 drivers/net/wireless/silabs/Makefile
 rename drivers/{staging => net/wireless/silabs}/wfx/Kconfig (100%)
 rename drivers/{staging => net/wireless/silabs}/wfx/Makefile (100%)
 rename drivers/{staging => net/wireless/silabs}/wfx/bh.c (98%)
 rename drivers/{staging => net/wireless/silabs}/wfx/bh.h (100%)
 rename drivers/{staging => net/wireless/silabs}/wfx/bus.h (100%)
 rename drivers/{staging => net/wireless/silabs}/wfx/bus_sdio.c (100%)
 rename drivers/{staging => net/wireless/silabs}/wfx/bus_spi.c (100%)
 rename drivers/{staging => net/wireless/silabs}/wfx/data_rx.c (93%)
 rename drivers/{staging => net/wireless/silabs}/wfx/data_rx.h (100%)
 rename drivers/{staging => net/wireless/silabs}/wfx/data_tx.c (99%)
 rename drivers/{staging => net/wireless/silabs}/wfx/data_tx.h (100%)
 rename drivers/{staging => net/wireless/silabs}/wfx/debug.c (100%)
 rename drivers/{staging => net/wireless/silabs}/wfx/debug.h (100%)
 rename drivers/{staging => net/wireless/silabs}/wfx/fwio.c (100%)
 rename drivers/{staging => net/wireless/silabs}/wfx/fwio.h (100%)
 rename drivers/{staging => net/wireless/silabs}/wfx/hif_api_cmd.h (100%)
 rename drivers/{staging => net/wireless/silabs}/wfx/hif_api_general.h (100%)
 rename drivers/{staging => net/wireless/silabs}/wfx/hif_api_mib.h (100%)
 rename drivers/{staging => net/wireless/silabs}/wfx/hif_rx.c (100%)
 rename drivers/{staging => net/wireless/silabs}/wfx/hif_rx.h (100%)
 rename drivers/{staging => net/wireless/silabs}/wfx/hif_tx.c (99%)
 rename drivers/{staging => net/wireless/silabs}/wfx/hif_tx.h (100%)
 rename drivers/{staging => net/wireless/silabs}/wfx/hif_tx_mib.c (100%)
 rename drivers/{staging => net/wireless/silabs}/wfx/hif_tx_mib.h (100%)
 rename drivers/{staging => net/wireless/silabs}/wfx/hwio.c (100%)
 rename drivers/{staging => net/wireless/silabs}/wfx/hwio.h (100%)
 rename drivers/{staging => net/wireless/silabs}/wfx/key.c (99%)
 rename drivers/{staging => net/wireless/silabs}/wfx/key.h (100%)
 rename drivers/{staging => net/wireless/silabs}/wfx/main.c (98%)
 rename drivers/{staging => net/wireless/silabs}/wfx/main.h (100%)
 rename drivers/{staging => net/wireless/silabs}/wfx/queue.c (98%)
 rename drivers/{staging => net/wireless/silabs}/wfx/queue.h (100%)
 rename drivers/{staging => net/wireless/silabs}/wfx/scan.c (92%)
 rename drivers/{staging => net/wireless/silabs}/wfx/scan.h (100%)
 rename drivers/{staging => net/wireless/silabs}/wfx/sta.c (90%)
 rename drivers/{staging => net/wireless/silabs}/wfx/sta.h (100%)
 rename drivers/{staging => net/wireless/silabs}/wfx/traces.h (100%)
 rename drivers/{staging => net/wireless/silabs}/wfx/wfx.h (95%)
 create mode 100644 drivers/net/wwan/t7xx/Makefile
 create mode 100644 drivers/net/wwan/t7xx/t7xx_cldma.c
 create mode 100644 drivers/net/wwan/t7xx/t7xx_cldma.h
 create mode 100644 drivers/net/wwan/t7xx/t7xx_dpmaif.c
 create mode 100644 drivers/net/wwan/t7xx/t7xx_dpmaif.h
 create mode 100644 drivers/net/wwan/t7xx/t7xx_hif_cldma.c
 create mode 100644 drivers/net/wwan/t7xx/t7xx_hif_cldma.h
 create mode 100644 drivers/net/wwan/t7xx/t7xx_hif_dpmaif.c
 create mode 100644 drivers/net/wwan/t7xx/t7xx_hif_dpmaif.h
 create mode 100644 drivers/net/wwan/t7xx/t7xx_hif_dpmaif_rx.c
 create mode 100644 drivers/net/wwan/t7xx/t7xx_hif_dpmaif_rx.h
 create mode 100644 drivers/net/wwan/t7xx/t7xx_hif_dpmaif_tx.c
 create mode 100644 drivers/net/wwan/t7xx/t7xx_hif_dpmaif_tx.h
 create mode 100644 drivers/net/wwan/t7xx/t7xx_mhccif.c
 create mode 100644 drivers/net/wwan/t7xx/t7xx_mhccif.h
 create mode 100644 drivers/net/wwan/t7xx/t7xx_modem_ops.c
 create mode 100644 drivers/net/wwan/t7xx/t7xx_modem_ops.h
 create mode 100644 drivers/net/wwan/t7xx/t7xx_netdev.c
 create mode 100644 drivers/net/wwan/t7xx/t7xx_netdev.h
 create mode 100644 drivers/net/wwan/t7xx/t7xx_pci.c
 create mode 100644 drivers/net/wwan/t7xx/t7xx_pci.h
 create mode 100644 drivers/net/wwan/t7xx/t7xx_pcie_mac.c
 create mode 100644 drivers/net/wwan/t7xx/t7xx_pcie_mac.h
 create mode 100644 drivers/net/wwan/t7xx/t7xx_port.h
 create mode 100644 drivers/net/wwan/t7xx/t7xx_port_ctrl_msg.c
 create mode 100644 drivers/net/wwan/t7xx/t7xx_port_proxy.c
 create mode 100644 drivers/net/wwan/t7xx/t7xx_port_proxy.h
 create mode 100644 drivers/net/wwan/t7xx/t7xx_port_wwan.c
 create mode 100644 drivers/net/wwan/t7xx/t7xx_reg.h
 create mode 100644 drivers/net/wwan/t7xx/t7xx_state_monitor.c
 create mode 100644 drivers/net/wwan/t7xx/t7xx_state_monitor.h
 delete mode 100644 drivers/staging/wfx/TODO
 delete mode 100644 include/linux/can/led.h
 delete mode 100644 include/linux/mlx5/accel.h
 delete mode 100644 include/linux/qed/qed_nvmetcp_ip_services_if.h
 create mode 100644 include/linux/soc/mediatek/mtk_wed.h
 create mode 100644 include/net/net_debug.h
 delete mode 100644 include/uapi/linux/atm_zatm.h
 create mode 100644 kernel/bpf/link_iter.c
 delete mode 100644 net/core/datagram.h
 create mode 100644 net/core/dev.h
 create mode 100644 net/mptcp/bpf.c
 create mode 100644 net/mptcp/pm_userspace.c
 create mode 100644 samples/bpf/xdp_router_ipv4.bpf.c
 delete mode 100644 samples/bpf/xdp_router_ipv4_kern.c
 create mode 100644 tools/lib/bpf/usdt.bpf.h
 create mode 100644 tools/lib/bpf/usdt.c
 delete mode 100644 tools/testing/selftests/bpf/bpf_rlimit.h
 create mode 100644 tools/testing/selftests/bpf/map_tests/map_in_map_batch_ops.c
 create mode 100644 tools/testing/selftests/bpf/prog_tests/arg_parsing.c
 create mode 100644 tools/testing/selftests/bpf/prog_tests/dynptr.c
 create mode 100644 tools/testing/selftests/bpf/prog_tests/log_fixup.c
 create mode 100644 tools/testing/selftests/bpf/prog_tests/map_kptr.c
 create mode 100644 tools/testing/selftests/bpf/prog_tests/map_lookup_percpu_elem.c
 create mode 100644 tools/testing/selftests/bpf/prog_tests/mptcp.c
 create mode 100644 tools/testing/selftests/bpf/prog_tests/prog_tests_framework.c
 create mode 100644 tools/testing/selftests/bpf/prog_tests/skb_load_bytes.c
 create mode 100644 tools/testing/selftests/bpf/prog_tests/test_tunnel.c
 create mode 100644 tools/testing/selftests/bpf/prog_tests/unpriv_bpf_disabled.c
 create mode 100644 tools/testing/selftests/bpf/prog_tests/uprobe_autoattach.c
 create mode 100644 tools/testing/selftests/bpf/prog_tests/usdt.c
 create mode 100644 tools/testing/selftests/bpf/progs/bpf_iter_bpf_link.c
 create mode 100644 tools/testing/selftests/bpf/progs/btf__core_reloc_size___diff_offs.c
 create mode 100644 tools/testing/selftests/bpf/progs/dynptr_fail.c
 create mode 100644 tools/testing/selftests/bpf/progs/dynptr_success.c
 create mode 100644 tools/testing/selftests/bpf/progs/for_each_map_elem_write_key.c
 create mode 100644 tools/testing/selftests/bpf/progs/kprobe_multi_empty.c
 create mode 100644 tools/testing/selftests/bpf/progs/map_kptr.c
 create mode 100644 tools/testing/selftests/bpf/progs/map_kptr_fail.c
 create mode 100644 tools/testing/selftests/bpf/progs/mptcp_sock.c
 create mode 100644 tools/testing/selftests/bpf/progs/skb_load_bytes.c
 create mode 100644 tools/testing/selftests/bpf/progs/test_global_func17.c
 create mode 100644 tools/testing/selftests/bpf/progs/test_log_fixup.c
 create mode 100644 tools/testing/selftests/bpf/progs/test_map_lookup_percpu_elem.c
 create mode 100644 tools/testing/selftests/bpf/progs/test_unpriv_bpf_disabled.c
 create mode 100644 tools/testing/selftests/bpf/progs/test_uprobe_autoattach.c
 create mode 100644 tools/testing/selftests/bpf/progs/test_urandom_usdt.c
 create mode 100644 tools/testing/selftests/bpf/progs/test_usdt.c
 create mode 100644 tools/testing/selftests/bpf/progs/test_usdt_multispec.c
 create mode 100644 tools/testing/selftests/bpf/sdt-config.h
 create mode 100644 tools/testing/selftests/bpf/sdt.h
 create mode 100644 tools/testing/selftests/bpf/urandom_read_aux.c
 create mode 100644 tools/testing/selftests/bpf/urandom_read_lib1.c
 create mode 100644 tools/testing/selftests/bpf/urandom_read_lib2.c
 create mode 100644 tools/testing/selftests/bpf/verifier/map_kptr.c
 create mode 120000 tools/testing/selftests/drivers/net/dsa/bridge_locked_port.sh
 create mode 120000 tools/testing/selftests/drivers/net/dsa/bridge_mdb.sh
 create mode 120000 tools/testing/selftests/drivers/net/dsa/bridge_mld.sh
 create mode 120000 tools/testing/selftests/drivers/net/dsa/bridge_vlan_aware.sh
 create mode 120000 tools/testing/selftests/drivers/net/dsa/bridge_vlan_mcast.sh
 create mode 120000 tools/testing/selftests/drivers/net/dsa/bridge_vlan_unaware.sh
 create mode 100644 tools/testing/selftests/drivers/net/dsa/forwarding.config
 create mode 120000 tools/testing/selftests/drivers/net/dsa/lib.sh
 create mode 120000 tools/testing/selftests/drivers/net/dsa/local_termination.sh
 create mode 120000 tools/testing/selftests/drivers/net/dsa/no_forwarding.sh
 create mode 100755 tools/testing/selftests/drivers/net/mlxsw/devlink_linecard.sh
 create mode 100755 tools/testing/selftests/drivers/net/mlxsw/qos_burst.sh
 create mode 100755 tools/testing/selftests/drivers/net/ocelot/basic_qos.sh
 create mode 100755 tools/testing/selftests/drivers/net/ocelot/psfp.sh
 create mode 100644 tools/testing/selftests/net/bind_bhash_test.c
 create mode 100755 tools/testing/selftests/net/forwarding/bridge_mdb.sh
 create mode 100755 tools/testing/selftests/net/forwarding/hw_stats_l3_gre.sh
 mode change 100644 => 100755 tools/testing/selftests/net/forwarding/lib.sh
 create mode 100755 tools/testing/selftests/net/forwarding/local_termination.sh
 create mode 100755 tools/testing/selftests/net/forwarding/no_forwarding.sh
 create mode 100644 tools/testing/selftests/net/forwarding/tsn_lib.sh
 create mode 100755 tools/testing/selftests/net/mptcp/userspace_pm.sh
 create mode 100755 tools/testing/selftests/net/ndisc_unsolicited_na_test.sh
 create mode 100644 tools/testing/selftests/net/stress_reuseport_listen.c
 create mode 100755 tools/testing/selftests/net/stress_reuseport_listen.sh

^ permalink raw reply	[relevance 1%]

* [PATCH v8 17/31] rust: add `kernel` crate
  @ 2022-08-02  1:50  1% ` Miguel Ojeda
  2022-08-02 13:34  0%   ` Greg Kroah-Hartman
  2022-08-02  1:50  3% ` [PATCH v8 28/31] samples: add Rust examples Miguel Ojeda
  1 sibling, 1 reply; 77+ results
From: Miguel Ojeda @ 2022-08-02  1:50 UTC (permalink / raw)
  To: Linus Torvalds, Greg Kroah-Hartman
  Cc: rust-for-linux, linux-kernel, Jarkko Sakkinen, Miguel Ojeda,
	Wedson Almeida Filho, Alex Gaynor, Geoffrey Thomas, Finn Behrens,
	Adam Bratschi-Kaye, Michael Ellerman, Sumera Priyadarsini,
	Sven Van Asbroeck, Gary Guo, Boris-Chengbiao Zhou, Boqun Feng,
	Fox Chen, Dan Robertson, Viktor Garske, Dariusz Sosnowski,
	Léo Lanteri Thauvin, Niklas Mohrin, Gioh Kim, Daniel Xu,
	Milan Landaverde, Morgan Bartlett, Maciej Falkowski,
	Jiapeng Chong, Nándor István Krácser, David Gow,
	John Baublitz, Björn Roy Baron

From: Wedson Almeida Filho <wedsonaf@google.com>

The `kernel` crate currently includes all the abstractions that wrap
kernel features written in C.

These abstractions call the C side of the kernel via the generated
bindings with the `bindgen` tool. Modules developed in Rust should
never call the bindings themselves.

In the future, as the abstractions grow in number, we may need
to split this crate into several, possibly following a similar
subdivision in subsystems as the kernel itself and/or moving
the code to the actual subsystems.

Co-developed-by: Alex Gaynor <alex.gaynor@gmail.com>
Signed-off-by: Alex Gaynor <alex.gaynor@gmail.com>
Co-developed-by: Geoffrey Thomas <geofft@ldpreload.com>
Signed-off-by: Geoffrey Thomas <geofft@ldpreload.com>
Co-developed-by: Finn Behrens <me@kloenk.de>
Signed-off-by: Finn Behrens <me@kloenk.de>
Co-developed-by: Adam Bratschi-Kaye <ark.email@gmail.com>
Signed-off-by: Adam Bratschi-Kaye <ark.email@gmail.com>
Co-developed-by: Michael Ellerman <mpe@ellerman.id.au>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Co-developed-by: Sumera Priyadarsini <sylphrenadin@gmail.com>
Signed-off-by: Sumera Priyadarsini <sylphrenadin@gmail.com>
Co-developed-by: Sven Van Asbroeck <thesven73@gmail.com>
Signed-off-by: Sven Van Asbroeck <thesven73@gmail.com>
Co-developed-by: Gary Guo <gary@garyguo.net>
Signed-off-by: Gary Guo <gary@garyguo.net>
Co-developed-by: Boris-Chengbiao Zhou <bobo1239@web.de>
Signed-off-by: Boris-Chengbiao Zhou <bobo1239@web.de>
Co-developed-by: Boqun Feng <boqun.feng@gmail.com>
Signed-off-by: Boqun Feng <boqun.feng@gmail.com>
Co-developed-by: Fox Chen <foxhlchen@gmail.com>
Signed-off-by: Fox Chen <foxhlchen@gmail.com>
Co-developed-by: Dan Robertson <daniel.robertson@starlab.io>
Signed-off-by: Dan Robertson <daniel.robertson@starlab.io>
Co-developed-by: Viktor Garske <viktor@v-gar.de>
Signed-off-by: Viktor Garske <viktor@v-gar.de>
Co-developed-by: Dariusz Sosnowski <dsosnowski@dsosnowski.pl>
Signed-off-by: Dariusz Sosnowski <dsosnowski@dsosnowski.pl>
Co-developed-by: Léo Lanteri Thauvin <leseulartichaut@gmail.com>
Signed-off-by: Léo Lanteri Thauvin <leseulartichaut@gmail.com>
Co-developed-by: Niklas Mohrin <dev@niklasmohrin.de>
Signed-off-by: Niklas Mohrin <dev@niklasmohrin.de>
Co-developed-by: Gioh Kim <gurugio@gmail.com>
Signed-off-by: Gioh Kim <gurugio@gmail.com>
Co-developed-by: Daniel Xu <dxu@dxuuu.xyz>
Signed-off-by: Daniel Xu <dxu@dxuuu.xyz>
Co-developed-by: Milan Landaverde <milan@mdaverde.com>
Signed-off-by: Milan Landaverde <milan@mdaverde.com>
Co-developed-by: Morgan Bartlett <mjmouse9999@gmail.com>
Signed-off-by: Morgan Bartlett <mjmouse9999@gmail.com>
Co-developed-by: Maciej Falkowski <m.falkowski@samsung.com>
Signed-off-by: Maciej Falkowski <m.falkowski@samsung.com>
Co-developed-by: Jiapeng Chong <jiapeng.chong@linux.alibaba.com>
Signed-off-by: Jiapeng Chong <jiapeng.chong@linux.alibaba.com>
Co-developed-by: Nándor István Krácser <bonifaido@gmail.com>
Signed-off-by: Nándor István Krácser <bonifaido@gmail.com>
Co-developed-by: David Gow <davidgow@google.com>
Signed-off-by: David Gow <davidgow@google.com>
Co-developed-by: John Baublitz <john.m.baublitz@gmail.com>
Signed-off-by: John Baublitz <john.m.baublitz@gmail.com>
Co-developed-by: Björn Roy Baron <bjorn3_gh@protonmail.com>
Signed-off-by: Björn Roy Baron <bjorn3_gh@protonmail.com>
Signed-off-by: Wedson Almeida Filho <wedsonaf@google.com>
Co-developed-by: Miguel Ojeda <ojeda@kernel.org>
Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
---
 rust/kernel/allocator.rs                 |  64 ++
 rust/kernel/amba.rs                      | 261 +++++++
 rust/kernel/build_assert.rs              |  83 +++
 rust/kernel/chrdev.rs                    | 206 ++++++
 rust/kernel/clk.rs                       |  79 ++
 rust/kernel/cred.rs                      |  46 ++
 rust/kernel/delay.rs                     | 104 +++
 rust/kernel/device.rs                    | 527 ++++++++++++++
 rust/kernel/driver.rs                    | 442 +++++++++++
 rust/kernel/error.rs                     | 564 ++++++++++++++
 rust/kernel/file.rs                      | 887 +++++++++++++++++++++++
 rust/kernel/fs.rs                        | 846 +++++++++++++++++++++
 rust/kernel/fs/param.rs                  | 553 ++++++++++++++
 rust/kernel/gpio.rs                      | 505 +++++++++++++
 rust/kernel/hwrng.rs                     | 210 ++++++
 rust/kernel/io_buffer.rs                 | 153 ++++
 rust/kernel/io_mem.rs                    | 278 +++++++
 rust/kernel/iov_iter.rs                  |  81 +++
 rust/kernel/irq.rs                       | 681 +++++++++++++++++
 rust/kernel/kasync.rs                    |  50 ++
 rust/kernel/kasync/executor.rs           | 154 ++++
 rust/kernel/kasync/executor/workqueue.rs | 291 ++++++++
 rust/kernel/kasync/net.rs                | 322 ++++++++
 rust/kernel/kunit.rs                     |  91 +++
 rust/kernel/lib.rs                       | 267 +++++++
 rust/kernel/linked_list.rs               | 247 +++++++
 rust/kernel/miscdev.rs                   | 290 ++++++++
 rust/kernel/mm.rs                        | 149 ++++
 rust/kernel/module_param.rs              | 499 +++++++++++++
 rust/kernel/net.rs                       | 392 ++++++++++
 rust/kernel/net/filter.rs                | 447 ++++++++++++
 rust/kernel/of.rs                        |  63 ++
 rust/kernel/pages.rs                     | 144 ++++
 rust/kernel/platform.rs                  | 223 ++++++
 rust/kernel/power.rs                     | 118 +++
 rust/kernel/prelude.rs                   |  36 +
 rust/kernel/print.rs                     | 406 +++++++++++
 rust/kernel/random.rs                    |  42 ++
 rust/kernel/raw_list.rs                  | 361 +++++++++
 rust/kernel/rbtree.rs                    | 563 ++++++++++++++
 rust/kernel/revocable.rs                 | 425 +++++++++++
 rust/kernel/security.rs                  |  38 +
 rust/kernel/static_assert.rs             |  34 +
 rust/kernel/std_vendor.rs                | 161 ++++
 rust/kernel/str.rs                       | 597 +++++++++++++++
 rust/kernel/sync.rs                      |  48 +-
 rust/kernel/sysctl.rs                    | 199 +++++
 rust/kernel/task.rs                      | 239 ++++++
 rust/kernel/types.rs                     | 705 ++++++++++++++++++
 rust/kernel/unsafe_list.rs               | 680 +++++++++++++++++
 rust/kernel/user_ptr.rs                  | 175 +++++
 rust/kernel/workqueue.rs                 | 512 +++++++++++++
 52 files changed, 15518 insertions(+), 20 deletions(-)
 create mode 100644 rust/kernel/allocator.rs
 create mode 100644 rust/kernel/amba.rs
 create mode 100644 rust/kernel/build_assert.rs
 create mode 100644 rust/kernel/chrdev.rs
 create mode 100644 rust/kernel/clk.rs
 create mode 100644 rust/kernel/cred.rs
 create mode 100644 rust/kernel/delay.rs
 create mode 100644 rust/kernel/device.rs
 create mode 100644 rust/kernel/driver.rs
 create mode 100644 rust/kernel/error.rs
 create mode 100644 rust/kernel/file.rs
 create mode 100644 rust/kernel/fs.rs
 create mode 100644 rust/kernel/fs/param.rs
 create mode 100644 rust/kernel/gpio.rs
 create mode 100644 rust/kernel/hwrng.rs
 create mode 100644 rust/kernel/io_buffer.rs
 create mode 100644 rust/kernel/io_mem.rs
 create mode 100644 rust/kernel/iov_iter.rs
 create mode 100644 rust/kernel/irq.rs
 create mode 100644 rust/kernel/kasync.rs
 create mode 100644 rust/kernel/kasync/executor.rs
 create mode 100644 rust/kernel/kasync/executor/workqueue.rs
 create mode 100644 rust/kernel/kasync/net.rs
 create mode 100644 rust/kernel/kunit.rs
 create mode 100644 rust/kernel/lib.rs
 create mode 100644 rust/kernel/linked_list.rs
 create mode 100644 rust/kernel/miscdev.rs
 create mode 100644 rust/kernel/mm.rs
 create mode 100644 rust/kernel/module_param.rs
 create mode 100644 rust/kernel/net.rs
 create mode 100644 rust/kernel/net/filter.rs
 create mode 100644 rust/kernel/of.rs
 create mode 100644 rust/kernel/pages.rs
 create mode 100644 rust/kernel/platform.rs
 create mode 100644 rust/kernel/power.rs
 create mode 100644 rust/kernel/prelude.rs
 create mode 100644 rust/kernel/print.rs
 create mode 100644 rust/kernel/random.rs
 create mode 100644 rust/kernel/raw_list.rs
 create mode 100644 rust/kernel/rbtree.rs
 create mode 100644 rust/kernel/revocable.rs
 create mode 100644 rust/kernel/security.rs
 create mode 100644 rust/kernel/static_assert.rs
 create mode 100644 rust/kernel/std_vendor.rs
 create mode 100644 rust/kernel/str.rs
 create mode 100644 rust/kernel/sysctl.rs
 create mode 100644 rust/kernel/task.rs
 create mode 100644 rust/kernel/types.rs
 create mode 100644 rust/kernel/unsafe_list.rs
 create mode 100644 rust/kernel/user_ptr.rs
 create mode 100644 rust/kernel/workqueue.rs

diff --git a/rust/kernel/allocator.rs b/rust/kernel/allocator.rs
new file mode 100644
index 000000000000..397a3dd57a9b
--- /dev/null
+++ b/rust/kernel/allocator.rs
@@ -0,0 +1,64 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Allocator support.
+
+use core::alloc::{GlobalAlloc, Layout};
+use core::ptr;
+
+use crate::bindings;
+
+struct KernelAllocator;
+
+unsafe impl GlobalAlloc for KernelAllocator {
+    unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
+        // `krealloc()` is used instead of `kmalloc()` because the latter is
+        // an inline function and cannot be bound to as a result.
+        unsafe { bindings::krealloc(ptr::null(), layout.size(), bindings::GFP_KERNEL) as *mut u8 }
+    }
+
+    unsafe fn dealloc(&self, ptr: *mut u8, _layout: Layout) {
+        unsafe {
+            bindings::kfree(ptr as *const core::ffi::c_void);
+        }
+    }
+}
+
+#[global_allocator]
+static ALLOCATOR: KernelAllocator = KernelAllocator;
+
+// `rustc` only generates these for some crate types. Even then, we would need
+// to extract the object file that has them from the archive. For the moment,
+// let's generate them ourselves instead.
+//
+// Note that `#[no_mangle]` implies exported too, nowadays.
+#[no_mangle]
+fn __rust_alloc(size: usize, _align: usize) -> *mut u8 {
+    unsafe { bindings::krealloc(core::ptr::null(), size, bindings::GFP_KERNEL) as *mut u8 }
+}
+
+#[no_mangle]
+fn __rust_dealloc(ptr: *mut u8, _size: usize, _align: usize) {
+    unsafe { bindings::kfree(ptr as *const core::ffi::c_void) };
+}
+
+#[no_mangle]
+fn __rust_realloc(ptr: *mut u8, _old_size: usize, _align: usize, new_size: usize) -> *mut u8 {
+    unsafe {
+        bindings::krealloc(
+            ptr as *const core::ffi::c_void,
+            new_size,
+            bindings::GFP_KERNEL,
+        ) as *mut u8
+    }
+}
+
+#[no_mangle]
+fn __rust_alloc_zeroed(size: usize, _align: usize) -> *mut u8 {
+    unsafe {
+        bindings::krealloc(
+            core::ptr::null(),
+            size,
+            bindings::GFP_KERNEL | bindings::__GFP_ZERO,
+        ) as *mut u8
+    }
+}
diff --git a/rust/kernel/amba.rs b/rust/kernel/amba.rs
new file mode 100644
index 000000000000..ec8808124a29
--- /dev/null
+++ b/rust/kernel/amba.rs
@@ -0,0 +1,261 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Amba devices and drivers.
+//!
+//! C header: [`include/linux/amba/bus.h`](../../../../include/linux/amba/bus.h)
+
+use crate::{
+    bindings, device, driver, error::from_kernel_result, io_mem::Resource, power, str::CStr,
+    to_result, types::PointerWrapper, Result, ThisModule,
+};
+
+/// A registration of an amba driver.
+pub type Registration<T> = driver::Registration<Adapter<T>>;
+
+/// Id of an Amba device.
+#[derive(Clone, Copy)]
+pub struct DeviceId {
+    /// Device id.
+    pub id: u32,
+
+    /// Mask that identifies which bits are valid in the device id.
+    pub mask: u32,
+}
+
+// SAFETY: `ZERO` is all zeroed-out and `to_rawid` stores `offset` in `amba_id::data`.
+unsafe impl const driver::RawDeviceId for DeviceId {
+    type RawType = bindings::amba_id;
+    const ZERO: Self::RawType = bindings::amba_id {
+        id: 0,
+        mask: 0,
+        data: core::ptr::null_mut(),
+    };
+
+    fn to_rawid(&self, offset: isize) -> Self::RawType {
+        bindings::amba_id {
+            id: self.id,
+            mask: self.mask,
+            data: offset as _,
+        }
+    }
+}
+
+/// An amba driver.
+pub trait Driver {
+    /// Data stored on device by driver.
+    type Data: PointerWrapper + Send + Sync + driver::DeviceRemoval = ();
+
+    /// The type that implements the power-management operations.
+    ///
+    /// The default is a type that implements no power-management operations. Drivers that do
+    /// implement them need to specify the type (commonly [`Self`]).
+    type PowerOps: power::Operations<Data = Self::Data> = power::NoOperations<Self::Data>;
+
+    /// The type holding information about each device id supported by the driver.
+    type IdInfo: 'static = ();
+
+    /// The table of device ids supported by the driver.
+    const ID_TABLE: Option<driver::IdTable<'static, DeviceId, Self::IdInfo>> = None;
+
+    /// Probes for the device with the given id.
+    fn probe(dev: &mut Device, id_info: Option<&Self::IdInfo>) -> Result<Self::Data>;
+
+    /// Cleans any resources up that are associated with the device.
+    ///
+    /// This is called when the driver is detached from the device.
+    fn remove(_data: &Self::Data) {}
+}
+
+/// An adapter for the registration of Amba drivers.
+pub struct Adapter<T: Driver>(T);
+
+impl<T: Driver> driver::DriverOps for Adapter<T> {
+    type RegType = bindings::amba_driver;
+
+    unsafe fn register(
+        reg: *mut bindings::amba_driver,
+        name: &'static CStr,
+        module: &'static ThisModule,
+    ) -> Result {
+        // SAFETY: By the safety requirements of this function (defined in the trait definition),
+        // `reg` is non-null and valid.
+        let amba = unsafe { &mut *reg };
+        amba.drv.name = name.as_char_ptr();
+        amba.drv.owner = module.0;
+        amba.probe = Some(probe_callback::<T>);
+        amba.remove = Some(remove_callback::<T>);
+        if let Some(t) = T::ID_TABLE {
+            amba.id_table = t.as_ref();
+        }
+        if cfg!(CONFIG_PM) {
+            // SAFETY: `probe_callback` sets the driver data after calling `T::Data::into_pointer`,
+            // and we guarantee that `T::Data` is the same as `T::PowerOps::Data` by a constraint
+            // in the type declaration.
+            amba.drv.pm = unsafe { power::OpsTable::<T::PowerOps>::build() };
+        }
+        // SAFETY: By the safety requirements of this function, `reg` is valid and fully
+        // initialised.
+        to_result(unsafe { bindings::amba_driver_register(reg) })
+    }
+
+    unsafe fn unregister(reg: *mut bindings::amba_driver) {
+        // SAFETY: By the safety requirements of this function (defined in the trait definition),
+        // `reg` was passed (and updated) by a previous successful call to `amba_driver_register`.
+        unsafe { bindings::amba_driver_unregister(reg) };
+    }
+}
+
+unsafe extern "C" fn probe_callback<T: Driver>(
+    adev: *mut bindings::amba_device,
+    aid: *const bindings::amba_id,
+) -> core::ffi::c_int {
+    from_kernel_result! {
+        // SAFETY: `adev` is valid by the contract with the C code. `dev` is alive only for the
+        // duration of this call, so it is guaranteed to remain alive for the lifetime of `dev`.
+        let mut dev = unsafe { Device::from_ptr(adev) };
+        // SAFETY: `aid` is valid by the requirements the contract with the C code.
+        let offset = unsafe { (*aid).data };
+        let info = if offset.is_null() {
+            None
+        } else {
+            // SAFETY: The offset comes from a previous call to `offset_from` in `IdArray::new`,
+            // which guarantees that the resulting pointer is within the table.
+            let ptr = unsafe {
+                aid.cast::<u8>()
+                    .offset(offset as _)
+                    .cast::<Option<T::IdInfo>>()
+            };
+            // SAFETY: The id table has a static lifetime, so `ptr` is guaranteed to be valid for
+            // read.
+            unsafe { (&*ptr).as_ref() }
+        };
+        let data = T::probe(&mut dev, info)?;
+        let ptr = T::Data::into_pointer(data);
+        // SAFETY: `adev` is valid for write by the contract with the C code.
+        unsafe { bindings::amba_set_drvdata(adev, ptr as _) };
+        Ok(0)
+    }
+}
+
+unsafe extern "C" fn remove_callback<T: Driver>(adev: *mut bindings::amba_device) {
+    // SAFETY: `adev` is valid by the contract with the C code.
+    let ptr = unsafe { bindings::amba_get_drvdata(adev) };
+    // SAFETY: The value returned by `amba_get_drvdata` was stored by a previous call to
+    // `amba_set_drvdata` in `probe_callback` above; the value comes from a call to
+    // `T::Data::into_pointer`.
+    let data = unsafe { T::Data::from_pointer(ptr) };
+    T::remove(&data);
+    <T::Data as driver::DeviceRemoval>::device_remove(&data);
+}
+
+/// An Amba device.
+///
+/// # Invariants
+///
+/// The field `ptr` is non-null and valid for the lifetime of the object.
+pub struct Device {
+    ptr: *mut bindings::amba_device,
+    res: Option<Resource>,
+}
+
+impl Device {
+    /// Creates a new device from the given pointer.
+    ///
+    /// # Safety
+    ///
+    /// `ptr` must be non-null and valid. It must remain valid for the lifetime of the returned
+    /// instance.
+    unsafe fn from_ptr(ptr: *mut bindings::amba_device) -> Self {
+        // SAFETY: The safety requirements of the function ensure that `ptr` is valid.
+        let dev = unsafe { &mut *ptr };
+        // INVARIANT: The safety requirements of the function ensure the lifetime invariant.
+        Self {
+            ptr,
+            res: Resource::new(dev.res.start, dev.res.end),
+        }
+    }
+
+    /// Returns the io mem resource associated with the device, if there is one.
+    ///
+    /// Ownership of the resource is transferred to the caller, so subsequent calls to this
+    /// function will return [`None`].
+    pub fn take_resource(&mut self) -> Option<Resource> {
+        self.res.take()
+    }
+
+    /// Returns the index-th irq associated with the device, if one exists.
+    pub fn irq(&self, index: usize) -> Option<u32> {
+        // SAFETY: By the type invariants, `self.ptr` is valid for read.
+        let dev = unsafe { &*self.ptr };
+        if index >= dev.irq.len() || dev.irq[index] == 0 {
+            None
+        } else {
+            Some(dev.irq[index])
+        }
+    }
+}
+
+// SAFETY: The device returned by `raw_device` is the raw Amba device.
+unsafe impl device::RawDevice for Device {
+    fn raw_device(&self) -> *mut bindings::device {
+        // SAFETY: By the type invariants, we know that `self.ptr` is non-null and valid.
+        unsafe { &mut (*self.ptr).dev }
+    }
+}
+
+/// Declares a kernel module that exposes a single amba driver.
+///
+/// # Examples
+///
+/// ```ignore
+/// # use kernel::{amba, define_amba_id_table, module_amba_driver};
+/// #
+/// struct MyDriver;
+/// impl amba::Driver for MyDriver {
+///     // [...]
+/// #   fn probe(_dev: &mut amba::Device, _id: Option<&Self::IdInfo>) -> Result {
+/// #       Ok(())
+/// #   }
+/// #   define_amba_id_table! {(), [
+/// #       ({ id: 0x00041061, mask: 0x000fffff }, None),
+/// #   ]}
+/// }
+///
+/// module_amba_driver! {
+///     type: MyDriver,
+///     name: b"module_name",
+///     author: b"Author name",
+///     license: b"GPL",
+/// }
+/// ```
+#[macro_export]
+macro_rules! module_amba_driver {
+    ($($f:tt)*) => {
+        $crate::module_driver!(<T>, $crate::amba::Adapter<T>, { $($f)* });
+    };
+}
+
+/// Defines the id table for amba devices.
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::{amba, define_amba_id_table};
+/// #
+/// # struct Sample;
+/// # impl kernel::amba::Driver for Sample {
+/// #   fn probe(_dev: &mut amba::Device, _id: Option<&Self::IdInfo>) -> Result {
+/// #       Ok(())
+/// #   }
+/// define_amba_id_table! {(), [
+///     ({ id: 0x00041061, mask: 0x000fffff }, None),
+/// ]}
+/// # }
+/// ```
+#[macro_export]
+macro_rules! define_amba_id_table {
+    ($data_type:ty, $($t:tt)*) => {
+        type IdInfo = $data_type;
+        $crate::define_id_table!(ID_TABLE, $crate::amba::DeviceId, $data_type, $($t)*);
+    };
+}
diff --git a/rust/kernel/build_assert.rs b/rust/kernel/build_assert.rs
new file mode 100644
index 000000000000..72c533d8058d
--- /dev/null
+++ b/rust/kernel/build_assert.rs
@@ -0,0 +1,83 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Build-time assert.
+
+/// Fails the build if the code path calling `build_error!` can possibly be executed.
+///
+/// If the macro is executed in const context, `build_error!` will panic.
+/// If the compiler or optimizer cannot guarantee that `build_error!` can never
+/// be called, a build error will be triggered.
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::build_error;
+/// #[inline]
+/// fn foo(a: usize) -> usize {
+///     a.checked_add(1).unwrap_or_else(|| build_error!("overflow"))
+/// }
+///
+/// assert_eq!(foo(usize::MAX - 1), usize::MAX); // OK.
+/// // foo(usize::MAX); // Fails to compile.
+/// ```
+#[macro_export]
+macro_rules! build_error {
+    () => {{
+        $crate::build_error("")
+    }};
+    ($msg:expr) => {{
+        $crate::build_error($msg)
+    }};
+}
+
+/// Asserts that a boolean expression is `true` at compile time.
+///
+/// If the condition is evaluated to `false` in const context, `build_assert!`
+/// will panic. If the compiler or optimizer cannot guarantee the condition will
+/// be evaluated to `true`, a build error will be triggered.
+///
+/// [`static_assert!`] should be preferred to `build_assert!` whenever possible.
+///
+/// # Examples
+///
+/// These examples show that different types of [`assert!`] will trigger errors
+/// at different stage of compilation. It is preferred to err as early as
+/// possible, so [`static_assert!`] should be used whenever possible.
+// TODO: Could be `compile_fail` when supported.
+/// ```ignore
+/// fn foo() {
+///     static_assert!(1 > 1); // Compile-time error
+///     build_assert!(1 > 1); // Build-time error
+///     assert!(1 > 1); // Run-time error
+/// }
+/// ```
+///
+/// When the condition refers to generic parameters or parameters of an inline function,
+/// [`static_assert!`] cannot be used. Use `build_assert!` in this scenario.
+/// ```
+/// fn foo<const N: usize>() {
+///     // `static_assert!(N > 1);` is not allowed
+///     build_assert!(N > 1); // Build-time check
+///     assert!(N > 1); // Run-time check
+/// }
+///
+/// #[inline]
+/// fn bar(n: usize) {
+///     // `static_assert!(n > 1);` is not allowed
+///     build_assert!(n > 1); // Build-time check
+///     assert!(n > 1); // Run-time check
+/// }
+/// ```
+#[macro_export]
+macro_rules! build_assert {
+    ($cond:expr $(,)?) => {{
+        if !$cond {
+            $crate::build_error(concat!("assertion failed: ", stringify!($cond)));
+        }
+    }};
+    ($cond:expr, $msg:expr) => {{
+        if !$cond {
+            $crate::build_error($msg);
+        }
+    }};
+}
diff --git a/rust/kernel/chrdev.rs b/rust/kernel/chrdev.rs
new file mode 100644
index 000000000000..5b1e083c23b9
--- /dev/null
+++ b/rust/kernel/chrdev.rs
@@ -0,0 +1,206 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Character devices.
+//!
+//! Also called "char devices", `chrdev`, `cdev`.
+//!
+//! C header: [`include/linux/cdev.h`](../../../../include/linux/cdev.h)
+//!
+//! Reference: <https://www.kernel.org/doc/html/latest/core-api/kernel-api.html#char-devices>
+
+use alloc::boxed::Box;
+use core::convert::TryInto;
+use core::marker::PhantomPinned;
+use core::pin::Pin;
+
+use crate::bindings;
+use crate::error::{code::*, Error, Result};
+use crate::file;
+use crate::str::CStr;
+
+/// Character device.
+///
+/// # Invariants
+///
+///   - [`self.0`] is valid and non-null.
+///   - [`(*self.0).ops`] is valid, non-null and has static lifetime.
+///   - [`(*self.0).owner`] is valid and, if non-null, has module lifetime.
+struct Cdev(*mut bindings::cdev);
+
+impl Cdev {
+    fn alloc(
+        fops: &'static bindings::file_operations,
+        module: &'static crate::ThisModule,
+    ) -> Result<Self> {
+        // SAFETY: FFI call.
+        let cdev = unsafe { bindings::cdev_alloc() };
+        if cdev.is_null() {
+            return Err(ENOMEM);
+        }
+        // SAFETY: `cdev` is valid and non-null since `cdev_alloc()`
+        // returned a valid pointer which was null-checked.
+        unsafe {
+            (*cdev).ops = fops;
+            (*cdev).owner = module.0;
+        }
+        // INVARIANTS:
+        //   - [`self.0`] is valid and non-null.
+        //   - [`(*self.0).ops`] is valid, non-null and has static lifetime,
+        //     because it was coerced from a reference with static lifetime.
+        //   - [`(*self.0).owner`] is valid and, if non-null, has module lifetime,
+        //     guaranteed by the [`ThisModule`] invariant.
+        Ok(Self(cdev))
+    }
+
+    fn add(&mut self, dev: bindings::dev_t, count: core::ffi::c_uint) -> Result {
+        // SAFETY: According to the type invariants:
+        //   - [`self.0`] can be safely passed to [`bindings::cdev_add`].
+        //   - [`(*self.0).ops`] will live at least as long as [`self.0`].
+        //   - [`(*self.0).owner`] will live at least as long as the
+        //     module, which is an implicit requirement.
+        let rc = unsafe { bindings::cdev_add(self.0, dev, count) };
+        if rc != 0 {
+            return Err(Error::from_kernel_errno(rc));
+        }
+        Ok(())
+    }
+}
+
+impl Drop for Cdev {
+    fn drop(&mut self) {
+        // SAFETY: [`self.0`] is valid and non-null by the type invariants.
+        unsafe {
+            bindings::cdev_del(self.0);
+        }
+    }
+}
+
+struct RegistrationInner<const N: usize> {
+    dev: bindings::dev_t,
+    used: usize,
+    cdevs: [Option<Cdev>; N],
+    _pin: PhantomPinned,
+}
+
+/// Character device registration.
+///
+/// May contain up to a fixed number (`N`) of devices. Must be pinned.
+pub struct Registration<const N: usize> {
+    name: &'static CStr,
+    minors_start: u16,
+    this_module: &'static crate::ThisModule,
+    inner: Option<RegistrationInner<N>>,
+}
+
+impl<const N: usize> Registration<{ N }> {
+    /// Creates a [`Registration`] object for a character device.
+    ///
+    /// This does *not* register the device: see [`Self::register()`].
+    ///
+    /// This associated function is intended to be used when you need to avoid
+    /// a memory allocation, e.g. when the [`Registration`] is a member of
+    /// a bigger structure inside your [`crate::Module`] instance. If you
+    /// are going to pin the registration right away, call
+    /// [`Self::new_pinned()`] instead.
+    pub fn new(
+        name: &'static CStr,
+        minors_start: u16,
+        this_module: &'static crate::ThisModule,
+    ) -> Self {
+        Registration {
+            name,
+            minors_start,
+            this_module,
+            inner: None,
+        }
+    }
+
+    /// Creates a pinned [`Registration`] object for a character device.
+    ///
+    /// This does *not* register the device: see [`Self::register()`].
+    pub fn new_pinned(
+        name: &'static CStr,
+        minors_start: u16,
+        this_module: &'static crate::ThisModule,
+    ) -> Result<Pin<Box<Self>>> {
+        Ok(Pin::from(Box::try_new(Self::new(
+            name,
+            minors_start,
+            this_module,
+        ))?))
+    }
+
+    /// Registers a character device.
+    ///
+    /// You may call this once per device type, up to `N` times.
+    pub fn register<T: file::Operations<OpenData = ()>>(self: Pin<&mut Self>) -> Result {
+        // SAFETY: We must ensure that we never move out of `this`.
+        let this = unsafe { self.get_unchecked_mut() };
+        if this.inner.is_none() {
+            let mut dev: bindings::dev_t = 0;
+            // SAFETY: Calling unsafe function. `this.name` has `'static`
+            // lifetime.
+            let res = unsafe {
+                bindings::alloc_chrdev_region(
+                    &mut dev,
+                    this.minors_start.into(),
+                    N.try_into()?,
+                    this.name.as_char_ptr(),
+                )
+            };
+            if res != 0 {
+                return Err(Error::from_kernel_errno(res));
+            }
+            const NONE: Option<Cdev> = None;
+            this.inner = Some(RegistrationInner {
+                dev,
+                used: 0,
+                cdevs: [NONE; N],
+                _pin: PhantomPinned,
+            });
+        }
+
+        let mut inner = this.inner.as_mut().unwrap();
+        if inner.used == N {
+            return Err(EINVAL);
+        }
+
+        // SAFETY: The adapter doesn't retrieve any state yet, so it's compatible with any
+        // registration.
+        let fops = unsafe { file::OperationsVtable::<Self, T>::build() };
+        let mut cdev = Cdev::alloc(fops, this.this_module)?;
+        cdev.add(inner.dev + inner.used as bindings::dev_t, 1)?;
+        inner.cdevs[inner.used].replace(cdev);
+        inner.used += 1;
+        Ok(())
+    }
+}
+
+impl<const N: usize> file::OpenAdapter<()> for Registration<{ N }> {
+    unsafe fn convert(_inode: *mut bindings::inode, _file: *mut bindings::file) -> *const () {
+        // TODO: Update the SAFETY comment on the call to `FileOperationsVTable::build` above once
+        // this is updated to retrieve state.
+        &()
+    }
+}
+
+// SAFETY: `Registration` does not expose any of its state across threads
+// (it is fine for multiple threads to have a shared reference to it).
+unsafe impl<const N: usize> Sync for Registration<{ N }> {}
+
+impl<const N: usize> Drop for Registration<{ N }> {
+    fn drop(&mut self) {
+        if let Some(inner) = self.inner.as_mut() {
+            // Replicate kernel C behaviour: drop [`Cdev`]s before calling
+            // [`bindings::unregister_chrdev_region`].
+            for i in 0..inner.used {
+                inner.cdevs[i].take();
+            }
+            // SAFETY: [`self.inner`] is Some, so [`inner.dev`] was previously
+            // created using [`bindings::alloc_chrdev_region`].
+            unsafe {
+                bindings::unregister_chrdev_region(inner.dev, N.try_into().unwrap());
+            }
+        }
+    }
+}
diff --git a/rust/kernel/clk.rs b/rust/kernel/clk.rs
new file mode 100644
index 000000000000..1ec478d96abc
--- /dev/null
+++ b/rust/kernel/clk.rs
@@ -0,0 +1,79 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Common clock framework.
+//!
+//! C header: [`include/linux/clk.h`](../../../../include/linux/clk.h)
+
+use crate::{bindings, error::Result, to_result};
+use core::mem::ManuallyDrop;
+
+/// Represents `struct clk *`.
+///
+/// # Invariants
+///
+/// The pointer is valid.
+pub struct Clk(*mut bindings::clk);
+
+impl Clk {
+    /// Creates new clock structure from a raw pointer.
+    ///
+    /// # Safety
+    ///
+    /// The pointer must be valid.
+    pub unsafe fn new(clk: *mut bindings::clk) -> Self {
+        Self(clk)
+    }
+
+    /// Returns value of the rate field of `struct clk`.
+    pub fn get_rate(&self) -> usize {
+        // SAFETY: The pointer is valid by the type invariant.
+        unsafe { bindings::clk_get_rate(self.0) as usize }
+    }
+
+    /// Prepares and enables the underlying hardware clock.
+    ///
+    /// This function should not be called in atomic context.
+    pub fn prepare_enable(self) -> Result<EnabledClk> {
+        // SAFETY: The pointer is valid by the type invariant.
+        to_result(unsafe { bindings::clk_prepare_enable(self.0) })?;
+        Ok(EnabledClk(self))
+    }
+}
+
+impl Drop for Clk {
+    fn drop(&mut self) {
+        // SAFETY: The pointer is valid by the type invariant.
+        unsafe { bindings::clk_put(self.0) };
+    }
+}
+
+// SAFETY: `Clk` is not restricted to a single thread so it is safe
+// to move it between threads.
+unsafe impl Send for Clk {}
+
+/// A clock variant that is prepared and enabled.
+pub struct EnabledClk(Clk);
+
+impl EnabledClk {
+    /// Returns value of the rate field of `struct clk`.
+    pub fn get_rate(&self) -> usize {
+        self.0.get_rate()
+    }
+
+    /// Disables and later unprepares the underlying hardware clock prematurely.
+    ///
+    /// This function should not be called in atomic context.
+    pub fn disable_unprepare(self) -> Clk {
+        let mut clk = ManuallyDrop::new(self);
+        // SAFETY: The pointer is valid by the type invariant.
+        unsafe { bindings::clk_disable_unprepare(clk.0 .0) };
+        core::mem::replace(&mut clk.0, Clk(core::ptr::null_mut()))
+    }
+}
+
+impl Drop for EnabledClk {
+    fn drop(&mut self) {
+        // SAFETY: The pointer is valid by the type invariant.
+        unsafe { bindings::clk_disable_unprepare(self.0 .0) };
+    }
+}
diff --git a/rust/kernel/cred.rs b/rust/kernel/cred.rs
new file mode 100644
index 000000000000..beacc71d92ac
--- /dev/null
+++ b/rust/kernel/cred.rs
@@ -0,0 +1,46 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Credentials management.
+//!
+//! C header: [`include/linux/cred.h`](../../../../include/linux/cred.h)
+//!
+//! Reference: <https://www.kernel.org/doc/html/latest/security/credentials.html>
+
+use crate::{bindings, AlwaysRefCounted};
+use core::cell::UnsafeCell;
+
+/// Wraps the kernel's `struct cred`.
+///
+/// # Invariants
+///
+/// Instances of this type are always ref-counted, that is, a call to `get_cred` ensures that the
+/// allocation remains valid at least until the matching call to `put_cred`.
+#[repr(transparent)]
+pub struct Credential(pub(crate) UnsafeCell<bindings::cred>);
+
+impl Credential {
+    /// Creates a reference to a [`Credential`] from a valid pointer.
+    ///
+    /// # Safety
+    ///
+    /// The caller must ensure that `ptr` is valid and remains valid for the lifetime of the
+    /// returned [`Credential`] reference.
+    pub(crate) unsafe fn from_ptr<'a>(ptr: *const bindings::cred) -> &'a Self {
+        // SAFETY: The safety requirements guarantee the validity of the dereference, while the
+        // `Credential` type being transparent makes the cast ok.
+        unsafe { &*ptr.cast() }
+    }
+}
+
+// SAFETY: The type invariants guarantee that `Credential` is always ref-counted.
+unsafe impl AlwaysRefCounted for Credential {
+    fn inc_ref(&self) {
+        // SAFETY: The existence of a shared reference means that the refcount is nonzero.
+        unsafe { bindings::get_cred(self.0.get()) };
+    }
+
+    unsafe fn dec_ref(obj: core::ptr::NonNull<Self>) {
+        // SAFETY: The safety requirements guarantee that the refcount is nonzero.
+        unsafe { bindings::put_cred(obj.cast().as_ptr()) };
+    }
+}
diff --git a/rust/kernel/delay.rs b/rust/kernel/delay.rs
new file mode 100644
index 000000000000..1e987fa65941
--- /dev/null
+++ b/rust/kernel/delay.rs
@@ -0,0 +1,104 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Delay functions for operations like sleeping.
+//!
+//! C header: [`include/linux/delay.h`](../../../../include/linux/delay.h)
+
+use crate::bindings;
+use core::{cmp::min, time::Duration};
+
+const MILLIS_PER_SEC: u64 = 1_000;
+
+fn coarse_sleep_conversion(duration: Duration) -> core::ffi::c_uint {
+    let milli_as_nanos = Duration::MILLISECOND.subsec_nanos();
+
+    // Rounds the nanosecond component of `duration` up to the nearest millisecond.
+    let nanos_as_millis = duration.subsec_nanos().wrapping_add(milli_as_nanos - 1) / milli_as_nanos;
+
+    // Saturates the second component of `duration` to `c_uint::MAX`.
+    let seconds_as_millis = min(
+        duration.as_secs().saturating_mul(MILLIS_PER_SEC),
+        u64::from(core::ffi::c_uint::MAX),
+    ) as core::ffi::c_uint;
+
+    seconds_as_millis.saturating_add(nanos_as_millis)
+}
+
+/// Sleeps safely even with waitqueue interruptions.
+///
+/// This function forwards the call to the C side `msleep` function. As a result,
+/// `duration` will be rounded up to the nearest millisecond if granularity less
+/// than a millisecond is provided. Any [`Duration`] that exceeds
+/// [`c_uint::MAX`][core::ffi::c_uint::MAX] in milliseconds is saturated.
+///
+/// # Examples
+///
+// Keep these in sync with `test_coarse_sleep_examples`.
+/// ```
+/// # use core::time::Duration;
+/// # use kernel::delay::coarse_sleep;
+/// coarse_sleep(Duration::ZERO);                   // Equivalent to `msleep(0)`.
+/// coarse_sleep(Duration::from_nanos(1));          // Equivalent to `msleep(1)`.
+///
+/// coarse_sleep(Duration::from_nanos(1_000_000));  // Equivalent to `msleep(1)`.
+/// coarse_sleep(Duration::from_nanos(1_000_001));  // Equivalent to `msleep(2)`.
+/// coarse_sleep(Duration::from_nanos(1_999_999));  // Equivalent to `msleep(2)`.
+///
+/// coarse_sleep(Duration::from_millis(1));         // Equivalent to `msleep(1)`.
+/// coarse_sleep(Duration::from_millis(2));         // Equivalent to `msleep(2)`.
+///
+/// coarse_sleep(Duration::from_secs(1));           // Equivalent to `msleep(1000)`.
+/// coarse_sleep(Duration::new(1, 1));              // Equivalent to `msleep(1001)`.
+/// coarse_sleep(Duration::new(1, 2));              // Equivalent to `msleep(1001)`.
+/// ```
+pub fn coarse_sleep(duration: Duration) {
+    // SAFETY: `msleep` is safe for all values of its argument.
+    unsafe { bindings::msleep(coarse_sleep_conversion(duration)) }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::{coarse_sleep_conversion, MILLIS_PER_SEC};
+    use core::time::Duration;
+
+    #[test]
+    fn test_coarse_sleep_examples() {
+        // Keep these in sync with `coarse_sleep`'s `# Examples` section.
+
+        assert_eq!(coarse_sleep_conversion(Duration::ZERO), 0);
+        assert_eq!(coarse_sleep_conversion(Duration::from_nanos(1)), 1);
+
+        assert_eq!(coarse_sleep_conversion(Duration::from_nanos(1_000_000)), 1);
+        assert_eq!(coarse_sleep_conversion(Duration::from_nanos(1_000_001)), 2);
+        assert_eq!(coarse_sleep_conversion(Duration::from_nanos(1_999_999)), 2);
+
+        assert_eq!(coarse_sleep_conversion(Duration::from_millis(1)), 1);
+        assert_eq!(coarse_sleep_conversion(Duration::from_millis(2)), 2);
+
+        assert_eq!(coarse_sleep_conversion(Duration::from_secs(1)), 1000);
+        assert_eq!(coarse_sleep_conversion(Duration::new(1, 1)), 1001);
+        assert_eq!(coarse_sleep_conversion(Duration::new(1, 2)), 1001);
+    }
+
+    #[test]
+    fn test_coarse_sleep_saturation() {
+        assert!(
+            coarse_sleep_conversion(Duration::new(
+                core::ffi::c_uint::MAX as u64 / MILLIS_PER_SEC,
+                0
+            )) < core::ffi::c_uint::MAX
+        );
+        assert_eq!(
+            coarse_sleep_conversion(Duration::new(
+                core::ffi::c_uint::MAX as u64 / MILLIS_PER_SEC,
+                999_999_999
+            )),
+            core::ffi::c_uint::MAX
+        );
+
+        assert_eq!(
+            coarse_sleep_conversion(Duration::MAX),
+            core::ffi::c_uint::MAX
+        );
+    }
+}
diff --git a/rust/kernel/device.rs b/rust/kernel/device.rs
new file mode 100644
index 000000000000..c37f555c534d
--- /dev/null
+++ b/rust/kernel/device.rs
@@ -0,0 +1,527 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Generic devices that are part of the kernel's driver model.
+//!
+//! C header: [`include/linux/device.h`](../../../../include/linux/device.h)
+
+#[cfg(CONFIG_COMMON_CLK)]
+use crate::{clk::Clk, error::from_kernel_err_ptr};
+
+use crate::{
+    bindings,
+    revocable::{Revocable, RevocableGuard},
+    str::CStr,
+    sync::{LockClassKey, NeedsLockClass, RevocableMutex, RevocableMutexGuard, UniqueRef},
+    Result,
+};
+use core::{
+    fmt,
+    ops::{Deref, DerefMut},
+    pin::Pin,
+};
+
+#[cfg(CONFIG_PRINTK)]
+use crate::c_str;
+
+/// A raw device.
+///
+/// # Safety
+///
+/// Implementers must ensure that the `*mut device` returned by [`RawDevice::raw_device`] is
+/// related to `self`, that is, actions on it will affect `self`. For example, if one calls
+/// `get_device`, then the refcount on the device represented by `self` will be incremented.
+///
+/// Additionally, implementers must ensure that the device is never renamed. Commit a5462516aa99
+/// ("driver-core: document restrictions on device_rename()") has details on why `device_rename`
+/// should not be used.
+pub unsafe trait RawDevice {
+    /// Returns the raw `struct device` related to `self`.
+    fn raw_device(&self) -> *mut bindings::device;
+
+    /// Returns the name of the device.
+    fn name(&self) -> &CStr {
+        let ptr = self.raw_device();
+
+        // SAFETY: `ptr` is valid because `self` keeps it alive.
+        let name = unsafe { bindings::dev_name(ptr) };
+
+        // SAFETY: The name of the device remains valid while it is alive (because the device is
+        // never renamed, per the safety requirement of this trait). This is guaranteed to be the
+        // case because the reference to `self` outlives the one of the returned `CStr` (enforced
+        // by the compiler because of their lifetimes).
+        unsafe { CStr::from_char_ptr(name) }
+    }
+
+    /// Lookups a clock producer consumed by this device.
+    ///
+    /// Returns a managed reference to the clock producer.
+    #[cfg(CONFIG_COMMON_CLK)]
+    fn clk_get(&self, id: Option<&CStr>) -> Result<Clk> {
+        let id_ptr = match id {
+            Some(cstr) => cstr.as_char_ptr(),
+            None => core::ptr::null(),
+        };
+
+        // SAFETY: `id_ptr` is optional and may be either a valid pointer
+        // from the type invariant or NULL otherwise.
+        let clk_ptr = unsafe { from_kernel_err_ptr(bindings::clk_get(self.raw_device(), id_ptr)) }?;
+
+        // SAFETY: Clock is initialized with valid pointer returned from `bindings::clk_get` call.
+        unsafe { Ok(Clk::new(clk_ptr)) }
+    }
+
+    /// Prints an emergency-level message (level 0) prefixed with device information.
+    ///
+    /// More details are available from [`dev_emerg`].
+    fn pr_emerg(&self, args: fmt::Arguments<'_>) {
+        // SAFETY: `klevel` is null-terminated, uses one of the kernel constants.
+        unsafe { self.printk(bindings::KERN_EMERG, args) };
+    }
+
+    /// Prints an alert-level message (level 1) prefixed with device information.
+    ///
+    /// More details are available from [`dev_alert`].
+    fn pr_alert(&self, args: fmt::Arguments<'_>) {
+        // SAFETY: `klevel` is null-terminated, uses one of the kernel constants.
+        unsafe { self.printk(bindings::KERN_ALERT, args) };
+    }
+
+    /// Prints a critical-level message (level 2) prefixed with device information.
+    ///
+    /// More details are available from [`dev_crit`].
+    fn pr_crit(&self, args: fmt::Arguments<'_>) {
+        // SAFETY: `klevel` is null-terminated, uses one of the kernel constants.
+        unsafe { self.printk(bindings::KERN_CRIT, args) };
+    }
+
+    /// Prints an error-level message (level 3) prefixed with device information.
+    ///
+    /// More details are available from [`dev_err`].
+    fn pr_err(&self, args: fmt::Arguments<'_>) {
+        // SAFETY: `klevel` is null-terminated, uses one of the kernel constants.
+        unsafe { self.printk(bindings::KERN_ERR, args) };
+    }
+
+    /// Prints a warning-level message (level 4) prefixed with device information.
+    ///
+    /// More details are available from [`dev_warn`].
+    fn pr_warn(&self, args: fmt::Arguments<'_>) {
+        // SAFETY: `klevel` is null-terminated, uses one of the kernel constants.
+        unsafe { self.printk(bindings::KERN_WARNING, args) };
+    }
+
+    /// Prints a notice-level message (level 5) prefixed with device information.
+    ///
+    /// More details are available from [`dev_notice`].
+    fn pr_notice(&self, args: fmt::Arguments<'_>) {
+        // SAFETY: `klevel` is null-terminated, uses one of the kernel constants.
+        unsafe { self.printk(bindings::KERN_NOTICE, args) };
+    }
+
+    /// Prints an info-level message (level 6) prefixed with device information.
+    ///
+    /// More details are available from [`dev_info`].
+    fn pr_info(&self, args: fmt::Arguments<'_>) {
+        // SAFETY: `klevel` is null-terminated, uses one of the kernel constants.
+        unsafe { self.printk(bindings::KERN_INFO, args) };
+    }
+
+    /// Prints a debug-level message (level 7) prefixed with device information.
+    ///
+    /// More details are available from [`dev_dbg`].
+    fn pr_dbg(&self, args: fmt::Arguments<'_>) {
+        if cfg!(debug_assertions) {
+            // SAFETY: `klevel` is null-terminated, uses one of the kernel constants.
+            unsafe { self.printk(bindings::KERN_DEBUG, args) };
+        }
+    }
+
+    /// Prints the provided message to the console.
+    ///
+    /// # Safety
+    ///
+    /// Callers must ensure that `klevel` is null-terminated; in particular, one of the
+    /// `KERN_*`constants, for example, `KERN_CRIT`, `KERN_ALERT`, etc.
+    #[cfg_attr(not(CONFIG_PRINTK), allow(unused_variables))]
+    unsafe fn printk(&self, klevel: &[u8], msg: fmt::Arguments<'_>) {
+        // SAFETY: `klevel` is null-terminated and one of the kernel constants. `self.raw_device`
+        // is valid because `self` is valid. The "%pA" format string expects a pointer to
+        // `fmt::Arguments`, which is what we're passing as the last argument.
+        #[cfg(CONFIG_PRINTK)]
+        unsafe {
+            bindings::_dev_printk(
+                klevel as *const _ as *const core::ffi::c_char,
+                self.raw_device(),
+                c_str!("%pA").as_char_ptr(),
+                &msg as *const _ as *const core::ffi::c_void,
+            )
+        };
+    }
+}
+
+/// A ref-counted device.
+///
+/// # Invariants
+///
+/// `ptr` is valid, non-null, and has a non-zero reference count. One of the references is owned by
+/// `self`, and will be decremented when `self` is dropped.
+pub struct Device {
+    pub(crate) ptr: *mut bindings::device,
+}
+
+// SAFETY: `Device` only holds a pointer to a C device, which is safe to be used from any thread.
+unsafe impl Send for Device {}
+
+// SAFETY: `Device` only holds a pointer to a C device, references to which are safe to be used
+// from any thread.
+unsafe impl Sync for Device {}
+
+impl Device {
+    /// Creates a new device instance.
+    ///
+    /// # Safety
+    ///
+    /// Callers must ensure that `ptr` is valid, non-null, and has a non-zero reference count.
+    pub unsafe fn new(ptr: *mut bindings::device) -> Self {
+        // SAFETY: By the safety requirements, ptr is valid and its refcounted will be incremented.
+        unsafe { bindings::get_device(ptr) };
+        // INVARIANT: The safety requirements satisfy all but one invariant, which is that `self`
+        // owns a reference. This is satisfied by the call to `get_device` above.
+        Self { ptr }
+    }
+
+    /// Creates a new device instance from an existing [`RawDevice`] instance.
+    pub fn from_dev(dev: &dyn RawDevice) -> Self {
+        // SAFETY: The requirements are satisfied by the existence of `RawDevice` and its safety
+        // requirements.
+        unsafe { Self::new(dev.raw_device()) }
+    }
+}
+
+// SAFETY: The device returned by `raw_device` is the one for which we hold a reference.
+unsafe impl RawDevice for Device {
+    fn raw_device(&self) -> *mut bindings::device {
+        self.ptr
+    }
+}
+
+impl Drop for Device {
+    fn drop(&mut self) {
+        // SAFETY: By the type invariants, we know that `self` owns a reference, so it is safe to
+        // relinquish it now.
+        unsafe { bindings::put_device(self.ptr) };
+    }
+}
+
+/// Device data.
+///
+/// When a device is removed (for whatever reason, for example, because the device was unplugged or
+/// because the user decided to unbind the driver), the driver is given a chance to clean its state
+/// up, and all io resources should ideally not be used anymore.
+///
+/// However, the device data is reference-counted because other subsystems hold pointers to it. So
+/// some device state must be freed and not used anymore, while others must remain accessible.
+///
+/// This struct separates the device data into three categories:
+///   1. Registrations: are destroyed when the device is removed, but before the io resources
+///      become inaccessible.
+///   2. Io resources: are available until the device is removed.
+///   3. General data: remain available as long as the ref count is nonzero.
+///
+/// This struct implements the `DeviceRemoval` trait so that it can clean resources up even if not
+/// explicitly called by the device drivers.
+pub struct Data<T, U, V> {
+    registrations: RevocableMutex<T>,
+    resources: Revocable<U>,
+    general: V,
+}
+
+/// Safely creates an new reference-counted instance of [`Data`].
+#[doc(hidden)]
+#[macro_export]
+macro_rules! new_device_data {
+    ($reg:expr, $res:expr, $gen:expr, $name:literal) => {{
+        static CLASS1: $crate::sync::LockClassKey = $crate::sync::LockClassKey::new();
+        static CLASS2: $crate::sync::LockClassKey = $crate::sync::LockClassKey::new();
+        let regs = $reg;
+        let res = $res;
+        let gen = $gen;
+        let name = $crate::c_str!($name);
+        $crate::device::Data::try_new(regs, res, gen, name, &CLASS1, &CLASS2)
+    }};
+}
+
+impl<T, U, V> Data<T, U, V> {
+    /// Creates a new instance of `Data`.
+    ///
+    /// It is recommended that the [`new_device_data`] macro be used as it automatically creates
+    /// the lock classes.
+    pub fn try_new(
+        registrations: T,
+        resources: U,
+        general: V,
+        name: &'static CStr,
+        key1: &'static LockClassKey,
+        key2: &'static LockClassKey,
+    ) -> Result<Pin<UniqueRef<Self>>> {
+        let mut ret = Pin::from(UniqueRef::try_new(Self {
+            // SAFETY: We call `RevocableMutex::init` below.
+            registrations: unsafe { RevocableMutex::new(registrations) },
+            resources: Revocable::new(resources),
+            general,
+        })?);
+
+        // SAFETY: `Data::registrations` is pinned when `Data` is.
+        let pinned = unsafe { ret.as_mut().map_unchecked_mut(|d| &mut d.registrations) };
+        pinned.init(name, key1, key2);
+        Ok(ret)
+    }
+
+    /// Returns the resources if they're still available.
+    pub fn resources(&self) -> Option<RevocableGuard<'_, U>> {
+        self.resources.try_access()
+    }
+
+    /// Returns the locked registrations if they're still available.
+    pub fn registrations(&self) -> Option<RevocableMutexGuard<'_, T>> {
+        self.registrations.try_write()
+    }
+}
+
+impl<T, U, V> crate::driver::DeviceRemoval for Data<T, U, V> {
+    fn device_remove(&self) {
+        // We revoke the registrations first so that resources are still available to them during
+        // unregistration.
+        self.registrations.revoke();
+
+        // Release resources now. General data remains available.
+        self.resources.revoke();
+    }
+}
+
+impl<T, U, V> Deref for Data<T, U, V> {
+    type Target = V;
+
+    fn deref(&self) -> &V {
+        &self.general
+    }
+}
+
+impl<T, U, V> DerefMut for Data<T, U, V> {
+    fn deref_mut(&mut self) -> &mut V {
+        &mut self.general
+    }
+}
+
+#[doc(hidden)]
+#[macro_export]
+macro_rules! dev_printk {
+    ($method:ident, $dev:expr, $($f:tt)*) => {
+        {
+            // We have an explicity `use` statement here so that callers of this macro are not
+            // required to explicitly use the `RawDevice` trait to use its functions.
+            use $crate::device::RawDevice;
+            ($dev).$method(core::format_args!($($f)*));
+        }
+    }
+}
+
+/// Prints an emergency-level message (level 0) prefixed with device information.
+///
+/// This level should be used if the system is unusable.
+///
+/// Equivalent to the kernel's `dev_emerg` macro.
+///
+/// Mimics the interface of [`std::print!`]. More information about the syntax is available from
+/// [`core::fmt`] and [`alloc::format!`].
+///
+/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::device::Device;
+///
+/// fn example(dev: &Device) {
+///     dev_emerg!(dev, "hello {}\n", "there");
+/// }
+/// ```
+#[macro_export]
+macro_rules! dev_emerg {
+    ($($f:tt)*) => { $crate::dev_printk!(pr_emerg, $($f)*); }
+}
+
+/// Prints an alert-level message (level 1) prefixed with device information.
+///
+/// This level should be used if action must be taken immediately.
+///
+/// Equivalent to the kernel's `dev_alert` macro.
+///
+/// Mimics the interface of [`std::print!`]. More information about the syntax is available from
+/// [`core::fmt`] and [`alloc::format!`].
+///
+/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::device::Device;
+///
+/// fn example(dev: &Device) {
+///     dev_alert!(dev, "hello {}\n", "there");
+/// }
+/// ```
+#[macro_export]
+macro_rules! dev_alert {
+    ($($f:tt)*) => { $crate::dev_printk!(pr_alert, $($f)*); }
+}
+
+/// Prints a critical-level message (level 2) prefixed with device information.
+///
+/// This level should be used in critical conditions.
+///
+/// Equivalent to the kernel's `dev_crit` macro.
+///
+/// Mimics the interface of [`std::print!`]. More information about the syntax is available from
+/// [`core::fmt`] and [`alloc::format!`].
+///
+/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::device::Device;
+///
+/// fn example(dev: &Device) {
+///     dev_crit!(dev, "hello {}\n", "there");
+/// }
+/// ```
+#[macro_export]
+macro_rules! dev_crit {
+    ($($f:tt)*) => { $crate::dev_printk!(pr_crit, $($f)*); }
+}
+
+/// Prints an error-level message (level 3) prefixed with device information.
+///
+/// This level should be used in error conditions.
+///
+/// Equivalent to the kernel's `dev_err` macro.
+///
+/// Mimics the interface of [`std::print!`]. More information about the syntax is available from
+/// [`core::fmt`] and [`alloc::format!`].
+///
+/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::device::Device;
+///
+/// fn example(dev: &Device) {
+///     dev_err!(dev, "hello {}\n", "there");
+/// }
+/// ```
+#[macro_export]
+macro_rules! dev_err {
+    ($($f:tt)*) => { $crate::dev_printk!(pr_err, $($f)*); }
+}
+
+/// Prints a warning-level message (level 4) prefixed with device information.
+///
+/// This level should be used in warning conditions.
+///
+/// Equivalent to the kernel's `dev_warn` macro.
+///
+/// Mimics the interface of [`std::print!`]. More information about the syntax is available from
+/// [`core::fmt`] and [`alloc::format!`].
+///
+/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::device::Device;
+///
+/// fn example(dev: &Device) {
+///     dev_warn!(dev, "hello {}\n", "there");
+/// }
+/// ```
+#[macro_export]
+macro_rules! dev_warn {
+    ($($f:tt)*) => { $crate::dev_printk!(pr_warn, $($f)*); }
+}
+
+/// Prints a notice-level message (level 5) prefixed with device information.
+///
+/// This level should be used in normal but significant conditions.
+///
+/// Equivalent to the kernel's `dev_notice` macro.
+///
+/// Mimics the interface of [`std::print!`]. More information about the syntax is available from
+/// [`core::fmt`] and [`alloc::format!`].
+///
+/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::device::Device;
+///
+/// fn example(dev: &Device) {
+///     dev_notice!(dev, "hello {}\n", "there");
+/// }
+/// ```
+#[macro_export]
+macro_rules! dev_notice {
+    ($($f:tt)*) => { $crate::dev_printk!(pr_notice, $($f)*); }
+}
+
+/// Prints an info-level message (level 6) prefixed with device information.
+///
+/// This level should be used for informational messages.
+///
+/// Equivalent to the kernel's `dev_info` macro.
+///
+/// Mimics the interface of [`std::print!`]. More information about the syntax is available from
+/// [`core::fmt`] and [`alloc::format!`].
+///
+/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::device::Device;
+///
+/// fn example(dev: &Device) {
+///     dev_info!(dev, "hello {}\n", "there");
+/// }
+/// ```
+#[macro_export]
+macro_rules! dev_info {
+    ($($f:tt)*) => { $crate::dev_printk!(pr_info, $($f)*); }
+}
+
+/// Prints a debug-level message (level 7) prefixed with device information.
+///
+/// This level should be used for debug messages.
+///
+/// Equivalent to the kernel's `dev_dbg` macro, except that it doesn't support dynamic debug yet.
+///
+/// Mimics the interface of [`std::print!`]. More information about the syntax is available from
+/// [`core::fmt`] and [`alloc::format!`].
+///
+/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::device::Device;
+///
+/// fn example(dev: &Device) {
+///     dev_dbg!(dev, "hello {}\n", "there");
+/// }
+/// ```
+#[macro_export]
+macro_rules! dev_dbg {
+    ($($f:tt)*) => { $crate::dev_printk!(pr_dbg, $($f)*); }
+}
diff --git a/rust/kernel/driver.rs b/rust/kernel/driver.rs
new file mode 100644
index 000000000000..82b39231e311
--- /dev/null
+++ b/rust/kernel/driver.rs
@@ -0,0 +1,442 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Generic support for drivers of different buses (e.g., PCI, Platform, Amba, etc.).
+//!
+//! Each bus/subsystem is expected to implement [`DriverOps`], which allows drivers to register
+//! using the [`Registration`] class.
+
+use crate::{error::code::*, str::CStr, sync::Ref, Result, ThisModule};
+use alloc::boxed::Box;
+use core::{cell::UnsafeCell, marker::PhantomData, ops::Deref, pin::Pin};
+
+/// A subsystem (e.g., PCI, Platform, Amba, etc.) that allows drivers to be written for it.
+pub trait DriverOps {
+    /// The type that holds information about the registration. This is typically a struct defined
+    /// by the C portion of the kernel.
+    type RegType: Default;
+
+    /// Registers a driver.
+    ///
+    /// # Safety
+    ///
+    /// `reg` must point to valid, initialised, and writable memory. It may be modified by this
+    /// function to hold registration state.
+    ///
+    /// On success, `reg` must remain pinned and valid until the matching call to
+    /// [`DriverOps::unregister`].
+    unsafe fn register(
+        reg: *mut Self::RegType,
+        name: &'static CStr,
+        module: &'static ThisModule,
+    ) -> Result;
+
+    /// Unregisters a driver previously registered with [`DriverOps::register`].
+    ///
+    /// # Safety
+    ///
+    /// `reg` must point to valid writable memory, initialised by a previous successful call to
+    /// [`DriverOps::register`].
+    unsafe fn unregister(reg: *mut Self::RegType);
+}
+
+/// The registration of a driver.
+pub struct Registration<T: DriverOps> {
+    is_registered: bool,
+    concrete_reg: UnsafeCell<T::RegType>,
+}
+
+// SAFETY: `Registration` has no fields or methods accessible via `&Registration`, so it is safe to
+// share references to it with multiple threads as nothing can be done.
+unsafe impl<T: DriverOps> Sync for Registration<T> {}
+
+impl<T: DriverOps> Registration<T> {
+    /// Creates a new instance of the registration object.
+    pub fn new() -> Self {
+        Self {
+            is_registered: false,
+            concrete_reg: UnsafeCell::new(T::RegType::default()),
+        }
+    }
+
+    /// Allocates a pinned registration object and registers it.
+    ///
+    /// Returns a pinned heap-allocated representation of the registration.
+    pub fn new_pinned(name: &'static CStr, module: &'static ThisModule) -> Result<Pin<Box<Self>>> {
+        let mut reg = Pin::from(Box::try_new(Self::new())?);
+        reg.as_mut().register(name, module)?;
+        Ok(reg)
+    }
+
+    /// Registers a driver with its subsystem.
+    ///
+    /// It must be pinned because the memory block that represents the registration is potentially
+    /// self-referential.
+    pub fn register(
+        self: Pin<&mut Self>,
+        name: &'static CStr,
+        module: &'static ThisModule,
+    ) -> Result {
+        // SAFETY: We never move out of `this`.
+        let this = unsafe { self.get_unchecked_mut() };
+        if this.is_registered {
+            // Already registered.
+            return Err(EINVAL);
+        }
+
+        // SAFETY: `concrete_reg` was initialised via its default constructor. It is only freed
+        // after `Self::drop` is called, which first calls `T::unregister`.
+        unsafe { T::register(this.concrete_reg.get(), name, module) }?;
+
+        this.is_registered = true;
+        Ok(())
+    }
+}
+
+impl<T: DriverOps> Default for Registration<T> {
+    fn default() -> Self {
+        Self::new()
+    }
+}
+
+impl<T: DriverOps> Drop for Registration<T> {
+    fn drop(&mut self) {
+        if self.is_registered {
+            // SAFETY: This path only runs if a previous call to `T::register` completed
+            // successfully.
+            unsafe { T::unregister(self.concrete_reg.get()) };
+        }
+    }
+}
+
+/// Conversion from a device id to a raw device id.
+///
+/// This is meant to be implemented by buses/subsystems so that they can use [`IdTable`] to
+/// guarantee (at compile-time) zero-termination of device id tables provided by drivers.
+///
+/// # Safety
+///
+/// Implementers must ensure that:
+///   - [`RawDeviceId::ZERO`] is actually a zeroed-out version of the raw device id.
+///   - [`RawDeviceId::to_rawid`] stores `offset` in the context/data field of the raw device id so
+///     that buses can recover the pointer to the data.
+pub unsafe trait RawDeviceId {
+    /// The raw type that holds the device id.
+    ///
+    /// Id tables created from [`Self`] are going to hold this type in its zero-terminated array.
+    type RawType: Copy;
+
+    /// A zeroed-out representation of the raw device id.
+    ///
+    /// Id tables created from [`Self`] use [`Self::ZERO`] as the sentinel to indicate the end of
+    /// the table.
+    const ZERO: Self::RawType;
+
+    /// Converts an id into a raw id.
+    ///
+    /// `offset` is the offset from the memory location where the raw device id is stored to the
+    /// location where its associated context information is stored. Implementations must store
+    /// this in the appropriate context/data field of the raw type.
+    fn to_rawid(&self, offset: isize) -> Self::RawType;
+}
+
+/// A zero-terminated device id array, followed by context data.
+#[repr(C)]
+pub struct IdArray<T: RawDeviceId, U, const N: usize> {
+    ids: [T::RawType; N],
+    sentinel: T::RawType,
+    id_infos: [Option<U>; N],
+}
+
+impl<T: RawDeviceId, U, const N: usize> IdArray<T, U, N> {
+    /// Creates a new instance of the array.
+    ///
+    /// The contents are derived from the given identifiers and context information.
+    pub const fn new(ids: [T; N], infos: [Option<U>; N]) -> Self
+    where
+        T: ~const RawDeviceId + Copy,
+    {
+        let mut array = Self {
+            ids: [T::ZERO; N],
+            sentinel: T::ZERO,
+            id_infos: infos,
+        };
+        let mut i = 0usize;
+        while i < N {
+            // SAFETY: Both pointers are within `array` (or one byte beyond), consequently they are
+            // derived from the same allocated object. We are using a `u8` pointer, whose size 1,
+            // so the pointers are necessarily 1-byte aligned.
+            let offset = unsafe {
+                (&array.id_infos[i] as *const _ as *const u8)
+                    .offset_from(&array.ids[i] as *const _ as _)
+            };
+            array.ids[i] = ids[i].to_rawid(offset);
+            i += 1;
+        }
+        array
+    }
+
+    /// Returns an `IdTable` backed by `self`.
+    ///
+    /// This is used to essentially erase the array size.
+    pub const fn as_table(&self) -> IdTable<'_, T, U> {
+        IdTable {
+            first: &self.ids[0],
+            _p: PhantomData,
+        }
+    }
+}
+
+/// A device id table.
+///
+/// The table is guaranteed to be zero-terminated and to be followed by an array of context data of
+/// type `Option<U>`.
+pub struct IdTable<'a, T: RawDeviceId, U> {
+    first: &'a T::RawType,
+    _p: PhantomData<&'a U>,
+}
+
+impl<T: RawDeviceId, U> const AsRef<T::RawType> for IdTable<'_, T, U> {
+    fn as_ref(&self) -> &T::RawType {
+        self.first
+    }
+}
+
+/// Counts the number of parenthesis-delimited, comma-separated items.
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::count_paren_items;
+///
+/// assert_eq!(0, count_paren_items!());
+/// assert_eq!(1, count_paren_items!((A)));
+/// assert_eq!(1, count_paren_items!((A),));
+/// assert_eq!(2, count_paren_items!((A), (B)));
+/// assert_eq!(2, count_paren_items!((A), (B),));
+/// assert_eq!(3, count_paren_items!((A), (B), (C)));
+/// assert_eq!(3, count_paren_items!((A), (B), (C),));
+/// ```
+#[macro_export]
+macro_rules! count_paren_items {
+    (($($item:tt)*), $($remaining:tt)*) => { 1 + $crate::count_paren_items!($($remaining)*) };
+    (($($item:tt)*)) => { 1 };
+    () => { 0 };
+}
+
+/// Converts a comma-separated list of pairs into an array with the first element. That is, it
+/// discards the second element of the pair.
+///
+/// Additionally, it automatically introduces a type if the first element is warpped in curly
+/// braces, for example, if it's `{v: 10}`, it becomes `X { v: 10 }`; this is to avoid repeating
+/// the type.
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::first_item;
+///
+/// #[derive(PartialEq, Debug)]
+/// struct X {
+///     v: u32,
+/// }
+///
+/// assert_eq!([] as [X; 0], first_item!(X, ));
+/// assert_eq!([X { v: 10 }], first_item!(X, ({ v: 10 }, Y)));
+/// assert_eq!([X { v: 10 }], first_item!(X, ({ v: 10 }, Y),));
+/// assert_eq!([X { v: 10 }], first_item!(X, (X { v: 10 }, Y)));
+/// assert_eq!([X { v: 10 }], first_item!(X, (X { v: 10 }, Y),));
+/// assert_eq!([X { v: 10 }, X { v: 20 }], first_item!(X, ({ v: 10 }, Y), ({ v: 20 }, Y)));
+/// assert_eq!([X { v: 10 }, X { v: 20 }], first_item!(X, ({ v: 10 }, Y), ({ v: 20 }, Y),));
+/// assert_eq!([X { v: 10 }, X { v: 20 }], first_item!(X, (X { v: 10 }, Y), (X { v: 20 }, Y)));
+/// assert_eq!([X { v: 10 }, X { v: 20 }], first_item!(X, (X { v: 10 }, Y), (X { v: 20 }, Y),));
+/// assert_eq!([X { v: 10 }, X { v: 20 }, X { v: 30 }],
+///            first_item!(X, ({ v: 10 }, Y), ({ v: 20 }, Y), ({v: 30}, Y)));
+/// assert_eq!([X { v: 10 }, X { v: 20 }, X { v: 30 }],
+///            first_item!(X, ({ v: 10 }, Y), ({ v: 20 }, Y), ({v: 30}, Y),));
+/// assert_eq!([X { v: 10 }, X { v: 20 }, X { v: 30 }],
+///            first_item!(X, (X { v: 10 }, Y), (X { v: 20 }, Y), (X {v: 30}, Y)));
+/// assert_eq!([X { v: 10 }, X { v: 20 }, X { v: 30 }],
+///            first_item!(X, (X { v: 10 }, Y), (X { v: 20 }, Y), (X {v: 30}, Y),));
+/// ```
+#[macro_export]
+macro_rules! first_item {
+    ($id_type:ty, $(({$($first:tt)*}, $second:expr)),* $(,)?) => {
+        {
+            type IdType = $id_type;
+            [$(IdType{$($first)*},)*]
+        }
+    };
+    ($id_type:ty, $(($first:expr, $second:expr)),* $(,)?) => { [$($first,)*] };
+}
+
+/// Converts a comma-separated list of pairs into an array with the second element. That is, it
+/// discards the first element of the pair.
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::second_item;
+///
+/// assert_eq!([] as [u32; 0], second_item!());
+/// assert_eq!([10u32], second_item!((X, 10u32)));
+/// assert_eq!([10u32], second_item!((X, 10u32),));
+/// assert_eq!([10u32], second_item!(({ X }, 10u32)));
+/// assert_eq!([10u32], second_item!(({ X }, 10u32),));
+/// assert_eq!([10u32, 20], second_item!((X, 10u32), (X, 20)));
+/// assert_eq!([10u32, 20], second_item!((X, 10u32), (X, 20),));
+/// assert_eq!([10u32, 20], second_item!(({ X }, 10u32), ({ X }, 20)));
+/// assert_eq!([10u32, 20], second_item!(({ X }, 10u32), ({ X }, 20),));
+/// assert_eq!([10u32, 20, 30], second_item!((X, 10u32), (X, 20), (X, 30)));
+/// assert_eq!([10u32, 20, 30], second_item!((X, 10u32), (X, 20), (X, 30),));
+/// assert_eq!([10u32, 20, 30], second_item!(({ X }, 10u32), ({ X }, 20), ({ X }, 30)));
+/// assert_eq!([10u32, 20, 30], second_item!(({ X }, 10u32), ({ X }, 20), ({ X }, 30),));
+/// ```
+#[macro_export]
+macro_rules! second_item {
+    ($(({$($first:tt)*}, $second:expr)),* $(,)?) => { [$($second,)*] };
+    ($(($first:expr, $second:expr)),* $(,)?) => { [$($second,)*] };
+}
+
+/// Defines a new constant [`IdArray`] with a concise syntax.
+///
+/// It is meant to be used by buses and subsystems to create a similar macro with their device id
+/// type already specified, i.e., with fewer parameters to the end user.
+///
+/// # Examples
+///
+// TODO: Exported but not usable by kernel modules (requires `const_trait_impl`).
+/// ```ignore
+/// #![feature(const_trait_impl)]
+/// # use kernel::{define_id_array, driver::RawDeviceId};
+///
+/// #[derive(Copy, Clone)]
+/// struct Id(u32);
+///
+/// // SAFETY: `ZERO` is all zeroes and `to_rawid` stores `offset` as the second element of the raw
+/// // device id pair.
+/// unsafe impl const RawDeviceId for Id {
+///     type RawType = (u64, isize);
+///     const ZERO: Self::RawType = (0, 0);
+///     fn to_rawid(&self, offset: isize) -> Self::RawType {
+///         (self.0 as u64 + 1, offset)
+///     }
+/// }
+///
+/// define_id_array!(A1, Id, (), []);
+/// define_id_array!(A2, Id, &'static [u8], [(Id(10), None)]);
+/// define_id_array!(A3, Id, &'static [u8], [(Id(10), Some(b"id1")), ]);
+/// define_id_array!(A4, Id, &'static [u8], [(Id(10), Some(b"id1")), (Id(20), Some(b"id2"))]);
+/// define_id_array!(A5, Id, &'static [u8], [(Id(10), Some(b"id1")), (Id(20), Some(b"id2")), ]);
+/// define_id_array!(A6, Id, &'static [u8], [(Id(10), None), (Id(20), Some(b"id2")), ]);
+/// define_id_array!(A7, Id, &'static [u8], [(Id(10), Some(b"id1")), (Id(20), None), ]);
+/// define_id_array!(A8, Id, &'static [u8], [(Id(10), None), (Id(20), None), ]);
+/// ```
+#[macro_export]
+macro_rules! define_id_array {
+    ($table_name:ident, $id_type:ty, $data_type:ty, [ $($t:tt)* ]) => {
+        const $table_name:
+            $crate::driver::IdArray<$id_type, $data_type, { $crate::count_paren_items!($($t)*) }> =
+                $crate::driver::IdArray::new(
+                    $crate::first_item!($id_type, $($t)*), $crate::second_item!($($t)*));
+    };
+}
+
+/// Defines a new constant [`IdTable`] with a concise syntax.
+///
+/// It is meant to be used by buses and subsystems to create a similar macro with their device id
+/// type already specified, i.e., with fewer parameters to the end user.
+///
+/// # Examples
+///
+// TODO: Exported but not usable by kernel modules (requires `const_trait_impl`).
+/// ```ignore
+/// #![feature(const_trait_impl)]
+/// # use kernel::{define_id_table, driver::RawDeviceId};
+///
+/// #[derive(Copy, Clone)]
+/// struct Id(u32);
+///
+/// // SAFETY: `ZERO` is all zeroes and `to_rawid` stores `offset` as the second element of the raw
+/// // device id pair.
+/// unsafe impl const RawDeviceId for Id {
+///     type RawType = (u64, isize);
+///     const ZERO: Self::RawType = (0, 0);
+///     fn to_rawid(&self, offset: isize) -> Self::RawType {
+///         (self.0 as u64 + 1, offset)
+///     }
+/// }
+///
+/// define_id_table!(T1, Id, &'static [u8], [(Id(10), None)]);
+/// define_id_table!(T2, Id, &'static [u8], [(Id(10), Some(b"id1")), ]);
+/// define_id_table!(T3, Id, &'static [u8], [(Id(10), Some(b"id1")), (Id(20), Some(b"id2"))]);
+/// define_id_table!(T4, Id, &'static [u8], [(Id(10), Some(b"id1")), (Id(20), Some(b"id2")), ]);
+/// define_id_table!(T5, Id, &'static [u8], [(Id(10), None), (Id(20), Some(b"id2")), ]);
+/// define_id_table!(T6, Id, &'static [u8], [(Id(10), Some(b"id1")), (Id(20), None), ]);
+/// define_id_table!(T7, Id, &'static [u8], [(Id(10), None), (Id(20), None), ]);
+/// ```
+#[macro_export]
+macro_rules! define_id_table {
+    ($table_name:ident, $id_type:ty, $data_type:ty, [ $($t:tt)* ]) => {
+        const $table_name: Option<$crate::driver::IdTable<'static, $id_type, $data_type>> = {
+            $crate::define_id_array!(ARRAY, $id_type, $data_type, [ $($t)* ]);
+            Some(ARRAY.as_table())
+        };
+    };
+}
+
+/// Custom code within device removal.
+pub trait DeviceRemoval {
+    /// Cleans resources up when the device is removed.
+    ///
+    /// This is called when a device is removed and offers implementers the chance to run some code
+    /// that cleans state up.
+    fn device_remove(&self);
+}
+
+impl DeviceRemoval for () {
+    fn device_remove(&self) {}
+}
+
+impl<T: DeviceRemoval> DeviceRemoval for Ref<T> {
+    fn device_remove(&self) {
+        self.deref().device_remove();
+    }
+}
+
+impl<T: DeviceRemoval> DeviceRemoval for Box<T> {
+    fn device_remove(&self) {
+        self.deref().device_remove();
+    }
+}
+
+/// A kernel module that only registers the given driver on init.
+///
+/// This is a helper struct to make it easier to define single-functionality modules, in this case,
+/// modules that offer a single driver.
+pub struct Module<T: DriverOps> {
+    _driver: Pin<Box<Registration<T>>>,
+}
+
+impl<T: DriverOps> crate::Module for Module<T> {
+    fn init(name: &'static CStr, module: &'static ThisModule) -> Result<Self> {
+        Ok(Self {
+            _driver: Registration::new_pinned(name, module)?,
+        })
+    }
+}
+
+/// Declares a kernel module that exposes a single driver.
+///
+/// It is meant to be used as a helper by other subsystems so they can more easily expose their own
+/// macros.
+#[macro_export]
+macro_rules! module_driver {
+    (<$gen_type:ident>, $driver_ops:ty, { type: $type:ty, $($f:tt)* }) => {
+        type Ops<$gen_type> = $driver_ops;
+        type ModuleType = $crate::driver::Module<Ops<$type>>;
+        $crate::prelude::module! {
+            type: ModuleType,
+            $($f)*
+        }
+    }
+}
diff --git a/rust/kernel/error.rs b/rust/kernel/error.rs
new file mode 100644
index 000000000000..f968aa91ddf2
--- /dev/null
+++ b/rust/kernel/error.rs
@@ -0,0 +1,564 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Kernel errors.
+//!
+//! C header: [`include/uapi/asm-generic/errno-base.h`](../../../include/uapi/asm-generic/errno-base.h)
+
+use crate::bindings;
+use crate::str::CStr;
+use alloc::{
+    alloc::{AllocError, LayoutError},
+    collections::TryReserveError,
+};
+use core::convert::From;
+use core::fmt;
+use core::num::TryFromIntError;
+use core::str::{self, Utf8Error};
+
+/// Contains the C-compatible error codes.
+pub mod code {
+    macro_rules! declare_err {
+        ($err:tt $(,)? $($doc:expr),+) => {
+            $(
+            #[doc = $doc]
+            )*
+            pub const $err: super::Error = super::Error(-(crate::bindings::$err as i32));
+        };
+    }
+
+    declare_err!(EPERM, "Operation not permitted.");
+
+    declare_err!(ENOENT, "No such file or directory.");
+
+    declare_err!(ESRCH, "No such process.");
+
+    declare_err!(EINTR, "Interrupted system call.");
+
+    declare_err!(EIO, "I/O error.");
+
+    declare_err!(ENXIO, "No such device or address.");
+
+    declare_err!(E2BIG, "Argument list too long.");
+
+    declare_err!(ENOEXEC, "Exec format error.");
+
+    declare_err!(EBADF, "Bad file number.");
+
+    declare_err!(ECHILD, "Exec format error.");
+
+    declare_err!(EAGAIN, "Try again.");
+
+    declare_err!(ENOMEM, "Out of memory.");
+
+    declare_err!(EACCES, "Permission denied.");
+
+    declare_err!(EFAULT, "Bad address.");
+
+    declare_err!(ENOTBLK, "Block device required.");
+
+    declare_err!(EBUSY, "Device or resource busy.");
+
+    declare_err!(EEXIST, "File exists.");
+
+    declare_err!(EXDEV, "Cross-device link.");
+
+    declare_err!(ENODEV, "No such device.");
+
+    declare_err!(ENOTDIR, "Not a directory.");
+
+    declare_err!(EISDIR, "Is a directory.");
+
+    declare_err!(EINVAL, "Invalid argument.");
+
+    declare_err!(ENFILE, "File table overflow.");
+
+    declare_err!(EMFILE, "Too many open files.");
+
+    declare_err!(ENOTTY, "Not a typewriter.");
+
+    declare_err!(ETXTBSY, "Text file busy.");
+
+    declare_err!(EFBIG, "File too large.");
+
+    declare_err!(ENOSPC, "No space left on device.");
+
+    declare_err!(ESPIPE, "Illegal seek.");
+
+    declare_err!(EROFS, "Read-only file system.");
+
+    declare_err!(EMLINK, "Too many links.");
+
+    declare_err!(EPIPE, "Broken pipe.");
+
+    declare_err!(EDOM, "Math argument out of domain of func.");
+
+    declare_err!(ERANGE, "Math result not representable.");
+
+    declare_err!(EDEADLK, "Resource deadlock would occur");
+
+    declare_err!(ENAMETOOLONG, "File name too long");
+
+    declare_err!(ENOLCK, "No record locks available");
+
+    declare_err!(
+        ENOSYS,
+        "Invalid system call number.",
+        "",
+        "This error code is special: arch syscall entry code will return",
+        "[`ENOSYS`] if users try to call a syscall that doesn't exist.",
+        "To keep failures of syscalls that really do exist distinguishable from",
+        "failures due to attempts to use a nonexistent syscall, syscall",
+        "implementations should refrain from returning [`ENOSYS`]."
+    );
+
+    declare_err!(ENOTEMPTY, "Directory not empty.");
+
+    declare_err!(ELOOP, "Too many symbolic links encountered.");
+
+    declare_err!(EWOULDBLOCK, "Operation would block.");
+
+    declare_err!(ENOMSG, "No message of desired type.");
+
+    declare_err!(EIDRM, "Identifier removed.");
+
+    declare_err!(ECHRNG, "Channel number out of range.");
+
+    declare_err!(EL2NSYNC, "Level 2 not synchronized.");
+
+    declare_err!(EL3HLT, "Level 3 halted.");
+
+    declare_err!(EL3RST, "Level 3 reset.");
+
+    declare_err!(ELNRNG, "Link number out of range.");
+
+    declare_err!(EUNATCH, "Protocol driver not attached.");
+
+    declare_err!(ENOCSI, "No CSI structure available.");
+
+    declare_err!(EL2HLT, "Level 2 halted.");
+
+    declare_err!(EBADE, "Invalid exchange.");
+
+    declare_err!(EBADR, "Invalid request descriptor.");
+
+    declare_err!(EXFULL, "Exchange full.");
+
+    declare_err!(ENOANO, "No anode.");
+
+    declare_err!(EBADRQC, "Invalid request code.");
+
+    declare_err!(EBADSLT, "Invalid slot.");
+
+    declare_err!(EDEADLOCK, "Resource deadlock would occur.");
+
+    declare_err!(EBFONT, "Bad font file format.");
+
+    declare_err!(ENOSTR, "Device not a stream.");
+
+    declare_err!(ENODATA, "No data available.");
+
+    declare_err!(ETIME, "Timer expired.");
+
+    declare_err!(ENOSR, "Out of streams resources.");
+
+    declare_err!(ENONET, "Machine is not on the network.");
+
+    declare_err!(ENOPKG, "Package not installed.");
+
+    declare_err!(EREMOTE, "Object is remote.");
+
+    declare_err!(ENOLINK, "Link has been severed.");
+
+    declare_err!(EADV, "Advertise error.");
+
+    declare_err!(ESRMNT, "Srmount error.");
+
+    declare_err!(ECOMM, "Communication error on send.");
+
+    declare_err!(EPROTO, "Protocol error.");
+
+    declare_err!(EMULTIHOP, "Multihop attempted.");
+
+    declare_err!(EDOTDOT, "RFS specific error.");
+
+    declare_err!(EBADMSG, "Not a data message.");
+
+    declare_err!(EOVERFLOW, "Value too large for defined data type.");
+
+    declare_err!(ENOTUNIQ, "Name not unique on network.");
+
+    declare_err!(EBADFD, "File descriptor in bad state.");
+
+    declare_err!(EREMCHG, "Remote address changed.");
+
+    declare_err!(ELIBACC, "Can not access a needed shared library.");
+
+    declare_err!(ELIBBAD, "Accessing a corrupted shared library.");
+
+    declare_err!(ELIBSCN, ".lib section in a.out corrupted.");
+
+    declare_err!(ELIBMAX, "Attempting to link in too many shared libraries.");
+
+    declare_err!(ELIBEXEC, "Cannot exec a shared library directly.");
+
+    declare_err!(EILSEQ, "Illegal byte sequence.");
+
+    declare_err!(ERESTART, "Interrupted system call should be restarted.");
+
+    declare_err!(ESTRPIPE, "Streams pipe error.");
+
+    declare_err!(EUSERS, "Too many users.");
+
+    declare_err!(ENOTSOCK, "Socket operation on non-socket.");
+
+    declare_err!(EDESTADDRREQ, "Destination address required.");
+
+    declare_err!(EMSGSIZE, "Message too long.");
+
+    declare_err!(EPROTOTYPE, "Protocol wrong type for socket.");
+
+    declare_err!(ENOPROTOOPT, "Protocol not available.");
+
+    declare_err!(EPROTONOSUPPORT, "Protocol not supported.");
+
+    declare_err!(ESOCKTNOSUPPORT, "Socket type not supported.");
+
+    declare_err!(EOPNOTSUPP, "Operation not supported on transport endpoint.");
+
+    declare_err!(EPFNOSUPPORT, "Protocol family not supported.");
+
+    declare_err!(EAFNOSUPPORT, "Address family not supported by protocol.");
+
+    declare_err!(EADDRINUSE, "Address already in use.");
+
+    declare_err!(EADDRNOTAVAIL, "Cannot assign requested address.");
+
+    declare_err!(ENETDOWN, "Network is down.");
+
+    declare_err!(ENETUNREACH, "Network is unreachable.");
+
+    declare_err!(ENETRESET, "Network dropped connection because of reset.");
+
+    declare_err!(ECONNABORTED, "Software caused connection abort.");
+
+    declare_err!(ECONNRESET, "Connection reset by peer.");
+
+    declare_err!(ENOBUFS, "No buffer space available.");
+
+    declare_err!(EISCONN, "Transport endpoint is already connected.");
+
+    declare_err!(ENOTCONN, "Transport endpoint is not connected.");
+
+    declare_err!(ESHUTDOWN, "Cannot send after transport endpoint shutdown.");
+
+    declare_err!(ETOOMANYREFS, "Too many references: cannot splice.");
+
+    declare_err!(ETIMEDOUT, "Connection timed out.");
+
+    declare_err!(ECONNREFUSED, "Connection refused.");
+
+    declare_err!(EHOSTDOWN, "Host is down.");
+
+    declare_err!(EHOSTUNREACH, "No route to host.");
+
+    declare_err!(EALREADY, "Operation already in progress.");
+
+    declare_err!(EINPROGRESS, "Operation now in progress.");
+
+    declare_err!(ESTALE, "Stale file handle.");
+
+    declare_err!(EUCLEAN, "Structure needs cleaning.");
+
+    declare_err!(ENOTNAM, "Not a XENIX named type file.");
+
+    declare_err!(ENAVAIL, "No XENIX semaphores available.");
+
+    declare_err!(EISNAM, "Is a named type file.");
+
+    declare_err!(EREMOTEIO, "Remote I/O error.");
+
+    declare_err!(EDQUOT, "Quota exceeded.");
+
+    declare_err!(ENOMEDIUM, "No medium found.");
+
+    declare_err!(EMEDIUMTYPE, "Wrong medium type.");
+
+    declare_err!(ECANCELED, "Operation Canceled.");
+
+    declare_err!(ENOKEY, "Required key not available.");
+
+    declare_err!(EKEYEXPIRED, "Key has expired.");
+
+    declare_err!(EKEYREVOKED, "Key has been revoked.");
+
+    declare_err!(EKEYREJECTED, "Key was rejected by service.");
+
+    declare_err!(EOWNERDEAD, "Owner died.", "", "For robust mutexes.");
+
+    declare_err!(ENOTRECOVERABLE, "State not recoverable.");
+
+    declare_err!(ERFKILL, "Operation not possible due to RF-kill.");
+
+    declare_err!(EHWPOISON, "Memory page has hardware error.");
+
+    declare_err!(ERESTARTSYS, "Restart the system call.");
+
+    declare_err!(ENOTSUPP, "Operation is not supported.");
+
+    declare_err!(ENOPARAM, "Parameter not supported.");
+}
+
+/// Generic integer kernel error.
+///
+/// The kernel defines a set of integer generic error codes based on C and
+/// POSIX ones. These codes may have a more specific meaning in some contexts.
+///
+/// # Invariants
+///
+/// The value is a valid `errno` (i.e. `>= -MAX_ERRNO && < 0`).
+#[derive(Clone, Copy, PartialEq, Eq)]
+pub struct Error(core::ffi::c_int);
+
+impl Error {
+    /// Creates an [`Error`] from a kernel error code.
+    ///
+    /// It is a bug to pass an out-of-range `errno`. `EINVAL` would
+    /// be returned in such a case.
+    pub(crate) fn from_kernel_errno(errno: core::ffi::c_int) -> Error {
+        if errno < -(bindings::MAX_ERRNO as i32) || errno >= 0 {
+            // TODO: Make it a `WARN_ONCE` once available.
+            crate::pr_warn!(
+                "attempted to create `Error` with out of range `errno`: {}",
+                errno
+            );
+            return code::EINVAL;
+        }
+
+        // INVARIANT: The check above ensures the type invariant
+        // will hold.
+        Error(errno)
+    }
+
+    /// Creates an [`Error`] from a kernel error code.
+    ///
+    /// # Safety
+    ///
+    /// `errno` must be within error code range (i.e. `>= -MAX_ERRNO && < 0`).
+    pub(crate) unsafe fn from_kernel_errno_unchecked(errno: core::ffi::c_int) -> Error {
+        // INVARIANT: The contract ensures the type invariant
+        // will hold.
+        Error(errno)
+    }
+
+    /// Returns the kernel error code.
+    pub fn to_kernel_errno(self) -> core::ffi::c_int {
+        self.0
+    }
+
+    /// Returns a string representing the error, if one exists.
+    #[cfg(not(testlib))]
+    pub fn name(&self) -> Option<&'static CStr> {
+        // SAFETY: Just an FFI call, there are no extra safety requirements.
+        let ptr = unsafe { bindings::errname(-self.0) };
+        if ptr.is_null() {
+            None
+        } else {
+            // SAFETY: The string returned by `errname` is static and `NUL`-terminated.
+            Some(unsafe { CStr::from_char_ptr(ptr) })
+        }
+    }
+
+    /// Returns a string representing the error, if one exists.
+    ///
+    /// When `testlib` is configured, this always returns `None` to avoid the dependency on a
+    /// kernel function so that tests that use this (e.g., by calling [`Result::unwrap`]) can still
+    /// run in userspace.
+    #[cfg(testlib)]
+    pub fn name(&self) -> Option<&'static CStr> {
+        None
+    }
+}
+
+impl fmt::Debug for Error {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match self.name() {
+            // Print out number if no name can be found.
+            None => f.debug_tuple("Error").field(&-self.0).finish(),
+            // SAFETY: These strings are ASCII-only.
+            Some(name) => f
+                .debug_tuple(unsafe { str::from_utf8_unchecked(name) })
+                .finish(),
+        }
+    }
+}
+
+impl From<TryFromIntError> for Error {
+    fn from(_: TryFromIntError) -> Error {
+        code::EINVAL
+    }
+}
+
+impl From<Utf8Error> for Error {
+    fn from(_: Utf8Error) -> Error {
+        code::EINVAL
+    }
+}
+
+impl From<TryReserveError> for Error {
+    fn from(_: TryReserveError) -> Error {
+        code::ENOMEM
+    }
+}
+
+impl From<LayoutError> for Error {
+    fn from(_: LayoutError) -> Error {
+        code::ENOMEM
+    }
+}
+
+impl From<core::fmt::Error> for Error {
+    fn from(_: core::fmt::Error) -> Error {
+        code::EINVAL
+    }
+}
+
+impl From<core::convert::Infallible> for Error {
+    fn from(e: core::convert::Infallible) -> Error {
+        match e {}
+    }
+}
+
+/// A [`Result`] with an [`Error`] error type.
+///
+/// To be used as the return type for functions that may fail.
+///
+/// # Error codes in C and Rust
+///
+/// In C, it is common that functions indicate success or failure through
+/// their return value; modifying or returning extra data through non-`const`
+/// pointer parameters. In particular, in the kernel, functions that may fail
+/// typically return an `int` that represents a generic error code. We model
+/// those as [`Error`].
+///
+/// In Rust, it is idiomatic to model functions that may fail as returning
+/// a [`Result`]. Since in the kernel many functions return an error code,
+/// [`Result`] is a type alias for a [`core::result::Result`] that uses
+/// [`Error`] as its error type.
+///
+/// Note that even if a function does not return anything when it succeeds,
+/// it should still be modeled as returning a `Result` rather than
+/// just an [`Error`].
+pub type Result<T = ()> = core::result::Result<T, Error>;
+
+impl From<AllocError> for Error {
+    fn from(_: AllocError) -> Error {
+        code::ENOMEM
+    }
+}
+
+// # Invariant: `-bindings::MAX_ERRNO` fits in an `i16`.
+crate::static_assert!(bindings::MAX_ERRNO <= -(i16::MIN as i32) as u32);
+
+pub(crate) fn from_kernel_result_helper<T>(r: Result<T>) -> T
+where
+    T: From<i16>,
+{
+    match r {
+        Ok(v) => v,
+        // NO-OVERFLOW: negative `errno`s are no smaller than `-bindings::MAX_ERRNO`,
+        // `-bindings::MAX_ERRNO` fits in an `i16` as per invariant above,
+        // therefore a negative `errno` always fits in an `i16` and will not overflow.
+        Err(e) => T::from(e.to_kernel_errno() as i16),
+    }
+}
+
+/// Transforms a [`crate::error::Result<T>`] to a kernel C integer result.
+///
+/// This is useful when calling Rust functions that return [`crate::error::Result<T>`]
+/// from inside `extern "C"` functions that need to return an integer
+/// error result.
+///
+/// `T` should be convertible to an `i16` via `From<i16>`.
+///
+/// # Examples
+///
+/// ```ignore
+/// # use kernel::from_kernel_result;
+/// # use kernel::bindings;
+/// unsafe extern "C" fn probe_callback(
+///     pdev: *mut bindings::platform_device,
+/// ) -> core::ffi::c_int {
+///     from_kernel_result! {
+///         let ptr = devm_alloc(pdev)?;
+///         bindings::platform_set_drvdata(pdev, ptr);
+///         Ok(0)
+///     }
+/// }
+/// ```
+macro_rules! from_kernel_result {
+    ($($tt:tt)*) => {{
+        $crate::error::from_kernel_result_helper((|| {
+            $($tt)*
+        })())
+    }};
+}
+
+pub(crate) use from_kernel_result;
+
+/// Transform a kernel "error pointer" to a normal pointer.
+///
+/// Some kernel C API functions return an "error pointer" which optionally
+/// embeds an `errno`. Callers are supposed to check the returned pointer
+/// for errors. This function performs the check and converts the "error pointer"
+/// to a normal pointer in an idiomatic fashion.
+///
+/// # Examples
+///
+/// ```ignore
+/// # use kernel::from_kernel_err_ptr;
+/// # use kernel::bindings;
+/// fn devm_platform_ioremap_resource(
+///     pdev: &mut PlatformDevice,
+///     index: u32,
+/// ) -> Result<*mut core::ffi::c_void> {
+///     // SAFETY: FFI call.
+///     unsafe {
+///         from_kernel_err_ptr(bindings::devm_platform_ioremap_resource(
+///             pdev.to_ptr(),
+///             index,
+///         ))
+///     }
+/// }
+/// ```
+// TODO: Remove `dead_code` marker once an in-kernel client is available.
+#[allow(dead_code)]
+pub(crate) fn from_kernel_err_ptr<T>(ptr: *mut T) -> Result<*mut T> {
+    // CAST: Casting a pointer to `*const core::ffi::c_void` is always valid.
+    let const_ptr: *const core::ffi::c_void = ptr.cast();
+    // SAFETY: The FFI function does not deref the pointer.
+    if unsafe { bindings::IS_ERR(const_ptr) } {
+        // SAFETY: The FFI function does not deref the pointer.
+        let err = unsafe { bindings::PTR_ERR(const_ptr) };
+        // CAST: If `IS_ERR()` returns `true`,
+        // then `PTR_ERR()` is guaranteed to return a
+        // negative value greater-or-equal to `-bindings::MAX_ERRNO`,
+        // which always fits in an `i16`, as per the invariant above.
+        // And an `i16` always fits in an `i32`. So casting `err` to
+        // an `i32` can never overflow, and is always valid.
+        //
+        // SAFETY: `IS_ERR()` ensures `err` is a
+        // negative value greater-or-equal to `-bindings::MAX_ERRNO`.
+        return Err(unsafe { Error::from_kernel_errno_unchecked(err as i32) });
+    }
+    Ok(ptr)
+}
+
+/// Converts an integer as returned by a C kernel function to an error if it's negative, and
+/// `Ok(())` otherwise.
+pub fn to_result(err: core::ffi::c_int) -> Result {
+    if err < 0 {
+        Err(Error::from_kernel_errno(err))
+    } else {
+        Ok(())
+    }
+}
diff --git a/rust/kernel/file.rs b/rust/kernel/file.rs
new file mode 100644
index 000000000000..62538e6b3eea
--- /dev/null
+++ b/rust/kernel/file.rs
@@ -0,0 +1,887 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Files and file descriptors.
+//!
+//! C headers: [`include/linux/fs.h`](../../../../include/linux/fs.h) and
+//! [`include/linux/file.h`](../../../../include/linux/file.h)
+
+use crate::{
+    bindings,
+    cred::Credential,
+    error::{code::*, from_kernel_result, Error, Result},
+    io_buffer::{IoBufferReader, IoBufferWriter},
+    iov_iter::IovIter,
+    mm,
+    sync::CondVar,
+    types::PointerWrapper,
+    user_ptr::{UserSlicePtr, UserSlicePtrReader, UserSlicePtrWriter},
+    ARef, AlwaysRefCounted,
+};
+use core::convert::{TryFrom, TryInto};
+use core::{cell::UnsafeCell, marker, mem, ptr};
+use macros::vtable;
+
+/// Flags associated with a [`File`].
+pub mod flags {
+    /// File is opened in append mode.
+    pub const O_APPEND: u32 = bindings::O_APPEND;
+
+    /// Signal-driven I/O is enabled.
+    pub const O_ASYNC: u32 = bindings::FASYNC;
+
+    /// Close-on-exec flag is set.
+    pub const O_CLOEXEC: u32 = bindings::O_CLOEXEC;
+
+    /// File was created if it didn't already exist.
+    pub const O_CREAT: u32 = bindings::O_CREAT;
+
+    /// Direct I/O is enabled for this file.
+    pub const O_DIRECT: u32 = bindings::O_DIRECT;
+
+    /// File must be a directory.
+    pub const O_DIRECTORY: u32 = bindings::O_DIRECTORY;
+
+    /// Like [`O_SYNC`] except metadata is not synced.
+    pub const O_DSYNC: u32 = bindings::O_DSYNC;
+
+    /// Ensure that this file is created with the `open(2)` call.
+    pub const O_EXCL: u32 = bindings::O_EXCL;
+
+    /// Large file size enabled (`off64_t` over `off_t`).
+    pub const O_LARGEFILE: u32 = bindings::O_LARGEFILE;
+
+    /// Do not update the file last access time.
+    pub const O_NOATIME: u32 = bindings::O_NOATIME;
+
+    /// File should not be used as process's controlling terminal.
+    pub const O_NOCTTY: u32 = bindings::O_NOCTTY;
+
+    /// If basename of path is a symbolic link, fail open.
+    pub const O_NOFOLLOW: u32 = bindings::O_NOFOLLOW;
+
+    /// File is using nonblocking I/O.
+    pub const O_NONBLOCK: u32 = bindings::O_NONBLOCK;
+
+    /// Also known as `O_NDELAY`.
+    ///
+    /// This is effectively the same flag as [`O_NONBLOCK`] on all architectures
+    /// except SPARC64.
+    pub const O_NDELAY: u32 = bindings::O_NDELAY;
+
+    /// Used to obtain a path file descriptor.
+    pub const O_PATH: u32 = bindings::O_PATH;
+
+    /// Write operations on this file will flush data and metadata.
+    pub const O_SYNC: u32 = bindings::O_SYNC;
+
+    /// This file is an unnamed temporary regular file.
+    pub const O_TMPFILE: u32 = bindings::O_TMPFILE;
+
+    /// File should be truncated to length 0.
+    pub const O_TRUNC: u32 = bindings::O_TRUNC;
+
+    /// Bitmask for access mode flags.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use kernel::file;
+    /// # fn do_something() {}
+    /// # let flags = 0;
+    /// if (flags & file::flags::O_ACCMODE) == file::flags::O_RDONLY {
+    ///     do_something();
+    /// }
+    /// ```
+    pub const O_ACCMODE: u32 = bindings::O_ACCMODE;
+
+    /// File is read only.
+    pub const O_RDONLY: u32 = bindings::O_RDONLY;
+
+    /// File is write only.
+    pub const O_WRONLY: u32 = bindings::O_WRONLY;
+
+    /// File can be both read and written.
+    pub const O_RDWR: u32 = bindings::O_RDWR;
+}
+
+/// Wraps the kernel's `struct file`.
+///
+/// # Invariants
+///
+/// Instances of this type are always ref-counted, that is, a call to `get_file` ensures that the
+/// allocation remains valid at least until the matching call to `fput`.
+#[repr(transparent)]
+pub struct File(pub(crate) UnsafeCell<bindings::file>);
+
+// TODO: Accessing fields of `struct file` through the pointer is UB because other threads may be
+// writing to them. However, this is how the C code currently operates: naked reads and writes to
+// fields. Even if we used relaxed atomics on the Rust side, we can't force this on the C side.
+impl File {
+    /// Constructs a new [`struct file`] wrapper from a file descriptor.
+    ///
+    /// The file descriptor belongs to the current process.
+    pub fn from_fd(fd: u32) -> Result<ARef<Self>> {
+        // SAFETY: FFI call, there are no requirements on `fd`.
+        let ptr = ptr::NonNull::new(unsafe { bindings::fget(fd) }).ok_or(EBADF)?;
+
+        // SAFETY: `fget` increments the refcount before returning.
+        Ok(unsafe { ARef::from_raw(ptr.cast()) })
+    }
+
+    /// Creates a reference to a [`File`] from a valid pointer.
+    ///
+    /// # Safety
+    ///
+    /// The caller must ensure that `ptr` is valid and remains valid for the lifetime of the
+    /// returned [`File`] instance.
+    pub(crate) unsafe fn from_ptr<'a>(ptr: *const bindings::file) -> &'a File {
+        // SAFETY: The safety requirements guarantee the validity of the dereference, while the
+        // `File` type being transparent makes the cast ok.
+        unsafe { &*ptr.cast() }
+    }
+
+    /// Returns the current seek/cursor/pointer position (`struct file::f_pos`).
+    pub fn pos(&self) -> u64 {
+        // SAFETY: The file is valid because the shared reference guarantees a nonzero refcount.
+        unsafe { core::ptr::addr_of!((*self.0.get()).f_pos).read() as _ }
+    }
+
+    /// Returns the credentials of the task that originally opened the file.
+    pub fn cred(&self) -> &Credential {
+        // SAFETY: The file is valid because the shared reference guarantees a nonzero refcount.
+        let ptr = unsafe { core::ptr::addr_of!((*self.0.get()).f_cred).read() };
+        // SAFETY: The lifetimes of `self` and `Credential` are tied, so it is guaranteed that
+        // the credential pointer remains valid (because the file is still alive, and it doesn't
+        // change over the lifetime of a file).
+        unsafe { Credential::from_ptr(ptr) }
+    }
+
+    /// Returns the flags associated with the file.
+    ///
+    /// The flags are a combination of the constants in [`flags`].
+    pub fn flags(&self) -> u32 {
+        // SAFETY: The file is valid because the shared reference guarantees a nonzero refcount.
+        unsafe { core::ptr::addr_of!((*self.0.get()).f_flags).read() }
+    }
+}
+
+// SAFETY: The type invariants guarantee that `File` is always ref-counted.
+unsafe impl AlwaysRefCounted for File {
+    fn inc_ref(&self) {
+        // SAFETY: The existence of a shared reference means that the refcount is nonzero.
+        unsafe { bindings::get_file(self.0.get()) };
+    }
+
+    unsafe fn dec_ref(obj: ptr::NonNull<Self>) {
+        // SAFETY: The safety requirements guarantee that the refcount is nonzero.
+        unsafe { bindings::fput(obj.cast().as_ptr()) }
+    }
+}
+
+/// A file descriptor reservation.
+///
+/// This allows the creation of a file descriptor in two steps: first, we reserve a slot for it,
+/// then we commit or drop the reservation. The first step may fail (e.g., the current process ran
+/// out of available slots), but commit and drop never fail (and are mutually exclusive).
+pub struct FileDescriptorReservation {
+    fd: u32,
+}
+
+impl FileDescriptorReservation {
+    /// Creates a new file descriptor reservation.
+    pub fn new(flags: u32) -> Result<Self> {
+        // SAFETY: FFI call, there are no safety requirements on `flags`.
+        let fd = unsafe { bindings::get_unused_fd_flags(flags) };
+        if fd < 0 {
+            return Err(Error::from_kernel_errno(fd));
+        }
+        Ok(Self { fd: fd as _ })
+    }
+
+    /// Returns the file descriptor number that was reserved.
+    pub fn reserved_fd(&self) -> u32 {
+        self.fd
+    }
+
+    /// Commits the reservation.
+    ///
+    /// The previously reserved file descriptor is bound to `file`.
+    pub fn commit(self, file: ARef<File>) {
+        // SAFETY: `self.fd` was previously returned by `get_unused_fd_flags`, and `file.ptr` is
+        // guaranteed to have an owned ref count by its type invariants.
+        unsafe { bindings::fd_install(self.fd, file.0.get()) };
+
+        // `fd_install` consumes both the file descriptor and the file reference, so we cannot run
+        // the destructors.
+        core::mem::forget(self);
+        core::mem::forget(file);
+    }
+}
+
+impl Drop for FileDescriptorReservation {
+    fn drop(&mut self) {
+        // SAFETY: `self.fd` was returned by a previous call to `get_unused_fd_flags`.
+        unsafe { bindings::put_unused_fd(self.fd) };
+    }
+}
+
+/// Wraps the kernel's `struct poll_table_struct`.
+///
+/// # Invariants
+///
+/// The pointer `PollTable::ptr` is null or valid.
+pub struct PollTable {
+    ptr: *mut bindings::poll_table_struct,
+}
+
+impl PollTable {
+    /// Constructors a new `struct poll_table_struct` wrapper.
+    ///
+    /// # Safety
+    ///
+    /// The pointer `ptr` must be either null or a valid pointer for the lifetime of the object.
+    unsafe fn from_ptr(ptr: *mut bindings::poll_table_struct) -> Self {
+        Self { ptr }
+    }
+
+    /// Associates the given file and condition variable to this poll table. It means notifying the
+    /// condition variable will notify the poll table as well; additionally, the association
+    /// between the condition variable and the file will automatically be undone by the kernel when
+    /// the file is destructed. To unilaterally remove the association before then, one can call
+    /// [`CondVar::free_waiters`].
+    ///
+    /// # Safety
+    ///
+    /// If the condition variable is destroyed before the file, then [`CondVar::free_waiters`] must
+    /// be called to ensure that all waiters are flushed out.
+    pub unsafe fn register_wait<'a>(&self, file: &'a File, cv: &'a CondVar) {
+        if self.ptr.is_null() {
+            return;
+        }
+
+        // SAFETY: `PollTable::ptr` is guaranteed to be valid by the type invariants and the null
+        // check above.
+        let table = unsafe { &*self.ptr };
+        if let Some(proc) = table._qproc {
+            // SAFETY: All pointers are known to be valid.
+            unsafe { proc(file.0.get() as _, cv.wait_list.get(), self.ptr) }
+        }
+    }
+}
+
+/// Equivalent to [`std::io::SeekFrom`].
+///
+/// [`std::io::SeekFrom`]: https://doc.rust-lang.org/std/io/enum.SeekFrom.html
+pub enum SeekFrom {
+    /// Equivalent to C's `SEEK_SET`.
+    Start(u64),
+
+    /// Equivalent to C's `SEEK_END`.
+    End(i64),
+
+    /// Equivalent to C's `SEEK_CUR`.
+    Current(i64),
+}
+
+pub(crate) struct OperationsVtable<A, T>(marker::PhantomData<A>, marker::PhantomData<T>);
+
+impl<A: OpenAdapter<T::OpenData>, T: Operations> OperationsVtable<A, T> {
+    /// Called by the VFS when an inode should be opened.
+    ///
+    /// Calls `T::open` on the returned value of `A::convert`.
+    ///
+    /// # Safety
+    ///
+    /// The returned value of `A::convert` must be a valid non-null pointer and
+    /// `T:open` must return a valid non-null pointer on an `Ok` result.
+    unsafe extern "C" fn open_callback(
+        inode: *mut bindings::inode,
+        file: *mut bindings::file,
+    ) -> core::ffi::c_int {
+        from_kernel_result! {
+            // SAFETY: `A::convert` must return a valid non-null pointer that
+            // should point to data in the inode or file that lives longer
+            // than the following use of `T::open`.
+            let arg = unsafe { A::convert(inode, file) };
+            // SAFETY: The C contract guarantees that `file` is valid. Additionally,
+            // `fileref` never outlives this function, so it is guaranteed to be
+            // valid.
+            let fileref = unsafe { File::from_ptr(file) };
+            // SAFETY: `arg` was previously returned by `A::convert` and must
+            // be a valid non-null pointer.
+            let ptr = T::open(unsafe { &*arg }, fileref)?.into_pointer();
+            // SAFETY: The C contract guarantees that `private_data` is available
+            // for implementers of the file operations (no other C code accesses
+            // it), so we know that there are no concurrent threads/CPUs accessing
+            // it (it's not visible to any other Rust code).
+            unsafe { (*file).private_data = ptr as *mut core::ffi::c_void };
+            Ok(0)
+        }
+    }
+
+    unsafe extern "C" fn read_callback(
+        file: *mut bindings::file,
+        buf: *mut core::ffi::c_char,
+        len: core::ffi::c_size_t,
+        offset: *mut bindings::loff_t,
+    ) -> core::ffi::c_ssize_t {
+        from_kernel_result! {
+            let mut data =
+                unsafe { UserSlicePtr::new(buf as *mut core::ffi::c_void, len).writer() };
+            // SAFETY: `private_data` was initialised by `open_callback` with a value returned by
+            // `T::Data::into_pointer`. `T::Data::from_pointer` is only called by the
+            // `release` callback, which the C API guarantees that will be called only when all
+            // references to `file` have been released, so we know it can't be called while this
+            // function is running.
+            let f = unsafe { T::Data::borrow((*file).private_data) };
+            // No `FMODE_UNSIGNED_OFFSET` support, so `offset` must be in [0, 2^63).
+            // See <https://github.com/fishinabarrel/linux-kernel-module-rust/pull/113>.
+            let read = T::read(
+                f,
+                unsafe { File::from_ptr(file) },
+                &mut data,
+                unsafe { *offset }.try_into()?,
+            )?;
+            unsafe { (*offset) += bindings::loff_t::try_from(read).unwrap() };
+            Ok(read as _)
+        }
+    }
+
+    unsafe extern "C" fn read_iter_callback(
+        iocb: *mut bindings::kiocb,
+        raw_iter: *mut bindings::iov_iter,
+    ) -> isize {
+        from_kernel_result! {
+            let mut iter = unsafe { IovIter::from_ptr(raw_iter) };
+            let file = unsafe { (*iocb).ki_filp };
+            let offset = unsafe { (*iocb).ki_pos };
+            // SAFETY: `private_data` was initialised by `open_callback` with a value returned by
+            // `T::Data::into_pointer`. `T::Data::from_pointer` is only called by the
+            // `release` callback, which the C API guarantees that will be called only when all
+            // references to `file` have been released, so we know it can't be called while this
+            // function is running.
+            let f = unsafe { T::Data::borrow((*file).private_data) };
+            let read = T::read(
+                f,
+                unsafe { File::from_ptr(file) },
+                &mut iter,
+                offset.try_into()?,
+            )?;
+            unsafe { (*iocb).ki_pos += bindings::loff_t::try_from(read).unwrap() };
+            Ok(read as _)
+        }
+    }
+
+    unsafe extern "C" fn write_callback(
+        file: *mut bindings::file,
+        buf: *const core::ffi::c_char,
+        len: core::ffi::c_size_t,
+        offset: *mut bindings::loff_t,
+    ) -> core::ffi::c_ssize_t {
+        from_kernel_result! {
+            let mut data =
+                unsafe { UserSlicePtr::new(buf as *mut core::ffi::c_void, len).reader() };
+            // SAFETY: `private_data` was initialised by `open_callback` with a value returned by
+            // `T::Data::into_pointer`. `T::Data::from_pointer` is only called by the
+            // `release` callback, which the C API guarantees that will be called only when all
+            // references to `file` have been released, so we know it can't be called while this
+            // function is running.
+            let f = unsafe { T::Data::borrow((*file).private_data) };
+            // No `FMODE_UNSIGNED_OFFSET` support, so `offset` must be in [0, 2^63).
+            // See <https://github.com/fishinabarrel/linux-kernel-module-rust/pull/113>.
+            let written = T::write(
+                f,
+                unsafe { File::from_ptr(file) },
+                &mut data,
+                unsafe { *offset }.try_into()?,
+            )?;
+            unsafe { (*offset) += bindings::loff_t::try_from(written).unwrap() };
+            Ok(written as _)
+        }
+    }
+
+    unsafe extern "C" fn write_iter_callback(
+        iocb: *mut bindings::kiocb,
+        raw_iter: *mut bindings::iov_iter,
+    ) -> isize {
+        from_kernel_result! {
+            let mut iter = unsafe { IovIter::from_ptr(raw_iter) };
+            let file = unsafe { (*iocb).ki_filp };
+            let offset = unsafe { (*iocb).ki_pos };
+            // SAFETY: `private_data` was initialised by `open_callback` with a value returned by
+            // `T::Data::into_pointer`. `T::Data::from_pointer` is only called by the
+            // `release` callback, which the C API guarantees that will be called only when all
+            // references to `file` have been released, so we know it can't be called while this
+            // function is running.
+            let f = unsafe { T::Data::borrow((*file).private_data) };
+            let written = T::write(
+                f,
+                unsafe { File::from_ptr(file) },
+                &mut iter,
+                offset.try_into()?,
+            )?;
+            unsafe { (*iocb).ki_pos += bindings::loff_t::try_from(written).unwrap() };
+            Ok(written as _)
+        }
+    }
+
+    unsafe extern "C" fn release_callback(
+        _inode: *mut bindings::inode,
+        file: *mut bindings::file,
+    ) -> core::ffi::c_int {
+        let ptr = mem::replace(unsafe { &mut (*file).private_data }, ptr::null_mut());
+        T::release(unsafe { T::Data::from_pointer(ptr as _) }, unsafe {
+            File::from_ptr(file)
+        });
+        0
+    }
+
+    unsafe extern "C" fn llseek_callback(
+        file: *mut bindings::file,
+        offset: bindings::loff_t,
+        whence: core::ffi::c_int,
+    ) -> bindings::loff_t {
+        from_kernel_result! {
+            let off = match whence as u32 {
+                bindings::SEEK_SET => SeekFrom::Start(offset.try_into()?),
+                bindings::SEEK_CUR => SeekFrom::Current(offset),
+                bindings::SEEK_END => SeekFrom::End(offset),
+                _ => return Err(EINVAL),
+            };
+            // SAFETY: `private_data` was initialised by `open_callback` with a value returned by
+            // `T::Data::into_pointer`. `T::Data::from_pointer` is only called by the
+            // `release` callback, which the C API guarantees that will be called only when all
+            // references to `file` have been released, so we know it can't be called while this
+            // function is running.
+            let f = unsafe { T::Data::borrow((*file).private_data) };
+            let off = T::seek(f, unsafe { File::from_ptr(file) }, off)?;
+            Ok(off as bindings::loff_t)
+        }
+    }
+
+    unsafe extern "C" fn unlocked_ioctl_callback(
+        file: *mut bindings::file,
+        cmd: core::ffi::c_uint,
+        arg: core::ffi::c_ulong,
+    ) -> core::ffi::c_long {
+        from_kernel_result! {
+            // SAFETY: `private_data` was initialised by `open_callback` with a value returned by
+            // `T::Data::into_pointer`. `T::Data::from_pointer` is only called by the
+            // `release` callback, which the C API guarantees that will be called only when all
+            // references to `file` have been released, so we know it can't be called while this
+            // function is running.
+            let f = unsafe { T::Data::borrow((*file).private_data) };
+            let mut cmd = IoctlCommand::new(cmd as _, arg as _);
+            let ret = T::ioctl(f, unsafe { File::from_ptr(file) }, &mut cmd)?;
+            Ok(ret as _)
+        }
+    }
+
+    unsafe extern "C" fn compat_ioctl_callback(
+        file: *mut bindings::file,
+        cmd: core::ffi::c_uint,
+        arg: core::ffi::c_ulong,
+    ) -> core::ffi::c_long {
+        from_kernel_result! {
+            // SAFETY: `private_data` was initialised by `open_callback` with a value returned by
+            // `T::Data::into_pointer`. `T::Data::from_pointer` is only called by the
+            // `release` callback, which the C API guarantees that will be called only when all
+            // references to `file` have been released, so we know it can't be called while this
+            // function is running.
+            let f = unsafe { T::Data::borrow((*file).private_data) };
+            let mut cmd = IoctlCommand::new(cmd as _, arg as _);
+            let ret = T::compat_ioctl(f, unsafe { File::from_ptr(file) }, &mut cmd)?;
+            Ok(ret as _)
+        }
+    }
+
+    unsafe extern "C" fn mmap_callback(
+        file: *mut bindings::file,
+        vma: *mut bindings::vm_area_struct,
+    ) -> core::ffi::c_int {
+        from_kernel_result! {
+            // SAFETY: `private_data` was initialised by `open_callback` with a value returned by
+            // `T::Data::into_pointer`. `T::Data::from_pointer` is only called by the
+            // `release` callback, which the C API guarantees that will be called only when all
+            // references to `file` have been released, so we know it can't be called while this
+            // function is running.
+            let f = unsafe { T::Data::borrow((*file).private_data) };
+
+            // SAFETY: The C API guarantees that `vma` is valid for the duration of this call.
+            // `area` only lives within this call, so it is guaranteed to be valid.
+            let mut area = unsafe { mm::virt::Area::from_ptr(vma) };
+
+            // SAFETY: The C API guarantees that `file` is valid for the duration of this call,
+            // which is longer than the lifetime of the file reference.
+            T::mmap(f, unsafe { File::from_ptr(file) }, &mut area)?;
+            Ok(0)
+        }
+    }
+
+    unsafe extern "C" fn fsync_callback(
+        file: *mut bindings::file,
+        start: bindings::loff_t,
+        end: bindings::loff_t,
+        datasync: core::ffi::c_int,
+    ) -> core::ffi::c_int {
+        from_kernel_result! {
+            let start = start.try_into()?;
+            let end = end.try_into()?;
+            let datasync = datasync != 0;
+            // SAFETY: `private_data` was initialised by `open_callback` with a value returned by
+            // `T::Data::into_pointer`. `T::Data::from_pointer` is only called by the
+            // `release` callback, which the C API guarantees that will be called only when all
+            // references to `file` have been released, so we know it can't be called while this
+            // function is running.
+            let f = unsafe { T::Data::borrow((*file).private_data) };
+            let res = T::fsync(f, unsafe { File::from_ptr(file) }, start, end, datasync)?;
+            Ok(res.try_into().unwrap())
+        }
+    }
+
+    unsafe extern "C" fn poll_callback(
+        file: *mut bindings::file,
+        wait: *mut bindings::poll_table_struct,
+    ) -> bindings::__poll_t {
+        // SAFETY: `private_data` was initialised by `open_callback` with a value returned by
+        // `T::Data::into_pointer`. `T::Data::from_pointer` is only called by the `release`
+        // callback, which the C API guarantees that will be called only when all references to
+        // `file` have been released, so we know it can't be called while this function is running.
+        let f = unsafe { T::Data::borrow((*file).private_data) };
+        match T::poll(f, unsafe { File::from_ptr(file) }, unsafe {
+            &PollTable::from_ptr(wait)
+        }) {
+            Ok(v) => v,
+            Err(_) => bindings::POLLERR,
+        }
+    }
+
+    const VTABLE: bindings::file_operations = bindings::file_operations {
+        open: Some(Self::open_callback),
+        release: Some(Self::release_callback),
+        read: if T::HAS_READ {
+            Some(Self::read_callback)
+        } else {
+            None
+        },
+        write: if T::HAS_WRITE {
+            Some(Self::write_callback)
+        } else {
+            None
+        },
+        llseek: if T::HAS_SEEK {
+            Some(Self::llseek_callback)
+        } else {
+            None
+        },
+
+        check_flags: None,
+        compat_ioctl: if T::HAS_COMPAT_IOCTL {
+            Some(Self::compat_ioctl_callback)
+        } else {
+            None
+        },
+        copy_file_range: None,
+        fallocate: None,
+        fadvise: None,
+        fasync: None,
+        flock: None,
+        flush: None,
+        fsync: if T::HAS_FSYNC {
+            Some(Self::fsync_callback)
+        } else {
+            None
+        },
+        get_unmapped_area: None,
+        iterate: None,
+        iterate_shared: None,
+        iopoll: None,
+        lock: None,
+        mmap: if T::HAS_MMAP {
+            Some(Self::mmap_callback)
+        } else {
+            None
+        },
+        mmap_supported_flags: 0,
+        owner: ptr::null_mut(),
+        poll: if T::HAS_POLL {
+            Some(Self::poll_callback)
+        } else {
+            None
+        },
+        read_iter: if T::HAS_READ {
+            Some(Self::read_iter_callback)
+        } else {
+            None
+        },
+        remap_file_range: None,
+        sendpage: None,
+        setlease: None,
+        show_fdinfo: None,
+        splice_read: None,
+        splice_write: None,
+        unlocked_ioctl: if T::HAS_IOCTL {
+            Some(Self::unlocked_ioctl_callback)
+        } else {
+            None
+        },
+        uring_cmd: None,
+        write_iter: if T::HAS_WRITE {
+            Some(Self::write_iter_callback)
+        } else {
+            None
+        },
+    };
+
+    /// Builds an instance of [`struct file_operations`].
+    ///
+    /// # Safety
+    ///
+    /// The caller must ensure that the adapter is compatible with the way the device is registered.
+    pub(crate) const unsafe fn build() -> &'static bindings::file_operations {
+        &Self::VTABLE
+    }
+}
+
+/// Allows the handling of ioctls defined with the `_IO`, `_IOR`, `_IOW`, and `_IOWR` macros.
+///
+/// For each macro, there is a handler function that takes the appropriate types as arguments.
+pub trait IoctlHandler: Sync {
+    /// The type of the first argument to each associated function.
+    type Target<'a>;
+
+    /// Handles ioctls defined with the `_IO` macro, that is, with no buffer as argument.
+    fn pure(_this: Self::Target<'_>, _file: &File, _cmd: u32, _arg: usize) -> Result<i32> {
+        Err(EINVAL)
+    }
+
+    /// Handles ioctls defined with the `_IOR` macro, that is, with an output buffer provided as
+    /// argument.
+    fn read(
+        _this: Self::Target<'_>,
+        _file: &File,
+        _cmd: u32,
+        _writer: &mut UserSlicePtrWriter,
+    ) -> Result<i32> {
+        Err(EINVAL)
+    }
+
+    /// Handles ioctls defined with the `_IOW` macro, that is, with an input buffer provided as
+    /// argument.
+    fn write(
+        _this: Self::Target<'_>,
+        _file: &File,
+        _cmd: u32,
+        _reader: &mut UserSlicePtrReader,
+    ) -> Result<i32> {
+        Err(EINVAL)
+    }
+
+    /// Handles ioctls defined with the `_IOWR` macro, that is, with a buffer for both input and
+    /// output provided as argument.
+    fn read_write(
+        _this: Self::Target<'_>,
+        _file: &File,
+        _cmd: u32,
+        _data: UserSlicePtr,
+    ) -> Result<i32> {
+        Err(EINVAL)
+    }
+}
+
+/// Represents an ioctl command.
+///
+/// It can use the components of an ioctl command to dispatch ioctls using
+/// [`IoctlCommand::dispatch`].
+pub struct IoctlCommand {
+    cmd: u32,
+    arg: usize,
+    user_slice: Option<UserSlicePtr>,
+}
+
+impl IoctlCommand {
+    /// Constructs a new [`IoctlCommand`].
+    fn new(cmd: u32, arg: usize) -> Self {
+        let size = (cmd >> bindings::_IOC_SIZESHIFT) & bindings::_IOC_SIZEMASK;
+
+        // SAFETY: We only create one instance of the user slice per ioctl call, so TOCTOU issues
+        // are not possible.
+        let user_slice = Some(unsafe { UserSlicePtr::new(arg as _, size as _) });
+        Self {
+            cmd,
+            arg,
+            user_slice,
+        }
+    }
+
+    /// Dispatches the given ioctl to the appropriate handler based on the value of the command. It
+    /// also creates a [`UserSlicePtr`], [`UserSlicePtrReader`], or [`UserSlicePtrWriter`]
+    /// depending on the direction of the buffer of the command.
+    ///
+    /// It is meant to be used in implementations of [`Operations::ioctl`] and
+    /// [`Operations::compat_ioctl`].
+    pub fn dispatch<T: IoctlHandler>(
+        &mut self,
+        handler: T::Target<'_>,
+        file: &File,
+    ) -> Result<i32> {
+        let dir = (self.cmd >> bindings::_IOC_DIRSHIFT) & bindings::_IOC_DIRMASK;
+        if dir == bindings::_IOC_NONE {
+            return T::pure(handler, file, self.cmd, self.arg);
+        }
+
+        let data = self.user_slice.take().ok_or(EINVAL)?;
+        const READ_WRITE: u32 = bindings::_IOC_READ | bindings::_IOC_WRITE;
+        match dir {
+            bindings::_IOC_WRITE => T::write(handler, file, self.cmd, &mut data.reader()),
+            bindings::_IOC_READ => T::read(handler, file, self.cmd, &mut data.writer()),
+            READ_WRITE => T::read_write(handler, file, self.cmd, data),
+            _ => Err(EINVAL),
+        }
+    }
+
+    /// Returns the raw 32-bit value of the command and the ptr-sized argument.
+    pub fn raw(&self) -> (u32, usize) {
+        (self.cmd, self.arg)
+    }
+}
+
+/// Trait for extracting file open arguments from kernel data structures.
+///
+/// This is meant to be implemented by registration managers.
+pub trait OpenAdapter<T: Sync> {
+    /// Converts untyped data stored in [`struct inode`] and [`struct file`] (when [`struct
+    /// file_operations::open`] is called) into the given type. For example, for `miscdev`
+    /// devices, a pointer to the registered [`struct miscdev`] is stored in [`struct
+    /// file::private_data`].
+    ///
+    /// # Safety
+    ///
+    /// This function must be called only when [`struct file_operations::open`] is being called for
+    /// a file that was registered by the implementer. The returned pointer must be valid and
+    /// not-null.
+    unsafe fn convert(_inode: *mut bindings::inode, _file: *mut bindings::file) -> *const T;
+}
+
+/// Corresponds to the kernel's `struct file_operations`.
+///
+/// You implement this trait whenever you would create a `struct file_operations`.
+///
+/// File descriptors may be used from multiple threads/processes concurrently, so your type must be
+/// [`Sync`]. It must also be [`Send`] because [`Operations::release`] will be called from the
+/// thread that decrements that associated file's refcount to zero.
+#[vtable]
+pub trait Operations {
+    /// The type of the context data returned by [`Operations::open`] and made available to
+    /// other methods.
+    type Data: PointerWrapper + Send + Sync = ();
+
+    /// The type of the context data passed to [`Operations::open`].
+    type OpenData: Sync = ();
+
+    /// Creates a new instance of this file.
+    ///
+    /// Corresponds to the `open` function pointer in `struct file_operations`.
+    fn open(context: &Self::OpenData, file: &File) -> Result<Self::Data>;
+
+    /// Cleans up after the last reference to the file goes away.
+    ///
+    /// Note that context data is moved, so it will be freed automatically unless the
+    /// implementation moves it elsewhere.
+    ///
+    /// Corresponds to the `release` function pointer in `struct file_operations`.
+    fn release(_data: Self::Data, _file: &File) {}
+
+    /// Reads data from this file to the caller's buffer.
+    ///
+    /// Corresponds to the `read` and `read_iter` function pointers in `struct file_operations`.
+    fn read(
+        _data: <Self::Data as PointerWrapper>::Borrowed<'_>,
+        _file: &File,
+        _writer: &mut impl IoBufferWriter,
+        _offset: u64,
+    ) -> Result<usize> {
+        Err(EINVAL)
+    }
+
+    /// Writes data from the caller's buffer to this file.
+    ///
+    /// Corresponds to the `write` and `write_iter` function pointers in `struct file_operations`.
+    fn write(
+        _data: <Self::Data as PointerWrapper>::Borrowed<'_>,
+        _file: &File,
+        _reader: &mut impl IoBufferReader,
+        _offset: u64,
+    ) -> Result<usize> {
+        Err(EINVAL)
+    }
+
+    /// Changes the position of the file.
+    ///
+    /// Corresponds to the `llseek` function pointer in `struct file_operations`.
+    fn seek(
+        _data: <Self::Data as PointerWrapper>::Borrowed<'_>,
+        _file: &File,
+        _offset: SeekFrom,
+    ) -> Result<u64> {
+        Err(EINVAL)
+    }
+
+    /// Performs IO control operations that are specific to the file.
+    ///
+    /// Corresponds to the `unlocked_ioctl` function pointer in `struct file_operations`.
+    fn ioctl(
+        _data: <Self::Data as PointerWrapper>::Borrowed<'_>,
+        _file: &File,
+        _cmd: &mut IoctlCommand,
+    ) -> Result<i32> {
+        Err(ENOTTY)
+    }
+
+    /// Performs 32-bit IO control operations on that are specific to the file on 64-bit kernels.
+    ///
+    /// Corresponds to the `compat_ioctl` function pointer in `struct file_operations`.
+    fn compat_ioctl(
+        _data: <Self::Data as PointerWrapper>::Borrowed<'_>,
+        _file: &File,
+        _cmd: &mut IoctlCommand,
+    ) -> Result<i32> {
+        Err(ENOTTY)
+    }
+
+    /// Syncs pending changes to this file.
+    ///
+    /// Corresponds to the `fsync` function pointer in `struct file_operations`.
+    fn fsync(
+        _data: <Self::Data as PointerWrapper>::Borrowed<'_>,
+        _file: &File,
+        _start: u64,
+        _end: u64,
+        _datasync: bool,
+    ) -> Result<u32> {
+        Err(EINVAL)
+    }
+
+    /// Maps areas of the caller's virtual memory with device/file memory.
+    ///
+    /// Corresponds to the `mmap` function pointer in `struct file_operations`.
+    fn mmap(
+        _data: <Self::Data as PointerWrapper>::Borrowed<'_>,
+        _file: &File,
+        _vma: &mut mm::virt::Area,
+    ) -> Result {
+        Err(EINVAL)
+    }
+
+    /// Checks the state of the file and optionally registers for notification when the state
+    /// changes.
+    ///
+    /// Corresponds to the `poll` function pointer in `struct file_operations`.
+    fn poll(
+        _data: <Self::Data as PointerWrapper>::Borrowed<'_>,
+        _file: &File,
+        _table: &PollTable,
+    ) -> Result<u32> {
+        Ok(bindings::POLLIN | bindings::POLLOUT | bindings::POLLRDNORM | bindings::POLLWRNORM)
+    }
+}
diff --git a/rust/kernel/fs.rs b/rust/kernel/fs.rs
new file mode 100644
index 000000000000..46dc38aad2bc
--- /dev/null
+++ b/rust/kernel/fs.rs
@@ -0,0 +1,846 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! File systems.
+//!
+//! C headers: [`include/linux/fs.h`](../../../../include/linux/fs.h)
+
+use crate::{
+    bindings, error::code::*, error::from_kernel_result, str::CStr, to_result,
+    types::PointerWrapper, AlwaysRefCounted, Error, Result, ScopeGuard, ThisModule,
+};
+use alloc::boxed::Box;
+use core::{
+    cell::UnsafeCell,
+    marker::{PhantomData, PhantomPinned},
+    pin::Pin,
+    ptr,
+};
+use macros::vtable;
+
+pub mod param;
+
+/// Type of superblock keying.
+///
+/// It determines how C's `fs_context_operations::get_tree` is implemented.
+pub enum Super {
+    /// Only one such superblock may exist.
+    Single,
+
+    /// As [`Super::Single`], but reconfigure if it exists.
+    SingleReconf,
+
+    /// Superblocks with different data pointers may exist.
+    Keyed,
+
+    /// Multiple independent superblocks may exist.
+    Independent,
+
+    /// Uses a block device.
+    BlockDev,
+}
+
+/// A file system context.
+///
+/// It is used to gather configuration to then mount or reconfigure a file system.
+#[vtable]
+pub trait Context<T: Type + ?Sized> {
+    /// Type of the data associated with the context.
+    type Data: PointerWrapper + Send + Sync + 'static;
+
+    /// The typed file system parameters.
+    ///
+    /// Users are encouraged to define it using the [`crate::define_fs_params`] macro.
+    const PARAMS: param::SpecTable<'static, Self::Data> = param::SpecTable::empty();
+
+    /// Creates a new context.
+    fn try_new() -> Result<Self::Data>;
+
+    /// Parses a parameter that wasn't specified in [`Self::PARAMS`].
+    fn parse_unknown_param(
+        _data: &mut Self::Data,
+        _name: &CStr,
+        _value: param::Value<'_>,
+    ) -> Result {
+        Err(ENOPARAM)
+    }
+
+    /// Parses the whole parameter block, potentially skipping regular handling for parts of it.
+    ///
+    /// The return value is the portion of the input buffer for which the regular handling
+    /// (involving [`Self::PARAMS`] and [`Self::parse_unknown_param`]) will still be carried out.
+    /// If it's `None`, the regular handling is not performed at all.
+    fn parse_monolithic<'a>(
+        _data: &mut Self::Data,
+        _buf: Option<&'a mut [u8]>,
+    ) -> Result<Option<&'a mut [u8]>> {
+        Ok(None)
+    }
+
+    /// Returns the superblock data to be used by this file system context.
+    ///
+    /// This is only needed when [`Type::SUPER_TYPE`] is [`Super::Keyed`], otherwise it is never
+    /// called. In the former case, when the fs is being mounted, an existing superblock is reused
+    /// if one can be found with the same data as the returned value; otherwise a new superblock is
+    /// created.
+    fn tree_key(_data: &mut Self::Data) -> Result<T::Data> {
+        Err(ENOTSUPP)
+    }
+}
+
+struct Tables<T: Type + ?Sized>(T);
+impl<T: Type + ?Sized> Tables<T> {
+    const CONTEXT: bindings::fs_context_operations = bindings::fs_context_operations {
+        free: Some(Self::free_callback),
+        parse_param: Some(Self::parse_param_callback),
+        get_tree: Some(Self::get_tree_callback),
+        reconfigure: Some(Self::reconfigure_callback),
+        parse_monolithic: if <T::Context as Context<T>>::HAS_PARSE_MONOLITHIC {
+            Some(Self::parse_monolithic_callback)
+        } else {
+            None
+        },
+        dup: None,
+    };
+
+    unsafe extern "C" fn free_callback(fc: *mut bindings::fs_context) {
+        // SAFETY: The callback contract guarantees that `fc` is valid.
+        let fc = unsafe { &*fc };
+
+        let ptr = fc.fs_private;
+        if !ptr.is_null() {
+            // SAFETY: `fs_private` was initialised with the result of a `to_pointer` call in
+            // `init_fs_context_callback`, so it's ok to call `from_pointer` here.
+            unsafe { <T::Context as Context<T>>::Data::from_pointer(ptr) };
+        }
+
+        let ptr = fc.s_fs_info;
+        if !ptr.is_null() {
+            // SAFETY: `s_fs_info` may be initialised with the result of a `to_pointer` call in
+            // `get_tree_callback` when keyed superblocks are used (`get_tree_keyed` sets it), so
+            // it's ok to call `from_pointer` here.
+            unsafe { T::Data::from_pointer(ptr) };
+        }
+    }
+
+    unsafe extern "C" fn parse_param_callback(
+        fc: *mut bindings::fs_context,
+        param: *mut bindings::fs_parameter,
+    ) -> core::ffi::c_int {
+        from_kernel_result! {
+            // SAFETY: The callback contract guarantees that `fc` is valid.
+            let ptr = unsafe { (*fc).fs_private };
+
+            // SAFETY: The value of `ptr` (coming from `fs_private` was initialised in
+            // `init_fs_context_callback` to the result of an `into_pointer` call. Since the
+            // context is valid, `from_pointer` wasn't called yet, so `ptr` is valid. Additionally,
+            // the callback contract guarantees that callbacks are serialised, so it is ok to
+            // mutably reference it.
+            let mut data =
+                unsafe { <<T::Context as Context<T>>::Data as PointerWrapper>::borrow_mut(ptr) };
+            let mut result = bindings::fs_parse_result::default();
+            // SAFETY: All parameters are valid at least for the duration of the call.
+            let opt =
+                unsafe { bindings::fs_parse(fc, T::Context::PARAMS.first, param, &mut result) };
+
+            // SAFETY: The callback contract guarantees that `param` is valid for the duration of
+            // the callback.
+            let param = unsafe { &*param };
+            if opt >= 0 {
+                let opt = opt as usize;
+                if opt >= T::Context::PARAMS.handlers.len() {
+                    return Err(EINVAL);
+                }
+                T::Context::PARAMS.handlers[opt].handle_param(&mut data, param, &result)?;
+                return Ok(0);
+            }
+
+            if opt != ENOPARAM.to_kernel_errno() {
+                return Err(Error::from_kernel_errno(opt));
+            }
+
+            if !T::Context::HAS_PARSE_UNKNOWN_PARAM {
+                return Err(ENOPARAM);
+            }
+
+            let val = param::Value::from_fs_parameter(param);
+            // SAFETY: The callback contract guarantees the parameter key to be valid and last at
+            // least the duration of the callback.
+            T::Context::parse_unknown_param(
+                &mut data,
+                unsafe { CStr::from_char_ptr(param.key) },
+                val,
+            )?;
+            Ok(0)
+        }
+    }
+
+    unsafe extern "C" fn fill_super_callback(
+        sb_ptr: *mut bindings::super_block,
+        fc: *mut bindings::fs_context,
+    ) -> core::ffi::c_int {
+        from_kernel_result! {
+            // SAFETY: The callback contract guarantees that `fc` is valid. It also guarantees that
+            // the callbacks are serialised for a given `fc`, so it is safe to mutably dereference
+            // it.
+            let fc = unsafe { &mut *fc };
+            let ptr = core::mem::replace(&mut fc.fs_private, ptr::null_mut());
+
+            // SAFETY: The value of `ptr` (coming from `fs_private` was initialised in
+            // `init_fs_context_callback` to the result of an `into_pointer` call. The context is
+            // being used to initialise a superblock, so we took over `ptr` (`fs_private` is set to
+            // null now) and call `from_pointer` below.
+            let data =
+                unsafe { <<T::Context as Context<T>>::Data as PointerWrapper>::from_pointer(ptr) };
+
+            // SAFETY: The callback contract guarantees that `sb_ptr` is a unique pointer to a
+            // newly-created superblock.
+            let newsb = unsafe { NewSuperBlock::new(sb_ptr) };
+            T::fill_super(data, newsb)?;
+            Ok(0)
+        }
+    }
+
+    unsafe extern "C" fn get_tree_callback(fc: *mut bindings::fs_context) -> core::ffi::c_int {
+        // N.B. When new types are added below, we may need to update `kill_sb_callback` to ensure
+        // that we're cleaning up properly.
+        match T::SUPER_TYPE {
+            Super::Single => unsafe {
+                // SAFETY: `fc` is valid per the callback contract. `fill_super_callback` also has
+                // the right type and is a valid callback.
+                bindings::get_tree_single(fc, Some(Self::fill_super_callback))
+            },
+            Super::SingleReconf => unsafe {
+                // SAFETY: `fc` is valid per the callback contract. `fill_super_callback` also has
+                // the right type and is a valid callback.
+                bindings::get_tree_single_reconf(fc, Some(Self::fill_super_callback))
+            },
+            Super::Independent => unsafe {
+                // SAFETY: `fc` is valid per the callback contract. `fill_super_callback` also has
+                // the right type and is a valid callback.
+                bindings::get_tree_nodev(fc, Some(Self::fill_super_callback))
+            },
+            Super::BlockDev => unsafe {
+                // SAFETY: `fc` is valid per the callback contract. `fill_super_callback` also has
+                // the right type and is a valid callback.
+                bindings::get_tree_bdev(fc, Some(Self::fill_super_callback))
+            },
+            Super::Keyed => {
+                from_kernel_result! {
+                    // SAFETY: `fc` is valid per the callback contract.
+                    let ctx = unsafe { &*fc };
+                    let ptr = ctx.fs_private;
+
+                    // SAFETY: The value of `ptr` (coming from `fs_private` was initialised in
+                    // `init_fs_context_callback` to the result of an `into_pointer` call. Since
+                    // the context is valid, `from_pointer` wasn't called yet, so `ptr` is valid.
+                    // Additionally, the callback contract guarantees that callbacks are
+                    // serialised, so it is ok to mutably reference it.
+                    let mut data = unsafe {
+                        <<T::Context as Context<T>>::Data as PointerWrapper>::borrow_mut(ptr)
+                    };
+                    let fs_data = T::Context::tree_key(&mut data)?;
+                    let fs_data_ptr = fs_data.into_pointer();
+
+                    // `get_tree_keyed` reassigns `ctx.s_fs_info`, which should be ok because
+                    // nowhere else is it assigned a non-null value. However, we add the assert
+                    // below to ensure that there are no unexpected paths on the C side that may do
+                    // this.
+                    assert_eq!(ctx.s_fs_info, core::ptr::null_mut());
+
+                    // SAFETY: `fc` is valid per the callback contract. `fill_super_callback` also
+                    // has the right type and is a valid callback. Lastly, we just called
+                    // `into_pointer` above, so `fs_data_ptr` is also valid.
+                    to_result(unsafe {
+                        bindings::get_tree_keyed(
+                            fc,
+                            Some(Self::fill_super_callback),
+                            fs_data_ptr as _,
+                        )
+                    })?;
+                    Ok(0)
+                }
+            }
+        }
+    }
+
+    unsafe extern "C" fn reconfigure_callback(_fc: *mut bindings::fs_context) -> core::ffi::c_int {
+        EINVAL.to_kernel_errno()
+    }
+
+    unsafe extern "C" fn parse_monolithic_callback(
+        fc: *mut bindings::fs_context,
+        buf: *mut core::ffi::c_void,
+    ) -> core::ffi::c_int {
+        from_kernel_result! {
+            // SAFETY: The callback contract guarantees that `fc` is valid.
+            let ptr = unsafe { (*fc).fs_private };
+
+            // SAFETY: The value of `ptr` (coming from `fs_private` was initialised in
+            // `init_fs_context_callback` to the result of an `into_pointer` call. Since the
+            // context is valid, `from_pointer` wasn't called yet, so `ptr` is valid. Additionally,
+            // the callback contract guarantees that callbacks are serialised, so it is ok to
+            // mutably reference it.
+            let mut data =
+                unsafe { <<T::Context as Context<T>>::Data as PointerWrapper>::borrow_mut(ptr) };
+            let page = if buf.is_null() {
+                None
+            } else {
+                // SAFETY: This callback is called to handle the `mount` syscall, which takes a
+                // page-sized buffer as data.
+                Some(unsafe { &mut *ptr::slice_from_raw_parts_mut(buf.cast(), crate::PAGE_SIZE) })
+            };
+            let regular = T::Context::parse_monolithic(&mut data, page)?;
+            if let Some(buf) = regular {
+                // SAFETY: Both `fc` and `buf` are guaranteed to be valid; the former because the
+                // callback is still ongoing and the latter because its lifefime is tied to that of
+                // `page`, which is also valid for the duration of the callback.
+                to_result(unsafe {
+                    bindings::generic_parse_monolithic(fc, buf.as_mut_ptr().cast())
+                })?;
+            }
+            Ok(0)
+        }
+    }
+
+    const SUPER_BLOCK: bindings::super_operations = bindings::super_operations {
+        alloc_inode: None,
+        destroy_inode: None,
+        free_inode: None,
+        dirty_inode: None,
+        write_inode: None,
+        drop_inode: None,
+        evict_inode: None,
+        put_super: None,
+        sync_fs: None,
+        freeze_super: None,
+        freeze_fs: None,
+        thaw_super: None,
+        unfreeze_fs: None,
+        statfs: None,
+        remount_fs: None,
+        umount_begin: None,
+        show_options: None,
+        show_devname: None,
+        show_path: None,
+        show_stats: None,
+        #[cfg(CONFIG_QUOTA)]
+        quota_read: None,
+        #[cfg(CONFIG_QUOTA)]
+        quota_write: None,
+        #[cfg(CONFIG_QUOTA)]
+        get_dquots: None,
+        nr_cached_objects: None,
+        free_cached_objects: None,
+    };
+}
+
+/// A file system type.
+pub trait Type {
+    /// The context used to build fs configuration before it is mounted or reconfigured.
+    type Context: Context<Self> + ?Sized;
+
+    /// Data associated with each file system instance.
+    type Data: PointerWrapper + Send + Sync = ();
+
+    /// Determines how superblocks for this file system type are keyed.
+    const SUPER_TYPE: Super;
+
+    /// The name of the file system type.
+    const NAME: &'static CStr;
+
+    /// The flags of this file system type.
+    ///
+    /// It is a combination of the flags in the [`flags`] module.
+    const FLAGS: i32;
+
+    /// Initialises a super block for this file system type.
+    fn fill_super(
+        data: <Self::Context as Context<Self>>::Data,
+        sb: NewSuperBlock<'_, Self>,
+    ) -> Result<&SuperBlock<Self>>;
+}
+
+/// File system flags.
+pub mod flags {
+    use crate::bindings;
+
+    /// The file system requires a device.
+    pub const REQUIRES_DEV: i32 = bindings::FS_REQUIRES_DEV as _;
+
+    /// The options provided when mounting are in binary form.
+    pub const BINARY_MOUNTDATA: i32 = bindings::FS_BINARY_MOUNTDATA as _;
+
+    /// The file system has a subtype. It is extracted from the name and passed in as a parameter.
+    pub const HAS_SUBTYPE: i32 = bindings::FS_HAS_SUBTYPE as _;
+
+    /// The file system can be mounted by userns root.
+    pub const USERNS_MOUNT: i32 = bindings::FS_USERNS_MOUNT as _;
+
+    /// Disables fanotify permission events.
+    pub const DISALLOW_NOTIFY_PERM: i32 = bindings::FS_DISALLOW_NOTIFY_PERM as _;
+
+    /// The file system has been updated to handle vfs idmappings.
+    pub const ALLOW_IDMAP: i32 = bindings::FS_ALLOW_IDMAP as _;
+
+    /// The file systen will handle `d_move` during `rename` internally.
+    pub const RENAME_DOES_D_MOVE: i32 = bindings::FS_RENAME_DOES_D_MOVE as _;
+}
+
+/// A file system registration.
+#[derive(Default)]
+pub struct Registration {
+    is_registered: bool,
+    fs: UnsafeCell<bindings::file_system_type>,
+    _pin: PhantomPinned,
+}
+
+// SAFETY: `Registration` doesn't really provide any `&self` methods, so it is safe to pass
+// references to it around.
+unsafe impl Sync for Registration {}
+
+// SAFETY: Both registration and unregistration are implemented in C and safe to be performed from
+// any thread, so `Registration` is `Send`.
+unsafe impl Send for Registration {}
+
+impl Registration {
+    /// Creates a new file system registration.
+    ///
+    /// It is not visible or accessible yet. A successful call to [`Registration::register`] needs
+    /// to be made before users can mount it.
+    pub fn new() -> Self {
+        Self {
+            is_registered: false,
+            fs: UnsafeCell::new(bindings::file_system_type::default()),
+            _pin: PhantomPinned,
+        }
+    }
+
+    /// Registers a file system so that it can be mounted by users.
+    ///
+    /// The file system is described by the [`Type`] argument.
+    ///
+    /// It is automatically unregistered when the registration is dropped.
+    pub fn register<T: Type + ?Sized>(self: Pin<&mut Self>, module: &'static ThisModule) -> Result {
+        // SAFETY: We never move out of `this`.
+        let this = unsafe { self.get_unchecked_mut() };
+
+        if this.is_registered {
+            return Err(EINVAL);
+        }
+
+        let mut fs = this.fs.get_mut();
+        fs.owner = module.0;
+        fs.name = T::NAME.as_char_ptr();
+        fs.fs_flags = T::FLAGS;
+        fs.parameters = T::Context::PARAMS.first;
+        fs.init_fs_context = Some(Self::init_fs_context_callback::<T>);
+        fs.kill_sb = Some(Self::kill_sb_callback::<T>);
+
+        // SAFETY: This block registers all fs type keys with lockdep. We just need the memory
+        // locations to be owned by the caller, which is the case.
+        unsafe {
+            bindings::lockdep_register_key(&mut fs.s_lock_key);
+            bindings::lockdep_register_key(&mut fs.s_umount_key);
+            bindings::lockdep_register_key(&mut fs.s_vfs_rename_key);
+            bindings::lockdep_register_key(&mut fs.i_lock_key);
+            bindings::lockdep_register_key(&mut fs.i_mutex_key);
+            bindings::lockdep_register_key(&mut fs.invalidate_lock_key);
+            bindings::lockdep_register_key(&mut fs.i_mutex_dir_key);
+            for key in &mut fs.s_writers_key {
+                bindings::lockdep_register_key(key);
+            }
+        }
+
+        let ptr = this.fs.get();
+
+        // SAFETY: `ptr` as valid as it points to the `self.fs`.
+        let key_guard = ScopeGuard::new(|| unsafe { Self::unregister_keys(ptr) });
+
+        // SAFETY: Pointers stored in `fs` are either static so will live for as long as the
+        // registration is active (it is undone in `drop`).
+        to_result(unsafe { bindings::register_filesystem(ptr) })?;
+        key_guard.dismiss();
+        this.is_registered = true;
+        Ok(())
+    }
+
+    /// Unregisters the lockdep keys in the file system type.
+    ///
+    /// # Safety
+    ///
+    /// `fs` must be non-null and valid.
+    unsafe fn unregister_keys(fs: *mut bindings::file_system_type) {
+        // SAFETY: This block unregisters all fs type keys from lockdep. They must have been
+        // registered before.
+        unsafe {
+            bindings::lockdep_unregister_key(ptr::addr_of_mut!((*fs).s_lock_key));
+            bindings::lockdep_unregister_key(ptr::addr_of_mut!((*fs).s_umount_key));
+            bindings::lockdep_unregister_key(ptr::addr_of_mut!((*fs).s_vfs_rename_key));
+            bindings::lockdep_unregister_key(ptr::addr_of_mut!((*fs).i_lock_key));
+            bindings::lockdep_unregister_key(ptr::addr_of_mut!((*fs).i_mutex_key));
+            bindings::lockdep_unregister_key(ptr::addr_of_mut!((*fs).invalidate_lock_key));
+            bindings::lockdep_unregister_key(ptr::addr_of_mut!((*fs).i_mutex_dir_key));
+            for i in 0..(*fs).s_writers_key.len() {
+                bindings::lockdep_unregister_key(ptr::addr_of_mut!((*fs).s_writers_key[i]));
+            }
+        }
+    }
+
+    unsafe extern "C" fn init_fs_context_callback<T: Type + ?Sized>(
+        fc_ptr: *mut bindings::fs_context,
+    ) -> core::ffi::c_int {
+        from_kernel_result! {
+            let data = T::Context::try_new()?;
+            // SAFETY: The callback contract guarantees that `fc_ptr` is the only pointer to a
+            // newly-allocated fs context, so it is safe to mutably reference it.
+            let fc = unsafe { &mut *fc_ptr };
+            fc.fs_private = data.into_pointer() as _;
+            fc.ops = &Tables::<T>::CONTEXT;
+            Ok(0)
+        }
+    }
+
+    unsafe extern "C" fn kill_sb_callback<T: Type + ?Sized>(sb_ptr: *mut bindings::super_block) {
+        if let Super::BlockDev = T::SUPER_TYPE {
+            // SAFETY: When the superblock type is `BlockDev`, we have a block device so it's safe
+            // to call `kill_block_super`. Additionally, the callback contract guarantees that
+            // `sb_ptr` is valid.
+            unsafe { bindings::kill_block_super(sb_ptr) }
+        } else {
+            // SAFETY: We always call a `get_tree_nodev` variant from `get_tree_callback` without a
+            // device when `T::SUPER_TYPE` is not `BlockDev`, so we never have a device in such
+            // cases, therefore it is ok to call the function below. Additionally, the callback
+            // contract guarantees that `sb_ptr` is valid.
+            unsafe { bindings::kill_anon_super(sb_ptr) }
+        }
+
+        // SAFETY: The callback contract guarantees that `sb_ptr` is valid.
+        let sb = unsafe { &*sb_ptr };
+
+        // SAFETY: The `kill_sb` callback being called implies that the `s_type` field is valid.
+        unsafe { Self::unregister_keys(sb.s_type) };
+
+        let ptr = sb.s_fs_info;
+        if !ptr.is_null() {
+            // SAFETY: The only place where `s_fs_info` is assigned is `NewSuperBlock::init`, where
+            // it's initialised with the result of a `to_pointer` call. We checked above that ptr
+            // is non-null because it would be null if we never reached the point where we init the
+            // field.
+            unsafe { T::Data::from_pointer(ptr) };
+        }
+    }
+}
+
+impl Drop for Registration {
+    fn drop(&mut self) {
+        if self.is_registered {
+            // SAFETY: When `is_registered` is `true`, a previous call to `register_filesystem` has
+            // succeeded, so it is safe to unregister here.
+            unsafe { bindings::unregister_filesystem(self.fs.get()) };
+        }
+    }
+}
+
+/// State of [`NewSuperBlock`] that indicates that [`NewSuperBlock::init`] needs to be called
+/// eventually.
+pub struct NeedsInit;
+
+/// State of [`NewSuperBlock`] that indicates that [`NewSuperBlock::init_root`] needs to be called
+/// eventually.
+pub struct NeedsRoot;
+
+/// Required superblock parameters.
+///
+/// This is used in [`NewSuperBlock::init`].
+pub struct SuperParams {
+    /// The magic number of the superblock.
+    pub magic: u32,
+
+    /// The size of a block in powers of 2 (i.e., for a value of `n`, the size is `2^n`.
+    pub blocksize_bits: u8,
+
+    /// Maximum size of a file.
+    pub maxbytes: i64,
+
+    /// Granularity of c/m/atime in ns (cannot be worse than a second).
+    pub time_gran: u32,
+}
+
+impl SuperParams {
+    /// Default value for instances of [`SuperParams`].
+    pub const DEFAULT: Self = Self {
+        magic: 0,
+        blocksize_bits: crate::PAGE_SIZE as _,
+        maxbytes: bindings::MAX_LFS_FILESIZE,
+        time_gran: 1,
+    };
+}
+
+/// A superblock that is still being initialised.
+///
+/// It uses type states to ensure that callers use the right sequence of calls.
+///
+/// # Invariants
+///
+/// The superblock is a newly-created one and this is the only active pointer to it.
+pub struct NewSuperBlock<'a, T: Type + ?Sized, S = NeedsInit> {
+    sb: *mut bindings::super_block,
+    _p: PhantomData<(&'a T, S)>,
+}
+
+impl<'a, T: Type + ?Sized> NewSuperBlock<'a, T, NeedsInit> {
+    /// Creates a new instance of [`NewSuperBlock`].
+    ///
+    /// # Safety
+    ///
+    /// `sb` must point to a newly-created superblock and it must be the only active pointer to it.
+    unsafe fn new(sb: *mut bindings::super_block) -> Self {
+        // INVARIANT: The invariants are satisfied by the safety requirements of this function.
+        Self {
+            sb,
+            _p: PhantomData,
+        }
+    }
+
+    /// Initialises the superblock so that it transitions to the [`NeedsRoot`] type state.
+    pub fn init(
+        self,
+        data: T::Data,
+        params: &SuperParams,
+    ) -> Result<NewSuperBlock<'a, T, NeedsRoot>> {
+        // SAFETY: The type invariant guarantees that `self.sb` is the only pointer to a
+        // newly-allocated superblock, so it is safe to mutably reference it.
+        let sb = unsafe { &mut *self.sb };
+
+        sb.s_magic = params.magic as _;
+        sb.s_op = &Tables::<T>::SUPER_BLOCK;
+        sb.s_maxbytes = params.maxbytes;
+        sb.s_time_gran = params.time_gran;
+        sb.s_blocksize_bits = params.blocksize_bits;
+        sb.s_blocksize = 1;
+        if sb.s_blocksize.leading_zeros() < params.blocksize_bits.into() {
+            return Err(EINVAL);
+        }
+        sb.s_blocksize = 1 << sb.s_blocksize_bits;
+
+        // Keyed file systems already have `s_fs_info` initialised.
+        let info = data.into_pointer() as *mut _;
+        if let Super::Keyed = T::SUPER_TYPE {
+            // SAFETY: We just called `into_pointer` above.
+            unsafe { T::Data::from_pointer(info) };
+
+            if sb.s_fs_info != info {
+                return Err(EINVAL);
+            }
+        } else {
+            sb.s_fs_info = info;
+        }
+
+        Ok(NewSuperBlock {
+            sb: self.sb,
+            _p: PhantomData,
+        })
+    }
+}
+
+impl<'a, T: Type + ?Sized> NewSuperBlock<'a, T, NeedsRoot> {
+    /// Initialises the root of the superblock.
+    pub fn init_root(self) -> Result<&'a SuperBlock<T>> {
+        // The following is temporary code to create the root inode and dentry. It will be replaced
+        // once we allow inodes and dentries to be created directly from Rust code.
+
+        // SAFETY: `sb` is initialised (`NeedsRoot` typestate implies it), so it is safe to pass it
+        // to `new_inode`.
+        let inode = unsafe { bindings::new_inode(self.sb) };
+        if inode.is_null() {
+            return Err(ENOMEM);
+        }
+
+        {
+            // SAFETY: This is a newly-created inode. No other references to it exist, so it is
+            // safe to mutably dereference it.
+            let inode = unsafe { &mut *inode };
+
+            // SAFETY: `current_time` requires that `inode.sb` be valid, which is the case here
+            // since we allocated the inode through the superblock.
+            let time = unsafe { bindings::current_time(inode) };
+            inode.i_ino = 1;
+            inode.i_mode = (bindings::S_IFDIR | 0o755) as _;
+            inode.i_mtime = time;
+            inode.i_atime = time;
+            inode.i_ctime = time;
+
+            // SAFETY: `simple_dir_operations` never changes, it's safe to reference it.
+            inode.__bindgen_anon_3.i_fop = unsafe { &bindings::simple_dir_operations };
+
+            // SAFETY: `simple_dir_inode_operations` never changes, it's safe to reference it.
+            inode.i_op = unsafe { &bindings::simple_dir_inode_operations };
+
+            // SAFETY: `inode` is valid for write.
+            unsafe { bindings::set_nlink(inode, 2) };
+        }
+
+        // SAFETY: `d_make_root` requires that `inode` be valid and referenced, which is the
+        // case for this call.
+        //
+        // It takes over the inode, even on failure, so we don't need to clean it up.
+        let dentry = unsafe { bindings::d_make_root(inode) };
+        if dentry.is_null() {
+            return Err(ENOMEM);
+        }
+
+        // SAFETY: The typestate guarantees that `self.sb` is valid.
+        unsafe { (*self.sb).s_root = dentry };
+
+        // SAFETY: The typestate guarantees that `self.sb` is initialised and we just finished
+        // setting its root, so it's a fully ready superblock.
+        Ok(unsafe { &mut *self.sb.cast() })
+    }
+}
+
+/// A file system super block.
+///
+/// Wraps the kernel's `struct super_block`.
+#[repr(transparent)]
+pub struct SuperBlock<T: Type + ?Sized>(
+    pub(crate) UnsafeCell<bindings::super_block>,
+    PhantomData<T>,
+);
+
+/// Wraps the kernel's `struct inode`.
+///
+/// # Invariants
+///
+/// Instances of this type are always ref-counted, that is, a call to `ihold` ensures that the
+/// allocation remains valid at least until the matching call to `iput`.
+#[repr(transparent)]
+pub struct INode(pub(crate) UnsafeCell<bindings::inode>);
+
+// SAFETY: The type invariants guarantee that `INode` is always ref-counted.
+unsafe impl AlwaysRefCounted for INode {
+    fn inc_ref(&self) {
+        // SAFETY: The existence of a shared reference means that the refcount is nonzero.
+        unsafe { bindings::ihold(self.0.get()) };
+    }
+
+    unsafe fn dec_ref(obj: ptr::NonNull<Self>) {
+        // SAFETY: The safety requirements guarantee that the refcount is nonzero.
+        unsafe { bindings::iput(obj.cast().as_ptr()) }
+    }
+}
+
+/// Wraps the kernel's `struct dentry`.
+///
+/// # Invariants
+///
+/// Instances of this type are always ref-counted, that is, a call to `dget` ensures that the
+/// allocation remains valid at least until the matching call to `dput`.
+#[repr(transparent)]
+pub struct DEntry(pub(crate) UnsafeCell<bindings::dentry>);
+
+// SAFETY: The type invariants guarantee that `DEntry` is always ref-counted.
+unsafe impl AlwaysRefCounted for DEntry {
+    fn inc_ref(&self) {
+        // SAFETY: The existence of a shared reference means that the refcount is nonzero.
+        unsafe { bindings::dget(self.0.get()) };
+    }
+
+    unsafe fn dec_ref(obj: ptr::NonNull<Self>) {
+        // SAFETY: The safety requirements guarantee that the refcount is nonzero.
+        unsafe { bindings::dput(obj.cast().as_ptr()) }
+    }
+}
+
+/// Wraps the kernel's `struct filename`.
+#[repr(transparent)]
+pub struct Filename(pub(crate) UnsafeCell<bindings::filename>);
+
+impl Filename {
+    /// Creates a reference to a [`Filename`] from a valid pointer.
+    ///
+    /// # Safety
+    ///
+    /// The caller must ensure that `ptr` is valid and remains valid for the lifetime of the
+    /// returned [`Filename`] instance.
+    pub(crate) unsafe fn from_ptr<'a>(ptr: *const bindings::filename) -> &'a Filename {
+        // SAFETY: The safety requirements guarantee the validity of the dereference, while the
+        // `Filename` type being transparent makes the cast ok.
+        unsafe { &*ptr.cast() }
+    }
+}
+
+/// Kernel module that exposes a single file system implemented by `T`.
+pub struct Module<T: Type> {
+    _fs: Pin<Box<Registration>>,
+    _p: PhantomData<T>,
+}
+
+impl<T: Type + Sync> crate::Module for Module<T> {
+    fn init(_name: &'static CStr, module: &'static ThisModule) -> Result<Self> {
+        let mut reg = Pin::from(Box::try_new(Registration::new())?);
+        reg.as_mut().register::<T>(module)?;
+        Ok(Self {
+            _fs: reg,
+            _p: PhantomData,
+        })
+    }
+}
+
+/// Declares a kernel module that exposes a single file system.
+///
+/// The `type` argument must be a type which implements the [`Type`] trait. Also accepts various
+/// forms of kernel metadata.
+///
+/// # Examples
+///
+/// ```ignore
+/// use kernel::prelude::*;
+/// use kernel::{c_str, fs};
+///
+/// module_fs! {
+///     type: MyFs,
+///     name: b"my_fs_kernel_module",
+///     author: b"Rust for Linux Contributors",
+///     description: b"My very own file system kernel module!",
+///     license: b"GPL",
+/// }
+///
+/// struct MyFs;
+///
+/// #[vtable]
+/// impl fs::Context<Self> for MyFs {
+///     type Data = ();
+///     fn try_new() -> Result {
+///         Ok(())
+///     }
+/// }
+///
+/// impl fs::Type for MyFs {
+///     type Context = Self;
+///     const SUPER_TYPE: fs::Super = fs::Super::Independent;
+///     const NAME: &'static CStr = c_str!("example");
+///     const FLAGS: i32 = 0;
+///
+///     fn fill_super(_data: (), sb: fs::NewSuperBlock<'_, Self>) -> Result<&fs::SuperBlock<Self>> {
+///         let sb = sb.init(
+///             (),
+///             &fs::SuperParams {
+///                 magic: 0x6578616d,
+///                 ..fs::SuperParams::DEFAULT
+///             },
+///         )?;
+///         let sb = sb.init_root()?;
+///         Ok(sb)
+///     }
+/// }
+/// ```
+#[macro_export]
+macro_rules! module_fs {
+    (type: $type:ty, $($f:tt)*) => {
+        type ModuleType = $crate::fs::Module<$type>;
+        $crate::macros::module! {
+            type: ModuleType,
+            $($f)*
+        }
+    }
+}
diff --git a/rust/kernel/fs/param.rs b/rust/kernel/fs/param.rs
new file mode 100644
index 000000000000..445cea404bcd
--- /dev/null
+++ b/rust/kernel/fs/param.rs
@@ -0,0 +1,553 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! File system parameters and parsing them.
+//!
+//! C headers: [`include/linux/fs_parser.h`](../../../../../include/linux/fs_parser.h)
+
+use crate::{bindings, file, fs, str::CStr, Result};
+use core::{marker::PhantomData, ptr};
+
+/// The value of a file system parameter.
+pub enum Value<'a> {
+    /// The value is undefined.
+    Undefined,
+
+    /// There is no value, but parameter itself is a flag.
+    Flag,
+
+    /// The value is the given string.
+    String(&'a CStr),
+
+    /// The value is the given binary blob.
+    Blob(&'a mut [u8]),
+
+    /// The value is the given file.
+    File(&'a file::File),
+
+    /// The value is the given filename and the given directory file descriptor (which may be
+    /// `AT_FDCWD`, to indicate the current directory).
+    Filename(&'a fs::Filename, i32),
+}
+
+impl<'a> Value<'a> {
+    pub(super) fn from_fs_parameter(p: &'a bindings::fs_parameter) -> Self {
+        match p.type_() {
+            bindings::fs_value_type_fs_value_is_string => {
+                // SAFETY: `type_` is string, so it is ok to use the union field. Additionally, it
+                // is guaranteed to be valid while `p` is valid.
+                Self::String(unsafe { CStr::from_char_ptr(p.__bindgen_anon_1.string) })
+            }
+            bindings::fs_value_type_fs_value_is_flag => Self::Flag,
+            bindings::fs_value_type_fs_value_is_blob => {
+                // SAFETY: `type_` is blob, so it is ok to use the union field and size.
+                // Additionally, it is guaranteed to be valid while `p` is valid.
+                let slice = unsafe {
+                    &mut *ptr::slice_from_raw_parts_mut(p.__bindgen_anon_1.blob.cast(), p.size)
+                };
+                Self::Blob(slice)
+            }
+            bindings::fs_value_type_fs_value_is_file => {
+                // SAFETY: `type_` is file, so it is ok to use the union field. Additionally, it is
+                // guaranteed to be valid while `p` is valid.
+                let file_ptr = unsafe { p.__bindgen_anon_1.file };
+                if file_ptr.is_null() {
+                    Self::Undefined
+                } else {
+                    // SAFETY: `file_ptr` is non-null and guaranteed to be valid while `p` is.
+                    Self::File(unsafe { file::File::from_ptr(file_ptr) })
+                }
+            }
+            bindings::fs_value_type_fs_value_is_filename => {
+                // SAFETY: `type_` is filename, so it is ok to use the union field. Additionally,
+                // it is guaranteed to be valid while `p` is valid.
+                let filename_ptr = unsafe { p.__bindgen_anon_1.name };
+                if filename_ptr.is_null() {
+                    Self::Undefined
+                } else {
+                    // SAFETY: `filename_ptr` is non-null and guaranteed to be valid while `p` is.
+                    Self::Filename(unsafe { fs::Filename::from_ptr(filename_ptr) }, p.dirfd)
+                }
+            }
+            _ => Self::Undefined,
+        }
+    }
+}
+
+/// A specification of a file system parameter.
+pub struct Spec {
+    name: &'static CStr,
+    flags: u16,
+    type_: bindings::fs_param_type,
+    extra: *const core::ffi::c_void,
+}
+
+const DEFAULT: Spec = Spec {
+    name: crate::c_str!(""),
+    flags: 0,
+    type_: None,
+    extra: core::ptr::null(),
+};
+
+macro_rules! define_param_type {
+    ($name:ident, $fntype:ty, $spec:expr, |$param:ident, $result:ident| $value:expr) => {
+        /// Module to support `$name` parameter types.
+        pub mod $name {
+            use super::*;
+
+            #[doc(hidden)]
+            pub const fn spec(name: &'static CStr) -> Spec {
+                const GIVEN: Spec = $spec;
+                Spec { name, ..GIVEN }
+            }
+
+            #[doc(hidden)]
+            pub const fn handler<S>(setfn: fn(&mut S, $fntype) -> Result) -> impl Handler<S> {
+                let c =
+                    move |s: &mut S,
+                          $param: &bindings::fs_parameter,
+                          $result: &bindings::fs_parse_result| { setfn(s, $value) };
+                ConcreteHandler {
+                    setfn: c,
+                    _p: PhantomData,
+                }
+            }
+        }
+    };
+}
+
+// SAFETY: This is only called when the parse result is a boolean, so it is ok to access to union
+// field.
+define_param_type!(flag, bool, Spec { ..DEFAULT }, |_p, r| unsafe {
+    r.__bindgen_anon_1.boolean
+});
+
+define_param_type!(
+    flag_no,
+    bool,
+    Spec {
+        flags: bindings::fs_param_neg_with_no as _,
+        ..DEFAULT
+    },
+    // SAFETY: This is only called when the parse result is a boolean, so it is ok to access to
+    // union field.
+    |_p, r| unsafe { r.__bindgen_anon_1.boolean }
+);
+
+define_param_type!(
+    bool,
+    bool,
+    Spec {
+        type_: Some(bindings::fs_param_is_bool),
+        ..DEFAULT
+    },
+    // SAFETY: This is only called when the parse result is a boolean, so it is ok to access to
+    // union field.
+    |_p, r| unsafe { r.__bindgen_anon_1.boolean }
+);
+
+define_param_type!(
+    u32,
+    u32,
+    Spec {
+        type_: Some(bindings::fs_param_is_u32),
+        ..DEFAULT
+    },
+    // SAFETY: This is only called when the parse result is a u32, so it is ok to access to union
+    // field.
+    |_p, r| unsafe { r.__bindgen_anon_1.uint_32 }
+);
+
+define_param_type!(
+    u32oct,
+    u32,
+    Spec {
+        type_: Some(bindings::fs_param_is_u32),
+        extra: 8 as _,
+        ..DEFAULT
+    },
+    // SAFETY: This is only called when the parse result is a u32, so it is ok to access to union
+    // field.
+    |_p, r| unsafe { r.__bindgen_anon_1.uint_32 }
+);
+
+define_param_type!(
+    u32hex,
+    u32,
+    Spec {
+        type_: Some(bindings::fs_param_is_u32),
+        extra: 16 as _,
+        ..DEFAULT
+    },
+    // SAFETY: This is only called when the parse result is a u32, so it is ok to access to union
+    // field.
+    |_p, r| unsafe { r.__bindgen_anon_1.uint_32 }
+);
+
+define_param_type!(
+    s32,
+    i32,
+    Spec {
+        type_: Some(bindings::fs_param_is_s32),
+        ..DEFAULT
+    },
+    // SAFETY: This is only called when the parse result is an i32, so it is ok to access to union
+    // field.
+    |_p, r| unsafe { r.__bindgen_anon_1.int_32 }
+);
+
+define_param_type!(
+    u64,
+    u64,
+    Spec {
+        type_: Some(bindings::fs_param_is_u64),
+        extra: 16 as _,
+        ..DEFAULT
+    },
+    // SAFETY: This is only called when the parse result is a u32, so it is ok to access to union
+    // field.
+    |_p, r| unsafe { r.__bindgen_anon_1.uint_64 }
+);
+
+define_param_type!(
+    string,
+    &CStr,
+    Spec {
+        type_: Some(bindings::fs_param_is_string),
+        ..DEFAULT
+    },
+    // SAFETY: This is only called when the parse result is a string, so it is ok to access to
+    // union field.
+    |p, _r| unsafe { CStr::from_char_ptr(p.__bindgen_anon_1.string) }
+);
+
+/// Module to support `enum` parameter types.
+pub mod enum_ {
+    use super::*;
+
+    #[doc(hidden)]
+    pub const fn spec(name: &'static CStr, options: ConstantTable<'static>) -> Spec {
+        Spec {
+            name,
+            type_: Some(bindings::fs_param_is_enum),
+            extra: options.first as *const _ as _,
+            ..DEFAULT
+        }
+    }
+
+    #[doc(hidden)]
+    pub const fn handler<S>(setfn: fn(&mut S, u32) -> Result) -> impl Handler<S> {
+        let c = move |s: &mut S, _p: &bindings::fs_parameter, r: &bindings::fs_parse_result| {
+            // SAFETY: This is only called when the parse result is an enum, so it is ok to access
+            // to union field.
+            setfn(s, unsafe { r.__bindgen_anon_1.uint_32 })
+        };
+        ConcreteHandler {
+            setfn: c,
+            _p: PhantomData,
+        }
+    }
+}
+
+const ZERO_SPEC: bindings::fs_parameter_spec = bindings::fs_parameter_spec {
+    name: core::ptr::null(),
+    type_: None,
+    opt: 0,
+    flags: 0,
+    data: core::ptr::null(),
+};
+
+/// A zero-terminated parameter spec array, followed by handlers.
+#[repr(C)]
+pub struct SpecArray<const N: usize, S: 'static> {
+    specs: [bindings::fs_parameter_spec; N],
+    sentinel: bindings::fs_parameter_spec,
+    handlers: [&'static dyn Handler<S>; N],
+}
+
+impl<const N: usize, S: 'static> SpecArray<N, S> {
+    /// Creates a new spec array.
+    ///
+    /// Users are encouraged to use the [`define_fs_params`] macro to define the
+    /// [`super::Context::PARAMS`] constant.
+    ///
+    /// # Safety
+    ///
+    /// The type of the elements in `handlers` must be compatible with the types in specs. For
+    /// example, if `specs` declares that the i-th element is a bool then the i-th handler
+    /// should be for a bool.
+    pub const unsafe fn new(specs: [Spec; N], handlers: [&'static dyn Handler<S>; N]) -> Self {
+        let mut array = Self {
+            specs: [ZERO_SPEC; N],
+            sentinel: ZERO_SPEC,
+            handlers,
+        };
+        let mut i = 0usize;
+        while i < N {
+            array.specs[i] = bindings::fs_parameter_spec {
+                name: specs[i].name.as_char_ptr(),
+                type_: specs[i].type_,
+                opt: i as _,
+                flags: specs[i].flags,
+                data: specs[i].extra,
+            };
+            i += 1;
+        }
+        array
+    }
+
+    /// Returns a [`SpecTable`] backed by `self`.
+    ///
+    /// This is used to essentially erase the array size.
+    pub const fn as_table(&self) -> SpecTable<'_, S> {
+        SpecTable {
+            first: &self.specs[0],
+            handlers: &self.handlers,
+            _p: PhantomData,
+        }
+    }
+}
+
+/// A parameter spec table.
+///
+/// The table is guaranteed to be zero-terminated.
+///
+/// Users are encouraged to use the [`define_fs_params`] macro to define the
+/// [`super::Context::PARAMS`] constant.
+pub struct SpecTable<'a, S: 'static> {
+    pub(super) first: &'a bindings::fs_parameter_spec,
+    pub(super) handlers: &'a [&'static dyn Handler<S>],
+    _p: PhantomData<S>,
+}
+
+impl<S> SpecTable<'static, S> {
+    pub(super) const fn empty() -> Self {
+        Self {
+            first: &ZERO_SPEC,
+            handlers: &[],
+            _p: PhantomData,
+        }
+    }
+}
+
+/// A zero-terminated parameter constant array.
+#[repr(C)]
+pub struct ConstantArray<const N: usize> {
+    consts: [bindings::constant_table; N],
+    sentinel: bindings::constant_table,
+}
+
+impl<const N: usize> ConstantArray<N> {
+    /// Creates a new constant array.
+    ///
+    /// Users are encouraged to use the [`define_fs_params`] macro to define the
+    /// [`super::Context::PARAMS`] constant.
+    pub const fn new(consts: [(&'static CStr, u32); N]) -> Self {
+        const ZERO: bindings::constant_table = bindings::constant_table {
+            name: core::ptr::null(),
+            value: 0,
+        };
+        let mut array = Self {
+            consts: [ZERO; N],
+            sentinel: ZERO,
+        };
+        let mut i = 0usize;
+        while i < N {
+            array.consts[i] = bindings::constant_table {
+                name: consts[i].0.as_char_ptr(),
+                value: consts[i].1 as _,
+            };
+            i += 1;
+        }
+        array
+    }
+
+    /// Returns a [`ConstantTable`] backed by `self`.
+    ///
+    /// This is used to essentially erase the array size.
+    pub const fn as_table(&self) -> ConstantTable<'_> {
+        ConstantTable {
+            first: &self.consts[0],
+        }
+    }
+}
+
+/// A parameter constant table.
+///
+/// The table is guaranteed to be zero-terminated.
+pub struct ConstantTable<'a> {
+    pub(super) first: &'a bindings::constant_table,
+}
+
+#[doc(hidden)]
+pub trait Handler<S> {
+    fn handle_param(
+        &self,
+        state: &mut S,
+        p: &bindings::fs_parameter,
+        r: &bindings::fs_parse_result,
+    ) -> Result;
+}
+
+struct ConcreteHandler<
+    S,
+    T: Fn(&mut S, &bindings::fs_parameter, &bindings::fs_parse_result) -> Result,
+> {
+    setfn: T,
+    _p: PhantomData<S>,
+}
+
+impl<S, T: Fn(&mut S, &bindings::fs_parameter, &bindings::fs_parse_result) -> Result> Handler<S>
+    for ConcreteHandler<S, T>
+{
+    fn handle_param(
+        &self,
+        state: &mut S,
+        p: &bindings::fs_parameter,
+        r: &bindings::fs_parse_result,
+    ) -> Result {
+        (self.setfn)(state, p, r)
+    }
+}
+
+/// Counts the number of comma-separated entries surrounded by braces.
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::count_brace_items;
+///
+/// assert_eq!(0, count_brace_items!());
+/// assert_eq!(1, count_brace_items!({ A }));
+/// assert_eq!(1, count_brace_items!({ A },));
+/// assert_eq!(2, count_brace_items!({ A }, { B }));
+/// assert_eq!(2, count_brace_items!({ A }, { B },));
+/// assert_eq!(3, count_brace_items!({ A }, { B }, { C }));
+/// assert_eq!(3, count_brace_items!({ A }, { B }, { C },));
+/// ```
+#[macro_export]
+macro_rules! count_brace_items {
+    ({$($item:tt)*}, $($remaining:tt)*) => { 1 + $crate::count_brace_items!($($remaining)*) };
+    ({$($item:tt)*}) => { 1 };
+    () => { 0 };
+}
+
+/// Defines the file system parameters of a given file system context.
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::prelude::*;
+/// # use kernel::{c_str, fs, str::CString};
+///
+/// #[derive(Default)]
+/// struct State {
+///     flag: Option<bool>,
+///     flag_no: Option<bool>,
+///     bool_value: Option<bool>,
+///     u32_value: Option<u32>,
+///     i32_value: Option<i32>,
+///     u64_value: Option<u64>,
+///     str_value: Option<CString>,
+///     enum_value: Option<u32>,
+/// }
+///
+/// fn set_u32(s: &mut Box<State>, v: u32) -> Result {
+///     s.u32_value = Some(v);
+///     Ok(())
+/// }
+///
+/// struct Example;
+///
+/// #[vtable]
+/// impl fs::Context<Self> for Example {
+///     type Data = Box<State>;
+///
+///     kernel::define_fs_params! {Box<State>,
+///         {flag, "flag", |s, v| { s.flag = Some(v); Ok(()) } },
+///         {flag_no, "flagno", |s, v| { s.flag_no = Some(v); Ok(()) } },
+///         {bool, "bool", |s, v| { s.bool_value = Some(v); Ok(()) } },
+///         {u32, "u32", set_u32 },
+///         {u32oct, "u32oct", set_u32 },
+///         {u32hex, "u32hex", set_u32 },
+///         {s32, "s32", |s, v| { s.i32_value = Some(v); Ok(()) } },
+///         {u64, "u64", |s, v| { s.u64_value = Some(v); Ok(()) } },
+///         {string, "string", |s, v| {
+///             s.str_value = Some(CString::try_from_fmt(fmt!("{v}"))?);
+///             Ok(())
+///         }},
+///         {enum, "enum", [("first", 10), ("second", 20)], |s, v| {
+///             s.enum_value = Some(v);
+///             Ok(())
+///         }},
+///     }
+///
+///     fn try_new() -> Result<Self::Data> {
+///         Ok(Box::try_new(State::default())?)
+///     }
+/// }
+///
+/// # impl fs::Type for Example {
+/// #    type Context = Self;
+/// #    const SUPER_TYPE: fs::Super = fs::Super::Independent;
+/// #    const NAME: &'static CStr = c_str!("example");
+/// #    const FLAGS: i32 = 0;
+/// #
+/// #    fn fill_super<'a>(
+/// #        _data: Box<State>,
+/// #        sb: fs::NewSuperBlock<'_, Self>,
+/// #    ) -> Result<&fs::SuperBlock<Self>> {
+/// #        let sb = sb.init(
+/// #            (),
+/// #            &fs::SuperParams {
+/// #                magic: 0x6578616d,
+/// #                ..fs::SuperParams::DEFAULT
+/// #            },
+/// #        )?;
+/// #        let sb = sb.init_root()?;
+/// #        Ok(sb)
+/// #    }
+/// # }
+/// ```
+#[macro_export]
+macro_rules! define_fs_params {
+    ($data_type:ty, $({$($t:tt)*}),+ $(,)?) => {
+        const PARAMS: $crate::fs::param::SpecTable<'static, $data_type> =
+            {
+                use $crate::fs::param::{self, ConstantArray, Spec, SpecArray, Handler};
+                use $crate::c_str;
+                const COUNT: usize = $crate::count_brace_items!($({$($t)*},)*);
+                const SPECS: [Spec; COUNT] = $crate::define_fs_params!(@specs $({$($t)*},)*);
+                const HANDLERS: [&dyn Handler<$data_type>; COUNT] =
+                    $crate::define_fs_params!(@handlers $data_type, $({$($t)*},)*);
+                // SAFETY: We defined matching specs and handlers above.
+                const ARRAY: SpecArray<COUNT, $data_type> =
+                    unsafe { SpecArray::new(SPECS, HANDLERS) };
+                ARRAY.as_table()
+            };
+    };
+
+    (@handlers $data_type:ty, $({$($t:tt)*},)*) => {
+        [ $($crate::define_fs_params!(@handler $data_type, $($t)*),)* ]
+    };
+    (@handler $data_type:ty, enum, $name:expr, $opts:expr, $closure:expr) => {
+        &param::enum_::handler::<$data_type>($closure)
+    };
+    (@handler $data_type:ty, $type:ident, $name:expr, $closure:expr) => {
+        &param::$type::handler::<$data_type>($closure)
+    };
+
+    (@specs $({$($t:tt)*},)*) => {[ $($crate::define_fs_params!(@spec $($t)*),)* ]};
+    (@spec enum, $name:expr, [$($opts:tt)*], $closure:expr) => {
+        {
+            const COUNT: usize = $crate::count_paren_items!($($opts)*);
+            const OPTIONS: ConstantArray<COUNT> =
+                ConstantArray::new($crate::define_fs_params!(@c_str_first $($opts)*));
+            param::enum_::spec(c_str!($name), OPTIONS.as_table())
+        }
+    };
+    (@spec $type:ident, $name:expr, $closure:expr) => { param::$type::spec(c_str!($name)) };
+
+    (@c_str_first $(($first:expr, $second:expr)),+ $(,)?) => {
+        [$((c_str!($first), $second),)*]
+    };
+}
diff --git a/rust/kernel/gpio.rs b/rust/kernel/gpio.rs
new file mode 100644
index 000000000000..53c7b398d10b
--- /dev/null
+++ b/rust/kernel/gpio.rs
@@ -0,0 +1,505 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Support for gpio device drivers.
+//!
+//! C header: [`include/linux/gpio/driver.h`](../../../../include/linux/gpio/driver.h)
+
+use crate::{
+    bindings, device, error::code::*, error::from_kernel_result, sync::LockClassKey,
+    types::PointerWrapper, Error, Result,
+};
+use core::{
+    cell::UnsafeCell,
+    marker::{PhantomData, PhantomPinned},
+    pin::Pin,
+};
+use macros::vtable;
+
+#[cfg(CONFIG_GPIOLIB_IRQCHIP)]
+pub use irqchip::{ChipWithIrqChip, RegistrationWithIrqChip};
+
+/// The direction of a gpio line.
+pub enum LineDirection {
+    /// Direction is input.
+    In = bindings::GPIO_LINE_DIRECTION_IN as _,
+
+    /// Direction is output.
+    Out = bindings::GPIO_LINE_DIRECTION_OUT as _,
+}
+
+/// A gpio chip.
+#[vtable]
+pub trait Chip {
+    /// Context data associated with the gpio chip.
+    ///
+    /// It determines the type of the context data passed to each of the methods of the trait.
+    type Data: PointerWrapper + Sync + Send;
+
+    /// Returns the direction of the given gpio line.
+    fn get_direction(
+        _data: <Self::Data as PointerWrapper>::Borrowed<'_>,
+        _offset: u32,
+    ) -> Result<LineDirection> {
+        Err(ENOTSUPP)
+    }
+
+    /// Configures the direction as input of the given gpio line.
+    fn direction_input(
+        _data: <Self::Data as PointerWrapper>::Borrowed<'_>,
+        _offset: u32,
+    ) -> Result {
+        Err(EIO)
+    }
+
+    /// Configures the direction as output of the given gpio line.
+    ///
+    /// The value that will be initially output is also specified.
+    fn direction_output(
+        _data: <Self::Data as PointerWrapper>::Borrowed<'_>,
+        _offset: u32,
+        _value: bool,
+    ) -> Result {
+        Err(ENOTSUPP)
+    }
+
+    /// Returns the current value of the given gpio line.
+    fn get(_data: <Self::Data as PointerWrapper>::Borrowed<'_>, _offset: u32) -> Result<bool> {
+        Err(EIO)
+    }
+
+    /// Sets the value of the given gpio line.
+    fn set(_data: <Self::Data as PointerWrapper>::Borrowed<'_>, _offset: u32, _value: bool) {}
+}
+
+/// A registration of a gpio chip.
+///
+/// # Examples
+///
+/// The following example registers an empty gpio chip.
+///
+/// ```
+/// # use kernel::prelude::*;
+/// use kernel::{
+///     device::RawDevice,
+///     gpio::{self, Registration},
+/// };
+///
+/// struct MyGpioChip;
+/// #[vtable]
+/// impl gpio::Chip for MyGpioChip {
+///     type Data = ();
+/// }
+///
+/// fn example(parent: &dyn RawDevice) -> Result<Pin<Box<Registration<MyGpioChip>>>> {
+///     let mut r = Pin::from(Box::try_new(Registration::new())?);
+///     kernel::gpio_chip_register!(r.as_mut(), 32, None, parent, ())?;
+///     Ok(r)
+/// }
+/// ```
+pub struct Registration<T: Chip> {
+    gc: UnsafeCell<bindings::gpio_chip>,
+    parent: Option<device::Device>,
+    _p: PhantomData<T>,
+    _pin: PhantomPinned,
+}
+
+impl<T: Chip> Registration<T> {
+    /// Creates a new [`Registration`] but does not register it yet.
+    ///
+    /// It is allowed to move.
+    pub fn new() -> Self {
+        Self {
+            parent: None,
+            gc: UnsafeCell::new(bindings::gpio_chip::default()),
+            _pin: PhantomPinned,
+            _p: PhantomData,
+        }
+    }
+
+    /// Registers a gpio chip with the rest of the kernel.
+    ///
+    /// Users are encouraged to use the [`gpio_chip_register`] macro because it automatically
+    /// defines the lock classes and calls the registration function.
+    pub fn register(
+        self: Pin<&mut Self>,
+        gpio_count: u16,
+        base: Option<i32>,
+        parent: &dyn device::RawDevice,
+        data: T::Data,
+        lock_keys: [&'static LockClassKey; 2],
+    ) -> Result {
+        if self.parent.is_some() {
+            // Already registered.
+            return Err(EINVAL);
+        }
+
+        // SAFETY: We never move out of `this`.
+        let this = unsafe { self.get_unchecked_mut() };
+        {
+            let gc = this.gc.get_mut();
+
+            // Set up the callbacks.
+            gc.request = Some(bindings::gpiochip_generic_request);
+            gc.free = Some(bindings::gpiochip_generic_free);
+            if T::HAS_GET_DIRECTION {
+                gc.get_direction = Some(get_direction_callback::<T>);
+            }
+            if T::HAS_DIRECTION_INPUT {
+                gc.direction_input = Some(direction_input_callback::<T>);
+            }
+            if T::HAS_DIRECTION_OUTPUT {
+                gc.direction_output = Some(direction_output_callback::<T>);
+            }
+            if T::HAS_GET {
+                gc.get = Some(get_callback::<T>);
+            }
+            if T::HAS_SET {
+                gc.set = Some(set_callback::<T>);
+            }
+
+            // When a base is not explicitly given, use -1 for one to be picked.
+            if let Some(b) = base {
+                gc.base = b;
+            } else {
+                gc.base = -1;
+            }
+
+            gc.ngpio = gpio_count;
+            gc.parent = parent.raw_device();
+            gc.label = parent.name().as_char_ptr();
+
+            // TODO: Define `gc.owner` as well.
+        }
+
+        let data_pointer = <T::Data as PointerWrapper>::into_pointer(data);
+        // SAFETY: `gc` was initilised above, so it is valid.
+        let ret = unsafe {
+            bindings::gpiochip_add_data_with_key(
+                this.gc.get(),
+                data_pointer as _,
+                lock_keys[0].get(),
+                lock_keys[1].get(),
+            )
+        };
+        if ret < 0 {
+            // SAFETY: `data_pointer` was returned by `into_pointer` above.
+            unsafe { T::Data::from_pointer(data_pointer) };
+            return Err(Error::from_kernel_errno(ret));
+        }
+
+        this.parent = Some(device::Device::from_dev(parent));
+        Ok(())
+    }
+}
+
+// SAFETY: `Registration` doesn't offer any methods or access to fields when shared between threads
+// or CPUs, so it is safe to share it.
+unsafe impl<T: Chip> Sync for Registration<T> {}
+
+// SAFETY: Registration with and unregistration from the gpio subsystem can happen from any thread.
+// Additionally, `T::Data` (which is dropped during unregistration) is `Send`, so it is ok to move
+// `Registration` to different threads.
+#[allow(clippy::non_send_fields_in_send_ty)]
+unsafe impl<T: Chip> Send for Registration<T> {}
+
+impl<T: Chip> Default for Registration<T> {
+    fn default() -> Self {
+        Self::new()
+    }
+}
+
+impl<T: Chip> Drop for Registration<T> {
+    /// Removes the registration from the kernel if it has completed successfully before.
+    fn drop(&mut self) {
+        if self.parent.is_some() {
+            // Get a pointer to the data stored in chip before destroying it.
+            // SAFETY: `gc` was during registration, which is guaranteed to have succeeded (because
+            // `parent` is `Some(_)`, so it remains valid.
+            let data_pointer = unsafe { bindings::gpiochip_get_data(self.gc.get()) };
+
+            // SAFETY: By the same argument above, `gc` is still valid.
+            unsafe { bindings::gpiochip_remove(self.gc.get()) };
+
+            // Free data as well.
+            // SAFETY: `data_pointer` was returned by `into_pointer` during registration.
+            unsafe { <T::Data as PointerWrapper>::from_pointer(data_pointer) };
+        }
+    }
+}
+
+/// Registers a gpio chip with the rest of the kernel.
+///
+/// It automatically defines the required lock classes.
+#[macro_export]
+macro_rules! gpio_chip_register {
+    ($reg:expr, $count:expr, $base:expr, $parent:expr, $data:expr $(,)?) => {{
+        static CLASS1: $crate::sync::LockClassKey = $crate::sync::LockClassKey::new();
+        static CLASS2: $crate::sync::LockClassKey = $crate::sync::LockClassKey::new();
+        $crate::gpio::Registration::register(
+            $reg,
+            $count,
+            $base,
+            $parent,
+            $data,
+            [&CLASS1, &CLASS2],
+        )
+    }};
+}
+
+unsafe extern "C" fn get_direction_callback<T: Chip>(
+    gc: *mut bindings::gpio_chip,
+    offset: core::ffi::c_uint,
+) -> core::ffi::c_int {
+    from_kernel_result! {
+        // SAFETY: The value stored as chip data was returned by `into_pointer` during registration.
+        let data = unsafe { T::Data::borrow(bindings::gpiochip_get_data(gc)) };
+        Ok(T::get_direction(data, offset)? as i32)
+    }
+}
+
+unsafe extern "C" fn direction_input_callback<T: Chip>(
+    gc: *mut bindings::gpio_chip,
+    offset: core::ffi::c_uint,
+) -> core::ffi::c_int {
+    from_kernel_result! {
+        // SAFETY: The value stored as chip data was returned by `into_pointer` during registration.
+        let data = unsafe { T::Data::borrow(bindings::gpiochip_get_data(gc)) };
+        T::direction_input(data, offset)?;
+        Ok(0)
+    }
+}
+
+unsafe extern "C" fn direction_output_callback<T: Chip>(
+    gc: *mut bindings::gpio_chip,
+    offset: core::ffi::c_uint,
+    value: core::ffi::c_int,
+) -> core::ffi::c_int {
+    from_kernel_result! {
+        // SAFETY: The value stored as chip data was returned by `into_pointer` during registration.
+        let data = unsafe { T::Data::borrow(bindings::gpiochip_get_data(gc)) };
+        T::direction_output(data, offset, value != 0)?;
+        Ok(0)
+    }
+}
+
+unsafe extern "C" fn get_callback<T: Chip>(
+    gc: *mut bindings::gpio_chip,
+    offset: core::ffi::c_uint,
+) -> core::ffi::c_int {
+    from_kernel_result! {
+        // SAFETY: The value stored as chip data was returned by `into_pointer` during registration.
+        let data = unsafe { T::Data::borrow(bindings::gpiochip_get_data(gc)) };
+        let v = T::get(data, offset)?;
+        Ok(v as _)
+    }
+}
+
+unsafe extern "C" fn set_callback<T: Chip>(
+    gc: *mut bindings::gpio_chip,
+    offset: core::ffi::c_uint,
+    value: core::ffi::c_int,
+) {
+    // SAFETY: The value stored as chip data was returned by `into_pointer` during registration.
+    let data = unsafe { T::Data::borrow(bindings::gpiochip_get_data(gc)) };
+    T::set(data, offset, value != 0);
+}
+
+#[cfg(CONFIG_GPIOLIB_IRQCHIP)]
+mod irqchip {
+    use super::*;
+    use crate::irq;
+
+    /// A gpio chip that includes an irq chip.
+    pub trait ChipWithIrqChip: Chip {
+        /// Implements the irq flow for the gpio chip.
+        fn handle_irq_flow(
+            _data: <Self::Data as PointerWrapper>::Borrowed<'_>,
+            _desc: &irq::Descriptor,
+            _domain: &irq::Domain,
+        );
+    }
+
+    /// A registration of a gpio chip that includes an irq chip.
+    pub struct RegistrationWithIrqChip<T: ChipWithIrqChip> {
+        reg: Registration<T>,
+        irq_chip: UnsafeCell<bindings::irq_chip>,
+        parent_irq: u32,
+    }
+
+    impl<T: ChipWithIrqChip> RegistrationWithIrqChip<T> {
+        /// Creates a new [`RegistrationWithIrqChip`] but does not register it yet.
+        ///
+        /// It is allowed to move.
+        pub fn new() -> Self {
+            Self {
+                reg: Registration::new(),
+                irq_chip: UnsafeCell::new(bindings::irq_chip::default()),
+                parent_irq: 0,
+            }
+        }
+
+        /// Registers a gpio chip and its irq chip with the rest of the kernel.
+        ///
+        /// Users are encouraged to use the [`gpio_irq_chip_register`] macro because it
+        /// automatically defines the lock classes and calls the registration function.
+        pub fn register<U: irq::Chip<Data = T::Data>>(
+            mut self: Pin<&mut Self>,
+            gpio_count: u16,
+            base: Option<i32>,
+            parent: &dyn device::RawDevice,
+            data: T::Data,
+            parent_irq: u32,
+            lock_keys: [&'static LockClassKey; 2],
+        ) -> Result {
+            if self.reg.parent.is_some() {
+                // Already registered.
+                return Err(EINVAL);
+            }
+
+            // SAFETY: We never move out of `this`.
+            let this = unsafe { self.as_mut().get_unchecked_mut() };
+
+            // Initialise the irq_chip.
+            {
+                let irq_chip = this.irq_chip.get_mut();
+                irq_chip.name = parent.name().as_char_ptr();
+
+                // SAFETY: The gpio subsystem configures a pointer to `gpio_chip` as the irq chip
+                // data, so we use `IrqChipAdapter` to convert to the `T::Data`, which is the same
+                // as `irq::Chip::Data` per the bound above.
+                unsafe { irq::init_chip::<IrqChipAdapter<U>>(irq_chip) };
+            }
+
+            // Initialise gc irq state.
+            {
+                let girq = &mut this.reg.gc.get_mut().irq;
+                girq.chip = this.irq_chip.get();
+                // SAFETY: By leaving `parent_handler_data` set to `null`, the gpio subsystem
+                // initialises it to a pointer to the gpio chip, which is what `FlowHandler<T>`
+                // expects.
+                girq.parent_handler = unsafe { irq::new_flow_handler::<FlowHandler<T>>() };
+                girq.num_parents = 1;
+                girq.parents = &mut this.parent_irq;
+                this.parent_irq = parent_irq;
+                girq.default_type = bindings::IRQ_TYPE_NONE;
+                girq.handler = Some(bindings::handle_bad_irq);
+            }
+
+            // SAFETY: `reg` is pinned when `self` is.
+            let pinned = unsafe { self.map_unchecked_mut(|r| &mut r.reg) };
+            pinned.register(gpio_count, base, parent, data, lock_keys)
+        }
+    }
+
+    impl<T: ChipWithIrqChip> Default for RegistrationWithIrqChip<T> {
+        fn default() -> Self {
+            Self::new()
+        }
+    }
+
+    // SAFETY: `RegistrationWithIrqChip` doesn't offer any methods or access to fields when shared
+    // between threads or CPUs, so it is safe to share it.
+    unsafe impl<T: ChipWithIrqChip> Sync for RegistrationWithIrqChip<T> {}
+
+    // SAFETY: Registration with and unregistration from the gpio subsystem (including irq chips for
+    // them) can happen from any thread. Additionally, `T::Data` (which is dropped during
+    // unregistration) is `Send`, so it is ok to move `Registration` to different threads.
+    #[allow(clippy::non_send_fields_in_send_ty)]
+    unsafe impl<T: ChipWithIrqChip> Send for RegistrationWithIrqChip<T> where T::Data: Send {}
+
+    struct FlowHandler<T: ChipWithIrqChip>(PhantomData<T>);
+
+    impl<T: ChipWithIrqChip> irq::FlowHandler for FlowHandler<T> {
+        type Data = *mut bindings::gpio_chip;
+
+        fn handle_irq_flow(gc: *mut bindings::gpio_chip, desc: &irq::Descriptor) {
+            // SAFETY: `FlowHandler` is only used in gpio chips, and it is removed when the gpio is
+            // unregistered, so we know that `gc` must still be valid. We also know that the value
+            // stored as gpio data was returned by `T::Data::into_pointer` again because
+            // `FlowHandler` is a private structure only used in this way.
+            let data = unsafe { T::Data::borrow(bindings::gpiochip_get_data(gc)) };
+
+            // SAFETY: `gc` is valid (see comment above), so we can dereference it.
+            let domain = unsafe { irq::Domain::from_ptr((*gc).irq.domain) };
+
+            T::handle_irq_flow(data, desc, &domain);
+        }
+    }
+
+    /// Adapter from an irq chip with `gpio_chip` pointer as context to one where the gpio chip
+    /// data is passed as context.
+    struct IrqChipAdapter<T: irq::Chip>(PhantomData<T>);
+
+    #[vtable]
+    impl<T: irq::Chip> irq::Chip for IrqChipAdapter<T> {
+        type Data = *mut bindings::gpio_chip;
+
+        const HAS_SET_TYPE: bool = T::HAS_SET_TYPE;
+        const HAS_SET_WAKE: bool = T::HAS_SET_WAKE;
+
+        fn ack(gc: *mut bindings::gpio_chip, irq_data: &irq::IrqData) {
+            // SAFETY: `IrqChipAdapter` is a private struct, only used when the data stored in the
+            // gpio chip is known to come from `T::Data`, and only valid while the gpio chip is
+            // registered, so `gc` is valid.
+            let data = unsafe { T::Data::borrow(bindings::gpiochip_get_data(gc as _)) };
+            T::ack(data, irq_data);
+        }
+
+        fn mask(gc: *mut bindings::gpio_chip, irq_data: &irq::IrqData) {
+            // SAFETY: `IrqChipAdapter` is a private struct, only used when the data stored in the
+            // gpio chip is known to come from `T::Data`, and only valid while the gpio chip is
+            // registered, so `gc` is valid.
+            let data = unsafe { T::Data::borrow(bindings::gpiochip_get_data(gc as _)) };
+            T::mask(data, irq_data);
+        }
+
+        fn unmask(gc: *mut bindings::gpio_chip, irq_data: &irq::IrqData) {
+            // SAFETY: `IrqChipAdapter` is a private struct, only used when the data stored in the
+            // gpio chip is known to come from `T::Data`, and only valid while the gpio chip is
+            // registered, so `gc` is valid.
+            let data = unsafe { T::Data::borrow(bindings::gpiochip_get_data(gc as _)) };
+            T::unmask(data, irq_data);
+        }
+
+        fn set_type(
+            gc: *mut bindings::gpio_chip,
+            irq_data: &mut irq::LockedIrqData,
+            flow_type: u32,
+        ) -> Result<irq::ExtraResult> {
+            // SAFETY: `IrqChipAdapter` is a private struct, only used when the data stored in the
+            // gpio chip is known to come from `T::Data`, and only valid while the gpio chip is
+            // registered, so `gc` is valid.
+            let data = unsafe { T::Data::borrow(bindings::gpiochip_get_data(gc as _)) };
+            T::set_type(data, irq_data, flow_type)
+        }
+
+        fn set_wake(gc: *mut bindings::gpio_chip, irq_data: &irq::IrqData, on: bool) -> Result {
+            // SAFETY: `IrqChipAdapter` is a private struct, only used when the data stored in the
+            // gpio chip is known to come from `T::Data`, and only valid while the gpio chip is
+            // registered, so `gc` is valid.
+            let data = unsafe { T::Data::borrow(bindings::gpiochip_get_data(gc as _)) };
+            T::set_wake(data, irq_data, on)
+        }
+    }
+
+    /// Registers a gpio chip and its irq chip with the rest of the kernel.
+    ///
+    /// It automatically defines the required lock classes.
+    #[macro_export]
+    macro_rules! gpio_irq_chip_register {
+        ($reg:expr, $irqchip:ty, $count:expr, $base:expr, $parent:expr, $data:expr,
+         $parent_irq:expr $(,)?) => {{
+            static CLASS1: $crate::sync::LockClassKey = $crate::sync::LockClassKey::new();
+            static CLASS2: $crate::sync::LockClassKey = $crate::sync::LockClassKey::new();
+            $crate::gpio::RegistrationWithIrqChip::register::<$irqchip>(
+                $reg,
+                $count,
+                $base,
+                $parent,
+                $data,
+                $parent_irq,
+                [&CLASS1, &CLASS2],
+            )
+        }};
+    }
+}
diff --git a/rust/kernel/hwrng.rs b/rust/kernel/hwrng.rs
new file mode 100644
index 000000000000..5918f567c332
--- /dev/null
+++ b/rust/kernel/hwrng.rs
@@ -0,0 +1,210 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Hardware Random Number Generator.
+//!
+//! C header: [`include/linux/hw_random.h`](../../../../include/linux/hw_random.h)
+
+use alloc::{boxed::Box, slice::from_raw_parts_mut};
+
+use crate::{
+    bindings, error::code::*, error::from_kernel_result, str::CString, to_result,
+    types::PointerWrapper, Result, ScopeGuard,
+};
+use macros::vtable;
+
+use core::{cell::UnsafeCell, fmt, marker::PhantomData, pin::Pin};
+
+/// This trait is implemented in order to provide callbacks to `struct hwrng`.
+#[vtable]
+pub trait Operations {
+    /// The pointer type that will be used to hold user-defined data type.
+    type Data: PointerWrapper + Send + Sync = ();
+
+    /// Initialization callback, can be left undefined.
+    fn init(_data: <Self::Data as PointerWrapper>::Borrowed<'_>) -> Result {
+        Err(EINVAL)
+    }
+
+    /// Cleanup callback, can be left undefined.
+    fn cleanup(_data: Self::Data) {}
+
+    /// Read data into the provided buffer.
+    /// Drivers can fill up to max bytes of data into the buffer.
+    /// The buffer is aligned for any type and its size is a multiple of 4 and >= 32 bytes.
+    fn read(
+        data: <Self::Data as PointerWrapper>::Borrowed<'_>,
+        buffer: &mut [u8],
+        wait: bool,
+    ) -> Result<u32>;
+}
+
+/// Registration structure for Hardware Random Number Generator driver.
+pub struct Registration<T: Operations> {
+    hwrng: UnsafeCell<bindings::hwrng>,
+    name: Option<CString>,
+    registered: bool,
+    _p: PhantomData<T>,
+}
+
+impl<T: Operations> Registration<T> {
+    /// Creates new instance of registration.
+    ///
+    /// The data must be registered.
+    pub fn new() -> Self {
+        Self {
+            hwrng: UnsafeCell::new(bindings::hwrng::default()),
+            name: None,
+            registered: false,
+            _p: PhantomData,
+        }
+    }
+
+    /// Returns a registered and pinned, heap-allocated representation of the registration.
+    pub fn new_pinned(
+        name: fmt::Arguments<'_>,
+        quality: u16,
+        data: T::Data,
+    ) -> Result<Pin<Box<Self>>> {
+        let mut reg = Pin::from(Box::try_new(Self::new())?);
+        reg.as_mut().register(name, quality, data)?;
+        Ok(reg)
+    }
+
+    /// Registers a hwrng device within the rest of the kernel.
+    ///
+    /// It must be pinned because the memory block that represents
+    /// the registration may be self-referential.
+    pub fn register(
+        self: Pin<&mut Self>,
+        name: fmt::Arguments<'_>,
+        quality: u16,
+        data: T::Data,
+    ) -> Result {
+        // SAFETY: We never move out of `this`.
+        let this = unsafe { self.get_unchecked_mut() };
+
+        if this.registered {
+            return Err(EINVAL);
+        }
+
+        let data_pointer = data.into_pointer();
+
+        // SAFETY: `data_pointer` comes from the call to `data.into_pointer()` above.
+        let guard = ScopeGuard::new(|| unsafe {
+            T::Data::from_pointer(data_pointer);
+        });
+
+        let name = CString::try_from_fmt(name)?;
+
+        // SAFETY: Registration is pinned and contains allocated and set to zero
+        // `bindings::hwrng` structure.
+        Self::init_hwrng(
+            unsafe { &mut *this.hwrng.get() },
+            &name,
+            quality,
+            data_pointer,
+        );
+
+        // SAFETY: `bindings::hwrng` is initialized above which guarantees safety.
+        to_result(unsafe { bindings::hwrng_register(this.hwrng.get()) })?;
+
+        this.registered = true;
+        this.name = Some(name);
+        guard.dismiss();
+        Ok(())
+    }
+
+    fn init_hwrng(
+        hwrng: &mut bindings::hwrng,
+        name: &CString,
+        quality: u16,
+        data: *const core::ffi::c_void,
+    ) {
+        hwrng.name = name.as_char_ptr();
+
+        hwrng.init = if T::HAS_INIT {
+            Some(Self::init_callback)
+        } else {
+            None
+        };
+        hwrng.cleanup = if T::HAS_CLEANUP {
+            Some(Self::cleanup_callback)
+        } else {
+            None
+        };
+        hwrng.data_present = None;
+        hwrng.data_read = None;
+        hwrng.read = Some(Self::read_callback);
+
+        hwrng.priv_ = data as _;
+        hwrng.quality = quality;
+
+        // SAFETY: All fields are properly initialized as
+        // remaining fields `list`, `ref` and `cleanup_done` are already
+        // zeroed by `bindings::hwrng::default()` call.
+    }
+
+    unsafe extern "C" fn init_callback(rng: *mut bindings::hwrng) -> core::ffi::c_int {
+        from_kernel_result! {
+            // SAFETY: `priv` private data field was initialized during creation of
+            // the `bindings::hwrng` in `Self::init_hwrng` method. This callback is only
+            // called once the driver is registered.
+            let data = unsafe { T::Data::borrow((*rng).priv_ as *const _) };
+            T::init(data)?;
+            Ok(0)
+        }
+    }
+
+    unsafe extern "C" fn cleanup_callback(rng: *mut bindings::hwrng) {
+        // SAFETY: `priv` private data field was initialized during creation of
+        // the `bindings::hwrng` in `Self::init_hwrng` method. This callback is only
+        // called once the driver is registered.
+        let data = unsafe { T::Data::from_pointer((*rng).priv_ as *const _) };
+        T::cleanup(data);
+    }
+
+    unsafe extern "C" fn read_callback(
+        rng: *mut bindings::hwrng,
+        data: *mut core::ffi::c_void,
+        max: usize,
+        wait: bindings::bool_,
+    ) -> core::ffi::c_int {
+        from_kernel_result! {
+            // SAFETY: `priv` private data field was initialized during creation of
+            // the `bindings::hwrng` in `Self::init_hwrng` method. This callback is only
+            // called once the driver is registered.
+            let drv_data = unsafe { T::Data::borrow((*rng).priv_ as *const _) };
+
+            // SAFETY: Slice is created from `data` and `max` arguments that are C's buffer
+            // along with its size in bytes that are safe for this conversion.
+            let buffer = unsafe { from_raw_parts_mut(data as *mut u8, max) };
+            let ret = T::read(drv_data, buffer, wait)?;
+            Ok(ret as _)
+        }
+    }
+}
+
+impl<T: Operations> Default for Registration<T> {
+    fn default() -> Self {
+        Self::new()
+    }
+}
+
+// SAFETY: `Registration` does not expose any of its state across threads.
+unsafe impl<T: Operations> Sync for Registration<T> {}
+
+// SAFETY: `Registration` is not restricted to a single thread,
+// its `T::Data` is also `Send` so it may be moved to different threads.
+#[allow(clippy::non_send_fields_in_send_ty)]
+unsafe impl<T: Operations> Send for Registration<T> {}
+
+impl<T: Operations> Drop for Registration<T> {
+    /// Removes the registration from the kernel if it has completed successfully before.
+    fn drop(&mut self) {
+        // SAFETY: The instance of Registration<T> is unregistered only
+        // after being initialized and registered before.
+        if self.registered {
+            unsafe { bindings::hwrng_unregister(self.hwrng.get()) };
+        }
+    }
+}
diff --git a/rust/kernel/io_buffer.rs b/rust/kernel/io_buffer.rs
new file mode 100644
index 000000000000..ccecc4763aca
--- /dev/null
+++ b/rust/kernel/io_buffer.rs
@@ -0,0 +1,153 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Buffers used in IO.
+
+use crate::Result;
+use alloc::vec::Vec;
+use core::mem::{size_of, MaybeUninit};
+
+/// Represents a buffer to be read from during IO.
+pub trait IoBufferReader {
+    /// Returns the number of bytes left to be read from the io buffer.
+    ///
+    /// Note that even reading less than this number of bytes may fail.
+    fn len(&self) -> usize;
+
+    /// Returns `true` if no data is available in the io buffer.
+    fn is_empty(&self) -> bool {
+        self.len() == 0
+    }
+
+    /// Reads raw data from the io buffer into a raw kernel buffer.
+    ///
+    /// # Safety
+    ///
+    /// The output buffer must be valid.
+    unsafe fn read_raw(&mut self, out: *mut u8, len: usize) -> Result;
+
+    /// Reads all data remaining in the io buffer.
+    ///
+    /// Returns `EFAULT` if the address does not currently point to mapped, readable memory.
+    fn read_all(&mut self) -> Result<Vec<u8>> {
+        let mut data = Vec::<u8>::new();
+        data.try_resize(self.len(), 0)?;
+
+        // SAFETY: The output buffer is valid as we just allocated it.
+        unsafe { self.read_raw(data.as_mut_ptr(), data.len())? };
+        Ok(data)
+    }
+
+    /// Reads a byte slice from the io buffer.
+    ///
+    /// Returns `EFAULT` if the byte slice is bigger than the remaining size of the user slice or
+    /// if the address does not currently point to mapped, readable memory.
+    fn read_slice(&mut self, data: &mut [u8]) -> Result {
+        // SAFETY: The output buffer is valid as it's coming from a live reference.
+        unsafe { self.read_raw(data.as_mut_ptr(), data.len()) }
+    }
+
+    /// Reads the contents of a plain old data (POD) type from the io buffer.
+    fn read<T: ReadableFromBytes>(&mut self) -> Result<T> {
+        let mut out = MaybeUninit::<T>::uninit();
+        // SAFETY: The buffer is valid as it was just allocated.
+        unsafe { self.read_raw(out.as_mut_ptr() as _, size_of::<T>()) }?;
+        // SAFETY: We just initialised the data.
+        Ok(unsafe { out.assume_init() })
+    }
+}
+
+/// Represents a buffer to be written to during IO.
+pub trait IoBufferWriter {
+    /// Returns the number of bytes left to be written into the io buffer.
+    ///
+    /// Note that even writing less than this number of bytes may fail.
+    fn len(&self) -> usize;
+
+    /// Returns `true` if the io buffer cannot hold any additional data.
+    fn is_empty(&self) -> bool {
+        self.len() == 0
+    }
+
+    /// Writes zeroes to the io buffer.
+    ///
+    /// Differently from the other write functions, `clear` will zero as much as it can and update
+    /// the writer internal state to reflect this. It will, however, return an error if it cannot
+    /// clear `len` bytes.
+    ///
+    /// For example, if a caller requests that 100 bytes be cleared but a segfault happens after
+    /// 20 bytes, then EFAULT is returned and the writer is advanced by 20 bytes.
+    fn clear(&mut self, len: usize) -> Result;
+
+    /// Writes a byte slice into the io buffer.
+    ///
+    /// Returns `EFAULT` if the byte slice is bigger than the remaining size of the io buffer or if
+    /// the address does not currently point to mapped, writable memory.
+    fn write_slice(&mut self, data: &[u8]) -> Result {
+        // SAFETY: The input buffer is valid as it's coming from a live reference.
+        unsafe { self.write_raw(data.as_ptr(), data.len()) }
+    }
+
+    /// Writes raw data to the io buffer from a raw kernel buffer.
+    ///
+    /// # Safety
+    ///
+    /// The input buffer must be valid.
+    unsafe fn write_raw(&mut self, data: *const u8, len: usize) -> Result;
+
+    /// Writes the contents of the given data into the io buffer.
+    fn write<T: WritableToBytes>(&mut self, data: &T) -> Result {
+        // SAFETY: The input buffer is valid as it's coming from a live
+        // reference to a type that implements `WritableToBytes`.
+        unsafe { self.write_raw(data as *const T as _, size_of::<T>()) }
+    }
+}
+
+/// Specifies that a type is safely readable from byte slices.
+///
+/// Not all types can be safely read from byte slices; examples from
+/// <https://doc.rust-lang.org/reference/behavior-considered-undefined.html> include `bool`
+/// that must be either `0` or `1`, and `char` that cannot be a surrogate or above `char::MAX`.
+///
+/// # Safety
+///
+/// Implementers must ensure that the type is made up only of types that can be safely read from
+/// arbitrary byte sequences (e.g., `u32`, `u64`, etc.).
+pub unsafe trait ReadableFromBytes {}
+
+// SAFETY: All bit patterns are acceptable values of the types below.
+unsafe impl ReadableFromBytes for u8 {}
+unsafe impl ReadableFromBytes for u16 {}
+unsafe impl ReadableFromBytes for u32 {}
+unsafe impl ReadableFromBytes for u64 {}
+unsafe impl ReadableFromBytes for usize {}
+unsafe impl ReadableFromBytes for i8 {}
+unsafe impl ReadableFromBytes for i16 {}
+unsafe impl ReadableFromBytes for i32 {}
+unsafe impl ReadableFromBytes for i64 {}
+unsafe impl ReadableFromBytes for isize {}
+
+/// Specifies that a type is safely writable to byte slices.
+///
+/// This means that we don't read undefined values (which leads to UB) in preparation for writing
+/// to the byte slice. It also ensures that no potentially sensitive information is leaked into the
+/// byte slices.
+///
+/// # Safety
+///
+/// A type must not include padding bytes and must be fully initialised to safely implement
+/// [`WritableToBytes`] (i.e., it doesn't contain [`MaybeUninit`] fields). A composition of
+/// writable types in a structure is not necessarily writable because it may result in padding
+/// bytes.
+pub unsafe trait WritableToBytes {}
+
+// SAFETY: Initialised instances of the following types have no uninitialised portions.
+unsafe impl WritableToBytes for u8 {}
+unsafe impl WritableToBytes for u16 {}
+unsafe impl WritableToBytes for u32 {}
+unsafe impl WritableToBytes for u64 {}
+unsafe impl WritableToBytes for usize {}
+unsafe impl WritableToBytes for i8 {}
+unsafe impl WritableToBytes for i16 {}
+unsafe impl WritableToBytes for i32 {}
+unsafe impl WritableToBytes for i64 {}
+unsafe impl WritableToBytes for isize {}
diff --git a/rust/kernel/io_mem.rs b/rust/kernel/io_mem.rs
new file mode 100644
index 000000000000..ff6886a9e3b7
--- /dev/null
+++ b/rust/kernel/io_mem.rs
@@ -0,0 +1,278 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Memory-mapped IO.
+//!
+//! C header: [`include/asm-generic/io.h`](../../../../include/asm-generic/io.h)
+
+#![allow(dead_code)]
+
+use crate::{bindings, error::code::*, Result};
+use core::convert::TryInto;
+
+/// Represents a memory resource.
+pub struct Resource {
+    offset: bindings::resource_size_t,
+    size: bindings::resource_size_t,
+}
+
+impl Resource {
+    pub(crate) fn new(
+        start: bindings::resource_size_t,
+        end: bindings::resource_size_t,
+    ) -> Option<Self> {
+        if start == 0 {
+            return None;
+        }
+        Some(Self {
+            offset: start,
+            size: end.checked_sub(start)?.checked_add(1)?,
+        })
+    }
+}
+
+/// Represents a memory block of at least `SIZE` bytes.
+///
+/// # Invariants
+///
+/// `ptr` is a non-null and valid address of at least `SIZE` bytes and returned by an `ioremap`
+/// variant. `ptr` is also 8-byte aligned.
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::prelude::*;
+/// use kernel::io_mem::{IoMem, Resource};
+///
+/// fn test(res: Resource) -> Result {
+///     // Create an io mem block of at least 100 bytes.
+///     // SAFETY: No DMA operations are initiated through `mem`.
+///     let mem = unsafe { IoMem::<100>::try_new(res) }?;
+///
+///     // Read one byte from offset 10.
+///     let v = mem.readb(10);
+///
+///     // Write value to offset 20.
+///     mem.writeb(v, 20);
+///
+///     Ok(())
+/// }
+/// ```
+pub struct IoMem<const SIZE: usize> {
+    ptr: usize,
+}
+
+macro_rules! define_read {
+    ($(#[$attr:meta])* $name:ident, $try_name:ident, $type_name:ty) => {
+        /// Reads IO data from the given offset known, at compile time.
+        ///
+        /// If the offset is not known at compile time, the build will fail.
+        $(#[$attr])*
+        #[inline]
+        pub fn $name(&self, offset: usize) -> $type_name {
+            Self::check_offset::<$type_name>(offset);
+            let ptr = self.ptr.wrapping_add(offset);
+            // SAFETY: The type invariants guarantee that `ptr` is a valid pointer. The check above
+            // guarantees that the code won't build if `offset` makes the read go out of bounds
+            // (including the type size).
+            unsafe { bindings::$name(ptr as _) }
+        }
+
+        /// Reads IO data from the given offset.
+        ///
+        /// It fails if/when the offset (plus the type size) is out of bounds.
+        $(#[$attr])*
+        pub fn $try_name(&self, offset: usize) -> Result<$type_name> {
+            if !Self::offset_ok::<$type_name>(offset) {
+                return Err(EINVAL);
+            }
+            let ptr = self.ptr.wrapping_add(offset);
+            // SAFETY: The type invariants guarantee that `ptr` is a valid pointer. The check above
+            // returns an error if `offset` would make the read go out of bounds (including the
+            // type size).
+            Ok(unsafe { bindings::$name(ptr as _) })
+        }
+    };
+}
+
+macro_rules! define_write {
+    ($(#[$attr:meta])* $name:ident, $try_name:ident, $type_name:ty) => {
+        /// Writes IO data to the given offset, known at compile time.
+        ///
+        /// If the offset is not known at compile time, the build will fail.
+        $(#[$attr])*
+        #[inline]
+        pub fn $name(&self, value: $type_name, offset: usize) {
+            Self::check_offset::<$type_name>(offset);
+            let ptr = self.ptr.wrapping_add(offset);
+            // SAFETY: The type invariants guarantee that `ptr` is a valid pointer. The check above
+            // guarantees that the code won't link if `offset` makes the write go out of bounds
+            // (including the type size).
+            unsafe { bindings::$name(value, ptr as _) }
+        }
+
+        /// Writes IO data to the given offset.
+        ///
+        /// It fails if/when the offset (plus the type size) is out of bounds.
+        $(#[$attr])*
+        pub fn $try_name(&self, value: $type_name, offset: usize) -> Result {
+            if !Self::offset_ok::<$type_name>(offset) {
+                return Err(EINVAL);
+            }
+            let ptr = self.ptr.wrapping_add(offset);
+            // SAFETY: The type invariants guarantee that `ptr` is a valid pointer. The check above
+            // returns an error if `offset` would make the write go out of bounds (including the
+            // type size).
+            unsafe { bindings::$name(value, ptr as _) };
+            Ok(())
+        }
+    };
+}
+
+impl<const SIZE: usize> IoMem<SIZE> {
+    /// Tries to create a new instance of a memory block.
+    ///
+    /// The resource described by `res` is mapped into the CPU's address space so that it can be
+    /// accessed directly. It is also consumed by this function so that it can't be mapped again
+    /// to a different address.
+    ///
+    /// # Safety
+    ///
+    /// Callers must ensure that either (a) the resulting interface cannot be used to initiate DMA
+    /// operations, or (b) that DMA operations initiated via the returned interface use DMA handles
+    /// allocated through the `dma` module.
+    pub unsafe fn try_new(res: Resource) -> Result<Self> {
+        // Check that the resource has at least `SIZE` bytes in it.
+        if res.size < SIZE.try_into()? {
+            return Err(EINVAL);
+        }
+
+        // To be able to check pointers at compile time based only on offsets, we need to guarantee
+        // that the base pointer is minimally aligned. So we conservatively expect at least 8 bytes.
+        if res.offset % 8 != 0 {
+            crate::pr_err!("Physical address is not 64-bit aligned: {:x}", res.offset);
+            return Err(EDOM);
+        }
+
+        // Try to map the resource.
+        // SAFETY: Just mapping the memory range.
+        let addr = unsafe { bindings::ioremap(res.offset, res.size as _) };
+        if addr.is_null() {
+            Err(ENOMEM)
+        } else {
+            // INVARIANT: `addr` is non-null and was returned by `ioremap`, so it is valid. It is
+            // also 8-byte aligned because we checked it above.
+            Ok(Self { ptr: addr as usize })
+        }
+    }
+
+    #[inline]
+    const fn offset_ok<T>(offset: usize) -> bool {
+        let type_size = core::mem::size_of::<T>();
+        if let Some(end) = offset.checked_add(type_size) {
+            end <= SIZE && offset % type_size == 0
+        } else {
+            false
+        }
+    }
+
+    fn offset_ok_of_val<T: ?Sized>(offset: usize, value: &T) -> bool {
+        let value_size = core::mem::size_of_val(value);
+        let value_alignment = core::mem::align_of_val(value);
+        if let Some(end) = offset.checked_add(value_size) {
+            end <= SIZE && offset % value_alignment == 0
+        } else {
+            false
+        }
+    }
+
+    #[inline]
+    const fn check_offset<T>(offset: usize) {
+        crate::build_assert!(Self::offset_ok::<T>(offset), "IoMem offset overflow");
+    }
+
+    /// Copy memory block from an i/o memory by filling the specified buffer with it.
+    ///
+    /// # Examples
+    /// ```
+    /// use kernel::io_mem::{self, IoMem, Resource};
+    ///
+    /// fn test(res: Resource) -> Result {
+    ///     // Create an i/o memory block of at least 100 bytes.
+    ///     let mem = unsafe { IoMem::<100>::try_new(res) }?;
+    ///
+    ///     let mut buffer: [u8; 32] = [0; 32];
+    ///
+    ///     // Memcpy 16 bytes from an offset 10 of i/o memory block into the buffer.
+    ///     mem.try_memcpy_fromio(&mut buffer[..16], 10)?;
+    ///
+    ///     Ok(())
+    /// }
+    /// ```
+    pub fn try_memcpy_fromio(&self, buffer: &mut [u8], offset: usize) -> Result {
+        if !Self::offset_ok_of_val(offset, buffer) {
+            return Err(EINVAL);
+        }
+
+        let ptr = self.ptr.wrapping_add(offset);
+
+        // SAFETY:
+        //   - The type invariants guarantee that `ptr` is a valid pointer.
+        //   - The bounds of `buffer` are checked with a call to `offset_ok_of_val()`.
+        unsafe {
+            bindings::memcpy_fromio(
+                buffer.as_mut_ptr() as *mut _,
+                ptr as *const _,
+                buffer.len() as _,
+            )
+        };
+        Ok(())
+    }
+
+    define_read!(readb, try_readb, u8);
+    define_read!(readw, try_readw, u16);
+    define_read!(readl, try_readl, u32);
+    define_read!(
+        #[cfg(CONFIG_64BIT)]
+        readq,
+        try_readq,
+        u64
+    );
+
+    define_read!(readb_relaxed, try_readb_relaxed, u8);
+    define_read!(readw_relaxed, try_readw_relaxed, u16);
+    define_read!(readl_relaxed, try_readl_relaxed, u32);
+    define_read!(
+        #[cfg(CONFIG_64BIT)]
+        readq_relaxed,
+        try_readq_relaxed,
+        u64
+    );
+
+    define_write!(writeb, try_writeb, u8);
+    define_write!(writew, try_writew, u16);
+    define_write!(writel, try_writel, u32);
+    define_write!(
+        #[cfg(CONFIG_64BIT)]
+        writeq,
+        try_writeq,
+        u64
+    );
+
+    define_write!(writeb_relaxed, try_writeb_relaxed, u8);
+    define_write!(writew_relaxed, try_writew_relaxed, u16);
+    define_write!(writel_relaxed, try_writel_relaxed, u32);
+    define_write!(
+        #[cfg(CONFIG_64BIT)]
+        writeq_relaxed,
+        try_writeq_relaxed,
+        u64
+    );
+}
+
+impl<const SIZE: usize> Drop for IoMem<SIZE> {
+    fn drop(&mut self) {
+        // SAFETY: By the type invariant, `self.ptr` is a value returned by a previous successful
+        // call to `ioremap`.
+        unsafe { bindings::iounmap(self.ptr as _) };
+    }
+}
diff --git a/rust/kernel/iov_iter.rs b/rust/kernel/iov_iter.rs
new file mode 100644
index 000000000000..b9b8dc882bd0
--- /dev/null
+++ b/rust/kernel/iov_iter.rs
@@ -0,0 +1,81 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! IO vector iterators.
+//!
+//! C header: [`include/linux/uio.h`](../../../../include/linux/uio.h)
+
+use crate::{
+    bindings,
+    error::code::*,
+    io_buffer::{IoBufferReader, IoBufferWriter},
+    Result,
+};
+
+/// Wraps the kernel's `struct iov_iter`.
+///
+/// # Invariants
+///
+/// The pointer `IovIter::ptr` is non-null and valid.
+pub struct IovIter {
+    ptr: *mut bindings::iov_iter,
+}
+
+impl IovIter {
+    fn common_len(&self) -> usize {
+        // SAFETY: `IovIter::ptr` is guaranteed to be valid by the type invariants.
+        unsafe { (*self.ptr).count }
+    }
+
+    /// Constructs a new [`struct iov_iter`] wrapper.
+    ///
+    /// # Safety
+    ///
+    /// The pointer `ptr` must be non-null and valid for the lifetime of the object.
+    pub(crate) unsafe fn from_ptr(ptr: *mut bindings::iov_iter) -> Self {
+        // INVARIANTS: the safety contract ensures the type invariant will hold.
+        Self { ptr }
+    }
+}
+
+impl IoBufferWriter for IovIter {
+    fn len(&self) -> usize {
+        self.common_len()
+    }
+
+    fn clear(&mut self, mut len: usize) -> Result {
+        while len > 0 {
+            // SAFETY: `IovIter::ptr` is guaranteed to be valid by the type invariants.
+            let written = unsafe { bindings::iov_iter_zero(len, self.ptr) };
+            if written == 0 {
+                return Err(EFAULT);
+            }
+
+            len -= written;
+        }
+        Ok(())
+    }
+
+    unsafe fn write_raw(&mut self, data: *const u8, len: usize) -> Result {
+        let res = unsafe { bindings::copy_to_iter(data as _, len, self.ptr) };
+        if res != len {
+            Err(EFAULT)
+        } else {
+            Ok(())
+        }
+    }
+}
+
+impl IoBufferReader for IovIter {
+    fn len(&self) -> usize {
+        self.common_len()
+    }
+
+    unsafe fn read_raw(&mut self, out: *mut u8, len: usize) -> Result {
+        let res = unsafe { bindings::copy_from_iter(out as _, len, self.ptr) };
+        if res != len {
+            Err(EFAULT)
+        } else {
+            Ok(())
+        }
+    }
+}
diff --git a/rust/kernel/irq.rs b/rust/kernel/irq.rs
new file mode 100644
index 000000000000..f2fa270dd728
--- /dev/null
+++ b/rust/kernel/irq.rs
@@ -0,0 +1,681 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Interrupts and interrupt chips.
+//!
+//! See <https://www.kernel.org/doc/Documentation/core-api/genericirq.rst>.
+//!
+//! C headers: [`include/linux/irq.h`](../../../../include/linux/irq.h) and
+//! [`include/linux/interrupt.h`](../../../../include/linux/interrupt.h).
+
+#![allow(dead_code)]
+
+use crate::{
+    bindings,
+    error::{from_kernel_result, to_result},
+    str::CString,
+    types::PointerWrapper,
+    Error, Result, ScopeGuard,
+};
+use core::{fmt, marker::PhantomData, ops::Deref};
+use macros::vtable;
+
+/// The type of irq hardware numbers.
+pub type HwNumber = bindings::irq_hw_number_t;
+
+/// Wraps the kernel's `struct irq_data`.
+///
+/// # Invariants
+///
+/// The pointer `IrqData::ptr` is non-null and valid.
+pub struct IrqData {
+    ptr: *mut bindings::irq_data,
+}
+
+impl IrqData {
+    /// Creates a new `IrqData` instance from a raw pointer.
+    ///
+    /// # Safety
+    ///
+    /// Callers must ensure that `ptr` is non-null and valid when the function is called, and that
+    /// it remains valid for the lifetime of the return [`IrqData`] instance.
+    unsafe fn from_ptr(ptr: *mut bindings::irq_data) -> Self {
+        // INVARIANTS: By the safety requirements, the instance we're creating satisfies the type
+        // invariants.
+        Self { ptr }
+    }
+
+    /// Returns the hardware irq number.
+    pub fn hwirq(&self) -> HwNumber {
+        // SAFETY: By the type invariants, it's ok to dereference `ptr`.
+        unsafe { (*self.ptr).hwirq }
+    }
+}
+
+/// Wraps the kernel's `struct irq_data` when it is locked.
+///
+/// Being locked allows additional operations to be performed on the data.
+pub struct LockedIrqData(IrqData);
+
+impl LockedIrqData {
+    /// Sets the high-level irq flow handler to the builtin one for level-triggered irqs.
+    pub fn set_level_handler(&mut self) {
+        // SAFETY: By the type invariants of `self.0`, we know `self.0.ptr` is valid.
+        unsafe { bindings::irq_set_handler_locked(self.0.ptr, Some(bindings::handle_level_irq)) };
+    }
+
+    /// Sets the high-level irq flow handler to the builtin one for edge-triggered irqs.
+    pub fn set_edge_handler(&mut self) {
+        // SAFETY: By the type invariants of `self.0`, we know `self.0.ptr` is valid.
+        unsafe { bindings::irq_set_handler_locked(self.0.ptr, Some(bindings::handle_edge_irq)) };
+    }
+
+    /// Sets the high-level irq flow handler to the builtin one for bad irqs.
+    pub fn set_bad_handler(&mut self) {
+        // SAFETY: By the type invariants of `self.0`, we know `self.0.ptr` is valid.
+        unsafe { bindings::irq_set_handler_locked(self.0.ptr, Some(bindings::handle_bad_irq)) };
+    }
+}
+
+impl Deref for LockedIrqData {
+    type Target = IrqData;
+
+    fn deref(&self) -> &Self::Target {
+        &self.0
+    }
+}
+
+/// Extra information returned by some of the [`Chip`] methods on success.
+pub enum ExtraResult {
+    /// Indicates that the caller (irq core) will update the descriptor state.
+    None = bindings::IRQ_SET_MASK_OK as _,
+
+    /// Indicates that the callee (irq chip implementation) already updated the descriptor state.
+    NoCopy = bindings::IRQ_SET_MASK_OK_NOCOPY as _,
+
+    /// Same as [`ExtraResult::None`] in terms of updating descriptor state. It is used in stacked
+    /// irq chips to indicate that descendant chips should be skipped.
+    Done = bindings::IRQ_SET_MASK_OK_DONE as _,
+}
+
+/// An irq chip.
+///
+/// It is a trait for the functions defined in [`struct irq_chip`].
+///
+/// [`struct irq_chip`]: ../../../include/linux/irq.h
+#[vtable]
+pub trait Chip: Sized {
+    /// The type of the context data stored in the irq chip and made available on each callback.
+    type Data: PointerWrapper;
+
+    /// Called at the start of a new interrupt.
+    fn ack(data: <Self::Data as PointerWrapper>::Borrowed<'_>, irq_data: &IrqData);
+
+    /// Masks an interrupt source.
+    fn mask(data: <Self::Data as PointerWrapper>::Borrowed<'_>, irq_data: &IrqData);
+
+    /// Unmasks an interrupt source.
+    fn unmask(_data: <Self::Data as PointerWrapper>::Borrowed<'_>, irq_data: &IrqData);
+
+    /// Sets the flow type of an interrupt.
+    ///
+    /// The flow type is a combination of the constants in [`Type`].
+    fn set_type(
+        _data: <Self::Data as PointerWrapper>::Borrowed<'_>,
+        _irq_data: &mut LockedIrqData,
+        _flow_type: u32,
+    ) -> Result<ExtraResult> {
+        Ok(ExtraResult::None)
+    }
+
+    /// Enables or disables power-management wake-on of an interrupt.
+    fn set_wake(
+        _data: <Self::Data as PointerWrapper>::Borrowed<'_>,
+        _irq_data: &IrqData,
+        _on: bool,
+    ) -> Result {
+        Ok(())
+    }
+}
+
+/// Initialises `chip` with the callbacks defined in `T`.
+///
+/// # Safety
+///
+/// The caller must ensure that the value stored in the irq chip data is the result of calling
+/// [`PointerWrapper::into_pointer] for the [`T::Data`] type.
+pub(crate) unsafe fn init_chip<T: Chip>(chip: &mut bindings::irq_chip) {
+    chip.irq_ack = Some(irq_ack_callback::<T>);
+    chip.irq_mask = Some(irq_mask_callback::<T>);
+    chip.irq_unmask = Some(irq_unmask_callback::<T>);
+
+    if T::HAS_SET_TYPE {
+        chip.irq_set_type = Some(irq_set_type_callback::<T>);
+    }
+
+    if T::HAS_SET_WAKE {
+        chip.irq_set_wake = Some(irq_set_wake_callback::<T>);
+    }
+}
+
+/// Enables or disables power-management wake-on for the given irq number.
+pub fn set_wake(irq: u32, on: bool) -> Result {
+    // SAFETY: Just an FFI call, there are no extra requirements for safety.
+    let ret = unsafe { bindings::irq_set_irq_wake(irq, on as _) };
+    if ret < 0 {
+        Err(Error::from_kernel_errno(ret))
+    } else {
+        Ok(())
+    }
+}
+
+unsafe extern "C" fn irq_ack_callback<T: Chip>(irq_data: *mut bindings::irq_data) {
+    // SAFETY: The safety requirements of `init_chip`, which is the only place that uses this
+    // callback, ensure that the value stored as irq chip data comes from a previous call to
+    // `PointerWrapper::into_pointer`.
+    let data = unsafe { T::Data::borrow(bindings::irq_data_get_irq_chip_data(irq_data)) };
+
+    // SAFETY: The value returned by `IrqData` is only valid until the end of this function, and
+    // `irq_data` is guaranteed to be valid until then (by the contract with C code).
+    T::ack(data, unsafe { &IrqData::from_ptr(irq_data) })
+}
+
+unsafe extern "C" fn irq_mask_callback<T: Chip>(irq_data: *mut bindings::irq_data) {
+    // SAFETY: The safety requirements of `init_chip`, which is the only place that uses this
+    // callback, ensure that the value stored as irq chip data comes from a previous call to
+    // `PointerWrapper::into_pointer`.
+    let data = unsafe { T::Data::borrow(bindings::irq_data_get_irq_chip_data(irq_data)) };
+
+    // SAFETY: The value returned by `IrqData` is only valid until the end of this function, and
+    // `irq_data` is guaranteed to be valid until then (by the contract with C code).
+    T::mask(data, unsafe { &IrqData::from_ptr(irq_data) })
+}
+
+unsafe extern "C" fn irq_unmask_callback<T: Chip>(irq_data: *mut bindings::irq_data) {
+    // SAFETY: The safety requirements of `init_chip`, which is the only place that uses this
+    // callback, ensure that the value stored as irq chip data comes from a previous call to
+    // `PointerWrapper::into_pointer`.
+    let data = unsafe { T::Data::borrow(bindings::irq_data_get_irq_chip_data(irq_data)) };
+
+    // SAFETY: The value returned by `IrqData` is only valid until the end of this function, and
+    // `irq_data` is guaranteed to be valid until then (by the contract with C code).
+    T::unmask(data, unsafe { &IrqData::from_ptr(irq_data) })
+}
+
+unsafe extern "C" fn irq_set_type_callback<T: Chip>(
+    irq_data: *mut bindings::irq_data,
+    flow_type: core::ffi::c_uint,
+) -> core::ffi::c_int {
+    from_kernel_result! {
+        // SAFETY: The safety requirements of `init_chip`, which is the only place that uses this
+        // callback, ensure that the value stored as irq chip data comes from a previous call to
+        // `PointerWrapper::into_pointer`.
+        let data = unsafe { T::Data::borrow(bindings::irq_data_get_irq_chip_data(irq_data)) };
+
+        // SAFETY: The value returned by `IrqData` is only valid until the end of this function, and
+        // `irq_data` is guaranteed to be valid until then (by the contract with C code).
+        let ret = T::set_type(
+            data,
+            &mut LockedIrqData(unsafe { IrqData::from_ptr(irq_data) }),
+            flow_type,
+        )?;
+        Ok(ret as _)
+    }
+}
+
+unsafe extern "C" fn irq_set_wake_callback<T: Chip>(
+    irq_data: *mut bindings::irq_data,
+    on: core::ffi::c_uint,
+) -> core::ffi::c_int {
+    from_kernel_result! {
+        // SAFETY: The safety requirements of `init_chip`, which is the only place that uses this
+        // callback, ensure that the value stored as irq chip data comes from a previous call to
+        // `PointerWrapper::into_pointer`.
+        let data = unsafe { T::Data::borrow(bindings::irq_data_get_irq_chip_data(irq_data)) };
+
+        // SAFETY: The value returned by `IrqData` is only valid until the end of this function, and
+        // `irq_data` is guaranteed to be valid until then (by the contract with C code).
+        T::set_wake(data, unsafe { &IrqData::from_ptr(irq_data) }, on != 0)?;
+        Ok(0)
+    }
+}
+
+/// Contains constants that describes how an interrupt can be triggered.
+///
+/// It is tagged with `non_exhaustive` to prevent users from instantiating it.
+#[non_exhaustive]
+pub struct Type;
+
+impl Type {
+    /// The interrupt cannot be triggered.
+    pub const NONE: u32 = bindings::IRQ_TYPE_NONE;
+
+    /// The interrupt is triggered when the signal goes from low to high.
+    pub const EDGE_RISING: u32 = bindings::IRQ_TYPE_EDGE_RISING;
+
+    /// The interrupt is triggered when the signal goes from high to low.
+    pub const EDGE_FALLING: u32 = bindings::IRQ_TYPE_EDGE_FALLING;
+
+    /// The interrupt is triggered when the signal goes from low to high and when it goes to high
+    /// to low.
+    pub const EDGE_BOTH: u32 = bindings::IRQ_TYPE_EDGE_BOTH;
+
+    /// The interrupt is triggered while the signal is held high.
+    pub const LEVEL_HIGH: u32 = bindings::IRQ_TYPE_LEVEL_HIGH;
+
+    /// The interrupt is triggered while the signal is held low.
+    pub const LEVEL_LOW: u32 = bindings::IRQ_TYPE_LEVEL_LOW;
+}
+
+/// Wraps the kernel's `struct irq_desc`.
+///
+/// # Invariants
+///
+/// The pointer `Descriptor::ptr` is non-null and valid.
+pub struct Descriptor {
+    pub(crate) ptr: *mut bindings::irq_desc,
+}
+
+impl Descriptor {
+    /// Constructs a new `struct irq_desc` wrapper.
+    ///
+    /// # Safety
+    ///
+    /// The pointer `ptr` must be non-null and valid for the lifetime of the returned object.
+    unsafe fn from_ptr(ptr: *mut bindings::irq_desc) -> Self {
+        // INVARIANT: The safety requirements ensure the invariant.
+        Self { ptr }
+    }
+
+    /// Calls `chained_irq_enter` and returns a guard that calls `chained_irq_exit` once dropped.
+    ///
+    /// It is meant to be used by chained irq handlers to dispatch irqs to the next handlers.
+    pub fn enter_chained(&self) -> ChainedGuard<'_> {
+        // SAFETY: By the type invariants, `ptr` is always non-null and valid.
+        let irq_chip = unsafe { bindings::irq_desc_get_chip(self.ptr) };
+
+        // SAFETY: By the type invariants, `ptr` is always non-null and valid. `irq_chip` was just
+        // returned from `ptr`, so it is still valid too.
+        unsafe { bindings::chained_irq_enter(irq_chip, self.ptr) };
+        ChainedGuard {
+            desc: self,
+            irq_chip,
+        }
+    }
+}
+
+struct InternalRegistration<T: PointerWrapper> {
+    irq: u32,
+    data: *mut core::ffi::c_void,
+    name: CString,
+    _p: PhantomData<T>,
+}
+
+impl<T: PointerWrapper> InternalRegistration<T> {
+    /// Registers a new irq handler.
+    ///
+    /// # Safety
+    ///
+    /// Callers must ensure that `handler` and `thread_fn` are compatible with the registration,
+    /// that is, that they only use their second argument while the call is happening and that they
+    /// only call [`T::borrow`] on it (e.g., they shouldn't call [`T::from_pointer`] and consume
+    /// it).
+    unsafe fn try_new(
+        irq: core::ffi::c_uint,
+        handler: bindings::irq_handler_t,
+        thread_fn: bindings::irq_handler_t,
+        flags: usize,
+        data: T,
+        name: fmt::Arguments<'_>,
+    ) -> Result<Self> {
+        let ptr = data.into_pointer() as *mut _;
+        let name = CString::try_from_fmt(name)?;
+        let guard = ScopeGuard::new(|| {
+            // SAFETY: `ptr` came from a previous call to `into_pointer`.
+            unsafe { T::from_pointer(ptr) };
+        });
+        // SAFETY: `name` and `ptr` remain valid as long as the registration is alive.
+        to_result(unsafe {
+            bindings::request_threaded_irq(
+                irq,
+                handler,
+                thread_fn,
+                flags as _,
+                name.as_char_ptr(),
+                ptr,
+            )
+        })?;
+        guard.dismiss();
+        Ok(Self {
+            irq,
+            name,
+            data: ptr,
+            _p: PhantomData,
+        })
+    }
+}
+
+impl<T: PointerWrapper> Drop for InternalRegistration<T> {
+    fn drop(&mut self) {
+        // Unregister irq handler.
+        //
+        // SAFETY: When `try_new` succeeds, the irq was successfully requested, so it is ok to free
+        // it here.
+        unsafe { bindings::free_irq(self.irq, self.data) };
+
+        // Free context data.
+        //
+        // SAFETY: This matches the call to `into_pointer` from `try_new` in the success case.
+        unsafe { T::from_pointer(self.data) };
+    }
+}
+
+/// An irq handler.
+pub trait Handler {
+    /// The context data associated with and made available to the handler.
+    type Data: PointerWrapper;
+
+    /// Called from interrupt context when the irq happens.
+    fn handle_irq(data: <Self::Data as PointerWrapper>::Borrowed<'_>) -> Return;
+}
+
+/// The registration of an interrupt handler.
+///
+/// # Examples
+///
+/// The following is an example of a regular handler with a boxed `u32` as data.
+///
+/// ```
+/// # use kernel::prelude::*;
+/// use kernel::irq;
+///
+/// struct Example;
+///
+/// impl irq::Handler for Example {
+///     type Data = Box<u32>;
+///
+///     fn handle_irq(_data: &u32) -> irq::Return {
+///         irq::Return::None
+///     }
+/// }
+///
+/// fn request_irq(irq: u32, data: Box<u32>) -> Result<irq::Registration<Example>> {
+///     irq::Registration::try_new(irq, data, irq::flags::SHARED, fmt!("example_{irq}"))
+/// }
+/// ```
+pub struct Registration<H: Handler>(InternalRegistration<H::Data>);
+
+impl<H: Handler> Registration<H> {
+    /// Registers a new irq handler.
+    ///
+    /// The valid values of `flags` come from the [`flags`] module.
+    pub fn try_new(
+        irq: u32,
+        data: H::Data,
+        flags: usize,
+        name: fmt::Arguments<'_>,
+    ) -> Result<Self> {
+        // SAFETY: `handler` only calls `H::Data::borrow` on `raw_data`.
+        Ok(Self(unsafe {
+            InternalRegistration::try_new(irq, Some(Self::handler), None, flags, data, name)?
+        }))
+    }
+
+    unsafe extern "C" fn handler(
+        _irq: core::ffi::c_int,
+        raw_data: *mut core::ffi::c_void,
+    ) -> bindings::irqreturn_t {
+        // SAFETY: On registration, `into_pointer` was called, so it is safe to borrow from it here
+        // because `from_pointer` is called only after the irq is unregistered.
+        let data = unsafe { H::Data::borrow(raw_data) };
+        H::handle_irq(data) as _
+    }
+}
+
+/// A threaded irq handler.
+pub trait ThreadedHandler {
+    /// The context data associated with and made available to the handlers.
+    type Data: PointerWrapper;
+
+    /// Called from interrupt context when the irq first happens.
+    fn handle_primary_irq(_data: <Self::Data as PointerWrapper>::Borrowed<'_>) -> Return {
+        Return::WakeThread
+    }
+
+    /// Called from the handler thread.
+    fn handle_threaded_irq(data: <Self::Data as PointerWrapper>::Borrowed<'_>) -> Return;
+}
+
+/// The registration of a threaded interrupt handler.
+///
+/// # Examples
+///
+/// The following is an example of a threaded handler with a ref-counted u32 as data:
+///
+/// ```
+/// # use kernel::prelude::*;
+/// use kernel::{
+///     irq,
+///     sync::{Ref, RefBorrow},
+/// };
+///
+/// struct Example;
+///
+/// impl irq::ThreadedHandler for Example {
+///     type Data = Ref<u32>;
+///
+///     fn handle_threaded_irq(_data: RefBorrow<'_, u32>) -> irq::Return {
+///         irq::Return::None
+///     }
+/// }
+///
+/// fn request_irq(irq: u32, data: Ref<u32>) -> Result<irq::ThreadedRegistration<Example>> {
+///     irq::ThreadedRegistration::try_new(irq, data, irq::flags::SHARED, fmt!("example_{irq}"))
+/// }
+/// ```
+pub struct ThreadedRegistration<H: ThreadedHandler>(InternalRegistration<H::Data>);
+
+impl<H: ThreadedHandler> ThreadedRegistration<H> {
+    /// Registers a new threaded irq handler.
+    ///
+    /// The valid values of `flags` come from the [`flags`] module.
+    pub fn try_new(
+        irq: u32,
+        data: H::Data,
+        flags: usize,
+        name: fmt::Arguments<'_>,
+    ) -> Result<Self> {
+        // SAFETY: both `primary_handler` and `threaded_handler` only call `H::Data::borrow` on
+        // `raw_data`.
+        Ok(Self(unsafe {
+            InternalRegistration::try_new(
+                irq,
+                Some(Self::primary_handler),
+                Some(Self::threaded_handler),
+                flags,
+                data,
+                name,
+            )?
+        }))
+    }
+
+    unsafe extern "C" fn primary_handler(
+        _irq: core::ffi::c_int,
+        raw_data: *mut core::ffi::c_void,
+    ) -> bindings::irqreturn_t {
+        // SAFETY: On registration, `into_pointer` was called, so it is safe to borrow from it here
+        // because `from_pointer` is called only after the irq is unregistered.
+        let data = unsafe { H::Data::borrow(raw_data) };
+        H::handle_primary_irq(data) as _
+    }
+
+    unsafe extern "C" fn threaded_handler(
+        _irq: core::ffi::c_int,
+        raw_data: *mut core::ffi::c_void,
+    ) -> bindings::irqreturn_t {
+        // SAFETY: On registration, `into_pointer` was called, so it is safe to borrow from it here
+        // because `from_pointer` is called only after the irq is unregistered.
+        let data = unsafe { H::Data::borrow(raw_data) };
+        H::handle_threaded_irq(data) as _
+    }
+}
+
+/// The return value from interrupt handlers.
+pub enum Return {
+    /// The interrupt was not from this device or was not handled.
+    None = bindings::irqreturn_IRQ_NONE as _,
+
+    /// The interrupt was handled by this device.
+    Handled = bindings::irqreturn_IRQ_HANDLED as _,
+
+    /// The handler wants the handler thread to wake up.
+    WakeThread = bindings::irqreturn_IRQ_WAKE_THREAD as _,
+}
+
+/// Container for interrupt flags.
+pub mod flags {
+    use crate::bindings;
+
+    /// Use the interrupt line as already configured.
+    pub const TRIGGER_NONE: usize = bindings::IRQF_TRIGGER_NONE as _;
+
+    /// The interrupt is triggered when the signal goes from low to high.
+    pub const TRIGGER_RISING: usize = bindings::IRQF_TRIGGER_RISING as _;
+
+    /// The interrupt is triggered when the signal goes from high to low.
+    pub const TRIGGER_FALLING: usize = bindings::IRQF_TRIGGER_FALLING as _;
+
+    /// The interrupt is triggered while the signal is held high.
+    pub const TRIGGER_HIGH: usize = bindings::IRQF_TRIGGER_HIGH as _;
+
+    /// The interrupt is triggered while the signal is held low.
+    pub const TRIGGER_LOW: usize = bindings::IRQF_TRIGGER_LOW as _;
+
+    /// Allow sharing the irq among several devices.
+    pub const SHARED: usize = bindings::IRQF_SHARED as _;
+
+    /// Set by callers when they expect sharing mismatches to occur.
+    pub const PROBE_SHARED: usize = bindings::IRQF_PROBE_SHARED as _;
+
+    /// Flag to mark this interrupt as timer interrupt.
+    pub const TIMER: usize = bindings::IRQF_TIMER as _;
+
+    /// Interrupt is per cpu.
+    pub const PERCPU: usize = bindings::IRQF_PERCPU as _;
+
+    /// Flag to exclude this interrupt from irq balancing.
+    pub const NOBALANCING: usize = bindings::IRQF_NOBALANCING as _;
+
+    /// Interrupt is used for polling (only the interrupt that is registered first in a shared
+    /// interrupt is considered for performance reasons).
+    pub const IRQPOLL: usize = bindings::IRQF_IRQPOLL as _;
+
+    /// Interrupt is not reenabled after the hardirq handler finished. Used by threaded interrupts
+    /// which need to keep the irq line disabled until the threaded handler has been run.
+    pub const ONESHOT: usize = bindings::IRQF_ONESHOT as _;
+
+    /// Do not disable this IRQ during suspend. Does not guarantee that this interrupt will wake
+    /// the system from a suspended state.
+    pub const NO_SUSPEND: usize = bindings::IRQF_NO_SUSPEND as _;
+
+    /// Force enable it on resume even if [`NO_SUSPEND`] is set.
+    pub const FORCE_RESUME: usize = bindings::IRQF_FORCE_RESUME as _;
+
+    /// Interrupt cannot be threaded.
+    pub const NO_THREAD: usize = bindings::IRQF_NO_THREAD as _;
+
+    /// Resume IRQ early during syscore instead of at device resume time.
+    pub const EARLY_RESUME: usize = bindings::IRQF_EARLY_RESUME as _;
+
+    /// If the IRQ is shared with a NO_SUSPEND user, execute this interrupt handler after
+    /// suspending interrupts. For system wakeup devices users need to implement wakeup detection
+    /// in their interrupt handlers.
+    pub const COND_SUSPEND: usize = bindings::IRQF_COND_SUSPEND as _;
+
+    /// Don't enable IRQ or NMI automatically when users request it. Users will enable it
+    /// explicitly by `enable_irq` or `enable_nmi` later.
+    pub const NO_AUTOEN: usize = bindings::IRQF_NO_AUTOEN as _;
+
+    /// Exclude from runnaway detection for IPI and similar handlers, depends on `PERCPU`.
+    pub const NO_DEBUG: usize = bindings::IRQF_NO_DEBUG as _;
+}
+
+/// A guard to call `chained_irq_exit` after `chained_irq_enter` was called.
+///
+/// It is also used as evidence that a previous `chained_irq_enter` was called. So there are no
+/// public constructors and it is only created after indeed calling `chained_irq_enter`.
+pub struct ChainedGuard<'a> {
+    desc: &'a Descriptor,
+    irq_chip: *mut bindings::irq_chip,
+}
+
+impl Drop for ChainedGuard<'_> {
+    fn drop(&mut self) {
+        // SAFETY: The lifetime of `ChainedGuard` guarantees that `self.desc` remains valid, so it
+        // also guarantess `irq_chip` (which was returned from it) and `self.desc.ptr` (guaranteed
+        // by the type invariants).
+        unsafe { bindings::chained_irq_exit(self.irq_chip, self.desc.ptr) };
+    }
+}
+
+/// Wraps the kernel's `struct irq_domain`.
+///
+/// # Invariants
+///
+/// The pointer `Domain::ptr` is non-null and valid.
+#[cfg(CONFIG_IRQ_DOMAIN)]
+pub struct Domain {
+    ptr: *mut bindings::irq_domain,
+}
+
+#[cfg(CONFIG_IRQ_DOMAIN)]
+impl Domain {
+    /// Constructs a new `struct irq_domain` wrapper.
+    ///
+    /// # Safety
+    ///
+    /// The pointer `ptr` must be non-null and valid for the lifetime of the returned object.
+    pub(crate) unsafe fn from_ptr(ptr: *mut bindings::irq_domain) -> Self {
+        // INVARIANT: The safety requirements ensure the invariant.
+        Self { ptr }
+    }
+
+    /// Invokes the chained handler of the given hw irq of the given domain.
+    ///
+    /// It requires evidence that `chained_irq_enter` was called, which is done by passing a
+    /// `ChainedGuard` instance.
+    pub fn generic_handle_chained(&self, hwirq: u32, _guard: &ChainedGuard<'_>) {
+        // SAFETY: `ptr` is valid by the type invariants.
+        unsafe { bindings::generic_handle_domain_irq(self.ptr, hwirq) };
+    }
+}
+
+/// A high-level irq flow handler.
+pub trait FlowHandler {
+    /// The data associated with the handler.
+    type Data: PointerWrapper;
+
+    /// Implements the irq flow for the given descriptor.
+    fn handle_irq_flow(data: <Self::Data as PointerWrapper>::Borrowed<'_>, desc: &Descriptor);
+}
+
+/// Returns the raw irq flow handler corresponding to the (high-level) one defined in `T`.
+///
+/// # Safety
+///
+/// The caller must ensure that the value stored in the irq handler data (as returned by
+/// `irq_desc_get_handler_data`) is the result of calling [`PointerWrapper::into_pointer] for the
+/// [`T::Data`] type.
+pub(crate) unsafe fn new_flow_handler<T: FlowHandler>() -> bindings::irq_flow_handler_t {
+    Some(irq_flow_handler::<T>)
+}
+
+unsafe extern "C" fn irq_flow_handler<T: FlowHandler>(desc: *mut bindings::irq_desc) {
+    // SAFETY: By the safety requirements of `new_flow_handler`, we know that the value returned by
+    // `irq_desc_get_handler_data` comes from calling `T::Data::into_pointer`. `desc` is valid by
+    // the C API contract.
+    let data = unsafe { T::Data::borrow(bindings::irq_desc_get_handler_data(desc)) };
+
+    // SAFETY: The C API guarantees that `desc` is valid for the duration of this call, which
+    // outlives the lifetime returned by `from_desc`.
+    T::handle_irq_flow(data, &unsafe { Descriptor::from_ptr(desc) });
+}
diff --git a/rust/kernel/kasync.rs b/rust/kernel/kasync.rs
new file mode 100644
index 000000000000..d48e9041e804
--- /dev/null
+++ b/rust/kernel/kasync.rs
@@ -0,0 +1,50 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Kernel async functionality.
+
+use core::{
+    future::Future,
+    pin::Pin,
+    task::{Context, Poll},
+};
+
+pub mod executor;
+#[cfg(CONFIG_NET)]
+pub mod net;
+
+/// Yields execution of the current task so that other tasks may execute.
+///
+/// The task continues to be in a "runnable" state though, so it will eventually run again.
+///
+/// # Examples
+///
+/// ```
+/// use kernel::kasync::yield_now;
+///
+/// async fn example() {
+///     pr_info!("Before yield\n");
+///     yield_now().await;
+///     pr_info!("After yield\n");
+/// }
+/// ```
+pub fn yield_now() -> impl Future<Output = ()> {
+    struct Yield {
+        first_poll: bool,
+    }
+
+    impl Future for Yield {
+        type Output = ();
+
+        fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> {
+            if !self.first_poll {
+                Poll::Ready(())
+            } else {
+                self.first_poll = false;
+                cx.waker().wake_by_ref();
+                Poll::Pending
+            }
+        }
+    }
+
+    Yield { first_poll: true }
+}
diff --git a/rust/kernel/kasync/executor.rs b/rust/kernel/kasync/executor.rs
new file mode 100644
index 000000000000..e8e55dcfdf35
--- /dev/null
+++ b/rust/kernel/kasync/executor.rs
@@ -0,0 +1,154 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Kernel support for executing futures.
+
+use crate::{
+    sync::{LockClassKey, Ref, RefBorrow},
+    types::PointerWrapper,
+    Result,
+};
+use core::{
+    future::Future,
+    task::{RawWaker, RawWakerVTable, Waker},
+};
+
+pub mod workqueue;
+
+/// Spawns a new task to run in the given executor.
+///
+/// It also automatically defines a new lockdep lock class for executors (e.g., workqueue) that
+/// require one.
+#[macro_export]
+macro_rules! spawn_task {
+    ($executor:expr, $task:expr) => {{
+        static CLASS: $crate::sync::LockClassKey = $crate::sync::LockClassKey::new();
+        $crate::kasync::executor::Executor::spawn($executor, &CLASS, $task)
+    }};
+}
+
+/// A task spawned in an executor.
+pub trait Task {
+    /// Synchronously stops the task.
+    ///
+    /// It ensures that the task won't run again and releases resources needed to run the task
+    /// (e.g., the closure is dropped). If the task is inflight, it waits for the task to block or
+    /// complete before cleaning up and returning.
+    ///
+    /// Callers must not call this from within the task itself as it will likely lead to a
+    /// deadlock.
+    fn sync_stop(self: Ref<Self>);
+}
+
+/// An environment for executing tasks.
+pub trait Executor: Sync + Send {
+    /// Starts executing a task defined by the given future.
+    ///
+    /// Callers are encouraged to use the [`spawn_task`] macro because it automatically defines a
+    /// new lock class key.
+    fn spawn(
+        self: RefBorrow<'_, Self>,
+        lock_class_key: &'static LockClassKey,
+        future: impl Future + 'static + Send,
+    ) -> Result<Ref<dyn Task>>
+    where
+        Self: Sized;
+
+    /// Stops the executor.
+    ///
+    /// After it is called, attempts to spawn new tasks will result in an error and existing ones
+    /// won't be polled anymore.
+    fn stop(&self);
+}
+
+/// A waker that is wrapped in [`Ref`] for its reference counting.
+///
+/// Types that implement this trait can get a [`Waker`] by calling [`ref_waker`].
+pub trait RefWake: Send + Sync {
+    /// Wakes a task up.
+    fn wake_by_ref(self: RefBorrow<'_, Self>);
+
+    /// Wakes a task up and consumes a reference.
+    fn wake(self: Ref<Self>) {
+        self.as_ref_borrow().wake_by_ref();
+    }
+}
+
+/// Creates a [`Waker`] from a [`Ref<T>`], where `T` implements the [`RefWake`] trait.
+pub fn ref_waker<T: 'static + RefWake>(w: Ref<T>) -> Waker {
+    fn raw_waker<T: 'static + RefWake>(w: Ref<T>) -> RawWaker {
+        let data = w.into_pointer();
+        RawWaker::new(
+            data.cast(),
+            &RawWakerVTable::new(clone::<T>, wake::<T>, wake_by_ref::<T>, drop::<T>),
+        )
+    }
+
+    unsafe fn clone<T: 'static + RefWake>(ptr: *const ()) -> RawWaker {
+        // SAFETY: The data stored in the raw waker is the result of a call to `into_pointer`.
+        let w = unsafe { Ref::<T>::borrow(ptr.cast()) };
+        raw_waker(w.into())
+    }
+
+    unsafe fn wake<T: 'static + RefWake>(ptr: *const ()) {
+        // SAFETY: The data stored in the raw waker is the result of a call to `into_pointer`.
+        let w = unsafe { Ref::<T>::from_pointer(ptr.cast()) };
+        w.wake();
+    }
+
+    unsafe fn wake_by_ref<T: 'static + RefWake>(ptr: *const ()) {
+        // SAFETY: The data stored in the raw waker is the result of a call to `into_pointer`.
+        let w = unsafe { Ref::<T>::borrow(ptr.cast()) };
+        w.wake_by_ref();
+    }
+
+    unsafe fn drop<T: 'static + RefWake>(ptr: *const ()) {
+        // SAFETY: The data stored in the raw waker is the result of a call to `into_pointer`.
+        unsafe { Ref::<T>::from_pointer(ptr.cast()) };
+    }
+
+    let raw = raw_waker(w);
+    // SAFETY: The vtable of the raw waker satisfy the behaviour requirements of a waker.
+    unsafe { Waker::from_raw(raw) }
+}
+
+/// A handle to an executor that automatically stops it on drop.
+pub struct AutoStopHandle<T: Executor + ?Sized> {
+    executor: Option<Ref<T>>,
+}
+
+impl<T: Executor + ?Sized> AutoStopHandle<T> {
+    /// Creates a new instance of an [`AutoStopHandle`].
+    pub fn new(executor: Ref<T>) -> Self {
+        Self {
+            executor: Some(executor),
+        }
+    }
+
+    /// Detaches from the auto-stop handle.
+    ///
+    /// That is, extracts the executor from the handle and doesn't stop it anymore.
+    pub fn detach(mut self) -> Ref<T> {
+        self.executor.take().unwrap()
+    }
+
+    /// Returns the executor associated with the auto-stop handle.
+    ///
+    /// This is so that callers can, for example, spawn new tasks.
+    pub fn executor(&self) -> RefBorrow<'_, T> {
+        self.executor.as_ref().unwrap().as_ref_borrow()
+    }
+}
+
+impl<T: Executor + ?Sized> Drop for AutoStopHandle<T> {
+    fn drop(&mut self) {
+        if let Some(ex) = self.executor.take() {
+            ex.stop();
+        }
+    }
+}
+
+impl<T: 'static + Executor> From<AutoStopHandle<T>> for AutoStopHandle<dyn Executor> {
+    fn from(src: AutoStopHandle<T>) -> Self {
+        Self::new(src.detach())
+    }
+}
diff --git a/rust/kernel/kasync/executor/workqueue.rs b/rust/kernel/kasync/executor/workqueue.rs
new file mode 100644
index 000000000000..81cd16880600
--- /dev/null
+++ b/rust/kernel/kasync/executor/workqueue.rs
@@ -0,0 +1,291 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Kernel support for executing futures in C workqueues (`struct workqueue_struct`).
+
+use super::{AutoStopHandle, RefWake};
+use crate::{
+    error::code::*,
+    mutex_init,
+    revocable::AsyncRevocable,
+    sync::{LockClassKey, Mutex, Ref, RefBorrow, UniqueRef},
+    unsafe_list,
+    workqueue::{BoxedQueue, Queue, Work, WorkAdapter},
+    Either, Left, Result, Right,
+};
+use core::{cell::UnsafeCell, future::Future, marker::PhantomPinned, pin::Pin, task::Context};
+
+trait RevocableTask {
+    fn revoke(&self);
+    fn flush(self: Ref<Self>);
+    fn to_links(&self) -> &unsafe_list::Links<dyn RevocableTask>;
+}
+
+// SAFETY: `Task` has a single `links` field and only one adapter.
+unsafe impl unsafe_list::Adapter for dyn RevocableTask {
+    type EntryType = dyn RevocableTask;
+    fn to_links(obj: &dyn RevocableTask) -> &unsafe_list::Links<dyn RevocableTask> {
+        obj.to_links()
+    }
+}
+
+struct Task<T: 'static + Send + Future> {
+    links: unsafe_list::Links<dyn RevocableTask>,
+    executor: Ref<Executor>,
+    work: Work,
+    future: AsyncRevocable<UnsafeCell<T>>,
+}
+
+// SAFETY: The `future` field is only used by one thread at a time (in the `poll` method, which is
+// called by the work queue, who guarantees no reentrancy), so a task is `Sync` as long as the
+// future is `Send`.
+unsafe impl<T: 'static + Send + Future> Sync for Task<T> {}
+
+// SAFETY: If the future `T` is `Send`, so is the task.
+unsafe impl<T: 'static + Send + Future> Send for Task<T> {}
+
+impl<T: 'static + Send + Future> Task<T> {
+    fn try_new(
+        executor: Ref<Executor>,
+        key: &'static LockClassKey,
+        future: T,
+    ) -> Result<Ref<Self>> {
+        let task = UniqueRef::try_new(Self {
+            executor: executor.clone(),
+            links: unsafe_list::Links::new(),
+            // SAFETY: `work` is initialised below.
+            work: unsafe { Work::new() },
+            future: AsyncRevocable::new(UnsafeCell::new(future)),
+        })?;
+
+        Work::init(&task, key);
+
+        let task = Ref::from(task);
+
+        // Add task to list.
+        {
+            let mut guard = executor.inner.lock();
+            if guard.stopped {
+                return Err(EINVAL);
+            }
+
+            // Convert one reference into a pointer so that we hold on to a ref count while the
+            // task is in the list.
+            Ref::into_raw(task.clone());
+
+            // SAFETY: The task was just created, so it is not in any other lists. It remains alive
+            // because we incremented the refcount to account for it being in the list. It never
+            // moves because it's pinned behind a `Ref`.
+            unsafe { guard.tasks.push_back(&*task) };
+        }
+
+        Ok(task)
+    }
+}
+
+unsafe impl<T: 'static + Send + Future> WorkAdapter for Task<T> {
+    type Target = Self;
+    const FIELD_OFFSET: isize = crate::offset_of!(Self, work);
+    fn run(task: Ref<Task<T>>) {
+        let waker = super::ref_waker(task.clone());
+        let mut ctx = Context::from_waker(&waker);
+
+        let guard = if let Some(g) = task.future.try_access() {
+            g
+        } else {
+            return;
+        };
+
+        // SAFETY: `future` is pinned when the task is. The task is pinned because it's behind a
+        // `Ref`, which is always pinned.
+        //
+        // Work queues guarantee no reentrancy and this is the only place where the future is
+        // dereferenced, so it's ok to do it mutably.
+        let future = unsafe { Pin::new_unchecked(&mut *guard.get()) };
+        if future.poll(&mut ctx).is_ready() {
+            drop(guard);
+            task.revoke();
+        }
+    }
+}
+
+impl<T: 'static + Send + Future> super::Task for Task<T> {
+    fn sync_stop(self: Ref<Self>) {
+        self.revoke();
+        self.flush();
+    }
+}
+
+impl<T: 'static + Send + Future> RevocableTask for Task<T> {
+    fn revoke(&self) {
+        if !self.future.revoke() {
+            // Nothing to do if the task was already revoked.
+            return;
+        }
+
+        // SAFETY: The object is inserted into the list on creation and only removed when the
+        // future is first revoked. (Subsequent revocations don't result in additional attempts
+        // to remove per the check above.)
+        unsafe { self.executor.inner.lock().tasks.remove(self) };
+
+        // Decrement the refcount now that the task is no longer in the list.
+        //
+        // SAFETY: `into_raw` was called from `try_new` when the task was added to the list.
+        unsafe { Ref::from_raw(self) };
+    }
+
+    fn flush(self: Ref<Self>) {
+        self.work.cancel();
+    }
+
+    fn to_links(&self) -> &unsafe_list::Links<dyn RevocableTask> {
+        &self.links
+    }
+}
+
+impl<T: 'static + Send + Future> RefWake for Task<T> {
+    fn wake(self: Ref<Self>) {
+        if self.future.is_revoked() {
+            return;
+        }
+
+        match &self.executor.queue {
+            Left(q) => &**q,
+            Right(q) => *q,
+        }
+        .enqueue(self.clone());
+    }
+
+    fn wake_by_ref(self: RefBorrow<'_, Self>) {
+        Ref::from(self).wake();
+    }
+}
+
+struct ExecutorInner {
+    stopped: bool,
+    tasks: unsafe_list::List<dyn RevocableTask>,
+}
+
+/// An executor backed by a work queue.
+///
+/// # Examples
+///
+/// The following example runs two tasks on the shared system workqueue.
+///
+/// ```
+/// # use kernel::prelude::*;
+/// use kernel::kasync::executor::workqueue::Executor;
+/// use kernel::spawn_task;
+/// use kernel::workqueue;
+///
+/// fn example_shared_workqueue() -> Result {
+///     let mut handle = Executor::try_new(workqueue::system())?;
+///     spawn_task!(handle.executor(), async {
+///         pr_info!("First workqueue task\n");
+///     })?;
+///     spawn_task!(handle.executor(), async {
+///         pr_info!("Second workqueue task\n");
+///     })?;
+///     handle.detach();
+///     Ok(())
+/// }
+///
+/// # example_shared_workqueue().unwrap();
+/// ```
+pub struct Executor {
+    queue: Either<BoxedQueue, &'static Queue>,
+    inner: Mutex<ExecutorInner>,
+    _pin: PhantomPinned,
+}
+
+// SAFETY: The executor is backed by a kernel `struct workqueue_struct`, which works from any
+// thread.
+unsafe impl Send for Executor {}
+
+// SAFETY: The executor is backed by a kernel `struct workqueue_struct`, which can be used
+// concurrently by multiple threads.
+unsafe impl Sync for Executor {}
+
+impl Executor {
+    /// Creates a new workqueue-based executor using a static work queue.
+    pub fn try_new(wq: &'static Queue) -> Result<AutoStopHandle<Self>> {
+        Self::new_internal(Right(wq))
+    }
+
+    /// Creates a new workqueue-based executor using an owned (boxed) work queue.
+    pub fn try_new_owned(wq: BoxedQueue) -> Result<AutoStopHandle<Self>> {
+        Self::new_internal(Left(wq))
+    }
+
+    /// Creates a new workqueue-based executor.
+    ///
+    /// It uses the given work queue to run its tasks.
+    fn new_internal(queue: Either<BoxedQueue, &'static Queue>) -> Result<AutoStopHandle<Self>> {
+        let mut e = Pin::from(UniqueRef::try_new(Self {
+            queue,
+            _pin: PhantomPinned,
+            // SAFETY: `mutex_init` is called below.
+            inner: unsafe {
+                Mutex::new(ExecutorInner {
+                    stopped: false,
+                    tasks: unsafe_list::List::new(),
+                })
+            },
+        })?);
+        // SAFETY: `tasks` is pinned when the executor is.
+        let pinned = unsafe { e.as_mut().map_unchecked_mut(|e| &mut e.inner) };
+        mutex_init!(pinned, "Executor::inner");
+
+        Ok(AutoStopHandle::new(e.into()))
+    }
+}
+
+impl super::Executor for Executor {
+    fn spawn(
+        self: RefBorrow<'_, Self>,
+        key: &'static LockClassKey,
+        future: impl Future + 'static + Send,
+    ) -> Result<Ref<dyn super::Task>> {
+        let task = Task::try_new(self.into(), key, future)?;
+        task.clone().wake();
+        Ok(task)
+    }
+
+    fn stop(&self) {
+        // Set the `stopped` flag.
+        self.inner.lock().stopped = true;
+
+        // Go through all tasks and revoke & flush them.
+        //
+        // N.B. If we decide to allow "asynchronous" stops, we need to ensure that tasks that have
+        // been revoked but not flushed yet remain in the list so that we can flush them here.
+        // Otherwise we may have a race where we may have a running task (was revoked while
+        // running) that isn't the list anymore, so we think we've synchronously stopped all tasks
+        // when we haven't really -- unloading a module in this situation leads to memory safety
+        // issues (running unloaded code).
+        loop {
+            let guard = self.inner.lock();
+
+            let front = if let Some(t) = guard.tasks.front() {
+                t
+            } else {
+                break;
+            };
+
+            // Get a new reference to the task.
+            //
+            // SAFETY: We know all entries in the list are of type `Ref<dyn RevocableTask>` and
+            // that a reference exists while the entry is in the list, and since we are holding the
+            // list lock, we know it cannot go away. The `into_raw` call below ensures that we
+            // don't decrement the refcount accidentally.
+            let tasktmp = unsafe { Ref::<dyn RevocableTask>::from_raw(front.as_ptr()) };
+            let task = tasktmp.clone();
+            Ref::into_raw(tasktmp);
+
+            // Release the mutex before revoking the task.
+            drop(guard);
+
+            task.revoke();
+            task.flush();
+        }
+    }
+}
diff --git a/rust/kernel/kasync/net.rs b/rust/kernel/kasync/net.rs
new file mode 100644
index 000000000000..b4bbeffad94a
--- /dev/null
+++ b/rust/kernel/kasync/net.rs
@@ -0,0 +1,322 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Async networking.
+
+use crate::{bindings, error::code::*, net, sync::NoWaitLock, types::Opaque, Result};
+use core::{
+    future::Future,
+    marker::{PhantomData, PhantomPinned},
+    ops::Deref,
+    pin::Pin,
+    task::{Context, Poll, Waker},
+};
+
+/// A socket listening on a TCP port.
+///
+/// The [`TcpListener::accept`] method is meant to be used in async contexts.
+pub struct TcpListener {
+    listener: net::TcpListener,
+}
+
+impl TcpListener {
+    /// Creates a new TCP listener.
+    ///
+    /// It is configured to listen on the given socket address for the given namespace.
+    pub fn try_new(ns: &net::Namespace, addr: &net::SocketAddr) -> Result<Self> {
+        Ok(Self {
+            listener: net::TcpListener::try_new(ns, addr)?,
+        })
+    }
+
+    /// Accepts a new connection.
+    ///
+    /// Returns a future that when ready indicates the result of the accept operation; on success,
+    /// it contains the newly-accepted tcp stream.
+    pub fn accept(&self) -> impl Future<Output = Result<TcpStream>> + '_ {
+        SocketFuture::from_listener(
+            self,
+            bindings::BINDINGS_EPOLLIN | bindings::BINDINGS_EPOLLERR,
+            || {
+                Ok(TcpStream {
+                    stream: self.listener.accept(false)?,
+                })
+            },
+        )
+    }
+}
+
+impl Deref for TcpListener {
+    type Target = net::TcpListener;
+
+    fn deref(&self) -> &Self::Target {
+        &self.listener
+    }
+}
+
+/// A connected TCP socket.
+///
+/// The potentially blocking methods (e.g., [`TcpStream::read`], [`TcpStream::write`]) are meant
+/// to be used in async contexts.
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::prelude::*;
+/// # use kernel::kasync::net::TcpStream;
+/// async fn echo_server(stream: TcpStream) -> Result {
+///     let mut buf = [0u8; 1024];
+///     loop {
+///         let n = stream.read(&mut buf).await?;
+///         if n == 0 {
+///             return Ok(());
+///         }
+///         stream.write_all(&buf[..n]).await?;
+///     }
+/// }
+/// ```
+pub struct TcpStream {
+    stream: net::TcpStream,
+}
+
+impl TcpStream {
+    /// Reads data from a connected socket.
+    ///
+    /// Returns a future that when ready indicates the result of the read operation; on success, it
+    /// contains the number of bytes read, which will be zero if the connection is closed.
+    pub fn read<'a>(&'a self, buf: &'a mut [u8]) -> impl Future<Output = Result<usize>> + 'a {
+        SocketFuture::from_stream(
+            self,
+            bindings::BINDINGS_EPOLLIN | bindings::BINDINGS_EPOLLHUP | bindings::BINDINGS_EPOLLERR,
+            || self.stream.read(buf, false),
+        )
+    }
+
+    /// Writes data to the connected socket.
+    ///
+    /// Returns a future that when ready indicates the result of the write operation; on success, it
+    /// contains the number of bytes written.
+    pub fn write<'a>(&'a self, buf: &'a [u8]) -> impl Future<Output = Result<usize>> + 'a {
+        SocketFuture::from_stream(
+            self,
+            bindings::BINDINGS_EPOLLOUT | bindings::BINDINGS_EPOLLHUP | bindings::BINDINGS_EPOLLERR,
+            || self.stream.write(buf, false),
+        )
+    }
+
+    /// Writes all the data to the connected socket.
+    ///
+    /// Returns a future that when ready indicates the result of the write operation; on success, it
+    /// has written all the data.
+    pub async fn write_all<'a>(&'a self, buf: &'a [u8]) -> Result {
+        let mut rem = buf;
+
+        while !rem.is_empty() {
+            let n = self.write(rem).await?;
+            rem = &rem[n..];
+        }
+
+        Ok(())
+    }
+}
+
+impl Deref for TcpStream {
+    type Target = net::TcpStream;
+
+    fn deref(&self) -> &Self::Target {
+        &self.stream
+    }
+}
+
+/// A future for a socket operation.
+///
+/// # Invariants
+///
+/// `sock` is always non-null and valid for the duration of the lifetime of the instance.
+struct SocketFuture<'a, Out, F: FnMut() -> Result<Out> + Send + 'a> {
+    sock: *mut bindings::socket,
+    mask: u32,
+    is_queued: bool,
+    wq_entry: Opaque<bindings::wait_queue_entry>,
+    waker: NoWaitLock<Option<Waker>>,
+    _p: PhantomData<&'a ()>,
+    _pin: PhantomPinned,
+    operation: F,
+}
+
+// SAFETY: A kernel socket can be used from any thread, `wq_entry` is only used on drop and when
+// `is_queued` is initially `false`.
+unsafe impl<Out, F: FnMut() -> Result<Out> + Send> Send for SocketFuture<'_, Out, F> {}
+
+impl<'a, Out, F: FnMut() -> Result<Out> + Send + 'a> SocketFuture<'a, Out, F> {
+    /// Creates a new socket future.
+    ///
+    /// # Safety
+    ///
+    /// Callers must ensure that `sock` is non-null, valid, and remains valid for the lifetime
+    /// (`'a`) of the returned instance.
+    unsafe fn new(sock: *mut bindings::socket, mask: u32, operation: F) -> Self {
+        Self {
+            sock,
+            mask,
+            is_queued: false,
+            wq_entry: Opaque::uninit(),
+            waker: NoWaitLock::new(None),
+            operation,
+            _p: PhantomData,
+            _pin: PhantomPinned,
+        }
+    }
+
+    /// Creates a new socket future for a tcp listener.
+    fn from_listener(listener: &'a TcpListener, mask: u32, operation: F) -> Self {
+        // SAFETY: The socket is guaranteed to remain valid because it is bound to the reference to
+        // the listener (whose existence guarantees the socket remains valid).
+        unsafe { Self::new(listener.listener.sock, mask, operation) }
+    }
+
+    /// Creates a new socket future for a tcp stream.
+    fn from_stream(stream: &'a TcpStream, mask: u32, operation: F) -> Self {
+        // SAFETY: The socket is guaranteed to remain valid because it is bound to the reference to
+        // the stream (whose existence guarantees the socket remains valid).
+        unsafe { Self::new(stream.stream.sock, mask, operation) }
+    }
+
+    /// Callback called when the socket changes state.
+    ///
+    /// If the state matches the one we're waiting on, we wake up the task so that the future can be
+    /// polled again.
+    unsafe extern "C" fn wake_callback(
+        wq_entry: *mut bindings::wait_queue_entry,
+        _mode: core::ffi::c_uint,
+        _flags: core::ffi::c_int,
+        key: *mut core::ffi::c_void,
+    ) -> core::ffi::c_int {
+        let mask = key as u32;
+
+        // SAFETY: The future is valid while this callback is called because we remove from the
+        // queue on drop.
+        //
+        // There is a potential soundness issue here because we're generating a shared reference to
+        // `Self` while `Self::poll` has a mutable (unique) reference. However, for `!Unpin` types
+        // (like `Self`), `&mut T` is treated as `*mut T` per
+        // <https://github.com/rust-lang/rust/issues/63818> -- so we avoid the unsoundness. Once a
+        // more definitive solution is available, we can change this to use it.
+        let s = unsafe { &*crate::container_of!(wq_entry, Self, wq_entry) };
+        if mask & s.mask == 0 {
+            // Nothing to do as this notification doesn't interest us.
+            return 0;
+        }
+
+        // If we can't acquire the waker lock, the waker is in the process of being modified. Our
+        // attempt to acquire the lock will be reported to the lock owner, so it will trigger the
+        // wake up.
+        if let Some(guard) = s.waker.try_lock() {
+            if let Some(ref w) = *guard {
+                let cloned = w.clone();
+                drop(guard);
+                cloned.wake();
+                return 1;
+            }
+        }
+        0
+    }
+
+    /// Poll the future once.
+    ///
+    /// It calls the operation and converts `EAGAIN` errors into a pending state.
+    fn poll_once(self: Pin<&mut Self>) -> Poll<Result<Out>> {
+        // SAFETY: We never move out of `this`.
+        let this = unsafe { self.get_unchecked_mut() };
+        match (this.operation)() {
+            Ok(s) => Poll::Ready(Ok(s)),
+            Err(e) => {
+                if e == EAGAIN {
+                    Poll::Pending
+                } else {
+                    Poll::Ready(Err(e))
+                }
+            }
+        }
+    }
+
+    /// Updates the waker stored in the future.
+    ///
+    /// It automatically triggers a wake up on races with the reactor.
+    fn set_waker(&self, waker: &Waker) {
+        if let Some(mut guard) = self.waker.try_lock() {
+            let old = core::mem::replace(&mut *guard, Some(waker.clone()));
+            let contention = guard.unlock();
+            drop(old);
+            if !contention {
+                return;
+            }
+        }
+
+        // We either couldn't store the waker because the existing one is being awakened, or the
+        // reactor tried to acquire the lock while we held it (contention). In either case, we just
+        // wake it up to ensure we don't miss any notification.
+        waker.wake_by_ref();
+    }
+}
+
+impl<Out, F: FnMut() -> Result<Out> + Send> Future for SocketFuture<'_, Out, F> {
+    type Output = Result<Out>;
+
+    fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
+        match self.as_mut().poll_once() {
+            Poll::Ready(r) => Poll::Ready(r),
+            Poll::Pending => {
+                // Store away the latest waker every time we may `Pending`.
+                self.set_waker(cx.waker());
+                if self.is_queued {
+                    // Nothing else to do was the waiter is already queued.
+                    return Poll::Pending;
+                }
+
+                // SAFETY: We never move out of `this`.
+                let this = unsafe { self.as_mut().get_unchecked_mut() };
+
+                this.is_queued = true;
+
+                // SAFETY: `wq_entry` is valid for write.
+                unsafe {
+                    bindings::init_waitqueue_func_entry(
+                        this.wq_entry.get(),
+                        Some(Self::wake_callback),
+                    )
+                };
+
+                // SAFETY: `wq_entry` was just initialised above and is valid for read/write.
+                // By the type invariants, the socket is always valid.
+                unsafe {
+                    bindings::add_wait_queue(
+                        core::ptr::addr_of_mut!((*this.sock).wq.wait),
+                        this.wq_entry.get(),
+                    )
+                };
+
+                // If the future wasn't queued yet, we need to poll again in case it reached
+                // the desired state between the last poll and being queued (in which case we
+                // would have missed the notification).
+                self.poll_once()
+            }
+        }
+    }
+}
+
+impl<Out, F: FnMut() -> Result<Out> + Send> Drop for SocketFuture<'_, Out, F> {
+    fn drop(&mut self) {
+        if !self.is_queued {
+            return;
+        }
+
+        // SAFETY: `wq_entry` is initialised because `is_queued` is set to `true`, so it is valid
+        // for read/write. By the type invariants, the socket is always valid.
+        unsafe {
+            bindings::remove_wait_queue(
+                core::ptr::addr_of_mut!((*self.sock).wq.wait),
+                self.wq_entry.get(),
+            )
+        };
+    }
+}
diff --git a/rust/kernel/kunit.rs b/rust/kernel/kunit.rs
new file mode 100644
index 000000000000..5f3e102962c3
--- /dev/null
+++ b/rust/kernel/kunit.rs
@@ -0,0 +1,91 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! KUnit-based macros for Rust unit tests.
+//!
+//! C header: [`include/kunit/test.h`](../../../../../include/kunit/test.h)
+//!
+//! Reference: <https://www.kernel.org/doc/html/latest/dev-tools/kunit/index.html>
+
+/// Asserts that a boolean expression is `true` at runtime.
+///
+/// Public but hidden since it should only be used from generated tests.
+///
+/// Unlike the one in `core`, this one does not panic; instead, it is mapped to the KUnit
+/// facilities. See [`assert!`] for more details.
+#[doc(hidden)]
+#[macro_export]
+macro_rules! kunit_assert {
+    ($test:expr, $cond:expr $(,)?) => {{
+        if !$cond {
+            #[repr(transparent)]
+            struct Location($crate::bindings::kunit_loc);
+
+            #[repr(transparent)]
+            struct UnaryAssert($crate::bindings::kunit_unary_assert);
+
+            // SAFETY: There is only a static instance and in that one the pointer field
+            // points to an immutable C string.
+            unsafe impl Sync for Location {}
+
+            // SAFETY: There is only a static instance and in that one the pointer field
+            // points to an immutable C string.
+            unsafe impl Sync for UnaryAssert {}
+
+            static FILE: &'static $crate::str::CStr = $crate::c_str!(core::file!());
+            static LOCATION: Location = Location($crate::bindings::kunit_loc {
+                file: FILE.as_char_ptr(),
+                line: core::line!() as i32,
+            });
+            static CONDITION: &'static $crate::str::CStr = $crate::c_str!(stringify!($cond));
+            static ASSERTION: UnaryAssert = UnaryAssert($crate::bindings::kunit_unary_assert {
+                assert: $crate::bindings::kunit_assert {
+                    format: Some($crate::bindings::kunit_unary_assert_format),
+                },
+                condition: CONDITION.as_char_ptr(),
+                expected_true: true,
+            });
+
+            // SAFETY:
+            //   - FFI call.
+            //   - The `test` pointer is valid because this hidden macro should only be called by
+            //     the generated documentation tests which forward the test pointer given by KUnit.
+            //   - The string pointers (`file` and `condition`) point to null-terminated ones.
+            //   - The function pointer (`format`) points to the proper function.
+            //   - The pointers passed will remain valid since they point to statics.
+            //   - The format string is allowed to be null.
+            //   - There are, however, problems with this: first of all, this will end up stopping
+            //     the thread, without running destructors. While that is problematic in itself,
+            //     it is considered UB to have what is effectively an forced foreign unwind
+            //     with `extern "C"` ABI. One could observe the stack that is now gone from
+            //     another thread. We should avoid pinning stack variables to prevent library UB,
+            //     too. For the moment, given test failures are reported immediately before the
+            //     next test runs, that test failures should be fixed and that KUnit is explicitly
+            //     documented as not suitable for production environments, we feel it is reasonable.
+            unsafe {
+                $crate::bindings::kunit_do_failed_assertion(
+                    $test,
+                    core::ptr::addr_of!(LOCATION.0),
+                    $crate::bindings::kunit_assert_type_KUNIT_ASSERTION,
+                    core::ptr::addr_of!(ASSERTION.0.assert),
+                    core::ptr::null(),
+                );
+            }
+        }
+    }};
+}
+
+/// Asserts that two expressions are equal to each other (using [`PartialEq`]).
+///
+/// Public but hidden since it should only be used from generated tests.
+///
+/// Unlike the one in `core`, this one does not panic; instead, it is mapped to the KUnit
+/// facilities. See [`assert!`] for more details.
+#[doc(hidden)]
+#[macro_export]
+macro_rules! kunit_assert_eq {
+    ($test:expr, $left:expr, $right:expr $(,)?) => {{
+        // For the moment, we just forward to the expression assert because,
+        // for binary asserts, KUnit supports only a few types (e.g. integers).
+        $crate::kunit_assert!($test, $left == $right);
+    }};
+}
diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs
new file mode 100644
index 000000000000..b55fe00761c2
--- /dev/null
+++ b/rust/kernel/lib.rs
@@ -0,0 +1,267 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! The `kernel` crate.
+//!
+//! This crate contains the kernel APIs that have been ported or wrapped for
+//! usage by Rust code in the kernel and is shared by all of them.
+//!
+//! In other words, all the rest of the Rust code in the kernel (e.g. kernel
+//! modules written in Rust) depends on [`core`], [`alloc`] and this crate.
+//!
+//! If you need a kernel C API that is not ported or wrapped yet here, then
+//! do so first instead of bypassing this crate.
+
+#![no_std]
+#![feature(allocator_api)]
+#![feature(associated_type_defaults)]
+#![feature(coerce_unsized)]
+#![feature(const_mut_refs)]
+#![feature(const_ptr_offset_from)]
+#![feature(const_refs_to_cell)]
+#![feature(const_trait_impl)]
+#![feature(core_ffi_c)]
+#![feature(c_size_t)]
+#![feature(dispatch_from_dyn)]
+#![feature(doc_cfg)]
+#![feature(duration_constants)]
+#![feature(generic_associated_types)]
+#![feature(ptr_metadata)]
+#![feature(receiver_trait)]
+#![feature(unsize)]
+
+// Ensure conditional compilation based on the kernel configuration works;
+// otherwise we may silently break things like initcall handling.
+#[cfg(not(CONFIG_RUST))]
+compile_error!("Missing kernel configuration for conditional compilation");
+
+#[cfg(not(test))]
+#[cfg(not(testlib))]
+mod allocator;
+
+#[doc(hidden)]
+pub use bindings;
+
+pub use macros;
+
+#[cfg(CONFIG_ARM_AMBA)]
+pub mod amba;
+pub mod chrdev;
+#[cfg(CONFIG_COMMON_CLK)]
+pub mod clk;
+pub mod cred;
+pub mod delay;
+pub mod device;
+pub mod driver;
+pub mod error;
+pub mod file;
+pub mod fs;
+pub mod gpio;
+pub mod hwrng;
+pub mod irq;
+pub mod kasync;
+pub mod miscdev;
+pub mod mm;
+#[cfg(CONFIG_NET)]
+pub mod net;
+pub mod pages;
+pub mod power;
+pub mod revocable;
+pub mod security;
+pub mod str;
+pub mod task;
+pub mod workqueue;
+
+pub mod linked_list;
+mod raw_list;
+pub mod rbtree;
+pub mod unsafe_list;
+
+#[doc(hidden)]
+pub mod module_param;
+
+mod build_assert;
+pub mod prelude;
+pub mod print;
+pub mod random;
+mod static_assert;
+#[doc(hidden)]
+pub mod std_vendor;
+pub mod sync;
+
+#[cfg(any(CONFIG_SYSCTL, doc))]
+#[doc(cfg(CONFIG_SYSCTL))]
+pub mod sysctl;
+
+pub mod io_buffer;
+#[cfg(CONFIG_HAS_IOMEM)]
+pub mod io_mem;
+pub mod iov_iter;
+pub mod of;
+pub mod platform;
+mod types;
+pub mod user_ptr;
+
+#[cfg(CONFIG_KUNIT)]
+pub mod kunit;
+
+#[doc(hidden)]
+pub use build_error::build_error;
+
+pub use crate::error::{to_result, Error, Result};
+pub use crate::types::{
+    bit, bits_iter, ARef, AlwaysRefCounted, Bool, Either, Either::Left, Either::Right, False, Mode,
+    Opaque, PointerWrapper, ScopeGuard, True,
+};
+
+use core::marker::PhantomData;
+
+/// Page size defined in terms of the `PAGE_SHIFT` macro from C.
+///
+/// [`PAGE_SHIFT`]: ../../../include/asm-generic/page.h
+pub const PAGE_SIZE: usize = 1 << bindings::PAGE_SHIFT;
+
+/// Prefix to appear before log messages printed from within the kernel crate.
+const __LOG_PREFIX: &[u8] = b"rust_kernel\0";
+
+/// The top level entrypoint to implementing a kernel module.
+///
+/// For any teardown or cleanup operations, your type may implement [`Drop`].
+pub trait Module: Sized + Sync {
+    /// Called at module initialization time.
+    ///
+    /// Use this method to perform whatever setup or registration your module
+    /// should do.
+    ///
+    /// Equivalent to the `module_init` macro in the C API.
+    fn init(name: &'static str::CStr, module: &'static ThisModule) -> Result<Self>;
+}
+
+/// Equivalent to `THIS_MODULE` in the C API.
+///
+/// C header: `include/linux/export.h`
+pub struct ThisModule(*mut bindings::module);
+
+// SAFETY: `THIS_MODULE` may be used from all threads within a module.
+unsafe impl Sync for ThisModule {}
+
+impl ThisModule {
+    /// Creates a [`ThisModule`] given the `THIS_MODULE` pointer.
+    ///
+    /// # Safety
+    ///
+    /// The pointer must be equal to the right `THIS_MODULE`.
+    pub const unsafe fn from_ptr(ptr: *mut bindings::module) -> ThisModule {
+        ThisModule(ptr)
+    }
+
+    /// Locks the module parameters to access them.
+    ///
+    /// Returns a [`KParamGuard`] that will release the lock when dropped.
+    pub fn kernel_param_lock(&self) -> KParamGuard<'_> {
+        // SAFETY: `kernel_param_lock` will check if the pointer is null and
+        // use the built-in mutex in that case.
+        #[cfg(CONFIG_SYSFS)]
+        unsafe {
+            bindings::kernel_param_lock(self.0)
+        }
+
+        KParamGuard {
+            #[cfg(CONFIG_SYSFS)]
+            this_module: self,
+            phantom: PhantomData,
+        }
+    }
+}
+
+/// Scoped lock on the kernel parameters of [`ThisModule`].
+///
+/// Lock will be released when this struct is dropped.
+pub struct KParamGuard<'a> {
+    #[cfg(CONFIG_SYSFS)]
+    this_module: &'a ThisModule,
+    phantom: PhantomData<&'a ()>,
+}
+
+#[cfg(CONFIG_SYSFS)]
+impl<'a> Drop for KParamGuard<'a> {
+    fn drop(&mut self) {
+        // SAFETY: `kernel_param_lock` will check if the pointer is null and
+        // use the built-in mutex in that case. The existence of `self`
+        // guarantees that the lock is held.
+        unsafe { bindings::kernel_param_unlock(self.this_module.0) }
+    }
+}
+
+/// Calculates the offset of a field from the beginning of the struct it belongs to.
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::prelude::*;
+/// # use kernel::offset_of;
+/// struct Test {
+///     a: u64,
+///     b: u32,
+/// }
+///
+/// assert_eq!(offset_of!(Test, b), 8);
+/// ```
+#[macro_export]
+macro_rules! offset_of {
+    ($type:ty, $($f:tt)*) => {{
+        let tmp = core::mem::MaybeUninit::<$type>::uninit();
+        let outer = tmp.as_ptr();
+        // To avoid warnings when nesting `unsafe` blocks.
+        #[allow(unused_unsafe)]
+        // SAFETY: The pointer is valid and aligned, just not initialised; `addr_of` ensures that
+        // we don't actually read from `outer` (which would be UB) nor create an intermediate
+        // reference.
+        let inner = unsafe { core::ptr::addr_of!((*outer).$($f)*) } as *const u8;
+        // To avoid warnings when nesting `unsafe` blocks.
+        #[allow(unused_unsafe)]
+        // SAFETY: The two pointers are within the same allocation block.
+        unsafe { inner.offset_from(outer as *const u8) }
+    }}
+}
+
+/// Produces a pointer to an object from a pointer to one of its fields.
+///
+/// # Safety
+///
+/// Callers must ensure that the pointer to the field is in fact a pointer to the specified field,
+/// as opposed to a pointer to another object of the same type. If this condition is not met,
+/// any dereference of the resulting pointer is UB.
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::container_of;
+/// struct Test {
+///     a: u64,
+///     b: u32,
+/// }
+///
+/// let test = Test { a: 10, b: 20 };
+/// let b_ptr = &test.b;
+/// let test_alias = container_of!(b_ptr, Test, b);
+/// assert!(core::ptr::eq(&test, test_alias));
+/// ```
+#[macro_export]
+macro_rules! container_of {
+    ($ptr:expr, $type:ty, $($f:tt)*) => {{
+        let ptr = $ptr as *const _ as *const u8;
+        let offset = $crate::offset_of!($type, $($f)*);
+        ptr.wrapping_offset(-offset) as *const $type
+    }}
+}
+
+#[cfg(not(any(testlib, test)))]
+#[panic_handler]
+fn panic(info: &core::panic::PanicInfo<'_>) -> ! {
+    pr_emerg!("{}\n", info);
+    // SAFETY: FFI call.
+    unsafe { bindings::BUG() };
+    // Bindgen currently does not recognize `__noreturn` so `BUG` returns `()`
+    // instead of `!`. See <https://github.com/rust-lang/rust-bindgen/issues/2094>.
+    loop {}
+}
diff --git a/rust/kernel/linked_list.rs b/rust/kernel/linked_list.rs
new file mode 100644
index 000000000000..3330edcc7ca8
--- /dev/null
+++ b/rust/kernel/linked_list.rs
@@ -0,0 +1,247 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Linked lists.
+//!
+//! TODO: This module is a work in progress.
+
+use alloc::boxed::Box;
+use core::ptr::NonNull;
+
+pub use crate::raw_list::{Cursor, GetLinks, Links};
+use crate::{raw_list, raw_list::RawList, sync::Ref};
+
+// TODO: Use the one from `kernel::file_operations::PointerWrapper` instead.
+/// Wraps an object to be inserted in a linked list.
+pub trait Wrapper<T: ?Sized> {
+    /// Converts the wrapped object into a pointer that represents it.
+    fn into_pointer(self) -> NonNull<T>;
+
+    /// Converts the object back from the pointer representation.
+    ///
+    /// # Safety
+    ///
+    /// The passed pointer must come from a previous call to [`Wrapper::into_pointer()`].
+    unsafe fn from_pointer(ptr: NonNull<T>) -> Self;
+
+    /// Returns a reference to the wrapped object.
+    fn as_ref(&self) -> &T;
+}
+
+impl<T: ?Sized> Wrapper<T> for Box<T> {
+    fn into_pointer(self) -> NonNull<T> {
+        NonNull::new(Box::into_raw(self)).unwrap()
+    }
+
+    unsafe fn from_pointer(ptr: NonNull<T>) -> Self {
+        unsafe { Box::from_raw(ptr.as_ptr()) }
+    }
+
+    fn as_ref(&self) -> &T {
+        AsRef::as_ref(self)
+    }
+}
+
+impl<T: ?Sized> Wrapper<T> for Ref<T> {
+    fn into_pointer(self) -> NonNull<T> {
+        NonNull::new(Ref::into_raw(self) as _).unwrap()
+    }
+
+    unsafe fn from_pointer(ptr: NonNull<T>) -> Self {
+        // SAFETY: The safety requirements of `from_pointer` satisfy the ones from `Ref::from_raw`.
+        unsafe { Ref::from_raw(ptr.as_ptr() as _) }
+    }
+
+    fn as_ref(&self) -> &T {
+        AsRef::as_ref(self)
+    }
+}
+
+impl<T: ?Sized> Wrapper<T> for &T {
+    fn into_pointer(self) -> NonNull<T> {
+        NonNull::from(self)
+    }
+
+    unsafe fn from_pointer(ptr: NonNull<T>) -> Self {
+        unsafe { &*ptr.as_ptr() }
+    }
+
+    fn as_ref(&self) -> &T {
+        self
+    }
+}
+
+/// A descriptor of wrapped list elements.
+pub trait GetLinksWrapped: GetLinks {
+    /// Specifies which wrapper (e.g., `Box` and `Arc`) wraps the list entries.
+    type Wrapped: Wrapper<Self::EntryType>;
+}
+
+impl<T: ?Sized> GetLinksWrapped for Box<T>
+where
+    Box<T>: GetLinks,
+{
+    type Wrapped = Box<<Box<T> as GetLinks>::EntryType>;
+}
+
+impl<T: GetLinks + ?Sized> GetLinks for Box<T> {
+    type EntryType = T::EntryType;
+    fn get_links(data: &Self::EntryType) -> &Links<Self::EntryType> {
+        <T as GetLinks>::get_links(data)
+    }
+}
+
+impl<T: ?Sized> GetLinksWrapped for Ref<T>
+where
+    Ref<T>: GetLinks,
+{
+    type Wrapped = Ref<<Ref<T> as GetLinks>::EntryType>;
+}
+
+impl<T: GetLinks + ?Sized> GetLinks for Ref<T> {
+    type EntryType = T::EntryType;
+
+    fn get_links(data: &Self::EntryType) -> &Links<Self::EntryType> {
+        <T as GetLinks>::get_links(data)
+    }
+}
+
+/// A linked list.
+///
+/// Elements in the list are wrapped and ownership is transferred to the list while the element is
+/// in the list.
+pub struct List<G: GetLinksWrapped> {
+    list: RawList<G>,
+}
+
+impl<G: GetLinksWrapped> List<G> {
+    /// Constructs a new empty linked list.
+    pub fn new() -> Self {
+        Self {
+            list: RawList::new(),
+        }
+    }
+
+    /// Returns whether the list is empty.
+    pub fn is_empty(&self) -> bool {
+        self.list.is_empty()
+    }
+
+    /// Adds the given object to the end (back) of the list.
+    ///
+    /// It is dropped if it's already on this (or another) list; this can happen for
+    /// reference-counted objects, so dropping means decrementing the reference count.
+    pub fn push_back(&mut self, data: G::Wrapped) {
+        let ptr = data.into_pointer();
+
+        // SAFETY: We took ownership of the entry, so it is safe to insert it.
+        if !unsafe { self.list.push_back(ptr.as_ref()) } {
+            // If insertion failed, rebuild object so that it can be freed.
+            // SAFETY: We just called `into_pointer` above.
+            unsafe { G::Wrapped::from_pointer(ptr) };
+        }
+    }
+
+    /// Inserts the given object after `existing`.
+    ///
+    /// It is dropped if it's already on this (or another) list; this can happen for
+    /// reference-counted objects, so dropping means decrementing the reference count.
+    ///
+    /// # Safety
+    ///
+    /// Callers must ensure that `existing` points to a valid entry that is on the list.
+    pub unsafe fn insert_after(&mut self, existing: NonNull<G::EntryType>, data: G::Wrapped) {
+        let ptr = data.into_pointer();
+        let entry = unsafe { &*existing.as_ptr() };
+        if unsafe { !self.list.insert_after(entry, ptr.as_ref()) } {
+            // If insertion failed, rebuild object so that it can be freed.
+            unsafe { G::Wrapped::from_pointer(ptr) };
+        }
+    }
+
+    /// Removes the given entry.
+    ///
+    /// # Safety
+    ///
+    /// Callers must ensure that `data` is either on this list or in no list. It being on another
+    /// list leads to memory unsafety.
+    pub unsafe fn remove(&mut self, data: &G::Wrapped) -> Option<G::Wrapped> {
+        let entry_ref = Wrapper::as_ref(data);
+        if unsafe { self.list.remove(entry_ref) } {
+            Some(unsafe { G::Wrapped::from_pointer(NonNull::from(entry_ref)) })
+        } else {
+            None
+        }
+    }
+
+    /// Removes the element currently at the front of the list and returns it.
+    ///
+    /// Returns `None` if the list is empty.
+    pub fn pop_front(&mut self) -> Option<G::Wrapped> {
+        let front = self.list.pop_front()?;
+        // SAFETY: Elements on the list were inserted after a call to `into_pointer `.
+        Some(unsafe { G::Wrapped::from_pointer(front) })
+    }
+
+    /// Returns a cursor starting on the first (front) element of the list.
+    pub fn cursor_front(&self) -> Cursor<'_, G> {
+        self.list.cursor_front()
+    }
+
+    /// Returns a mutable cursor starting on the first (front) element of the list.
+    pub fn cursor_front_mut(&mut self) -> CursorMut<'_, G> {
+        CursorMut::new(self.list.cursor_front_mut())
+    }
+}
+
+impl<G: GetLinksWrapped> Default for List<G> {
+    fn default() -> Self {
+        Self::new()
+    }
+}
+
+impl<G: GetLinksWrapped> Drop for List<G> {
+    fn drop(&mut self) {
+        while self.pop_front().is_some() {}
+    }
+}
+
+/// A list cursor that allows traversing a linked list and inspecting & mutating elements.
+pub struct CursorMut<'a, G: GetLinksWrapped> {
+    cursor: raw_list::CursorMut<'a, G>,
+}
+
+impl<'a, G: GetLinksWrapped> CursorMut<'a, G> {
+    fn new(cursor: raw_list::CursorMut<'a, G>) -> Self {
+        Self { cursor }
+    }
+
+    /// Returns the element the cursor is currently positioned on.
+    pub fn current(&mut self) -> Option<&mut G::EntryType> {
+        self.cursor.current()
+    }
+
+    /// Removes the element the cursor is currently positioned on.
+    ///
+    /// After removal, it advances the cursor to the next element.
+    pub fn remove_current(&mut self) -> Option<G::Wrapped> {
+        let ptr = self.cursor.remove_current()?;
+
+        // SAFETY: Elements on the list were inserted after a call to `into_pointer `.
+        Some(unsafe { G::Wrapped::from_pointer(ptr) })
+    }
+
+    /// Returns the element immediately after the one the cursor is positioned on.
+    pub fn peek_next(&mut self) -> Option<&mut G::EntryType> {
+        self.cursor.peek_next()
+    }
+
+    /// Returns the element immediately before the one the cursor is positioned on.
+    pub fn peek_prev(&mut self) -> Option<&mut G::EntryType> {
+        self.cursor.peek_prev()
+    }
+
+    /// Moves the cursor to the next element.
+    pub fn move_next(&mut self) {
+        self.cursor.move_next();
+    }
+}
diff --git a/rust/kernel/miscdev.rs b/rust/kernel/miscdev.rs
new file mode 100644
index 000000000000..65b95d6dba90
--- /dev/null
+++ b/rust/kernel/miscdev.rs
@@ -0,0 +1,290 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Miscellaneous devices.
+//!
+//! C header: [`include/linux/miscdevice.h`](../../../../include/linux/miscdevice.h)
+//!
+//! Reference: <https://www.kernel.org/doc/html/latest/driver-api/misc_devices.html>
+
+use crate::bindings;
+use crate::error::{code::*, Error, Result};
+use crate::file;
+use crate::{device, str::CStr, str::CString, ThisModule};
+use alloc::boxed::Box;
+use core::marker::PhantomPinned;
+use core::{fmt, mem::MaybeUninit, pin::Pin};
+
+/// Options which can be used to configure how a misc device is registered.
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::{c_str, device::RawDevice, file, miscdev, prelude::*};
+/// fn example(
+///     reg: Pin<&mut miscdev::Registration<impl file::Operations<OpenData = ()>>>,
+///     parent: &dyn RawDevice,
+/// ) -> Result {
+///     miscdev::Options::new()
+///         .mode(0o600)
+///         .minor(10)
+///         .parent(parent)
+///         .register(reg, fmt!("sample"), ())
+/// }
+/// ```
+#[derive(Default)]
+pub struct Options<'a> {
+    minor: Option<i32>,
+    mode: Option<u16>,
+    parent: Option<&'a dyn device::RawDevice>,
+}
+
+impl<'a> Options<'a> {
+    /// Creates new [`Options`] instance with the required fields.
+    pub const fn new() -> Self {
+        Self {
+            minor: None,
+            mode: None,
+            parent: None,
+        }
+    }
+
+    /// Sets the minor device number.
+    pub const fn minor(&mut self, v: i32) -> &mut Self {
+        self.minor = Some(v);
+        self
+    }
+
+    /// Sets the device mode.
+    ///
+    /// This is usually an octal number and describes who can perform read/write/execute operations
+    /// on the device.
+    pub const fn mode(&mut self, m: u16) -> &mut Self {
+        self.mode = Some(m);
+        self
+    }
+
+    /// Sets the device parent.
+    pub const fn parent(&mut self, p: &'a dyn device::RawDevice) -> &mut Self {
+        self.parent = Some(p);
+        self
+    }
+
+    /// Registers a misc device using the configured options.
+    pub fn register<T: file::Operations>(
+        &self,
+        reg: Pin<&mut Registration<T>>,
+        name: fmt::Arguments<'_>,
+        open_data: T::OpenData,
+    ) -> Result {
+        reg.register_with_options(name, open_data, self)
+    }
+
+    /// Allocates a new registration of a misc device and completes the registration with the
+    /// configured options.
+    pub fn register_new<T: file::Operations>(
+        &self,
+        name: fmt::Arguments<'_>,
+        open_data: T::OpenData,
+    ) -> Result<Pin<Box<Registration<T>>>> {
+        let mut r = Pin::from(Box::try_new(Registration::new())?);
+        self.register(r.as_mut(), name, open_data)?;
+        Ok(r)
+    }
+}
+
+/// A registration of a miscellaneous device.
+///
+/// # Invariants
+///
+/// `Context` is always initialised when `registered` is `true`, and not initialised otherwise.
+pub struct Registration<T: file::Operations> {
+    registered: bool,
+    mdev: bindings::miscdevice,
+    name: Option<CString>,
+    _pin: PhantomPinned,
+
+    /// Context initialised on construction and made available to all file instances on
+    /// [`file::Operations::open`].
+    open_data: MaybeUninit<T::OpenData>,
+}
+
+impl<T: file::Operations> Registration<T> {
+    /// Creates a new [`Registration`] but does not register it yet.
+    ///
+    /// It is allowed to move.
+    pub fn new() -> Self {
+        // INVARIANT: `registered` is `false` and `open_data` is not initialised.
+        Self {
+            registered: false,
+            mdev: bindings::miscdevice::default(),
+            name: None,
+            _pin: PhantomPinned,
+            open_data: MaybeUninit::uninit(),
+        }
+    }
+
+    /// Registers a miscellaneous device.
+    ///
+    /// Returns a pinned heap-allocated representation of the registration.
+    pub fn new_pinned(name: fmt::Arguments<'_>, open_data: T::OpenData) -> Result<Pin<Box<Self>>> {
+        Options::new().register_new(name, open_data)
+    }
+
+    /// Registers a miscellaneous device with the rest of the kernel.
+    ///
+    /// It must be pinned because the memory block that represents the registration is
+    /// self-referential.
+    pub fn register(
+        self: Pin<&mut Self>,
+        name: fmt::Arguments<'_>,
+        open_data: T::OpenData,
+    ) -> Result {
+        Options::new().register(self, name, open_data)
+    }
+
+    /// Registers a miscellaneous device with the rest of the kernel. Additional optional settings
+    /// are provided via the `opts` parameter.
+    ///
+    /// It must be pinned because the memory block that represents the registration is
+    /// self-referential.
+    pub fn register_with_options(
+        self: Pin<&mut Self>,
+        name: fmt::Arguments<'_>,
+        open_data: T::OpenData,
+        opts: &Options<'_>,
+    ) -> Result {
+        // SAFETY: We must ensure that we never move out of `this`.
+        let this = unsafe { self.get_unchecked_mut() };
+        if this.registered {
+            // Already registered.
+            return Err(EINVAL);
+        }
+
+        let name = CString::try_from_fmt(name)?;
+
+        // SAFETY: The adapter is compatible with `misc_register`.
+        this.mdev.fops = unsafe { file::OperationsVtable::<Self, T>::build() };
+        this.mdev.name = name.as_char_ptr();
+        this.mdev.minor = opts.minor.unwrap_or(bindings::MISC_DYNAMIC_MINOR as i32);
+        this.mdev.mode = opts.mode.unwrap_or(0);
+        this.mdev.parent = opts
+            .parent
+            .map_or(core::ptr::null_mut(), |p| p.raw_device());
+
+        // We write to `open_data` here because as soon as `misc_register` succeeds, the file can be
+        // opened, so we need `open_data` configured ahead of time.
+        //
+        // INVARIANT: `registered` is set to `true`, but `open_data` is also initialised.
+        this.registered = true;
+        this.open_data.write(open_data);
+
+        let ret = unsafe { bindings::misc_register(&mut this.mdev) };
+        if ret < 0 {
+            // INVARIANT: `registered` is set back to `false` and the `open_data` is destructued.
+            this.registered = false;
+            // SAFETY: `open_data` was initialised a few lines above.
+            unsafe { this.open_data.assume_init_drop() };
+            return Err(Error::from_kernel_errno(ret));
+        }
+
+        this.name = Some(name);
+
+        Ok(())
+    }
+}
+
+impl<T: file::Operations> Default for Registration<T> {
+    fn default() -> Self {
+        Self::new()
+    }
+}
+
+impl<T: file::Operations> file::OpenAdapter<T::OpenData> for Registration<T> {
+    unsafe fn convert(
+        _inode: *mut bindings::inode,
+        file: *mut bindings::file,
+    ) -> *const T::OpenData {
+        // SAFETY: The caller must guarantee that `file` is valid.
+        let reg = crate::container_of!(unsafe { (*file).private_data }, Self, mdev);
+
+        // SAFETY: This function is only called while the misc device is still registered, so the
+        // registration must be valid. Additionally, the type invariants guarantee that while the
+        // miscdev is registered, `open_data` is initialised.
+        unsafe { (*reg).open_data.as_ptr() }
+    }
+}
+
+// SAFETY: The only method is `register()`, which requires a (pinned) mutable `Registration`, so it
+// is safe to pass `&Registration` to multiple threads because it offers no interior mutability.
+unsafe impl<T: file::Operations> Sync for Registration<T> {}
+
+// SAFETY: All functions work from any thread. So as long as the `Registration::open_data` is
+// `Send`, so is `Registration<T>`.
+unsafe impl<T: file::Operations> Send for Registration<T> where T::OpenData: Send {}
+
+impl<T: file::Operations> Drop for Registration<T> {
+    /// Removes the registration from the kernel if it has completed successfully before.
+    fn drop(&mut self) {
+        if self.registered {
+            // SAFETY: `registered` being `true` indicates that a previous call to  `misc_register`
+            // succeeded.
+            unsafe { bindings::misc_deregister(&mut self.mdev) };
+
+            // SAFETY: The type invariant guarantees that `open_data` is initialised when
+            // `registered` is `true`.
+            unsafe { self.open_data.assume_init_drop() };
+        }
+    }
+}
+
+/// Kernel module that exposes a single miscdev device implemented by `T`.
+pub struct Module<T: file::Operations<OpenData = ()>> {
+    _dev: Pin<Box<Registration<T>>>,
+}
+
+impl<T: file::Operations<OpenData = ()>> crate::Module for Module<T> {
+    fn init(name: &'static CStr, _module: &'static ThisModule) -> Result<Self> {
+        Ok(Self {
+            _dev: Registration::new_pinned(crate::fmt!("{name}"), ())?,
+        })
+    }
+}
+
+/// Declares a kernel module that exposes a single misc device.
+///
+/// The `type` argument should be a type which implements the [`FileOpener`] trait. Also accepts
+/// various forms of kernel metadata.
+///
+/// C header: [`include/linux/moduleparam.h`](../../../include/linux/moduleparam.h)
+///
+/// [`FileOpener`]: ../kernel/file_operations/trait.FileOpener.html
+///
+/// # Examples
+///
+/// ```ignore
+/// use kernel::prelude::*;
+///
+/// module_misc_device! {
+///     type: MyFile,
+///     name: b"my_miscdev_kernel_module",
+///     author: b"Rust for Linux Contributors",
+///     description: b"My very own misc device kernel module!",
+///     license: b"GPL",
+/// }
+///
+/// #[derive(Default)]
+/// struct MyFile;
+///
+/// #[vtable]
+/// impl kernel::file::Operations for MyFile {}
+/// ```
+#[macro_export]
+macro_rules! module_misc_device {
+    (type: $type:ty, $($f:tt)*) => {
+        type ModuleType = kernel::miscdev::Module<$type>;
+        module! {
+            type: ModuleType,
+            $($f)*
+        }
+    }
+}
diff --git a/rust/kernel/mm.rs b/rust/kernel/mm.rs
new file mode 100644
index 000000000000..8a69c69dddd9
--- /dev/null
+++ b/rust/kernel/mm.rs
@@ -0,0 +1,149 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Memory management.
+//!
+//! C header: [`include/linux/mm.h`](../../../../include/linux/mm.h)
+
+use crate::{bindings, pages, to_result, Result};
+
+/// Virtual memory.
+pub mod virt {
+    use super::*;
+
+    /// A wrapper for the kernel's `struct vm_area_struct`.
+    ///
+    /// It represents an area of virtual memory.
+    ///
+    /// # Invariants
+    ///
+    /// `vma` is always non-null and valid.
+    pub struct Area {
+        vma: *mut bindings::vm_area_struct,
+    }
+
+    impl Area {
+        /// Creates a new instance of a virtual memory area.
+        ///
+        /// # Safety
+        ///
+        /// Callers must ensure that `vma` is non-null and valid for the duration of the new area's
+        /// lifetime.
+        pub(crate) unsafe fn from_ptr(vma: *mut bindings::vm_area_struct) -> Self {
+            // INVARIANTS: The safety requirements guarantee the invariants.
+            Self { vma }
+        }
+
+        /// Returns the flags associated with the virtual memory area.
+        ///
+        /// The possible flags are a combination of the constants in [`flags`].
+        pub fn flags(&self) -> usize {
+            // SAFETY: `self.vma` is valid by the type invariants.
+            unsafe { (*self.vma).vm_flags as _ }
+        }
+
+        /// Sets the flags associated with the virtual memory area.
+        ///
+        /// The possible flags are a combination of the constants in [`flags`].
+        pub fn set_flags(&mut self, flags: usize) {
+            // SAFETY: `self.vma` is valid by the type invariants.
+            unsafe { (*self.vma).vm_flags = flags as _ };
+        }
+
+        /// Returns the start address of the virtual memory area.
+        pub fn start(&self) -> usize {
+            // SAFETY: `self.vma` is valid by the type invariants.
+            unsafe { (*self.vma).vm_start as _ }
+        }
+
+        /// Returns the end address of the virtual memory area.
+        pub fn end(&self) -> usize {
+            // SAFETY: `self.vma` is valid by the type invariants.
+            unsafe { (*self.vma).vm_end as _ }
+        }
+
+        /// Maps a single page at the given address within the virtual memory area.
+        pub fn insert_page(&mut self, address: usize, page: &pages::Pages<0>) -> Result {
+            // SAFETY: The page is guaranteed to be order 0 by the type system. The range of
+            // `address` is already checked by `vm_insert_page`. `self.vma` and `page.pages` are
+            // guaranteed by their repective type invariants to be valid.
+            to_result(unsafe { bindings::vm_insert_page(self.vma, address as _, page.pages) })
+        }
+    }
+
+    /// Container for [`Area`] flags.
+    pub mod flags {
+        use crate::bindings;
+
+        /// No flags are set.
+        pub const NONE: usize = bindings::VM_NONE as _;
+
+        /// Mapping allows reads.
+        pub const READ: usize = bindings::VM_READ as _;
+
+        /// Mapping allows writes.
+        pub const WRITE: usize = bindings::VM_WRITE as _;
+
+        /// Mapping allows execution.
+        pub const EXEC: usize = bindings::VM_EXEC as _;
+
+        /// Mapping is shared.
+        pub const SHARED: usize = bindings::VM_SHARED as _;
+
+        /// Mapping may be updated to allow reads.
+        pub const MAYREAD: usize = bindings::VM_MAYREAD as _;
+
+        /// Mapping may be updated to allow writes.
+        pub const MAYWRITE: usize = bindings::VM_MAYWRITE as _;
+
+        /// Mapping may be updated to allow execution.
+        pub const MAYEXEC: usize = bindings::VM_MAYEXEC as _;
+
+        /// Mapping may be updated to be shared.
+        pub const MAYSHARE: usize = bindings::VM_MAYSHARE as _;
+
+        /// Do not copy this vma on fork.
+        pub const DONTCOPY: usize = bindings::VM_DONTCOPY as _;
+
+        /// Cannot expand with mremap().
+        pub const DONTEXPAND: usize = bindings::VM_DONTEXPAND as _;
+
+        /// Lock the pages covered when they are faulted in.
+        pub const LOCKONFAULT: usize = bindings::VM_LOCKONFAULT as _;
+
+        /// Is a VM accounted object.
+        pub const ACCOUNT: usize = bindings::VM_ACCOUNT as _;
+
+        /// should the VM suppress accounting.
+        pub const NORESERVE: usize = bindings::VM_NORESERVE as _;
+
+        /// Huge TLB Page VM.
+        pub const HUGETLB: usize = bindings::VM_HUGETLB as _;
+
+        /// Synchronous page faults.
+        pub const SYNC: usize = bindings::VM_SYNC as _;
+
+        /// Architecture-specific flag.
+        pub const ARCH_1: usize = bindings::VM_ARCH_1 as _;
+
+        /// Wipe VMA contents in child..
+        pub const WIPEONFORK: usize = bindings::VM_WIPEONFORK as _;
+
+        /// Do not include in the core dump.
+        pub const DONTDUMP: usize = bindings::VM_DONTDUMP as _;
+
+        /// Not soft dirty clean area.
+        pub const SOFTDIRTY: usize = bindings::VM_SOFTDIRTY as _;
+
+        /// Can contain "struct page" and pure PFN pages.
+        pub const MIXEDMAP: usize = bindings::VM_MIXEDMAP as _;
+
+        /// MADV_HUGEPAGE marked this vma.
+        pub const HUGEPAGE: usize = bindings::VM_HUGEPAGE as _;
+
+        /// MADV_NOHUGEPAGE marked this vma.
+        pub const NOHUGEPAGE: usize = bindings::VM_NOHUGEPAGE as _;
+
+        /// KSM may merge identical pages.
+        pub const MERGEABLE: usize = bindings::VM_MERGEABLE as _;
+    }
+}
diff --git a/rust/kernel/module_param.rs b/rust/kernel/module_param.rs
new file mode 100644
index 000000000000..6df38c78c65c
--- /dev/null
+++ b/rust/kernel/module_param.rs
@@ -0,0 +1,499 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Types for module parameters.
+//!
+//! C header: [`include/linux/moduleparam.h`](../../../include/linux/moduleparam.h)
+
+use crate::error::{code::*, from_kernel_result};
+use crate::str::{CStr, Formatter};
+use core::fmt::Write;
+
+/// Types that can be used for module parameters.
+///
+/// Note that displaying the type in `sysfs` will fail if
+/// [`alloc::string::ToString::to_string`] (as implemented through the
+/// [`core::fmt::Display`] trait) writes more than [`PAGE_SIZE`]
+/// bytes (including an additional null terminator).
+///
+/// [`PAGE_SIZE`]: `crate::PAGE_SIZE`
+pub trait ModuleParam: core::fmt::Display + core::marker::Sized {
+    /// The `ModuleParam` will be used by the kernel module through this type.
+    ///
+    /// This may differ from `Self` if, for example, `Self` needs to track
+    /// ownership without exposing it or allocate extra space for other possible
+    /// parameter values. See [`StringParam`] or [`ArrayParam`] for examples.
+    type Value: ?Sized;
+
+    /// Whether the parameter is allowed to be set without an argument.
+    ///
+    /// Setting this to `true` allows the parameter to be passed without an
+    /// argument (e.g. just `module.param` instead of `module.param=foo`).
+    const NOARG_ALLOWED: bool;
+
+    /// Convert a parameter argument into the parameter value.
+    ///
+    /// `None` should be returned when parsing of the argument fails.
+    /// `arg == None` indicates that the parameter was passed without an
+    /// argument. If `NOARG_ALLOWED` is set to `false` then `arg` is guaranteed
+    /// to always be `Some(_)`.
+    ///
+    /// Parameters passed at boot time will be set before [`kmalloc`] is
+    /// available (even if the module is loaded at a later time). However, in
+    /// this case, the argument buffer will be valid for the entire lifetime of
+    /// the kernel. So implementations of this method which need to allocate
+    /// should first check that the allocator is available (with
+    /// [`crate::bindings::slab_is_available`]) and when it is not available
+    /// provide an alternative implementation which doesn't allocate. In cases
+    /// where the allocator is not available it is safe to save references to
+    /// `arg` in `Self`, but in other cases a copy should be made.
+    ///
+    /// [`kmalloc`]: ../../../include/linux/slab.h
+    fn try_from_param_arg(arg: Option<&'static [u8]>) -> Option<Self>;
+
+    /// Get the current value of the parameter for use in the kernel module.
+    ///
+    /// This function should not be used directly. Instead use the wrapper
+    /// `read` which will be generated by [`macros::module`].
+    fn value(&self) -> &Self::Value;
+
+    /// Set the module parameter from a string.
+    ///
+    /// Used to set the parameter value when loading the module or when set
+    /// through `sysfs`.
+    ///
+    /// # Safety
+    ///
+    /// If `val` is non-null then it must point to a valid null-terminated
+    /// string. The `arg` field of `param` must be an instance of `Self`.
+    unsafe extern "C" fn set_param(
+        val: *const core::ffi::c_char,
+        param: *const crate::bindings::kernel_param,
+    ) -> core::ffi::c_int {
+        let arg = if val.is_null() {
+            None
+        } else {
+            Some(unsafe { CStr::from_char_ptr(val).as_bytes() })
+        };
+        match Self::try_from_param_arg(arg) {
+            Some(new_value) => {
+                let old_value = unsafe { (*param).__bindgen_anon_1.arg as *mut Self };
+                let _ = unsafe { core::ptr::replace(old_value, new_value) };
+                0
+            }
+            None => EINVAL.to_kernel_errno(),
+        }
+    }
+
+    /// Write a string representation of the current parameter value to `buf`.
+    ///
+    /// Used for displaying the current parameter value in `sysfs`.
+    ///
+    /// # Safety
+    ///
+    /// `buf` must be a buffer of length at least `kernel::PAGE_SIZE` that is
+    /// writeable. The `arg` field of `param` must be an instance of `Self`.
+    unsafe extern "C" fn get_param(
+        buf: *mut core::ffi::c_char,
+        param: *const crate::bindings::kernel_param,
+    ) -> core::ffi::c_int {
+        from_kernel_result! {
+            // SAFETY: The C contracts guarantees that the buffer is at least `PAGE_SIZE` bytes.
+            let mut f = unsafe { Formatter::from_buffer(buf.cast(), crate::PAGE_SIZE) };
+            unsafe { write!(f, "{}\0", *((*param).__bindgen_anon_1.arg as *mut Self)) }?;
+            Ok(f.bytes_written().try_into()?)
+        }
+    }
+
+    /// Drop the parameter.
+    ///
+    /// Called when unloading a module.
+    ///
+    /// # Safety
+    ///
+    /// The `arg` field of `param` must be an instance of `Self`.
+    unsafe extern "C" fn free(arg: *mut core::ffi::c_void) {
+        unsafe { core::ptr::drop_in_place(arg as *mut Self) };
+    }
+}
+
+/// Trait for parsing integers.
+///
+/// Strings beginning with `0x`, `0o`, or `0b` are parsed as hex, octal, or
+/// binary respectively. Strings beginning with `0` otherwise are parsed as
+/// octal. Anything else is parsed as decimal. A leading `+` or `-` is also
+/// permitted. Any string parsed by [`kstrtol()`] or [`kstrtoul()`] will be
+/// successfully parsed.
+///
+/// [`kstrtol()`]: https://www.kernel.org/doc/html/latest/core-api/kernel-api.html#c.kstrtol
+/// [`kstrtoul()`]: https://www.kernel.org/doc/html/latest/core-api/kernel-api.html#c.kstrtoul
+trait ParseInt: Sized {
+    fn from_str_radix(src: &str, radix: u32) -> Result<Self, core::num::ParseIntError>;
+    fn checked_neg(self) -> Option<Self>;
+
+    fn from_str_unsigned(src: &str) -> Result<Self, core::num::ParseIntError> {
+        let (radix, digits) = if let Some(n) = src.strip_prefix("0x") {
+            (16, n)
+        } else if let Some(n) = src.strip_prefix("0X") {
+            (16, n)
+        } else if let Some(n) = src.strip_prefix("0o") {
+            (8, n)
+        } else if let Some(n) = src.strip_prefix("0O") {
+            (8, n)
+        } else if let Some(n) = src.strip_prefix("0b") {
+            (2, n)
+        } else if let Some(n) = src.strip_prefix("0B") {
+            (2, n)
+        } else if src.starts_with('0') {
+            (8, src)
+        } else {
+            (10, src)
+        };
+        Self::from_str_radix(digits, radix)
+    }
+
+    fn from_str(src: &str) -> Option<Self> {
+        match src.bytes().next() {
+            None => None,
+            Some(b'-') => Self::from_str_unsigned(&src[1..]).ok()?.checked_neg(),
+            Some(b'+') => Some(Self::from_str_unsigned(&src[1..]).ok()?),
+            Some(_) => Some(Self::from_str_unsigned(src).ok()?),
+        }
+    }
+}
+
+macro_rules! impl_parse_int {
+    ($ty:ident) => {
+        impl ParseInt for $ty {
+            fn from_str_radix(src: &str, radix: u32) -> Result<Self, core::num::ParseIntError> {
+                $ty::from_str_radix(src, radix)
+            }
+
+            fn checked_neg(self) -> Option<Self> {
+                self.checked_neg()
+            }
+        }
+    };
+}
+
+impl_parse_int!(i8);
+impl_parse_int!(u8);
+impl_parse_int!(i16);
+impl_parse_int!(u16);
+impl_parse_int!(i32);
+impl_parse_int!(u32);
+impl_parse_int!(i64);
+impl_parse_int!(u64);
+impl_parse_int!(isize);
+impl_parse_int!(usize);
+
+macro_rules! impl_module_param {
+    ($ty:ident) => {
+        impl ModuleParam for $ty {
+            type Value = $ty;
+
+            const NOARG_ALLOWED: bool = false;
+
+            fn try_from_param_arg(arg: Option<&'static [u8]>) -> Option<Self> {
+                let bytes = arg?;
+                let utf8 = core::str::from_utf8(bytes).ok()?;
+                <$ty as crate::module_param::ParseInt>::from_str(utf8)
+            }
+
+            fn value(&self) -> &Self::Value {
+                self
+            }
+        }
+    };
+}
+
+#[doc(hidden)]
+#[macro_export]
+/// Generate a static [`kernel_param_ops`](../../../include/linux/moduleparam.h) struct.
+///
+/// # Examples
+///
+/// ```ignore
+/// make_param_ops!(
+///     /// Documentation for new param ops.
+///     PARAM_OPS_MYTYPE, // Name for the static.
+///     MyType // A type which implements [`ModuleParam`].
+/// );
+/// ```
+macro_rules! make_param_ops {
+    ($ops:ident, $ty:ty) => {
+        $crate::make_param_ops!(
+            #[doc=""]
+            $ops,
+            $ty
+        );
+    };
+    ($(#[$meta:meta])* $ops:ident, $ty:ty) => {
+        $(#[$meta])*
+        ///
+        /// Static [`kernel_param_ops`](../../../include/linux/moduleparam.h)
+        /// struct generated by [`make_param_ops`].
+        pub static $ops: $crate::bindings::kernel_param_ops = $crate::bindings::kernel_param_ops {
+            flags: if <$ty as $crate::module_param::ModuleParam>::NOARG_ALLOWED {
+                $crate::bindings::KERNEL_PARAM_OPS_FL_NOARG
+            } else {
+                0
+            },
+            set: Some(<$ty as $crate::module_param::ModuleParam>::set_param),
+            get: Some(<$ty as $crate::module_param::ModuleParam>::get_param),
+            free: Some(<$ty as $crate::module_param::ModuleParam>::free),
+        };
+    };
+}
+
+impl_module_param!(i8);
+impl_module_param!(u8);
+impl_module_param!(i16);
+impl_module_param!(u16);
+impl_module_param!(i32);
+impl_module_param!(u32);
+impl_module_param!(i64);
+impl_module_param!(u64);
+impl_module_param!(isize);
+impl_module_param!(usize);
+
+make_param_ops!(
+    /// Rust implementation of [`kernel_param_ops`](../../../include/linux/moduleparam.h)
+    /// for [`i8`].
+    PARAM_OPS_I8,
+    i8
+);
+make_param_ops!(
+    /// Rust implementation of [`kernel_param_ops`](../../../include/linux/moduleparam.h)
+    /// for [`u8`].
+    PARAM_OPS_U8,
+    u8
+);
+make_param_ops!(
+    /// Rust implementation of [`kernel_param_ops`](../../../include/linux/moduleparam.h)
+    /// for [`i16`].
+    PARAM_OPS_I16,
+    i16
+);
+make_param_ops!(
+    /// Rust implementation of [`kernel_param_ops`](../../../include/linux/moduleparam.h)
+    /// for [`u16`].
+    PARAM_OPS_U16,
+    u16
+);
+make_param_ops!(
+    /// Rust implementation of [`kernel_param_ops`](../../../include/linux/moduleparam.h)
+    /// for [`i32`].
+    PARAM_OPS_I32,
+    i32
+);
+make_param_ops!(
+    /// Rust implementation of [`kernel_param_ops`](../../../include/linux/moduleparam.h)
+    /// for [`u32`].
+    PARAM_OPS_U32,
+    u32
+);
+make_param_ops!(
+    /// Rust implementation of [`kernel_param_ops`](../../../include/linux/moduleparam.h)
+    /// for [`i64`].
+    PARAM_OPS_I64,
+    i64
+);
+make_param_ops!(
+    /// Rust implementation of [`kernel_param_ops`](../../../include/linux/moduleparam.h)
+    /// for [`u64`].
+    PARAM_OPS_U64,
+    u64
+);
+make_param_ops!(
+    /// Rust implementation of [`kernel_param_ops`](../../../include/linux/moduleparam.h)
+    /// for [`isize`].
+    PARAM_OPS_ISIZE,
+    isize
+);
+make_param_ops!(
+    /// Rust implementation of [`kernel_param_ops`](../../../include/linux/moduleparam.h)
+    /// for [`usize`].
+    PARAM_OPS_USIZE,
+    usize
+);
+
+impl ModuleParam for bool {
+    type Value = bool;
+
+    const NOARG_ALLOWED: bool = true;
+
+    fn try_from_param_arg(arg: Option<&'static [u8]>) -> Option<Self> {
+        match arg {
+            None => Some(true),
+            Some(b"y") | Some(b"Y") | Some(b"1") | Some(b"true") => Some(true),
+            Some(b"n") | Some(b"N") | Some(b"0") | Some(b"false") => Some(false),
+            _ => None,
+        }
+    }
+
+    fn value(&self) -> &Self::Value {
+        self
+    }
+}
+
+make_param_ops!(
+    /// Rust implementation of [`kernel_param_ops`](../../../include/linux/moduleparam.h)
+    /// for [`bool`].
+    PARAM_OPS_BOOL,
+    bool
+);
+
+/// An array of at __most__ `N` values.
+///
+/// # Invariant
+///
+/// The first `self.used` elements of `self.values` are initialized.
+pub struct ArrayParam<T, const N: usize> {
+    values: [core::mem::MaybeUninit<T>; N],
+    used: usize,
+}
+
+impl<T, const N: usize> ArrayParam<T, { N }> {
+    fn values(&self) -> &[T] {
+        // SAFETY: The invariant maintained by `ArrayParam` allows us to cast
+        // the first `self.used` elements to `T`.
+        unsafe {
+            &*(&self.values[0..self.used] as *const [core::mem::MaybeUninit<T>] as *const [T])
+        }
+    }
+}
+
+impl<T: Copy, const N: usize> ArrayParam<T, { N }> {
+    const fn new() -> Self {
+        // INVARIANT: The first `self.used` elements of `self.values` are
+        // initialized.
+        ArrayParam {
+            values: [core::mem::MaybeUninit::uninit(); N],
+            used: 0,
+        }
+    }
+
+    const fn push(&mut self, val: T) {
+        if self.used < N {
+            // INVARIANT: The first `self.used` elements of `self.values` are
+            // initialized.
+            self.values[self.used] = core::mem::MaybeUninit::new(val);
+            self.used += 1;
+        }
+    }
+
+    /// Create an instance of `ArrayParam` initialized with `vals`.
+    ///
+    /// This function is only meant to be used in the [`module::module`] macro.
+    pub const fn create(vals: &[T]) -> Self {
+        let mut result = ArrayParam::new();
+        let mut i = 0;
+        while i < vals.len() {
+            result.push(vals[i]);
+            i += 1;
+        }
+        result
+    }
+}
+
+impl<T: core::fmt::Display, const N: usize> core::fmt::Display for ArrayParam<T, { N }> {
+    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
+        for val in self.values() {
+            write!(f, "{},", val)?;
+        }
+        Ok(())
+    }
+}
+
+impl<T: Copy + core::fmt::Display + ModuleParam, const N: usize> ModuleParam
+    for ArrayParam<T, { N }>
+{
+    type Value = [T];
+
+    const NOARG_ALLOWED: bool = false;
+
+    fn try_from_param_arg(arg: Option<&'static [u8]>) -> Option<Self> {
+        arg.and_then(|args| {
+            let mut result = Self::new();
+            for arg in args.split(|b| *b == b',') {
+                result.push(T::try_from_param_arg(Some(arg))?);
+            }
+            Some(result)
+        })
+    }
+
+    fn value(&self) -> &Self::Value {
+        self.values()
+    }
+}
+
+/// A C-style string parameter.
+///
+/// The Rust version of the [`charp`] parameter. This type is meant to be
+/// used by the [`macros::module`] macro, not handled directly. Instead use the
+/// `read` method generated by that macro.
+///
+/// [`charp`]: ../../../include/linux/moduleparam.h
+pub enum StringParam {
+    /// A borrowed parameter value.
+    ///
+    /// Either the default value (which is static in the module) or borrowed
+    /// from the original argument buffer used to set the value.
+    Ref(&'static [u8]),
+
+    /// A value that was allocated when the parameter was set.
+    ///
+    /// The value needs to be freed when the parameter is reset or the module is
+    /// unloaded.
+    Owned(alloc::vec::Vec<u8>),
+}
+
+impl StringParam {
+    fn bytes(&self) -> &[u8] {
+        match self {
+            StringParam::Ref(bytes) => *bytes,
+            StringParam::Owned(vec) => &vec[..],
+        }
+    }
+}
+
+impl core::fmt::Display for StringParam {
+    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
+        let bytes = self.bytes();
+        match core::str::from_utf8(bytes) {
+            Ok(utf8) => write!(f, "{}", utf8),
+            Err(_) => write!(f, "{:?}", bytes),
+        }
+    }
+}
+
+impl ModuleParam for StringParam {
+    type Value = [u8];
+
+    const NOARG_ALLOWED: bool = false;
+
+    fn try_from_param_arg(arg: Option<&'static [u8]>) -> Option<Self> {
+        // SAFETY: It is always safe to call [`slab_is_available`](../../../include/linux/slab.h).
+        let slab_available = unsafe { crate::bindings::slab_is_available() };
+        arg.and_then(|arg| {
+            if slab_available {
+                let mut vec = alloc::vec::Vec::new();
+                vec.try_extend_from_slice(arg).ok()?;
+                Some(StringParam::Owned(vec))
+            } else {
+                Some(StringParam::Ref(arg))
+            }
+        })
+    }
+
+    fn value(&self) -> &Self::Value {
+        self.bytes()
+    }
+}
+
+make_param_ops!(
+    /// Rust implementation of [`kernel_param_ops`](../../../include/linux/moduleparam.h)
+    /// for [`StringParam`].
+    PARAM_OPS_STR,
+    StringParam
+);
diff --git a/rust/kernel/net.rs b/rust/kernel/net.rs
new file mode 100644
index 000000000000..0115f3a35cd0
--- /dev/null
+++ b/rust/kernel/net.rs
@@ -0,0 +1,392 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Networking core.
+//!
+//! C headers: [`include/net/net_namespace.h`](../../../../include/linux/net/net_namespace.h),
+//! [`include/linux/netdevice.h`](../../../../include/linux/netdevice.h),
+//! [`include/linux/skbuff.h`](../../../../include/linux/skbuff.h).
+
+use crate::{bindings, str::CStr, to_result, ARef, AlwaysRefCounted, Error, Result};
+use core::{cell::UnsafeCell, ptr::NonNull};
+
+#[cfg(CONFIG_NETFILTER)]
+pub mod filter;
+
+/// Wraps the kernel's `struct net_device`.
+#[repr(transparent)]
+pub struct Device(UnsafeCell<bindings::net_device>);
+
+// SAFETY: Instances of `Device` are created on the C side. They are always refcounted.
+unsafe impl AlwaysRefCounted for Device {
+    fn inc_ref(&self) {
+        // SAFETY: The existence of a shared reference means that the refcount is nonzero.
+        unsafe { bindings::dev_hold(self.0.get()) };
+    }
+
+    unsafe fn dec_ref(obj: core::ptr::NonNull<Self>) {
+        // SAFETY: The safety requirements guarantee that the refcount is nonzero.
+        unsafe { bindings::dev_put(obj.cast().as_ptr()) };
+    }
+}
+
+/// Wraps the kernel's `struct net`.
+#[repr(transparent)]
+pub struct Namespace(UnsafeCell<bindings::net>);
+
+impl Namespace {
+    /// Finds a network device with the given name in the namespace.
+    pub fn dev_get_by_name(&self, name: &CStr) -> Option<ARef<Device>> {
+        // SAFETY: The existence of a shared reference guarantees the refcount is nonzero.
+        let ptr =
+            NonNull::new(unsafe { bindings::dev_get_by_name(self.0.get(), name.as_char_ptr()) })?;
+        Some(unsafe { ARef::from_raw(ptr.cast()) })
+    }
+}
+
+// SAFETY: Instances of `Namespace` are created on the C side. They are always refcounted.
+unsafe impl AlwaysRefCounted for Namespace {
+    fn inc_ref(&self) {
+        // SAFETY: The existence of a shared reference means that the refcount is nonzero.
+        unsafe { bindings::get_net(self.0.get()) };
+    }
+
+    unsafe fn dec_ref(obj: core::ptr::NonNull<Self>) {
+        // SAFETY: The safety requirements guarantee that the refcount is nonzero.
+        unsafe { bindings::put_net(obj.cast().as_ptr()) };
+    }
+}
+
+/// Returns the network namespace for the `init` process.
+pub fn init_ns() -> &'static Namespace {
+    unsafe { &*core::ptr::addr_of!(bindings::init_net).cast() }
+}
+
+/// Wraps the kernel's `struct sk_buff`.
+#[repr(transparent)]
+pub struct SkBuff(UnsafeCell<bindings::sk_buff>);
+
+impl SkBuff {
+    /// Creates a reference to an [`SkBuff`] from a valid pointer.
+    ///
+    /// # Safety
+    ///
+    /// The caller must ensure that `ptr` is valid and remains valid for the lifetime of the
+    /// returned [`SkBuff`] instance.
+    pub unsafe fn from_ptr<'a>(ptr: *const bindings::sk_buff) -> &'a SkBuff {
+        // SAFETY: The safety requirements guarantee the validity of the dereference, while the
+        // `SkBuff` type being transparent makes the cast ok.
+        unsafe { &*ptr.cast() }
+    }
+
+    /// Returns the remaining data in the buffer's first segment.
+    pub fn head_data(&self) -> &[u8] {
+        // SAFETY: The existence of a shared reference means that the refcount is nonzero.
+        let headlen = unsafe { bindings::skb_headlen(self.0.get()) };
+        let len = headlen.try_into().unwrap_or(usize::MAX);
+        // SAFETY: The existence of a shared reference means `self.0` is valid.
+        let data = unsafe { core::ptr::addr_of!((*self.0.get()).data).read() };
+        // SAFETY: The `struct sk_buff` conventions guarantee that at least `skb_headlen(skb)` bytes
+        // are valid from `skb->data`.
+        unsafe { core::slice::from_raw_parts(data, len) }
+    }
+
+    /// Returns the total length of the data (in all segments) in the skb.
+    #[allow(clippy::len_without_is_empty)]
+    pub fn len(&self) -> u32 {
+        // SAFETY: The existence of a shared reference means `self.0` is valid.
+        unsafe { core::ptr::addr_of!((*self.0.get()).len).read() }
+    }
+}
+
+// SAFETY: Instances of `SkBuff` are created on the C side. They are always refcounted.
+unsafe impl AlwaysRefCounted for SkBuff {
+    fn inc_ref(&self) {
+        // SAFETY: The existence of a shared reference means that the refcount is nonzero.
+        unsafe { bindings::skb_get(self.0.get()) };
+    }
+
+    unsafe fn dec_ref(obj: core::ptr::NonNull<Self>) {
+        // SAFETY: The safety requirements guarantee that the refcount is nonzero.
+        unsafe {
+            bindings::kfree_skb_reason(
+                obj.cast().as_ptr(),
+                bindings::skb_drop_reason_SKB_DROP_REASON_NOT_SPECIFIED,
+            )
+        };
+    }
+}
+
+/// An IPv4 address.
+///
+/// This is equivalent to C's `in_addr`.
+#[repr(transparent)]
+pub struct Ipv4Addr(bindings::in_addr);
+
+impl Ipv4Addr {
+    /// A wildcard IPv4 address.
+    ///
+    /// Binding to this address means binding to all IPv4 addresses.
+    pub const ANY: Self = Self::new(0, 0, 0, 0);
+
+    /// The IPv4 loopback address.
+    pub const LOOPBACK: Self = Self::new(127, 0, 0, 1);
+
+    /// The IPv4 broadcast address.
+    pub const BROADCAST: Self = Self::new(255, 255, 255, 255);
+
+    /// Creates a new IPv4 address with the given components.
+    pub const fn new(a: u8, b: u8, c: u8, d: u8) -> Self {
+        Self(bindings::in_addr {
+            s_addr: u32::from_be_bytes([a, b, c, d]).to_be(),
+        })
+    }
+}
+
+/// An IPv6 address.
+///
+/// This is equivalent to C's `in6_addr`.
+#[repr(transparent)]
+pub struct Ipv6Addr(bindings::in6_addr);
+
+impl Ipv6Addr {
+    /// A wildcard IPv6 address.
+    ///
+    /// Binding to this address means binding to all IPv6 addresses.
+    pub const ANY: Self = Self::new(0, 0, 0, 0, 0, 0, 0, 0);
+
+    /// The IPv6 loopback address.
+    pub const LOOPBACK: Self = Self::new(0, 0, 0, 0, 0, 0, 0, 1);
+
+    /// Creates a new IPv6 address with the given components.
+    #[allow(clippy::too_many_arguments)]
+    pub const fn new(a: u16, b: u16, c: u16, d: u16, e: u16, f: u16, g: u16, h: u16) -> Self {
+        Self(bindings::in6_addr {
+            in6_u: bindings::in6_addr__bindgen_ty_1 {
+                u6_addr16: [
+                    a.to_be(),
+                    b.to_be(),
+                    c.to_be(),
+                    d.to_be(),
+                    e.to_be(),
+                    f.to_be(),
+                    g.to_be(),
+                    h.to_be(),
+                ],
+            },
+        })
+    }
+}
+
+/// A socket address.
+///
+/// It's an enum with either an IPv4 or IPv6 socket address.
+pub enum SocketAddr {
+    /// An IPv4 socket address.
+    V4(SocketAddrV4),
+
+    /// An IPv6 socket address.
+    V6(SocketAddrV6),
+}
+
+/// An IPv4 socket address.
+///
+/// This is equivalent to C's `sockaddr_in`.
+#[repr(transparent)]
+pub struct SocketAddrV4(bindings::sockaddr_in);
+
+impl SocketAddrV4 {
+    /// Creates a new IPv4 socket address.
+    pub const fn new(addr: Ipv4Addr, port: u16) -> Self {
+        Self(bindings::sockaddr_in {
+            sin_family: bindings::AF_INET as _,
+            sin_port: port.to_be(),
+            sin_addr: addr.0,
+            __pad: [0; 8],
+        })
+    }
+}
+
+/// An IPv6 socket address.
+///
+/// This is equivalent to C's `sockaddr_in6`.
+#[repr(transparent)]
+pub struct SocketAddrV6(bindings::sockaddr_in6);
+
+impl SocketAddrV6 {
+    /// Creates a new IPv6 socket address.
+    pub const fn new(addr: Ipv6Addr, port: u16, flowinfo: u32, scopeid: u32) -> Self {
+        Self(bindings::sockaddr_in6 {
+            sin6_family: bindings::AF_INET6 as _,
+            sin6_port: port.to_be(),
+            sin6_addr: addr.0,
+            sin6_flowinfo: flowinfo,
+            sin6_scope_id: scopeid,
+        })
+    }
+}
+
+/// A socket listening on a TCP port.
+///
+/// # Invariants
+///
+/// The socket pointer is always non-null and valid.
+pub struct TcpListener {
+    pub(crate) sock: *mut bindings::socket,
+}
+
+// SAFETY: `TcpListener` is just a wrapper for a kernel socket, which can be used from any thread.
+unsafe impl Send for TcpListener {}
+
+// SAFETY: `TcpListener` is just a wrapper for a kernel socket, which can be used from any thread.
+unsafe impl Sync for TcpListener {}
+
+impl TcpListener {
+    /// Creates a new TCP listener.
+    ///
+    /// It is configured to listen on the given socket address for the given namespace.
+    pub fn try_new(ns: &Namespace, addr: &SocketAddr) -> Result<Self> {
+        let mut socket = core::ptr::null_mut();
+        let (pf, addr, addrlen) = match addr {
+            SocketAddr::V4(addr) => (
+                bindings::PF_INET,
+                addr as *const _ as _,
+                core::mem::size_of::<bindings::sockaddr_in>(),
+            ),
+            SocketAddr::V6(addr) => (
+                bindings::PF_INET6,
+                addr as *const _ as _,
+                core::mem::size_of::<bindings::sockaddr_in6>(),
+            ),
+        };
+
+        // SAFETY: The namespace is valid and the output socket pointer is valid for write.
+        to_result(unsafe {
+            bindings::sock_create_kern(
+                ns.0.get(),
+                pf as _,
+                bindings::sock_type_SOCK_STREAM as _,
+                bindings::IPPROTO_TCP as _,
+                &mut socket,
+            )
+        })?;
+
+        // INVARIANT: The socket was just created, so it is valid.
+        let listener = Self { sock: socket };
+
+        // SAFETY: The type invariant guarantees that the socket is valid, and `addr` and `addrlen`
+        // were initialised based on valid values provided in the address enum.
+        to_result(unsafe { bindings::kernel_bind(socket, addr, addrlen as _) })?;
+
+        // SAFETY: The socket is valid per the type invariant.
+        to_result(unsafe { bindings::kernel_listen(socket, bindings::SOMAXCONN as _) })?;
+
+        Ok(listener)
+    }
+
+    /// Accepts a new connection.
+    ///
+    /// On success, returns the newly-accepted socket stream.
+    ///
+    /// If no connection is available to be accepted, one of two behaviours will occur:
+    /// - If `block` is `false`, returns [`crate::error::code::EAGAIN`];
+    /// - If `block` is `true`, blocks until an error occurs or some connection can be accepted.
+    pub fn accept(&self, block: bool) -> Result<TcpStream> {
+        let mut new = core::ptr::null_mut();
+        let flags = if block { 0 } else { bindings::O_NONBLOCK };
+        // SAFETY: The type invariant guarantees that the socket is valid, and the output argument
+        // is also valid for write.
+        to_result(unsafe { bindings::kernel_accept(self.sock, &mut new, flags as _) })?;
+        Ok(TcpStream { sock: new })
+    }
+}
+
+impl Drop for TcpListener {
+    fn drop(&mut self) {
+        // SAFETY: The type invariant guarantees that the socket is valid.
+        unsafe { bindings::sock_release(self.sock) };
+    }
+}
+
+/// A connected TCP socket.
+///
+/// # Invariants
+///
+/// The socket pointer is always non-null and valid.
+pub struct TcpStream {
+    pub(crate) sock: *mut bindings::socket,
+}
+
+// SAFETY: `TcpStream` is just a wrapper for a kernel socket, which can be used from any thread.
+unsafe impl Send for TcpStream {}
+
+// SAFETY: `TcpStream` is just a wrapper for a kernel socket, which can be used from any thread.
+unsafe impl Sync for TcpStream {}
+
+impl TcpStream {
+    /// Reads data from a connected socket.
+    ///
+    /// On success, returns the number of bytes read, which will be zero if the connection is
+    /// closed.
+    ///
+    /// If no data is immediately available for reading, one of two behaviours will occur:
+    /// - If `block` is `false`, returns [`crate::error::code::EAGAIN`];
+    /// - If `block` is `true`, blocks until an error occurs, the connection is closed, or some
+    ///   becomes readable.
+    pub fn read(&self, buf: &mut [u8], block: bool) -> Result<usize> {
+        let mut msg = bindings::msghdr::default();
+        let mut vec = bindings::kvec {
+            iov_base: buf.as_mut_ptr().cast(),
+            iov_len: buf.len(),
+        };
+        // SAFETY: The type invariant guarantees that the socket is valid, and `vec` was
+        // initialised with the output buffer.
+        let r = unsafe {
+            bindings::kernel_recvmsg(
+                self.sock,
+                &mut msg,
+                &mut vec,
+                1,
+                vec.iov_len,
+                if block { 0 } else { bindings::MSG_DONTWAIT } as _,
+            )
+        };
+        if r < 0 {
+            Err(Error::from_kernel_errno(r))
+        } else {
+            Ok(r as _)
+        }
+    }
+
+    /// Writes data to the connected socket.
+    ///
+    /// On success, returns the number of bytes written.
+    ///
+    /// If the send buffer of the socket is full, one of two behaviours will occur:
+    /// - If `block` is `false`, returns [`crate::error::code::EAGAIN`];
+    /// - If `block` is `true`, blocks until an error occurs or some data is written.
+    pub fn write(&self, buf: &[u8], block: bool) -> Result<usize> {
+        let mut msg = bindings::msghdr {
+            msg_flags: if block { 0 } else { bindings::MSG_DONTWAIT },
+            ..bindings::msghdr::default()
+        };
+        let mut vec = bindings::kvec {
+            iov_base: buf.as_ptr() as *mut u8 as _,
+            iov_len: buf.len(),
+        };
+        // SAFETY: The type invariant guarantees that the socket is valid, and `vec` was
+        // initialised with the input  buffer.
+        let r = unsafe { bindings::kernel_sendmsg(self.sock, &mut msg, &mut vec, 1, vec.iov_len) };
+        if r < 0 {
+            Err(Error::from_kernel_errno(r))
+        } else {
+            Ok(r as _)
+        }
+    }
+}
+
+impl Drop for TcpStream {
+    fn drop(&mut self) {
+        // SAFETY: The type invariant guarantees that the socket is valid.
+        unsafe { bindings::sock_release(self.sock) };
+    }
+}
diff --git a/rust/kernel/net/filter.rs b/rust/kernel/net/filter.rs
new file mode 100644
index 000000000000..a50422d53848
--- /dev/null
+++ b/rust/kernel/net/filter.rs
@@ -0,0 +1,447 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Networking filters.
+//!
+//! C header: [`include/linux/netfilter.h`](../../../../../include/linux/netfilter.h)
+
+use crate::{
+    bindings,
+    error::{code::*, to_result},
+    net,
+    types::PointerWrapper,
+    ARef, AlwaysRefCounted, Result, ScopeGuard,
+};
+use alloc::boxed::Box;
+use core::{
+    marker::{PhantomData, PhantomPinned},
+    pin::Pin,
+};
+
+/// A network filter.
+pub trait Filter {
+    /// The type of the context data stored on registration and made available to the
+    /// [`Filter::filter`] function.
+    type Data: PointerWrapper + Sync = ();
+
+    /// Filters the packet stored in the given buffer.
+    ///
+    /// It dictates to the netfilter core what the fate of the packet should be.
+    fn filter(
+        _data: <Self::Data as PointerWrapper>::Borrowed<'_>,
+        _skb: &net::SkBuff,
+    ) -> Disposition;
+}
+
+/// Specifies the action to be taken by the netfilter core.
+pub enum Disposition {
+    /// Drop the packet.
+    Drop,
+
+    /// Accept the packet.
+    Accept,
+
+    /// The packet was stolen by the filter and must be treated as if it didn't exist.
+    Stolen,
+
+    /// Queue the packet to the given user-space queue.
+    Queue {
+        /// The identifier of the queue to which the packet should be added.
+        queue_id: u16,
+
+        /// Specifies the behaviour if a queue with the given identifier doesn't exist: if `true`,
+        /// the packet is accepted, otherwise it is rejected.
+        accept_if_queue_non_existent: bool,
+    },
+}
+
+/// The filter hook families.
+pub enum Family {
+    ///  IPv4 and IPv6 packets.
+    INet(inet::Hook),
+
+    /// IPv4 packets.
+    Ipv4(ipv4::Hook, ipv4::PriorityBase),
+
+    /// All packets through a device.
+    ///
+    /// When this family is used, a device _must_ be specified.
+    NetDev(netdev::Hook),
+
+    /// IPv6 packets.
+    Ipv6(ipv6::Hook, ipv6::PriorityBase),
+
+    /// Address resolution protocol (ARP) packets.
+    Arp(arp::Hook),
+}
+
+/// A registration of a networking filter.
+///
+/// # Examples
+///
+/// The following is an example of a function that attaches an inbound filter (that always accepts
+/// all packets after printing their lengths) on the specified device (in the `init` ns).
+///
+/// ```
+/// use kernel::net::{self, filter as netfilter};
+///
+/// struct MyFilter;
+/// impl netfilter::Filter for MyFilter {
+///     fn filter(_data: (), skb: &net::SkBuff) -> netfilter::Disposition {
+///         pr_info!("Packet of length {}\n", skb.len());
+///         netfilter::Disposition::Accept
+///     }
+/// }
+///
+/// fn register(name: &CStr) -> Result<Pin<Box<netfilter::Registration<MyFilter>>>> {
+///     let ns = net::init_ns();
+///     let dev = ns.dev_get_by_name(name).ok_or(ENOENT)?;
+///     netfilter::Registration::new_pinned(
+///         netfilter::Family::NetDev(netfilter::netdev::Hook::Ingress),
+///         0,
+///         ns.into(),
+///         Some(dev),
+///         (),
+///     )
+/// }
+/// ```
+#[derive(Default)]
+pub struct Registration<T: Filter> {
+    hook: bindings::nf_hook_ops,
+    // When `ns` is `Some(_)`, the hook is registered.
+    ns: Option<ARef<net::Namespace>>,
+    dev: Option<ARef<net::Device>>,
+    _p: PhantomData<T>,
+    _pinned: PhantomPinned,
+}
+
+// SAFETY: `Registration` does not expose any of its state across threads.
+unsafe impl<T: Filter> Sync for Registration<T> {}
+
+impl<T: Filter> Registration<T> {
+    /// Creates a new [`Registration`] but does not register it yet.
+    ///
+    /// It is allowed to move.
+    pub fn new() -> Self {
+        Self {
+            hook: bindings::nf_hook_ops::default(),
+            dev: None,
+            ns: None,
+            _p: PhantomData,
+            _pinned: PhantomPinned,
+        }
+    }
+
+    /// Creates a new filter registration and registers it.
+    ///
+    /// Returns a pinned heap-allocated representation of the registration.
+    pub fn new_pinned(
+        family: Family,
+        priority: i32,
+        ns: ARef<net::Namespace>,
+        dev: Option<ARef<net::Device>>,
+        data: T::Data,
+    ) -> Result<Pin<Box<Self>>> {
+        let mut filter = Pin::from(Box::try_new(Self::new())?);
+        filter.as_mut().register(family, priority, ns, dev, data)?;
+        Ok(filter)
+    }
+
+    /// Registers a network filter.
+    ///
+    /// It must be pinned because the C portion of the kernel stores a pointer to it while it is
+    /// registered.
+    ///
+    /// The priority is relative to the family's base priority. For example, if the base priority
+    /// is `100` and `priority` is `-1`, the actual priority will be `99`. If a family doesn't
+    /// explicitly allow a base to be specified, `0` is assumed.
+    pub fn register(
+        self: Pin<&mut Self>,
+        family: Family,
+        priority: i32,
+        ns: ARef<net::Namespace>,
+        dev: Option<ARef<net::Device>>,
+        data: T::Data,
+    ) -> Result {
+        // SAFETY: We must ensure that we never move out of `this`.
+        let this = unsafe { self.get_unchecked_mut() };
+        if this.ns.is_some() {
+            // Already registered.
+            return Err(EINVAL);
+        }
+
+        let data_pointer = data.into_pointer();
+
+        // SAFETY: `data_pointer` comes from the call to `data.into_pointer()` above.
+        let guard = ScopeGuard::new(|| unsafe {
+            T::Data::from_pointer(data_pointer);
+        });
+
+        let mut pri_base = 0i32;
+        match family {
+            Family::INet(hook) => {
+                this.hook.pf = bindings::NFPROTO_INET as _;
+                this.hook.hooknum = hook as _;
+            }
+            Family::Ipv4(hook, pbase) => {
+                this.hook.pf = bindings::NFPROTO_IPV4 as _;
+                this.hook.hooknum = hook as _;
+                pri_base = pbase as _;
+            }
+            Family::Ipv6(hook, pbase) => {
+                this.hook.pf = bindings::NFPROTO_IPV6 as _;
+                this.hook.hooknum = hook as _;
+                pri_base = pbase as _;
+            }
+            Family::NetDev(hook) => {
+                this.hook.pf = bindings::NFPROTO_NETDEV as _;
+                this.hook.hooknum = hook as _;
+            }
+            Family::Arp(hook) => {
+                this.hook.pf = bindings::NFPROTO_ARP as _;
+                this.hook.hooknum = hook as _;
+            }
+        }
+
+        this.hook.priority = pri_base.saturating_add(priority);
+        this.hook.priv_ = data_pointer as _;
+        this.hook.hook = Some(Self::hook_callback);
+        crate::static_assert!(bindings::nf_hook_ops_type_NF_HOOK_OP_UNDEFINED == 0);
+
+        if let Some(ref device) = dev {
+            this.hook.dev = device.0.get();
+        }
+
+        // SAFETY: `ns` has a valid reference to the namespace, and `this.hook` was just
+        // initialised above, so they're both valid.
+        to_result(unsafe { bindings::nf_register_net_hook(ns.0.get(), &this.hook) })?;
+
+        this.dev = dev;
+        this.ns = Some(ns);
+        guard.dismiss();
+        Ok(())
+    }
+
+    unsafe extern "C" fn hook_callback(
+        priv_: *mut core::ffi::c_void,
+        skb: *mut bindings::sk_buff,
+        _state: *const bindings::nf_hook_state,
+    ) -> core::ffi::c_uint {
+        // SAFETY: `priv_` was initialised on registration by a value returned from
+        // `T::Data::into_pointer`, and it remains valid until the hook is unregistered.
+        let data = unsafe { T::Data::borrow(priv_) };
+
+        // SAFETY: The C contract guarantees that `skb` remains valid for the duration of this
+        // function call.
+        match T::filter(data, unsafe { net::SkBuff::from_ptr(skb) }) {
+            Disposition::Drop => bindings::NF_DROP,
+            Disposition::Accept => bindings::NF_ACCEPT,
+            Disposition::Stolen => {
+                // SAFETY: This function takes over ownership of `skb` when it returns `NF_STOLEN`,
+                // so we decrement the refcount here to avoid a leak.
+                unsafe { net::SkBuff::dec_ref(core::ptr::NonNull::new(skb).unwrap().cast()) };
+                bindings::NF_STOLEN
+            }
+            Disposition::Queue {
+                queue_id,
+                accept_if_queue_non_existent,
+            } => {
+                // SAFETY: Just an FFI call, no additional safety requirements.
+                let verdict = unsafe { bindings::NF_QUEUE_NR(queue_id as _) };
+                if accept_if_queue_non_existent {
+                    verdict | bindings::NF_VERDICT_FLAG_QUEUE_BYPASS
+                } else {
+                    verdict
+                }
+            }
+        }
+    }
+}
+
+impl<T: Filter> Drop for Registration<T> {
+    fn drop(&mut self) {
+        if let Some(ref ns) = self.ns {
+            // SAFETY: `self.ns` is `Some(_)` only when a previous call to `nf_register_net_hook`
+            // succeeded. And the arguments are the same.
+            unsafe { bindings::nf_unregister_net_hook(ns.0.get(), &self.hook) };
+
+            // `self.hook.priv_` was initialised during registration to a value returned from
+            // `T::Data::into_pointer`, so it is ok to convert back here.
+            unsafe { T::Data::from_pointer(self.hook.priv_) };
+        }
+    }
+}
+
+/// Definitions used when defining hooks for the [`Family::NetDev`] family.
+pub mod netdev {
+    use crate::bindings;
+
+    /// Hooks allowed in the [`super::Family::NetDev`] family.
+    #[repr(u32)]
+    pub enum Hook {
+        /// All inbound packets through the given device.
+        Ingress = bindings::nf_dev_hooks_NF_NETDEV_INGRESS,
+
+        /// All outbound packets through the given device.
+        Egress = bindings::nf_dev_hooks_NF_NETDEV_EGRESS,
+    }
+}
+
+/// Definitions used when defining hooks for the [`Family::Ipv4`] family.
+pub mod ipv4 {
+    use crate::bindings;
+
+    /// Hooks allowed in [`super::Family::Ipv4`] family.
+    pub type Hook = super::inet::Hook;
+
+    /// The base priority for [`super::Family::Ipv4`] hooks.
+    ///
+    /// The actual priority is the base priority plus the priority specified when registering.
+    #[repr(i32)]
+    pub enum PriorityBase {
+        /// Same as the `NF_IP_PRI_FIRST` C constant.
+        First = bindings::nf_ip_hook_priorities_NF_IP_PRI_FIRST,
+
+        /// Same as the `NF_IP_PRI_RAW_BEFORE_DEFRAG` C constant.
+        RawBeforeDefrag = bindings::nf_ip_hook_priorities_NF_IP_PRI_RAW_BEFORE_DEFRAG,
+
+        /// Same as the `NF_IP_PRI_CONNTRACK_DEFRAG` C constant.
+        ConnTrackDefrag = bindings::nf_ip_hook_priorities_NF_IP_PRI_CONNTRACK_DEFRAG,
+
+        /// Same as the `NF_IP_PRI_RAW` C constant.
+        Raw = bindings::nf_ip_hook_priorities_NF_IP_PRI_RAW,
+
+        /// Same as the `NF_IP_PRI_SELINUX_FIRST` C constant.
+        SeLinuxFirst = bindings::nf_ip_hook_priorities_NF_IP_PRI_SELINUX_FIRST,
+
+        /// Same as the `NF_IP_PRI_CONNTRACK` C constant.
+        ConnTrack = bindings::nf_ip_hook_priorities_NF_IP_PRI_CONNTRACK,
+
+        /// Same as the `NF_IP_PRI_MANGLE` C constant.
+        Mangle = bindings::nf_ip_hook_priorities_NF_IP_PRI_MANGLE,
+
+        /// Same as the `NF_IP_PRI_NAT_DST` C constant.
+        NatDst = bindings::nf_ip_hook_priorities_NF_IP_PRI_NAT_DST,
+
+        /// Same as the `NF_IP_PRI_FILTER` C constant.
+        Filter = bindings::nf_ip_hook_priorities_NF_IP_PRI_FILTER,
+
+        /// Same as the `NF_IP_PRI_SECURITY` C constant.
+        Security = bindings::nf_ip_hook_priorities_NF_IP_PRI_SECURITY,
+
+        /// Same as the `NF_IP_PRI_NAT_SRC` C constant.
+        NatSrc = bindings::nf_ip_hook_priorities_NF_IP_PRI_NAT_SRC,
+
+        /// Same as the `NF_IP_PRI_SELINUX_LAST` C constant.
+        SeLinuxLast = bindings::nf_ip_hook_priorities_NF_IP_PRI_SELINUX_LAST,
+
+        /// Same as the `NF_IP_PRI_CONNTRACK_HELPER` C constant.
+        ConnTrackHelper = bindings::nf_ip_hook_priorities_NF_IP_PRI_CONNTRACK_HELPER,
+
+        /// Same as the `NF_IP_PRI_LAST` and `NF_IP_PRI_CONNTRACK_CONFIRM` C constants.
+        Last = bindings::nf_ip_hook_priorities_NF_IP_PRI_LAST,
+    }
+}
+
+/// Definitions used when defining hooks for the [`Family::Ipv6`] family.
+pub mod ipv6 {
+    use crate::bindings;
+
+    /// Hooks allowed in [`super::Family::Ipv6`] family.
+    pub type Hook = super::inet::Hook;
+
+    /// The base priority for [`super::Family::Ipv6`] hooks.
+    ///
+    /// The actual priority is the base priority plus the priority specified when registering.
+    #[repr(i32)]
+    pub enum PriorityBase {
+        /// Same as the `NF_IP6_PRI_FIRST` C constant.
+        First = bindings::nf_ip6_hook_priorities_NF_IP6_PRI_FIRST,
+
+        /// Same as the `NF_IP6_PRI_RAW_BEFORE_DEFRAG` C constant.
+        RawBeforeDefrag = bindings::nf_ip6_hook_priorities_NF_IP6_PRI_RAW_BEFORE_DEFRAG,
+
+        /// Same as the `NF_IP6_PRI_CONNTRACK_DEFRAG` C constant.
+        ConnTrackDefrag = bindings::nf_ip6_hook_priorities_NF_IP6_PRI_CONNTRACK_DEFRAG,
+
+        /// Same as the `NF_IP6_PRI_RAW` C constant.
+        Raw = bindings::nf_ip6_hook_priorities_NF_IP6_PRI_RAW,
+
+        /// Same as the `NF_IP6_PRI_SELINUX_FIRST` C constant.
+        SeLinuxFirst = bindings::nf_ip6_hook_priorities_NF_IP6_PRI_SELINUX_FIRST,
+
+        /// Same as the `NF_IP6_PRI_CONNTRACK` C constant.
+        ConnTrack = bindings::nf_ip6_hook_priorities_NF_IP6_PRI_CONNTRACK,
+
+        /// Same as the `NF_IP6_PRI_MANGLE` C constant.
+        Mangle = bindings::nf_ip6_hook_priorities_NF_IP6_PRI_MANGLE,
+
+        /// Same as the `NF_IP6_PRI_NAT_DST` C constant.
+        NatDst = bindings::nf_ip6_hook_priorities_NF_IP6_PRI_NAT_DST,
+
+        /// Same as the `NF_IP6_PRI_FILTER` C constant.
+        Filter = bindings::nf_ip6_hook_priorities_NF_IP6_PRI_FILTER,
+
+        /// Same as the `NF_IP6_PRI_SECURITY` C constant.
+        Security = bindings::nf_ip6_hook_priorities_NF_IP6_PRI_SECURITY,
+
+        /// Same as the `NF_IP6_PRI_NAT_SRC` C constant.
+        NatSrc = bindings::nf_ip6_hook_priorities_NF_IP6_PRI_NAT_SRC,
+
+        /// Same as the `NF_IP6_PRI_SELINUX_LAST` C constant.
+        SeLinuxLast = bindings::nf_ip6_hook_priorities_NF_IP6_PRI_SELINUX_LAST,
+
+        /// Same as the `NF_IP6_PRI_CONNTRACK_HELPER` C constant.
+        ConnTrackHelper = bindings::nf_ip6_hook_priorities_NF_IP6_PRI_CONNTRACK_HELPER,
+
+        /// Same as the `NF_IP6_PRI_LAST` C constant.
+        Last = bindings::nf_ip6_hook_priorities_NF_IP6_PRI_LAST,
+    }
+}
+
+/// Definitions used when defining hooks for the [`Family::Arp`] family.
+pub mod arp {
+    use crate::bindings;
+
+    /// Hooks allowed in the [`super::Family::Arp`] family.
+    #[repr(u32)]
+    pub enum Hook {
+        /// Inbound ARP packets.
+        In = bindings::NF_ARP_IN,
+
+        /// Outbound ARP packets.
+        Out = bindings::NF_ARP_OUT,
+
+        /// Forwarded ARP packets.
+        Forward = bindings::NF_ARP_FORWARD,
+    }
+}
+
+/// Definitions used when defining hooks for the [`Family::INet`] family.
+pub mod inet {
+    use crate::bindings;
+
+    /// Hooks allowed in the [`super::Family::INet`], [`super::Family::Ipv4`], and
+    /// [`super::Family::Ipv6`] families.
+    #[repr(u32)]
+    pub enum Hook {
+        /// Inbound packets before routing decisions are made (i.e., before it's determined if the
+        /// packet is to be delivered locally or forwarded to another host).
+        PreRouting = bindings::nf_inet_hooks_NF_INET_PRE_ROUTING as _,
+
+        /// Inbound packets that are meant to be delivered locally.
+        LocalIn = bindings::nf_inet_hooks_NF_INET_LOCAL_IN as _,
+
+        /// Inbound packets that are meant to be forwarded to another host.
+        Forward = bindings::nf_inet_hooks_NF_INET_FORWARD as _,
+
+        /// Outbound packet created by the local networking stack.
+        LocalOut = bindings::nf_inet_hooks_NF_INET_LOCAL_OUT as _,
+
+        /// All outbound packets (i.e., generated locally or being forwarded to another host).
+        PostRouting = bindings::nf_inet_hooks_NF_INET_POST_ROUTING as _,
+
+        /// Equivalent to [`super::netdev::Hook::Ingress`], so a device must be specified. Packets
+        /// of all types (not just ipv4/ipv6) will be delivered to the filter.
+        Ingress = bindings::nf_inet_hooks_NF_INET_INGRESS as _,
+    }
+}
diff --git a/rust/kernel/of.rs b/rust/kernel/of.rs
new file mode 100644
index 000000000000..cdcd83244337
--- /dev/null
+++ b/rust/kernel/of.rs
@@ -0,0 +1,63 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Devicetree and Open Firmware abstractions.
+//!
+//! C header: [`include/linux/of_*.h`](../../../../include/linux/of_*.h)
+
+use crate::{bindings, driver, str::BStr};
+
+/// An open firmware device id.
+#[derive(Clone, Copy)]
+pub enum DeviceId {
+    /// An open firmware device id where only a compatible string is specified.
+    Compatible(&'static BStr),
+}
+
+/// Defines a const open firmware device id table that also carries per-entry data/context/info.
+///
+/// The name of the const is `OF_DEVICE_ID_TABLE`, which is what buses are expected to name their
+/// open firmware tables.
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::define_of_id_table;
+/// use kernel::of;
+///
+/// define_of_id_table! {u32, [
+///     (of::DeviceId::Compatible(b"test-device1,test-device2"), Some(0xff)),
+///     (of::DeviceId::Compatible(b"test-device3"), None),
+/// ]};
+/// ```
+#[macro_export]
+macro_rules! define_of_id_table {
+    ($data_type:ty, $($t:tt)*) => {
+        $crate::define_id_table!(OF_DEVICE_ID_TABLE, $crate::of::DeviceId, $data_type, $($t)*);
+    };
+}
+
+// SAFETY: `ZERO` is all zeroed-out and `to_rawid` stores `offset` in `of_device_id::data`.
+unsafe impl const driver::RawDeviceId for DeviceId {
+    type RawType = bindings::of_device_id;
+    const ZERO: Self::RawType = bindings::of_device_id {
+        name: [0; 32],
+        type_: [0; 32],
+        compatible: [0; 128],
+        data: core::ptr::null(),
+    };
+
+    fn to_rawid(&self, offset: isize) -> Self::RawType {
+        let DeviceId::Compatible(compatible) = self;
+        let mut id = Self::ZERO;
+        let mut i = 0;
+        while i < compatible.len() {
+            // If `compatible` does not fit in `id.compatible`, an "index out of bounds" build time
+            // error will be triggered.
+            id.compatible[i] = compatible[i] as _;
+            i += 1;
+        }
+        id.compatible[i] = b'\0' as _;
+        id.data = offset as _;
+        id
+    }
+}
diff --git a/rust/kernel/pages.rs b/rust/kernel/pages.rs
new file mode 100644
index 000000000000..f2bb26810cd7
--- /dev/null
+++ b/rust/kernel/pages.rs
@@ -0,0 +1,144 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Kernel page allocation and management.
+//!
+//! TODO: This module is a work in progress.
+
+use crate::{
+    bindings, error::code::*, io_buffer::IoBufferReader, user_ptr::UserSlicePtrReader, Result,
+    PAGE_SIZE,
+};
+use core::{marker::PhantomData, ptr};
+
+/// A set of physical pages.
+///
+/// `Pages` holds a reference to a set of pages of order `ORDER`. Having the order as a generic
+/// const allows the struct to have the same size as a pointer.
+///
+/// # Invariants
+///
+/// The pointer `Pages::pages` is valid and points to 2^ORDER pages.
+pub struct Pages<const ORDER: u32> {
+    pub(crate) pages: *mut bindings::page,
+}
+
+impl<const ORDER: u32> Pages<ORDER> {
+    /// Allocates a new set of contiguous pages.
+    pub fn new() -> Result<Self> {
+        // TODO: Consider whether we want to allow callers to specify flags.
+        // SAFETY: This only allocates pages. We check that it succeeds in the next statement.
+        let pages = unsafe {
+            bindings::alloc_pages(
+                bindings::GFP_KERNEL | bindings::__GFP_ZERO | bindings::__GFP_HIGHMEM,
+                ORDER,
+            )
+        };
+        if pages.is_null() {
+            return Err(ENOMEM);
+        }
+        // INVARIANTS: We checked that the allocation above succeeded.
+        Ok(Self { pages })
+    }
+
+    /// Copies data from the given [`UserSlicePtrReader`] into the pages.
+    pub fn copy_into_page(
+        &self,
+        reader: &mut UserSlicePtrReader,
+        offset: usize,
+        len: usize,
+    ) -> Result {
+        // TODO: For now this only works on the first page.
+        let end = offset.checked_add(len).ok_or(EINVAL)?;
+        if end > PAGE_SIZE {
+            return Err(EINVAL);
+        }
+
+        let mapping = self.kmap(0).ok_or(EINVAL)?;
+
+        // SAFETY: We ensured that the buffer was valid with the check above.
+        unsafe { reader.read_raw((mapping.ptr as usize + offset) as _, len) }?;
+        Ok(())
+    }
+
+    /// Maps the pages and reads from them into the given buffer.
+    ///
+    /// # Safety
+    ///
+    /// Callers must ensure that the destination buffer is valid for the given length.
+    /// Additionally, if the raw buffer is intended to be recast, they must ensure that the data
+    /// can be safely cast; [`crate::io_buffer::ReadableFromBytes`] has more details about it.
+    pub unsafe fn read(&self, dest: *mut u8, offset: usize, len: usize) -> Result {
+        // TODO: For now this only works on the first page.
+        let end = offset.checked_add(len).ok_or(EINVAL)?;
+        if end > PAGE_SIZE {
+            return Err(EINVAL);
+        }
+
+        let mapping = self.kmap(0).ok_or(EINVAL)?;
+        unsafe { ptr::copy((mapping.ptr as *mut u8).add(offset), dest, len) };
+        Ok(())
+    }
+
+    /// Maps the pages and writes into them from the given buffer.
+    ///
+    /// # Safety
+    ///
+    /// Callers must ensure that the buffer is valid for the given length. Additionally, if the
+    /// page is (or will be) mapped by userspace, they must ensure that no kernel data is leaked
+    /// through padding if it was cast from another type; [`crate::io_buffer::WritableToBytes`] has
+    /// more details about it.
+    pub unsafe fn write(&self, src: *const u8, offset: usize, len: usize) -> Result {
+        // TODO: For now this only works on the first page.
+        let end = offset.checked_add(len).ok_or(EINVAL)?;
+        if end > PAGE_SIZE {
+            return Err(EINVAL);
+        }
+
+        let mapping = self.kmap(0).ok_or(EINVAL)?;
+        unsafe { ptr::copy(src, (mapping.ptr as *mut u8).add(offset), len) };
+        Ok(())
+    }
+
+    /// Maps the page at index `index`.
+    fn kmap(&self, index: usize) -> Option<PageMapping<'_>> {
+        if index >= 1usize << ORDER {
+            return None;
+        }
+
+        // SAFETY: We checked above that `index` is within range.
+        let page = unsafe { self.pages.add(index) };
+
+        // SAFETY: `page` is valid based on the checks above.
+        let ptr = unsafe { bindings::kmap(page) };
+        if ptr.is_null() {
+            return None;
+        }
+
+        Some(PageMapping {
+            page,
+            ptr,
+            _phantom: PhantomData,
+        })
+    }
+}
+
+impl<const ORDER: u32> Drop for Pages<ORDER> {
+    fn drop(&mut self) {
+        // SAFETY: By the type invariants, we know the pages are allocated with the given order.
+        unsafe { bindings::__free_pages(self.pages, ORDER) };
+    }
+}
+
+struct PageMapping<'a> {
+    page: *mut bindings::page,
+    ptr: *mut core::ffi::c_void,
+    _phantom: PhantomData<&'a i32>,
+}
+
+impl Drop for PageMapping<'_> {
+    fn drop(&mut self) {
+        // SAFETY: An instance of `PageMapping` is created only when `kmap` succeeded for the given
+        // page, so it is safe to unmap it here.
+        unsafe { bindings::kunmap(self.page) };
+    }
+}
diff --git a/rust/kernel/platform.rs b/rust/kernel/platform.rs
new file mode 100644
index 000000000000..d8cc0e0120aa
--- /dev/null
+++ b/rust/kernel/platform.rs
@@ -0,0 +1,223 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Platform devices and drivers.
+//!
+//! Also called `platdev`, `pdev`.
+//!
+//! C header: [`include/linux/platform_device.h`](../../../../include/linux/platform_device.h)
+
+use crate::{
+    bindings,
+    device::{self, RawDevice},
+    driver,
+    error::{from_kernel_result, Result},
+    of,
+    str::CStr,
+    to_result,
+    types::PointerWrapper,
+    ThisModule,
+};
+
+/// A registration of a platform driver.
+pub type Registration<T> = driver::Registration<Adapter<T>>;
+
+/// An adapter for the registration of platform drivers.
+pub struct Adapter<T: Driver>(T);
+
+impl<T: Driver> driver::DriverOps for Adapter<T> {
+    type RegType = bindings::platform_driver;
+
+    unsafe fn register(
+        reg: *mut bindings::platform_driver,
+        name: &'static CStr,
+        module: &'static ThisModule,
+    ) -> Result {
+        // SAFETY: By the safety requirements of this function (defined in the trait definition),
+        // `reg` is non-null and valid.
+        let pdrv = unsafe { &mut *reg };
+
+        pdrv.driver.name = name.as_char_ptr();
+        pdrv.probe = Some(Self::probe_callback);
+        pdrv.remove = Some(Self::remove_callback);
+        if let Some(t) = T::OF_DEVICE_ID_TABLE {
+            pdrv.driver.of_match_table = t.as_ref();
+        }
+        // SAFETY:
+        //   - `pdrv` lives at least until the call to `platform_driver_unregister()` returns.
+        //   - `name` pointer has static lifetime.
+        //   - `module.0` lives at least as long as the module.
+        //   - `probe()` and `remove()` are static functions.
+        //   - `of_match_table` is either a raw pointer with static lifetime,
+        //      as guaranteed by the [`driver::IdTable`] type, or null.
+        to_result(unsafe { bindings::__platform_driver_register(reg, module.0) })
+    }
+
+    unsafe fn unregister(reg: *mut bindings::platform_driver) {
+        // SAFETY: By the safety requirements of this function (defined in the trait definition),
+        // `reg` was passed (and updated) by a previous successful call to
+        // `platform_driver_register`.
+        unsafe { bindings::platform_driver_unregister(reg) };
+    }
+}
+
+impl<T: Driver> Adapter<T> {
+    fn get_id_info(dev: &Device) -> Option<&'static T::IdInfo> {
+        let table = T::OF_DEVICE_ID_TABLE?;
+
+        // SAFETY: `table` has static lifetime, so it is valid for read. `dev` is guaranteed to be
+        // valid while it's alive, so is the raw device returned by it.
+        let id = unsafe { bindings::of_match_device(table.as_ref(), dev.raw_device()) };
+        if id.is_null() {
+            return None;
+        }
+
+        // SAFETY: `id` is a pointer within the static table, so it's always valid.
+        let offset = unsafe { (*id).data };
+        if offset.is_null() {
+            return None;
+        }
+
+        // SAFETY: The offset comes from a previous call to `offset_from` in `IdArray::new`, which
+        // guarantees that the resulting pointer is within the table.
+        let ptr = unsafe {
+            id.cast::<u8>()
+                .offset(offset as _)
+                .cast::<Option<T::IdInfo>>()
+        };
+
+        // SAFETY: The id table has a static lifetime, so `ptr` is guaranteed to be valid for read.
+        unsafe { (&*ptr).as_ref() }
+    }
+
+    extern "C" fn probe_callback(pdev: *mut bindings::platform_device) -> core::ffi::c_int {
+        from_kernel_result! {
+            // SAFETY: `pdev` is valid by the contract with the C code. `dev` is alive only for the
+            // duration of this call, so it is guaranteed to remain alive for the lifetime of
+            // `pdev`.
+            let mut dev = unsafe { Device::from_ptr(pdev) };
+            let info = Self::get_id_info(&dev);
+            let data = T::probe(&mut dev, info)?;
+            // SAFETY: `pdev` is guaranteed to be a valid, non-null pointer.
+            unsafe { bindings::platform_set_drvdata(pdev, data.into_pointer() as _) };
+            Ok(0)
+        }
+    }
+
+    extern "C" fn remove_callback(pdev: *mut bindings::platform_device) -> core::ffi::c_int {
+        from_kernel_result! {
+            // SAFETY: `pdev` is guaranteed to be a valid, non-null pointer.
+            let ptr = unsafe { bindings::platform_get_drvdata(pdev) };
+            // SAFETY:
+            //   - we allocated this pointer using `T::Data::into_pointer`,
+            //     so it is safe to turn back into a `T::Data`.
+            //   - the allocation happened in `probe`, no-one freed the memory,
+            //     `remove` is the canonical kernel location to free driver data. so OK
+            //     to convert the pointer back to a Rust structure here.
+            let data = unsafe { T::Data::from_pointer(ptr) };
+            let ret = T::remove(&data);
+            <T::Data as driver::DeviceRemoval>::device_remove(&data);
+            ret?;
+            Ok(0)
+        }
+    }
+}
+
+/// A platform driver.
+pub trait Driver {
+    /// Data stored on device by driver.
+    ///
+    /// Corresponds to the data set or retrieved via the kernel's
+    /// `platform_{set,get}_drvdata()` functions.
+    ///
+    /// Require that `Data` implements `PointerWrapper`. We guarantee to
+    /// never move the underlying wrapped data structure. This allows
+    type Data: PointerWrapper + Send + Sync + driver::DeviceRemoval = ();
+
+    /// The type holding information about each device id supported by the driver.
+    type IdInfo: 'static = ();
+
+    /// The table of device ids supported by the driver.
+    const OF_DEVICE_ID_TABLE: Option<driver::IdTable<'static, of::DeviceId, Self::IdInfo>> = None;
+
+    /// Platform driver probe.
+    ///
+    /// Called when a new platform device is added or discovered.
+    /// Implementers should attempt to initialize the device here.
+    fn probe(dev: &mut Device, id_info: Option<&Self::IdInfo>) -> Result<Self::Data>;
+
+    /// Platform driver remove.
+    ///
+    /// Called when a platform device is removed.
+    /// Implementers should prepare the device for complete removal here.
+    fn remove(_data: &Self::Data) -> Result {
+        Ok(())
+    }
+}
+
+/// A platform device.
+///
+/// # Invariants
+///
+/// The field `ptr` is non-null and valid for the lifetime of the object.
+pub struct Device {
+    ptr: *mut bindings::platform_device,
+}
+
+impl Device {
+    /// Creates a new device from the given pointer.
+    ///
+    /// # Safety
+    ///
+    /// `ptr` must be non-null and valid. It must remain valid for the lifetime of the returned
+    /// instance.
+    unsafe fn from_ptr(ptr: *mut bindings::platform_device) -> Self {
+        // INVARIANT: The safety requirements of the function ensure the lifetime invariant.
+        Self { ptr }
+    }
+
+    /// Returns id of the platform device.
+    pub fn id(&self) -> i32 {
+        // SAFETY: By the type invariants, we know that `self.ptr` is non-null and valid.
+        unsafe { (*self.ptr).id }
+    }
+}
+
+// SAFETY: The device returned by `raw_device` is the raw platform device.
+unsafe impl device::RawDevice for Device {
+    fn raw_device(&self) -> *mut bindings::device {
+        // SAFETY: By the type invariants, we know that `self.ptr` is non-null and valid.
+        unsafe { &mut (*self.ptr).dev }
+    }
+}
+
+/// Declares a kernel module that exposes a single platform driver.
+///
+/// # Examples
+///
+/// ```ignore
+/// # use kernel::{platform, define_of_id_table, module_platform_driver};
+/// #
+/// struct MyDriver;
+/// impl platform::Driver for MyDriver {
+///     // [...]
+/// #   fn probe(_dev: &mut platform::Device, _id_info: Option<&Self::IdInfo>) -> Result {
+/// #       Ok(())
+/// #   }
+/// #   define_of_id_table! {(), [
+/// #       (of::DeviceId::Compatible(b"brcm,bcm2835-rng"), None),
+/// #   ]}
+/// }
+///
+/// module_platform_driver! {
+///     type: MyDriver,
+///     name: b"module_name",
+///     author: b"Author name",
+///     license: b"GPL",
+/// }
+/// ```
+#[macro_export]
+macro_rules! module_platform_driver {
+    ($($f:tt)*) => {
+        $crate::module_driver!(<T>, $crate::platform::Adapter<T>, { $($f)* });
+    };
+}
diff --git a/rust/kernel/power.rs b/rust/kernel/power.rs
new file mode 100644
index 000000000000..ef788557b269
--- /dev/null
+++ b/rust/kernel/power.rs
@@ -0,0 +1,118 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Power management interfaces.
+//!
+//! C header: [`include/linux/pm.h`](../../../../include/linux/pm.h)
+
+#![allow(dead_code)]
+
+use crate::{bindings, error::from_kernel_result, types::PointerWrapper, Result};
+use core::marker::PhantomData;
+
+/// Corresponds to the kernel's `struct dev_pm_ops`.
+///
+/// It is meant to be implemented by drivers that support power-management operations.
+pub trait Operations {
+    /// The type of the context data stored by the driver on each device.
+    type Data: PointerWrapper + Sync + Send;
+
+    /// Called before the system goes into a sleep state.
+    fn suspend(_data: <Self::Data as PointerWrapper>::Borrowed<'_>) -> Result {
+        Ok(())
+    }
+
+    /// Called after the system comes back from a sleep state.
+    fn resume(_data: <Self::Data as PointerWrapper>::Borrowed<'_>) -> Result {
+        Ok(())
+    }
+
+    /// Called before creating a hibernation image.
+    fn freeze(_data: <Self::Data as PointerWrapper>::Borrowed<'_>) -> Result {
+        Ok(())
+    }
+
+    /// Called after the system is restored from a hibernation image.
+    fn restore(_data: <Self::Data as PointerWrapper>::Borrowed<'_>) -> Result {
+        Ok(())
+    }
+}
+
+macro_rules! pm_callback {
+    ($callback:ident, $method:ident) => {
+        unsafe extern "C" fn $callback<T: Operations>(
+            dev: *mut bindings::device,
+        ) -> core::ffi::c_int {
+            from_kernel_result! {
+                // SAFETY: `dev` is valid as it was passed in by the C portion.
+                let ptr = unsafe { bindings::dev_get_drvdata(dev) };
+                // SAFETY: By the safety requirements of `OpsTable::build`, we know that `ptr` came
+                // from a previous call to `T::Data::into_pointer`.
+                let data = unsafe { T::Data::borrow(ptr) };
+                T::$method(data)?;
+                Ok(0)
+            }
+        }
+    };
+}
+
+pm_callback!(suspend_callback, suspend);
+pm_callback!(resume_callback, resume);
+pm_callback!(freeze_callback, freeze);
+pm_callback!(restore_callback, restore);
+
+pub(crate) struct OpsTable<T: Operations>(PhantomData<*const T>);
+
+impl<T: Operations> OpsTable<T> {
+    const VTABLE: bindings::dev_pm_ops = bindings::dev_pm_ops {
+        prepare: None,
+        complete: None,
+        suspend: Some(suspend_callback::<T>),
+        resume: Some(resume_callback::<T>),
+        freeze: Some(freeze_callback::<T>),
+        thaw: None,
+        poweroff: None,
+        restore: Some(restore_callback::<T>),
+        suspend_late: None,
+        resume_early: None,
+        freeze_late: None,
+        thaw_early: None,
+        poweroff_late: None,
+        restore_early: None,
+        suspend_noirq: None,
+        resume_noirq: None,
+        freeze_noirq: None,
+        thaw_noirq: None,
+        poweroff_noirq: None,
+        restore_noirq: None,
+        runtime_suspend: None,
+        runtime_resume: None,
+        runtime_idle: None,
+    };
+
+    /// Builds an instance of `struct dev_pm_ops`.
+    ///
+    /// # Safety
+    ///
+    /// The caller must ensure that `dev_get_drvdata` will result in a value returned by
+    /// [`T::Data::into_pointer`].
+    pub(crate) const unsafe fn build() -> &'static bindings::dev_pm_ops {
+        &Self::VTABLE
+    }
+}
+
+/// Implements the [`Operations`] trait as no-ops.
+///
+/// This is useful when one doesn't want to provide the implementation of any power-manager related
+/// operation.
+pub struct NoOperations<T: PointerWrapper>(PhantomData<T>);
+
+impl<T: PointerWrapper + Send + Sync> Operations for NoOperations<T> {
+    type Data = T;
+}
+
+// SAFETY: `NoOperation` provides no functionality, it is safe to send a reference to it to
+// different threads.
+unsafe impl<T: PointerWrapper> Sync for NoOperations<T> {}
+
+// SAFETY: `NoOperation` provides no functionality, it is safe to send it to different threads.
+unsafe impl<T: PointerWrapper> Send for NoOperations<T> {}
diff --git a/rust/kernel/prelude.rs b/rust/kernel/prelude.rs
new file mode 100644
index 000000000000..26f8af9e16ab
--- /dev/null
+++ b/rust/kernel/prelude.rs
@@ -0,0 +1,36 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! The `kernel` prelude.
+//!
+//! These are the most common items used by Rust code in the kernel,
+//! intended to be imported by all Rust code, for convenience.
+//!
+//! # Examples
+//!
+//! ```
+//! use kernel::prelude::*;
+//! ```
+
+pub use core::pin::Pin;
+
+pub use alloc::{boxed::Box, string::String, vec::Vec};
+
+pub use macros::{module, vtable};
+
+pub use super::build_assert;
+
+pub use super::{
+    dbg, dev_alert, dev_crit, dev_dbg, dev_emerg, dev_err, dev_info, dev_notice, dev_warn, fmt,
+    pr_alert, pr_crit, pr_debug, pr_emerg, pr_err, pr_info, pr_notice, pr_warn,
+};
+
+pub use super::{module_fs, module_misc_device};
+
+#[cfg(CONFIG_ARM_AMBA)]
+pub use super::module_amba_driver;
+
+pub use super::static_assert;
+
+pub use super::{error::code::*, Error, Result};
+
+pub use super::{str::CStr, ARef, ThisModule};
diff --git a/rust/kernel/print.rs b/rust/kernel/print.rs
new file mode 100644
index 000000000000..92541efc7e22
--- /dev/null
+++ b/rust/kernel/print.rs
@@ -0,0 +1,406 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Printing facilities.
+//!
+//! C header: [`include/linux/printk.h`](../../../../include/linux/printk.h)
+//!
+//! Reference: <https://www.kernel.org/doc/html/latest/core-api/printk-basics.html>
+
+use core::{
+    ffi::{c_char, c_void},
+    fmt,
+};
+
+use crate::str::RawFormatter;
+
+#[cfg(CONFIG_PRINTK)]
+use crate::bindings;
+
+// Called from `vsprintf` with format specifier `%pA`.
+#[no_mangle]
+unsafe fn rust_fmt_argument(buf: *mut c_char, end: *mut c_char, ptr: *const c_void) -> *mut c_char {
+    use fmt::Write;
+    // SAFETY: The C contract guarantees that `buf` is valid if it's less than `end`.
+    let mut w = unsafe { RawFormatter::from_ptrs(buf.cast(), end.cast()) };
+    let _ = w.write_fmt(unsafe { *(ptr as *const fmt::Arguments<'_>) });
+    w.pos().cast()
+}
+
+/// Format strings.
+///
+/// Public but hidden since it should only be used from public macros.
+#[doc(hidden)]
+pub mod format_strings {
+    use crate::bindings;
+
+    /// The length we copy from the `KERN_*` kernel prefixes.
+    const LENGTH_PREFIX: usize = 2;
+
+    /// The length of the fixed format strings.
+    pub const LENGTH: usize = 10;
+
+    /// Generates a fixed format string for the kernel's [`_printk`].
+    ///
+    /// The format string is always the same for a given level, i.e. for a
+    /// given `prefix`, which are the kernel's `KERN_*` constants.
+    ///
+    /// [`_printk`]: ../../../../include/linux/printk.h
+    const fn generate(is_cont: bool, prefix: &[u8; 3]) -> [u8; LENGTH] {
+        // Ensure the `KERN_*` macros are what we expect.
+        assert!(prefix[0] == b'\x01');
+        if is_cont {
+            assert!(prefix[1] == b'c');
+        } else {
+            assert!(prefix[1] >= b'0' && prefix[1] <= b'7');
+        }
+        assert!(prefix[2] == b'\x00');
+
+        let suffix: &[u8; LENGTH - LENGTH_PREFIX] = if is_cont {
+            b"%pA\0\0\0\0\0"
+        } else {
+            b"%s: %pA\0"
+        };
+
+        [
+            prefix[0], prefix[1], suffix[0], suffix[1], suffix[2], suffix[3], suffix[4], suffix[5],
+            suffix[6], suffix[7],
+        ]
+    }
+
+    // Generate the format strings at compile-time.
+    //
+    // This avoids the compiler generating the contents on the fly in the stack.
+    //
+    // Furthermore, `static` instead of `const` is used to share the strings
+    // for all the kernel.
+    pub static EMERG: [u8; LENGTH] = generate(false, bindings::KERN_EMERG);
+    pub static ALERT: [u8; LENGTH] = generate(false, bindings::KERN_ALERT);
+    pub static CRIT: [u8; LENGTH] = generate(false, bindings::KERN_CRIT);
+    pub static ERR: [u8; LENGTH] = generate(false, bindings::KERN_ERR);
+    pub static WARNING: [u8; LENGTH] = generate(false, bindings::KERN_WARNING);
+    pub static NOTICE: [u8; LENGTH] = generate(false, bindings::KERN_NOTICE);
+    pub static INFO: [u8; LENGTH] = generate(false, bindings::KERN_INFO);
+    pub static DEBUG: [u8; LENGTH] = generate(false, bindings::KERN_DEBUG);
+    pub static CONT: [u8; LENGTH] = generate(true, bindings::KERN_CONT);
+}
+
+/// Prints a message via the kernel's [`_printk`].
+///
+/// Public but hidden since it should only be used from public macros.
+///
+/// # Safety
+///
+/// The format string must be one of the ones in [`format_strings`], and
+/// the module name must be null-terminated.
+///
+/// [`_printk`]: ../../../../include/linux/_printk.h
+#[doc(hidden)]
+#[cfg_attr(not(CONFIG_PRINTK), allow(unused_variables))]
+pub unsafe fn call_printk(
+    format_string: &[u8; format_strings::LENGTH],
+    module_name: &[u8],
+    args: fmt::Arguments<'_>,
+) {
+    // `_printk` does not seem to fail in any path.
+    #[cfg(CONFIG_PRINTK)]
+    unsafe {
+        bindings::_printk(
+            format_string.as_ptr() as _,
+            module_name.as_ptr(),
+            &args as *const _ as *const c_void,
+        );
+    }
+}
+
+/// Prints a message via the kernel's [`_printk`] for the `CONT` level.
+///
+/// Public but hidden since it should only be used from public macros.
+///
+/// [`_printk`]: ../../../../include/linux/printk.h
+#[doc(hidden)]
+#[cfg_attr(not(CONFIG_PRINTK), allow(unused_variables))]
+pub fn call_printk_cont(args: fmt::Arguments<'_>) {
+    // `_printk` does not seem to fail in any path.
+    //
+    // SAFETY: The format string is fixed.
+    #[cfg(CONFIG_PRINTK)]
+    unsafe {
+        bindings::_printk(
+            format_strings::CONT.as_ptr() as _,
+            &args as *const _ as *const c_void,
+        );
+    }
+}
+
+/// Performs formatting and forwards the string to [`call_printk`].
+///
+/// Public but hidden since it should only be used from public macros.
+#[doc(hidden)]
+#[cfg(not(testlib))]
+#[macro_export]
+#[allow(clippy::crate_in_macro_def)]
+macro_rules! print_macro (
+    // The non-continuation cases (most of them, e.g. `INFO`).
+    ($format_string:path, false, $($arg:tt)+) => (
+        // SAFETY: This hidden macro should only be called by the documented
+        // printing macros which ensure the format string is one of the fixed
+        // ones. All `__LOG_PREFIX`s are null-terminated as they are generated
+        // by the `module!` proc macro or fixed values defined in a kernel
+        // crate.
+        unsafe {
+            $crate::print::call_printk(
+                &$format_string,
+                crate::__LOG_PREFIX,
+                format_args!($($arg)+),
+            );
+        }
+    );
+
+    // The `CONT` case.
+    ($format_string:path, true, $($arg:tt)+) => (
+        $crate::print::call_printk_cont(
+            format_args!($($arg)+),
+        );
+    );
+);
+
+/// Stub for doctests
+#[cfg(testlib)]
+#[macro_export]
+macro_rules! print_macro (
+    ($format_string:path, $e:expr, $($arg:tt)+) => (
+        ()
+    );
+);
+
+// We could use a macro to generate these macros. However, doing so ends
+// up being a bit ugly: it requires the dollar token trick to escape `$` as
+// well as playing with the `doc` attribute. Furthermore, they cannot be easily
+// imported in the prelude due to [1]. So, for the moment, we just write them
+// manually, like in the C side; while keeping most of the logic in another
+// macro, i.e. [`print_macro`].
+//
+// [1]: https://github.com/rust-lang/rust/issues/52234
+
+/// Prints an emergency-level message (level 0).
+///
+/// Use this level if the system is unusable.
+///
+/// Equivalent to the kernel's [`pr_emerg`] macro.
+///
+/// Mimics the interface of [`std::print!`]. See [`core::fmt`] and
+/// [`alloc::format!`] for information about the formatting syntax.
+///
+/// [`pr_emerg`]: https://www.kernel.org/doc/html/latest/core-api/printk-basics.html#c.pr_emerg
+/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html
+///
+/// # Examples
+///
+/// ```
+/// pr_emerg!("hello {}\n", "there");
+/// ```
+#[macro_export]
+macro_rules! pr_emerg (
+    ($($arg:tt)*) => (
+        $crate::print_macro!($crate::print::format_strings::EMERG, false, $($arg)*)
+    )
+);
+
+/// Prints an alert-level message (level 1).
+///
+/// Use this level if action must be taken immediately.
+///
+/// Equivalent to the kernel's [`pr_alert`] macro.
+///
+/// Mimics the interface of [`std::print!`]. See [`core::fmt`] and
+/// [`alloc::format!`] for information about the formatting syntax.
+///
+/// [`pr_alert`]: https://www.kernel.org/doc/html/latest/core-api/printk-basics.html#c.pr_alert
+/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html
+///
+/// # Examples
+///
+/// ```
+/// pr_alert!("hello {}\n", "there");
+/// ```
+#[macro_export]
+macro_rules! pr_alert (
+    ($($arg:tt)*) => (
+        $crate::print_macro!($crate::print::format_strings::ALERT, false, $($arg)*)
+    )
+);
+
+/// Prints a critical-level message (level 2).
+///
+/// Use this level for critical conditions.
+///
+/// Equivalent to the kernel's [`pr_crit`] macro.
+///
+/// Mimics the interface of [`std::print!`]. See [`core::fmt`] and
+/// [`alloc::format!`] for information about the formatting syntax.
+///
+/// [`pr_crit`]: https://www.kernel.org/doc/html/latest/core-api/printk-basics.html#c.pr_crit
+/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html
+///
+/// # Examples
+///
+/// ```
+/// pr_crit!("hello {}\n", "there");
+/// ```
+#[macro_export]
+macro_rules! pr_crit (
+    ($($arg:tt)*) => (
+        $crate::print_macro!($crate::print::format_strings::CRIT, false, $($arg)*)
+    )
+);
+
+/// Prints an error-level message (level 3).
+///
+/// Use this level for error conditions.
+///
+/// Equivalent to the kernel's [`pr_err`] macro.
+///
+/// Mimics the interface of [`std::print!`]. See [`core::fmt`] and
+/// [`alloc::format!`] for information about the formatting syntax.
+///
+/// [`pr_err`]: https://www.kernel.org/doc/html/latest/core-api/printk-basics.html#c.pr_err
+/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html
+///
+/// # Examples
+///
+/// ```
+/// pr_err!("hello {}\n", "there");
+/// ```
+#[macro_export]
+macro_rules! pr_err (
+    ($($arg:tt)*) => (
+        $crate::print_macro!($crate::print::format_strings::ERR, false, $($arg)*)
+    )
+);
+
+/// Prints a warning-level message (level 4).
+///
+/// Use this level for warning conditions.
+///
+/// Equivalent to the kernel's [`pr_warn`] macro.
+///
+/// Mimics the interface of [`std::print!`]. See [`core::fmt`] and
+/// [`alloc::format!`] for information about the formatting syntax.
+///
+/// [`pr_warn`]: https://www.kernel.org/doc/html/latest/core-api/printk-basics.html#c.pr_warn
+/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html
+///
+/// # Examples
+///
+/// ```
+/// pr_warn!("hello {}\n", "there");
+/// ```
+#[macro_export]
+macro_rules! pr_warn (
+    ($($arg:tt)*) => (
+        $crate::print_macro!($crate::print::format_strings::WARNING, false, $($arg)*)
+    )
+);
+
+/// Prints a notice-level message (level 5).
+///
+/// Use this level for normal but significant conditions.
+///
+/// Equivalent to the kernel's [`pr_notice`] macro.
+///
+/// Mimics the interface of [`std::print!`]. See [`core::fmt`] and
+/// [`alloc::format!`] for information about the formatting syntax.
+///
+/// [`pr_notice`]: https://www.kernel.org/doc/html/latest/core-api/printk-basics.html#c.pr_notice
+/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html
+///
+/// # Examples
+///
+/// ```
+/// pr_notice!("hello {}\n", "there");
+/// ```
+#[macro_export]
+macro_rules! pr_notice (
+    ($($arg:tt)*) => (
+        $crate::print_macro!($crate::print::format_strings::NOTICE, false, $($arg)*)
+    )
+);
+
+/// Prints an info-level message (level 6).
+///
+/// Use this level for informational messages.
+///
+/// Equivalent to the kernel's [`pr_info`] macro.
+///
+/// Mimics the interface of [`std::print!`]. See [`core::fmt`] and
+/// [`alloc::format!`] for information about the formatting syntax.
+///
+/// [`pr_info`]: https://www.kernel.org/doc/html/latest/core-api/printk-basics.html#c.pr_info
+/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html
+///
+/// # Examples
+///
+/// ```
+/// pr_info!("hello {}\n", "there");
+/// ```
+#[macro_export]
+#[doc(alias = "print")]
+macro_rules! pr_info (
+    ($($arg:tt)*) => (
+        $crate::print_macro!($crate::print::format_strings::INFO, false, $($arg)*)
+    )
+);
+
+/// Prints a debug-level message (level 7).
+///
+/// Use this level for debug messages.
+///
+/// Equivalent to the kernel's [`pr_debug`] macro, except that it doesn't support dynamic debug
+/// yet.
+///
+/// Mimics the interface of [`std::print!`]. See [`core::fmt`] and
+/// [`alloc::format!`] for information about the formatting syntax.
+///
+/// [`pr_debug`]: https://www.kernel.org/doc/html/latest/core-api/printk-basics.html#c.pr_debug
+/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html
+///
+/// # Examples
+///
+/// ```
+/// pr_debug!("hello {}\n", "there");
+/// ```
+#[macro_export]
+#[doc(alias = "print")]
+macro_rules! pr_debug (
+    ($($arg:tt)*) => (
+        if cfg!(debug_assertions) {
+            $crate::print_macro!($crate::print::format_strings::DEBUG, false, $($arg)*)
+        }
+    )
+);
+
+/// Continues a previous log message in the same line.
+///
+/// Use only when continuing a previous `pr_*!` macro (e.g. [`pr_info!`]).
+///
+/// Equivalent to the kernel's [`pr_cont`] macro.
+///
+/// Mimics the interface of [`std::print!`]. See [`core::fmt`] and
+/// [`alloc::format!`] for information about the formatting syntax.
+///
+/// [`pr_cont`]: https://www.kernel.org/doc/html/latest/core-api/printk-basics.html#c.pr_cont
+/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::pr_cont;
+/// pr_info!("hello");
+/// pr_cont!(" {}\n", "there");
+/// ```
+#[macro_export]
+macro_rules! pr_cont (
+    ($($arg:tt)*) => (
+        $crate::print_macro!($crate::print::format_strings::CONT, true, $($arg)*)
+    )
+);
diff --git a/rust/kernel/random.rs b/rust/kernel/random.rs
new file mode 100644
index 000000000000..c30dd675d6a0
--- /dev/null
+++ b/rust/kernel/random.rs
@@ -0,0 +1,42 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Random numbers.
+//!
+//! C header: [`include/linux/random.h`](../../../../include/linux/random.h)
+
+use crate::{bindings, error::code::*, Error, Result};
+
+/// Fills a byte slice with random bytes generated from the kernel's CSPRNG.
+///
+/// Ensures that the CSPRNG has been seeded before generating any random bytes,
+/// and will block until it is ready.
+pub fn getrandom(dest: &mut [u8]) -> Result {
+    let res = unsafe { bindings::wait_for_random_bytes() };
+    if res != 0 {
+        return Err(Error::from_kernel_errno(res));
+    }
+
+    unsafe {
+        bindings::get_random_bytes(dest.as_mut_ptr() as *mut core::ffi::c_void, dest.len());
+    }
+    Ok(())
+}
+
+/// Fills a byte slice with random bytes generated from the kernel's CSPRNG.
+///
+/// If the CSPRNG is not yet seeded, returns an `Err(EAGAIN)` immediately.
+pub fn getrandom_nonblock(dest: &mut [u8]) -> Result {
+    if !unsafe { bindings::rng_is_initialized() } {
+        return Err(EAGAIN);
+    }
+    getrandom(dest)
+}
+
+/// Contributes the contents of a byte slice to the kernel's entropy pool.
+///
+/// Does *not* credit the kernel entropy counter though.
+pub fn add_randomness(data: &[u8]) {
+    unsafe {
+        bindings::add_device_randomness(data.as_ptr() as *const core::ffi::c_void, data.len());
+    }
+}
diff --git a/rust/kernel/raw_list.rs b/rust/kernel/raw_list.rs
new file mode 100644
index 000000000000..267b21709c29
--- /dev/null
+++ b/rust/kernel/raw_list.rs
@@ -0,0 +1,361 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Raw lists.
+//!
+//! TODO: This module is a work in progress.
+
+use core::{
+    cell::UnsafeCell,
+    ptr,
+    ptr::NonNull,
+    sync::atomic::{AtomicBool, Ordering},
+};
+
+/// A descriptor of list elements.
+///
+/// It describes the type of list elements and provides a function to determine how to get the
+/// links to be used on a list.
+///
+/// A type that may be in multiple lists simultaneously needs to implement one of these for each
+/// simultaneous list.
+pub trait GetLinks {
+    /// The type of the entries in the list.
+    type EntryType: ?Sized;
+
+    /// Returns the links to be used when linking an entry within a list.
+    fn get_links(data: &Self::EntryType) -> &Links<Self::EntryType>;
+}
+
+/// The links used to link an object on a linked list.
+///
+/// Instances of this type are usually embedded in structures and returned in calls to
+/// [`GetLinks::get_links`].
+pub struct Links<T: ?Sized> {
+    inserted: AtomicBool,
+    entry: UnsafeCell<ListEntry<T>>,
+}
+
+impl<T: ?Sized> Links<T> {
+    /// Constructs a new [`Links`] instance that isn't inserted on any lists yet.
+    pub fn new() -> Self {
+        Self {
+            inserted: AtomicBool::new(false),
+            entry: UnsafeCell::new(ListEntry::new()),
+        }
+    }
+
+    fn acquire_for_insertion(&self) -> bool {
+        self.inserted
+            .compare_exchange(false, true, Ordering::Acquire, Ordering::Relaxed)
+            .is_ok()
+    }
+
+    fn release_after_removal(&self) {
+        self.inserted.store(false, Ordering::Release);
+    }
+}
+
+impl<T: ?Sized> Default for Links<T> {
+    fn default() -> Self {
+        Self::new()
+    }
+}
+
+struct ListEntry<T: ?Sized> {
+    next: Option<NonNull<T>>,
+    prev: Option<NonNull<T>>,
+}
+
+impl<T: ?Sized> ListEntry<T> {
+    fn new() -> Self {
+        Self {
+            next: None,
+            prev: None,
+        }
+    }
+}
+
+/// A linked list.
+///
+/// # Invariants
+///
+/// The links of objects added to a list are owned by the list.
+pub(crate) struct RawList<G: GetLinks> {
+    head: Option<NonNull<G::EntryType>>,
+}
+
+impl<G: GetLinks> RawList<G> {
+    pub(crate) fn new() -> Self {
+        Self { head: None }
+    }
+
+    pub(crate) fn is_empty(&self) -> bool {
+        self.head.is_none()
+    }
+
+    fn insert_after_priv(
+        &mut self,
+        existing: &G::EntryType,
+        new_entry: &mut ListEntry<G::EntryType>,
+        new_ptr: Option<NonNull<G::EntryType>>,
+    ) {
+        {
+            // SAFETY: It's safe to get the previous entry of `existing` because the list cannot
+            // change.
+            let existing_links = unsafe { &mut *G::get_links(existing).entry.get() };
+            new_entry.next = existing_links.next;
+            existing_links.next = new_ptr;
+        }
+
+        new_entry.prev = Some(NonNull::from(existing));
+
+        // SAFETY: It's safe to get the next entry of `existing` because the list cannot change.
+        let next_links =
+            unsafe { &mut *G::get_links(new_entry.next.unwrap().as_ref()).entry.get() };
+        next_links.prev = new_ptr;
+    }
+
+    /// Inserts the given object after `existing`.
+    ///
+    /// # Safety
+    ///
+    /// Callers must ensure that `existing` points to a valid entry that is on the list.
+    pub(crate) unsafe fn insert_after(
+        &mut self,
+        existing: &G::EntryType,
+        new: &G::EntryType,
+    ) -> bool {
+        let links = G::get_links(new);
+        if !links.acquire_for_insertion() {
+            // Nothing to do if already inserted.
+            return false;
+        }
+
+        // SAFETY: The links are now owned by the list, so it is safe to get a mutable reference.
+        let new_entry = unsafe { &mut *links.entry.get() };
+        self.insert_after_priv(existing, new_entry, Some(NonNull::from(new)));
+        true
+    }
+
+    fn push_back_internal(&mut self, new: &G::EntryType) -> bool {
+        let links = G::get_links(new);
+        if !links.acquire_for_insertion() {
+            // Nothing to do if already inserted.
+            return false;
+        }
+
+        // SAFETY: The links are now owned by the list, so it is safe to get a mutable reference.
+        let new_entry = unsafe { &mut *links.entry.get() };
+        let new_ptr = Some(NonNull::from(new));
+        match self.back() {
+            // SAFETY: `back` is valid as the list cannot change.
+            Some(back) => self.insert_after_priv(unsafe { back.as_ref() }, new_entry, new_ptr),
+            None => {
+                self.head = new_ptr;
+                new_entry.next = new_ptr;
+                new_entry.prev = new_ptr;
+            }
+        }
+        true
+    }
+
+    pub(crate) unsafe fn push_back(&mut self, new: &G::EntryType) -> bool {
+        self.push_back_internal(new)
+    }
+
+    fn remove_internal(&mut self, data: &G::EntryType) -> bool {
+        let links = G::get_links(data);
+
+        // SAFETY: The links are now owned by the list, so it is safe to get a mutable reference.
+        let entry = unsafe { &mut *links.entry.get() };
+        let next = if let Some(next) = entry.next {
+            next
+        } else {
+            // Nothing to do if the entry is not on the list.
+            return false;
+        };
+
+        if ptr::eq(data, next.as_ptr()) {
+            // We're removing the only element.
+            self.head = None
+        } else {
+            // Update the head if we're removing it.
+            if let Some(raw_head) = self.head {
+                if ptr::eq(data, raw_head.as_ptr()) {
+                    self.head = Some(next);
+                }
+            }
+
+            // SAFETY: It's safe to get the previous entry because the list cannot change.
+            unsafe { &mut *G::get_links(entry.prev.unwrap().as_ref()).entry.get() }.next =
+                entry.next;
+
+            // SAFETY: It's safe to get the next entry because the list cannot change.
+            unsafe { &mut *G::get_links(next.as_ref()).entry.get() }.prev = entry.prev;
+        }
+
+        // Reset the links of the element we're removing so that we know it's not on any list.
+        entry.next = None;
+        entry.prev = None;
+        links.release_after_removal();
+        true
+    }
+
+    /// Removes the given entry.
+    ///
+    /// # Safety
+    ///
+    /// Callers must ensure that `data` is either on this list or in no list. It being on another
+    /// list leads to memory unsafety.
+    pub(crate) unsafe fn remove(&mut self, data: &G::EntryType) -> bool {
+        self.remove_internal(data)
+    }
+
+    fn pop_front_internal(&mut self) -> Option<NonNull<G::EntryType>> {
+        let head = self.head?;
+        // SAFETY: The head is on the list as we just got it from there and it cannot change.
+        unsafe { self.remove(head.as_ref()) };
+        Some(head)
+    }
+
+    pub(crate) fn pop_front(&mut self) -> Option<NonNull<G::EntryType>> {
+        self.pop_front_internal()
+    }
+
+    pub(crate) fn front(&self) -> Option<NonNull<G::EntryType>> {
+        self.head
+    }
+
+    pub(crate) fn back(&self) -> Option<NonNull<G::EntryType>> {
+        // SAFETY: The links of head are owned by the list, so it is safe to get a reference.
+        unsafe { &*G::get_links(self.head?.as_ref()).entry.get() }.prev
+    }
+
+    pub(crate) fn cursor_front(&self) -> Cursor<'_, G> {
+        Cursor::new(self, self.front())
+    }
+
+    pub(crate) fn cursor_front_mut(&mut self) -> CursorMut<'_, G> {
+        CursorMut::new(self, self.front())
+    }
+}
+
+struct CommonCursor<G: GetLinks> {
+    cur: Option<NonNull<G::EntryType>>,
+}
+
+impl<G: GetLinks> CommonCursor<G> {
+    fn new(cur: Option<NonNull<G::EntryType>>) -> Self {
+        Self { cur }
+    }
+
+    fn move_next(&mut self, list: &RawList<G>) {
+        match self.cur.take() {
+            None => self.cur = list.head,
+            Some(cur) => {
+                if let Some(head) = list.head {
+                    // SAFETY: We have a shared ref to the linked list, so the links can't change.
+                    let links = unsafe { &*G::get_links(cur.as_ref()).entry.get() };
+                    if links.next.unwrap() != head {
+                        self.cur = links.next;
+                    }
+                }
+            }
+        }
+    }
+
+    fn move_prev(&mut self, list: &RawList<G>) {
+        match list.head {
+            None => self.cur = None,
+            Some(head) => {
+                let next = match self.cur.take() {
+                    None => head,
+                    Some(cur) => {
+                        if cur == head {
+                            return;
+                        }
+                        cur
+                    }
+                };
+                // SAFETY: There's a shared ref to the list, so the links can't change.
+                let links = unsafe { &*G::get_links(next.as_ref()).entry.get() };
+                self.cur = links.prev;
+            }
+        }
+    }
+}
+
+/// A list cursor that allows traversing a linked list and inspecting elements.
+pub struct Cursor<'a, G: GetLinks> {
+    cursor: CommonCursor<G>,
+    list: &'a RawList<G>,
+}
+
+impl<'a, G: GetLinks> Cursor<'a, G> {
+    fn new(list: &'a RawList<G>, cur: Option<NonNull<G::EntryType>>) -> Self {
+        Self {
+            list,
+            cursor: CommonCursor::new(cur),
+        }
+    }
+
+    /// Returns the element the cursor is currently positioned on.
+    pub fn current(&self) -> Option<&'a G::EntryType> {
+        let cur = self.cursor.cur?;
+        // SAFETY: Objects must be kept alive while on the list.
+        Some(unsafe { &*cur.as_ptr() })
+    }
+
+    /// Moves the cursor to the next element.
+    pub fn move_next(&mut self) {
+        self.cursor.move_next(self.list);
+    }
+}
+
+pub(crate) struct CursorMut<'a, G: GetLinks> {
+    cursor: CommonCursor<G>,
+    list: &'a mut RawList<G>,
+}
+
+impl<'a, G: GetLinks> CursorMut<'a, G> {
+    fn new(list: &'a mut RawList<G>, cur: Option<NonNull<G::EntryType>>) -> Self {
+        Self {
+            list,
+            cursor: CommonCursor::new(cur),
+        }
+    }
+
+    pub(crate) fn current(&mut self) -> Option<&mut G::EntryType> {
+        let cur = self.cursor.cur?;
+        // SAFETY: Objects must be kept alive while on the list.
+        Some(unsafe { &mut *cur.as_ptr() })
+    }
+
+    /// Removes the entry the cursor is pointing to and advances the cursor to the next entry. It
+    /// returns a raw pointer to the removed element (if one is removed).
+    pub(crate) fn remove_current(&mut self) -> Option<NonNull<G::EntryType>> {
+        let entry = self.cursor.cur?;
+        self.cursor.move_next(self.list);
+        // SAFETY: The entry is on the list as we just got it from there and it cannot change.
+        unsafe { self.list.remove(entry.as_ref()) };
+        Some(entry)
+    }
+
+    pub(crate) fn peek_next(&mut self) -> Option<&mut G::EntryType> {
+        let mut new = CommonCursor::new(self.cursor.cur);
+        new.move_next(self.list);
+        // SAFETY: Objects must be kept alive while on the list.
+        Some(unsafe { &mut *new.cur?.as_ptr() })
+    }
+
+    pub(crate) fn peek_prev(&mut self) -> Option<&mut G::EntryType> {
+        let mut new = CommonCursor::new(self.cursor.cur);
+        new.move_prev(self.list);
+        // SAFETY: Objects must be kept alive while on the list.
+        Some(unsafe { &mut *new.cur?.as_ptr() })
+    }
+
+    pub(crate) fn move_next(&mut self) {
+        self.cursor.move_next(self.list);
+    }
+}
diff --git a/rust/kernel/rbtree.rs b/rust/kernel/rbtree.rs
new file mode 100644
index 000000000000..a30739cc6839
--- /dev/null
+++ b/rust/kernel/rbtree.rs
@@ -0,0 +1,563 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Red-black trees.
+//!
+//! C header: [`include/linux/rbtree.h`](../../../../include/linux/rbtree.h)
+//!
+//! Reference: <https://www.kernel.org/doc/html/latest/core-api/rbtree.html>
+
+use crate::{bindings, Result};
+use alloc::boxed::Box;
+use core::{
+    cmp::{Ord, Ordering},
+    iter::{IntoIterator, Iterator},
+    marker::PhantomData,
+    mem::MaybeUninit,
+    ptr::{addr_of_mut, NonNull},
+};
+
+struct Node<K, V> {
+    links: bindings::rb_node,
+    key: K,
+    value: V,
+}
+
+/// A red-black tree with owned nodes.
+///
+/// It is backed by the kernel C red-black trees.
+///
+/// # Invariants
+///
+/// Non-null parent/children pointers stored in instances of the `rb_node` C struct are always
+/// valid, and pointing to a field of our internal representation of a node.
+///
+/// # Examples
+///
+/// In the example below we do several operations on a tree. We note that insertions may fail if
+/// the system is out of memory.
+///
+/// ```
+/// use kernel::rbtree::RBTree;
+///
+/// # fn test() -> Result {
+/// // Create a new tree.
+/// let mut tree = RBTree::new();
+///
+/// // Insert three elements.
+/// tree.try_insert(20, 200)?;
+/// tree.try_insert(10, 100)?;
+/// tree.try_insert(30, 300)?;
+///
+/// // Check the nodes we just inserted.
+/// {
+///     let mut iter = tree.iter();
+///     assert_eq!(iter.next().unwrap(), (&10, &100));
+///     assert_eq!(iter.next().unwrap(), (&20, &200));
+///     assert_eq!(iter.next().unwrap(), (&30, &300));
+///     assert!(iter.next().is_none());
+/// }
+///
+/// // Print all elements.
+/// for (key, value) in &tree {
+///     pr_info!("{} = {}\n", key, value);
+/// }
+///
+/// // Replace one of the elements.
+/// tree.try_insert(10, 1000)?;
+///
+/// // Check that the tree reflects the replacement.
+/// {
+///     let mut iter = tree.iter();
+///     assert_eq!(iter.next().unwrap(), (&10, &1000));
+///     assert_eq!(iter.next().unwrap(), (&20, &200));
+///     assert_eq!(iter.next().unwrap(), (&30, &300));
+///     assert!(iter.next().is_none());
+/// }
+///
+/// // Change the value of one of the elements.
+/// *tree.get_mut(&30).unwrap() = 3000;
+///
+/// // Check that the tree reflects the update.
+/// {
+///     let mut iter = tree.iter();
+///     assert_eq!(iter.next().unwrap(), (&10, &1000));
+///     assert_eq!(iter.next().unwrap(), (&20, &200));
+///     assert_eq!(iter.next().unwrap(), (&30, &3000));
+///     assert!(iter.next().is_none());
+/// }
+///
+/// // Remove an element.
+/// tree.remove(&10);
+///
+/// // Check that the tree reflects the removal.
+/// {
+///     let mut iter = tree.iter();
+///     assert_eq!(iter.next().unwrap(), (&20, &200));
+///     assert_eq!(iter.next().unwrap(), (&30, &3000));
+///     assert!(iter.next().is_none());
+/// }
+///
+/// // Update all values.
+/// for value in tree.values_mut() {
+///     *value *= 10;
+/// }
+///
+/// // Check that the tree reflects the changes to values.
+/// {
+///     let mut iter = tree.iter();
+///     assert_eq!(iter.next().unwrap(), (&20, &2000));
+///     assert_eq!(iter.next().unwrap(), (&30, &30000));
+///     assert!(iter.next().is_none());
+/// }
+///
+/// # Ok(())
+/// # }
+/// #
+/// # assert_eq!(test(), Ok(()));
+/// ```
+///
+/// In the example below, we first allocate a node, acquire a spinlock, then insert the node into
+/// the tree. This is useful when the insertion context does not allow sleeping, for example, when
+/// holding a spinlock.
+///
+/// ```
+/// use kernel::{rbtree::RBTree, sync::SpinLock};
+///
+/// fn insert_test(tree: &SpinLock<RBTree<u32, u32>>) -> Result {
+///     // Pre-allocate node. This may fail (as it allocates memory).
+///     let node = RBTree::try_allocate_node(10, 100)?;
+///
+///     // Insert node while holding the lock. It is guaranteed to succeed with no allocation
+///     // attempts.
+///     let mut guard = tree.lock();
+///     guard.insert(node);
+///     Ok(())
+/// }
+/// ```
+///
+/// In the example below, we reuse an existing node allocation from an element we removed.
+///
+/// ```
+/// use kernel::rbtree::RBTree;
+///
+/// # fn test() -> Result {
+/// // Create a new tree.
+/// let mut tree = RBTree::new();
+///
+/// // Insert three elements.
+/// tree.try_insert(20, 200)?;
+/// tree.try_insert(10, 100)?;
+/// tree.try_insert(30, 300)?;
+///
+/// // Check the nodes we just inserted.
+/// {
+///     let mut iter = tree.iter();
+///     assert_eq!(iter.next().unwrap(), (&10, &100));
+///     assert_eq!(iter.next().unwrap(), (&20, &200));
+///     assert_eq!(iter.next().unwrap(), (&30, &300));
+///     assert!(iter.next().is_none());
+/// }
+///
+/// // Remove a node, getting back ownership of it.
+/// let existing = tree.remove_node(&30).unwrap();
+///
+/// // Check that the tree reflects the removal.
+/// {
+///     let mut iter = tree.iter();
+///     assert_eq!(iter.next().unwrap(), (&10, &100));
+///     assert_eq!(iter.next().unwrap(), (&20, &200));
+///     assert!(iter.next().is_none());
+/// }
+///
+/// // Turn the node into a reservation so that we can reuse it with a different key/value.
+/// let reservation = existing.into_reservation();
+///
+/// // Insert a new node into the tree, reusing the previous allocation. This is guaranteed to
+/// // succeed (no memory allocations).
+/// tree.insert(reservation.into_node(15, 150));
+///
+/// // Check that the tree reflect the new insertion.
+/// {
+///     let mut iter = tree.iter();
+///     assert_eq!(iter.next().unwrap(), (&10, &100));
+///     assert_eq!(iter.next().unwrap(), (&15, &150));
+///     assert_eq!(iter.next().unwrap(), (&20, &200));
+///     assert!(iter.next().is_none());
+/// }
+///
+/// # Ok(())
+/// # }
+/// #
+/// # assert_eq!(test(), Ok(()));
+/// ```
+pub struct RBTree<K, V> {
+    root: bindings::rb_root,
+    _p: PhantomData<Node<K, V>>,
+}
+
+impl<K, V> RBTree<K, V> {
+    /// Creates a new and empty tree.
+    pub fn new() -> Self {
+        Self {
+            // INVARIANT: There are no nodes in the tree, so the invariant holds vacuously.
+            root: bindings::rb_root::default(),
+            _p: PhantomData,
+        }
+    }
+
+    /// Tries to insert a new value into the tree.
+    ///
+    /// It overwrites a node if one already exists with the same key and returns it (containing the
+    /// key/value pair). Returns [`None`] if a node with the same key didn't already exist.
+    ///
+    /// Returns an error if it cannot allocate memory for the new node.
+    pub fn try_insert(&mut self, key: K, value: V) -> Result<Option<RBTreeNode<K, V>>>
+    where
+        K: Ord,
+    {
+        Ok(self.insert(Self::try_allocate_node(key, value)?))
+    }
+
+    /// Allocates memory for a node to be eventually initialised and inserted into the tree via a
+    /// call to [`RBTree::insert`].
+    pub fn try_reserve_node() -> Result<RBTreeNodeReservation<K, V>> {
+        Ok(RBTreeNodeReservation {
+            node: Box::try_new(MaybeUninit::uninit())?,
+        })
+    }
+
+    /// Allocates and initialiases a node that can be inserted into the tree via
+    /// [`RBTree::insert`].
+    pub fn try_allocate_node(key: K, value: V) -> Result<RBTreeNode<K, V>> {
+        Ok(Self::try_reserve_node()?.into_node(key, value))
+    }
+
+    /// Inserts a new node into the tree.
+    ///
+    /// It overwrites a node if one already exists with the same key and returns it (containing the
+    /// key/value pair). Returns [`None`] if a node with the same key didn't already exist.
+    ///
+    /// This function always succeeds.
+    pub fn insert(&mut self, node: RBTreeNode<K, V>) -> Option<RBTreeNode<K, V>>
+    where
+        K: Ord,
+    {
+        let RBTreeNode { node } = node;
+        let node = Box::into_raw(node);
+        // SAFETY: `node` is valid at least until we call `Box::from_raw`, which only happens when
+        // the node is removed or replaced.
+        let node_links = unsafe { addr_of_mut!((*node).links) };
+        let mut new_link: &mut *mut bindings::rb_node = &mut self.root.rb_node;
+        let mut parent = core::ptr::null_mut();
+        while !new_link.is_null() {
+            let this = crate::container_of!(*new_link, Node<K, V>, links);
+
+            parent = *new_link;
+
+            // SAFETY: `this` is a non-null node so it is valid by the type invariants. `node` is
+            // valid until the node is removed.
+            match unsafe { (*node).key.cmp(&(*this).key) } {
+                // SAFETY: `parent` is a non-null node so it is valid by the type invariants.
+                Ordering::Less => new_link = unsafe { &mut (*parent).rb_left },
+                // SAFETY: `parent` is a non-null node so it is valid by the type invariants.
+                Ordering::Greater => new_link = unsafe { &mut (*parent).rb_right },
+                Ordering::Equal => {
+                    // INVARIANT: We are replacing an existing node with a new one, which is valid.
+                    // It remains valid because we "forgot" it with `Box::into_raw`.
+                    // SAFETY: All pointers are non-null and valid (parent, despite the name, really
+                    // is the node we're replacing).
+                    unsafe { bindings::rb_replace_node(parent, node_links, &mut self.root) };
+
+                    // INVARIANT: The node is being returned and the caller may free it, however,
+                    // it was removed from the tree. So the invariants still hold.
+                    return Some(RBTreeNode {
+                        // SAFETY: `this` was a node in the tree, so it is valid.
+                        node: unsafe { Box::from_raw(this as _) },
+                    });
+                }
+            }
+        }
+
+        // INVARIANT: We are linking in a new node, which is valid. It remains valid because we
+        // "forgot" it with `Box::into_raw`.
+        // SAFETY: All pointers are non-null and valid (`*new_link` is null, but `new_link` is a
+        // mutable reference).
+        unsafe { bindings::rb_link_node(node_links, parent, new_link) };
+
+        // SAFETY: All pointers are valid. `node` has just been inserted into the tree.
+        unsafe { bindings::rb_insert_color(node_links, &mut self.root) };
+        None
+    }
+
+    /// Returns a node with the given key, if one exists.
+    fn find(&self, key: &K) -> Option<NonNull<Node<K, V>>>
+    where
+        K: Ord,
+    {
+        let mut node = self.root.rb_node;
+        while !node.is_null() {
+            let this = crate::container_of!(node, Node<K, V>, links);
+            // SAFETY: `this` is a non-null node so it is valid by the type invariants.
+            node = match key.cmp(unsafe { &(*this).key }) {
+                // SAFETY: `node` is a non-null node so it is valid by the type invariants.
+                Ordering::Less => unsafe { (*node).rb_left },
+                // SAFETY: `node` is a non-null node so it is valid by the type invariants.
+                Ordering::Greater => unsafe { (*node).rb_right },
+                Ordering::Equal => return NonNull::new(this as _),
+            }
+        }
+        None
+    }
+
+    /// Returns a reference to the value corresponding to the key.
+    pub fn get(&self, key: &K) -> Option<&V>
+    where
+        K: Ord,
+    {
+        // SAFETY: The `find` return value is a node in the tree, so it is valid.
+        self.find(key).map(|node| unsafe { &node.as_ref().value })
+    }
+
+    /// Returns a mutable reference to the value corresponding to the key.
+    pub fn get_mut(&mut self, key: &K) -> Option<&mut V>
+    where
+        K: Ord,
+    {
+        // SAFETY: The `find` return value is a node in the tree, so it is valid.
+        self.find(key)
+            .map(|mut node| unsafe { &mut node.as_mut().value })
+    }
+
+    /// Removes the node with the given key from the tree.
+    ///
+    /// It returns the node that was removed if one exists, or [`None`] otherwise.
+    pub fn remove_node(&mut self, key: &K) -> Option<RBTreeNode<K, V>>
+    where
+        K: Ord,
+    {
+        let mut node = self.find(key)?;
+
+        // SAFETY: The `find` return value is a node in the tree, so it is valid.
+        unsafe { bindings::rb_erase(&mut node.as_mut().links, &mut self.root) };
+
+        // INVARIANT: The node is being returned and the caller may free it, however, it was
+        // removed from the tree. So the invariants still hold.
+        Some(RBTreeNode {
+            // SAFETY: The `find` return value was a node in the tree, so it is valid.
+            node: unsafe { Box::from_raw(node.as_ptr()) },
+        })
+    }
+
+    /// Removes the node with the given key from the tree.
+    ///
+    /// It returns the value that was removed if one exists, or [`None`] otherwise.
+    pub fn remove(&mut self, key: &K) -> Option<V>
+    where
+        K: Ord,
+    {
+        let node = self.remove_node(key)?;
+        let RBTreeNode { node } = node;
+        let Node {
+            links: _,
+            key: _,
+            value,
+        } = *node;
+        Some(value)
+    }
+
+    /// Returns an iterator over the tree nodes, sorted by key.
+    pub fn iter(&self) -> RBTreeIterator<'_, K, V> {
+        RBTreeIterator {
+            _tree: PhantomData,
+            // SAFETY: `root` is valid as it's embedded in `self` and we have a valid `self`.
+            next: unsafe { bindings::rb_first(&self.root) },
+        }
+    }
+
+    /// Returns a mutable iterator over the tree nodes, sorted by key.
+    pub fn iter_mut(&mut self) -> RBTreeIteratorMut<'_, K, V> {
+        RBTreeIteratorMut {
+            _tree: PhantomData,
+            // SAFETY: `root` is valid as it's embedded in `self` and we have a valid `self`.
+            next: unsafe { bindings::rb_first(&self.root) },
+        }
+    }
+
+    /// Returns an iterator over the keys of the nodes in the tree, in sorted order.
+    pub fn keys(&self) -> impl Iterator<Item = &'_ K> {
+        self.iter().map(|(k, _)| k)
+    }
+
+    /// Returns an iterator over the values of the nodes in the tree, sorted by key.
+    pub fn values(&self) -> impl Iterator<Item = &'_ V> {
+        self.iter().map(|(_, v)| v)
+    }
+
+    /// Returns a mutable iterator over the values of the nodes in the tree, sorted by key.
+    pub fn values_mut(&mut self) -> impl Iterator<Item = &'_ mut V> {
+        self.iter_mut().map(|(_, v)| v)
+    }
+}
+
+impl<K, V> Default for RBTree<K, V> {
+    fn default() -> Self {
+        Self::new()
+    }
+}
+
+impl<K, V> Drop for RBTree<K, V> {
+    fn drop(&mut self) {
+        // SAFETY: `root` is valid as it's embedded in `self` and we have a valid `self`.
+        let mut next = unsafe { bindings::rb_first_postorder(&self.root) };
+
+        // INVARIANT: The loop invariant is that all tree nodes from `next` in postorder are valid.
+        while !next.is_null() {
+            let this = crate::container_of!(next, Node<K, V>, links);
+
+            // Find out what the next node is before disposing of the current one.
+            // SAFETY: `next` and all nodes in postorder are still valid.
+            next = unsafe { bindings::rb_next_postorder(next) };
+
+            // INVARIANT: This is the destructor, so we break the type invariant during clean-up,
+            // but it is not observable. The loop invariant is still maintained.
+            // SAFETY: `this` is valid per the loop invariant.
+            unsafe { Box::from_raw(this as *mut Node<K, V>) };
+        }
+    }
+}
+
+impl<'a, K, V> IntoIterator for &'a RBTree<K, V> {
+    type Item = (&'a K, &'a V);
+    type IntoIter = RBTreeIterator<'a, K, V>;
+
+    fn into_iter(self) -> Self::IntoIter {
+        self.iter()
+    }
+}
+
+/// An iterator over the nodes of a [`RBTree`].
+///
+/// Instances are created by calling [`RBTree::iter`].
+pub struct RBTreeIterator<'a, K, V> {
+    _tree: PhantomData<&'a RBTree<K, V>>,
+    next: *mut bindings::rb_node,
+}
+
+impl<'a, K, V> Iterator for RBTreeIterator<'a, K, V> {
+    type Item = (&'a K, &'a V);
+
+    fn next(&mut self) -> Option<Self::Item> {
+        if self.next.is_null() {
+            return None;
+        }
+
+        let cur = crate::container_of!(self.next, Node<K, V>, links);
+
+        // SAFETY: The reference to the tree used to create the iterator outlives the iterator, so
+        // the tree cannot change. By the tree invariant, all nodes are valid.
+        self.next = unsafe { bindings::rb_next(self.next) };
+
+        // SAFETY: By the same reasoning above, it is safe to dereference the node. Additionally,
+        // it is ok to return a reference to members because the iterator must outlive it.
+        Some(unsafe { (&(*cur).key, &(*cur).value) })
+    }
+}
+
+impl<'a, K, V> IntoIterator for &'a mut RBTree<K, V> {
+    type Item = (&'a K, &'a mut V);
+    type IntoIter = RBTreeIteratorMut<'a, K, V>;
+
+    fn into_iter(self) -> Self::IntoIter {
+        self.iter_mut()
+    }
+}
+
+/// A mutable iterator over the nodes of a [`RBTree`].
+///
+/// Instances are created by calling [`RBTree::iter_mut`].
+pub struct RBTreeIteratorMut<'a, K, V> {
+    _tree: PhantomData<&'a RBTree<K, V>>,
+    next: *mut bindings::rb_node,
+}
+
+impl<'a, K, V> Iterator for RBTreeIteratorMut<'a, K, V> {
+    type Item = (&'a K, &'a mut V);
+
+    fn next(&mut self) -> Option<Self::Item> {
+        if self.next.is_null() {
+            return None;
+        }
+
+        let cur = crate::container_of!(self.next, Node<K, V>, links) as *mut Node<K, V>;
+
+        // SAFETY: The reference to the tree used to create the iterator outlives the iterator, so
+        // the tree cannot change (except for the value of previous nodes, but those don't affect
+        // the iteration process). By the tree invariant, all nodes are valid.
+        self.next = unsafe { bindings::rb_next(self.next) };
+
+        // SAFETY: By the same reasoning above, it is safe to dereference the node. Additionally,
+        // it is ok to return a reference to members because the iterator must outlive it.
+        Some(unsafe { (&(*cur).key, &mut (*cur).value) })
+    }
+}
+
+/// A memory reservation for a red-black tree node.
+///
+/// It contains the memory needed to hold a node that can be inserted into a red-black tree. One
+/// can be obtained by directly allocating it ([`RBTree::try_reserve_node`]) or by "uninitialising"
+/// ([`RBTreeNode::into_reservation`]) an actual node (usually returned by some operation like
+/// removal from a tree).
+pub struct RBTreeNodeReservation<K, V> {
+    node: Box<MaybeUninit<Node<K, V>>>,
+}
+
+impl<K, V> RBTreeNodeReservation<K, V> {
+    /// Initialises a node reservation.
+    ///
+    /// It then becomes an [`RBTreeNode`] that can be inserted into a tree.
+    pub fn into_node(mut self, key: K, value: V) -> RBTreeNode<K, V> {
+        let node_ptr = self.node.as_mut_ptr();
+        // SAFETY: `node_ptr` is valid, and so are its fields.
+        unsafe { addr_of_mut!((*node_ptr).links).write(bindings::rb_node::default()) };
+        // SAFETY: `node_ptr` is valid, and so are its fields.
+        unsafe { addr_of_mut!((*node_ptr).key).write(key) };
+        // SAFETY: `node_ptr` is valid, and so are its fields.
+        unsafe { addr_of_mut!((*node_ptr).value).write(value) };
+        let raw = Box::into_raw(self.node);
+        RBTreeNode {
+            // SAFETY: The pointer came from a `MaybeUninit<Node>` whose fields have all been
+            // initialised. Additionally, it has the same layout as `Node`.
+            node: unsafe { Box::from_raw(raw as _) },
+        }
+    }
+}
+
+/// A red-black tree node.
+///
+/// The node is fully initialised (with key and value) and can be inserted into a tree without any
+/// extra allocations or failure paths.
+pub struct RBTreeNode<K, V> {
+    node: Box<Node<K, V>>,
+}
+
+impl<K, V> RBTreeNode<K, V> {
+    /// "Uninitialises" a node.
+    ///
+    /// It then becomes a reservation that can be re-initialised into a different node (i.e., with
+    /// a different key and/or value).
+    ///
+    /// The existing key and value are dropped in-place as part of this operation, that is, memory
+    /// may be freed (but only for the key/value; memory for the node itself is kept for reuse).
+    pub fn into_reservation(self) -> RBTreeNodeReservation<K, V> {
+        let raw = Box::into_raw(self.node);
+        let mut ret = RBTreeNodeReservation {
+            // SAFETY: The pointer came from a valid `Node`, which has the same layout as
+            // `MaybeUninit<Node>`.
+            node: unsafe { Box::from_raw(raw as _) },
+        };
+        // SAFETY: Although the type is `MaybeUninit<Node>`, we know it has been initialised
+        // because it came from a `Node`. So it is safe to drop it.
+        unsafe { core::ptr::drop_in_place(ret.node.as_mut_ptr()) };
+        ret
+    }
+}
diff --git a/rust/kernel/revocable.rs b/rust/kernel/revocable.rs
new file mode 100644
index 000000000000..1093c4d26026
--- /dev/null
+++ b/rust/kernel/revocable.rs
@@ -0,0 +1,425 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Revocable objects.
+//!
+//! The [`Revocable`] type wraps other types and allows access to them to be revoked. The existence
+//! of a [`RevocableGuard`] ensures that objects remain valid.
+
+use crate::{bindings, sync::rcu};
+use core::{
+    cell::UnsafeCell,
+    marker::PhantomData,
+    mem::MaybeUninit,
+    ops::Deref,
+    ptr::drop_in_place,
+    sync::atomic::{fence, AtomicBool, AtomicU32, Ordering},
+};
+
+/// An object that can become inaccessible at runtime.
+///
+/// Once access is revoked and all concurrent users complete (i.e., all existing instances of
+/// [`RevocableGuard`] are dropped), the wrapped object is also dropped.
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::revocable::Revocable;
+///
+/// struct Example {
+///     a: u32,
+///     b: u32,
+/// }
+///
+/// fn add_two(v: &Revocable<Example>) -> Option<u32> {
+///     let guard = v.try_access()?;
+///     Some(guard.a + guard.b)
+/// }
+///
+/// let v = Revocable::new(Example { a: 10, b: 20 });
+/// assert_eq!(add_two(&v), Some(30));
+/// v.revoke();
+/// assert_eq!(add_two(&v), None);
+/// ```
+///
+/// Sample example as above, but explicitly using the rcu read side lock.
+///
+/// ```
+/// # use kernel::revocable::Revocable;
+/// use kernel::sync::rcu;
+///
+/// struct Example {
+///     a: u32,
+///     b: u32,
+/// }
+///
+/// fn add_two(v: &Revocable<Example>) -> Option<u32> {
+///     let guard = rcu::read_lock();
+///     let e = v.try_access_with_guard(&guard)?;
+///     Some(e.a + e.b)
+/// }
+///
+/// let v = Revocable::new(Example { a: 10, b: 20 });
+/// assert_eq!(add_two(&v), Some(30));
+/// v.revoke();
+/// assert_eq!(add_two(&v), None);
+/// ```
+pub struct Revocable<T> {
+    is_available: AtomicBool,
+    data: MaybeUninit<UnsafeCell<T>>,
+}
+
+// SAFETY: `Revocable` is `Send` if the wrapped object is also `Send`. This is because while the
+// functionality exposed by `Revocable` can be accessed from any thread/CPU, it is possible that
+// this isn't supported by the wrapped object.
+unsafe impl<T: Send> Send for Revocable<T> {}
+
+// SAFETY: `Revocable` is `Sync` if the wrapped object is both `Send` and `Sync`. We require `Send`
+// from the wrapped object as well because  of `Revocable::revoke`, which can trigger the `Drop`
+// implementation of the wrapped object from an arbitrary thread.
+unsafe impl<T: Sync + Send> Sync for Revocable<T> {}
+
+impl<T> Revocable<T> {
+    /// Creates a new revocable instance of the given data.
+    pub const fn new(data: T) -> Self {
+        Self {
+            is_available: AtomicBool::new(true),
+            data: MaybeUninit::new(UnsafeCell::new(data)),
+        }
+    }
+
+    /// Tries to access the \[revocable\] wrapped object.
+    ///
+    /// Returns `None` if the object has been revoked and is therefore no longer accessible.
+    ///
+    /// Returns a guard that gives access to the object otherwise; the object is guaranteed to
+    /// remain accessible while the guard is alive. In such cases, callers are not allowed to sleep
+    /// because another CPU may be waiting to complete the revocation of this object.
+    pub fn try_access(&self) -> Option<RevocableGuard<'_, T>> {
+        let guard = rcu::read_lock();
+        if self.is_available.load(Ordering::Relaxed) {
+            // SAFETY: Since `self.is_available` is true, data is initialised and has to remain
+            // valid because the RCU read side lock prevents it from being dropped.
+            Some(unsafe { RevocableGuard::new(self.data.assume_init_ref().get(), guard) })
+        } else {
+            None
+        }
+    }
+
+    /// Tries to access the \[revocable\] wrapped object.
+    ///
+    /// Returns `None` if the object has been revoked and is therefore no longer accessible.
+    ///
+    /// Returns a shared reference to the object otherwise; the object is guaranteed to
+    /// remain accessible while the rcu read side guard is alive. In such cases, callers are not
+    /// allowed to sleep because another CPU may be waiting to complete the revocation of this
+    /// object.
+    pub fn try_access_with_guard<'a>(&'a self, _guard: &'a rcu::Guard) -> Option<&'a T> {
+        if self.is_available.load(Ordering::Relaxed) {
+            // SAFETY: Since `self.is_available` is true, data is initialised and has to remain
+            // valid because the RCU read side lock prevents it from being dropped.
+            Some(unsafe { &*self.data.assume_init_ref().get() })
+        } else {
+            None
+        }
+    }
+
+    /// Revokes access to and drops the wrapped object.
+    ///
+    /// Access to the object is revoked immediately to new callers of [`Revocable::try_access`]. If
+    /// there are concurrent users of the object (i.e., ones that called [`Revocable::try_access`]
+    /// beforehand and still haven't dropped the returned guard), this function waits for the
+    /// concurrent access to complete before dropping the wrapped object.
+    pub fn revoke(&self) {
+        if self
+            .is_available
+            .compare_exchange(true, false, Ordering::Relaxed, Ordering::Relaxed)
+            .is_ok()
+        {
+            // SAFETY: Just an FFI call, there are no further requirements.
+            unsafe { bindings::synchronize_rcu() };
+
+            // SAFETY: We know `self.data` is valid because only one CPU can succeed the
+            // `compare_exchange` above that takes `is_available` from `true` to `false`.
+            unsafe { drop_in_place(self.data.assume_init_ref().get()) };
+        }
+    }
+}
+
+impl<T> Drop for Revocable<T> {
+    fn drop(&mut self) {
+        // Drop only if the data hasn't been revoked yet (in which case it has already been
+        // dropped).
+        if *self.is_available.get_mut() {
+            // SAFETY: We know `self.data` is valid because no other CPU has changed
+            // `is_available` to `false` yet, and no other CPU can do it anymore because this CPU
+            // holds the only reference (mutable) to `self` now.
+            unsafe { drop_in_place(self.data.assume_init_ref().get()) };
+        }
+    }
+}
+
+/// A guard that allows access to a revocable object and keeps it alive.
+///
+/// CPUs may not sleep while holding on to [`RevocableGuard`] because it's in atomic context
+/// holding the RCU read-side lock.
+///
+/// # Invariants
+///
+/// The RCU read-side lock is held while the guard is alive.
+pub struct RevocableGuard<'a, T> {
+    data_ref: *const T,
+    _rcu_guard: rcu::Guard,
+    _p: PhantomData<&'a ()>,
+}
+
+impl<T> RevocableGuard<'_, T> {
+    fn new(data_ref: *const T, rcu_guard: rcu::Guard) -> Self {
+        Self {
+            data_ref,
+            _rcu_guard: rcu_guard,
+            _p: PhantomData,
+        }
+    }
+}
+
+impl<T> Deref for RevocableGuard<'_, T> {
+    type Target = T;
+
+    fn deref(&self) -> &Self::Target {
+        // SAFETY: By the type invariants, we hold the rcu read-side lock, so the object is
+        // guaranteed to remain valid.
+        unsafe { &*self.data_ref }
+    }
+}
+
+/// An object that can become inaccessible at runtime.
+///
+/// Once access is revoked and all concurrent users complete (i.e., all existing instances of
+/// [`AsyncRevocableGuard`] are dropped), the wrapped object is also dropped.
+///
+/// Unlike [`Revocable`], [`AsyncRevocable`] does not wait for concurrent users of the wrapped
+/// object to finish before [`AsyncRevocable::revoke`] completes -- thus the async qualifier. This
+/// has the advantage of not requiring RCU locks or waits of any kind.
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::revocable::AsyncRevocable;
+///
+/// struct Example {
+///     a: u32,
+///     b: u32,
+/// }
+///
+/// fn add_two(v: &AsyncRevocable<Example>) -> Option<u32> {
+///     let guard = v.try_access()?;
+///     Some(guard.a + guard.b)
+/// }
+///
+/// let v = AsyncRevocable::new(Example { a: 10, b: 20 });
+/// assert_eq!(add_two(&v), Some(30));
+/// v.revoke();
+/// assert_eq!(add_two(&v), None);
+/// ```
+///
+/// Example where revocation happens while there is a user:
+///
+/// ```
+/// # use kernel::revocable::AsyncRevocable;
+/// use core::sync::atomic::{AtomicBool, Ordering};
+///
+/// struct Example {
+///     a: u32,
+///     b: u32,
+/// }
+///
+/// static DROPPED: AtomicBool = AtomicBool::new(false);
+///
+/// impl Drop for Example {
+///     fn drop(&mut self) {
+///         DROPPED.store(true, Ordering::Relaxed);
+///     }
+/// }
+///
+/// fn add_two(v: &AsyncRevocable<Example>) -> Option<u32> {
+///     let guard = v.try_access()?;
+///     Some(guard.a + guard.b)
+/// }
+///
+/// let v = AsyncRevocable::new(Example { a: 10, b: 20 });
+/// assert_eq!(add_two(&v), Some(30));
+///
+/// let guard = v.try_access().unwrap();
+/// assert!(!v.is_revoked());
+/// assert!(!DROPPED.load(Ordering::Relaxed));
+/// v.revoke();
+/// assert!(!DROPPED.load(Ordering::Relaxed));
+/// assert!(v.is_revoked());
+/// assert!(v.try_access().is_none());
+/// assert_eq!(guard.a + guard.b, 30);
+/// drop(guard);
+/// assert!(DROPPED.load(Ordering::Relaxed));
+/// ```
+pub struct AsyncRevocable<T> {
+    usage_count: AtomicU32,
+    data: MaybeUninit<UnsafeCell<T>>,
+}
+
+// SAFETY: `AsyncRevocable` is `Send` if the wrapped object is also `Send`. This is because while
+// the functionality exposed by `AsyncRevocable` can be accessed from any thread/CPU, it is
+// possible that this isn't supported by the wrapped object.
+unsafe impl<T: Send> Send for AsyncRevocable<T> {}
+
+// SAFETY: `AsyncRevocable` is `Sync` if the wrapped object is both `Send` and `Sync`. We require
+// `Send` from the wrapped object as well because  of `AsyncRevocable::revoke`, which can trigger
+// the `Drop` implementation of the wrapped object from an arbitrary thread.
+unsafe impl<T: Sync + Send> Sync for AsyncRevocable<T> {}
+
+const REVOKED: u32 = 0x80000000;
+const COUNT_MASK: u32 = !REVOKED;
+const SATURATED_COUNT: u32 = REVOKED - 1;
+
+impl<T> AsyncRevocable<T> {
+    /// Creates a new asynchronously revocable instance of the given data.
+    pub fn new(data: T) -> Self {
+        Self {
+            usage_count: AtomicU32::new(0),
+            data: MaybeUninit::new(UnsafeCell::new(data)),
+        }
+    }
+
+    /// Tries to access the \[revocable\] wrapped object.
+    ///
+    /// Returns `None` if the object has been revoked and is therefore no longer accessible.
+    ///
+    /// Returns a guard that gives access to the object otherwise; the object is guaranteed to
+    /// remain accessible while the guard is alive.
+    pub fn try_access(&self) -> Option<AsyncRevocableGuard<'_, T>> {
+        loop {
+            let count = self.usage_count.load(Ordering::Relaxed);
+
+            // Fail attempt to access if the object is already revoked.
+            if count & REVOKED != 0 {
+                return None;
+            }
+
+            // No need to increment if the count is saturated.
+            if count == SATURATED_COUNT
+                || self
+                    .usage_count
+                    .compare_exchange(count, count + 1, Ordering::Relaxed, Ordering::Relaxed)
+                    .is_ok()
+            {
+                return Some(AsyncRevocableGuard { revocable: self });
+            }
+        }
+    }
+
+    /// Revokes access to the protected object.
+    ///
+    /// Returns `true` if access has been revoked, or `false` when the object has already been
+    /// revoked by a previous call to [`AsyncRevocable::revoke`].
+    ///
+    /// This call is non-blocking, that is, no new users of the revocable object will be allowed,
+    /// but potential current users are able to continue to use it and the thread won't wait for
+    /// them to finish. In such cases, the object will be dropped when the last user completes.
+    pub fn revoke(&self) -> bool {
+        // Set the `REVOKED` bit.
+        //
+        // The acquire barrier matches up with the release when decrementing the usage count.
+        let prev = self.usage_count.fetch_or(REVOKED, Ordering::Acquire);
+        if prev & REVOKED != 0 {
+            // Another thread already revoked this object.
+            return false;
+        }
+
+        if prev == 0 {
+            // SAFETY: This thread just revoked the object and the usage count is zero, so the
+            // object is valid and there will be no future users.
+            unsafe { drop_in_place(UnsafeCell::raw_get(self.data.as_ptr())) };
+        }
+
+        true
+    }
+
+    /// Returns whether access to the object has been revoked.
+    pub fn is_revoked(&self) -> bool {
+        self.usage_count.load(Ordering::Relaxed) & REVOKED != 0
+    }
+}
+
+impl<T> Drop for AsyncRevocable<T> {
+    fn drop(&mut self) {
+        let count = *self.usage_count.get_mut();
+        if count != REVOKED {
+            // The object hasn't been dropped yet, so we do it now.
+
+            // This matches with the release when decrementing the usage count.
+            fence(Ordering::Acquire);
+
+            // SAFETY: Since `count` is does not indicate a count of 0 and the REVOKED bit set, the
+            // object is still valid.
+            unsafe { drop_in_place(UnsafeCell::raw_get(self.data.as_ptr())) };
+        }
+    }
+}
+
+/// A guard that allows access to a revocable object and keeps it alive.
+///
+/// # Invariants
+///
+/// The owner owns an increment on the usage count (which may have saturated it), which keeps the
+/// revocable object alive.
+pub struct AsyncRevocableGuard<'a, T> {
+    revocable: &'a AsyncRevocable<T>,
+}
+
+impl<T> Deref for AsyncRevocableGuard<'_, T> {
+    type Target = T;
+
+    fn deref(&self) -> &Self::Target {
+        // SAFETY: The type invariants guarantee that the caller owns an increment.
+        unsafe { &*self.revocable.data.assume_init_ref().get() }
+    }
+}
+
+impl<T> Drop for AsyncRevocableGuard<'_, T> {
+    fn drop(&mut self) {
+        loop {
+            let count = self.revocable.usage_count.load(Ordering::Relaxed);
+            let actual_count = count & COUNT_MASK;
+            if actual_count == SATURATED_COUNT {
+                // The count is saturated, so we won't decrement (nor do we drop the object).
+                return;
+            }
+
+            if actual_count == 0 {
+                // Trying to underflow the count.
+                panic!("actual_count is zero");
+            }
+
+            // On success, we use release ordering, which matches with the acquire in one of the
+            // places where we drop the object, namely: below, in `AsyncRevocable::revoke`, or in
+            // `AsyncRevocable::drop`.
+            if self
+                .revocable
+                .usage_count
+                .compare_exchange(count, count - 1, Ordering::Release, Ordering::Relaxed)
+                .is_ok()
+            {
+                if count == 1 | REVOKED {
+                    // `count`  is now zero and it is revoked, so free it now.
+
+                    // This matches with the release above (which may have happened in other
+                    // threads concurrently).
+                    fence(Ordering::Acquire);
+
+                    // SAFETY: Since `count` was 1, the object is still alive.
+                    unsafe { drop_in_place(UnsafeCell::raw_get(self.revocable.data.as_ptr())) };
+                }
+
+                return;
+            }
+        }
+    }
+}
diff --git a/rust/kernel/security.rs b/rust/kernel/security.rs
new file mode 100644
index 000000000000..0a33363289d3
--- /dev/null
+++ b/rust/kernel/security.rs
@@ -0,0 +1,38 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Linux Security Modules (LSM).
+//!
+//! C header: [`include/linux/security.h`](../../../../include/linux/security.h).
+
+use crate::{bindings, cred::Credential, file::File, to_result, Result};
+
+/// Calls the security modules to determine if the given task can become the manager of a binder
+/// context.
+pub fn binder_set_context_mgr(mgr: &Credential) -> Result {
+    // SAFETY: `mrg.0` is valid because the shared reference guarantees a nonzero refcount.
+    to_result(unsafe { bindings::security_binder_set_context_mgr(mgr.0.get()) })
+}
+
+/// Calls the security modules to determine if binder transactions are allowed from task `from` to
+/// task `to`.
+pub fn binder_transaction(from: &Credential, to: &Credential) -> Result {
+    // SAFETY: `from` and `to` are valid because the shared references guarantee nonzero refcounts.
+    to_result(unsafe { bindings::security_binder_transaction(from.0.get(), to.0.get()) })
+}
+
+/// Calls the security modules to determine if task `from` is allowed to send binder objects
+/// (owned by itself or other processes) to task `to` through a binder transaction.
+pub fn binder_transfer_binder(from: &Credential, to: &Credential) -> Result {
+    // SAFETY: `from` and `to` are valid because the shared references guarantee nonzero refcounts.
+    to_result(unsafe { bindings::security_binder_transfer_binder(from.0.get(), to.0.get()) })
+}
+
+/// Calls the security modules to determine if task `from` is allowed to send the given file to
+/// task `to` (which would get its own file descriptor) through a binder transaction.
+pub fn binder_transfer_file(from: &Credential, to: &Credential, file: &File) -> Result {
+    // SAFETY: `from`, `to` and `file` are valid because the shared references guarantee nonzero
+    // refcounts.
+    to_result(unsafe {
+        bindings::security_binder_transfer_file(from.0.get(), to.0.get(), file.0.get())
+    })
+}
diff --git a/rust/kernel/static_assert.rs b/rust/kernel/static_assert.rs
new file mode 100644
index 000000000000..3115ee0ba8e9
--- /dev/null
+++ b/rust/kernel/static_assert.rs
@@ -0,0 +1,34 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Static assert.
+
+/// Static assert (i.e. compile-time assert).
+///
+/// Similar to C11 [`_Static_assert`] and C++11 [`static_assert`].
+///
+/// The feature may be added to Rust in the future: see [RFC 2790].
+///
+/// [`_Static_assert`]: https://en.cppreference.com/w/c/language/_Static_assert
+/// [`static_assert`]: https://en.cppreference.com/w/cpp/language/static_assert
+/// [RFC 2790]: https://github.com/rust-lang/rfcs/issues/2790
+///
+/// # Examples
+///
+/// ```
+/// static_assert!(42 > 24);
+/// static_assert!(core::mem::size_of::<u8>() == 1);
+///
+/// const X: &[u8] = b"bar";
+/// static_assert!(X[1] == b'a');
+///
+/// const fn f(x: i32) -> i32 {
+///     x + 2
+/// }
+/// static_assert!(f(40) == 42);
+/// ```
+#[macro_export]
+macro_rules! static_assert {
+    ($condition:expr) => {
+        const _: () = core::assert!($condition);
+    };
+}
diff --git a/rust/kernel/std_vendor.rs b/rust/kernel/std_vendor.rs
new file mode 100644
index 000000000000..ffbaca0c4cb7
--- /dev/null
+++ b/rust/kernel/std_vendor.rs
@@ -0,0 +1,161 @@
+// SPDX-License-Identifier: Apache-2.0 OR MIT
+
+//! The contents of this file come from the Rust standard library, hosted in
+//! the <https://github.com/rust-lang/rust> repository, licensed under
+//! "Apache-2.0 OR MIT" and adapted for kernel use. For copyright details,
+//! see <https://github.com/rust-lang/rust/blob/master/COPYRIGHT>.
+
+/// [`std::dbg`], but using [`pr_info`] instead of [`eprintln`].
+///
+/// Prints and returns the value of a given expression for quick and dirty
+/// debugging.
+///
+/// An example:
+///
+/// ```rust
+/// let a = 2;
+/// # #[allow(clippy::dbg_macro)]
+/// let b = dbg!(a * 2) + 1;
+/// //      ^-- prints: [src/main.rs:2] a * 2 = 4
+/// assert_eq!(b, 5);
+/// ```
+///
+/// The macro works by using the `Debug` implementation of the type of
+/// the given expression to print the value with [`printk`] along with the
+/// source location of the macro invocation as well as the source code
+/// of the expression.
+///
+/// Invoking the macro on an expression moves and takes ownership of it
+/// before returning the evaluated expression unchanged. If the type
+/// of the expression does not implement `Copy` and you don't want
+/// to give up ownership, you can instead borrow with `dbg!(&expr)`
+/// for some expression `expr`.
+///
+/// The `dbg!` macro works exactly the same in release builds.
+/// This is useful when debugging issues that only occur in release
+/// builds or when debugging in release mode is significantly faster.
+///
+/// Note that the macro is intended as a debugging tool and therefore you
+/// should avoid having uses of it in version control for long periods
+/// (other than in tests and similar).
+///
+/// # Stability
+///
+/// The exact output printed by this macro should not be relied upon
+/// and is subject to future changes.
+///
+/// # Further examples
+///
+/// With a method call:
+///
+/// ```rust
+/// # #[allow(clippy::dbg_macro)]
+/// fn foo(n: usize) {
+///     if dbg!(n.checked_sub(4)).is_some() {
+///         // ...
+///     }
+/// }
+///
+/// foo(3)
+/// ```
+///
+/// This prints to the kernel log:
+///
+/// ```text,ignore
+/// [src/main.rs:4] n.checked_sub(4) = None
+/// ```
+///
+/// Naive factorial implementation:
+///
+/// ```rust
+/// # #[allow(clippy::dbg_macro)]
+/// # {
+/// fn factorial(n: u32) -> u32 {
+///     if dbg!(n <= 1) {
+///         dbg!(1)
+///     } else {
+///         dbg!(n * factorial(n - 1))
+///     }
+/// }
+///
+/// dbg!(factorial(4));
+/// # }
+/// ```
+///
+/// This prints to the kernel log:
+///
+/// ```text,ignore
+/// [src/main.rs:3] n <= 1 = false
+/// [src/main.rs:3] n <= 1 = false
+/// [src/main.rs:3] n <= 1 = false
+/// [src/main.rs:3] n <= 1 = true
+/// [src/main.rs:4] 1 = 1
+/// [src/main.rs:5] n * factorial(n - 1) = 2
+/// [src/main.rs:5] n * factorial(n - 1) = 6
+/// [src/main.rs:5] n * factorial(n - 1) = 24
+/// [src/main.rs:11] factorial(4) = 24
+/// ```
+///
+/// The `dbg!(..)` macro moves the input:
+///
+// TODO: Could be `compile_fail` when supported.
+/// ```ignore
+/// /// A wrapper around `usize` which importantly is not Copyable.
+/// #[derive(Debug)]
+/// struct NoCopy(usize);
+///
+/// let a = NoCopy(42);
+/// let _ = dbg!(a); // <-- `a` is moved here.
+/// let _ = dbg!(a); // <-- `a` is moved again; error!
+/// ```
+///
+/// You can also use `dbg!()` without a value to just print the
+/// file and line whenever it's reached.
+///
+/// Finally, if you want to `dbg!(..)` multiple values, it will treat them as
+/// a tuple (and return it, too):
+///
+/// ```
+/// # #[allow(clippy::dbg_macro)]
+/// assert_eq!(dbg!(1usize, 2u32), (1, 2));
+/// ```
+///
+/// However, a single argument with a trailing comma will still not be treated
+/// as a tuple, following the convention of ignoring trailing commas in macro
+/// invocations. You can use a 1-tuple directly if you need one:
+///
+/// ```
+/// # #[allow(clippy::dbg_macro)]
+/// # {
+/// assert_eq!(1, dbg!(1u32,)); // trailing comma ignored
+/// assert_eq!((1,), dbg!((1u32,))); // 1-tuple
+/// # }
+/// ```
+///
+/// [`std::dbg`]: https://doc.rust-lang.org/std/macro.dbg.html
+/// [`eprintln`]: https://doc.rust-lang.org/std/macro.eprintln.html
+/// [`printk`]: https://www.kernel.org/doc/html/latest/core-api/printk-basics.html
+#[macro_export]
+macro_rules! dbg {
+    // NOTE: We cannot use `concat!` to make a static string as a format argument
+    // of `pr_info!` because `file!` could contain a `{` or
+    // `$val` expression could be a block (`{ .. }`), in which case the `pr_info!`
+    // will be malformed.
+    () => {
+        $crate::pr_info!("[{}:{}]\n", ::core::file!(), ::core::line!())
+    };
+    ($val:expr $(,)?) => {
+        // Use of `match` here is intentional because it affects the lifetimes
+        // of temporaries - https://stackoverflow.com/a/48732525/1063961
+        match $val {
+            tmp => {
+                $crate::pr_info!("[{}:{}] {} = {:#?}\n",
+                    ::core::file!(), ::core::line!(), ::core::stringify!($val), &tmp);
+                tmp
+            }
+        }
+    };
+    ($($val:expr),+ $(,)?) => {
+        ($($crate::dbg!($val)),+,)
+    };
+}
diff --git a/rust/kernel/str.rs b/rust/kernel/str.rs
new file mode 100644
index 000000000000..874003e39cba
--- /dev/null
+++ b/rust/kernel/str.rs
@@ -0,0 +1,597 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! String representations.
+
+use alloc::vec::Vec;
+use core::fmt::{self, Write};
+use core::ops::{self, Deref, Index};
+
+use crate::{bindings, error::code::*, Error};
+
+/// Byte string without UTF-8 validity guarantee.
+///
+/// `BStr` is simply an alias to `[u8]`, but has a more evident semantical meaning.
+pub type BStr = [u8];
+
+/// Creates a new [`BStr`] from a string literal.
+///
+/// `b_str!` converts the supplied string literal to byte string, so non-ASCII
+/// characters can be included.
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::b_str;
+/// # use kernel::str::BStr;
+/// const MY_BSTR: &BStr = b_str!("My awesome BStr!");
+/// ```
+#[macro_export]
+macro_rules! b_str {
+    ($str:literal) => {{
+        const S: &'static str = $str;
+        const C: &'static $crate::str::BStr = S.as_bytes();
+        C
+    }};
+}
+
+/// Possible errors when using conversion functions in [`CStr`].
+#[derive(Debug, Clone, Copy)]
+pub enum CStrConvertError {
+    /// Supplied bytes contain an interior `NUL`.
+    InteriorNul,
+
+    /// Supplied bytes are not terminated by `NUL`.
+    NotNulTerminated,
+}
+
+impl From<CStrConvertError> for Error {
+    #[inline]
+    fn from(_: CStrConvertError) -> Error {
+        EINVAL
+    }
+}
+
+/// A string that is guaranteed to have exactly one `NUL` byte, which is at the
+/// end.
+///
+/// Used for interoperability with kernel APIs that take C strings.
+#[repr(transparent)]
+pub struct CStr([u8]);
+
+impl CStr {
+    /// Returns the length of this string excluding `NUL`.
+    #[inline]
+    pub const fn len(&self) -> usize {
+        self.len_with_nul() - 1
+    }
+
+    /// Returns the length of this string with `NUL`.
+    #[inline]
+    pub const fn len_with_nul(&self) -> usize {
+        // SAFETY: This is one of the invariant of `CStr`.
+        // We add a `unreachable_unchecked` here to hint the optimizer that
+        // the value returned from this function is non-zero.
+        if self.0.is_empty() {
+            unsafe { core::hint::unreachable_unchecked() };
+        }
+        self.0.len()
+    }
+
+    /// Returns `true` if the string only includes `NUL`.
+    #[inline]
+    pub const fn is_empty(&self) -> bool {
+        self.len() == 0
+    }
+
+    /// Wraps a raw C string pointer.
+    ///
+    /// # Safety
+    ///
+    /// `ptr` must be a valid pointer to a `NUL`-terminated C string, and it must
+    /// last at least `'a`. When `CStr` is alive, the memory pointed by `ptr`
+    /// must not be mutated.
+    #[inline]
+    pub unsafe fn from_char_ptr<'a>(ptr: *const core::ffi::c_char) -> &'a Self {
+        // SAFETY: The safety precondition guarantees `ptr` is a valid pointer
+        // to a `NUL`-terminated C string.
+        let len = unsafe { bindings::strlen(ptr) } + 1;
+        // SAFETY: Lifetime guaranteed by the safety precondition.
+        let bytes = unsafe { core::slice::from_raw_parts(ptr as _, len as _) };
+        // SAFETY: As `len` is returned by `strlen`, `bytes` does not contain interior `NUL`.
+        // As we have added 1 to `len`, the last byte is known to be `NUL`.
+        unsafe { Self::from_bytes_with_nul_unchecked(bytes) }
+    }
+
+    /// Creates a [`CStr`] from a `[u8]`.
+    ///
+    /// The provided slice must be `NUL`-terminated, does not contain any
+    /// interior `NUL` bytes.
+    pub const fn from_bytes_with_nul(bytes: &[u8]) -> Result<&Self, CStrConvertError> {
+        if bytes.is_empty() {
+            return Err(CStrConvertError::NotNulTerminated);
+        }
+        if bytes[bytes.len() - 1] != 0 {
+            return Err(CStrConvertError::NotNulTerminated);
+        }
+        let mut i = 0;
+        // `i + 1 < bytes.len()` allows LLVM to optimize away bounds checking,
+        // while it couldn't optimize away bounds checks for `i < bytes.len() - 1`.
+        while i + 1 < bytes.len() {
+            if bytes[i] == 0 {
+                return Err(CStrConvertError::InteriorNul);
+            }
+            i += 1;
+        }
+        // SAFETY: We just checked that all properties hold.
+        Ok(unsafe { Self::from_bytes_with_nul_unchecked(bytes) })
+    }
+
+    /// Creates a [`CStr`] from a `[u8]`, panic if input is not valid.
+    ///
+    /// This function is only meant to be used by `c_str!` macro, so
+    /// crates using `c_str!` macro don't have to enable `const_panic` feature.
+    #[doc(hidden)]
+    pub const fn from_bytes_with_nul_unwrap(bytes: &[u8]) -> &Self {
+        match Self::from_bytes_with_nul(bytes) {
+            Ok(v) => v,
+            Err(_) => panic!("string contains interior NUL"),
+        }
+    }
+
+    /// Creates a [`CStr`] from a `[u8]` without performing any additional
+    /// checks.
+    ///
+    /// # Safety
+    ///
+    /// `bytes` *must* end with a `NUL` byte, and should only have a single
+    /// `NUL` byte (or the string will be truncated).
+    #[inline]
+    pub const unsafe fn from_bytes_with_nul_unchecked(bytes: &[u8]) -> &CStr {
+        // SAFETY: Properties of `bytes` guaranteed by the safety precondition.
+        unsafe { core::mem::transmute(bytes) }
+    }
+
+    /// Returns a C pointer to the string.
+    #[inline]
+    pub const fn as_char_ptr(&self) -> *const core::ffi::c_char {
+        self.0.as_ptr() as _
+    }
+
+    /// Convert the string to a byte slice without the trailing 0 byte.
+    #[inline]
+    pub fn as_bytes(&self) -> &[u8] {
+        &self.0[..self.len()]
+    }
+
+    /// Convert the string to a byte slice containing the trailing 0 byte.
+    #[inline]
+    pub const fn as_bytes_with_nul(&self) -> &[u8] {
+        &self.0
+    }
+
+    /// Yields a [`&str`] slice if the [`CStr`] contains valid UTF-8.
+    ///
+    /// If the contents of the [`CStr`] are valid UTF-8 data, this
+    /// function will return the corresponding [`&str`] slice. Otherwise,
+    /// it will return an error with details of where UTF-8 validation failed.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # use kernel::str::CStr;
+    /// let cstr = CStr::from_bytes_with_nul(b"foo\0").unwrap();
+    /// assert_eq!(cstr.to_str(), Ok("foo"));
+    /// ```
+    #[inline]
+    pub fn to_str(&self) -> Result<&str, core::str::Utf8Error> {
+        core::str::from_utf8(self.as_bytes())
+    }
+
+    /// Unsafely convert this [`CStr`] into a [`&str`], without checking for
+    /// valid UTF-8.
+    ///
+    /// # Safety
+    ///
+    /// The contents must be valid UTF-8.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # use kernel::c_str;
+    /// # use kernel::str::CStr;
+    /// // SAFETY: String literals are guaranteed to be valid UTF-8
+    /// // by the Rust compiler.
+    /// let bar = c_str!("ツ");
+    /// assert_eq!(unsafe { bar.as_str_unchecked() }, "ツ");
+    /// ```
+    #[inline]
+    pub unsafe fn as_str_unchecked(&self) -> &str {
+        unsafe { core::str::from_utf8_unchecked(self.as_bytes()) }
+    }
+}
+
+impl fmt::Display for CStr {
+    /// Formats printable ASCII characters, escaping the rest.
+    ///
+    /// ```
+    /// # use kernel::c_str;
+    /// # use kernel::str::CStr;
+    /// # use kernel::str::CString;
+    /// let penguin = c_str!("🐧");
+    /// let s = CString::try_from_fmt(fmt!("{}", penguin)).unwrap();
+    /// assert_eq!(s.as_bytes_with_nul(), "\\xf0\\x9f\\x90\\xa7\0".as_bytes());
+    ///
+    /// let ascii = c_str!("so \"cool\"");
+    /// let s = CString::try_from_fmt(fmt!("{}", ascii)).unwrap();
+    /// assert_eq!(s.as_bytes_with_nul(), "so \"cool\"\0".as_bytes());
+    /// ```
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        for &c in self.as_bytes() {
+            if (0x20..0x7f).contains(&c) {
+                // Printable character.
+                f.write_char(c as char)?;
+            } else {
+                write!(f, "\\x{:02x}", c)?;
+            }
+        }
+        Ok(())
+    }
+}
+
+impl fmt::Debug for CStr {
+    /// Formats printable ASCII characters with a double quote on either end, escaping the rest.
+    ///
+    /// ```
+    /// # use kernel::c_str;
+    /// # use kernel::str::CStr;
+    /// # use kernel::str::CString;
+    /// let penguin = c_str!("🐧");
+    /// let s = CString::try_from_fmt(fmt!("{:?}", penguin)).unwrap();
+    /// assert_eq!(s.as_bytes_with_nul(), "\"\\xf0\\x9f\\x90\\xa7\"\0".as_bytes());
+    ///
+    /// // Embedded double quotes are escaped.
+    /// let ascii = c_str!("so \"cool\"");
+    /// let s = CString::try_from_fmt(fmt!("{:?}", ascii)).unwrap();
+    /// assert_eq!(s.as_bytes_with_nul(), "\"so \\\"cool\\\"\"\0".as_bytes());
+    /// ```
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.write_str("\"")?;
+        for &c in self.as_bytes() {
+            match c {
+                // Printable characters.
+                b'\"' => f.write_str("\\\"")?,
+                0x20..=0x7e => f.write_char(c as char)?,
+                _ => write!(f, "\\x{:02x}", c)?,
+            }
+        }
+        f.write_str("\"")
+    }
+}
+
+impl AsRef<BStr> for CStr {
+    #[inline]
+    fn as_ref(&self) -> &BStr {
+        self.as_bytes()
+    }
+}
+
+impl Deref for CStr {
+    type Target = BStr;
+
+    #[inline]
+    fn deref(&self) -> &Self::Target {
+        self.as_bytes()
+    }
+}
+
+impl Index<ops::RangeFrom<usize>> for CStr {
+    type Output = CStr;
+
+    #[inline]
+    fn index(&self, index: ops::RangeFrom<usize>) -> &Self::Output {
+        // Delegate bounds checking to slice.
+        // Assign to _ to mute clippy's unnecessary operation warning.
+        let _ = &self.as_bytes()[index.start..];
+        // SAFETY: We just checked the bounds.
+        unsafe { Self::from_bytes_with_nul_unchecked(&self.0[index.start..]) }
+    }
+}
+
+impl Index<ops::RangeFull> for CStr {
+    type Output = CStr;
+
+    #[inline]
+    fn index(&self, _index: ops::RangeFull) -> &Self::Output {
+        self
+    }
+}
+
+mod private {
+    use core::ops;
+
+    // Marker trait for index types that can be forward to `BStr`.
+    pub trait CStrIndex {}
+
+    impl CStrIndex for usize {}
+    impl CStrIndex for ops::Range<usize> {}
+    impl CStrIndex for ops::RangeInclusive<usize> {}
+    impl CStrIndex for ops::RangeToInclusive<usize> {}
+}
+
+impl<Idx> Index<Idx> for CStr
+where
+    Idx: private::CStrIndex,
+    BStr: Index<Idx>,
+{
+    type Output = <BStr as Index<Idx>>::Output;
+
+    #[inline]
+    fn index(&self, index: Idx) -> &Self::Output {
+        &self.as_bytes()[index]
+    }
+}
+
+/// Creates a new [`CStr`] from a string literal.
+///
+/// The string literal should not contain any `NUL` bytes.
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::c_str;
+/// # use kernel::str::CStr;
+/// const MY_CSTR: &CStr = c_str!("My awesome CStr!");
+/// ```
+#[macro_export]
+macro_rules! c_str {
+    ($str:expr) => {{
+        const S: &str = concat!($str, "\0");
+        const C: &$crate::str::CStr = $crate::str::CStr::from_bytes_with_nul_unwrap(S.as_bytes());
+        C
+    }};
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn test_cstr_to_str() {
+        let good_bytes = b"\xf0\x9f\xa6\x80\0";
+        let checked_cstr = CStr::from_bytes_with_nul(good_bytes).unwrap();
+        let checked_str = checked_cstr.to_str().unwrap();
+        assert_eq!(checked_str, "🦀");
+    }
+
+    #[test]
+    #[should_panic]
+    fn test_cstr_to_str_panic() {
+        let bad_bytes = b"\xc3\x28\0";
+        let checked_cstr = CStr::from_bytes_with_nul(bad_bytes).unwrap();
+        checked_cstr.to_str().unwrap();
+    }
+
+    #[test]
+    fn test_cstr_as_str_unchecked() {
+        let good_bytes = b"\xf0\x9f\x90\xA7\0";
+        let checked_cstr = CStr::from_bytes_with_nul(good_bytes).unwrap();
+        let unchecked_str = unsafe { checked_cstr.as_str_unchecked() };
+        assert_eq!(unchecked_str, "🐧");
+    }
+}
+
+/// Allows formatting of [`fmt::Arguments`] into a raw buffer.
+///
+/// It does not fail if callers write past the end of the buffer so that they can calculate the
+/// size required to fit everything.
+///
+/// # Invariants
+///
+/// The memory region between `pos` (inclusive) and `end` (exclusive) is valid for writes if `pos`
+/// is less than `end`.
+pub(crate) struct RawFormatter {
+    // Use `usize` to use `saturating_*` functions.
+    beg: usize,
+    pos: usize,
+    end: usize,
+}
+
+impl RawFormatter {
+    /// Creates a new instance of [`RawFormatter`] with an empty buffer.
+    fn new() -> Self {
+        // INVARIANT: The buffer is empty, so the region that needs to be writable is empty.
+        Self {
+            beg: 0,
+            pos: 0,
+            end: 0,
+        }
+    }
+
+    /// Creates a new instance of [`RawFormatter`] with the given buffer pointers.
+    ///
+    /// # Safety
+    ///
+    /// If `pos` is less than `end`, then the region between `pos` (inclusive) and `end`
+    /// (exclusive) must be valid for writes for the lifetime of the returned [`RawFormatter`].
+    pub(crate) unsafe fn from_ptrs(pos: *mut u8, end: *mut u8) -> Self {
+        // INVARIANT: The safety requierments guarantee the type invariants.
+        Self {
+            beg: pos as _,
+            pos: pos as _,
+            end: end as _,
+        }
+    }
+
+    /// Creates a new instance of [`RawFormatter`] with the given buffer.
+    ///
+    /// # Safety
+    ///
+    /// The memory region starting at `buf` and extending for `len` bytes must be valid for writes
+    /// for the lifetime of the returned [`RawFormatter`].
+    pub(crate) unsafe fn from_buffer(buf: *mut u8, len: usize) -> Self {
+        let pos = buf as usize;
+        // INVARIANT: We ensure that `end` is never less then `buf`, and the safety requirements
+        // guarantees that the memory region is valid for writes.
+        Self {
+            pos,
+            beg: pos,
+            end: pos.saturating_add(len),
+        }
+    }
+
+    /// Returns the current insert position.
+    ///
+    /// N.B. It may point to invalid memory.
+    pub(crate) fn pos(&self) -> *mut u8 {
+        self.pos as _
+    }
+
+    /// Return the number of bytes written to the formatter.
+    pub(crate) fn bytes_written(&self) -> usize {
+        self.pos - self.beg
+    }
+}
+
+impl fmt::Write for RawFormatter {
+    fn write_str(&mut self, s: &str) -> fmt::Result {
+        // `pos` value after writing `len` bytes. This does not have to be bounded by `end`, but we
+        // don't want it to wrap around to 0.
+        let pos_new = self.pos.saturating_add(s.len());
+
+        // Amount that we can copy. `saturating_sub` ensures we get 0 if `pos` goes past `end`.
+        let len_to_copy = core::cmp::min(pos_new, self.end).saturating_sub(self.pos);
+
+        if len_to_copy > 0 {
+            // SAFETY: If `len_to_copy` is non-zero, then we know `pos` has not gone past `end`
+            // yet, so it is valid for write per the type invariants.
+            unsafe {
+                core::ptr::copy_nonoverlapping(
+                    s.as_bytes().as_ptr(),
+                    self.pos as *mut u8,
+                    len_to_copy,
+                )
+            };
+        }
+
+        self.pos = pos_new;
+        Ok(())
+    }
+}
+
+/// Allows formatting of [`fmt::Arguments`] into a raw buffer.
+///
+/// Fails if callers attempt to write more than will fit in the buffer.
+pub(crate) struct Formatter(RawFormatter);
+
+impl Formatter {
+    /// Creates a new instance of [`Formatter`] with the given buffer.
+    ///
+    /// # Safety
+    ///
+    /// The memory region starting at `buf` and extending for `len` bytes must be valid for writes
+    /// for the lifetime of the returned [`Formatter`].
+    pub(crate) unsafe fn from_buffer(buf: *mut u8, len: usize) -> Self {
+        // SAFETY: The safety requirements of this function satisfy those of the callee.
+        Self(unsafe { RawFormatter::from_buffer(buf, len) })
+    }
+}
+
+impl Deref for Formatter {
+    type Target = RawFormatter;
+
+    fn deref(&self) -> &Self::Target {
+        &self.0
+    }
+}
+
+impl fmt::Write for Formatter {
+    fn write_str(&mut self, s: &str) -> fmt::Result {
+        self.0.write_str(s)?;
+
+        // Fail the request if we go past the end of the buffer.
+        if self.0.pos > self.0.end {
+            Err(fmt::Error)
+        } else {
+            Ok(())
+        }
+    }
+}
+
+/// An owned string that is guaranteed to have exactly one `NUL` byte, which is at the end.
+///
+/// Used for interoperability with kernel APIs that take C strings.
+///
+/// # Invariants
+///
+/// The string is always `NUL`-terminated and contains no other `NUL` bytes.
+///
+/// # Examples
+///
+/// ```
+/// use kernel::str::CString;
+///
+/// let s = CString::try_from_fmt(fmt!("{}{}{}", "abc", 10, 20)).unwrap();
+/// assert_eq!(s.as_bytes_with_nul(), "abc1020\0".as_bytes());
+///
+/// let tmp = "testing";
+/// let s = CString::try_from_fmt(fmt!("{tmp}{}", 123)).unwrap();
+/// assert_eq!(s.as_bytes_with_nul(), "testing123\0".as_bytes());
+///
+/// // This fails because it has an embedded `NUL` byte.
+/// let s = CString::try_from_fmt(fmt!("a\0b{}", 123));
+/// assert_eq!(s.is_ok(), false);
+/// ```
+pub struct CString {
+    buf: Vec<u8>,
+}
+
+impl CString {
+    /// Creates an instance of [`CString`] from the given formatted arguments.
+    pub fn try_from_fmt(args: fmt::Arguments<'_>) -> Result<Self, Error> {
+        // Calculate the size needed (formatted string plus `NUL` terminator).
+        let mut f = RawFormatter::new();
+        f.write_fmt(args)?;
+        f.write_str("\0")?;
+        let size = f.bytes_written();
+
+        // Allocate a vector with the required number of bytes, and write to it.
+        let mut buf = Vec::try_with_capacity(size)?;
+        // SAFETY: The buffer stored in `buf` is at least of size `size` and is valid for writes.
+        let mut f = unsafe { Formatter::from_buffer(buf.as_mut_ptr(), size) };
+        f.write_fmt(args)?;
+        f.write_str("\0")?;
+
+        // SAFETY: The number of bytes that can be written to `f` is bounded by `size`, which is
+        // `buf`'s capacity. The contents of the buffer have been initialised by writes to `f`.
+        unsafe { buf.set_len(f.bytes_written()) };
+
+        // Check that there are no `NUL` bytes before the end.
+        // SAFETY: The buffer is valid for read because `f.bytes_written()` is bounded by `size`
+        // (which the minimum buffer size) and is non-zero (we wrote at least the `NUL` terminator)
+        // so `f.bytes_written() - 1` doesn't underflow.
+        let ptr = unsafe { bindings::memchr(buf.as_ptr().cast(), 0, (f.bytes_written() - 1) as _) };
+        if !ptr.is_null() {
+            return Err(EINVAL);
+        }
+
+        // INVARIANT: We wrote the `NUL` terminator and checked above that no other `NUL` bytes
+        // exist in the buffer.
+        Ok(Self { buf })
+    }
+}
+
+impl Deref for CString {
+    type Target = CStr;
+
+    fn deref(&self) -> &Self::Target {
+        // SAFETY: The type invariants guarantee that the string is `NUL`-terminated and that no
+        // other `NUL` bytes exist.
+        unsafe { CStr::from_bytes_with_nul_unchecked(self.buf.as_slice()) }
+    }
+}
+
+/// A convenience alias for [`core::format_args`].
+#[macro_export]
+macro_rules! fmt {
+    ($($f:tt)*) => ( core::format_args!($($f)*) )
+}
diff --git a/rust/kernel/sync.rs b/rust/kernel/sync.rs
index dbf705d573e6..255a4928a47a 100644
--- a/rust/kernel/sync.rs
+++ b/rust/kernel/sync.rs
@@ -22,7 +22,7 @@
 //! ```
 
 use crate::{bindings, str::CStr};
-use core::pin::Pin;
+use core::{cell::UnsafeCell, mem::MaybeUninit, pin::Pin};
 
 mod arc;
 mod condvar;
@@ -30,13 +30,14 @@ mod guard;
 mod locked_by;
 mod mutex;
 mod nowait;
+pub mod rcu;
 mod revocable;
 mod rwsem;
 mod seqlock;
 pub mod smutex;
 mod spinlock;
 
-pub use arc::{Ref, RefBorrow, UniqueRef};
+pub use arc::{new_refcount, Ref, RefBorrow, StaticRef, UniqueRef};
 pub use condvar::CondVar;
 pub use guard::{Guard, Lock, LockFactory, LockInfo, LockIniter, ReadLock, WriteLock};
 pub use locked_by::LockedBy;
@@ -47,6 +48,25 @@ pub use rwsem::{RevocableRwSemaphore, RevocableRwSemaphoreGuard, RwSemaphore};
 pub use seqlock::{SeqLock, SeqLockReadGuard};
 pub use spinlock::{RawSpinLock, SpinLock};
 
+/// Represents a lockdep class. It's a wrapper around C's `lock_class_key`.
+#[repr(transparent)]
+pub struct LockClassKey(UnsafeCell<MaybeUninit<bindings::lock_class_key>>);
+
+// SAFETY: This is a wrapper around a lock class key, so it is safe to use references to it from
+// any thread.
+unsafe impl Sync for LockClassKey {}
+
+impl LockClassKey {
+    /// Creates a new lock class key.
+    pub const fn new() -> Self {
+        Self(UnsafeCell::new(MaybeUninit::uninit()))
+    }
+
+    pub(crate) fn get(&self) -> *mut bindings::lock_class_key {
+        self.0.get().cast()
+    }
+}
+
 /// Safely initialises an object that has an `init` function that takes a name and a lock class as
 /// arguments, examples of these are [`Mutex`] and [`SpinLock`]. Each of them also provides a more
 /// specialised name that uses this macro.
@@ -54,18 +74,11 @@ pub use spinlock::{RawSpinLock, SpinLock};
 #[macro_export]
 macro_rules! init_with_lockdep {
     ($obj:expr, $name:expr) => {{
-        static mut CLASS1: core::mem::MaybeUninit<$crate::bindings::lock_class_key> =
-            core::mem::MaybeUninit::uninit();
-        static mut CLASS2: core::mem::MaybeUninit<$crate::bindings::lock_class_key> =
-            core::mem::MaybeUninit::uninit();
+        static CLASS1: $crate::sync::LockClassKey = $crate::sync::LockClassKey::new();
+        static CLASS2: $crate::sync::LockClassKey = $crate::sync::LockClassKey::new();
         let obj = $obj;
         let name = $crate::c_str!($name);
-        // SAFETY: `CLASS1` and `CLASS2` are never used by Rust code directly; the C portion of the
-        // kernel may change it though.
-        #[allow(unused_unsafe)]
-        unsafe {
-            $crate::sync::NeedsLockClass::init(obj, name, CLASS1.as_mut_ptr(), CLASS2.as_mut_ptr())
-        };
+        $crate::sync::NeedsLockClass::init(obj, name, &CLASS1, &CLASS2)
     }};
 }
 
@@ -78,16 +91,11 @@ pub trait NeedsLockClass {
     ///
     /// Callers are encouraged to use the [`init_with_lockdep`] macro as it automatically creates a
     /// new lock class on each usage.
-    ///
-    /// # Safety
-    ///
-    /// `key1` and `key2` must point to valid memory locations and remain valid until `self` is
-    /// dropped.
-    unsafe fn init(
+    fn init(
         self: Pin<&mut Self>,
         name: &'static CStr,
-        key1: *mut bindings::lock_class_key,
-        key2: *mut bindings::lock_class_key,
+        key1: &'static LockClassKey,
+        key2: &'static LockClassKey,
     );
 }
 
diff --git a/rust/kernel/sysctl.rs b/rust/kernel/sysctl.rs
new file mode 100644
index 000000000000..8f742d60037d
--- /dev/null
+++ b/rust/kernel/sysctl.rs
@@ -0,0 +1,199 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! System control.
+//!
+//! C header: [`include/linux/sysctl.h`](../../../../include/linux/sysctl.h)
+//!
+//! Reference: <https://www.kernel.org/doc/Documentation/sysctl/README>
+
+use alloc::boxed::Box;
+use alloc::vec::Vec;
+use core::mem;
+use core::ptr;
+use core::sync::atomic;
+
+use crate::{
+    bindings,
+    error::code::*,
+    io_buffer::IoBufferWriter,
+    str::CStr,
+    types,
+    user_ptr::{UserSlicePtr, UserSlicePtrWriter},
+    Result,
+};
+
+/// Sysctl storage.
+pub trait SysctlStorage: Sync {
+    /// Writes a byte slice.
+    fn store_value(&self, data: &[u8]) -> (usize, Result);
+
+    /// Reads via a [`UserSlicePtrWriter`].
+    fn read_value(&self, data: &mut UserSlicePtrWriter) -> (usize, Result);
+}
+
+fn trim_whitespace(mut data: &[u8]) -> &[u8] {
+    while !data.is_empty() && (data[0] == b' ' || data[0] == b'\t' || data[0] == b'\n') {
+        data = &data[1..];
+    }
+    while !data.is_empty()
+        && (data[data.len() - 1] == b' '
+            || data[data.len() - 1] == b'\t'
+            || data[data.len() - 1] == b'\n')
+    {
+        data = &data[..data.len() - 1];
+    }
+    data
+}
+
+impl<T> SysctlStorage for &T
+where
+    T: SysctlStorage,
+{
+    fn store_value(&self, data: &[u8]) -> (usize, Result) {
+        (*self).store_value(data)
+    }
+
+    fn read_value(&self, data: &mut UserSlicePtrWriter) -> (usize, Result) {
+        (*self).read_value(data)
+    }
+}
+
+impl SysctlStorage for atomic::AtomicBool {
+    fn store_value(&self, data: &[u8]) -> (usize, Result) {
+        let result = match trim_whitespace(data) {
+            b"0" => {
+                self.store(false, atomic::Ordering::Relaxed);
+                Ok(())
+            }
+            b"1" => {
+                self.store(true, atomic::Ordering::Relaxed);
+                Ok(())
+            }
+            _ => Err(EINVAL),
+        };
+        (data.len(), result)
+    }
+
+    fn read_value(&self, data: &mut UserSlicePtrWriter) -> (usize, Result) {
+        let value = if self.load(atomic::Ordering::Relaxed) {
+            b"1\n"
+        } else {
+            b"0\n"
+        };
+        (value.len(), data.write_slice(value))
+    }
+}
+
+/// Holds a single `sysctl` entry (and its table).
+pub struct Sysctl<T: SysctlStorage> {
+    inner: Box<T>,
+    // Responsible for keeping the `ctl_table` alive.
+    _table: Box<[bindings::ctl_table]>,
+    header: *mut bindings::ctl_table_header,
+}
+
+// SAFETY: The only public method we have is `get()`, which returns `&T`, and
+// `T: Sync`. Any new methods must adhere to this requirement.
+unsafe impl<T: SysctlStorage> Sync for Sysctl<T> {}
+
+unsafe extern "C" fn proc_handler<T: SysctlStorage>(
+    ctl: *mut bindings::ctl_table,
+    write: core::ffi::c_int,
+    buffer: *mut core::ffi::c_void,
+    len: *mut usize,
+    ppos: *mut bindings::loff_t,
+) -> core::ffi::c_int {
+    // If we are reading from some offset other than the beginning of the file,
+    // return an empty read to signal EOF.
+    if unsafe { *ppos } != 0 && write == 0 {
+        unsafe { *len = 0 };
+        return 0;
+    }
+
+    let data = unsafe { UserSlicePtr::new(buffer, *len) };
+    let storage = unsafe { &*((*ctl).data as *const T) };
+    let (bytes_processed, result) = if write != 0 {
+        let data = match data.read_all() {
+            Ok(r) => r,
+            Err(e) => return e.to_kernel_errno(),
+        };
+        storage.store_value(&data)
+    } else {
+        let mut writer = data.writer();
+        storage.read_value(&mut writer)
+    };
+    unsafe { *len = bytes_processed };
+    unsafe { *ppos += *len as bindings::loff_t };
+    match result {
+        Ok(()) => 0,
+        Err(e) => e.to_kernel_errno(),
+    }
+}
+
+impl<T: SysctlStorage> Sysctl<T> {
+    /// Registers a single entry in `sysctl`.
+    pub fn register(
+        path: &'static CStr,
+        name: &'static CStr,
+        storage: T,
+        mode: types::Mode,
+    ) -> Result<Sysctl<T>> {
+        if name.contains(&b'/') {
+            return Err(EINVAL);
+        }
+
+        let storage = Box::try_new(storage)?;
+        let mut table = Vec::try_with_capacity(2)?;
+        table.try_push(bindings::ctl_table {
+            procname: name.as_char_ptr(),
+            mode: mode.as_int(),
+            data: &*storage as *const T as *mut core::ffi::c_void,
+            proc_handler: Some(proc_handler::<T>),
+
+            maxlen: 0,
+            child: ptr::null_mut(),
+            poll: ptr::null_mut(),
+            extra1: ptr::null_mut(),
+            extra2: ptr::null_mut(),
+        })?;
+        table.try_push(unsafe { mem::zeroed() })?;
+        let mut table = table.try_into_boxed_slice()?;
+
+        let result = unsafe { bindings::register_sysctl(path.as_char_ptr(), table.as_mut_ptr()) };
+        if result.is_null() {
+            return Err(ENOMEM);
+        }
+
+        Ok(Sysctl {
+            inner: storage,
+            _table: table,
+            header: result,
+        })
+    }
+
+    /// Gets the storage.
+    pub fn get(&self) -> &T {
+        &self.inner
+    }
+}
+
+impl<T: SysctlStorage> Drop for Sysctl<T> {
+    fn drop(&mut self) {
+        unsafe {
+            bindings::unregister_sysctl_table(self.header);
+        }
+        self.header = ptr::null_mut();
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn test_trim_whitespace() {
+        assert_eq!(trim_whitespace(b"foo    "), b"foo");
+        assert_eq!(trim_whitespace(b"    foo"), b"foo");
+        assert_eq!(trim_whitespace(b"  foo  "), b"foo");
+    }
+}
diff --git a/rust/kernel/task.rs b/rust/kernel/task.rs
new file mode 100644
index 000000000000..67040b532816
--- /dev/null
+++ b/rust/kernel/task.rs
@@ -0,0 +1,239 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Tasks (threads and processes).
+//!
+//! C header: [`include/linux/sched.h`](../../../../include/linux/sched.h).
+
+use crate::{
+    bindings, c_str, error::from_kernel_err_ptr, types::PointerWrapper, ARef, AlwaysRefCounted,
+    Result, ScopeGuard,
+};
+use alloc::boxed::Box;
+use core::{cell::UnsafeCell, fmt, marker::PhantomData, ops::Deref, ptr};
+
+/// Wraps the kernel's `struct task_struct`.
+///
+/// # Invariants
+///
+/// Instances of this type are always ref-counted, that is, a call to `get_task_struct` ensures
+/// that the allocation remains valid at least until the matching call to `put_task_struct`.
+///
+/// # Examples
+///
+/// The following is an example of getting the PID of the current thread with zero additional cost
+/// when compared to the C version:
+///
+/// ```
+/// use kernel::task::Task;
+///
+/// let pid = Task::current().pid();
+/// ```
+///
+/// Getting the PID of the current process, also zero additional cost:
+///
+/// ```
+/// use kernel::task::Task;
+///
+/// let pid = Task::current().group_leader().pid();
+/// ```
+///
+/// Getting the current task and storing it in some struct. The reference count is automatically
+/// incremented when creating `State` and decremented when it is dropped:
+///
+/// ```
+/// use kernel::{task::Task, ARef};
+///
+/// struct State {
+///     creator: ARef<Task>,
+///     index: u32,
+/// }
+///
+/// impl State {
+///     fn new() -> Self {
+///         Self {
+///             creator: Task::current().into(),
+///             index: 0,
+///         }
+///     }
+/// }
+/// ```
+#[repr(transparent)]
+pub struct Task(pub(crate) UnsafeCell<bindings::task_struct>);
+
+// SAFETY: It's OK to access `Task` through references from other threads because we're either
+// accessing properties that don't change (e.g., `pid`, `group_leader`) or that are properly
+// synchronised by C code (e.g., `signal_pending`).
+unsafe impl Sync for Task {}
+
+/// The type of process identifiers (PIDs).
+type Pid = bindings::pid_t;
+
+impl Task {
+    /// Returns a task reference for the currently executing task/thread.
+    pub fn current<'a>() -> TaskRef<'a> {
+        // SAFETY: Just an FFI call.
+        let ptr = unsafe { bindings::get_current() };
+
+        TaskRef {
+            // SAFETY: If the current thread is still running, the current task is valid. Given
+            // that `TaskRef` is not `Send`, we know it cannot be transferred to another thread
+            // (where it could potentially outlive the caller).
+            task: unsafe { &*ptr.cast() },
+            _not_send: PhantomData,
+        }
+    }
+
+    /// Returns the group leader of the given task.
+    pub fn group_leader(&self) -> &Task {
+        // SAFETY: By the type invariant, we know that `self.0` is valid.
+        let ptr = unsafe { core::ptr::addr_of!((*self.0.get()).group_leader).read() };
+
+        // SAFETY: The lifetime of the returned task reference is tied to the lifetime of `self`,
+        // and given that a task has a reference to its group leader, we know it must be valid for
+        // the lifetime of the returned task reference.
+        unsafe { &*ptr.cast() }
+    }
+
+    /// Returns the PID of the given task.
+    pub fn pid(&self) -> Pid {
+        // SAFETY: By the type invariant, we know that `self.0` is valid.
+        unsafe { core::ptr::addr_of!((*self.0.get()).pid).read() }
+    }
+
+    /// Determines whether the given task has pending signals.
+    pub fn signal_pending(&self) -> bool {
+        // SAFETY: By the type invariant, we know that `self.0` is valid.
+        unsafe { bindings::signal_pending(self.0.get()) != 0 }
+    }
+
+    /// Starts a new kernel thread and runs it.
+    ///
+    /// # Examples
+    ///
+    /// Launches 10 threads and waits for them to complete.
+    ///
+    /// ```
+    /// use core::sync::atomic::{AtomicU32, Ordering};
+    /// use kernel::sync::{CondVar, Mutex};
+    /// use kernel::task::Task;
+    ///
+    /// kernel::init_static_sync! {
+    ///     static COUNT: Mutex<u32> = 0;
+    ///     static COUNT_IS_ZERO: CondVar;
+    /// }
+    ///
+    /// fn threadfn() {
+    ///     pr_info!("Running from thread {}\n", Task::current().pid());
+    ///     let mut guard = COUNT.lock();
+    ///     *guard -= 1;
+    ///     if *guard == 0 {
+    ///         COUNT_IS_ZERO.notify_all();
+    ///     }
+    /// }
+    ///
+    /// // Set count to 10 and spawn 10 threads.
+    /// *COUNT.lock() = 10;
+    /// for i in 0..10 {
+    ///     Task::spawn(fmt!("test{i}"), threadfn).unwrap();
+    /// }
+    ///
+    /// // Wait for count to drop to zero.
+    /// let mut guard = COUNT.lock();
+    /// while (*guard != 0) {
+    ///     COUNT_IS_ZERO.wait(&mut guard);
+    /// }
+    /// ```
+    pub fn spawn<T: FnOnce() + Send + 'static>(
+        name: fmt::Arguments<'_>,
+        func: T,
+    ) -> Result<ARef<Task>> {
+        unsafe extern "C" fn threadfn<T: FnOnce() + Send + 'static>(
+            arg: *mut core::ffi::c_void,
+        ) -> core::ffi::c_int {
+            // SAFETY: The thread argument is always a `Box<T>` because it is only called via the
+            // thread creation below.
+            let bfunc = unsafe { Box::<T>::from_pointer(arg) };
+            bfunc();
+            0
+        }
+
+        let arg = Box::try_new(func)?.into_pointer();
+
+        // SAFETY: `arg` was just created with a call to `into_pointer` above.
+        let guard = ScopeGuard::new(|| unsafe {
+            Box::<T>::from_pointer(arg);
+        });
+
+        // SAFETY: The function pointer is always valid (as long as the module remains loaded).
+        // Ownership of `raw` is transferred to the new thread (if one is actually created), so it
+        // remains valid. Lastly, the C format string is a constant that require formatting as the
+        // one and only extra argument.
+        let ktask = from_kernel_err_ptr(unsafe {
+            bindings::kthread_create_on_node(
+                Some(threadfn::<T>),
+                arg as _,
+                bindings::NUMA_NO_NODE,
+                c_str!("%pA").as_char_ptr(),
+                &name as *const _ as *const core::ffi::c_void,
+            )
+        })?;
+
+        // SAFETY: Since the kthread creation succeeded and we haven't run it yet, we know the task
+        // is valid.
+        let task: ARef<_> = unsafe { &*(ktask as *const Task) }.into();
+
+        // Wakes up the thread, otherwise it won't run.
+        task.wake_up();
+
+        guard.dismiss();
+        Ok(task)
+    }
+
+    /// Wakes up the task.
+    pub fn wake_up(&self) {
+        // SAFETY: By the type invariant, we know that `self.0.get()` is non-null and valid.
+        // And `wake_up_process` is safe to be called for any valid task, even if the task is
+        // running.
+        unsafe { bindings::wake_up_process(self.0.get()) };
+    }
+}
+
+// SAFETY: The type invariants guarantee that `Task` is always ref-counted.
+unsafe impl AlwaysRefCounted for Task {
+    fn inc_ref(&self) {
+        // SAFETY: The existence of a shared reference means that the refcount is nonzero.
+        unsafe { bindings::get_task_struct(self.0.get()) };
+    }
+
+    unsafe fn dec_ref(obj: ptr::NonNull<Self>) {
+        // SAFETY: The safety requirements guarantee that the refcount is nonzero.
+        unsafe { bindings::put_task_struct(obj.cast().as_ptr()) }
+    }
+}
+
+/// A wrapper for a shared reference to [`Task`] that isn't [`Send`].
+///
+/// We make this explicitly not [`Send`] so that we can use it to represent the current thread
+/// without having to increment/decrement the task's reference count.
+///
+/// # Invariants
+///
+/// The wrapped [`Task`] remains valid for the lifetime of the object.
+pub struct TaskRef<'a> {
+    task: &'a Task,
+    _not_send: PhantomData<*mut ()>,
+}
+
+impl Deref for TaskRef<'_> {
+    type Target = Task;
+
+    fn deref(&self) -> &Self::Target {
+        self.task
+    }
+}
+
+impl From<TaskRef<'_>> for ARef<Task> {
+    fn from(t: TaskRef<'_>) -> Self {
+        t.deref().into()
+    }
+}
diff --git a/rust/kernel/types.rs b/rust/kernel/types.rs
new file mode 100644
index 000000000000..b1f73aeece0b
--- /dev/null
+++ b/rust/kernel/types.rs
@@ -0,0 +1,705 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Kernel types.
+//!
+//! C header: [`include/linux/types.h`](../../../../include/linux/types.h)
+
+use crate::{
+    bindings,
+    sync::{Ref, RefBorrow},
+};
+use alloc::boxed::Box;
+use core::{
+    cell::UnsafeCell,
+    marker::PhantomData,
+    mem::MaybeUninit,
+    ops::{self, Deref, DerefMut},
+    pin::Pin,
+    ptr::NonNull,
+};
+
+/// Permissions.
+///
+/// C header: [`include/uapi/linux/stat.h`](../../../../include/uapi/linux/stat.h)
+///
+/// C header: [`include/linux/stat.h`](../../../../include/linux/stat.h)
+pub struct Mode(bindings::umode_t);
+
+impl Mode {
+    /// Creates a [`Mode`] from an integer.
+    pub fn from_int(m: u16) -> Mode {
+        Mode(m)
+    }
+
+    /// Returns the mode as an integer.
+    pub fn as_int(&self) -> u16 {
+        self.0
+    }
+}
+
+/// Used to convert an object into a raw pointer that represents it.
+///
+/// It can eventually be converted back into the object. This is used to store objects as pointers
+/// in kernel data structures, for example, an implementation of
+/// [`Operations`][crate::file::Operations] in `struct
+/// file::private_data`.
+pub trait PointerWrapper {
+    /// Type of values borrowed between calls to [`PointerWrapper::into_pointer`] and
+    /// [`PointerWrapper::from_pointer`].
+    type Borrowed<'a>;
+
+    /// Returns the raw pointer.
+    fn into_pointer(self) -> *const core::ffi::c_void;
+
+    /// Returns a borrowed value.
+    ///
+    /// # Safety
+    ///
+    /// `ptr` must have been returned by a previous call to [`PointerWrapper::into_pointer`].
+    /// Additionally, [`PointerWrapper::from_pointer`] can only be called after *all* values
+    /// returned by [`PointerWrapper::borrow`] have been dropped.
+    unsafe fn borrow<'a>(ptr: *const core::ffi::c_void) -> Self::Borrowed<'a>;
+
+    /// Returns a mutably borrowed value.
+    ///
+    /// # Safety
+    ///
+    /// The passed pointer must come from a previous to [`PointerWrapper::into_pointer`], and no
+    /// other concurrent users of the pointer (except the ones derived from the returned value) run
+    /// at least until the returned [`ScopeGuard`] is dropped.
+    unsafe fn borrow_mut<T: PointerWrapper>(ptr: *const core::ffi::c_void) -> ScopeGuard<T, fn(T)> {
+        // SAFETY: The safety requirements ensure that `ptr` came from a previous call to
+        // `into_pointer`.
+        ScopeGuard::new_with_data(unsafe { T::from_pointer(ptr) }, |d| {
+            d.into_pointer();
+        })
+    }
+
+    /// Returns the instance back from the raw pointer.
+    ///
+    /// # Safety
+    ///
+    /// The passed pointer must come from a previous call to [`PointerWrapper::into_pointer()`].
+    unsafe fn from_pointer(ptr: *const core::ffi::c_void) -> Self;
+}
+
+impl<T: 'static> PointerWrapper for Box<T> {
+    type Borrowed<'a> = &'a T;
+
+    fn into_pointer(self) -> *const core::ffi::c_void {
+        Box::into_raw(self) as _
+    }
+
+    unsafe fn borrow<'a>(ptr: *const core::ffi::c_void) -> &'a T {
+        // SAFETY: The safety requirements for this function ensure that the object is still alive,
+        // so it is safe to dereference the raw pointer.
+        // The safety requirements also ensure that the object remains alive for the lifetime of
+        // the returned value.
+        unsafe { &*ptr.cast() }
+    }
+
+    unsafe fn from_pointer(ptr: *const core::ffi::c_void) -> Self {
+        // SAFETY: The passed pointer comes from a previous call to [`Self::into_pointer()`].
+        unsafe { Box::from_raw(ptr as _) }
+    }
+}
+
+impl<T: 'static> PointerWrapper for Ref<T> {
+    type Borrowed<'a> = RefBorrow<'a, T>;
+
+    fn into_pointer(self) -> *const core::ffi::c_void {
+        Ref::into_usize(self) as _
+    }
+
+    unsafe fn borrow<'a>(ptr: *const core::ffi::c_void) -> RefBorrow<'a, T> {
+        // SAFETY: The safety requirements for this function ensure that the underlying object
+        // remains valid for the lifetime of the returned value.
+        unsafe { Ref::borrow_usize(ptr as _) }
+    }
+
+    unsafe fn from_pointer(ptr: *const core::ffi::c_void) -> Self {
+        // SAFETY: The passed pointer comes from a previous call to [`Self::into_pointer()`].
+        unsafe { Ref::from_usize(ptr as _) }
+    }
+}
+
+impl<T: PointerWrapper + Deref> PointerWrapper for Pin<T> {
+    type Borrowed<'a> = T::Borrowed<'a>;
+
+    fn into_pointer(self) -> *const core::ffi::c_void {
+        // SAFETY: We continue to treat the pointer as pinned by returning just a pointer to it to
+        // the caller.
+        let inner = unsafe { Pin::into_inner_unchecked(self) };
+        inner.into_pointer()
+    }
+
+    unsafe fn borrow<'a>(ptr: *const core::ffi::c_void) -> Self::Borrowed<'a> {
+        // SAFETY: The safety requirements for this function are the same as the ones for
+        // `T::borrow`.
+        unsafe { T::borrow(ptr) }
+    }
+
+    unsafe fn from_pointer(p: *const core::ffi::c_void) -> Self {
+        // SAFETY: The object was originally pinned.
+        // The passed pointer comes from a previous call to `inner::into_pointer()`.
+        unsafe { Pin::new_unchecked(T::from_pointer(p)) }
+    }
+}
+
+impl<T> PointerWrapper for *mut T {
+    type Borrowed<'a> = *mut T;
+
+    fn into_pointer(self) -> *const core::ffi::c_void {
+        self as _
+    }
+
+    unsafe fn borrow<'a>(ptr: *const core::ffi::c_void) -> Self::Borrowed<'a> {
+        ptr as _
+    }
+
+    unsafe fn from_pointer(ptr: *const core::ffi::c_void) -> Self {
+        ptr as _
+    }
+}
+
+impl PointerWrapper for () {
+    type Borrowed<'a> = ();
+
+    fn into_pointer(self) -> *const core::ffi::c_void {
+        // We use 1 to be different from a null pointer.
+        1usize as _
+    }
+
+    unsafe fn borrow<'a>(_: *const core::ffi::c_void) -> Self::Borrowed<'a> {}
+
+    unsafe fn from_pointer(_: *const core::ffi::c_void) -> Self {}
+}
+
+/// Runs a cleanup function/closure when dropped.
+///
+/// The [`ScopeGuard::dismiss`] function prevents the cleanup function from running.
+///
+/// # Examples
+///
+/// In the example below, we have multiple exit paths and we want to log regardless of which one is
+/// taken:
+/// ```
+/// # use kernel::ScopeGuard;
+/// fn example1(arg: bool) {
+///     let _log = ScopeGuard::new(|| pr_info!("example1 completed\n"));
+///
+///     if arg {
+///         return;
+///     }
+///
+///     pr_info!("Do something...\n");
+/// }
+///
+/// # example1(false);
+/// # example1(true);
+/// ```
+///
+/// In the example below, we want to log the same message on all early exits but a different one on
+/// the main exit path:
+/// ```
+/// # use kernel::ScopeGuard;
+/// fn example2(arg: bool) {
+///     let log = ScopeGuard::new(|| pr_info!("example2 returned early\n"));
+///
+///     if arg {
+///         return;
+///     }
+///
+///     // (Other early returns...)
+///
+///     log.dismiss();
+///     pr_info!("example2 no early return\n");
+/// }
+///
+/// # example2(false);
+/// # example2(true);
+/// ```
+///
+/// In the example below, we need a mutable object (the vector) to be accessible within the log
+/// function, so we wrap it in the [`ScopeGuard`]:
+/// ```
+/// # use kernel::ScopeGuard;
+/// fn example3(arg: bool) -> Result {
+///     let mut vec =
+///         ScopeGuard::new_with_data(Vec::new(), |v| pr_info!("vec had {} elements\n", v.len()));
+///
+///     vec.try_push(10u8)?;
+///     if arg {
+///         return Ok(());
+///     }
+///     vec.try_push(20u8)?;
+///     Ok(())
+/// }
+///
+/// # assert_eq!(example3(false), Ok(()));
+/// # assert_eq!(example3(true), Ok(()));
+/// ```
+///
+/// # Invariants
+///
+/// The value stored in the struct is nearly always `Some(_)`, except between
+/// [`ScopeGuard::dismiss`] and [`ScopeGuard::drop`]: in this case, it will be `None` as the value
+/// will have been returned to the caller. Since  [`ScopeGuard::dismiss`] consumes the guard,
+/// callers won't be able to use it anymore.
+pub struct ScopeGuard<T, F: FnOnce(T)>(Option<(T, F)>);
+
+impl<T, F: FnOnce(T)> ScopeGuard<T, F> {
+    /// Creates a new guarded object wrapping the given data and with the given cleanup function.
+    pub fn new_with_data(data: T, cleanup_func: F) -> Self {
+        // INVARIANT: The struct is being initialised with `Some(_)`.
+        Self(Some((data, cleanup_func)))
+    }
+
+    /// Prevents the cleanup function from running and returns the guarded data.
+    pub fn dismiss(mut self) -> T {
+        // INVARIANT: This is the exception case in the invariant; it is not visible to callers
+        // because this function consumes `self`.
+        self.0.take().unwrap().0
+    }
+}
+
+impl ScopeGuard<(), Box<dyn FnOnce(())>> {
+    /// Creates a new guarded object with the given cleanup function.
+    pub fn new(cleanup: impl FnOnce()) -> ScopeGuard<(), impl FnOnce(())> {
+        ScopeGuard::new_with_data((), move |_| cleanup())
+    }
+}
+
+impl<T, F: FnOnce(T)> Deref for ScopeGuard<T, F> {
+    type Target = T;
+
+    fn deref(&self) -> &T {
+        // The type invariants guarantee that `unwrap` will succeed.
+        &self.0.as_ref().unwrap().0
+    }
+}
+
+impl<T, F: FnOnce(T)> DerefMut for ScopeGuard<T, F> {
+    fn deref_mut(&mut self) -> &mut T {
+        // The type invariants guarantee that `unwrap` will succeed.
+        &mut self.0.as_mut().unwrap().0
+    }
+}
+
+impl<T, F: FnOnce(T)> Drop for ScopeGuard<T, F> {
+    fn drop(&mut self) {
+        // Run the cleanup function if one is still present.
+        if let Some((data, cleanup)) = self.0.take() {
+            cleanup(data)
+        }
+    }
+}
+
+/// Stores an opaque value.
+///
+/// This is meant to be used with FFI objects that are never interpreted by Rust code.
+#[repr(transparent)]
+pub struct Opaque<T>(MaybeUninit<UnsafeCell<T>>);
+
+impl<T> Opaque<T> {
+    /// Creates a new opaque value.
+    pub const fn new(value: T) -> Self {
+        Self(MaybeUninit::new(UnsafeCell::new(value)))
+    }
+
+    /// Creates an uninitialised value.
+    pub const fn uninit() -> Self {
+        Self(MaybeUninit::uninit())
+    }
+
+    /// Returns a raw pointer to the opaque data.
+    pub fn get(&self) -> *mut T {
+        UnsafeCell::raw_get(self.0.as_ptr())
+    }
+}
+
+/// A bitmask.
+///
+/// It has a restriction that all bits must be the same, except one. For example, `0b1110111` and
+/// `0b1000` are acceptable masks.
+#[derive(Clone, Copy)]
+pub struct Bit<T> {
+    index: T,
+    inverted: bool,
+}
+
+/// Creates a bit mask with a single bit set.
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::bit;
+/// let mut x = 0xfeu32;
+///
+/// assert_eq!(x & bit(0), 0);
+/// assert_eq!(x & bit(1), 2);
+/// assert_eq!(x & bit(2), 4);
+/// assert_eq!(x & bit(3), 8);
+///
+/// x |= bit(0);
+/// assert_eq!(x, 0xff);
+///
+/// x &= !bit(1);
+/// assert_eq!(x, 0xfd);
+///
+/// x &= !bit(7);
+/// assert_eq!(x, 0x7d);
+///
+/// let y: u64 = bit(34).into();
+/// assert_eq!(y, 0x400000000);
+///
+/// assert_eq!(y | bit(35), 0xc00000000);
+/// ```
+pub fn bit<T: Copy>(index: T) -> Bit<T> {
+    Bit {
+        index,
+        inverted: false,
+    }
+}
+
+impl<T: Copy> ops::Not for Bit<T> {
+    type Output = Self;
+    fn not(self) -> Self {
+        Self {
+            index: self.index,
+            inverted: !self.inverted,
+        }
+    }
+}
+
+/// Implemented by integer types that allow counting the number of trailing zeroes.
+pub trait TrailingZeros {
+    /// Returns the number of trailing zeroes in the binary representation of `self`.
+    fn trailing_zeros(&self) -> u32;
+}
+
+macro_rules! define_unsigned_number_traits {
+    ($type_name:ty) => {
+        impl TrailingZeros for $type_name {
+            fn trailing_zeros(&self) -> u32 {
+                <$type_name>::trailing_zeros(*self)
+            }
+        }
+
+        impl<T: Copy> core::convert::From<Bit<T>> for $type_name
+        where
+            Self: ops::Shl<T, Output = Self> + core::convert::From<u8> + ops::Not<Output = Self>,
+        {
+            fn from(v: Bit<T>) -> Self {
+                let c = Self::from(1u8) << v.index;
+                if v.inverted {
+                    !c
+                } else {
+                    c
+                }
+            }
+        }
+
+        impl<T: Copy> ops::BitAnd<Bit<T>> for $type_name
+        where
+            Self: ops::Shl<T, Output = Self> + core::convert::From<u8>,
+        {
+            type Output = Self;
+            fn bitand(self, rhs: Bit<T>) -> Self::Output {
+                self & Self::from(rhs)
+            }
+        }
+
+        impl<T: Copy> ops::BitOr<Bit<T>> for $type_name
+        where
+            Self: ops::Shl<T, Output = Self> + core::convert::From<u8>,
+        {
+            type Output = Self;
+            fn bitor(self, rhs: Bit<T>) -> Self::Output {
+                self | Self::from(rhs)
+            }
+        }
+
+        impl<T: Copy> ops::BitAndAssign<Bit<T>> for $type_name
+        where
+            Self: ops::Shl<T, Output = Self> + core::convert::From<u8>,
+        {
+            fn bitand_assign(&mut self, rhs: Bit<T>) {
+                *self &= Self::from(rhs)
+            }
+        }
+
+        impl<T: Copy> ops::BitOrAssign<Bit<T>> for $type_name
+        where
+            Self: ops::Shl<T, Output = Self> + core::convert::From<u8>,
+        {
+            fn bitor_assign(&mut self, rhs: Bit<T>) {
+                *self |= Self::from(rhs)
+            }
+        }
+    };
+}
+
+define_unsigned_number_traits!(u8);
+define_unsigned_number_traits!(u16);
+define_unsigned_number_traits!(u32);
+define_unsigned_number_traits!(u64);
+define_unsigned_number_traits!(usize);
+
+/// Returns an iterator over the set bits of `value`.
+///
+/// # Examples
+///
+/// ```
+/// use kernel::bits_iter;
+///
+/// let mut iter = bits_iter(5usize);
+/// assert_eq!(iter.next().unwrap(), 0);
+/// assert_eq!(iter.next().unwrap(), 2);
+/// assert!(iter.next().is_none());
+/// ```
+///
+/// ```
+/// use kernel::bits_iter;
+///
+/// fn print_bits(x: usize) {
+///     for bit in bits_iter(x) {
+///         pr_info!("{}\n", bit);
+///     }
+/// }
+///
+/// # print_bits(42);
+/// ```
+#[inline]
+pub fn bits_iter<T>(value: T) -> impl Iterator<Item = u32>
+where
+    T: core::cmp::PartialEq
+        + From<u8>
+        + ops::Shl<u32, Output = T>
+        + ops::Not<Output = T>
+        + ops::BitAndAssign
+        + TrailingZeros,
+{
+    struct BitIterator<U> {
+        value: U,
+    }
+
+    impl<U> Iterator for BitIterator<U>
+    where
+        U: core::cmp::PartialEq
+            + From<u8>
+            + ops::Shl<u32, Output = U>
+            + ops::Not<Output = U>
+            + ops::BitAndAssign
+            + TrailingZeros,
+    {
+        type Item = u32;
+
+        #[inline]
+        fn next(&mut self) -> Option<u32> {
+            if self.value == U::from(0u8) {
+                return None;
+            }
+            let ret = self.value.trailing_zeros();
+            self.value &= !(U::from(1u8) << ret);
+            Some(ret)
+        }
+    }
+
+    BitIterator { value }
+}
+
+/// A trait for boolean types.
+///
+/// This is meant to be used in type states to allow boolean constraints in implementation blocks.
+/// In the example below, the implementation containing `MyType::set_value` could _not_ be
+/// constrained to type states containing `Writable = true` if `Writable` were a constant instead
+/// of a type.
+///
+/// # Safety
+///
+/// No additional implementations of [`Bool`] should be provided, as [`True`] and [`False`] are
+/// already provided.
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::{Bool, False, True};
+/// use core::marker::PhantomData;
+///
+/// // Type state specifies whether the type is writable.
+/// trait MyTypeState {
+///     type Writable: Bool;
+/// }
+///
+/// // In state S1, the type is writable.
+/// struct S1;
+/// impl MyTypeState for S1 {
+///     type Writable = True;
+/// }
+///
+/// // In state S2, the type is not writable.
+/// struct S2;
+/// impl MyTypeState for S2 {
+///     type Writable = False;
+/// }
+///
+/// struct MyType<T: MyTypeState> {
+///     value: u32,
+///     _p: PhantomData<T>,
+/// }
+///
+/// impl<T: MyTypeState> MyType<T> {
+///     fn new(value: u32) -> Self {
+///         Self {
+///             value,
+///             _p: PhantomData,
+///         }
+///     }
+/// }
+///
+/// // This implementation block only applies if the type state is writable.
+/// impl<T> MyType<T>
+/// where
+///     T: MyTypeState<Writable = True>,
+/// {
+///     fn set_value(&mut self, v: u32) {
+///         self.value = v;
+///     }
+/// }
+///
+/// let mut x = MyType::<S1>::new(10);
+/// let mut y = MyType::<S2>::new(20);
+///
+/// x.set_value(30);
+///
+/// // The code below fails to compile because `S2` is not writable.
+/// // y.set_value(40);
+/// ```
+pub unsafe trait Bool {}
+
+/// Represents the `true` value for types with [`Bool`] bound.
+pub struct True;
+
+// SAFETY: This is one of the only two implementations of `Bool`.
+unsafe impl Bool for True {}
+
+/// Represents the `false` value for types wth [`Bool`] bound.
+pub struct False;
+
+// SAFETY: This is one of the only two implementations of `Bool`.
+unsafe impl Bool for False {}
+
+/// Types that are _always_ reference counted.
+///
+/// It allows such types to define their own custom ref increment and decrement functions.
+/// Additionally, it allows users to convert from a shared reference `&T` to an owned reference
+/// [`ARef<T>`].
+///
+/// This is usually implemented by wrappers to existing structures on the C side of the code. For
+/// Rust code, the recommendation is to use [`Ref`] to create reference-counted instances of a
+/// type.
+///
+/// # Safety
+///
+/// Implementers must ensure that increments to the reference count keeps the object alive in
+/// memory at least until a matching decrement performed.
+///
+/// Implementers must also ensure that all instances are reference-counted. (Otherwise they
+/// won't be able to honour the requirement that [`AlwaysRefCounted::inc_ref`] keep the object
+/// alive.)
+pub unsafe trait AlwaysRefCounted {
+    /// Increments the reference count on the object.
+    fn inc_ref(&self);
+
+    /// Decrements the reference count on the object.
+    ///
+    /// Frees the object when the count reaches zero.
+    ///
+    /// # Safety
+    ///
+    /// Callers must ensure that there was a previous matching increment to the reference count,
+    /// and that the object is no longer used after its reference count is decremented (as it may
+    /// result in the object being freed), unless the caller owns another increment on the refcount
+    /// (e.g., it calls [`AlwaysRefCounted::inc_ref`] twice, then calls
+    /// [`AlwaysRefCounted::dec_ref`] once).
+    unsafe fn dec_ref(obj: NonNull<Self>);
+}
+
+/// An owned reference to an always-reference-counted object.
+///
+/// The object's reference count is automatically decremented when an instance of [`ARef`] is
+/// dropped. It is also automatically incremented when a new instance is created via
+/// [`ARef::clone`].
+///
+/// # Invariants
+///
+/// The pointer stored in `ptr` is non-null and valid for the lifetime of the [`ARef`] instance. In
+/// particular, the [`ARef`] instance owns an increment on underlying object's reference count.
+pub struct ARef<T: AlwaysRefCounted> {
+    ptr: NonNull<T>,
+    _p: PhantomData<T>,
+}
+
+impl<T: AlwaysRefCounted> ARef<T> {
+    /// Creates a new instance of [`ARef`].
+    ///
+    /// It takes over an increment of the reference count on the underlying object.
+    ///
+    /// # Safety
+    ///
+    /// Callers must ensure that the reference count was incremented at least once, and that they
+    /// are properly relinquishing one increment. That is, if there is only one increment, callers
+    /// must not use the underlying object anymore -- it is only safe to do so via the newly
+    /// created [`ARef`].
+    pub unsafe fn from_raw(ptr: NonNull<T>) -> Self {
+        // INVARIANT: The safety requirements guarantee that the new instance now owns the
+        // increment on the refcount.
+        Self {
+            ptr,
+            _p: PhantomData,
+        }
+    }
+}
+
+impl<T: AlwaysRefCounted> Clone for ARef<T> {
+    fn clone(&self) -> Self {
+        self.inc_ref();
+        // SAFETY: We just incremented the refcount above.
+        unsafe { Self::from_raw(self.ptr) }
+    }
+}
+
+impl<T: AlwaysRefCounted> Deref for ARef<T> {
+    type Target = T;
+
+    fn deref(&self) -> &Self::Target {
+        // SAFETY: The type invariants guarantee that the object is valid.
+        unsafe { self.ptr.as_ref() }
+    }
+}
+
+impl<T: AlwaysRefCounted> From<&T> for ARef<T> {
+    fn from(b: &T) -> Self {
+        b.inc_ref();
+        // SAFETY: We just incremented the refcount above.
+        unsafe { Self::from_raw(NonNull::from(b)) }
+    }
+}
+
+impl<T: AlwaysRefCounted> Drop for ARef<T> {
+    fn drop(&mut self) {
+        // SAFETY: The type invariants guarantee that the `ARef` owns the reference we're about to
+        // decrement.
+        unsafe { T::dec_ref(self.ptr) };
+    }
+}
+
+/// A sum type that always holds either a value of type `L` or `R`.
+pub enum Either<L, R> {
+    /// Constructs an instance of [`Either`] containing a value of type `L`.
+    Left(L),
+
+    /// Constructs an instance of [`Either`] containing a value of type `R`.
+    Right(R),
+}
diff --git a/rust/kernel/unsafe_list.rs b/rust/kernel/unsafe_list.rs
new file mode 100644
index 000000000000..df496667c033
--- /dev/null
+++ b/rust/kernel/unsafe_list.rs
@@ -0,0 +1,680 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Intrusive circular doubly-linked lists.
+//!
+//! We don't use the C version for two main reasons:
+//! - Next/prev pointers do not support `?Sized` types, so wouldn't be able to have a list of, for
+//!   example, `dyn Trait`.
+//! - It would require the list head to be pinned (in addition to the list entries).
+
+use core::{cell::UnsafeCell, iter, marker::PhantomPinned, mem::MaybeUninit, ptr::NonNull};
+
+/// An intrusive circular doubly-linked list.
+///
+/// Membership of elements of the list must be tracked by the owner of the list.
+///
+/// While elements of the list must remain pinned while in the list, the list itself does not
+/// require pinning. In other words, users are allowed to move instances of [`List`].
+///
+/// # Invariants
+///
+/// The links of an entry are wrapped in [`UnsafeCell`] and they are acessible when the list itself
+/// is. For example, when a thread has a mutable reference to a list, it may also safely get
+/// mutable references to the links of the elements in the list.
+///
+/// The links of an entry are also wrapped in [`MaybeUninit`] and they are initialised when they
+/// are present in a list. Otherwise they are uninitialised.
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::unsafe_list::{Adapter, Links, List};
+///
+/// struct Example {
+///     v: usize,
+///     links: Links<Example>,
+/// }
+///
+/// // SAFETY: This adapter is the only one that uses `Example::links`.
+/// unsafe impl Adapter for Example {
+///     type EntryType = Self;
+///     fn to_links(obj: &Self) -> &Links<Self> {
+///         &obj.links
+///     }
+/// }
+///
+/// let a = Example {
+///     v: 0,
+///     links: Links::new(),
+/// };
+/// let b = Example {
+///     v: 1,
+///     links: Links::new(),
+/// };
+///
+/// let mut list = List::<Example>::new();
+/// assert!(list.is_empty());
+///
+/// // SAFETY: `a` was declared above, it's not in any lists yet, is never moved, and outlives the
+/// // list.
+/// unsafe { list.push_back(&a) };
+///
+/// // SAFETY: `b` was declared above, it's not in any lists yet, is never moved, and outlives the
+/// // list.
+/// unsafe { list.push_back(&b) };
+///
+/// assert!(core::ptr::eq(&a, list.front().unwrap().as_ptr()));
+/// assert!(core::ptr::eq(&b, list.back().unwrap().as_ptr()));
+///
+/// for (i, e) in list.iter().enumerate() {
+///     assert_eq!(i, e.v);
+/// }
+///
+/// for e in &list {
+///     pr_info!("{}", e.v);
+/// }
+///
+/// // SAFETY: `b` was added to the list above and wasn't removed yet.
+/// unsafe { list.remove(&b) };
+///
+/// assert!(core::ptr::eq(&a, list.front().unwrap().as_ptr()));
+/// assert!(core::ptr::eq(&a, list.back().unwrap().as_ptr()));
+/// ```
+pub struct List<A: Adapter + ?Sized> {
+    first: Option<NonNull<A::EntryType>>,
+}
+
+// SAFETY: The list is itself can be safely sent to other threads but we restrict it to being `Send`
+// only when its entries are also `Send`.
+unsafe impl<A: Adapter + ?Sized> Send for List<A> where A::EntryType: Send {}
+
+// SAFETY: The list is itself usable from other threads via references but we restrict it to being
+// `Sync` only when its entries are also `Sync`.
+unsafe impl<A: Adapter + ?Sized> Sync for List<A> where A::EntryType: Sync {}
+
+impl<A: Adapter + ?Sized> List<A> {
+    /// Constructs a new empty list.
+    pub const fn new() -> Self {
+        Self { first: None }
+    }
+
+    /// Determines if the list is empty.
+    pub fn is_empty(&self) -> bool {
+        self.first.is_none()
+    }
+
+    /// Inserts the only entry to a list.
+    ///
+    /// This must only be called when the list is empty.
+    pub fn insert_only_entry(&mut self, obj: &A::EntryType) {
+        let obj_ptr = NonNull::from(obj);
+
+        // SAFETY: We have mutable access to the list, so we also have access to the entry
+        // we're about to insert (and it's not in any other lists per the function safety
+        // requirements).
+        let obj_inner = unsafe { &mut *A::to_links(obj).0.get() };
+
+        // INVARIANTS: All fields of the links of the newly-inserted object are initialised
+        // below.
+        obj_inner.write(LinksInner {
+            next: obj_ptr,
+            prev: obj_ptr,
+            _pin: PhantomPinned,
+        });
+        self.first = Some(obj_ptr);
+    }
+
+    /// Adds the given object to the end of the list.
+    ///
+    /// # Safety
+    ///
+    /// Callers must ensure that:
+    /// - The object is not currently in any lists.
+    /// - The object remains alive until it is removed from the list.
+    /// - The object is not moved until it is removed from the list.
+    pub unsafe fn push_back(&mut self, obj: &A::EntryType) {
+        if let Some(first) = self.first {
+            // SAFETY: The previous entry to the first one is necessarily present in the list (it
+            // may in fact be the first entry itself as this is a circular list). The safety
+            // requirements of this function regarding `obj` satisfy those of `insert_after`.
+            unsafe { self.insert_after(self.inner_ref(first).prev, obj) };
+        } else {
+            self.insert_only_entry(obj);
+        }
+    }
+
+    /// Adds the given object to the beginning of the list.
+    ///
+    /// # Safety
+    ///
+    /// Callers must ensure that:
+    /// - The object is not currently in any lists.
+    /// - The object remains alive until it is removed from the list.
+    /// - The object is not moved until it is removed from the list.
+    pub unsafe fn push_front(&mut self, obj: &A::EntryType) {
+        if let Some(first) = self.first {
+            // SAFETY: The safety requirements of this function regarding `obj` satisfy those of
+            // `insert_before`. Additionally, `first` is in the list.
+            unsafe { self.insert_before(first, obj) };
+        } else {
+            self.insert_only_entry(obj);
+        }
+    }
+
+    /// Removes the given object from the list.
+    ///
+    /// # Safety
+    ///
+    /// The object must be in the list. In other words, the object must have previously been
+    /// inserted into this list and not removed yet.
+    pub unsafe fn remove(&mut self, entry: &A::EntryType) {
+        // SAFETY: Per the function safety requirements, `entry` is in the list.
+        let inner = unsafe { self.inner_ref(NonNull::from(entry)) };
+        let next = inner.next;
+        let prev = inner.prev;
+
+        // SAFETY: We have mutable access to the list, so we also have access to the entry we're
+        // about to remove (which we know is in the list per the function safety requirements).
+        let inner = unsafe { &mut *A::to_links(entry).0.get() };
+
+        // SAFETY: Since the entry was in the list, it was initialised.
+        unsafe { inner.assume_init_drop() };
+
+        if core::ptr::eq(next.as_ptr(), entry) {
+            // Removing the only element.
+            self.first = None;
+        } else {
+            // SAFETY: `prev` is in the list because it is pointed at by the entry being removed.
+            unsafe { self.inner(prev).next = next };
+            // SAFETY: `next` is in the list because it is pointed at by the entry being removed.
+            unsafe { self.inner(next).prev = prev };
+
+            if core::ptr::eq(self.first.unwrap().as_ptr(), entry) {
+                // Update the pointer to the first element as we're removing it.
+                self.first = Some(next);
+            }
+        }
+    }
+
+    /// Adds the given object after another object already in the list.
+    ///
+    /// # Safety
+    ///
+    /// Callers must ensure that:
+    /// - The existing object is currently in the list.
+    /// - The new object is not currently in any lists.
+    /// - The new object remains alive until it is removed from the list.
+    /// - The new object is not moved until it is removed from the list.
+    pub unsafe fn insert_after(&mut self, existing: NonNull<A::EntryType>, new: &A::EntryType) {
+        // SAFETY: We have mutable access to the list, so we also have access to the entry we're
+        // about to insert (and it's not in any other lists per the function safety requirements).
+        let new_inner = unsafe { &mut *A::to_links(new).0.get() };
+
+        // SAFETY: Per the function safety requirements, `existing` is in the list.
+        let existing_inner = unsafe { self.inner(existing) };
+        let next = existing_inner.next;
+
+        // INVARIANTS: All fields of the links of the newly-inserted object are initialised below.
+        new_inner.write(LinksInner {
+            next,
+            prev: existing,
+            _pin: PhantomPinned,
+        });
+
+        existing_inner.next = NonNull::from(new);
+
+        // SAFETY: `next` is in the list because it's pointed at by the existing entry.
+        unsafe { self.inner(next).prev = NonNull::from(new) };
+    }
+
+    /// Adds the given object before another object already in the list.
+    ///
+    /// # Safety
+    ///
+    /// Callers must ensure that:
+    /// - The existing object is currently in the list.
+    /// - The new object is not currently in any lists.
+    /// - The new object remains alive until it is removed from the list.
+    /// - The new object is not moved until it is removed from the list.
+    pub unsafe fn insert_before(&mut self, existing: NonNull<A::EntryType>, new: &A::EntryType) {
+        // SAFETY: The safety requirements of this function satisfy those of `insert_after`.
+        unsafe { self.insert_after(self.inner_ref(existing).prev, new) };
+
+        if self.first.unwrap() == existing {
+            // Update the pointer to the first element as we're inserting before it.
+            self.first = Some(NonNull::from(new));
+        }
+    }
+
+    /// Returns the first element of the list, if one exists.
+    pub fn front(&self) -> Option<NonNull<A::EntryType>> {
+        self.first
+    }
+
+    /// Returns the last element of the list, if one exists.
+    pub fn back(&self) -> Option<NonNull<A::EntryType>> {
+        // SAFETY: Having a pointer to it guarantees that the object is in the list.
+        self.first.map(|f| unsafe { self.inner_ref(f).prev })
+    }
+
+    /// Returns an iterator for the list starting at the first entry.
+    pub fn iter(&self) -> Iterator<'_, A> {
+        Iterator::new(self.cursor_front())
+    }
+
+    /// Returns an iterator for the list starting at the last entry.
+    pub fn iter_back(&self) -> impl iter::DoubleEndedIterator<Item = &'_ A::EntryType> {
+        Iterator::new(self.cursor_back())
+    }
+
+    /// Returns a cursor starting on the first (front) element of the list.
+    pub fn cursor_front(&self) -> Cursor<'_, A> {
+        // SAFETY: `front` is in the list (or is `None`) because we've read it from the list head
+        // and the list cannot have changed because we hold a shared reference to it.
+        unsafe { Cursor::new(self, self.front()) }
+    }
+
+    /// Returns a cursor starting on the last (back) element of the list.
+    pub fn cursor_back(&self) -> Cursor<'_, A> {
+        // SAFETY: `back` is in the list (or is `None`) because we've read it from the list head
+        // and the list cannot have changed because we hold a shared reference to it.
+        unsafe { Cursor::new(self, self.back()) }
+    }
+
+    /// Returns a mutable reference to the links of a given object.
+    ///
+    /// # Safety
+    ///
+    /// Callers must ensure that the element is in the list.
+    unsafe fn inner(&mut self, ptr: NonNull<A::EntryType>) -> &mut LinksInner<A::EntryType> {
+        // SAFETY: The safety requirements guarantee that we the links are initialised because
+        // that's part of the type invariants. Additionally, the type invariants also guarantee
+        // that having a mutable reference to the list guarantees that the links are mutably
+        // accessible as well.
+        unsafe { (*A::to_links(ptr.as_ref()).0.get()).assume_init_mut() }
+    }
+
+    /// Returns a shared reference to the links of a given object.
+    ///
+    /// # Safety
+    ///
+    /// Callers must ensure that the element is in the list.
+    unsafe fn inner_ref(&self, ptr: NonNull<A::EntryType>) -> &LinksInner<A::EntryType> {
+        // SAFETY: The safety requirements guarantee that we the links are initialised because
+        // that's part of the type invariants. Additionally, the type invariants also guarantee
+        // that having a shared reference to the list guarantees that the links are accessible in
+        // shared mode as well.
+        unsafe { (*A::to_links(ptr.as_ref()).0.get()).assume_init_ref() }
+    }
+}
+
+impl<'a, A: Adapter + ?Sized> iter::IntoIterator for &'a List<A> {
+    type Item = &'a A::EntryType;
+    type IntoIter = Iterator<'a, A>;
+    fn into_iter(self) -> Self::IntoIter {
+        self.iter()
+    }
+}
+
+/// An iterator for the linked list.
+pub struct Iterator<'a, A: Adapter + ?Sized> {
+    cursor: Cursor<'a, A>,
+}
+
+impl<'a, A: Adapter + ?Sized> Iterator<'a, A> {
+    fn new(cursor: Cursor<'a, A>) -> Self {
+        Self { cursor }
+    }
+}
+
+impl<'a, A: Adapter + ?Sized> iter::Iterator for Iterator<'a, A> {
+    type Item = &'a A::EntryType;
+
+    fn next(&mut self) -> Option<Self::Item> {
+        let ret = self.cursor.current()?;
+        self.cursor.move_next();
+        Some(ret)
+    }
+}
+
+impl<A: Adapter + ?Sized> iter::DoubleEndedIterator for Iterator<'_, A> {
+    fn next_back(&mut self) -> Option<Self::Item> {
+        let ret = self.cursor.current()?;
+        self.cursor.move_prev();
+        Some(ret)
+    }
+}
+
+/// A linked-list adapter.
+///
+/// It is a separate type (as opposed to implemented by the type of the elements of the list)
+/// so that a given type can be inserted into multiple lists at the same time; in such cases, each
+/// list needs its own adapter that returns a different pointer to links.
+///
+/// It may, however, be implemented by the type itself to be inserted into lists, which makes it
+/// more readable.
+///
+/// # Safety
+///
+/// Implementers must ensure that the links returned by [`Adapter::to_links`] are unique to the
+/// adapter. That is, different adapters must return different links for a given object.
+///
+/// The reason for this requirement is to avoid confusion that may lead to UB. In particular, if
+/// two adapters were to use the same links, a user may have two lists (one for each adapter) and
+/// try to insert the same object into both at the same time; although this clearly violates the
+/// list safety requirements (e.g., those in [`List::push_back`]), for users to notice it, they'd
+/// have to dig into the details of the two adapters.
+///
+/// By imposing the requirement on the adapter, we make it easier for users to check compliance
+/// with the requirements when using the list.
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::unsafe_list::{Adapter, Links, List};
+///
+/// struct Example {
+///     a: u32,
+///     b: u32,
+///     links1: Links<Example>,
+///     links2: Links<Example>,
+/// }
+///
+/// // SAFETY: This adapter is the only one that uses `Example::links1`.
+/// unsafe impl Adapter for Example {
+///     type EntryType = Self;
+///     fn to_links(obj: &Self) -> &Links<Self> {
+///         &obj.links1
+///     }
+/// }
+///
+/// struct ExampleAdapter;
+///
+/// // SAFETY: This adapter is the only one that uses `Example::links2`.
+/// unsafe impl Adapter for ExampleAdapter {
+///     type EntryType = Example;
+///     fn to_links(obj: &Example) -> &Links<Example> {
+///         &obj.links2
+///     }
+/// }
+///
+/// static LIST1: List<Example> = List::new();
+/// static LIST2: List<ExampleAdapter> = List::new();
+/// ```
+pub unsafe trait Adapter {
+    /// The type of the enties in the list.
+    type EntryType: ?Sized;
+
+    /// Retrieves the linked list links for the given object.
+    fn to_links(obj: &Self::EntryType) -> &Links<Self::EntryType>;
+}
+
+struct LinksInner<T: ?Sized> {
+    next: NonNull<T>,
+    prev: NonNull<T>,
+    _pin: PhantomPinned,
+}
+
+/// Links of a linked list.
+///
+/// List entries need one of these per concurrent list.
+pub struct Links<T: ?Sized>(UnsafeCell<MaybeUninit<LinksInner<T>>>);
+
+// SAFETY: `Links` can be safely sent to other threads but we restrict it to being `Send` only when
+// the list entries it points to are also `Send`.
+unsafe impl<T: ?Sized> Send for Links<T> {}
+
+// SAFETY: `Links` is usable from other threads via references but we restrict it to being `Sync`
+// only when the list entries it points to are also `Sync`.
+unsafe impl<T: ?Sized> Sync for Links<T> {}
+
+impl<T: ?Sized> Links<T> {
+    /// Constructs a new instance of the linked-list links.
+    pub const fn new() -> Self {
+        Self(UnsafeCell::new(MaybeUninit::uninit()))
+    }
+}
+
+pub(crate) struct CommonCursor<A: Adapter + ?Sized> {
+    pub(crate) cur: Option<NonNull<A::EntryType>>,
+}
+
+impl<A: Adapter + ?Sized> CommonCursor<A> {
+    pub(crate) fn new(cur: Option<NonNull<A::EntryType>>) -> Self {
+        Self { cur }
+    }
+
+    /// Moves the cursor to the next entry of the list.
+    ///
+    /// # Safety
+    ///
+    /// Callers must ensure that the cursor is either [`None`] or points to an entry that is in
+    /// `list`.
+    pub(crate) unsafe fn move_next(&mut self, list: &List<A>) {
+        match self.cur.take() {
+            None => self.cur = list.first,
+            Some(cur) => {
+                if let Some(head) = list.first {
+                    // SAFETY: Per the function safety requirements, `cur` is in the list.
+                    let links = unsafe { list.inner_ref(cur) };
+                    if links.next != head {
+                        self.cur = Some(links.next);
+                    }
+                }
+            }
+        }
+    }
+
+    /// Moves the cursor to the previous entry of the list.
+    ///
+    /// # Safety
+    ///
+    /// Callers must ensure that the cursor is either [`None`] or points to an entry that is in
+    /// `list`.
+    pub(crate) unsafe fn move_prev(&mut self, list: &List<A>) {
+        match list.first {
+            None => self.cur = None,
+            Some(head) => {
+                let next = match self.cur.take() {
+                    None => head,
+                    Some(cur) => {
+                        if cur == head {
+                            return;
+                        }
+                        cur
+                    }
+                };
+                // SAFETY: `next` is either `head` or `cur`. The former is in the list because it's
+                // its head; the latter is in the list per the function safety requirements.
+                self.cur = Some(unsafe { list.inner_ref(next) }.prev);
+            }
+        }
+    }
+}
+
+/// A list cursor that allows traversing a linked list and inspecting elements.
+pub struct Cursor<'a, A: Adapter + ?Sized> {
+    cursor: CommonCursor<A>,
+    list: &'a List<A>,
+}
+
+impl<'a, A: Adapter + ?Sized> Cursor<'a, A> {
+    /// Creates a new cursor.
+    ///
+    /// # Safety
+    ///
+    /// Callers must ensure that `cur` is either [`None`] or points to an entry in `list`.
+    pub(crate) unsafe fn new(list: &'a List<A>, cur: Option<NonNull<A::EntryType>>) -> Self {
+        Self {
+            list,
+            cursor: CommonCursor::new(cur),
+        }
+    }
+
+    /// Returns the element the cursor is currently positioned on.
+    pub fn current(&self) -> Option<&'a A::EntryType> {
+        let cur = self.cursor.cur?;
+        // SAFETY: `cursor` starts off in the list and only changes within the list. Additionally,
+        // the list cannot change because we hold a shared reference to it, so the cursor is always
+        // within the list.
+        Some(unsafe { cur.as_ref() })
+    }
+
+    /// Moves the cursor to the next element.
+    pub fn move_next(&mut self) {
+        // SAFETY: `cursor` starts off in the list and only changes within the list. Additionally,
+        // the list cannot change because we hold a shared reference to it, so the cursor is always
+        // within the list.
+        unsafe { self.cursor.move_next(self.list) };
+    }
+
+    /// Moves the cursor to the previous element.
+    pub fn move_prev(&mut self) {
+        // SAFETY: `cursor` starts off in the list and only changes within the list. Additionally,
+        // the list cannot change because we hold a shared reference to it, so the cursor is always
+        // within the list.
+        unsafe { self.cursor.move_prev(self.list) };
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use alloc::{boxed::Box, vec::Vec};
+    use core::ptr::NonNull;
+
+    struct Example {
+        links: super::Links<Self>,
+    }
+
+    // SAFETY: This is the only adapter that uses `Example::links`.
+    unsafe impl super::Adapter for Example {
+        type EntryType = Self;
+        fn to_links(obj: &Self) -> &super::Links<Self> {
+            &obj.links
+        }
+    }
+
+    fn build_vector(size: usize) -> Vec<Box<Example>> {
+        let mut v = Vec::new();
+        v.reserve(size);
+        for _ in 0..size {
+            v.push(Box::new(Example {
+                links: super::Links::new(),
+            }));
+        }
+        v
+    }
+
+    #[track_caller]
+    fn assert_list_contents(v: &[Box<Example>], list: &super::List<Example>) {
+        let n = v.len();
+
+        // Assert that the list is ok going forward.
+        let mut count = 0;
+        for (i, e) in list.iter().enumerate() {
+            assert!(core::ptr::eq(e, &*v[i]));
+            count += 1;
+        }
+        assert_eq!(count, n);
+
+        // Assert that the list is ok going backwards.
+        let mut count = 0;
+        for (i, e) in list.iter_back().rev().enumerate() {
+            assert!(core::ptr::eq(e, &*v[n - 1 - i]));
+            count += 1;
+        }
+        assert_eq!(count, n);
+    }
+
+    #[track_caller]
+    fn test_each_element(
+        min_len: usize,
+        max_len: usize,
+        test: impl Fn(&mut Vec<Box<Example>>, &mut super::List<Example>, usize, Box<Example>),
+    ) {
+        for n in min_len..=max_len {
+            for i in 0..n {
+                let extra = Box::new(Example {
+                    links: super::Links::new(),
+                });
+                let mut v = build_vector(n);
+                let mut list = super::List::<Example>::new();
+
+                // Build list.
+                for j in 0..n {
+                    // SAFETY: The entry was allocated above, it's not in any lists yet, is never
+                    // moved, and outlives the list.
+                    unsafe { list.push_back(&v[j]) };
+                }
+
+                // Call the test case.
+                test(&mut v, &mut list, i, extra);
+
+                // Check that the list is ok.
+                assert_list_contents(&v, &list);
+            }
+        }
+    }
+
+    #[test]
+    fn test_push_back() {
+        const MAX: usize = 10;
+        let v = build_vector(MAX);
+        let mut list = super::List::<Example>::new();
+
+        for n in 1..=MAX {
+            // SAFETY: The entry was allocated above, it's not in any lists yet, is never moved,
+            // and outlives the list.
+            unsafe { list.push_back(&v[n - 1]) };
+            assert_list_contents(&v[..n], &list);
+        }
+    }
+
+    #[test]
+    fn test_push_front() {
+        const MAX: usize = 10;
+        let v = build_vector(MAX);
+        let mut list = super::List::<Example>::new();
+
+        for n in 1..=MAX {
+            // SAFETY: The entry was allocated above, it's not in any lists yet, is never moved,
+            // and outlives the list.
+            unsafe { list.push_front(&v[MAX - n]) };
+            assert_list_contents(&v[MAX - n..], &list);
+        }
+    }
+
+    #[test]
+    fn test_one_removal() {
+        test_each_element(1, 10, |v, list, i, _| {
+            // Remove the i-th element.
+            // SAFETY: The i-th element was added to the list above, and wasn't removed yet.
+            unsafe { list.remove(&v[i]) };
+            v.remove(i);
+        });
+    }
+
+    #[test]
+    fn test_one_insert_after() {
+        test_each_element(1, 10, |v, list, i, extra| {
+            // Insert after the i-th element.
+            // SAFETY: The i-th element was added to the list above, and wasn't removed yet.
+            // Additionally, the new element isn't in any list yet, isn't moved, and outlives
+            // the list.
+            unsafe { list.insert_after(NonNull::from(&*v[i]), &*extra) };
+            v.insert(i + 1, extra);
+        });
+    }
+
+    #[test]
+    fn test_one_insert_before() {
+        test_each_element(1, 10, |v, list, i, extra| {
+            // Insert before the i-th element.
+            // SAFETY: The i-th element was added to the list above, and wasn't removed yet.
+            // Additionally, the new element isn't in any list yet, isn't moved, and outlives
+            // the list.
+            unsafe { list.insert_before(NonNull::from(&*v[i]), &*extra) };
+            v.insert(i, extra);
+        });
+    }
+}
diff --git a/rust/kernel/user_ptr.rs b/rust/kernel/user_ptr.rs
new file mode 100644
index 000000000000..0bc2c7f1331e
--- /dev/null
+++ b/rust/kernel/user_ptr.rs
@@ -0,0 +1,175 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! User pointers.
+//!
+//! C header: [`include/linux/uaccess.h`](../../../../include/linux/uaccess.h)
+
+use crate::{
+    bindings,
+    error::code::*,
+    io_buffer::{IoBufferReader, IoBufferWriter},
+    Result,
+};
+use alloc::vec::Vec;
+
+/// A reference to an area in userspace memory, which can be either
+/// read-only or read-write.
+///
+/// All methods on this struct are safe: invalid pointers return
+/// `EFAULT`. Concurrent access, *including data races to/from userspace
+/// memory*, is permitted, because fundamentally another userspace
+/// thread/process could always be modifying memory at the same time
+/// (in the same way that userspace Rust's [`std::io`] permits data races
+/// with the contents of files on disk). In the presence of a race, the
+/// exact byte values read/written are unspecified but the operation is
+/// well-defined. Kernelspace code should validate its copy of data
+/// after completing a read, and not expect that multiple reads of the
+/// same address will return the same value.
+///
+/// All APIs enforce the invariant that a given byte of memory from userspace
+/// may only be read once. By preventing double-fetches we avoid TOCTOU
+/// vulnerabilities. This is accomplished by taking `self` by value to prevent
+/// obtaining multiple readers on a given [`UserSlicePtr`], and the readers
+/// only permitting forward reads.
+///
+/// Constructing a [`UserSlicePtr`] performs no checks on the provided
+/// address and length, it can safely be constructed inside a kernel thread
+/// with no current userspace process. Reads and writes wrap the kernel APIs
+/// `copy_from_user` and `copy_to_user`, which check the memory map of the
+/// current process and enforce that the address range is within the user
+/// range (no additional calls to `access_ok` are needed).
+///
+/// [`std::io`]: https://doc.rust-lang.org/std/io/index.html
+pub struct UserSlicePtr(*mut core::ffi::c_void, usize);
+
+impl UserSlicePtr {
+    /// Constructs a user slice from a raw pointer and a length in bytes.
+    ///
+    /// # Safety
+    ///
+    /// Callers must be careful to avoid time-of-check-time-of-use
+    /// (TOCTOU) issues. The simplest way is to create a single instance of
+    /// [`UserSlicePtr`] per user memory block as it reads each byte at
+    /// most once.
+    pub unsafe fn new(ptr: *mut core::ffi::c_void, length: usize) -> Self {
+        UserSlicePtr(ptr, length)
+    }
+
+    /// Reads the entirety of the user slice.
+    ///
+    /// Returns `EFAULT` if the address does not currently point to
+    /// mapped, readable memory.
+    pub fn read_all(self) -> Result<Vec<u8>> {
+        self.reader().read_all()
+    }
+
+    /// Constructs a [`UserSlicePtrReader`].
+    pub fn reader(self) -> UserSlicePtrReader {
+        UserSlicePtrReader(self.0, self.1)
+    }
+
+    /// Writes the provided slice into the user slice.
+    ///
+    /// Returns `EFAULT` if the address does not currently point to
+    /// mapped, writable memory (in which case some data from before the
+    /// fault may be written), or `data` is larger than the user slice
+    /// (in which case no data is written).
+    pub fn write_all(self, data: &[u8]) -> Result {
+        self.writer().write_slice(data)
+    }
+
+    /// Constructs a [`UserSlicePtrWriter`].
+    pub fn writer(self) -> UserSlicePtrWriter {
+        UserSlicePtrWriter(self.0, self.1)
+    }
+
+    /// Constructs both a [`UserSlicePtrReader`] and a [`UserSlicePtrWriter`].
+    pub fn reader_writer(self) -> (UserSlicePtrReader, UserSlicePtrWriter) {
+        (
+            UserSlicePtrReader(self.0, self.1),
+            UserSlicePtrWriter(self.0, self.1),
+        )
+    }
+}
+
+/// A reader for [`UserSlicePtr`].
+///
+/// Used to incrementally read from the user slice.
+pub struct UserSlicePtrReader(*mut core::ffi::c_void, usize);
+
+impl IoBufferReader for UserSlicePtrReader {
+    /// Returns the number of bytes left to be read from this.
+    ///
+    /// Note that even reading less than this number of bytes may fail.
+    fn len(&self) -> usize {
+        self.1
+    }
+
+    /// Reads raw data from the user slice into a raw kernel buffer.
+    ///
+    /// # Safety
+    ///
+    /// The output buffer must be valid.
+    unsafe fn read_raw(&mut self, out: *mut u8, len: usize) -> Result {
+        if len > self.1 || len > u32::MAX as usize {
+            return Err(EFAULT);
+        }
+        let res = unsafe { bindings::copy_from_user(out as _, self.0, len as _) };
+        if res != 0 {
+            return Err(EFAULT);
+        }
+        // Since this is not a pointer to a valid object in our program,
+        // we cannot use `add`, which has C-style rules for defined
+        // behavior.
+        self.0 = self.0.wrapping_add(len);
+        self.1 -= len;
+        Ok(())
+    }
+}
+
+/// A writer for [`UserSlicePtr`].
+///
+/// Used to incrementally write into the user slice.
+pub struct UserSlicePtrWriter(*mut core::ffi::c_void, usize);
+
+impl IoBufferWriter for UserSlicePtrWriter {
+    fn len(&self) -> usize {
+        self.1
+    }
+
+    fn clear(&mut self, mut len: usize) -> Result {
+        let mut ret = Ok(());
+        if len > self.1 {
+            ret = Err(EFAULT);
+            len = self.1;
+        }
+
+        // SAFETY: The buffer will be validated by `clear_user`. We ensure that `len` is within
+        // bounds in the check above.
+        let left = unsafe { bindings::clear_user(self.0, len as _) } as usize;
+        if left != 0 {
+            ret = Err(EFAULT);
+            len -= left;
+        }
+
+        self.0 = self.0.wrapping_add(len);
+        self.1 -= len;
+        ret
+    }
+
+    unsafe fn write_raw(&mut self, data: *const u8, len: usize) -> Result {
+        if len > self.1 || len > u32::MAX as usize {
+            return Err(EFAULT);
+        }
+        let res = unsafe { bindings::copy_to_user(self.0, data as _, len as _) };
+        if res != 0 {
+            return Err(EFAULT);
+        }
+        // Since this is not a pointer to a valid object in our program,
+        // we cannot use `add`, which has C-style rules for defined
+        // behavior.
+        self.0 = self.0.wrapping_add(len);
+        self.1 -= len;
+        Ok(())
+    }
+}
diff --git a/rust/kernel/workqueue.rs b/rust/kernel/workqueue.rs
new file mode 100644
index 000000000000..c6b89f137469
--- /dev/null
+++ b/rust/kernel/workqueue.rs
@@ -0,0 +1,512 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Work queues.
+//!
+//! C header: [`include/linux/workqueue.h`](../../../../include/linux/workqueue.h)
+
+use crate::{
+    bindings, c_str,
+    error::code::*,
+    sync::{LockClassKey, Ref, UniqueRef},
+    Opaque, Result,
+};
+use core::{fmt, ops::Deref, ptr::NonNull};
+
+/// Spawns a new work item to run in the work queue.
+///
+/// It also automatically defines a new lockdep lock class for the work item.
+#[macro_export]
+macro_rules! spawn_work_item {
+    ($queue:expr, $func:expr) => {{
+        static CLASS: $crate::sync::LockClassKey = $crate::sync::LockClassKey::new();
+        $crate::workqueue::Queue::try_spawn($queue, &CLASS, $func)
+    }};
+}
+
+/// Implements the [`WorkAdapter`] trait for a type where its [`Work`] instance is a field.
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::workqueue::Work;
+///
+/// struct Example {
+///     work: Work,
+/// }
+///
+/// kernel::impl_self_work_adapter!(Example, work, |_| {});
+/// ```
+#[macro_export]
+macro_rules! impl_self_work_adapter {
+    ($work_type:ty, $field:ident, $closure:expr) => {
+        $crate::impl_work_adapter!($work_type, $work_type, $field, $closure);
+    };
+}
+
+/// Implements the [`WorkAdapter`] trait for an adapter type.
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::workqueue::Work;
+///
+/// struct Example {
+///     work: Work,
+/// }
+///
+/// struct Adapter;
+///
+/// kernel::impl_work_adapter!(Adapter, Example, work, |_| {});
+/// ```
+#[macro_export]
+macro_rules! impl_work_adapter {
+    ($adapter:ty, $work_type:ty, $field:ident, $closure:expr) => {
+        // SAFETY: We use `offset_of` to ensure that the field is within the given type, and we
+        // also check its type is `Work`.
+        unsafe impl $crate::workqueue::WorkAdapter for $adapter {
+            type Target = $work_type;
+            const FIELD_OFFSET: isize = $crate::offset_of!(Self::Target, $field);
+            fn run(w: $crate::sync::Ref<Self::Target>) {
+                let closure: fn($crate::sync::Ref<Self::Target>) = $closure;
+                closure(w);
+                return;
+
+                // Checks that the type of the field is actually `Work`.
+                let tmp = core::mem::MaybeUninit::<$work_type>::uninit();
+                // SAFETY: The pointer is valid and aligned, just not initialised; `addr_of`
+                // ensures that we don't actually read from it (which would be UB) nor create an
+                // intermediate reference.
+                let _x: *const $crate::workqueue::Work =
+                    unsafe { core::ptr::addr_of!((*tmp.as_ptr()).$field) };
+            }
+        }
+    };
+}
+
+/// Initialises a work item.
+///
+/// It automatically defines a new lockdep lock class for the work item.
+#[macro_export]
+macro_rules! init_work_item {
+    ($work_container:expr) => {{
+        static CLASS: $crate::sync::LockClassKey = $crate::sync::LockClassKey::new();
+        $crate::workqueue::Work::init($work_container, &CLASS)
+    }};
+}
+
+/// Initialises a work item with the given adapter.
+///
+/// It automatically defines a new lockdep lock class for the work item.
+#[macro_export]
+macro_rules! init_work_item_adapter {
+    ($adapter:ty, $work_container:expr) => {{
+        static CLASS: $crate::sync::LockClassKey = $crate::sync::LockClassKey::new();
+        $crate::workqueue::Work::init_with_adapter::<$adapter>($work_container, &CLASS)
+    }};
+}
+
+/// A kernel work queue.
+///
+/// Wraps the kernel's C `struct workqueue_struct`.
+///
+/// It allows work items to be queued to run on thread pools managed by the kernel. Several are
+/// always available, for example, the ones returned by [`system`], [`system_highpri`],
+/// [`system_long`], etc.
+///
+/// # Examples
+///
+/// The following example is the simplest way to launch a work item:
+///
+/// ```
+/// # use kernel::{spawn_work_item, workqueue};
+///
+/// # fn example() -> Result {
+/// spawn_work_item!(workqueue::system(), || pr_info!("Hello from a work item\n"))?;
+/// #     Ok(())
+/// # }
+///
+/// # example().unwrap()
+/// ```
+///
+/// The following example is used to create a work item and enqueue it several times. We note that
+/// enqueuing while the work item is already queued is a no-op, so we enqueue it when it is not
+/// enqueued yet.
+///
+/// ```
+/// # use kernel::workqueue::{self, Work};
+/// use core::sync::atomic::{AtomicU32, Ordering};
+/// use kernel::sync::UniqueRef;
+///
+/// struct Example {
+///     count: AtomicU32,
+///     work: Work,
+/// }
+///
+/// kernel::impl_self_work_adapter!(Example, work, |w| {
+///     let count = w.count.fetch_add(1, Ordering::Relaxed);
+///     pr_info!("Called with count={}\n", count);
+///
+///     // Queue again if the count is less than 10.
+///     if count < 10 {
+///         workqueue::system().enqueue(w);
+///     }
+/// });
+///
+/// # fn example() -> Result {
+/// let e = UniqueRef::try_new(Example {
+///     count: AtomicU32::new(0),
+///     // SAFETY: `work` is initialised below.
+///     work: unsafe { Work::new() },
+/// })?;
+///
+/// kernel::init_work_item!(&e);
+///
+/// // Queue the first time.
+/// workqueue::system().enqueue(e.into());
+/// #     Ok(())
+/// # }
+///
+/// # example().unwrap()
+/// ```
+///
+/// The following example has two different work items in the same struct, which allows it to be
+/// queued twice.
+///
+/// ```
+/// # use kernel::workqueue::{self, Work, WorkAdapter};
+/// use core::sync::atomic::{AtomicU32, Ordering};
+/// use kernel::sync::{Ref, UniqueRef};
+///
+/// struct Example {
+///     work1: Work,
+///     work2: Work,
+/// }
+///
+/// kernel::impl_self_work_adapter!(Example, work1, |_| pr_info!("First work\n"));
+///
+/// struct SecondAdapter;
+/// kernel::impl_work_adapter!(SecondAdapter, Example, work2, |_| pr_info!("Second work\n"));
+///
+/// # fn example() -> Result {
+/// let e = UniqueRef::try_new(Example {
+///     // SAFETY: `work1` is initialised below.
+///     work1: unsafe { Work::new() },
+///     // SAFETY: `work2` is initialised below.
+///     work2: unsafe { Work::new() },
+/// })?;
+///
+/// kernel::init_work_item!(&e);
+/// kernel::init_work_item_adapter!(SecondAdapter, &e);
+///
+/// let e = Ref::from(e);
+///
+/// // Enqueue the two different work items.
+/// workqueue::system().enqueue(e.clone());
+/// workqueue::system().enqueue_adapter::<SecondAdapter>(e);
+/// #     Ok(())
+/// # }
+///
+/// # example().unwrap()
+/// ```
+#[repr(transparent)]
+pub struct Queue(Opaque<bindings::workqueue_struct>);
+
+// SAFETY: Kernel workqueues are usable from any thread.
+unsafe impl Sync for Queue {}
+
+impl Queue {
+    /// Tries to allocate a new work queue.
+    ///
+    /// Callers should first consider using one of the existing ones (e.g. [`system`]) before
+    /// deciding to create a new one.
+    pub fn try_new(name: fmt::Arguments<'_>) -> Result<BoxedQueue> {
+        // SAFETY: We use a format string that requires an `fmt::Arguments` pointer as the first
+        // and only argument.
+        let ptr = unsafe {
+            bindings::alloc_workqueue(
+                c_str!("%pA").as_char_ptr(),
+                0,
+                0,
+                &name as *const _ as *const core::ffi::c_void,
+            )
+        };
+        if ptr.is_null() {
+            return Err(ENOMEM);
+        }
+
+        // SAFETY: `ptr` was just allocated and checked above, so it non-null and valid. Plus, it
+        // isn't touched after the call below, so ownership is transferred.
+        Ok(unsafe { BoxedQueue::new(ptr) })
+    }
+
+    /// Enqueues a work item.
+    ///
+    /// Returns `true` if the work item was successfully enqueue; returns `false` if it had already
+    /// been (and continued to be) enqueued.
+    pub fn enqueue<T: WorkAdapter<Target = T>>(&self, w: Ref<T>) -> bool {
+        self.enqueue_adapter::<T>(w)
+    }
+
+    /// Enqueues a work item with an explicit adapter.
+    ///
+    /// Returns `true` if the work item was successfully enqueue; returns `false` if it had already
+    /// been (and continued to be) enqueued.
+    pub fn enqueue_adapter<A: WorkAdapter + ?Sized>(&self, w: Ref<A::Target>) -> bool {
+        let ptr = Ref::into_raw(w);
+        let field_ptr =
+            (ptr as *const u8).wrapping_offset(A::FIELD_OFFSET) as *mut bindings::work_struct;
+
+        // SAFETY: Having a shared reference to work queue guarantees that it remains valid, while
+        // the work item remains valid because we called `into_raw` and only call `from_raw` again
+        // if the object was already queued (so a previous call already guarantees it remains
+        // alive), when the work item runs, or when the work item is canceled.
+        let ret = unsafe {
+            bindings::queue_work_on(bindings::WORK_CPU_UNBOUND as _, self.0.get(), field_ptr)
+        };
+
+        if !ret {
+            // SAFETY: `ptr` comes from a previous call to `into_raw`. Additionally, given that
+            // `queue_work_on` returned `false`, we know that no-one is going to use the result of
+            // `into_raw`, so we must drop it here to avoid a reference leak.
+            unsafe { Ref::from_raw(ptr) };
+        }
+
+        ret
+    }
+
+    /// Tries to spawn the given function or closure as a work item.
+    ///
+    /// Users are encouraged to use [`spawn_work_item`] as it automatically defines the lock class
+    /// key to be used.
+    pub fn try_spawn<T: 'static + Send + Fn()>(
+        &self,
+        key: &'static LockClassKey,
+        func: T,
+    ) -> Result {
+        let w = UniqueRef::<ClosureAdapter<T>>::try_new(ClosureAdapter {
+            // SAFETY: `work` is initialised below.
+            work: unsafe { Work::new() },
+            func,
+        })?;
+        Work::init(&w, key);
+        self.enqueue(w.into());
+        Ok(())
+    }
+}
+
+struct ClosureAdapter<T: Fn() + Send> {
+    work: Work,
+    func: T,
+}
+
+// SAFETY: `ClosureAdapter::work` is of type `Work`.
+unsafe impl<T: Fn() + Send> WorkAdapter for ClosureAdapter<T> {
+    type Target = Self;
+    const FIELD_OFFSET: isize = crate::offset_of!(Self, work);
+
+    fn run(w: Ref<Self::Target>) {
+        (w.func)();
+    }
+}
+
+/// An adapter for work items.
+///
+/// For the most usual case where a type has a [`Work`] in it and is itself the adapter, it is
+/// recommended that they use the [`impl_self_work_adapter`] or [`impl_work_adapter`] macros
+/// instead of implementing the [`WorkAdapter`] manually. The great advantage is that they don't
+/// require any unsafe blocks.
+///
+/// # Safety
+///
+/// Implementers must ensure that there is a [`Work`] instance `FIELD_OFFSET` bytes from the
+/// beginning of a valid `Target` type. It is normally safe to use the [`crate::offset_of`] macro
+/// for this.
+pub unsafe trait WorkAdapter {
+    /// The type that this work adapter is meant to use.
+    type Target;
+
+    /// The offset, in bytes, from the beginning of [`Self::Target`] to the instance of [`Work`].
+    const FIELD_OFFSET: isize;
+
+    /// Runs when the work item is picked up for execution after it has been enqueued to some work
+    /// queue.
+    fn run(w: Ref<Self::Target>);
+}
+
+/// A work item.
+///
+/// Wraps the kernel's C `struct work_struct`.
+///
+/// Users must add a field of this type to a structure, then implement [`WorkAdapter`] so that it
+/// can be queued for execution in a thread pool. Examples of it being used are available in the
+/// documentation for [`Queue`].
+#[repr(transparent)]
+pub struct Work(Opaque<bindings::work_struct>);
+
+impl Work {
+    /// Creates a new instance of [`Work`].
+    ///
+    /// # Safety
+    ///
+    /// Callers must call either [`Work::init`] or [`Work::init_with_adapter`] before the work item
+    /// can be used.
+    pub unsafe fn new() -> Self {
+        Self(Opaque::uninit())
+    }
+
+    /// Initialises the work item.
+    ///
+    /// Users should prefer the [`init_work_item`] macro because it automatically defines a new
+    /// lock class key.
+    pub fn init<T: WorkAdapter<Target = T>>(obj: &UniqueRef<T>, key: &'static LockClassKey) {
+        Self::init_with_adapter::<T>(obj, key)
+    }
+
+    /// Initialises the work item with the given adapter.
+    ///
+    /// Users should prefer the [`init_work_item_adapter`] macro because it automatically defines a
+    /// new lock class key.
+    pub fn init_with_adapter<A: WorkAdapter>(
+        obj: &UniqueRef<A::Target>,
+        key: &'static LockClassKey,
+    ) {
+        let ptr = &**obj as *const _ as *const u8;
+        let field_ptr = ptr.wrapping_offset(A::FIELD_OFFSET) as *mut bindings::work_struct;
+
+        // SAFETY: `work` is valid for writes -- the `UniqueRef` instance guarantees that it has
+        // been allocated and there is only one pointer to it. Additionally, `work_func` is a valid
+        // callback for the work item.
+        unsafe {
+            bindings::__INIT_WORK_WITH_KEY(field_ptr, Some(Self::work_func::<A>), false, key.get())
+        };
+    }
+
+    /// Cancels the work item.
+    ///
+    /// It is ok for this to be called when the work is not queued.
+    pub fn cancel(&self) {
+        // SAFETY: The work is valid (we have a reference to it), and the function can be called
+        // whether the work is queued or not.
+        if unsafe { bindings::cancel_work_sync(self.0.get()) } {
+            // SAFETY: When the work was queued, a call to `into_raw` was made. We just canceled
+            // the work without it having the chance to run, so we need to explicitly destroy this
+            // reference (which would have happened in `work_func` if it did run).
+            unsafe { Ref::from_raw(&*self) };
+        }
+    }
+
+    unsafe extern "C" fn work_func<A: WorkAdapter>(work: *mut bindings::work_struct) {
+        let field_ptr = work as *const _ as *const u8;
+        let ptr = field_ptr.wrapping_offset(-A::FIELD_OFFSET) as *const A::Target;
+
+        // SAFETY: This callback is only ever used by the `init_with_adapter` method, so it is
+        // always the case that the work item is embedded in a `Work` (Self) struct.
+        let w = unsafe { Ref::from_raw(ptr) };
+        A::run(w);
+    }
+}
+
+/// A boxed owned workqueue.
+///
+/// # Invariants
+///
+/// `ptr` is owned by this instance of [`BoxedQueue`], so it's always valid.
+pub struct BoxedQueue {
+    ptr: NonNull<Queue>,
+}
+
+impl BoxedQueue {
+    /// Creates a new instance of [`BoxedQueue`].
+    ///
+    /// # Safety
+    ///
+    /// `ptr` must be non-null and valid. Additionally, ownership must be handed over to new
+    /// instance of [`BoxedQueue`].
+    unsafe fn new(ptr: *mut bindings::workqueue_struct) -> Self {
+        Self {
+            // SAFETY: We checked above that `ptr` is non-null.
+            ptr: unsafe { NonNull::new_unchecked(ptr.cast()) },
+        }
+    }
+}
+
+impl Deref for BoxedQueue {
+    type Target = Queue;
+
+    fn deref(&self) -> &Queue {
+        // SAFETY: The type invariants guarantee that `ptr` is always valid.
+        unsafe { self.ptr.as_ref() }
+    }
+}
+
+impl Drop for BoxedQueue {
+    fn drop(&mut self) {
+        // SAFETY: The type invariants guarantee that `ptr` is always valid.
+        unsafe { bindings::destroy_workqueue(self.ptr.as_ref().0.get()) };
+    }
+}
+
+/// Returns the system work queue (`system_wq`).
+///
+/// It is the one used by schedule\[_delayed\]_work\[_on\](). Multi-CPU multi-threaded. There are
+/// users which expect relatively short queue flush time.
+///
+/// Callers shouldn't queue work items which can run for too long.
+pub fn system() -> &'static Queue {
+    // SAFETY: `system_wq` is a C global, always available.
+    unsafe { &*bindings::system_wq.cast() }
+}
+
+/// Returns the system high-priority work queue (`system_highpri_wq`).
+///
+/// It is similar to the one returned by [`system`] but for work items which require higher
+/// scheduling priority.
+pub fn system_highpri() -> &'static Queue {
+    // SAFETY: `system_highpri_wq` is a C global, always available.
+    unsafe { &*bindings::system_highpri_wq.cast() }
+}
+
+/// Returns the system work queue for potentially long-running work items (`system_long_wq`).
+///
+/// It is similar to the one returned by [`system`] but may host long running work items. Queue
+/// flushing might take relatively long.
+pub fn system_long() -> &'static Queue {
+    // SAFETY: `system_long_wq` is a C global, always available.
+    unsafe { &*bindings::system_long_wq.cast() }
+}
+
+/// Returns the system unbound work queue (`system_unbound_wq`).
+///
+/// Workers are not bound to any specific CPU, not concurrency managed, and all queued work items
+/// are executed immediately as long as `max_active` limit is not reached and resources are
+/// available.
+pub fn system_unbound() -> &'static Queue {
+    // SAFETY: `system_unbound_wq` is a C global, always available.
+    unsafe { &*bindings::system_unbound_wq.cast() }
+}
+
+/// Returns the system freezable work queue (`system_freezable_wq`).
+///
+/// It is equivalent to the one returned by [`system`] except that it's freezable.
+pub fn system_freezable() -> &'static Queue {
+    // SAFETY: `system_freezable_wq` is a C global, always available.
+    unsafe { &*bindings::system_freezable_wq.cast() }
+}
+
+/// Returns the system power-efficient work queue (`system_power_efficient_wq`).
+///
+/// It is inclined towards saving power and is converted to "unbound" variants if the
+/// `workqueue.power_efficient` kernel parameter is specified; otherwise, it is similar to the one
+/// returned by [`system`].
+pub fn system_power_efficient() -> &'static Queue {
+    // SAFETY: `system_power_efficient_wq` is a C global, always available.
+    unsafe { &*bindings::system_power_efficient_wq.cast() }
+}
+
+/// Returns the system freezable power-efficient work queue (`system_freezable_power_efficient_wq`).
+///
+/// It is similar to the one returned by [`system_power_efficient`] except that is freezable.
+pub fn system_freezable_power_efficient() -> &'static Queue {
+    // SAFETY: `system_freezable_power_efficient_wq` is a C global, always available.
+    unsafe { &*bindings::system_freezable_power_efficient_wq.cast() }
+}
-- 
2.37.1


^ permalink raw reply related	[relevance 1%]

* [PATCH v8 28/31] samples: add Rust examples
    2022-08-02  1:50  1% ` [PATCH v8 17/31] rust: add `kernel` crate Miguel Ojeda
@ 2022-08-02  1:50  3% ` Miguel Ojeda
  1 sibling, 0 replies; 77+ results
From: Miguel Ojeda @ 2022-08-02  1:50 UTC (permalink / raw)
  To: Linus Torvalds, Greg Kroah-Hartman
  Cc: rust-for-linux, linux-kernel, Jarkko Sakkinen, Miguel Ojeda,
	Alex Gaynor, Finn Behrens, Wedson Almeida Filho,
	Sven Van Asbroeck, Gary Guo, Boris-Chengbiao Zhou, Boqun Feng,
	Ayaan Zaidi, Daniel Xu, Milan Landaverde

A set of Rust modules that showcase how Rust modules look like
and how to use the abstracted kernel features, as well as
an example of a Rust host program with several modules.

These samples also double as tests in the CI.

The semaphore sample comes with a C version for comparison.

Co-developed-by: Alex Gaynor <alex.gaynor@gmail.com>
Signed-off-by: Alex Gaynor <alex.gaynor@gmail.com>
Co-developed-by: Finn Behrens <me@kloenk.de>
Signed-off-by: Finn Behrens <me@kloenk.de>
Co-developed-by: Wedson Almeida Filho <wedsonaf@google.com>
Signed-off-by: Wedson Almeida Filho <wedsonaf@google.com>
Co-developed-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Co-developed-by: Sven Van Asbroeck <thesven73@gmail.com>
Signed-off-by: Sven Van Asbroeck <thesven73@gmail.com>
Co-developed-by: Gary Guo <gary@garyguo.net>
Signed-off-by: Gary Guo <gary@garyguo.net>
Co-developed-by: Boris-Chengbiao Zhou <bobo1239@web.de>
Signed-off-by: Boris-Chengbiao Zhou <bobo1239@web.de>
Co-developed-by: Boqun Feng <boqun.feng@gmail.com>
Signed-off-by: Boqun Feng <boqun.feng@gmail.com>
Co-developed-by: Ayaan Zaidi <zaidi.ayaan@gmail.com>
Signed-off-by: Ayaan Zaidi <zaidi.ayaan@gmail.com>
Co-developed-by: Daniel Xu <dxu@dxuuu.xyz>
Signed-off-by: Daniel Xu <dxu@dxuuu.xyz>
Co-developed-by: Milan Landaverde <milan@mdaverde.com>
Signed-off-by: Milan Landaverde <milan@mdaverde.com>
Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
---
 samples/Kconfig                        |   2 +
 samples/Makefile                       |   1 +
 samples/rust/Kconfig                   | 165 +++++++++++++++++++
 samples/rust/Makefile                  |  19 +++
 samples/rust/hostprogs/.gitignore      |   3 +
 samples/rust/hostprogs/Makefile        |   5 +
 samples/rust/hostprogs/a.rs            |   7 +
 samples/rust/hostprogs/b.rs            |   5 +
 samples/rust/hostprogs/single.rs       |  12 ++
 samples/rust/rust_chrdev.rs            |  49 ++++++
 samples/rust/rust_echo_server.rs       |  60 +++++++
 samples/rust/rust_fs.rs                |  59 +++++++
 samples/rust/rust_minimal.rs           |  35 ++++
 samples/rust/rust_miscdev.rs           | 142 +++++++++++++++++
 samples/rust/rust_module_parameters.rs |  69 ++++++++
 samples/rust/rust_netfilter.rs         |  54 +++++++
 samples/rust/rust_platform.rs          |  22 +++
 samples/rust/rust_print.rs             |  54 +++++++
 samples/rust/rust_random.rs            |  60 +++++++
 samples/rust/rust_selftests.rs         |  99 ++++++++++++
 samples/rust/rust_semaphore.rs         | 170 ++++++++++++++++++++
 samples/rust/rust_semaphore_c.c        | 212 +++++++++++++++++++++++++
 samples/rust/rust_stack_probing.rs     |  36 +++++
 samples/rust/rust_sync.rs              |  93 +++++++++++
 24 files changed, 1433 insertions(+)
 create mode 100644 samples/rust/Kconfig
 create mode 100644 samples/rust/Makefile
 create mode 100644 samples/rust/hostprogs/.gitignore
 create mode 100644 samples/rust/hostprogs/Makefile
 create mode 100644 samples/rust/hostprogs/a.rs
 create mode 100644 samples/rust/hostprogs/b.rs
 create mode 100644 samples/rust/hostprogs/single.rs
 create mode 100644 samples/rust/rust_chrdev.rs
 create mode 100644 samples/rust/rust_echo_server.rs
 create mode 100644 samples/rust/rust_fs.rs
 create mode 100644 samples/rust/rust_minimal.rs
 create mode 100644 samples/rust/rust_miscdev.rs
 create mode 100644 samples/rust/rust_module_parameters.rs
 create mode 100644 samples/rust/rust_netfilter.rs
 create mode 100644 samples/rust/rust_platform.rs
 create mode 100644 samples/rust/rust_print.rs
 create mode 100644 samples/rust/rust_random.rs
 create mode 100644 samples/rust/rust_selftests.rs
 create mode 100644 samples/rust/rust_semaphore.rs
 create mode 100644 samples/rust/rust_semaphore_c.c
 create mode 100644 samples/rust/rust_stack_probing.rs
 create mode 100644 samples/rust/rust_sync.rs

diff --git a/samples/Kconfig b/samples/Kconfig
index 470ee3baf2e1..0d81c00289ee 100644
--- a/samples/Kconfig
+++ b/samples/Kconfig
@@ -263,6 +263,8 @@ config SAMPLE_CORESIGHT_SYSCFG
 	  This demonstrates how a user may create their own CoreSight
 	  configurations and easily load them into the system at runtime.
 
+source "samples/rust/Kconfig"
+
 endif # SAMPLES
 
 config HAVE_SAMPLE_FTRACE_DIRECT
diff --git a/samples/Makefile b/samples/Makefile
index 701e912ab5af..9832ef3f8fcb 100644
--- a/samples/Makefile
+++ b/samples/Makefile
@@ -35,3 +35,4 @@ subdir-$(CONFIG_SAMPLE_WATCH_QUEUE)	+= watch_queue
 obj-$(CONFIG_DEBUG_KMEMLEAK_TEST)	+= kmemleak/
 obj-$(CONFIG_SAMPLE_CORESIGHT_SYSCFG)	+= coresight/
 obj-$(CONFIG_SAMPLE_FPROBE)		+= fprobe/
+obj-$(CONFIG_SAMPLES_RUST)		+= rust/
diff --git a/samples/rust/Kconfig b/samples/rust/Kconfig
new file mode 100644
index 000000000000..861b35318b4d
--- /dev/null
+++ b/samples/rust/Kconfig
@@ -0,0 +1,165 @@
+# SPDX-License-Identifier: GPL-2.0
+
+menuconfig SAMPLES_RUST
+	bool "Rust samples"
+	depends on RUST
+	help
+	  You can build sample Rust kernel code here.
+
+	  If unsure, say N.
+
+if SAMPLES_RUST
+
+config SAMPLE_RUST_MINIMAL
+	tristate "Minimal"
+	help
+	  This option builds the Rust minimal module sample.
+
+	  To compile this as a module, choose M here:
+	  the module will be called rust_minimal.
+
+	  If unsure, say N.
+
+config SAMPLE_RUST_PRINT
+	tristate "Printing macros"
+	help
+	  This option builds the Rust printing macros sample.
+
+	  To compile this as a module, choose M here:
+	  the module will be called rust_print.
+
+	  If unsure, say N.
+
+config SAMPLE_RUST_MODULE_PARAMETERS
+	tristate "Module parameters"
+	help
+	  This option builds the Rust module parameters sample.
+
+	  To compile this as a module, choose M here:
+	  the module will be called rust_module_parameters.
+
+	  If unsure, say N.
+
+config SAMPLE_RUST_SYNC
+	tristate "Synchronisation primitives"
+	help
+	  This option builds the Rust synchronisation primitives sample.
+
+	  To compile this as a module, choose M here:
+	  the module will be called rust_sync.
+
+	  If unsure, say N.
+
+config SAMPLE_RUST_CHRDEV
+	tristate "Character device"
+	help
+	  This option builds the Rust character device sample.
+
+	  To compile this as a module, choose M here:
+	  the module will be called rust_chrdev.
+
+	  If unsure, say N.
+
+config SAMPLE_RUST_MISCDEV
+	tristate "Miscellaneous device"
+	help
+	  This option builds the Rust miscellaneous device sample.
+
+	  To compile this as a module, choose M here:
+	  the module will be called rust_miscdev.
+
+	  If unsure, say N.
+
+config SAMPLE_RUST_STACK_PROBING
+	tristate "Stack probing"
+	help
+	  This option builds the Rust stack probing sample.
+
+	  To compile this as a module, choose M here:
+	  the module will be called rust_stack_probing.
+
+	  If unsure, say N.
+
+config SAMPLE_RUST_SEMAPHORE
+	tristate "Semaphore"
+	help
+	  This option builds the Rust semaphore sample.
+
+	  To compile this as a module, choose M here:
+	  the module will be called rust_semaphore.
+
+	  If unsure, say N.
+
+config SAMPLE_RUST_SEMAPHORE_C
+	tristate "Semaphore (in C, for comparison)"
+	help
+	  This option builds the Rust semaphore sample (in C, for comparison).
+
+	  To compile this as a module, choose M here:
+	  the module will be called rust_semaphore_c.
+
+	  If unsure, say N.
+
+config SAMPLE_RUST_RANDOM
+	tristate "Random"
+	help
+	  This option builds the Rust random sample.
+
+	  To compile this as a module, choose M here:
+	  the module will be called rust_random.
+
+	  If unsure, say N.
+
+config SAMPLE_RUST_PLATFORM
+	tristate "Platform device driver"
+	help
+	  This option builds the Rust platform device driver sample.
+
+	  To compile this as a module, choose M here:
+	  the module will be called rust_platform.
+
+config SAMPLE_RUST_FS
+	tristate "File system"
+	help
+	  This option builds the Rust file system sample.
+
+	  To compile this as a module, choose M here:
+	  the module will be called rust_fs.
+
+	  If unsure, say N.
+
+config SAMPLE_RUST_NETFILTER
+	tristate "Network filter module"
+	help
+	  This option builds the Rust netfilter module sample.
+
+	  To compile this as a module, choose M here:
+	  the module will be called rust_netfilter.
+
+	  If unsure, say N.
+
+config SAMPLE_RUST_ECHO_SERVER
+	tristate "Echo server module"
+	help
+	  This option builds the Rust echo server  module sample.
+
+	  To compile this as a module, choose M here:
+	  the module will be called rust_echo_server.
+
+	  If unsure, say N.
+
+config SAMPLE_RUST_HOSTPROGS
+	bool "Host programs"
+	help
+	  This option builds the Rust host program samples.
+
+	  If unsure, say N.
+
+config SAMPLE_RUST_SELFTESTS
+	tristate "Self tests"
+	help
+	  This option builds the self test cases for Rust.
+
+	  If unsure, say N.
+
+endif # SAMPLES_RUST
diff --git a/samples/rust/Makefile b/samples/rust/Makefile
new file mode 100644
index 000000000000..420bcefeb082
--- /dev/null
+++ b/samples/rust/Makefile
@@ -0,0 +1,19 @@
+# SPDX-License-Identifier: GPL-2.0
+
+obj-$(CONFIG_SAMPLE_RUST_MINIMAL)		+= rust_minimal.o
+obj-$(CONFIG_SAMPLE_RUST_PRINT)			+= rust_print.o
+obj-$(CONFIG_SAMPLE_RUST_MODULE_PARAMETERS)	+= rust_module_parameters.o
+obj-$(CONFIG_SAMPLE_RUST_SYNC)			+= rust_sync.o
+obj-$(CONFIG_SAMPLE_RUST_CHRDEV)		+= rust_chrdev.o
+obj-$(CONFIG_SAMPLE_RUST_MISCDEV)		+= rust_miscdev.o
+obj-$(CONFIG_SAMPLE_RUST_STACK_PROBING)		+= rust_stack_probing.o
+obj-$(CONFIG_SAMPLE_RUST_SEMAPHORE)		+= rust_semaphore.o
+obj-$(CONFIG_SAMPLE_RUST_SEMAPHORE_C)		+= rust_semaphore_c.o
+obj-$(CONFIG_SAMPLE_RUST_RANDOM)		+= rust_random.o
+obj-$(CONFIG_SAMPLE_RUST_PLATFORM)		+= rust_platform.o
+obj-$(CONFIG_SAMPLE_RUST_NETFILTER)		+= rust_netfilter.o
+obj-$(CONFIG_SAMPLE_RUST_ECHO_SERVER)		+= rust_echo_server.o
+obj-$(CONFIG_SAMPLE_RUST_FS)			+= rust_fs.o
+obj-$(CONFIG_SAMPLE_RUST_SELFTESTS)		+= rust_selftests.o
+
+subdir-$(CONFIG_SAMPLE_RUST_HOSTPROGS)		+= hostprogs
diff --git a/samples/rust/hostprogs/.gitignore b/samples/rust/hostprogs/.gitignore
new file mode 100644
index 000000000000..a6c173da5048
--- /dev/null
+++ b/samples/rust/hostprogs/.gitignore
@@ -0,0 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0
+
+single
diff --git a/samples/rust/hostprogs/Makefile b/samples/rust/hostprogs/Makefile
new file mode 100644
index 000000000000..8ddcbd7416db
--- /dev/null
+++ b/samples/rust/hostprogs/Makefile
@@ -0,0 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0
+
+hostprogs-always-y := single
+
+single-rust := y
diff --git a/samples/rust/hostprogs/a.rs b/samples/rust/hostprogs/a.rs
new file mode 100644
index 000000000000..f7a4a3d0f4e0
--- /dev/null
+++ b/samples/rust/hostprogs/a.rs
@@ -0,0 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Rust single host program sample: module `a`.
+
+pub(crate) fn f(x: i32) {
+    println!("The number is {}.", x);
+}
diff --git a/samples/rust/hostprogs/b.rs b/samples/rust/hostprogs/b.rs
new file mode 100644
index 000000000000..c1675890648f
--- /dev/null
+++ b/samples/rust/hostprogs/b.rs
@@ -0,0 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Rust single host program sample: module `b`.
+
+pub(crate) const CONSTANT: i32 = 42;
diff --git a/samples/rust/hostprogs/single.rs b/samples/rust/hostprogs/single.rs
new file mode 100644
index 000000000000..8c48a119339a
--- /dev/null
+++ b/samples/rust/hostprogs/single.rs
@@ -0,0 +1,12 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Rust single host program sample.
+
+mod a;
+mod b;
+
+fn main() {
+    println!("Hello world!");
+
+    a::f(b::CONSTANT);
+}
diff --git a/samples/rust/rust_chrdev.rs b/samples/rust/rust_chrdev.rs
new file mode 100644
index 000000000000..52f6e652d1a6
--- /dev/null
+++ b/samples/rust/rust_chrdev.rs
@@ -0,0 +1,49 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Rust character device sample.
+
+use kernel::prelude::*;
+use kernel::{chrdev, file};
+
+module! {
+    type: RustChrdev,
+    name: b"rust_chrdev",
+    author: b"Rust for Linux Contributors",
+    description: b"Rust character device sample",
+    license: b"GPL",
+}
+
+struct RustFile;
+
+#[vtable]
+impl file::Operations for RustFile {
+    fn open(_shared: &(), _file: &file::File) -> Result {
+        Ok(())
+    }
+}
+
+struct RustChrdev {
+    _dev: Pin<Box<chrdev::Registration<2>>>,
+}
+
+impl kernel::Module for RustChrdev {
+    fn init(name: &'static CStr, module: &'static ThisModule) -> Result<Self> {
+        pr_info!("Rust character device sample (init)\n");
+
+        let mut chrdev_reg = chrdev::Registration::new_pinned(name, 0, module)?;
+
+        // Register the same kind of device twice, we're just demonstrating
+        // that you can use multiple minors. There are two minors in this case
+        // because its type is `chrdev::Registration<2>`
+        chrdev_reg.as_mut().register::<RustFile>()?;
+        chrdev_reg.as_mut().register::<RustFile>()?;
+
+        Ok(RustChrdev { _dev: chrdev_reg })
+    }
+}
+
+impl Drop for RustChrdev {
+    fn drop(&mut self) {
+        pr_info!("Rust character device sample (exit)\n");
+    }
+}
diff --git a/samples/rust/rust_echo_server.rs b/samples/rust/rust_echo_server.rs
new file mode 100644
index 000000000000..5fc802f4dc33
--- /dev/null
+++ b/samples/rust/rust_echo_server.rs
@@ -0,0 +1,60 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Rust echo server sample.
+
+use kernel::{
+    kasync::executor::{workqueue::Executor as WqExecutor, AutoStopHandle, Executor},
+    kasync::net::{TcpListener, TcpStream},
+    net::{self, Ipv4Addr, SocketAddr, SocketAddrV4},
+    prelude::*,
+    spawn_task,
+    sync::{Ref, RefBorrow},
+};
+
+async fn echo_server(stream: TcpStream) -> Result {
+    let mut buf = [0u8; 1024];
+    loop {
+        let n = stream.read(&mut buf).await?;
+        if n == 0 {
+            return Ok(());
+        }
+        stream.write_all(&buf[..n]).await?;
+    }
+}
+
+async fn accept_loop(listener: TcpListener, executor: Ref<impl Executor>) {
+    loop {
+        if let Ok(stream) = listener.accept().await {
+            let _ = spawn_task!(executor.as_ref_borrow(), echo_server(stream));
+        }
+    }
+}
+
+fn start_listener(ex: RefBorrow<'_, impl Executor + Send + Sync + 'static>) -> Result {
+    let addr = SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::ANY, 8080));
+    let listener = TcpListener::try_new(net::init_ns(), &addr)?;
+    spawn_task!(ex, accept_loop(listener, ex.into()))?;
+    Ok(())
+}
+
+struct RustEchoServer {
+    _handle: AutoStopHandle<dyn Executor>,
+}
+
+impl kernel::Module for RustEchoServer {
+    fn init(_name: &'static CStr, _module: &'static ThisModule) -> Result<Self> {
+        let handle = WqExecutor::try_new(kernel::workqueue::system())?;
+        start_listener(handle.executor())?;
+        Ok(Self {
+            _handle: handle.into(),
+        })
+    }
+}
+
+module! {
+    type: RustEchoServer,
+    name: b"rust_echo_server",
+    author: b"Rust for Linux Contributors",
+    description: b"Rust tcp echo sample",
+    license: b"GPL v2",
+}
diff --git a/samples/rust/rust_fs.rs b/samples/rust/rust_fs.rs
new file mode 100644
index 000000000000..d286b396dd17
--- /dev/null
+++ b/samples/rust/rust_fs.rs
@@ -0,0 +1,59 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Rust file system sample.
+
+use kernel::prelude::*;
+use kernel::{c_str, fs};
+
+module_fs! {
+    type: RustFs,
+    name: b"rust_fs",
+    author: b"Rust for Linux Contributors",
+    license: b"GPL",
+}
+
+struct RustFs;
+
+#[vtable]
+impl fs::Context<Self> for RustFs {
+    type Data = ();
+
+    kernel::define_fs_params! {(),
+        {flag, "flag", |_, v| { pr_info!("flag passed-in: {v}\n"); Ok(()) } },
+        {flag_no, "flagno", |_, v| { pr_info!("flagno passed-in: {v}\n"); Ok(()) } },
+        {bool, "bool", |_, v| { pr_info!("bool passed-in: {v}\n"); Ok(()) } },
+        {u32, "u32", |_, v| { pr_info!("u32 passed-in: {v}\n"); Ok(()) } },
+        {u32oct, "u32oct", |_, v| { pr_info!("u32oct passed-in: {v}\n"); Ok(()) } },
+        {u32hex, "u32hex", |_, v| { pr_info!("u32hex passed-in: {v}\n"); Ok(()) } },
+        {s32, "s32", |_, v| { pr_info!("s32 passed-in: {v}\n"); Ok(()) } },
+        {u64, "u64", |_, v| { pr_info!("u64 passed-in: {v}\n"); Ok(()) } },
+        {string, "string", |_, v| { pr_info!("string passed-in: {v}\n"); Ok(()) } },
+        {enum, "enum", [("first", 10), ("second", 20)], |_, v| {
+            pr_info!("enum passed-in: {v}\n"); Ok(()) }
+        },
+    }
+
+    fn try_new() -> Result {
+        pr_info!("context created!\n");
+        Ok(())
+    }
+}
+
+impl fs::Type for RustFs {
+    type Context = Self;
+    const SUPER_TYPE: fs::Super = fs::Super::Independent;
+    const NAME: &'static CStr = c_str!("rustfs");
+    const FLAGS: i32 = fs::flags::USERNS_MOUNT;
+
+    fn fill_super(_data: (), sb: fs::NewSuperBlock<'_, Self>) -> Result<&fs::SuperBlock<Self>> {
+        let sb = sb.init(
+            (),
+            &fs::SuperParams {
+                magic: 0x72757374,
+                ..fs::SuperParams::DEFAULT
+            },
+        )?;
+        let sb = sb.init_root()?;
+        Ok(sb)
+    }
+}
diff --git a/samples/rust/rust_minimal.rs b/samples/rust/rust_minimal.rs
new file mode 100644
index 000000000000..6e1a926c6f62
--- /dev/null
+++ b/samples/rust/rust_minimal.rs
@@ -0,0 +1,35 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Rust minimal sample.
+
+use kernel::prelude::*;
+
+module! {
+    type: RustMinimal,
+    name: b"rust_minimal",
+    author: b"Rust for Linux Contributors",
+    description: b"Rust minimal sample",
+    license: b"GPL",
+}
+
+struct RustMinimal {
+    message: String,
+}
+
+impl kernel::Module for RustMinimal {
+    fn init(_name: &'static CStr, _module: &'static ThisModule) -> Result<Self> {
+        pr_info!("Rust minimal sample (init)\n");
+        pr_info!("Am I built-in? {}\n", !cfg!(MODULE));
+
+        Ok(RustMinimal {
+            message: "on the heap!".try_to_owned()?,
+        })
+    }
+}
+
+impl Drop for RustMinimal {
+    fn drop(&mut self) {
+        pr_info!("My message is {}\n", self.message);
+        pr_info!("Rust minimal sample (exit)\n");
+    }
+}
diff --git a/samples/rust/rust_miscdev.rs b/samples/rust/rust_miscdev.rs
new file mode 100644
index 000000000000..647b77864f10
--- /dev/null
+++ b/samples/rust/rust_miscdev.rs
@@ -0,0 +1,142 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Rust miscellaneous device sample.
+
+use kernel::prelude::*;
+use kernel::{
+    file::{self, File},
+    io_buffer::{IoBufferReader, IoBufferWriter},
+    miscdev,
+    sync::{CondVar, Mutex, Ref, RefBorrow, UniqueRef},
+};
+
+module! {
+    type: RustMiscdev,
+    name: b"rust_miscdev",
+    author: b"Rust for Linux Contributors",
+    description: b"Rust miscellaneous device sample",
+    license: b"GPL",
+}
+
+const MAX_TOKENS: usize = 3;
+
+struct SharedStateInner {
+    token_count: usize,
+}
+
+struct SharedState {
+    state_changed: CondVar,
+    inner: Mutex<SharedStateInner>,
+}
+
+impl SharedState {
+    fn try_new() -> Result<Ref<Self>> {
+        let mut state = Pin::from(UniqueRef::try_new(Self {
+            // SAFETY: `condvar_init!` is called below.
+            state_changed: unsafe { CondVar::new() },
+            // SAFETY: `mutex_init!` is called below.
+            inner: unsafe { Mutex::new(SharedStateInner { token_count: 0 }) },
+        })?);
+
+        // SAFETY: `state_changed` is pinned when `state` is.
+        let pinned = unsafe { state.as_mut().map_unchecked_mut(|s| &mut s.state_changed) };
+        kernel::condvar_init!(pinned, "SharedState::state_changed");
+
+        // SAFETY: `inner` is pinned when `state` is.
+        let pinned = unsafe { state.as_mut().map_unchecked_mut(|s| &mut s.inner) };
+        kernel::mutex_init!(pinned, "SharedState::inner");
+
+        Ok(state.into())
+    }
+}
+
+struct Token;
+#[vtable]
+impl file::Operations for Token {
+    type Data = Ref<SharedState>;
+    type OpenData = Ref<SharedState>;
+
+    fn open(shared: &Ref<SharedState>, _file: &File) -> Result<Self::Data> {
+        Ok(shared.clone())
+    }
+
+    fn read(
+        shared: RefBorrow<'_, SharedState>,
+        _: &File,
+        data: &mut impl IoBufferWriter,
+        offset: u64,
+    ) -> Result<usize> {
+        // Succeed if the caller doesn't provide a buffer or if not at the start.
+        if data.is_empty() || offset != 0 {
+            return Ok(0);
+        }
+
+        {
+            let mut inner = shared.inner.lock();
+
+            // Wait until we are allowed to decrement the token count or a signal arrives.
+            while inner.token_count == 0 {
+                if shared.state_changed.wait(&mut inner) {
+                    return Err(EINTR);
+                }
+            }
+
+            // Consume a token.
+            inner.token_count -= 1;
+        }
+
+        // Notify a possible writer waiting.
+        shared.state_changed.notify_all();
+
+        // Write a one-byte 1 to the reader.
+        data.write_slice(&[1u8; 1])?;
+        Ok(1)
+    }
+
+    fn write(
+        shared: RefBorrow<'_, SharedState>,
+        _: &File,
+        data: &mut impl IoBufferReader,
+        _offset: u64,
+    ) -> Result<usize> {
+        {
+            let mut inner = shared.inner.lock();
+
+            // Wait until we are allowed to increment the token count or a signal arrives.
+            while inner.token_count == MAX_TOKENS {
+                if shared.state_changed.wait(&mut inner) {
+                    return Err(EINTR);
+                }
+            }
+
+            // Increment the number of token so that a reader can be released.
+            inner.token_count += 1;
+        }
+
+        // Notify a possible reader waiting.
+        shared.state_changed.notify_all();
+        Ok(data.len())
+    }
+}
+
+struct RustMiscdev {
+    _dev: Pin<Box<miscdev::Registration<Token>>>,
+}
+
+impl kernel::Module for RustMiscdev {
+    fn init(name: &'static CStr, _module: &'static ThisModule) -> Result<Self> {
+        pr_info!("Rust miscellaneous device sample (init)\n");
+
+        let state = SharedState::try_new()?;
+
+        Ok(RustMiscdev {
+            _dev: miscdev::Registration::new_pinned(fmt!("{name}"), state)?,
+        })
+    }
+}
+
+impl Drop for RustMiscdev {
+    fn drop(&mut self) {
+        pr_info!("Rust miscellaneous device sample (exit)\n");
+    }
+}
diff --git a/samples/rust/rust_module_parameters.rs b/samples/rust/rust_module_parameters.rs
new file mode 100644
index 000000000000..12fe5e738e83
--- /dev/null
+++ b/samples/rust/rust_module_parameters.rs
@@ -0,0 +1,69 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Rust module parameters sample.
+
+use kernel::prelude::*;
+
+module! {
+    type: RustModuleParameters,
+    name: b"rust_module_parameters",
+    author: b"Rust for Linux Contributors",
+    description: b"Rust module parameters sample",
+    license: b"GPL",
+    params: {
+        my_bool: bool {
+            default: true,
+            permissions: 0,
+            description: b"Example of bool",
+        },
+        my_i32: i32 {
+            default: 42,
+            permissions: 0o644,
+            description: b"Example of i32",
+        },
+        my_str: str {
+            default: b"default str val",
+            permissions: 0o644,
+            description: b"Example of a string param",
+        },
+        my_usize: usize {
+            default: 42,
+            permissions: 0o644,
+            description: b"Example of usize",
+        },
+        my_array: ArrayParam<i32, 3> {
+            default: [0, 1],
+            permissions: 0,
+            description: b"Example of array",
+        },
+    },
+}
+
+struct RustModuleParameters;
+
+impl kernel::Module for RustModuleParameters {
+    fn init(_name: &'static CStr, module: &'static ThisModule) -> Result<Self> {
+        pr_info!("Rust module parameters sample (init)\n");
+
+        {
+            let lock = module.kernel_param_lock();
+            pr_info!("Parameters:\n");
+            pr_info!("  my_bool:    {}\n", my_bool.read());
+            pr_info!("  my_i32:     {}\n", my_i32.read(&lock));
+            pr_info!(
+                "  my_str:     {}\n",
+                core::str::from_utf8(my_str.read(&lock))?
+            );
+            pr_info!("  my_usize:   {}\n", my_usize.read(&lock));
+            pr_info!("  my_array:   {:?}\n", my_array.read());
+        }
+
+        Ok(RustModuleParameters)
+    }
+}
+
+impl Drop for RustModuleParameters {
+    fn drop(&mut self) {
+        pr_info!("Rust module parameters sample (exit)\n");
+    }
+}
diff --git a/samples/rust/rust_netfilter.rs b/samples/rust/rust_netfilter.rs
new file mode 100644
index 000000000000..4bd5c07fee8c
--- /dev/null
+++ b/samples/rust/rust_netfilter.rs
@@ -0,0 +1,54 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Rust netfilter sample.
+
+use kernel::net;
+use kernel::net::filter::{self as netfilter, inet, Disposition, Family};
+use kernel::prelude::*;
+
+module! {
+    type: RustNetfilter,
+    name: b"rust_netfilter",
+    author: b"Rust for Linux Contributors",
+    description: b"Rust netfilter sample",
+    license: b"GPL",
+}
+
+struct RustNetfilter {
+    _in: Pin<Box<netfilter::Registration<Self>>>,
+    _out: Pin<Box<netfilter::Registration<Self>>>,
+}
+
+impl netfilter::Filter for RustNetfilter {
+    fn filter(_: (), skb: &net::SkBuff) -> Disposition {
+        let data = skb.head_data();
+        pr_info!(
+            "packet headlen={}, len={}, first bytes={:02x?}\n",
+            data.len(),
+            skb.len(),
+            &data[..core::cmp::min(10, data.len())]
+        );
+        Disposition::Accept
+    }
+}
+
+impl kernel::Module for RustNetfilter {
+    fn init(_name: &'static CStr, _module: &'static ThisModule) -> Result<Self> {
+        Ok(Self {
+            _in: netfilter::Registration::new_pinned(
+                Family::INet(inet::Hook::PreRouting),
+                0,
+                net::init_ns().into(),
+                None,
+                (),
+            )?,
+            _out: netfilter::Registration::new_pinned(
+                Family::INet(inet::Hook::PostRouting),
+                0,
+                net::init_ns().into(),
+                None,
+                (),
+            )?,
+        })
+    }
+}
diff --git a/samples/rust/rust_platform.rs b/samples/rust/rust_platform.rs
new file mode 100644
index 000000000000..f62784676919
--- /dev/null
+++ b/samples/rust/rust_platform.rs
@@ -0,0 +1,22 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Rust platform device driver sample.
+
+use kernel::{module_platform_driver, of, platform, prelude::*};
+
+module_platform_driver! {
+    type: Driver,
+    name: b"rust_platform",
+    license: b"GPL",
+}
+
+struct Driver;
+impl platform::Driver for Driver {
+    kernel::define_of_id_table! {(), [
+        (of::DeviceId::Compatible(b"rust,sample"), None),
+    ]}
+
+    fn probe(_dev: &mut platform::Device, _id_info: Option<&Self::IdInfo>) -> Result {
+        Ok(())
+    }
+}
diff --git a/samples/rust/rust_print.rs b/samples/rust/rust_print.rs
new file mode 100644
index 000000000000..30d96e025d89
--- /dev/null
+++ b/samples/rust/rust_print.rs
@@ -0,0 +1,54 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Rust printing macros sample.
+
+use kernel::prelude::*;
+use kernel::{pr_cont, str::CStr, ThisModule};
+
+module! {
+    type: RustPrint,
+    name: b"rust_print",
+    author: b"Rust for Linux Contributors",
+    description: b"Rust printing macros sample",
+    license: b"GPL",
+}
+
+struct RustPrint;
+
+impl kernel::Module for RustPrint {
+    fn init(_name: &'static CStr, _module: &'static ThisModule) -> Result<Self> {
+        pr_info!("Rust printing macros sample (init)\n");
+
+        pr_emerg!("Emergency message (level 0) without args\n");
+        pr_alert!("Alert message (level 1) without args\n");
+        pr_crit!("Critical message (level 2) without args\n");
+        pr_err!("Error message (level 3) without args\n");
+        pr_warn!("Warning message (level 4) without args\n");
+        pr_notice!("Notice message (level 5) without args\n");
+        pr_info!("Info message (level 6) without args\n");
+
+        pr_info!("A line that");
+        pr_cont!(" is continued");
+        pr_cont!(" without args\n");
+
+        pr_emerg!("{} message (level {}) with args\n", "Emergency", 0);
+        pr_alert!("{} message (level {}) with args\n", "Alert", 1);
+        pr_crit!("{} message (level {}) with args\n", "Critical", 2);
+        pr_err!("{} message (level {}) with args\n", "Error", 3);
+        pr_warn!("{} message (level {}) with args\n", "Warning", 4);
+        pr_notice!("{} message (level {}) with args\n", "Notice", 5);
+        pr_info!("{} message (level {}) with args\n", "Info", 6);
+
+        pr_info!("A {} that", "line");
+        pr_cont!(" is {}", "continued");
+        pr_cont!(" with {}\n", "args");
+
+        Ok(RustPrint)
+    }
+}
+
+impl Drop for RustPrint {
+    fn drop(&mut self) {
+        pr_info!("Rust printing macros sample (exit)\n");
+    }
+}
diff --git a/samples/rust/rust_random.rs b/samples/rust/rust_random.rs
new file mode 100644
index 000000000000..771c7a940b3d
--- /dev/null
+++ b/samples/rust/rust_random.rs
@@ -0,0 +1,60 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Rust random device.
+//!
+//! Adapted from Alex Gaynor's original available at
+//! <https://github.com/alex/just-use/blob/master/src/lib.rs>.
+
+use kernel::{
+    file::{self, File},
+    io_buffer::{IoBufferReader, IoBufferWriter},
+    prelude::*,
+};
+
+module_misc_device! {
+    type: RandomFile,
+    name: b"rust_random",
+    author: b"Rust for Linux Contributors",
+    description: b"Just use /dev/urandom: Now with early-boot safety",
+    license: b"GPL",
+}
+
+struct RandomFile;
+
+#[vtable]
+impl file::Operations for RandomFile {
+    fn open(_data: &(), _file: &File) -> Result {
+        Ok(())
+    }
+
+    fn read(_this: (), file: &File, buf: &mut impl IoBufferWriter, _: u64) -> Result<usize> {
+        let total_len = buf.len();
+        let mut chunkbuf = [0; 256];
+
+        while !buf.is_empty() {
+            let len = chunkbuf.len().min(buf.len());
+            let chunk = &mut chunkbuf[0..len];
+            let blocking = (file.flags() & file::flags::O_NONBLOCK) == 0;
+
+            if blocking {
+                kernel::random::getrandom(chunk)?;
+            } else {
+                kernel::random::getrandom_nonblock(chunk)?;
+            }
+            buf.write_slice(chunk)?;
+        }
+        Ok(total_len)
+    }
+
+    fn write(_this: (), _file: &File, buf: &mut impl IoBufferReader, _: u64) -> Result<usize> {
+        let total_len = buf.len();
+        let mut chunkbuf = [0; 256];
+        while !buf.is_empty() {
+            let len = chunkbuf.len().min(buf.len());
+            let chunk = &mut chunkbuf[0..len];
+            buf.read_slice(chunk)?;
+            kernel::random::add_randomness(chunk);
+        }
+        Ok(total_len)
+    }
+}
diff --git a/samples/rust/rust_selftests.rs b/samples/rust/rust_selftests.rs
new file mode 100644
index 000000000000..965c48fd0e29
--- /dev/null
+++ b/samples/rust/rust_selftests.rs
@@ -0,0 +1,99 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Self test cases for Rust.
+
+use kernel::prelude::*;
+// Keep the `use` for a test in its test function. Module-level `use`s are only for the test
+// framework.
+
+module! {
+    type: RustSelftests,
+    name: b"rust_selftests",
+    author: b"Rust for Linux Contributors",
+    description: b"Self test cases for Rust",
+    license: b"GPL",
+}
+
+struct RustSelftests;
+
+/// A summary of testing.
+///
+/// A test can
+///
+/// * pass (successfully), or
+/// * fail (without hitting any error), or
+/// * hit an error (interrupted).
+///
+/// This is the type that differentiates the first two (pass and fail) cases.
+///
+/// When a test hits an error, the test function should skip and return the error. Note that this
+/// doesn't mean the test fails, for example if the system doesn't have enough memory for
+/// testing, the test function may return an `Err(ENOMEM)` and skip.
+#[allow(dead_code)]
+enum TestSummary {
+    Pass,
+    Fail,
+}
+
+use TestSummary::Fail;
+use TestSummary::Pass;
+
+macro_rules! do_tests {
+    ($($name:ident),*) => {
+        let mut total = 0;
+        let mut pass = 0;
+        let mut fail = 0;
+
+        $({
+            total += 1;
+
+            match $name() {
+                Ok(Pass) => {
+                    pass += 1;
+                    pr_info!("{} passed!", stringify!($name));
+                },
+                Ok(Fail) => {
+                    fail += 1;
+                    pr_info!("{} failed!", stringify!($name));
+                },
+                Err(err) => {
+                    pr_info!("{} hit error {:?}", stringify!($name), err);
+                }
+            }
+        })*
+
+        pr_info!("{} tests run, {} passed, {} failed, {} hit errors\n",
+                 total, pass, fail, total - pass - fail);
+
+        if total == pass {
+            pr_info!("All tests passed. Congratulations!\n");
+        }
+    }
+}
+
+/// An example of test.
+#[allow(dead_code)]
+fn test_example() -> Result<TestSummary> {
+    // `use` declarations for the test can be put here, e.g. `use foo::bar;`.
+
+    // Always pass.
+    Ok(Pass)
+}
+
+impl kernel::Module for RustSelftests {
+    fn init(_name: &'static CStr, _module: &'static ThisModule) -> Result<Self> {
+        pr_info!("Rust self tests (init)\n");
+
+        do_tests! {
+            test_example // TODO: Remove when there is at least a real test.
+        };
+
+        Ok(RustSelftests)
+    }
+}
+
+impl Drop for RustSelftests {
+    fn drop(&mut self) {
+        pr_info!("Rust self tests (exit)\n");
+    }
+}
diff --git a/samples/rust/rust_semaphore.rs b/samples/rust/rust_semaphore.rs
new file mode 100644
index 000000000000..e91f82a6abfb
--- /dev/null
+++ b/samples/rust/rust_semaphore.rs
@@ -0,0 +1,170 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Rust semaphore sample.
+//!
+//! A counting semaphore that can be used by userspace.
+//!
+//! The count is incremented by writes to the device. A write of `n` bytes results in an increment
+//! of `n`. It is decremented by reads; each read results in the count being decremented by 1. If
+//! the count is already zero, a read will block until another write increments it.
+//!
+//! This can be used in user space from the shell for example  as follows (assuming a node called
+//! `semaphore`): `cat semaphore` decrements the count by 1 (waiting for it to become non-zero
+//! before decrementing); `echo -n 123 > semaphore` increments the semaphore by 3, potentially
+//! unblocking up to 3 blocked readers.
+
+use core::sync::atomic::{AtomicU64, Ordering};
+use kernel::{
+    condvar_init,
+    file::{self, File, IoctlCommand, IoctlHandler},
+    io_buffer::{IoBufferReader, IoBufferWriter},
+    miscdev::Registration,
+    mutex_init,
+    prelude::*,
+    sync::{CondVar, Mutex, Ref, UniqueRef},
+    user_ptr::{UserSlicePtrReader, UserSlicePtrWriter},
+};
+
+module! {
+    type: RustSemaphore,
+    name: b"rust_semaphore",
+    author: b"Rust for Linux Contributors",
+    description: b"Rust semaphore sample",
+    license: b"GPL",
+}
+
+struct SemaphoreInner {
+    count: usize,
+    max_seen: usize,
+}
+
+struct Semaphore {
+    changed: CondVar,
+    inner: Mutex<SemaphoreInner>,
+}
+
+struct FileState {
+    read_count: AtomicU64,
+    shared: Ref<Semaphore>,
+}
+
+impl FileState {
+    fn consume(&self) -> Result {
+        let mut inner = self.shared.inner.lock();
+        while inner.count == 0 {
+            if self.shared.changed.wait(&mut inner) {
+                return Err(EINTR);
+            }
+        }
+        inner.count -= 1;
+        Ok(())
+    }
+}
+
+#[vtable]
+impl file::Operations for FileState {
+    type Data = Box<Self>;
+    type OpenData = Ref<Semaphore>;
+
+    fn open(shared: &Ref<Semaphore>, _file: &File) -> Result<Box<Self>> {
+        Ok(Box::try_new(Self {
+            read_count: AtomicU64::new(0),
+            shared: shared.clone(),
+        })?)
+    }
+
+    fn read(this: &Self, _: &File, data: &mut impl IoBufferWriter, offset: u64) -> Result<usize> {
+        if data.is_empty() || offset > 0 {
+            return Ok(0);
+        }
+        this.consume()?;
+        data.write_slice(&[0u8; 1])?;
+        this.read_count.fetch_add(1, Ordering::Relaxed);
+        Ok(1)
+    }
+
+    fn write(this: &Self, _: &File, data: &mut impl IoBufferReader, _offs: u64) -> Result<usize> {
+        {
+            let mut inner = this.shared.inner.lock();
+            inner.count = inner.count.saturating_add(data.len());
+            if inner.count > inner.max_seen {
+                inner.max_seen = inner.count;
+            }
+        }
+
+        this.shared.changed.notify_all();
+        Ok(data.len())
+    }
+
+    fn ioctl(this: &Self, file: &File, cmd: &mut IoctlCommand) -> Result<i32> {
+        cmd.dispatch::<Self>(this, file)
+    }
+}
+
+struct RustSemaphore {
+    _dev: Pin<Box<Registration<FileState>>>,
+}
+
+impl kernel::Module for RustSemaphore {
+    fn init(name: &'static CStr, _module: &'static ThisModule) -> Result<Self> {
+        pr_info!("Rust semaphore sample (init)\n");
+
+        let mut sema = Pin::from(UniqueRef::try_new(Semaphore {
+            // SAFETY: `condvar_init!` is called below.
+            changed: unsafe { CondVar::new() },
+
+            // SAFETY: `mutex_init!` is called below.
+            inner: unsafe {
+                Mutex::new(SemaphoreInner {
+                    count: 0,
+                    max_seen: 0,
+                })
+            },
+        })?);
+
+        // SAFETY: `changed` is pinned when `sema` is.
+        let pinned = unsafe { sema.as_mut().map_unchecked_mut(|s| &mut s.changed) };
+        condvar_init!(pinned, "Semaphore::changed");
+
+        // SAFETY: `inner` is pinned when `sema` is.
+        let pinned = unsafe { sema.as_mut().map_unchecked_mut(|s| &mut s.inner) };
+        mutex_init!(pinned, "Semaphore::inner");
+
+        Ok(Self {
+            _dev: Registration::new_pinned(fmt!("{name}"), sema.into())?,
+        })
+    }
+}
+
+impl Drop for RustSemaphore {
+    fn drop(&mut self) {
+        pr_info!("Rust semaphore sample (exit)\n");
+    }
+}
+
+const IOCTL_GET_READ_COUNT: u32 = 0x80086301;
+const IOCTL_SET_READ_COUNT: u32 = 0x40086301;
+
+impl IoctlHandler for FileState {
+    type Target<'a> = &'a Self;
+
+    fn read(this: &Self, _: &File, cmd: u32, writer: &mut UserSlicePtrWriter) -> Result<i32> {
+        match cmd {
+            IOCTL_GET_READ_COUNT => {
+                writer.write(&this.read_count.load(Ordering::Relaxed))?;
+                Ok(0)
+            }
+            _ => Err(EINVAL),
+        }
+    }
+
+    fn write(this: &Self, _: &File, cmd: u32, reader: &mut UserSlicePtrReader) -> Result<i32> {
+        match cmd {
+            IOCTL_SET_READ_COUNT => {
+                this.read_count.store(reader.read()?, Ordering::Relaxed);
+                Ok(0)
+            }
+            _ => Err(EINVAL),
+        }
+    }
+}
diff --git a/samples/rust/rust_semaphore_c.c b/samples/rust/rust_semaphore_c.c
new file mode 100644
index 000000000000..7672b0b4c105
--- /dev/null
+++ b/samples/rust/rust_semaphore_c.c
@@ -0,0 +1,212 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Rust semaphore sample (in C, for comparison)
+ *
+ * This is a C implementation of `rust_semaphore.rs`. Refer to the description
+ * in that file for details on the device.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/miscdevice.h>
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/slab.h>
+#include <linux/refcount.h>
+#include <linux/wait.h>
+
+#define IOCTL_GET_READ_COUNT _IOR('c', 1, u64)
+#define IOCTL_SET_READ_COUNT _IOW('c', 1, u64)
+
+struct semaphore_state {
+	struct kref ref;
+	struct miscdevice miscdev;
+	wait_queue_head_t changed;
+	struct mutex mutex;
+	size_t count;
+	size_t max_seen;
+};
+
+struct file_state {
+	atomic64_t read_count;
+	struct semaphore_state *shared;
+};
+
+static int semaphore_consume(struct semaphore_state *state)
+{
+	DEFINE_WAIT(wait);
+
+	mutex_lock(&state->mutex);
+	while (state->count == 0) {
+		prepare_to_wait(&state->changed, &wait, TASK_INTERRUPTIBLE);
+		mutex_unlock(&state->mutex);
+		schedule();
+		finish_wait(&state->changed, &wait);
+		if (signal_pending(current))
+			return -EINTR;
+		mutex_lock(&state->mutex);
+	}
+
+	state->count--;
+	mutex_unlock(&state->mutex);
+
+	return 0;
+}
+
+static int semaphore_open(struct inode *nodp, struct file *filp)
+{
+	struct semaphore_state *shared =
+		container_of(filp->private_data, struct semaphore_state, miscdev);
+	struct file_state *state;
+
+	state = kzalloc(sizeof(*state), GFP_KERNEL);
+	if (!state)
+		return -ENOMEM;
+
+	kref_get(&shared->ref);
+	state->shared = shared;
+	atomic64_set(&state->read_count, 0);
+
+	filp->private_data = state;
+
+	return 0;
+}
+
+static ssize_t semaphore_write(struct file *filp, const char __user *buffer, size_t count,
+			       loff_t *ppos)
+{
+	struct file_state *state = filp->private_data;
+	struct semaphore_state *shared = state->shared;
+
+	mutex_lock(&shared->mutex);
+
+	shared->count += count;
+	if (shared->count < count)
+		shared->count = SIZE_MAX;
+
+	if (shared->count > shared->max_seen)
+		shared->max_seen = shared->count;
+
+	mutex_unlock(&shared->mutex);
+
+	wake_up_all(&shared->changed);
+
+	return count;
+}
+
+static ssize_t semaphore_read(struct file *filp, char __user *buffer,
+			      size_t count, loff_t *ppos)
+{
+	struct file_state *state = filp->private_data;
+	char c = 0;
+	int ret;
+
+	if (count == 0 || *ppos > 0)
+		return 0;
+
+	ret = semaphore_consume(state->shared);
+	if (ret)
+		return ret;
+
+	if (copy_to_user(buffer, &c, sizeof(c)))
+		return -EFAULT;
+
+	atomic64_add(1, &state->read_count);
+	*ppos += 1;
+	return 1;
+}
+
+static long semaphore_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
+{
+	struct file_state *state = filp->private_data;
+	void __user *buffer = (void __user *)arg;
+	u64 value;
+
+	switch (cmd) {
+	case IOCTL_GET_READ_COUNT:
+		value = atomic64_read(&state->read_count);
+		if (copy_to_user(buffer, &value, sizeof(value)))
+			return -EFAULT;
+		return 0;
+	case IOCTL_SET_READ_COUNT:
+		if (copy_from_user(&value, buffer, sizeof(value)))
+			return -EFAULT;
+		atomic64_set(&state->read_count, value);
+		return 0;
+	default:
+		return -EINVAL;
+	}
+}
+
+static void semaphore_free(struct kref *kref)
+{
+	struct semaphore_state *device;
+
+	device = container_of(kref, struct semaphore_state, ref);
+	kfree(device);
+}
+
+static int semaphore_release(struct inode *nodp, struct file *filp)
+{
+	struct file_state *state = filp->private_data;
+
+	kref_put(&state->shared->ref, semaphore_free);
+	kfree(state);
+	return 0;
+}
+
+static const struct file_operations semaphore_fops = {
+	.owner = THIS_MODULE,
+	.open = semaphore_open,
+	.read = semaphore_read,
+	.write = semaphore_write,
+	.compat_ioctl = semaphore_ioctl,
+	.release = semaphore_release,
+};
+
+static struct semaphore_state *device;
+
+static int __init semaphore_init(void)
+{
+	int ret;
+	struct semaphore_state *state;
+
+	pr_info("Rust semaphore sample (in C, for comparison) (init)\n");
+
+	state = kzalloc(sizeof(*state), GFP_KERNEL);
+	if (!state)
+		return -ENOMEM;
+
+	mutex_init(&state->mutex);
+	kref_init(&state->ref);
+	init_waitqueue_head(&state->changed);
+
+	state->miscdev.fops = &semaphore_fops;
+	state->miscdev.minor = MISC_DYNAMIC_MINOR;
+	state->miscdev.name = "semaphore";
+
+	ret = misc_register(&state->miscdev);
+	if (ret < 0) {
+		kfree(state);
+		return ret;
+	}
+
+	device = state;
+
+	return 0;
+}
+
+static void __exit semaphore_exit(void)
+{
+	pr_info("Rust semaphore sample (in C, for comparison) (exit)\n");
+
+	misc_deregister(&device->miscdev);
+	kref_put(&device->ref, semaphore_free);
+}
+
+module_init(semaphore_init);
+module_exit(semaphore_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Rust for Linux Contributors");
+MODULE_DESCRIPTION("Rust semaphore sample (in C, for comparison)");
diff --git a/samples/rust/rust_stack_probing.rs b/samples/rust/rust_stack_probing.rs
new file mode 100644
index 000000000000..1448fe8e1b56
--- /dev/null
+++ b/samples/rust/rust_stack_probing.rs
@@ -0,0 +1,36 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Rust stack probing sample.
+
+use kernel::prelude::*;
+
+module! {
+    type: RustStackProbing,
+    name: b"rust_stack_probing",
+    author: b"Rust for Linux Contributors",
+    description: b"Rust stack probing sample",
+    license: b"GPL",
+}
+
+struct RustStackProbing;
+
+impl kernel::Module for RustStackProbing {
+    fn init(_name: &'static CStr, _module: &'static ThisModule) -> Result<Self> {
+        pr_info!("Rust stack probing sample (init)\n");
+
+        // Including this large variable on the stack will trigger
+        // stack probing on the supported archs.
+        // This will verify that stack probing does not lead to
+        // any errors if we need to link `__rust_probestack`.
+        let x: [u64; 514] = core::hint::black_box([5; 514]);
+        pr_info!("Large array has length: {}\n", x.len());
+
+        Ok(RustStackProbing)
+    }
+}
+
+impl Drop for RustStackProbing {
+    fn drop(&mut self) {
+        pr_info!("Rust stack probing sample (exit)\n");
+    }
+}
diff --git a/samples/rust/rust_sync.rs b/samples/rust/rust_sync.rs
new file mode 100644
index 000000000000..46637ace2f7f
--- /dev/null
+++ b/samples/rust/rust_sync.rs
@@ -0,0 +1,93 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Rust synchronisation primitives sample.
+
+use kernel::prelude::*;
+use kernel::{
+    condvar_init, mutex_init, spinlock_init,
+    sync::{CondVar, Mutex, SpinLock},
+};
+
+module! {
+    type: RustSync,
+    name: b"rust_sync",
+    author: b"Rust for Linux Contributors",
+    description: b"Rust synchronisation primitives sample",
+    license: b"GPL",
+}
+
+kernel::init_static_sync! {
+    static SAMPLE_MUTEX: Mutex<u32> = 10;
+    static SAMPLE_CONDVAR: CondVar;
+}
+
+struct RustSync;
+
+impl kernel::Module for RustSync {
+    fn init(_name: &'static CStr, _module: &'static ThisModule) -> Result<Self> {
+        pr_info!("Rust synchronisation primitives sample (init)\n");
+
+        // Test mutexes.
+        {
+            // SAFETY: `init` is called below.
+            let mut data = Pin::from(Box::try_new(unsafe { Mutex::new(0) })?);
+            mutex_init!(data.as_mut(), "RustSync::init::data1");
+            *data.lock() = 10;
+            pr_info!("Value: {}\n", *data.lock());
+
+            // SAFETY: `init` is called below.
+            let mut cv = Pin::from(Box::try_new(unsafe { CondVar::new() })?);
+            condvar_init!(cv.as_mut(), "RustSync::init::cv1");
+
+            {
+                let mut guard = data.lock();
+                while *guard != 10 {
+                    let _ = cv.wait(&mut guard);
+                }
+            }
+            cv.notify_one();
+            cv.notify_all();
+            cv.free_waiters();
+        }
+
+        // Test static mutex + condvar.
+        *SAMPLE_MUTEX.lock() = 20;
+
+        {
+            let mut guard = SAMPLE_MUTEX.lock();
+            while *guard != 20 {
+                let _ = SAMPLE_CONDVAR.wait(&mut guard);
+            }
+        }
+
+        // Test spinlocks.
+        {
+            // SAFETY: `init` is called below.
+            let mut data = Pin::from(Box::try_new(unsafe { SpinLock::new(0) })?);
+            spinlock_init!(data.as_mut(), "RustSync::init::data2");
+            *data.lock() = 10;
+            pr_info!("Value: {}\n", *data.lock());
+
+            // SAFETY: `init` is called below.
+            let mut cv = Pin::from(Box::try_new(unsafe { CondVar::new() })?);
+            condvar_init!(cv.as_mut(), "RustSync::init::cv2");
+            {
+                let mut guard = data.lock();
+                while *guard != 10 {
+                    let _ = cv.wait(&mut guard);
+                }
+            }
+            cv.notify_one();
+            cv.notify_all();
+            cv.free_waiters();
+        }
+
+        Ok(RustSync)
+    }
+}
+
+impl Drop for RustSync {
+    fn drop(&mut self) {
+        pr_info!("Rust synchronisation primitives sample (exit)\n");
+    }
+}
-- 
2.37.1


^ permalink raw reply related	[relevance 3%]

* Re: [PATCH v8 17/31] rust: add `kernel` crate
  2022-08-02  1:50  1% ` [PATCH v8 17/31] rust: add `kernel` crate Miguel Ojeda
@ 2022-08-02 13:34  0%   ` Greg Kroah-Hartman
  0 siblings, 0 replies; 77+ results
From: Greg Kroah-Hartman @ 2022-08-02 13:34 UTC (permalink / raw)
  To: Miguel Ojeda
  Cc: Linus Torvalds, rust-for-linux, linux-kernel, Jarkko Sakkinen,
	Wedson Almeida Filho, Alex Gaynor, Geoffrey Thomas, Finn Behrens,
	Adam Bratschi-Kaye, Michael Ellerman, Sumera Priyadarsini,
	Sven Van Asbroeck, Gary Guo, Boris-Chengbiao Zhou, Boqun Feng,
	Fox Chen, Dan Robertson, Viktor Garske, Dariusz Sosnowski,
	Léo Lanteri Thauvin, Niklas Mohrin, Gioh Kim, Daniel Xu,
	Milan Landaverde, Morgan Bartlett, Maciej Falkowski,
	Jiapeng Chong, Nándor István Krácser, David Gow,
	John Baublitz, Björn Roy Baron

On Tue, Aug 02, 2022 at 03:50:04AM +0200, Miguel Ojeda wrote:
> From: Wedson Almeida Filho <wedsonaf@google.com>
> 
> The `kernel` crate currently includes all the abstractions that wrap
> kernel features written in C.
> 
> These abstractions call the C side of the kernel via the generated
> bindings with the `bindgen` tool. Modules developed in Rust should
> never call the bindings themselves.
> 
> In the future, as the abstractions grow in number, we may need
> to split this crate into several, possibly following a similar
> subdivision in subsystems as the kernel itself and/or moving
> the code to the actual subsystems.
> 
> Co-developed-by: Alex Gaynor <alex.gaynor@gmail.com>
> Signed-off-by: Alex Gaynor <alex.gaynor@gmail.com>
> Co-developed-by: Geoffrey Thomas <geofft@ldpreload.com>
> Signed-off-by: Geoffrey Thomas <geofft@ldpreload.com>
> Co-developed-by: Finn Behrens <me@kloenk.de>
> Signed-off-by: Finn Behrens <me@kloenk.de>
> Co-developed-by: Adam Bratschi-Kaye <ark.email@gmail.com>
> Signed-off-by: Adam Bratschi-Kaye <ark.email@gmail.com>
> Co-developed-by: Michael Ellerman <mpe@ellerman.id.au>
> Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
> Co-developed-by: Sumera Priyadarsini <sylphrenadin@gmail.com>
> Signed-off-by: Sumera Priyadarsini <sylphrenadin@gmail.com>
> Co-developed-by: Sven Van Asbroeck <thesven73@gmail.com>
> Signed-off-by: Sven Van Asbroeck <thesven73@gmail.com>
> Co-developed-by: Gary Guo <gary@garyguo.net>
> Signed-off-by: Gary Guo <gary@garyguo.net>
> Co-developed-by: Boris-Chengbiao Zhou <bobo1239@web.de>
> Signed-off-by: Boris-Chengbiao Zhou <bobo1239@web.de>
> Co-developed-by: Boqun Feng <boqun.feng@gmail.com>
> Signed-off-by: Boqun Feng <boqun.feng@gmail.com>
> Co-developed-by: Fox Chen <foxhlchen@gmail.com>
> Signed-off-by: Fox Chen <foxhlchen@gmail.com>
> Co-developed-by: Dan Robertson <daniel.robertson@starlab.io>
> Signed-off-by: Dan Robertson <daniel.robertson@starlab.io>
> Co-developed-by: Viktor Garske <viktor@v-gar.de>
> Signed-off-by: Viktor Garske <viktor@v-gar.de>
> Co-developed-by: Dariusz Sosnowski <dsosnowski@dsosnowski.pl>
> Signed-off-by: Dariusz Sosnowski <dsosnowski@dsosnowski.pl>
> Co-developed-by: Léo Lanteri Thauvin <leseulartichaut@gmail.com>
> Signed-off-by: Léo Lanteri Thauvin <leseulartichaut@gmail.com>
> Co-developed-by: Niklas Mohrin <dev@niklasmohrin.de>
> Signed-off-by: Niklas Mohrin <dev@niklasmohrin.de>
> Co-developed-by: Gioh Kim <gurugio@gmail.com>
> Signed-off-by: Gioh Kim <gurugio@gmail.com>
> Co-developed-by: Daniel Xu <dxu@dxuuu.xyz>
> Signed-off-by: Daniel Xu <dxu@dxuuu.xyz>
> Co-developed-by: Milan Landaverde <milan@mdaverde.com>
> Signed-off-by: Milan Landaverde <milan@mdaverde.com>
> Co-developed-by: Morgan Bartlett <mjmouse9999@gmail.com>
> Signed-off-by: Morgan Bartlett <mjmouse9999@gmail.com>
> Co-developed-by: Maciej Falkowski <m.falkowski@samsung.com>
> Signed-off-by: Maciej Falkowski <m.falkowski@samsung.com>
> Co-developed-by: Jiapeng Chong <jiapeng.chong@linux.alibaba.com>
> Signed-off-by: Jiapeng Chong <jiapeng.chong@linux.alibaba.com>
> Co-developed-by: Nándor István Krácser <bonifaido@gmail.com>
> Signed-off-by: Nándor István Krácser <bonifaido@gmail.com>
> Co-developed-by: David Gow <davidgow@google.com>
> Signed-off-by: David Gow <davidgow@google.com>
> Co-developed-by: John Baublitz <john.m.baublitz@gmail.com>
> Signed-off-by: John Baublitz <john.m.baublitz@gmail.com>
> Co-developed-by: Björn Roy Baron <bjorn3_gh@protonmail.com>
> Signed-off-by: Björn Roy Baron <bjorn3_gh@protonmail.com>
> Signed-off-by: Wedson Almeida Filho <wedsonaf@google.com>
> Co-developed-by: Miguel Ojeda <ojeda@kernel.org>
> Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
> ---
>  rust/kernel/allocator.rs                 |  64 ++
>  rust/kernel/amba.rs                      | 261 +++++++
>  rust/kernel/build_assert.rs              |  83 +++
>  rust/kernel/chrdev.rs                    | 206 ++++++
>  rust/kernel/clk.rs                       |  79 ++
>  rust/kernel/cred.rs                      |  46 ++
>  rust/kernel/delay.rs                     | 104 +++
>  rust/kernel/device.rs                    | 527 ++++++++++++++
>  rust/kernel/driver.rs                    | 442 +++++++++++
>  rust/kernel/error.rs                     | 564 ++++++++++++++
>  rust/kernel/file.rs                      | 887 +++++++++++++++++++++++
>  rust/kernel/fs.rs                        | 846 +++++++++++++++++++++
>  rust/kernel/fs/param.rs                  | 553 ++++++++++++++
>  rust/kernel/gpio.rs                      | 505 +++++++++++++
>  rust/kernel/hwrng.rs                     | 210 ++++++
>  rust/kernel/io_buffer.rs                 | 153 ++++
>  rust/kernel/io_mem.rs                    | 278 +++++++
>  rust/kernel/iov_iter.rs                  |  81 +++
>  rust/kernel/irq.rs                       | 681 +++++++++++++++++
>  rust/kernel/kasync.rs                    |  50 ++
>  rust/kernel/kasync/executor.rs           | 154 ++++
>  rust/kernel/kasync/executor/workqueue.rs | 291 ++++++++
>  rust/kernel/kasync/net.rs                | 322 ++++++++
>  rust/kernel/kunit.rs                     |  91 +++
>  rust/kernel/lib.rs                       | 267 +++++++
>  rust/kernel/linked_list.rs               | 247 +++++++
>  rust/kernel/miscdev.rs                   | 290 ++++++++
>  rust/kernel/mm.rs                        | 149 ++++
>  rust/kernel/module_param.rs              | 499 +++++++++++++
>  rust/kernel/net.rs                       | 392 ++++++++++
>  rust/kernel/net/filter.rs                | 447 ++++++++++++
>  rust/kernel/of.rs                        |  63 ++
>  rust/kernel/pages.rs                     | 144 ++++
>  rust/kernel/platform.rs                  | 223 ++++++
>  rust/kernel/power.rs                     | 118 +++
>  rust/kernel/prelude.rs                   |  36 +
>  rust/kernel/print.rs                     | 406 +++++++++++
>  rust/kernel/random.rs                    |  42 ++
>  rust/kernel/raw_list.rs                  | 361 +++++++++
>  rust/kernel/rbtree.rs                    | 563 ++++++++++++++
>  rust/kernel/revocable.rs                 | 425 +++++++++++
>  rust/kernel/security.rs                  |  38 +
>  rust/kernel/static_assert.rs             |  34 +
>  rust/kernel/std_vendor.rs                | 161 ++++
>  rust/kernel/str.rs                       | 597 +++++++++++++++
>  rust/kernel/sync.rs                      |  48 +-
>  rust/kernel/sysctl.rs                    | 199 +++++
>  rust/kernel/task.rs                      | 239 ++++++
>  rust/kernel/types.rs                     | 705 ++++++++++++++++++
>  rust/kernel/unsafe_list.rs               | 680 +++++++++++++++++
>  rust/kernel/user_ptr.rs                  | 175 +++++
>  rust/kernel/workqueue.rs                 | 512 +++++++++++++
>  52 files changed, 15518 insertions(+), 20 deletions(-)

This is huge for a single commit, and pretty much impossible to review
as-is.

Any chance you can turn this into a series of commits, that starts with
the basics and builds on top of that?  Right now you are mixing many
many different subsystems all at once into one commit, guaranteeing that
no one can review the whole thing properly :(

thanks,

greg k-h

^ permalink raw reply	[relevance 0%]

* [PATCH v9 12/27] rust: add `kernel` crate
  @ 2022-08-05 15:41  4% ` Miguel Ojeda
  2022-08-05 15:42  6% ` [PATCH v9 26/27] samples: add first Rust examples Miguel Ojeda
  1 sibling, 0 replies; 77+ results
From: Miguel Ojeda @ 2022-08-05 15:41 UTC (permalink / raw)
  To: Linus Torvalds, Greg Kroah-Hartman
  Cc: rust-for-linux, linux-kernel, linux-fsdevel, patches,
	Jarkko Sakkinen, Miguel Ojeda, Wedson Almeida Filho, Alex Gaynor,
	Geoffrey Thomas, Finn Behrens, Adam Bratschi-Kaye,
	Sven Van Asbroeck, Gary Guo, Boris-Chengbiao Zhou, Boqun Feng,
	Fox Chen, Viktor Garske, Dariusz Sosnowski,
	Léo Lanteri Thauvin, Niklas Mohrin, Milan Landaverde,
	Morgan Bartlett, Maciej Falkowski,
	Nándor István Krácser, David Gow, John Baublitz,
	Björn Roy Baron

From: Wedson Almeida Filho <wedsonaf@google.com>

The `kernel` crate currently includes all the abstractions that wrap
kernel features written in C.

These abstractions call the C side of the kernel via the generated
bindings with the `bindgen` tool. Modules developed in Rust should
never call the bindings themselves.

In the future, as the abstractions grow in number, we may need
to split this crate into several, possibly following a similar
subdivision in subsystems as the kernel itself and/or moving
the code to the actual subsystems.

Co-developed-by: Alex Gaynor <alex.gaynor@gmail.com>
Signed-off-by: Alex Gaynor <alex.gaynor@gmail.com>
Co-developed-by: Geoffrey Thomas <geofft@ldpreload.com>
Signed-off-by: Geoffrey Thomas <geofft@ldpreload.com>
Co-developed-by: Finn Behrens <me@kloenk.de>
Signed-off-by: Finn Behrens <me@kloenk.de>
Co-developed-by: Adam Bratschi-Kaye <ark.email@gmail.com>
Signed-off-by: Adam Bratschi-Kaye <ark.email@gmail.com>
Co-developed-by: Sven Van Asbroeck <thesven73@gmail.com>
Signed-off-by: Sven Van Asbroeck <thesven73@gmail.com>
Co-developed-by: Gary Guo <gary@garyguo.net>
Signed-off-by: Gary Guo <gary@garyguo.net>
Co-developed-by: Boris-Chengbiao Zhou <bobo1239@web.de>
Signed-off-by: Boris-Chengbiao Zhou <bobo1239@web.de>
Co-developed-by: Boqun Feng <boqun.feng@gmail.com>
Signed-off-by: Boqun Feng <boqun.feng@gmail.com>
Co-developed-by: Fox Chen <foxhlchen@gmail.com>
Signed-off-by: Fox Chen <foxhlchen@gmail.com>
Co-developed-by: Viktor Garske <viktor@v-gar.de>
Signed-off-by: Viktor Garske <viktor@v-gar.de>
Co-developed-by: Dariusz Sosnowski <dsosnowski@dsosnowski.pl>
Signed-off-by: Dariusz Sosnowski <dsosnowski@dsosnowski.pl>
Co-developed-by: Léo Lanteri Thauvin <leseulartichaut@gmail.com>
Signed-off-by: Léo Lanteri Thauvin <leseulartichaut@gmail.com>
Co-developed-by: Niklas Mohrin <dev@niklasmohrin.de>
Signed-off-by: Niklas Mohrin <dev@niklasmohrin.de>
Co-developed-by: Milan Landaverde <milan@mdaverde.com>
Signed-off-by: Milan Landaverde <milan@mdaverde.com>
Co-developed-by: Morgan Bartlett <mjmouse9999@gmail.com>
Signed-off-by: Morgan Bartlett <mjmouse9999@gmail.com>
Co-developed-by: Maciej Falkowski <m.falkowski@samsung.com>
Signed-off-by: Maciej Falkowski <m.falkowski@samsung.com>
Co-developed-by: Nándor István Krácser <bonifaido@gmail.com>
Signed-off-by: Nándor István Krácser <bonifaido@gmail.com>
Co-developed-by: David Gow <davidgow@google.com>
Signed-off-by: David Gow <davidgow@google.com>
Co-developed-by: John Baublitz <john.m.baublitz@gmail.com>
Signed-off-by: John Baublitz <john.m.baublitz@gmail.com>
Co-developed-by: Björn Roy Baron <bjorn3_gh@protonmail.com>
Signed-off-by: Björn Roy Baron <bjorn3_gh@protonmail.com>
Signed-off-by: Wedson Almeida Filho <wedsonaf@google.com>
Co-developed-by: Miguel Ojeda <ojeda@kernel.org>
Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
---
 rust/kernel/allocator.rs |  64 +++++++++++++
 rust/kernel/error.rs     |  59 ++++++++++++
 rust/kernel/lib.rs       |  78 +++++++++++++++
 rust/kernel/prelude.rs   |  20 ++++
 rust/kernel/print.rs     | 198 +++++++++++++++++++++++++++++++++++++++
 rust/kernel/str.rs       |  72 ++++++++++++++
 6 files changed, 491 insertions(+)
 create mode 100644 rust/kernel/allocator.rs
 create mode 100644 rust/kernel/error.rs
 create mode 100644 rust/kernel/lib.rs
 create mode 100644 rust/kernel/prelude.rs
 create mode 100644 rust/kernel/print.rs
 create mode 100644 rust/kernel/str.rs

diff --git a/rust/kernel/allocator.rs b/rust/kernel/allocator.rs
new file mode 100644
index 000000000000..397a3dd57a9b
--- /dev/null
+++ b/rust/kernel/allocator.rs
@@ -0,0 +1,64 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Allocator support.
+
+use core::alloc::{GlobalAlloc, Layout};
+use core::ptr;
+
+use crate::bindings;
+
+struct KernelAllocator;
+
+unsafe impl GlobalAlloc for KernelAllocator {
+    unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
+        // `krealloc()` is used instead of `kmalloc()` because the latter is
+        // an inline function and cannot be bound to as a result.
+        unsafe { bindings::krealloc(ptr::null(), layout.size(), bindings::GFP_KERNEL) as *mut u8 }
+    }
+
+    unsafe fn dealloc(&self, ptr: *mut u8, _layout: Layout) {
+        unsafe {
+            bindings::kfree(ptr as *const core::ffi::c_void);
+        }
+    }
+}
+
+#[global_allocator]
+static ALLOCATOR: KernelAllocator = KernelAllocator;
+
+// `rustc` only generates these for some crate types. Even then, we would need
+// to extract the object file that has them from the archive. For the moment,
+// let's generate them ourselves instead.
+//
+// Note that `#[no_mangle]` implies exported too, nowadays.
+#[no_mangle]
+fn __rust_alloc(size: usize, _align: usize) -> *mut u8 {
+    unsafe { bindings::krealloc(core::ptr::null(), size, bindings::GFP_KERNEL) as *mut u8 }
+}
+
+#[no_mangle]
+fn __rust_dealloc(ptr: *mut u8, _size: usize, _align: usize) {
+    unsafe { bindings::kfree(ptr as *const core::ffi::c_void) };
+}
+
+#[no_mangle]
+fn __rust_realloc(ptr: *mut u8, _old_size: usize, _align: usize, new_size: usize) -> *mut u8 {
+    unsafe {
+        bindings::krealloc(
+            ptr as *const core::ffi::c_void,
+            new_size,
+            bindings::GFP_KERNEL,
+        ) as *mut u8
+    }
+}
+
+#[no_mangle]
+fn __rust_alloc_zeroed(size: usize, _align: usize) -> *mut u8 {
+    unsafe {
+        bindings::krealloc(
+            core::ptr::null(),
+            size,
+            bindings::GFP_KERNEL | bindings::__GFP_ZERO,
+        ) as *mut u8
+    }
+}
diff --git a/rust/kernel/error.rs b/rust/kernel/error.rs
new file mode 100644
index 000000000000..466b2a8fe569
--- /dev/null
+++ b/rust/kernel/error.rs
@@ -0,0 +1,59 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Kernel errors.
+//!
+//! C header: [`include/uapi/asm-generic/errno-base.h`](../../../include/uapi/asm-generic/errno-base.h)
+
+use alloc::collections::TryReserveError;
+
+/// Contains the C-compatible error codes.
+pub mod code {
+    /// Out of memory.
+    pub const ENOMEM: super::Error = super::Error(-(crate::bindings::ENOMEM as i32));
+}
+
+/// Generic integer kernel error.
+///
+/// The kernel defines a set of integer generic error codes based on C and
+/// POSIX ones. These codes may have a more specific meaning in some contexts.
+///
+/// # Invariants
+///
+/// The value is a valid `errno` (i.e. `>= -MAX_ERRNO && < 0`).
+#[derive(Clone, Copy, PartialEq, Eq)]
+pub struct Error(core::ffi::c_int);
+
+impl Error {
+    /// Returns the kernel error code.
+    pub fn to_kernel_errno(self) -> core::ffi::c_int {
+        self.0
+    }
+}
+
+impl From<TryReserveError> for Error {
+    fn from(_: TryReserveError) -> Error {
+        code::ENOMEM
+    }
+}
+
+/// A [`Result`] with an [`Error`] error type.
+///
+/// To be used as the return type for functions that may fail.
+///
+/// # Error codes in C and Rust
+///
+/// In C, it is common that functions indicate success or failure through
+/// their return value; modifying or returning extra data through non-`const`
+/// pointer parameters. In particular, in the kernel, functions that may fail
+/// typically return an `int` that represents a generic error code. We model
+/// those as [`Error`].
+///
+/// In Rust, it is idiomatic to model functions that may fail as returning
+/// a [`Result`]. Since in the kernel many functions return an error code,
+/// [`Result`] is a type alias for a [`core::result::Result`] that uses
+/// [`Error`] as its error type.
+///
+/// Note that even if a function does not return anything when it succeeds,
+/// it should still be modeled as returning a `Result` rather than
+/// just an [`Error`].
+pub type Result<T = ()> = core::result::Result<T, Error>;
diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs
new file mode 100644
index 000000000000..abd46261d385
--- /dev/null
+++ b/rust/kernel/lib.rs
@@ -0,0 +1,78 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! The `kernel` crate.
+//!
+//! This crate contains the kernel APIs that have been ported or wrapped for
+//! usage by Rust code in the kernel and is shared by all of them.
+//!
+//! In other words, all the rest of the Rust code in the kernel (e.g. kernel
+//! modules written in Rust) depends on [`core`], [`alloc`] and this crate.
+//!
+//! If you need a kernel C API that is not ported or wrapped yet here, then
+//! do so first instead of bypassing this crate.
+
+#![no_std]
+#![feature(core_ffi_c)]
+
+// Ensure conditional compilation based on the kernel configuration works;
+// otherwise we may silently break things like initcall handling.
+#[cfg(not(CONFIG_RUST))]
+compile_error!("Missing kernel configuration for conditional compilation");
+
+#[cfg(not(test))]
+#[cfg(not(testlib))]
+mod allocator;
+pub mod error;
+pub mod prelude;
+pub mod print;
+pub mod str;
+
+#[doc(hidden)]
+pub use bindings;
+pub use macros;
+
+/// Prefix to appear before log messages printed from within the `kernel` crate.
+const __LOG_PREFIX: &[u8] = b"rust_kernel\0";
+
+/// The top level entrypoint to implementing a kernel module.
+///
+/// For any teardown or cleanup operations, your type may implement [`Drop`].
+pub trait Module: Sized + Sync {
+    /// Called at module initialization time.
+    ///
+    /// Use this method to perform whatever setup or registration your module
+    /// should do.
+    ///
+    /// Equivalent to the `module_init` macro in the C API.
+    fn init(module: &'static ThisModule) -> error::Result<Self>;
+}
+
+/// Equivalent to `THIS_MODULE` in the C API.
+///
+/// C header: `include/linux/export.h`
+pub struct ThisModule(*mut bindings::module);
+
+// SAFETY: `THIS_MODULE` may be used from all threads within a module.
+unsafe impl Sync for ThisModule {}
+
+impl ThisModule {
+    /// Creates a [`ThisModule`] given the `THIS_MODULE` pointer.
+    ///
+    /// # Safety
+    ///
+    /// The pointer must be equal to the right `THIS_MODULE`.
+    pub const unsafe fn from_ptr(ptr: *mut bindings::module) -> ThisModule {
+        ThisModule(ptr)
+    }
+}
+
+#[cfg(not(any(testlib, test)))]
+#[panic_handler]
+fn panic(info: &core::panic::PanicInfo<'_>) -> ! {
+    pr_emerg!("{}\n", info);
+    // SAFETY: FFI call.
+    unsafe { bindings::BUG() };
+    // Bindgen currently does not recognize `__noreturn` so `BUG` returns `()`
+    // instead of `!`. See <https://github.com/rust-lang/rust-bindgen/issues/2094>.
+    loop {}
+}
diff --git a/rust/kernel/prelude.rs b/rust/kernel/prelude.rs
new file mode 100644
index 000000000000..495e22250726
--- /dev/null
+++ b/rust/kernel/prelude.rs
@@ -0,0 +1,20 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! The `kernel` prelude.
+//!
+//! These are the most common items used by Rust code in the kernel,
+//! intended to be imported by all Rust code, for convenience.
+//!
+//! # Examples
+//!
+//! ```
+//! use kernel::prelude::*;
+//! ```
+
+pub use super::{
+    error::{Error, Result},
+    pr_emerg, pr_info, ThisModule,
+};
+pub use alloc::{boxed::Box, vec::Vec};
+pub use core::pin::Pin;
+pub use macros::module;
diff --git a/rust/kernel/print.rs b/rust/kernel/print.rs
new file mode 100644
index 000000000000..55db5a1ba752
--- /dev/null
+++ b/rust/kernel/print.rs
@@ -0,0 +1,198 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Printing facilities.
+//!
+//! C header: [`include/linux/printk.h`](../../../../include/linux/printk.h)
+//!
+//! Reference: <https://www.kernel.org/doc/html/latest/core-api/printk-basics.html>
+
+use core::{
+    ffi::{c_char, c_void},
+    fmt,
+};
+
+use crate::str::RawFormatter;
+
+#[cfg(CONFIG_PRINTK)]
+use crate::bindings;
+
+// Called from `vsprintf` with format specifier `%pA`.
+#[no_mangle]
+unsafe fn rust_fmt_argument(buf: *mut c_char, end: *mut c_char, ptr: *const c_void) -> *mut c_char {
+    use fmt::Write;
+    // SAFETY: The C contract guarantees that `buf` is valid if it's less than `end`.
+    let mut w = unsafe { RawFormatter::from_ptrs(buf.cast(), end.cast()) };
+    let _ = w.write_fmt(unsafe { *(ptr as *const fmt::Arguments<'_>) });
+    w.pos().cast()
+}
+
+/// Format strings.
+///
+/// Public but hidden since it should only be used from public macros.
+#[doc(hidden)]
+pub mod format_strings {
+    use crate::bindings;
+
+    /// The length we copy from the `KERN_*` kernel prefixes.
+    const LENGTH_PREFIX: usize = 2;
+
+    /// The length of the fixed format strings.
+    pub const LENGTH: usize = 10;
+
+    /// Generates a fixed format string for the kernel's [`_printk`].
+    ///
+    /// The format string is always the same for a given level, i.e. for a
+    /// given `prefix`, which are the kernel's `KERN_*` constants.
+    ///
+    /// [`_printk`]: ../../../../include/linux/printk.h
+    const fn generate(is_cont: bool, prefix: &[u8; 3]) -> [u8; LENGTH] {
+        // Ensure the `KERN_*` macros are what we expect.
+        assert!(prefix[0] == b'\x01');
+        if is_cont {
+            assert!(prefix[1] == b'c');
+        } else {
+            assert!(prefix[1] >= b'0' && prefix[1] <= b'7');
+        }
+        assert!(prefix[2] == b'\x00');
+
+        let suffix: &[u8; LENGTH - LENGTH_PREFIX] = if is_cont {
+            b"%pA\0\0\0\0\0"
+        } else {
+            b"%s: %pA\0"
+        };
+
+        [
+            prefix[0], prefix[1], suffix[0], suffix[1], suffix[2], suffix[3], suffix[4], suffix[5],
+            suffix[6], suffix[7],
+        ]
+    }
+
+    // Generate the format strings at compile-time.
+    //
+    // This avoids the compiler generating the contents on the fly in the stack.
+    //
+    // Furthermore, `static` instead of `const` is used to share the strings
+    // for all the kernel.
+    pub static EMERG: [u8; LENGTH] = generate(false, bindings::KERN_EMERG);
+    pub static INFO: [u8; LENGTH] = generate(false, bindings::KERN_INFO);
+}
+
+/// Prints a message via the kernel's [`_printk`].
+///
+/// Public but hidden since it should only be used from public macros.
+///
+/// # Safety
+///
+/// The format string must be one of the ones in [`format_strings`], and
+/// the module name must be null-terminated.
+///
+/// [`_printk`]: ../../../../include/linux/_printk.h
+#[doc(hidden)]
+#[cfg_attr(not(CONFIG_PRINTK), allow(unused_variables))]
+pub unsafe fn call_printk(
+    format_string: &[u8; format_strings::LENGTH],
+    module_name: &[u8],
+    args: fmt::Arguments<'_>,
+) {
+    // `_printk` does not seem to fail in any path.
+    #[cfg(CONFIG_PRINTK)]
+    unsafe {
+        bindings::_printk(
+            format_string.as_ptr() as _,
+            module_name.as_ptr(),
+            &args as *const _ as *const c_void,
+        );
+    }
+}
+
+/// Performs formatting and forwards the string to [`call_printk`].
+///
+/// Public but hidden since it should only be used from public macros.
+#[doc(hidden)]
+#[cfg(not(testlib))]
+#[macro_export]
+#[allow(clippy::crate_in_macro_def)]
+macro_rules! print_macro (
+    // The non-continuation cases (most of them, e.g. `INFO`).
+    ($format_string:path, $($arg:tt)+) => (
+        // SAFETY: This hidden macro should only be called by the documented
+        // printing macros which ensure the format string is one of the fixed
+        // ones. All `__LOG_PREFIX`s are null-terminated as they are generated
+        // by the `module!` proc macro or fixed values defined in a kernel
+        // crate.
+        unsafe {
+            $crate::print::call_printk(
+                &$format_string,
+                crate::__LOG_PREFIX,
+                format_args!($($arg)+),
+            );
+        }
+    );
+);
+
+/// Stub for doctests
+#[cfg(testlib)]
+#[macro_export]
+macro_rules! print_macro (
+    ($format_string:path, $e:expr, $($arg:tt)+) => (
+        ()
+    );
+);
+
+// We could use a macro to generate these macros. However, doing so ends
+// up being a bit ugly: it requires the dollar token trick to escape `$` as
+// well as playing with the `doc` attribute. Furthermore, they cannot be easily
+// imported in the prelude due to [1]. So, for the moment, we just write them
+// manually, like in the C side; while keeping most of the logic in another
+// macro, i.e. [`print_macro`].
+//
+// [1]: https://github.com/rust-lang/rust/issues/52234
+
+/// Prints an emergency-level message (level 0).
+///
+/// Use this level if the system is unusable.
+///
+/// Equivalent to the kernel's [`pr_emerg`] macro.
+///
+/// Mimics the interface of [`std::print!`]. See [`core::fmt`] and
+/// `alloc::format!` for information about the formatting syntax.
+///
+/// [`pr_emerg`]: https://www.kernel.org/doc/html/latest/core-api/printk-basics.html#c.pr_emerg
+/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html
+///
+/// # Examples
+///
+/// ```
+/// pr_emerg!("hello {}\n", "there");
+/// ```
+#[macro_export]
+macro_rules! pr_emerg (
+    ($($arg:tt)*) => (
+        $crate::print_macro!($crate::print::format_strings::EMERG, $($arg)*)
+    )
+);
+
+/// Prints an info-level message (level 6).
+///
+/// Use this level for informational messages.
+///
+/// Equivalent to the kernel's [`pr_info`] macro.
+///
+/// Mimics the interface of [`std::print!`]. See [`core::fmt`] and
+/// `alloc::format!` for information about the formatting syntax.
+///
+/// [`pr_info`]: https://www.kernel.org/doc/html/latest/core-api/printk-basics.html#c.pr_info
+/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html
+///
+/// # Examples
+///
+/// ```
+/// pr_info!("hello {}\n", "there");
+/// ```
+#[macro_export]
+#[doc(alias = "print")]
+macro_rules! pr_info (
+    ($($arg:tt)*) => (
+        $crate::print_macro!($crate::print::format_strings::INFO, $($arg)*)
+    )
+);
diff --git a/rust/kernel/str.rs b/rust/kernel/str.rs
new file mode 100644
index 000000000000..e45ff220ae50
--- /dev/null
+++ b/rust/kernel/str.rs
@@ -0,0 +1,72 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! String representations.
+
+use core::fmt;
+
+/// Allows formatting of [`fmt::Arguments`] into a raw buffer.
+///
+/// It does not fail if callers write past the end of the buffer so that they can calculate the
+/// size required to fit everything.
+///
+/// # Invariants
+///
+/// The memory region between `pos` (inclusive) and `end` (exclusive) is valid for writes if `pos`
+/// is less than `end`.
+pub(crate) struct RawFormatter {
+    // Use `usize` to use `saturating_*` functions.
+    #[allow(dead_code)]
+    beg: usize,
+    pos: usize,
+    end: usize,
+}
+
+impl RawFormatter {
+    /// Creates a new instance of [`RawFormatter`] with the given buffer pointers.
+    ///
+    /// # Safety
+    ///
+    /// If `pos` is less than `end`, then the region between `pos` (inclusive) and `end`
+    /// (exclusive) must be valid for writes for the lifetime of the returned [`RawFormatter`].
+    pub(crate) unsafe fn from_ptrs(pos: *mut u8, end: *mut u8) -> Self {
+        // INVARIANT: The safety requierments guarantee the type invariants.
+        Self {
+            beg: pos as _,
+            pos: pos as _,
+            end: end as _,
+        }
+    }
+
+    /// Returns the current insert position.
+    ///
+    /// N.B. It may point to invalid memory.
+    pub(crate) fn pos(&self) -> *mut u8 {
+        self.pos as _
+    }
+}
+
+impl fmt::Write for RawFormatter {
+    fn write_str(&mut self, s: &str) -> fmt::Result {
+        // `pos` value after writing `len` bytes. This does not have to be bounded by `end`, but we
+        // don't want it to wrap around to 0.
+        let pos_new = self.pos.saturating_add(s.len());
+
+        // Amount that we can copy. `saturating_sub` ensures we get 0 if `pos` goes past `end`.
+        let len_to_copy = core::cmp::min(pos_new, self.end).saturating_sub(self.pos);
+
+        if len_to_copy > 0 {
+            // SAFETY: If `len_to_copy` is non-zero, then we know `pos` has not gone past `end`
+            // yet, so it is valid for write per the type invariants.
+            unsafe {
+                core::ptr::copy_nonoverlapping(
+                    s.as_bytes().as_ptr(),
+                    self.pos as *mut u8,
+                    len_to_copy,
+                )
+            };
+        }
+
+        self.pos = pos_new;
+        Ok(())
+    }
+}
-- 
2.37.1


^ permalink raw reply related	[relevance 4%]

* [PATCH v9 26/27] samples: add first Rust examples
    2022-08-05 15:41  4% ` [PATCH v9 12/27] rust: add `kernel` crate Miguel Ojeda
@ 2022-08-05 15:42  6% ` Miguel Ojeda
  1 sibling, 0 replies; 77+ results
From: Miguel Ojeda @ 2022-08-05 15:42 UTC (permalink / raw)
  To: Linus Torvalds, Greg Kroah-Hartman
  Cc: rust-for-linux, linux-kernel, linux-fsdevel, patches,
	Jarkko Sakkinen, Miguel Ojeda, Alex Gaynor, Finn Behrens,
	Wedson Almeida Filho, Milan Landaverde, Boqun Feng, Gary Guo,
	Björn Roy Baron

The beginning of a set of Rust modules that showcase how Rust
modules look like and how to use the abstracted kernel features.

It also includes an example of a Rust host program with
several modules.

These samples also double as tests in the CI.

Co-developed-by: Alex Gaynor <alex.gaynor@gmail.com>
Signed-off-by: Alex Gaynor <alex.gaynor@gmail.com>
Co-developed-by: Finn Behrens <me@kloenk.de>
Signed-off-by: Finn Behrens <me@kloenk.de>
Co-developed-by: Wedson Almeida Filho <wedsonaf@google.com>
Signed-off-by: Wedson Almeida Filho <wedsonaf@google.com>
Co-developed-by: Milan Landaverde <milan@mdaverde.com>
Signed-off-by: Milan Landaverde <milan@mdaverde.com>
Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
---
 samples/Kconfig                   |  2 ++
 samples/Makefile                  |  1 +
 samples/rust/Kconfig              | 30 ++++++++++++++++++++++++
 samples/rust/Makefile             |  5 ++++
 samples/rust/hostprogs/.gitignore |  3 +++
 samples/rust/hostprogs/Makefile   |  5 ++++
 samples/rust/hostprogs/a.rs       |  7 ++++++
 samples/rust/hostprogs/b.rs       |  5 ++++
 samples/rust/hostprogs/single.rs  | 12 ++++++++++
 samples/rust/rust_minimal.rs      | 38 +++++++++++++++++++++++++++++++
 10 files changed, 108 insertions(+)
 create mode 100644 samples/rust/Kconfig
 create mode 100644 samples/rust/Makefile
 create mode 100644 samples/rust/hostprogs/.gitignore
 create mode 100644 samples/rust/hostprogs/Makefile
 create mode 100644 samples/rust/hostprogs/a.rs
 create mode 100644 samples/rust/hostprogs/b.rs
 create mode 100644 samples/rust/hostprogs/single.rs
 create mode 100644 samples/rust/rust_minimal.rs

diff --git a/samples/Kconfig b/samples/Kconfig
index 470ee3baf2e1..0d81c00289ee 100644
--- a/samples/Kconfig
+++ b/samples/Kconfig
@@ -263,6 +263,8 @@ config SAMPLE_CORESIGHT_SYSCFG
 	  This demonstrates how a user may create their own CoreSight
 	  configurations and easily load them into the system at runtime.
 
+source "samples/rust/Kconfig"
+
 endif # SAMPLES
 
 config HAVE_SAMPLE_FTRACE_DIRECT
diff --git a/samples/Makefile b/samples/Makefile
index 701e912ab5af..9832ef3f8fcb 100644
--- a/samples/Makefile
+++ b/samples/Makefile
@@ -35,3 +35,4 @@ subdir-$(CONFIG_SAMPLE_WATCH_QUEUE)	+= watch_queue
 obj-$(CONFIG_DEBUG_KMEMLEAK_TEST)	+= kmemleak/
 obj-$(CONFIG_SAMPLE_CORESIGHT_SYSCFG)	+= coresight/
 obj-$(CONFIG_SAMPLE_FPROBE)		+= fprobe/
+obj-$(CONFIG_SAMPLES_RUST)		+= rust/
diff --git a/samples/rust/Kconfig b/samples/rust/Kconfig
new file mode 100644
index 000000000000..841e0906e943
--- /dev/null
+++ b/samples/rust/Kconfig
@@ -0,0 +1,30 @@
+# SPDX-License-Identifier: GPL-2.0
+
+menuconfig SAMPLES_RUST
+	bool "Rust samples"
+	depends on RUST
+	help
+	  You can build sample Rust kernel code here.
+
+	  If unsure, say N.
+
+if SAMPLES_RUST
+
+config SAMPLE_RUST_MINIMAL
+	tristate "Minimal"
+	help
+	  This option builds the Rust minimal module sample.
+
+	  To compile this as a module, choose M here:
+	  the module will be called rust_minimal.
+
+	  If unsure, say N.
+
+config SAMPLE_RUST_HOSTPROGS
+	bool "Host programs"
+	help
+	  This option builds the Rust host program samples.
+
+	  If unsure, say N.
+
+endif # SAMPLES_RUST
diff --git a/samples/rust/Makefile b/samples/rust/Makefile
new file mode 100644
index 000000000000..1daba5f8658a
--- /dev/null
+++ b/samples/rust/Makefile
@@ -0,0 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0
+
+obj-$(CONFIG_SAMPLE_RUST_MINIMAL)		+= rust_minimal.o
+
+subdir-$(CONFIG_SAMPLE_RUST_HOSTPROGS)		+= hostprogs
diff --git a/samples/rust/hostprogs/.gitignore b/samples/rust/hostprogs/.gitignore
new file mode 100644
index 000000000000..a6c173da5048
--- /dev/null
+++ b/samples/rust/hostprogs/.gitignore
@@ -0,0 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0
+
+single
diff --git a/samples/rust/hostprogs/Makefile b/samples/rust/hostprogs/Makefile
new file mode 100644
index 000000000000..8ddcbd7416db
--- /dev/null
+++ b/samples/rust/hostprogs/Makefile
@@ -0,0 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0
+
+hostprogs-always-y := single
+
+single-rust := y
diff --git a/samples/rust/hostprogs/a.rs b/samples/rust/hostprogs/a.rs
new file mode 100644
index 000000000000..f7a4a3d0f4e0
--- /dev/null
+++ b/samples/rust/hostprogs/a.rs
@@ -0,0 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Rust single host program sample: module `a`.
+
+pub(crate) fn f(x: i32) {
+    println!("The number is {}.", x);
+}
diff --git a/samples/rust/hostprogs/b.rs b/samples/rust/hostprogs/b.rs
new file mode 100644
index 000000000000..c1675890648f
--- /dev/null
+++ b/samples/rust/hostprogs/b.rs
@@ -0,0 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Rust single host program sample: module `b`.
+
+pub(crate) const CONSTANT: i32 = 42;
diff --git a/samples/rust/hostprogs/single.rs b/samples/rust/hostprogs/single.rs
new file mode 100644
index 000000000000..8c48a119339a
--- /dev/null
+++ b/samples/rust/hostprogs/single.rs
@@ -0,0 +1,12 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Rust single host program sample.
+
+mod a;
+mod b;
+
+fn main() {
+    println!("Hello world!");
+
+    a::f(b::CONSTANT);
+}
diff --git a/samples/rust/rust_minimal.rs b/samples/rust/rust_minimal.rs
new file mode 100644
index 000000000000..54ad17685742
--- /dev/null
+++ b/samples/rust/rust_minimal.rs
@@ -0,0 +1,38 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Rust minimal sample.
+
+use kernel::prelude::*;
+
+module! {
+    type: RustMinimal,
+    name: b"rust_minimal",
+    author: b"Rust for Linux Contributors",
+    description: b"Rust minimal sample",
+    license: b"GPL",
+}
+
+struct RustMinimal {
+    numbers: Vec<i32>,
+}
+
+impl kernel::Module for RustMinimal {
+    fn init(_module: &'static ThisModule) -> Result<Self> {
+        pr_info!("Rust minimal sample (init)\n");
+        pr_info!("Am I built-in? {}\n", !cfg!(MODULE));
+
+        let mut numbers = Vec::new();
+        numbers.try_push(72)?;
+        numbers.try_push(108)?;
+        numbers.try_push(200)?;
+
+        Ok(RustMinimal { numbers })
+    }
+}
+
+impl Drop for RustMinimal {
+    fn drop(&mut self) {
+        pr_info!("My numbers are {:?}\n", self.numbers);
+        pr_info!("Rust minimal sample (exit)\n");
+    }
+}
-- 
2.37.1


^ permalink raw reply related	[relevance 6%]

* [PATCH 5.18 0000/1095] 5.18.18-rc1 review
@ 2022-08-15 17:49  1% Greg Kroah-Hartman
  2022-08-15 17:57  8% ` [PATCH 5.18 0453/1095] bpftool: Add missing link types Greg Kroah-Hartman
  0 siblings, 1 reply; 77+ results
From: Greg Kroah-Hartman @ 2022-08-15 17:49 UTC (permalink / raw)
  To: linux-kernel
  Cc: Greg Kroah-Hartman, stable, torvalds, akpm, linux, shuah,
	patches, lkft-triage, pavel, jonathanh, f.fainelli,
	sudipm.mukherjee, slade

This is the start of the stable review cycle for the 5.18.18 release.
There are 1095 patches in this series, all will be posted as a response
to this one.  If anyone has any issues with these being applied, please
let me know.

Responses should be made by Wed, 17 Aug 2022 18:01:29 +0000.
Anything received after that time might be too late.

The whole patch series can be found in one patch at:
	https://www.kernel.org/pub/linux/kernel/v5.x/stable-review/patch-5.18.18-rc1.gz
or in the git tree and branch at:
	git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable-rc.git linux-5.18.y
and the diffstat can be found below.

thanks,

greg k-h

-------------
Pseudo-Shortlog of commits:

Greg Kroah-Hartman <gregkh@linuxfoundation.org>
    Linux 5.18.18-rc1

Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
    Bluetooth: L2CAP: Fix l2cap_global_chan_by_psm regression

Pavel Begunkov <asml.silence@gmail.com>
    io_uring: mem-account pbuf buckets

Ye Bin <yebin10@huawei.com>
    f2fs: fix null-ptr-deref in f2fs_get_dnode_of_data

Tom Rix <trix@redhat.com>
    drm/vc4: change vc4_dma_range_matches from a global to static

Daeho Jeong <daehojeong@google.com>
    f2fs: revive F2FS_IOC_ABORT_VOLATILE_WRITE

Lukas Wunner <lukas@wunner.de>
    net: phy: smsc: Disable Energy Detect Power-Down in interrupt mode

Kumar Kartikeya Dwivedi <memxor@gmail.com>
    bpf: Suppress 'passing zero to PTR_ERR' warning

Kumar Kartikeya Dwivedi <memxor@gmail.com>
    bpf: Fix sparse warning for bpf_kptr_xchg_proto

Marek Vasut <marex@denx.de>
    drm/bridge: tc358767: Fix (e)DP bridge endpoint parsing in dedicated function

Russell Currey <ruscur@russell.cc>
    powerpc/kexec: Fix build failure from uninitialised variable

Alexander Gordeev <agordeev@linux.ibm.com>
    Revert "s390/smp: enforce lowcore protection on CPU restart"

Vladimir Oltean <vladimir.oltean@nxp.com>
    net: dsa: felix: fix min gate len calculation for tc when its first gate is closed

Steven Rostedt (Google) <rostedt@goodmis.org>
    tracing: Use a copy of the va_list for __assign_vstr()

Paolo Abeni <pabeni@redhat.com>
    mptcp: refine memory scheduling

Greg Kroah-Hartman <gregkh@linuxfoundation.org>
    Revert "mwifiex: fix sleep in atomic context bugs caused by dev_coredumpv"

Eric Dumazet <edumazet@google.com>
    raw: fix a typo in raw_icmp_error()

Eric Dumazet <edumazet@google.com>
    raw: remove unused variables from raw6_icmp_error()

Jason A. Donenfeld <Jason@zx2c4.com>
    crypto: lib/blake2s - reduce stack frame usage in self test

Eric Dumazet <edumazet@google.com>
    tcp: fix over estimation in sk_forced_mem_schedule()

Thadeu Lima de Souza Cascardo <cascardo@canonical.com>
    net_sched: cls_route: remove from list when handle is 0

Naohiro Aota <naohiro.aota@wdc.com>
    btrfs: convert count_max_extents() to use fs_info->max_extent_size

Filipe Manana <fdmanana@suse.com>
    btrfs: join running log transaction when logging new name

Christophe Leroy <christophe.leroy@csgroup.eu>
    powerpc: Fix eh field when calling lwarx on PPC32

SeongJae Park <sj@kernel.org>
    xen-blkfront: Apply 'feature_persistent' parameter when connect

Maximilian Heyne <mheyne@amazon.de>
    xen-blkback: Apply 'feature_persistent' parameter when connect

SeongJae Park <sj@kernel.org>
    xen-blkback: fix persistent grants negotiation

Mårten Lindahl <marten.lindahl@axis.com>
    tpm: Add check for Failure mode for TPM2 modules

Huacai Chen <chenhuacai@kernel.org>
    tpm: eventlog: Fix section mismatch for DEBUG_SECTION_MISMATCH

Tianjia Zhang <tianjia.zhang@linux.alibaba.com>
    KEYS: asymmetric: enforce SM2 signature use pkey algo

Jan Kara <jack@suse.cz>
    ext4: fix race when reusing xattr blocks

Jan Kara <jack@suse.cz>
    ext4: unindent codeblock in ext4_xattr_block_set()

Shuqi Zhang <zhangshuqi3@huawei.com>
    ext4: use kmemdup() to replace kmalloc + memcpy

Jan Kara <jack@suse.cz>
    ext4: remove EA inode entry from mbcache on inode eviction

Lukas Czerner <lczerner@redhat.com>
    ext4: make sure ext4_append() always allocates new block

Lukas Czerner <lczerner@redhat.com>
    ext4: check if directory block is within i_size

Ye Bin <yebin10@huawei.com>
    ext4: fix warning in ext4_iomap_begin as race between bmap and write

Baokun Li <libaokun1@huawei.com>
    ext4: correct the misjudgment in ext4_iget_extra_inode

Baokun Li <libaokun1@huawei.com>
    ext4: correct max_inline_xattr_value_size computing

Baokun Li <libaokun1@huawei.com>
    ext4: fix use-after-free in ext4_xattr_set_entry

Baokun Li <libaokun1@huawei.com>
    ext4: add EXT4_INODE_HAS_XATTR_SPACE macro in xattr.h

Eric Whitney <enwlinux@gmail.com>
    ext4: fix extent status tree race in writeback error recovery path

Theodore Ts'o <tytso@mit.edu>
    ext4: update s_overhead_clusters in the superblock during an on-line resize

Hyunchul Lee <hyc.lee@gmail.com>
    ksmbd: prevent out of bound read for SMB2_WRITE

Namjae Jeon <linkinjeon@kernel.org>
    ksmbd: fix wrong smbd max read/write size check

Namjae Jeon <linkinjeon@kernel.org>
    ksmbd: add smbd max io size parameter

Hyunchul Lee <hyc.lee@gmail.com>
    ksmbd: smbd: introduce read/write credits for RDMA read/write

Hyunchul Lee <hyc.lee@gmail.com>
    ksmbd: smbd: change prototypes of RDMA read/write related functions

Marios Makassikis <mmakassikis@freebox.fr>
    ksmbd: validate length in smb2_write()

Steven Rostedt (Google) <rostedt@goodmis.org>
    tracing: Use a struct alignof to determine trace event field alignment

Steven Rostedt (Google) <rostedt@goodmis.org>
    batman-adv: tracing: Use the new __vstring() helper

Miaohe Lin <linmiaohe@huawei.com>
    hugetlb_cgroup: fix wrong hugetlb cgroup numa stat

Jianglei Nie <niejianglei2021@163.com>
    mm/damon/reclaim: fix potential memory leak in damon_reclaim_init()

Mikulas Patocka <mpatocka@redhat.com>
    dm raid: fix address sanitizer warning in raid_resume

Mikulas Patocka <mpatocka@redhat.com>
    dm raid: fix address sanitizer warning in raid_status

Sean Christopherson <seanjc@google.com>
    KVM: nVMX: Attempt to load PERF_GLOBAL_CTRL on nVMX xfer iff it exists

Sean Christopherson <seanjc@google.com>
    KVM: VMX: Add helper to check if the guest PMU has PERF_GLOBAL_CTRL

Like Xu <likexu@tencent.com>
    KVM: x86/pmu: Ignore pmu->global_ctrl check if vPMU doesn't support global_ctrl

Sean Christopherson <seanjc@google.com>
    KVM: VMX: Mark all PERF_GLOBAL_(OVF)_CTRL bits reserved if there's no vPMU

Like Xu <like.xu@linux.intel.com>
    KVM: x86/pmu: Introduce the ctrl_mask value for fixed counter

Sumanth Korikkar <sumanthk@linux.ibm.com>
    s390/unwind: fix fgraph return address recovery

Jason A. Donenfeld <Jason@zx2c4.com>
    powerpc/powernv/kvm: Use darn for H_RANDOM on Power9

Rafael J. Wysocki <rafael.j.wysocki@intel.com>
    ACPI: CPPC: Do not prevent CPPC from working in the future

Artem Bityutskiy <artem.bityutskiy@linux.intel.com>
    intel_idle: make SPR C1 and C1E be independent

Zhang Rui <rui.zhang@intel.com>
    intel_idle: Add AlderLake support

Naohiro Aota <naohiro.aota@wdc.com>
    btrfs: zoned: wait until zone is finished when allocation didn't progress

Naohiro Aota <naohiro.aota@wdc.com>
    btrfs: zoned: write out partially allocated region

Naohiro Aota <naohiro.aota@wdc.com>
    btrfs: zoned: activate necessary block group

Naohiro Aota <naohiro.aota@wdc.com>
    btrfs: zoned: activate metadata block group on flush_space

Naohiro Aota <naohiro.aota@wdc.com>
    btrfs: zoned: introduce space_info->active_total_bytes

Stefan Roesch <shr@fb.com>
    btrfs: store chunk size in space-info struct

Naohiro Aota <naohiro.aota@wdc.com>
    btrfs: zoned: introduce btrfs_zoned_bg_is_full

Josef Bacik <josef@toxicpanda.com>
    btrfs: make the bg_reclaim_threshold per-space info

Naohiro Aota <naohiro.aota@wdc.com>
    btrfs: zoned: disable metadata overcommit for zoned

Naohiro Aota <naohiro.aota@wdc.com>
    btrfs: zoned: finish least available block group on data bg allocation

Naohiro Aota <naohiro.aota@wdc.com>
    btrfs: let can_allocate_chunk return error

Naohiro Aota <naohiro.aota@wdc.com>
    btrfs: replace BTRFS_MAX_EXTENT_SIZE with fs_info->max_extent_size

Naohiro Aota <naohiro.aota@wdc.com>
    btrfs: zoned: revive max_zone_append_bytes

Naohiro Aota <naohiro.aota@wdc.com>
    block: add bdev_max_segments() helper

Christoph Hellwig <hch@lst.de>
    block: add a bdev_max_zone_append_sectors helper

Nikolay Borisov <nborisov@suse.com>
    btrfs: properly flag filesystem with BTRFS_FEATURE_INCOMPAT_BIG_METADATA

Josef Bacik <josef@toxicpanda.com>
    btrfs: reset block group chunk force if we have to wait

Naohiro Aota <naohiro.aota@wdc.com>
    btrfs: fix error handling of fallback uncompress write

Naohiro Aota <naohiro.aota@wdc.com>
    btrfs: ensure pages are unlocked on cow_file_range() failure

Josef Bacik <josef@toxicpanda.com>
    btrfs: tree-log: make the return value for log syncing consistent

Jinke Han <hanjinke.666@bytedance.com>
    block: don't allow the same type rq_qos add more than once

Christoph Hellwig <hch@lst.de>
    block: serialize all debugfs operations using q->debugfs_mutex

Chen Zhongjin <chenzhongjin@huawei.com>
    locking/csd_lock: Change csdlock_debug from early_param to __setup

Jason A. Donenfeld <Jason@zx2c4.com>
    timekeeping: contribute wall clock to rng on time change

Tyler Hicks <tyhicks@linux.microsoft.com>
    net/9p: Initialize the iounit field during fid creation

Luo Meng <luomeng12@huawei.com>
    dm thin: fix use-after-free crash in dm_sm_register_threshold_callback

Steven Rostedt (Google) <rostedt@goodmis.org>
    tracing/events: Add __vstring() and __assign_vstr() helper macros

Michal Suchanek <msuchanek@suse.de>
    kexec, KEYS, s390: Make use of built-in and secondary keyring for signature verification

Coiby Xu <coxu@redhat.com>
    kexec: clean up arch_kexec_kernel_verify_sig

Naveen N. Rao <naveen.n.rao@linux.vnet.ibm.com>
    kexec_file: drop weak attribute from functions

Mikulas Patocka <mpatocka@redhat.com>
    dm writecache: set a default MAX_WRITEBACK_JOBS

Cameron Williams <cang1@live.co.uk>
    tty: 8250: Add support for Brainboxes PX cards.

Maciej W. Rozycki <macro@orcam.me.uk>
    serial: 8250: Add proper clock handling for OxSemi PCIe devices

Maciej W. Rozycki <macro@orcam.me.uk>
    serial: 8250: Fold EndRun device support into OxSemi Tornado code

Robert Marko <robimarko@gmail.com>
    PCI: qcom: Power on PHY before IPQ8074 DBI register accesses

Mohamed Khalfella <mkhalfella@purestorage.com>
    PCI/AER: Iterate over error counters instead of error strings

Alexander Lobakin <alexandr.lobakin@intel.com>
    iommu/vt-d: avoid invalid memory access via node_online(NUMA_NO_NODE)

Sean Christopherson <seanjc@google.com>
    KVM: x86: Signal #GP, not -EPERM, on bad WRMSR(MCi_CTL/STATUS)

Lev Kujawski <lkujaw@member.fsf.org>
    KVM: set_msr_mce: Permit guests to ignore single-bit ECC errors

Alexander Shishkin <alexander.shishkin@linux.intel.com>
    intel_th: pci: Add Raptor Lake-S CPU support

Alexander Shishkin <alexander.shishkin@linux.intel.com>
    intel_th: pci: Add Raptor Lake-S PCH support

Alexander Shishkin <alexander.shishkin@linux.intel.com>
    intel_th: pci: Add Meteor Lake-P support

Sudeep Holla <sudeep.holla@arm.com>
    firmware: arm_scpi: Ensure scpi_info is not assigned if the probe fails

Lukas Wunner <lukas@wunner.de>
    usbnet: smsc95xx: Fix deadlock on runtime resume

Lukas Wunner <lukas@wunner.de>
    usbnet: smsc95xx: Forward PHY interrupts to PHY driver to avoid polling

Lukas Wunner <lukas@wunner.de>
    usbnet: smsc95xx: Avoid link settings race on interrupt reception

Lukas Wunner <lukas@wunner.de>
    usbnet: smsc95xx: Don't clear read-only PHY interrupt

Dave Stevenson <dave.stevenson@raspberrypi.com>
    drm/vc4: drv: Adopt the dma configuration from the HVS or V3D component

Imre Deak <imre.deak@intel.com>
    drm/dp/mst: Read the extended DPCD capabilities during system resume

Jason A. Donenfeld <Jason@zx2c4.com>
    crypto: blake2s - remove shash module

Jitao Shi <jitao.shi@mediatek.com>
    drm/mediatek: Keep dsi as LP00 before dcs cmds transfer

Phil Auld <pauld@redhat.com>
    drivers/base: fix userspace break from using bin_attributes for cpumap and cpulist

David Collins <quic_collinsd@quicinc.com>
    spmi: trace: fix stack-out-of-bound access in SPMI tracing functions

Al Viro <viro@zeniv.linux.org.uk>
    __follow_mount_rcu(): verify that mount_lock remains unchanged

Xie Shaowen <studentxswpy@163.com>
    Input: gscps2 - check return value of ioremap() in gscps2_probe()

Thadeu Lima de Souza Cascardo <cascardo@canonical.com>
    posix-cpu-timers: Cleanup CPU timers before freeing them during exec

Bharath SM <bharathsm@microsoft.com>
    SMB3: fix lease break timeout when multiple deferred close handles for the same file.

Alexander Lobakin <alexandr.lobakin@intel.com>
    x86/olpc: fix 'logical not is only applied to the left hand side'

Masami Hiramatsu (Google) <mhiramat@kernel.org>
    x86/kprobes: Update kcb status flag after singlestepping

Steven Rostedt (Google) <rostedt@goodmis.org>
    ftrace/x86: Add back ftrace_expected assignment

Kim Phillips <kim.phillips@amd.com>
    x86/bugs: Enable STIBP for IBPB mitigated RETBleed

Arun Easi <aeasi@marvell.com>
    scsi: qla2xxx: Fix losing FCP-2 targets during port perturbation tests

Arun Easi <aeasi@marvell.com>
    scsi: qla2xxx: Fix losing target when it reappears during delete

Arun Easi <aeasi@marvell.com>
    scsi: qla2xxx: Fix losing FCP-2 targets on long port disable with I/Os

Quinn Tran <qutran@marvell.com>
    scsi: qla2xxx: Wind down adapter after PCIe error

Quinn Tran <qutran@marvell.com>
    scsi: qla2xxx: Fix erroneous mailbox timeout after PCI error injection

Arun Easi <aeasi@marvell.com>
    scsi: qla2xxx: Fix excessive I/O error messages by default

Arun Easi <aeasi@marvell.com>
    scsi: qla2xxx: Fix crash due to stale SRB access around I/O timeouts

Quinn Tran <qutran@marvell.com>
    scsi: qla2xxx: Turn off multi-queue for 8G adapters

Arun Easi <aeasi@marvell.com>
    scsi: qla2xxx: Fix discovery issues in FC-AL topology

Quinn Tran <qutran@marvell.com>
    scsi: qla2xxx: Fix imbalance vha->vref_count

Steffen Maier <maier@linux.ibm.com>
    scsi: zfcp: Fix missing auto port scan and thus missing target ports

Peter Wang <peter.wang@mediatek.com>
    scsi: ufs: core: Correct ufshcd_shutdown() flow

Zheyu Ma <zheyuma97@gmail.com>
    video: fbdev: s3fb: Check the size of screen before memset_io()

Zheyu Ma <zheyuma97@gmail.com>
    video: fbdev: arkfb: Check the size of screen before memset_io()

Zheyu Ma <zheyuma97@gmail.com>
    video: fbdev: vt8623fb: Check the size of screen before memset_io()

Jaewook Kim <jw5454.kim@samsung.com>
    f2fs: do not allow to decompress files have FI_COMPRESS_RELEASED

Sungjong Seo <sj1557.seo@samsung.com>
    f2fs: allow compression for mmap files in compress_mode=user

Andrea Righi <andrea.righi@canonical.com>
    x86/entry: Build thunk_$(BITS) only if CONFIG_PREEMPTION=y

Mel Gorman <mgorman@techsingularity.net>
    sched/core: Do not requeue task on CPU excluded from cpus_mask

Tianchen Ding <dtcccc@linux.alibaba.com>
    sched: Remove the limitation of WF_ON_CPU on wakelist if wakee cpu is idle

Tianchen Ding <dtcccc@linux.alibaba.com>
    sched: Fix the check of nr_running at queue wakelist

Florian Fainelli <f.fainelli@gmail.com>
    tools/thermal: Fix possible path truncations

Zheyu Ma <zheyuma97@gmail.com>
    video: fbdev: arkfb: Fix a divide-by-zero bug in ark_set_pixclock()

Siddh Raman Pant <code@siddh.me>
    x86/numa: Use cpumask_available instead of hardcoded NULL check

Waiman Long <longman@redhat.com>
    sched, cpuset: Fix dl_cpu_busy() panic due to empty cs->cpus_allowed

Michael Ellerman <mpe@ellerman.id.au>
    powerpc/64e: Fix kexec build error

Josh Poimboeuf <jpoimboe@kernel.org>
    scripts/faddr2line: Fix vmlinux detection on arm64

Arnaldo Carvalho de Melo <acme@redhat.com>
    genelf: Use HAVE_LIBCRYPTO_SUPPORT, not the never defined HAVE_LIBCRYPTO

Michael Ellerman <mpe@ellerman.id.au>
    powerpc/pci: Fix PHB numbering when using opal-phbid

Chenyi Qiang <chenyi.qiang@intel.com>
    x86/bus_lock: Don't assume the init value of DEBUGCTLMSR.BUS_LOCK_DETECT to be zero

Chen Zhongjin <chenzhongjin@huawei.com>
    kprobes: Forbid probing on trampoline and BPF code areas

Ian Rogers <irogers@google.com>
    perf symbol: Fail to read phdr workaround

Miaoqian Lin <linmq006@gmail.com>
    powerpc/cell/axon_msi: Fix refcount leak in setup_msi_msg_address

Miaoqian Lin <linmq006@gmail.com>
    powerpc/xive: Fix refcount leak in xive_get_max_prio

Miaoqian Lin <linmq006@gmail.com>
    powerpc/spufs: Fix refcount leak in spufs_init_isolated_loader

Matthew Wilcox (Oracle) <willy@infradead.org>
    cifs: Fix memory leak when using fscache

Chao Liu <liuchao@coolpad.com>
    f2fs: fix to remove F2FS_COMPR_FL and tag F2FS_NOCOMP_FL at the same time

Chao Yu <chao@kernel.org>
    f2fs: fix to check inline_data during compressed inode conversion

Jaegeuk Kim <jaegeuk@kernel.org>
    f2fs: kill volatile write support

Daeho Jeong <daehojeong@google.com>
    f2fs: change the current atomic write way

Chao Yu <chao@kernel.org>
    f2fs: give priority to select unpinned section for foreground GC

Byungki Lee <dominicus79@gmail.com>
    f2fs: write checkpoint during FG_GC

Chao Yu <chao@kernel.org>
    f2fs: don't set GC_FAILURE_PIN for background GC

Chao Yu <chao@kernel.org>
    f2fs: check pinfile in gc_data_segment() in advance

Chao Yu <chao@kernel.org>
    f2fs: fix to invalidate META_MAPPING before DIO write

Kan Liang <kan.liang@linux.intel.com>
    perf stat: Revert "perf stat: Add default hybrid events"

Alexander Gordeev <agordeev@linux.ibm.com>
    s390/smp: enforce lowcore protection on CPU restart

Sherry Sun <sherry.sun@nxp.com>
    tty: serial: fsl_lpuart: correct the count of break characters

Guo Mengqi <guomengqi3@huawei.com>
    serial: 8250_bcm2835aux: Add missing clk_disable_unprepare()

Pali Rohár <pali@kernel.org>
    powerpc/pci: Prefer PCI domain assignment via DT 'linux,pci-domain' and alias

Alexey Kardashevskiy <aik@ozlabs.ru>
    powerpc/iommu: Fix iommu_table_in_use for a small default DMA window case

Alexey Kardashevskiy <aik@ozlabs.ru>
    pseries/iommu/ddw: Fix kdump to work in absence of ibm,dma-window

Julia Lawall <Julia.Lawall@inria.fr>
    powerpc: fix typos in comments

Christophe Leroy <christophe.leroy@csgroup.eu>
    powerpc/32: Do not allow selection of e5500 or e6500 CPUs on PPC32

Christophe Leroy <christophe.leroy@csgroup.eu>
    powerpc/32s: Fix boot failure with KASAN + SMP + JUMP_LABEL_FEATURE_CHECK_DEBUG

Christophe Leroy <christophe.leroy@csgroup.eu>
    powerpc/32: Call mmu_mark_initmem_nx() regardless of data block mapping.

Claudiu Beznea <claudiu.beznea@microchip.com>
    ASoC: mchp-spdifrx: disable end of block interrupt on failures

Rustam Subkhankulov <subkhankulov@ispras.ru>
    video: fbdev: sis: fix typos in SiS_GetModeID()

Liang He <windhl@126.com>
    video: fbdev: amba-clcd: Fix refcount leak bugs

Yong Zhi <yong.zhi@intel.com>
    ASoC: Intel: sof_rt5682: Perform quirk check first in card late probe

William Dean <williamsukatube@gmail.com>
    watchdog: armada_37xx_wdt: check the return value of devm_ioremap() in armada_37xx_wdt_probe()

Jean Delvare <jdelvare@suse.de>
    watchdog: sp5100_tco: Fix a memory leak of EFCH MMIO resource

Jiasheng Jiang <jiasheng@iscas.ac.cn>
    watchdog: f71808e_wdt: Add check for platform_driver_register

Liang He <windhl@126.com>
    ASoC: audio-graph-card2: Add of_node_put() in fail path

Liang He <windhl@126.com>
    ASoC: audio-graph-card: Add of_node_put() in fail path

Xie Yongji <xieyongji@bytedance.com>
    fuse: Remove the control interface for virtio-fs

Christophe JAILLET <christophe.jaillet@wanadoo.fr>
    ASoC: qcom: q6dsp: Fix an off-by-one in q6adm_alloc_copp()

Shengjiu Wang <shengjiu.wang@nxp.com>
    ASoC: imx-card: use snd_pcm_format_t type for asrc_format

Shengjiu Wang <shengjiu.wang@nxp.com>
    ASoC: fsl_easrc: use snd_pcm_format_t type for sample_format

Shengjiu Wang <shengjiu.wang@nxp.com>
    ASoC: fsl-asoc-card: force cast the asrc_format type

Shengjiu Wang <shengjiu.wang@nxp.com>
    ASoC: fsl_asrc: force cast the asrc_format type

Alexander Gordeev <agordeev@linux.ibm.com>
    s390/zcore: fix race when reading from hardware system area

Alexander Gordeev <agordeev@linux.ibm.com>
    s390/crash: fix incorrect number of bytes to copy to user space

Sunil V L <sunilvl@ventanamicro.com>
    riscv: spinwait: Fix hartid variable type

Adrian Hunter <adrian.hunter@intel.com>
    perf tools: Fix dso_id inode generation comparison

Liang He <windhl@126.com>
    iommu/arm-smmu: qcom_iommu: Add of_node_put() when breaking out of loop

Miaoqian Lin <linmq006@gmail.com>
    mfd: max77620: Fix refcount leak in max77620_initialise_fps

Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
    mfd: t7l66xb: Drop platform disable callback

Sibi Sankar <quic_sibis@quicinc.com>
    remoteproc: sysmon: Wait for SSCTL service to come up

Siddharth Gupta <sidgup@codeaurora.org>
    remoteproc: qcom: pas: Check if coredump is enabled

Zhihao Cheng <chengzhihao1@huawei.com>
    proc: fix a dentry lock race between release_task and lookup

Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
    lib/smp_processor_id: fix imbalanced instrumentation_end() call

Dan Carpenter <dan.carpenter@oracle.com>
    kfifo: fix kfifo_to_user() return type

Miaoqian Lin <linmq006@gmail.com>
    rpmsg: qcom_smd: Fix refcount leak in qcom_smd_parse_edge

Florian Fainelli <f.fainelli@gmail.com>
    MIPS: Fixed __debug_virt_addr_valid()

Hangyu Hua <hbh25y@gmail.com>
    net: 9p: fix refcount leak in p9_read_work() error handling

Kent Overstreet <kent.overstreet@gmail.com>
    9p: Add client parameter to p9_req_put()

Kent Overstreet <kent.overstreet@gmail.com>
    9p: Drop kref usage

Sam Protsenko <semen.protsenko@linaro.org>
    iommu/exynos: Handle failed IOMMU device registration properly

Doug Berger <opendmb@gmail.com>
    serial: 8250_bcm7271: Save/restore RTS in suspend/resume

Liang He <windhl@126.com>
    ASoC: mt6359: Fix refcount leak bug

Liang He <windhl@126.com>
    ASoc: audio-graph-card2: Fix refcount leak bug in __graph_get_type()

Peter Ujfalusi <peter.ujfalusi@linux.intel.com>
    ASoC: SOF: ipc3-topology: Prevent double freeing of ipc_control_data via load_bytes

Robin Murphy <robin.murphy@arm.com>
    swiotlb: fail map correctly with failed io_tlb_default_mem

YC Hung <yc.hung@mediatek.com>
    ASoC: SOF: mediatek: fix mt8195 StatvectorSel wrong setting

Florian Fainelli <f.fainelli@gmail.com>
    MIPS: vdso: Utilize __pa() for gic_pfn

Daniel Starke <daniel.starke@siemens.com>
    tty: n_gsm: fix missing corner cases in gsmld_poll()

Daniel Starke <daniel.starke@siemens.com>
    tty: n_gsm: fix flow control handling in tx path

Daniel Starke <daniel.starke@siemens.com>
    tty: n_gsm: fix DM command

Daniel Starke <daniel.starke@siemens.com>
    tty: n_gsm: fix wrong T1 retry count handling

Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
    serial: 8250_fsl: Don't report FE, PE and OE twice

Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
    ASoC: audio-graph-card2.c: use of_property_read_u32() for rate

Eric Farman <farman@linux.ibm.com>
    vfio/ccw: Do not change FSM state in subchannel event

Eric Farman <farman@linux.ibm.com>
    vfio/ccw: Fix FSM state if mdev probe fails

Sireesh Kodali <sireeshkodali1@gmail.com>
    remoteproc: qcom: wcnss: Fix handling of IRQs

Shengjiu Wang <shengjiu.wang@nxp.com>
    ASoC: imx-card: Fix DSD/PDM mclk frequency

Tiezhu Yang <yangtiezhu@loongson.cn>
    MIPS: Loongson64: Fix section mismatch warning

Liang He <windhl@126.com>
    ASoC: qcom: Fix missing of_node_put() in asoc_qcom_lpass_cpu_platform_probe()

Daniel Starke <daniel.starke@siemens.com>
    tty: n_gsm: fix resource allocation order in gsm_activate_mux()

Daniel Starke <daniel.starke@siemens.com>
    tty: n_gsm: fix deadlock and link starvation in outgoing data path

Daniel Starke <daniel.starke@siemens.com>
    tty: n_gsm: fix race condition in gsmld_write()

Daniel Starke <daniel.starke@siemens.com>
    tty: n_gsm: fix packet re-transmission without open control channel

Daniel Starke <daniel.starke@siemens.com>
    tty: n_gsm: fix non flow control frames during mux flow off

Daniel Starke <daniel.starke@siemens.com>
    tty: n_gsm: fix missing timer to handle stalled links

Daniel Starke <daniel.starke@siemens.com>
    tty: n_gsm: fix wrong queuing behavior in gsm_dlci_data_output()

Daniel Starke <daniel.starke@siemens.com>
    tty: n_gsm: fix tty registration before control channel open

Daniel Starke <daniel.starke@siemens.com>
    tty: n_gsm: fix user open not possible at responder until initiator open

Alexander Lobakin <alexandr.lobakin@intel.com>
    net/ice: fix initializing the bitmap in the switch code

Jason Gunthorpe <jgg@ziepe.ca>
    vfio/pci: Have all VFIO PCI drivers store the vfio_pci_core_device in drvdata

Yishai Hadas <yishaih@nvidia.com>
    net/mlx5: Expose mlx5_sriov_blocking_notifier_register / unregister APIs

Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
    ASoC: codecs: wsa881x: handle timeouts in resume path

Tom Rix <trix@redhat.com>
    ASoC: samsung: change gpiod_speaker_power and rx1950_audio from global to static variables

Athira Rajeev <atrajeev@linux.vnet.ibm.com>
    powerpc/perf: Optimize clearing the pending PMI and remove WARN_ON for PMI check in power_pmu_disable

Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
    ASoC: samsung: h1940_uda1380: include proepr GPIO consumer header

Michael Ellerman <mpe@ellerman.id.au>
    selftests/powerpc: Skip energy_scale_info test on older firmware

Miaoqian Lin <linmq006@gmail.com>
    remoteproc: imx_rproc: Fix refcount leak in imx_rproc_addr_init

Chen Zhongjin <chenzhongjin@huawei.com>
    profiling: fix shift too large makes kernel panic

Joe Lawrence <joe.lawrence@redhat.com>
    selftests/livepatch: better synchronize test_klp_callbacks_busy

Miaoqian Lin <linmq006@gmail.com>
    remoteproc: k3-r5: Fix refcount leak in k3_r5_cluster_of_init

AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
    rpmsg: mtk_rpmsg: Fix circular locking dependency

Shengjiu Wang <shengjiu.wang@nxp.com>
    rpmsg: char: Add mutex protection for rpmsg_eptdev_open()

Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
    ASoC: codecs: wcd9335: move gains from SX_TLV to S8_TLV

Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
    ASoC: codecs: msm8916-wcd-digital: move gains from SX_TLV to S8_TLV

Peter Ujfalusi <peter.ujfalusi@linux.intel.com>
    ASoC: SOF: make ctx_store and ctx_restore as optional

Maciej W. Rozycki <macro@orcam.me.uk>
    serial: 8250: Export ICR access helpers for internal use

Yang Yingliang <yangyingliang@huawei.com>
    serial: pic32: fix missing clk_disable_unprepare() on error in pic32_uart_startup()

Jiri Slaby <jirislaby@kernel.org>
    serial: pic32: free up irq names correctly

Miaoqian Lin <linmq006@gmail.com>
    ASoC: mediatek: mt8173-rt5650: Fix refcount leak in mt8173_rt5650_dev_probe

Jiasheng Jiang <jiasheng@iscas.ac.cn>
    ASoC: codecs: da7210: add check for i2c_add_driver

Miaoqian Lin <linmq006@gmail.com>
    ASoC: mt6797-mt6351: Fix refcount leak in mt6797_mt6351_dev_probe

Miaoqian Lin <linmq006@gmail.com>
    ASoC: mediatek: mt8173: Fix refcount leak in mt8173_rt5650_rt5676_dev_probe

Fabio Estevam <festevam@gmail.com>
    ASoC: imx-audmux: Silence a clang warning

Miaoqian Lin <linmq006@gmail.com>
    ASoC: samsung: Fix error handling in aries_audio_probe

Miaoqian Lin <linmq006@gmail.com>
    ASoC: cros_ec_codec: Fix refcount leak in cros_ec_codec_platform_probe

Tang Bin <tangbin@cmss.chinamobile.com>
    opp: Fix error check in dev_pm_opp_attach_genpd()

Nathan Chancellor <nathan@kernel.org>
    usb: cdns3: Don't use priv_dev uninitialized in cdns3_gadget_ep_enable()

Zhihao Cheng <chengzhihao1@huawei.com>
    jbd2: fix assertion 'jh->b_frozen_data == NULL' failure when journal aborted

Li Lingfeng <lilingfeng3@huawei.com>
    ext4: recover csum seed of tmp_inode after migrating to extents

Zhang Yi <yi.zhang@huawei.com>
    jbd2: fix outstanding credits assert in jbd2_journal_commit_transaction()

Keith Busch <kbusch@kernel.org>
    block: ensure iov_iter advances for added pages

Keith Busch <kbusch@kernel.org>
    block/bio: remove duplicate append pages code

Christoph Hellwig <hch@lst.de>
    nvme: catch -ENODEV from nvme_revalidate_zones again

Nick Bowler <nbowler@draconx.ca>
    nvme: define compat_ioctl again to unbreak 32-bit userspace.

Bean Huo <beanhuo@micron.com>
    nvme: use command_id instead of req->tag in trace_nvme_complete_rq()

Dan Carpenter <dan.carpenter@oracle.com>
    null_blk: fix ida error handling in null_add_dev()

Md Haris Iqbal <haris.iqbal@ionos.com>
    block/rnbd-srv: Set keep_id to true after mutex_trylock

Zhu Yanjun <yanjun.zhu@linux.dev>
    RDMA/rxe: Fix error unwind in rxe_create_qp()

Maor Gottlieb <maorg@nvidia.com>
    RDMA/mlx5: Add missing check for return value in get namespace flow

Xu Qiang <xuqiang36@huawei.com>
    of/fdt: declared return type does not match actual return type

Andrei Vagin <avagin@google.com>
    selftests: kvm: set rax before vmcall

Andreas Schwab <schwab@suse.de>
    rtla: Fix double free

Daniel Bristot de Oliveira <bristot@kernel.org>
    rtla: Fix Makefile when called from -C tools/

Dan Carpenter <dan.carpenter@oracle.com>
    selftest/vm: uninitialized variable in main()

Dan Carpenter <dan.carpenter@oracle.com>
    tools/testing/selftests/vm/hugetlb-madvise.c: silence uninitialized variable warning

Miaohe Lin <linmiaohe@huawei.com>
    mm/mmap.c: fix missing call to vm_unacct_memory in mmap_region

Liam R. Howlett <Liam.Howlett@oracle.com>
    android: binder: stop saving a pointer to the VMA

Bart Van Assche <bvanassche@acm.org>
    RDMA/srpt: Fix a use-after-free

Bart Van Assche <bvanassche@acm.org>
    RDMA/srpt: Introduce a reference count in struct srpt_device

Bart Van Assche <bvanassche@acm.org>
    RDMA/srpt: Duplicate port name members

Dan Carpenter <dan.carpenter@oracle.com>
    platform/olpc: Fix uninitialized data in debugfs write

Vadim Pasternak <vadimp@nvidia.com>
    platform/mellanox: mlxreg-lc: Fix error flow and extend verbosity

Hans de Goede <hdegoede@redhat.com>
    platform/x86: pmc_atom: Match all Lex BayTrail boards with critclk_systems DMI table

Dan Carpenter <dan.carpenter@oracle.com>
    tools/power/x86/intel-speed-select: Fix off by one check

Sean Christopherson <seanjc@google.com>
    KVM: nVMX: Set UMIP bit CR4_FIXED1 MSR when emulating UMIP

Peter Suti <peter.suti@streamunlimited.com>
    staging: fbtft: core: set smem_len before fb_deferred_io_init call

Patrice Chotard <patrice.chotard@foss.st.com>
    mtd: spi-nor: fix spi_nor_spimem_setup_op() call in spi_nor_erase_{sector,chip}()

Andrey Strachuk <strochuk@ispras.ru>
    usb: cdns3: change place of 'priv_ep' assignment in cdns3_gadget_ep_dequeue(), cdns3_gadget_ep_enable()

Johan Hovold <johan@kernel.org>
    USB: serial: fix tty-port initialized comments

Basavaraj Natikar <Basavaraj.Natikar@amd.com>
    HID: amd_sfh: Handle condition of "no sensors"

Vidya Sagar <vidyas@nvidia.com>
    PCI: tegra194: Fix link up retry sequence

Vidya Sagar <vidyas@nvidia.com>
    PCI: tegra194: Fix Root Port interrupt handling

Bob Pearson <rpearsonhpe@gmail.com>
    RDMA/rxe: Fix rnr retry behavior

Md Haris Iqbal <haris.phnx@gmail.com>
    RDMA/rxe: For invalidate compare according to set keys in mr

Artem Borisov <dedsa2002@gmail.com>
    HID: alps: Declare U1_UNICORN_LEGACY support

Liang He <windhl@126.com>
    mmc: cavium-thunderx: Add of_node_put() when breaking out of loop

Liang He <windhl@126.com>
    mmc: cavium-octeon: Add of_node_put() when breaking out of loop

Liang He <windhl@126.com>
    mmc: core: quirks: Add of_node_put() when breaking out of loop

Bob Pearson <rpearsonhpe@gmail.com>
    RDMA/rxe: Fix mw bind to allow any consumer key portion

Antonio Borneo <antonio.borneo@foss.st.com>
    scripts/gdb: fix 'lx-dmesg' on 32 bits arch

Fabio Estevam <festevam@denx.de>
    dmaengine: imx-dma: Cast of_device_get_match_data() with (uintptr_t)

Basavaraj Natikar <Basavaraj.Natikar@amd.com>
    HID: amd_sfh: Add NULL check for hid device

Harshit Mogalapalli <harshit.m.mogalapalli@oracle.com>
    HID: mcp2221: prevent a buffer overflow in mcp_smbus_write()

Dan Carpenter <dan.carpenter@oracle.com>
    iio: adc: max1027: unlock on error path in max1027_read_single_value()

Liang He <windhl@126.com>
    gpio: gpiolib-of: Fix refcount bugs in of_mm_gpiochip_add_data()

Jianglei Nie <niejianglei2021@163.com>
    RDMA/hfi1: fix potential memory leak in setup_base_ctxt()

Bryan O'Donoghue <bryan.odonoghue@linaro.org>
    clk: qcom: gcc-msm8939: Fix weird field spacing in ftbl_gcc_camss_cci_clk

Bjorn Andersson <bjorn.andersson@linaro.org>
    clk: qcom: gdsc: Bump parent usage count when GDSC is found enabled

Abel Vesa <abel.vesa@linaro.org>
    clk: qcom: Drop mmcx gdsc supply for dispcc and videocc

Gwendal Grignou <gwendal@chromium.org>
    iio: cros: Register FIFO callback after sensor is registered

Cheng Xu <chengyou@linux.alibaba.com>
    RDMA/siw: Fix duplicated reported IW_CM_EVENT_CONNECT_REPLY event

Haoyue Xu <xuhaoyue1@hisilicon.com>
    RDMA/hns: Fix incorrect clearing of interrupt status register

Jianglei Nie <niejianglei2021@163.com>
    RDMA/qedr: Fix potential memory leak in __qedr_alloc_mr()

Md Haris Iqbal <haris.iqbal@ionos.com>
    RDMA/rtrs-clt: Replace list_next_or_null_rr_rcu with an inline function

Jack Wang <jinpu.wang@ionos.com>
    RDMA/rtrs-srv: Fix modinfo output for stringify

Mustafa Ismail <mustafa.ismail@intel.com>
    RDMA/irdma: Fix setting of QP context err_rq_idx_valid field

Mustafa Ismail <mustafa.ismail@intel.com>
    RDMA/irdma: Fix VLAN connection with wildcard address

Mustafa Ismail <mustafa.ismail@intel.com>
    RDMA/irdma: Fix a window for use-after-free

Christopher Obbard <chris.obbard@collabora.com>
    um: random: Don't initialise hwrng struct with zero

Peng Fan <peng.fan@nxp.com>
    interconnect: imx: fix max_node_id

Samuel Holland <samuel@sholland.org>
    phy: rockchip-inno-usb2: Ignore OTG IRQs in host mode

Fabrice Gasnier <fabrice.gasnier@foss.st.com>
    phy: stm32: fix error return in stm32_usbphyc_phy_init

Dan Carpenter <dan.carpenter@oracle.com>
    eeprom: idt_89hpesx: uninitialized data in idt_dbgfs_csr_write()

Johan Hovold <johan+linaro@kernel.org>
    usb: dwc3: qcom: fix missing optional irq warnings

Rohith Kollalsi <quic_rkollals@quicinc.com>
    usb: dwc3: core: Do not perform GCTL_CORE_SOFTRESET during bootup

Thinh Nguyen <Thinh.Nguyen@synopsys.com>
    usb: dwc3: core: Deprecate GCTL.CORESOFTRESET

Liang He <windhl@126.com>
    usb: aspeed-vhub: Fix refcount leak bug in ast_vhub_init_desc()

Randy Dunlap <rdunlap@infradead.org>
    usb: gadget: udc: amd5536 depends on HAS_DMA

Yang Yingliang <yangyingliang@huawei.com>
    xtensa: iss: fix handling error cases in iss_net_configure()

Max Filippov <jcmvbkbc@gmail.com>
    xtensa: iss/network: provide release() callback

Mahesh Rajashekhara <Mahesh.Rajashekhara@microchip.com>
    scsi: smartpqi: Fix DMA direction for RAID requests

Christian Marangi <ansuelsmth@gmail.com>
    PCI: qcom: Set up rev 2.1.0 PARF_PHY before enabling clocks

Stefan Roese <sr@denx.de>
    PCI/portdrv: Don't disable AER reporting in get_port_device_capability()

Claudio Imbrenda <imbrenda@linux.ibm.com>
    KVM: s390: pv: leak the topmost page table when destroy fails

Christian Loehle <CLoehle@hyperstone.com>
    mmc: block: Add single read for 4k sector cards

Liang He <windhl@126.com>
    of: device: Fix missing of_node_put() in of_dma_set_restricted_buffer

Eugen Hristev <eugen.hristev@microchip.com>
    mmc: sdhci-of-at91: fix set_uhs_signaling rewriting of MC1R

Christophe JAILLET <christophe.jaillet@wanadoo.fr>
    memstick/ms_block: Fix a memory leak

Christophe JAILLET <christophe.jaillet@wanadoo.fr>
    memstick/ms_block: Fix some incorrect memory allocation

Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
    mmc: renesas_sdhi: Get the reset handle early in the probe

Fabio Estevam <festevam@gmail.com>
    mmc: mxcmmc: Silence a clang warning

Miaoqian Lin <linmq006@gmail.com>
    mmc: sdhci-of-esdhc: Fix refcount leak in esdhc_signal_voltage_switch

jianchunfu <jianchunfu@cmss.chinamobile.com>
    rtla/utils: Use calloc and check the potential memory allocation failure

Duoming Zhou <duoming@zju.edu.cn>
    staging: rtl8192u: Fix sleep in atomic context bug in dm_fsync_timer_callback

Carlos Llamas <cmllamas@google.com>
    binder: fix redefinition of seq_file attributes

Alexander Shishkin <alexander.shishkin@linux.intel.com>
    intel_th: msu: Fix vmalloced buffers

Jiasheng Jiang <jiasheng@iscas.ac.cn>
    intel_th: msu-sink: Potential dereference of null pointer

Christophe JAILLET <christophe.jaillet@wanadoo.fr>
    intel_th: Fix a resource leak in an error handling path

Dan Carpenter <dan.carpenter@oracle.com>
    scsi: qla2xxx: Check correct variable in qla24xx_async_gffid()

Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
    phy: qcom-qmp: fix the QSERDES_V5_COM_CMN_MODE register

Shunsuke Mie <mie@igel.co.jp>
    PCI: endpoint: Don't stop controller when unbinding endpoint function

Viacheslav Mitrofanov <v.v.mitrofanov@yadro.com>
    dmaengine: sf-pdma: Add multithread support for a DMA channel

Quentin Perret <qperret@google.com>
    KVM: arm64: Don't return from void function

Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
    soundwire: revisit driver bind/unbind and callbacks

Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
    soundwire: bus_type: fix remove and shutdown support

Serge Semin <Sergey.Semin@baikalelectronics.ru>
    PCI: dwc: Always enable CDM check if "snps,enable-cdm-check" exists

Serge Semin <Sergey.Semin@baikalelectronics.ru>
    PCI: dwc: Deallocate EPC memory on dw_pcie_ep_init() errors

Serge Semin <Sergey.Semin@baikalelectronics.ru>
    PCI: dwc: Set INCREASE_REGION_SIZE flag based on limit address

Serge Semin <Sergey.Semin@baikalelectronics.ru>
    PCI: dwc: Disable outbound windows only for controllers using iATU

Serge Semin <Sergey.Semin@baikalelectronics.ru>
    PCI: dwc: Add unroll iATU space support to dw_pcie_disable_atu()

Serge Semin <Sergey.Semin@baikalelectronics.ru>
    PCI: dwc: Stop link on host_init errors and de-initialization

Andy Shevchenko <andriy.shevchenko@linux.intel.com>
    phy: ti: tusb1210: Don't check for write errors when powering on

Tianyu Li <tianyu.li@arm.com>
    mm/mempolicy: fix get_nodes out of bound access

Andrey Konovalov <andreyknvl@gmail.com>
    kasan: fix zeroing vmalloc memory with HW_TAGS

Miaohe Lin <linmiaohe@huawei.com>
    mm/migration: fix potential pte_unmap on an not mapped pte

Miaohe Lin <linmiaohe@huawei.com>
    mm/migration: return errno when isolate_huge_page failed

Yang Shi <shy828301@gmail.com>
    mm: rmap: use the correct parameter name for DEFINE_PAGE_VMA_WALK

Yushan Zhou <katrinzhou@tencent.com>
    kernfs: fix potential NULL dereference in __kernfs_remove

Nikita Travkin <nikita@trvn.ru>
    clk: qcom: clk-rcg2: Make sure to not write d=0 to the NMD register

Nikita Travkin <nikita@trvn.ru>
    clk: qcom: clk-rcg2: Fail Duty-Cycle configuration if MND divider is not enabled.

Vladimir Zapolskiy <vladimir.zapolskiy@linaro.org>
    clk: qcom: camcc-sm8250: Fix topology around titan_top power domain

Vladimir Zapolskiy <vladimir.zapolskiy@linaro.org>
    clk: qcom: camcc-sdm845: Fix topology around titan_top power domain

Robert Marko <robimarko@gmail.com>
    clk: qcom: ipq8074: set BRANCH_HALT_DELAY flag for UBI clocks

Robert Marko <robimarko@gmail.com>
    clk: qcom: ipq8074: fix NSS port frequency tables

Robert Marko <robimarko@gmail.com>
    clk: qcom: ipq8074: SW workaround for UBI32 PLL lock

Robert Marko <robimarko@gmail.com>
    clk: qcom: ipq8074: fix NSS core PLL-s

Bob Pearson <rpearsonhpe@gmail.com>
    RDMA/rxe: Fix deadlock in rxe_do_local_ops()

Sergey Shtylyov <s.shtylyov@omp.ru>
    usb: host: xhci: use snprintf() in xhci_decode_trb()

Bryan O'Donoghue <bryan.odonoghue@linaro.org>
    clk: qcom: gcc-msm8939: Point MM peripherals to system_mm_noc clock

Bryan O'Donoghue <bryan.odonoghue@linaro.org>
    clk: qcom: gcc-msm8939: Add missing system_mm_noc_bfdcd_clk_src

Bryan O'Donoghue <bryan.odonoghue@linaro.org>
    clk: qcom: gcc-msm8939: Fix bimc_ddr_clk_src rcgr base address

Bryan O'Donoghue <bryan.odonoghue@linaro.org>
    clk: qcom: gcc-msm8939: Add missing SYSTEM_MM_NOC_BFDCD_CLK_SRC

Neal Liu <neal_liu@aspeedtech.com>
    usb: gadget: f_mass_storage: Make CD-ROM emulation works with Windows OS

Mike Leach <mike.leach@linaro.org>
    coresight: syscfg: Update load and unload operations

Mike Leach <mike.leach@linaro.org>
    coresight: configfs: Fix unload of configurations on module exit

Ansuel Smith <ansuelsmth@gmail.com>
    clk: qcom: clk-krait: unlock spin after mux completion

Zhang Wensheng <zhangwensheng5@huawei.com>
    driver core: fix potential deadlock in __driver_attach

Christophe JAILLET <christophe.jaillet@wanadoo.fr>
    misc: rtsx: Fix an error handling path in rtsx_pci_probe()

Vladimir Zapolskiy <vladimir.zapolskiy@linaro.org>
    clk: qcom: camcc-sm8250: Fix halt on boot by reducing driver's init level

Mark Brown <broonie@kernel.org>
    mtd: dataflash: Add SPI ID table

Geert Uytterhoeven <geert+renesas@glider.be>
    mtd: hyperbus: rpc-if: Fix RPM imbalance in probe error path

Ben Gardon <bgardon@google.com>
    KVM: x86: Fix errant brace in KVM capability handling

Serge Semin <Sergey.Semin@baikalelectronics.ru>
    dmaengine: dw-edma: Fix eDMA Rd/Wr-channels and DMA-direction semantics

Mike Christie <michael.christie@oracle.com>
    scsi: iscsi: Fix session removal on shutdown

Mike Christie <michael.christie@oracle.com>
    scsi: iscsi: Add helper to remove a session from the kernel

Mike Christie <michael.christie@oracle.com>
    scsi: iscsi: Allow iscsi_if_stop_conn() to be called from kernel

Duoming Zhou <duoming@zju.edu.cn>
    mwifiex: fix sleep in atomic context bugs caused by dev_coredumpv

Sean Christopherson <seanjc@google.com>
    KVM: Don't set Accessed/Dirty bits for ZERO_PAGE

Miaohe Lin <linmiaohe@huawei.com>
    mm/memremap: fix memunmap_pages() race with get_dev_pagemap()

Miaohe Lin <linmiaohe@huawei.com>
    lib/test_hmm: avoid accessing uninitialized pages

Dongliang Mu <mudongliangabcd@gmail.com>
    RDMA/rxe: fix xa_alloc_cycle() error return value check again

Peng Fan <peng.fan@nxp.com>
    clk: imx: clk-fracn-gppll: correct rdiv

Liu Ying <victor.liu@nxp.com>
    clk: imx: clk-fracn-gppll: Return rate in rate table properly in ->recalc_rate()

Peng Fan <peng.fan@nxp.com>
    clk: imx: clk-fracn-gppll: fix mfd value

Peng Fan <peng.fan@nxp.com>
    clk: imx93: correct nic_media parent

Haibo Chen <haibo.chen@nxp.com>
    clk: imx93: use adc_root as the parent clock of adc1

Rex-BC Chen <rex-bc.chen@mediatek.com>
    clk: mediatek: reset: Fix written reset bit offset

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: temp: maxim_thermocouple: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: temp: max31865: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: temp: ltc2983: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: resolver: ad2s90: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: resolver: ad2s1200: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: proximity: as3935: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: potentiometer: mcp4131: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: potentiometer: mcp41010: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: potentiometer: max5481: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: potentiometer: ad5272: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: potentiometer: ad5110: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: imu: mpu6050: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: imu: inv_icm42600: Fix alignment for DMA safety in buffer code.

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: imu: inv_icm42600: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: imu: fxos8700: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: gyro: fxas210002c: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: gyro: adxrs450: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: gyro: adis16130: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: gyro: adis16080: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: frequency: adrf6780: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: frequency: admv4420: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: frequency: admv1014: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: frequency: admv1013: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: frequency: adf4371: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: frequency: adf4350: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: frequency: ad9523: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: dac: ti-dac7612: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: dac: ti-dac7311: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: dac: ti-dac5571: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: dac: ti-dac082s085: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: dac: mcp4922: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: dac: ltc2688: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: dac: ad8801: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: dac: ad7303: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: dac: ad7293: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: dac: ad5791: Fix alignment for DMA saftey

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: dac: ad5770r: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: dac: ad5766: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: dac: ad5764: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: dac: ad5761: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: dac: ad5755: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: dac: ad5686: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: dac: ad5592r: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: dac: ad5504: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: dac: ad5449: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: dac: ad5421: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: dac: ad5360: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: dac: ad5064: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: common: ssp: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: amplifiers: ad8366: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: addac: ad74413r: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: adc: ti-tlc4541: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: adc: ti-ads8688: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: adc: ti-ads8344: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: adc: ti-ads7950: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: adc: ti-ads131e08: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: adc: ti-ads124s08: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: adc: ti-adc161s626: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: adc: ti-adc128s052: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: adc: ti-adc12138: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: adc: ti-adc108s102: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: adc: ti-adc084s021: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: adc: ti-adc0832: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: adc: mcp320x: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: adc: max1241: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: adc: max1118: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: adc: max11100: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: adc: max1027: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: adc: ltc2497: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: adc: ltc2496: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: adc: hi8435: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: adc: ad7949: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: adc: ad7923: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: adc: ad7887: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: adc: ad7768-1: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: adc: ad7766: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: adc: ad7606: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: adc: ad7476: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: adc: ad7298: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: adc: ad7292: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: adc: ad7280a: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: adc: ad7266: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: accel: sca3300: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: accel: sca3000: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: accel: bma220: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: accel: adxl367: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: accel: adxl355: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: accel: adxl313: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: core: Fix IIO_ALIGN and rename as it was not sufficiently large

Jagath Jog J <jagathjog1996@gmail.com>
    iio: accel: bma400: conversion to device-managed function

Jagath Jog J <jagathjog1996@gmail.com>
    iio: accel: bma400: Reordering of header files

Gwendal Grignou <gwendal@chromium.org>
    iio: sx9324: Fix register field spelling

Stephen Boyd <swboyd@chromium.org>
    platform/chrome: cros_ec: Always expose last resume result

Jagath Jog J <jagathjog1996@gmail.com>
    iio: accel: bma400: Fix the scale min and max macro values

Quinn Tran <qutran@marvell.com>
    scsi: qla2xxx: edif: Reduce N2N thrashing at app_start time

Quinn Tran <qutran@marvell.com>
    scsi: qla2xxx: edif: Fix no logout on delete for N2N

Quinn Tran <qutran@marvell.com>
    scsi: qla2xxx: edif: Fix session thrash

Quinn Tran <qutran@marvell.com>
    scsi: qla2xxx: edif: Tear down session if keys have been removed

Quinn Tran <qutran@marvell.com>
    scsi: qla2xxx: edif: Fix no login after app start

Quinn Tran <qutran@marvell.com>
    scsi: qla2xxx: edif: Reduce disruption due to multiple app start

Quinn Tran <qutran@marvell.com>
    scsi: qla2xxx: edif: Send LOGO for unexpected IKE message

Thomas Gleixner <tglx@linutronix.de>
    netfilter: xtables: Bring SPDX identifier back

Tang Bin <tangbin@cmss.chinamobile.com>
    usb: xhci: tegra: Fix error check

Tang Bin <tangbin@cmss.chinamobile.com>
    usb: gadget: tegra-xudc: Fix error check in tegra_xudc_powerdomain_init()

Miaoqian Lin <linmq006@gmail.com>
    usb: ohci-nxp: Fix refcount leak in ohci_hcd_nxp_probe

Miaoqian Lin <linmq006@gmail.com>
    usb: host: Fix refcount leak in ehci_hcd_ppc_of_probe

Marco Pagani <marpagan@redhat.com>
    fpga: altera-pr-ip: fix unsigned comparison with less than zero

Miaoqian Lin <linmq006@gmail.com>
    PCI: mediatek-gen3: Fix refcount leak in mtk_pcie_init_irq_domains()

Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
    mtd: st_spi_fsm: Add a clk_disable_unprepare() in .probe()'s error path

Miaoqian Lin <linmq006@gmail.com>
    mtd: parsers: ofpart: Fix refcount leak in bcm4908_partitions_fw_offset

Miaoqian Lin <linmq006@gmail.com>
    mtd: partitions: Fix refcount leak in parse_redboot_of

Duoming Zhou <duoming@zju.edu.cn>
    mtd: sm_ftl: Fix deadlock caused by cancel_work_sync in sm_release

Harshit Mogalapalli <harshit.m.mogalapalli@oracle.com>
    HID: cp2112: prevent a buffer overflow in cp2112_xfer()

Miaoqian Lin <linmq006@gmail.com>
    PCI: tegra194: Fix PM error handling in tegra_pcie_config_ep()

Miaoqian Lin <linmq006@gmail.com>
    PCI: microchip: Fix refcount leak in mc_pcie_init_irq_domains()

Chanho Park <chanho61.park@samsung.com>
    phy: samsung: exynosautov9-ufs: correct TSRV register configurations

Sean Christopherson <seanjc@google.com>
    KVM: x86/mmu: Drop RWX=0 SPTEs during ept_sync_page()

Sean Christopherson <seanjc@google.com>
    KVM: SVM: Stuff next_rip on emulated INT3 injection if NRIPS is supported

Sean Christopherson <seanjc@google.com>
    KVM: SVM: Unwind "speculative" RIP advancement if INTn injection "fails"

Quinn Tran <qutran@marvell.com>
    scsi: qla2xxx: edif: Fix n2n login retry for secure device

Quinn Tran <qutran@marvell.com>
    scsi: qla2xxx: edif: Fix n2n discovery issue with secure target

Quinn Tran <qutran@marvell.com>
    scsi: qla2xxx: edif: Add retry for ELS passthrough

Quinn Tran <qutran@marvell.com>
    scsi: qla2xxx: edif: Synchronize NPIV deletion with authentication application

Quinn Tran <qutran@marvell.com>
    scsi: qla2xxx: edif: Fix potential stuck session in sa update

Quinn Tran <qutran@marvell.com>
    scsi: qla2xxx: edif: Add bsg interface to read doorbell events

Quinn Tran <qutran@marvell.com>
    scsi: qla2xxx: edif: Wait for app to ack on sess down

Quinn Tran <qutran@marvell.com>
    scsi: qla2xxx: edif: bsg refactor

Quinn Tran <qutran@marvell.com>
    scsi: qla2xxx: edif: Reduce Initiator-Initiator thrashing

Vaibhav Jain <vaibhav@linux.ibm.com>
    of: check previous kernel's ima-kexec-buffer against memory bounds

Biju Das <biju.das.jz@bp.renesas.com>
    clk: renesas: rzg2l: Fix reset status function

Christophe JAILLET <christophe.jaillet@wanadoo.fr>
    mtd: rawnand: meson: Fix a potential double free issue

Miaoqian Lin <linmq006@gmail.com>
    mtd: maps: Fix refcount leak in ap_flash_init

Miaoqian Lin <linmq006@gmail.com>
    mtd: maps: Fix refcount leak in of_flash_probe_versatile

Ralph Siemsen <ralph.siemsen@linaro.org>
    clk: renesas: r9a06g032: Fix UART clkgrp bitsel

Mario Limonciello <mario.limonciello@amd.com>
    HID: amd_sfh: Don't show client init failed as error when discovery fails

Jason A. Donenfeld <Jason@zx2c4.com>
    wireguard: allowedips: don't corrupt stack when detecting overflow

Jason A. Donenfeld <Jason@zx2c4.com>
    wireguard: ratelimiter: use hrtimer in selftest

Maxim Mikityanskiy <maximmi@nvidia.com>
    net/mlx5e: xsk: Discard unaligned XSK frames on striding RQ

Maciej Żenczykowski <maze@google.com>
    net: usb: make USB_RTL8153_ECM non user configurable

Hangyu Hua <hbh25y@gmail.com>
    dccp: put dccp_qpolicy_full() and dccp_qpolicy_push() in the same lock

Jian Shen <shenjian15@huawei.com>
    net: ionic: fix error check for vlan flags in ionic_set_nic_features()

Jian Shen <shenjian15@huawei.com>
    net: ice: fix error NETIF_F_HW_VLAN_CTAG_FILTER check in ice_vsi_sync_fltr()

Eric Dumazet <edumazet@google.com>
    net: rose: fix netdev reference changes

Jakub Kicinski <kuba@kernel.org>
    netdevsim: Avoid allocation warnings triggered from user space

Przemyslaw Patynowski <przemyslawx.patynowski@intel.com>
    iavf: Fix 'tc qdisc show' listing too many queues

Przemyslaw Patynowski <przemyslawx.patynowski@intel.com>
    iavf: Fix max_rate limiting

William Dean <williamsukatube@gmail.com>
    wifi: rtw88: check the return value of alloc_workqueue()

Ido Schimmel <idosch@nvidia.com>
    netdevsim: fib: Fix reference count leak on route deletion failure

Mike Manning <mvrmanning@gmail.com>
    net: allow unbound socket for packets in VRF when tcp_l3mdev_accept set

Eric Dumazet <edumazet@google.com>
    ipv6: add READ_ONCE(sk->sk_bound_dev_if) in INET6_MATCH()

Eric Dumazet <edumazet@google.com>
    inet: add READ_ONCE(sk->sk_bound_dev_if) in INET_MATCH()

Kai Ye <yekai13@huawei.com>
    crypto: hisilicon/sec - fix auth key size error

Pali Rohár <pali@kernel.org>
    crypto: inside-secure - Add missing MODULE_DEVICE_TABLE for of

Zhengchao Shao <shaozhengchao@huawei.com>
    crypto: hisilicon/hpre - don't use GFP_KERNEL to alloc mem during softirq

Eric Dumazet <edumazet@google.com>
    ax25: fix incorrect dev_tracker usage

Shay Drory <shayd@nvidia.com>
    net/mlx5: Fix driver use of uninitialized timeout

Yevgeny Kliteynik <kliteyn@nvidia.com>
    net/mlx5: DR, Fix SMFS steering info dump format

Maher Sanalla <msanalla@nvidia.com>
    net/mlx5: Adjust log_max_qp to be 18 at most

Vlad Buslov <vladbu@nvidia.com>
    net/mlx5e: Modify slow path rules to go to slow fdb

Maxim Mikityanskiy <maximmi@nvidia.com>
    net/mlx5e: Fix calculations related to max MPWQE size

Maxim Mikityanskiy <maximmi@nvidia.com>
    net/mlx5e: xsk: Account for XSK RQ UMRs when calculating ICOSQ size

Maxim Mikityanskiy <maximmi@nvidia.com>
    net/mlx5e: Fix the value of MLX5E_MAX_RQ_NUM_MTTS

Maor Dickman <maord@nvidia.com>
    net/mlx5e: TC, Fix post_act to not match on in_port metadata

Gal Pressman <gal@nvidia.com>
    net/mlx5e: Remove WARN_ON when trying to offload an unsupported TLS cipher/version

Dan Carpenter <dan.carpenter@oracle.com>
    drm/amd/display: fix signedness bug in execute_synaptics_rc_command()

Ezequiel Garcia <ezequiel@vanguardiasur.com.ar>
    hantro: Remove incorrect HEVC SPS validation

Jernej Skrabec <jernej.skrabec@gmail.com>
    media: cedrus: hevc: Add check for invalid timestamp

Hangyu Hua <hbh25y@gmail.com>
    wifi: libertas: Fix possible refcount leak in if_usb_probe()

Jose Ignacio Tornos Martinez <jtornosm@redhat.com>
    wifi: iwlwifi: mvm: fix double list_add at iwl_mvm_mac_wake_tx_queue

Ammar Faizi <ammarfaizi2@gnuweeb.org>
    wifi: wil6210: debugfs: fix uninitialized variable use in `wil_write_file_wmi()`

Liang He <windhl@126.com>
    i2c: mux-gpmux: Add of_node_put() when breaking out of loop

Joanne Koong <joannelkoong@gmail.com>
    bpf: Fix bpf_xdp_pointer return pointer

Bjorn Andersson <bjorn.andersson@linaro.org>
    i2c: qcom-geni: Use the correct return value

Lars-Peter Clausen <lars@metafoo.de>
    i2c: cadence: Support PEC for SMBus block read

Ying Hsu <yinghsu@chromium.org>
    Bluetooth: Add default wakeup callback for HCI UART driver

Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
    Bluetooth: hci_sync: Fix not updating privacy_mode

Zhengping Jiang <jiangzp@google.com>
    Bluetooth: hci_sync: Fix resuming scan after suspend resume

Zhengping Jiang <jiangzp@google.com>
    Bluetooth: mgmt: Fix refresh cached connection info

Schspa Shi <schspa@gmail.com>
    Bluetooth: When HCI work queue is drained, only queue chained work

Jiasheng Jiang <jiasheng@iscas.ac.cn>
    Bluetooth: hci_intel: Add check for platform_driver_register

Vincent Mailhol <mailhol.vincent@wanadoo.fr>
    can: pch_can: pch_can_error(): initialize errc before using it

Vincent Mailhol <mailhol.vincent@wanadoo.fr>
    can: error: specify the values of data[5..7] of CAN error frames

Vincent Mailhol <mailhol.vincent@wanadoo.fr>
    can: usb_8dev: do not report txerr and rxerr during bus-off

Vincent Mailhol <mailhol.vincent@wanadoo.fr>
    can: kvaser_usb_leaf: do not report txerr and rxerr during bus-off

Vincent Mailhol <mailhol.vincent@wanadoo.fr>
    can: kvaser_usb_hydra: do not report txerr and rxerr during bus-off

Vincent Mailhol <mailhol.vincent@wanadoo.fr>
    can: sun4i_can: do not report txerr and rxerr during bus-off

Vincent Mailhol <mailhol.vincent@wanadoo.fr>
    can: hi311x: do not report txerr and rxerr during bus-off

Vincent Mailhol <mailhol.vincent@wanadoo.fr>
    can: sja1000: do not report txerr and rxerr during bus-off

Vincent Mailhol <mailhol.vincent@wanadoo.fr>
    can: rcar_can: do not report txerr and rxerr during bus-off

Vincent Mailhol <mailhol.vincent@wanadoo.fr>
    can: pch_can: do not report txerr and rxerr during bus-off

Dan Carpenter <dan.carpenter@oracle.com>
    libbpf: fix an snprintf() overflow check

Dan Carpenter <dan.carpenter@oracle.com>
    selftests/bpf: fix a test for snprintf() overflow

Andrii Nakryiko <andrii@kernel.org>
    bpf: fix potential 32-bit overflow when accessing ARRAY map element

Kumar Kartikeya Dwivedi <memxor@gmail.com>
    bpf: Wire up freeing of referenced kptr

Kumar Kartikeya Dwivedi <memxor@gmail.com>
    bpf: Populate pairs of btf_id and destructor kfunc in btf

Kumar Kartikeya Dwivedi <memxor@gmail.com>
    bpf: Adapt copy_map_value for multiple offset case

Kumar Kartikeya Dwivedi <memxor@gmail.com>
    bpf: Allow storing referenced kptr in map

Kumar Kartikeya Dwivedi <memxor@gmail.com>
    bpf: Tag argument to be released in bpf_func_proto

Kumar Kartikeya Dwivedi <memxor@gmail.com>
    bpf: Allow storing unreferenced kptr in map

Kumar Kartikeya Dwivedi <memxor@gmail.com>
    bpf: Move check_ptr_off_reg before check_map_access

Kumar Kartikeya Dwivedi <memxor@gmail.com>
    bpf: Make btf_find_field more generic

Alex Deucher <alexander.deucher@amd.com>
    drm/amdgpu: restore original stable pstate on ctx fini

Christian König <christian.koenig@amd.com>
    drm/amdgpu: cleanup ctx implementation

Alex Deucher <alexander.deucher@amd.com>
    drm/amdgpu: use the same HDP flush registers for all nbio 2.3.x

Alex Deucher <alexander.deucher@amd.com>
    drm/amdgpu: use the same HDP flush registers for all nbio 7.4.x

Rustam Subkhankulov <subkhankulov@ispras.ru>
    wifi: p54: add missing parentheses in p54_flush()

Christophe JAILLET <christophe.jaillet@wanadoo.fr>
    wifi: p54: Fix an error handling path in p54spi_probe()

Dan Carpenter <dan.carpenter@oracle.com>
    wifi: wil6210: debugfs: fix info leak in wil_write_file_wmi()

Jernej Skrabec <jernej.skrabec@gmail.com>
    media: cedrus: h265: Fix logic for not low delay flag

Benjamin Gaignard <benjamin.gaignard@collabora.com>
    media: uapi: HEVC: Change pic_order_cnt definition in v4l2_hevc_dpb_entry

Jernej Skrabec <jernej.skrabec@gmail.com>
    media: cedrus: h265: Fix flag name

Jason A. Donenfeld <Jason@zx2c4.com>
    fs: check FMODE_LSEEK to control internal pipe splicing

Alexei Starovoitov <ast@kernel.org>
    bpf: Fix subprog names in stack traces.

Wolfram Sang <wsa+renesas@sang-engineering.com>
    selftests: timers: clocksource-switch: fix passing errors from child

Wolfram Sang <wsa+renesas@sang-engineering.com>
    selftests: timers: valid-adjtimex: build fix for newer toolchains

David Gow <davidgow@google.com>
    kunit: executor: Fix a memory leak on failure in kunit_filter_tests

Anquan Wu <leiqi96@hotmail.com>
    libbpf: Fix the name of a reused map

Yonglong Li <liyonglong@chinatelecom.cn>
    tcp: make retransmitted SKB fit into the send window

Song Liu <song@kernel.org>
    bpf, x86: fix freeing of not-finalized bpf_prog_pack

Tony Ambardar <tony.ambardar@gmail.com>
    bpf, x64: Add predicate for bpf2bpf with tailcalls support in JIT

Kui-Feng Lee <kuifeng@fb.com>
    bpf, x86: Generate trampolines from bpf_tramp_links

Milan Landaverde <milan@mdaverde.com>
    bpftool: Add missing link types

Jian Zhang <zhangjian210@huawei.com>
    drm/exynos/exynos7_drm_decon: free resources when clk_set_parent() failed.

Liu Jian <liujian56@huawei.com>
    skmsg: Fix invalid last sg check in sk_msg_recvmsg()

Liang He <windhl@126.com>
    mediatek: mt76: eeprom: fix missing of_node_put() in mt76_find_power_limits_node()

Liang He <windhl@126.com>
    mediatek: mt76: mac80211: Fix missing of_node_put() in mt76_led_init()

Felix Fietkau <nbd@nbd.name>
    mt76: mt7615: fix throughput regression on DFS channels

Deren Wu <deren.wu@mediatek.com>
    mt76: mt7921: enlarge maximum VHT MPDU length to 11454

Deren Wu <deren.wu@mediatek.com>
    mt76: mt7921: fix aggregation subframes setting to HE max

Deren Wu <deren.wu@mediatek.com>
    mt76: mt7921s: fix possible sdio deadlock in command fail

Lorenzo Bianconi <lorenzo@kernel.org>
    mt76: mt7921: do not update pm states in case of error

Lorenzo Bianconi <lorenzo@kernel.org>
    mt76: mt7615: do not update pm stats in case of error

YN Chen <yn.chen@mediatek.com>
    mt76: mt7921s: fix firmware download random fail

Lorenzo Bianconi <lorenzo@kernel.org>
    mt76: mt76x02u: fix possible memory leak in __mt76x02u_mcu_send_msg

Ming Qian <ming.qian@nxp.com>
    media: amphion: only insert the first sequence startcode for vc1l format

Ming Qian <ming.qian@nxp.com>
    media: amphion: sync buffer status with firmware during abort

Ming Qian <ming.qian@nxp.com>
    media: amphion: decoder copy timestamp from output to capture

Ezequiel Garcia <ezequiel@vanguardiasur.com.ar>
    media: hantro: Fix RK3399 H.264 format advertising

Benjamin Gaignard <benjamin.gaignard@collabora.com>
    media: hantro: Be more accurate on pixel formats step_width constraints

Benjamin Gaignard <benjamin.gaignard@collabora.com>
    media: hantro: HEVC: Fix reference frames management

Benjamin Gaignard <benjamin.gaignard@collabora.com>
    media: hantro: HEVC: Fix output frame chroma offset

Sebastian Fricke <sebastian.fricke@collabora.com>
    media: staging: media: hantro: Fix typos

Piotr Oniszczuk <piotr.oniszczuk@gmail.com>
    media: hantro: Add support for Hantro G1 on RK356x

Ming Qian <ming.qian@nxp.com>
    media: amphion: defer setting last_buffer_dequeued until resolution changes are processed

Chen-Yu Tsai <wenst@chromium.org>
    media: mediatek: vcodec: Initialize decoder parameters for each instance

Rob Clark <robdclark@chromium.org>
    drm/msm/dpu: Fix for non-visible planes

Ming Qian <ming.qian@nxp.com>
    media: amphion: release core lock before reset vpu core

AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
    media: platform: mtk-mdp: Fix mdp_ipi_comm structure alignment

Zhengchao Shao <shaozhengchao@huawei.com>
    crypto: hisilicon - Kunpeng916 crypto driver don't sleep when in softirq

Zhengchao Shao <shaozhengchao@huawei.com>
    crypto: hisilicon/sec - don't sleep when in softirq

Mateusz Jończyk <mat.jonczyk@o2.pl>
    drm/radeon: avoid bogus "vram limit (0) must be a power of 2" warning

Rob Clark <robdclark@chromium.org>
    drm/msm/mdp5: Fix global state lock backoff

Yixun Lan <dlan@gentoo.org>
    libbpf, riscv: Use a0 for RC register

Douglas Anderson <dianders@chromium.org>
    drm/msm: Avoid unclocked GMU register access in 6xx gpu_busy

Hsin-Yi Wang <hsinyi@chromium.org>
    drm/bridge: anx7625: Fix NULL pointer crash when using edp-panel

Qiao Ma <mqaio@linux.alibaba.com>
    net: hinic: avoid kernel hung in hinic_get_stats64()

Qiao Ma <mqaio@linux.alibaba.com>
    net: hinic: fix bug that ethtool get wrong stats

Christophe JAILLET <christophe.jaillet@wanadoo.fr>
    hinic: Use the bitmap API when applicable

Vladimir Oltean <vladimir.oltean@nxp.com>
    net: dsa: felix: build as module when tc-taprio is module

Vladimir Oltean <vladimir.oltean@nxp.com>
    net: sched: provide shim definitions for taprio_offload_{get,free}

Hangyu Hua <hbh25y@gmail.com>
    drm: bridge: sii8620: fix possible off-by-one

Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
    drm/msm/hdmi: fill the pwr_regs bulk regulators

Guillaume Ranquet <granquet@baylibre.com>
    drm/mediatek: dpi: Only enable dpi after the bridge is enabled

Bo-Chen Chen <rex-bc.chen@mediatek.com>
    drm/mediatek: dpi: Remove output format of YUV

Christophe JAILLET <christophe.jaillet@wanadoo.fr>
    drm/rockchip: Fix an error handling path rockchip_dp_probe()

Brian Norris <briannorris@chromium.org>
    drm/rockchip: vop: Don't crash for invalid duplicate_state()

Vladimir Oltean <vladimir.oltean@nxp.com>
    net: dsa: felix: drop oversized frames with tc-taprio instead of hanging the port

Vladimir Oltean <vladimir.oltean@nxp.com>
    net: dsa: felix: keep reference on entire tc-taprio config

Xiaoliang Yang <xiaoliang.yang_1@nxp.com>
    net: dsa: felix: update base time of time-aware shaper when adjusting PTP time

Vladimir Oltean <vladimir.oltean@nxp.com>
    net: mscc: ocelot: minimize holes in struct ocelot_port

Vladimir Oltean <vladimir.oltean@nxp.com>
    net: mscc: ocelot: delete ocelot_port :: xmit_template

Maciej Fijalkowski <maciej.fijalkowski@intel.com>
    selftests/xsk: Destroy BPF resources only when ctx refcount drops to 0

Qian Cai <quic_qiancai@quicinc.com>
    crypto: arm64/gcm - Select AEAD for GHASH_ARM64_CE

Matthew Wilcox (Oracle) <willy@infradead.org>
    mm: Account dirty folios properly during splits

Dave Stevenson <dave.stevenson@raspberrypi.com>
    drm/vc4: hdmi: Move pixel doubling from Pixelvalve to HDMI block

Dave Stevenson <dave.stevenson@raspberrypi.com>
    drm/vc4: hdmi: Correct HDMI timing registers for interlaced modes

Mateusz Kwiatkowski <kfyatek+publicgit@gmail.com>
    drm/vc4: hdmi: Fix timings for interlaced modes

Dave Stevenson <dave.stevenson@raspberrypi.com>
    drm/vc4: hdmi: Move HDMI reset to pm_resume

Dave Stevenson <dave.stevenson@raspberrypi.com>
    drm/vc4: hdmi: Switch to pm_runtime_status_suspended

Dave Stevenson <dave.stevenson@raspberrypi.com>
    drm/vc4: hdmi: Reset HDMI MISC_CONTROL register

Dom Cobley <popcornmix@gmail.com>
    drm/vc4: hdmi: Avoid full hdmi audio fifo writes

Dom Cobley <popcornmix@gmail.com>
    drm/vc4: hdmi: Clear unused infoframe packet RAM registers

Dave Stevenson <dave.stevenson@raspberrypi.com>
    drm/vc4: hdmi: Add all the vc5 HDMI registers into the debugfs dumps

Dave Stevenson <dave.stevenson@raspberrypi.com>
    drm/vc4: dsi: Add correct stop condition to vc4_dsi_encoder_disable iteration

Dave Stevenson <dave.stevenson@raspberrypi.com>
    drm/vc4: dsi: Fix dsi0 interrupt support

Dave Stevenson <dave.stevenson@raspberrypi.com>
    drm/vc4: dsi: Register dsi0 as the correct vc4 encoder type

Dave Stevenson <dave.stevenson@raspberrypi.com>
    drm/vc4: dsi: Correct pixel order for DSI0

Dave Stevenson <dave.stevenson@raspberrypi.com>
    drm/vc4: dsi: Correct DSI divider calculations

Dave Stevenson <dave.stevenson@raspberrypi.com>
    drm/vc4: dsi: Release workaround buffer and DMA

Dave Stevenson <dave.stevenson@raspberrypi.com>
    drm/vc4: plane: Fix margin calculations for the right/bottom edges

Dom Cobley <popcornmix@gmail.com>
    drm/vc4: plane: Remove subpixel positioning check

Maxime Ripard <maxime@cerno.tech>
    drm/vc4: kms: Use maximum FIFO load for the HVS clock rate

Yunfei Dong <yunfei.dong@mediatek.com>
    media: mediatek: vcodec: Fix non subdev architecture open power fail

Miaoqian Lin <linmq006@gmail.com>
    media: tw686x: Fix memory leak in tw686x_video_init

Jian Zhang <zhangjian210@huawei.com>
    media: driver/nxp/imx-jpeg: fix a unexpected return value problem

Chen-Yu Tsai <wenst@chromium.org>
    media: mediatek: vcodec: Skip SOURCE_CHANGE & EOS events for stateless

Yunfei Dong <yunfei.dong@mediatek.com>
    media: mediatek: vcodec: Initialize decoder parameters after getting dec_capability

Arnd Bergmann <arnd@arndb.de>
    media: sta2x11: remove VIRT_TO_BUS dependency

Ming Qian <ming.qian@nxp.com>
    media: v4l2-mem2mem: prevent pollerr when last_buffer_dequeued is set

Niels Dossche <dossche.niels@gmail.com>
    media: hdpvr: fix error value returns in hdpvr_read

Miaoqian Lin <linmq006@gmail.com>
    drm/mcde: Fix refcount leak in mcde_dsi_bind

Ming Qian <ming.qian@nxp.com>
    media: amphion: output firmware error message

Ming Qian <ming.qian@nxp.com>
    media: imx-jpeg: Disable slot interrupt when frame done

Jiasheng Jiang <jiasheng@iscas.ac.cn>
    drm: bridge: adv7511: Add check for mipi_dsi_driver_register

Tom Lendacky <thomas.lendacky@amd.com>
    crypto: ccp - During shutdown, check SEV data pointer before using

Jörn-Thorben Hinz <jthinz@mailbox.tu-berlin.de>
    selftests/bpf: Fix rare segfault in sock_fields prog test

Jian Shen <shenjian15@huawei.com>
    test_bpf: fix incorrect netdev features

Frederic Weisbecker <frederic@kernel.org>
    rcutorture: Fix ksoftirqd boosting timing and iteration

Paul E. McKenney <paulmck@kernel.org>
    torture: Adjust to again produce debugging information

Paul E. McKenney <paulmck@kernel.org>
    rcutorture: Make kvm.sh allow more memory for --kasan runs

Alex Deucher <alexander.deucher@amd.com>
    drm/radeon: fix incorrrect SPDX-License-Identifiers

Ping-Ke Shih <pkshih@realtek.com>
    wifi: rtw89: 8852a: rfk: fix div 0 exception

Alexey Kodanev <aleksei.kodanev@bell-sw.com>
    wifi: iwlegacy: 4965: fix potential off-by-one overflow in il4965_rs_fill_link_cmd()

Pavel Skripkin <paskripkin@gmail.com>
    ath9k: fix use-after-free in ath9k_hif_usb_rx_cb

Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
    media: rcar-vin: Fix channel routing for Ebisu

Ming Qian <ming.qian@nxp.com>
    media: imx-jpeg: Implement drain using v4l2-mem2mem helpers

Ming Qian <ming.qian@nxp.com>
    media: imx-jpeg: Align upwards buffer size

Ming Qian <ming.qian@nxp.com>
    media: imx-jpeg: Support dynamic resolution change

Ming Qian <ming.qian@nxp.com>
    media: imx-jpeg: Handle source change in a function

Ming Qian <ming.qian@nxp.com>
    media: imx-jpeg: Identify and handle precision correctly

Ming Qian <ming.qian@nxp.com>
    media: imx-jpeg: Refactor function mxc_jpeg_parse

Ming Qian <ming.qian@nxp.com>
    media: imx-jpeg: Leave a blank space before the configuration data

Ming Qian <ming.qian@nxp.com>
    media: imx-jpeg: Correct some definition according specification

Benjamin Gaignard <benjamin.gaignard@collabora.com>
    media: Hantro: Correct G2 init qp field

Ming Qian <ming.qian@nxp.com>
    media: amphion: return error if format is unsupported by vpu

Zheyu Ma <zheyuma97@gmail.com>
    media: tw686x: Register the irq at the end of probe

Yang Yingliang <yangyingliang@huawei.com>
    media: camss: csid: fix wrong size passed to devm_kmalloc_array()

Eugen Hristev <eugen.hristev@microchip.com>
    media: atmel: atmel-sama7g5-isc: fix warning in configs without OF

Kuniyuki Iwashima <kuniyu@amazon.com>
    raw: Fix mixed declarations error in raw_icmp_error().

Eric Dumazet <edumazet@google.com>
    raw: convert raw sockets to RCU

Eric Dumazet <edumazet@google.com>
    raw: use more conventional iterators

Oleksij Rempel <linux@rempel-privat.de>
    net: ag71xx: fix discards 'const' qualifier warning

Alexey Khoroshilov <khoroshilov@ispras.ru>
    crypto: sun8i-ss - fix infinite loop in sun8i_ss_setup_ivs()

Eric Dumazet <edumazet@google.com>
    tcp: fix possible freeze in tx path under memory pressure

Xu Wang <vulab@iscas.ac.cn>
    i2c: Fix a potential use after free

Zheng Bin <zhengbin13@huawei.com>
    drm/bridge: it6505: Add missing CRYPTO_HASH dependency

Marc Kleine-Budde <mkl@pengutronix.de>
    can: netlink: allow configuring of fixed data bit rates without need for do_set_data_bittiming callback

Tales Lelo da Aparecida <tales.aparecida@gmail.com>
    drm/vkms: check plane_composer->map[0] before using it

Marc Kleine-Budde <mkl@pengutronix.de>
    can: netlink: allow configuring of fixed bit rates without need for do_set_bittiming callback

Eric Dumazet <edumazet@google.com>
    net: fix sk_wmem_schedule() and sk_rmem_schedule() errors

Dan Carpenter <dan.carpenter@oracle.com>
    crypto: sun8i-ss - fix error codes in allocate_flows()

Corentin Labbe <clabbe@baylibre.com>
    crypto: sun8i-ss - do not allocate memory when handling hash requests

Antonio Borneo <antonio.borneo@foss.st.com>
    drm: adv7511: override i2c address of cec before accessing it

Miaoqian Lin <linmq006@gmail.com>
    drm/virtio: Fix NULL vs IS_ERR checking in virtio_gpu_object_shmem_init

Xiaomeng Tong <xiam0nd.tong@gmail.com>
    virtio-gpu: fix a missing check to avoid NULL dereference

Fabio Estevam <festevam@gmail.com>
    i2c: mxs: Silence a clang warning

Tali Perry <tali.perry1@gmail.com>
    i2c: npcm: Correct slave role behavior

Tali Perry <tali.perry1@gmail.com>
    i2c: npcm: Remove own slave addresses 2:10

Bjorn Andersson <bjorn.andersson@linaro.org>
    drm/bridge: lt9611uxc: Cancel only driver's work

Miaoqian Lin <linmq006@gmail.com>
    drm/meson: encoder_hdmi: Fix refcount leak in meson_encoder_hdmi_init

Miaoqian Lin <linmq006@gmail.com>
    drm/meson: encoder_cvbs: Fix refcount leak in meson_encoder_cvbs_init

Xinlei Lee <xinlei.lee@mediatek.com>
    drm/mediatek: Add pull-down MIPI operation in mtk_dsi_poweroff function

Jitao Shi <jitao.shi@mediatek.com>
    drm/mediatek: Separate poweron/poweroff from enable/disable and define new funcs

Xinlei Lee <xinlei.lee@mediatek.com>
    drm/mediatek: Modify dsi funcs to atomic operations

Alexey Kodanev <aleksei.kodanev@bell-sw.com>
    drm/radeon: fix potential buffer overflow in ni_set_mc_special_registers()

Manikanta Pubbisetty <quic_mpubbise@quicinc.com>
    ath11k: Avoid REO CMD failed prints during firmware recovery

Manikanta Pubbisetty <quic_mpubbise@quicinc.com>
    ath11k: Fix incorrect debug_mask mappings

Christian 'Ansuel' Marangi <ansuelsmth@gmail.com>
    ath11k: fix missing skb drop on htc_tx_completion error

Martin KaFai Lau <kafai@fb.com>
    selftests/bpf: Fix tc_redirect_dtime

Yuntao Wang <ytcoode@gmail.com>
    selftests/bpf: Fix test_run logic in fexit_stress.c

Yunhao Tian <t123yh.xyz@gmail.com>
    drm/mipi-dbi: align max_chunk to 2 in spi_transfer

Johan Hovold <johan+linaro@kernel.org>
    ath11k: fix IRQ affinity warning on shutdown

Johan Hovold <johan+linaro@kernel.org>
    ath11k: fix netdev open race

Ajay Singh <ajay.kathat@microchip.com>
    wifi: wilc1000: use correct sequence of RESET for chip Power-UP/Down

Dan Carpenter <dan.carpenter@oracle.com>
    wifi: rtlwifi: fix error codes in rtl_debugfs_set_write_h2c()

Gao Chao <gaochao49@huawei.com>
    drm/panel: Fix build error when CONFIG_DRM_PANEL_SAMSUNG_ATNA33XC20=y && CONFIG_DRM_DISPLAY_HELPER=m

Javier Martinez Canillas <javierm@redhat.com>
    drm/st7735r: Fix module autoloading for Okaya RH128128T

John Stultz <jstultz@google.com>
    drm/bridge: lt9611: Use both bits for HDMI sensing

Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
    ath10k: do not enforce interrupt trigger type

Marek Vasut <marex@denx.de>
    drm/bridge: tc358767: Make sure Refclk clock are enabled

Marek Vasut <marex@denx.de>
    drm/bridge: tc358767: Move (e)DP bridge endpoint parsing into dedicated function

Douglas Anderson <dianders@chromium.org>
    drm/dp: Export symbol / kerneldoc fixes for DP AUX bus

Miaoqian Lin <linmq006@gmail.com>
    drm/meson: Fix refcount leak in meson_encoder_hdmi_init

Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
    pwm: lpc18xx: Fix period handling

Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
    pwm: sifive: Shut down hardware only after pwmchip_remove() completed

Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
    pwm: sifive: Ensure the clk is enabled exactly once per running PWM

Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
    pwm: sifive: Simplify offset calculation for PWMCMP registers

Mike Snitzer <snitzer@kernel.org>
    dm: return early from dm_pr_call() if DM device is suspended

Markus Mayer <mmayer@broadcom.com>
    thermal/tools/tmon: Include pthread and time headers in tmon.h

YiFei Zhu <zhuyifei@google.com>
    selftests/seccomp: Fix compile warning when CC=clang

Michal Koutný <mkoutny@suse.com>
    io_uring: Don't require reinitable percpu_ref

Marc Zyngier <maz@kernel.org>
    arm64: Expand ESR_ELx_WFx_ISS_TI to match its ARMv8.7 definition

Muneendra Kumar <muneendra.kumar@broadcom.com>
    scsi: nvme-fc: Add new routine nvme_fc_io_getuuid()

Jens Axboe <axboe@kernel.dk>
    io_uring: move to separate directory

Peter Zijlstra <peterz@infradead.org>
    x86/extable: Fix ex_handler_msr() print condition

Nicolas Saenz Julienne <nsaenzju@redhat.com>
    nohz/full, sched/rt: Fix missed tick-reenabling bug in dequeue_task_rt()

Anshuman Khandual <anshuman.khandual@arm.com>
    drivers/perf: arm_spe: Fix consistency of SYS_PMSCR_EL1.CX

Liang He <windhl@126.com>
    perf: RISC-V: Add of_node_put() when breaking out of for_each_of_cpu_node()

Xu Qiang <xuqiang36@huawei.com>
    irqdomain: Report irq number for NOMAP domains

Stephan Gerhold <stephan.gerhold@kernkonzept.com>
    ARM: dts: qcom: msm8974: Disable remoteprocs by default

Luca Weiss <luca@z3ntu.xyz>
    ARM: dts: qcom: msm8974-FP2: Add supplies for remoteprocs

Sumit Garg <sumit.garg@linaro.org>
    arm64: dts: qcom: qcs404: Fix incorrect USB2 PHYs assignment

Marijn Suijten <marijn.suijten@somainline.org>
    arm64: dts: qcom: msm8998: Make regulator voltages multiple of step-size

Parikshit Pareek <quic_ppareek@quicinc.com>
    soc: qcom: socinfo: Fix the id of SA8540P SoC

Konrad Dybcio <konrad.dybcio@somainline.org>
    soc: qcom: Make QCOM_RPMPD depend on PM

Liang He <windhl@126.com>
    regulator: of: Fix refcount leak bug in of_get_regulation_constraints()

Mikulas Patocka <mpatocka@redhat.com>
    dm writecache: count number of blocks discarded, not number of discard bios

Mikulas Patocka <mpatocka@redhat.com>
    dm writecache: count number of blocks written, not number of write bios

Mikulas Patocka <mpatocka@redhat.com>
    dm writecache: count number of blocks read, not number of read bios

Mikulas Patocka <mpatocka@redhat.com>
    dm writecache: return void from functions

Hsin-Yi Wang <hsinyi@chromium.org>
    PM: domains: Ensure genpd_debugfs_dir exists before remove

Bart Van Assche <bvanassche@acm.org>
    blktrace: Trace remapped requests correctly

Linus Walleij <linus.walleij@linaro.org>
    hwmon: (drivetemp) Add module alias

Armin Wolf <W_Armin@gmx.de>
    hwmon: (sch56xx-common) Add DMI override table

Yang Yingliang <yangyingliang@huawei.com>
    spi: tegra20-slink: fix UAF in tegra_slink_remove()

Yang Yingliang <yangyingliang@huawei.com>
    spi: Fix simplification of devm_spi_register_controller

Nandhini Srikandan <nandhini.srikandan@intel.com>
    spi: dw: Fix IP-core versions macro

Ming Lei <ming.lei@redhat.com>
    blk-mq: don't create hctx debugfs dir until q->debugfs_dir is created

Andy Shevchenko <andriy.shevchenko@linux.intel.com>
    spi: Return deferred probe error when controller isn't yet available

Gao Xiang <hsiangkao@linux.alibaba.com>
    erofs: avoid consecutive detection for Highmem memory

Yuwen Chen <chenyuwen1@meizu.com>
    erofs: wake up all waiters after z_erofs_lzma_head ready

Johan Hovold <johan+linaro@kernel.org>
    arm64: dts: qcom: sc7280: fix PCIe clock reference

Tamás Szűcs <tszucs@protonmail.ch>
    arm64: tegra: Fix SDMMC1 CD on P2888

Mikko Perttunen <mperttunen@nvidia.com>
    arm64: tegra: Mark BPMP channels as no-memory-wc

Nick Hainke <vincent@systemli.org>
    arm64: dts: mt7622: fix BPI-R64 WPS button

Johan Hovold <johan+linaro@kernel.org>
    arm64: dts: qcom: sm8250: add missing PCIe PHY clock-cells

Johan Hovold <johan+linaro@kernel.org>
    arm64: dts: qcom: sc7280: drop PCIe PHY clock index

Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
    arm64: dts: qcom: msm8996: correct #clock-cells for QMP PHY nodes

Marijn Suijten <marijn.suijten@somainline.org>
    arm64: dts: qcom: sm6125: Append -state suffix to pinctrl nodes

Marijn Suijten <marijn.suijten@somainline.org>
    arm64: dts: qcom: sm6125: Move sdc2 pinctrl from seine-pdx201 to sm6125

Eric Auger <eric.auger@redhat.com>
    ACPI: VIOT: Fix ACS setup

Chanho Park <chanho61.park@samsung.com>
    arm64: dts: exynosautov9: correct spi11 pin names

Stephane Eranian <eranian@google.com>
    perf/core: Add perf_clear_branch_entry_bitfields() helper

Sireesh Kodali <sireeshkodali1@gmail.com>
    arm64: dts: qcom: msm8916: Fix typo in pronto remoteproc node

GONG, Ruiqi <gongruiqi1@huawei.com>
    stack: Declare {randomize_,}kstack_offset to fix Sparse warnings

Kees Cook <keescook@chromium.org>
    lib: overflow: Do not define 64-bit tests on 32-bit

Yang Yingliang <yangyingliang@huawei.com>
    bus: hisi_lpc: fix missing platform_device_put() in hisi_lpc_acpi_probe()

Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
    ARM: dts: qcom: pm8841: add required thermal-sensor-cells

Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
    ARM: dts: qcom: msm8974: add required ranges to OCMEM

Miaoqian Lin <linmq006@gmail.com>
    soc: qcom: aoss: Fix refcount leak in qmp_cooling_devices_register

Miaoqian Lin <linmq006@gmail.com>
    soc: qcom: ocmem: Fix refcount leak in of_get_ocmem

Julia Lawall <Julia.Lawall@inria.fr>
    ia64: fix typos in comments

Alexander Vorwerk <alexander.vorwerk@stud.uni-goettingen.de>
    iio: core: fix a few code style issues

Jing Leng <jleng@ambarella.com>
    kbuild: Fix include path in scripts/Makefile.modpost

Luca Weiss <luca@z3ntu.xyz>
    ARM: dts: qcom-msm8974: fix irq type on blsp2_uart1

Konrad Dybcio <konrad.dybcio@somainline.org>
    ARM: dts: qcom-msm8974: Sort and clean up nodes

Konrad Dybcio <konrad.dybcio@somainline.org>
    ARM: dts: qcom-msm8974: Convert ADSP to a MMIO device

Konrad Dybcio <konrad.dybcio@somainline.org>
    ARM: dts: qcom-msm8974-castor: Use &labels

Konrad Dybcio <konrad.dybcio@somainline.org>
    ARM: dts: qcom-msm8974-{"hon","am"}ami: Commonize and modernize the DTs

Konrad Dybcio <konrad.dybcio@somainline.org>
    ARM: dts: qcom-msm8974-klte: Use &labels

Konrad Dybcio <konrad.dybcio@somainline.org>
    ARM: dts: qcom-msm8974-lge-nexus5: Use &labels

Konrad Dybcio <konrad.dybcio@somainline.org>
    ARM: dts: qcom-msm8974-fp2: Use &labels

Konrad Dybcio <konrad.dybcio@somainline.org>
    ARM: dts: qcom-apq8074-dragonboard: Use &labels

Konrad Dybcio <konrad.dybcio@somainline.org>
    ARM: dts: qcom-msm8974*: Rename msmgpio to tlmm

Konrad Dybcio <konrad.dybcio@somainline.org>
    ARM: dts: qcom-msm8974: Fix up SDHCI nodes

Konrad Dybcio <konrad.dybcio@somainline.org>
    ARM: dts: qcom-msm8974: Fix up mdss nodes

Konrad Dybcio <konrad.dybcio@somainline.org>
    ARM: dts: qcom-msm8974*: Fix I2C labels

Konrad Dybcio <konrad.dybcio@somainline.org>
    ARM: dts: qcom-msm8974*: Fix UART naming

Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
    ARM: dts: qcom: do not use underscore in node name

Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
    ARM: dts: qcom: msm8974-samsung-klte: move gpio-keys out of soc

Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
    ARM: dts: qcom: msm8974-lge-nexus5: move gpio-keys out of soc

Dan Williams <dan.j.williams@intel.com>
    ACPI: APEI: Fix _EINJ vs EFI_MEMORY_SP

Stephan Gerhold <stephan.gerhold@kernkonzept.com>
    regulator: qcom_smd: Fix pm8916_pldo range

Chris Paterson <chris.paterson2@renesas.com>
    arm64: dts: renesas: r9a07g054l2-smarc: Correct SoC name in comment

Geert Uytterhoeven <geert+renesas@glider.be>
    arm64: dts: renesas: r8a779m8: Drop operating points above 1.5 GHz

Miaoqian Lin <linmq006@gmail.com>
    cpufreq: zynq: Fix refcount leak in zynq_get_revision

Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
    arm64: dts: qcom: sdm636-sony-xperia-ganges-mermaid: correct sdc2 pinconf

Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
    arm64: dts: qcom: sdm630: fix gpu's interconnect path

Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
    arm64: dts: qcom: sdm630: fix the qusb2phy ref clock

Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
    arm64: dts: qcom: sdm630: disable GPU by default

Miaoqian Lin <linmq006@gmail.com>
    ARM: OMAP2+: Fix refcount leak in omap3xxx_prm_late_init

Miaoqian Lin <linmq006@gmail.com>
    ARM: OMAP2+: Fix refcount leak in omapdss_init_of

Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
    ARM: dts: qcom: mdm9615: add missing PMIC GPIO reg

Marijn Suijten <marijn.suijten@somainline.org>
    arm64: dts: qcom: sdm845-akatsuki: Round down l22a regulator voltage

Keith Busch <kbusch@kernel.org>
    block: fix infinite loop for invalid zone append

Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
    spi: s3c64xx: constify fsd_spi_port_config

Michael Walle <michael@walle.cc>
    soc: fsl: guts: machine variable might be unset

Stephen Boyd <swboyd@chromium.org>
    arm64: dts: qcom: sc7180: Remove ipa_fw_mem node on trogdor

Peter Zijlstra <peterz@infradead.org>
    locking/lockdep: Fix lockdep_init_map_*() confusion

Alexandru Elisei <alexandru.elisei@arm.com>
    arm64: cpufeature: Allow different PMU versions in ID_DFR0_EL1

Mark Rutland <mark.rutland@arm.com>
    arm64: select TRACE_IRQFLAGS_NMI_SUPPORT

Nícolas F. R. A. Prado <nfraprado@collabora.com>
    arm64: dts: mt8192: Fix idle-states entry-method

Nícolas F. R. A. Prado <nfraprado@collabora.com>
    arm64: dts: mt8192: Fix idle-states nodes naming scheme

Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
    ARM: dts: ast2600-evb-a1: fix board compatible

Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
    ARM: dts: ast2600-evb: fix board compatible

Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
    ARM: dts: ast2500-evb: fix board compatible

Johan Hovold <johan@kernel.org>
    x86/pmem: Fix platform-device leak in error path

Max Krummenacher <max.krummenacher@toradex.com>
    Revert "ARM: dts: imx6qdl-apalis: Avoid underscore in node name"

Geert Uytterhoeven <geert+renesas@glider.be>
    arm64: dts: renesas: Fix thermal-sensors on single-zone sensors

Liang He <windhl@126.com>
    soc: amlogic: Fix refcount leak in meson-secure-pwrc.c

Geert Uytterhoeven <geert+renesas@glider.be>
    soc: renesas: r8a779a0-sysc: Fix A2DP1 and A2CV[2357] PDR values

Marcel Ziswiler <marcel.ziswiler@toradex.com>
    ARM: dts: imx7d-colibri-emmc: add cpu1 supply

Guilherme G. Piccoli <gpiccoli@igalia.com>
    ACPI: processor/idle: Annotate more functions to live in cpuidle section

Miaoqian Lin <linmq006@gmail.com>
    ARM: bcm: Fix refcount leak in bcm_kona_smc_init

Christophe JAILLET <christophe.jaillet@wanadoo.fr>
    spi: spi-altera-dfl: Fix an error handling path

Geert Uytterhoeven <geert+renesas@glider.be>
    arm64: dts: renesas: beacon: Fix regulator node names

Miaoqian Lin <linmq006@gmail.com>
    meson-mx-socinfo: Fix refcount leak in meson_mx_socinfo_init

Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
    ARM: findbit: fix overflowing offset

Florian Westphal <fw@strlen.de>
    netfilter: nft_queue: only allow supported familes and hooks

Florian Westphal <fw@strlen.de>
    netfilter: nf_tables: add rescheduling points during loop detection walks

Biju Das <biju.das.jz@bp.renesas.com>
    spi: spi-rspi: Fix PIO fallback on RZ platforms

Michael Ellerman <mpe@ellerman.id.au>
    powerpc/64s: Disable stack variable initialisation for prom_init

xinhui pan <xinhui.pan@amd.com>
    drm/amdgpu: Remove one duplicated ef removal

Mario Limonciello <mario.limonciello@amd.com>
    pinctrl: Don't allow PINCTRL_AMD to be a module

Kees Cook <keescook@chromium.org>
    kasan: test: Silence GCC 12 warnings

Xiu Jianfeng <xiujianfeng@huawei.com>
    selinux: Add boundary check in put_entry()

Xiu Jianfeng <xiujianfeng@huawei.com>
    selinux: fix memleak in security_read_state_kernel()

Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
    PM: hibernate: defer device probing when resuming from hibernation

Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
    hwmon: (sht15) Fix wrong assumptions in device remove callback

Hans de Goede <hdegoede@redhat.com>
    ACPI: video: Use native backlight on Dell Inspiron N4010

Armin Wolf <W_Armin@gmx.de>
    hwmon: (dell-smm) Add Dell XPS 13 7390 to fan control whitelist

Lv Ruyi <lv.ruyi@zte.com.cn>
    firmware: tegra: Fix error check return value of debugfs_create_file()

Liang He <windhl@126.com>
    ARM: shmobile: rcar-gen2: Increase refcount for new reference

Samuel Holland <samuel@sholland.org>
    arm64: dts: allwinner: a64: orangepi-win: Fix LED node name

Robert Marko <robimarko@gmail.com>
    arm64: dts: qcom: ipq8074: fix NAND node name

Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
    arm64: dts: qcom: add missing AOSS QMP compatible fallback

Manivannan Sadhasivam <mani@kernel.org>
    ARM: dts: qcom: sdx55: Fix the IRQ trigger type for UART

huhai <huhai@kylinos.cn>
    ACPI: LPSS: Fix missing check in register_device_clock()

Manyi Li <limanyi@uniontech.com>
    ACPI: PM: save NVS memory for Lenovo G40-45

Hans de Goede <hdegoede@redhat.com>
    ACPI: EC: Drop the EC_FLAGS_IGNORE_DSDT_GPE quirk

Hans de Goede <hdegoede@redhat.com>
    ACPI: EC: Remove duplicate ThinkPad X1 Carbon 6th entry from DMI quirks

Liang He <windhl@126.com>
    ARM: OMAP2+: pdata-quirks: Fix refcount leak bug

Liang He <windhl@126.com>
    ARM: OMAP2+: display: Fix refcount leak bug

Guo Mengqi <guomengqi3@huawei.com>
    spi: synquacer: Add missing clk_disable_unprepare()

David Heidelberg <david@ixit.cz>
    arm64: dts: qcom: timer should use only 32-bit size

Linus Walleij <linus.walleij@linaro.org>
    ARM: dts: ux500: Fix Gavini accelerometer mounting matrix

Linus Walleij <linus.walleij@linaro.org>
    ARM: dts: ux500: Fix Codina accelerometer mounting matrix

Linus Walleij <linus.walleij@linaro.org>
    ARM: dts: ux500: Fix Janice accelerometer mounting matrix

Christian Lamparter <chunkeey@gmail.com>
    ARM: dts: BCM5301X: Add DT for Meraki MR26

Alexander Stein <alexander.stein@ew.tq-group.com>
    ARM: dts: imx6ul: fix qspi node compatible

Alexander Stein <alexander.stein@ew.tq-group.com>
    ARM: dts: imx6ul: fix lcdif node compatible

Alexander Stein <alexander.stein@ew.tq-group.com>
    ARM: dts: imx6ul: fix csi node compatible

Alexander Stein <alexander.stein@ew.tq-group.com>
    ARM: dts: imx6ul: fix keypad compatible

Alexander Stein <alexander.stein@ew.tq-group.com>
    ARM: dts: imx6ul: change operating-points to uint32-matrix

Alexander Stein <alexander.stein@ew.tq-group.com>
    ARM: dts: imx6ul: add missing properties for sram

Juri Lelli <juri.lelli@redhat.com>
    wait: Fix __wait_event_hrtimeout for RT/DL tasks

William Dean <williamsukatube@163.com>
    irqchip/mips-gic: Check the return value of ioremap() in gic_of_init()

John Keeping <john@metanate.com>
    sched/core: Always flush pending blk_plug

Vincent Guittot <vincent.guittot@linaro.org>
    sched/fair: fix case with reduced capacity CPU

Samuel Holland <samuel@sholland.org>
    genirq: GENERIC_IRQ_IPI depends on SMP

Samuel Holland <samuel@sholland.org>
    irqchip/mips-gic: Only register IPI domain when SMP is enabled

Antonio Borneo <antonio.borneo@foss.st.com>
    genirq: Don't return error on missing optional irq_request_resources()

Chen Yu <yu.c.chen@intel.com>
    sched/fair: Introduce SIS_UTIL to search idle CPU based on sum of util_avg

Jan Kara <jack@suse.cz>
    ext2: Add more validity checks for inode counts

James Morse <james.morse@arm.com>
    arm64: errata: Remove AES hwcap for COMPAT tasks

Catalin Marinas <catalin.marinas@arm.com>
    arm64: kasan: Revert "arm64: mte: reset the page tag in page->flags"

haibinzhang (张海斌) <haibinzhang@tencent.com>
    arm64: fix oops in concurrently setting insn_emulation sysctls

Francis Laniel <flaniel@linux.microsoft.com>
    arm64: Do not forget syscall when starting a new thread.

Mark Rutland <mark.rutland@arm.com>
    arch: make TRACE_IRQFLAGS_NMI_SUPPORT generic

Wyes Karny <wyes.karny@amd.com>
    x86: Handle idle=nomwait cmdline properly for x86_idle

Benjamin Segall <bsegall@google.com>
    epoll: autoremove wakers even more aggressively

Florian Westphal <fw@strlen.de>
    netfilter: nf_tables: fix null deref due to zeroed list head

Thadeu Lima de Souza Cascardo <cascardo@canonical.com>
    netfilter: nf_tables: do not allow RULE_ID to refer to another chain

Thadeu Lima de Souza Cascardo <cascardo@canonical.com>
    netfilter: nf_tables: do not allow CHAIN_ID to refer to another table

Thadeu Lima de Souza Cascardo <cascardo@canonical.com>
    netfilter: nf_tables: do not allow SET_ID to refer to another table

Michael Grzeschik <m.grzeschik@pengutronix.de>
    usb: dwc3: gadget: fix high speed multiplier setting

Michael Grzeschik <m.grzeschik@pengutronix.de>
    usb: dwc3: gadget: refactor dwc3_repare_one_trb

Alan Stern <stern@rowland.harvard.edu>
    USB: gadget: Fix use-after-free Read in usb_udc_uevent()

Kunihiko Hayashi <hayashi.kunihiko@socionext.com>
    arm64: dts: uniphier: Fix USB interrupts for PXs3 SoC

Kunihiko Hayashi <hayashi.kunihiko@socionext.com>
    ARM: dts: uniphier: Fix USB interrupts for PXs2 SoC

Jose Alonso <joalonsof@gmail.com>
    Revert "net: usb: ax88179_178a needs FLAG_SEND_ZLP"

Weitao Wang <WeitaoWang-oc@zhaoxin.com>
    USB: HCD: Fix URB giveback issue in tasklet function

Linyu Yuan <quic_linyyuan@quicinc.com>
    usb: typec: ucsi: Acknowledge the GET_ERROR_STATUS command completion

Suzuki K Poulose <suzuki.poulose@arm.com>
    coresight: Clear the connection field properly

Huacai Chen <chenhuacai@kernel.org>
    MIPS: cpuinfo: Fix a warning for CONFIG_CPUMASK_OFFSTACK

Michael Ellerman <mpe@ellerman.id.au>
    powerpc/powernv: Avoid crashing if rng is NULL

Christophe Leroy <christophe.leroy@csgroup.eu>
    powerpc/ptdump: Fix display of RW pages on FSL_BOOK3E

Pali Rohár <pali@kernel.org>
    powerpc/fsl-pci: Fix Class Code of PCIe Root Port

Christophe Leroy <christophe.leroy@csgroup.eu>
    powerpc/64e: Fix early TLB miss with KUAP

Christophe Leroy <christophe.leroy@csgroup.eu>
    powerpc: Restore CONFIG_DEBUG_INFO in defconfigs

Alexander Lobakin <alexandr.lobakin@intel.com>
    ia64, processor: fix -Wincompatible-pointer-types in ia64_get_irr()

Xiaomeng Tong <xiam0nd.tong@gmail.com>
    media: [PATCH] pci: atomisp_cmd: fix three missing checks on list iterator

Randy Dunlap <rdunlap@infradead.org>
    media: isl7998x: select V4L2_FWNODE to fix build error

Jan Kara <jack@suse.cz>
    mbcache: add functions to delete entry if unused

Jan Kara <jack@suse.cz>
    mbcache: don't reclaim used entries

Mikulas Patocka <mpatocka@redhat.com>
    md-raid10: fix KASAN warning

Mikulas Patocka <mpatocka@redhat.com>
    md-raid: destroy the bitmap after destroying the thread

Narendra Hadke <nhadke@marvell.com>
    serial: mvebu-uart: uart2 error bits clearing

Miklos Szeredi <mszeredi@redhat.com>
    fuse: fix deadlock between atomic O_TRUNC and page invalidation

Miklos Szeredi <mszeredi@redhat.com>
    fuse: write inode in fuse_release()

Miklos Szeredi <mszeredi@redhat.com>
    fuse: ioctl: translate ENOSYS

Miklos Szeredi <mszeredi@redhat.com>
    fuse: limit nsec

Namjae Jeon <linkinjeon@kernel.org>
    ksmbd: fix heap-based overflow in set_ntacl_dacl()

Namjae Jeon <linkinjeon@kernel.org>
    ksmbd: fix use-after-free bug in smb2_tree_disconect

Hyunchul Lee <hyc.lee@gmail.com>
    ksmbd: prevent out of bound read for SMB2_TREE_CONNNECT

Namjae Jeon <linkinjeon@kernel.org>
    ksmbd: fix memory leak in smb2_handle_negotiate

Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
    soundwire: qcom: Check device status before reading devid

Bikash Hazarika <bhazarika@marvell.com>
    scsi: qla2xxx: Zero undefined mailbox IN registers

Bikash Hazarika <bhazarika@marvell.com>
    scsi: qla2xxx: Fix incorrect display of max frame size

Tony Battersby <tonyb@cybernetics.com>
    scsi: sg: Allow waiting for commands to complete on removed device

James Smart <jsmart2021@gmail.com>
    scsi: lpfc: Remove extra atomic_inc on cmd_pending in queuecommand after VMID

Zheyu Ma <zheyuma97@gmail.com>
    iio: light: isl29028: Fix the warning in isl29028_remove()

Fawzi Khaber <fawzi.khaber@tdk.com>
    iio: fix iio_format_avail_range() printing for none IIO_VAL_INT

Jason A. Donenfeld <Jason@zx2c4.com>
    um: seed rng using host OS rng

Benjamin Beichler <benjamin.beichler@uni-rostock.de>
    um: Remove straying parenthesis

Amit Kumar Mahapatra <amit.kumar-mahapatra@xilinx.com>
    mtd: rawnand: arasan: Update NAND bus clock instead of system clock

Olga Kitaina <okitain@gmail.com>
    mtd: rawnand: arasan: Fix clock rate in NV-DDR

Qu Wenruo <wqu@suse.com>
    btrfs: reject log replay if there is unsupported RO compat flag

Tadeusz Struk <tadeusz.struk@linaro.org>
    bpf: Fix KASAN use-after-free Read in compute_effective_progs

Leo Li <sunpeng.li@amd.com>
    drm/amdgpu: Check BO's requested pinning domains against its preferred_domains

Dmitry Osipenko <dmitry.osipenko@collabora.com>
    drm/tegra: Fix vmapping of prime buffers

Lyude Paul <lyude@redhat.com>
    drm/nouveau/kms: Fix failure path for creating DP connectors

Lyude Paul <lyude@redhat.com>
    drm/nouveau/acpi: Don't print error when we get -EINPROGRESS from pm_runtime

Lyude Paul <lyude@redhat.com>
    drm/nouveau: Don't pm_runtime_put_sync(), only pm_runtime_put_autosuspend()

Timur Tabi <ttabi@nvidia.com>
    drm/nouveau: fix another off-by-one in nvbios_addr

Thomas Zimmermann <tzimmermann@suse.de>
    drm/hyperv-drm: Include framebuffer and EDID headers

Paul Cercueil <paul@crapouillou.net>
    drm/ingenic: Use the highest possible DMA burst size

Phil Elwell <phil@raspberrypi.org>
    drm/vc4: hdmi: Disable audio if dmas property is present but empty

Dmitry Osipenko <dmitry.osipenko@collabora.com>
    drm/shmem-helper: Add missing vunmap on error

Dmitry Osipenko <dmitry.osipenko@collabora.com>
    drm/gem: Properly annotate WW context on drm_gem_lock_reservations() error

Mathew McBride <matt@traverse.com.au>
    rtc: rx8025: fix 12/24 hour mode detection on RX-8035

Jason A. Donenfeld <Jason@zx2c4.com>
    wireguard: selftests: set CONFIG_NONPORTABLE on riscv32

Xianting Tian <xianting.tian@linux.alibaba.com>
    RISC-V: Add modules to virtual kernel memory layout dump

Atish Patra <atishp@rivosinc.com>
    RISC-V: Update user page mapping only once during start

Atish Patra <atishp@rivosinc.com>
    RISC-V: Fix SBI PMU calls for RV32

Atish Patra <atishp@rivosinc.com>
    RISC-V: Fix counter restart during overflow for RV32

Xianting Tian <xianting.tian@linux.alibaba.com>
    RISC-V: Fixup schedule out issue in machine_crash_shutdown()

Xianting Tian <xianting.tian@linux.alibaba.com>
    RISC-V: Fixup get incorrect user mode PC for kernel mode regs

Xianting Tian <xianting.tian@linux.alibaba.com>
    RISC-V: kexec: Fixup use of smp_processor_id() in preemptible context

Ben Dooks <ben.dooks@sifive.com>
    RISC-V: Declare cpu_ops_spinwait in <asm/cpu_ops.h>

Ben Dooks <ben.dooks@sifive.com>
    RISC-V: cpu_ops_spinwait.c should include head.h

Mark Kettenis <kettenis@openbsd.org>
    riscv: dts: starfive: correct number of external interrupts

Conor Dooley <conor.dooley@microchip.com>
    dt-bindings: riscv: fix SiFive l2-cache's cache-sets

Chen Lifu <chenlifu@huawei.com>
    riscv: lib: uaccess: fix CSR_STATUS SR_SUM bit

Yipeng Zou <zouyipeng@huawei.com>
    riscv:uprobe fix SR_SPIE set/clear handling

Helge Deller <deller@gmx.de>
    parisc: io_pgetevents_time64() needs compat syscall in 32-bit compat mode

William Dean <williamsukatube@gmail.com>
    parisc: Check the return value of ioremap() in lba_driver_probe()

Helge Deller <deller@gmx.de>
    parisc: Drop pa_swapper_pg_lock spinlock

Helge Deller <deller@gmx.de>
    parisc: Fix device names in /proc/iomem

Jiachen Zhang <zhangjiachen.jaycee@bytedance.com>
    ovl: drop WARN_ON() dentry is NULL in ovl_encode_fh()

John Allen <john.allen@amd.com>
    crypto: ccp - Use kzalloc for sev ioctl interfaces to prevent kernel memory leak

Al Viro <viro@zeniv.linux.org.uk>
    fix short copy handling in copy_mc_pipe_to_iter()

Lukas Wunner <lukas@wunner.de>
    usbnet: Fix linkwatch use-after-free on disconnect

Helge Deller <deller@gmx.de>
    fbcon: Fix accelerated fbdev scrolling while logo is still shown

Helge Deller <deller@gmx.de>
    fbcon: Fix boundary checks for fbcon=vc:n1-n2 parameters

Rafael J. Wysocki <rafael.j.wysocki@intel.com>
    thermal: sysfs: Fix cooling_device_stats_setup() error code path

Yang Xu <xuyang2018.jy@fujitsu.com>
    fs: Add missing umask strip in vfs_tmpfile

David Howells <dhowells@redhat.com>
    vfs: Check the truncate maximum size in inode_newsize_ok()

Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
    tty: vt: initialize unicode screen buffer

Bedant Patnaik <bedant.patnaik@gmail.com>
    ALSA: hda/realtek: Add a quirk for HP OMEN 15 (8786) mute LED

Meng Tang <tangmeng@uniontech.com>
    ALSA: hda/realtek: Add quirk for another Asus K42JZ model

Allen Ballway <ballway@chromium.org>
    ALSA: hda/cirrus - support for iMac 12,1 model

Meng Tang <tangmeng@uniontech.com>
    ALSA: hda/conexant: Add quirk for LENOVO 20149 Notebook model

Paolo Bonzini <pbonzini@redhat.com>
    KVM: x86: revalidate steal time cache if MSR value changes

Paolo Bonzini <pbonzini@redhat.com>
    KVM: x86: do not report preemption if the steal time cache is stale

Sean Christopherson <seanjc@google.com>
    KVM: x86: Tag kvm_mmu_x86_module_init() with __init

Vitaly Kuznetsov <vkuznets@redhat.com>
    KVM: nVMX: Always enable TSC scaling for L2 when it was enabled for L1

Sean Christopherson <seanjc@google.com>
    KVM: x86: Set error code to segment selector on LLDT/LTR non-canonical #GP

Sean Christopherson <seanjc@google.com>
    KVM: x86: Mark TSS busy during LTR emulation _after_ all fault checks

Sean Christopherson <seanjc@google.com>
    KVM: nVMX: Inject #UD if VMXON is attempted with incompatible CR0/CR4

Sean Christopherson <seanjc@google.com>
    KVM: nVMX: Account for KVM reserved CR4 bits in consistency checks

Sean Christopherson <seanjc@google.com>
    KVM: nVMX: Let userspace set nVMX MSR to any _host_ supported value

Sean Christopherson <seanjc@google.com>
    KVM: x86: Split kvm_is_valid_cr4() and export only the non-vendor bits

Sean Christopherson <seanjc@google.com>
    KVM: Do not incorporate page offset into gfn=>pfn cache user address

Sean Christopherson <seanjc@google.com>
    KVM: Fix multiple races in gfn=>pfn cache refresh

Sean Christopherson <seanjc@google.com>
    KVM: Fully serialize gfn=>pfn cache refresh via mutex

Sean Christopherson <seanjc@google.com>
    KVM: Put the extra pfn reference when reusing a pfn in the gpc cache

Sean Christopherson <seanjc@google.com>
    KVM: Drop unused @gpa param from gfn=>pfn cache's __release_gpc() helper

Nico Boehr <nrb@linux.ibm.com>
    KVM: s390: pv: don't present the ecall interrupt twice

Maciej S. Szmigiero <maciej.szmigiero@oracle.com>
    KVM: SVM: Don't BUG if userspace injects an interrupt with GIF=0

Sean Christopherson <seanjc@google.com>
    KVM: nVMX: Snapshot pre-VM-Enter DEBUGCTL for !nested_run_pending case

Sean Christopherson <seanjc@google.com>
    KVM: nVMX: Snapshot pre-VM-Enter BNDCFGS for !nested_run_pending case

Ping Cheng <pinglinux@gmail.com>
    HID: wacom: Don't register pad_input for touch switch

Ping Cheng <pinglinux@gmail.com>
    HID: wacom: Only report rotation for art pen

Guenter Roeck <linux@roeck-us.net>
    HID: nintendo: Add missing array termination

Maximilian Luz <luzmaximilian@gmail.com>
    HID: hid-input: add Surface Go battery quirk

Jeff Layton <jlayton@kernel.org>
    lockd: detect and reject lock arguments that overflow

Mikulas Patocka <mpatocka@redhat.com>
    add barriers to buffer_uptodate and set_buffer_uptodate

Johannes Berg <johannes.berg@intel.com>
    wifi: mac80211_hwsim: use 32-bit skb cookie

Johannes Berg <johannes.berg@intel.com>
    wifi: mac80211_hwsim: add back erroneously removed cast

Jeongik Cha <jeongik@google.com>
    wifi: mac80211_hwsim: fix race condition in pending packet

syed sabakareem <Syed.SabaKareem@amd.com>
    ASoC: amd: yc: Update DMI table entries

Philipp Jungkamp <p.jungkamp@gmx.net>
    ALSA: hda/realtek: Add quirk for Lenovo Yoga9 14IAP7

Ivan Hasenkampf <ivan.hasenkampf@gmail.com>
    ALSA: hda/realtek: Add quirk for HP Spectre x360 15-eb0xxx

Tim Crawford <tcrawford@system76.com>
    ALSA: hda/realtek: Add quirk for Clevo NV45PZ

Zheyu Ma <zheyuma97@gmail.com>
    ALSA: bcd2000: Fix a UAF bug on the error path of probing

Takashi Iwai <tiwai@suse.de>
    ALSA: usb-audio: Add quirk for Behringer UMC202HD

Jeff Layton <jlayton@kernel.org>
    nfsd: eliminate the NFSD_FILE_BREAK_* flags

Chuck Lever <chuck.lever@oracle.com>
    NFSD: Clean up the show_nf_flags() macro

Trond Myklebust <trond.myklebust@hammerspace.com>
    pNFS/flexfiles: Report RDMA connection errors to the server

Nilesh Javali <njavali@marvell.com>
    scsi: Revert "scsi: qla2xxx: Fix disk failure to rediscover"

Trond Myklebust <trond.myklebust@hammerspace.com>
    Revert "pNFS: nfs3_set_ds_client should set NFS_CS_NOPING"

Nick Desaulniers <ndesaulniers@google.com>
    x86: link vdso and boot with -z noexecstack --no-warn-rwx-segments

Nick Desaulniers <ndesaulniers@google.com>
    Makefile: link with -z noexecstack --no-warn-rwx-segments


-------------

Diffstat:

 Documentation/ABI/testing/sysfs-driver-xen-blkback |    2 +-
 .../ABI/testing/sysfs-driver-xen-blkfront          |    2 +-
 .../admin-guide/device-mapper/writecache.rst       |   16 +-
 Documentation/admin-guide/kernel-parameters.txt    |   29 +-
 Documentation/admin-guide/pm/cpuidle.rst           |   15 +-
 Documentation/arm64/silicon-errata.rst             |    4 +
 .../devicetree/bindings/riscv/sifive-l2-cache.yaml |    6 +-
 .../tty/device_drivers/oxsemi-tornado.rst          |  129 ++
 .../userspace-api/media/v4l/ext-ctrls-codec.rst    |    2 +-
 MAINTAINERS                                        |    7 +-
 Makefile                                           |   10 +-
 arch/Kconfig                                       |    3 +
 arch/arm/boot/dts/Makefile                         |    1 +
 arch/arm/boot/dts/aspeed-ast2500-evb.dts           |    2 +-
 arch/arm/boot/dts/aspeed-ast2600-evb-a1.dts        |    1 +
 arch/arm/boot/dts/aspeed-ast2600-evb.dts           |    2 +-
 arch/arm/boot/dts/bcm53015-meraki-mr26.dts         |  166 ++
 arch/arm/boot/dts/imx6qdl-apalis.dtsi              |    4 +-
 arch/arm/boot/dts/imx6ul.dtsi                      |   33 +-
 arch/arm/boot/dts/imx7d-colibri-emmc.dtsi          |    4 +
 arch/arm/boot/dts/qcom-apq8064.dtsi                |    8 +-
 arch/arm/boot/dts/qcom-apq8074-dragonboard.dts     |  609 ++++----
 arch/arm/boot/dts/qcom-apq8084.dtsi                |    2 +-
 arch/arm/boot/dts/qcom-mdm9615.dtsi                |    1 +
 arch/arm/boot/dts/qcom-msm8974-fairphone-fp2.dts   |  604 ++++----
 .../dts/qcom-msm8974-lge-nexus5-hammerhead.dts     | 1145 +++++++-------
 arch/arm/boot/dts/qcom-msm8974-samsung-klte.dts    | 1258 ++++++++--------
 .../boot/dts/qcom-msm8974-sony-xperia-amami.dts    |  432 +-----
 .../boot/dts/qcom-msm8974-sony-xperia-castor.dts   |  996 ++++++------
 .../boot/dts/qcom-msm8974-sony-xperia-honami.dts   |  479 +-----
 .../boot/dts/qcom-msm8974-sony-xperia-rhine.dtsi   |  455 ++++++
 arch/arm/boot/dts/qcom-msm8974.dtsi                | 1587 ++++++++++----------
 arch/arm/boot/dts/qcom-pm8841.dtsi                 |    1 +
 arch/arm/boot/dts/qcom-pm8941.dtsi                 |    2 +-
 arch/arm/boot/dts/qcom-sdx55.dtsi                  |    2 +-
 arch/arm/boot/dts/ste-ux500-samsung-codina.dts     |    4 +-
 arch/arm/boot/dts/ste-ux500-samsung-gavini.dts     |    4 +-
 arch/arm/boot/dts/ste-ux500-samsung-janice.dts     |    4 +-
 arch/arm/boot/dts/uniphier-pxs2.dtsi               |    8 +-
 arch/arm/crypto/Kconfig                            |    2 +-
 arch/arm/crypto/Makefile                           |    4 +-
 arch/arm/crypto/blake2s-shash.c                    |   75 -
 arch/arm/lib/findbit.S                             |   16 +-
 arch/arm/mach-bcm/bcm_kona_smc.c                   |    1 +
 arch/arm/mach-omap2/display.c                      |    3 +
 arch/arm/mach-omap2/pdata-quirks.c                 |    2 +
 arch/arm/mach-omap2/prm3xxx.c                      |    1 +
 arch/arm/mach-shmobile/regulator-quirk-rcar-gen2.c |    5 +-
 arch/arm/mach-zynq/common.c                        |    1 +
 arch/arm64/Kconfig                                 |   17 +
 .../boot/dts/allwinner/sun50i-a64-orangepi-win.dts |    2 +-
 .../boot/dts/exynos/exynosautov9-pinctrl.dtsi      |    6 +-
 .../boot/dts/mediatek/mt7622-bananapi-bpi-r64.dts  |    2 +-
 arch/arm64/boot/dts/mediatek/mt8192.dtsi           |   26 +-
 arch/arm64/boot/dts/nvidia/tegra186.dtsi           |    1 +
 arch/arm64/boot/dts/nvidia/tegra194-p2888.dtsi     |    2 +-
 arch/arm64/boot/dts/nvidia/tegra194.dtsi           |    1 +
 arch/arm64/boot/dts/nvidia/tegra234.dtsi           |    1 +
 arch/arm64/boot/dts/qcom/ipq6018.dtsi              |   22 +-
 arch/arm64/boot/dts/qcom/ipq8074.dtsi              |    2 +-
 arch/arm64/boot/dts/qcom/msm8916.dtsi              |    4 +-
 arch/arm64/boot/dts/qcom/msm8996.dtsi              |    6 +-
 .../qcom/msm8998-sony-xperia-yoshino-poplar.dts    |   10 +-
 arch/arm64/boot/dts/qcom/qcs404.dtsi               |    4 +-
 arch/arm64/boot/dts/qcom/sc7180-trogdor.dtsi       |    1 +
 arch/arm64/boot/dts/qcom/sc7180.dtsi               |   24 +-
 arch/arm64/boot/dts/qcom/sc7280.dtsi               |   30 +-
 arch/arm64/boot/dts/qcom/sdm630.dtsi               |    7 +-
 .../dts/qcom/sdm636-sony-xperia-ganges-mermaid.dts |    2 +-
 .../dts/qcom/sdm845-sony-xperia-tama-akatsuki.dts  |    5 +-
 arch/arm64/boot/dts/qcom/sdm845.dtsi               |   22 +-
 .../dts/qcom/sm6125-sony-xperia-seine-pdx201.dts   |   36 +-
 arch/arm64/boot/dts/qcom/sm6125.dtsi               |   30 +-
 arch/arm64/boot/dts/qcom/sm6350.dtsi               |   22 +-
 arch/arm64/boot/dts/qcom/sm8150.dtsi               |   24 +-
 arch/arm64/boot/dts/qcom/sm8250.dtsi               |   30 +-
 arch/arm64/boot/dts/qcom/sm8350.dtsi               |   24 +-
 arch/arm64/boot/dts/qcom/sm8450.dtsi               |   22 +-
 .../boot/dts/renesas/beacon-renesom-baseboard.dtsi |    6 +-
 arch/arm64/boot/dts/renesas/r8a774c0.dtsi          |    2 +-
 arch/arm64/boot/dts/renesas/r8a77990.dtsi          |    2 +-
 arch/arm64/boot/dts/renesas/r8a779m8.dtsi          |    5 +
 arch/arm64/boot/dts/renesas/r9a07g054l2-smarc.dts  |    2 +-
 arch/arm64/boot/dts/socionext/uniphier-pxs3.dtsi   |    8 +-
 arch/arm64/crypto/Kconfig                          |    1 +
 arch/arm64/include/asm/esr.h                       |    6 +-
 arch/arm64/include/asm/kexec.h                     |    4 +-
 arch/arm64/include/asm/processor.h                 |    3 +-
 arch/arm64/kernel/armv8_deprecated.c               |    9 +-
 arch/arm64/kernel/cpu_errata.c                     |   16 +
 arch/arm64/kernel/cpufeature.c                     |   16 +-
 arch/arm64/kernel/hibernate.c                      |    5 -
 arch/arm64/kernel/mte.c                            |    9 -
 arch/arm64/kvm/hyp/nvhe/switch.c                   |    2 +-
 arch/arm64/kvm/hyp/vhe/switch.c                    |    2 +-
 arch/arm64/mm/copypage.c                           |    9 -
 arch/arm64/mm/mteswap.c                            |    9 -
 arch/arm64/tools/cpucaps                           |    1 +
 arch/ia64/include/asm/processor.h                  |    2 +-
 arch/ia64/kernel/palinfo.c                         |    2 +-
 arch/ia64/kernel/traps.c                           |    2 +-
 arch/ia64/mm/init.c                                |    2 +-
 arch/ia64/mm/tlb.c                                 |    4 +-
 arch/mips/kernel/proc.c                            |    2 +-
 arch/mips/kernel/vdso.c                            |    2 +-
 arch/mips/loongson64/numa.c                        |    1 -
 arch/mips/mm/physaddr.c                            |   14 +-
 arch/parisc/kernel/cache.c                         |    3 -
 arch/parisc/kernel/drivers.c                       |    9 +-
 arch/parisc/kernel/syscalls/syscall.tbl            |    2 +-
 arch/powerpc/boot/cuboot-hotfoot.c                 |    2 +-
 arch/powerpc/configs/44x/akebono_defconfig         |    2 +-
 arch/powerpc/configs/44x/currituck_defconfig       |    2 +-
 arch/powerpc/configs/44x/fsp2_defconfig            |    2 +-
 arch/powerpc/configs/44x/iss476-smp_defconfig      |    2 +-
 arch/powerpc/configs/44x/warp_defconfig            |    2 +-
 arch/powerpc/configs/52xx/lite5200b_defconfig      |    2 +-
 arch/powerpc/configs/52xx/motionpro_defconfig      |    2 +-
 arch/powerpc/configs/52xx/tqm5200_defconfig        |    2 +-
 arch/powerpc/configs/adder875_defconfig            |    2 +-
 arch/powerpc/configs/ep8248e_defconfig             |    2 +-
 arch/powerpc/configs/ep88xc_defconfig              |    2 +-
 arch/powerpc/configs/fsl-emb-nonhw.config          |    2 +-
 arch/powerpc/configs/mgcoge_defconfig              |    2 +-
 arch/powerpc/configs/mpc5200_defconfig             |    2 +-
 arch/powerpc/configs/mpc8272_ads_defconfig         |    2 +-
 arch/powerpc/configs/mpc885_ads_defconfig          |    2 +-
 arch/powerpc/configs/ppc6xx_defconfig              |    2 +-
 arch/powerpc/configs/pq2fads_defconfig             |    2 +-
 arch/powerpc/configs/ps3_defconfig                 |    2 +-
 arch/powerpc/configs/tqm8xx_defconfig              |    2 +-
 arch/powerpc/crypto/aes-spe-glue.c                 |    2 +-
 arch/powerpc/include/asm/archrandom.h              |    5 -
 arch/powerpc/include/asm/kexec.h                   |    9 +
 arch/powerpc/include/asm/simple_spinlock.h         |   15 +-
 arch/powerpc/kernel/Makefile                       |    1 +
 arch/powerpc/kernel/cputable.c                     |    2 +-
 arch/powerpc/kernel/dawr.c                         |    2 +-
 arch/powerpc/kernel/eeh.c                          |    4 +-
 arch/powerpc/kernel/eeh_event.c                    |    2 +-
 arch/powerpc/kernel/fadump.c                       |    4 +-
 arch/powerpc/kernel/iommu.c                        |    5 +
 arch/powerpc/kernel/module_32.c                    |    2 +-
 arch/powerpc/kernel/module_64.c                    |    4 +-
 arch/powerpc/kernel/pci-common.c                   |   31 +-
 arch/powerpc/kernel/pci_of_scan.c                  |    2 +-
 arch/powerpc/kernel/process.c                      |    4 +-
 arch/powerpc/kernel/prom_init.c                    |    2 +-
 arch/powerpc/kernel/ptrace/ptrace-view.c           |    2 +-
 arch/powerpc/kernel/rtas_flash.c                   |    2 +-
 arch/powerpc/kernel/setup-common.c                 |    2 +-
 arch/powerpc/kernel/signal_64.c                    |    2 +-
 arch/powerpc/kernel/smp.c                          |    2 +-
 arch/powerpc/kernel/time.c                         |    4 +-
 arch/powerpc/kernel/watchdog.c                     |    2 +-
 arch/powerpc/kexec/core_64.c                       |    2 +-
 arch/powerpc/kexec/file_load_64.c                  |   55 +
 arch/powerpc/kvm/book3s_64_mmu_hv.c                |    2 +-
 arch/powerpc/kvm/book3s_64_vio_hv.c                |    2 +-
 arch/powerpc/kvm/book3s_emulate.c                  |    2 +-
 arch/powerpc/kvm/book3s_hv_builtin.c               |    7 +-
 arch/powerpc/kvm/book3s_hv_p9_entry.c              |    2 +-
 arch/powerpc/kvm/book3s_hv_uvmem.c                 |    2 +-
 arch/powerpc/kvm/book3s_pr.c                       |    2 +-
 arch/powerpc/kvm/book3s_xics.c                     |    2 +-
 arch/powerpc/kvm/book3s_xive.c                     |    6 +-
 arch/powerpc/kvm/e500mc.c                          |    2 +-
 arch/powerpc/mm/book3s64/hash_pgtable.c            |    2 +-
 arch/powerpc/mm/book3s64/hash_utils.c              |    4 +-
 arch/powerpc/mm/book3s64/pgtable.c                 |    2 +-
 arch/powerpc/mm/book3s64/radix_pgtable.c           |    2 +-
 arch/powerpc/mm/book3s64/radix_tlb.c               |    2 +-
 arch/powerpc/mm/book3s64/slb.c                     |    4 +-
 arch/powerpc/mm/init_64.c                          |    4 +-
 arch/powerpc/mm/kasan/kasan_init_32.c              |    2 +-
 arch/powerpc/mm/nohash/8xx.c                       |    4 +-
 arch/powerpc/mm/nohash/book3e_hugetlbpage.c        |    2 +-
 arch/powerpc/mm/nohash/kaslr_booke.c               |    2 +-
 arch/powerpc/mm/nohash/tlb_low_64e.S               |   17 +-
 arch/powerpc/mm/pgtable-frag.c                     |    2 +-
 arch/powerpc/mm/pgtable_32.c                       |    6 +-
 arch/powerpc/mm/ptdump/shared.c                    |    6 +-
 arch/powerpc/perf/8xx-pmu.c                        |    2 +-
 arch/powerpc/perf/core-book3s.c                    |   41 +-
 arch/powerpc/perf/imc-pmu.c                        |    4 +-
 arch/powerpc/perf/isa207-common.c                  |    6 +-
 arch/powerpc/platforms/512x/clock-commonclk.c      |    2 +-
 arch/powerpc/platforms/512x/mpc512x_shared.c       |    2 +-
 arch/powerpc/platforms/52xx/mpc52xx_common.c       |    2 +-
 arch/powerpc/platforms/52xx/mpc52xx_gpt.c          |    2 +-
 arch/powerpc/platforms/52xx/mpc52xx_lpbfifo.c      |    2 +-
 arch/powerpc/platforms/85xx/mpc85xx_cds.c          |    2 +-
 arch/powerpc/platforms/86xx/gef_ppc9a.c            |    2 +-
 arch/powerpc/platforms/86xx/gef_sbc310.c           |    2 +-
 arch/powerpc/platforms/86xx/gef_sbc610.c           |    2 +-
 arch/powerpc/platforms/Kconfig.cputype             |    4 +-
 arch/powerpc/platforms/book3s/vas-api.c            |    2 +-
 arch/powerpc/platforms/cell/axon_msi.c             |    1 +
 arch/powerpc/platforms/cell/cbe_regs.c             |    2 +-
 arch/powerpc/platforms/cell/iommu.c                |    2 +-
 arch/powerpc/platforms/cell/spider-pci.c           |    2 +-
 arch/powerpc/platforms/cell/spu_manage.c           |    2 +-
 arch/powerpc/platforms/cell/spufs/inode.c          |    1 +
 arch/powerpc/platforms/powermac/low_i2c.c          |    2 +-
 arch/powerpc/platforms/powernv/eeh-powernv.c       |   10 +-
 arch/powerpc/platforms/powernv/idle.c              |    4 +-
 arch/powerpc/platforms/powernv/ocxl.c              |    2 +-
 arch/powerpc/platforms/powernv/opal-fadump.c       |    2 +-
 arch/powerpc/platforms/powernv/opal-lpc.c          |    2 +-
 .../powerpc/platforms/powernv/opal-memory-errors.c |    2 +-
 arch/powerpc/platforms/powernv/pci-sriov.c         |    2 +-
 arch/powerpc/platforms/powernv/rng.c               |   34 +-
 arch/powerpc/platforms/ps3/mm.c                    |    2 +-
 arch/powerpc/platforms/ps3/system-bus.c            |    2 +-
 arch/powerpc/platforms/pseries/eeh_pseries.c       |    2 +-
 arch/powerpc/platforms/pseries/iommu.c             |   89 +-
 arch/powerpc/platforms/pseries/setup.c             |    4 +-
 arch/powerpc/platforms/pseries/vas-sysfs.c         |    2 +-
 arch/powerpc/platforms/pseries/vas.c               |    2 +-
 arch/powerpc/sysdev/fsl_lbc.c                      |    2 +-
 arch/powerpc/sysdev/fsl_pci.c                      |   10 +-
 arch/powerpc/sysdev/fsl_pci.h                      |    1 +
 arch/powerpc/sysdev/ge/ge_pic.c                    |    2 +-
 arch/powerpc/sysdev/mpic_msgr.c                    |    2 +-
 arch/powerpc/sysdev/mpic_msi.c                     |    2 +-
 arch/powerpc/sysdev/mpic_timer.c                   |    2 +-
 arch/powerpc/sysdev/mpic_u3msi.c                   |    2 +-
 arch/powerpc/sysdev/xive/native.c                  |    2 +-
 arch/powerpc/sysdev/xive/spapr.c                   |    1 +
 arch/powerpc/xmon/ppc-opc.c                        |    2 +-
 arch/powerpc/xmon/xmon.c                           |    2 +-
 arch/riscv/boot/dts/starfive/jh7100.dtsi           |    2 +-
 arch/riscv/include/asm/cpu_ops.h                   |    1 +
 arch/riscv/kernel/cpu_ops.c                        |    4 +-
 arch/riscv/kernel/cpu_ops_spinwait.c               |    6 +-
 arch/riscv/kernel/crash_save_regs.S                |    2 +-
 arch/riscv/kernel/machine_kexec.c                  |   28 +-
 arch/riscv/kernel/probes/uprobes.c                 |    6 -
 arch/riscv/lib/uaccess.S                           |    4 +-
 arch/riscv/mm/init.c                               |    4 +
 arch/s390/include/asm/gmap.h                       |    2 +
 arch/s390/include/asm/kexec.h                      |    3 +
 arch/s390/include/asm/unwind.h                     |    2 +-
 arch/s390/kernel/crash_dump.c                      |    2 +-
 arch/s390/kernel/machine_kexec_file.c              |   18 +-
 arch/s390/kvm/intercept.c                          |   15 +
 arch/s390/kvm/pv.c                                 |    9 +-
 arch/s390/kvm/sigp.c                               |    4 +-
 arch/s390/mm/gmap.c                                |   86 ++
 arch/um/drivers/random.c                           |    2 +-
 arch/um/include/asm/archrandom.h                   |   30 +
 arch/um/include/asm/xor.h                          |    2 +-
 arch/um/include/shared/os.h                        |    7 +
 arch/um/kernel/um_arch.c                           |    8 +
 arch/um/os-Linux/util.c                            |    6 +
 arch/x86/Kconfig                                   |    1 +
 arch/x86/Kconfig.debug                             |    3 -
 arch/x86/boot/Makefile                             |    2 +-
 arch/x86/boot/compressed/Makefile                  |    4 +
 arch/x86/crypto/Makefile                           |    4 +-
 arch/x86/crypto/blake2s-glue.c                     |    3 +-
 arch/x86/crypto/blake2s-shash.c                    |   77 -
 arch/x86/entry/Makefile                            |    3 +-
 arch/x86/entry/thunk_32.S                          |    2 -
 arch/x86/entry/thunk_64.S                          |    4 -
 arch/x86/entry/vdso/Makefile                       |    2 +-
 arch/x86/events/intel/lbr.c                        |   36 +-
 arch/x86/include/asm/kexec.h                       |    6 +
 arch/x86/include/asm/kvm_host.h                    |    3 +-
 arch/x86/kernel/cpu/bugs.c                         |   10 +-
 arch/x86/kernel/cpu/intel.c                        |   27 +-
 arch/x86/kernel/ftrace.c                           |    1 +
 arch/x86/kernel/kprobes/core.c                     |   18 +-
 arch/x86/kernel/pmem.c                             |    7 +-
 arch/x86/kernel/process.c                          |    9 +-
 arch/x86/kvm/emulate.c                             |   23 +-
 arch/x86/kvm/mmu/mmu.c                             |    2 +-
 arch/x86/kvm/mmu/paging_tmpl.h                     |    9 +-
 arch/x86/kvm/mmu/spte.c                            |    2 +
 arch/x86/kvm/svm/nested.c                          |    3 +-
 arch/x86/kvm/svm/svm.c                             |   29 +-
 arch/x86/kvm/vmx/nested.c                          |  107 +-
 arch/x86/kvm/vmx/nested.h                          |    3 +-
 arch/x86/kvm/vmx/pmu_intel.c                       |   13 +-
 arch/x86/kvm/vmx/vmx.c                             |    4 +-
 arch/x86/kvm/vmx/vmx.h                             |   12 +
 arch/x86/kvm/x86.c                                 |   33 +-
 arch/x86/kvm/x86.h                                 |    2 +-
 arch/x86/mm/extable.c                              |   16 +-
 arch/x86/mm/numa.c                                 |    4 +-
 arch/x86/net/bpf_jit_comp.c                        |   67 +-
 arch/x86/platform/olpc/olpc-xo1-sci.c              |    2 +-
 arch/x86/um/Makefile                               |    3 +-
 arch/xtensa/platforms/iss/network.c                |   42 +-
 block/bio.c                                        |   99 +-
 block/blk-iocost.c                                 |   20 +-
 block/blk-iolatency.c                              |   18 +-
 block/blk-mq-debugfs.c                             |   28 +-
 block/blk-mq-debugfs.h                             |    5 -
 block/blk-mq-sched.c                               |   11 +
 block/blk-rq-qos.c                                 |    2 +
 block/blk-rq-qos.h                                 |   18 +-
 block/blk-sysfs.c                                  |   20 +-
 block/blk-wbt.c                                    |   12 +-
 crypto/Kconfig                                     |   20 +-
 crypto/Makefile                                    |    1 -
 crypto/asymmetric_keys/public_key.c                |    7 +-
 crypto/blake2s_generic.c                           |   75 -
 crypto/tcrypt.c                                    |   12 -
 crypto/testmgr.c                                   |   24 -
 crypto/testmgr.h                                   |  217 ---
 drivers/acpi/acpi_lpss.c                           |    3 +
 drivers/acpi/apei/einj.c                           |    2 +
 drivers/acpi/bus.c                                 |    1 +
 drivers/acpi/cppc_acpi.c                           |   54 +-
 drivers/acpi/ec.c                                  |   82 +-
 drivers/acpi/processor_idle.c                      |    6 +-
 drivers/acpi/sleep.c                               |    8 +
 drivers/acpi/video_detect.c                        |    8 +
 drivers/acpi/viot.c                                |   26 +-
 drivers/android/binder.c                           |  114 +-
 drivers/android/binder_alloc.c                     |   30 +-
 drivers/android/binder_alloc.h                     |    2 +-
 drivers/android/binder_alloc_selftest.c            |    2 +-
 drivers/android/binder_internal.h                  |   46 +-
 drivers/android/binderfs.c                         |   47 +-
 drivers/base/dd.c                                  |    5 +-
 drivers/base/node.c                                |    4 +-
 drivers/base/power/domain.c                        |    3 +
 drivers/base/topology.c                            |   32 +-
 drivers/block/null_blk/main.c                      |   14 +-
 drivers/block/rnbd/rnbd-srv.c                      |    3 +-
 drivers/block/xen-blkback/xenbus.c                 |   20 +-
 drivers/block/xen-blkfront.c                       |    4 +-
 drivers/bluetooth/hci_intel.c                      |    6 +-
 drivers/bluetooth/hci_serdev.c                     |   11 +
 drivers/bus/hisi_lpc.c                             |   10 +-
 drivers/char/tpm/tpm2-cmd.c                        |    6 +
 drivers/clk/imx/clk-fracn-gppll.c                  |   33 +-
 drivers/clk/imx/clk-imx93.c                        |    4 +-
 drivers/clk/mediatek/reset.c                       |    4 +-
 drivers/clk/qcom/camcc-sdm845.c                    |    4 +
 drivers/clk/qcom/camcc-sm8250.c                    |   16 +-
 drivers/clk/qcom/clk-krait.c                       |    7 +-
 drivers/clk/qcom/clk-rcg2.c                        |   16 +-
 drivers/clk/qcom/dispcc-sm8250.c                   |    1 -
 drivers/clk/qcom/gcc-ipq8074.c                     |   60 +-
 drivers/clk/qcom/gcc-msm8939.c                     |   33 +-
 drivers/clk/qcom/gdsc.c                            |    8 +
 drivers/clk/qcom/videocc-sm8250.c                  |    4 -
 drivers/clk/renesas/r9a06g032-clocks.c             |    8 +-
 drivers/clk/renesas/rzg2l-cpg.c                    |    2 +-
 .../crypto/allwinner/sun8i-ss/sun8i-ss-cipher.c    |    1 +
 drivers/crypto/allwinner/sun8i-ss/sun8i-ss-core.c  |   22 +-
 drivers/crypto/allwinner/sun8i-ss/sun8i-ss-hash.c  |   15 +-
 drivers/crypto/allwinner/sun8i-ss/sun8i-ss.h       |    4 +
 drivers/crypto/ccp/sev-dev.c                       |   12 +-
 drivers/crypto/hisilicon/hpre/hpre_crypto.c        |    2 +-
 drivers/crypto/hisilicon/sec/sec_algs.c            |   14 +-
 drivers/crypto/hisilicon/sec/sec_drv.h             |    2 +-
 drivers/crypto/hisilicon/sec2/sec.h                |    2 +-
 drivers/crypto/hisilicon/sec2/sec_crypto.c         |   26 +-
 drivers/crypto/hisilicon/sec2/sec_crypto.h         |    1 +
 drivers/crypto/inside-secure/safexcel.c            |    2 +
 drivers/dma/dw-edma/dw-edma-core.c                 |    2 +-
 drivers/dma/imx-dma.c                              |    2 +-
 drivers/dma/sf-pdma/sf-pdma.c                      |   44 +-
 drivers/firmware/arm_scpi.c                        |   61 +-
 drivers/firmware/tegra/bpmp-debugfs.c              |   10 +-
 drivers/fpga/altera-pr-ip-core.c                   |    2 +-
 drivers/gpio/gpiolib-of.c                          |    4 +-
 drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c   |    6 -
 drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c             |    2 +-
 drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c            |   96 +-
 drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.h            |   11 +-
 drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c      |   10 +-
 drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c            |    2 +-
 drivers/gpu/drm/amd/amdgpu/amdgpu_object.c         |    4 +
 drivers/gpu/drm/amd/amdgpu/nbio_v2_3.c             |   21 -
 drivers/gpu/drm/amd/amdgpu/nbio_v2_3.h             |    1 -
 drivers/gpu/drm/amd/amdgpu/nbio_v7_4.c             |   21 -
 drivers/gpu/drm/amd/amdgpu/nbio_v7_4.h             |    1 -
 .../drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c  |    2 +-
 drivers/gpu/drm/bridge/Kconfig                     |    2 +
 drivers/gpu/drm/bridge/adv7511/adv7511_drv.c       |   24 +-
 drivers/gpu/drm/bridge/analogix/anx7625.c          |   17 +-
 drivers/gpu/drm/bridge/lontium-lt9611.c            |    2 +-
 drivers/gpu/drm/bridge/lontium-lt9611uxc.c         |    2 +-
 drivers/gpu/drm/bridge/sil-sii8620.c               |    4 +-
 drivers/gpu/drm/bridge/tc358767.c                  |   62 +-
 drivers/gpu/drm/dp/drm_dp_aux_bus.c                |    4 +-
 drivers/gpu/drm/dp/drm_dp_mst_topology.c           |    7 +-
 drivers/gpu/drm/drm_gem.c                          |    4 +-
 drivers/gpu/drm/drm_gem_shmem_helper.c             |    1 +
 drivers/gpu/drm/drm_mipi_dbi.c                     |    7 +
 drivers/gpu/drm/exynos/exynos7_drm_decon.c         |   17 +-
 drivers/gpu/drm/hyperv/hyperv_drm_modeset.c        |    2 +
 drivers/gpu/drm/ingenic/ingenic-drm-drv.c          |   10 +-
 drivers/gpu/drm/ingenic/ingenic-drm.h              |    3 +
 drivers/gpu/drm/mcde/mcde_dsi.c                    |    1 +
 drivers/gpu/drm/mediatek/mtk_dpi.c                 |   33 +-
 drivers/gpu/drm/mediatek/mtk_dsi.c                 |   93 +-
 drivers/gpu/drm/meson/meson_encoder_cvbs.c         |    1 +
 drivers/gpu/drm/meson/meson_encoder_hdmi.c         |   19 +-
 drivers/gpu/drm/msm/adreno/a5xx_gpu.c              |    8 -
 drivers/gpu/drm/msm/adreno/a6xx_gmu.c              |   13 +-
 drivers/gpu/drm/msm/adreno/a6xx_gpu.c              |   12 +-
 drivers/gpu/drm/msm/adreno/a6xx_gpu.h              |    3 +-
 drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c           |    6 +
 drivers/gpu/drm/msm/disp/mdp5/mdp5_pipe.c          |    3 +-
 drivers/gpu/drm/msm/hdmi/hdmi.c                    |    3 +
 drivers/gpu/drm/msm/msm_gpu.h                      |   11 +-
 drivers/gpu/drm/msm/msm_gpu_devfreq.c              |   39 +-
 drivers/gpu/drm/nouveau/nouveau_connector.c        |    8 +-
 drivers/gpu/drm/nouveau/nouveau_display.c          |    4 +-
 drivers/gpu/drm/nouveau/nouveau_fbcon.c            |    2 +-
 drivers/gpu/drm/nouveau/nvkm/subdev/bios/base.c    |    2 +-
 drivers/gpu/drm/panel/Kconfig                      |    2 +
 drivers/gpu/drm/radeon/.gitignore                  |    2 +-
 drivers/gpu/drm/radeon/Kconfig                     |    2 +-
 drivers/gpu/drm/radeon/Makefile                    |    2 +-
 drivers/gpu/drm/radeon/ni_dpm.c                    |    6 +-
 drivers/gpu/drm/radeon/radeon_device.c             |    2 +-
 drivers/gpu/drm/rockchip/analogix_dp-rockchip.c    |   10 +-
 drivers/gpu/drm/rockchip/rockchip_drm_vop.c        |    3 +
 drivers/gpu/drm/tegra/gem.c                        |   11 +-
 drivers/gpu/drm/tiny/st7735r.c                     |    1 +
 drivers/gpu/drm/vc4/vc4_crtc.c                     |   14 +-
 drivers/gpu/drm/vc4/vc4_drv.c                      |   19 +
 drivers/gpu/drm/vc4/vc4_dsi.c                      |  152 +-
 drivers/gpu/drm/vc4/vc4_hdmi.c                     |  157 +-
 drivers/gpu/drm/vc4/vc4_hdmi.h                     |    8 +
 drivers/gpu/drm/vc4/vc4_hdmi_regs.h                |    7 +-
 drivers/gpu/drm/vc4/vc4_kms.c                      |    4 +-
 drivers/gpu/drm/vc4/vc4_plane.c                    |   30 +-
 drivers/gpu/drm/virtio/virtgpu_ioctl.c             |    6 +-
 drivers/gpu/drm/virtio/virtgpu_object.c            |    4 +-
 drivers/gpu/drm/vkms/vkms_composer.c               |    2 +-
 drivers/hid/amd-sfh-hid/amd_sfh_client.c           |    2 +
 drivers/hid/amd-sfh-hid/amd_sfh_hid.c              |   12 +-
 drivers/hid/amd-sfh-hid/amd_sfh_pcie.c             |    3 +-
 drivers/hid/hid-alps.c                             |    2 +
 drivers/hid/hid-cp2112.c                           |    5 +
 drivers/hid/hid-ids.h                              |    1 +
 drivers/hid/hid-input.c                            |    2 +
 drivers/hid/hid-mcp2221.c                          |    3 +
 drivers/hid/hid-nintendo.c                         |    1 +
 drivers/hid/wacom_sys.c                            |    2 +-
 drivers/hid/wacom_wac.c                            |   72 +-
 drivers/hwmon/dell-smm-hwmon.c                     |    8 +
 drivers/hwmon/drivetemp.c                          |    1 +
 drivers/hwmon/sch56xx-common.c                     |   44 +-
 drivers/hwmon/sht15.c                              |   17 +-
 drivers/hwtracing/coresight/coresight-config.h     |    2 +
 drivers/hwtracing/coresight/coresight-core.c       |    1 +
 drivers/hwtracing/coresight/coresight-syscfg.c     |  295 +++-
 drivers/hwtracing/coresight/coresight-syscfg.h     |   13 +
 drivers/hwtracing/intel_th/msu-sink.c              |    3 +
 drivers/hwtracing/intel_th/msu.c                   |   14 +-
 drivers/hwtracing/intel_th/pci.c                   |   25 +-
 drivers/i2c/busses/i2c-cadence.c                   |   10 +-
 drivers/i2c/busses/i2c-mxs.c                       |    2 +-
 drivers/i2c/busses/i2c-npcm7xx.c                   |   50 +-
 drivers/i2c/busses/i2c-qcom-geni.c                 |    2 +-
 drivers/i2c/i2c-core-base.c                        |    3 +-
 drivers/i2c/muxes/i2c-mux-gpmux.c                  |    1 +
 drivers/idle/intel_idle.c                          |  149 +-
 drivers/iio/accel/adxl313_core.c                   |    2 +-
 drivers/iio/accel/adxl355_core.c                   |    2 +-
 drivers/iio/accel/adxl367.c                        |    2 +-
 drivers/iio/accel/adxl367_spi.c                    |    8 +-
 drivers/iio/accel/bma220_spi.c                     |    2 +-
 drivers/iio/accel/bma400.h                         |   25 +-
 drivers/iio/accel/bma400_core.c                    |   81 +-
 drivers/iio/accel/bma400_i2c.c                     |    8 -
 drivers/iio/accel/bma400_spi.c                     |    6 -
 drivers/iio/accel/cros_ec_accel_legacy.c           |    4 +-
 drivers/iio/accel/sca3000.c                        |    4 +-
 drivers/iio/accel/sca3300.c                        |    2 +-
 drivers/iio/adc/ad7266.c                           |    4 +-
 drivers/iio/adc/ad7280a.c                          |    2 +-
 drivers/iio/adc/ad7292.c                           |    2 +-
 drivers/iio/adc/ad7298.c                           |    2 +-
 drivers/iio/adc/ad7476.c                           |    5 +-
 drivers/iio/adc/ad7606.h                           |    4 +-
 drivers/iio/adc/ad7766.c                           |    5 +-
 drivers/iio/adc/ad7768-1.c                         |    4 +-
 drivers/iio/adc/ad7887.c                           |    5 +-
 drivers/iio/adc/ad7923.c                           |    4 +-
 drivers/iio/adc/ad7949.c                           |    2 +-
 drivers/iio/adc/adi-axi-adc.c                      |    7 +-
 drivers/iio/adc/hi8435.c                           |    2 +-
 drivers/iio/adc/ltc2496.c                          |    4 +-
 drivers/iio/adc/ltc2497.c                          |    4 +-
 drivers/iio/adc/max1027.c                          |    8 +-
 drivers/iio/adc/max11100.c                         |    4 +-
 drivers/iio/adc/max1118.c                          |    2 +-
 drivers/iio/adc/max1241.c                          |    2 +-
 drivers/iio/adc/mcp320x.c                          |    2 +-
 drivers/iio/adc/ti-adc0832.c                       |    2 +-
 drivers/iio/adc/ti-adc084s021.c                    |    4 +-
 drivers/iio/adc/ti-adc108s102.c                    |    4 +-
 drivers/iio/adc/ti-adc12138.c                      |    2 +-
 drivers/iio/adc/ti-adc128s052.c                    |    2 +-
 drivers/iio/adc/ti-adc161s626.c                    |    2 +-
 drivers/iio/adc/ti-ads124s08.c                     |    2 +-
 drivers/iio/adc/ti-ads131e08.c                     |    2 +-
 drivers/iio/adc/ti-ads7950.c                       |    4 +-
 drivers/iio/adc/ti-ads8344.c                       |    2 +-
 drivers/iio/adc/ti-ads8688.c                       |    2 +-
 drivers/iio/adc/ti-tlc4541.c                       |    4 +-
 drivers/iio/addac/ad74413r.c                       |    4 +-
 drivers/iio/amplifiers/ad8366.c                    |    4 +-
 .../iio/common/cros_ec_sensors/cros_ec_lid_angle.c |    4 +-
 .../iio/common/cros_ec_sensors/cros_ec_sensors.c   |    6 +-
 .../common/cros_ec_sensors/cros_ec_sensors_core.c  |   58 +-
 drivers/iio/common/ssp_sensors/ssp.h               |    3 +-
 drivers/iio/dac/ad5064.c                           |    4 +-
 drivers/iio/dac/ad5360.c                           |    4 +-
 drivers/iio/dac/ad5421.c                           |    4 +-
 drivers/iio/dac/ad5449.c                           |    4 +-
 drivers/iio/dac/ad5504.c                           |    2 +-
 drivers/iio/dac/ad5592r-base.h                     |    4 +-
 drivers/iio/dac/ad5686.h                           |    6 +-
 drivers/iio/dac/ad5755.c                           |    4 +-
 drivers/iio/dac/ad5761.c                           |    4 +-
 drivers/iio/dac/ad5764.c                           |    4 +-
 drivers/iio/dac/ad5766.c                           |    2 +-
 drivers/iio/dac/ad5770r.c                          |    2 +-
 drivers/iio/dac/ad5791.c                           |    2 +-
 drivers/iio/dac/ad7293.c                           |    2 +-
 drivers/iio/dac/ad7303.c                           |    4 +-
 drivers/iio/dac/ad8801.c                           |    2 +-
 drivers/iio/dac/ltc2688.c                          |    4 +-
 drivers/iio/dac/mcp4922.c                          |    2 +-
 drivers/iio/dac/ti-dac082s085.c                    |    2 +-
 drivers/iio/dac/ti-dac5571.c                       |    2 +-
 drivers/iio/dac/ti-dac7311.c                       |    2 +-
 drivers/iio/dac/ti-dac7612.c                       |    4 +-
 drivers/iio/frequency/ad9523.c                     |    6 +-
 drivers/iio/frequency/adf4350.c                    |    6 +-
 drivers/iio/frequency/adf4371.c                    |    2 +-
 drivers/iio/frequency/admv1013.c                   |    2 +-
 drivers/iio/frequency/admv1014.c                   |    2 +-
 drivers/iio/frequency/admv4420.c                   |    2 +-
 drivers/iio/frequency/adrf6780.c                   |    2 +-
 drivers/iio/gyro/adis16080.c                       |    2 +-
 drivers/iio/gyro/adis16130.c                       |    2 +-
 drivers/iio/gyro/adxrs450.c                        |    2 +-
 drivers/iio/gyro/fxas21002c_core.c                 |    6 +-
 drivers/iio/imu/fxos8700_core.c                    |    2 +-
 drivers/iio/imu/inv_icm42600/inv_icm42600.h        |    2 +-
 drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.h |    2 +-
 drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h          |    2 +-
 drivers/iio/industrialio-buffer.c                  |    4 +-
 drivers/iio/industrialio-core.c                    |   25 +-
 drivers/iio/light/cros_ec_light_prox.c             |    6 +-
 drivers/iio/light/isl29028.c                       |    2 +-
 drivers/iio/potentiometer/ad5110.c                 |    4 +-
 drivers/iio/potentiometer/ad5272.c                 |    2 +-
 drivers/iio/potentiometer/max5481.c                |    2 +-
 drivers/iio/potentiometer/mcp41010.c               |    2 +-
 drivers/iio/potentiometer/mcp4131.c                |    2 +-
 drivers/iio/pressure/cros_ec_baro.c                |    6 +-
 drivers/iio/proximity/as3935.c                     |    2 +-
 drivers/iio/proximity/sx9324.c                     |    4 +-
 drivers/iio/resolver/ad2s1200.c                    |    2 +-
 drivers/iio/resolver/ad2s90.c                      |    2 +-
 drivers/iio/temperature/ltc2983.c                  |    4 +-
 drivers/iio/temperature/max31865.c                 |    2 +-
 drivers/iio/temperature/maxim_thermocouple.c       |    2 +-
 drivers/infiniband/hw/hfi1/file_ops.c              |    4 +-
 drivers/infiniband/hw/hns/hns_roce_hw_v2.c         |    4 +-
 drivers/infiniband/hw/irdma/cm.c                   |   11 +-
 drivers/infiniband/hw/irdma/hw.c                   |   15 +-
 drivers/infiniband/hw/irdma/verbs.c                |    2 +-
 drivers/infiniband/hw/mlx5/fs.c                    |    6 +-
 drivers/infiniband/hw/qedr/verbs.c                 |    8 +-
 drivers/infiniband/sw/rxe/rxe_comp.c               |    8 +-
 drivers/infiniband/sw/rxe/rxe_loc.h                |    2 +-
 drivers/infiniband/sw/rxe/rxe_mr.c                 |   12 +-
 drivers/infiniband/sw/rxe/rxe_mw.c                 |    7 -
 drivers/infiniband/sw/rxe/rxe_pool.c               |    4 +-
 drivers/infiniband/sw/rxe/rxe_qp.c                 |   13 +-
 drivers/infiniband/sw/rxe/rxe_req.c                |   23 +-
 drivers/infiniband/sw/rxe/rxe_verbs.h              |    1 +
 drivers/infiniband/sw/siw/siw_cm.c                 |    7 +-
 drivers/infiniband/ulp/iser/iscsi_iser.c           |    4 +-
 drivers/infiniband/ulp/rtrs/rtrs-clt.c             |   35 +-
 drivers/infiniband/ulp/rtrs/rtrs-pri.h             |   21 +-
 drivers/infiniband/ulp/srpt/ib_srpt.c              |  148 +-
 drivers/infiniband/ulp/srpt/ib_srpt.h              |   18 +-
 drivers/input/serio/gscps2.c                       |    4 +
 drivers/interconnect/imx/imx.c                     |    8 +-
 drivers/iommu/arm/arm-smmu/qcom_iommu.c            |    7 +-
 drivers/iommu/exynos-iommu.c                       |    6 +-
 drivers/iommu/intel/dmar.c                         |    2 +-
 drivers/irqchip/Kconfig                            |    5 +-
 drivers/irqchip/irq-mips-gic.c                     |   84 +-
 drivers/md/dm-raid.c                               |    4 +-
 drivers/md/dm-thin-metadata.c                      |    7 +-
 drivers/md/dm-thin.c                               |    4 +-
 drivers/md/dm-writecache.c                         |   43 +-
 drivers/md/dm.c                                    |    5 +
 drivers/md/md.c                                    |    2 +-
 drivers/md/raid10.c                                |    5 +-
 drivers/media/i2c/Kconfig                          |    1 +
 drivers/media/pci/sta2x11/Kconfig                  |    2 +-
 drivers/media/pci/tw686x/tw686x-core.c             |   18 +-
 drivers/media/pci/tw686x/tw686x-video.c            |    4 +-
 drivers/media/platform/amphion/vdec.c              |  123 +-
 drivers/media/platform/amphion/vpu.h               |    1 +
 drivers/media/platform/amphion/vpu_core.c          |    7 +-
 drivers/media/platform/amphion/vpu_malone.c        |    6 +-
 drivers/media/platform/amphion/vpu_msgs.c          |    7 +-
 drivers/media/platform/amphion/vpu_rpc.h           |    7 +-
 drivers/media/platform/amphion/vpu_v4l2.c          |   62 +-
 drivers/media/platform/amphion/vpu_v4l2.h          |    3 +
 drivers/media/platform/atmel/atmel-sama7g5-isc.c   |    2 +
 drivers/media/platform/mediatek/mdp/mtk_mdp_ipi.h  |    2 +
 .../platform/mediatek/vcodec/mtk_vcodec_dec.c      |    7 +-
 .../platform/mediatek/vcodec/mtk_vcodec_dec_drv.c  |    5 +
 drivers/media/platform/nxp/imx-jpeg/mxc-jpeg-hw.c  |    5 +
 drivers/media/platform/nxp/imx-jpeg/mxc-jpeg-hw.h  |    9 +-
 drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c     |  477 +++---
 drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.h     |    6 +-
 drivers/media/platform/qcom/camss/camss-csid.c     |    2 +-
 .../media/platform/renesas/rcar-vin/rcar-core.c    |    2 +-
 drivers/media/usb/hdpvr/hdpvr-video.c              |    2 +-
 drivers/media/v4l2-core/v4l2-mem2mem.c             |    2 +-
 drivers/memstick/core/ms_block.c                   |   11 +-
 drivers/mfd/max77620.c                             |    2 +
 drivers/mfd/t7l66xb.c                              |    6 +-
 drivers/misc/cardreader/rtsx_pcr.c                 |    6 +-
 drivers/misc/eeprom/idt_89hpesx.c                  |    8 +-
 drivers/mmc/core/block.c                           |   28 +-
 drivers/mmc/core/quirks.h                          |    4 +-
 drivers/mmc/host/cavium-octeon.c                   |    1 +
 drivers/mmc/host/cavium-thunderx.c                 |    4 +-
 drivers/mmc/host/mxcmmc.c                          |    2 +-
 drivers/mmc/host/renesas_sdhi_core.c               |    8 +-
 drivers/mmc/host/sdhci-of-at91.c                   |    9 +-
 drivers/mmc/host/sdhci-of-esdhc.c                  |    1 +
 drivers/mtd/devices/mtd_dataflash.c                |    8 +
 drivers/mtd/devices/st_spi_fsm.c                   |    8 +-
 drivers/mtd/hyperbus/rpc-if.c                      |    8 +-
 drivers/mtd/maps/physmap-versatile.c               |    2 +
 drivers/mtd/nand/raw/arasan-nand-controller.c      |   16 +-
 drivers/mtd/nand/raw/meson_nand.c                  |    1 -
 drivers/mtd/parsers/ofpart_bcm4908.c               |    3 +
 drivers/mtd/parsers/redboot.c                      |    1 +
 drivers/mtd/sm_ftl.c                               |    2 +-
 drivers/mtd/spi-nor/core.c                         |    6 +-
 drivers/net/can/dev/netlink.c                      |    6 +-
 drivers/net/can/pch_can.c                          |    8 +-
 drivers/net/can/rcar/rcar_can.c                    |    8 +-
 drivers/net/can/sja1000/sja1000.c                  |    7 +-
 drivers/net/can/spi/hi311x.c                       |    5 +-
 drivers/net/can/sun4i_can.c                        |    9 +-
 drivers/net/can/usb/kvaser_usb/kvaser_usb_hydra.c  |   12 +-
 drivers/net/can/usb/kvaser_usb/kvaser_usb_leaf.c   |    6 +-
 drivers/net/can/usb/usb_8dev.c                     |    7 +-
 drivers/net/dsa/ocelot/Kconfig                     |    1 +
 drivers/net/dsa/ocelot/felix.c                     |    9 +
 drivers/net/dsa/ocelot/felix.h                     |    1 +
 drivers/net/dsa/ocelot/felix_vsc9959.c             |  300 +++-
 drivers/net/ethernet/atheros/ag71xx.c              |    2 +-
 drivers/net/ethernet/huawei/hinic/hinic_dev.h      |    3 -
 drivers/net/ethernet/huawei/hinic/hinic_main.c     |   68 +-
 drivers/net/ethernet/huawei/hinic/hinic_rx.c       |    2 -
 drivers/net/ethernet/huawei/hinic/hinic_tx.c       |    2 -
 drivers/net/ethernet/intel/iavf/iavf.h             |    6 +
 drivers/net/ethernet/intel/iavf/iavf_main.c        |   46 +-
 drivers/net/ethernet/intel/ice/ice_main.c          |    2 +-
 drivers/net/ethernet/intel/ice/ice_switch.c        |    2 +-
 drivers/net/ethernet/mellanox/mlx5/core/en.h       |   21 +-
 .../net/ethernet/mellanox/mlx5/core/en/params.c    |   12 +
 .../ethernet/mellanox/mlx5/core/en/tc/post_act.c   |    1 +
 .../net/ethernet/mellanox/mlx5/core/en/xsk/rx.h    |   14 +
 .../ethernet/mellanox/mlx5/core/en_accel/ktls.c    |    2 +-
 .../ethernet/mellanox/mlx5/core/eswitch_offloads.c |   23 +-
 drivers/net/ethernet/mellanox/mlx5/core/lib/tout.c |   11 +-
 drivers/net/ethernet/mellanox/mlx5/core/lib/tout.h |    1 -
 drivers/net/ethernet/mellanox/mlx5/core/main.c     |    4 +-
 drivers/net/ethernet/mellanox/mlx5/core/sriov.c    |   65 +-
 .../ethernet/mellanox/mlx5/core/steering/dr_dbg.c  |   13 +-
 drivers/net/ethernet/mscc/ocelot.c                 |    1 +
 drivers/net/ethernet/mscc/ocelot_ptp.c             |    8 +
 drivers/net/ethernet/pensando/ionic/ionic_lif.c    |    2 +-
 drivers/net/netdevsim/bpf.c                        |    8 +-
 drivers/net/netdevsim/fib.c                        |   27 +-
 drivers/net/phy/smsc.c                             |    6 +-
 drivers/net/usb/Kconfig                            |    3 +-
 drivers/net/usb/ax88179_178a.c                     |   26 +-
 drivers/net/usb/smsc95xx.c                         |  157 +-
 drivers/net/usb/usbnet.c                           |    8 +-
 drivers/net/wireguard/allowedips.c                 |    9 +-
 drivers/net/wireguard/selftest/allowedips.c        |    6 +-
 drivers/net/wireguard/selftest/ratelimiter.c       |   25 +-
 drivers/net/wireless/ath/ath10k/snoc.c             |    5 +-
 drivers/net/wireless/ath/ath11k/core.c             |   16 +-
 drivers/net/wireless/ath/ath11k/debug.h            |    4 +-
 drivers/net/wireless/ath/ath11k/dp_rx.c            |    5 +-
 drivers/net/wireless/ath/ath11k/htc.c              |    4 +-
 drivers/net/wireless/ath/ath11k/pci.c              |    2 +
 drivers/net/wireless/ath/ath9k/htc.h               |   10 +-
 drivers/net/wireless/ath/ath9k/htc_drv_init.c      |    3 +-
 drivers/net/wireless/ath/wil6210/debugfs.c         |   18 +-
 drivers/net/wireless/intel/iwlegacy/4965-rs.c      |    5 +-
 drivers/net/wireless/intel/iwlwifi/mvm/sta.c       |    1 +
 drivers/net/wireless/intersil/p54/main.c           |    2 +-
 drivers/net/wireless/intersil/p54/p54spi.c         |    3 +-
 drivers/net/wireless/mac80211_hwsim.c              |   14 +-
 drivers/net/wireless/marvell/libertas/if_usb.c     |    1 +
 drivers/net/wireless/mediatek/mt76/eeprom.c        |    5 +-
 drivers/net/wireless/mediatek/mt76/mac80211.c      |    1 +
 drivers/net/wireless/mediatek/mt76/mt7615/mac.c    |    7 +-
 drivers/net/wireless/mediatek/mt76/mt7615/main.c   |   21 -
 drivers/net/wireless/mediatek/mt76/mt7615/mcu.c    |   12 +-
 drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h |    1 -
 .../net/wireless/mediatek/mt76/mt76x02_usb_mcu.c   |    2 +-
 drivers/net/wireless/mediatek/mt76/mt7921/init.c   |    6 +-
 drivers/net/wireless/mediatek/mt76/mt7921/mcu.c    |   15 +-
 .../net/wireless/mediatek/mt76/mt7921/pci_mcu.c    |    6 +-
 .../net/wireless/mediatek/mt76/mt7921/sdio_mcu.c   |   10 +-
 drivers/net/wireless/microchip/wilc1000/spi.c      |    6 +-
 drivers/net/wireless/realtek/rtlwifi/debug.c       |    8 +-
 drivers/net/wireless/realtek/rtw88/main.c          |    4 +
 drivers/net/wireless/realtek/rtw89/rtw8852a_rfk.c  |    4 +-
 drivers/nvme/host/core.c                           |   14 +-
 drivers/nvme/host/fc.c                             |   18 +
 drivers/nvme/host/multipath.c                      |    1 +
 drivers/nvme/host/trace.h                          |    2 +-
 drivers/nvme/target/zns.c                          |    3 +-
 drivers/of/device.c                                |    5 +-
 drivers/of/fdt.c                                   |    2 +-
 drivers/of/kexec.c                                 |   17 +
 drivers/opp/core.c                                 |    4 +-
 drivers/parisc/lba_pci.c                           |    6 +-
 drivers/pci/controller/dwc/pcie-designware-ep.c    |   18 +-
 drivers/pci/controller/dwc/pcie-designware-host.c  |   30 +-
 drivers/pci/controller/dwc/pcie-designware.c       |   46 +-
 drivers/pci/controller/dwc/pcie-qcom.c             |   58 +-
 drivers/pci/controller/dwc/pcie-tegra194.c         |   49 +-
 drivers/pci/controller/pcie-mediatek-gen3.c        |    7 +-
 drivers/pci/controller/pcie-microchip-host.c       |    2 +
 drivers/pci/endpoint/functions/pci-epf-test.c      |    1 -
 drivers/pci/pcie/aer.c                             |    7 +-
 drivers/pci/pcie/portdrv_core.c                    |    9 +-
 drivers/perf/arm_spe_pmu.c                         |   22 +-
 drivers/perf/riscv_pmu.c                           |    1 -
 drivers/perf/riscv_pmu_sbi.c                       |   21 +-
 drivers/phy/qualcomm/phy-qcom-qmp.h                |    3 +-
 drivers/phy/rockchip/phy-rockchip-inno-usb2.c      |    4 +-
 drivers/phy/samsung/phy-exynosautov9-ufs.c         |   18 +-
 drivers/phy/st/phy-stm32-usbphyc.c                 |    4 +-
 drivers/phy/ti/phy-tusb1210.c                      |    5 +-
 drivers/pinctrl/Kconfig                            |    2 +-
 drivers/platform/chrome/cros_ec.c                  |    8 +-
 drivers/platform/mellanox/mlxreg-lc.c              |   82 +-
 drivers/platform/olpc/olpc-ec.c                    |    2 +-
 drivers/platform/x86/pmc_atom.c                    |   19 +-
 drivers/pwm/pwm-lpc18xx-sct.c                      |   55 +-
 drivers/pwm/pwm-sifive.c                           |   61 +-
 drivers/regulator/of_regulator.c                   |    6 +-
 drivers/regulator/qcom_smd-regulator.c             |    4 +-
 drivers/remoteproc/imx_rproc.c                     |    7 +-
 drivers/remoteproc/qcom_q6v5_pas.c                 |    3 +
 drivers/remoteproc/qcom_sysmon.c                   |   10 +
 drivers/remoteproc/qcom_wcnss.c                    |   10 +-
 drivers/remoteproc/ti_k3_r5_remoteproc.c           |    2 +
 drivers/rpmsg/mtk_rpmsg.c                          |    2 +
 drivers/rpmsg/qcom_smd.c                           |    1 +
 drivers/rpmsg/rpmsg_char.c                         |    7 +-
 drivers/rtc/rtc-rx8025.c                           |   22 +-
 drivers/s390/char/zcore.c                          |   11 +-
 drivers/s390/cio/vfio_ccw_drv.c                    |   19 +-
 drivers/s390/cio/vfio_ccw_ops.c                    |    2 +-
 drivers/s390/scsi/zfcp_fc.c                        |   29 +-
 drivers/s390/scsi/zfcp_fc.h                        |    6 +-
 drivers/s390/scsi/zfcp_fsf.c                       |    4 +-
 drivers/scsi/be2iscsi/be_main.c                    |    2 +-
 drivers/scsi/bnx2i/bnx2i_iscsi.c                   |    2 +-
 drivers/scsi/cxgbi/libcxgbi.c                      |    2 +-
 drivers/scsi/iscsi_tcp.c                           |    4 +-
 drivers/scsi/libiscsi.c                            |    9 +-
 drivers/scsi/lpfc/lpfc_scsi.c                      |    1 -
 drivers/scsi/qedi/qedi_main.c                      |    9 +-
 drivers/scsi/qla2xxx/qla_attr.c                    |   24 +-
 drivers/scsi/qla2xxx/qla_bsg.c                     |   10 +-
 drivers/scsi/qla2xxx/qla_dbg.h                     |    2 +-
 drivers/scsi/qla2xxx/qla_def.h                     |   18 +-
 drivers/scsi/qla2xxx/qla_edif.c                    |  502 +++++--
 drivers/scsi/qla2xxx/qla_edif.h                    |    7 +-
 drivers/scsi/qla2xxx/qla_edif_bsg.h                |  106 +-
 drivers/scsi/qla2xxx/qla_fw.h                      |    2 +-
 drivers/scsi/qla2xxx/qla_gbl.h                     |    6 +-
 drivers/scsi/qla2xxx/qla_gs.c                      |  129 +-
 drivers/scsi/qla2xxx/qla_init.c                    |   93 +-
 drivers/scsi/qla2xxx/qla_iocb.c                    |    5 +-
 drivers/scsi/qla2xxx/qla_isr.c                     |   25 +-
 drivers/scsi/qla2xxx/qla_mbx.c                     |   19 +-
 drivers/scsi/qla2xxx/qla_mid.c                     |    6 +-
 drivers/scsi/qla2xxx/qla_nvme.c                    |    5 -
 drivers/scsi/qla2xxx/qla_os.c                      |   93 +-
 drivers/scsi/qla2xxx/qla_target.c                  |   35 +-
 drivers/scsi/scsi_transport_iscsi.c                |   66 +-
 drivers/scsi/sg.c                                  |   53 +-
 drivers/scsi/smartpqi/smartpqi_init.c              |    4 +-
 drivers/scsi/ufs/ufshcd.c                          |    6 +-
 drivers/soc/amlogic/meson-mx-socinfo.c             |    1 +
 drivers/soc/amlogic/meson-secure-pwrc.c            |    4 +-
 drivers/soc/fsl/guts.c                             |    2 +-
 drivers/soc/qcom/Kconfig                           |    1 +
 drivers/soc/qcom/ocmem.c                           |    3 +
 drivers/soc/qcom/qcom_aoss.c                       |    4 +-
 drivers/soc/qcom/socinfo.c                         |    3 +-
 drivers/soc/renesas/r8a779a0-sysc.c                |   10 +-
 drivers/soundwire/bus.c                            |   75 +-
 drivers/soundwire/bus_type.c                       |   38 +-
 drivers/soundwire/qcom.c                           |    4 +
 drivers/soundwire/slave.c                          |    3 +-
 drivers/soundwire/stream.c                         |   53 +-
 drivers/spi/spi-altera-dfl.c                       |   14 +-
 drivers/spi/spi-dw.h                               |    2 +-
 drivers/spi/spi-rspi.c                             |    4 +
 drivers/spi/spi-s3c64xx.c                          |    2 +-
 drivers/spi/spi-synquacer.c                        |    1 +
 drivers/spi/spi-tegra20-slink.c                    |    3 +-
 drivers/spi/spi.c                                  |   21 +-
 drivers/staging/fbtft/fbtft-core.c                 |    2 +-
 drivers/staging/media/atomisp/pci/atomisp_cmd.c    |   57 +-
 drivers/staging/media/hantro/hantro_drv.c          |    1 +
 drivers/staging/media/hantro/hantro_g2_hevc_dec.c  |   32 +-
 drivers/staging/media/hantro/hantro_g2_regs.h      |    2 +-
 drivers/staging/media/hantro/hantro_hevc.c         |   71 +-
 drivers/staging/media/hantro/hantro_hw.h           |   22 +-
 drivers/staging/media/hantro/hantro_v4l2.c         |    2 +-
 drivers/staging/media/hantro/imx8m_vpu_hw.c        |   80 +-
 drivers/staging/media/hantro/rockchip_vpu_hw.c     |  174 ++-
 drivers/staging/media/hantro/sama5d4_vdec_hw.c     |   40 +-
 drivers/staging/media/hantro/sunxi_vpu_hw.c        |   24 +-
 drivers/staging/media/sunxi/cedrus/cedrus_h265.c   |   36 +-
 drivers/staging/media/sunxi/cedrus/cedrus_regs.h   |    3 +-
 drivers/staging/rtl8192u/r8192U.h                  |    2 +-
 drivers/staging/rtl8192u/r8192U_dm.c               |   38 +-
 drivers/staging/rtl8192u/r8192U_dm.h               |    2 +-
 drivers/thermal/thermal_sysfs.c                    |   10 +-
 drivers/tty/n_gsm.c                                |  757 +++++++---
 drivers/tty/serial/8250/8250.h                     |   22 +
 drivers/tty/serial/8250/8250_bcm2835aux.c          |    6 +-
 drivers/tty/serial/8250/8250_bcm7271.c             |   24 +-
 drivers/tty/serial/8250/8250_fsl.c                 |    2 +-
 drivers/tty/serial/8250/8250_pci.c                 |  522 +++++--
 drivers/tty/serial/8250/8250_port.c                |   21 -
 drivers/tty/serial/fsl_lpuart.c                    |   12 +-
 drivers/tty/serial/mvebu-uart.c                    |   11 +
 drivers/tty/serial/pic32_uart.c                    |   13 +-
 drivers/tty/vt/vt.c                                |    2 +-
 drivers/usb/cdns3/cdns3-gadget.c                   |   11 +-
 drivers/usb/core/hcd.c                             |   26 +-
 drivers/usb/dwc3/core.c                            |    9 +-
 drivers/usb/dwc3/dwc3-qcom.c                       |    4 +-
 drivers/usb/dwc3/gadget.c                          |   92 +-
 drivers/usb/gadget/function/f_mass_storage.c       |   11 +-
 drivers/usb/gadget/udc/Kconfig                     |    2 +-
 drivers/usb/gadget/udc/aspeed-vhub/hub.c           |    4 +-
 drivers/usb/gadget/udc/core.c                      |   11 +-
 drivers/usb/gadget/udc/tegra-xudc.c                |    8 +-
 drivers/usb/host/ehci-ppc-of.c                     |    1 +
 drivers/usb/host/ohci-nxp.c                        |    1 +
 drivers/usb/host/xhci-tegra.c                      |    8 +-
 drivers/usb/host/xhci.h                            |    2 +-
 drivers/usb/serial/sierra.c                        |    3 +-
 drivers/usb/serial/usb-serial.c                    |    2 +-
 drivers/usb/serial/usb_wwan.c                      |    3 +-
 drivers/usb/typec/ucsi/ucsi.c                      |    4 +
 drivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.c     |   15 +-
 drivers/vfio/pci/mlx5/main.c                       |   15 +-
 drivers/vfio/pci/vfio_pci.c                        |    2 +-
 drivers/vfio/pci/vfio_pci_core.c                   |    4 +
 drivers/video/fbdev/amba-clcd.c                    |   24 +-
 drivers/video/fbdev/arkfb.c                        |    9 +-
 drivers/video/fbdev/core/fbcon.c                   |   12 +-
 drivers/video/fbdev/s3fb.c                         |    2 +
 drivers/video/fbdev/sis/init.c                     |    4 +-
 drivers/video/fbdev/vt8623fb.c                     |    2 +
 drivers/watchdog/armada_37xx_wdt.c                 |    2 +
 drivers/watchdog/f71808e_wdt.c                     |    4 +-
 drivers/watchdog/sp5100_tco.c                      |    1 +
 fs/Makefile                                        |    2 -
 fs/attr.c                                          |    2 +
 fs/btrfs/block-group.c                             |   29 +-
 fs/btrfs/ctree.h                                   |   34 +-
 fs/btrfs/delalloc-space.c                          |    6 +-
 fs/btrfs/disk-io.c                                 |   38 +-
 fs/btrfs/extent-tree.c                             |   74 +-
 fs/btrfs/extent_io.c                               |    4 +-
 fs/btrfs/file.c                                    |    2 +-
 fs/btrfs/free-space-cache.c                        |    7 +-
 fs/btrfs/inode.c                                   |  177 ++-
 fs/btrfs/space-info.c                              |  117 +-
 fs/btrfs/space-info.h                              |   14 +-
 fs/btrfs/sysfs.c                                   |   37 +
 fs/btrfs/tree-log.c                                |   27 +-
 fs/btrfs/tree-log.h                                |    3 +
 fs/btrfs/volumes.c                                 |   28 +-
 fs/btrfs/zoned.c                                   |  127 +-
 fs/btrfs/zoned.h                                   |   30 +-
 fs/cifs/file.c                                     |   28 +-
 fs/erofs/decompressor.c                            |   16 +-
 fs/erofs/decompressor_lzma.c                       |    1 +
 fs/eventpoll.c                                     |   22 +
 fs/exec.c                                          |    3 +
 fs/ext2/super.c                                    |   12 +-
 fs/ext4/inline.c                                   |    3 +
 fs/ext4/inode.c                                    |   24 +-
 fs/ext4/migrate.c                                  |    4 +-
 fs/ext4/namei.c                                    |   23 +
 fs/ext4/resize.c                                   |    1 +
 fs/ext4/xattr.c                                    |  169 ++-
 fs/ext4/xattr.h                                    |   14 +
 fs/f2fs/checkpoint.c                               |    4 +-
 fs/f2fs/data.c                                     |  192 ++-
 fs/f2fs/debug.c                                    |   18 +-
 fs/f2fs/f2fs.h                                     |   60 +-
 fs/f2fs/file.c                                     |  164 +-
 fs/f2fs/gc.c                                       |  134 +-
 fs/f2fs/inode.c                                    |    3 +-
 fs/f2fs/namei.c                                    |   28 +-
 fs/f2fs/node.c                                     |    4 -
 fs/f2fs/node.h                                     |    1 -
 fs/f2fs/segment.c                                  |  391 ++---
 fs/f2fs/segment.h                                  |    7 +-
 fs/f2fs/super.c                                    |    6 +-
 fs/f2fs/verity.c                                   |    2 +-
 fs/fuse/control.c                                  |    4 +-
 fs/fuse/dir.c                                      |    7 +-
 fs/fuse/file.c                                     |   39 +-
 fs/fuse/inode.c                                    |    6 +
 fs/fuse/ioctl.c                                    |   15 +-
 fs/jbd2/commit.c                                   |    2 +-
 fs/jbd2/transaction.c                              |   14 +-
 fs/kernfs/dir.c                                    |    7 +-
 fs/ksmbd/connection.c                              |   20 +-
 fs/ksmbd/connection.h                              |   27 +-
 fs/ksmbd/ksmbd_netlink.h                           |    3 +-
 fs/ksmbd/smb2misc.c                                |   12 +-
 fs/ksmbd/smb2pdu.c                                 |  151 +-
 fs/ksmbd/smbacl.c                                  |  130 +-
 fs/ksmbd/smbacl.h                                  |    2 +-
 fs/ksmbd/transport_ipc.c                           |    3 +
 fs/ksmbd/transport_rdma.c                          |  161 +-
 fs/ksmbd/transport_rdma.h                          |    8 +
 fs/ksmbd/vfs.c                                     |    5 +
 fs/lockd/svc4proc.c                                |    8 +
 fs/lockd/xdr4.c                                    |   19 +-
 fs/mbcache.c                                       |   76 +-
 fs/namei.c                                         |    4 +
 fs/nfs/flexfilelayout/flexfilelayout.c             |    4 +
 fs/nfs/nfs3client.c                                |    1 -
 fs/nfsd/filecache.c                                |   22 +-
 fs/nfsd/filecache.h                                |    4 +-
 fs/nfsd/trace.h                                    |    8 -
 fs/overlayfs/export.c                              |    2 +-
 fs/proc/base.c                                     |   46 +-
 fs/splice.c                                        |   10 +-
 fs/zonefs/super.c                                  |    3 +-
 include/acpi/cppc_acpi.h                           |    2 +-
 include/crypto/internal/blake2s.h                  |  108 --
 include/dt-bindings/clock/qcom,gcc-msm8939.h       |    1 +
 include/linux/acpi_viot.h                          |    2 +
 include/linux/blkdev.h                             |   19 +-
 include/linux/bpf.h                                |  140 +-
 include/linux/bpf_types.h                          |    1 +
 include/linux/bpf_verifier.h                       |    3 +-
 include/linux/btf.h                                |   21 +
 include/linux/buffer_head.h                        |   25 +-
 include/linux/cpumask.h                            |   18 +
 include/linux/filter.h                             |    9 +
 include/linux/hugetlb.h                            |    6 +-
 include/linux/iio/common/cros_ec_sensors_core.h    |    7 +-
 include/linux/iio/iio.h                            |   10 +-
 include/linux/kexec.h                              |   45 +-
 include/linux/kfifo.h                              |    2 +-
 include/linux/kvm_types.h                          |    2 +
 include/linux/lockd/xdr.h                          |    2 +
 include/linux/lockdep.h                            |   30 +-
 include/linux/mbcache.h                            |   10 +-
 include/linux/mfd/t7l66xb.h                        |    1 -
 include/linux/mlx5/driver.h                        |   12 +
 include/linux/nvme-fc-driver.h                     |   14 +
 include/linux/once_lite.h                          |   20 +-
 include/linux/perf_event.h                         |   16 +
 include/linux/pipe_fs_i.h                          |    9 +
 include/linux/rmap.h                               |    4 +-
 include/linux/sched.h                              |    2 +-
 include/linux/sched/rt.h                           |    8 -
 include/linux/sched/topology.h                     |    1 +
 include/linux/soundwire/sdw.h                      |    6 +-
 include/linux/swapops.h                            |   12 +-
 include/linux/tpm_eventlog.h                       |    2 +-
 include/linux/trace_events.h                       |   18 +
 include/linux/usb/hcd.h                            |    1 +
 include/linux/wait.h                               |    9 +-
 include/media/hevc-ctrls.h                         |    4 +-
 include/net/9p/client.h                            |    8 +-
 include/net/ax25.h                                 |    1 +
 include/net/bluetooth/hci.h                        |    1 +
 include/net/inet6_hashtables.h                     |   27 +-
 include/net/inet_hashtables.h                      |   44 +-
 include/net/inet_sock.h                            |   11 +
 include/net/pkt_sched.h                            |   17 +
 include/net/raw.h                                  |   16 +-
 include/net/rawv6.h                                |    7 +-
 include/net/sock.h                                 |   15 +-
 include/net/xdp_sock_drv.h                         |   11 +
 include/scsi/libiscsi.h                            |    2 +-
 include/scsi/scsi_transport_iscsi.h                |    1 +
 include/soc/mscc/ocelot.h                          |   27 +-
 include/trace/events/f2fs.h                        |   22 -
 include/trace/events/spmi.h                        |   12 +-
 include/trace/stages/stage1_struct_define.h        |    3 +
 include/trace/stages/stage2_data_offsets.h         |    3 +
 include/trace/stages/stage4_event_fields.h         |   11 +-
 include/trace/stages/stage5_get_offsets.h          |    4 +
 include/trace/stages/stage6_event_callback.h       |   12 +
 include/uapi/linux/bpf.h                           |   13 +
 include/uapi/linux/can/error.h                     |    5 +-
 include/uapi/linux/f2fs.h                          |    2 +-
 include/uapi/linux/netfilter/xt_IDLETIMER.h        |   17 +-
 init/main.c                                        |    1 +
 io_uring/Makefile                                  |    6 +
 {fs => io_uring}/io-wq.c                           |    0
 {fs => io_uring}/io-wq.h                           |    0
 {fs => io_uring}/io_uring.c                        |    6 +-
 kernel/bpf/arraymap.c                              |   36 +-
 kernel/bpf/bpf_struct_ops.c                        |   71 +-
 kernel/bpf/btf.c                                   |  470 +++++-
 kernel/bpf/cgroup.c                                |   70 +-
 kernel/bpf/core.c                                  |   35 +-
 kernel/bpf/hashtab.c                               |   64 +-
 kernel/bpf/helpers.c                               |   24 +
 kernel/bpf/map_in_map.c                            |    5 +-
 kernel/bpf/ringbuf.c                               |    4 +-
 kernel/bpf/syscall.c                               |  257 +++-
 kernel/bpf/trampoline.c                            |   73 +-
 kernel/bpf/verifier.c                              |  418 ++++--
 kernel/cgroup/cpuset.c                             |    2 +-
 kernel/dma/swiotlb.c                               |    2 +-
 kernel/irq/Kconfig                                 |    1 +
 kernel/irq/chip.c                                  |    3 +-
 kernel/irq/irqdomain.c                             |    2 +
 kernel/kexec_file.c                                |   66 +-
 kernel/kprobes.c                                   |    3 +-
 kernel/locking/lockdep.c                           |    7 +-
 kernel/power/user.c                                |   13 +-
 kernel/profile.c                                   |    7 +
 kernel/rcu/rcutorture.c                            |   28 +-
 kernel/sched/core.c                                |   52 +-
 kernel/sched/fair.c                                |  141 +-
 kernel/sched/features.h                            |    3 +-
 kernel/sched/rt.c                                  |   15 +-
 kernel/sched/sched.h                               |    1 -
 kernel/smp.c                                       |    4 +-
 kernel/time/hrtimer.c                              |    1 +
 kernel/time/timekeeping.c                          |    7 +-
 kernel/trace/blktrace.c                            |    5 +-
 lib/crypto/blake2s-selftest.c                      |   41 +
 lib/crypto/blake2s.c                               |   37 +-
 lib/iov_iter.c                                     |   15 +-
 lib/kunit/executor.c                               |    4 +-
 lib/livepatch/test_klp_callbacks_busy.c            |    8 +
 lib/overflow_kunit.c                               |    6 +
 lib/smp_processor_id.c                             |    2 +-
 lib/test_bpf.c                                     |    4 +-
 lib/test_hmm.c                                     |   10 +-
 lib/test_kasan.c                                   |   10 +
 mm/damon/reclaim.c                                 |    4 +-
 mm/gup.c                                           |    2 +-
 mm/huge_memory.c                                   |   11 +-
 mm/hugetlb.c                                       |   15 +-
 mm/hugetlb_cgroup.c                                |    1 +
 mm/kasan/hw_tags.c                                 |   32 +-
 mm/memory-failure.c                                |    2 +-
 mm/memory_hotplug.c                                |    2 +-
 mm/mempolicy.c                                     |    4 +-
 mm/memremap.c                                      |    2 +-
 mm/migrate.c                                       |   30 +-
 mm/mmap.c                                          |    1 -
 mm/vmalloc.c                                       |   10 +-
 net/9p/client.c                                    |   36 +-
 net/9p/trans_fd.c                                  |   13 +-
 net/9p/trans_rdma.c                                |    2 +-
 net/9p/trans_virtio.c                              |    4 +-
 net/9p/trans_xen.c                                 |    2 +-
 net/ax25/af_ax25.c                                 |    4 +-
 net/batman-adv/trace.h                             |    9 +-
 net/bluetooth/hci_core.c                           |   10 +-
 net/bluetooth/hci_event.c                          |    5 +-
 net/bluetooth/hci_sync.c                           |    8 +-
 net/bluetooth/l2cap_core.c                         |   13 +-
 net/bluetooth/mgmt.c                               |   10 +-
 net/bpf/bpf_dummy_struct_ops.c                     |   24 +-
 net/core/filter.c                                  |    4 +-
 net/core/skmsg.c                                   |    4 +-
 net/dccp/proto.c                                   |   10 +-
 net/ipv4/af_inet.c                                 |    2 +
 net/ipv4/inet_hashtables.c                         |   17 +-
 net/ipv4/raw.c                                     |  164 +-
 net/ipv4/raw_diag.c                                |   53 +-
 net/ipv4/tcp.c                                     |   33 +-
 net/ipv4/tcp_output.c                              |   30 +-
 net/ipv4/udp.c                                     |    3 +-
 net/ipv6/af_inet6.c                                |    3 +
 net/ipv6/inet6_hashtables.c                        |    6 +-
 net/ipv6/raw.c                                     |  120 +-
 net/ipv6/udp.c                                     |    2 +-
 net/mptcp/protocol.c                               |    3 +-
 net/netfilter/nf_tables_api.c                      |   24 +-
 net/netfilter/nft_queue.c                          |   27 +
 net/rose/af_rose.c                                 |   11 +-
 net/rose/rose_route.c                              |    2 +
 net/sched/cls_route.c                              |    2 +-
 scripts/Makefile.modpost                           |    3 +-
 scripts/faddr2line                                 |    4 +-
 scripts/gdb/linux/dmesg.py                         |    9 +-
 scripts/gdb/linux/utils.py                         |   14 +-
 security/selinux/ss/policydb.h                     |    2 +
 security/selinux/ss/services.c                     |    9 +-
 sound/pci/hda/patch_cirrus.c                       |    1 +
 sound/pci/hda/patch_conexant.c                     |   11 +-
 sound/pci/hda/patch_realtek.c                      |  124 ++
 sound/soc/amd/yc/acp6x-mach.c                      |   32 +-
 sound/soc/atmel/mchp-spdifrx.c                     |    9 +-
 sound/soc/codecs/cros_ec_codec.c                   |    1 +
 sound/soc/codecs/da7210.c                          |    2 +
 sound/soc/codecs/msm8916-wcd-digital.c             |   46 +-
 sound/soc/codecs/mt6359-accdet.c                   |    1 +
 sound/soc/codecs/mt6359.c                          |    1 +
 sound/soc/codecs/wcd9335.c                         |   81 +-
 sound/soc/codecs/wsa881x.c                         |   10 +-
 sound/soc/fsl/fsl-asoc-card.c                      |    5 +-
 sound/soc/fsl/fsl_asrc.c                           |    6 +-
 sound/soc/fsl/fsl_easrc.c                          |    9 +-
 sound/soc/fsl/fsl_easrc.h                          |    2 +-
 sound/soc/fsl/imx-audmux.c                         |    2 +-
 sound/soc/fsl/imx-card.c                           |   22 +-
 sound/soc/generic/audio-graph-card.c               |    4 +-
 sound/soc/generic/audio-graph-card2.c              |   44 +-
 sound/soc/intel/boards/sof_rt5682.c                |   18 +-
 sound/soc/mediatek/mt6797/mt6797-mt6351.c          |    6 +-
 sound/soc/mediatek/mt8173/mt8173-rt5650-rt5676.c   |   10 +-
 sound/soc/mediatek/mt8173/mt8173-rt5650.c          |    9 +-
 sound/soc/qcom/lpass-cpu.c                         |    1 +
 sound/soc/qcom/qdsp6/q6adm.c                       |    2 +-
 sound/soc/samsung/aries_wm8994.c                   |    6 +-
 sound/soc/samsung/h1940_uda1380.c                  |    2 +-
 sound/soc/samsung/rx1950_uda1380.c                 |    4 +-
 sound/soc/sof/ipc3-topology.c                      |    1 +
 sound/soc/sof/mediatek/mt8195/mt8195-loader.c      |    2 +-
 sound/soc/sof/sof-priv.h                           |    4 +-
 sound/usb/bcd2000/bcd2000.c                        |    3 +-
 sound/usb/quirks.c                                 |    2 +
 tools/bpf/bpftool/link.c                           |    4 +
 tools/include/uapi/linux/bpf.h                     |   13 +
 tools/lib/bpf/bpf_tracing.h                        |    2 +-
 tools/lib/bpf/gen_loader.c                         |    2 +-
 tools/lib/bpf/libbpf.c                             |    9 +-
 tools/lib/bpf/xsk.c                                |    9 +-
 tools/perf/builtin-stat.c                          |   30 -
 tools/perf/util/dsos.c                             |   15 +-
 tools/perf/util/genelf.c                           |    6 +-
 tools/perf/util/symbol-elf.c                       |   27 +-
 tools/power/x86/intel-speed-select/isst-daemon.c   |    2 +-
 tools/testing/selftests/bpf/prog_tests/btf.c       |    2 +-
 .../selftests/bpf/prog_tests/fexit_stress.c        |   32 +-
 .../testing/selftests/bpf/prog_tests/sock_fields.c |    1 -
 .../testing/selftests/bpf/prog_tests/tc_redirect.c |    8 +-
 tools/testing/selftests/bpf/progs/test_tc_dtime.c  |   53 +-
 .../testing/selftests/bpf/verifier/ref_tracking.c  |    2 +-
 tools/testing/selftests/bpf/verifier/sock.c        |    6 +-
 tools/testing/selftests/kvm/lib/x86_64/processor.c |    2 +-
 .../selftests/powerpc/papr_attributes/attr_test.c  |   30 +-
 tools/testing/selftests/rcutorture/bin/kvm.sh      |   12 +-
 tools/testing/selftests/seccomp/seccomp_bpf.c      |    2 +-
 .../testing/selftests/timers/clocksource-switch.c  |    6 +-
 tools/testing/selftests/timers/valid-adjtimex.c    |    2 +-
 tools/testing/selftests/vm/hugepage-mremap.c       |    2 +-
 tools/testing/selftests/vm/hugetlb-madvise.c       |    5 +-
 .../selftests/wireguard/qemu/arch/riscv32.config   |    1 +
 tools/thermal/tmon/sysfs.c                         |   24 +-
 tools/thermal/tmon/tmon.h                          |    3 +
 tools/tracing/rtla/Makefile                        |    2 +-
 tools/tracing/rtla/src/trace.c                     |    9 +-
 tools/tracing/rtla/src/utils.c                     |    5 +-
 virt/kvm/kvm_main.c                                |   25 +-
 virt/kvm/pfncache.c                                |  207 ++-
 1198 files changed, 17321 insertions(+), 11537 deletions(-)



^ permalink raw reply	[relevance 1%]

* [PATCH 5.18 0453/1095] bpftool: Add missing link types
  2022-08-15 17:49  1% [PATCH 5.18 0000/1095] 5.18.18-rc1 review Greg Kroah-Hartman
@ 2022-08-15 17:57  8% ` Greg Kroah-Hartman
  0 siblings, 0 replies; 77+ results
From: Greg Kroah-Hartman @ 2022-08-15 17:57 UTC (permalink / raw)
  To: linux-kernel
  Cc: Greg Kroah-Hartman, stable, Milan Landaverde, Andrii Nakryiko,
	Sasha Levin

From: Milan Landaverde <milan@mdaverde.com>

[ Upstream commit fff3dfab17866f6ac5c5666839f6132b6c52f306 ]

Will display the link type names in bpftool link show output

Signed-off-by: Milan Landaverde <milan@mdaverde.com>
Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
Link: https://lore.kernel.org/bpf/20220331154555.422506-3-milan@mdaverde.com
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
 tools/bpf/bpftool/link.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/tools/bpf/bpftool/link.c b/tools/bpf/bpftool/link.c
index 97dec81950e5..8fb0116f9136 100644
--- a/tools/bpf/bpftool/link.c
+++ b/tools/bpf/bpftool/link.c
@@ -20,6 +20,9 @@ static const char * const link_type_name[] = {
 	[BPF_LINK_TYPE_CGROUP]			= "cgroup",
 	[BPF_LINK_TYPE_ITER]			= "iter",
 	[BPF_LINK_TYPE_NETNS]			= "netns",
+	[BPF_LINK_TYPE_XDP]			= "xdp",
+	[BPF_LINK_TYPE_PERF_EVENT]		= "perf_event",
+	[BPF_LINK_TYPE_KPROBE_MULTI]		= "kprobe_multi",
 };
 
 static struct hashmap *link_table;
-- 
2.35.1




^ permalink raw reply related	[relevance 8%]

* [PATCH 5.18 0000/1094] 5.18.18-rc2 review
@ 2022-08-16 12:59  1% Greg Kroah-Hartman
  0 siblings, 0 replies; 77+ results
From: Greg Kroah-Hartman @ 2022-08-16 12:59 UTC (permalink / raw)
  To: linux-kernel
  Cc: Greg Kroah-Hartman, stable, torvalds, akpm, linux, shuah,
	patches, lkft-triage, pavel, jonathanh, f.fainelli,
	sudipm.mukherjee, slade

This is the start of the stable review cycle for the 5.18.18 release.
There are 1094 patches in this series, all will be posted as a response
to this one.  If anyone has any issues with these being applied, please
let me know.

Responses should be made by Thu, 18 Aug 2022 12:43:14 +0000.
Anything received after that time might be too late.

The whole patch series can be found in one patch at:
	https://www.kernel.org/pub/linux/kernel/v5.x/stable-review/patch-5.18.18-rc2.gz
or in the git tree and branch at:
	git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable-rc.git linux-5.18.y
and the diffstat can be found below.

thanks,

greg k-h

-------------
Pseudo-Shortlog of commits:

Greg Kroah-Hartman <gregkh@linuxfoundation.org>
    Linux 5.18.18-rc2

Andrey Konovalov <andreyknvl@gmail.com>
    mm: introduce clear_highpage_kasan_tagged

Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
    Bluetooth: L2CAP: Fix l2cap_global_chan_by_psm regression

Pavel Begunkov <asml.silence@gmail.com>
    io_uring: mem-account pbuf buckets

Ye Bin <yebin10@huawei.com>
    f2fs: fix null-ptr-deref in f2fs_get_dnode_of_data

Tom Rix <trix@redhat.com>
    drm/vc4: change vc4_dma_range_matches from a global to static

Daeho Jeong <daehojeong@google.com>
    f2fs: revive F2FS_IOC_ABORT_VOLATILE_WRITE

Lukas Wunner <lukas@wunner.de>
    net: phy: smsc: Disable Energy Detect Power-Down in interrupt mode

Kumar Kartikeya Dwivedi <memxor@gmail.com>
    bpf: Suppress 'passing zero to PTR_ERR' warning

Kumar Kartikeya Dwivedi <memxor@gmail.com>
    bpf: Fix sparse warning for bpf_kptr_xchg_proto

Marek Vasut <marex@denx.de>
    drm/bridge: tc358767: Fix (e)DP bridge endpoint parsing in dedicated function

Russell Currey <ruscur@russell.cc>
    powerpc/kexec: Fix build failure from uninitialised variable

Alexander Gordeev <agordeev@linux.ibm.com>
    Revert "s390/smp: enforce lowcore protection on CPU restart"

Vladimir Oltean <vladimir.oltean@nxp.com>
    net: dsa: felix: fix min gate len calculation for tc when its first gate is closed

Steven Rostedt (Google) <rostedt@goodmis.org>
    tracing: Use a copy of the va_list for __assign_vstr()

Paolo Abeni <pabeni@redhat.com>
    mptcp: refine memory scheduling

Greg Kroah-Hartman <gregkh@linuxfoundation.org>
    Revert "mwifiex: fix sleep in atomic context bugs caused by dev_coredumpv"

Eric Dumazet <edumazet@google.com>
    raw: fix a typo in raw_icmp_error()

Eric Dumazet <edumazet@google.com>
    raw: remove unused variables from raw6_icmp_error()

Jason A. Donenfeld <Jason@zx2c4.com>
    crypto: lib/blake2s - reduce stack frame usage in self test

Eric Dumazet <edumazet@google.com>
    tcp: fix over estimation in sk_forced_mem_schedule()

Thadeu Lima de Souza Cascardo <cascardo@canonical.com>
    net_sched: cls_route: remove from list when handle is 0

Naohiro Aota <naohiro.aota@wdc.com>
    btrfs: convert count_max_extents() to use fs_info->max_extent_size

Filipe Manana <fdmanana@suse.com>
    btrfs: join running log transaction when logging new name

Christophe Leroy <christophe.leroy@csgroup.eu>
    powerpc: Fix eh field when calling lwarx on PPC32

SeongJae Park <sj@kernel.org>
    xen-blkfront: Apply 'feature_persistent' parameter when connect

Maximilian Heyne <mheyne@amazon.de>
    xen-blkback: Apply 'feature_persistent' parameter when connect

SeongJae Park <sj@kernel.org>
    xen-blkback: fix persistent grants negotiation

Mårten Lindahl <marten.lindahl@axis.com>
    tpm: Add check for Failure mode for TPM2 modules

Huacai Chen <chenhuacai@kernel.org>
    tpm: eventlog: Fix section mismatch for DEBUG_SECTION_MISMATCH

Tianjia Zhang <tianjia.zhang@linux.alibaba.com>
    KEYS: asymmetric: enforce SM2 signature use pkey algo

Jan Kara <jack@suse.cz>
    ext4: fix race when reusing xattr blocks

Jan Kara <jack@suse.cz>
    ext4: unindent codeblock in ext4_xattr_block_set()

Shuqi Zhang <zhangshuqi3@huawei.com>
    ext4: use kmemdup() to replace kmalloc + memcpy

Jan Kara <jack@suse.cz>
    ext4: remove EA inode entry from mbcache on inode eviction

Lukas Czerner <lczerner@redhat.com>
    ext4: make sure ext4_append() always allocates new block

Lukas Czerner <lczerner@redhat.com>
    ext4: check if directory block is within i_size

Ye Bin <yebin10@huawei.com>
    ext4: fix warning in ext4_iomap_begin as race between bmap and write

Baokun Li <libaokun1@huawei.com>
    ext4: correct the misjudgment in ext4_iget_extra_inode

Baokun Li <libaokun1@huawei.com>
    ext4: correct max_inline_xattr_value_size computing

Baokun Li <libaokun1@huawei.com>
    ext4: fix use-after-free in ext4_xattr_set_entry

Baokun Li <libaokun1@huawei.com>
    ext4: add EXT4_INODE_HAS_XATTR_SPACE macro in xattr.h

Eric Whitney <enwlinux@gmail.com>
    ext4: fix extent status tree race in writeback error recovery path

Theodore Ts'o <tytso@mit.edu>
    ext4: update s_overhead_clusters in the superblock during an on-line resize

Hyunchul Lee <hyc.lee@gmail.com>
    ksmbd: prevent out of bound read for SMB2_WRITE

Namjae Jeon <linkinjeon@kernel.org>
    ksmbd: fix wrong smbd max read/write size check

Namjae Jeon <linkinjeon@kernel.org>
    ksmbd: add smbd max io size parameter

Hyunchul Lee <hyc.lee@gmail.com>
    ksmbd: smbd: introduce read/write credits for RDMA read/write

Hyunchul Lee <hyc.lee@gmail.com>
    ksmbd: smbd: change prototypes of RDMA read/write related functions

Marios Makassikis <mmakassikis@freebox.fr>
    ksmbd: validate length in smb2_write()

Steven Rostedt (Google) <rostedt@goodmis.org>
    tracing: Use a struct alignof to determine trace event field alignment

Steven Rostedt (Google) <rostedt@goodmis.org>
    batman-adv: tracing: Use the new __vstring() helper

Miaohe Lin <linmiaohe@huawei.com>
    hugetlb_cgroup: fix wrong hugetlb cgroup numa stat

Jianglei Nie <niejianglei2021@163.com>
    mm/damon/reclaim: fix potential memory leak in damon_reclaim_init()

Mikulas Patocka <mpatocka@redhat.com>
    dm raid: fix address sanitizer warning in raid_resume

Mikulas Patocka <mpatocka@redhat.com>
    dm raid: fix address sanitizer warning in raid_status

Sean Christopherson <seanjc@google.com>
    KVM: nVMX: Attempt to load PERF_GLOBAL_CTRL on nVMX xfer iff it exists

Sean Christopherson <seanjc@google.com>
    KVM: VMX: Add helper to check if the guest PMU has PERF_GLOBAL_CTRL

Like Xu <likexu@tencent.com>
    KVM: x86/pmu: Ignore pmu->global_ctrl check if vPMU doesn't support global_ctrl

Sean Christopherson <seanjc@google.com>
    KVM: VMX: Mark all PERF_GLOBAL_(OVF)_CTRL bits reserved if there's no vPMU

Like Xu <like.xu@linux.intel.com>
    KVM: x86/pmu: Introduce the ctrl_mask value for fixed counter

Sumanth Korikkar <sumanthk@linux.ibm.com>
    s390/unwind: fix fgraph return address recovery

Jason A. Donenfeld <Jason@zx2c4.com>
    powerpc/powernv/kvm: Use darn for H_RANDOM on Power9

Rafael J. Wysocki <rafael.j.wysocki@intel.com>
    ACPI: CPPC: Do not prevent CPPC from working in the future

Artem Bityutskiy <artem.bityutskiy@linux.intel.com>
    intel_idle: make SPR C1 and C1E be independent

Zhang Rui <rui.zhang@intel.com>
    intel_idle: Add AlderLake support

Naohiro Aota <naohiro.aota@wdc.com>
    btrfs: zoned: wait until zone is finished when allocation didn't progress

Naohiro Aota <naohiro.aota@wdc.com>
    btrfs: zoned: write out partially allocated region

Naohiro Aota <naohiro.aota@wdc.com>
    btrfs: zoned: activate necessary block group

Naohiro Aota <naohiro.aota@wdc.com>
    btrfs: zoned: activate metadata block group on flush_space

Naohiro Aota <naohiro.aota@wdc.com>
    btrfs: zoned: introduce space_info->active_total_bytes

Stefan Roesch <shr@fb.com>
    btrfs: store chunk size in space-info struct

Naohiro Aota <naohiro.aota@wdc.com>
    btrfs: zoned: introduce btrfs_zoned_bg_is_full

Josef Bacik <josef@toxicpanda.com>
    btrfs: make the bg_reclaim_threshold per-space info

Naohiro Aota <naohiro.aota@wdc.com>
    btrfs: zoned: disable metadata overcommit for zoned

Naohiro Aota <naohiro.aota@wdc.com>
    btrfs: zoned: finish least available block group on data bg allocation

Naohiro Aota <naohiro.aota@wdc.com>
    btrfs: let can_allocate_chunk return error

Naohiro Aota <naohiro.aota@wdc.com>
    btrfs: replace BTRFS_MAX_EXTENT_SIZE with fs_info->max_extent_size

Naohiro Aota <naohiro.aota@wdc.com>
    btrfs: zoned: revive max_zone_append_bytes

Naohiro Aota <naohiro.aota@wdc.com>
    block: add bdev_max_segments() helper

Christoph Hellwig <hch@lst.de>
    block: add a bdev_max_zone_append_sectors helper

Nikolay Borisov <nborisov@suse.com>
    btrfs: properly flag filesystem with BTRFS_FEATURE_INCOMPAT_BIG_METADATA

Josef Bacik <josef@toxicpanda.com>
    btrfs: reset block group chunk force if we have to wait

Naohiro Aota <naohiro.aota@wdc.com>
    btrfs: fix error handling of fallback uncompress write

Naohiro Aota <naohiro.aota@wdc.com>
    btrfs: ensure pages are unlocked on cow_file_range() failure

Josef Bacik <josef@toxicpanda.com>
    btrfs: tree-log: make the return value for log syncing consistent

Jinke Han <hanjinke.666@bytedance.com>
    block: don't allow the same type rq_qos add more than once

Christoph Hellwig <hch@lst.de>
    block: serialize all debugfs operations using q->debugfs_mutex

Chen Zhongjin <chenzhongjin@huawei.com>
    locking/csd_lock: Change csdlock_debug from early_param to __setup

Jason A. Donenfeld <Jason@zx2c4.com>
    timekeeping: contribute wall clock to rng on time change

Tyler Hicks <tyhicks@linux.microsoft.com>
    net/9p: Initialize the iounit field during fid creation

Luo Meng <luomeng12@huawei.com>
    dm thin: fix use-after-free crash in dm_sm_register_threshold_callback

Steven Rostedt (Google) <rostedt@goodmis.org>
    tracing/events: Add __vstring() and __assign_vstr() helper macros

Michal Suchanek <msuchanek@suse.de>
    kexec, KEYS, s390: Make use of built-in and secondary keyring for signature verification

Coiby Xu <coxu@redhat.com>
    kexec: clean up arch_kexec_kernel_verify_sig

Naveen N. Rao <naveen.n.rao@linux.vnet.ibm.com>
    kexec_file: drop weak attribute from functions

Mikulas Patocka <mpatocka@redhat.com>
    dm writecache: set a default MAX_WRITEBACK_JOBS

Cameron Williams <cang1@live.co.uk>
    tty: 8250: Add support for Brainboxes PX cards.

Maciej W. Rozycki <macro@orcam.me.uk>
    serial: 8250: Add proper clock handling for OxSemi PCIe devices

Maciej W. Rozycki <macro@orcam.me.uk>
    serial: 8250: Fold EndRun device support into OxSemi Tornado code

Robert Marko <robimarko@gmail.com>
    PCI: qcom: Power on PHY before IPQ8074 DBI register accesses

Mohamed Khalfella <mkhalfella@purestorage.com>
    PCI/AER: Iterate over error counters instead of error strings

Alexander Lobakin <alexandr.lobakin@intel.com>
    iommu/vt-d: avoid invalid memory access via node_online(NUMA_NO_NODE)

Sean Christopherson <seanjc@google.com>
    KVM: x86: Signal #GP, not -EPERM, on bad WRMSR(MCi_CTL/STATUS)

Lev Kujawski <lkujaw@member.fsf.org>
    KVM: set_msr_mce: Permit guests to ignore single-bit ECC errors

Alexander Shishkin <alexander.shishkin@linux.intel.com>
    intel_th: pci: Add Raptor Lake-S CPU support

Alexander Shishkin <alexander.shishkin@linux.intel.com>
    intel_th: pci: Add Raptor Lake-S PCH support

Alexander Shishkin <alexander.shishkin@linux.intel.com>
    intel_th: pci: Add Meteor Lake-P support

Sudeep Holla <sudeep.holla@arm.com>
    firmware: arm_scpi: Ensure scpi_info is not assigned if the probe fails

Lukas Wunner <lukas@wunner.de>
    usbnet: smsc95xx: Fix deadlock on runtime resume

Lukas Wunner <lukas@wunner.de>
    usbnet: smsc95xx: Forward PHY interrupts to PHY driver to avoid polling

Lukas Wunner <lukas@wunner.de>
    usbnet: smsc95xx: Avoid link settings race on interrupt reception

Lukas Wunner <lukas@wunner.de>
    usbnet: smsc95xx: Don't clear read-only PHY interrupt

Dave Stevenson <dave.stevenson@raspberrypi.com>
    drm/vc4: drv: Adopt the dma configuration from the HVS or V3D component

Imre Deak <imre.deak@intel.com>
    drm/dp/mst: Read the extended DPCD capabilities during system resume

Jason A. Donenfeld <Jason@zx2c4.com>
    crypto: blake2s - remove shash module

Jitao Shi <jitao.shi@mediatek.com>
    drm/mediatek: Keep dsi as LP00 before dcs cmds transfer

Phil Auld <pauld@redhat.com>
    drivers/base: fix userspace break from using bin_attributes for cpumap and cpulist

David Collins <quic_collinsd@quicinc.com>
    spmi: trace: fix stack-out-of-bound access in SPMI tracing functions

Al Viro <viro@zeniv.linux.org.uk>
    __follow_mount_rcu(): verify that mount_lock remains unchanged

Xie Shaowen <studentxswpy@163.com>
    Input: gscps2 - check return value of ioremap() in gscps2_probe()

Thadeu Lima de Souza Cascardo <cascardo@canonical.com>
    posix-cpu-timers: Cleanup CPU timers before freeing them during exec

Bharath SM <bharathsm@microsoft.com>
    SMB3: fix lease break timeout when multiple deferred close handles for the same file.

Alexander Lobakin <alexandr.lobakin@intel.com>
    x86/olpc: fix 'logical not is only applied to the left hand side'

Masami Hiramatsu (Google) <mhiramat@kernel.org>
    x86/kprobes: Update kcb status flag after singlestepping

Steven Rostedt (Google) <rostedt@goodmis.org>
    ftrace/x86: Add back ftrace_expected assignment

Kim Phillips <kim.phillips@amd.com>
    x86/bugs: Enable STIBP for IBPB mitigated RETBleed

Arun Easi <aeasi@marvell.com>
    scsi: qla2xxx: Fix losing FCP-2 targets during port perturbation tests

Arun Easi <aeasi@marvell.com>
    scsi: qla2xxx: Fix losing target when it reappears during delete

Arun Easi <aeasi@marvell.com>
    scsi: qla2xxx: Fix losing FCP-2 targets on long port disable with I/Os

Quinn Tran <qutran@marvell.com>
    scsi: qla2xxx: Wind down adapter after PCIe error

Quinn Tran <qutran@marvell.com>
    scsi: qla2xxx: Fix erroneous mailbox timeout after PCI error injection

Arun Easi <aeasi@marvell.com>
    scsi: qla2xxx: Fix excessive I/O error messages by default

Arun Easi <aeasi@marvell.com>
    scsi: qla2xxx: Fix crash due to stale SRB access around I/O timeouts

Quinn Tran <qutran@marvell.com>
    scsi: qla2xxx: Turn off multi-queue for 8G adapters

Arun Easi <aeasi@marvell.com>
    scsi: qla2xxx: Fix discovery issues in FC-AL topology

Quinn Tran <qutran@marvell.com>
    scsi: qla2xxx: Fix imbalance vha->vref_count

Steffen Maier <maier@linux.ibm.com>
    scsi: zfcp: Fix missing auto port scan and thus missing target ports

Peter Wang <peter.wang@mediatek.com>
    scsi: ufs: core: Correct ufshcd_shutdown() flow

Zheyu Ma <zheyuma97@gmail.com>
    video: fbdev: s3fb: Check the size of screen before memset_io()

Zheyu Ma <zheyuma97@gmail.com>
    video: fbdev: arkfb: Check the size of screen before memset_io()

Zheyu Ma <zheyuma97@gmail.com>
    video: fbdev: vt8623fb: Check the size of screen before memset_io()

Jaewook Kim <jw5454.kim@samsung.com>
    f2fs: do not allow to decompress files have FI_COMPRESS_RELEASED

Sungjong Seo <sj1557.seo@samsung.com>
    f2fs: allow compression for mmap files in compress_mode=user

Andrea Righi <andrea.righi@canonical.com>
    x86/entry: Build thunk_$(BITS) only if CONFIG_PREEMPTION=y

Mel Gorman <mgorman@techsingularity.net>
    sched/core: Do not requeue task on CPU excluded from cpus_mask

Tianchen Ding <dtcccc@linux.alibaba.com>
    sched: Remove the limitation of WF_ON_CPU on wakelist if wakee cpu is idle

Tianchen Ding <dtcccc@linux.alibaba.com>
    sched: Fix the check of nr_running at queue wakelist

Florian Fainelli <f.fainelli@gmail.com>
    tools/thermal: Fix possible path truncations

Zheyu Ma <zheyuma97@gmail.com>
    video: fbdev: arkfb: Fix a divide-by-zero bug in ark_set_pixclock()

Siddh Raman Pant <code@siddh.me>
    x86/numa: Use cpumask_available instead of hardcoded NULL check

Waiman Long <longman@redhat.com>
    sched, cpuset: Fix dl_cpu_busy() panic due to empty cs->cpus_allowed

Michael Ellerman <mpe@ellerman.id.au>
    powerpc/64e: Fix kexec build error

Josh Poimboeuf <jpoimboe@kernel.org>
    scripts/faddr2line: Fix vmlinux detection on arm64

Arnaldo Carvalho de Melo <acme@redhat.com>
    genelf: Use HAVE_LIBCRYPTO_SUPPORT, not the never defined HAVE_LIBCRYPTO

Michael Ellerman <mpe@ellerman.id.au>
    powerpc/pci: Fix PHB numbering when using opal-phbid

Chenyi Qiang <chenyi.qiang@intel.com>
    x86/bus_lock: Don't assume the init value of DEBUGCTLMSR.BUS_LOCK_DETECT to be zero

Chen Zhongjin <chenzhongjin@huawei.com>
    kprobes: Forbid probing on trampoline and BPF code areas

Ian Rogers <irogers@google.com>
    perf symbol: Fail to read phdr workaround

Miaoqian Lin <linmq006@gmail.com>
    powerpc/cell/axon_msi: Fix refcount leak in setup_msi_msg_address

Miaoqian Lin <linmq006@gmail.com>
    powerpc/xive: Fix refcount leak in xive_get_max_prio

Miaoqian Lin <linmq006@gmail.com>
    powerpc/spufs: Fix refcount leak in spufs_init_isolated_loader

Matthew Wilcox (Oracle) <willy@infradead.org>
    cifs: Fix memory leak when using fscache

Chao Liu <liuchao@coolpad.com>
    f2fs: fix to remove F2FS_COMPR_FL and tag F2FS_NOCOMP_FL at the same time

Chao Yu <chao@kernel.org>
    f2fs: fix to check inline_data during compressed inode conversion

Jaegeuk Kim <jaegeuk@kernel.org>
    f2fs: kill volatile write support

Daeho Jeong <daehojeong@google.com>
    f2fs: change the current atomic write way

Chao Yu <chao@kernel.org>
    f2fs: give priority to select unpinned section for foreground GC

Byungki Lee <dominicus79@gmail.com>
    f2fs: write checkpoint during FG_GC

Chao Yu <chao@kernel.org>
    f2fs: don't set GC_FAILURE_PIN for background GC

Chao Yu <chao@kernel.org>
    f2fs: check pinfile in gc_data_segment() in advance

Chao Yu <chao@kernel.org>
    f2fs: fix to invalidate META_MAPPING before DIO write

Kan Liang <kan.liang@linux.intel.com>
    perf stat: Revert "perf stat: Add default hybrid events"

Alexander Gordeev <agordeev@linux.ibm.com>
    s390/smp: enforce lowcore protection on CPU restart

Sherry Sun <sherry.sun@nxp.com>
    tty: serial: fsl_lpuart: correct the count of break characters

Guo Mengqi <guomengqi3@huawei.com>
    serial: 8250_bcm2835aux: Add missing clk_disable_unprepare()

Pali Rohár <pali@kernel.org>
    powerpc/pci: Prefer PCI domain assignment via DT 'linux,pci-domain' and alias

Alexey Kardashevskiy <aik@ozlabs.ru>
    powerpc/iommu: Fix iommu_table_in_use for a small default DMA window case

Alexey Kardashevskiy <aik@ozlabs.ru>
    pseries/iommu/ddw: Fix kdump to work in absence of ibm,dma-window

Julia Lawall <Julia.Lawall@inria.fr>
    powerpc: fix typos in comments

Christophe Leroy <christophe.leroy@csgroup.eu>
    powerpc/32: Do not allow selection of e5500 or e6500 CPUs on PPC32

Christophe Leroy <christophe.leroy@csgroup.eu>
    powerpc/32s: Fix boot failure with KASAN + SMP + JUMP_LABEL_FEATURE_CHECK_DEBUG

Christophe Leroy <christophe.leroy@csgroup.eu>
    powerpc/32: Call mmu_mark_initmem_nx() regardless of data block mapping.

Claudiu Beznea <claudiu.beznea@microchip.com>
    ASoC: mchp-spdifrx: disable end of block interrupt on failures

Rustam Subkhankulov <subkhankulov@ispras.ru>
    video: fbdev: sis: fix typos in SiS_GetModeID()

Liang He <windhl@126.com>
    video: fbdev: amba-clcd: Fix refcount leak bugs

Yong Zhi <yong.zhi@intel.com>
    ASoC: Intel: sof_rt5682: Perform quirk check first in card late probe

William Dean <williamsukatube@gmail.com>
    watchdog: armada_37xx_wdt: check the return value of devm_ioremap() in armada_37xx_wdt_probe()

Jean Delvare <jdelvare@suse.de>
    watchdog: sp5100_tco: Fix a memory leak of EFCH MMIO resource

Jiasheng Jiang <jiasheng@iscas.ac.cn>
    watchdog: f71808e_wdt: Add check for platform_driver_register

Liang He <windhl@126.com>
    ASoC: audio-graph-card2: Add of_node_put() in fail path

Liang He <windhl@126.com>
    ASoC: audio-graph-card: Add of_node_put() in fail path

Xie Yongji <xieyongji@bytedance.com>
    fuse: Remove the control interface for virtio-fs

Christophe JAILLET <christophe.jaillet@wanadoo.fr>
    ASoC: qcom: q6dsp: Fix an off-by-one in q6adm_alloc_copp()

Shengjiu Wang <shengjiu.wang@nxp.com>
    ASoC: imx-card: use snd_pcm_format_t type for asrc_format

Shengjiu Wang <shengjiu.wang@nxp.com>
    ASoC: fsl_easrc: use snd_pcm_format_t type for sample_format

Shengjiu Wang <shengjiu.wang@nxp.com>
    ASoC: fsl-asoc-card: force cast the asrc_format type

Shengjiu Wang <shengjiu.wang@nxp.com>
    ASoC: fsl_asrc: force cast the asrc_format type

Alexander Gordeev <agordeev@linux.ibm.com>
    s390/zcore: fix race when reading from hardware system area

Alexander Gordeev <agordeev@linux.ibm.com>
    s390/crash: fix incorrect number of bytes to copy to user space

Sunil V L <sunilvl@ventanamicro.com>
    riscv: spinwait: Fix hartid variable type

Adrian Hunter <adrian.hunter@intel.com>
    perf tools: Fix dso_id inode generation comparison

Liang He <windhl@126.com>
    iommu/arm-smmu: qcom_iommu: Add of_node_put() when breaking out of loop

Miaoqian Lin <linmq006@gmail.com>
    mfd: max77620: Fix refcount leak in max77620_initialise_fps

Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
    mfd: t7l66xb: Drop platform disable callback

Sibi Sankar <quic_sibis@quicinc.com>
    remoteproc: sysmon: Wait for SSCTL service to come up

Siddharth Gupta <sidgup@codeaurora.org>
    remoteproc: qcom: pas: Check if coredump is enabled

Zhihao Cheng <chengzhihao1@huawei.com>
    proc: fix a dentry lock race between release_task and lookup

Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
    lib/smp_processor_id: fix imbalanced instrumentation_end() call

Dan Carpenter <dan.carpenter@oracle.com>
    kfifo: fix kfifo_to_user() return type

Miaoqian Lin <linmq006@gmail.com>
    rpmsg: qcom_smd: Fix refcount leak in qcom_smd_parse_edge

Florian Fainelli <f.fainelli@gmail.com>
    MIPS: Fixed __debug_virt_addr_valid()

Hangyu Hua <hbh25y@gmail.com>
    net: 9p: fix refcount leak in p9_read_work() error handling

Kent Overstreet <kent.overstreet@gmail.com>
    9p: Add client parameter to p9_req_put()

Kent Overstreet <kent.overstreet@gmail.com>
    9p: Drop kref usage

Sam Protsenko <semen.protsenko@linaro.org>
    iommu/exynos: Handle failed IOMMU device registration properly

Doug Berger <opendmb@gmail.com>
    serial: 8250_bcm7271: Save/restore RTS in suspend/resume

Liang He <windhl@126.com>
    ASoC: mt6359: Fix refcount leak bug

Liang He <windhl@126.com>
    ASoc: audio-graph-card2: Fix refcount leak bug in __graph_get_type()

Peter Ujfalusi <peter.ujfalusi@linux.intel.com>
    ASoC: SOF: ipc3-topology: Prevent double freeing of ipc_control_data via load_bytes

Robin Murphy <robin.murphy@arm.com>
    swiotlb: fail map correctly with failed io_tlb_default_mem

YC Hung <yc.hung@mediatek.com>
    ASoC: SOF: mediatek: fix mt8195 StatvectorSel wrong setting

Florian Fainelli <f.fainelli@gmail.com>
    MIPS: vdso: Utilize __pa() for gic_pfn

Daniel Starke <daniel.starke@siemens.com>
    tty: n_gsm: fix missing corner cases in gsmld_poll()

Daniel Starke <daniel.starke@siemens.com>
    tty: n_gsm: fix flow control handling in tx path

Daniel Starke <daniel.starke@siemens.com>
    tty: n_gsm: fix DM command

Daniel Starke <daniel.starke@siemens.com>
    tty: n_gsm: fix wrong T1 retry count handling

Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
    serial: 8250_fsl: Don't report FE, PE and OE twice

Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
    ASoC: audio-graph-card2.c: use of_property_read_u32() for rate

Eric Farman <farman@linux.ibm.com>
    vfio/ccw: Do not change FSM state in subchannel event

Eric Farman <farman@linux.ibm.com>
    vfio/ccw: Fix FSM state if mdev probe fails

Sireesh Kodali <sireeshkodali1@gmail.com>
    remoteproc: qcom: wcnss: Fix handling of IRQs

Shengjiu Wang <shengjiu.wang@nxp.com>
    ASoC: imx-card: Fix DSD/PDM mclk frequency

Tiezhu Yang <yangtiezhu@loongson.cn>
    MIPS: Loongson64: Fix section mismatch warning

Liang He <windhl@126.com>
    ASoC: qcom: Fix missing of_node_put() in asoc_qcom_lpass_cpu_platform_probe()

Daniel Starke <daniel.starke@siemens.com>
    tty: n_gsm: fix resource allocation order in gsm_activate_mux()

Daniel Starke <daniel.starke@siemens.com>
    tty: n_gsm: fix deadlock and link starvation in outgoing data path

Daniel Starke <daniel.starke@siemens.com>
    tty: n_gsm: fix race condition in gsmld_write()

Daniel Starke <daniel.starke@siemens.com>
    tty: n_gsm: fix packet re-transmission without open control channel

Daniel Starke <daniel.starke@siemens.com>
    tty: n_gsm: fix non flow control frames during mux flow off

Daniel Starke <daniel.starke@siemens.com>
    tty: n_gsm: fix missing timer to handle stalled links

Daniel Starke <daniel.starke@siemens.com>
    tty: n_gsm: fix wrong queuing behavior in gsm_dlci_data_output()

Daniel Starke <daniel.starke@siemens.com>
    tty: n_gsm: fix tty registration before control channel open

Daniel Starke <daniel.starke@siemens.com>
    tty: n_gsm: fix user open not possible at responder until initiator open

Alexander Lobakin <alexandr.lobakin@intel.com>
    net/ice: fix initializing the bitmap in the switch code

Jason Gunthorpe <jgg@ziepe.ca>
    vfio/pci: Have all VFIO PCI drivers store the vfio_pci_core_device in drvdata

Yishai Hadas <yishaih@nvidia.com>
    net/mlx5: Expose mlx5_sriov_blocking_notifier_register / unregister APIs

Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
    ASoC: codecs: wsa881x: handle timeouts in resume path

Tom Rix <trix@redhat.com>
    ASoC: samsung: change gpiod_speaker_power and rx1950_audio from global to static variables

Athira Rajeev <atrajeev@linux.vnet.ibm.com>
    powerpc/perf: Optimize clearing the pending PMI and remove WARN_ON for PMI check in power_pmu_disable

Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
    ASoC: samsung: h1940_uda1380: include proepr GPIO consumer header

Michael Ellerman <mpe@ellerman.id.au>
    selftests/powerpc: Skip energy_scale_info test on older firmware

Miaoqian Lin <linmq006@gmail.com>
    remoteproc: imx_rproc: Fix refcount leak in imx_rproc_addr_init

Chen Zhongjin <chenzhongjin@huawei.com>
    profiling: fix shift too large makes kernel panic

Joe Lawrence <joe.lawrence@redhat.com>
    selftests/livepatch: better synchronize test_klp_callbacks_busy

Miaoqian Lin <linmq006@gmail.com>
    remoteproc: k3-r5: Fix refcount leak in k3_r5_cluster_of_init

AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
    rpmsg: mtk_rpmsg: Fix circular locking dependency

Shengjiu Wang <shengjiu.wang@nxp.com>
    rpmsg: char: Add mutex protection for rpmsg_eptdev_open()

Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
    ASoC: codecs: wcd9335: move gains from SX_TLV to S8_TLV

Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
    ASoC: codecs: msm8916-wcd-digital: move gains from SX_TLV to S8_TLV

Peter Ujfalusi <peter.ujfalusi@linux.intel.com>
    ASoC: SOF: make ctx_store and ctx_restore as optional

Maciej W. Rozycki <macro@orcam.me.uk>
    serial: 8250: Export ICR access helpers for internal use

Yang Yingliang <yangyingliang@huawei.com>
    serial: pic32: fix missing clk_disable_unprepare() on error in pic32_uart_startup()

Jiri Slaby <jirislaby@kernel.org>
    serial: pic32: free up irq names correctly

Miaoqian Lin <linmq006@gmail.com>
    ASoC: mediatek: mt8173-rt5650: Fix refcount leak in mt8173_rt5650_dev_probe

Jiasheng Jiang <jiasheng@iscas.ac.cn>
    ASoC: codecs: da7210: add check for i2c_add_driver

Miaoqian Lin <linmq006@gmail.com>
    ASoC: mt6797-mt6351: Fix refcount leak in mt6797_mt6351_dev_probe

Miaoqian Lin <linmq006@gmail.com>
    ASoC: mediatek: mt8173: Fix refcount leak in mt8173_rt5650_rt5676_dev_probe

Fabio Estevam <festevam@gmail.com>
    ASoC: imx-audmux: Silence a clang warning

Miaoqian Lin <linmq006@gmail.com>
    ASoC: samsung: Fix error handling in aries_audio_probe

Miaoqian Lin <linmq006@gmail.com>
    ASoC: cros_ec_codec: Fix refcount leak in cros_ec_codec_platform_probe

Tang Bin <tangbin@cmss.chinamobile.com>
    opp: Fix error check in dev_pm_opp_attach_genpd()

Nathan Chancellor <nathan@kernel.org>
    usb: cdns3: Don't use priv_dev uninitialized in cdns3_gadget_ep_enable()

Zhihao Cheng <chengzhihao1@huawei.com>
    jbd2: fix assertion 'jh->b_frozen_data == NULL' failure when journal aborted

Li Lingfeng <lilingfeng3@huawei.com>
    ext4: recover csum seed of tmp_inode after migrating to extents

Zhang Yi <yi.zhang@huawei.com>
    jbd2: fix outstanding credits assert in jbd2_journal_commit_transaction()

Keith Busch <kbusch@kernel.org>
    block: ensure iov_iter advances for added pages

Keith Busch <kbusch@kernel.org>
    block/bio: remove duplicate append pages code

Christoph Hellwig <hch@lst.de>
    nvme: catch -ENODEV from nvme_revalidate_zones again

Nick Bowler <nbowler@draconx.ca>
    nvme: define compat_ioctl again to unbreak 32-bit userspace.

Bean Huo <beanhuo@micron.com>
    nvme: use command_id instead of req->tag in trace_nvme_complete_rq()

Dan Carpenter <dan.carpenter@oracle.com>
    null_blk: fix ida error handling in null_add_dev()

Md Haris Iqbal <haris.iqbal@ionos.com>
    block/rnbd-srv: Set keep_id to true after mutex_trylock

Zhu Yanjun <yanjun.zhu@linux.dev>
    RDMA/rxe: Fix error unwind in rxe_create_qp()

Maor Gottlieb <maorg@nvidia.com>
    RDMA/mlx5: Add missing check for return value in get namespace flow

Xu Qiang <xuqiang36@huawei.com>
    of/fdt: declared return type does not match actual return type

Andrei Vagin <avagin@google.com>
    selftests: kvm: set rax before vmcall

Andreas Schwab <schwab@suse.de>
    rtla: Fix double free

Daniel Bristot de Oliveira <bristot@kernel.org>
    rtla: Fix Makefile when called from -C tools/

Dan Carpenter <dan.carpenter@oracle.com>
    selftest/vm: uninitialized variable in main()

Dan Carpenter <dan.carpenter@oracle.com>
    tools/testing/selftests/vm/hugetlb-madvise.c: silence uninitialized variable warning

Miaohe Lin <linmiaohe@huawei.com>
    mm/mmap.c: fix missing call to vm_unacct_memory in mmap_region

Liam R. Howlett <Liam.Howlett@oracle.com>
    android: binder: stop saving a pointer to the VMA

Bart Van Assche <bvanassche@acm.org>
    RDMA/srpt: Fix a use-after-free

Bart Van Assche <bvanassche@acm.org>
    RDMA/srpt: Introduce a reference count in struct srpt_device

Bart Van Assche <bvanassche@acm.org>
    RDMA/srpt: Duplicate port name members

Dan Carpenter <dan.carpenter@oracle.com>
    platform/olpc: Fix uninitialized data in debugfs write

Vadim Pasternak <vadimp@nvidia.com>
    platform/mellanox: mlxreg-lc: Fix error flow and extend verbosity

Hans de Goede <hdegoede@redhat.com>
    platform/x86: pmc_atom: Match all Lex BayTrail boards with critclk_systems DMI table

Dan Carpenter <dan.carpenter@oracle.com>
    tools/power/x86/intel-speed-select: Fix off by one check

Sean Christopherson <seanjc@google.com>
    KVM: nVMX: Set UMIP bit CR4_FIXED1 MSR when emulating UMIP

Peter Suti <peter.suti@streamunlimited.com>
    staging: fbtft: core: set smem_len before fb_deferred_io_init call

Patrice Chotard <patrice.chotard@foss.st.com>
    mtd: spi-nor: fix spi_nor_spimem_setup_op() call in spi_nor_erase_{sector,chip}()

Andrey Strachuk <strochuk@ispras.ru>
    usb: cdns3: change place of 'priv_ep' assignment in cdns3_gadget_ep_dequeue(), cdns3_gadget_ep_enable()

Johan Hovold <johan@kernel.org>
    USB: serial: fix tty-port initialized comments

Basavaraj Natikar <Basavaraj.Natikar@amd.com>
    HID: amd_sfh: Handle condition of "no sensors"

Vidya Sagar <vidyas@nvidia.com>
    PCI: tegra194: Fix link up retry sequence

Vidya Sagar <vidyas@nvidia.com>
    PCI: tegra194: Fix Root Port interrupt handling

Bob Pearson <rpearsonhpe@gmail.com>
    RDMA/rxe: Fix rnr retry behavior

Md Haris Iqbal <haris.phnx@gmail.com>
    RDMA/rxe: For invalidate compare according to set keys in mr

Artem Borisov <dedsa2002@gmail.com>
    HID: alps: Declare U1_UNICORN_LEGACY support

Liang He <windhl@126.com>
    mmc: cavium-thunderx: Add of_node_put() when breaking out of loop

Liang He <windhl@126.com>
    mmc: cavium-octeon: Add of_node_put() when breaking out of loop

Liang He <windhl@126.com>
    mmc: core: quirks: Add of_node_put() when breaking out of loop

Bob Pearson <rpearsonhpe@gmail.com>
    RDMA/rxe: Fix mw bind to allow any consumer key portion

Antonio Borneo <antonio.borneo@foss.st.com>
    scripts/gdb: fix 'lx-dmesg' on 32 bits arch

Fabio Estevam <festevam@denx.de>
    dmaengine: imx-dma: Cast of_device_get_match_data() with (uintptr_t)

Basavaraj Natikar <Basavaraj.Natikar@amd.com>
    HID: amd_sfh: Add NULL check for hid device

Harshit Mogalapalli <harshit.m.mogalapalli@oracle.com>
    HID: mcp2221: prevent a buffer overflow in mcp_smbus_write()

Dan Carpenter <dan.carpenter@oracle.com>
    iio: adc: max1027: unlock on error path in max1027_read_single_value()

Liang He <windhl@126.com>
    gpio: gpiolib-of: Fix refcount bugs in of_mm_gpiochip_add_data()

Jianglei Nie <niejianglei2021@163.com>
    RDMA/hfi1: fix potential memory leak in setup_base_ctxt()

Bryan O'Donoghue <bryan.odonoghue@linaro.org>
    clk: qcom: gcc-msm8939: Fix weird field spacing in ftbl_gcc_camss_cci_clk

Bjorn Andersson <bjorn.andersson@linaro.org>
    clk: qcom: gdsc: Bump parent usage count when GDSC is found enabled

Abel Vesa <abel.vesa@linaro.org>
    clk: qcom: Drop mmcx gdsc supply for dispcc and videocc

Gwendal Grignou <gwendal@chromium.org>
    iio: cros: Register FIFO callback after sensor is registered

Cheng Xu <chengyou@linux.alibaba.com>
    RDMA/siw: Fix duplicated reported IW_CM_EVENT_CONNECT_REPLY event

Haoyue Xu <xuhaoyue1@hisilicon.com>
    RDMA/hns: Fix incorrect clearing of interrupt status register

Jianglei Nie <niejianglei2021@163.com>
    RDMA/qedr: Fix potential memory leak in __qedr_alloc_mr()

Md Haris Iqbal <haris.iqbal@ionos.com>
    RDMA/rtrs-clt: Replace list_next_or_null_rr_rcu with an inline function

Jack Wang <jinpu.wang@ionos.com>
    RDMA/rtrs-srv: Fix modinfo output for stringify

Mustafa Ismail <mustafa.ismail@intel.com>
    RDMA/irdma: Fix setting of QP context err_rq_idx_valid field

Mustafa Ismail <mustafa.ismail@intel.com>
    RDMA/irdma: Fix VLAN connection with wildcard address

Mustafa Ismail <mustafa.ismail@intel.com>
    RDMA/irdma: Fix a window for use-after-free

Christopher Obbard <chris.obbard@collabora.com>
    um: random: Don't initialise hwrng struct with zero

Peng Fan <peng.fan@nxp.com>
    interconnect: imx: fix max_node_id

Samuel Holland <samuel@sholland.org>
    phy: rockchip-inno-usb2: Ignore OTG IRQs in host mode

Fabrice Gasnier <fabrice.gasnier@foss.st.com>
    phy: stm32: fix error return in stm32_usbphyc_phy_init

Dan Carpenter <dan.carpenter@oracle.com>
    eeprom: idt_89hpesx: uninitialized data in idt_dbgfs_csr_write()

Johan Hovold <johan+linaro@kernel.org>
    usb: dwc3: qcom: fix missing optional irq warnings

Rohith Kollalsi <quic_rkollals@quicinc.com>
    usb: dwc3: core: Do not perform GCTL_CORE_SOFTRESET during bootup

Thinh Nguyen <Thinh.Nguyen@synopsys.com>
    usb: dwc3: core: Deprecate GCTL.CORESOFTRESET

Liang He <windhl@126.com>
    usb: aspeed-vhub: Fix refcount leak bug in ast_vhub_init_desc()

Randy Dunlap <rdunlap@infradead.org>
    usb: gadget: udc: amd5536 depends on HAS_DMA

Yang Yingliang <yangyingliang@huawei.com>
    xtensa: iss: fix handling error cases in iss_net_configure()

Max Filippov <jcmvbkbc@gmail.com>
    xtensa: iss/network: provide release() callback

Mahesh Rajashekhara <Mahesh.Rajashekhara@microchip.com>
    scsi: smartpqi: Fix DMA direction for RAID requests

Christian Marangi <ansuelsmth@gmail.com>
    PCI: qcom: Set up rev 2.1.0 PARF_PHY before enabling clocks

Stefan Roese <sr@denx.de>
    PCI/portdrv: Don't disable AER reporting in get_port_device_capability()

Claudio Imbrenda <imbrenda@linux.ibm.com>
    KVM: s390: pv: leak the topmost page table when destroy fails

Christian Loehle <CLoehle@hyperstone.com>
    mmc: block: Add single read for 4k sector cards

Liang He <windhl@126.com>
    of: device: Fix missing of_node_put() in of_dma_set_restricted_buffer

Eugen Hristev <eugen.hristev@microchip.com>
    mmc: sdhci-of-at91: fix set_uhs_signaling rewriting of MC1R

Christophe JAILLET <christophe.jaillet@wanadoo.fr>
    memstick/ms_block: Fix a memory leak

Christophe JAILLET <christophe.jaillet@wanadoo.fr>
    memstick/ms_block: Fix some incorrect memory allocation

Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
    mmc: renesas_sdhi: Get the reset handle early in the probe

Fabio Estevam <festevam@gmail.com>
    mmc: mxcmmc: Silence a clang warning

Miaoqian Lin <linmq006@gmail.com>
    mmc: sdhci-of-esdhc: Fix refcount leak in esdhc_signal_voltage_switch

jianchunfu <jianchunfu@cmss.chinamobile.com>
    rtla/utils: Use calloc and check the potential memory allocation failure

Duoming Zhou <duoming@zju.edu.cn>
    staging: rtl8192u: Fix sleep in atomic context bug in dm_fsync_timer_callback

Carlos Llamas <cmllamas@google.com>
    binder: fix redefinition of seq_file attributes

Alexander Shishkin <alexander.shishkin@linux.intel.com>
    intel_th: msu: Fix vmalloced buffers

Jiasheng Jiang <jiasheng@iscas.ac.cn>
    intel_th: msu-sink: Potential dereference of null pointer

Christophe JAILLET <christophe.jaillet@wanadoo.fr>
    intel_th: Fix a resource leak in an error handling path

Dan Carpenter <dan.carpenter@oracle.com>
    scsi: qla2xxx: Check correct variable in qla24xx_async_gffid()

Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
    phy: qcom-qmp: fix the QSERDES_V5_COM_CMN_MODE register

Shunsuke Mie <mie@igel.co.jp>
    PCI: endpoint: Don't stop controller when unbinding endpoint function

Viacheslav Mitrofanov <v.v.mitrofanov@yadro.com>
    dmaengine: sf-pdma: Add multithread support for a DMA channel

Quentin Perret <qperret@google.com>
    KVM: arm64: Don't return from void function

Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
    soundwire: revisit driver bind/unbind and callbacks

Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
    soundwire: bus_type: fix remove and shutdown support

Serge Semin <Sergey.Semin@baikalelectronics.ru>
    PCI: dwc: Always enable CDM check if "snps,enable-cdm-check" exists

Serge Semin <Sergey.Semin@baikalelectronics.ru>
    PCI: dwc: Deallocate EPC memory on dw_pcie_ep_init() errors

Serge Semin <Sergey.Semin@baikalelectronics.ru>
    PCI: dwc: Set INCREASE_REGION_SIZE flag based on limit address

Serge Semin <Sergey.Semin@baikalelectronics.ru>
    PCI: dwc: Disable outbound windows only for controllers using iATU

Serge Semin <Sergey.Semin@baikalelectronics.ru>
    PCI: dwc: Add unroll iATU space support to dw_pcie_disable_atu()

Serge Semin <Sergey.Semin@baikalelectronics.ru>
    PCI: dwc: Stop link on host_init errors and de-initialization

Andy Shevchenko <andriy.shevchenko@linux.intel.com>
    phy: ti: tusb1210: Don't check for write errors when powering on

Tianyu Li <tianyu.li@arm.com>
    mm/mempolicy: fix get_nodes out of bound access

Andrey Konovalov <andreyknvl@gmail.com>
    kasan: fix zeroing vmalloc memory with HW_TAGS

Miaohe Lin <linmiaohe@huawei.com>
    mm/migration: fix potential pte_unmap on an not mapped pte

Miaohe Lin <linmiaohe@huawei.com>
    mm/migration: return errno when isolate_huge_page failed

Yang Shi <shy828301@gmail.com>
    mm: rmap: use the correct parameter name for DEFINE_PAGE_VMA_WALK

Yushan Zhou <katrinzhou@tencent.com>
    kernfs: fix potential NULL dereference in __kernfs_remove

Nikita Travkin <nikita@trvn.ru>
    clk: qcom: clk-rcg2: Make sure to not write d=0 to the NMD register

Nikita Travkin <nikita@trvn.ru>
    clk: qcom: clk-rcg2: Fail Duty-Cycle configuration if MND divider is not enabled.

Vladimir Zapolskiy <vladimir.zapolskiy@linaro.org>
    clk: qcom: camcc-sm8250: Fix topology around titan_top power domain

Vladimir Zapolskiy <vladimir.zapolskiy@linaro.org>
    clk: qcom: camcc-sdm845: Fix topology around titan_top power domain

Robert Marko <robimarko@gmail.com>
    clk: qcom: ipq8074: set BRANCH_HALT_DELAY flag for UBI clocks

Robert Marko <robimarko@gmail.com>
    clk: qcom: ipq8074: fix NSS port frequency tables

Robert Marko <robimarko@gmail.com>
    clk: qcom: ipq8074: SW workaround for UBI32 PLL lock

Robert Marko <robimarko@gmail.com>
    clk: qcom: ipq8074: fix NSS core PLL-s

Bob Pearson <rpearsonhpe@gmail.com>
    RDMA/rxe: Fix deadlock in rxe_do_local_ops()

Sergey Shtylyov <s.shtylyov@omp.ru>
    usb: host: xhci: use snprintf() in xhci_decode_trb()

Bryan O'Donoghue <bryan.odonoghue@linaro.org>
    clk: qcom: gcc-msm8939: Point MM peripherals to system_mm_noc clock

Bryan O'Donoghue <bryan.odonoghue@linaro.org>
    clk: qcom: gcc-msm8939: Add missing system_mm_noc_bfdcd_clk_src

Bryan O'Donoghue <bryan.odonoghue@linaro.org>
    clk: qcom: gcc-msm8939: Fix bimc_ddr_clk_src rcgr base address

Bryan O'Donoghue <bryan.odonoghue@linaro.org>
    clk: qcom: gcc-msm8939: Add missing SYSTEM_MM_NOC_BFDCD_CLK_SRC

Neal Liu <neal_liu@aspeedtech.com>
    usb: gadget: f_mass_storage: Make CD-ROM emulation works with Windows OS

Mike Leach <mike.leach@linaro.org>
    coresight: syscfg: Update load and unload operations

Mike Leach <mike.leach@linaro.org>
    coresight: configfs: Fix unload of configurations on module exit

Ansuel Smith <ansuelsmth@gmail.com>
    clk: qcom: clk-krait: unlock spin after mux completion

Zhang Wensheng <zhangwensheng5@huawei.com>
    driver core: fix potential deadlock in __driver_attach

Christophe JAILLET <christophe.jaillet@wanadoo.fr>
    misc: rtsx: Fix an error handling path in rtsx_pci_probe()

Vladimir Zapolskiy <vladimir.zapolskiy@linaro.org>
    clk: qcom: camcc-sm8250: Fix halt on boot by reducing driver's init level

Mark Brown <broonie@kernel.org>
    mtd: dataflash: Add SPI ID table

Geert Uytterhoeven <geert+renesas@glider.be>
    mtd: hyperbus: rpc-if: Fix RPM imbalance in probe error path

Ben Gardon <bgardon@google.com>
    KVM: x86: Fix errant brace in KVM capability handling

Serge Semin <Sergey.Semin@baikalelectronics.ru>
    dmaengine: dw-edma: Fix eDMA Rd/Wr-channels and DMA-direction semantics

Mike Christie <michael.christie@oracle.com>
    scsi: iscsi: Fix session removal on shutdown

Mike Christie <michael.christie@oracle.com>
    scsi: iscsi: Add helper to remove a session from the kernel

Mike Christie <michael.christie@oracle.com>
    scsi: iscsi: Allow iscsi_if_stop_conn() to be called from kernel

Duoming Zhou <duoming@zju.edu.cn>
    mwifiex: fix sleep in atomic context bugs caused by dev_coredumpv

Sean Christopherson <seanjc@google.com>
    KVM: Don't set Accessed/Dirty bits for ZERO_PAGE

Miaohe Lin <linmiaohe@huawei.com>
    mm/memremap: fix memunmap_pages() race with get_dev_pagemap()

Miaohe Lin <linmiaohe@huawei.com>
    lib/test_hmm: avoid accessing uninitialized pages

Dongliang Mu <mudongliangabcd@gmail.com>
    RDMA/rxe: fix xa_alloc_cycle() error return value check again

Peng Fan <peng.fan@nxp.com>
    clk: imx: clk-fracn-gppll: correct rdiv

Liu Ying <victor.liu@nxp.com>
    clk: imx: clk-fracn-gppll: Return rate in rate table properly in ->recalc_rate()

Peng Fan <peng.fan@nxp.com>
    clk: imx: clk-fracn-gppll: fix mfd value

Peng Fan <peng.fan@nxp.com>
    clk: imx93: correct nic_media parent

Haibo Chen <haibo.chen@nxp.com>
    clk: imx93: use adc_root as the parent clock of adc1

Rex-BC Chen <rex-bc.chen@mediatek.com>
    clk: mediatek: reset: Fix written reset bit offset

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: temp: maxim_thermocouple: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: temp: max31865: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: temp: ltc2983: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: resolver: ad2s90: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: resolver: ad2s1200: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: proximity: as3935: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: potentiometer: mcp4131: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: potentiometer: mcp41010: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: potentiometer: max5481: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: potentiometer: ad5272: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: potentiometer: ad5110: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: imu: mpu6050: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: imu: inv_icm42600: Fix alignment for DMA safety in buffer code.

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: imu: inv_icm42600: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: imu: fxos8700: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: gyro: fxas210002c: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: gyro: adxrs450: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: gyro: adis16130: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: gyro: adis16080: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: frequency: adrf6780: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: frequency: admv4420: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: frequency: admv1014: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: frequency: admv1013: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: frequency: adf4371: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: frequency: adf4350: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: frequency: ad9523: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: dac: ti-dac7612: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: dac: ti-dac7311: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: dac: ti-dac5571: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: dac: ti-dac082s085: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: dac: mcp4922: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: dac: ltc2688: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: dac: ad8801: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: dac: ad7303: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: dac: ad7293: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: dac: ad5791: Fix alignment for DMA saftey

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: dac: ad5770r: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: dac: ad5766: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: dac: ad5764: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: dac: ad5761: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: dac: ad5755: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: dac: ad5686: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: dac: ad5592r: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: dac: ad5504: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: dac: ad5449: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: dac: ad5421: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: dac: ad5360: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: dac: ad5064: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: common: ssp: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: amplifiers: ad8366: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: addac: ad74413r: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: adc: ti-tlc4541: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: adc: ti-ads8688: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: adc: ti-ads8344: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: adc: ti-ads7950: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: adc: ti-ads131e08: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: adc: ti-ads124s08: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: adc: ti-adc161s626: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: adc: ti-adc128s052: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: adc: ti-adc12138: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: adc: ti-adc108s102: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: adc: ti-adc084s021: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: adc: ti-adc0832: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: adc: mcp320x: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: adc: max1241: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: adc: max1118: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: adc: max11100: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: adc: max1027: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: adc: ltc2497: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: adc: ltc2496: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: adc: hi8435: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: adc: ad7949: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: adc: ad7923: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: adc: ad7887: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: adc: ad7768-1: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: adc: ad7766: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: adc: ad7606: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: adc: ad7476: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: adc: ad7298: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: adc: ad7292: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: adc: ad7280a: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: adc: ad7266: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: accel: sca3300: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: accel: sca3000: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: accel: bma220: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: accel: adxl367: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: accel: adxl355: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: accel: adxl313: Fix alignment for DMA safety

Jonathan Cameron <Jonathan.Cameron@huawei.com>
    iio: core: Fix IIO_ALIGN and rename as it was not sufficiently large

Jagath Jog J <jagathjog1996@gmail.com>
    iio: accel: bma400: conversion to device-managed function

Jagath Jog J <jagathjog1996@gmail.com>
    iio: accel: bma400: Reordering of header files

Gwendal Grignou <gwendal@chromium.org>
    iio: sx9324: Fix register field spelling

Stephen Boyd <swboyd@chromium.org>
    platform/chrome: cros_ec: Always expose last resume result

Jagath Jog J <jagathjog1996@gmail.com>
    iio: accel: bma400: Fix the scale min and max macro values

Quinn Tran <qutran@marvell.com>
    scsi: qla2xxx: edif: Reduce N2N thrashing at app_start time

Quinn Tran <qutran@marvell.com>
    scsi: qla2xxx: edif: Fix no logout on delete for N2N

Quinn Tran <qutran@marvell.com>
    scsi: qla2xxx: edif: Fix session thrash

Quinn Tran <qutran@marvell.com>
    scsi: qla2xxx: edif: Tear down session if keys have been removed

Quinn Tran <qutran@marvell.com>
    scsi: qla2xxx: edif: Fix no login after app start

Quinn Tran <qutran@marvell.com>
    scsi: qla2xxx: edif: Reduce disruption due to multiple app start

Quinn Tran <qutran@marvell.com>
    scsi: qla2xxx: edif: Send LOGO for unexpected IKE message

Thomas Gleixner <tglx@linutronix.de>
    netfilter: xtables: Bring SPDX identifier back

Tang Bin <tangbin@cmss.chinamobile.com>
    usb: xhci: tegra: Fix error check

Tang Bin <tangbin@cmss.chinamobile.com>
    usb: gadget: tegra-xudc: Fix error check in tegra_xudc_powerdomain_init()

Miaoqian Lin <linmq006@gmail.com>
    usb: ohci-nxp: Fix refcount leak in ohci_hcd_nxp_probe

Miaoqian Lin <linmq006@gmail.com>
    usb: host: Fix refcount leak in ehci_hcd_ppc_of_probe

Marco Pagani <marpagan@redhat.com>
    fpga: altera-pr-ip: fix unsigned comparison with less than zero

Miaoqian Lin <linmq006@gmail.com>
    PCI: mediatek-gen3: Fix refcount leak in mtk_pcie_init_irq_domains()

Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
    mtd: st_spi_fsm: Add a clk_disable_unprepare() in .probe()'s error path

Miaoqian Lin <linmq006@gmail.com>
    mtd: parsers: ofpart: Fix refcount leak in bcm4908_partitions_fw_offset

Miaoqian Lin <linmq006@gmail.com>
    mtd: partitions: Fix refcount leak in parse_redboot_of

Duoming Zhou <duoming@zju.edu.cn>
    mtd: sm_ftl: Fix deadlock caused by cancel_work_sync in sm_release

Harshit Mogalapalli <harshit.m.mogalapalli@oracle.com>
    HID: cp2112: prevent a buffer overflow in cp2112_xfer()

Miaoqian Lin <linmq006@gmail.com>
    PCI: tegra194: Fix PM error handling in tegra_pcie_config_ep()

Miaoqian Lin <linmq006@gmail.com>
    PCI: microchip: Fix refcount leak in mc_pcie_init_irq_domains()

Chanho Park <chanho61.park@samsung.com>
    phy: samsung: exynosautov9-ufs: correct TSRV register configurations

Sean Christopherson <seanjc@google.com>
    KVM: x86/mmu: Drop RWX=0 SPTEs during ept_sync_page()

Sean Christopherson <seanjc@google.com>
    KVM: SVM: Stuff next_rip on emulated INT3 injection if NRIPS is supported

Sean Christopherson <seanjc@google.com>
    KVM: SVM: Unwind "speculative" RIP advancement if INTn injection "fails"

Quinn Tran <qutran@marvell.com>
    scsi: qla2xxx: edif: Fix n2n login retry for secure device

Quinn Tran <qutran@marvell.com>
    scsi: qla2xxx: edif: Fix n2n discovery issue with secure target

Quinn Tran <qutran@marvell.com>
    scsi: qla2xxx: edif: Add retry for ELS passthrough

Quinn Tran <qutran@marvell.com>
    scsi: qla2xxx: edif: Synchronize NPIV deletion with authentication application

Quinn Tran <qutran@marvell.com>
    scsi: qla2xxx: edif: Fix potential stuck session in sa update

Quinn Tran <qutran@marvell.com>
    scsi: qla2xxx: edif: Add bsg interface to read doorbell events

Quinn Tran <qutran@marvell.com>
    scsi: qla2xxx: edif: Wait for app to ack on sess down

Quinn Tran <qutran@marvell.com>
    scsi: qla2xxx: edif: bsg refactor

Quinn Tran <qutran@marvell.com>
    scsi: qla2xxx: edif: Reduce Initiator-Initiator thrashing

Vaibhav Jain <vaibhav@linux.ibm.com>
    of: check previous kernel's ima-kexec-buffer against memory bounds

Biju Das <biju.das.jz@bp.renesas.com>
    clk: renesas: rzg2l: Fix reset status function

Christophe JAILLET <christophe.jaillet@wanadoo.fr>
    mtd: rawnand: meson: Fix a potential double free issue

Miaoqian Lin <linmq006@gmail.com>
    mtd: maps: Fix refcount leak in ap_flash_init

Miaoqian Lin <linmq006@gmail.com>
    mtd: maps: Fix refcount leak in of_flash_probe_versatile

Ralph Siemsen <ralph.siemsen@linaro.org>
    clk: renesas: r9a06g032: Fix UART clkgrp bitsel

Mario Limonciello <mario.limonciello@amd.com>
    HID: amd_sfh: Don't show client init failed as error when discovery fails

Jason A. Donenfeld <Jason@zx2c4.com>
    wireguard: allowedips: don't corrupt stack when detecting overflow

Jason A. Donenfeld <Jason@zx2c4.com>
    wireguard: ratelimiter: use hrtimer in selftest

Maxim Mikityanskiy <maximmi@nvidia.com>
    net/mlx5e: xsk: Discard unaligned XSK frames on striding RQ

Maciej Żenczykowski <maze@google.com>
    net: usb: make USB_RTL8153_ECM non user configurable

Hangyu Hua <hbh25y@gmail.com>
    dccp: put dccp_qpolicy_full() and dccp_qpolicy_push() in the same lock

Jian Shen <shenjian15@huawei.com>
    net: ionic: fix error check for vlan flags in ionic_set_nic_features()

Jian Shen <shenjian15@huawei.com>
    net: ice: fix error NETIF_F_HW_VLAN_CTAG_FILTER check in ice_vsi_sync_fltr()

Eric Dumazet <edumazet@google.com>
    net: rose: fix netdev reference changes

Jakub Kicinski <kuba@kernel.org>
    netdevsim: Avoid allocation warnings triggered from user space

Przemyslaw Patynowski <przemyslawx.patynowski@intel.com>
    iavf: Fix 'tc qdisc show' listing too many queues

Przemyslaw Patynowski <przemyslawx.patynowski@intel.com>
    iavf: Fix max_rate limiting

William Dean <williamsukatube@gmail.com>
    wifi: rtw88: check the return value of alloc_workqueue()

Ido Schimmel <idosch@nvidia.com>
    netdevsim: fib: Fix reference count leak on route deletion failure

Mike Manning <mvrmanning@gmail.com>
    net: allow unbound socket for packets in VRF when tcp_l3mdev_accept set

Eric Dumazet <edumazet@google.com>
    ipv6: add READ_ONCE(sk->sk_bound_dev_if) in INET6_MATCH()

Eric Dumazet <edumazet@google.com>
    inet: add READ_ONCE(sk->sk_bound_dev_if) in INET_MATCH()

Kai Ye <yekai13@huawei.com>
    crypto: hisilicon/sec - fix auth key size error

Pali Rohár <pali@kernel.org>
    crypto: inside-secure - Add missing MODULE_DEVICE_TABLE for of

Zhengchao Shao <shaozhengchao@huawei.com>
    crypto: hisilicon/hpre - don't use GFP_KERNEL to alloc mem during softirq

Eric Dumazet <edumazet@google.com>
    ax25: fix incorrect dev_tracker usage

Shay Drory <shayd@nvidia.com>
    net/mlx5: Fix driver use of uninitialized timeout

Yevgeny Kliteynik <kliteyn@nvidia.com>
    net/mlx5: DR, Fix SMFS steering info dump format

Maher Sanalla <msanalla@nvidia.com>
    net/mlx5: Adjust log_max_qp to be 18 at most

Vlad Buslov <vladbu@nvidia.com>
    net/mlx5e: Modify slow path rules to go to slow fdb

Maxim Mikityanskiy <maximmi@nvidia.com>
    net/mlx5e: Fix calculations related to max MPWQE size

Maxim Mikityanskiy <maximmi@nvidia.com>
    net/mlx5e: xsk: Account for XSK RQ UMRs when calculating ICOSQ size

Maxim Mikityanskiy <maximmi@nvidia.com>
    net/mlx5e: Fix the value of MLX5E_MAX_RQ_NUM_MTTS

Maor Dickman <maord@nvidia.com>
    net/mlx5e: TC, Fix post_act to not match on in_port metadata

Gal Pressman <gal@nvidia.com>
    net/mlx5e: Remove WARN_ON when trying to offload an unsupported TLS cipher/version

Dan Carpenter <dan.carpenter@oracle.com>
    drm/amd/display: fix signedness bug in execute_synaptics_rc_command()

Ezequiel Garcia <ezequiel@vanguardiasur.com.ar>
    hantro: Remove incorrect HEVC SPS validation

Jernej Skrabec <jernej.skrabec@gmail.com>
    media: cedrus: hevc: Add check for invalid timestamp

Hangyu Hua <hbh25y@gmail.com>
    wifi: libertas: Fix possible refcount leak in if_usb_probe()

Jose Ignacio Tornos Martinez <jtornosm@redhat.com>
    wifi: iwlwifi: mvm: fix double list_add at iwl_mvm_mac_wake_tx_queue

Ammar Faizi <ammarfaizi2@gnuweeb.org>
    wifi: wil6210: debugfs: fix uninitialized variable use in `wil_write_file_wmi()`

Liang He <windhl@126.com>
    i2c: mux-gpmux: Add of_node_put() when breaking out of loop

Joanne Koong <joannelkoong@gmail.com>
    bpf: Fix bpf_xdp_pointer return pointer

Bjorn Andersson <bjorn.andersson@linaro.org>
    i2c: qcom-geni: Use the correct return value

Lars-Peter Clausen <lars@metafoo.de>
    i2c: cadence: Support PEC for SMBus block read

Ying Hsu <yinghsu@chromium.org>
    Bluetooth: Add default wakeup callback for HCI UART driver

Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
    Bluetooth: hci_sync: Fix not updating privacy_mode

Zhengping Jiang <jiangzp@google.com>
    Bluetooth: hci_sync: Fix resuming scan after suspend resume

Zhengping Jiang <jiangzp@google.com>
    Bluetooth: mgmt: Fix refresh cached connection info

Schspa Shi <schspa@gmail.com>
    Bluetooth: When HCI work queue is drained, only queue chained work

Jiasheng Jiang <jiasheng@iscas.ac.cn>
    Bluetooth: hci_intel: Add check for platform_driver_register

Vincent Mailhol <mailhol.vincent@wanadoo.fr>
    can: pch_can: pch_can_error(): initialize errc before using it

Vincent Mailhol <mailhol.vincent@wanadoo.fr>
    can: error: specify the values of data[5..7] of CAN error frames

Vincent Mailhol <mailhol.vincent@wanadoo.fr>
    can: usb_8dev: do not report txerr and rxerr during bus-off

Vincent Mailhol <mailhol.vincent@wanadoo.fr>
    can: kvaser_usb_leaf: do not report txerr and rxerr during bus-off

Vincent Mailhol <mailhol.vincent@wanadoo.fr>
    can: kvaser_usb_hydra: do not report txerr and rxerr during bus-off

Vincent Mailhol <mailhol.vincent@wanadoo.fr>
    can: sun4i_can: do not report txerr and rxerr during bus-off

Vincent Mailhol <mailhol.vincent@wanadoo.fr>
    can: hi311x: do not report txerr and rxerr during bus-off

Vincent Mailhol <mailhol.vincent@wanadoo.fr>
    can: sja1000: do not report txerr and rxerr during bus-off

Vincent Mailhol <mailhol.vincent@wanadoo.fr>
    can: rcar_can: do not report txerr and rxerr during bus-off

Vincent Mailhol <mailhol.vincent@wanadoo.fr>
    can: pch_can: do not report txerr and rxerr during bus-off

Dan Carpenter <dan.carpenter@oracle.com>
    libbpf: fix an snprintf() overflow check

Dan Carpenter <dan.carpenter@oracle.com>
    selftests/bpf: fix a test for snprintf() overflow

Andrii Nakryiko <andrii@kernel.org>
    bpf: fix potential 32-bit overflow when accessing ARRAY map element

Kumar Kartikeya Dwivedi <memxor@gmail.com>
    bpf: Wire up freeing of referenced kptr

Kumar Kartikeya Dwivedi <memxor@gmail.com>
    bpf: Populate pairs of btf_id and destructor kfunc in btf

Kumar Kartikeya Dwivedi <memxor@gmail.com>
    bpf: Adapt copy_map_value for multiple offset case

Kumar Kartikeya Dwivedi <memxor@gmail.com>
    bpf: Allow storing referenced kptr in map

Kumar Kartikeya Dwivedi <memxor@gmail.com>
    bpf: Tag argument to be released in bpf_func_proto

Kumar Kartikeya Dwivedi <memxor@gmail.com>
    bpf: Allow storing unreferenced kptr in map

Kumar Kartikeya Dwivedi <memxor@gmail.com>
    bpf: Move check_ptr_off_reg before check_map_access

Kumar Kartikeya Dwivedi <memxor@gmail.com>
    bpf: Make btf_find_field more generic

Alex Deucher <alexander.deucher@amd.com>
    drm/amdgpu: restore original stable pstate on ctx fini

Christian König <christian.koenig@amd.com>
    drm/amdgpu: cleanup ctx implementation

Alex Deucher <alexander.deucher@amd.com>
    drm/amdgpu: use the same HDP flush registers for all nbio 2.3.x

Alex Deucher <alexander.deucher@amd.com>
    drm/amdgpu: use the same HDP flush registers for all nbio 7.4.x

Rustam Subkhankulov <subkhankulov@ispras.ru>
    wifi: p54: add missing parentheses in p54_flush()

Christophe JAILLET <christophe.jaillet@wanadoo.fr>
    wifi: p54: Fix an error handling path in p54spi_probe()

Dan Carpenter <dan.carpenter@oracle.com>
    wifi: wil6210: debugfs: fix info leak in wil_write_file_wmi()

Jernej Skrabec <jernej.skrabec@gmail.com>
    media: cedrus: h265: Fix logic for not low delay flag

Benjamin Gaignard <benjamin.gaignard@collabora.com>
    media: uapi: HEVC: Change pic_order_cnt definition in v4l2_hevc_dpb_entry

Jernej Skrabec <jernej.skrabec@gmail.com>
    media: cedrus: h265: Fix flag name

Jason A. Donenfeld <Jason@zx2c4.com>
    fs: check FMODE_LSEEK to control internal pipe splicing

Alexei Starovoitov <ast@kernel.org>
    bpf: Fix subprog names in stack traces.

Wolfram Sang <wsa+renesas@sang-engineering.com>
    selftests: timers: clocksource-switch: fix passing errors from child

Wolfram Sang <wsa+renesas@sang-engineering.com>
    selftests: timers: valid-adjtimex: build fix for newer toolchains

David Gow <davidgow@google.com>
    kunit: executor: Fix a memory leak on failure in kunit_filter_tests

Anquan Wu <leiqi96@hotmail.com>
    libbpf: Fix the name of a reused map

Yonglong Li <liyonglong@chinatelecom.cn>
    tcp: make retransmitted SKB fit into the send window

Song Liu <song@kernel.org>
    bpf, x86: fix freeing of not-finalized bpf_prog_pack

Tony Ambardar <tony.ambardar@gmail.com>
    bpf, x64: Add predicate for bpf2bpf with tailcalls support in JIT

Kui-Feng Lee <kuifeng@fb.com>
    bpf, x86: Generate trampolines from bpf_tramp_links

Milan Landaverde <milan@mdaverde.com>
    bpftool: Add missing link types

Jian Zhang <zhangjian210@huawei.com>
    drm/exynos/exynos7_drm_decon: free resources when clk_set_parent() failed.

Liu Jian <liujian56@huawei.com>
    skmsg: Fix invalid last sg check in sk_msg_recvmsg()

Liang He <windhl@126.com>
    mediatek: mt76: eeprom: fix missing of_node_put() in mt76_find_power_limits_node()

Liang He <windhl@126.com>
    mediatek: mt76: mac80211: Fix missing of_node_put() in mt76_led_init()

Felix Fietkau <nbd@nbd.name>
    mt76: mt7615: fix throughput regression on DFS channels

Deren Wu <deren.wu@mediatek.com>
    mt76: mt7921: enlarge maximum VHT MPDU length to 11454

Deren Wu <deren.wu@mediatek.com>
    mt76: mt7921: fix aggregation subframes setting to HE max

Deren Wu <deren.wu@mediatek.com>
    mt76: mt7921s: fix possible sdio deadlock in command fail

Lorenzo Bianconi <lorenzo@kernel.org>
    mt76: mt7921: do not update pm states in case of error

Lorenzo Bianconi <lorenzo@kernel.org>
    mt76: mt7615: do not update pm stats in case of error

YN Chen <yn.chen@mediatek.com>
    mt76: mt7921s: fix firmware download random fail

Lorenzo Bianconi <lorenzo@kernel.org>
    mt76: mt76x02u: fix possible memory leak in __mt76x02u_mcu_send_msg

Ming Qian <ming.qian@nxp.com>
    media: amphion: only insert the first sequence startcode for vc1l format

Ming Qian <ming.qian@nxp.com>
    media: amphion: sync buffer status with firmware during abort

Ming Qian <ming.qian@nxp.com>
    media: amphion: decoder copy timestamp from output to capture

Ezequiel Garcia <ezequiel@vanguardiasur.com.ar>
    media: hantro: Fix RK3399 H.264 format advertising

Benjamin Gaignard <benjamin.gaignard@collabora.com>
    media: hantro: Be more accurate on pixel formats step_width constraints

Benjamin Gaignard <benjamin.gaignard@collabora.com>
    media: hantro: HEVC: Fix reference frames management

Benjamin Gaignard <benjamin.gaignard@collabora.com>
    media: hantro: HEVC: Fix output frame chroma offset

Sebastian Fricke <sebastian.fricke@collabora.com>
    media: staging: media: hantro: Fix typos

Piotr Oniszczuk <piotr.oniszczuk@gmail.com>
    media: hantro: Add support for Hantro G1 on RK356x

Ming Qian <ming.qian@nxp.com>
    media: amphion: defer setting last_buffer_dequeued until resolution changes are processed

Chen-Yu Tsai <wenst@chromium.org>
    media: mediatek: vcodec: Initialize decoder parameters for each instance

Rob Clark <robdclark@chromium.org>
    drm/msm/dpu: Fix for non-visible planes

Ming Qian <ming.qian@nxp.com>
    media: amphion: release core lock before reset vpu core

AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
    media: platform: mtk-mdp: Fix mdp_ipi_comm structure alignment

Zhengchao Shao <shaozhengchao@huawei.com>
    crypto: hisilicon - Kunpeng916 crypto driver don't sleep when in softirq

Zhengchao Shao <shaozhengchao@huawei.com>
    crypto: hisilicon/sec - don't sleep when in softirq

Mateusz Jończyk <mat.jonczyk@o2.pl>
    drm/radeon: avoid bogus "vram limit (0) must be a power of 2" warning

Rob Clark <robdclark@chromium.org>
    drm/msm/mdp5: Fix global state lock backoff

Yixun Lan <dlan@gentoo.org>
    libbpf, riscv: Use a0 for RC register

Douglas Anderson <dianders@chromium.org>
    drm/msm: Avoid unclocked GMU register access in 6xx gpu_busy

Hsin-Yi Wang <hsinyi@chromium.org>
    drm/bridge: anx7625: Fix NULL pointer crash when using edp-panel

Qiao Ma <mqaio@linux.alibaba.com>
    net: hinic: avoid kernel hung in hinic_get_stats64()

Qiao Ma <mqaio@linux.alibaba.com>
    net: hinic: fix bug that ethtool get wrong stats

Christophe JAILLET <christophe.jaillet@wanadoo.fr>
    hinic: Use the bitmap API when applicable

Vladimir Oltean <vladimir.oltean@nxp.com>
    net: dsa: felix: build as module when tc-taprio is module

Vladimir Oltean <vladimir.oltean@nxp.com>
    net: sched: provide shim definitions for taprio_offload_{get,free}

Hangyu Hua <hbh25y@gmail.com>
    drm: bridge: sii8620: fix possible off-by-one

Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
    drm/msm/hdmi: fill the pwr_regs bulk regulators

Guillaume Ranquet <granquet@baylibre.com>
    drm/mediatek: dpi: Only enable dpi after the bridge is enabled

Bo-Chen Chen <rex-bc.chen@mediatek.com>
    drm/mediatek: dpi: Remove output format of YUV

Christophe JAILLET <christophe.jaillet@wanadoo.fr>
    drm/rockchip: Fix an error handling path rockchip_dp_probe()

Brian Norris <briannorris@chromium.org>
    drm/rockchip: vop: Don't crash for invalid duplicate_state()

Vladimir Oltean <vladimir.oltean@nxp.com>
    net: dsa: felix: drop oversized frames with tc-taprio instead of hanging the port

Vladimir Oltean <vladimir.oltean@nxp.com>
    net: dsa: felix: keep reference on entire tc-taprio config

Xiaoliang Yang <xiaoliang.yang_1@nxp.com>
    net: dsa: felix: update base time of time-aware shaper when adjusting PTP time

Vladimir Oltean <vladimir.oltean@nxp.com>
    net: mscc: ocelot: minimize holes in struct ocelot_port

Vladimir Oltean <vladimir.oltean@nxp.com>
    net: mscc: ocelot: delete ocelot_port :: xmit_template

Maciej Fijalkowski <maciej.fijalkowski@intel.com>
    selftests/xsk: Destroy BPF resources only when ctx refcount drops to 0

Qian Cai <quic_qiancai@quicinc.com>
    crypto: arm64/gcm - Select AEAD for GHASH_ARM64_CE

Matthew Wilcox (Oracle) <willy@infradead.org>
    mm: Account dirty folios properly during splits

Dave Stevenson <dave.stevenson@raspberrypi.com>
    drm/vc4: hdmi: Move pixel doubling from Pixelvalve to HDMI block

Dave Stevenson <dave.stevenson@raspberrypi.com>
    drm/vc4: hdmi: Correct HDMI timing registers for interlaced modes

Mateusz Kwiatkowski <kfyatek+publicgit@gmail.com>
    drm/vc4: hdmi: Fix timings for interlaced modes

Dave Stevenson <dave.stevenson@raspberrypi.com>
    drm/vc4: hdmi: Move HDMI reset to pm_resume

Dave Stevenson <dave.stevenson@raspberrypi.com>
    drm/vc4: hdmi: Switch to pm_runtime_status_suspended

Dave Stevenson <dave.stevenson@raspberrypi.com>
    drm/vc4: hdmi: Reset HDMI MISC_CONTROL register

Dom Cobley <popcornmix@gmail.com>
    drm/vc4: hdmi: Avoid full hdmi audio fifo writes

Dom Cobley <popcornmix@gmail.com>
    drm/vc4: hdmi: Clear unused infoframe packet RAM registers

Dave Stevenson <dave.stevenson@raspberrypi.com>
    drm/vc4: hdmi: Add all the vc5 HDMI registers into the debugfs dumps

Dave Stevenson <dave.stevenson@raspberrypi.com>
    drm/vc4: dsi: Add correct stop condition to vc4_dsi_encoder_disable iteration

Dave Stevenson <dave.stevenson@raspberrypi.com>
    drm/vc4: dsi: Fix dsi0 interrupt support

Dave Stevenson <dave.stevenson@raspberrypi.com>
    drm/vc4: dsi: Register dsi0 as the correct vc4 encoder type

Dave Stevenson <dave.stevenson@raspberrypi.com>
    drm/vc4: dsi: Correct pixel order for DSI0

Dave Stevenson <dave.stevenson@raspberrypi.com>
    drm/vc4: dsi: Correct DSI divider calculations

Dave Stevenson <dave.stevenson@raspberrypi.com>
    drm/vc4: dsi: Release workaround buffer and DMA

Dave Stevenson <dave.stevenson@raspberrypi.com>
    drm/vc4: plane: Fix margin calculations for the right/bottom edges

Dom Cobley <popcornmix@gmail.com>
    drm/vc4: plane: Remove subpixel positioning check

Maxime Ripard <maxime@cerno.tech>
    drm/vc4: kms: Use maximum FIFO load for the HVS clock rate

Yunfei Dong <yunfei.dong@mediatek.com>
    media: mediatek: vcodec: Fix non subdev architecture open power fail

Miaoqian Lin <linmq006@gmail.com>
    media: tw686x: Fix memory leak in tw686x_video_init

Jian Zhang <zhangjian210@huawei.com>
    media: driver/nxp/imx-jpeg: fix a unexpected return value problem

Chen-Yu Tsai <wenst@chromium.org>
    media: mediatek: vcodec: Skip SOURCE_CHANGE & EOS events for stateless

Yunfei Dong <yunfei.dong@mediatek.com>
    media: mediatek: vcodec: Initialize decoder parameters after getting dec_capability

Arnd Bergmann <arnd@arndb.de>
    media: sta2x11: remove VIRT_TO_BUS dependency

Ming Qian <ming.qian@nxp.com>
    media: v4l2-mem2mem: prevent pollerr when last_buffer_dequeued is set

Niels Dossche <dossche.niels@gmail.com>
    media: hdpvr: fix error value returns in hdpvr_read

Miaoqian Lin <linmq006@gmail.com>
    drm/mcde: Fix refcount leak in mcde_dsi_bind

Ming Qian <ming.qian@nxp.com>
    media: amphion: output firmware error message

Ming Qian <ming.qian@nxp.com>
    media: imx-jpeg: Disable slot interrupt when frame done

Jiasheng Jiang <jiasheng@iscas.ac.cn>
    drm: bridge: adv7511: Add check for mipi_dsi_driver_register

Tom Lendacky <thomas.lendacky@amd.com>
    crypto: ccp - During shutdown, check SEV data pointer before using

Jörn-Thorben Hinz <jthinz@mailbox.tu-berlin.de>
    selftests/bpf: Fix rare segfault in sock_fields prog test

Jian Shen <shenjian15@huawei.com>
    test_bpf: fix incorrect netdev features

Frederic Weisbecker <frederic@kernel.org>
    rcutorture: Fix ksoftirqd boosting timing and iteration

Paul E. McKenney <paulmck@kernel.org>
    torture: Adjust to again produce debugging information

Paul E. McKenney <paulmck@kernel.org>
    rcutorture: Make kvm.sh allow more memory for --kasan runs

Alex Deucher <alexander.deucher@amd.com>
    drm/radeon: fix incorrrect SPDX-License-Identifiers

Ping-Ke Shih <pkshih@realtek.com>
    wifi: rtw89: 8852a: rfk: fix div 0 exception

Alexey Kodanev <aleksei.kodanev@bell-sw.com>
    wifi: iwlegacy: 4965: fix potential off-by-one overflow in il4965_rs_fill_link_cmd()

Pavel Skripkin <paskripkin@gmail.com>
    ath9k: fix use-after-free in ath9k_hif_usb_rx_cb

Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
    media: rcar-vin: Fix channel routing for Ebisu

Ming Qian <ming.qian@nxp.com>
    media: imx-jpeg: Implement drain using v4l2-mem2mem helpers

Ming Qian <ming.qian@nxp.com>
    media: imx-jpeg: Align upwards buffer size

Ming Qian <ming.qian@nxp.com>
    media: imx-jpeg: Support dynamic resolution change

Ming Qian <ming.qian@nxp.com>
    media: imx-jpeg: Handle source change in a function

Ming Qian <ming.qian@nxp.com>
    media: imx-jpeg: Identify and handle precision correctly

Ming Qian <ming.qian@nxp.com>
    media: imx-jpeg: Refactor function mxc_jpeg_parse

Ming Qian <ming.qian@nxp.com>
    media: imx-jpeg: Leave a blank space before the configuration data

Ming Qian <ming.qian@nxp.com>
    media: imx-jpeg: Correct some definition according specification

Benjamin Gaignard <benjamin.gaignard@collabora.com>
    media: Hantro: Correct G2 init qp field

Ming Qian <ming.qian@nxp.com>
    media: amphion: return error if format is unsupported by vpu

Zheyu Ma <zheyuma97@gmail.com>
    media: tw686x: Register the irq at the end of probe

Yang Yingliang <yangyingliang@huawei.com>
    media: camss: csid: fix wrong size passed to devm_kmalloc_array()

Eugen Hristev <eugen.hristev@microchip.com>
    media: atmel: atmel-sama7g5-isc: fix warning in configs without OF

Kuniyuki Iwashima <kuniyu@amazon.com>
    raw: Fix mixed declarations error in raw_icmp_error().

Eric Dumazet <edumazet@google.com>
    raw: convert raw sockets to RCU

Eric Dumazet <edumazet@google.com>
    raw: use more conventional iterators

Oleksij Rempel <linux@rempel-privat.de>
    net: ag71xx: fix discards 'const' qualifier warning

Alexey Khoroshilov <khoroshilov@ispras.ru>
    crypto: sun8i-ss - fix infinite loop in sun8i_ss_setup_ivs()

Eric Dumazet <edumazet@google.com>
    tcp: fix possible freeze in tx path under memory pressure

Xu Wang <vulab@iscas.ac.cn>
    i2c: Fix a potential use after free

Zheng Bin <zhengbin13@huawei.com>
    drm/bridge: it6505: Add missing CRYPTO_HASH dependency

Marc Kleine-Budde <mkl@pengutronix.de>
    can: netlink: allow configuring of fixed data bit rates without need for do_set_data_bittiming callback

Tales Lelo da Aparecida <tales.aparecida@gmail.com>
    drm/vkms: check plane_composer->map[0] before using it

Marc Kleine-Budde <mkl@pengutronix.de>
    can: netlink: allow configuring of fixed bit rates without need for do_set_bittiming callback

Eric Dumazet <edumazet@google.com>
    net: fix sk_wmem_schedule() and sk_rmem_schedule() errors

Dan Carpenter <dan.carpenter@oracle.com>
    crypto: sun8i-ss - fix error codes in allocate_flows()

Corentin Labbe <clabbe@baylibre.com>
    crypto: sun8i-ss - do not allocate memory when handling hash requests

Antonio Borneo <antonio.borneo@foss.st.com>
    drm: adv7511: override i2c address of cec before accessing it

Miaoqian Lin <linmq006@gmail.com>
    drm/virtio: Fix NULL vs IS_ERR checking in virtio_gpu_object_shmem_init

Xiaomeng Tong <xiam0nd.tong@gmail.com>
    virtio-gpu: fix a missing check to avoid NULL dereference

Fabio Estevam <festevam@gmail.com>
    i2c: mxs: Silence a clang warning

Tali Perry <tali.perry1@gmail.com>
    i2c: npcm: Correct slave role behavior

Tali Perry <tali.perry1@gmail.com>
    i2c: npcm: Remove own slave addresses 2:10

Bjorn Andersson <bjorn.andersson@linaro.org>
    drm/bridge: lt9611uxc: Cancel only driver's work

Miaoqian Lin <linmq006@gmail.com>
    drm/meson: encoder_hdmi: Fix refcount leak in meson_encoder_hdmi_init

Miaoqian Lin <linmq006@gmail.com>
    drm/meson: encoder_cvbs: Fix refcount leak in meson_encoder_cvbs_init

Xinlei Lee <xinlei.lee@mediatek.com>
    drm/mediatek: Add pull-down MIPI operation in mtk_dsi_poweroff function

Jitao Shi <jitao.shi@mediatek.com>
    drm/mediatek: Separate poweron/poweroff from enable/disable and define new funcs

Xinlei Lee <xinlei.lee@mediatek.com>
    drm/mediatek: Modify dsi funcs to atomic operations

Alexey Kodanev <aleksei.kodanev@bell-sw.com>
    drm/radeon: fix potential buffer overflow in ni_set_mc_special_registers()

Manikanta Pubbisetty <quic_mpubbise@quicinc.com>
    ath11k: Avoid REO CMD failed prints during firmware recovery

Manikanta Pubbisetty <quic_mpubbise@quicinc.com>
    ath11k: Fix incorrect debug_mask mappings

Christian 'Ansuel' Marangi <ansuelsmth@gmail.com>
    ath11k: fix missing skb drop on htc_tx_completion error

Martin KaFai Lau <kafai@fb.com>
    selftests/bpf: Fix tc_redirect_dtime

Yuntao Wang <ytcoode@gmail.com>
    selftests/bpf: Fix test_run logic in fexit_stress.c

Yunhao Tian <t123yh.xyz@gmail.com>
    drm/mipi-dbi: align max_chunk to 2 in spi_transfer

Johan Hovold <johan+linaro@kernel.org>
    ath11k: fix IRQ affinity warning on shutdown

Johan Hovold <johan+linaro@kernel.org>
    ath11k: fix netdev open race

Ajay Singh <ajay.kathat@microchip.com>
    wifi: wilc1000: use correct sequence of RESET for chip Power-UP/Down

Dan Carpenter <dan.carpenter@oracle.com>
    wifi: rtlwifi: fix error codes in rtl_debugfs_set_write_h2c()

Gao Chao <gaochao49@huawei.com>
    drm/panel: Fix build error when CONFIG_DRM_PANEL_SAMSUNG_ATNA33XC20=y && CONFIG_DRM_DISPLAY_HELPER=m

Javier Martinez Canillas <javierm@redhat.com>
    drm/st7735r: Fix module autoloading for Okaya RH128128T

John Stultz <jstultz@google.com>
    drm/bridge: lt9611: Use both bits for HDMI sensing

Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
    ath10k: do not enforce interrupt trigger type

Marek Vasut <marex@denx.de>
    drm/bridge: tc358767: Make sure Refclk clock are enabled

Marek Vasut <marex@denx.de>
    drm/bridge: tc358767: Move (e)DP bridge endpoint parsing into dedicated function

Douglas Anderson <dianders@chromium.org>
    drm/dp: Export symbol / kerneldoc fixes for DP AUX bus

Miaoqian Lin <linmq006@gmail.com>
    drm/meson: Fix refcount leak in meson_encoder_hdmi_init

Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
    pwm: lpc18xx: Fix period handling

Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
    pwm: sifive: Shut down hardware only after pwmchip_remove() completed

Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
    pwm: sifive: Ensure the clk is enabled exactly once per running PWM

Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
    pwm: sifive: Simplify offset calculation for PWMCMP registers

Mike Snitzer <snitzer@kernel.org>
    dm: return early from dm_pr_call() if DM device is suspended

Markus Mayer <mmayer@broadcom.com>
    thermal/tools/tmon: Include pthread and time headers in tmon.h

YiFei Zhu <zhuyifei@google.com>
    selftests/seccomp: Fix compile warning when CC=clang

Michal Koutný <mkoutny@suse.com>
    io_uring: Don't require reinitable percpu_ref

Marc Zyngier <maz@kernel.org>
    arm64: Expand ESR_ELx_WFx_ISS_TI to match its ARMv8.7 definition

Muneendra Kumar <muneendra.kumar@broadcom.com>
    scsi: nvme-fc: Add new routine nvme_fc_io_getuuid()

Jens Axboe <axboe@kernel.dk>
    io_uring: move to separate directory

Peter Zijlstra <peterz@infradead.org>
    x86/extable: Fix ex_handler_msr() print condition

Nicolas Saenz Julienne <nsaenzju@redhat.com>
    nohz/full, sched/rt: Fix missed tick-reenabling bug in dequeue_task_rt()

Anshuman Khandual <anshuman.khandual@arm.com>
    drivers/perf: arm_spe: Fix consistency of SYS_PMSCR_EL1.CX

Liang He <windhl@126.com>
    perf: RISC-V: Add of_node_put() when breaking out of for_each_of_cpu_node()

Xu Qiang <xuqiang36@huawei.com>
    irqdomain: Report irq number for NOMAP domains

Stephan Gerhold <stephan.gerhold@kernkonzept.com>
    ARM: dts: qcom: msm8974: Disable remoteprocs by default

Luca Weiss <luca@z3ntu.xyz>
    ARM: dts: qcom: msm8974-FP2: Add supplies for remoteprocs

Sumit Garg <sumit.garg@linaro.org>
    arm64: dts: qcom: qcs404: Fix incorrect USB2 PHYs assignment

Marijn Suijten <marijn.suijten@somainline.org>
    arm64: dts: qcom: msm8998: Make regulator voltages multiple of step-size

Parikshit Pareek <quic_ppareek@quicinc.com>
    soc: qcom: socinfo: Fix the id of SA8540P SoC

Konrad Dybcio <konrad.dybcio@somainline.org>
    soc: qcom: Make QCOM_RPMPD depend on PM

Liang He <windhl@126.com>
    regulator: of: Fix refcount leak bug in of_get_regulation_constraints()

Mikulas Patocka <mpatocka@redhat.com>
    dm writecache: count number of blocks discarded, not number of discard bios

Mikulas Patocka <mpatocka@redhat.com>
    dm writecache: count number of blocks written, not number of write bios

Mikulas Patocka <mpatocka@redhat.com>
    dm writecache: count number of blocks read, not number of read bios

Mikulas Patocka <mpatocka@redhat.com>
    dm writecache: return void from functions

Hsin-Yi Wang <hsinyi@chromium.org>
    PM: domains: Ensure genpd_debugfs_dir exists before remove

Bart Van Assche <bvanassche@acm.org>
    blktrace: Trace remapped requests correctly

Linus Walleij <linus.walleij@linaro.org>
    hwmon: (drivetemp) Add module alias

Armin Wolf <W_Armin@gmx.de>
    hwmon: (sch56xx-common) Add DMI override table

Yang Yingliang <yangyingliang@huawei.com>
    spi: tegra20-slink: fix UAF in tegra_slink_remove()

Yang Yingliang <yangyingliang@huawei.com>
    spi: Fix simplification of devm_spi_register_controller

Nandhini Srikandan <nandhini.srikandan@intel.com>
    spi: dw: Fix IP-core versions macro

Ming Lei <ming.lei@redhat.com>
    blk-mq: don't create hctx debugfs dir until q->debugfs_dir is created

Andy Shevchenko <andriy.shevchenko@linux.intel.com>
    spi: Return deferred probe error when controller isn't yet available

Gao Xiang <hsiangkao@linux.alibaba.com>
    erofs: avoid consecutive detection for Highmem memory

Yuwen Chen <chenyuwen1@meizu.com>
    erofs: wake up all waiters after z_erofs_lzma_head ready

Johan Hovold <johan+linaro@kernel.org>
    arm64: dts: qcom: sc7280: fix PCIe clock reference

Tamás Szűcs <tszucs@protonmail.ch>
    arm64: tegra: Fix SDMMC1 CD on P2888

Mikko Perttunen <mperttunen@nvidia.com>
    arm64: tegra: Mark BPMP channels as no-memory-wc

Nick Hainke <vincent@systemli.org>
    arm64: dts: mt7622: fix BPI-R64 WPS button

Johan Hovold <johan+linaro@kernel.org>
    arm64: dts: qcom: sm8250: add missing PCIe PHY clock-cells

Johan Hovold <johan+linaro@kernel.org>
    arm64: dts: qcom: sc7280: drop PCIe PHY clock index

Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
    arm64: dts: qcom: msm8996: correct #clock-cells for QMP PHY nodes

Marijn Suijten <marijn.suijten@somainline.org>
    arm64: dts: qcom: sm6125: Append -state suffix to pinctrl nodes

Marijn Suijten <marijn.suijten@somainline.org>
    arm64: dts: qcom: sm6125: Move sdc2 pinctrl from seine-pdx201 to sm6125

Eric Auger <eric.auger@redhat.com>
    ACPI: VIOT: Fix ACS setup

Chanho Park <chanho61.park@samsung.com>
    arm64: dts: exynosautov9: correct spi11 pin names

Stephane Eranian <eranian@google.com>
    perf/core: Add perf_clear_branch_entry_bitfields() helper

Sireesh Kodali <sireeshkodali1@gmail.com>
    arm64: dts: qcom: msm8916: Fix typo in pronto remoteproc node

GONG, Ruiqi <gongruiqi1@huawei.com>
    stack: Declare {randomize_,}kstack_offset to fix Sparse warnings

Kees Cook <keescook@chromium.org>
    lib: overflow: Do not define 64-bit tests on 32-bit

Yang Yingliang <yangyingliang@huawei.com>
    bus: hisi_lpc: fix missing platform_device_put() in hisi_lpc_acpi_probe()

Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
    ARM: dts: qcom: pm8841: add required thermal-sensor-cells

Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
    ARM: dts: qcom: msm8974: add required ranges to OCMEM

Miaoqian Lin <linmq006@gmail.com>
    soc: qcom: aoss: Fix refcount leak in qmp_cooling_devices_register

Miaoqian Lin <linmq006@gmail.com>
    soc: qcom: ocmem: Fix refcount leak in of_get_ocmem

Julia Lawall <Julia.Lawall@inria.fr>
    ia64: fix typos in comments

Alexander Vorwerk <alexander.vorwerk@stud.uni-goettingen.de>
    iio: core: fix a few code style issues

Jing Leng <jleng@ambarella.com>
    kbuild: Fix include path in scripts/Makefile.modpost

Luca Weiss <luca@z3ntu.xyz>
    ARM: dts: qcom-msm8974: fix irq type on blsp2_uart1

Konrad Dybcio <konrad.dybcio@somainline.org>
    ARM: dts: qcom-msm8974: Sort and clean up nodes

Konrad Dybcio <konrad.dybcio@somainline.org>
    ARM: dts: qcom-msm8974: Convert ADSP to a MMIO device

Konrad Dybcio <konrad.dybcio@somainline.org>
    ARM: dts: qcom-msm8974-castor: Use &labels

Konrad Dybcio <konrad.dybcio@somainline.org>
    ARM: dts: qcom-msm8974-{"hon","am"}ami: Commonize and modernize the DTs

Konrad Dybcio <konrad.dybcio@somainline.org>
    ARM: dts: qcom-msm8974-klte: Use &labels

Konrad Dybcio <konrad.dybcio@somainline.org>
    ARM: dts: qcom-msm8974-lge-nexus5: Use &labels

Konrad Dybcio <konrad.dybcio@somainline.org>
    ARM: dts: qcom-msm8974-fp2: Use &labels

Konrad Dybcio <konrad.dybcio@somainline.org>
    ARM: dts: qcom-apq8074-dragonboard: Use &labels

Konrad Dybcio <konrad.dybcio@somainline.org>
    ARM: dts: qcom-msm8974*: Rename msmgpio to tlmm

Konrad Dybcio <konrad.dybcio@somainline.org>
    ARM: dts: qcom-msm8974: Fix up SDHCI nodes

Konrad Dybcio <konrad.dybcio@somainline.org>
    ARM: dts: qcom-msm8974: Fix up mdss nodes

Konrad Dybcio <konrad.dybcio@somainline.org>
    ARM: dts: qcom-msm8974*: Fix I2C labels

Konrad Dybcio <konrad.dybcio@somainline.org>
    ARM: dts: qcom-msm8974*: Fix UART naming

Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
    ARM: dts: qcom: do not use underscore in node name

Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
    ARM: dts: qcom: msm8974-samsung-klte: move gpio-keys out of soc

Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
    ARM: dts: qcom: msm8974-lge-nexus5: move gpio-keys out of soc

Dan Williams <dan.j.williams@intel.com>
    ACPI: APEI: Fix _EINJ vs EFI_MEMORY_SP

Stephan Gerhold <stephan.gerhold@kernkonzept.com>
    regulator: qcom_smd: Fix pm8916_pldo range

Chris Paterson <chris.paterson2@renesas.com>
    arm64: dts: renesas: r9a07g054l2-smarc: Correct SoC name in comment

Geert Uytterhoeven <geert+renesas@glider.be>
    arm64: dts: renesas: r8a779m8: Drop operating points above 1.5 GHz

Miaoqian Lin <linmq006@gmail.com>
    cpufreq: zynq: Fix refcount leak in zynq_get_revision

Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
    arm64: dts: qcom: sdm636-sony-xperia-ganges-mermaid: correct sdc2 pinconf

Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
    arm64: dts: qcom: sdm630: fix gpu's interconnect path

Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
    arm64: dts: qcom: sdm630: fix the qusb2phy ref clock

Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
    arm64: dts: qcom: sdm630: disable GPU by default

Miaoqian Lin <linmq006@gmail.com>
    ARM: OMAP2+: Fix refcount leak in omap3xxx_prm_late_init

Miaoqian Lin <linmq006@gmail.com>
    ARM: OMAP2+: Fix refcount leak in omapdss_init_of

Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
    ARM: dts: qcom: mdm9615: add missing PMIC GPIO reg

Marijn Suijten <marijn.suijten@somainline.org>
    arm64: dts: qcom: sdm845-akatsuki: Round down l22a regulator voltage

Keith Busch <kbusch@kernel.org>
    block: fix infinite loop for invalid zone append

Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
    spi: s3c64xx: constify fsd_spi_port_config

Michael Walle <michael@walle.cc>
    soc: fsl: guts: machine variable might be unset

Stephen Boyd <swboyd@chromium.org>
    arm64: dts: qcom: sc7180: Remove ipa_fw_mem node on trogdor

Peter Zijlstra <peterz@infradead.org>
    locking/lockdep: Fix lockdep_init_map_*() confusion

Alexandru Elisei <alexandru.elisei@arm.com>
    arm64: cpufeature: Allow different PMU versions in ID_DFR0_EL1

Mark Rutland <mark.rutland@arm.com>
    arm64: select TRACE_IRQFLAGS_NMI_SUPPORT

Nícolas F. R. A. Prado <nfraprado@collabora.com>
    arm64: dts: mt8192: Fix idle-states entry-method

Nícolas F. R. A. Prado <nfraprado@collabora.com>
    arm64: dts: mt8192: Fix idle-states nodes naming scheme

Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
    ARM: dts: ast2600-evb-a1: fix board compatible

Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
    ARM: dts: ast2600-evb: fix board compatible

Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
    ARM: dts: ast2500-evb: fix board compatible

Johan Hovold <johan@kernel.org>
    x86/pmem: Fix platform-device leak in error path

Max Krummenacher <max.krummenacher@toradex.com>
    Revert "ARM: dts: imx6qdl-apalis: Avoid underscore in node name"

Geert Uytterhoeven <geert+renesas@glider.be>
    arm64: dts: renesas: Fix thermal-sensors on single-zone sensors

Liang He <windhl@126.com>
    soc: amlogic: Fix refcount leak in meson-secure-pwrc.c

Geert Uytterhoeven <geert+renesas@glider.be>
    soc: renesas: r8a779a0-sysc: Fix A2DP1 and A2CV[2357] PDR values

Marcel Ziswiler <marcel.ziswiler@toradex.com>
    ARM: dts: imx7d-colibri-emmc: add cpu1 supply

Guilherme G. Piccoli <gpiccoli@igalia.com>
    ACPI: processor/idle: Annotate more functions to live in cpuidle section

Miaoqian Lin <linmq006@gmail.com>
    ARM: bcm: Fix refcount leak in bcm_kona_smc_init

Christophe JAILLET <christophe.jaillet@wanadoo.fr>
    spi: spi-altera-dfl: Fix an error handling path

Geert Uytterhoeven <geert+renesas@glider.be>
    arm64: dts: renesas: beacon: Fix regulator node names

Miaoqian Lin <linmq006@gmail.com>
    meson-mx-socinfo: Fix refcount leak in meson_mx_socinfo_init

Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
    ARM: findbit: fix overflowing offset

Florian Westphal <fw@strlen.de>
    netfilter: nft_queue: only allow supported familes and hooks

Biju Das <biju.das.jz@bp.renesas.com>
    spi: spi-rspi: Fix PIO fallback on RZ platforms

Michael Ellerman <mpe@ellerman.id.au>
    powerpc/64s: Disable stack variable initialisation for prom_init

xinhui pan <xinhui.pan@amd.com>
    drm/amdgpu: Remove one duplicated ef removal

Mario Limonciello <mario.limonciello@amd.com>
    pinctrl: Don't allow PINCTRL_AMD to be a module

Kees Cook <keescook@chromium.org>
    kasan: test: Silence GCC 12 warnings

Xiu Jianfeng <xiujianfeng@huawei.com>
    selinux: Add boundary check in put_entry()

Xiu Jianfeng <xiujianfeng@huawei.com>
    selinux: fix memleak in security_read_state_kernel()

Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
    PM: hibernate: defer device probing when resuming from hibernation

Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
    hwmon: (sht15) Fix wrong assumptions in device remove callback

Hans de Goede <hdegoede@redhat.com>
    ACPI: video: Use native backlight on Dell Inspiron N4010

Armin Wolf <W_Armin@gmx.de>
    hwmon: (dell-smm) Add Dell XPS 13 7390 to fan control whitelist

Lv Ruyi <lv.ruyi@zte.com.cn>
    firmware: tegra: Fix error check return value of debugfs_create_file()

Liang He <windhl@126.com>
    ARM: shmobile: rcar-gen2: Increase refcount for new reference

Samuel Holland <samuel@sholland.org>
    arm64: dts: allwinner: a64: orangepi-win: Fix LED node name

Robert Marko <robimarko@gmail.com>
    arm64: dts: qcom: ipq8074: fix NAND node name

Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
    arm64: dts: qcom: add missing AOSS QMP compatible fallback

Manivannan Sadhasivam <mani@kernel.org>
    ARM: dts: qcom: sdx55: Fix the IRQ trigger type for UART

huhai <huhai@kylinos.cn>
    ACPI: LPSS: Fix missing check in register_device_clock()

Manyi Li <limanyi@uniontech.com>
    ACPI: PM: save NVS memory for Lenovo G40-45

Hans de Goede <hdegoede@redhat.com>
    ACPI: EC: Drop the EC_FLAGS_IGNORE_DSDT_GPE quirk

Hans de Goede <hdegoede@redhat.com>
    ACPI: EC: Remove duplicate ThinkPad X1 Carbon 6th entry from DMI quirks

Liang He <windhl@126.com>
    ARM: OMAP2+: pdata-quirks: Fix refcount leak bug

Liang He <windhl@126.com>
    ARM: OMAP2+: display: Fix refcount leak bug

Guo Mengqi <guomengqi3@huawei.com>
    spi: synquacer: Add missing clk_disable_unprepare()

David Heidelberg <david@ixit.cz>
    arm64: dts: qcom: timer should use only 32-bit size

Linus Walleij <linus.walleij@linaro.org>
    ARM: dts: ux500: Fix Gavini accelerometer mounting matrix

Linus Walleij <linus.walleij@linaro.org>
    ARM: dts: ux500: Fix Codina accelerometer mounting matrix

Linus Walleij <linus.walleij@linaro.org>
    ARM: dts: ux500: Fix Janice accelerometer mounting matrix

Christian Lamparter <chunkeey@gmail.com>
    ARM: dts: BCM5301X: Add DT for Meraki MR26

Alexander Stein <alexander.stein@ew.tq-group.com>
    ARM: dts: imx6ul: fix qspi node compatible

Alexander Stein <alexander.stein@ew.tq-group.com>
    ARM: dts: imx6ul: fix lcdif node compatible

Alexander Stein <alexander.stein@ew.tq-group.com>
    ARM: dts: imx6ul: fix csi node compatible

Alexander Stein <alexander.stein@ew.tq-group.com>
    ARM: dts: imx6ul: fix keypad compatible

Alexander Stein <alexander.stein@ew.tq-group.com>
    ARM: dts: imx6ul: change operating-points to uint32-matrix

Alexander Stein <alexander.stein@ew.tq-group.com>
    ARM: dts: imx6ul: add missing properties for sram

Juri Lelli <juri.lelli@redhat.com>
    wait: Fix __wait_event_hrtimeout for RT/DL tasks

William Dean <williamsukatube@163.com>
    irqchip/mips-gic: Check the return value of ioremap() in gic_of_init()

John Keeping <john@metanate.com>
    sched/core: Always flush pending blk_plug

Vincent Guittot <vincent.guittot@linaro.org>
    sched/fair: fix case with reduced capacity CPU

Samuel Holland <samuel@sholland.org>
    genirq: GENERIC_IRQ_IPI depends on SMP

Samuel Holland <samuel@sholland.org>
    irqchip/mips-gic: Only register IPI domain when SMP is enabled

Antonio Borneo <antonio.borneo@foss.st.com>
    genirq: Don't return error on missing optional irq_request_resources()

Chen Yu <yu.c.chen@intel.com>
    sched/fair: Introduce SIS_UTIL to search idle CPU based on sum of util_avg

Jan Kara <jack@suse.cz>
    ext2: Add more validity checks for inode counts

James Morse <james.morse@arm.com>
    arm64: errata: Remove AES hwcap for COMPAT tasks

Catalin Marinas <catalin.marinas@arm.com>
    arm64: kasan: Revert "arm64: mte: reset the page tag in page->flags"

haibinzhang (张海斌) <haibinzhang@tencent.com>
    arm64: fix oops in concurrently setting insn_emulation sysctls

Francis Laniel <flaniel@linux.microsoft.com>
    arm64: Do not forget syscall when starting a new thread.

Mark Rutland <mark.rutland@arm.com>
    arch: make TRACE_IRQFLAGS_NMI_SUPPORT generic

Wyes Karny <wyes.karny@amd.com>
    x86: Handle idle=nomwait cmdline properly for x86_idle

Benjamin Segall <bsegall@google.com>
    epoll: autoremove wakers even more aggressively

Florian Westphal <fw@strlen.de>
    netfilter: nf_tables: fix null deref due to zeroed list head

Thadeu Lima de Souza Cascardo <cascardo@canonical.com>
    netfilter: nf_tables: do not allow RULE_ID to refer to another chain

Thadeu Lima de Souza Cascardo <cascardo@canonical.com>
    netfilter: nf_tables: do not allow CHAIN_ID to refer to another table

Thadeu Lima de Souza Cascardo <cascardo@canonical.com>
    netfilter: nf_tables: do not allow SET_ID to refer to another table

Michael Grzeschik <m.grzeschik@pengutronix.de>
    usb: dwc3: gadget: fix high speed multiplier setting

Michael Grzeschik <m.grzeschik@pengutronix.de>
    usb: dwc3: gadget: refactor dwc3_repare_one_trb

Kunihiko Hayashi <hayashi.kunihiko@socionext.com>
    arm64: dts: uniphier: Fix USB interrupts for PXs3 SoC

Kunihiko Hayashi <hayashi.kunihiko@socionext.com>
    ARM: dts: uniphier: Fix USB interrupts for PXs2 SoC

Jose Alonso <joalonsof@gmail.com>
    Revert "net: usb: ax88179_178a needs FLAG_SEND_ZLP"

Weitao Wang <WeitaoWang-oc@zhaoxin.com>
    USB: HCD: Fix URB giveback issue in tasklet function

Linyu Yuan <quic_linyyuan@quicinc.com>
    usb: typec: ucsi: Acknowledge the GET_ERROR_STATUS command completion

Suzuki K Poulose <suzuki.poulose@arm.com>
    coresight: Clear the connection field properly

Huacai Chen <chenhuacai@kernel.org>
    MIPS: cpuinfo: Fix a warning for CONFIG_CPUMASK_OFFSTACK

Michael Ellerman <mpe@ellerman.id.au>
    powerpc/powernv: Avoid crashing if rng is NULL

Christophe Leroy <christophe.leroy@csgroup.eu>
    powerpc/ptdump: Fix display of RW pages on FSL_BOOK3E

Pali Rohár <pali@kernel.org>
    powerpc/fsl-pci: Fix Class Code of PCIe Root Port

Christophe Leroy <christophe.leroy@csgroup.eu>
    powerpc/64e: Fix early TLB miss with KUAP

Christophe Leroy <christophe.leroy@csgroup.eu>
    powerpc: Restore CONFIG_DEBUG_INFO in defconfigs

Alexander Lobakin <alexandr.lobakin@intel.com>
    ia64, processor: fix -Wincompatible-pointer-types in ia64_get_irr()

Xiaomeng Tong <xiam0nd.tong@gmail.com>
    media: [PATCH] pci: atomisp_cmd: fix three missing checks on list iterator

Randy Dunlap <rdunlap@infradead.org>
    media: isl7998x: select V4L2_FWNODE to fix build error

Jan Kara <jack@suse.cz>
    mbcache: add functions to delete entry if unused

Jan Kara <jack@suse.cz>
    mbcache: don't reclaim used entries

Mikulas Patocka <mpatocka@redhat.com>
    md-raid10: fix KASAN warning

Mikulas Patocka <mpatocka@redhat.com>
    md-raid: destroy the bitmap after destroying the thread

Narendra Hadke <nhadke@marvell.com>
    serial: mvebu-uart: uart2 error bits clearing

Miklos Szeredi <mszeredi@redhat.com>
    fuse: fix deadlock between atomic O_TRUNC and page invalidation

Miklos Szeredi <mszeredi@redhat.com>
    fuse: write inode in fuse_release()

Miklos Szeredi <mszeredi@redhat.com>
    fuse: ioctl: translate ENOSYS

Miklos Szeredi <mszeredi@redhat.com>
    fuse: limit nsec

Namjae Jeon <linkinjeon@kernel.org>
    ksmbd: fix heap-based overflow in set_ntacl_dacl()

Namjae Jeon <linkinjeon@kernel.org>
    ksmbd: fix use-after-free bug in smb2_tree_disconect

Hyunchul Lee <hyc.lee@gmail.com>
    ksmbd: prevent out of bound read for SMB2_TREE_CONNNECT

Namjae Jeon <linkinjeon@kernel.org>
    ksmbd: fix memory leak in smb2_handle_negotiate

Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
    soundwire: qcom: Check device status before reading devid

Bikash Hazarika <bhazarika@marvell.com>
    scsi: qla2xxx: Zero undefined mailbox IN registers

Bikash Hazarika <bhazarika@marvell.com>
    scsi: qla2xxx: Fix incorrect display of max frame size

Tony Battersby <tonyb@cybernetics.com>
    scsi: sg: Allow waiting for commands to complete on removed device

James Smart <jsmart2021@gmail.com>
    scsi: lpfc: Remove extra atomic_inc on cmd_pending in queuecommand after VMID

Zheyu Ma <zheyuma97@gmail.com>
    iio: light: isl29028: Fix the warning in isl29028_remove()

Fawzi Khaber <fawzi.khaber@tdk.com>
    iio: fix iio_format_avail_range() printing for none IIO_VAL_INT

Jason A. Donenfeld <Jason@zx2c4.com>
    um: seed rng using host OS rng

Benjamin Beichler <benjamin.beichler@uni-rostock.de>
    um: Remove straying parenthesis

Amit Kumar Mahapatra <amit.kumar-mahapatra@xilinx.com>
    mtd: rawnand: arasan: Update NAND bus clock instead of system clock

Olga Kitaina <okitain@gmail.com>
    mtd: rawnand: arasan: Fix clock rate in NV-DDR

Qu Wenruo <wqu@suse.com>
    btrfs: reject log replay if there is unsupported RO compat flag

Tadeusz Struk <tadeusz.struk@linaro.org>
    bpf: Fix KASAN use-after-free Read in compute_effective_progs

Leo Li <sunpeng.li@amd.com>
    drm/amdgpu: Check BO's requested pinning domains against its preferred_domains

Dmitry Osipenko <dmitry.osipenko@collabora.com>
    drm/tegra: Fix vmapping of prime buffers

Lyude Paul <lyude@redhat.com>
    drm/nouveau/kms: Fix failure path for creating DP connectors

Lyude Paul <lyude@redhat.com>
    drm/nouveau/acpi: Don't print error when we get -EINPROGRESS from pm_runtime

Lyude Paul <lyude@redhat.com>
    drm/nouveau: Don't pm_runtime_put_sync(), only pm_runtime_put_autosuspend()

Timur Tabi <ttabi@nvidia.com>
    drm/nouveau: fix another off-by-one in nvbios_addr

Thomas Zimmermann <tzimmermann@suse.de>
    drm/hyperv-drm: Include framebuffer and EDID headers

Paul Cercueil <paul@crapouillou.net>
    drm/ingenic: Use the highest possible DMA burst size

Phil Elwell <phil@raspberrypi.org>
    drm/vc4: hdmi: Disable audio if dmas property is present but empty

Dmitry Osipenko <dmitry.osipenko@collabora.com>
    drm/shmem-helper: Add missing vunmap on error

Dmitry Osipenko <dmitry.osipenko@collabora.com>
    drm/gem: Properly annotate WW context on drm_gem_lock_reservations() error

Mathew McBride <matt@traverse.com.au>
    rtc: rx8025: fix 12/24 hour mode detection on RX-8035

Jason A. Donenfeld <Jason@zx2c4.com>
    wireguard: selftests: set CONFIG_NONPORTABLE on riscv32

Xianting Tian <xianting.tian@linux.alibaba.com>
    RISC-V: Add modules to virtual kernel memory layout dump

Atish Patra <atishp@rivosinc.com>
    RISC-V: Update user page mapping only once during start

Atish Patra <atishp@rivosinc.com>
    RISC-V: Fix SBI PMU calls for RV32

Atish Patra <atishp@rivosinc.com>
    RISC-V: Fix counter restart during overflow for RV32

Xianting Tian <xianting.tian@linux.alibaba.com>
    RISC-V: Fixup schedule out issue in machine_crash_shutdown()

Xianting Tian <xianting.tian@linux.alibaba.com>
    RISC-V: Fixup get incorrect user mode PC for kernel mode regs

Xianting Tian <xianting.tian@linux.alibaba.com>
    RISC-V: kexec: Fixup use of smp_processor_id() in preemptible context

Ben Dooks <ben.dooks@sifive.com>
    RISC-V: Declare cpu_ops_spinwait in <asm/cpu_ops.h>

Ben Dooks <ben.dooks@sifive.com>
    RISC-V: cpu_ops_spinwait.c should include head.h

Mark Kettenis <kettenis@openbsd.org>
    riscv: dts: starfive: correct number of external interrupts

Conor Dooley <conor.dooley@microchip.com>
    dt-bindings: riscv: fix SiFive l2-cache's cache-sets

Chen Lifu <chenlifu@huawei.com>
    riscv: lib: uaccess: fix CSR_STATUS SR_SUM bit

Yipeng Zou <zouyipeng@huawei.com>
    riscv:uprobe fix SR_SPIE set/clear handling

Helge Deller <deller@gmx.de>
    parisc: io_pgetevents_time64() needs compat syscall in 32-bit compat mode

William Dean <williamsukatube@gmail.com>
    parisc: Check the return value of ioremap() in lba_driver_probe()

Helge Deller <deller@gmx.de>
    parisc: Drop pa_swapper_pg_lock spinlock

Helge Deller <deller@gmx.de>
    parisc: Fix device names in /proc/iomem

Jiachen Zhang <zhangjiachen.jaycee@bytedance.com>
    ovl: drop WARN_ON() dentry is NULL in ovl_encode_fh()

John Allen <john.allen@amd.com>
    crypto: ccp - Use kzalloc for sev ioctl interfaces to prevent kernel memory leak

Al Viro <viro@zeniv.linux.org.uk>
    fix short copy handling in copy_mc_pipe_to_iter()

Lukas Wunner <lukas@wunner.de>
    usbnet: Fix linkwatch use-after-free on disconnect

Helge Deller <deller@gmx.de>
    fbcon: Fix accelerated fbdev scrolling while logo is still shown

Helge Deller <deller@gmx.de>
    fbcon: Fix boundary checks for fbcon=vc:n1-n2 parameters

Rafael J. Wysocki <rafael.j.wysocki@intel.com>
    thermal: sysfs: Fix cooling_device_stats_setup() error code path

Yang Xu <xuyang2018.jy@fujitsu.com>
    fs: Add missing umask strip in vfs_tmpfile

David Howells <dhowells@redhat.com>
    vfs: Check the truncate maximum size in inode_newsize_ok()

Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
    tty: vt: initialize unicode screen buffer

Bedant Patnaik <bedant.patnaik@gmail.com>
    ALSA: hda/realtek: Add a quirk for HP OMEN 15 (8786) mute LED

Meng Tang <tangmeng@uniontech.com>
    ALSA: hda/realtek: Add quirk for another Asus K42JZ model

Allen Ballway <ballway@chromium.org>
    ALSA: hda/cirrus - support for iMac 12,1 model

Meng Tang <tangmeng@uniontech.com>
    ALSA: hda/conexant: Add quirk for LENOVO 20149 Notebook model

Paolo Bonzini <pbonzini@redhat.com>
    KVM: x86: revalidate steal time cache if MSR value changes

Paolo Bonzini <pbonzini@redhat.com>
    KVM: x86: do not report preemption if the steal time cache is stale

Sean Christopherson <seanjc@google.com>
    KVM: x86: Tag kvm_mmu_x86_module_init() with __init

Vitaly Kuznetsov <vkuznets@redhat.com>
    KVM: nVMX: Always enable TSC scaling for L2 when it was enabled for L1

Sean Christopherson <seanjc@google.com>
    KVM: x86: Set error code to segment selector on LLDT/LTR non-canonical #GP

Sean Christopherson <seanjc@google.com>
    KVM: x86: Mark TSS busy during LTR emulation _after_ all fault checks

Sean Christopherson <seanjc@google.com>
    KVM: nVMX: Inject #UD if VMXON is attempted with incompatible CR0/CR4

Sean Christopherson <seanjc@google.com>
    KVM: nVMX: Account for KVM reserved CR4 bits in consistency checks

Sean Christopherson <seanjc@google.com>
    KVM: nVMX: Let userspace set nVMX MSR to any _host_ supported value

Sean Christopherson <seanjc@google.com>
    KVM: x86: Split kvm_is_valid_cr4() and export only the non-vendor bits

Sean Christopherson <seanjc@google.com>
    KVM: Do not incorporate page offset into gfn=>pfn cache user address

Sean Christopherson <seanjc@google.com>
    KVM: Fix multiple races in gfn=>pfn cache refresh

Sean Christopherson <seanjc@google.com>
    KVM: Fully serialize gfn=>pfn cache refresh via mutex

Sean Christopherson <seanjc@google.com>
    KVM: Put the extra pfn reference when reusing a pfn in the gpc cache

Sean Christopherson <seanjc@google.com>
    KVM: Drop unused @gpa param from gfn=>pfn cache's __release_gpc() helper

Nico Boehr <nrb@linux.ibm.com>
    KVM: s390: pv: don't present the ecall interrupt twice

Maciej S. Szmigiero <maciej.szmigiero@oracle.com>
    KVM: SVM: Don't BUG if userspace injects an interrupt with GIF=0

Sean Christopherson <seanjc@google.com>
    KVM: nVMX: Snapshot pre-VM-Enter DEBUGCTL for !nested_run_pending case

Sean Christopherson <seanjc@google.com>
    KVM: nVMX: Snapshot pre-VM-Enter BNDCFGS for !nested_run_pending case

Ping Cheng <pinglinux@gmail.com>
    HID: wacom: Don't register pad_input for touch switch

Ping Cheng <pinglinux@gmail.com>
    HID: wacom: Only report rotation for art pen

Guenter Roeck <linux@roeck-us.net>
    HID: nintendo: Add missing array termination

Maximilian Luz <luzmaximilian@gmail.com>
    HID: hid-input: add Surface Go battery quirk

Jeff Layton <jlayton@kernel.org>
    lockd: detect and reject lock arguments that overflow

Mikulas Patocka <mpatocka@redhat.com>
    add barriers to buffer_uptodate and set_buffer_uptodate

Johannes Berg <johannes.berg@intel.com>
    wifi: mac80211_hwsim: use 32-bit skb cookie

Johannes Berg <johannes.berg@intel.com>
    wifi: mac80211_hwsim: add back erroneously removed cast

Jeongik Cha <jeongik@google.com>
    wifi: mac80211_hwsim: fix race condition in pending packet

syed sabakareem <Syed.SabaKareem@amd.com>
    ASoC: amd: yc: Update DMI table entries

Philipp Jungkamp <p.jungkamp@gmx.net>
    ALSA: hda/realtek: Add quirk for Lenovo Yoga9 14IAP7

Ivan Hasenkampf <ivan.hasenkampf@gmail.com>
    ALSA: hda/realtek: Add quirk for HP Spectre x360 15-eb0xxx

Tim Crawford <tcrawford@system76.com>
    ALSA: hda/realtek: Add quirk for Clevo NV45PZ

Zheyu Ma <zheyuma97@gmail.com>
    ALSA: bcd2000: Fix a UAF bug on the error path of probing

Takashi Iwai <tiwai@suse.de>
    ALSA: usb-audio: Add quirk for Behringer UMC202HD

Jeff Layton <jlayton@kernel.org>
    nfsd: eliminate the NFSD_FILE_BREAK_* flags

Chuck Lever <chuck.lever@oracle.com>
    NFSD: Clean up the show_nf_flags() macro

Trond Myklebust <trond.myklebust@hammerspace.com>
    pNFS/flexfiles: Report RDMA connection errors to the server

Nilesh Javali <njavali@marvell.com>
    scsi: Revert "scsi: qla2xxx: Fix disk failure to rediscover"

Trond Myklebust <trond.myklebust@hammerspace.com>
    Revert "pNFS: nfs3_set_ds_client should set NFS_CS_NOPING"

Nick Desaulniers <ndesaulniers@google.com>
    x86: link vdso and boot with -z noexecstack --no-warn-rwx-segments

Nick Desaulniers <ndesaulniers@google.com>
    Makefile: link with -z noexecstack --no-warn-rwx-segments


-------------

Diffstat:

 Documentation/ABI/testing/sysfs-driver-xen-blkback |    2 +-
 .../ABI/testing/sysfs-driver-xen-blkfront          |    2 +-
 .../admin-guide/device-mapper/writecache.rst       |   16 +-
 Documentation/admin-guide/kernel-parameters.txt    |   29 +-
 Documentation/admin-guide/pm/cpuidle.rst           |   15 +-
 Documentation/arm64/silicon-errata.rst             |    4 +
 .../devicetree/bindings/riscv/sifive-l2-cache.yaml |    6 +-
 .../tty/device_drivers/oxsemi-tornado.rst          |  129 ++
 .../userspace-api/media/v4l/ext-ctrls-codec.rst    |    2 +-
 MAINTAINERS                                        |    7 +-
 Makefile                                           |   10 +-
 arch/Kconfig                                       |    3 +
 arch/arm/boot/dts/Makefile                         |    1 +
 arch/arm/boot/dts/aspeed-ast2500-evb.dts           |    2 +-
 arch/arm/boot/dts/aspeed-ast2600-evb-a1.dts        |    1 +
 arch/arm/boot/dts/aspeed-ast2600-evb.dts           |    2 +-
 arch/arm/boot/dts/bcm53015-meraki-mr26.dts         |  166 ++
 arch/arm/boot/dts/imx6qdl-apalis.dtsi              |    4 +-
 arch/arm/boot/dts/imx6ul.dtsi                      |   33 +-
 arch/arm/boot/dts/imx7d-colibri-emmc.dtsi          |    4 +
 arch/arm/boot/dts/qcom-apq8064.dtsi                |    8 +-
 arch/arm/boot/dts/qcom-apq8074-dragonboard.dts     |  609 ++++----
 arch/arm/boot/dts/qcom-apq8084.dtsi                |    2 +-
 arch/arm/boot/dts/qcom-mdm9615.dtsi                |    1 +
 arch/arm/boot/dts/qcom-msm8974-fairphone-fp2.dts   |  604 ++++----
 .../dts/qcom-msm8974-lge-nexus5-hammerhead.dts     | 1145 +++++++-------
 arch/arm/boot/dts/qcom-msm8974-samsung-klte.dts    | 1258 ++++++++--------
 .../boot/dts/qcom-msm8974-sony-xperia-amami.dts    |  432 +-----
 .../boot/dts/qcom-msm8974-sony-xperia-castor.dts   |  996 ++++++------
 .../boot/dts/qcom-msm8974-sony-xperia-honami.dts   |  479 +-----
 .../boot/dts/qcom-msm8974-sony-xperia-rhine.dtsi   |  455 ++++++
 arch/arm/boot/dts/qcom-msm8974.dtsi                | 1587 ++++++++++----------
 arch/arm/boot/dts/qcom-pm8841.dtsi                 |    1 +
 arch/arm/boot/dts/qcom-pm8941.dtsi                 |    2 +-
 arch/arm/boot/dts/qcom-sdx55.dtsi                  |    2 +-
 arch/arm/boot/dts/ste-ux500-samsung-codina.dts     |    4 +-
 arch/arm/boot/dts/ste-ux500-samsung-gavini.dts     |    4 +-
 arch/arm/boot/dts/ste-ux500-samsung-janice.dts     |    4 +-
 arch/arm/boot/dts/uniphier-pxs2.dtsi               |    8 +-
 arch/arm/crypto/Kconfig                            |    2 +-
 arch/arm/crypto/Makefile                           |    4 +-
 arch/arm/crypto/blake2s-shash.c                    |   75 -
 arch/arm/lib/findbit.S                             |   16 +-
 arch/arm/mach-bcm/bcm_kona_smc.c                   |    1 +
 arch/arm/mach-omap2/display.c                      |    3 +
 arch/arm/mach-omap2/pdata-quirks.c                 |    2 +
 arch/arm/mach-omap2/prm3xxx.c                      |    1 +
 arch/arm/mach-shmobile/regulator-quirk-rcar-gen2.c |    5 +-
 arch/arm/mach-zynq/common.c                        |    1 +
 arch/arm64/Kconfig                                 |   17 +
 .../boot/dts/allwinner/sun50i-a64-orangepi-win.dts |    2 +-
 .../boot/dts/exynos/exynosautov9-pinctrl.dtsi      |    6 +-
 .../boot/dts/mediatek/mt7622-bananapi-bpi-r64.dts  |    2 +-
 arch/arm64/boot/dts/mediatek/mt8192.dtsi           |   26 +-
 arch/arm64/boot/dts/nvidia/tegra186.dtsi           |    1 +
 arch/arm64/boot/dts/nvidia/tegra194-p2888.dtsi     |    2 +-
 arch/arm64/boot/dts/nvidia/tegra194.dtsi           |    1 +
 arch/arm64/boot/dts/nvidia/tegra234.dtsi           |    1 +
 arch/arm64/boot/dts/qcom/ipq6018.dtsi              |   22 +-
 arch/arm64/boot/dts/qcom/ipq8074.dtsi              |    2 +-
 arch/arm64/boot/dts/qcom/msm8916.dtsi              |    4 +-
 arch/arm64/boot/dts/qcom/msm8996.dtsi              |    6 +-
 .../qcom/msm8998-sony-xperia-yoshino-poplar.dts    |   10 +-
 arch/arm64/boot/dts/qcom/qcs404.dtsi               |    4 +-
 arch/arm64/boot/dts/qcom/sc7180-trogdor.dtsi       |    1 +
 arch/arm64/boot/dts/qcom/sc7180.dtsi               |   24 +-
 arch/arm64/boot/dts/qcom/sc7280.dtsi               |   30 +-
 arch/arm64/boot/dts/qcom/sdm630.dtsi               |    7 +-
 .../dts/qcom/sdm636-sony-xperia-ganges-mermaid.dts |    2 +-
 .../dts/qcom/sdm845-sony-xperia-tama-akatsuki.dts  |    5 +-
 arch/arm64/boot/dts/qcom/sdm845.dtsi               |   22 +-
 .../dts/qcom/sm6125-sony-xperia-seine-pdx201.dts   |   36 +-
 arch/arm64/boot/dts/qcom/sm6125.dtsi               |   30 +-
 arch/arm64/boot/dts/qcom/sm6350.dtsi               |   22 +-
 arch/arm64/boot/dts/qcom/sm8150.dtsi               |   24 +-
 arch/arm64/boot/dts/qcom/sm8250.dtsi               |   30 +-
 arch/arm64/boot/dts/qcom/sm8350.dtsi               |   24 +-
 arch/arm64/boot/dts/qcom/sm8450.dtsi               |   22 +-
 .../boot/dts/renesas/beacon-renesom-baseboard.dtsi |    6 +-
 arch/arm64/boot/dts/renesas/r8a774c0.dtsi          |    2 +-
 arch/arm64/boot/dts/renesas/r8a77990.dtsi          |    2 +-
 arch/arm64/boot/dts/renesas/r8a779m8.dtsi          |    5 +
 arch/arm64/boot/dts/renesas/r9a07g054l2-smarc.dts  |    2 +-
 arch/arm64/boot/dts/socionext/uniphier-pxs3.dtsi   |    8 +-
 arch/arm64/crypto/Kconfig                          |    1 +
 arch/arm64/include/asm/esr.h                       |    6 +-
 arch/arm64/include/asm/kexec.h                     |    4 +-
 arch/arm64/include/asm/processor.h                 |    3 +-
 arch/arm64/kernel/armv8_deprecated.c               |    9 +-
 arch/arm64/kernel/cpu_errata.c                     |   16 +
 arch/arm64/kernel/cpufeature.c                     |   16 +-
 arch/arm64/kernel/hibernate.c                      |    5 -
 arch/arm64/kernel/mte.c                            |    9 -
 arch/arm64/kvm/hyp/nvhe/switch.c                   |    2 +-
 arch/arm64/kvm/hyp/vhe/switch.c                    |    2 +-
 arch/arm64/mm/copypage.c                           |    9 -
 arch/arm64/mm/mteswap.c                            |    9 -
 arch/arm64/tools/cpucaps                           |    1 +
 arch/ia64/include/asm/processor.h                  |    2 +-
 arch/ia64/kernel/palinfo.c                         |    2 +-
 arch/ia64/kernel/traps.c                           |    2 +-
 arch/ia64/mm/init.c                                |    2 +-
 arch/ia64/mm/tlb.c                                 |    4 +-
 arch/mips/kernel/proc.c                            |    2 +-
 arch/mips/kernel/vdso.c                            |    2 +-
 arch/mips/loongson64/numa.c                        |    1 -
 arch/mips/mm/physaddr.c                            |   14 +-
 arch/parisc/kernel/cache.c                         |    3 -
 arch/parisc/kernel/drivers.c                       |    9 +-
 arch/parisc/kernel/syscalls/syscall.tbl            |    2 +-
 arch/powerpc/boot/cuboot-hotfoot.c                 |    2 +-
 arch/powerpc/configs/44x/akebono_defconfig         |    2 +-
 arch/powerpc/configs/44x/currituck_defconfig       |    2 +-
 arch/powerpc/configs/44x/fsp2_defconfig            |    2 +-
 arch/powerpc/configs/44x/iss476-smp_defconfig      |    2 +-
 arch/powerpc/configs/44x/warp_defconfig            |    2 +-
 arch/powerpc/configs/52xx/lite5200b_defconfig      |    2 +-
 arch/powerpc/configs/52xx/motionpro_defconfig      |    2 +-
 arch/powerpc/configs/52xx/tqm5200_defconfig        |    2 +-
 arch/powerpc/configs/adder875_defconfig            |    2 +-
 arch/powerpc/configs/ep8248e_defconfig             |    2 +-
 arch/powerpc/configs/ep88xc_defconfig              |    2 +-
 arch/powerpc/configs/fsl-emb-nonhw.config          |    2 +-
 arch/powerpc/configs/mgcoge_defconfig              |    2 +-
 arch/powerpc/configs/mpc5200_defconfig             |    2 +-
 arch/powerpc/configs/mpc8272_ads_defconfig         |    2 +-
 arch/powerpc/configs/mpc885_ads_defconfig          |    2 +-
 arch/powerpc/configs/ppc6xx_defconfig              |    2 +-
 arch/powerpc/configs/pq2fads_defconfig             |    2 +-
 arch/powerpc/configs/ps3_defconfig                 |    2 +-
 arch/powerpc/configs/tqm8xx_defconfig              |    2 +-
 arch/powerpc/crypto/aes-spe-glue.c                 |    2 +-
 arch/powerpc/include/asm/archrandom.h              |    5 -
 arch/powerpc/include/asm/kexec.h                   |    9 +
 arch/powerpc/include/asm/simple_spinlock.h         |   15 +-
 arch/powerpc/kernel/Makefile                       |    1 +
 arch/powerpc/kernel/cputable.c                     |    2 +-
 arch/powerpc/kernel/dawr.c                         |    2 +-
 arch/powerpc/kernel/eeh.c                          |    4 +-
 arch/powerpc/kernel/eeh_event.c                    |    2 +-
 arch/powerpc/kernel/fadump.c                       |    4 +-
 arch/powerpc/kernel/iommu.c                        |    5 +
 arch/powerpc/kernel/module_32.c                    |    2 +-
 arch/powerpc/kernel/module_64.c                    |    4 +-
 arch/powerpc/kernel/pci-common.c                   |   31 +-
 arch/powerpc/kernel/pci_of_scan.c                  |    2 +-
 arch/powerpc/kernel/process.c                      |    4 +-
 arch/powerpc/kernel/prom_init.c                    |    2 +-
 arch/powerpc/kernel/ptrace/ptrace-view.c           |    2 +-
 arch/powerpc/kernel/rtas_flash.c                   |    2 +-
 arch/powerpc/kernel/setup-common.c                 |    2 +-
 arch/powerpc/kernel/signal_64.c                    |    2 +-
 arch/powerpc/kernel/smp.c                          |    2 +-
 arch/powerpc/kernel/time.c                         |    4 +-
 arch/powerpc/kernel/watchdog.c                     |    2 +-
 arch/powerpc/kexec/core_64.c                       |    2 +-
 arch/powerpc/kexec/file_load_64.c                  |   55 +
 arch/powerpc/kvm/book3s_64_mmu_hv.c                |    2 +-
 arch/powerpc/kvm/book3s_64_vio_hv.c                |    2 +-
 arch/powerpc/kvm/book3s_emulate.c                  |    2 +-
 arch/powerpc/kvm/book3s_hv_builtin.c               |    7 +-
 arch/powerpc/kvm/book3s_hv_p9_entry.c              |    2 +-
 arch/powerpc/kvm/book3s_hv_uvmem.c                 |    2 +-
 arch/powerpc/kvm/book3s_pr.c                       |    2 +-
 arch/powerpc/kvm/book3s_xics.c                     |    2 +-
 arch/powerpc/kvm/book3s_xive.c                     |    6 +-
 arch/powerpc/kvm/e500mc.c                          |    2 +-
 arch/powerpc/mm/book3s64/hash_pgtable.c            |    2 +-
 arch/powerpc/mm/book3s64/hash_utils.c              |    4 +-
 arch/powerpc/mm/book3s64/pgtable.c                 |    2 +-
 arch/powerpc/mm/book3s64/radix_pgtable.c           |    2 +-
 arch/powerpc/mm/book3s64/radix_tlb.c               |    2 +-
 arch/powerpc/mm/book3s64/slb.c                     |    4 +-
 arch/powerpc/mm/init_64.c                          |    4 +-
 arch/powerpc/mm/kasan/kasan_init_32.c              |    2 +-
 arch/powerpc/mm/nohash/8xx.c                       |    4 +-
 arch/powerpc/mm/nohash/book3e_hugetlbpage.c        |    2 +-
 arch/powerpc/mm/nohash/kaslr_booke.c               |    2 +-
 arch/powerpc/mm/nohash/tlb_low_64e.S               |   17 +-
 arch/powerpc/mm/pgtable-frag.c                     |    2 +-
 arch/powerpc/mm/pgtable_32.c                       |    6 +-
 arch/powerpc/mm/ptdump/shared.c                    |    6 +-
 arch/powerpc/perf/8xx-pmu.c                        |    2 +-
 arch/powerpc/perf/core-book3s.c                    |   41 +-
 arch/powerpc/perf/imc-pmu.c                        |    4 +-
 arch/powerpc/perf/isa207-common.c                  |    6 +-
 arch/powerpc/platforms/512x/clock-commonclk.c      |    2 +-
 arch/powerpc/platforms/512x/mpc512x_shared.c       |    2 +-
 arch/powerpc/platforms/52xx/mpc52xx_common.c       |    2 +-
 arch/powerpc/platforms/52xx/mpc52xx_gpt.c          |    2 +-
 arch/powerpc/platforms/52xx/mpc52xx_lpbfifo.c      |    2 +-
 arch/powerpc/platforms/85xx/mpc85xx_cds.c          |    2 +-
 arch/powerpc/platforms/86xx/gef_ppc9a.c            |    2 +-
 arch/powerpc/platforms/86xx/gef_sbc310.c           |    2 +-
 arch/powerpc/platforms/86xx/gef_sbc610.c           |    2 +-
 arch/powerpc/platforms/Kconfig.cputype             |    4 +-
 arch/powerpc/platforms/book3s/vas-api.c            |    2 +-
 arch/powerpc/platforms/cell/axon_msi.c             |    1 +
 arch/powerpc/platforms/cell/cbe_regs.c             |    2 +-
 arch/powerpc/platforms/cell/iommu.c                |    2 +-
 arch/powerpc/platforms/cell/spider-pci.c           |    2 +-
 arch/powerpc/platforms/cell/spu_manage.c           |    2 +-
 arch/powerpc/platforms/cell/spufs/inode.c          |    1 +
 arch/powerpc/platforms/powermac/low_i2c.c          |    2 +-
 arch/powerpc/platforms/powernv/eeh-powernv.c       |   10 +-
 arch/powerpc/platforms/powernv/idle.c              |    4 +-
 arch/powerpc/platforms/powernv/ocxl.c              |    2 +-
 arch/powerpc/platforms/powernv/opal-fadump.c       |    2 +-
 arch/powerpc/platforms/powernv/opal-lpc.c          |    2 +-
 .../powerpc/platforms/powernv/opal-memory-errors.c |    2 +-
 arch/powerpc/platforms/powernv/pci-sriov.c         |    2 +-
 arch/powerpc/platforms/powernv/rng.c               |   34 +-
 arch/powerpc/platforms/ps3/mm.c                    |    2 +-
 arch/powerpc/platforms/ps3/system-bus.c            |    2 +-
 arch/powerpc/platforms/pseries/eeh_pseries.c       |    2 +-
 arch/powerpc/platforms/pseries/iommu.c             |   89 +-
 arch/powerpc/platforms/pseries/setup.c             |    4 +-
 arch/powerpc/platforms/pseries/vas-sysfs.c         |    2 +-
 arch/powerpc/platforms/pseries/vas.c               |    2 +-
 arch/powerpc/sysdev/fsl_lbc.c                      |    2 +-
 arch/powerpc/sysdev/fsl_pci.c                      |   10 +-
 arch/powerpc/sysdev/fsl_pci.h                      |    1 +
 arch/powerpc/sysdev/ge/ge_pic.c                    |    2 +-
 arch/powerpc/sysdev/mpic_msgr.c                    |    2 +-
 arch/powerpc/sysdev/mpic_msi.c                     |    2 +-
 arch/powerpc/sysdev/mpic_timer.c                   |    2 +-
 arch/powerpc/sysdev/mpic_u3msi.c                   |    2 +-
 arch/powerpc/sysdev/xive/native.c                  |    2 +-
 arch/powerpc/sysdev/xive/spapr.c                   |    1 +
 arch/powerpc/xmon/ppc-opc.c                        |    2 +-
 arch/powerpc/xmon/xmon.c                           |    2 +-
 arch/riscv/boot/dts/starfive/jh7100.dtsi           |    2 +-
 arch/riscv/include/asm/cpu_ops.h                   |    1 +
 arch/riscv/kernel/cpu_ops.c                        |    4 +-
 arch/riscv/kernel/cpu_ops_spinwait.c               |    6 +-
 arch/riscv/kernel/crash_save_regs.S                |    2 +-
 arch/riscv/kernel/machine_kexec.c                  |   28 +-
 arch/riscv/kernel/probes/uprobes.c                 |    6 -
 arch/riscv/lib/uaccess.S                           |    4 +-
 arch/riscv/mm/init.c                               |    4 +
 arch/s390/include/asm/gmap.h                       |    2 +
 arch/s390/include/asm/kexec.h                      |    3 +
 arch/s390/include/asm/unwind.h                     |    2 +-
 arch/s390/kernel/crash_dump.c                      |    2 +-
 arch/s390/kernel/machine_kexec_file.c              |   18 +-
 arch/s390/kvm/intercept.c                          |   15 +
 arch/s390/kvm/pv.c                                 |    9 +-
 arch/s390/kvm/sigp.c                               |    4 +-
 arch/s390/mm/gmap.c                                |   86 ++
 arch/um/drivers/random.c                           |    2 +-
 arch/um/include/asm/archrandom.h                   |   30 +
 arch/um/include/asm/xor.h                          |    2 +-
 arch/um/include/shared/os.h                        |    7 +
 arch/um/kernel/um_arch.c                           |    8 +
 arch/um/os-Linux/util.c                            |    6 +
 arch/x86/Kconfig                                   |    1 +
 arch/x86/Kconfig.debug                             |    3 -
 arch/x86/boot/Makefile                             |    2 +-
 arch/x86/boot/compressed/Makefile                  |    4 +
 arch/x86/crypto/Makefile                           |    4 +-
 arch/x86/crypto/blake2s-glue.c                     |    3 +-
 arch/x86/crypto/blake2s-shash.c                    |   77 -
 arch/x86/entry/Makefile                            |    3 +-
 arch/x86/entry/thunk_32.S                          |    2 -
 arch/x86/entry/thunk_64.S                          |    4 -
 arch/x86/entry/vdso/Makefile                       |    2 +-
 arch/x86/events/intel/lbr.c                        |   36 +-
 arch/x86/include/asm/kexec.h                       |    6 +
 arch/x86/include/asm/kvm_host.h                    |    3 +-
 arch/x86/kernel/cpu/bugs.c                         |   10 +-
 arch/x86/kernel/cpu/intel.c                        |   27 +-
 arch/x86/kernel/ftrace.c                           |    1 +
 arch/x86/kernel/kprobes/core.c                     |   18 +-
 arch/x86/kernel/pmem.c                             |    7 +-
 arch/x86/kernel/process.c                          |    9 +-
 arch/x86/kvm/emulate.c                             |   23 +-
 arch/x86/kvm/mmu/mmu.c                             |    2 +-
 arch/x86/kvm/mmu/paging_tmpl.h                     |    9 +-
 arch/x86/kvm/mmu/spte.c                            |    2 +
 arch/x86/kvm/svm/nested.c                          |    3 +-
 arch/x86/kvm/svm/svm.c                             |   29 +-
 arch/x86/kvm/vmx/nested.c                          |  107 +-
 arch/x86/kvm/vmx/nested.h                          |    3 +-
 arch/x86/kvm/vmx/pmu_intel.c                       |   13 +-
 arch/x86/kvm/vmx/vmx.c                             |    4 +-
 arch/x86/kvm/vmx/vmx.h                             |   12 +
 arch/x86/kvm/x86.c                                 |   33 +-
 arch/x86/kvm/x86.h                                 |    2 +-
 arch/x86/mm/extable.c                              |   16 +-
 arch/x86/mm/numa.c                                 |    4 +-
 arch/x86/net/bpf_jit_comp.c                        |   67 +-
 arch/x86/platform/olpc/olpc-xo1-sci.c              |    2 +-
 arch/x86/um/Makefile                               |    3 +-
 arch/xtensa/platforms/iss/network.c                |   42 +-
 block/bio.c                                        |   99 +-
 block/blk-iocost.c                                 |   20 +-
 block/blk-iolatency.c                              |   18 +-
 block/blk-mq-debugfs.c                             |   28 +-
 block/blk-mq-debugfs.h                             |    5 -
 block/blk-mq-sched.c                               |   11 +
 block/blk-rq-qos.c                                 |    2 +
 block/blk-rq-qos.h                                 |   18 +-
 block/blk-sysfs.c                                  |   20 +-
 block/blk-wbt.c                                    |   12 +-
 crypto/Kconfig                                     |   20 +-
 crypto/Makefile                                    |    1 -
 crypto/asymmetric_keys/public_key.c                |    7 +-
 crypto/blake2s_generic.c                           |   75 -
 crypto/tcrypt.c                                    |   12 -
 crypto/testmgr.c                                   |   24 -
 crypto/testmgr.h                                   |  217 ---
 drivers/acpi/acpi_lpss.c                           |    3 +
 drivers/acpi/apei/einj.c                           |    2 +
 drivers/acpi/bus.c                                 |    1 +
 drivers/acpi/cppc_acpi.c                           |   54 +-
 drivers/acpi/ec.c                                  |   82 +-
 drivers/acpi/processor_idle.c                      |    6 +-
 drivers/acpi/sleep.c                               |    8 +
 drivers/acpi/video_detect.c                        |    8 +
 drivers/acpi/viot.c                                |   26 +-
 drivers/android/binder.c                           |  114 +-
 drivers/android/binder_alloc.c                     |   30 +-
 drivers/android/binder_alloc.h                     |    2 +-
 drivers/android/binder_alloc_selftest.c            |    2 +-
 drivers/android/binder_internal.h                  |   46 +-
 drivers/android/binderfs.c                         |   47 +-
 drivers/base/dd.c                                  |    5 +-
 drivers/base/node.c                                |    4 +-
 drivers/base/power/domain.c                        |    3 +
 drivers/base/topology.c                            |   32 +-
 drivers/block/null_blk/main.c                      |   14 +-
 drivers/block/rnbd/rnbd-srv.c                      |    3 +-
 drivers/block/xen-blkback/xenbus.c                 |   20 +-
 drivers/block/xen-blkfront.c                       |    4 +-
 drivers/bluetooth/hci_intel.c                      |    6 +-
 drivers/bluetooth/hci_serdev.c                     |   11 +
 drivers/bus/hisi_lpc.c                             |   10 +-
 drivers/char/tpm/tpm2-cmd.c                        |    6 +
 drivers/clk/imx/clk-fracn-gppll.c                  |   33 +-
 drivers/clk/imx/clk-imx93.c                        |    4 +-
 drivers/clk/mediatek/reset.c                       |    4 +-
 drivers/clk/qcom/camcc-sdm845.c                    |    4 +
 drivers/clk/qcom/camcc-sm8250.c                    |   16 +-
 drivers/clk/qcom/clk-krait.c                       |    7 +-
 drivers/clk/qcom/clk-rcg2.c                        |   16 +-
 drivers/clk/qcom/dispcc-sm8250.c                   |    1 -
 drivers/clk/qcom/gcc-ipq8074.c                     |   60 +-
 drivers/clk/qcom/gcc-msm8939.c                     |   33 +-
 drivers/clk/qcom/gdsc.c                            |    8 +
 drivers/clk/qcom/videocc-sm8250.c                  |    4 -
 drivers/clk/renesas/r9a06g032-clocks.c             |    8 +-
 drivers/clk/renesas/rzg2l-cpg.c                    |    2 +-
 .../crypto/allwinner/sun8i-ss/sun8i-ss-cipher.c    |    1 +
 drivers/crypto/allwinner/sun8i-ss/sun8i-ss-core.c  |   22 +-
 drivers/crypto/allwinner/sun8i-ss/sun8i-ss-hash.c  |   15 +-
 drivers/crypto/allwinner/sun8i-ss/sun8i-ss.h       |    4 +
 drivers/crypto/ccp/sev-dev.c                       |   12 +-
 drivers/crypto/hisilicon/hpre/hpre_crypto.c        |    2 +-
 drivers/crypto/hisilicon/sec/sec_algs.c            |   14 +-
 drivers/crypto/hisilicon/sec/sec_drv.h             |    2 +-
 drivers/crypto/hisilicon/sec2/sec.h                |    2 +-
 drivers/crypto/hisilicon/sec2/sec_crypto.c         |   26 +-
 drivers/crypto/hisilicon/sec2/sec_crypto.h         |    1 +
 drivers/crypto/inside-secure/safexcel.c            |    2 +
 drivers/dma/dw-edma/dw-edma-core.c                 |    2 +-
 drivers/dma/imx-dma.c                              |    2 +-
 drivers/dma/sf-pdma/sf-pdma.c                      |   44 +-
 drivers/firmware/arm_scpi.c                        |   61 +-
 drivers/firmware/tegra/bpmp-debugfs.c              |   10 +-
 drivers/fpga/altera-pr-ip-core.c                   |    2 +-
 drivers/gpio/gpiolib-of.c                          |    4 +-
 drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c   |    6 -
 drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c             |    2 +-
 drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c            |   96 +-
 drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.h            |   11 +-
 drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c      |   10 +-
 drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c            |    2 +-
 drivers/gpu/drm/amd/amdgpu/amdgpu_object.c         |    4 +
 drivers/gpu/drm/amd/amdgpu/nbio_v2_3.c             |   21 -
 drivers/gpu/drm/amd/amdgpu/nbio_v2_3.h             |    1 -
 drivers/gpu/drm/amd/amdgpu/nbio_v7_4.c             |   21 -
 drivers/gpu/drm/amd/amdgpu/nbio_v7_4.h             |    1 -
 .../drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c  |    2 +-
 drivers/gpu/drm/bridge/Kconfig                     |    2 +
 drivers/gpu/drm/bridge/adv7511/adv7511_drv.c       |   24 +-
 drivers/gpu/drm/bridge/analogix/anx7625.c          |   17 +-
 drivers/gpu/drm/bridge/lontium-lt9611.c            |    2 +-
 drivers/gpu/drm/bridge/lontium-lt9611uxc.c         |    2 +-
 drivers/gpu/drm/bridge/sil-sii8620.c               |    4 +-
 drivers/gpu/drm/bridge/tc358767.c                  |   62 +-
 drivers/gpu/drm/dp/drm_dp_aux_bus.c                |    4 +-
 drivers/gpu/drm/dp/drm_dp_mst_topology.c           |    7 +-
 drivers/gpu/drm/drm_gem.c                          |    4 +-
 drivers/gpu/drm/drm_gem_shmem_helper.c             |    1 +
 drivers/gpu/drm/drm_mipi_dbi.c                     |    7 +
 drivers/gpu/drm/exynos/exynos7_drm_decon.c         |   17 +-
 drivers/gpu/drm/hyperv/hyperv_drm_modeset.c        |    2 +
 drivers/gpu/drm/ingenic/ingenic-drm-drv.c          |   10 +-
 drivers/gpu/drm/ingenic/ingenic-drm.h              |    3 +
 drivers/gpu/drm/mcde/mcde_dsi.c                    |    1 +
 drivers/gpu/drm/mediatek/mtk_dpi.c                 |   33 +-
 drivers/gpu/drm/mediatek/mtk_dsi.c                 |   93 +-
 drivers/gpu/drm/meson/meson_encoder_cvbs.c         |    1 +
 drivers/gpu/drm/meson/meson_encoder_hdmi.c         |   19 +-
 drivers/gpu/drm/msm/adreno/a5xx_gpu.c              |    8 -
 drivers/gpu/drm/msm/adreno/a6xx_gmu.c              |   13 +-
 drivers/gpu/drm/msm/adreno/a6xx_gpu.c              |   12 +-
 drivers/gpu/drm/msm/adreno/a6xx_gpu.h              |    3 +-
 drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c           |    6 +
 drivers/gpu/drm/msm/disp/mdp5/mdp5_pipe.c          |    3 +-
 drivers/gpu/drm/msm/hdmi/hdmi.c                    |    3 +
 drivers/gpu/drm/msm/msm_gpu.h                      |   11 +-
 drivers/gpu/drm/msm/msm_gpu_devfreq.c              |   39 +-
 drivers/gpu/drm/nouveau/nouveau_connector.c        |    8 +-
 drivers/gpu/drm/nouveau/nouveau_display.c          |    4 +-
 drivers/gpu/drm/nouveau/nouveau_fbcon.c            |    2 +-
 drivers/gpu/drm/nouveau/nvkm/subdev/bios/base.c    |    2 +-
 drivers/gpu/drm/panel/Kconfig                      |    2 +
 drivers/gpu/drm/radeon/.gitignore                  |    2 +-
 drivers/gpu/drm/radeon/Kconfig                     |    2 +-
 drivers/gpu/drm/radeon/Makefile                    |    2 +-
 drivers/gpu/drm/radeon/ni_dpm.c                    |    6 +-
 drivers/gpu/drm/radeon/radeon_device.c             |    2 +-
 drivers/gpu/drm/rockchip/analogix_dp-rockchip.c    |   10 +-
 drivers/gpu/drm/rockchip/rockchip_drm_vop.c        |    3 +
 drivers/gpu/drm/tegra/gem.c                        |   11 +-
 drivers/gpu/drm/tiny/st7735r.c                     |    1 +
 drivers/gpu/drm/vc4/vc4_crtc.c                     |   14 +-
 drivers/gpu/drm/vc4/vc4_drv.c                      |   19 +
 drivers/gpu/drm/vc4/vc4_dsi.c                      |  152 +-
 drivers/gpu/drm/vc4/vc4_hdmi.c                     |  157 +-
 drivers/gpu/drm/vc4/vc4_hdmi.h                     |    8 +
 drivers/gpu/drm/vc4/vc4_hdmi_regs.h                |    7 +-
 drivers/gpu/drm/vc4/vc4_kms.c                      |    4 +-
 drivers/gpu/drm/vc4/vc4_plane.c                    |   30 +-
 drivers/gpu/drm/virtio/virtgpu_ioctl.c             |    6 +-
 drivers/gpu/drm/virtio/virtgpu_object.c            |    4 +-
 drivers/gpu/drm/vkms/vkms_composer.c               |    2 +-
 drivers/hid/amd-sfh-hid/amd_sfh_client.c           |    2 +
 drivers/hid/amd-sfh-hid/amd_sfh_hid.c              |   12 +-
 drivers/hid/amd-sfh-hid/amd_sfh_pcie.c             |    3 +-
 drivers/hid/hid-alps.c                             |    2 +
 drivers/hid/hid-cp2112.c                           |    5 +
 drivers/hid/hid-ids.h                              |    1 +
 drivers/hid/hid-input.c                            |    2 +
 drivers/hid/hid-mcp2221.c                          |    3 +
 drivers/hid/hid-nintendo.c                         |    1 +
 drivers/hid/wacom_sys.c                            |    2 +-
 drivers/hid/wacom_wac.c                            |   72 +-
 drivers/hwmon/dell-smm-hwmon.c                     |    8 +
 drivers/hwmon/drivetemp.c                          |    1 +
 drivers/hwmon/sch56xx-common.c                     |   44 +-
 drivers/hwmon/sht15.c                              |   17 +-
 drivers/hwtracing/coresight/coresight-config.h     |    2 +
 drivers/hwtracing/coresight/coresight-core.c       |    1 +
 drivers/hwtracing/coresight/coresight-syscfg.c     |  295 +++-
 drivers/hwtracing/coresight/coresight-syscfg.h     |   13 +
 drivers/hwtracing/intel_th/msu-sink.c              |    3 +
 drivers/hwtracing/intel_th/msu.c                   |   14 +-
 drivers/hwtracing/intel_th/pci.c                   |   25 +-
 drivers/i2c/busses/i2c-cadence.c                   |   10 +-
 drivers/i2c/busses/i2c-mxs.c                       |    2 +-
 drivers/i2c/busses/i2c-npcm7xx.c                   |   50 +-
 drivers/i2c/busses/i2c-qcom-geni.c                 |    2 +-
 drivers/i2c/i2c-core-base.c                        |    3 +-
 drivers/i2c/muxes/i2c-mux-gpmux.c                  |    1 +
 drivers/idle/intel_idle.c                          |  149 +-
 drivers/iio/accel/adxl313_core.c                   |    2 +-
 drivers/iio/accel/adxl355_core.c                   |    2 +-
 drivers/iio/accel/adxl367.c                        |    2 +-
 drivers/iio/accel/adxl367_spi.c                    |    8 +-
 drivers/iio/accel/bma220_spi.c                     |    2 +-
 drivers/iio/accel/bma400.h                         |   25 +-
 drivers/iio/accel/bma400_core.c                    |   81 +-
 drivers/iio/accel/bma400_i2c.c                     |    8 -
 drivers/iio/accel/bma400_spi.c                     |    6 -
 drivers/iio/accel/cros_ec_accel_legacy.c           |    4 +-
 drivers/iio/accel/sca3000.c                        |    4 +-
 drivers/iio/accel/sca3300.c                        |    2 +-
 drivers/iio/adc/ad7266.c                           |    4 +-
 drivers/iio/adc/ad7280a.c                          |    2 +-
 drivers/iio/adc/ad7292.c                           |    2 +-
 drivers/iio/adc/ad7298.c                           |    2 +-
 drivers/iio/adc/ad7476.c                           |    5 +-
 drivers/iio/adc/ad7606.h                           |    4 +-
 drivers/iio/adc/ad7766.c                           |    5 +-
 drivers/iio/adc/ad7768-1.c                         |    4 +-
 drivers/iio/adc/ad7887.c                           |    5 +-
 drivers/iio/adc/ad7923.c                           |    4 +-
 drivers/iio/adc/ad7949.c                           |    2 +-
 drivers/iio/adc/adi-axi-adc.c                      |    7 +-
 drivers/iio/adc/hi8435.c                           |    2 +-
 drivers/iio/adc/ltc2496.c                          |    4 +-
 drivers/iio/adc/ltc2497.c                          |    4 +-
 drivers/iio/adc/max1027.c                          |    8 +-
 drivers/iio/adc/max11100.c                         |    4 +-
 drivers/iio/adc/max1118.c                          |    2 +-
 drivers/iio/adc/max1241.c                          |    2 +-
 drivers/iio/adc/mcp320x.c                          |    2 +-
 drivers/iio/adc/ti-adc0832.c                       |    2 +-
 drivers/iio/adc/ti-adc084s021.c                    |    4 +-
 drivers/iio/adc/ti-adc108s102.c                    |    4 +-
 drivers/iio/adc/ti-adc12138.c                      |    2 +-
 drivers/iio/adc/ti-adc128s052.c                    |    2 +-
 drivers/iio/adc/ti-adc161s626.c                    |    2 +-
 drivers/iio/adc/ti-ads124s08.c                     |    2 +-
 drivers/iio/adc/ti-ads131e08.c                     |    2 +-
 drivers/iio/adc/ti-ads7950.c                       |    4 +-
 drivers/iio/adc/ti-ads8344.c                       |    2 +-
 drivers/iio/adc/ti-ads8688.c                       |    2 +-
 drivers/iio/adc/ti-tlc4541.c                       |    4 +-
 drivers/iio/addac/ad74413r.c                       |    4 +-
 drivers/iio/amplifiers/ad8366.c                    |    4 +-
 .../iio/common/cros_ec_sensors/cros_ec_lid_angle.c |    4 +-
 .../iio/common/cros_ec_sensors/cros_ec_sensors.c   |    6 +-
 .../common/cros_ec_sensors/cros_ec_sensors_core.c  |   58 +-
 drivers/iio/common/ssp_sensors/ssp.h               |    3 +-
 drivers/iio/dac/ad5064.c                           |    4 +-
 drivers/iio/dac/ad5360.c                           |    4 +-
 drivers/iio/dac/ad5421.c                           |    4 +-
 drivers/iio/dac/ad5449.c                           |    4 +-
 drivers/iio/dac/ad5504.c                           |    2 +-
 drivers/iio/dac/ad5592r-base.h                     |    4 +-
 drivers/iio/dac/ad5686.h                           |    6 +-
 drivers/iio/dac/ad5755.c                           |    4 +-
 drivers/iio/dac/ad5761.c                           |    4 +-
 drivers/iio/dac/ad5764.c                           |    4 +-
 drivers/iio/dac/ad5766.c                           |    2 +-
 drivers/iio/dac/ad5770r.c                          |    2 +-
 drivers/iio/dac/ad5791.c                           |    2 +-
 drivers/iio/dac/ad7293.c                           |    2 +-
 drivers/iio/dac/ad7303.c                           |    4 +-
 drivers/iio/dac/ad8801.c                           |    2 +-
 drivers/iio/dac/ltc2688.c                          |    4 +-
 drivers/iio/dac/mcp4922.c                          |    2 +-
 drivers/iio/dac/ti-dac082s085.c                    |    2 +-
 drivers/iio/dac/ti-dac5571.c                       |    2 +-
 drivers/iio/dac/ti-dac7311.c                       |    2 +-
 drivers/iio/dac/ti-dac7612.c                       |    4 +-
 drivers/iio/frequency/ad9523.c                     |    6 +-
 drivers/iio/frequency/adf4350.c                    |    6 +-
 drivers/iio/frequency/adf4371.c                    |    2 +-
 drivers/iio/frequency/admv1013.c                   |    2 +-
 drivers/iio/frequency/admv1014.c                   |    2 +-
 drivers/iio/frequency/admv4420.c                   |    2 +-
 drivers/iio/frequency/adrf6780.c                   |    2 +-
 drivers/iio/gyro/adis16080.c                       |    2 +-
 drivers/iio/gyro/adis16130.c                       |    2 +-
 drivers/iio/gyro/adxrs450.c                        |    2 +-
 drivers/iio/gyro/fxas21002c_core.c                 |    6 +-
 drivers/iio/imu/fxos8700_core.c                    |    2 +-
 drivers/iio/imu/inv_icm42600/inv_icm42600.h        |    2 +-
 drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.h |    2 +-
 drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h          |    2 +-
 drivers/iio/industrialio-buffer.c                  |    4 +-
 drivers/iio/industrialio-core.c                    |   25 +-
 drivers/iio/light/cros_ec_light_prox.c             |    6 +-
 drivers/iio/light/isl29028.c                       |    2 +-
 drivers/iio/potentiometer/ad5110.c                 |    4 +-
 drivers/iio/potentiometer/ad5272.c                 |    2 +-
 drivers/iio/potentiometer/max5481.c                |    2 +-
 drivers/iio/potentiometer/mcp41010.c               |    2 +-
 drivers/iio/potentiometer/mcp4131.c                |    2 +-
 drivers/iio/pressure/cros_ec_baro.c                |    6 +-
 drivers/iio/proximity/as3935.c                     |    2 +-
 drivers/iio/proximity/sx9324.c                     |    4 +-
 drivers/iio/resolver/ad2s1200.c                    |    2 +-
 drivers/iio/resolver/ad2s90.c                      |    2 +-
 drivers/iio/temperature/ltc2983.c                  |    4 +-
 drivers/iio/temperature/max31865.c                 |    2 +-
 drivers/iio/temperature/maxim_thermocouple.c       |    2 +-
 drivers/infiniband/hw/hfi1/file_ops.c              |    4 +-
 drivers/infiniband/hw/hns/hns_roce_hw_v2.c         |    4 +-
 drivers/infiniband/hw/irdma/cm.c                   |   11 +-
 drivers/infiniband/hw/irdma/hw.c                   |   15 +-
 drivers/infiniband/hw/irdma/verbs.c                |    2 +-
 drivers/infiniband/hw/mlx5/fs.c                    |    6 +-
 drivers/infiniband/hw/qedr/verbs.c                 |    8 +-
 drivers/infiniband/sw/rxe/rxe_comp.c               |    8 +-
 drivers/infiniband/sw/rxe/rxe_loc.h                |    2 +-
 drivers/infiniband/sw/rxe/rxe_mr.c                 |   12 +-
 drivers/infiniband/sw/rxe/rxe_mw.c                 |    7 -
 drivers/infiniband/sw/rxe/rxe_pool.c               |    4 +-
 drivers/infiniband/sw/rxe/rxe_qp.c                 |   13 +-
 drivers/infiniband/sw/rxe/rxe_req.c                |   23 +-
 drivers/infiniband/sw/rxe/rxe_verbs.h              |    1 +
 drivers/infiniband/sw/siw/siw_cm.c                 |    7 +-
 drivers/infiniband/ulp/iser/iscsi_iser.c           |    4 +-
 drivers/infiniband/ulp/rtrs/rtrs-clt.c             |   35 +-
 drivers/infiniband/ulp/rtrs/rtrs-pri.h             |   21 +-
 drivers/infiniband/ulp/srpt/ib_srpt.c              |  148 +-
 drivers/infiniband/ulp/srpt/ib_srpt.h              |   18 +-
 drivers/input/serio/gscps2.c                       |    4 +
 drivers/interconnect/imx/imx.c                     |    8 +-
 drivers/iommu/arm/arm-smmu/qcom_iommu.c            |    7 +-
 drivers/iommu/exynos-iommu.c                       |    6 +-
 drivers/iommu/intel/dmar.c                         |    2 +-
 drivers/irqchip/Kconfig                            |    5 +-
 drivers/irqchip/irq-mips-gic.c                     |   84 +-
 drivers/md/dm-raid.c                               |    4 +-
 drivers/md/dm-thin-metadata.c                      |    7 +-
 drivers/md/dm-thin.c                               |    4 +-
 drivers/md/dm-writecache.c                         |   43 +-
 drivers/md/dm.c                                    |    5 +
 drivers/md/md.c                                    |    2 +-
 drivers/md/raid10.c                                |    5 +-
 drivers/media/i2c/Kconfig                          |    1 +
 drivers/media/pci/sta2x11/Kconfig                  |    2 +-
 drivers/media/pci/tw686x/tw686x-core.c             |   18 +-
 drivers/media/pci/tw686x/tw686x-video.c            |    4 +-
 drivers/media/platform/amphion/vdec.c              |  123 +-
 drivers/media/platform/amphion/vpu.h               |    1 +
 drivers/media/platform/amphion/vpu_core.c          |    7 +-
 drivers/media/platform/amphion/vpu_malone.c        |    6 +-
 drivers/media/platform/amphion/vpu_msgs.c          |    7 +-
 drivers/media/platform/amphion/vpu_rpc.h           |    7 +-
 drivers/media/platform/amphion/vpu_v4l2.c          |   62 +-
 drivers/media/platform/amphion/vpu_v4l2.h          |    3 +
 drivers/media/platform/atmel/atmel-sama7g5-isc.c   |    2 +
 drivers/media/platform/mediatek/mdp/mtk_mdp_ipi.h  |    2 +
 .../platform/mediatek/vcodec/mtk_vcodec_dec.c      |    7 +-
 .../platform/mediatek/vcodec/mtk_vcodec_dec_drv.c  |    5 +
 drivers/media/platform/nxp/imx-jpeg/mxc-jpeg-hw.c  |    5 +
 drivers/media/platform/nxp/imx-jpeg/mxc-jpeg-hw.h  |    9 +-
 drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c     |  477 +++---
 drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.h     |    6 +-
 drivers/media/platform/qcom/camss/camss-csid.c     |    2 +-
 .../media/platform/renesas/rcar-vin/rcar-core.c    |    2 +-
 drivers/media/usb/hdpvr/hdpvr-video.c              |    2 +-
 drivers/media/v4l2-core/v4l2-mem2mem.c             |    2 +-
 drivers/memstick/core/ms_block.c                   |   11 +-
 drivers/mfd/max77620.c                             |    2 +
 drivers/mfd/t7l66xb.c                              |    6 +-
 drivers/misc/cardreader/rtsx_pcr.c                 |    6 +-
 drivers/misc/eeprom/idt_89hpesx.c                  |    8 +-
 drivers/mmc/core/block.c                           |   28 +-
 drivers/mmc/core/quirks.h                          |    4 +-
 drivers/mmc/host/cavium-octeon.c                   |    1 +
 drivers/mmc/host/cavium-thunderx.c                 |    4 +-
 drivers/mmc/host/mxcmmc.c                          |    2 +-
 drivers/mmc/host/renesas_sdhi_core.c               |    8 +-
 drivers/mmc/host/sdhci-of-at91.c                   |    9 +-
 drivers/mmc/host/sdhci-of-esdhc.c                  |    1 +
 drivers/mtd/devices/mtd_dataflash.c                |    8 +
 drivers/mtd/devices/st_spi_fsm.c                   |    8 +-
 drivers/mtd/hyperbus/rpc-if.c                      |    8 +-
 drivers/mtd/maps/physmap-versatile.c               |    2 +
 drivers/mtd/nand/raw/arasan-nand-controller.c      |   16 +-
 drivers/mtd/nand/raw/meson_nand.c                  |    1 -
 drivers/mtd/parsers/ofpart_bcm4908.c               |    3 +
 drivers/mtd/parsers/redboot.c                      |    1 +
 drivers/mtd/sm_ftl.c                               |    2 +-
 drivers/mtd/spi-nor/core.c                         |    6 +-
 drivers/net/can/dev/netlink.c                      |    6 +-
 drivers/net/can/pch_can.c                          |    8 +-
 drivers/net/can/rcar/rcar_can.c                    |    8 +-
 drivers/net/can/sja1000/sja1000.c                  |    7 +-
 drivers/net/can/spi/hi311x.c                       |    5 +-
 drivers/net/can/sun4i_can.c                        |    9 +-
 drivers/net/can/usb/kvaser_usb/kvaser_usb_hydra.c  |   12 +-
 drivers/net/can/usb/kvaser_usb/kvaser_usb_leaf.c   |    6 +-
 drivers/net/can/usb/usb_8dev.c                     |    7 +-
 drivers/net/dsa/ocelot/Kconfig                     |    1 +
 drivers/net/dsa/ocelot/felix.c                     |    9 +
 drivers/net/dsa/ocelot/felix.h                     |    1 +
 drivers/net/dsa/ocelot/felix_vsc9959.c             |  300 +++-
 drivers/net/ethernet/atheros/ag71xx.c              |    2 +-
 drivers/net/ethernet/huawei/hinic/hinic_dev.h      |    3 -
 drivers/net/ethernet/huawei/hinic/hinic_main.c     |   68 +-
 drivers/net/ethernet/huawei/hinic/hinic_rx.c       |    2 -
 drivers/net/ethernet/huawei/hinic/hinic_tx.c       |    2 -
 drivers/net/ethernet/intel/iavf/iavf.h             |    6 +
 drivers/net/ethernet/intel/iavf/iavf_main.c        |   46 +-
 drivers/net/ethernet/intel/ice/ice_main.c          |    2 +-
 drivers/net/ethernet/intel/ice/ice_switch.c        |    2 +-
 drivers/net/ethernet/mellanox/mlx5/core/en.h       |   21 +-
 .../net/ethernet/mellanox/mlx5/core/en/params.c    |   12 +
 .../ethernet/mellanox/mlx5/core/en/tc/post_act.c   |    1 +
 .../net/ethernet/mellanox/mlx5/core/en/xsk/rx.h    |   14 +
 .../ethernet/mellanox/mlx5/core/en_accel/ktls.c    |    2 +-
 .../ethernet/mellanox/mlx5/core/eswitch_offloads.c |   23 +-
 drivers/net/ethernet/mellanox/mlx5/core/lib/tout.c |   11 +-
 drivers/net/ethernet/mellanox/mlx5/core/lib/tout.h |    1 -
 drivers/net/ethernet/mellanox/mlx5/core/main.c     |    4 +-
 drivers/net/ethernet/mellanox/mlx5/core/sriov.c    |   65 +-
 .../ethernet/mellanox/mlx5/core/steering/dr_dbg.c  |   13 +-
 drivers/net/ethernet/mscc/ocelot.c                 |    1 +
 drivers/net/ethernet/mscc/ocelot_ptp.c             |    8 +
 drivers/net/ethernet/pensando/ionic/ionic_lif.c    |    2 +-
 drivers/net/netdevsim/bpf.c                        |    8 +-
 drivers/net/netdevsim/fib.c                        |   27 +-
 drivers/net/phy/smsc.c                             |    6 +-
 drivers/net/usb/Kconfig                            |    3 +-
 drivers/net/usb/ax88179_178a.c                     |   26 +-
 drivers/net/usb/smsc95xx.c                         |  157 +-
 drivers/net/usb/usbnet.c                           |    8 +-
 drivers/net/wireguard/allowedips.c                 |    9 +-
 drivers/net/wireguard/selftest/allowedips.c        |    6 +-
 drivers/net/wireguard/selftest/ratelimiter.c       |   25 +-
 drivers/net/wireless/ath/ath10k/snoc.c             |    5 +-
 drivers/net/wireless/ath/ath11k/core.c             |   16 +-
 drivers/net/wireless/ath/ath11k/debug.h            |    4 +-
 drivers/net/wireless/ath/ath11k/dp_rx.c            |    5 +-
 drivers/net/wireless/ath/ath11k/htc.c              |    4 +-
 drivers/net/wireless/ath/ath11k/pci.c              |    2 +
 drivers/net/wireless/ath/ath9k/htc.h               |   10 +-
 drivers/net/wireless/ath/ath9k/htc_drv_init.c      |    3 +-
 drivers/net/wireless/ath/wil6210/debugfs.c         |   18 +-
 drivers/net/wireless/intel/iwlegacy/4965-rs.c      |    5 +-
 drivers/net/wireless/intel/iwlwifi/mvm/sta.c       |    1 +
 drivers/net/wireless/intersil/p54/main.c           |    2 +-
 drivers/net/wireless/intersil/p54/p54spi.c         |    3 +-
 drivers/net/wireless/mac80211_hwsim.c              |   14 +-
 drivers/net/wireless/marvell/libertas/if_usb.c     |    1 +
 drivers/net/wireless/mediatek/mt76/eeprom.c        |    5 +-
 drivers/net/wireless/mediatek/mt76/mac80211.c      |    1 +
 drivers/net/wireless/mediatek/mt76/mt7615/mac.c    |    7 +-
 drivers/net/wireless/mediatek/mt76/mt7615/main.c   |   21 -
 drivers/net/wireless/mediatek/mt76/mt7615/mcu.c    |   12 +-
 drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h |    1 -
 .../net/wireless/mediatek/mt76/mt76x02_usb_mcu.c   |    2 +-
 drivers/net/wireless/mediatek/mt76/mt7921/init.c   |    6 +-
 drivers/net/wireless/mediatek/mt76/mt7921/mcu.c    |   15 +-
 .../net/wireless/mediatek/mt76/mt7921/pci_mcu.c    |    6 +-
 .../net/wireless/mediatek/mt76/mt7921/sdio_mcu.c   |   10 +-
 drivers/net/wireless/microchip/wilc1000/spi.c      |    6 +-
 drivers/net/wireless/realtek/rtlwifi/debug.c       |    8 +-
 drivers/net/wireless/realtek/rtw88/main.c          |    4 +
 drivers/net/wireless/realtek/rtw89/rtw8852a_rfk.c  |    4 +-
 drivers/nvme/host/core.c                           |   14 +-
 drivers/nvme/host/fc.c                             |   18 +
 drivers/nvme/host/multipath.c                      |    1 +
 drivers/nvme/host/trace.h                          |    2 +-
 drivers/nvme/target/zns.c                          |    3 +-
 drivers/of/device.c                                |    5 +-
 drivers/of/fdt.c                                   |    2 +-
 drivers/of/kexec.c                                 |   17 +
 drivers/opp/core.c                                 |    4 +-
 drivers/parisc/lba_pci.c                           |    6 +-
 drivers/pci/controller/dwc/pcie-designware-ep.c    |   18 +-
 drivers/pci/controller/dwc/pcie-designware-host.c  |   30 +-
 drivers/pci/controller/dwc/pcie-designware.c       |   46 +-
 drivers/pci/controller/dwc/pcie-qcom.c             |   58 +-
 drivers/pci/controller/dwc/pcie-tegra194.c         |   49 +-
 drivers/pci/controller/pcie-mediatek-gen3.c        |    7 +-
 drivers/pci/controller/pcie-microchip-host.c       |    2 +
 drivers/pci/endpoint/functions/pci-epf-test.c      |    1 -
 drivers/pci/pcie/aer.c                             |    7 +-
 drivers/pci/pcie/portdrv_core.c                    |    9 +-
 drivers/perf/arm_spe_pmu.c                         |   22 +-
 drivers/perf/riscv_pmu.c                           |    1 -
 drivers/perf/riscv_pmu_sbi.c                       |   21 +-
 drivers/phy/qualcomm/phy-qcom-qmp.h                |    3 +-
 drivers/phy/rockchip/phy-rockchip-inno-usb2.c      |    4 +-
 drivers/phy/samsung/phy-exynosautov9-ufs.c         |   18 +-
 drivers/phy/st/phy-stm32-usbphyc.c                 |    4 +-
 drivers/phy/ti/phy-tusb1210.c                      |    5 +-
 drivers/pinctrl/Kconfig                            |    2 +-
 drivers/platform/chrome/cros_ec.c                  |    8 +-
 drivers/platform/mellanox/mlxreg-lc.c              |   82 +-
 drivers/platform/olpc/olpc-ec.c                    |    2 +-
 drivers/platform/x86/pmc_atom.c                    |   19 +-
 drivers/pwm/pwm-lpc18xx-sct.c                      |   55 +-
 drivers/pwm/pwm-sifive.c                           |   61 +-
 drivers/regulator/of_regulator.c                   |    6 +-
 drivers/regulator/qcom_smd-regulator.c             |    4 +-
 drivers/remoteproc/imx_rproc.c                     |    7 +-
 drivers/remoteproc/qcom_q6v5_pas.c                 |    3 +
 drivers/remoteproc/qcom_sysmon.c                   |   10 +
 drivers/remoteproc/qcom_wcnss.c                    |   10 +-
 drivers/remoteproc/ti_k3_r5_remoteproc.c           |    2 +
 drivers/rpmsg/mtk_rpmsg.c                          |    2 +
 drivers/rpmsg/qcom_smd.c                           |    1 +
 drivers/rpmsg/rpmsg_char.c                         |    7 +-
 drivers/rtc/rtc-rx8025.c                           |   22 +-
 drivers/s390/char/zcore.c                          |   11 +-
 drivers/s390/cio/vfio_ccw_drv.c                    |   19 +-
 drivers/s390/cio/vfio_ccw_ops.c                    |    2 +-
 drivers/s390/scsi/zfcp_fc.c                        |   29 +-
 drivers/s390/scsi/zfcp_fc.h                        |    6 +-
 drivers/s390/scsi/zfcp_fsf.c                       |    4 +-
 drivers/scsi/be2iscsi/be_main.c                    |    2 +-
 drivers/scsi/bnx2i/bnx2i_iscsi.c                   |    2 +-
 drivers/scsi/cxgbi/libcxgbi.c                      |    2 +-
 drivers/scsi/iscsi_tcp.c                           |    4 +-
 drivers/scsi/libiscsi.c                            |    9 +-
 drivers/scsi/lpfc/lpfc_scsi.c                      |    1 -
 drivers/scsi/qedi/qedi_main.c                      |    9 +-
 drivers/scsi/qla2xxx/qla_attr.c                    |   24 +-
 drivers/scsi/qla2xxx/qla_bsg.c                     |   10 +-
 drivers/scsi/qla2xxx/qla_dbg.h                     |    2 +-
 drivers/scsi/qla2xxx/qla_def.h                     |   18 +-
 drivers/scsi/qla2xxx/qla_edif.c                    |  502 +++++--
 drivers/scsi/qla2xxx/qla_edif.h                    |    7 +-
 drivers/scsi/qla2xxx/qla_edif_bsg.h                |  106 +-
 drivers/scsi/qla2xxx/qla_fw.h                      |    2 +-
 drivers/scsi/qla2xxx/qla_gbl.h                     |    6 +-
 drivers/scsi/qla2xxx/qla_gs.c                      |  129 +-
 drivers/scsi/qla2xxx/qla_init.c                    |   93 +-
 drivers/scsi/qla2xxx/qla_iocb.c                    |    5 +-
 drivers/scsi/qla2xxx/qla_isr.c                     |   25 +-
 drivers/scsi/qla2xxx/qla_mbx.c                     |   19 +-
 drivers/scsi/qla2xxx/qla_mid.c                     |    6 +-
 drivers/scsi/qla2xxx/qla_nvme.c                    |    5 -
 drivers/scsi/qla2xxx/qla_os.c                      |   93 +-
 drivers/scsi/qla2xxx/qla_target.c                  |   35 +-
 drivers/scsi/scsi_transport_iscsi.c                |   66 +-
 drivers/scsi/sg.c                                  |   53 +-
 drivers/scsi/smartpqi/smartpqi_init.c              |    4 +-
 drivers/scsi/ufs/ufshcd.c                          |    6 +-
 drivers/soc/amlogic/meson-mx-socinfo.c             |    1 +
 drivers/soc/amlogic/meson-secure-pwrc.c            |    4 +-
 drivers/soc/fsl/guts.c                             |    2 +-
 drivers/soc/qcom/Kconfig                           |    1 +
 drivers/soc/qcom/ocmem.c                           |    3 +
 drivers/soc/qcom/qcom_aoss.c                       |    4 +-
 drivers/soc/qcom/socinfo.c                         |    3 +-
 drivers/soc/renesas/r8a779a0-sysc.c                |   10 +-
 drivers/soundwire/bus.c                            |   75 +-
 drivers/soundwire/bus_type.c                       |   38 +-
 drivers/soundwire/qcom.c                           |    4 +
 drivers/soundwire/slave.c                          |    3 +-
 drivers/soundwire/stream.c                         |   53 +-
 drivers/spi/spi-altera-dfl.c                       |   14 +-
 drivers/spi/spi-dw.h                               |    2 +-
 drivers/spi/spi-rspi.c                             |    4 +
 drivers/spi/spi-s3c64xx.c                          |    2 +-
 drivers/spi/spi-synquacer.c                        |    1 +
 drivers/spi/spi-tegra20-slink.c                    |    3 +-
 drivers/spi/spi.c                                  |   21 +-
 drivers/staging/fbtft/fbtft-core.c                 |    2 +-
 drivers/staging/media/atomisp/pci/atomisp_cmd.c    |   57 +-
 drivers/staging/media/hantro/hantro_drv.c          |    1 +
 drivers/staging/media/hantro/hantro_g2_hevc_dec.c  |   32 +-
 drivers/staging/media/hantro/hantro_g2_regs.h      |    2 +-
 drivers/staging/media/hantro/hantro_hevc.c         |   71 +-
 drivers/staging/media/hantro/hantro_hw.h           |   22 +-
 drivers/staging/media/hantro/hantro_v4l2.c         |    2 +-
 drivers/staging/media/hantro/imx8m_vpu_hw.c        |   80 +-
 drivers/staging/media/hantro/rockchip_vpu_hw.c     |  174 ++-
 drivers/staging/media/hantro/sama5d4_vdec_hw.c     |   40 +-
 drivers/staging/media/hantro/sunxi_vpu_hw.c        |   24 +-
 drivers/staging/media/sunxi/cedrus/cedrus_h265.c   |   36 +-
 drivers/staging/media/sunxi/cedrus/cedrus_regs.h   |    3 +-
 drivers/staging/rtl8192u/r8192U.h                  |    2 +-
 drivers/staging/rtl8192u/r8192U_dm.c               |   38 +-
 drivers/staging/rtl8192u/r8192U_dm.h               |    2 +-
 drivers/thermal/thermal_sysfs.c                    |   10 +-
 drivers/tty/n_gsm.c                                |  757 +++++++---
 drivers/tty/serial/8250/8250.h                     |   22 +
 drivers/tty/serial/8250/8250_bcm2835aux.c          |    6 +-
 drivers/tty/serial/8250/8250_bcm7271.c             |   24 +-
 drivers/tty/serial/8250/8250_fsl.c                 |    2 +-
 drivers/tty/serial/8250/8250_pci.c                 |  522 +++++--
 drivers/tty/serial/8250/8250_port.c                |   21 -
 drivers/tty/serial/fsl_lpuart.c                    |   12 +-
 drivers/tty/serial/mvebu-uart.c                    |   11 +
 drivers/tty/serial/pic32_uart.c                    |   13 +-
 drivers/tty/vt/vt.c                                |    2 +-
 drivers/usb/cdns3/cdns3-gadget.c                   |   11 +-
 drivers/usb/core/hcd.c                             |   26 +-
 drivers/usb/dwc3/core.c                            |    9 +-
 drivers/usb/dwc3/dwc3-qcom.c                       |    4 +-
 drivers/usb/dwc3/gadget.c                          |   92 +-
 drivers/usb/gadget/function/f_mass_storage.c       |   11 +-
 drivers/usb/gadget/udc/Kconfig                     |    2 +-
 drivers/usb/gadget/udc/aspeed-vhub/hub.c           |    4 +-
 drivers/usb/gadget/udc/tegra-xudc.c                |    8 +-
 drivers/usb/host/ehci-ppc-of.c                     |    1 +
 drivers/usb/host/ohci-nxp.c                        |    1 +
 drivers/usb/host/xhci-tegra.c                      |    8 +-
 drivers/usb/host/xhci.h                            |    2 +-
 drivers/usb/serial/sierra.c                        |    3 +-
 drivers/usb/serial/usb-serial.c                    |    2 +-
 drivers/usb/serial/usb_wwan.c                      |    3 +-
 drivers/usb/typec/ucsi/ucsi.c                      |    4 +
 drivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.c     |   15 +-
 drivers/vfio/pci/mlx5/main.c                       |   15 +-
 drivers/vfio/pci/vfio_pci.c                        |    2 +-
 drivers/vfio/pci/vfio_pci_core.c                   |    4 +
 drivers/video/fbdev/amba-clcd.c                    |   24 +-
 drivers/video/fbdev/arkfb.c                        |    9 +-
 drivers/video/fbdev/core/fbcon.c                   |   12 +-
 drivers/video/fbdev/s3fb.c                         |    2 +
 drivers/video/fbdev/sis/init.c                     |    4 +-
 drivers/video/fbdev/vt8623fb.c                     |    2 +
 drivers/watchdog/armada_37xx_wdt.c                 |    2 +
 drivers/watchdog/f71808e_wdt.c                     |    4 +-
 drivers/watchdog/sp5100_tco.c                      |    1 +
 fs/Makefile                                        |    2 -
 fs/attr.c                                          |    2 +
 fs/btrfs/block-group.c                             |   29 +-
 fs/btrfs/ctree.h                                   |   34 +-
 fs/btrfs/delalloc-space.c                          |    6 +-
 fs/btrfs/disk-io.c                                 |   38 +-
 fs/btrfs/extent-tree.c                             |   74 +-
 fs/btrfs/extent_io.c                               |    4 +-
 fs/btrfs/file.c                                    |    2 +-
 fs/btrfs/free-space-cache.c                        |    7 +-
 fs/btrfs/inode.c                                   |  177 ++-
 fs/btrfs/space-info.c                              |  117 +-
 fs/btrfs/space-info.h                              |   14 +-
 fs/btrfs/sysfs.c                                   |   37 +
 fs/btrfs/tree-log.c                                |   27 +-
 fs/btrfs/tree-log.h                                |    3 +
 fs/btrfs/volumes.c                                 |   28 +-
 fs/btrfs/zoned.c                                   |  127 +-
 fs/btrfs/zoned.h                                   |   30 +-
 fs/cifs/file.c                                     |   28 +-
 fs/erofs/decompressor.c                            |   16 +-
 fs/erofs/decompressor_lzma.c                       |    1 +
 fs/eventpoll.c                                     |   22 +
 fs/exec.c                                          |    3 +
 fs/ext2/super.c                                    |   12 +-
 fs/ext4/inline.c                                   |    3 +
 fs/ext4/inode.c                                    |   24 +-
 fs/ext4/migrate.c                                  |    4 +-
 fs/ext4/namei.c                                    |   23 +
 fs/ext4/resize.c                                   |    1 +
 fs/ext4/xattr.c                                    |  169 ++-
 fs/ext4/xattr.h                                    |   14 +
 fs/f2fs/checkpoint.c                               |    4 +-
 fs/f2fs/data.c                                     |  192 ++-
 fs/f2fs/debug.c                                    |   18 +-
 fs/f2fs/f2fs.h                                     |   60 +-
 fs/f2fs/file.c                                     |  164 +-
 fs/f2fs/gc.c                                       |  134 +-
 fs/f2fs/inode.c                                    |    3 +-
 fs/f2fs/namei.c                                    |   28 +-
 fs/f2fs/node.c                                     |    4 -
 fs/f2fs/node.h                                     |    1 -
 fs/f2fs/segment.c                                  |  391 ++---
 fs/f2fs/segment.h                                  |    7 +-
 fs/f2fs/super.c                                    |    6 +-
 fs/f2fs/verity.c                                   |    2 +-
 fs/fuse/control.c                                  |    4 +-
 fs/fuse/dir.c                                      |    7 +-
 fs/fuse/file.c                                     |   39 +-
 fs/fuse/inode.c                                    |    6 +
 fs/fuse/ioctl.c                                    |   15 +-
 fs/jbd2/commit.c                                   |    2 +-
 fs/jbd2/transaction.c                              |   14 +-
 fs/kernfs/dir.c                                    |    7 +-
 fs/ksmbd/connection.c                              |   20 +-
 fs/ksmbd/connection.h                              |   27 +-
 fs/ksmbd/ksmbd_netlink.h                           |    3 +-
 fs/ksmbd/smb2misc.c                                |   12 +-
 fs/ksmbd/smb2pdu.c                                 |  151 +-
 fs/ksmbd/smbacl.c                                  |  130 +-
 fs/ksmbd/smbacl.h                                  |    2 +-
 fs/ksmbd/transport_ipc.c                           |    3 +
 fs/ksmbd/transport_rdma.c                          |  161 +-
 fs/ksmbd/transport_rdma.h                          |    8 +
 fs/ksmbd/vfs.c                                     |    5 +
 fs/lockd/svc4proc.c                                |    8 +
 fs/lockd/xdr4.c                                    |   19 +-
 fs/mbcache.c                                       |   76 +-
 fs/namei.c                                         |    4 +
 fs/nfs/flexfilelayout/flexfilelayout.c             |    4 +
 fs/nfs/nfs3client.c                                |    1 -
 fs/nfsd/filecache.c                                |   22 +-
 fs/nfsd/filecache.h                                |    4 +-
 fs/nfsd/trace.h                                    |    8 -
 fs/overlayfs/export.c                              |    2 +-
 fs/proc/base.c                                     |   46 +-
 fs/splice.c                                        |   10 +-
 fs/zonefs/super.c                                  |    3 +-
 include/acpi/cppc_acpi.h                           |    2 +-
 include/crypto/internal/blake2s.h                  |  108 --
 include/dt-bindings/clock/qcom,gcc-msm8939.h       |    1 +
 include/linux/acpi_viot.h                          |    2 +
 include/linux/blkdev.h                             |   19 +-
 include/linux/bpf.h                                |  140 +-
 include/linux/bpf_types.h                          |    1 +
 include/linux/bpf_verifier.h                       |    3 +-
 include/linux/btf.h                                |   21 +
 include/linux/buffer_head.h                        |   25 +-
 include/linux/cpumask.h                            |   18 +
 include/linux/filter.h                             |    9 +
 include/linux/highmem.h                            |   10 +
 include/linux/hugetlb.h                            |    6 +-
 include/linux/iio/common/cros_ec_sensors_core.h    |    7 +-
 include/linux/iio/iio.h                            |   10 +-
 include/linux/kexec.h                              |   45 +-
 include/linux/kfifo.h                              |    2 +-
 include/linux/kvm_types.h                          |    2 +
 include/linux/lockd/xdr.h                          |    2 +
 include/linux/lockdep.h                            |   30 +-
 include/linux/mbcache.h                            |   10 +-
 include/linux/mfd/t7l66xb.h                        |    1 -
 include/linux/mlx5/driver.h                        |   12 +
 include/linux/nvme-fc-driver.h                     |   14 +
 include/linux/once_lite.h                          |   20 +-
 include/linux/perf_event.h                         |   16 +
 include/linux/pipe_fs_i.h                          |    9 +
 include/linux/rmap.h                               |    4 +-
 include/linux/sched.h                              |    2 +-
 include/linux/sched/rt.h                           |    8 -
 include/linux/sched/topology.h                     |    1 +
 include/linux/soundwire/sdw.h                      |    6 +-
 include/linux/swapops.h                            |   12 +-
 include/linux/tpm_eventlog.h                       |    2 +-
 include/linux/trace_events.h                       |   18 +
 include/linux/usb/hcd.h                            |    1 +
 include/linux/wait.h                               |    9 +-
 include/media/hevc-ctrls.h                         |    4 +-
 include/net/9p/client.h                            |    8 +-
 include/net/ax25.h                                 |    1 +
 include/net/bluetooth/hci.h                        |    1 +
 include/net/inet6_hashtables.h                     |   27 +-
 include/net/inet_hashtables.h                      |   44 +-
 include/net/inet_sock.h                            |   11 +
 include/net/pkt_sched.h                            |   17 +
 include/net/raw.h                                  |   16 +-
 include/net/rawv6.h                                |    7 +-
 include/net/sock.h                                 |   15 +-
 include/net/xdp_sock_drv.h                         |   11 +
 include/scsi/libiscsi.h                            |    2 +-
 include/scsi/scsi_transport_iscsi.h                |    1 +
 include/soc/mscc/ocelot.h                          |   27 +-
 include/trace/events/f2fs.h                        |   22 -
 include/trace/events/spmi.h                        |   12 +-
 include/trace/stages/stage1_struct_define.h        |    3 +
 include/trace/stages/stage2_data_offsets.h         |    3 +
 include/trace/stages/stage4_event_fields.h         |   11 +-
 include/trace/stages/stage5_get_offsets.h          |    4 +
 include/trace/stages/stage6_event_callback.h       |   12 +
 include/uapi/linux/bpf.h                           |   13 +
 include/uapi/linux/can/error.h                     |    5 +-
 include/uapi/linux/f2fs.h                          |    2 +-
 include/uapi/linux/netfilter/xt_IDLETIMER.h        |   17 +-
 init/main.c                                        |    1 +
 io_uring/Makefile                                  |    6 +
 {fs => io_uring}/io-wq.c                           |    0
 {fs => io_uring}/io-wq.h                           |    0
 {fs => io_uring}/io_uring.c                        |    6 +-
 kernel/bpf/arraymap.c                              |   36 +-
 kernel/bpf/bpf_struct_ops.c                        |   71 +-
 kernel/bpf/btf.c                                   |  470 +++++-
 kernel/bpf/cgroup.c                                |   70 +-
 kernel/bpf/core.c                                  |   35 +-
 kernel/bpf/hashtab.c                               |   64 +-
 kernel/bpf/helpers.c                               |   24 +
 kernel/bpf/map_in_map.c                            |    5 +-
 kernel/bpf/ringbuf.c                               |    4 +-
 kernel/bpf/syscall.c                               |  257 +++-
 kernel/bpf/trampoline.c                            |   73 +-
 kernel/bpf/verifier.c                              |  418 ++++--
 kernel/cgroup/cpuset.c                             |    2 +-
 kernel/dma/swiotlb.c                               |    2 +-
 kernel/irq/Kconfig                                 |    1 +
 kernel/irq/chip.c                                  |    3 +-
 kernel/irq/irqdomain.c                             |    2 +
 kernel/kexec_file.c                                |   66 +-
 kernel/kprobes.c                                   |    3 +-
 kernel/locking/lockdep.c                           |    7 +-
 kernel/power/user.c                                |   13 +-
 kernel/profile.c                                   |    7 +
 kernel/rcu/rcutorture.c                            |   28 +-
 kernel/sched/core.c                                |   52 +-
 kernel/sched/fair.c                                |  141 +-
 kernel/sched/features.h                            |    3 +-
 kernel/sched/rt.c                                  |   15 +-
 kernel/sched/sched.h                               |    1 -
 kernel/smp.c                                       |    4 +-
 kernel/time/hrtimer.c                              |    1 +
 kernel/time/timekeeping.c                          |    7 +-
 kernel/trace/blktrace.c                            |    5 +-
 lib/crypto/blake2s-selftest.c                      |   41 +
 lib/crypto/blake2s.c                               |   37 +-
 lib/iov_iter.c                                     |   15 +-
 lib/kunit/executor.c                               |    4 +-
 lib/livepatch/test_klp_callbacks_busy.c            |    8 +
 lib/overflow_kunit.c                               |    6 +
 lib/smp_processor_id.c                             |    2 +-
 lib/test_bpf.c                                     |    4 +-
 lib/test_hmm.c                                     |   10 +-
 lib/test_kasan.c                                   |   10 +
 mm/damon/reclaim.c                                 |    4 +-
 mm/gup.c                                           |    2 +-
 mm/huge_memory.c                                   |   11 +-
 mm/hugetlb.c                                       |   15 +-
 mm/hugetlb_cgroup.c                                |    1 +
 mm/kasan/hw_tags.c                                 |   32 +-
 mm/memory-failure.c                                |    2 +-
 mm/memory_hotplug.c                                |    2 +-
 mm/mempolicy.c                                     |    4 +-
 mm/memremap.c                                      |    2 +-
 mm/migrate.c                                       |   30 +-
 mm/mmap.c                                          |    1 -
 mm/page_alloc.c                                    |    8 +-
 mm/vmalloc.c                                       |   10 +-
 net/9p/client.c                                    |   36 +-
 net/9p/trans_fd.c                                  |   13 +-
 net/9p/trans_rdma.c                                |    2 +-
 net/9p/trans_virtio.c                              |    4 +-
 net/9p/trans_xen.c                                 |    2 +-
 net/ax25/af_ax25.c                                 |    4 +-
 net/batman-adv/trace.h                             |    9 +-
 net/bluetooth/hci_core.c                           |   10 +-
 net/bluetooth/hci_event.c                          |    5 +-
 net/bluetooth/hci_sync.c                           |    8 +-
 net/bluetooth/l2cap_core.c                         |   13 +-
 net/bluetooth/mgmt.c                               |   10 +-
 net/bpf/bpf_dummy_struct_ops.c                     |   24 +-
 net/core/filter.c                                  |    4 +-
 net/core/skmsg.c                                   |    4 +-
 net/dccp/proto.c                                   |   10 +-
 net/ipv4/af_inet.c                                 |    2 +
 net/ipv4/inet_hashtables.c                         |   17 +-
 net/ipv4/raw.c                                     |  164 +-
 net/ipv4/raw_diag.c                                |   53 +-
 net/ipv4/tcp.c                                     |   33 +-
 net/ipv4/tcp_output.c                              |   30 +-
 net/ipv4/udp.c                                     |    3 +-
 net/ipv6/af_inet6.c                                |    3 +
 net/ipv6/inet6_hashtables.c                        |    6 +-
 net/ipv6/raw.c                                     |  120 +-
 net/ipv6/udp.c                                     |    2 +-
 net/mptcp/protocol.c                               |    3 +-
 net/netfilter/nf_tables_api.c                      |   18 +-
 net/netfilter/nft_queue.c                          |   27 +
 net/rose/af_rose.c                                 |   11 +-
 net/rose/rose_route.c                              |    2 +
 net/sched/cls_route.c                              |    2 +-
 scripts/Makefile.modpost                           |    3 +-
 scripts/faddr2line                                 |    4 +-
 scripts/gdb/linux/dmesg.py                         |    9 +-
 scripts/gdb/linux/utils.py                         |   14 +-
 security/selinux/ss/policydb.h                     |    2 +
 security/selinux/ss/services.c                     |    9 +-
 sound/pci/hda/patch_cirrus.c                       |    1 +
 sound/pci/hda/patch_conexant.c                     |   11 +-
 sound/pci/hda/patch_realtek.c                      |  124 ++
 sound/soc/amd/yc/acp6x-mach.c                      |   32 +-
 sound/soc/atmel/mchp-spdifrx.c                     |    9 +-
 sound/soc/codecs/cros_ec_codec.c                   |    1 +
 sound/soc/codecs/da7210.c                          |    2 +
 sound/soc/codecs/msm8916-wcd-digital.c             |   46 +-
 sound/soc/codecs/mt6359-accdet.c                   |    1 +
 sound/soc/codecs/mt6359.c                          |    1 +
 sound/soc/codecs/wcd9335.c                         |   81 +-
 sound/soc/codecs/wsa881x.c                         |   10 +-
 sound/soc/fsl/fsl-asoc-card.c                      |    5 +-
 sound/soc/fsl/fsl_asrc.c                           |    6 +-
 sound/soc/fsl/fsl_easrc.c                          |    9 +-
 sound/soc/fsl/fsl_easrc.h                          |    2 +-
 sound/soc/fsl/imx-audmux.c                         |    2 +-
 sound/soc/fsl/imx-card.c                           |   22 +-
 sound/soc/generic/audio-graph-card.c               |    4 +-
 sound/soc/generic/audio-graph-card2.c              |   44 +-
 sound/soc/intel/boards/sof_rt5682.c                |   18 +-
 sound/soc/mediatek/mt6797/mt6797-mt6351.c          |    6 +-
 sound/soc/mediatek/mt8173/mt8173-rt5650-rt5676.c   |   10 +-
 sound/soc/mediatek/mt8173/mt8173-rt5650.c          |    9 +-
 sound/soc/qcom/lpass-cpu.c                         |    1 +
 sound/soc/qcom/qdsp6/q6adm.c                       |    2 +-
 sound/soc/samsung/aries_wm8994.c                   |    6 +-
 sound/soc/samsung/h1940_uda1380.c                  |    2 +-
 sound/soc/samsung/rx1950_uda1380.c                 |    4 +-
 sound/soc/sof/ipc3-topology.c                      |    1 +
 sound/soc/sof/mediatek/mt8195/mt8195-loader.c      |    2 +-
 sound/soc/sof/sof-priv.h                           |    4 +-
 sound/usb/bcd2000/bcd2000.c                        |    3 +-
 sound/usb/quirks.c                                 |    2 +
 tools/bpf/bpftool/link.c                           |    4 +
 tools/include/uapi/linux/bpf.h                     |   13 +
 tools/lib/bpf/bpf_tracing.h                        |    2 +-
 tools/lib/bpf/gen_loader.c                         |    2 +-
 tools/lib/bpf/libbpf.c                             |    9 +-
 tools/lib/bpf/xsk.c                                |    9 +-
 tools/perf/builtin-stat.c                          |   30 -
 tools/perf/util/dsos.c                             |   15 +-
 tools/perf/util/genelf.c                           |    6 +-
 tools/perf/util/symbol-elf.c                       |   27 +-
 tools/power/x86/intel-speed-select/isst-daemon.c   |    2 +-
 tools/testing/selftests/bpf/prog_tests/btf.c       |    2 +-
 .../selftests/bpf/prog_tests/fexit_stress.c        |   32 +-
 .../testing/selftests/bpf/prog_tests/sock_fields.c |    1 -
 .../testing/selftests/bpf/prog_tests/tc_redirect.c |    8 +-
 tools/testing/selftests/bpf/progs/test_tc_dtime.c  |   53 +-
 .../testing/selftests/bpf/verifier/ref_tracking.c  |    2 +-
 tools/testing/selftests/bpf/verifier/sock.c        |    6 +-
 tools/testing/selftests/kvm/lib/x86_64/processor.c |    2 +-
 .../selftests/powerpc/papr_attributes/attr_test.c  |   30 +-
 tools/testing/selftests/rcutorture/bin/kvm.sh      |   12 +-
 tools/testing/selftests/seccomp/seccomp_bpf.c      |    2 +-
 .../testing/selftests/timers/clocksource-switch.c  |    6 +-
 tools/testing/selftests/timers/valid-adjtimex.c    |    2 +-
 tools/testing/selftests/vm/hugepage-mremap.c       |    2 +-
 tools/testing/selftests/vm/hugetlb-madvise.c       |    5 +-
 .../selftests/wireguard/qemu/arch/riscv32.config   |    1 +
 tools/thermal/tmon/sysfs.c                         |   24 +-
 tools/thermal/tmon/tmon.h                          |    3 +
 tools/tracing/rtla/Makefile                        |    2 +-
 tools/tracing/rtla/src/trace.c                     |    9 +-
 tools/tracing/rtla/src/utils.c                     |    5 +-
 virt/kvm/kvm_main.c                                |   25 +-
 virt/kvm/pfncache.c                                |  207 ++-
 1199 files changed, 17321 insertions(+), 11538 deletions(-)



^ permalink raw reply	[relevance 1%]

* Linux 5.18.18
@ 2022-08-17 13:24  1% Greg Kroah-Hartman
  0 siblings, 0 replies; 77+ results
From: Greg Kroah-Hartman @ 2022-08-17 13:24 UTC (permalink / raw)
  To: linux-kernel, akpm, torvalds, stable; +Cc: lwn, jslaby, Greg Kroah-Hartman

I'm announcing the release of the 5.18.18 kernel.

All users of the 5.18 kernel series must upgrade.

The updated 5.18.y git tree can be found at:
	git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable.git linux-5.18.y
and can be browsed at the normal kernel.org git web browser:
	https://git.kernel.org/?p=linux/kernel/git/stable/linux-stable.git;a=summary

thanks,

greg k-h

------------

 Documentation/ABI/testing/sysfs-driver-xen-blkback              |    2 
 Documentation/ABI/testing/sysfs-driver-xen-blkfront             |    2 
 Documentation/admin-guide/device-mapper/writecache.rst          |   16 
 Documentation/admin-guide/kernel-parameters.txt                 |   29 
 Documentation/admin-guide/pm/cpuidle.rst                        |   15 
 Documentation/arm64/silicon-errata.rst                          |    4 
 Documentation/devicetree/bindings/riscv/sifive-l2-cache.yaml    |    6 
 Documentation/tty/device_drivers/oxsemi-tornado.rst             |  129 
 Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst       |    2 
 MAINTAINERS                                                     |    7 
 Makefile                                                        |    8 
 arch/Kconfig                                                    |    3 
 arch/arm/boot/dts/Makefile                                      |    1 
 arch/arm/boot/dts/aspeed-ast2500-evb.dts                        |    2 
 arch/arm/boot/dts/aspeed-ast2600-evb-a1.dts                     |    1 
 arch/arm/boot/dts/aspeed-ast2600-evb.dts                        |    2 
 arch/arm/boot/dts/bcm53015-meraki-mr26.dts                      |  166 
 arch/arm/boot/dts/imx6qdl-apalis.dtsi                           |    4 
 arch/arm/boot/dts/imx6ul.dtsi                                   |   33 
 arch/arm/boot/dts/imx7d-colibri-emmc.dtsi                       |    4 
 arch/arm/boot/dts/qcom-apq8064.dtsi                             |    8 
 arch/arm/boot/dts/qcom-apq8074-dragonboard.dts                  |  609 
 arch/arm/boot/dts/qcom-apq8084.dtsi                             |    2 
 arch/arm/boot/dts/qcom-mdm9615.dtsi                             |    1 
 arch/arm/boot/dts/qcom-msm8974-fairphone-fp2.dts                |  604 
 arch/arm/boot/dts/qcom-msm8974-lge-nexus5-hammerhead.dts        | 1145 
 arch/arm/boot/dts/qcom-msm8974-samsung-klte.dts                 | 1258 -
 arch/arm/boot/dts/qcom-msm8974-sony-xperia-amami.dts            |  432 
 arch/arm/boot/dts/qcom-msm8974-sony-xperia-castor.dts           |  996 
 arch/arm/boot/dts/qcom-msm8974-sony-xperia-honami.dts           |  479 
 arch/arm/boot/dts/qcom-msm8974-sony-xperia-rhine.dtsi           |  455 
 arch/arm/boot/dts/qcom-msm8974.dtsi                             | 1587 -
 arch/arm/boot/dts/qcom-pm8841.dtsi                              |    1 
 arch/arm/boot/dts/qcom-pm8941.dtsi                              |    2 
 arch/arm/boot/dts/qcom-sdx55.dtsi                               |    2 
 arch/arm/boot/dts/ste-ux500-samsung-codina.dts                  |    4 
 arch/arm/boot/dts/ste-ux500-samsung-gavini.dts                  |    4 
 arch/arm/boot/dts/ste-ux500-samsung-janice.dts                  |    4 
 arch/arm/boot/dts/uniphier-pxs2.dtsi                            |    8 
 arch/arm/crypto/Kconfig                                         |    2 
 arch/arm/crypto/Makefile                                        |    4 
 arch/arm/crypto/blake2s-shash.c                                 |   75 
 arch/arm/lib/findbit.S                                          |   16 
 arch/arm/mach-bcm/bcm_kona_smc.c                                |    1 
 arch/arm/mach-omap2/display.c                                   |    3 
 arch/arm/mach-omap2/pdata-quirks.c                              |    2 
 arch/arm/mach-omap2/prm3xxx.c                                   |    1 
 arch/arm/mach-shmobile/regulator-quirk-rcar-gen2.c              |    5 
 arch/arm/mach-zynq/common.c                                     |    1 
 arch/arm64/Kconfig                                              |   17 
 arch/arm64/boot/dts/allwinner/sun50i-a64-orangepi-win.dts       |    2 
 arch/arm64/boot/dts/exynos/exynosautov9-pinctrl.dtsi            |    6 
 arch/arm64/boot/dts/mediatek/mt7622-bananapi-bpi-r64.dts        |    2 
 arch/arm64/boot/dts/mediatek/mt8192.dtsi                        |   26 
 arch/arm64/boot/dts/nvidia/tegra186.dtsi                        |    1 
 arch/arm64/boot/dts/nvidia/tegra194-p2888.dtsi                  |    2 
 arch/arm64/boot/dts/nvidia/tegra194.dtsi                        |    1 
 arch/arm64/boot/dts/nvidia/tegra234.dtsi                        |    1 
 arch/arm64/boot/dts/qcom/ipq6018.dtsi                           |   22 
 arch/arm64/boot/dts/qcom/ipq8074.dtsi                           |    2 
 arch/arm64/boot/dts/qcom/msm8916.dtsi                           |    4 
 arch/arm64/boot/dts/qcom/msm8996.dtsi                           |    6 
 arch/arm64/boot/dts/qcom/msm8998-sony-xperia-yoshino-poplar.dts |   10 
 arch/arm64/boot/dts/qcom/qcs404.dtsi                            |    4 
 arch/arm64/boot/dts/qcom/sc7180-trogdor.dtsi                    |    1 
 arch/arm64/boot/dts/qcom/sc7180.dtsi                            |   24 
 arch/arm64/boot/dts/qcom/sc7280.dtsi                            |   30 
 arch/arm64/boot/dts/qcom/sdm630.dtsi                            |    7 
 arch/arm64/boot/dts/qcom/sdm636-sony-xperia-ganges-mermaid.dts  |    2 
 arch/arm64/boot/dts/qcom/sdm845-sony-xperia-tama-akatsuki.dts   |    5 
 arch/arm64/boot/dts/qcom/sdm845.dtsi                            |   22 
 arch/arm64/boot/dts/qcom/sm6125-sony-xperia-seine-pdx201.dts    |   36 
 arch/arm64/boot/dts/qcom/sm6125.dtsi                            |   30 
 arch/arm64/boot/dts/qcom/sm6350.dtsi                            |   22 
 arch/arm64/boot/dts/qcom/sm8150.dtsi                            |   24 
 arch/arm64/boot/dts/qcom/sm8250.dtsi                            |   30 
 arch/arm64/boot/dts/qcom/sm8350.dtsi                            |   24 
 arch/arm64/boot/dts/qcom/sm8450.dtsi                            |   22 
 arch/arm64/boot/dts/renesas/beacon-renesom-baseboard.dtsi       |    6 
 arch/arm64/boot/dts/renesas/r8a774c0.dtsi                       |    2 
 arch/arm64/boot/dts/renesas/r8a77990.dtsi                       |    2 
 arch/arm64/boot/dts/renesas/r8a779m8.dtsi                       |    5 
 arch/arm64/boot/dts/renesas/r9a07g054l2-smarc.dts               |    2 
 arch/arm64/boot/dts/socionext/uniphier-pxs3.dtsi                |    8 
 arch/arm64/crypto/Kconfig                                       |    1 
 arch/arm64/include/asm/esr.h                                    |    6 
 arch/arm64/include/asm/kexec.h                                  |    4 
 arch/arm64/include/asm/processor.h                              |    3 
 arch/arm64/kernel/armv8_deprecated.c                            |    9 
 arch/arm64/kernel/cpu_errata.c                                  |   16 
 arch/arm64/kernel/cpufeature.c                                  |   16 
 arch/arm64/kernel/hibernate.c                                   |    5 
 arch/arm64/kernel/mte.c                                         |    9 
 arch/arm64/kvm/hyp/nvhe/switch.c                                |    2 
 arch/arm64/kvm/hyp/vhe/switch.c                                 |    2 
 arch/arm64/mm/copypage.c                                        |    9 
 arch/arm64/mm/mteswap.c                                         |    9 
 arch/arm64/tools/cpucaps                                        |    1 
 arch/ia64/include/asm/processor.h                               |    2 
 arch/ia64/kernel/palinfo.c                                      |    2 
 arch/ia64/kernel/traps.c                                        |    2 
 arch/ia64/mm/init.c                                             |    2 
 arch/ia64/mm/tlb.c                                              |    4 
 arch/mips/kernel/proc.c                                         |    2 
 arch/mips/kernel/vdso.c                                         |    2 
 arch/mips/loongson64/numa.c                                     |    1 
 arch/mips/mm/physaddr.c                                         |   14 
 arch/parisc/kernel/cache.c                                      |    3 
 arch/parisc/kernel/drivers.c                                    |    9 
 arch/parisc/kernel/syscalls/syscall.tbl                         |    2 
 arch/powerpc/boot/cuboot-hotfoot.c                              |    2 
 arch/powerpc/configs/44x/akebono_defconfig                      |    2 
 arch/powerpc/configs/44x/currituck_defconfig                    |    2 
 arch/powerpc/configs/44x/fsp2_defconfig                         |    2 
 arch/powerpc/configs/44x/iss476-smp_defconfig                   |    2 
 arch/powerpc/configs/44x/warp_defconfig                         |    2 
 arch/powerpc/configs/52xx/lite5200b_defconfig                   |    2 
 arch/powerpc/configs/52xx/motionpro_defconfig                   |    2 
 arch/powerpc/configs/52xx/tqm5200_defconfig                     |    2 
 arch/powerpc/configs/adder875_defconfig                         |    2 
 arch/powerpc/configs/ep8248e_defconfig                          |    2 
 arch/powerpc/configs/ep88xc_defconfig                           |    2 
 arch/powerpc/configs/fsl-emb-nonhw.config                       |    2 
 arch/powerpc/configs/mgcoge_defconfig                           |    2 
 arch/powerpc/configs/mpc5200_defconfig                          |    2 
 arch/powerpc/configs/mpc8272_ads_defconfig                      |    2 
 arch/powerpc/configs/mpc885_ads_defconfig                       |    2 
 arch/powerpc/configs/ppc6xx_defconfig                           |    2 
 arch/powerpc/configs/pq2fads_defconfig                          |    2 
 arch/powerpc/configs/ps3_defconfig                              |    2 
 arch/powerpc/configs/tqm8xx_defconfig                           |    2 
 arch/powerpc/crypto/aes-spe-glue.c                              |    2 
 arch/powerpc/include/asm/archrandom.h                           |    5 
 arch/powerpc/include/asm/kexec.h                                |    9 
 arch/powerpc/include/asm/simple_spinlock.h                      |   15 
 arch/powerpc/kernel/Makefile                                    |    1 
 arch/powerpc/kernel/cputable.c                                  |    2 
 arch/powerpc/kernel/dawr.c                                      |    2 
 arch/powerpc/kernel/eeh.c                                       |    4 
 arch/powerpc/kernel/eeh_event.c                                 |    2 
 arch/powerpc/kernel/fadump.c                                    |    4 
 arch/powerpc/kernel/iommu.c                                     |    5 
 arch/powerpc/kernel/module_32.c                                 |    2 
 arch/powerpc/kernel/module_64.c                                 |    4 
 arch/powerpc/kernel/pci-common.c                                |   31 
 arch/powerpc/kernel/pci_of_scan.c                               |    2 
 arch/powerpc/kernel/process.c                                   |    4 
 arch/powerpc/kernel/prom_init.c                                 |    2 
 arch/powerpc/kernel/ptrace/ptrace-view.c                        |    2 
 arch/powerpc/kernel/rtas_flash.c                                |    2 
 arch/powerpc/kernel/setup-common.c                              |    2 
 arch/powerpc/kernel/signal_64.c                                 |    2 
 arch/powerpc/kernel/smp.c                                       |    2 
 arch/powerpc/kernel/time.c                                      |    4 
 arch/powerpc/kernel/watchdog.c                                  |    2 
 arch/powerpc/kexec/core_64.c                                    |    2 
 arch/powerpc/kexec/file_load_64.c                               |   55 
 arch/powerpc/kvm/book3s_64_mmu_hv.c                             |    2 
 arch/powerpc/kvm/book3s_64_vio_hv.c                             |    2 
 arch/powerpc/kvm/book3s_emulate.c                               |    2 
 arch/powerpc/kvm/book3s_hv_builtin.c                            |    7 
 arch/powerpc/kvm/book3s_hv_p9_entry.c                           |    2 
 arch/powerpc/kvm/book3s_hv_uvmem.c                              |    2 
 arch/powerpc/kvm/book3s_pr.c                                    |    2 
 arch/powerpc/kvm/book3s_xics.c                                  |    2 
 arch/powerpc/kvm/book3s_xive.c                                  |    6 
 arch/powerpc/kvm/e500mc.c                                       |    2 
 arch/powerpc/mm/book3s64/hash_pgtable.c                         |    2 
 arch/powerpc/mm/book3s64/hash_utils.c                           |    4 
 arch/powerpc/mm/book3s64/pgtable.c                              |    2 
 arch/powerpc/mm/book3s64/radix_pgtable.c                        |    2 
 arch/powerpc/mm/book3s64/radix_tlb.c                            |    2 
 arch/powerpc/mm/book3s64/slb.c                                  |    4 
 arch/powerpc/mm/init_64.c                                       |    4 
 arch/powerpc/mm/kasan/kasan_init_32.c                           |    2 
 arch/powerpc/mm/nohash/8xx.c                                    |    4 
 arch/powerpc/mm/nohash/book3e_hugetlbpage.c                     |    2 
 arch/powerpc/mm/nohash/kaslr_booke.c                            |    2 
 arch/powerpc/mm/nohash/tlb_low_64e.S                            |   17 
 arch/powerpc/mm/pgtable-frag.c                                  |    2 
 arch/powerpc/mm/pgtable_32.c                                    |    6 
 arch/powerpc/mm/ptdump/shared.c                                 |    6 
 arch/powerpc/perf/8xx-pmu.c                                     |    2 
 arch/powerpc/perf/core-book3s.c                                 |   41 
 arch/powerpc/perf/imc-pmu.c                                     |    4 
 arch/powerpc/perf/isa207-common.c                               |    6 
 arch/powerpc/platforms/512x/clock-commonclk.c                   |    2 
 arch/powerpc/platforms/512x/mpc512x_shared.c                    |    2 
 arch/powerpc/platforms/52xx/mpc52xx_common.c                    |    2 
 arch/powerpc/platforms/52xx/mpc52xx_gpt.c                       |    2 
 arch/powerpc/platforms/52xx/mpc52xx_lpbfifo.c                   |    2 
 arch/powerpc/platforms/85xx/mpc85xx_cds.c                       |    2 
 arch/powerpc/platforms/86xx/gef_ppc9a.c                         |    2 
 arch/powerpc/platforms/86xx/gef_sbc310.c                        |    2 
 arch/powerpc/platforms/86xx/gef_sbc610.c                        |    2 
 arch/powerpc/platforms/Kconfig.cputype                          |    4 
 arch/powerpc/platforms/book3s/vas-api.c                         |    2 
 arch/powerpc/platforms/cell/axon_msi.c                          |    1 
 arch/powerpc/platforms/cell/cbe_regs.c                          |    2 
 arch/powerpc/platforms/cell/iommu.c                             |    2 
 arch/powerpc/platforms/cell/spider-pci.c                        |    2 
 arch/powerpc/platforms/cell/spu_manage.c                        |    2 
 arch/powerpc/platforms/cell/spufs/inode.c                       |    1 
 arch/powerpc/platforms/powermac/low_i2c.c                       |    2 
 arch/powerpc/platforms/powernv/eeh-powernv.c                    |   10 
 arch/powerpc/platforms/powernv/idle.c                           |    4 
 arch/powerpc/platforms/powernv/ocxl.c                           |    2 
 arch/powerpc/platforms/powernv/opal-fadump.c                    |    2 
 arch/powerpc/platforms/powernv/opal-lpc.c                       |    2 
 arch/powerpc/platforms/powernv/opal-memory-errors.c             |    2 
 arch/powerpc/platforms/powernv/pci-sriov.c                      |    2 
 arch/powerpc/platforms/powernv/rng.c                            |   34 
 arch/powerpc/platforms/ps3/mm.c                                 |    2 
 arch/powerpc/platforms/ps3/system-bus.c                         |    2 
 arch/powerpc/platforms/pseries/eeh_pseries.c                    |    2 
 arch/powerpc/platforms/pseries/iommu.c                          |   89 
 arch/powerpc/platforms/pseries/setup.c                          |    4 
 arch/powerpc/platforms/pseries/vas-sysfs.c                      |    2 
 arch/powerpc/platforms/pseries/vas.c                            |    2 
 arch/powerpc/sysdev/fsl_lbc.c                                   |    2 
 arch/powerpc/sysdev/fsl_pci.c                                   |   10 
 arch/powerpc/sysdev/fsl_pci.h                                   |    1 
 arch/powerpc/sysdev/ge/ge_pic.c                                 |    2 
 arch/powerpc/sysdev/mpic_msgr.c                                 |    2 
 arch/powerpc/sysdev/mpic_msi.c                                  |    2 
 arch/powerpc/sysdev/mpic_timer.c                                |    2 
 arch/powerpc/sysdev/mpic_u3msi.c                                |    2 
 arch/powerpc/sysdev/xive/native.c                               |    2 
 arch/powerpc/sysdev/xive/spapr.c                                |    1 
 arch/powerpc/xmon/ppc-opc.c                                     |    2 
 arch/powerpc/xmon/xmon.c                                        |    2 
 arch/riscv/boot/dts/starfive/jh7100.dtsi                        |    2 
 arch/riscv/include/asm/cpu_ops.h                                |    1 
 arch/riscv/kernel/cpu_ops.c                                     |    4 
 arch/riscv/kernel/cpu_ops_spinwait.c                            |    6 
 arch/riscv/kernel/crash_save_regs.S                             |    2 
 arch/riscv/kernel/machine_kexec.c                               |   28 
 arch/riscv/kernel/probes/uprobes.c                              |    6 
 arch/riscv/lib/uaccess.S                                        |    4 
 arch/riscv/mm/init.c                                            |    4 
 arch/s390/include/asm/gmap.h                                    |    2 
 arch/s390/include/asm/kexec.h                                   |    3 
 arch/s390/include/asm/unwind.h                                  |    2 
 arch/s390/kernel/crash_dump.c                                   |    2 
 arch/s390/kernel/machine_kexec_file.c                           |   18 
 arch/s390/kvm/intercept.c                                       |   15 
 arch/s390/kvm/pv.c                                              |    9 
 arch/s390/kvm/sigp.c                                            |    4 
 arch/s390/mm/gmap.c                                             |   86 
 arch/um/drivers/random.c                                        |    2 
 arch/um/include/asm/archrandom.h                                |   30 
 arch/um/include/asm/xor.h                                       |    2 
 arch/um/include/shared/os.h                                     |    7 
 arch/um/kernel/um_arch.c                                        |    8 
 arch/um/os-Linux/util.c                                         |    6 
 arch/x86/Kconfig                                                |    1 
 arch/x86/Kconfig.debug                                          |    3 
 arch/x86/boot/Makefile                                          |    2 
 arch/x86/boot/compressed/Makefile                               |    4 
 arch/x86/crypto/Makefile                                        |    4 
 arch/x86/crypto/blake2s-glue.c                                  |    3 
 arch/x86/crypto/blake2s-shash.c                                 |   77 
 arch/x86/entry/Makefile                                         |    3 
 arch/x86/entry/thunk_32.S                                       |    2 
 arch/x86/entry/thunk_64.S                                       |    4 
 arch/x86/entry/vdso/Makefile                                    |    2 
 arch/x86/events/intel/lbr.c                                     |   36 
 arch/x86/include/asm/kexec.h                                    |    6 
 arch/x86/include/asm/kvm_host.h                                 |    3 
 arch/x86/kernel/cpu/bugs.c                                      |   10 
 arch/x86/kernel/cpu/intel.c                                     |   27 
 arch/x86/kernel/ftrace.c                                        |    1 
 arch/x86/kernel/kprobes/core.c                                  |   18 
 arch/x86/kernel/pmem.c                                          |    7 
 arch/x86/kernel/process.c                                       |    9 
 arch/x86/kvm/emulate.c                                          |   23 
 arch/x86/kvm/mmu/mmu.c                                          |    2 
 arch/x86/kvm/mmu/paging_tmpl.h                                  |    9 
 arch/x86/kvm/mmu/spte.c                                         |    2 
 arch/x86/kvm/svm/nested.c                                       |    3 
 arch/x86/kvm/svm/svm.c                                          |   29 
 arch/x86/kvm/vmx/nested.c                                       |  107 
 arch/x86/kvm/vmx/nested.h                                       |    3 
 arch/x86/kvm/vmx/pmu_intel.c                                    |   13 
 arch/x86/kvm/vmx/vmx.c                                          |    4 
 arch/x86/kvm/vmx/vmx.h                                          |   12 
 arch/x86/kvm/x86.c                                              |   33 
 arch/x86/kvm/x86.h                                              |    2 
 arch/x86/mm/extable.c                                           |   16 
 arch/x86/mm/numa.c                                              |    4 
 arch/x86/net/bpf_jit_comp.c                                     |   67 
 arch/x86/platform/olpc/olpc-xo1-sci.c                           |    2 
 arch/x86/um/Makefile                                            |    3 
 arch/xtensa/platforms/iss/network.c                             |   42 
 block/bio.c                                                     |   99 
 block/blk-iocost.c                                              |   20 
 block/blk-iolatency.c                                           |   18 
 block/blk-mq-debugfs.c                                          |   28 
 block/blk-mq-debugfs.h                                          |    5 
 block/blk-mq-sched.c                                            |   11 
 block/blk-rq-qos.c                                              |    2 
 block/blk-rq-qos.h                                              |   18 
 block/blk-sysfs.c                                               |   20 
 block/blk-wbt.c                                                 |   12 
 crypto/Kconfig                                                  |   20 
 crypto/Makefile                                                 |    1 
 crypto/asymmetric_keys/public_key.c                             |    7 
 crypto/blake2s_generic.c                                        |   75 
 crypto/tcrypt.c                                                 |   12 
 crypto/testmgr.c                                                |   24 
 crypto/testmgr.h                                                |  217 
 drivers/acpi/acpi_lpss.c                                        |    3 
 drivers/acpi/apei/einj.c                                        |    2 
 drivers/acpi/bus.c                                              |    1 
 drivers/acpi/cppc_acpi.c                                        |   54 
 drivers/acpi/ec.c                                               |   82 
 drivers/acpi/processor_idle.c                                   |    6 
 drivers/acpi/sleep.c                                            |    8 
 drivers/acpi/video_detect.c                                     |    8 
 drivers/acpi/viot.c                                             |   26 
 drivers/android/binder.c                                        |  114 
 drivers/android/binder_alloc.c                                  |   30 
 drivers/android/binder_alloc.h                                  |    2 
 drivers/android/binder_alloc_selftest.c                         |    2 
 drivers/android/binder_internal.h                               |   46 
 drivers/android/binderfs.c                                      |   47 
 drivers/base/dd.c                                               |    5 
 drivers/base/node.c                                             |    4 
 drivers/base/power/domain.c                                     |    3 
 drivers/base/topology.c                                         |   32 
 drivers/block/null_blk/main.c                                   |   14 
 drivers/block/rnbd/rnbd-srv.c                                   |    3 
 drivers/block/xen-blkback/xenbus.c                              |   20 
 drivers/block/xen-blkfront.c                                    |    4 
 drivers/bluetooth/hci_intel.c                                   |    6 
 drivers/bluetooth/hci_serdev.c                                  |   11 
 drivers/bus/hisi_lpc.c                                          |   10 
 drivers/char/tpm/tpm2-cmd.c                                     |    6 
 drivers/clk/imx/clk-fracn-gppll.c                               |   33 
 drivers/clk/imx/clk-imx93.c                                     |    4 
 drivers/clk/mediatek/reset.c                                    |    4 
 drivers/clk/qcom/camcc-sdm845.c                                 |    4 
 drivers/clk/qcom/camcc-sm8250.c                                 |   16 
 drivers/clk/qcom/clk-krait.c                                    |    7 
 drivers/clk/qcom/clk-rcg2.c                                     |   16 
 drivers/clk/qcom/dispcc-sm8250.c                                |    1 
 drivers/clk/qcom/gcc-ipq8074.c                                  |   60 
 drivers/clk/qcom/gcc-msm8939.c                                  |   33 
 drivers/clk/qcom/gdsc.c                                         |    8 
 drivers/clk/qcom/videocc-sm8250.c                               |    4 
 drivers/clk/renesas/r9a06g032-clocks.c                          |    8 
 drivers/clk/renesas/rzg2l-cpg.c                                 |    2 
 drivers/crypto/allwinner/sun8i-ss/sun8i-ss-cipher.c             |    1 
 drivers/crypto/allwinner/sun8i-ss/sun8i-ss-core.c               |   22 
 drivers/crypto/allwinner/sun8i-ss/sun8i-ss-hash.c               |   15 
 drivers/crypto/allwinner/sun8i-ss/sun8i-ss.h                    |    4 
 drivers/crypto/ccp/sev-dev.c                                    |   12 
 drivers/crypto/hisilicon/hpre/hpre_crypto.c                     |    2 
 drivers/crypto/hisilicon/sec/sec_algs.c                         |   14 
 drivers/crypto/hisilicon/sec/sec_drv.h                          |    2 
 drivers/crypto/hisilicon/sec2/sec.h                             |    2 
 drivers/crypto/hisilicon/sec2/sec_crypto.c                      |   26 
 drivers/crypto/hisilicon/sec2/sec_crypto.h                      |    1 
 drivers/crypto/inside-secure/safexcel.c                         |    2 
 drivers/dma/dw-edma/dw-edma-core.c                              |    2 
 drivers/dma/imx-dma.c                                           |    2 
 drivers/dma/sf-pdma/sf-pdma.c                                   |   44 
 drivers/firmware/arm_scpi.c                                     |   61 
 drivers/firmware/tegra/bpmp-debugfs.c                           |   10 
 drivers/fpga/altera-pr-ip-core.c                                |    2 
 drivers/gpio/gpiolib-of.c                                       |    4 
 drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c                |    6 
 drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c                          |    2 
 drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c                         |   96 
 drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.h                         |   11 
 drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c                   |   10 
 drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c                         |    2 
 drivers/gpu/drm/amd/amdgpu/amdgpu_object.c                      |    4 
 drivers/gpu/drm/amd/amdgpu/nbio_v2_3.c                          |   21 
 drivers/gpu/drm/amd/amdgpu/nbio_v2_3.h                          |    1 
 drivers/gpu/drm/amd/amdgpu/nbio_v7_4.c                          |   21 
 drivers/gpu/drm/amd/amdgpu/nbio_v7_4.h                          |    1 
 drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c       |    2 
 drivers/gpu/drm/bridge/Kconfig                                  |    2 
 drivers/gpu/drm/bridge/adv7511/adv7511_drv.c                    |   24 
 drivers/gpu/drm/bridge/analogix/anx7625.c                       |   17 
 drivers/gpu/drm/bridge/lontium-lt9611.c                         |    2 
 drivers/gpu/drm/bridge/lontium-lt9611uxc.c                      |    2 
 drivers/gpu/drm/bridge/sil-sii8620.c                            |    4 
 drivers/gpu/drm/bridge/tc358767.c                               |   62 
 drivers/gpu/drm/dp/drm_dp_aux_bus.c                             |    4 
 drivers/gpu/drm/dp/drm_dp_mst_topology.c                        |    7 
 drivers/gpu/drm/drm_gem.c                                       |    4 
 drivers/gpu/drm/drm_gem_shmem_helper.c                          |    1 
 drivers/gpu/drm/drm_mipi_dbi.c                                  |    7 
 drivers/gpu/drm/exynos/exynos7_drm_decon.c                      |   17 
 drivers/gpu/drm/hyperv/hyperv_drm_modeset.c                     |    2 
 drivers/gpu/drm/ingenic/ingenic-drm-drv.c                       |   10 
 drivers/gpu/drm/ingenic/ingenic-drm.h                           |    3 
 drivers/gpu/drm/mcde/mcde_dsi.c                                 |    1 
 drivers/gpu/drm/mediatek/mtk_dpi.c                              |   33 
 drivers/gpu/drm/mediatek/mtk_dsi.c                              |   93 
 drivers/gpu/drm/meson/meson_encoder_cvbs.c                      |    1 
 drivers/gpu/drm/meson/meson_encoder_hdmi.c                      |   19 
 drivers/gpu/drm/msm/adreno/a5xx_gpu.c                           |    8 
 drivers/gpu/drm/msm/adreno/a6xx_gmu.c                           |   13 
 drivers/gpu/drm/msm/adreno/a6xx_gpu.c                           |   12 
 drivers/gpu/drm/msm/adreno/a6xx_gpu.h                           |    3 
 drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c                        |    6 
 drivers/gpu/drm/msm/disp/mdp5/mdp5_pipe.c                       |    3 
 drivers/gpu/drm/msm/hdmi/hdmi.c                                 |    3 
 drivers/gpu/drm/msm/msm_gpu.h                                   |   11 
 drivers/gpu/drm/msm/msm_gpu_devfreq.c                           |   39 
 drivers/gpu/drm/nouveau/nouveau_connector.c                     |    8 
 drivers/gpu/drm/nouveau/nouveau_display.c                       |    4 
 drivers/gpu/drm/nouveau/nouveau_fbcon.c                         |    2 
 drivers/gpu/drm/nouveau/nvkm/subdev/bios/base.c                 |    2 
 drivers/gpu/drm/panel/Kconfig                                   |    2 
 drivers/gpu/drm/radeon/.gitignore                               |    2 
 drivers/gpu/drm/radeon/Kconfig                                  |    2 
 drivers/gpu/drm/radeon/Makefile                                 |    2 
 drivers/gpu/drm/radeon/ni_dpm.c                                 |    6 
 drivers/gpu/drm/radeon/radeon_device.c                          |    2 
 drivers/gpu/drm/rockchip/analogix_dp-rockchip.c                 |   10 
 drivers/gpu/drm/rockchip/rockchip_drm_vop.c                     |    3 
 drivers/gpu/drm/tegra/gem.c                                     |   11 
 drivers/gpu/drm/tiny/st7735r.c                                  |    1 
 drivers/gpu/drm/vc4/vc4_crtc.c                                  |   14 
 drivers/gpu/drm/vc4/vc4_drv.c                                   |   19 
 drivers/gpu/drm/vc4/vc4_dsi.c                                   |  152 
 drivers/gpu/drm/vc4/vc4_hdmi.c                                  |  157 
 drivers/gpu/drm/vc4/vc4_hdmi.h                                  |    8 
 drivers/gpu/drm/vc4/vc4_hdmi_regs.h                             |    7 
 drivers/gpu/drm/vc4/vc4_kms.c                                   |    4 
 drivers/gpu/drm/vc4/vc4_plane.c                                 |   30 
 drivers/gpu/drm/virtio/virtgpu_ioctl.c                          |    6 
 drivers/gpu/drm/virtio/virtgpu_object.c                         |    4 
 drivers/gpu/drm/vkms/vkms_composer.c                            |    2 
 drivers/hid/amd-sfh-hid/amd_sfh_client.c                        |    2 
 drivers/hid/amd-sfh-hid/amd_sfh_hid.c                           |   12 
 drivers/hid/amd-sfh-hid/amd_sfh_pcie.c                          |    3 
 drivers/hid/hid-alps.c                                          |    2 
 drivers/hid/hid-cp2112.c                                        |    5 
 drivers/hid/hid-ids.h                                           |    1 
 drivers/hid/hid-input.c                                         |    2 
 drivers/hid/hid-mcp2221.c                                       |    3 
 drivers/hid/hid-nintendo.c                                      |    1 
 drivers/hid/wacom_sys.c                                         |    2 
 drivers/hid/wacom_wac.c                                         |   72 
 drivers/hwmon/dell-smm-hwmon.c                                  |    8 
 drivers/hwmon/drivetemp.c                                       |    1 
 drivers/hwmon/sch56xx-common.c                                  |   44 
 drivers/hwmon/sht15.c                                           |   17 
 drivers/hwtracing/coresight/coresight-config.h                  |    2 
 drivers/hwtracing/coresight/coresight-core.c                    |    1 
 drivers/hwtracing/coresight/coresight-syscfg.c                  |  295 
 drivers/hwtracing/coresight/coresight-syscfg.h                  |   13 
 drivers/hwtracing/intel_th/msu-sink.c                           |    3 
 drivers/hwtracing/intel_th/msu.c                                |   14 
 drivers/hwtracing/intel_th/pci.c                                |   25 
 drivers/i2c/busses/i2c-cadence.c                                |   10 
 drivers/i2c/busses/i2c-mxs.c                                    |    2 
 drivers/i2c/busses/i2c-npcm7xx.c                                |   50 
 drivers/i2c/busses/i2c-qcom-geni.c                              |    2 
 drivers/i2c/i2c-core-base.c                                     |    3 
 drivers/i2c/muxes/i2c-mux-gpmux.c                               |    1 
 drivers/idle/intel_idle.c                                       |  149 
 drivers/iio/accel/adxl313_core.c                                |    2 
 drivers/iio/accel/adxl355_core.c                                |    2 
 drivers/iio/accel/adxl367.c                                     |    2 
 drivers/iio/accel/adxl367_spi.c                                 |    8 
 drivers/iio/accel/bma220_spi.c                                  |    2 
 drivers/iio/accel/bma400.h                                      |   25 
 drivers/iio/accel/bma400_core.c                                 |   81 
 drivers/iio/accel/bma400_i2c.c                                  |    8 
 drivers/iio/accel/bma400_spi.c                                  |    6 
 drivers/iio/accel/cros_ec_accel_legacy.c                        |    4 
 drivers/iio/accel/sca3000.c                                     |    4 
 drivers/iio/accel/sca3300.c                                     |    2 
 drivers/iio/adc/ad7266.c                                        |    4 
 drivers/iio/adc/ad7280a.c                                       |    2 
 drivers/iio/adc/ad7292.c                                        |    2 
 drivers/iio/adc/ad7298.c                                        |    2 
 drivers/iio/adc/ad7476.c                                        |    5 
 drivers/iio/adc/ad7606.h                                        |    4 
 drivers/iio/adc/ad7766.c                                        |    5 
 drivers/iio/adc/ad7768-1.c                                      |    4 
 drivers/iio/adc/ad7887.c                                        |    5 
 drivers/iio/adc/ad7923.c                                        |    4 
 drivers/iio/adc/ad7949.c                                        |    2 
 drivers/iio/adc/adi-axi-adc.c                                   |    7 
 drivers/iio/adc/hi8435.c                                        |    2 
 drivers/iio/adc/ltc2496.c                                       |    4 
 drivers/iio/adc/ltc2497.c                                       |    4 
 drivers/iio/adc/max1027.c                                       |    8 
 drivers/iio/adc/max11100.c                                      |    4 
 drivers/iio/adc/max1118.c                                       |    2 
 drivers/iio/adc/max1241.c                                       |    2 
 drivers/iio/adc/mcp320x.c                                       |    2 
 drivers/iio/adc/ti-adc0832.c                                    |    2 
 drivers/iio/adc/ti-adc084s021.c                                 |    4 
 drivers/iio/adc/ti-adc108s102.c                                 |    4 
 drivers/iio/adc/ti-adc12138.c                                   |    2 
 drivers/iio/adc/ti-adc128s052.c                                 |    2 
 drivers/iio/adc/ti-adc161s626.c                                 |    2 
 drivers/iio/adc/ti-ads124s08.c                                  |    2 
 drivers/iio/adc/ti-ads131e08.c                                  |    2 
 drivers/iio/adc/ti-ads7950.c                                    |    4 
 drivers/iio/adc/ti-ads8344.c                                    |    2 
 drivers/iio/adc/ti-ads8688.c                                    |    2 
 drivers/iio/adc/ti-tlc4541.c                                    |    4 
 drivers/iio/addac/ad74413r.c                                    |    4 
 drivers/iio/amplifiers/ad8366.c                                 |    4 
 drivers/iio/common/cros_ec_sensors/cros_ec_lid_angle.c          |    4 
 drivers/iio/common/cros_ec_sensors/cros_ec_sensors.c            |    6 
 drivers/iio/common/cros_ec_sensors/cros_ec_sensors_core.c       |   58 
 drivers/iio/common/ssp_sensors/ssp.h                            |    3 
 drivers/iio/dac/ad5064.c                                        |    4 
 drivers/iio/dac/ad5360.c                                        |    4 
 drivers/iio/dac/ad5421.c                                        |    4 
 drivers/iio/dac/ad5449.c                                        |    4 
 drivers/iio/dac/ad5504.c                                        |    2 
 drivers/iio/dac/ad5592r-base.h                                  |    4 
 drivers/iio/dac/ad5686.h                                        |    6 
 drivers/iio/dac/ad5755.c                                        |    4 
 drivers/iio/dac/ad5761.c                                        |    4 
 drivers/iio/dac/ad5764.c                                        |    4 
 drivers/iio/dac/ad5766.c                                        |    2 
 drivers/iio/dac/ad5770r.c                                       |    2 
 drivers/iio/dac/ad5791.c                                        |    2 
 drivers/iio/dac/ad7293.c                                        |    2 
 drivers/iio/dac/ad7303.c                                        |    4 
 drivers/iio/dac/ad8801.c                                        |    2 
 drivers/iio/dac/ltc2688.c                                       |    4 
 drivers/iio/dac/mcp4922.c                                       |    2 
 drivers/iio/dac/ti-dac082s085.c                                 |    2 
 drivers/iio/dac/ti-dac5571.c                                    |    2 
 drivers/iio/dac/ti-dac7311.c                                    |    2 
 drivers/iio/dac/ti-dac7612.c                                    |    4 
 drivers/iio/frequency/ad9523.c                                  |    6 
 drivers/iio/frequency/adf4350.c                                 |    6 
 drivers/iio/frequency/adf4371.c                                 |    2 
 drivers/iio/frequency/admv1013.c                                |    2 
 drivers/iio/frequency/admv1014.c                                |    2 
 drivers/iio/frequency/admv4420.c                                |    2 
 drivers/iio/frequency/adrf6780.c                                |    2 
 drivers/iio/gyro/adis16080.c                                    |    2 
 drivers/iio/gyro/adis16130.c                                    |    2 
 drivers/iio/gyro/adxrs450.c                                     |    2 
 drivers/iio/gyro/fxas21002c_core.c                              |    6 
 drivers/iio/imu/fxos8700_core.c                                 |    2 
 drivers/iio/imu/inv_icm42600/inv_icm42600.h                     |    2 
 drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.h              |    2 
 drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h                       |    2 
 drivers/iio/industrialio-buffer.c                               |    4 
 drivers/iio/industrialio-core.c                                 |   25 
 drivers/iio/light/cros_ec_light_prox.c                          |    6 
 drivers/iio/light/isl29028.c                                    |    2 
 drivers/iio/potentiometer/ad5110.c                              |    4 
 drivers/iio/potentiometer/ad5272.c                              |    2 
 drivers/iio/potentiometer/max5481.c                             |    2 
 drivers/iio/potentiometer/mcp41010.c                            |    2 
 drivers/iio/potentiometer/mcp4131.c                             |    2 
 drivers/iio/pressure/cros_ec_baro.c                             |    6 
 drivers/iio/proximity/as3935.c                                  |    2 
 drivers/iio/proximity/sx9324.c                                  |    4 
 drivers/iio/resolver/ad2s1200.c                                 |    2 
 drivers/iio/resolver/ad2s90.c                                   |    2 
 drivers/iio/temperature/ltc2983.c                               |    4 
 drivers/iio/temperature/max31865.c                              |    2 
 drivers/iio/temperature/maxim_thermocouple.c                    |    2 
 drivers/infiniband/hw/hfi1/file_ops.c                           |    4 
 drivers/infiniband/hw/hns/hns_roce_hw_v2.c                      |    4 
 drivers/infiniband/hw/irdma/cm.c                                |   11 
 drivers/infiniband/hw/irdma/hw.c                                |   15 
 drivers/infiniband/hw/irdma/verbs.c                             |    2 
 drivers/infiniband/hw/mlx5/fs.c                                 |    6 
 drivers/infiniband/hw/qedr/verbs.c                              |    8 
 drivers/infiniband/sw/rxe/rxe_comp.c                            |    8 
 drivers/infiniband/sw/rxe/rxe_loc.h                             |    2 
 drivers/infiniband/sw/rxe/rxe_mr.c                              |   12 
 drivers/infiniband/sw/rxe/rxe_mw.c                              |    7 
 drivers/infiniband/sw/rxe/rxe_pool.c                            |    4 
 drivers/infiniband/sw/rxe/rxe_qp.c                              |   13 
 drivers/infiniband/sw/rxe/rxe_req.c                             |   23 
 drivers/infiniband/sw/rxe/rxe_verbs.h                           |    1 
 drivers/infiniband/sw/siw/siw_cm.c                              |    7 
 drivers/infiniband/ulp/iser/iscsi_iser.c                        |    4 
 drivers/infiniband/ulp/rtrs/rtrs-clt.c                          |   35 
 drivers/infiniband/ulp/rtrs/rtrs-pri.h                          |   21 
 drivers/infiniband/ulp/srpt/ib_srpt.c                           |  148 
 drivers/infiniband/ulp/srpt/ib_srpt.h                           |   18 
 drivers/input/serio/gscps2.c                                    |    4 
 drivers/interconnect/imx/imx.c                                  |    8 
 drivers/iommu/arm/arm-smmu/qcom_iommu.c                         |    7 
 drivers/iommu/exynos-iommu.c                                    |    6 
 drivers/iommu/intel/dmar.c                                      |    2 
 drivers/irqchip/Kconfig                                         |    5 
 drivers/irqchip/irq-mips-gic.c                                  |   84 
 drivers/md/dm-raid.c                                            |    4 
 drivers/md/dm-thin-metadata.c                                   |    7 
 drivers/md/dm-thin.c                                            |    4 
 drivers/md/dm-writecache.c                                      |   43 
 drivers/md/dm.c                                                 |    5 
 drivers/md/md.c                                                 |    2 
 drivers/md/raid10.c                                             |    5 
 drivers/media/i2c/Kconfig                                       |    1 
 drivers/media/pci/sta2x11/Kconfig                               |    2 
 drivers/media/pci/tw686x/tw686x-core.c                          |   18 
 drivers/media/pci/tw686x/tw686x-video.c                         |    4 
 drivers/media/platform/amphion/vdec.c                           |  123 
 drivers/media/platform/amphion/vpu.h                            |    1 
 drivers/media/platform/amphion/vpu_core.c                       |    7 
 drivers/media/platform/amphion/vpu_malone.c                     |    6 
 drivers/media/platform/amphion/vpu_msgs.c                       |    7 
 drivers/media/platform/amphion/vpu_rpc.h                        |    7 
 drivers/media/platform/amphion/vpu_v4l2.c                       |   62 
 drivers/media/platform/amphion/vpu_v4l2.h                       |    3 
 drivers/media/platform/atmel/atmel-sama7g5-isc.c                |    2 
 drivers/media/platform/mediatek/mdp/mtk_mdp_ipi.h               |    2 
 drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec.c         |    7 
 drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_drv.c     |    5 
 drivers/media/platform/nxp/imx-jpeg/mxc-jpeg-hw.c               |    5 
 drivers/media/platform/nxp/imx-jpeg/mxc-jpeg-hw.h               |    9 
 drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c                  |  477 
 drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.h                  |    6 
 drivers/media/platform/qcom/camss/camss-csid.c                  |    2 
 drivers/media/platform/renesas/rcar-vin/rcar-core.c             |    2 
 drivers/media/usb/hdpvr/hdpvr-video.c                           |    2 
 drivers/media/v4l2-core/v4l2-mem2mem.c                          |    2 
 drivers/memstick/core/ms_block.c                                |   11 
 drivers/mfd/max77620.c                                          |    2 
 drivers/mfd/t7l66xb.c                                           |    6 
 drivers/misc/cardreader/rtsx_pcr.c                              |    6 
 drivers/misc/eeprom/idt_89hpesx.c                               |    8 
 drivers/mmc/core/block.c                                        |   28 
 drivers/mmc/core/quirks.h                                       |    4 
 drivers/mmc/host/cavium-octeon.c                                |    1 
 drivers/mmc/host/cavium-thunderx.c                              |    4 
 drivers/mmc/host/mxcmmc.c                                       |    2 
 drivers/mmc/host/renesas_sdhi_core.c                            |    8 
 drivers/mmc/host/sdhci-of-at91.c                                |    9 
 drivers/mmc/host/sdhci-of-esdhc.c                               |    1 
 drivers/mtd/devices/mtd_dataflash.c                             |    8 
 drivers/mtd/devices/st_spi_fsm.c                                |    8 
 drivers/mtd/hyperbus/rpc-if.c                                   |    8 
 drivers/mtd/maps/physmap-versatile.c                            |    2 
 drivers/mtd/nand/raw/arasan-nand-controller.c                   |   16 
 drivers/mtd/nand/raw/meson_nand.c                               |    1 
 drivers/mtd/parsers/ofpart_bcm4908.c                            |    3 
 drivers/mtd/parsers/redboot.c                                   |    1 
 drivers/mtd/sm_ftl.c                                            |    2 
 drivers/mtd/spi-nor/core.c                                      |    6 
 drivers/net/can/dev/netlink.c                                   |    6 
 drivers/net/can/pch_can.c                                       |    8 
 drivers/net/can/rcar/rcar_can.c                                 |    8 
 drivers/net/can/sja1000/sja1000.c                               |    7 
 drivers/net/can/spi/hi311x.c                                    |    5 
 drivers/net/can/sun4i_can.c                                     |    9 
 drivers/net/can/usb/kvaser_usb/kvaser_usb_hydra.c               |   12 
 drivers/net/can/usb/kvaser_usb/kvaser_usb_leaf.c                |    6 
 drivers/net/can/usb/usb_8dev.c                                  |    7 
 drivers/net/dsa/ocelot/Kconfig                                  |    1 
 drivers/net/dsa/ocelot/felix.c                                  |    9 
 drivers/net/dsa/ocelot/felix.h                                  |    1 
 drivers/net/dsa/ocelot/felix_vsc9959.c                          |  300 
 drivers/net/ethernet/atheros/ag71xx.c                           |    2 
 drivers/net/ethernet/huawei/hinic/hinic_dev.h                   |    3 
 drivers/net/ethernet/huawei/hinic/hinic_main.c                  |   68 
 drivers/net/ethernet/huawei/hinic/hinic_rx.c                    |    2 
 drivers/net/ethernet/huawei/hinic/hinic_tx.c                    |    2 
 drivers/net/ethernet/intel/iavf/iavf.h                          |    6 
 drivers/net/ethernet/intel/iavf/iavf_main.c                     |   46 
 drivers/net/ethernet/intel/ice/ice_main.c                       |    2 
 drivers/net/ethernet/intel/ice/ice_switch.c                     |    2 
 drivers/net/ethernet/mellanox/mlx5/core/en.h                    |   21 
 drivers/net/ethernet/mellanox/mlx5/core/en/params.c             |   12 
 drivers/net/ethernet/mellanox/mlx5/core/en/tc/post_act.c        |    1 
 drivers/net/ethernet/mellanox/mlx5/core/en/xsk/rx.h             |   14 
 drivers/net/ethernet/mellanox/mlx5/core/en_accel/ktls.c         |    2 
 drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c      |   23 
 drivers/net/ethernet/mellanox/mlx5/core/lib/tout.c              |   11 
 drivers/net/ethernet/mellanox/mlx5/core/lib/tout.h              |    1 
 drivers/net/ethernet/mellanox/mlx5/core/main.c                  |    4 
 drivers/net/ethernet/mellanox/mlx5/core/sriov.c                 |   65 
 drivers/net/ethernet/mellanox/mlx5/core/steering/dr_dbg.c       |   13 
 drivers/net/ethernet/mscc/ocelot.c                              |    1 
 drivers/net/ethernet/mscc/ocelot_ptp.c                          |    8 
 drivers/net/ethernet/pensando/ionic/ionic_lif.c                 |    2 
 drivers/net/netdevsim/bpf.c                                     |    8 
 drivers/net/netdevsim/fib.c                                     |   27 
 drivers/net/phy/smsc.c                                          |    6 
 drivers/net/usb/Kconfig                                         |    3 
 drivers/net/usb/ax88179_178a.c                                  |   26 
 drivers/net/usb/smsc95xx.c                                      |  157 
 drivers/net/usb/usbnet.c                                        |    8 
 drivers/net/wireguard/allowedips.c                              |    9 
 drivers/net/wireguard/selftest/allowedips.c                     |    6 
 drivers/net/wireguard/selftest/ratelimiter.c                    |   25 
 drivers/net/wireless/ath/ath10k/snoc.c                          |    5 
 drivers/net/wireless/ath/ath11k/core.c                          |   16 
 drivers/net/wireless/ath/ath11k/debug.h                         |    4 
 drivers/net/wireless/ath/ath11k/dp_rx.c                         |    5 
 drivers/net/wireless/ath/ath11k/htc.c                           |    4 
 drivers/net/wireless/ath/ath11k/pci.c                           |    2 
 drivers/net/wireless/ath/ath9k/htc.h                            |   10 
 drivers/net/wireless/ath/ath9k/htc_drv_init.c                   |    3 
 drivers/net/wireless/ath/wil6210/debugfs.c                      |   18 
 drivers/net/wireless/intel/iwlegacy/4965-rs.c                   |    5 
 drivers/net/wireless/intel/iwlwifi/mvm/sta.c                    |    1 
 drivers/net/wireless/intersil/p54/main.c                        |    2 
 drivers/net/wireless/intersil/p54/p54spi.c                      |    3 
 drivers/net/wireless/mac80211_hwsim.c                           |   14 
 drivers/net/wireless/marvell/libertas/if_usb.c                  |    1 
 drivers/net/wireless/mediatek/mt76/eeprom.c                     |    5 
 drivers/net/wireless/mediatek/mt76/mac80211.c                   |    1 
 drivers/net/wireless/mediatek/mt76/mt7615/mac.c                 |    7 
 drivers/net/wireless/mediatek/mt76/mt7615/main.c                |   21 
 drivers/net/wireless/mediatek/mt76/mt7615/mcu.c                 |   12 
 drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h              |    1 
 drivers/net/wireless/mediatek/mt76/mt76x02_usb_mcu.c            |    2 
 drivers/net/wireless/mediatek/mt76/mt7921/init.c                |    6 
 drivers/net/wireless/mediatek/mt76/mt7921/mcu.c                 |   15 
 drivers/net/wireless/mediatek/mt76/mt7921/pci_mcu.c             |    6 
 drivers/net/wireless/mediatek/mt76/mt7921/sdio_mcu.c            |   10 
 drivers/net/wireless/microchip/wilc1000/spi.c                   |    6 
 drivers/net/wireless/realtek/rtlwifi/debug.c                    |    8 
 drivers/net/wireless/realtek/rtw88/main.c                       |    4 
 drivers/net/wireless/realtek/rtw89/rtw8852a_rfk.c               |    4 
 drivers/nvme/host/core.c                                        |   14 
 drivers/nvme/host/fc.c                                          |   18 
 drivers/nvme/host/multipath.c                                   |    1 
 drivers/nvme/host/trace.h                                       |    2 
 drivers/nvme/target/zns.c                                       |    3 
 drivers/of/device.c                                             |    5 
 drivers/of/fdt.c                                                |    2 
 drivers/of/kexec.c                                              |   17 
 drivers/opp/core.c                                              |    4 
 drivers/parisc/lba_pci.c                                        |    6 
 drivers/pci/controller/dwc/pcie-designware-ep.c                 |   18 
 drivers/pci/controller/dwc/pcie-designware-host.c               |   30 
 drivers/pci/controller/dwc/pcie-designware.c                    |   46 
 drivers/pci/controller/dwc/pcie-qcom.c                          |   58 
 drivers/pci/controller/dwc/pcie-tegra194.c                      |   49 
 drivers/pci/controller/pcie-mediatek-gen3.c                     |    7 
 drivers/pci/controller/pcie-microchip-host.c                    |    2 
 drivers/pci/endpoint/functions/pci-epf-test.c                   |    1 
 drivers/pci/pcie/aer.c                                          |    7 
 drivers/pci/pcie/portdrv_core.c                                 |    9 
 drivers/perf/arm_spe_pmu.c                                      |   22 
 drivers/perf/riscv_pmu.c                                        |    1 
 drivers/perf/riscv_pmu_sbi.c                                    |   21 
 drivers/phy/qualcomm/phy-qcom-qmp.h                             |    3 
 drivers/phy/rockchip/phy-rockchip-inno-usb2.c                   |    4 
 drivers/phy/samsung/phy-exynosautov9-ufs.c                      |   18 
 drivers/phy/st/phy-stm32-usbphyc.c                              |    4 
 drivers/phy/ti/phy-tusb1210.c                                   |    5 
 drivers/pinctrl/Kconfig                                         |    2 
 drivers/platform/chrome/cros_ec.c                               |    8 
 drivers/platform/mellanox/mlxreg-lc.c                           |   82 
 drivers/platform/olpc/olpc-ec.c                                 |    2 
 drivers/platform/x86/pmc_atom.c                                 |   19 
 drivers/pwm/pwm-lpc18xx-sct.c                                   |   55 
 drivers/pwm/pwm-sifive.c                                        |   61 
 drivers/regulator/of_regulator.c                                |    6 
 drivers/regulator/qcom_smd-regulator.c                          |    4 
 drivers/remoteproc/imx_rproc.c                                  |    7 
 drivers/remoteproc/qcom_q6v5_pas.c                              |    3 
 drivers/remoteproc/qcom_sysmon.c                                |   10 
 drivers/remoteproc/qcom_wcnss.c                                 |   10 
 drivers/remoteproc/ti_k3_r5_remoteproc.c                        |    2 
 drivers/rpmsg/mtk_rpmsg.c                                       |    2 
 drivers/rpmsg/qcom_smd.c                                        |    1 
 drivers/rpmsg/rpmsg_char.c                                      |    7 
 drivers/rtc/rtc-rx8025.c                                        |   22 
 drivers/s390/char/zcore.c                                       |   11 
 drivers/s390/cio/vfio_ccw_drv.c                                 |   19 
 drivers/s390/cio/vfio_ccw_ops.c                                 |    2 
 drivers/s390/scsi/zfcp_fc.c                                     |   29 
 drivers/s390/scsi/zfcp_fc.h                                     |    6 
 drivers/s390/scsi/zfcp_fsf.c                                    |    4 
 drivers/scsi/be2iscsi/be_main.c                                 |    2 
 drivers/scsi/bnx2i/bnx2i_iscsi.c                                |    2 
 drivers/scsi/cxgbi/libcxgbi.c                                   |    2 
 drivers/scsi/iscsi_tcp.c                                        |    4 
 drivers/scsi/libiscsi.c                                         |    9 
 drivers/scsi/lpfc/lpfc_scsi.c                                   |    1 
 drivers/scsi/qedi/qedi_main.c                                   |    9 
 drivers/scsi/qla2xxx/qla_attr.c                                 |   24 
 drivers/scsi/qla2xxx/qla_bsg.c                                  |   10 
 drivers/scsi/qla2xxx/qla_dbg.h                                  |    2 
 drivers/scsi/qla2xxx/qla_def.h                                  |   18 
 drivers/scsi/qla2xxx/qla_edif.c                                 |  502 
 drivers/scsi/qla2xxx/qla_edif.h                                 |    7 
 drivers/scsi/qla2xxx/qla_edif_bsg.h                             |  106 
 drivers/scsi/qla2xxx/qla_fw.h                                   |    2 
 drivers/scsi/qla2xxx/qla_gbl.h                                  |    6 
 drivers/scsi/qla2xxx/qla_gs.c                                   |  129 
 drivers/scsi/qla2xxx/qla_init.c                                 |   93 
 drivers/scsi/qla2xxx/qla_iocb.c                                 |    5 
 drivers/scsi/qla2xxx/qla_isr.c                                  |   25 
 drivers/scsi/qla2xxx/qla_mbx.c                                  |   19 
 drivers/scsi/qla2xxx/qla_mid.c                                  |    6 
 drivers/scsi/qla2xxx/qla_nvme.c                                 |    5 
 drivers/scsi/qla2xxx/qla_os.c                                   |   93 
 drivers/scsi/qla2xxx/qla_target.c                               |   35 
 drivers/scsi/scsi_transport_iscsi.c                             |   66 
 drivers/scsi/sg.c                                               |   53 
 drivers/scsi/smartpqi/smartpqi_init.c                           |    4 
 drivers/scsi/ufs/ufshcd.c                                       |    6 
 drivers/soc/amlogic/meson-mx-socinfo.c                          |    1 
 drivers/soc/amlogic/meson-secure-pwrc.c                         |    4 
 drivers/soc/fsl/guts.c                                          |    2 
 drivers/soc/qcom/Kconfig                                        |    1 
 drivers/soc/qcom/ocmem.c                                        |    3 
 drivers/soc/qcom/qcom_aoss.c                                    |    4 
 drivers/soc/qcom/socinfo.c                                      |    3 
 drivers/soc/renesas/r8a779a0-sysc.c                             |   10 
 drivers/soundwire/bus.c                                         |   75 
 drivers/soundwire/bus_type.c                                    |   38 
 drivers/soundwire/qcom.c                                        |    4 
 drivers/soundwire/slave.c                                       |    3 
 drivers/soundwire/stream.c                                      |   53 
 drivers/spi/spi-altera-dfl.c                                    |   14 
 drivers/spi/spi-dw.h                                            |    2 
 drivers/spi/spi-rspi.c                                          |    4 
 drivers/spi/spi-s3c64xx.c                                       |    2 
 drivers/spi/spi-synquacer.c                                     |    1 
 drivers/spi/spi-tegra20-slink.c                                 |    3 
 drivers/spi/spi.c                                               |   21 
 drivers/staging/fbtft/fbtft-core.c                              |    2 
 drivers/staging/media/atomisp/pci/atomisp_cmd.c                 |   57 
 drivers/staging/media/hantro/hantro_drv.c                       |    1 
 drivers/staging/media/hantro/hantro_g2_hevc_dec.c               |   32 
 drivers/staging/media/hantro/hantro_g2_regs.h                   |    2 
 drivers/staging/media/hantro/hantro_hevc.c                      |   71 
 drivers/staging/media/hantro/hantro_hw.h                        |   22 
 drivers/staging/media/hantro/hantro_v4l2.c                      |    2 
 drivers/staging/media/hantro/imx8m_vpu_hw.c                     |   80 
 drivers/staging/media/hantro/rockchip_vpu_hw.c                  |  174 
 drivers/staging/media/hantro/sama5d4_vdec_hw.c                  |   40 
 drivers/staging/media/hantro/sunxi_vpu_hw.c                     |   24 
 drivers/staging/media/sunxi/cedrus/cedrus_h265.c                |   36 
 drivers/staging/media/sunxi/cedrus/cedrus_regs.h                |    3 
 drivers/staging/rtl8192u/r8192U.h                               |    2 
 drivers/staging/rtl8192u/r8192U_dm.c                            |   38 
 drivers/staging/rtl8192u/r8192U_dm.h                            |    2 
 drivers/thermal/thermal_sysfs.c                                 |   10 
 drivers/tty/n_gsm.c                                             |  757 
 drivers/tty/serial/8250/8250.h                                  |   22 
 drivers/tty/serial/8250/8250_bcm2835aux.c                       |    6 
 drivers/tty/serial/8250/8250_bcm7271.c                          |   24 
 drivers/tty/serial/8250/8250_fsl.c                              |    2 
 drivers/tty/serial/8250/8250_pci.c                              |  522 
 drivers/tty/serial/8250/8250_port.c                             |   21 
 drivers/tty/serial/fsl_lpuart.c                                 |   12 
 drivers/tty/serial/mvebu-uart.c                                 |   11 
 drivers/tty/serial/pic32_uart.c                                 |   13 
 drivers/tty/vt/vt.c                                             |    2 
 drivers/usb/cdns3/cdns3-gadget.c                                |   11 
 drivers/usb/core/hcd.c                                          |   26 
 drivers/usb/dwc3/core.c                                         |    9 
 drivers/usb/dwc3/dwc3-qcom.c                                    |    4 
 drivers/usb/dwc3/gadget.c                                       |   92 
 drivers/usb/gadget/function/f_mass_storage.c                    |   11 
 drivers/usb/gadget/udc/Kconfig                                  |    2 
 drivers/usb/gadget/udc/aspeed-vhub/hub.c                        |    4 
 drivers/usb/gadget/udc/tegra-xudc.c                             |    8 
 drivers/usb/host/ehci-ppc-of.c                                  |    1 
 drivers/usb/host/ohci-nxp.c                                     |    1 
 drivers/usb/host/xhci-tegra.c                                   |    8 
 drivers/usb/host/xhci.h                                         |    2 
 drivers/usb/serial/sierra.c                                     |    3 
 drivers/usb/serial/usb-serial.c                                 |    2 
 drivers/usb/serial/usb_wwan.c                                   |    3 
 drivers/usb/typec/ucsi/ucsi.c                                   |    4 
 drivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.c                  |   15 
 drivers/vfio/pci/mlx5/main.c                                    |   15 
 drivers/vfio/pci/vfio_pci.c                                     |    2 
 drivers/vfio/pci/vfio_pci_core.c                                |    4 
 drivers/video/fbdev/amba-clcd.c                                 |   24 
 drivers/video/fbdev/arkfb.c                                     |    9 
 drivers/video/fbdev/core/fbcon.c                                |   12 
 drivers/video/fbdev/s3fb.c                                      |    2 
 drivers/video/fbdev/sis/init.c                                  |    4 
 drivers/video/fbdev/vt8623fb.c                                  |    2 
 drivers/watchdog/armada_37xx_wdt.c                              |    2 
 drivers/watchdog/f71808e_wdt.c                                  |    4 
 drivers/watchdog/sp5100_tco.c                                   |    1 
 fs/Makefile                                                     |    2 
 fs/attr.c                                                       |    2 
 fs/btrfs/block-group.c                                          |   29 
 fs/btrfs/ctree.h                                                |   34 
 fs/btrfs/delalloc-space.c                                       |    6 
 fs/btrfs/disk-io.c                                              |   38 
 fs/btrfs/extent-tree.c                                          |   74 
 fs/btrfs/extent_io.c                                            |    4 
 fs/btrfs/file.c                                                 |    2 
 fs/btrfs/free-space-cache.c                                     |    7 
 fs/btrfs/inode.c                                                |  177 
 fs/btrfs/space-info.c                                           |  117 
 fs/btrfs/space-info.h                                           |   14 
 fs/btrfs/sysfs.c                                                |   37 
 fs/btrfs/tree-log.c                                             |   27 
 fs/btrfs/tree-log.h                                             |    3 
 fs/btrfs/volumes.c                                              |   28 
 fs/btrfs/zoned.c                                                |  127 
 fs/btrfs/zoned.h                                                |   30 
 fs/cifs/file.c                                                  |   28 
 fs/erofs/decompressor.c                                         |   16 
 fs/erofs/decompressor_lzma.c                                    |    1 
 fs/eventpoll.c                                                  |   22 
 fs/exec.c                                                       |    3 
 fs/ext2/super.c                                                 |   12 
 fs/ext4/inline.c                                                |    3 
 fs/ext4/inode.c                                                 |   24 
 fs/ext4/migrate.c                                               |    4 
 fs/ext4/namei.c                                                 |   23 
 fs/ext4/resize.c                                                |    1 
 fs/ext4/xattr.c                                                 |  169 
 fs/ext4/xattr.h                                                 |   14 
 fs/f2fs/checkpoint.c                                            |    4 
 fs/f2fs/data.c                                                  |  192 
 fs/f2fs/debug.c                                                 |   18 
 fs/f2fs/f2fs.h                                                  |   60 
 fs/f2fs/file.c                                                  |  164 
 fs/f2fs/gc.c                                                    |  134 
 fs/f2fs/inode.c                                                 |    3 
 fs/f2fs/namei.c                                                 |   28 
 fs/f2fs/node.c                                                  |    4 
 fs/f2fs/node.h                                                  |    1 
 fs/f2fs/segment.c                                               |  391 
 fs/f2fs/segment.h                                               |    7 
 fs/f2fs/super.c                                                 |    6 
 fs/f2fs/verity.c                                                |    2 
 fs/fuse/control.c                                               |    4 
 fs/fuse/dir.c                                                   |    7 
 fs/fuse/file.c                                                  |   39 
 fs/fuse/inode.c                                                 |    6 
 fs/fuse/ioctl.c                                                 |   15 
 fs/io-wq.c                                                      | 1424 -
 fs/io-wq.h                                                      |  227 
 fs/io_uring.c                                                   |11915 ----------
 fs/jbd2/commit.c                                                |    2 
 fs/jbd2/transaction.c                                           |   14 
 fs/kernfs/dir.c                                                 |    7 
 fs/ksmbd/connection.c                                           |   20 
 fs/ksmbd/connection.h                                           |   27 
 fs/ksmbd/ksmbd_netlink.h                                        |    3 
 fs/ksmbd/smb2misc.c                                             |   12 
 fs/ksmbd/smb2pdu.c                                              |  151 
 fs/ksmbd/smbacl.c                                               |  130 
 fs/ksmbd/smbacl.h                                               |    2 
 fs/ksmbd/transport_ipc.c                                        |    3 
 fs/ksmbd/transport_rdma.c                                       |  161 
 fs/ksmbd/transport_rdma.h                                       |    8 
 fs/ksmbd/vfs.c                                                  |    5 
 fs/lockd/svc4proc.c                                             |    8 
 fs/lockd/xdr4.c                                                 |   19 
 fs/mbcache.c                                                    |   76 
 fs/namei.c                                                      |    4 
 fs/nfs/flexfilelayout/flexfilelayout.c                          |    4 
 fs/nfs/nfs3client.c                                             |    1 
 fs/nfsd/filecache.c                                             |   22 
 fs/nfsd/filecache.h                                             |    4 
 fs/nfsd/trace.h                                                 |    8 
 fs/overlayfs/export.c                                           |    2 
 fs/proc/base.c                                                  |   46 
 fs/splice.c                                                     |   10 
 fs/zonefs/super.c                                               |    3 
 include/acpi/cppc_acpi.h                                        |    2 
 include/crypto/internal/blake2s.h                               |  108 
 include/dt-bindings/clock/qcom,gcc-msm8939.h                    |    1 
 include/linux/acpi_viot.h                                       |    2 
 include/linux/blkdev.h                                          |   19 
 include/linux/bpf.h                                             |  140 
 include/linux/bpf_types.h                                       |    1 
 include/linux/bpf_verifier.h                                    |    3 
 include/linux/btf.h                                             |   21 
 include/linux/buffer_head.h                                     |   25 
 include/linux/cpumask.h                                         |   18 
 include/linux/filter.h                                          |    9 
 include/linux/highmem.h                                         |   10 
 include/linux/hugetlb.h                                         |    6 
 include/linux/iio/common/cros_ec_sensors_core.h                 |    7 
 include/linux/iio/iio.h                                         |   10 
 include/linux/kexec.h                                           |   45 
 include/linux/kfifo.h                                           |    2 
 include/linux/kvm_types.h                                       |    2 
 include/linux/lockd/xdr.h                                       |    2 
 include/linux/lockdep.h                                         |   30 
 include/linux/mbcache.h                                         |   10 
 include/linux/mfd/t7l66xb.h                                     |    1 
 include/linux/mlx5/driver.h                                     |   12 
 include/linux/nvme-fc-driver.h                                  |   14 
 include/linux/once_lite.h                                       |   20 
 include/linux/perf_event.h                                      |   16 
 include/linux/pipe_fs_i.h                                       |    9 
 include/linux/rmap.h                                            |    4 
 include/linux/sched.h                                           |    2 
 include/linux/sched/rt.h                                        |    8 
 include/linux/sched/topology.h                                  |    1 
 include/linux/soundwire/sdw.h                                   |    6 
 include/linux/swapops.h                                         |   12 
 include/linux/tpm_eventlog.h                                    |    2 
 include/linux/trace_events.h                                    |   18 
 include/linux/usb/hcd.h                                         |    1 
 include/linux/wait.h                                            |    9 
 include/media/hevc-ctrls.h                                      |    4 
 include/net/9p/client.h                                         |    8 
 include/net/ax25.h                                              |    1 
 include/net/bluetooth/hci.h                                     |    1 
 include/net/inet6_hashtables.h                                  |   27 
 include/net/inet_hashtables.h                                   |   44 
 include/net/inet_sock.h                                         |   11 
 include/net/pkt_sched.h                                         |   17 
 include/net/raw.h                                               |   16 
 include/net/rawv6.h                                             |    7 
 include/net/sock.h                                              |   15 
 include/net/xdp_sock_drv.h                                      |   11 
 include/scsi/libiscsi.h                                         |    2 
 include/scsi/scsi_transport_iscsi.h                             |    1 
 include/soc/mscc/ocelot.h                                       |   27 
 include/trace/events/f2fs.h                                     |   22 
 include/trace/events/spmi.h                                     |   12 
 include/trace/stages/stage1_struct_define.h                     |    3 
 include/trace/stages/stage2_data_offsets.h                      |    3 
 include/trace/stages/stage4_event_fields.h                      |   11 
 include/trace/stages/stage5_get_offsets.h                       |    4 
 include/trace/stages/stage6_event_callback.h                    |   12 
 include/uapi/linux/bpf.h                                        |   13 
 include/uapi/linux/can/error.h                                  |    5 
 include/uapi/linux/f2fs.h                                       |    2 
 include/uapi/linux/netfilter/xt_IDLETIMER.h                     |   17 
 init/main.c                                                     |    1 
 io_uring/Makefile                                               |    6 
 io_uring/io-wq.c                                                | 1424 +
 io_uring/io-wq.h                                                |  227 
 io_uring/io_uring.c                                             |11915 ++++++++++
 kernel/bpf/arraymap.c                                           |   36 
 kernel/bpf/bpf_struct_ops.c                                     |   71 
 kernel/bpf/btf.c                                                |  470 
 kernel/bpf/cgroup.c                                             |   70 
 kernel/bpf/core.c                                               |   35 
 kernel/bpf/hashtab.c                                            |   64 
 kernel/bpf/helpers.c                                            |   24 
 kernel/bpf/map_in_map.c                                         |    5 
 kernel/bpf/ringbuf.c                                            |    4 
 kernel/bpf/syscall.c                                            |  257 
 kernel/bpf/trampoline.c                                         |   73 
 kernel/bpf/verifier.c                                           |  418 
 kernel/cgroup/cpuset.c                                          |    2 
 kernel/dma/swiotlb.c                                            |    2 
 kernel/irq/Kconfig                                              |    1 
 kernel/irq/chip.c                                               |    3 
 kernel/irq/irqdomain.c                                          |    2 
 kernel/kexec_file.c                                             |   66 
 kernel/kprobes.c                                                |    3 
 kernel/locking/lockdep.c                                        |    7 
 kernel/power/user.c                                             |   13 
 kernel/profile.c                                                |    7 
 kernel/rcu/rcutorture.c                                         |   28 
 kernel/sched/core.c                                             |   52 
 kernel/sched/fair.c                                             |  141 
 kernel/sched/features.h                                         |    3 
 kernel/sched/rt.c                                               |   15 
 kernel/sched/sched.h                                            |    1 
 kernel/smp.c                                                    |    4 
 kernel/time/hrtimer.c                                           |    1 
 kernel/time/timekeeping.c                                       |    7 
 kernel/trace/blktrace.c                                         |    5 
 lib/crypto/blake2s-selftest.c                                   |   41 
 lib/crypto/blake2s.c                                            |   37 
 lib/iov_iter.c                                                  |   15 
 lib/kunit/executor.c                                            |    4 
 lib/livepatch/test_klp_callbacks_busy.c                         |    8 
 lib/overflow_kunit.c                                            |    6 
 lib/smp_processor_id.c                                          |    2 
 lib/test_bpf.c                                                  |    4 
 lib/test_hmm.c                                                  |   10 
 lib/test_kasan.c                                                |   10 
 mm/damon/reclaim.c                                              |    4 
 mm/gup.c                                                        |    2 
 mm/huge_memory.c                                                |   11 
 mm/hugetlb.c                                                    |   15 
 mm/hugetlb_cgroup.c                                             |    1 
 mm/kasan/hw_tags.c                                              |   32 
 mm/memory-failure.c                                             |    2 
 mm/memory_hotplug.c                                             |    2 
 mm/mempolicy.c                                                  |    4 
 mm/memremap.c                                                   |    2 
 mm/migrate.c                                                    |   30 
 mm/mmap.c                                                       |    1 
 mm/page_alloc.c                                                 |    8 
 mm/vmalloc.c                                                    |   10 
 net/9p/client.c                                                 |   36 
 net/9p/trans_fd.c                                               |   13 
 net/9p/trans_rdma.c                                             |    2 
 net/9p/trans_virtio.c                                           |    4 
 net/9p/trans_xen.c                                              |    2 
 net/ax25/af_ax25.c                                              |    4 
 net/batman-adv/trace.h                                          |    9 
 net/bluetooth/hci_core.c                                        |   10 
 net/bluetooth/hci_event.c                                       |    5 
 net/bluetooth/hci_sync.c                                        |    8 
 net/bluetooth/l2cap_core.c                                      |   13 
 net/bluetooth/mgmt.c                                            |   10 
 net/bpf/bpf_dummy_struct_ops.c                                  |   24 
 net/core/filter.c                                               |    4 
 net/core/skmsg.c                                                |    4 
 net/dccp/proto.c                                                |   10 
 net/ipv4/af_inet.c                                              |    2 
 net/ipv4/inet_hashtables.c                                      |   17 
 net/ipv4/raw.c                                                  |  164 
 net/ipv4/raw_diag.c                                             |   53 
 net/ipv4/tcp.c                                                  |   33 
 net/ipv4/tcp_output.c                                           |   30 
 net/ipv4/udp.c                                                  |    3 
 net/ipv6/af_inet6.c                                             |    3 
 net/ipv6/inet6_hashtables.c                                     |    6 
 net/ipv6/raw.c                                                  |  120 
 net/ipv6/udp.c                                                  |    2 
 net/mptcp/protocol.c                                            |    3 
 net/netfilter/nf_tables_api.c                                   |   18 
 net/netfilter/nft_queue.c                                       |   27 
 net/rose/af_rose.c                                              |   11 
 net/rose/rose_route.c                                           |    2 
 net/sched/cls_route.c                                           |    2 
 scripts/Makefile.modpost                                        |    3 
 scripts/faddr2line                                              |    4 
 scripts/gdb/linux/dmesg.py                                      |    9 
 scripts/gdb/linux/utils.py                                      |   14 
 security/selinux/ss/policydb.h                                  |    2 
 security/selinux/ss/services.c                                  |    9 
 sound/pci/hda/patch_cirrus.c                                    |    1 
 sound/pci/hda/patch_conexant.c                                  |   11 
 sound/pci/hda/patch_realtek.c                                   |  124 
 sound/soc/amd/yc/acp6x-mach.c                                   |   32 
 sound/soc/atmel/mchp-spdifrx.c                                  |    9 
 sound/soc/codecs/cros_ec_codec.c                                |    1 
 sound/soc/codecs/da7210.c                                       |    2 
 sound/soc/codecs/msm8916-wcd-digital.c                          |   46 
 sound/soc/codecs/mt6359-accdet.c                                |    1 
 sound/soc/codecs/mt6359.c                                       |    1 
 sound/soc/codecs/wcd9335.c                                      |   81 
 sound/soc/codecs/wsa881x.c                                      |   10 
 sound/soc/fsl/fsl-asoc-card.c                                   |    5 
 sound/soc/fsl/fsl_asrc.c                                        |    6 
 sound/soc/fsl/fsl_easrc.c                                       |    9 
 sound/soc/fsl/fsl_easrc.h                                       |    2 
 sound/soc/fsl/imx-audmux.c                                      |    2 
 sound/soc/fsl/imx-card.c                                        |   22 
 sound/soc/generic/audio-graph-card.c                            |    4 
 sound/soc/generic/audio-graph-card2.c                           |   44 
 sound/soc/intel/boards/sof_rt5682.c                             |   18 
 sound/soc/mediatek/mt6797/mt6797-mt6351.c                       |    6 
 sound/soc/mediatek/mt8173/mt8173-rt5650-rt5676.c                |   10 
 sound/soc/mediatek/mt8173/mt8173-rt5650.c                       |    9 
 sound/soc/qcom/lpass-cpu.c                                      |    1 
 sound/soc/qcom/qdsp6/q6adm.c                                    |    2 
 sound/soc/samsung/aries_wm8994.c                                |    6 
 sound/soc/samsung/h1940_uda1380.c                               |    2 
 sound/soc/samsung/rx1950_uda1380.c                              |    4 
 sound/soc/sof/ipc3-topology.c                                   |    1 
 sound/soc/sof/mediatek/mt8195/mt8195-loader.c                   |    2 
 sound/soc/sof/sof-priv.h                                        |    4 
 sound/usb/bcd2000/bcd2000.c                                     |    3 
 sound/usb/quirks.c                                              |    2 
 tools/bpf/bpftool/link.c                                        |    4 
 tools/include/uapi/linux/bpf.h                                  |   13 
 tools/lib/bpf/bpf_tracing.h                                     |    2 
 tools/lib/bpf/gen_loader.c                                      |    2 
 tools/lib/bpf/libbpf.c                                          |    9 
 tools/lib/bpf/xsk.c                                             |    9 
 tools/perf/builtin-stat.c                                       |   30 
 tools/perf/util/dsos.c                                          |   15 
 tools/perf/util/genelf.c                                        |    6 
 tools/perf/util/symbol-elf.c                                    |   27 
 tools/power/x86/intel-speed-select/isst-daemon.c                |    2 
 tools/testing/selftests/bpf/prog_tests/btf.c                    |    2 
 tools/testing/selftests/bpf/prog_tests/fexit_stress.c           |   32 
 tools/testing/selftests/bpf/prog_tests/sock_fields.c            |    1 
 tools/testing/selftests/bpf/prog_tests/tc_redirect.c            |    8 
 tools/testing/selftests/bpf/progs/test_tc_dtime.c               |   53 
 tools/testing/selftests/bpf/verifier/ref_tracking.c             |    2 
 tools/testing/selftests/bpf/verifier/sock.c                     |    6 
 tools/testing/selftests/kvm/lib/x86_64/processor.c              |    2 
 tools/testing/selftests/powerpc/papr_attributes/attr_test.c     |   30 
 tools/testing/selftests/rcutorture/bin/kvm.sh                   |   12 
 tools/testing/selftests/seccomp/seccomp_bpf.c                   |    2 
 tools/testing/selftests/timers/clocksource-switch.c             |    6 
 tools/testing/selftests/timers/valid-adjtimex.c                 |    2 
 tools/testing/selftests/vm/hugepage-mremap.c                    |    2 
 tools/testing/selftests/vm/hugetlb-madvise.c                    |    5 
 tools/testing/selftests/wireguard/qemu/arch/riscv32.config      |    1 
 tools/thermal/tmon/sysfs.c                                      |   24 
 tools/thermal/tmon/tmon.h                                       |    3 
 tools/tracing/rtla/Makefile                                     |    2 
 tools/tracing/rtla/src/trace.c                                  |    9 
 tools/tracing/rtla/src/utils.c                                  |    5 
 virt/kvm/kvm_main.c                                             |   25 
 virt/kvm/pfncache.c                                             |  207 
 1202 files changed, 30883 insertions(+), 25100 deletions(-)

Abel Vesa (1):
      clk: qcom: Drop mmcx gdsc supply for dispcc and videocc

Adrian Hunter (1):
      perf tools: Fix dso_id inode generation comparison

Ajay Singh (1):
      wifi: wilc1000: use correct sequence of RESET for chip Power-UP/Down

Al Viro (2):
      fix short copy handling in copy_mc_pipe_to_iter()
      __follow_mount_rcu(): verify that mount_lock remains unchanged

Alex Deucher (4):
      drm/radeon: fix incorrrect SPDX-License-Identifiers
      drm/amdgpu: use the same HDP flush registers for all nbio 7.4.x
      drm/amdgpu: use the same HDP flush registers for all nbio 2.3.x
      drm/amdgpu: restore original stable pstate on ctx fini

Alexander Gordeev (4):
      s390/crash: fix incorrect number of bytes to copy to user space
      s390/zcore: fix race when reading from hardware system area
      s390/smp: enforce lowcore protection on CPU restart
      Revert "s390/smp: enforce lowcore protection on CPU restart"

Alexander Lobakin (4):
      ia64, processor: fix -Wincompatible-pointer-types in ia64_get_irr()
      net/ice: fix initializing the bitmap in the switch code
      x86/olpc: fix 'logical not is only applied to the left hand side'
      iommu/vt-d: avoid invalid memory access via node_online(NUMA_NO_NODE)

Alexander Shishkin (4):
      intel_th: msu: Fix vmalloced buffers
      intel_th: pci: Add Meteor Lake-P support
      intel_th: pci: Add Raptor Lake-S PCH support
      intel_th: pci: Add Raptor Lake-S CPU support

Alexander Stein (6):
      ARM: dts: imx6ul: add missing properties for sram
      ARM: dts: imx6ul: change operating-points to uint32-matrix
      ARM: dts: imx6ul: fix keypad compatible
      ARM: dts: imx6ul: fix csi node compatible
      ARM: dts: imx6ul: fix lcdif node compatible
      ARM: dts: imx6ul: fix qspi node compatible

Alexander Vorwerk (1):
      iio: core: fix a few code style issues

Alexandru Elisei (1):
      arm64: cpufeature: Allow different PMU versions in ID_DFR0_EL1

Alexei Starovoitov (1):
      bpf: Fix subprog names in stack traces.

Alexey Kardashevskiy (2):
      pseries/iommu/ddw: Fix kdump to work in absence of ibm,dma-window
      powerpc/iommu: Fix iommu_table_in_use for a small default DMA window case

Alexey Khoroshilov (1):
      crypto: sun8i-ss - fix infinite loop in sun8i_ss_setup_ivs()

Alexey Kodanev (2):
      drm/radeon: fix potential buffer overflow in ni_set_mc_special_registers()
      wifi: iwlegacy: 4965: fix potential off-by-one overflow in il4965_rs_fill_link_cmd()

Allen Ballway (1):
      ALSA: hda/cirrus - support for iMac 12,1 model

Amit Kumar Mahapatra (1):
      mtd: rawnand: arasan: Update NAND bus clock instead of system clock

Ammar Faizi (1):
      wifi: wil6210: debugfs: fix uninitialized variable use in `wil_write_file_wmi()`

Andrea Righi (1):
      x86/entry: Build thunk_$(BITS) only if CONFIG_PREEMPTION=y

Andreas Schwab (1):
      rtla: Fix double free

Andrei Vagin (1):
      selftests: kvm: set rax before vmcall

Andrey Konovalov (2):
      kasan: fix zeroing vmalloc memory with HW_TAGS
      mm: introduce clear_highpage_kasan_tagged

Andrey Strachuk (1):
      usb: cdns3: change place of 'priv_ep' assignment in cdns3_gadget_ep_dequeue(), cdns3_gadget_ep_enable()

Andrii Nakryiko (1):
      bpf: fix potential 32-bit overflow when accessing ARRAY map element

Andy Shevchenko (2):
      spi: Return deferred probe error when controller isn't yet available
      phy: ti: tusb1210: Don't check for write errors when powering on

AngeloGioacchino Del Regno (2):
      media: platform: mtk-mdp: Fix mdp_ipi_comm structure alignment
      rpmsg: mtk_rpmsg: Fix circular locking dependency

Anquan Wu (1):
      libbpf: Fix the name of a reused map

Anshuman Khandual (1):
      drivers/perf: arm_spe: Fix consistency of SYS_PMSCR_EL1.CX

Ansuel Smith (1):
      clk: qcom: clk-krait: unlock spin after mux completion

Antonio Borneo (3):
      genirq: Don't return error on missing optional irq_request_resources()
      drm: adv7511: override i2c address of cec before accessing it
      scripts/gdb: fix 'lx-dmesg' on 32 bits arch

Armin Wolf (2):
      hwmon: (dell-smm) Add Dell XPS 13 7390 to fan control whitelist
      hwmon: (sch56xx-common) Add DMI override table

Arnaldo Carvalho de Melo (1):
      genelf: Use HAVE_LIBCRYPTO_SUPPORT, not the never defined HAVE_LIBCRYPTO

Arnd Bergmann (1):
      media: sta2x11: remove VIRT_TO_BUS dependency

Artem Bityutskiy (1):
      intel_idle: make SPR C1 and C1E be independent

Artem Borisov (1):
      HID: alps: Declare U1_UNICORN_LEGACY support

Arun Easi (6):
      scsi: qla2xxx: Fix discovery issues in FC-AL topology
      scsi: qla2xxx: Fix crash due to stale SRB access around I/O timeouts
      scsi: qla2xxx: Fix excessive I/O error messages by default
      scsi: qla2xxx: Fix losing FCP-2 targets on long port disable with I/Os
      scsi: qla2xxx: Fix losing target when it reappears during delete
      scsi: qla2xxx: Fix losing FCP-2 targets during port perturbation tests

Athira Rajeev (1):
      powerpc/perf: Optimize clearing the pending PMI and remove WARN_ON for PMI check in power_pmu_disable

Atish Patra (3):
      RISC-V: Fix counter restart during overflow for RV32
      RISC-V: Fix SBI PMU calls for RV32
      RISC-V: Update user page mapping only once during start

Baokun Li (4):
      ext4: add EXT4_INODE_HAS_XATTR_SPACE macro in xattr.h
      ext4: fix use-after-free in ext4_xattr_set_entry
      ext4: correct max_inline_xattr_value_size computing
      ext4: correct the misjudgment in ext4_iget_extra_inode

Bart Van Assche (4):
      blktrace: Trace remapped requests correctly
      RDMA/srpt: Duplicate port name members
      RDMA/srpt: Introduce a reference count in struct srpt_device
      RDMA/srpt: Fix a use-after-free

Basavaraj Natikar (2):
      HID: amd_sfh: Add NULL check for hid device
      HID: amd_sfh: Handle condition of "no sensors"

Bean Huo (1):
      nvme: use command_id instead of req->tag in trace_nvme_complete_rq()

Bedant Patnaik (1):
      ALSA: hda/realtek: Add a quirk for HP OMEN 15 (8786) mute LED

Ben Dooks (2):
      RISC-V: cpu_ops_spinwait.c should include head.h
      RISC-V: Declare cpu_ops_spinwait in <asm/cpu_ops.h>

Ben Gardon (1):
      KVM: x86: Fix errant brace in KVM capability handling

Benjamin Beichler (1):
      um: Remove straying parenthesis

Benjamin Gaignard (5):
      media: Hantro: Correct G2 init qp field
      media: hantro: HEVC: Fix output frame chroma offset
      media: hantro: HEVC: Fix reference frames management
      media: hantro: Be more accurate on pixel formats step_width constraints
      media: uapi: HEVC: Change pic_order_cnt definition in v4l2_hevc_dpb_entry

Benjamin Segall (1):
      epoll: autoremove wakers even more aggressively

Bharath SM (1):
      SMB3: fix lease break timeout when multiple deferred close handles for the same file.

Biju Das (2):
      spi: spi-rspi: Fix PIO fallback on RZ platforms
      clk: renesas: rzg2l: Fix reset status function

Bikash Hazarika (2):
      scsi: qla2xxx: Fix incorrect display of max frame size
      scsi: qla2xxx: Zero undefined mailbox IN registers

Bjorn Andersson (3):
      drm/bridge: lt9611uxc: Cancel only driver's work
      i2c: qcom-geni: Use the correct return value
      clk: qcom: gdsc: Bump parent usage count when GDSC is found enabled

Bo-Chen Chen (1):
      drm/mediatek: dpi: Remove output format of YUV

Bob Pearson (3):
      RDMA/rxe: Fix deadlock in rxe_do_local_ops()
      RDMA/rxe: Fix mw bind to allow any consumer key portion
      RDMA/rxe: Fix rnr retry behavior

Brian Norris (1):
      drm/rockchip: vop: Don't crash for invalid duplicate_state()

Bryan O'Donoghue (5):
      clk: qcom: gcc-msm8939: Add missing SYSTEM_MM_NOC_BFDCD_CLK_SRC
      clk: qcom: gcc-msm8939: Fix bimc_ddr_clk_src rcgr base address
      clk: qcom: gcc-msm8939: Add missing system_mm_noc_bfdcd_clk_src
      clk: qcom: gcc-msm8939: Point MM peripherals to system_mm_noc clock
      clk: qcom: gcc-msm8939: Fix weird field spacing in ftbl_gcc_camss_cci_clk

Byungki Lee (1):
      f2fs: write checkpoint during FG_GC

Cameron Williams (1):
      tty: 8250: Add support for Brainboxes PX cards.

Carlos Llamas (1):
      binder: fix redefinition of seq_file attributes

Catalin Marinas (1):
      arm64: kasan: Revert "arm64: mte: reset the page tag in page->flags"

Chanho Park (2):
      arm64: dts: exynosautov9: correct spi11 pin names
      phy: samsung: exynosautov9-ufs: correct TSRV register configurations

Chao Liu (1):
      f2fs: fix to remove F2FS_COMPR_FL and tag F2FS_NOCOMP_FL at the same time

Chao Yu (5):
      f2fs: fix to invalidate META_MAPPING before DIO write
      f2fs: check pinfile in gc_data_segment() in advance
      f2fs: don't set GC_FAILURE_PIN for background GC
      f2fs: give priority to select unpinned section for foreground GC
      f2fs: fix to check inline_data during compressed inode conversion

Chen Lifu (1):
      riscv: lib: uaccess: fix CSR_STATUS SR_SUM bit

Chen Yu (1):
      sched/fair: Introduce SIS_UTIL to search idle CPU based on sum of util_avg

Chen Zhongjin (3):
      profiling: fix shift too large makes kernel panic
      kprobes: Forbid probing on trampoline and BPF code areas
      locking/csd_lock: Change csdlock_debug from early_param to __setup

Chen-Yu Tsai (2):
      media: mediatek: vcodec: Skip SOURCE_CHANGE & EOS events for stateless
      media: mediatek: vcodec: Initialize decoder parameters for each instance

Cheng Xu (1):
      RDMA/siw: Fix duplicated reported IW_CM_EVENT_CONNECT_REPLY event

Chenyi Qiang (1):
      x86/bus_lock: Don't assume the init value of DEBUGCTLMSR.BUS_LOCK_DETECT to be zero

Chris Paterson (1):
      arm64: dts: renesas: r9a07g054l2-smarc: Correct SoC name in comment

Christian 'Ansuel' Marangi (1):
      ath11k: fix missing skb drop on htc_tx_completion error

Christian König (1):
      drm/amdgpu: cleanup ctx implementation

Christian Lamparter (1):
      ARM: dts: BCM5301X: Add DT for Meraki MR26

Christian Loehle (1):
      mmc: block: Add single read for 4k sector cards

Christian Marangi (1):
      PCI: qcom: Set up rev 2.1.0 PARF_PHY before enabling clocks

Christoph Hellwig (3):
      nvme: catch -ENODEV from nvme_revalidate_zones again
      block: serialize all debugfs operations using q->debugfs_mutex
      block: add a bdev_max_zone_append_sectors helper

Christophe JAILLET (10):
      spi: spi-altera-dfl: Fix an error handling path
      drm/rockchip: Fix an error handling path rockchip_dp_probe()
      hinic: Use the bitmap API when applicable
      wifi: p54: Fix an error handling path in p54spi_probe()
      mtd: rawnand: meson: Fix a potential double free issue
      misc: rtsx: Fix an error handling path in rtsx_pci_probe()
      intel_th: Fix a resource leak in an error handling path
      memstick/ms_block: Fix some incorrect memory allocation
      memstick/ms_block: Fix a memory leak
      ASoC: qcom: q6dsp: Fix an off-by-one in q6adm_alloc_copp()

Christophe Leroy (7):
      powerpc: Restore CONFIG_DEBUG_INFO in defconfigs
      powerpc/64e: Fix early TLB miss with KUAP
      powerpc/ptdump: Fix display of RW pages on FSL_BOOK3E
      powerpc/32: Call mmu_mark_initmem_nx() regardless of data block mapping.
      powerpc/32s: Fix boot failure with KASAN + SMP + JUMP_LABEL_FEATURE_CHECK_DEBUG
      powerpc/32: Do not allow selection of e5500 or e6500 CPUs on PPC32
      powerpc: Fix eh field when calling lwarx on PPC32

Christopher Obbard (1):
      um: random: Don't initialise hwrng struct with zero

Chuck Lever (1):
      NFSD: Clean up the show_nf_flags() macro

Claudio Imbrenda (1):
      KVM: s390: pv: leak the topmost page table when destroy fails

Claudiu Beznea (1):
      ASoC: mchp-spdifrx: disable end of block interrupt on failures

Coiby Xu (1):
      kexec: clean up arch_kexec_kernel_verify_sig

Conor Dooley (1):
      dt-bindings: riscv: fix SiFive l2-cache's cache-sets

Corentin Labbe (1):
      crypto: sun8i-ss - do not allocate memory when handling hash requests

Daeho Jeong (2):
      f2fs: change the current atomic write way
      f2fs: revive F2FS_IOC_ABORT_VOLATILE_WRITE

Dan Carpenter (15):
      wifi: rtlwifi: fix error codes in rtl_debugfs_set_write_h2c()
      crypto: sun8i-ss - fix error codes in allocate_flows()
      wifi: wil6210: debugfs: fix info leak in wil_write_file_wmi()
      selftests/bpf: fix a test for snprintf() overflow
      libbpf: fix an snprintf() overflow check
      drm/amd/display: fix signedness bug in execute_synaptics_rc_command()
      scsi: qla2xxx: Check correct variable in qla24xx_async_gffid()
      eeprom: idt_89hpesx: uninitialized data in idt_dbgfs_csr_write()
      iio: adc: max1027: unlock on error path in max1027_read_single_value()
      tools/power/x86/intel-speed-select: Fix off by one check
      platform/olpc: Fix uninitialized data in debugfs write
      tools/testing/selftests/vm/hugetlb-madvise.c: silence uninitialized variable warning
      selftest/vm: uninitialized variable in main()
      null_blk: fix ida error handling in null_add_dev()
      kfifo: fix kfifo_to_user() return type

Dan Williams (1):
      ACPI: APEI: Fix _EINJ vs EFI_MEMORY_SP

Daniel Bristot de Oliveira (1):
      rtla: Fix Makefile when called from -C tools/

Daniel Starke (13):
      tty: n_gsm: fix user open not possible at responder until initiator open
      tty: n_gsm: fix tty registration before control channel open
      tty: n_gsm: fix wrong queuing behavior in gsm_dlci_data_output()
      tty: n_gsm: fix missing timer to handle stalled links
      tty: n_gsm: fix non flow control frames during mux flow off
      tty: n_gsm: fix packet re-transmission without open control channel
      tty: n_gsm: fix race condition in gsmld_write()
      tty: n_gsm: fix deadlock and link starvation in outgoing data path
      tty: n_gsm: fix resource allocation order in gsm_activate_mux()
      tty: n_gsm: fix wrong T1 retry count handling
      tty: n_gsm: fix DM command
      tty: n_gsm: fix flow control handling in tx path
      tty: n_gsm: fix missing corner cases in gsmld_poll()

Dave Stevenson (14):
      drm/vc4: plane: Fix margin calculations for the right/bottom edges
      drm/vc4: dsi: Release workaround buffer and DMA
      drm/vc4: dsi: Correct DSI divider calculations
      drm/vc4: dsi: Correct pixel order for DSI0
      drm/vc4: dsi: Register dsi0 as the correct vc4 encoder type
      drm/vc4: dsi: Fix dsi0 interrupt support
      drm/vc4: dsi: Add correct stop condition to vc4_dsi_encoder_disable iteration
      drm/vc4: hdmi: Add all the vc5 HDMI registers into the debugfs dumps
      drm/vc4: hdmi: Reset HDMI MISC_CONTROL register
      drm/vc4: hdmi: Switch to pm_runtime_status_suspended
      drm/vc4: hdmi: Move HDMI reset to pm_resume
      drm/vc4: hdmi: Correct HDMI timing registers for interlaced modes
      drm/vc4: hdmi: Move pixel doubling from Pixelvalve to HDMI block
      drm/vc4: drv: Adopt the dma configuration from the HVS or V3D component

David Collins (1):
      spmi: trace: fix stack-out-of-bound access in SPMI tracing functions

David Gow (1):
      kunit: executor: Fix a memory leak on failure in kunit_filter_tests

David Heidelberg (1):
      arm64: dts: qcom: timer should use only 32-bit size

David Howells (1):
      vfs: Check the truncate maximum size in inode_newsize_ok()

Deren Wu (3):
      mt76: mt7921s: fix possible sdio deadlock in command fail
      mt76: mt7921: fix aggregation subframes setting to HE max
      mt76: mt7921: enlarge maximum VHT MPDU length to 11454

Dmitry Baryshkov (7):
      arm64: dts: qcom: sdm630: disable GPU by default
      arm64: dts: qcom: sdm630: fix the qusb2phy ref clock
      arm64: dts: qcom: sdm630: fix gpu's interconnect path
      arm64: dts: qcom: sdm636-sony-xperia-ganges-mermaid: correct sdc2 pinconf
      arm64: dts: qcom: msm8996: correct #clock-cells for QMP PHY nodes
      drm/msm/hdmi: fill the pwr_regs bulk regulators
      phy: qcom-qmp: fix the QSERDES_V5_COM_CMN_MODE register

Dmitry Osipenko (3):
      drm/gem: Properly annotate WW context on drm_gem_lock_reservations() error
      drm/shmem-helper: Add missing vunmap on error
      drm/tegra: Fix vmapping of prime buffers

Dom Cobley (3):
      drm/vc4: plane: Remove subpixel positioning check
      drm/vc4: hdmi: Clear unused infoframe packet RAM registers
      drm/vc4: hdmi: Avoid full hdmi audio fifo writes

Dongliang Mu (1):
      RDMA/rxe: fix xa_alloc_cycle() error return value check again

Doug Berger (1):
      serial: 8250_bcm7271: Save/restore RTS in suspend/resume

Douglas Anderson (2):
      drm/dp: Export symbol / kerneldoc fixes for DP AUX bus
      drm/msm: Avoid unclocked GMU register access in 6xx gpu_busy

Duoming Zhou (3):
      mtd: sm_ftl: Fix deadlock caused by cancel_work_sync in sm_release
      mwifiex: fix sleep in atomic context bugs caused by dev_coredumpv
      staging: rtl8192u: Fix sleep in atomic context bug in dm_fsync_timer_callback

Eric Auger (1):
      ACPI: VIOT: Fix ACS setup

Eric Dumazet (11):
      net: fix sk_wmem_schedule() and sk_rmem_schedule() errors
      tcp: fix possible freeze in tx path under memory pressure
      raw: use more conventional iterators
      raw: convert raw sockets to RCU
      ax25: fix incorrect dev_tracker usage
      inet: add READ_ONCE(sk->sk_bound_dev_if) in INET_MATCH()
      ipv6: add READ_ONCE(sk->sk_bound_dev_if) in INET6_MATCH()
      net: rose: fix netdev reference changes
      tcp: fix over estimation in sk_forced_mem_schedule()
      raw: remove unused variables from raw6_icmp_error()
      raw: fix a typo in raw_icmp_error()

Eric Farman (2):
      vfio/ccw: Fix FSM state if mdev probe fails
      vfio/ccw: Do not change FSM state in subchannel event

Eric Whitney (1):
      ext4: fix extent status tree race in writeback error recovery path

Eugen Hristev (2):
      media: atmel: atmel-sama7g5-isc: fix warning in configs without OF
      mmc: sdhci-of-at91: fix set_uhs_signaling rewriting of MC1R

Ezequiel Garcia (2):
      media: hantro: Fix RK3399 H.264 format advertising
      hantro: Remove incorrect HEVC SPS validation

Fabio Estevam (4):
      i2c: mxs: Silence a clang warning
      mmc: mxcmmc: Silence a clang warning
      dmaengine: imx-dma: Cast of_device_get_match_data() with (uintptr_t)
      ASoC: imx-audmux: Silence a clang warning

Fabrice Gasnier (1):
      phy: stm32: fix error return in stm32_usbphyc_phy_init

Fawzi Khaber (1):
      iio: fix iio_format_avail_range() printing for none IIO_VAL_INT

Felix Fietkau (1):
      mt76: mt7615: fix throughput regression on DFS channels

Filipe Manana (1):
      btrfs: join running log transaction when logging new name

Florian Fainelli (3):
      MIPS: vdso: Utilize __pa() for gic_pfn
      MIPS: Fixed __debug_virt_addr_valid()
      tools/thermal: Fix possible path truncations

Florian Westphal (2):
      netfilter: nf_tables: fix null deref due to zeroed list head
      netfilter: nft_queue: only allow supported familes and hooks

Francis Laniel (1):
      arm64: Do not forget syscall when starting a new thread.

Frederic Weisbecker (1):
      rcutorture: Fix ksoftirqd boosting timing and iteration

GONG, Ruiqi (1):
      stack: Declare {randomize_,}kstack_offset to fix Sparse warnings

Gal Pressman (1):
      net/mlx5e: Remove WARN_ON when trying to offload an unsupported TLS cipher/version

Gao Chao (1):
      drm/panel: Fix build error when CONFIG_DRM_PANEL_SAMSUNG_ATNA33XC20=y && CONFIG_DRM_DISPLAY_HELPER=m

Gao Xiang (1):
      erofs: avoid consecutive detection for Highmem memory

Geert Uytterhoeven (5):
      arm64: dts: renesas: beacon: Fix regulator node names
      soc: renesas: r8a779a0-sysc: Fix A2DP1 and A2CV[2357] PDR values
      arm64: dts: renesas: Fix thermal-sensors on single-zone sensors
      arm64: dts: renesas: r8a779m8: Drop operating points above 1.5 GHz
      mtd: hyperbus: rpc-if: Fix RPM imbalance in probe error path

Greg Kroah-Hartman (2):
      Revert "mwifiex: fix sleep in atomic context bugs caused by dev_coredumpv"
      Linux 5.18.18

Guenter Roeck (1):
      HID: nintendo: Add missing array termination

Guilherme G. Piccoli (1):
      ACPI: processor/idle: Annotate more functions to live in cpuidle section

Guillaume Ranquet (1):
      drm/mediatek: dpi: Only enable dpi after the bridge is enabled

Guo Mengqi (2):
      spi: synquacer: Add missing clk_disable_unprepare()
      serial: 8250_bcm2835aux: Add missing clk_disable_unprepare()

Gwendal Grignou (2):
      iio: sx9324: Fix register field spelling
      iio: cros: Register FIFO callback after sensor is registered

Haibo Chen (1):
      clk: imx93: use adc_root as the parent clock of adc1

Hangyu Hua (4):
      drm: bridge: sii8620: fix possible off-by-one
      wifi: libertas: Fix possible refcount leak in if_usb_probe()
      dccp: put dccp_qpolicy_full() and dccp_qpolicy_push() in the same lock
      net: 9p: fix refcount leak in p9_read_work() error handling

Hans de Goede (4):
      ACPI: EC: Remove duplicate ThinkPad X1 Carbon 6th entry from DMI quirks
      ACPI: EC: Drop the EC_FLAGS_IGNORE_DSDT_GPE quirk
      ACPI: video: Use native backlight on Dell Inspiron N4010
      platform/x86: pmc_atom: Match all Lex BayTrail boards with critclk_systems DMI table

Haoyue Xu (1):
      RDMA/hns: Fix incorrect clearing of interrupt status register

Harshit Mogalapalli (2):
      HID: cp2112: prevent a buffer overflow in cp2112_xfer()
      HID: mcp2221: prevent a buffer overflow in mcp_smbus_write()

Helge Deller (5):
      fbcon: Fix boundary checks for fbcon=vc:n1-n2 parameters
      fbcon: Fix accelerated fbdev scrolling while logo is still shown
      parisc: Fix device names in /proc/iomem
      parisc: Drop pa_swapper_pg_lock spinlock
      parisc: io_pgetevents_time64() needs compat syscall in 32-bit compat mode

Hsin-Yi Wang (2):
      PM: domains: Ensure genpd_debugfs_dir exists before remove
      drm/bridge: anx7625: Fix NULL pointer crash when using edp-panel

Huacai Chen (2):
      MIPS: cpuinfo: Fix a warning for CONFIG_CPUMASK_OFFSTACK
      tpm: eventlog: Fix section mismatch for DEBUG_SECTION_MISMATCH

Hyunchul Lee (4):
      ksmbd: prevent out of bound read for SMB2_TREE_CONNNECT
      ksmbd: smbd: change prototypes of RDMA read/write related functions
      ksmbd: smbd: introduce read/write credits for RDMA read/write
      ksmbd: prevent out of bound read for SMB2_WRITE

Ian Rogers (1):
      perf symbol: Fail to read phdr workaround

Ido Schimmel (1):
      netdevsim: fib: Fix reference count leak on route deletion failure

Imre Deak (1):
      drm/dp/mst: Read the extended DPCD capabilities during system resume

Ivan Hasenkampf (1):
      ALSA: hda/realtek: Add quirk for HP Spectre x360 15-eb0xxx

Jack Wang (1):
      RDMA/rtrs-srv: Fix modinfo output for stringify

Jaegeuk Kim (1):
      f2fs: kill volatile write support

Jaewook Kim (1):
      f2fs: do not allow to decompress files have FI_COMPRESS_RELEASED

Jagath Jog J (3):
      iio: accel: bma400: Fix the scale min and max macro values
      iio: accel: bma400: Reordering of header files
      iio: accel: bma400: conversion to device-managed function

Jakub Kicinski (1):
      netdevsim: Avoid allocation warnings triggered from user space

James Morse (1):
      arm64: errata: Remove AES hwcap for COMPAT tasks

James Smart (1):
      scsi: lpfc: Remove extra atomic_inc on cmd_pending in queuecommand after VMID

Jan Kara (6):
      mbcache: don't reclaim used entries
      mbcache: add functions to delete entry if unused
      ext2: Add more validity checks for inode counts
      ext4: remove EA inode entry from mbcache on inode eviction
      ext4: unindent codeblock in ext4_xattr_block_set()
      ext4: fix race when reusing xattr blocks

Jason A. Donenfeld (9):
      wireguard: selftests: set CONFIG_NONPORTABLE on riscv32
      um: seed rng using host OS rng
      fs: check FMODE_LSEEK to control internal pipe splicing
      wireguard: ratelimiter: use hrtimer in selftest
      wireguard: allowedips: don't corrupt stack when detecting overflow
      crypto: blake2s - remove shash module
      timekeeping: contribute wall clock to rng on time change
      powerpc/powernv/kvm: Use darn for H_RANDOM on Power9
      crypto: lib/blake2s - reduce stack frame usage in self test

Jason Gunthorpe (1):
      vfio/pci: Have all VFIO PCI drivers store the vfio_pci_core_device in drvdata

Javier Martinez Canillas (1):
      drm/st7735r: Fix module autoloading for Okaya RH128128T

Jean Delvare (1):
      watchdog: sp5100_tco: Fix a memory leak of EFCH MMIO resource

Jeff Layton (2):
      nfsd: eliminate the NFSD_FILE_BREAK_* flags
      lockd: detect and reject lock arguments that overflow

Jens Axboe (1):
      io_uring: move to separate directory

Jeongik Cha (1):
      wifi: mac80211_hwsim: fix race condition in pending packet

Jernej Skrabec (3):
      media: cedrus: h265: Fix flag name
      media: cedrus: h265: Fix logic for not low delay flag
      media: cedrus: hevc: Add check for invalid timestamp

Jiachen Zhang (1):
      ovl: drop WARN_ON() dentry is NULL in ovl_encode_fh()

Jian Shen (3):
      test_bpf: fix incorrect netdev features
      net: ice: fix error NETIF_F_HW_VLAN_CTAG_FILTER check in ice_vsi_sync_fltr()
      net: ionic: fix error check for vlan flags in ionic_set_nic_features()

Jian Zhang (2):
      media: driver/nxp/imx-jpeg: fix a unexpected return value problem
      drm/exynos/exynos7_drm_decon: free resources when clk_set_parent() failed.

Jianglei Nie (3):
      RDMA/qedr: Fix potential memory leak in __qedr_alloc_mr()
      RDMA/hfi1: fix potential memory leak in setup_base_ctxt()
      mm/damon/reclaim: fix potential memory leak in damon_reclaim_init()

Jiasheng Jiang (5):
      drm: bridge: adv7511: Add check for mipi_dsi_driver_register
      Bluetooth: hci_intel: Add check for platform_driver_register
      intel_th: msu-sink: Potential dereference of null pointer
      ASoC: codecs: da7210: add check for i2c_add_driver
      watchdog: f71808e_wdt: Add check for platform_driver_register

Jing Leng (1):
      kbuild: Fix include path in scripts/Makefile.modpost

Jinke Han (1):
      block: don't allow the same type rq_qos add more than once

Jiri Slaby (1):
      serial: pic32: free up irq names correctly

Jitao Shi (2):
      drm/mediatek: Separate poweron/poweroff from enable/disable and define new funcs
      drm/mediatek: Keep dsi as LP00 before dcs cmds transfer

Joanne Koong (1):
      bpf: Fix bpf_xdp_pointer return pointer

Joe Lawrence (1):
      selftests/livepatch: better synchronize test_klp_callbacks_busy

Johan Hovold (8):
      x86/pmem: Fix platform-device leak in error path
      arm64: dts: qcom: sc7280: drop PCIe PHY clock index
      arm64: dts: qcom: sm8250: add missing PCIe PHY clock-cells
      arm64: dts: qcom: sc7280: fix PCIe clock reference
      ath11k: fix netdev open race
      ath11k: fix IRQ affinity warning on shutdown
      usb: dwc3: qcom: fix missing optional irq warnings
      USB: serial: fix tty-port initialized comments

Johannes Berg (2):
      wifi: mac80211_hwsim: add back erroneously removed cast
      wifi: mac80211_hwsim: use 32-bit skb cookie

John Allen (1):
      crypto: ccp - Use kzalloc for sev ioctl interfaces to prevent kernel memory leak

John Keeping (1):
      sched/core: Always flush pending blk_plug

John Stultz (1):
      drm/bridge: lt9611: Use both bits for HDMI sensing

Jonathan Cameron (89):
      iio: core: Fix IIO_ALIGN and rename as it was not sufficiently large
      iio: accel: adxl313: Fix alignment for DMA safety
      iio: accel: adxl355: Fix alignment for DMA safety
      iio: accel: adxl367: Fix alignment for DMA safety
      iio: accel: bma220: Fix alignment for DMA safety
      iio: accel: sca3000: Fix alignment for DMA safety
      iio: accel: sca3300: Fix alignment for DMA safety
      iio: adc: ad7266: Fix alignment for DMA safety
      iio: adc: ad7280a: Fix alignment for DMA safety
      iio: adc: ad7292: Fix alignment for DMA safety
      iio: adc: ad7298: Fix alignment for DMA safety
      iio: adc: ad7476: Fix alignment for DMA safety
      iio: adc: ad7606: Fix alignment for DMA safety
      iio: adc: ad7766: Fix alignment for DMA safety
      iio: adc: ad7768-1: Fix alignment for DMA safety
      iio: adc: ad7887: Fix alignment for DMA safety
      iio: adc: ad7923: Fix alignment for DMA safety
      iio: adc: ad7949: Fix alignment for DMA safety
      iio: adc: hi8435: Fix alignment for DMA safety
      iio: adc: ltc2496: Fix alignment for DMA safety
      iio: adc: ltc2497: Fix alignment for DMA safety
      iio: adc: max1027: Fix alignment for DMA safety
      iio: adc: max11100: Fix alignment for DMA safety
      iio: adc: max1118: Fix alignment for DMA safety
      iio: adc: max1241: Fix alignment for DMA safety
      iio: adc: mcp320x: Fix alignment for DMA safety
      iio: adc: ti-adc0832: Fix alignment for DMA safety
      iio: adc: ti-adc084s021: Fix alignment for DMA safety
      iio: adc: ti-adc108s102: Fix alignment for DMA safety
      iio: adc: ti-adc12138: Fix alignment for DMA safety
      iio: adc: ti-adc128s052: Fix alignment for DMA safety
      iio: adc: ti-adc161s626: Fix alignment for DMA safety
      iio: adc: ti-ads124s08: Fix alignment for DMA safety
      iio: adc: ti-ads131e08: Fix alignment for DMA safety
      iio: adc: ti-ads7950: Fix alignment for DMA safety
      iio: adc: ti-ads8344: Fix alignment for DMA safety
      iio: adc: ti-ads8688: Fix alignment for DMA safety
      iio: adc: ti-tlc4541: Fix alignment for DMA safety
      iio: addac: ad74413r: Fix alignment for DMA safety
      iio: amplifiers: ad8366: Fix alignment for DMA safety
      iio: common: ssp: Fix alignment for DMA safety
      iio: dac: ad5064: Fix alignment for DMA safety
      iio: dac: ad5360: Fix alignment for DMA safety
      iio: dac: ad5421: Fix alignment for DMA safety
      iio: dac: ad5449: Fix alignment for DMA safety
      iio: dac: ad5504: Fix alignment for DMA safety
      iio: dac: ad5592r: Fix alignment for DMA safety
      iio: dac: ad5686: Fix alignment for DMA safety
      iio: dac: ad5755: Fix alignment for DMA safety
      iio: dac: ad5761: Fix alignment for DMA safety
      iio: dac: ad5764: Fix alignment for DMA safety
      iio: dac: ad5766: Fix alignment for DMA safety
      iio: dac: ad5770r: Fix alignment for DMA safety
      iio: dac: ad5791: Fix alignment for DMA saftey
      iio: dac: ad7293: Fix alignment for DMA safety
      iio: dac: ad7303: Fix alignment for DMA safety
      iio: dac: ad8801: Fix alignment for DMA safety
      iio: dac: ltc2688: Fix alignment for DMA safety
      iio: dac: mcp4922: Fix alignment for DMA safety
      iio: dac: ti-dac082s085: Fix alignment for DMA safety
      iio: dac: ti-dac5571: Fix alignment for DMA safety
      iio: dac: ti-dac7311: Fix alignment for DMA safety
      iio: dac: ti-dac7612: Fix alignment for DMA safety
      iio: frequency: ad9523: Fix alignment for DMA safety
      iio: frequency: adf4350: Fix alignment for DMA safety
      iio: frequency: adf4371: Fix alignment for DMA safety
      iio: frequency: admv1013: Fix alignment for DMA safety
      iio: frequency: admv1014: Fix alignment for DMA safety
      iio: frequency: admv4420: Fix alignment for DMA safety
      iio: frequency: adrf6780: Fix alignment for DMA safety
      iio: gyro: adis16080: Fix alignment for DMA safety
      iio: gyro: adis16130: Fix alignment for DMA safety
      iio: gyro: adxrs450: Fix alignment for DMA safety
      iio: gyro: fxas210002c: Fix alignment for DMA safety
      iio: imu: fxos8700: Fix alignment for DMA safety
      iio: imu: inv_icm42600: Fix alignment for DMA safety
      iio: imu: inv_icm42600: Fix alignment for DMA safety in buffer code.
      iio: imu: mpu6050: Fix alignment for DMA safety
      iio: potentiometer: ad5110: Fix alignment for DMA safety
      iio: potentiometer: ad5272: Fix alignment for DMA safety
      iio: potentiometer: max5481: Fix alignment for DMA safety
      iio: potentiometer: mcp41010: Fix alignment for DMA safety
      iio: potentiometer: mcp4131: Fix alignment for DMA safety
      iio: proximity: as3935: Fix alignment for DMA safety
      iio: resolver: ad2s1200: Fix alignment for DMA safety
      iio: resolver: ad2s90: Fix alignment for DMA safety
      iio: temp: ltc2983: Fix alignment for DMA safety
      iio: temp: max31865: Fix alignment for DMA safety
      iio: temp: maxim_thermocouple: Fix alignment for DMA safety

Jose Alonso (1):
      Revert "net: usb: ax88179_178a needs FLAG_SEND_ZLP"

Jose Ignacio Tornos Martinez (1):
      wifi: iwlwifi: mvm: fix double list_add at iwl_mvm_mac_wake_tx_queue

Josef Bacik (3):
      btrfs: tree-log: make the return value for log syncing consistent
      btrfs: reset block group chunk force if we have to wait
      btrfs: make the bg_reclaim_threshold per-space info

Josh Poimboeuf (1):
      scripts/faddr2line: Fix vmlinux detection on arm64

Julia Lawall (2):
      ia64: fix typos in comments
      powerpc: fix typos in comments

Juri Lelli (1):
      wait: Fix __wait_event_hrtimeout for RT/DL tasks

Jörn-Thorben Hinz (1):
      selftests/bpf: Fix rare segfault in sock_fields prog test

Kai Ye (1):
      crypto: hisilicon/sec - fix auth key size error

Kan Liang (1):
      perf stat: Revert "perf stat: Add default hybrid events"

Kees Cook (2):
      kasan: test: Silence GCC 12 warnings
      lib: overflow: Do not define 64-bit tests on 32-bit

Keith Busch (3):
      block: fix infinite loop for invalid zone append
      block/bio: remove duplicate append pages code
      block: ensure iov_iter advances for added pages

Kent Overstreet (2):
      9p: Drop kref usage
      9p: Add client parameter to p9_req_put()

Kim Phillips (1):
      x86/bugs: Enable STIBP for IBPB mitigated RETBleed

Konrad Dybcio (14):
      ARM: dts: qcom-msm8974*: Fix UART naming
      ARM: dts: qcom-msm8974*: Fix I2C labels
      ARM: dts: qcom-msm8974: Fix up mdss nodes
      ARM: dts: qcom-msm8974: Fix up SDHCI nodes
      ARM: dts: qcom-msm8974*: Rename msmgpio to tlmm
      ARM: dts: qcom-apq8074-dragonboard: Use &labels
      ARM: dts: qcom-msm8974-fp2: Use &labels
      ARM: dts: qcom-msm8974-lge-nexus5: Use &labels
      ARM: dts: qcom-msm8974-klte: Use &labels
      ARM: dts: qcom-msm8974-{"hon","am"}ami: Commonize and modernize the DTs
      ARM: dts: qcom-msm8974-castor: Use &labels
      ARM: dts: qcom-msm8974: Convert ADSP to a MMIO device
      ARM: dts: qcom-msm8974: Sort and clean up nodes
      soc: qcom: Make QCOM_RPMPD depend on PM

Krzysztof Kozlowski (13):
      arm64: dts: qcom: add missing AOSS QMP compatible fallback
      ARM: dts: ast2500-evb: fix board compatible
      ARM: dts: ast2600-evb: fix board compatible
      ARM: dts: ast2600-evb-a1: fix board compatible
      spi: s3c64xx: constify fsd_spi_port_config
      ARM: dts: qcom: mdm9615: add missing PMIC GPIO reg
      ARM: dts: qcom: msm8974-lge-nexus5: move gpio-keys out of soc
      ARM: dts: qcom: msm8974-samsung-klte: move gpio-keys out of soc
      ARM: dts: qcom: do not use underscore in node name
      ARM: dts: qcom: msm8974: add required ranges to OCMEM
      ARM: dts: qcom: pm8841: add required thermal-sensor-cells
      ath10k: do not enforce interrupt trigger type
      ASoC: samsung: h1940_uda1380: include proepr GPIO consumer header

Kui-Feng Lee (1):
      bpf, x86: Generate trampolines from bpf_tramp_links

Kumar Kartikeya Dwivedi (10):
      bpf: Make btf_find_field more generic
      bpf: Move check_ptr_off_reg before check_map_access
      bpf: Allow storing unreferenced kptr in map
      bpf: Tag argument to be released in bpf_func_proto
      bpf: Allow storing referenced kptr in map
      bpf: Adapt copy_map_value for multiple offset case
      bpf: Populate pairs of btf_id and destructor kfunc in btf
      bpf: Wire up freeing of referenced kptr
      bpf: Fix sparse warning for bpf_kptr_xchg_proto
      bpf: Suppress 'passing zero to PTR_ERR' warning

Kunihiko Hayashi (2):
      ARM: dts: uniphier: Fix USB interrupts for PXs2 SoC
      arm64: dts: uniphier: Fix USB interrupts for PXs3 SoC

Kuninori Morimoto (1):
      ASoC: audio-graph-card2.c: use of_property_read_u32() for rate

Kuniyuki Iwashima (1):
      raw: Fix mixed declarations error in raw_icmp_error().

Lad Prabhakar (1):
      mmc: renesas_sdhi: Get the reset handle early in the probe

Lars-Peter Clausen (1):
      i2c: cadence: Support PEC for SMBus block read

Leo Li (1):
      drm/amdgpu: Check BO's requested pinning domains against its preferred_domains

Lev Kujawski (1):
      KVM: set_msr_mce: Permit guests to ignore single-bit ECC errors

Li Lingfeng (1):
      ext4: recover csum seed of tmp_inode after migrating to extents

Liam R. Howlett (1):
      android: binder: stop saving a pointer to the VMA

Liang He (22):
      ARM: OMAP2+: display: Fix refcount leak bug
      ARM: OMAP2+: pdata-quirks: Fix refcount leak bug
      ARM: shmobile: rcar-gen2: Increase refcount for new reference
      soc: amlogic: Fix refcount leak in meson-secure-pwrc.c
      regulator: of: Fix refcount leak bug in of_get_regulation_constraints()
      perf: RISC-V: Add of_node_put() when breaking out of for_each_of_cpu_node()
      mediatek: mt76: mac80211: Fix missing of_node_put() in mt76_led_init()
      mediatek: mt76: eeprom: fix missing of_node_put() in mt76_find_power_limits_node()
      i2c: mux-gpmux: Add of_node_put() when breaking out of loop
      of: device: Fix missing of_node_put() in of_dma_set_restricted_buffer
      usb: aspeed-vhub: Fix refcount leak bug in ast_vhub_init_desc()
      gpio: gpiolib-of: Fix refcount bugs in of_mm_gpiochip_add_data()
      mmc: core: quirks: Add of_node_put() when breaking out of loop
      mmc: cavium-octeon: Add of_node_put() when breaking out of loop
      mmc: cavium-thunderx: Add of_node_put() when breaking out of loop
      ASoC: qcom: Fix missing of_node_put() in asoc_qcom_lpass_cpu_platform_probe()
      ASoc: audio-graph-card2: Fix refcount leak bug in __graph_get_type()
      ASoC: mt6359: Fix refcount leak bug
      iommu/arm-smmu: qcom_iommu: Add of_node_put() when breaking out of loop
      ASoC: audio-graph-card: Add of_node_put() in fail path
      ASoC: audio-graph-card2: Add of_node_put() in fail path
      video: fbdev: amba-clcd: Fix refcount leak bugs

Like Xu (2):
      KVM: x86/pmu: Introduce the ctrl_mask value for fixed counter
      KVM: x86/pmu: Ignore pmu->global_ctrl check if vPMU doesn't support global_ctrl

Linus Walleij (4):
      ARM: dts: ux500: Fix Janice accelerometer mounting matrix
      ARM: dts: ux500: Fix Codina accelerometer mounting matrix
      ARM: dts: ux500: Fix Gavini accelerometer mounting matrix
      hwmon: (drivetemp) Add module alias

Linyu Yuan (1):
      usb: typec: ucsi: Acknowledge the GET_ERROR_STATUS command completion

Liu Jian (1):
      skmsg: Fix invalid last sg check in sk_msg_recvmsg()

Liu Ying (1):
      clk: imx: clk-fracn-gppll: Return rate in rate table properly in ->recalc_rate()

Lorenzo Bianconi (3):
      mt76: mt76x02u: fix possible memory leak in __mt76x02u_mcu_send_msg
      mt76: mt7615: do not update pm stats in case of error
      mt76: mt7921: do not update pm states in case of error

Luca Weiss (2):
      ARM: dts: qcom-msm8974: fix irq type on blsp2_uart1
      ARM: dts: qcom: msm8974-FP2: Add supplies for remoteprocs

Luiz Augusto von Dentz (2):
      Bluetooth: hci_sync: Fix not updating privacy_mode
      Bluetooth: L2CAP: Fix l2cap_global_chan_by_psm regression

Lukas Czerner (2):
      ext4: check if directory block is within i_size
      ext4: make sure ext4_append() always allocates new block

Lukas Wunner (6):
      usbnet: Fix linkwatch use-after-free on disconnect
      usbnet: smsc95xx: Don't clear read-only PHY interrupt
      usbnet: smsc95xx: Avoid link settings race on interrupt reception
      usbnet: smsc95xx: Forward PHY interrupts to PHY driver to avoid polling
      usbnet: smsc95xx: Fix deadlock on runtime resume
      net: phy: smsc: Disable Energy Detect Power-Down in interrupt mode

Luo Meng (1):
      dm thin: fix use-after-free crash in dm_sm_register_threshold_callback

Lv Ruyi (1):
      firmware: tegra: Fix error check return value of debugfs_create_file()

Lyude Paul (3):
      drm/nouveau: Don't pm_runtime_put_sync(), only pm_runtime_put_autosuspend()
      drm/nouveau/acpi: Don't print error when we get -EINPROGRESS from pm_runtime
      drm/nouveau/kms: Fix failure path for creating DP connectors

Maciej Fijalkowski (1):
      selftests/xsk: Destroy BPF resources only when ctx refcount drops to 0

Maciej S. Szmigiero (1):
      KVM: SVM: Don't BUG if userspace injects an interrupt with GIF=0

Maciej W. Rozycki (3):
      serial: 8250: Export ICR access helpers for internal use
      serial: 8250: Fold EndRun device support into OxSemi Tornado code
      serial: 8250: Add proper clock handling for OxSemi PCIe devices

Maciej Żenczykowski (1):
      net: usb: make USB_RTL8153_ECM non user configurable

Maher Sanalla (1):
      net/mlx5: Adjust log_max_qp to be 18 at most

Mahesh Rajashekhara (1):
      scsi: smartpqi: Fix DMA direction for RAID requests

Manikanta Pubbisetty (2):
      ath11k: Fix incorrect debug_mask mappings
      ath11k: Avoid REO CMD failed prints during firmware recovery

Manivannan Sadhasivam (1):
      ARM: dts: qcom: sdx55: Fix the IRQ trigger type for UART

Manyi Li (1):
      ACPI: PM: save NVS memory for Lenovo G40-45

Maor Dickman (1):
      net/mlx5e: TC, Fix post_act to not match on in_port metadata

Maor Gottlieb (1):
      RDMA/mlx5: Add missing check for return value in get namespace flow

Marc Kleine-Budde (2):
      can: netlink: allow configuring of fixed bit rates without need for do_set_bittiming callback
      can: netlink: allow configuring of fixed data bit rates without need for do_set_data_bittiming callback

Marc Zyngier (1):
      arm64: Expand ESR_ELx_WFx_ISS_TI to match its ARMv8.7 definition

Marcel Ziswiler (1):
      ARM: dts: imx7d-colibri-emmc: add cpu1 supply

Marco Pagani (1):
      fpga: altera-pr-ip: fix unsigned comparison with less than zero

Marek Vasut (3):
      drm/bridge: tc358767: Move (e)DP bridge endpoint parsing into dedicated function
      drm/bridge: tc358767: Make sure Refclk clock are enabled
      drm/bridge: tc358767: Fix (e)DP bridge endpoint parsing in dedicated function

Marijn Suijten (4):
      arm64: dts: qcom: sdm845-akatsuki: Round down l22a regulator voltage
      arm64: dts: qcom: sm6125: Move sdc2 pinctrl from seine-pdx201 to sm6125
      arm64: dts: qcom: sm6125: Append -state suffix to pinctrl nodes
      arm64: dts: qcom: msm8998: Make regulator voltages multiple of step-size

Mario Limonciello (2):
      pinctrl: Don't allow PINCTRL_AMD to be a module
      HID: amd_sfh: Don't show client init failed as error when discovery fails

Marios Makassikis (1):
      ksmbd: validate length in smb2_write()

Mark Brown (1):
      mtd: dataflash: Add SPI ID table

Mark Kettenis (1):
      riscv: dts: starfive: correct number of external interrupts

Mark Rutland (2):
      arch: make TRACE_IRQFLAGS_NMI_SUPPORT generic
      arm64: select TRACE_IRQFLAGS_NMI_SUPPORT

Markus Mayer (1):
      thermal/tools/tmon: Include pthread and time headers in tmon.h

Martin KaFai Lau (1):
      selftests/bpf: Fix tc_redirect_dtime

Masami Hiramatsu (Google) (1):
      x86/kprobes: Update kcb status flag after singlestepping

Mateusz Jończyk (1):
      drm/radeon: avoid bogus "vram limit (0) must be a power of 2" warning

Mateusz Kwiatkowski (1):
      drm/vc4: hdmi: Fix timings for interlaced modes

Mathew McBride (1):
      rtc: rx8025: fix 12/24 hour mode detection on RX-8035

Matthew Wilcox (Oracle) (2):
      mm: Account dirty folios properly during splits
      cifs: Fix memory leak when using fscache

Max Filippov (1):
      xtensa: iss/network: provide release() callback

Max Krummenacher (1):
      Revert "ARM: dts: imx6qdl-apalis: Avoid underscore in node name"

Maxim Mikityanskiy (4):
      net/mlx5e: Fix the value of MLX5E_MAX_RQ_NUM_MTTS
      net/mlx5e: xsk: Account for XSK RQ UMRs when calculating ICOSQ size
      net/mlx5e: Fix calculations related to max MPWQE size
      net/mlx5e: xsk: Discard unaligned XSK frames on striding RQ

Maxime Ripard (1):
      drm/vc4: kms: Use maximum FIFO load for the HVS clock rate

Maximilian Heyne (1):
      xen-blkback: Apply 'feature_persistent' parameter when connect

Maximilian Luz (1):
      HID: hid-input: add Surface Go battery quirk

Md Haris Iqbal (3):
      RDMA/rtrs-clt: Replace list_next_or_null_rr_rcu with an inline function
      RDMA/rxe: For invalidate compare according to set keys in mr
      block/rnbd-srv: Set keep_id to true after mutex_trylock

Mel Gorman (1):
      sched/core: Do not requeue task on CPU excluded from cpus_mask

Meng Tang (2):
      ALSA: hda/conexant: Add quirk for LENOVO 20149 Notebook model
      ALSA: hda/realtek: Add quirk for another Asus K42JZ model

Miaohe Lin (6):
      lib/test_hmm: avoid accessing uninitialized pages
      mm/memremap: fix memunmap_pages() race with get_dev_pagemap()
      mm/migration: return errno when isolate_huge_page failed
      mm/migration: fix potential pte_unmap on an not mapped pte
      mm/mmap.c: fix missing call to vm_unacct_memory in mmap_region
      hugetlb_cgroup: fix wrong hugetlb cgroup numa stat

Miaoqian Lin (35):
      meson-mx-socinfo: Fix refcount leak in meson_mx_socinfo_init
      ARM: bcm: Fix refcount leak in bcm_kona_smc_init
      ARM: OMAP2+: Fix refcount leak in omapdss_init_of
      ARM: OMAP2+: Fix refcount leak in omap3xxx_prm_late_init
      cpufreq: zynq: Fix refcount leak in zynq_get_revision
      soc: qcom: ocmem: Fix refcount leak in of_get_ocmem
      soc: qcom: aoss: Fix refcount leak in qmp_cooling_devices_register
      drm/meson: Fix refcount leak in meson_encoder_hdmi_init
      drm/meson: encoder_cvbs: Fix refcount leak in meson_encoder_cvbs_init
      drm/meson: encoder_hdmi: Fix refcount leak in meson_encoder_hdmi_init
      drm/virtio: Fix NULL vs IS_ERR checking in virtio_gpu_object_shmem_init
      drm/mcde: Fix refcount leak in mcde_dsi_bind
      media: tw686x: Fix memory leak in tw686x_video_init
      mtd: maps: Fix refcount leak in of_flash_probe_versatile
      mtd: maps: Fix refcount leak in ap_flash_init
      PCI: microchip: Fix refcount leak in mc_pcie_init_irq_domains()
      PCI: tegra194: Fix PM error handling in tegra_pcie_config_ep()
      mtd: partitions: Fix refcount leak in parse_redboot_of
      mtd: parsers: ofpart: Fix refcount leak in bcm4908_partitions_fw_offset
      PCI: mediatek-gen3: Fix refcount leak in mtk_pcie_init_irq_domains()
      usb: host: Fix refcount leak in ehci_hcd_ppc_of_probe
      usb: ohci-nxp: Fix refcount leak in ohci_hcd_nxp_probe
      mmc: sdhci-of-esdhc: Fix refcount leak in esdhc_signal_voltage_switch
      ASoC: cros_ec_codec: Fix refcount leak in cros_ec_codec_platform_probe
      ASoC: samsung: Fix error handling in aries_audio_probe
      ASoC: mediatek: mt8173: Fix refcount leak in mt8173_rt5650_rt5676_dev_probe
      ASoC: mt6797-mt6351: Fix refcount leak in mt6797_mt6351_dev_probe
      ASoC: mediatek: mt8173-rt5650: Fix refcount leak in mt8173_rt5650_dev_probe
      remoteproc: k3-r5: Fix refcount leak in k3_r5_cluster_of_init
      remoteproc: imx_rproc: Fix refcount leak in imx_rproc_addr_init
      rpmsg: qcom_smd: Fix refcount leak in qcom_smd_parse_edge
      mfd: max77620: Fix refcount leak in max77620_initialise_fps
      powerpc/spufs: Fix refcount leak in spufs_init_isolated_loader
      powerpc/xive: Fix refcount leak in xive_get_max_prio
      powerpc/cell/axon_msi: Fix refcount leak in setup_msi_msg_address

Michael Ellerman (5):
      powerpc/powernv: Avoid crashing if rng is NULL
      powerpc/64s: Disable stack variable initialisation for prom_init
      selftests/powerpc: Skip energy_scale_info test on older firmware
      powerpc/pci: Fix PHB numbering when using opal-phbid
      powerpc/64e: Fix kexec build error

Michael Grzeschik (2):
      usb: dwc3: gadget: refactor dwc3_repare_one_trb
      usb: dwc3: gadget: fix high speed multiplier setting

Michael Walle (1):
      soc: fsl: guts: machine variable might be unset

Michal Koutný (1):
      io_uring: Don't require reinitable percpu_ref

Michal Suchanek (1):
      kexec, KEYS, s390: Make use of built-in and secondary keyring for signature verification

Mike Christie (3):
      scsi: iscsi: Allow iscsi_if_stop_conn() to be called from kernel
      scsi: iscsi: Add helper to remove a session from the kernel
      scsi: iscsi: Fix session removal on shutdown

Mike Leach (2):
      coresight: configfs: Fix unload of configurations on module exit
      coresight: syscfg: Update load and unload operations

Mike Manning (1):
      net: allow unbound socket for packets in VRF when tcp_l3mdev_accept set

Mike Snitzer (1):
      dm: return early from dm_pr_call() if DM device is suspended

Mikko Perttunen (1):
      arm64: tegra: Mark BPMP channels as no-memory-wc

Miklos Szeredi (4):
      fuse: limit nsec
      fuse: ioctl: translate ENOSYS
      fuse: write inode in fuse_release()
      fuse: fix deadlock between atomic O_TRUNC and page invalidation

Mikulas Patocka (10):
      add barriers to buffer_uptodate and set_buffer_uptodate
      md-raid: destroy the bitmap after destroying the thread
      md-raid10: fix KASAN warning
      dm writecache: return void from functions
      dm writecache: count number of blocks read, not number of read bios
      dm writecache: count number of blocks written, not number of write bios
      dm writecache: count number of blocks discarded, not number of discard bios
      dm writecache: set a default MAX_WRITEBACK_JOBS
      dm raid: fix address sanitizer warning in raid_status
      dm raid: fix address sanitizer warning in raid_resume

Milan Landaverde (1):
      bpftool: Add missing link types

Ming Lei (1):
      blk-mq: don't create hctx debugfs dir until q->debugfs_dir is created

Ming Qian (17):
      media: amphion: return error if format is unsupported by vpu
      media: imx-jpeg: Correct some definition according specification
      media: imx-jpeg: Leave a blank space before the configuration data
      media: imx-jpeg: Refactor function mxc_jpeg_parse
      media: imx-jpeg: Identify and handle precision correctly
      media: imx-jpeg: Handle source change in a function
      media: imx-jpeg: Support dynamic resolution change
      media: imx-jpeg: Align upwards buffer size
      media: imx-jpeg: Implement drain using v4l2-mem2mem helpers
      media: imx-jpeg: Disable slot interrupt when frame done
      media: amphion: output firmware error message
      media: v4l2-mem2mem: prevent pollerr when last_buffer_dequeued is set
      media: amphion: release core lock before reset vpu core
      media: amphion: defer setting last_buffer_dequeued until resolution changes are processed
      media: amphion: decoder copy timestamp from output to capture
      media: amphion: sync buffer status with firmware during abort
      media: amphion: only insert the first sequence startcode for vc1l format

Mohamed Khalfella (1):
      PCI/AER: Iterate over error counters instead of error strings

Muneendra Kumar (1):
      scsi: nvme-fc: Add new routine nvme_fc_io_getuuid()

Mustafa Ismail (3):
      RDMA/irdma: Fix a window for use-after-free
      RDMA/irdma: Fix VLAN connection with wildcard address
      RDMA/irdma: Fix setting of QP context err_rq_idx_valid field

Mårten Lindahl (1):
      tpm: Add check for Failure mode for TPM2 modules

Namjae Jeon (5):
      ksmbd: fix memory leak in smb2_handle_negotiate
      ksmbd: fix use-after-free bug in smb2_tree_disconect
      ksmbd: fix heap-based overflow in set_ntacl_dacl()
      ksmbd: add smbd max io size parameter
      ksmbd: fix wrong smbd max read/write size check

Nandhini Srikandan (1):
      spi: dw: Fix IP-core versions macro

Naohiro Aota (15):
      btrfs: ensure pages are unlocked on cow_file_range() failure
      btrfs: fix error handling of fallback uncompress write
      block: add bdev_max_segments() helper
      btrfs: zoned: revive max_zone_append_bytes
      btrfs: replace BTRFS_MAX_EXTENT_SIZE with fs_info->max_extent_size
      btrfs: let can_allocate_chunk return error
      btrfs: zoned: finish least available block group on data bg allocation
      btrfs: zoned: disable metadata overcommit for zoned
      btrfs: zoned: introduce btrfs_zoned_bg_is_full
      btrfs: zoned: introduce space_info->active_total_bytes
      btrfs: zoned: activate metadata block group on flush_space
      btrfs: zoned: activate necessary block group
      btrfs: zoned: write out partially allocated region
      btrfs: zoned: wait until zone is finished when allocation didn't progress
      btrfs: convert count_max_extents() to use fs_info->max_extent_size

Narendra Hadke (1):
      serial: mvebu-uart: uart2 error bits clearing

Nathan Chancellor (1):
      usb: cdns3: Don't use priv_dev uninitialized in cdns3_gadget_ep_enable()

Naveen N. Rao (1):
      kexec_file: drop weak attribute from functions

Neal Liu (1):
      usb: gadget: f_mass_storage: Make CD-ROM emulation works with Windows OS

Nick Bowler (1):
      nvme: define compat_ioctl again to unbreak 32-bit userspace.

Nick Desaulniers (2):
      Makefile: link with -z noexecstack --no-warn-rwx-segments
      x86: link vdso and boot with -z noexecstack --no-warn-rwx-segments

Nick Hainke (1):
      arm64: dts: mt7622: fix BPI-R64 WPS button

Nico Boehr (1):
      KVM: s390: pv: don't present the ecall interrupt twice

Nicolas Saenz Julienne (1):
      nohz/full, sched/rt: Fix missed tick-reenabling bug in dequeue_task_rt()

Niels Dossche (1):
      media: hdpvr: fix error value returns in hdpvr_read

Nikita Travkin (2):
      clk: qcom: clk-rcg2: Fail Duty-Cycle configuration if MND divider is not enabled.
      clk: qcom: clk-rcg2: Make sure to not write d=0 to the NMD register

Niklas Söderlund (1):
      media: rcar-vin: Fix channel routing for Ebisu

Nikolay Borisov (1):
      btrfs: properly flag filesystem with BTRFS_FEATURE_INCOMPAT_BIG_METADATA

Nilesh Javali (1):
      scsi: Revert "scsi: qla2xxx: Fix disk failure to rediscover"

Nícolas F. R. A. Prado (2):
      arm64: dts: mt8192: Fix idle-states nodes naming scheme
      arm64: dts: mt8192: Fix idle-states entry-method

Oleksij Rempel (1):
      net: ag71xx: fix discards 'const' qualifier warning

Olga Kitaina (1):
      mtd: rawnand: arasan: Fix clock rate in NV-DDR

Pali Rohár (3):
      powerpc/fsl-pci: Fix Class Code of PCIe Root Port
      crypto: inside-secure - Add missing MODULE_DEVICE_TABLE for of
      powerpc/pci: Prefer PCI domain assignment via DT 'linux,pci-domain' and alias

Paolo Abeni (1):
      mptcp: refine memory scheduling

Paolo Bonzini (2):
      KVM: x86: do not report preemption if the steal time cache is stale
      KVM: x86: revalidate steal time cache if MSR value changes

Parikshit Pareek (1):
      soc: qcom: socinfo: Fix the id of SA8540P SoC

Patrice Chotard (1):
      mtd: spi-nor: fix spi_nor_spimem_setup_op() call in spi_nor_erase_{sector,chip}()

Paul Cercueil (1):
      drm/ingenic: Use the highest possible DMA burst size

Paul E. McKenney (2):
      rcutorture: Make kvm.sh allow more memory for --kasan runs
      torture: Adjust to again produce debugging information

Pavel Begunkov (1):
      io_uring: mem-account pbuf buckets

Pavel Skripkin (1):
      ath9k: fix use-after-free in ath9k_hif_usb_rx_cb

Peng Fan (4):
      clk: imx93: correct nic_media parent
      clk: imx: clk-fracn-gppll: fix mfd value
      clk: imx: clk-fracn-gppll: correct rdiv
      interconnect: imx: fix max_node_id

Peter Suti (1):
      staging: fbtft: core: set smem_len before fb_deferred_io_init call

Peter Ujfalusi (2):
      ASoC: SOF: make ctx_store and ctx_restore as optional
      ASoC: SOF: ipc3-topology: Prevent double freeing of ipc_control_data via load_bytes

Peter Wang (1):
      scsi: ufs: core: Correct ufshcd_shutdown() flow

Peter Zijlstra (2):
      locking/lockdep: Fix lockdep_init_map_*() confusion
      x86/extable: Fix ex_handler_msr() print condition

Phil Auld (1):
      drivers/base: fix userspace break from using bin_attributes for cpumap and cpulist

Phil Elwell (1):
      drm/vc4: hdmi: Disable audio if dmas property is present but empty

Philipp Jungkamp (1):
      ALSA: hda/realtek: Add quirk for Lenovo Yoga9 14IAP7

Pierre-Louis Bossart (2):
      soundwire: bus_type: fix remove and shutdown support
      soundwire: revisit driver bind/unbind and callbacks

Ping Cheng (2):
      HID: wacom: Only report rotation for art pen
      HID: wacom: Don't register pad_input for touch switch

Ping-Ke Shih (1):
      wifi: rtw89: 8852a: rfk: fix div 0 exception

Piotr Oniszczuk (1):
      media: hantro: Add support for Hantro G1 on RK356x

Przemyslaw Patynowski (2):
      iavf: Fix max_rate limiting
      iavf: Fix 'tc qdisc show' listing too many queues

Qian Cai (1):
      crypto: arm64/gcm - Select AEAD for GHASH_ARM64_CE

Qiao Ma (2):
      net: hinic: fix bug that ethtool get wrong stats
      net: hinic: avoid kernel hung in hinic_get_stats64()

Qu Wenruo (1):
      btrfs: reject log replay if there is unsupported RO compat flag

Quentin Perret (1):
      KVM: arm64: Don't return from void function

Quinn Tran (20):
      scsi: qla2xxx: edif: Reduce Initiator-Initiator thrashing
      scsi: qla2xxx: edif: bsg refactor
      scsi: qla2xxx: edif: Wait for app to ack on sess down
      scsi: qla2xxx: edif: Add bsg interface to read doorbell events
      scsi: qla2xxx: edif: Fix potential stuck session in sa update
      scsi: qla2xxx: edif: Synchronize NPIV deletion with authentication application
      scsi: qla2xxx: edif: Add retry for ELS passthrough
      scsi: qla2xxx: edif: Fix n2n discovery issue with secure target
      scsi: qla2xxx: edif: Fix n2n login retry for secure device
      scsi: qla2xxx: edif: Send LOGO for unexpected IKE message
      scsi: qla2xxx: edif: Reduce disruption due to multiple app start
      scsi: qla2xxx: edif: Fix no login after app start
      scsi: qla2xxx: edif: Tear down session if keys have been removed
      scsi: qla2xxx: edif: Fix session thrash
      scsi: qla2xxx: edif: Fix no logout on delete for N2N
      scsi: qla2xxx: edif: Reduce N2N thrashing at app_start time
      scsi: qla2xxx: Fix imbalance vha->vref_count
      scsi: qla2xxx: Turn off multi-queue for 8G adapters
      scsi: qla2xxx: Fix erroneous mailbox timeout after PCI error injection
      scsi: qla2xxx: Wind down adapter after PCIe error

Rafael J. Wysocki (2):
      thermal: sysfs: Fix cooling_device_stats_setup() error code path
      ACPI: CPPC: Do not prevent CPPC from working in the future

Ralph Siemsen (1):
      clk: renesas: r9a06g032: Fix UART clkgrp bitsel

Randy Dunlap (2):
      media: isl7998x: select V4L2_FWNODE to fix build error
      usb: gadget: udc: amd5536 depends on HAS_DMA

Rex-BC Chen (1):
      clk: mediatek: reset: Fix written reset bit offset

Rob Clark (2):
      drm/msm/mdp5: Fix global state lock backoff
      drm/msm/dpu: Fix for non-visible planes

Robert Marko (6):
      arm64: dts: qcom: ipq8074: fix NAND node name
      clk: qcom: ipq8074: fix NSS core PLL-s
      clk: qcom: ipq8074: SW workaround for UBI32 PLL lock
      clk: qcom: ipq8074: fix NSS port frequency tables
      clk: qcom: ipq8074: set BRANCH_HALT_DELAY flag for UBI clocks
      PCI: qcom: Power on PHY before IPQ8074 DBI register accesses

Robin Murphy (1):
      swiotlb: fail map correctly with failed io_tlb_default_mem

Rohith Kollalsi (1):
      usb: dwc3: core: Do not perform GCTL_CORE_SOFTRESET during bootup

Russell Currey (1):
      powerpc/kexec: Fix build failure from uninitialised variable

Russell King (Oracle) (1):
      ARM: findbit: fix overflowing offset

Rustam Subkhankulov (2):
      wifi: p54: add missing parentheses in p54_flush()
      video: fbdev: sis: fix typos in SiS_GetModeID()

Sam Protsenko (1):
      iommu/exynos: Handle failed IOMMU device registration properly

Samuel Holland (4):
      irqchip/mips-gic: Only register IPI domain when SMP is enabled
      genirq: GENERIC_IRQ_IPI depends on SMP
      arm64: dts: allwinner: a64: orangepi-win: Fix LED node name
      phy: rockchip-inno-usb2: Ignore OTG IRQs in host mode

Schspa Shi (1):
      Bluetooth: When HCI work queue is drained, only queue chained work

Sean Christopherson (23):
      KVM: nVMX: Snapshot pre-VM-Enter BNDCFGS for !nested_run_pending case
      KVM: nVMX: Snapshot pre-VM-Enter DEBUGCTL for !nested_run_pending case
      KVM: Drop unused @gpa param from gfn=>pfn cache's __release_gpc() helper
      KVM: Put the extra pfn reference when reusing a pfn in the gpc cache
      KVM: Fully serialize gfn=>pfn cache refresh via mutex
      KVM: Fix multiple races in gfn=>pfn cache refresh
      KVM: Do not incorporate page offset into gfn=>pfn cache user address
      KVM: x86: Split kvm_is_valid_cr4() and export only the non-vendor bits
      KVM: nVMX: Let userspace set nVMX MSR to any _host_ supported value
      KVM: nVMX: Account for KVM reserved CR4 bits in consistency checks
      KVM: nVMX: Inject #UD if VMXON is attempted with incompatible CR0/CR4
      KVM: x86: Mark TSS busy during LTR emulation _after_ all fault checks
      KVM: x86: Set error code to segment selector on LLDT/LTR non-canonical #GP
      KVM: x86: Tag kvm_mmu_x86_module_init() with __init
      KVM: SVM: Unwind "speculative" RIP advancement if INTn injection "fails"
      KVM: SVM: Stuff next_rip on emulated INT3 injection if NRIPS is supported
      KVM: x86/mmu: Drop RWX=0 SPTEs during ept_sync_page()
      KVM: Don't set Accessed/Dirty bits for ZERO_PAGE
      KVM: nVMX: Set UMIP bit CR4_FIXED1 MSR when emulating UMIP
      KVM: x86: Signal #GP, not -EPERM, on bad WRMSR(MCi_CTL/STATUS)
      KVM: VMX: Mark all PERF_GLOBAL_(OVF)_CTRL bits reserved if there's no vPMU
      KVM: VMX: Add helper to check if the guest PMU has PERF_GLOBAL_CTRL
      KVM: nVMX: Attempt to load PERF_GLOBAL_CTRL on nVMX xfer iff it exists

Sebastian Fricke (1):
      media: staging: media: hantro: Fix typos

SeongJae Park (2):
      xen-blkback: fix persistent grants negotiation
      xen-blkfront: Apply 'feature_persistent' parameter when connect

Serge Semin (7):
      dmaengine: dw-edma: Fix eDMA Rd/Wr-channels and DMA-direction semantics
      PCI: dwc: Stop link on host_init errors and de-initialization
      PCI: dwc: Add unroll iATU space support to dw_pcie_disable_atu()
      PCI: dwc: Disable outbound windows only for controllers using iATU
      PCI: dwc: Set INCREASE_REGION_SIZE flag based on limit address
      PCI: dwc: Deallocate EPC memory on dw_pcie_ep_init() errors
      PCI: dwc: Always enable CDM check if "snps,enable-cdm-check" exists

Sergey Shtylyov (1):
      usb: host: xhci: use snprintf() in xhci_decode_trb()

Shay Drory (1):
      net/mlx5: Fix driver use of uninitialized timeout

Shengjiu Wang (6):
      rpmsg: char: Add mutex protection for rpmsg_eptdev_open()
      ASoC: imx-card: Fix DSD/PDM mclk frequency
      ASoC: fsl_asrc: force cast the asrc_format type
      ASoC: fsl-asoc-card: force cast the asrc_format type
      ASoC: fsl_easrc: use snd_pcm_format_t type for sample_format
      ASoC: imx-card: use snd_pcm_format_t type for asrc_format

Sherry Sun (1):
      tty: serial: fsl_lpuart: correct the count of break characters

Shunsuke Mie (1):
      PCI: endpoint: Don't stop controller when unbinding endpoint function

Shuqi Zhang (1):
      ext4: use kmemdup() to replace kmalloc + memcpy

Sibi Sankar (1):
      remoteproc: sysmon: Wait for SSCTL service to come up

Siddh Raman Pant (1):
      x86/numa: Use cpumask_available instead of hardcoded NULL check

Siddharth Gupta (1):
      remoteproc: qcom: pas: Check if coredump is enabled

Sireesh Kodali (2):
      arm64: dts: qcom: msm8916: Fix typo in pronto remoteproc node
      remoteproc: qcom: wcnss: Fix handling of IRQs

Song Liu (1):
      bpf, x86: fix freeing of not-finalized bpf_prog_pack

Srinivas Kandagatla (4):
      soundwire: qcom: Check device status before reading devid
      ASoC: codecs: msm8916-wcd-digital: move gains from SX_TLV to S8_TLV
      ASoC: codecs: wcd9335: move gains from SX_TLV to S8_TLV
      ASoC: codecs: wsa881x: handle timeouts in resume path

Stefan Roesch (1):
      btrfs: store chunk size in space-info struct

Stefan Roese (1):
      PCI/portdrv: Don't disable AER reporting in get_port_device_capability()

Steffen Maier (1):
      scsi: zfcp: Fix missing auto port scan and thus missing target ports

Stephan Gerhold (2):
      regulator: qcom_smd: Fix pm8916_pldo range
      ARM: dts: qcom: msm8974: Disable remoteprocs by default

Stephane Eranian (1):
      perf/core: Add perf_clear_branch_entry_bitfields() helper

Stephen Boyd (2):
      arm64: dts: qcom: sc7180: Remove ipa_fw_mem node on trogdor
      platform/chrome: cros_ec: Always expose last resume result

Steven Rostedt (Google) (5):
      ftrace/x86: Add back ftrace_expected assignment
      tracing/events: Add __vstring() and __assign_vstr() helper macros
      batman-adv: tracing: Use the new __vstring() helper
      tracing: Use a struct alignof to determine trace event field alignment
      tracing: Use a copy of the va_list for __assign_vstr()

Sudeep Holla (1):
      firmware: arm_scpi: Ensure scpi_info is not assigned if the probe fails

Sumanth Korikkar (1):
      s390/unwind: fix fgraph return address recovery

Sumit Garg (1):
      arm64: dts: qcom: qcs404: Fix incorrect USB2 PHYs assignment

Sungjong Seo (1):
      f2fs: allow compression for mmap files in compress_mode=user

Sunil V L (1):
      riscv: spinwait: Fix hartid variable type

Suzuki K Poulose (1):
      coresight: Clear the connection field properly

Tadeusz Struk (1):
      bpf: Fix KASAN use-after-free Read in compute_effective_progs

Takashi Iwai (1):
      ALSA: usb-audio: Add quirk for Behringer UMC202HD

Tales Lelo da Aparecida (1):
      drm/vkms: check plane_composer->map[0] before using it

Tali Perry (2):
      i2c: npcm: Remove own slave addresses 2:10
      i2c: npcm: Correct slave role behavior

Tamás Szűcs (1):
      arm64: tegra: Fix SDMMC1 CD on P2888

Tang Bin (3):
      usb: gadget: tegra-xudc: Fix error check in tegra_xudc_powerdomain_init()
      usb: xhci: tegra: Fix error check
      opp: Fix error check in dev_pm_opp_attach_genpd()

Tetsuo Handa (3):
      tty: vt: initialize unicode screen buffer
      PM: hibernate: defer device probing when resuming from hibernation
      lib/smp_processor_id: fix imbalanced instrumentation_end() call

Thadeu Lima de Souza Cascardo (5):
      netfilter: nf_tables: do not allow SET_ID to refer to another table
      netfilter: nf_tables: do not allow CHAIN_ID to refer to another table
      netfilter: nf_tables: do not allow RULE_ID to refer to another chain
      posix-cpu-timers: Cleanup CPU timers before freeing them during exec
      net_sched: cls_route: remove from list when handle is 0

Theodore Ts'o (1):
      ext4: update s_overhead_clusters in the superblock during an on-line resize

Thinh Nguyen (1):
      usb: dwc3: core: Deprecate GCTL.CORESOFTRESET

Thomas Gleixner (1):
      netfilter: xtables: Bring SPDX identifier back

Thomas Zimmermann (1):
      drm/hyperv-drm: Include framebuffer and EDID headers

Tianchen Ding (2):
      sched: Fix the check of nr_running at queue wakelist
      sched: Remove the limitation of WF_ON_CPU on wakelist if wakee cpu is idle

Tianjia Zhang (1):
      KEYS: asymmetric: enforce SM2 signature use pkey algo

Tianyu Li (1):
      mm/mempolicy: fix get_nodes out of bound access

Tiezhu Yang (1):
      MIPS: Loongson64: Fix section mismatch warning

Tim Crawford (1):
      ALSA: hda/realtek: Add quirk for Clevo NV45PZ

Timur Tabi (1):
      drm/nouveau: fix another off-by-one in nvbios_addr

Tom Lendacky (1):
      crypto: ccp - During shutdown, check SEV data pointer before using

Tom Rix (2):
      ASoC: samsung: change gpiod_speaker_power and rx1950_audio from global to static variables
      drm/vc4: change vc4_dma_range_matches from a global to static

Tony Ambardar (1):
      bpf, x64: Add predicate for bpf2bpf with tailcalls support in JIT

Tony Battersby (1):
      scsi: sg: Allow waiting for commands to complete on removed device

Trond Myklebust (2):
      Revert "pNFS: nfs3_set_ds_client should set NFS_CS_NOPING"
      pNFS/flexfiles: Report RDMA connection errors to the server

Tyler Hicks (1):
      net/9p: Initialize the iounit field during fid creation

Uwe Kleine-König (8):
      hwmon: (sht15) Fix wrong assumptions in device remove callback
      pwm: sifive: Simplify offset calculation for PWMCMP registers
      pwm: sifive: Ensure the clk is enabled exactly once per running PWM
      pwm: sifive: Shut down hardware only after pwmchip_remove() completed
      pwm: lpc18xx: Fix period handling
      mtd: st_spi_fsm: Add a clk_disable_unprepare() in .probe()'s error path
      serial: 8250_fsl: Don't report FE, PE and OE twice
      mfd: t7l66xb: Drop platform disable callback

Vadim Pasternak (1):
      platform/mellanox: mlxreg-lc: Fix error flow and extend verbosity

Vaibhav Jain (1):
      of: check previous kernel's ima-kexec-buffer against memory bounds

Viacheslav Mitrofanov (1):
      dmaengine: sf-pdma: Add multithread support for a DMA channel

Vidya Sagar (2):
      PCI: tegra194: Fix Root Port interrupt handling
      PCI: tegra194: Fix link up retry sequence

Vincent Guittot (1):
      sched/fair: fix case with reduced capacity CPU

Vincent Mailhol (10):
      can: pch_can: do not report txerr and rxerr during bus-off
      can: rcar_can: do not report txerr and rxerr during bus-off
      can: sja1000: do not report txerr and rxerr during bus-off
      can: hi311x: do not report txerr and rxerr during bus-off
      can: sun4i_can: do not report txerr and rxerr during bus-off
      can: kvaser_usb_hydra: do not report txerr and rxerr during bus-off
      can: kvaser_usb_leaf: do not report txerr and rxerr during bus-off
      can: usb_8dev: do not report txerr and rxerr during bus-off
      can: error: specify the values of data[5..7] of CAN error frames
      can: pch_can: pch_can_error(): initialize errc before using it

Vitaly Kuznetsov (1):
      KVM: nVMX: Always enable TSC scaling for L2 when it was enabled for L1

Vlad Buslov (1):
      net/mlx5e: Modify slow path rules to go to slow fdb

Vladimir Oltean (7):
      net: mscc: ocelot: delete ocelot_port :: xmit_template
      net: mscc: ocelot: minimize holes in struct ocelot_port
      net: dsa: felix: keep reference on entire tc-taprio config
      net: dsa: felix: drop oversized frames with tc-taprio instead of hanging the port
      net: sched: provide shim definitions for taprio_offload_{get,free}
      net: dsa: felix: build as module when tc-taprio is module
      net: dsa: felix: fix min gate len calculation for tc when its first gate is closed

Vladimir Zapolskiy (3):
      clk: qcom: camcc-sm8250: Fix halt on boot by reducing driver's init level
      clk: qcom: camcc-sdm845: Fix topology around titan_top power domain
      clk: qcom: camcc-sm8250: Fix topology around titan_top power domain

Waiman Long (1):
      sched, cpuset: Fix dl_cpu_busy() panic due to empty cs->cpus_allowed

Weitao Wang (1):
      USB: HCD: Fix URB giveback issue in tasklet function

William Dean (4):
      parisc: Check the return value of ioremap() in lba_driver_probe()
      irqchip/mips-gic: Check the return value of ioremap() in gic_of_init()
      wifi: rtw88: check the return value of alloc_workqueue()
      watchdog: armada_37xx_wdt: check the return value of devm_ioremap() in armada_37xx_wdt_probe()

Wolfram Sang (2):
      selftests: timers: valid-adjtimex: build fix for newer toolchains
      selftests: timers: clocksource-switch: fix passing errors from child

Wyes Karny (1):
      x86: Handle idle=nomwait cmdline properly for x86_idle

Xianting Tian (4):
      RISC-V: kexec: Fixup use of smp_processor_id() in preemptible context
      RISC-V: Fixup get incorrect user mode PC for kernel mode regs
      RISC-V: Fixup schedule out issue in machine_crash_shutdown()
      RISC-V: Add modules to virtual kernel memory layout dump

Xiaoliang Yang (1):
      net: dsa: felix: update base time of time-aware shaper when adjusting PTP time

Xiaomeng Tong (2):
      media: [PATCH] pci: atomisp_cmd: fix three missing checks on list iterator
      virtio-gpu: fix a missing check to avoid NULL dereference

Xie Shaowen (1):
      Input: gscps2 - check return value of ioremap() in gscps2_probe()

Xie Yongji (1):
      fuse: Remove the control interface for virtio-fs

Xinlei Lee (2):
      drm/mediatek: Modify dsi funcs to atomic operations
      drm/mediatek: Add pull-down MIPI operation in mtk_dsi_poweroff function

Xiu Jianfeng (2):
      selinux: fix memleak in security_read_state_kernel()
      selinux: Add boundary check in put_entry()

Xu Qiang (2):
      irqdomain: Report irq number for NOMAP domains
      of/fdt: declared return type does not match actual return type

Xu Wang (1):
      i2c: Fix a potential use after free

YC Hung (1):
      ASoC: SOF: mediatek: fix mt8195 StatvectorSel wrong setting

YN Chen (1):
      mt76: mt7921s: fix firmware download random fail

Yang Shi (1):
      mm: rmap: use the correct parameter name for DEFINE_PAGE_VMA_WALK

Yang Xu (1):
      fs: Add missing umask strip in vfs_tmpfile

Yang Yingliang (6):
      bus: hisi_lpc: fix missing platform_device_put() in hisi_lpc_acpi_probe()
      spi: Fix simplification of devm_spi_register_controller
      spi: tegra20-slink: fix UAF in tegra_slink_remove()
      media: camss: csid: fix wrong size passed to devm_kmalloc_array()
      xtensa: iss: fix handling error cases in iss_net_configure()
      serial: pic32: fix missing clk_disable_unprepare() on error in pic32_uart_startup()

Ye Bin (2):
      ext4: fix warning in ext4_iomap_begin as race between bmap and write
      f2fs: fix null-ptr-deref in f2fs_get_dnode_of_data

Yevgeny Kliteynik (1):
      net/mlx5: DR, Fix SMFS steering info dump format

YiFei Zhu (1):
      selftests/seccomp: Fix compile warning when CC=clang

Ying Hsu (1):
      Bluetooth: Add default wakeup callback for HCI UART driver

Yipeng Zou (1):
      riscv:uprobe fix SR_SPIE set/clear handling

Yishai Hadas (1):
      net/mlx5: Expose mlx5_sriov_blocking_notifier_register / unregister APIs

Yixun Lan (1):
      libbpf, riscv: Use a0 for RC register

Yong Zhi (1):
      ASoC: Intel: sof_rt5682: Perform quirk check first in card late probe

Yonglong Li (1):
      tcp: make retransmitted SKB fit into the send window

Yunfei Dong (2):
      media: mediatek: vcodec: Initialize decoder parameters after getting dec_capability
      media: mediatek: vcodec: Fix non subdev architecture open power fail

Yunhao Tian (1):
      drm/mipi-dbi: align max_chunk to 2 in spi_transfer

Yuntao Wang (1):
      selftests/bpf: Fix test_run logic in fexit_stress.c

Yushan Zhou (1):
      kernfs: fix potential NULL dereference in __kernfs_remove

Yuwen Chen (1):
      erofs: wake up all waiters after z_erofs_lzma_head ready

Zhang Rui (1):
      intel_idle: Add AlderLake support

Zhang Wensheng (1):
      driver core: fix potential deadlock in __driver_attach

Zhang Yi (1):
      jbd2: fix outstanding credits assert in jbd2_journal_commit_transaction()

Zheng Bin (1):
      drm/bridge: it6505: Add missing CRYPTO_HASH dependency

Zhengchao Shao (3):
      crypto: hisilicon/sec - don't sleep when in softirq
      crypto: hisilicon - Kunpeng916 crypto driver don't sleep when in softirq
      crypto: hisilicon/hpre - don't use GFP_KERNEL to alloc mem during softirq

Zhengping Jiang (2):
      Bluetooth: mgmt: Fix refresh cached connection info
      Bluetooth: hci_sync: Fix resuming scan after suspend resume

Zheyu Ma (7):
      ALSA: bcd2000: Fix a UAF bug on the error path of probing
      iio: light: isl29028: Fix the warning in isl29028_remove()
      media: tw686x: Register the irq at the end of probe
      video: fbdev: arkfb: Fix a divide-by-zero bug in ark_set_pixclock()
      video: fbdev: vt8623fb: Check the size of screen before memset_io()
      video: fbdev: arkfb: Check the size of screen before memset_io()
      video: fbdev: s3fb: Check the size of screen before memset_io()

Zhihao Cheng (2):
      jbd2: fix assertion 'jh->b_frozen_data == NULL' failure when journal aborted
      proc: fix a dentry lock race between release_task and lookup

Zhu Yanjun (1):
      RDMA/rxe: Fix error unwind in rxe_create_qp()

haibinzhang (张海斌) (1):
      arm64: fix oops in concurrently setting insn_emulation sysctls

huhai (1):
      ACPI: LPSS: Fix missing check in register_device_clock()

jianchunfu (1):
      rtla/utils: Use calloc and check the potential memory allocation failure

syed sabakareem (1):
      ASoC: amd: yc: Update DMI table entries

xinhui pan (1):
      drm/amdgpu: Remove one duplicated ef removal


^ permalink raw reply	[relevance 1%]

* [PATCH v10 12/27] rust: add `kernel` crate
  @ 2022-09-27 13:14  4% ` Miguel Ojeda
  2022-09-27 13:14  6% ` [PATCH v10 26/27] samples: add first Rust examples Miguel Ojeda
  1 sibling, 0 replies; 77+ results
From: Miguel Ojeda @ 2022-09-27 13:14 UTC (permalink / raw)
  To: Linus Torvalds, Greg Kroah-Hartman
  Cc: rust-for-linux, linux-kernel, linux-fsdevel, patches,
	Jarkko Sakkinen, Miguel Ojeda, Wedson Almeida Filho, Alex Gaynor,
	Geoffrey Thomas, Finn Behrens, Adam Bratschi-Kaye,
	Sven Van Asbroeck, Gary Guo, Boris-Chengbiao Zhou, Boqun Feng,
	Fox Chen, Viktor Garske, Dariusz Sosnowski,
	Léo Lanteri Thauvin, Niklas Mohrin, Milan Landaverde,
	Morgan Bartlett, Maciej Falkowski,
	Nándor István Krácser, David Gow, John Baublitz,
	Björn Roy Baron

From: Wedson Almeida Filho <wedsonaf@google.com>

The `kernel` crate currently includes all the abstractions that wrap
kernel features written in C.

These abstractions call the C side of the kernel via the generated
bindings with the `bindgen` tool. Modules developed in Rust should
never call the bindings themselves.

In the future, as the abstractions grow in number, we may need
to split this crate into several, possibly following a similar
subdivision in subsystems as the kernel itself and/or moving
the code to the actual subsystems.

Co-developed-by: Alex Gaynor <alex.gaynor@gmail.com>
Signed-off-by: Alex Gaynor <alex.gaynor@gmail.com>
Co-developed-by: Geoffrey Thomas <geofft@ldpreload.com>
Signed-off-by: Geoffrey Thomas <geofft@ldpreload.com>
Co-developed-by: Finn Behrens <me@kloenk.de>
Signed-off-by: Finn Behrens <me@kloenk.de>
Co-developed-by: Adam Bratschi-Kaye <ark.email@gmail.com>
Signed-off-by: Adam Bratschi-Kaye <ark.email@gmail.com>
Co-developed-by: Sven Van Asbroeck <thesven73@gmail.com>
Signed-off-by: Sven Van Asbroeck <thesven73@gmail.com>
Co-developed-by: Gary Guo <gary@garyguo.net>
Signed-off-by: Gary Guo <gary@garyguo.net>
Co-developed-by: Boris-Chengbiao Zhou <bobo1239@web.de>
Signed-off-by: Boris-Chengbiao Zhou <bobo1239@web.de>
Co-developed-by: Boqun Feng <boqun.feng@gmail.com>
Signed-off-by: Boqun Feng <boqun.feng@gmail.com>
Co-developed-by: Fox Chen <foxhlchen@gmail.com>
Signed-off-by: Fox Chen <foxhlchen@gmail.com>
Co-developed-by: Viktor Garske <viktor@v-gar.de>
Signed-off-by: Viktor Garske <viktor@v-gar.de>
Co-developed-by: Dariusz Sosnowski <dsosnowski@dsosnowski.pl>
Signed-off-by: Dariusz Sosnowski <dsosnowski@dsosnowski.pl>
Co-developed-by: Léo Lanteri Thauvin <leseulartichaut@gmail.com>
Signed-off-by: Léo Lanteri Thauvin <leseulartichaut@gmail.com>
Co-developed-by: Niklas Mohrin <dev@niklasmohrin.de>
Signed-off-by: Niklas Mohrin <dev@niklasmohrin.de>
Co-developed-by: Milan Landaverde <milan@mdaverde.com>
Signed-off-by: Milan Landaverde <milan@mdaverde.com>
Co-developed-by: Morgan Bartlett <mjmouse9999@gmail.com>
Signed-off-by: Morgan Bartlett <mjmouse9999@gmail.com>
Co-developed-by: Maciej Falkowski <m.falkowski@samsung.com>
Signed-off-by: Maciej Falkowski <m.falkowski@samsung.com>
Co-developed-by: Nándor István Krácser <bonifaido@gmail.com>
Signed-off-by: Nándor István Krácser <bonifaido@gmail.com>
Co-developed-by: David Gow <davidgow@google.com>
Signed-off-by: David Gow <davidgow@google.com>
Co-developed-by: John Baublitz <john.m.baublitz@gmail.com>
Signed-off-by: John Baublitz <john.m.baublitz@gmail.com>
Co-developed-by: Björn Roy Baron <bjorn3_gh@protonmail.com>
Signed-off-by: Björn Roy Baron <bjorn3_gh@protonmail.com>
Signed-off-by: Wedson Almeida Filho <wedsonaf@google.com>
Co-developed-by: Miguel Ojeda <ojeda@kernel.org>
Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
---
 rust/kernel/allocator.rs |  64 +++++++++++++
 rust/kernel/error.rs     |  59 ++++++++++++
 rust/kernel/lib.rs       |  78 +++++++++++++++
 rust/kernel/prelude.rs   |  20 ++++
 rust/kernel/print.rs     | 198 +++++++++++++++++++++++++++++++++++++++
 rust/kernel/str.rs       |  72 ++++++++++++++
 6 files changed, 491 insertions(+)
 create mode 100644 rust/kernel/allocator.rs
 create mode 100644 rust/kernel/error.rs
 create mode 100644 rust/kernel/lib.rs
 create mode 100644 rust/kernel/prelude.rs
 create mode 100644 rust/kernel/print.rs
 create mode 100644 rust/kernel/str.rs

diff --git a/rust/kernel/allocator.rs b/rust/kernel/allocator.rs
new file mode 100644
index 000000000000..397a3dd57a9b
--- /dev/null
+++ b/rust/kernel/allocator.rs
@@ -0,0 +1,64 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Allocator support.
+
+use core::alloc::{GlobalAlloc, Layout};
+use core::ptr;
+
+use crate::bindings;
+
+struct KernelAllocator;
+
+unsafe impl GlobalAlloc for KernelAllocator {
+    unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
+        // `krealloc()` is used instead of `kmalloc()` because the latter is
+        // an inline function and cannot be bound to as a result.
+        unsafe { bindings::krealloc(ptr::null(), layout.size(), bindings::GFP_KERNEL) as *mut u8 }
+    }
+
+    unsafe fn dealloc(&self, ptr: *mut u8, _layout: Layout) {
+        unsafe {
+            bindings::kfree(ptr as *const core::ffi::c_void);
+        }
+    }
+}
+
+#[global_allocator]
+static ALLOCATOR: KernelAllocator = KernelAllocator;
+
+// `rustc` only generates these for some crate types. Even then, we would need
+// to extract the object file that has them from the archive. For the moment,
+// let's generate them ourselves instead.
+//
+// Note that `#[no_mangle]` implies exported too, nowadays.
+#[no_mangle]
+fn __rust_alloc(size: usize, _align: usize) -> *mut u8 {
+    unsafe { bindings::krealloc(core::ptr::null(), size, bindings::GFP_KERNEL) as *mut u8 }
+}
+
+#[no_mangle]
+fn __rust_dealloc(ptr: *mut u8, _size: usize, _align: usize) {
+    unsafe { bindings::kfree(ptr as *const core::ffi::c_void) };
+}
+
+#[no_mangle]
+fn __rust_realloc(ptr: *mut u8, _old_size: usize, _align: usize, new_size: usize) -> *mut u8 {
+    unsafe {
+        bindings::krealloc(
+            ptr as *const core::ffi::c_void,
+            new_size,
+            bindings::GFP_KERNEL,
+        ) as *mut u8
+    }
+}
+
+#[no_mangle]
+fn __rust_alloc_zeroed(size: usize, _align: usize) -> *mut u8 {
+    unsafe {
+        bindings::krealloc(
+            core::ptr::null(),
+            size,
+            bindings::GFP_KERNEL | bindings::__GFP_ZERO,
+        ) as *mut u8
+    }
+}
diff --git a/rust/kernel/error.rs b/rust/kernel/error.rs
new file mode 100644
index 000000000000..466b2a8fe569
--- /dev/null
+++ b/rust/kernel/error.rs
@@ -0,0 +1,59 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Kernel errors.
+//!
+//! C header: [`include/uapi/asm-generic/errno-base.h`](../../../include/uapi/asm-generic/errno-base.h)
+
+use alloc::collections::TryReserveError;
+
+/// Contains the C-compatible error codes.
+pub mod code {
+    /// Out of memory.
+    pub const ENOMEM: super::Error = super::Error(-(crate::bindings::ENOMEM as i32));
+}
+
+/// Generic integer kernel error.
+///
+/// The kernel defines a set of integer generic error codes based on C and
+/// POSIX ones. These codes may have a more specific meaning in some contexts.
+///
+/// # Invariants
+///
+/// The value is a valid `errno` (i.e. `>= -MAX_ERRNO && < 0`).
+#[derive(Clone, Copy, PartialEq, Eq)]
+pub struct Error(core::ffi::c_int);
+
+impl Error {
+    /// Returns the kernel error code.
+    pub fn to_kernel_errno(self) -> core::ffi::c_int {
+        self.0
+    }
+}
+
+impl From<TryReserveError> for Error {
+    fn from(_: TryReserveError) -> Error {
+        code::ENOMEM
+    }
+}
+
+/// A [`Result`] with an [`Error`] error type.
+///
+/// To be used as the return type for functions that may fail.
+///
+/// # Error codes in C and Rust
+///
+/// In C, it is common that functions indicate success or failure through
+/// their return value; modifying or returning extra data through non-`const`
+/// pointer parameters. In particular, in the kernel, functions that may fail
+/// typically return an `int` that represents a generic error code. We model
+/// those as [`Error`].
+///
+/// In Rust, it is idiomatic to model functions that may fail as returning
+/// a [`Result`]. Since in the kernel many functions return an error code,
+/// [`Result`] is a type alias for a [`core::result::Result`] that uses
+/// [`Error`] as its error type.
+///
+/// Note that even if a function does not return anything when it succeeds,
+/// it should still be modeled as returning a `Result` rather than
+/// just an [`Error`].
+pub type Result<T = ()> = core::result::Result<T, Error>;
diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs
new file mode 100644
index 000000000000..abd46261d385
--- /dev/null
+++ b/rust/kernel/lib.rs
@@ -0,0 +1,78 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! The `kernel` crate.
+//!
+//! This crate contains the kernel APIs that have been ported or wrapped for
+//! usage by Rust code in the kernel and is shared by all of them.
+//!
+//! In other words, all the rest of the Rust code in the kernel (e.g. kernel
+//! modules written in Rust) depends on [`core`], [`alloc`] and this crate.
+//!
+//! If you need a kernel C API that is not ported or wrapped yet here, then
+//! do so first instead of bypassing this crate.
+
+#![no_std]
+#![feature(core_ffi_c)]
+
+// Ensure conditional compilation based on the kernel configuration works;
+// otherwise we may silently break things like initcall handling.
+#[cfg(not(CONFIG_RUST))]
+compile_error!("Missing kernel configuration for conditional compilation");
+
+#[cfg(not(test))]
+#[cfg(not(testlib))]
+mod allocator;
+pub mod error;
+pub mod prelude;
+pub mod print;
+pub mod str;
+
+#[doc(hidden)]
+pub use bindings;
+pub use macros;
+
+/// Prefix to appear before log messages printed from within the `kernel` crate.
+const __LOG_PREFIX: &[u8] = b"rust_kernel\0";
+
+/// The top level entrypoint to implementing a kernel module.
+///
+/// For any teardown or cleanup operations, your type may implement [`Drop`].
+pub trait Module: Sized + Sync {
+    /// Called at module initialization time.
+    ///
+    /// Use this method to perform whatever setup or registration your module
+    /// should do.
+    ///
+    /// Equivalent to the `module_init` macro in the C API.
+    fn init(module: &'static ThisModule) -> error::Result<Self>;
+}
+
+/// Equivalent to `THIS_MODULE` in the C API.
+///
+/// C header: `include/linux/export.h`
+pub struct ThisModule(*mut bindings::module);
+
+// SAFETY: `THIS_MODULE` may be used from all threads within a module.
+unsafe impl Sync for ThisModule {}
+
+impl ThisModule {
+    /// Creates a [`ThisModule`] given the `THIS_MODULE` pointer.
+    ///
+    /// # Safety
+    ///
+    /// The pointer must be equal to the right `THIS_MODULE`.
+    pub const unsafe fn from_ptr(ptr: *mut bindings::module) -> ThisModule {
+        ThisModule(ptr)
+    }
+}
+
+#[cfg(not(any(testlib, test)))]
+#[panic_handler]
+fn panic(info: &core::panic::PanicInfo<'_>) -> ! {
+    pr_emerg!("{}\n", info);
+    // SAFETY: FFI call.
+    unsafe { bindings::BUG() };
+    // Bindgen currently does not recognize `__noreturn` so `BUG` returns `()`
+    // instead of `!`. See <https://github.com/rust-lang/rust-bindgen/issues/2094>.
+    loop {}
+}
diff --git a/rust/kernel/prelude.rs b/rust/kernel/prelude.rs
new file mode 100644
index 000000000000..495e22250726
--- /dev/null
+++ b/rust/kernel/prelude.rs
@@ -0,0 +1,20 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! The `kernel` prelude.
+//!
+//! These are the most common items used by Rust code in the kernel,
+//! intended to be imported by all Rust code, for convenience.
+//!
+//! # Examples
+//!
+//! ```
+//! use kernel::prelude::*;
+//! ```
+
+pub use super::{
+    error::{Error, Result},
+    pr_emerg, pr_info, ThisModule,
+};
+pub use alloc::{boxed::Box, vec::Vec};
+pub use core::pin::Pin;
+pub use macros::module;
diff --git a/rust/kernel/print.rs b/rust/kernel/print.rs
new file mode 100644
index 000000000000..55db5a1ba752
--- /dev/null
+++ b/rust/kernel/print.rs
@@ -0,0 +1,198 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Printing facilities.
+//!
+//! C header: [`include/linux/printk.h`](../../../../include/linux/printk.h)
+//!
+//! Reference: <https://www.kernel.org/doc/html/latest/core-api/printk-basics.html>
+
+use core::{
+    ffi::{c_char, c_void},
+    fmt,
+};
+
+use crate::str::RawFormatter;
+
+#[cfg(CONFIG_PRINTK)]
+use crate::bindings;
+
+// Called from `vsprintf` with format specifier `%pA`.
+#[no_mangle]
+unsafe fn rust_fmt_argument(buf: *mut c_char, end: *mut c_char, ptr: *const c_void) -> *mut c_char {
+    use fmt::Write;
+    // SAFETY: The C contract guarantees that `buf` is valid if it's less than `end`.
+    let mut w = unsafe { RawFormatter::from_ptrs(buf.cast(), end.cast()) };
+    let _ = w.write_fmt(unsafe { *(ptr as *const fmt::Arguments<'_>) });
+    w.pos().cast()
+}
+
+/// Format strings.
+///
+/// Public but hidden since it should only be used from public macros.
+#[doc(hidden)]
+pub mod format_strings {
+    use crate::bindings;
+
+    /// The length we copy from the `KERN_*` kernel prefixes.
+    const LENGTH_PREFIX: usize = 2;
+
+    /// The length of the fixed format strings.
+    pub const LENGTH: usize = 10;
+
+    /// Generates a fixed format string for the kernel's [`_printk`].
+    ///
+    /// The format string is always the same for a given level, i.e. for a
+    /// given `prefix`, which are the kernel's `KERN_*` constants.
+    ///
+    /// [`_printk`]: ../../../../include/linux/printk.h
+    const fn generate(is_cont: bool, prefix: &[u8; 3]) -> [u8; LENGTH] {
+        // Ensure the `KERN_*` macros are what we expect.
+        assert!(prefix[0] == b'\x01');
+        if is_cont {
+            assert!(prefix[1] == b'c');
+        } else {
+            assert!(prefix[1] >= b'0' && prefix[1] <= b'7');
+        }
+        assert!(prefix[2] == b'\x00');
+
+        let suffix: &[u8; LENGTH - LENGTH_PREFIX] = if is_cont {
+            b"%pA\0\0\0\0\0"
+        } else {
+            b"%s: %pA\0"
+        };
+
+        [
+            prefix[0], prefix[1], suffix[0], suffix[1], suffix[2], suffix[3], suffix[4], suffix[5],
+            suffix[6], suffix[7],
+        ]
+    }
+
+    // Generate the format strings at compile-time.
+    //
+    // This avoids the compiler generating the contents on the fly in the stack.
+    //
+    // Furthermore, `static` instead of `const` is used to share the strings
+    // for all the kernel.
+    pub static EMERG: [u8; LENGTH] = generate(false, bindings::KERN_EMERG);
+    pub static INFO: [u8; LENGTH] = generate(false, bindings::KERN_INFO);
+}
+
+/// Prints a message via the kernel's [`_printk`].
+///
+/// Public but hidden since it should only be used from public macros.
+///
+/// # Safety
+///
+/// The format string must be one of the ones in [`format_strings`], and
+/// the module name must be null-terminated.
+///
+/// [`_printk`]: ../../../../include/linux/_printk.h
+#[doc(hidden)]
+#[cfg_attr(not(CONFIG_PRINTK), allow(unused_variables))]
+pub unsafe fn call_printk(
+    format_string: &[u8; format_strings::LENGTH],
+    module_name: &[u8],
+    args: fmt::Arguments<'_>,
+) {
+    // `_printk` does not seem to fail in any path.
+    #[cfg(CONFIG_PRINTK)]
+    unsafe {
+        bindings::_printk(
+            format_string.as_ptr() as _,
+            module_name.as_ptr(),
+            &args as *const _ as *const c_void,
+        );
+    }
+}
+
+/// Performs formatting and forwards the string to [`call_printk`].
+///
+/// Public but hidden since it should only be used from public macros.
+#[doc(hidden)]
+#[cfg(not(testlib))]
+#[macro_export]
+#[allow(clippy::crate_in_macro_def)]
+macro_rules! print_macro (
+    // The non-continuation cases (most of them, e.g. `INFO`).
+    ($format_string:path, $($arg:tt)+) => (
+        // SAFETY: This hidden macro should only be called by the documented
+        // printing macros which ensure the format string is one of the fixed
+        // ones. All `__LOG_PREFIX`s are null-terminated as they are generated
+        // by the `module!` proc macro or fixed values defined in a kernel
+        // crate.
+        unsafe {
+            $crate::print::call_printk(
+                &$format_string,
+                crate::__LOG_PREFIX,
+                format_args!($($arg)+),
+            );
+        }
+    );
+);
+
+/// Stub for doctests
+#[cfg(testlib)]
+#[macro_export]
+macro_rules! print_macro (
+    ($format_string:path, $e:expr, $($arg:tt)+) => (
+        ()
+    );
+);
+
+// We could use a macro to generate these macros. However, doing so ends
+// up being a bit ugly: it requires the dollar token trick to escape `$` as
+// well as playing with the `doc` attribute. Furthermore, they cannot be easily
+// imported in the prelude due to [1]. So, for the moment, we just write them
+// manually, like in the C side; while keeping most of the logic in another
+// macro, i.e. [`print_macro`].
+//
+// [1]: https://github.com/rust-lang/rust/issues/52234
+
+/// Prints an emergency-level message (level 0).
+///
+/// Use this level if the system is unusable.
+///
+/// Equivalent to the kernel's [`pr_emerg`] macro.
+///
+/// Mimics the interface of [`std::print!`]. See [`core::fmt`] and
+/// `alloc::format!` for information about the formatting syntax.
+///
+/// [`pr_emerg`]: https://www.kernel.org/doc/html/latest/core-api/printk-basics.html#c.pr_emerg
+/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html
+///
+/// # Examples
+///
+/// ```
+/// pr_emerg!("hello {}\n", "there");
+/// ```
+#[macro_export]
+macro_rules! pr_emerg (
+    ($($arg:tt)*) => (
+        $crate::print_macro!($crate::print::format_strings::EMERG, $($arg)*)
+    )
+);
+
+/// Prints an info-level message (level 6).
+///
+/// Use this level for informational messages.
+///
+/// Equivalent to the kernel's [`pr_info`] macro.
+///
+/// Mimics the interface of [`std::print!`]. See [`core::fmt`] and
+/// `alloc::format!` for information about the formatting syntax.
+///
+/// [`pr_info`]: https://www.kernel.org/doc/html/latest/core-api/printk-basics.html#c.pr_info
+/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html
+///
+/// # Examples
+///
+/// ```
+/// pr_info!("hello {}\n", "there");
+/// ```
+#[macro_export]
+#[doc(alias = "print")]
+macro_rules! pr_info (
+    ($($arg:tt)*) => (
+        $crate::print_macro!($crate::print::format_strings::INFO, $($arg)*)
+    )
+);
diff --git a/rust/kernel/str.rs b/rust/kernel/str.rs
new file mode 100644
index 000000000000..e45ff220ae50
--- /dev/null
+++ b/rust/kernel/str.rs
@@ -0,0 +1,72 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! String representations.
+
+use core::fmt;
+
+/// Allows formatting of [`fmt::Arguments`] into a raw buffer.
+///
+/// It does not fail if callers write past the end of the buffer so that they can calculate the
+/// size required to fit everything.
+///
+/// # Invariants
+///
+/// The memory region between `pos` (inclusive) and `end` (exclusive) is valid for writes if `pos`
+/// is less than `end`.
+pub(crate) struct RawFormatter {
+    // Use `usize` to use `saturating_*` functions.
+    #[allow(dead_code)]
+    beg: usize,
+    pos: usize,
+    end: usize,
+}
+
+impl RawFormatter {
+    /// Creates a new instance of [`RawFormatter`] with the given buffer pointers.
+    ///
+    /// # Safety
+    ///
+    /// If `pos` is less than `end`, then the region between `pos` (inclusive) and `end`
+    /// (exclusive) must be valid for writes for the lifetime of the returned [`RawFormatter`].
+    pub(crate) unsafe fn from_ptrs(pos: *mut u8, end: *mut u8) -> Self {
+        // INVARIANT: The safety requierments guarantee the type invariants.
+        Self {
+            beg: pos as _,
+            pos: pos as _,
+            end: end as _,
+        }
+    }
+
+    /// Returns the current insert position.
+    ///
+    /// N.B. It may point to invalid memory.
+    pub(crate) fn pos(&self) -> *mut u8 {
+        self.pos as _
+    }
+}
+
+impl fmt::Write for RawFormatter {
+    fn write_str(&mut self, s: &str) -> fmt::Result {
+        // `pos` value after writing `len` bytes. This does not have to be bounded by `end`, but we
+        // don't want it to wrap around to 0.
+        let pos_new = self.pos.saturating_add(s.len());
+
+        // Amount that we can copy. `saturating_sub` ensures we get 0 if `pos` goes past `end`.
+        let len_to_copy = core::cmp::min(pos_new, self.end).saturating_sub(self.pos);
+
+        if len_to_copy > 0 {
+            // SAFETY: If `len_to_copy` is non-zero, then we know `pos` has not gone past `end`
+            // yet, so it is valid for write per the type invariants.
+            unsafe {
+                core::ptr::copy_nonoverlapping(
+                    s.as_bytes().as_ptr(),
+                    self.pos as *mut u8,
+                    len_to_copy,
+                )
+            };
+        }
+
+        self.pos = pos_new;
+        Ok(())
+    }
+}
-- 
2.37.3


^ permalink raw reply related	[relevance 4%]

* [PATCH v10 26/27] samples: add first Rust examples
    2022-09-27 13:14  4% ` [PATCH v10 12/27] rust: add `kernel` crate Miguel Ojeda
@ 2022-09-27 13:14  6% ` Miguel Ojeda
  2022-09-27 15:25  0%   ` Greg Kroah-Hartman
  2022-09-28 14:23  0%   ` Wei Liu
  1 sibling, 2 replies; 77+ results
From: Miguel Ojeda @ 2022-09-27 13:14 UTC (permalink / raw)
  To: Linus Torvalds, Greg Kroah-Hartman
  Cc: rust-for-linux, linux-kernel, linux-fsdevel, patches,
	Jarkko Sakkinen, Miguel Ojeda, Kees Cook, Alex Gaynor,
	Finn Behrens, Wedson Almeida Filho, Milan Landaverde, Boqun Feng,
	Gary Guo, Björn Roy Baron

The beginning of a set of Rust modules that showcase how Rust
modules look like and how to use the abstracted kernel features.

It also includes an example of a Rust host program with
several modules.

These samples also double as tests in the CI.

Reviewed-by: Kees Cook <keescook@chromium.org>
Co-developed-by: Alex Gaynor <alex.gaynor@gmail.com>
Signed-off-by: Alex Gaynor <alex.gaynor@gmail.com>
Co-developed-by: Finn Behrens <me@kloenk.de>
Signed-off-by: Finn Behrens <me@kloenk.de>
Co-developed-by: Wedson Almeida Filho <wedsonaf@google.com>
Signed-off-by: Wedson Almeida Filho <wedsonaf@google.com>
Co-developed-by: Milan Landaverde <milan@mdaverde.com>
Signed-off-by: Milan Landaverde <milan@mdaverde.com>
Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
---
 samples/Kconfig                   |  2 ++
 samples/Makefile                  |  1 +
 samples/rust/Kconfig              | 30 ++++++++++++++++++++++++
 samples/rust/Makefile             |  5 ++++
 samples/rust/hostprogs/.gitignore |  3 +++
 samples/rust/hostprogs/Makefile   |  5 ++++
 samples/rust/hostprogs/a.rs       |  7 ++++++
 samples/rust/hostprogs/b.rs       |  5 ++++
 samples/rust/hostprogs/single.rs  | 12 ++++++++++
 samples/rust/rust_minimal.rs      | 38 +++++++++++++++++++++++++++++++
 10 files changed, 108 insertions(+)
 create mode 100644 samples/rust/Kconfig
 create mode 100644 samples/rust/Makefile
 create mode 100644 samples/rust/hostprogs/.gitignore
 create mode 100644 samples/rust/hostprogs/Makefile
 create mode 100644 samples/rust/hostprogs/a.rs
 create mode 100644 samples/rust/hostprogs/b.rs
 create mode 100644 samples/rust/hostprogs/single.rs
 create mode 100644 samples/rust/rust_minimal.rs

diff --git a/samples/Kconfig b/samples/Kconfig
index 470ee3baf2e1..0d81c00289ee 100644
--- a/samples/Kconfig
+++ b/samples/Kconfig
@@ -263,6 +263,8 @@ config SAMPLE_CORESIGHT_SYSCFG
 	  This demonstrates how a user may create their own CoreSight
 	  configurations and easily load them into the system at runtime.
 
+source "samples/rust/Kconfig"
+
 endif # SAMPLES
 
 config HAVE_SAMPLE_FTRACE_DIRECT
diff --git a/samples/Makefile b/samples/Makefile
index 701e912ab5af..9832ef3f8fcb 100644
--- a/samples/Makefile
+++ b/samples/Makefile
@@ -35,3 +35,4 @@ subdir-$(CONFIG_SAMPLE_WATCH_QUEUE)	+= watch_queue
 obj-$(CONFIG_DEBUG_KMEMLEAK_TEST)	+= kmemleak/
 obj-$(CONFIG_SAMPLE_CORESIGHT_SYSCFG)	+= coresight/
 obj-$(CONFIG_SAMPLE_FPROBE)		+= fprobe/
+obj-$(CONFIG_SAMPLES_RUST)		+= rust/
diff --git a/samples/rust/Kconfig b/samples/rust/Kconfig
new file mode 100644
index 000000000000..841e0906e943
--- /dev/null
+++ b/samples/rust/Kconfig
@@ -0,0 +1,30 @@
+# SPDX-License-Identifier: GPL-2.0
+
+menuconfig SAMPLES_RUST
+	bool "Rust samples"
+	depends on RUST
+	help
+	  You can build sample Rust kernel code here.
+
+	  If unsure, say N.
+
+if SAMPLES_RUST
+
+config SAMPLE_RUST_MINIMAL
+	tristate "Minimal"
+	help
+	  This option builds the Rust minimal module sample.
+
+	  To compile this as a module, choose M here:
+	  the module will be called rust_minimal.
+
+	  If unsure, say N.
+
+config SAMPLE_RUST_HOSTPROGS
+	bool "Host programs"
+	help
+	  This option builds the Rust host program samples.
+
+	  If unsure, say N.
+
+endif # SAMPLES_RUST
diff --git a/samples/rust/Makefile b/samples/rust/Makefile
new file mode 100644
index 000000000000..1daba5f8658a
--- /dev/null
+++ b/samples/rust/Makefile
@@ -0,0 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0
+
+obj-$(CONFIG_SAMPLE_RUST_MINIMAL)		+= rust_minimal.o
+
+subdir-$(CONFIG_SAMPLE_RUST_HOSTPROGS)		+= hostprogs
diff --git a/samples/rust/hostprogs/.gitignore b/samples/rust/hostprogs/.gitignore
new file mode 100644
index 000000000000..a6c173da5048
--- /dev/null
+++ b/samples/rust/hostprogs/.gitignore
@@ -0,0 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0
+
+single
diff --git a/samples/rust/hostprogs/Makefile b/samples/rust/hostprogs/Makefile
new file mode 100644
index 000000000000..8ddcbd7416db
--- /dev/null
+++ b/samples/rust/hostprogs/Makefile
@@ -0,0 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0
+
+hostprogs-always-y := single
+
+single-rust := y
diff --git a/samples/rust/hostprogs/a.rs b/samples/rust/hostprogs/a.rs
new file mode 100644
index 000000000000..f7a4a3d0f4e0
--- /dev/null
+++ b/samples/rust/hostprogs/a.rs
@@ -0,0 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Rust single host program sample: module `a`.
+
+pub(crate) fn f(x: i32) {
+    println!("The number is {}.", x);
+}
diff --git a/samples/rust/hostprogs/b.rs b/samples/rust/hostprogs/b.rs
new file mode 100644
index 000000000000..c1675890648f
--- /dev/null
+++ b/samples/rust/hostprogs/b.rs
@@ -0,0 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Rust single host program sample: module `b`.
+
+pub(crate) const CONSTANT: i32 = 42;
diff --git a/samples/rust/hostprogs/single.rs b/samples/rust/hostprogs/single.rs
new file mode 100644
index 000000000000..8c48a119339a
--- /dev/null
+++ b/samples/rust/hostprogs/single.rs
@@ -0,0 +1,12 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Rust single host program sample.
+
+mod a;
+mod b;
+
+fn main() {
+    println!("Hello world!");
+
+    a::f(b::CONSTANT);
+}
diff --git a/samples/rust/rust_minimal.rs b/samples/rust/rust_minimal.rs
new file mode 100644
index 000000000000..54ad17685742
--- /dev/null
+++ b/samples/rust/rust_minimal.rs
@@ -0,0 +1,38 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Rust minimal sample.
+
+use kernel::prelude::*;
+
+module! {
+    type: RustMinimal,
+    name: b"rust_minimal",
+    author: b"Rust for Linux Contributors",
+    description: b"Rust minimal sample",
+    license: b"GPL",
+}
+
+struct RustMinimal {
+    numbers: Vec<i32>,
+}
+
+impl kernel::Module for RustMinimal {
+    fn init(_module: &'static ThisModule) -> Result<Self> {
+        pr_info!("Rust minimal sample (init)\n");
+        pr_info!("Am I built-in? {}\n", !cfg!(MODULE));
+
+        let mut numbers = Vec::new();
+        numbers.try_push(72)?;
+        numbers.try_push(108)?;
+        numbers.try_push(200)?;
+
+        Ok(RustMinimal { numbers })
+    }
+}
+
+impl Drop for RustMinimal {
+    fn drop(&mut self) {
+        pr_info!("My numbers are {:?}\n", self.numbers);
+        pr_info!("Rust minimal sample (exit)\n");
+    }
+}
-- 
2.37.3


^ permalink raw reply related	[relevance 6%]

* Re: [PATCH v10 26/27] samples: add first Rust examples
  2022-09-27 13:14  6% ` [PATCH v10 26/27] samples: add first Rust examples Miguel Ojeda
@ 2022-09-27 15:25  0%   ` Greg Kroah-Hartman
  2022-09-28 14:23  0%   ` Wei Liu
  1 sibling, 0 replies; 77+ results
From: Greg Kroah-Hartman @ 2022-09-27 15:25 UTC (permalink / raw)
  To: Miguel Ojeda
  Cc: Linus Torvalds, rust-for-linux, linux-kernel, linux-fsdevel,
	patches, Jarkko Sakkinen, Kees Cook, Alex Gaynor, Finn Behrens,
	Wedson Almeida Filho, Milan Landaverde, Boqun Feng, Gary Guo,
	Björn Roy Baron

On Tue, Sep 27, 2022 at 03:14:57PM +0200, Miguel Ojeda wrote:
> The beginning of a set of Rust modules that showcase how Rust
> modules look like and how to use the abstracted kernel features.
> 
> It also includes an example of a Rust host program with
> several modules.
> 
> These samples also double as tests in the CI.
> 
> Reviewed-by: Kees Cook <keescook@chromium.org>
> Co-developed-by: Alex Gaynor <alex.gaynor@gmail.com>
> Signed-off-by: Alex Gaynor <alex.gaynor@gmail.com>
> Co-developed-by: Finn Behrens <me@kloenk.de>
> Signed-off-by: Finn Behrens <me@kloenk.de>
> Co-developed-by: Wedson Almeida Filho <wedsonaf@google.com>
> Signed-off-by: Wedson Almeida Filho <wedsonaf@google.com>
> Co-developed-by: Milan Landaverde <milan@mdaverde.com>
> Signed-off-by: Milan Landaverde <milan@mdaverde.com>
> Signed-off-by: Miguel Ojeda <ojeda@kernel.org>

Reviewed-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

^ permalink raw reply	[relevance 0%]

* Re: [PATCH v10 26/27] samples: add first Rust examples
  2022-09-27 13:14  6% ` [PATCH v10 26/27] samples: add first Rust examples Miguel Ojeda
  2022-09-27 15:25  0%   ` Greg Kroah-Hartman
@ 2022-09-28 14:23  0%   ` Wei Liu
  1 sibling, 0 replies; 77+ results
From: Wei Liu @ 2022-09-28 14:23 UTC (permalink / raw)
  To: Miguel Ojeda
  Cc: Linus Torvalds, Greg Kroah-Hartman, rust-for-linux, linux-kernel,
	linux-fsdevel, patches, Jarkko Sakkinen, Kees Cook, Alex Gaynor,
	Finn Behrens, Wedson Almeida Filho, Milan Landaverde, Boqun Feng,
	Gary Guo, Björn Roy Baron, Wei Liu

On Tue, Sep 27, 2022 at 03:14:57PM +0200, Miguel Ojeda wrote:
> The beginning of a set of Rust modules that showcase how Rust
> modules look like and how to use the abstracted kernel features.
> 
> It also includes an example of a Rust host program with
> several modules.
> 
> These samples also double as tests in the CI.
> 
> Reviewed-by: Kees Cook <keescook@chromium.org>
> Co-developed-by: Alex Gaynor <alex.gaynor@gmail.com>
> Signed-off-by: Alex Gaynor <alex.gaynor@gmail.com>
> Co-developed-by: Finn Behrens <me@kloenk.de>
> Signed-off-by: Finn Behrens <me@kloenk.de>
> Co-developed-by: Wedson Almeida Filho <wedsonaf@google.com>
> Signed-off-by: Wedson Almeida Filho <wedsonaf@google.com>
> Co-developed-by: Milan Landaverde <milan@mdaverde.com>
> Signed-off-by: Milan Landaverde <milan@mdaverde.com>
> Signed-off-by: Miguel Ojeda <ojeda@kernel.org>

Reviewed-by: Wei Liu <wei.liu@kernel.org>

^ permalink raw reply	[relevance 0%]

* [GIT PULL] Rust introduction for v6.1-rc1
@ 2022-10-01 15:58  3% Kees Cook
  0 siblings, 0 replies; 77+ results
From: Kees Cook @ 2022-10-01 15:58 UTC (permalink / raw)
  To: Linus Torvalds
  Cc: linux-kernel, Adam Bratschi-Kaye, Alex Gaynor, Antonio Terceiro,
	Björn Roy Baron, Boqun Feng, Boris-Chengbiao Zhou,
	Daniel Xu, Dariusz Sosnowski, David Gow, Douglas Su,
	Finn Behrens, Fox Chen, Gary Guo, Geert Stappers,
	Geoffrey Thomas, Greg Kroah-Hartman, Jiapeng Chong, Joe Perches,
	John Baublitz, Julian Merkle, Kees Cook,
	Léo Lanteri Thauvin, Maciej Falkowski,
	Martin Rodriguez Reboredo, Matthew Bakhtiari, Matthew Wilcox,
	Michael Ellerman, Miguel Cano, Miguel Ojeda, Milan Landaverde,
	Morgan Bartlett, Nándor István Krácser,
	Nick Desaulniers, Niklas Mohrin, Petr Mladek,
	Sumera Priyadarsini, Sven Van Asbroeck, Tiago Lam, Viktor Garske,
	Wedson Almeida Filho, Wei Liu, Wu XiangCheng, Yuki Okushi

Hi Linus,

Please pull the initial Rust support for v6.1-rc1. The tree has a recent
base, but has fundamentally been in linux-next for a year and a half[1].
It's been updated based on feedback from the Kernel Maintainer's Summit,
and to gain recent Reviewed-by: tags. Miguel is the primary maintainer,
with me helping where needed/wanted. Our plan is for the tree to switch to
the standard non-rebasing practice once this initial infrastructure series
lands. The contents are the absolute minimum to get Rust code building
in the kernel, with many more interfaces[2] (and drivers[3]) on the way.

Expected conflicts are minimal:
- docs-next: https://lore.kernel.org/lkml/87czbegets.fsf@meer.lwn.net/

Thanks!

-Kees

[1] https://lwn.net/Articles/849849/
[2] https://github.com/Rust-for-Linux/linux/commits/rust
[3] NVMe:   https://github.com/metaspace/rust-linux/commit/d88c3744d6cbdf11767e08bad56cbfb67c4c96d0
    9p:     https://github.com/wedsonaf/linux/commit/9367032607f7670de0ba1537cf09ab0f4365a338
    M1 GPU: https://github.com/AsahiLinux/linux/commits/gpu/rust-wip

The following changes since commit f76349cf41451c5c42a99f18a9163377e4b364ff:

  Linux 6.0-rc7 (2022-09-25 14:01:02 -0700)

are available in the Git repository at:

  https://github.com/Rust-for-Linux/linux.git tags/rust-v6.1-rc1

for you to fetch changes up to 615131b8e9bcd88e2d3ef78a4954ff4abfbb1fb7:

  MAINTAINERS: Rust (2022-09-28 09:05:20 +0200)

----------------------------------------------------------------
Rust introduction for v6.1-rc1

The initial support of Rust-for-Linux comes in roughly 4 areas:

- Kernel internals (kallsyms expansion for Rust symbols, %pA format)

- Kbuild infrastructure (Rust build rules and support scripts)

- Rust crates and bindings for initial minimum viable build

- Rust kernel documentation and samples

Rust support has been in linux-next for a year and a half now, and the
short log doesn't do justice to the number of people who have contributed
both to the Linux kernel side but also to the upstream Rust side to
support the kernel's needs. Thanks to these 173 people, and many more,
who have been involved in all kinds of ways:

Miguel Ojeda, Wedson Almeida Filho, Alex Gaynor, Boqun Feng, Gary Guo,
Björn Roy Baron, Andreas Hindborg, Adam Bratschi-Kaye, Benno Lossin,
Maciej Falkowski, Finn Behrens, Sven Van Asbroeck, Asahi Lina, FUJITA
Tomonori, John Baublitz, Wei Liu, Geoffrey Thomas, Philip Herron,
Arthur Cohen, David Faust, Antoni Boucher, Philip Li, Yujie Liu,
Jonathan Corbet, Greg Kroah-Hartman, Paul E. McKenney, Josh Triplett,
Kent Overstreet, David Gow, Alice Ryhl, Robin Randhawa, Kees Cook,
Nick Desaulniers, Matthew Wilcox, Linus Walleij, Joe Perches, Michael
Ellerman, Petr Mladek, Masahiro Yamada, Arnaldo Carvalho de Melo,
Andrii Nakryiko, Konstantin Shelekhin, Rasmus Villemoes, Konstantin
Ryabitsev, Stephen Rothwell, Andy Shevchenko, Sergey Senozhatsky, John
Paul Adrian Glaubitz, David Laight, Nathan Chancellor, Jonathan
Cameron, Daniel Latypov, Shuah Khan, Brendan Higgins, Julia Lawall,
Laurent Pinchart, Geert Uytterhoeven, Akira Yokosawa, Pavel Machek,
David S. Miller, John Hawley, James Bottomley, Arnd Bergmann,
Christian Brauner, Dan Robertson, Nicholas Piggin, Zhouyi Zhou, Elena
Zannoni, Jose E. Marchesi, Leon Romanovsky, Will Deacon, Richard
Weinberger, Randy Dunlap, Paolo Bonzini, Roland Dreier, Mark Brown,
Sasha Levin, Ted Ts'o, Steven Rostedt, Jarkko Sakkinen, Michal
Kubecek, Marco Elver, Al Viro, Keith Busch, Johannes Berg, Jan Kara,
David Sterba, Connor Kuehl, Andy Lutomirski, Andrew Lunn, Alexandre
Belloni, Peter Zijlstra, Russell King, Eric W. Biederman, Willy
Tarreau, Christoph Hellwig, Emilio Cobos Álvarez, Christian Poveda,
Mark Rousskov, John Ericson, TennyZhuang, Xuanwo, Daniel Paoliello,
Manish Goregaokar, comex, Josh Stone, Stephan Sokolow, Philipp Krones,
Guillaume Gomez, Joshua Nelson, Mats Larsen, Marc Poulhiès, Samantha
Miller, Esteban Blanc, Martin Schmidt, Martin Rodriguez Reboredo,
Daniel Xu, Viresh Kumar, Bartosz Golaszewski, Vegard Nossum, Milan
Landaverde, Dariusz Sosnowski, Yuki Okushi, Matthew Bakhtiari, Wu
XiangCheng, Tiago Lam, Boris-Chengbiao Zhou, Sumera Priyadarsini,
Viktor Garske, Niklas Mohrin, Nándor István Krácser, Morgan Bartlett,
Miguel Cano, Léo Lanteri Thauvin, Julian Merkle, Andreas Reindl,
Jiapeng Chong, Fox Chen, Douglas Su, Antonio Terceiro, SeongJae Park,
Sergio González Collado, Ngo Iok Ui (Wu Yu Wei), Joshua Abraham,
Milan, Daniel Kolsoi, ahomescu, Manas, Luis Gerhorst, Li Hongyu,
Philipp Gesang, Russell Currey, Jalil David Salamé Messina, Jon Olson,
Raghvender, Angelos, Kaviraj Kanagaraj, Paul Römer, Sladyn Nunes,
Mauro Baladés, Hsiang-Cheng Yang, Abhik Jain, Hongyu Li, Sean Nash,
Yuheng Su, Peng Hao, Anhad Singh, Roel Kluin, Sara Saa, Geert
Stappers, Garrett LeSage, IFo Hancroft, and Linus Torvalds.

----------------------------------------------------------------
Boqun Feng (2):
      kallsyms: use `ARRAY_SIZE` instead of hardcoded size
      kallsyms: avoid hardcoding buffer size

Daniel Xu (1):
      scripts: add `is_rust_module.sh`

Gary Guo (1):
      vsprintf: add new `%pA` format specifier

Miguel Ojeda (22):
      kallsyms: add static relationship between `KSYM_NAME_LEN{,_BUFFER}`
      kallsyms: support "big" kernel symbols
      kallsyms: increase maximum kernel symbol length to 512
      rust: add C helpers
      rust: import upstream `alloc` crate
      rust: adapt `alloc` crate to the kernel
      rust: add `compiler_builtins` crate
      rust: add `macros` crate
      rust: add `bindings` crate
      rust: export generated symbols
      scripts: checkpatch: diagnose uses of `%pA` in the C side as errors
      scripts: checkpatch: enable language-independent checks for Rust
      scripts: decode_stacktrace: demangle Rust symbols
      scripts: add `generate_rust_analyzer.py`
      scripts: add `generate_rust_target.rs`
      scripts: add `rust_is_available.sh`
      rust: add `.rustfmt.toml`
      Kbuild: add Rust support
      docs: add Rust documentation
      x86: enable initial Rust support
      samples: add first Rust examples
      MAINTAINERS: Rust

Wedson Almeida Filho (1):
      rust: add `kernel` crate

 .gitignore                                   |    6 +
 .rustfmt.toml                                |   12 +
 Documentation/core-api/printk-formats.rst    |   10 +
 Documentation/doc-guide/kernel-doc.rst       |    3 +
 Documentation/index.rst                      |    1 +
 Documentation/kbuild/kbuild.rst              |   17 +
 Documentation/kbuild/makefiles.rst           |   50 +-
 Documentation/process/changes.rst            |   41 +
 Documentation/rust/arch-support.rst          |   19 +
 Documentation/rust/coding-guidelines.rst     |  216 ++
 Documentation/rust/general-information.rst   |   79 +
 Documentation/rust/index.rst                 |   22 +
 Documentation/rust/quick-start.rst           |  232 ++
 MAINTAINERS                                  |   18 +
 Makefile                                     |  172 +-
 arch/Kconfig                                 |    6 +
 arch/x86/Kconfig                             |    1 +
 arch/x86/Makefile                            |   10 +
 include/linux/compiler_types.h               |    6 +-
 include/linux/kallsyms.h                     |    2 +-
 init/Kconfig                                 |   46 +-
 kernel/configs/rust.config                   |    1 +
 kernel/kallsyms.c                            |   26 +-
 kernel/livepatch/core.c                      |    4 +-
 lib/Kconfig.debug                            |   34 +
 lib/vsprintf.c                               |   13 +
 rust/.gitignore                              |    8 +
 rust/Makefile                                |  381 ++++
 rust/alloc/README.md                         |   33 +
 rust/alloc/alloc.rs                          |  440 ++++
 rust/alloc/borrow.rs                         |  498 ++++
 rust/alloc/boxed.rs                          | 2028 +++++++++++++++++
 rust/alloc/collections/mod.rs                |  156 ++
 rust/alloc/lib.rs                            |  244 ++
 rust/alloc/raw_vec.rs                        |  527 +++++
 rust/alloc/slice.rs                          | 1204 ++++++++++
 rust/alloc/vec/drain.rs                      |  186 ++
 rust/alloc/vec/drain_filter.rs               |  145 ++
 rust/alloc/vec/into_iter.rs                  |  366 +++
 rust/alloc/vec/is_zero.rs                    |  120 +
 rust/alloc/vec/mod.rs                        | 3140 ++++++++++++++++++++++++++
 rust/alloc/vec/partial_eq.rs                 |   49 +
 rust/bindgen_parameters                      |   21 +
 rust/bindings/bindings_helper.h              |   13 +
 rust/bindings/lib.rs                         |   53 +
 rust/compiler_builtins.rs                    |   63 +
 rust/exports.c                               |   21 +
 rust/helpers.c                               |   51 +
 rust/kernel/allocator.rs                     |   64 +
 rust/kernel/error.rs                         |   59 +
 rust/kernel/lib.rs                           |   78 +
 rust/kernel/prelude.rs                       |   20 +
 rust/kernel/print.rs                         |  198 ++
 rust/kernel/str.rs                           |   72 +
 rust/macros/helpers.rs                       |   51 +
 rust/macros/lib.rs                           |   72 +
 rust/macros/module.rs                        |  282 +++
 samples/Kconfig                              |    2 +
 samples/Makefile                             |    1 +
 samples/rust/Kconfig                         |   30 +
 samples/rust/Makefile                        |    5 +
 samples/rust/hostprogs/.gitignore            |    3 +
 samples/rust/hostprogs/Makefile              |    5 +
 samples/rust/hostprogs/a.rs                  |    7 +
 samples/rust/hostprogs/b.rs                  |    5 +
 samples/rust/hostprogs/single.rs             |   12 +
 samples/rust/rust_minimal.rs                 |   38 +
 scripts/.gitignore                           |    1 +
 scripts/Kconfig.include                      |    6 +-
 scripts/Makefile                             |    3 +
 scripts/Makefile.build                       |   60 +
 scripts/Makefile.debug                       |    8 +
 scripts/Makefile.host                        |   34 +-
 scripts/Makefile.lib                         |   12 +
 scripts/Makefile.modfinal                    |    8 +-
 scripts/cc-version.sh                        |   12 +-
 scripts/checkpatch.pl                        |   12 +-
 scripts/decode_stacktrace.sh                 |   14 +
 scripts/generate_rust_analyzer.py            |  135 ++
 scripts/generate_rust_target.rs              |  182 ++
 scripts/is_rust_module.sh                    |   16 +
 scripts/kallsyms.c                           |   53 +-
 scripts/kconfig/confdata.c                   |   75 +
 scripts/min-tool-version.sh                  |    6 +
 scripts/rust_is_available.sh                 |  160 ++
 scripts/rust_is_available_bindgen_libclang.h |    2 +
 tools/include/linux/kallsyms.h               |    2 +-
 tools/lib/perf/include/perf/event.h          |    2 +-
 tools/lib/symbol/kallsyms.h                  |    2 +-
 89 files changed, 12552 insertions(+), 51 deletions(-)
 create mode 100644 .rustfmt.toml
 create mode 100644 Documentation/rust/arch-support.rst
 create mode 100644 Documentation/rust/coding-guidelines.rst
 create mode 100644 Documentation/rust/general-information.rst
 create mode 100644 Documentation/rust/index.rst
 create mode 100644 Documentation/rust/quick-start.rst
 create mode 100644 kernel/configs/rust.config
 create mode 100644 rust/.gitignore
 create mode 100644 rust/Makefile
 create mode 100644 rust/alloc/README.md
 create mode 100644 rust/alloc/alloc.rs
 create mode 100644 rust/alloc/borrow.rs
 create mode 100644 rust/alloc/boxed.rs
 create mode 100644 rust/alloc/collections/mod.rs
 create mode 100644 rust/alloc/lib.rs
 create mode 100644 rust/alloc/raw_vec.rs
 create mode 100644 rust/alloc/slice.rs
 create mode 100644 rust/alloc/vec/drain.rs
 create mode 100644 rust/alloc/vec/drain_filter.rs
 create mode 100644 rust/alloc/vec/into_iter.rs
 create mode 100644 rust/alloc/vec/is_zero.rs
 create mode 100644 rust/alloc/vec/mod.rs
 create mode 100644 rust/alloc/vec/partial_eq.rs
 create mode 100644 rust/bindgen_parameters
 create mode 100644 rust/bindings/bindings_helper.h
 create mode 100644 rust/bindings/lib.rs
 create mode 100644 rust/compiler_builtins.rs
 create mode 100644 rust/exports.c
 create mode 100644 rust/helpers.c
 create mode 100644 rust/kernel/allocator.rs
 create mode 100644 rust/kernel/error.rs
 create mode 100644 rust/kernel/lib.rs
 create mode 100644 rust/kernel/prelude.rs
 create mode 100644 rust/kernel/print.rs
 create mode 100644 rust/kernel/str.rs
 create mode 100644 rust/macros/helpers.rs
 create mode 100644 rust/macros/lib.rs
 create mode 100644 rust/macros/module.rs
 create mode 100644 samples/rust/Kconfig
 create mode 100644 samples/rust/Makefile
 create mode 100644 samples/rust/hostprogs/.gitignore
 create mode 100644 samples/rust/hostprogs/Makefile
 create mode 100644 samples/rust/hostprogs/a.rs
 create mode 100644 samples/rust/hostprogs/b.rs
 create mode 100644 samples/rust/hostprogs/single.rs
 create mode 100644 samples/rust/rust_minimal.rs
 create mode 100755 scripts/generate_rust_analyzer.py
 create mode 100644 scripts/generate_rust_target.rs
 create mode 100755 scripts/is_rust_module.sh
 create mode 100755 scripts/rust_is_available.sh
 create mode 100644 scripts/rust_is_available_bindgen_libclang.h

-- 
Kees Cook

^ permalink raw reply	[relevance 3%]

* [linux-linus test] 173411: tolerable FAIL - PUSHED
@ 2022-10-04  8:06  3% osstest service owner
  0 siblings, 0 replies; 77+ results
From: osstest service owner @ 2022-10-04  8:06 UTC (permalink / raw)
  To: xen-devel

flight 173411 linux-linus real [real]
http://logs.test-lab.xenproject.org/osstest/logs/173411/

Failures :-/ but no regressions.

Tests which did not succeed, but are not blocking:
 test-amd64-amd64-xl-qemut-win7-amd64 19 guest-stop            fail like 173405
 test-amd64-amd64-xl-qemuu-ws16-amd64 19 guest-stop            fail like 173405
 test-amd64-amd64-xl-qemuu-win7-amd64 19 guest-stop            fail like 173405
 test-amd64-amd64-qemuu-nested-amd 20 debian-hvm-install/l1/l2 fail like 173405
 test-armhf-armhf-libvirt-qcow2 15 saverestore-support-check   fail like 173405
 test-armhf-armhf-libvirt     16 saverestore-support-check    fail  like 173405
 test-armhf-armhf-libvirt-raw 15 saverestore-support-check    fail  like 173405
 test-amd64-amd64-xl-qemut-ws16-amd64 19 guest-stop            fail like 173405
 test-amd64-amd64-libvirt     15 migrate-support-check        fail   never pass
 test-amd64-amd64-libvirt-xsm 15 migrate-support-check        fail   never pass
 test-arm64-arm64-xl-seattle  15 migrate-support-check        fail   never pass
 test-arm64-arm64-xl-seattle  16 saverestore-support-check    fail   never pass
 test-arm64-arm64-xl-thunderx 15 migrate-support-check        fail   never pass
 test-arm64-arm64-xl-thunderx 16 saverestore-support-check    fail   never pass
 test-arm64-arm64-xl-xsm      15 migrate-support-check        fail   never pass
 test-arm64-arm64-xl-credit1  15 migrate-support-check        fail   never pass
 test-arm64-arm64-xl-xsm      16 saverestore-support-check    fail   never pass
 test-arm64-arm64-xl-credit1  16 saverestore-support-check    fail   never pass
 test-arm64-arm64-xl-credit2  15 migrate-support-check        fail   never pass
 test-arm64-arm64-libvirt-xsm 15 migrate-support-check        fail   never pass
 test-arm64-arm64-xl-credit2  16 saverestore-support-check    fail   never pass
 test-arm64-arm64-libvirt-xsm 16 saverestore-support-check    fail   never pass
 test-arm64-arm64-xl          15 migrate-support-check        fail   never pass
 test-arm64-arm64-xl          16 saverestore-support-check    fail   never pass
 test-amd64-amd64-libvirt-qemuu-debianhvm-amd64-xsm 13 migrate-support-check fail never pass
 test-amd64-amd64-libvirt-qcow2 14 migrate-support-check        fail never pass
 test-amd64-amd64-libvirt-raw 14 migrate-support-check        fail   never pass
 test-arm64-arm64-libvirt-raw 14 migrate-support-check        fail   never pass
 test-arm64-arm64-libvirt-raw 15 saverestore-support-check    fail   never pass
 test-arm64-arm64-xl-vhd      14 migrate-support-check        fail   never pass
 test-arm64-arm64-xl-vhd      15 saverestore-support-check    fail   never pass
 test-armhf-armhf-xl-arndale  15 migrate-support-check        fail   never pass
 test-armhf-armhf-xl-arndale  16 saverestore-support-check    fail   never pass
 test-armhf-armhf-xl-credit2  15 migrate-support-check        fail   never pass
 test-armhf-armhf-xl-credit2  16 saverestore-support-check    fail   never pass
 test-armhf-armhf-xl-multivcpu 15 migrate-support-check        fail  never pass
 test-armhf-armhf-xl-multivcpu 16 saverestore-support-check    fail  never pass
 test-armhf-armhf-xl-credit1  15 migrate-support-check        fail   never pass
 test-armhf-armhf-xl-credit1  16 saverestore-support-check    fail   never pass
 test-armhf-armhf-xl-rtds     15 migrate-support-check        fail   never pass
 test-armhf-armhf-xl-rtds     16 saverestore-support-check    fail   never pass
 test-armhf-armhf-xl          15 migrate-support-check        fail   never pass
 test-armhf-armhf-xl          16 saverestore-support-check    fail   never pass
 test-armhf-armhf-xl-vhd      14 migrate-support-check        fail   never pass
 test-armhf-armhf-xl-vhd      15 saverestore-support-check    fail   never pass
 test-armhf-armhf-libvirt-qcow2 14 migrate-support-check        fail never pass
 test-armhf-armhf-libvirt     15 migrate-support-check        fail   never pass
 test-armhf-armhf-libvirt-raw 14 migrate-support-check        fail   never pass
 test-armhf-armhf-xl-cubietruck 15 migrate-support-check        fail never pass
 test-armhf-armhf-xl-cubietruck 16 saverestore-support-check    fail never pass

version targeted for testing:
 linux                26b84401da8458c5cbd6818d5732f7bbb84124a2
baseline version:
 linux                f3dfe925f9548a4337883926db542ccf4ca55fe1

Last test of basis   173405  2022-10-03 17:40:10 Z    0 days
Testing same since   173411  2022-10-04 01:09:43 Z    0 days    1 attempts

------------------------------------------------------------
People who touched revisions under test:
  "Eric W. Biederman" <ebiederm@xmission.com>
  Adam Bratschi-Kaye <ark.email@gmail.com>
  Adam Skladowski <a39.skl@gmail.com>
  Alan Stern <stern@rowland.harvard.edu>
  Alex Gaynor <alex.gaynor@gmail.com>
  Alexei Starovoitov <ast@kernel.org>
  Andreas Larsson <andreas@gaisler.com>
  Android Treehugger Robot
  Andy Shevchenko <andriy.shevchenko@linux.intel.com>
  AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
  Antonio Terceiro <antonio.terceiro@linaro.org>
  Arnd Bergmann <arnd@arndb.de> # arm defconfigs
  Arvid Norlander <lkml@vorpal.se>
  Bart Van Assche <bvanassche@acm.org>
  Bill Wendling <morbo@google.com>
  Björn Roy Baron <bjorn3_gh@protonmail.com>
  Boqun Feng <boqun.feng@gmail.com>
  Boris-Chengbiao Zhou <bobo1239@web.de>
  Casey Schaufler <casey@schaufler-ca.com>
  catalin@antebit.com
  Chanwoo Choi <cw00.choi@samsung.com>
  Chao Qin <chao.qin@intel.com>
  Christian Brauner (Microsoft) <brauner@kernel.org>
  Christian Göttsche <cgzones@googlemail.com>
  Christophe JAILLET <christophe.jaillet@wanadoo.fr>
  Damien Le Moal <damien.lemoal@opensource.wdc.com>
  Dan Carpenter <dan.carpenter@oracle.com>
  Daniel Latypov <dlatypov@google.com>
  Daniel Lezcano <daniel.lezcano@linaro.org>
  Daniel Lezcano <daniel.lezcano@linexp.org>
  Daniel Scally <djrscally@gmail.com>
  Daniel Xu <dxu@dxuuu.xyz>
  Dariusz Sosnowski <dsosnowski@dsosnowski.pl>
  David Gow <davidgow@google.com>
  Dmitry Monakhov <dmtrmonakhov@yandex-team.ru>
  Dmitry Torokhov <dmitry.torokhov@gmail.com>
  Doug Smythies <dsmythies@telus.net>
  Douglas Su <d0u9.su@outlook.com>
  Eric W. Biederman <ebiederm@xmission.com>
  Finn Behrens <me@kloenk.de>
  Florian Fainelli <f.fainelli@gmail.com>
  Fox Chen <foxhlchen@gmail.com>
  Frederick Lawler <fred@cloudflare.com>
  Gaosheng Cui <cuigaosheng1@huawei.com>
  Gary Guo <gary@garyguo.net>
  Geoffrey Thomas <geofft@ldpreload.com>
  Greg Kroah-Hartman <gregkh@linuxfoundation.org>
  Guenter Roeck <linux@roeck-us.net>
  Gwan-gyeong Mun <gwan-gyeong.mun@intel.com>
  Hanjun Guo <guohanjun@huawei.com>
  Hans de Goede <hdegoede@redhat.com>
  Heikki Krogerus <heikki.krogerus@linux.intel.com>
  Huacai Chen <chenhuacai@loongson.cn>
  Huang Rui <ray.huang@amd.com>
  Huisong Li <lihuisong@huawei.com>
  Isabella Basso <isabbasso@riseup.net>
  Jakub Kicinski <kuba@kernel.org>
  Jason Wang <wangborong@cdjrlc.com>
  Jean Delvare <jdelvare@suse.de>
  Jeremy Linton <jeremy.linton@arm.com>
  Jernej Skrabec <jernej.skrabec@gmail.com>
  Jianmin Lv <lvjianmin@loongson.cn>
  Jiapeng Chong <jiapeng.chong@linux.alibaba.com>
  Jilin Yuan <yuanjilin@cdjrlc.com>
  Joe Perches <joe@perches.com>
  John Baublitz <john.m.baublitz@gmail.com>
  John Garry <john.garry@huawei.com>
  Jonathan Cameron <Jonathan.Cameron@huawei.com>
  Josh Poimboeuf <jpoimboe@kernel.org>
  Julian Merkle <me@jvmerkle.de>
  Keerthy <j-keerthy@ti.com>
  Kees Cook <keescook@chromium.org>
  Kellen Renshaw <kellen.renshaw@canonical.com>
  KP Singh <kpsingh@kernel.org>
  Linus Torvalds <torvalds@linux-foundation.org>
  Liu Shixin <liushixin2@huawei.com>
  Lontke Michael <michael.lontke@elektrobit.com>
  Lukas Bulwahn <lukas.bulwahn@gmail.com>
  Lukas Wunner <lukas@wunner.de>
  Lukasz Luba <lukasz.luba@arm.com>
  Léo Lanteri Thauvin <leseulartichaut@gmail.com>
  Maciej Falkowski <m.falkowski@samsung.com>
  Marek Szyprowski <m.szyprowski@samsung.com>
  Mario Limonciello <mario.limonciello@amd.com>
  Mark Brown <broonie@kernel.org>
  Marko Cekrlic <marko.cekrlic.26@gmail.com>
  Martin Rodriguez Reboredo <yakoyoku@gmail.com>
  Matthew Anderson <ruinairas1992@gmail.com>
  Matthew Bakhtiari <dev@mtbk.me>
  Matthew Wilcox <willy@infradead.org>
  Matthias Kaehlcke <mka@chromium.org>
  Michael Ellerman <mpe@ellerman.id.au>
  Michael Walle <michael@walle.cc>
  Miguel Cano <macanroj@gmail.com>
  Miguel Ojeda <ojeda@kernel.org>
  Mika Westerberg <mika.westerberg@linux.intel.com>
  Milan Landaverde <milan@mdaverde.com>
  Mimi Zohar <zohar@linux.ibm.com>
  Morgan Bartlett <mjmouse9999@gmail.com>
  Nathan Chancellor <nathan@kernel.org>
  Nathan Lynch <nathanl@linux.ibm.com>
  Nick Desaulniers <ndesaulniers@google.com>
  Niklas Mohrin <dev@niklasmohrin.de>
  Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
  Nándor István Krácser <bonifaido@gmail.com>
  Ondrej Mosnacek <omosnace@redhat.com>
  Orlando Chamberlain <redecorating@protonmail.com>
  Paul Moore <paul@paul-moore.com>
  Perry Yuan <Perry.Yuan@amd.com>
  Peter Xu <peterx@redhat.com>
  Peter Zijlstra (Intel) <peterz@infradead.org>
  Petr Mladek <pmladek@suse.com>
  Philipp Zabel <philipp.zabel@gmail.com>
  Philipp Zabel <philipp.zabel@gmail.com> # GA402RJ
  Rafael J. Wysocki <rafael.j.wysocki@intel.com>
  Rafael Mendonca <rafaelmendsr@gmail.com>
  Rasmus Villemoes <linux@rasmusvillemoes.dk>
  Rich Felker <dalias@libc.org>
  Sakari Ailus <sakari.ailus@linux.intel.com>
  Sami Tolvanen <samitolvanen@google.com>
  Samuel Jiang <chyishian.jiang@gmail.com>
  Sedat Dilek <sedat.dilek@gmail.com>
  Shang XiaoJing <shangxiaojing@huawei.com>
  Shi junming <junming@nfschina.com>
  short-circuit <davidedp91@gmail.com>
  Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
  Stephen Boyd <sboyd@kernel.org>
  Su Jinzhou <jinzhou.su@amd.com>
  Sumeet Pawnikar <sumeet.r.pawnikar@intel.com>
  Sumera Priyadarsini <sylphrenadin@gmail.com>
  Sumit Gupta <sumitg@nvidia.com>
  Sunand <sunandchakradhar@gmail.com>
  Sven Van Asbroeck <thesven73@gmail.com>
  Tamim Khan <tamim@fusetak.com>
  Thierry Reding <treding@nvidia.com>
  Tiago Lam <tiagolam@gmail.com>
  Tony Luck <tony.luck@intel.com>
  Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
  Vadim Pasternak <vadimp@nvidia.com>
  Vijayenthiran Subramaniam <vijayenthiran.subramaniam@arm.com>
  Viktor Garske <viktor@v-gar.de>
  Viresh Kumar <viresh.kumar@linaro.org>
  Wang Wendy <wendy.wang@intel.com>
  Wedson Almeida Filho <wedsonaf@google.com>
  Wei Liu <wei.liu@kernel.org>
  Wolfram Sang <wsa+renesas@sang-engineering.com>
  Wolfram Sang <wsa@kernel.org>
  Wu XiangCheng <bobwxc@email.cn>
  Xiu Jianfeng <xiujianfeng@huawei.com>
  Xu Panda <xu.panda@zte.com.cn>
  Xuewen Yan <xuewen.yan@unisoc.com>
  Yang Yingliang <yangyingliang@huawei.com>
  ye xingchen <ye.xingchen@zte.com.cn>
  Yu Liao <liaoyu15@huawei.com>
  Yuki Okushi <jtitor@2k36.org>
  Zhang Jianhua <chris.zjh@huawei.com>
  Zhang Rui <rui.zhang@intel.com>
  zhaoxiao <zhaoxiao@uniontech.com>

jobs:
 build-amd64-xsm                                              pass    
 build-arm64-xsm                                              pass    
 build-i386-xsm                                               pass    
 build-amd64                                                  pass    
 build-arm64                                                  pass    
 build-armhf                                                  pass    
 build-i386                                                   pass    
 build-amd64-libvirt                                          pass    
 build-arm64-libvirt                                          pass    
 build-armhf-libvirt                                          pass    
 build-i386-libvirt                                           pass    
 build-amd64-pvops                                            pass    
 build-arm64-pvops                                            pass    
 build-armhf-pvops                                            pass    
 build-i386-pvops                                             pass    
 test-amd64-amd64-xl                                          pass    
 test-amd64-coresched-amd64-xl                                pass    
 test-arm64-arm64-xl                                          pass    
 test-armhf-armhf-xl                                          pass    
 test-amd64-amd64-libvirt-qemuu-debianhvm-amd64-xsm           pass    
 test-amd64-amd64-xl-qemut-stubdom-debianhvm-amd64-xsm        pass    
 test-amd64-amd64-xl-qemut-debianhvm-i386-xsm                 pass    
 test-amd64-amd64-xl-qemuu-debianhvm-i386-xsm                 pass    
 test-amd64-amd64-libvirt-xsm                                 pass    
 test-arm64-arm64-libvirt-xsm                                 pass    
 test-amd64-amd64-xl-xsm                                      pass    
 test-arm64-arm64-xl-xsm                                      pass    
 test-amd64-amd64-qemuu-nested-amd                            fail    
 test-amd64-amd64-xl-pvhv2-amd                                pass    
 test-amd64-amd64-dom0pvh-xl-amd                              pass    
 test-amd64-amd64-xl-qemut-debianhvm-amd64                    pass    
 test-amd64-amd64-xl-qemuu-debianhvm-amd64                    pass    
 test-amd64-amd64-freebsd11-amd64                             pass    
 test-amd64-amd64-freebsd12-amd64                             pass    
 test-amd64-amd64-xl-qemuu-ovmf-amd64                         pass    
 test-amd64-amd64-xl-qemut-win7-amd64                         fail    
 test-amd64-amd64-xl-qemuu-win7-amd64                         fail    
 test-amd64-amd64-xl-qemut-ws16-amd64                         fail    
 test-amd64-amd64-xl-qemuu-ws16-amd64                         fail    
 test-armhf-armhf-xl-arndale                                  pass    
 test-amd64-amd64-examine-bios                                pass    
 test-amd64-amd64-xl-credit1                                  pass    
 test-arm64-arm64-xl-credit1                                  pass    
 test-armhf-armhf-xl-credit1                                  pass    
 test-amd64-amd64-xl-credit2                                  pass    
 test-arm64-arm64-xl-credit2                                  pass    
 test-armhf-armhf-xl-credit2                                  pass    
 test-armhf-armhf-xl-cubietruck                               pass    
 test-amd64-amd64-xl-qemuu-dmrestrict-amd64-dmrestrict        pass    
 test-amd64-amd64-examine                                     pass    
 test-arm64-arm64-examine                                     pass    
 test-armhf-armhf-examine                                     pass    
 test-amd64-amd64-qemuu-nested-intel                          pass    
 test-amd64-amd64-xl-pvhv2-intel                              pass    
 test-amd64-amd64-dom0pvh-xl-intel                            pass    
 test-amd64-amd64-libvirt                                     pass    
 test-armhf-armhf-libvirt                                     pass    
 test-amd64-amd64-xl-multivcpu                                pass    
 test-armhf-armhf-xl-multivcpu                                pass    
 test-amd64-amd64-pair                                        pass    
 test-amd64-amd64-libvirt-pair                                pass    
 test-amd64-amd64-xl-pvshim                                   pass    
 test-amd64-amd64-pygrub                                      pass    
 test-amd64-amd64-libvirt-qcow2                               pass    
 test-armhf-armhf-libvirt-qcow2                               pass    
 test-amd64-amd64-libvirt-raw                                 pass    
 test-arm64-arm64-libvirt-raw                                 pass    
 test-armhf-armhf-libvirt-raw                                 pass    
 test-amd64-amd64-xl-rtds                                     pass    
 test-armhf-armhf-xl-rtds                                     pass    
 test-arm64-arm64-xl-seattle                                  pass    
 test-amd64-amd64-xl-qemuu-debianhvm-amd64-shadow             pass    
 test-amd64-amd64-xl-shadow                                   pass    
 test-arm64-arm64-xl-thunderx                                 pass    
 test-amd64-amd64-examine-uefi                                pass    
 test-amd64-amd64-xl-vhd                                      pass    
 test-arm64-arm64-xl-vhd                                      pass    
 test-armhf-armhf-xl-vhd                                      pass    


------------------------------------------------------------
sg-report-flight on osstest.test-lab.xenproject.org
logs: /home/logs/logs
images: /home/logs/images

Logs, config files, etc. are available at
    http://logs.test-lab.xenproject.org/osstest/logs

Explanation of these reports, and of osstest in general, is at
    http://xenbits.xen.org/gitweb/?p=osstest.git;a=blob;f=README.email;hb=master
    http://xenbits.xen.org/gitweb/?p=osstest.git;a=blob;f=README;hb=master

Test harness code can be found at
    http://xenbits.xen.org/gitweb?p=osstest.git;a=summary


Pushing revision :

hint: The 'hooks/update' hook was ignored because it's not set as executable.
hint: You can disable this warning with `git config advice.ignoredHook false`.
hint: The 'hooks/post-receive' hook was ignored because it's not set as executable.
hint: You can disable this warning with `git config advice.ignoredHook false`.
hint: The 'hooks/post-update' hook was ignored because it's not set as executable.
hint: You can disable this warning with `git config advice.ignoredHook false`.
To xenbits.xen.org:/home/xen/git/linux-pvops.git
   f3dfe925f954..26b84401da84  26b84401da8458c5cbd6818d5732f7bbb84124a2 -> tested/linux-linus


^ permalink raw reply	[relevance 3%]

* [PATCH v1 00/28] Rust core additions
@ 2022-11-10 16:41  4% Miguel Ojeda
  2022-11-10 16:41  6% ` [PATCH v1 16/28] rust: str: add `CStr` type Miguel Ojeda
  2022-11-10 16:41  8% ` [PATCH v1 18/28] rust: str: add `CStr` unit tests Miguel Ojeda
  0 siblings, 2 replies; 77+ results
From: Miguel Ojeda @ 2022-11-10 16:41 UTC (permalink / raw)
  To: Miguel Ojeda, Wedson Almeida Filho, Alex Gaynor, Boqun Feng,
	Gary Guo, Björn Roy Baron
  Cc: rust-for-linux, linux-kernel, patches

This patch series is the first batch of changes to upstream the rest
of the Rust support.

In this instance, all the facilities introduced are part of the "Rust
core". They do not interact with the C side in new major ways (no new
C types used; only `strlen`, `memchr`, additional error codes and some
more `printk` format strings).

After this series, `str.rs` and `print.rs` are in sync with downstream
and all remaining proc macros have been added. `error.rs` is fairly
complete too, though a few more `pub(crate)` features will come later
(to avoid leaving dead code in-between series).

Note that a few temporary `#[allow(dead_code)]` attributes are used in
order to have a bit more freedom organizing the patches while keeping
all of them buildable without warnings/errors, but at the end of the
series there is none remaining (of the temporary ones).

Virtually all the code has been in linux-next for months and was part
of the Rust patch series before the trimming down (i.e. up to v8).

Each patch has been built-tested on a Rust-enabled `defconfig` with
`CLIPPY=1` on the `all`, `rustfmtcheck`, `rustdoc` and `rusttest`
targets.

Björn Roy Baron (1):
  rust: macros: add `concat_idents!` proc macro

Finn Behrens (1):
  rust: error: declare errors using macro

Gary Guo (9):
  rust: macros: add `#[vtable]` proc macro
  rust: macros: take string literals in `module!`
  rust: str: add `BStr` type
  rust: str: add `b_str!` macro
  rust: str: add `CStr` type
  rust: str: implement several traits for `CStr`
  rust: str: add `c_str!` macro
  rust: add `build_error` crate
  rust: build_assert: add `build_{error,assert}!` macros

Miguel Ojeda (7):
  rust: prelude: split re-exports into groups
  rust: print: add more `pr_*!` levels
  rust: print: add `pr_cont!` macro
  rust: samples: add `rust_print` example
  rust: alloc: add `RawVec::try_with_capacity_in()` constructor
  rust: alloc: add `Vec::try_with_capacity{,_in}()` constructors
  rust: static_assert: add `static_assert!` macro

Milan Landaverde (1):
  rust: str: add `CStr` unit tests

Niklas Mohrin (1):
  rust: std_vendor: add `dbg!` macro based on `std`'s one

Viktor Garske (1):
  rust: error: add codes from `errno-base.h`

Wedson Almeida Filho (7):
  rust: error: add `From` implementations for `Error`
  rust: prelude: add `error::code::*` constant items
  rust: str: add `Formatter` type
  rust: str: add `CString` type
  rust: str: add `fmt!` macro
  rust: types: add `Either` type
  rust: types: add `Opaque` type

 lib/Kconfig.debug                 |  16 +
 rust/Makefile                     |  22 +-
 rust/alloc/raw_vec.rs             |  33 +-
 rust/alloc/vec/mod.rs             |  89 +++++
 rust/build_error.rs               |  24 ++
 rust/exports.c                    |   5 +
 rust/kernel/build_assert.rs       |  82 +++++
 rust/kernel/error.rs              |  90 ++++-
 rust/kernel/lib.rs                |   9 +
 rust/kernel/prelude.rs            |  20 +-
 rust/kernel/print.rs              | 214 +++++++++++-
 rust/kernel/static_assert.rs      |  34 ++
 rust/kernel/std_vendor.rs         | 160 +++++++++
 rust/kernel/str.rs                | 532 +++++++++++++++++++++++++++++-
 rust/kernel/types.rs              |  37 +++
 rust/macros/concat_idents.rs      |  23 ++
 rust/macros/helpers.rs            |  24 +-
 rust/macros/lib.rs                | 108 +++++-
 rust/macros/module.rs             |  10 +-
 rust/macros/vtable.rs             |  95 ++++++
 samples/rust/Kconfig              |  10 +
 samples/rust/Makefile             |   1 +
 samples/rust/rust_minimal.rs      |   8 +-
 samples/rust/rust_print.rs        |  54 +++
 scripts/generate_rust_analyzer.py |   8 +-
 25 files changed, 1666 insertions(+), 42 deletions(-)
 create mode 100644 rust/build_error.rs
 create mode 100644 rust/kernel/build_assert.rs
 create mode 100644 rust/kernel/static_assert.rs
 create mode 100644 rust/kernel/std_vendor.rs
 create mode 100644 rust/kernel/types.rs
 create mode 100644 rust/macros/concat_idents.rs
 create mode 100644 rust/macros/vtable.rs
 create mode 100644 samples/rust/rust_print.rs


base-commit: f0c4d9fc9cc9462659728d168387191387e903cc
-- 
2.38.1


^ permalink raw reply	[relevance 4%]

* [PATCH v1 16/28] rust: str: add `CStr` type
  2022-11-10 16:41  4% [PATCH v1 00/28] Rust core additions Miguel Ojeda
@ 2022-11-10 16:41  6% ` Miguel Ojeda
  2022-11-10 16:41  8% ` [PATCH v1 18/28] rust: str: add `CStr` unit tests Miguel Ojeda
  1 sibling, 0 replies; 77+ results
From: Miguel Ojeda @ 2022-11-10 16:41 UTC (permalink / raw)
  To: Miguel Ojeda, Wedson Almeida Filho, Alex Gaynor, Boqun Feng,
	Gary Guo, Björn Roy Baron
  Cc: rust-for-linux, linux-kernel, patches, Milan Landaverde

From: Gary Guo <gary@garyguo.net>

Add the `CStr` type, which is a borrowed string that is guaranteed
to have exactly one `NUL` byte, which is at the end.

It is used for interoperability with kernel APIs that take C strings.

Add it to the prelude too.

Co-developed-by: Alex Gaynor <alex.gaynor@gmail.com>
Signed-off-by: Alex Gaynor <alex.gaynor@gmail.com>
Co-developed-by: Milan Landaverde <milan@mdaverde.com>
Signed-off-by: Milan Landaverde <milan@mdaverde.com>
Signed-off-by: Gary Guo <gary@garyguo.net>
[Reworded, adapted for upstream and applied latest changes]
Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
---
 rust/kernel/prelude.rs |   2 +-
 rust/kernel/str.rs     | 169 +++++++++++++++++++++++++++++++++++++++++
 2 files changed, 170 insertions(+), 1 deletion(-)

diff --git a/rust/kernel/prelude.rs b/rust/kernel/prelude.rs
index 1e08b08e9420..89c2c9f4e7a7 100644
--- a/rust/kernel/prelude.rs
+++ b/rust/kernel/prelude.rs
@@ -21,4 +21,4 @@ pub use super::{pr_alert, pr_crit, pr_debug, pr_emerg, pr_err, pr_info, pr_notic
 
 pub use super::error::{code::*, Error, Result};
 
-pub use super::ThisModule;
+pub use super::{str::CStr, ThisModule};
diff --git a/rust/kernel/str.rs b/rust/kernel/str.rs
index 95eb757c619d..d66565f92f71 100644
--- a/rust/kernel/str.rs
+++ b/rust/kernel/str.rs
@@ -4,6 +4,11 @@
 
 use core::fmt;
 
+use crate::{
+    bindings,
+    error::{code::*, Error},
+};
+
 /// Byte string without UTF-8 validity guarantee.
 ///
 /// `BStr` is simply an alias to `[u8]`, but has a more evident semantical meaning.
@@ -30,6 +35,170 @@ macro_rules! b_str {
     }};
 }
 
+/// Possible errors when using conversion functions in [`CStr`].
+#[derive(Debug, Clone, Copy)]
+pub enum CStrConvertError {
+    /// Supplied bytes contain an interior `NUL`.
+    InteriorNul,
+
+    /// Supplied bytes are not terminated by `NUL`.
+    NotNulTerminated,
+}
+
+impl From<CStrConvertError> for Error {
+    #[inline]
+    fn from(_: CStrConvertError) -> Error {
+        EINVAL
+    }
+}
+
+/// A string that is guaranteed to have exactly one `NUL` byte, which is at the
+/// end.
+///
+/// Used for interoperability with kernel APIs that take C strings.
+#[repr(transparent)]
+pub struct CStr([u8]);
+
+impl CStr {
+    /// Returns the length of this string excluding `NUL`.
+    #[inline]
+    pub const fn len(&self) -> usize {
+        self.len_with_nul() - 1
+    }
+
+    /// Returns the length of this string with `NUL`.
+    #[inline]
+    pub const fn len_with_nul(&self) -> usize {
+        // SAFETY: This is one of the invariant of `CStr`.
+        // We add a `unreachable_unchecked` here to hint the optimizer that
+        // the value returned from this function is non-zero.
+        if self.0.is_empty() {
+            unsafe { core::hint::unreachable_unchecked() };
+        }
+        self.0.len()
+    }
+
+    /// Returns `true` if the string only includes `NUL`.
+    #[inline]
+    pub const fn is_empty(&self) -> bool {
+        self.len() == 0
+    }
+
+    /// Wraps a raw C string pointer.
+    ///
+    /// # Safety
+    ///
+    /// `ptr` must be a valid pointer to a `NUL`-terminated C string, and it must
+    /// last at least `'a`. When `CStr` is alive, the memory pointed by `ptr`
+    /// must not be mutated.
+    #[inline]
+    pub unsafe fn from_char_ptr<'a>(ptr: *const core::ffi::c_char) -> &'a Self {
+        // SAFETY: The safety precondition guarantees `ptr` is a valid pointer
+        // to a `NUL`-terminated C string.
+        let len = unsafe { bindings::strlen(ptr) } + 1;
+        // SAFETY: Lifetime guaranteed by the safety precondition.
+        let bytes = unsafe { core::slice::from_raw_parts(ptr as _, len as _) };
+        // SAFETY: As `len` is returned by `strlen`, `bytes` does not contain interior `NUL`.
+        // As we have added 1 to `len`, the last byte is known to be `NUL`.
+        unsafe { Self::from_bytes_with_nul_unchecked(bytes) }
+    }
+
+    /// Creates a [`CStr`] from a `[u8]`.
+    ///
+    /// The provided slice must be `NUL`-terminated, does not contain any
+    /// interior `NUL` bytes.
+    pub const fn from_bytes_with_nul(bytes: &[u8]) -> Result<&Self, CStrConvertError> {
+        if bytes.is_empty() {
+            return Err(CStrConvertError::NotNulTerminated);
+        }
+        if bytes[bytes.len() - 1] != 0 {
+            return Err(CStrConvertError::NotNulTerminated);
+        }
+        let mut i = 0;
+        // `i + 1 < bytes.len()` allows LLVM to optimize away bounds checking,
+        // while it couldn't optimize away bounds checks for `i < bytes.len() - 1`.
+        while i + 1 < bytes.len() {
+            if bytes[i] == 0 {
+                return Err(CStrConvertError::InteriorNul);
+            }
+            i += 1;
+        }
+        // SAFETY: We just checked that all properties hold.
+        Ok(unsafe { Self::from_bytes_with_nul_unchecked(bytes) })
+    }
+
+    /// Creates a [`CStr`] from a `[u8]` without performing any additional
+    /// checks.
+    ///
+    /// # Safety
+    ///
+    /// `bytes` *must* end with a `NUL` byte, and should only have a single
+    /// `NUL` byte (or the string will be truncated).
+    #[inline]
+    pub const unsafe fn from_bytes_with_nul_unchecked(bytes: &[u8]) -> &CStr {
+        // SAFETY: Properties of `bytes` guaranteed by the safety precondition.
+        unsafe { core::mem::transmute(bytes) }
+    }
+
+    /// Returns a C pointer to the string.
+    #[inline]
+    pub const fn as_char_ptr(&self) -> *const core::ffi::c_char {
+        self.0.as_ptr() as _
+    }
+
+    /// Convert the string to a byte slice without the trailing 0 byte.
+    #[inline]
+    pub fn as_bytes(&self) -> &[u8] {
+        &self.0[..self.len()]
+    }
+
+    /// Convert the string to a byte slice containing the trailing 0 byte.
+    #[inline]
+    pub const fn as_bytes_with_nul(&self) -> &[u8] {
+        &self.0
+    }
+
+    /// Yields a [`&str`] slice if the [`CStr`] contains valid UTF-8.
+    ///
+    /// If the contents of the [`CStr`] are valid UTF-8 data, this
+    /// function will return the corresponding [`&str`] slice. Otherwise,
+    /// it will return an error with details of where UTF-8 validation failed.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # use kernel::str::CStr;
+    /// let cstr = CStr::from_bytes_with_nul(b"foo\0").unwrap();
+    /// assert_eq!(cstr.to_str(), Ok("foo"));
+    /// ```
+    #[inline]
+    pub fn to_str(&self) -> Result<&str, core::str::Utf8Error> {
+        core::str::from_utf8(self.as_bytes())
+    }
+
+    /// Unsafely convert this [`CStr`] into a [`&str`], without checking for
+    /// valid UTF-8.
+    ///
+    /// # Safety
+    ///
+    /// The contents must be valid UTF-8.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # use kernel::c_str;
+    /// # use kernel::str::CStr;
+    /// // SAFETY: String literals are guaranteed to be valid UTF-8
+    /// // by the Rust compiler.
+    /// let bar = c_str!("ツ");
+    /// assert_eq!(unsafe { bar.as_str_unchecked() }, "ツ");
+    /// ```
+    #[inline]
+    pub unsafe fn as_str_unchecked(&self) -> &str {
+        unsafe { core::str::from_utf8_unchecked(self.as_bytes()) }
+    }
+}
+
 /// Allows formatting of [`fmt::Arguments`] into a raw buffer.
 ///
 /// It does not fail if callers write past the end of the buffer so that they can calculate the
-- 
2.38.1


^ permalink raw reply related	[relevance 6%]

* [PATCH v1 18/28] rust: str: add `CStr` unit tests
  2022-11-10 16:41  4% [PATCH v1 00/28] Rust core additions Miguel Ojeda
  2022-11-10 16:41  6% ` [PATCH v1 16/28] rust: str: add `CStr` type Miguel Ojeda
@ 2022-11-10 16:41  8% ` Miguel Ojeda
  1 sibling, 0 replies; 77+ results
From: Miguel Ojeda @ 2022-11-10 16:41 UTC (permalink / raw)
  To: Miguel Ojeda, Wedson Almeida Filho, Alex Gaynor, Boqun Feng,
	Gary Guo, Björn Roy Baron
  Cc: rust-for-linux, linux-kernel, patches, Milan Landaverde

From: Milan Landaverde <milan@mdaverde.com>

Add unit tests for `CStr::from_bytes_with_nul()` and
`CStr::from_bytes_with_nul_unchecked()`.

These serve as an example of the first unit tests for Rust code
(i.e. different from documentation tests).

Signed-off-by: Milan Landaverde <milan@mdaverde.com>
[Reworded, adapted for upstream and applied latest changes]
Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
---
 rust/kernel/str.rs | 29 +++++++++++++++++++++++++++++
 1 file changed, 29 insertions(+)

diff --git a/rust/kernel/str.rs b/rust/kernel/str.rs
index 11d297c1a61c..3ed685cb5a3c 100644
--- a/rust/kernel/str.rs
+++ b/rust/kernel/str.rs
@@ -321,6 +321,35 @@ where
     }
 }
 
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn test_cstr_to_str() {
+        let good_bytes = b"\xf0\x9f\xa6\x80\0";
+        let checked_cstr = CStr::from_bytes_with_nul(good_bytes).unwrap();
+        let checked_str = checked_cstr.to_str().unwrap();
+        assert_eq!(checked_str, "🦀");
+    }
+
+    #[test]
+    #[should_panic]
+    fn test_cstr_to_str_panic() {
+        let bad_bytes = b"\xc3\x28\0";
+        let checked_cstr = CStr::from_bytes_with_nul(bad_bytes).unwrap();
+        checked_cstr.to_str().unwrap();
+    }
+
+    #[test]
+    fn test_cstr_as_str_unchecked() {
+        let good_bytes = b"\xf0\x9f\x90\xA7\0";
+        let checked_cstr = CStr::from_bytes_with_nul(good_bytes).unwrap();
+        let unchecked_str = unsafe { checked_cstr.as_str_unchecked() };
+        assert_eq!(unchecked_str, "🐧");
+    }
+}
+
 /// Allows formatting of [`fmt::Arguments`] into a raw buffer.
 ///
 /// It does not fail if callers write past the end of the buffer so that they can calculate the
-- 
2.38.1


^ permalink raw reply related	[relevance 8%]

* [PATCH v2 00/28] Rust core additions
@ 2022-12-02 16:14  3% ojeda
  2022-12-02 16:14  6% ` [PATCH v2 16/28] rust: str: add `CStr` type ojeda
  2022-12-02 16:14  8% ` [PATCH v2 18/28] rust: str: add `CStr` unit tests ojeda
  0 siblings, 2 replies; 77+ results
From: ojeda @ 2022-12-02 16:14 UTC (permalink / raw)
  To: Miguel Ojeda, Wedson Almeida Filho, Alex Gaynor, Boqun Feng,
	Gary Guo, Björn Roy Baron
  Cc: rust-for-linux, linux-kernel, patches

From: Miguel Ojeda <ojeda@kernel.org>

This is v2 of the first batch of changes to upstream the rest of
the Rust support. v1 is at:

    https://lore.kernel.org/rust-for-linux/20221110164152.26136-1-ojeda@kernel.org/

I collected the tags and applied the agreed changes. The full diff
follows (with respect to v1), since they are minor enough.

I will be applying the patches tomorrow, since v1 has had more than
three weeks of review time.

diff --git a/rust/build_error.rs b/rust/build_error.rs
index 0ff6b33059aa..fa24eeef9929 100644
--- a/rust/build_error.rs
+++ b/rust/build_error.rs
@@ -2,19 +2,26 @@
 
 //! Build-time error.
 //!
-//! This crate provides a function `build_error`, which will panic in
-//! compile-time if executed in const context, and will cause a build error
-//! if not executed at compile time and the optimizer does not optimise away the
-//! call.
+//! This crate provides a [const function][const-functions] `build_error`, which will panic in
+//! compile-time if executed in [const context][const-context], and will cause a build error
+//! if not executed at compile time and the optimizer does not optimise away the call.
 //!
 //! It is used by `build_assert!` in the kernel crate, allowing checking of
 //! conditions that could be checked statically, but could not be enforced in
-//! Rust yet (e.g. perform some checks in const functions, but those
+//! Rust yet (e.g. perform some checks in [const functions][const-functions], but those
 //! functions could still be called in the runtime).
+//!
+//! For details on constant evaluation in Rust, please see the [Reference][const-eval].
+//!
+//! [const-eval]: https://doc.rust-lang.org/reference/const_eval.html
+//! [const-functions]: https://doc.rust-lang.org/reference/const_eval.html#const-functions
+//! [const-context]: https://doc.rust-lang.org/reference/const_eval.html#const-context
 
 #![no_std]
 
-/// Panics if executed in const context, or triggers a build error if not.
+/// Panics if executed in [const context][const-context], or triggers a build error if not.
+///
+/// [const-context]: https://doc.rust-lang.org/reference/const_eval.html#const-context
 #[inline(never)]
 #[cold]
 #[export_name = "rust_build_error"]
diff --git a/rust/kernel/std_vendor.rs b/rust/kernel/std_vendor.rs
index da57b4e521f4..b3e68b24a8c6 100644
--- a/rust/kernel/std_vendor.rs
+++ b/rust/kernel/std_vendor.rs
@@ -35,9 +35,12 @@
 /// This is useful when debugging issues that only occur in release
 /// builds or when debugging in release mode is significantly faster.
 ///
-/// Note that the macro is intended as a debugging tool and therefore you
-/// should avoid having uses of it in version control for long periods
-/// (other than in tests and similar).
+/// Note that the macro is intended as a temporary debugging tool to be
+/// used during development. Therefore, avoid committing `dbg!` macro
+/// invocations into the kernel tree.
+///
+/// For debug output that is intended to be kept in the kernel tree,
+/// use [`pr_debug`] and similar facilities instead.
 ///
 /// # Stability
 ///
diff --git a/rust/kernel/str.rs b/rust/kernel/str.rs
index ffac633423db..b771310fa4a4 100644
--- a/rust/kernel/str.rs
+++ b/rust/kernel/str.rs
@@ -129,18 +129,6 @@ impl CStr {
         Ok(unsafe { Self::from_bytes_with_nul_unchecked(bytes) })
     }
 
-    /// Creates a [`CStr`] from a `[u8]`, panic if input is not valid.
-    ///
-    /// This function is only meant to be used by `c_str!` macro, so
-    /// crates using `c_str!` macro don't have to enable `const_panic` feature.
-    #[doc(hidden)]
-    pub const fn from_bytes_with_nul_unwrap(bytes: &[u8]) -> &Self {
-        match Self::from_bytes_with_nul(bytes) {
-            Ok(v) => v,
-            Err(_) => panic!("string contains interior NUL"),
-        }
-    }
-
     /// Creates a [`CStr`] from a `[u8]` without performing any additional
     /// checks.
     ///
@@ -349,7 +337,10 @@ where
 macro_rules! c_str {
     ($str:expr) => {{
         const S: &str = concat!($str, "\0");
-        const C: &$crate::str::CStr = $crate::str::CStr::from_bytes_with_nul_unwrap(S.as_bytes());
+        const C: &$crate::str::CStr = match $crate::str::CStr::from_bytes_with_nul(S.as_bytes()) {
+            Ok(v) => v,
+            Err(_) => panic!("string contains interior NUL"),
+        };
         C
     }};
 }
diff --git a/rust/macros/concat_idents.rs b/rust/macros/concat_idents.rs
index 3b5a9dd70e8a..7e4b450f3a50 100644
--- a/rust/macros/concat_idents.rs
+++ b/rust/macros/concat_idents.rs
@@ -18,6 +18,6 @@ pub(crate) fn concat_idents(ts: TokenStream) -> TokenStream {
     assert_eq!(expect_punct(&mut it), ',');
     let b = expect_ident(&mut it);
     assert!(it.next().is_none(), "only two idents can be concatenated");
-    let res = Ident::new(&(a.to_string() + &b.to_string()), b.span());
+    let res = Ident::new(&format!("{a}{b}"), b.span());
     TokenStream::from_iter([TokenTree::Ident(res)])
 }

Björn Roy Baron (1):
  rust: macros: add `concat_idents!` proc macro

Finn Behrens (1):
  rust: error: declare errors using macro

Gary Guo (9):
  rust: macros: add `#[vtable]` proc macro
  rust: macros: take string literals in `module!`
  rust: str: add `BStr` type
  rust: str: add `b_str!` macro
  rust: str: add `CStr` type
  rust: str: implement several traits for `CStr`
  rust: str: add `c_str!` macro
  rust: add `build_error` crate
  rust: build_assert: add `build_{error,assert}!` macros

Miguel Ojeda (7):
  rust: prelude: split re-exports into groups
  rust: print: add more `pr_*!` levels
  rust: print: add `pr_cont!` macro
  rust: samples: add `rust_print` example
  rust: alloc: add `RawVec::try_with_capacity_in()` constructor
  rust: alloc: add `Vec::try_with_capacity{,_in}()` constructors
  rust: static_assert: add `static_assert!` macro

Milan Landaverde (1):
  rust: str: add `CStr` unit tests

Niklas Mohrin (1):
  rust: std_vendor: add `dbg!` macro based on `std`'s one

Viktor Garske (1):
  rust: error: add codes from `errno-base.h`

Wedson Almeida Filho (7):
  rust: error: add `From` implementations for `Error`
  rust: prelude: add `error::code::*` constant items
  rust: str: add `Formatter` type
  rust: str: add `CString` type
  rust: str: add `fmt!` macro
  rust: types: add `Either` type
  rust: types: add `Opaque` type

 lib/Kconfig.debug                 |  16 +
 rust/Makefile                     |  22 +-
 rust/alloc/raw_vec.rs             |  33 +-
 rust/alloc/vec/mod.rs             |  89 +++++
 rust/build_error.rs               |  31 ++
 rust/exports.c                    |   5 +
 rust/kernel/build_assert.rs       |  82 +++++
 rust/kernel/error.rs              |  90 ++++-
 rust/kernel/lib.rs                |   9 +
 rust/kernel/prelude.rs            |  20 +-
 rust/kernel/print.rs              | 214 +++++++++++-
 rust/kernel/static_assert.rs      |  34 ++
 rust/kernel/std_vendor.rs         | 163 ++++++++++
 rust/kernel/str.rs                | 523 +++++++++++++++++++++++++++++-
 rust/kernel/types.rs              |  37 +++
 rust/macros/concat_idents.rs      |  23 ++
 rust/macros/helpers.rs            |  24 +-
 rust/macros/lib.rs                | 108 +++++-
 rust/macros/module.rs             |  10 +-
 rust/macros/vtable.rs             |  95 ++++++
 samples/rust/Kconfig              |  10 +
 samples/rust/Makefile             |   1 +
 samples/rust/rust_minimal.rs      |   8 +-
 samples/rust/rust_print.rs        |  54 +++
 scripts/generate_rust_analyzer.py |   8 +-
 25 files changed, 1667 insertions(+), 42 deletions(-)
 create mode 100644 rust/build_error.rs
 create mode 100644 rust/kernel/build_assert.rs
 create mode 100644 rust/kernel/static_assert.rs
 create mode 100644 rust/kernel/std_vendor.rs
 create mode 100644 rust/kernel/types.rs
 create mode 100644 rust/macros/concat_idents.rs
 create mode 100644 rust/macros/vtable.rs
 create mode 100644 samples/rust/rust_print.rs


base-commit: f0c4d9fc9cc9462659728d168387191387e903cc
-- 
2.38.1


^ permalink raw reply related	[relevance 3%]

* [PATCH v2 16/28] rust: str: add `CStr` type
  2022-12-02 16:14  3% [PATCH v2 00/28] Rust core additions ojeda
@ 2022-12-02 16:14  6% ` ojeda
  2022-12-02 16:14  8% ` [PATCH v2 18/28] rust: str: add `CStr` unit tests ojeda
  1 sibling, 0 replies; 77+ results
From: ojeda @ 2022-12-02 16:14 UTC (permalink / raw)
  To: Miguel Ojeda, Wedson Almeida Filho, Alex Gaynor, Boqun Feng,
	Gary Guo, Björn Roy Baron
  Cc: rust-for-linux, linux-kernel, patches, Milan Landaverde

From: Gary Guo <gary@garyguo.net>

Add the `CStr` type, which is a borrowed string that is guaranteed
to have exactly one `NUL` byte, which is at the end.

It is used for interoperability with kernel APIs that take C strings.

Add it to the prelude too.

Co-developed-by: Alex Gaynor <alex.gaynor@gmail.com>
Signed-off-by: Alex Gaynor <alex.gaynor@gmail.com>
Co-developed-by: Milan Landaverde <milan@mdaverde.com>
Signed-off-by: Milan Landaverde <milan@mdaverde.com>
Signed-off-by: Gary Guo <gary@garyguo.net>
[Reworded, adapted for upstream and applied latest changes]
Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
---
 rust/kernel/prelude.rs |   2 +-
 rust/kernel/str.rs     | 169 +++++++++++++++++++++++++++++++++++++++++
 2 files changed, 170 insertions(+), 1 deletion(-)

diff --git a/rust/kernel/prelude.rs b/rust/kernel/prelude.rs
index 1e08b08e9420..89c2c9f4e7a7 100644
--- a/rust/kernel/prelude.rs
+++ b/rust/kernel/prelude.rs
@@ -21,4 +21,4 @@ pub use super::{pr_alert, pr_crit, pr_debug, pr_emerg, pr_err, pr_info, pr_notic
 
 pub use super::error::{code::*, Error, Result};
 
-pub use super::ThisModule;
+pub use super::{str::CStr, ThisModule};
diff --git a/rust/kernel/str.rs b/rust/kernel/str.rs
index 95eb757c619d..d66565f92f71 100644
--- a/rust/kernel/str.rs
+++ b/rust/kernel/str.rs
@@ -4,6 +4,11 @@
 
 use core::fmt;
 
+use crate::{
+    bindings,
+    error::{code::*, Error},
+};
+
 /// Byte string without UTF-8 validity guarantee.
 ///
 /// `BStr` is simply an alias to `[u8]`, but has a more evident semantical meaning.
@@ -30,6 +35,170 @@ macro_rules! b_str {
     }};
 }
 
+/// Possible errors when using conversion functions in [`CStr`].
+#[derive(Debug, Clone, Copy)]
+pub enum CStrConvertError {
+    /// Supplied bytes contain an interior `NUL`.
+    InteriorNul,
+
+    /// Supplied bytes are not terminated by `NUL`.
+    NotNulTerminated,
+}
+
+impl From<CStrConvertError> for Error {
+    #[inline]
+    fn from(_: CStrConvertError) -> Error {
+        EINVAL
+    }
+}
+
+/// A string that is guaranteed to have exactly one `NUL` byte, which is at the
+/// end.
+///
+/// Used for interoperability with kernel APIs that take C strings.
+#[repr(transparent)]
+pub struct CStr([u8]);
+
+impl CStr {
+    /// Returns the length of this string excluding `NUL`.
+    #[inline]
+    pub const fn len(&self) -> usize {
+        self.len_with_nul() - 1
+    }
+
+    /// Returns the length of this string with `NUL`.
+    #[inline]
+    pub const fn len_with_nul(&self) -> usize {
+        // SAFETY: This is one of the invariant of `CStr`.
+        // We add a `unreachable_unchecked` here to hint the optimizer that
+        // the value returned from this function is non-zero.
+        if self.0.is_empty() {
+            unsafe { core::hint::unreachable_unchecked() };
+        }
+        self.0.len()
+    }
+
+    /// Returns `true` if the string only includes `NUL`.
+    #[inline]
+    pub const fn is_empty(&self) -> bool {
+        self.len() == 0
+    }
+
+    /// Wraps a raw C string pointer.
+    ///
+    /// # Safety
+    ///
+    /// `ptr` must be a valid pointer to a `NUL`-terminated C string, and it must
+    /// last at least `'a`. When `CStr` is alive, the memory pointed by `ptr`
+    /// must not be mutated.
+    #[inline]
+    pub unsafe fn from_char_ptr<'a>(ptr: *const core::ffi::c_char) -> &'a Self {
+        // SAFETY: The safety precondition guarantees `ptr` is a valid pointer
+        // to a `NUL`-terminated C string.
+        let len = unsafe { bindings::strlen(ptr) } + 1;
+        // SAFETY: Lifetime guaranteed by the safety precondition.
+        let bytes = unsafe { core::slice::from_raw_parts(ptr as _, len as _) };
+        // SAFETY: As `len` is returned by `strlen`, `bytes` does not contain interior `NUL`.
+        // As we have added 1 to `len`, the last byte is known to be `NUL`.
+        unsafe { Self::from_bytes_with_nul_unchecked(bytes) }
+    }
+
+    /// Creates a [`CStr`] from a `[u8]`.
+    ///
+    /// The provided slice must be `NUL`-terminated, does not contain any
+    /// interior `NUL` bytes.
+    pub const fn from_bytes_with_nul(bytes: &[u8]) -> Result<&Self, CStrConvertError> {
+        if bytes.is_empty() {
+            return Err(CStrConvertError::NotNulTerminated);
+        }
+        if bytes[bytes.len() - 1] != 0 {
+            return Err(CStrConvertError::NotNulTerminated);
+        }
+        let mut i = 0;
+        // `i + 1 < bytes.len()` allows LLVM to optimize away bounds checking,
+        // while it couldn't optimize away bounds checks for `i < bytes.len() - 1`.
+        while i + 1 < bytes.len() {
+            if bytes[i] == 0 {
+                return Err(CStrConvertError::InteriorNul);
+            }
+            i += 1;
+        }
+        // SAFETY: We just checked that all properties hold.
+        Ok(unsafe { Self::from_bytes_with_nul_unchecked(bytes) })
+    }
+
+    /// Creates a [`CStr`] from a `[u8]` without performing any additional
+    /// checks.
+    ///
+    /// # Safety
+    ///
+    /// `bytes` *must* end with a `NUL` byte, and should only have a single
+    /// `NUL` byte (or the string will be truncated).
+    #[inline]
+    pub const unsafe fn from_bytes_with_nul_unchecked(bytes: &[u8]) -> &CStr {
+        // SAFETY: Properties of `bytes` guaranteed by the safety precondition.
+        unsafe { core::mem::transmute(bytes) }
+    }
+
+    /// Returns a C pointer to the string.
+    #[inline]
+    pub const fn as_char_ptr(&self) -> *const core::ffi::c_char {
+        self.0.as_ptr() as _
+    }
+
+    /// Convert the string to a byte slice without the trailing 0 byte.
+    #[inline]
+    pub fn as_bytes(&self) -> &[u8] {
+        &self.0[..self.len()]
+    }
+
+    /// Convert the string to a byte slice containing the trailing 0 byte.
+    #[inline]
+    pub const fn as_bytes_with_nul(&self) -> &[u8] {
+        &self.0
+    }
+
+    /// Yields a [`&str`] slice if the [`CStr`] contains valid UTF-8.
+    ///
+    /// If the contents of the [`CStr`] are valid UTF-8 data, this
+    /// function will return the corresponding [`&str`] slice. Otherwise,
+    /// it will return an error with details of where UTF-8 validation failed.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # use kernel::str::CStr;
+    /// let cstr = CStr::from_bytes_with_nul(b"foo\0").unwrap();
+    /// assert_eq!(cstr.to_str(), Ok("foo"));
+    /// ```
+    #[inline]
+    pub fn to_str(&self) -> Result<&str, core::str::Utf8Error> {
+        core::str::from_utf8(self.as_bytes())
+    }
+
+    /// Unsafely convert this [`CStr`] into a [`&str`], without checking for
+    /// valid UTF-8.
+    ///
+    /// # Safety
+    ///
+    /// The contents must be valid UTF-8.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # use kernel::c_str;
+    /// # use kernel::str::CStr;
+    /// // SAFETY: String literals are guaranteed to be valid UTF-8
+    /// // by the Rust compiler.
+    /// let bar = c_str!("ツ");
+    /// assert_eq!(unsafe { bar.as_str_unchecked() }, "ツ");
+    /// ```
+    #[inline]
+    pub unsafe fn as_str_unchecked(&self) -> &str {
+        unsafe { core::str::from_utf8_unchecked(self.as_bytes()) }
+    }
+}
+
 /// Allows formatting of [`fmt::Arguments`] into a raw buffer.
 ///
 /// It does not fail if callers write past the end of the buffer so that they can calculate the
-- 
2.38.1


^ permalink raw reply related	[relevance 6%]

* [PATCH v2 18/28] rust: str: add `CStr` unit tests
  2022-12-02 16:14  3% [PATCH v2 00/28] Rust core additions ojeda
  2022-12-02 16:14  6% ` [PATCH v2 16/28] rust: str: add `CStr` type ojeda
@ 2022-12-02 16:14  8% ` ojeda
  1 sibling, 0 replies; 77+ results
From: ojeda @ 2022-12-02 16:14 UTC (permalink / raw)
  To: Miguel Ojeda, Wedson Almeida Filho, Alex Gaynor, Boqun Feng,
	Gary Guo, Björn Roy Baron
  Cc: rust-for-linux, linux-kernel, patches, Milan Landaverde

From: Milan Landaverde <milan@mdaverde.com>

Add unit tests for `CStr::from_bytes_with_nul()` and
`CStr::from_bytes_with_nul_unchecked()`.

These serve as an example of the first unit tests for Rust code
(i.e. different from documentation tests).

Signed-off-by: Milan Landaverde <milan@mdaverde.com>
[Reworded, adapted for upstream and applied latest changes]
Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
---
 rust/kernel/str.rs | 29 +++++++++++++++++++++++++++++
 1 file changed, 29 insertions(+)

diff --git a/rust/kernel/str.rs b/rust/kernel/str.rs
index 11d297c1a61c..3ed685cb5a3c 100644
--- a/rust/kernel/str.rs
+++ b/rust/kernel/str.rs
@@ -321,6 +321,35 @@ where
     }
 }
 
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn test_cstr_to_str() {
+        let good_bytes = b"\xf0\x9f\xa6\x80\0";
+        let checked_cstr = CStr::from_bytes_with_nul(good_bytes).unwrap();
+        let checked_str = checked_cstr.to_str().unwrap();
+        assert_eq!(checked_str, "🦀");
+    }
+
+    #[test]
+    #[should_panic]
+    fn test_cstr_to_str_panic() {
+        let bad_bytes = b"\xc3\x28\0";
+        let checked_cstr = CStr::from_bytes_with_nul(bad_bytes).unwrap();
+        checked_cstr.to_str().unwrap();
+    }
+
+    #[test]
+    fn test_cstr_as_str_unchecked() {
+        let good_bytes = b"\xf0\x9f\x90\xA7\0";
+        let checked_cstr = CStr::from_bytes_with_nul(good_bytes).unwrap();
+        let unchecked_str = unsafe { checked_cstr.as_str_unchecked() };
+        assert_eq!(unchecked_str, "🐧");
+    }
+}
+
 /// Allows formatting of [`fmt::Arguments`] into a raw buffer.
 ///
 /// It does not fail if callers write past the end of the buffer so that they can calculate the
-- 
2.38.1


^ permalink raw reply related	[relevance 8%]

* [GIT PULL] Rust for 6.2
@ 2022-12-11  0:56  4% ojeda
  0 siblings, 0 replies; 77+ results
From: ojeda @ 2022-12-11  0:56 UTC (permalink / raw)
  To: Linus Torvalds
  Cc: Miguel Ojeda, Wedson Almeida Filho, Alex Gaynor, Boqun Feng,
	Gary Guo, Björn Roy Baron, rust-for-linux, linux-kernel

From: Miguel Ojeda <ojeda@kernel.org>

Hi Linus,

This is the first Rust PR after the merge.

It contains a set of new functionality to start the upstreaming of
the rest of the pieces we had. There are no changes to the C side.

The commits have been in linux-next for a week, though most of the
code has been there for months. No conflicts expected.

Please pull for v6.2 -- thanks!

Cheers,
Miguel

The following changes since commit f0c4d9fc9cc9462659728d168387191387e903cc:

  Linux 6.1-rc4 (2022-11-06 15:07:11 -0800)

are available in the Git repository at:

  https://github.com/Rust-for-Linux/linux tags/rust-6.2

for you to fetch changes up to b9ecf9b9ac5969d7b7ea786ce5c76e24246df2c5:

  rust: types: add `Opaque` type (2022-12-04 01:59:16 +0100)

----------------------------------------------------------------
Rust changes for v6.2

The first set of changes after the merge, the major ones being:

- String and formatting: new types `CString`, `CStr`, `BStr` and
  `Formatter`; new macros `c_str!`, `b_str!` and `fmt!`.

- Errors: the rest of the error codes from `errno-base.h`, as well as
  some `From` trait implementations for the `Error` type.

- Printing: the rest of the `pr_*!` levels and the continuation one
  `pr_cont!`, as well as a new sample.

- `alloc` crate: new constructors `try_with_capacity()` and
  `try_with_capacity_in()` for `RawVec` and `Vec`.

- Procedural macros: new macros `#[vtable]` and `concat_idents!`, as
  well as better ergonomics for `module!` users.

- Asserting: new macros `static_assert!`, `build_error!` and
  `build_assert!`, as well as a new crate `build_error` to support them.

- Vocabulary types: new types `Opaque` and `Either`.

- Debugging: new macro `dbg!`.

----------------------------------------------------------------
Björn Roy Baron (1):
      rust: macros: add `concat_idents!` proc macro

Finn Behrens (1):
      rust: error: declare errors using macro

Gary Guo (9):
      rust: macros: add `#[vtable]` proc macro
      rust: macros: take string literals in `module!`
      rust: str: add `BStr` type
      rust: str: add `b_str!` macro
      rust: str: add `CStr` type
      rust: str: implement several traits for `CStr`
      rust: str: add `c_str!` macro
      rust: add `build_error` crate
      rust: build_assert: add `build_{error,assert}!` macros

Miguel Ojeda (7):
      rust: prelude: split re-exports into groups
      rust: print: add more `pr_*!` levels
      rust: print: add `pr_cont!` macro
      rust: samples: add `rust_print` example
      rust: alloc: add `RawVec::try_with_capacity_in()` constructor
      rust: alloc: add `Vec::try_with_capacity{,_in}()` constructors
      rust: static_assert: add `static_assert!` macro

Milan Landaverde (1):
      rust: str: add `CStr` unit tests

Niklas Mohrin (1):
      rust: std_vendor: add `dbg!` macro based on `std`'s one

Viktor Garske (1):
      rust: error: add codes from `errno-base.h`

Wedson Almeida Filho (7):
      rust: error: add `From` implementations for `Error`
      rust: prelude: add `error::code::*` constant items
      rust: str: add `Formatter` type
      rust: str: add `CString` type
      rust: str: add `fmt!` macro
      rust: types: add `Either` type
      rust: types: add `Opaque` type

 lib/Kconfig.debug                 |  16 ++
 rust/Makefile                     |  22 +-
 rust/alloc/raw_vec.rs             |  33 ++-
 rust/alloc/vec/mod.rs             |  89 +++++++
 rust/build_error.rs               |  31 +++
 rust/exports.c                    |   5 +
 rust/kernel/build_assert.rs       |  82 ++++++
 rust/kernel/error.rs              |  90 ++++++-
 rust/kernel/lib.rs                |   9 +
 rust/kernel/prelude.rs            |  20 +-
 rust/kernel/print.rs              | 214 +++++++++++++++-
 rust/kernel/static_assert.rs      |  34 +++
 rust/kernel/std_vendor.rs         | 163 ++++++++++++
 rust/kernel/str.rs                | 523 +++++++++++++++++++++++++++++++++++++-
 rust/kernel/types.rs              |  37 +++
 rust/macros/concat_idents.rs      |  23 ++
 rust/macros/helpers.rs            |  24 +-
 rust/macros/lib.rs                | 108 +++++++-
 rust/macros/module.rs             |  10 +-
 rust/macros/vtable.rs             |  95 +++++++
 samples/rust/Kconfig              |  10 +
 samples/rust/Makefile             |   1 +
 samples/rust/rust_minimal.rs      |   8 +-
 samples/rust/rust_print.rs        |  54 ++++
 scripts/generate_rust_analyzer.py |   8 +-
 25 files changed, 1667 insertions(+), 42 deletions(-)
 create mode 100644 rust/build_error.rs
 create mode 100644 rust/kernel/build_assert.rs
 create mode 100644 rust/kernel/static_assert.rs
 create mode 100644 rust/kernel/std_vendor.rs
 create mode 100644 rust/kernel/types.rs
 create mode 100644 rust/macros/concat_idents.rs
 create mode 100644 rust/macros/vtable.rs
 create mode 100644 samples/rust/rust_print.rs

^ permalink raw reply	[relevance 4%]

* [PATCH bpf-next] bpf: prevent leak of lsm program after failed attach
@ 2022-12-13 17:57 13% Milan Landaverde
  2022-12-13 18:43  6% ` Stanislav Fomichev
  0 siblings, 1 reply; 77+ results
From: Milan Landaverde @ 2022-12-13 17:57 UTC (permalink / raw)
  To: bpf
  Cc: Alexei Starovoitov, Daniel Borkmann, John Fastabend,
	Andrii Nakryiko, Martin KaFai Lau, Song Liu, Yonghong Song,
	KP Singh, Stanislav Fomichev, Hao Luo, Jiri Olsa, linux-kernel,
	Milan Landaverde

In [0], we added the ability to bpf_prog_attach LSM programs to cgroups,
but in our validation to make sure the prog is meant to be attached to
BPF_LSM_CGROUP, we return too early if the check fails. This results in
lack of decrementing prog's refcnt (through bpf_prog_put)
leaving the LSM program alive past the point of the expected lifecycle.
This fix allows for the decrement to take place.

[0] https://lore.kernel.org/all/20220628174314.1216643-4-sdf@google.com/

Fixes: 69fd337a975c ("bpf: per-cgroup lsm flavor")
Signed-off-by: Milan Landaverde <milan@mdaverde.com>
---
 kernel/bpf/syscall.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c
index 35972afb6850..64131f88c553 100644
--- a/kernel/bpf/syscall.c
+++ b/kernel/bpf/syscall.c
@@ -3518,9 +3518,9 @@ static int bpf_prog_attach(const union bpf_attr *attr)
 	case BPF_PROG_TYPE_LSM:
 		if (ptype == BPF_PROG_TYPE_LSM &&
 		    prog->expected_attach_type != BPF_LSM_CGROUP)
-			return -EINVAL;
-
-		ret = cgroup_bpf_prog_attach(attr, ptype, prog);
+			ret = -EINVAL;
+		else
+			ret = cgroup_bpf_prog_attach(attr, ptype, prog);
 		break;
 	default:
 		ret = -EINVAL;
-- 
2.34.1


^ permalink raw reply related	[relevance 13%]

* Re: [PATCH bpf-next] bpf: prevent leak of lsm program after failed attach
  2022-12-13 17:57 13% [PATCH bpf-next] bpf: prevent leak of lsm program after failed attach Milan Landaverde
@ 2022-12-13 18:43  6% ` Stanislav Fomichev
  0 siblings, 0 replies; 77+ results
From: Stanislav Fomichev @ 2022-12-13 18:43 UTC (permalink / raw)
  To: Milan Landaverde
  Cc: bpf, Alexei Starovoitov, Daniel Borkmann, John Fastabend,
	Andrii Nakryiko, Martin KaFai Lau, Song Liu, Yonghong Song,
	KP Singh, Hao Luo, Jiri Olsa, linux-kernel

On Tue, Dec 13, 2022 at 9:58 AM Milan Landaverde <milan@mdaverde.com> wrote:
>
> In [0], we added the ability to bpf_prog_attach LSM programs to cgroups,
> but in our validation to make sure the prog is meant to be attached to
> BPF_LSM_CGROUP, we return too early if the check fails. This results in
> lack of decrementing prog's refcnt (through bpf_prog_put)
> leaving the LSM program alive past the point of the expected lifecycle.
> This fix allows for the decrement to take place.
>
> [0] https://lore.kernel.org/all/20220628174314.1216643-4-sdf@google.com/
>
> Fixes: 69fd337a975c ("bpf: per-cgroup lsm flavor")
> Signed-off-by: Milan Landaverde <milan@mdaverde.com>

Makes sense, thank you!

Reviewed-by: Stanislav Fomichev <sdf@google.com>

> ---
>  kernel/bpf/syscall.c | 6 +++---
>  1 file changed, 3 insertions(+), 3 deletions(-)
>
> diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c
> index 35972afb6850..64131f88c553 100644
> --- a/kernel/bpf/syscall.c
> +++ b/kernel/bpf/syscall.c
> @@ -3518,9 +3518,9 @@ static int bpf_prog_attach(const union bpf_attr *attr)
>         case BPF_PROG_TYPE_LSM:
>                 if (ptype == BPF_PROG_TYPE_LSM &&
>                     prog->expected_attach_type != BPF_LSM_CGROUP)
> -                       return -EINVAL;
> -
> -               ret = cgroup_bpf_prog_attach(attr, ptype, prog);
> +                       ret = -EINVAL;
> +               else
> +                       ret = cgroup_bpf_prog_attach(attr, ptype, prog);
>                 break;
>         default:
>                 ret = -EINVAL;
> --
> 2.34.1
>

^ permalink raw reply	[relevance 6%]

* pull-request: bpf 2022-12-16
@ 2022-12-16 17:45  7% Daniel Borkmann
  0 siblings, 0 replies; 77+ results
From: Daniel Borkmann @ 2022-12-16 17:45 UTC (permalink / raw)
  To: davem
  Cc: kuba, pabeni, edumazet, daniel, ast, andrii, martin.lau, netdev, bpf

Hi David, hi Jakub, hi Paolo, hi Eric,

The following pull-request contains BPF updates for your *net* tree.

We've added 7 non-merge commits during the last 2 day(s) which contain
a total of 9 files changed, 119 insertions(+), 36 deletions(-).

The main changes are:

1) Fix for recent syzkaller XDP dispatcher update splat, from Jiri Olsa.

2) Fix BPF program refcount leak in LSM attachment failure path, from Milan Landaverde.

3) Fix BPF program type in map compatibility check for fext, from Toke Høiland-Jørgensen.

4) Fix a BPF selftest compilation error under !CONFIG_SMP config, from Yonghong Song.

5) Fix CI to enable CONFIG_FUNCTION_ERROR_INJECTION after it got changed to a prompt, from Song Liu.

6) Various BPF documentation fixes for socket local storage, from Donald Hunter.

Please consider pulling these changes from:

  git://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf.git tags/for-netdev

Thanks a lot!

Also thanks to reporters, reviewers and testers of commits in this pull-request:

Andrii Nakryiko, Daniel Müller, David Vernet, Hao Sun, kernel test 
robot, Martin KaFai Lau, Paul E. McKenney, Stanislav Fomichev, Yonghong 
Song

----------------------------------------------------------------

The following changes since commit 7ae9888d6e1ce4062d27367a28e46a26270a3e52:

  Merge git://git.kernel.org/pub/scm/linux/kernel/git/netfilter/nf (2022-12-13 19:32:53 -0800)

are available in the Git repository at:

  https://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf.git tags/for-netdev

for you to fetch changes up to f506439ec3dee11e0e77b0a1f3fb3eec22c97873:

  selftests/bpf: Add a test for using a cpumap from an freplace-to-XDP program (2022-12-14 21:30:40 -0800)

----------------------------------------------------------------
bpf-for-netdev

----------------------------------------------------------------
Donald Hunter (1):
      docs/bpf: Reword docs for BPF_MAP_TYPE_SK_STORAGE

Jiri Olsa (1):
      bpf: Synchronize dispatcher update with bpf_dispatcher_xdp_func

Milan Landaverde (1):
      bpf: prevent leak of lsm program after failed attach

Song Liu (1):
      selftests/bpf: Select CONFIG_FUNCTION_ERROR_INJECTION

Toke Høiland-Jørgensen (2):
      bpf: Resolve fext program type when checking map compatibility
      selftests/bpf: Add a test for using a cpumap from an freplace-to-XDP program

Yonghong Song (1):
      selftests/bpf: Fix a selftest compilation error with CONFIG_SMP=n

 Documentation/bpf/map_sk_storage.rst               | 56 ++++++++++++----------
 kernel/bpf/core.c                                  |  5 +-
 kernel/bpf/dispatcher.c                            |  5 ++
 kernel/bpf/syscall.c                               |  6 +--
 tools/testing/selftests/bpf/config                 |  1 +
 .../selftests/bpf/prog_tests/fexit_bpf2bpf.c       | 48 +++++++++++++++++++
 .../testing/selftests/bpf/progs/freplace_progmap.c | 24 ++++++++++
 tools/testing/selftests/bpf/progs/rcu_read_lock.c  |  8 ++--
 .../selftests/bpf/progs/task_kfunc_failure.c       |  2 +-
 9 files changed, 119 insertions(+), 36 deletions(-)
 create mode 100644 tools/testing/selftests/bpf/progs/freplace_progmap.c

^ permalink raw reply	[relevance 7%]

* vmlinux.o: warning: objtool: _RINvNtCs3yuwAp0waWO_4core3ptr13drop_in_placeINtNtB4_6option6OptionNtCsdVu6umiBwhr_12rust_minimal11RustMinimalEEB14_+0x1b: relocation to !ENDBR: _RNvXsm_NtCsdvv6pRyacSq_5alloc3vecINtB5_3VeclENtNtCs3yuwAp0waWO_4core3fmt5Debug3f...
@ 2022-12-17  9:03  1% kernel test robot
  0 siblings, 0 replies; 77+ results
From: kernel test robot @ 2022-12-17  9:03 UTC (permalink / raw)
  Cc: oe-kbuild-all, llvm

[-- Attachment #1: Type: text/plain, Size: 83970 bytes --]

CC: linux-kernel@vger.kernel.org
TO: Miguel Ojeda <ojeda@kernel.org>
CC: Kees Cook <keescook@chromium.org>
CC: "Greg Kroah-Hartman" <gregkh@linuxfoundation.org>
CC: Alex Gaynor <alex.gaynor@gmail.com>
CC: Finn Behrens <me@kloenk.de>
CC: Wedson Almeida Filho <wedsonaf@google.com>
CC: Milan Landaverde <milan@mdaverde.com>

tree:   https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git master
head:   77856d911a8c8724ee8e2b09d55979fc1de8f1c0
commit: e4fc6580b0796bcba8ca12c2c4b0352d280c91e5 samples: add first Rust examples
date:   3 months ago
config: x86_64-rhel-8.3-rust
compiler: clang version 14.0.6 (https://github.com/llvm/llvm-project f28c006a5895fc0e329fe15fead81e37457cb1d1)
reproduce (this is a W=1 build):
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=e4fc6580b0796bcba8ca12c2c4b0352d280c91e5
        git remote add linus https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
        git fetch --no-tags linus master
        git checkout e4fc6580b0796bcba8ca12c2c4b0352d280c91e5
        # save the config file
        mkdir build_dir && cp config build_dir/.config
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross W=1 O=build_dir ARCH=x86_64 olddefconfig
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross W=1 O=build_dir ARCH=x86_64 SHELL=/bin/bash

If you fix the issue, kindly add following tag where applicable
| Reported-by: kernel test robot <lkp@intel.com>

All warnings (new ones prefixed by >>):

   vmlinux.o: warning: objtool: _RNvXs1Z_NtNtCs3yuwAp0waWO_4core3str4iterNtB6_11EscapeDebugNtNtBa_3fmt7Display3fmt+0x154: indirect jump found in RETPOLINE build
   vmlinux.o: warning: objtool: _RNvXs1Z_NtNtCs3yuwAp0waWO_4core3str4iterNtB6_11EscapeDebugNtNtBa_3fmt7Display3fmt+0x1ea: indirect jump found in RETPOLINE build
   vmlinux.o: warning: objtool: _RNvXs1Z_NtNtCs3yuwAp0waWO_4core3str4iterNtB6_11EscapeDebugNtNtBa_3fmt7Display3fmt+0x266: indirect jump found in RETPOLINE build
   vmlinux.o: warning: objtool: _RNvXs1Z_NtNtCs3yuwAp0waWO_4core3str4iterNtB6_11EscapeDebugNtNtBa_3fmt7Display3fmt+0x27e: indirect jump found in RETPOLINE build
   vmlinux.o: warning: objtool: _RNvXs1Z_NtNtCs3yuwAp0waWO_4core3str4iterNtB6_11EscapeDebugNtNtBa_3fmt7Display3fmt+0x40a: indirect jump found in RETPOLINE build
   vmlinux.o: warning: objtool: _RNvXs1Z_NtNtCs3yuwAp0waWO_4core3str4iterNtB6_11EscapeDebugNtNtBa_3fmt7Display3fmt+0x498: indirect jump found in RETPOLINE build
   vmlinux.o: warning: objtool: _RNvXs1Z_NtNtCs3yuwAp0waWO_4core3str4iterNtB6_11EscapeDebugNtNtBa_3fmt7Display3fmt+0x4b1: indirect jump found in RETPOLINE build
   vmlinux.o: warning: objtool: _RNvXs1Z_NtNtCs3yuwAp0waWO_4core3str4iterNtB6_11EscapeDebugNtNtBa_3fmt7Display3fmt+0x5aa: indirect jump found in RETPOLINE build
   vmlinux.o: warning: objtool: _RNvXs1Z_NtNtCs3yuwAp0waWO_4core3str4iterNtB6_11EscapeDebugNtNtBa_3fmt7Display3fmt+0x5cb: indirect jump found in RETPOLINE build
   vmlinux.o: warning: objtool: _RNvXs1Z_NtNtCs3yuwAp0waWO_4core3str4iterNtB6_11EscapeDebugNtNtBa_3fmt7Display3fmt+0x6a6: indirect jump found in RETPOLINE build
   vmlinux.o: warning: objtool: _RNvXs1Z_NtNtCs3yuwAp0waWO_4core3str4iterNtB6_11EscapeDebugNtNtBa_3fmt7Display3fmt+0x6c2: indirect jump found in RETPOLINE build
   vmlinux.o: warning: objtool: _RNvXs1Z_NtNtCs3yuwAp0waWO_4core3str4iterNtB6_11EscapeDebugNtNtBa_3fmt7Display3fmt+0x7a1: indirect jump found in RETPOLINE build
   vmlinux.o: warning: objtool: _RNvXs1Z_NtNtCs3yuwAp0waWO_4core3str4iterNtB6_11EscapeDebugNtNtBa_3fmt7Display3fmt+0x7c2: indirect jump found in RETPOLINE build
   vmlinux.o: warning: objtool: _RNvXs1Z_NtNtCs3yuwAp0waWO_4core3str4iterNtB6_11EscapeDebugNtNtBa_3fmt7Display3fmt+0x899: indirect jump found in RETPOLINE build
   vmlinux.o: warning: objtool: _RNvXs1Z_NtNtCs3yuwAp0waWO_4core3str4iterNtB6_11EscapeDebugNtNtBa_3fmt7Display3fmt+0x8b8: indirect jump found in RETPOLINE build
   vmlinux.o: warning: objtool: _RNvXs22_NtNtCs3yuwAp0waWO_4core3str4iterNtB6_13EscapeDefaultNtNtBa_3fmt7Display3fmt+0x33: indirect jump found in RETPOLINE build
   vmlinux.o: warning: objtool: _RNvXs22_NtNtCs3yuwAp0waWO_4core3str4iterNtB6_13EscapeDefaultNtNtBa_3fmt7Display3fmt+0x88: indirect jump found in RETPOLINE build
   vmlinux.o: warning: objtool: _RNvXs22_NtNtCs3yuwAp0waWO_4core3str4iterNtB6_13EscapeDefaultNtNtBa_3fmt7Display3fmt+0x1b3: indirect jump found in RETPOLINE build
   vmlinux.o: warning: objtool: _RNvXs22_NtNtCs3yuwAp0waWO_4core3str4iterNtB6_13EscapeDefaultNtNtBa_3fmt7Display3fmt+0x235: indirect jump found in RETPOLINE build
   vmlinux.o: warning: objtool: _RNvXs22_NtNtCs3yuwAp0waWO_4core3str4iterNtB6_13EscapeDefaultNtNtBa_3fmt7Display3fmt+0x24d: indirect jump found in RETPOLINE build
   vmlinux.o: warning: objtool: _RNvXs22_NtNtCs3yuwAp0waWO_4core3str4iterNtB6_13EscapeDefaultNtNtBa_3fmt7Display3fmt+0x339: indirect jump found in RETPOLINE build
   vmlinux.o: warning: objtool: _RNvXs22_NtNtCs3yuwAp0waWO_4core3str4iterNtB6_13EscapeDefaultNtNtBa_3fmt7Display3fmt+0x352: indirect jump found in RETPOLINE build
   vmlinux.o: warning: objtool: _RNvXs22_NtNtCs3yuwAp0waWO_4core3str4iterNtB6_13EscapeDefaultNtNtBa_3fmt7Display3fmt+0x428: indirect jump found in RETPOLINE build
   vmlinux.o: warning: objtool: _RNvXs22_NtNtCs3yuwAp0waWO_4core3str4iterNtB6_13EscapeDefaultNtNtBa_3fmt7Display3fmt+0x448: indirect jump found in RETPOLINE build
   vmlinux.o: warning: objtool: _RNvXs25_NtNtCs3yuwAp0waWO_4core3str4iterNtB6_13EscapeUnicodeNtNtBa_3fmt7Display3fmt+0x13e: indirect jump found in RETPOLINE build
   vmlinux.o: warning: objtool: _RNvXs25_NtNtCs3yuwAp0waWO_4core3str4iterNtB6_13EscapeUnicodeNtNtBa_3fmt7Display3fmt+0x21d: indirect jump found in RETPOLINE build
   vmlinux.o: warning: objtool: _RNvXs25_NtNtCs3yuwAp0waWO_4core3str4iterNtB6_13EscapeUnicodeNtNtBa_3fmt7Display3fmt+0x2ce: indirect jump found in RETPOLINE build
   vmlinux.o: warning: objtool: _RINvNtCs3yuwAp0waWO_4core3num14from_str_radixaEB4_+0x2b6: relocation to !ENDBR: _RNvXs3_NtNtNtCs3yuwAp0waWO_4core3fmt3num3impmNtB9_7Display3fmt+0x0
   vmlinux.o: warning: objtool: _RINvNtCs3yuwAp0waWO_4core3num14from_str_radixhEB4_+0x16a: relocation to !ENDBR: _RNvXs3_NtNtNtCs3yuwAp0waWO_4core3fmt3num3impmNtB9_7Display3fmt+0x0
   vmlinux.o: warning: objtool: _RINvNtCs3yuwAp0waWO_4core3num14from_str_radixiEB4_+0x268: relocation to !ENDBR: _RNvXs3_NtNtNtCs3yuwAp0waWO_4core3fmt3num3impmNtB9_7Display3fmt+0x0
   vmlinux.o: warning: objtool: _RINvNtCs3yuwAp0waWO_4core3num14from_str_radixjEB4_+0x16d: relocation to !ENDBR: _RNvXs3_NtNtNtCs3yuwAp0waWO_4core3fmt3num3impmNtB9_7Display3fmt+0x0
   vmlinux.o: warning: objtool: _RINvNtCs3yuwAp0waWO_4core3num14from_str_radixlEB4_+0x2c7: relocation to !ENDBR: _RNvXs3_NtNtNtCs3yuwAp0waWO_4core3fmt3num3impmNtB9_7Display3fmt+0x0
   vmlinux.o: warning: objtool: _RINvNtCs3yuwAp0waWO_4core3num14from_str_radixmEB4_+0x18f: relocation to !ENDBR: _RNvXs3_NtNtNtCs3yuwAp0waWO_4core3fmt3num3impmNtB9_7Display3fmt+0x0
   vmlinux.o: warning: objtool: _RINvNtCs3yuwAp0waWO_4core3num14from_str_radixnEB4_+0x3aa: relocation to !ENDBR: _RNvXs3_NtNtNtCs3yuwAp0waWO_4core3fmt3num3impmNtB9_7Display3fmt+0x0
   vmlinux.o: warning: objtool: _RINvNtCs3yuwAp0waWO_4core3num14from_str_radixoEB4_+0x1c1: relocation to !ENDBR: _RNvXs3_NtNtNtCs3yuwAp0waWO_4core3fmt3num3impmNtB9_7Display3fmt+0x0
   vmlinux.o: warning: objtool: _RINvNtCs3yuwAp0waWO_4core3num14from_str_radixsEB4_+0x2ce: relocation to !ENDBR: _RNvXs3_NtNtNtCs3yuwAp0waWO_4core3fmt3num3impmNtB9_7Display3fmt+0x0
   vmlinux.o: warning: objtool: _RINvNtCs3yuwAp0waWO_4core3num14from_str_radixtEB4_+0x190: relocation to !ENDBR: _RNvXs3_NtNtNtCs3yuwAp0waWO_4core3fmt3num3impmNtB9_7Display3fmt+0x0
   vmlinux.o: warning: objtool: _RNvXs_NtNtCs3yuwAp0waWO_4core3mem11valid_alignNtB4_10ValidAlignNtNtB8_3fmt5Debug3fmt+0x1e: relocation to !ENDBR: _RNvXs2G_NtNtCs3yuwAp0waWO_4core3num7nonzeroNtB6_12NonZeroUsizeNtNtBa_3fmt5Debug3fmt+0x0
   vmlinux.o: warning: objtool: _RNvXs_NtNtCs3yuwAp0waWO_4core3mem11valid_alignNtB4_10ValidAlignNtNtB8_3fmt5Debug3fmt+0x31: relocation to !ENDBR: _RNvXs1m_NtNtCs3yuwAp0waWO_4core3fmt3nummNtB8_5Debug3fmt+0x0
   vmlinux.o: warning: objtool: _RNvXs0_NtNtCs3yuwAp0waWO_4core4char6decodeNtB5_16DecodeUtf16ErrorNtNtB9_3fmt7Display3fmt+0x9: relocation to !ENDBR: _RNvXsK_NtNtCs3yuwAp0waWO_4core3fmt3numsNtB7_8LowerHex3fmt+0x0
   vmlinux.o: warning: objtool: _RNvXs2_NtNtCs3yuwAp0waWO_4core3ffi5c_strNtB5_21FromBytesWithNulErrorNtNtB9_3fmt7Display3fmt+0x63: relocation to !ENDBR: _RNvXs5_NtNtNtCs3yuwAp0waWO_4core3fmt3num3impyNtB9_7Display3fmt+0x0
   vmlinux.o: warning: objtool: _RNvXs8_NtNtCs3yuwAp0waWO_4core3ffi5c_strNtB5_4CStrINtNtNtB9_3ops5index5IndexINtNtBR_5range9RangeFromjEE5index+0x2e: relocation to !ENDBR: _RNvXs5_NtNtNtCs3yuwAp0waWO_4core3fmt3num3impyNtB9_7Display3fmt+0x0
   vmlinux.o: warning: objtool: _RNvXs8_NtNtCs3yuwAp0waWO_4core3ffi5c_strNtB5_4CStrINtNtNtB9_3ops5index5IndexINtNtBR_5range9RangeFromjEE5index+0x41: relocation to !ENDBR: _RNvXs5_NtNtNtCs3yuwAp0waWO_4core3fmt3num3impyNtB9_7Display3fmt+0x0
   vmlinux.o: warning: objtool: _RNvXs0_NtNtCs3yuwAp0waWO_4core5panic8locationNtB5_8LocationNtNtB9_3fmt7Display3fmt+0x11: relocation to !ENDBR: _RNvXsR_NtCs3yuwAp0waWO_4core3fmtReNtB5_7Display3fmtB7_+0x0
   vmlinux.o: warning: objtool: _RNvXs0_NtNtCs3yuwAp0waWO_4core5panic8locationNtB5_8LocationNtNtB9_3fmt7Display3fmt+0x1f: relocation to !ENDBR: _RNvXs3_NtNtNtCs3yuwAp0waWO_4core3fmt3num3impmNtB9_7Display3fmt+0x0
   vmlinux.o: warning: objtool: _RNvXs0_NtNtCs3yuwAp0waWO_4core5panic8locationNtB5_8LocationNtNtB9_3fmt7Display3fmt+0x2d: relocation to !ENDBR: _RNvXs3_NtNtNtCs3yuwAp0waWO_4core3fmt3num3impmNtB9_7Display3fmt+0x0
   vmlinux.o: warning: objtool: _RNvXs_NtNtCs3yuwAp0waWO_4core5panic10panic_infoNtB4_9PanicInfoNtNtB8_3fmt7Display3fmt+0x52: relocation to !ENDBR: _RNvXsR_NtCs3yuwAp0waWO_4core3fmtRNtB5_9ArgumentsNtB5_7Display3fmtB7_+0x0
   vmlinux.o: warning: objtool: _RNvXs_NtNtCs3yuwAp0waWO_4core5panic10panic_infoNtB4_9PanicInfoNtNtB8_3fmt7Display3fmt+0x8e: relocation to !ENDBR: _RNvXsR_NtCs3yuwAp0waWO_4core3fmtRReNtB5_7Display3fmtB7_+0x0
   vmlinux.o: warning: objtool: _RNvXs_NtNtCs3yuwAp0waWO_4core5panic10panic_infoNtB4_9PanicInfoNtNtB8_3fmt7Display3fmt+0xea: relocation to !ENDBR: _RNvXsR_NtCs3yuwAp0waWO_4core3fmtReNtB5_7Display3fmtB7_+0x0
   vmlinux.o: warning: objtool: _RNvXs_NtNtCs3yuwAp0waWO_4core5panic10panic_infoNtB4_9PanicInfoNtNtB8_3fmt7Display3fmt+0xf8: relocation to !ENDBR: _RNvXs3_NtNtNtCs3yuwAp0waWO_4core3fmt3num3impmNtB9_7Display3fmt+0x0
   vmlinux.o: warning: objtool: _RNvXs_NtNtCs3yuwAp0waWO_4core5panic10panic_infoNtB4_9PanicInfoNtNtB8_3fmt7Display3fmt+0x106: relocation to !ENDBR: _RNvXs3_NtNtNtCs3yuwAp0waWO_4core3fmt3num3impmNtB9_7Display3fmt+0x0
   vmlinux.o: warning: objtool: _RINvNtCs3yuwAp0waWO_4core9panicking13panic_displayReEB4_+0x9: relocation to !ENDBR: _RNvXsR_NtCs3yuwAp0waWO_4core3fmtReNtB5_7Display3fmtB7_+0x0
   vmlinux.o: warning: objtool: _RNvNtCs3yuwAp0waWO_4core9panicking19assert_failed_inner+0x71: relocation to !ENDBR: _RNvXsR_NtCs3yuwAp0waWO_4core3fmtReNtB5_7Display3fmtB7_+0x0
   vmlinux.o: warning: objtool: _RNvNtCs3yuwAp0waWO_4core9panicking19assert_failed_inner+0x84: relocation to !ENDBR: _RNvXsP_NtCs3yuwAp0waWO_4core3fmtRDNtB5_5DebugEL_Bw_3fmtB7_+0x0
   vmlinux.o: warning: objtool: _RNvNtCs3yuwAp0waWO_4core9panicking19assert_failed_inner+0x97: relocation to !ENDBR: _RNvXsP_NtCs3yuwAp0waWO_4core3fmtRDNtB5_5DebugEL_Bw_3fmtB7_+0x0
   vmlinux.o: warning: objtool: _RNvNtCs3yuwAp0waWO_4core9panicking19assert_failed_inner+0x130: relocation to !ENDBR: _RNvXsR_NtCs3yuwAp0waWO_4core3fmtReNtB5_7Display3fmtB7_+0x0
   vmlinux.o: warning: objtool: _RNvNtCs3yuwAp0waWO_4core9panicking19assert_failed_inner+0x143: relocation to !ENDBR: _RNvXsP_NtCs3yuwAp0waWO_4core3fmtRDNtB5_5DebugEL_Bw_3fmtB7_+0x0
   vmlinux.o: warning: objtool: _RNvNtCs3yuwAp0waWO_4core9panicking19assert_failed_inner+0x156: relocation to !ENDBR: _RNvXsP_NtCs3yuwAp0waWO_4core3fmtRDNtB5_5DebugEL_Bw_3fmtB7_+0x0
   vmlinux.o: warning: objtool: _RNvNtCs3yuwAp0waWO_4core9panicking19assert_failed_inner+0x16c: relocation to !ENDBR: _RNvXs5_NtCs3yuwAp0waWO_4core3fmtNtB5_9ArgumentsNtB5_7Display3fmt+0x0
   vmlinux.o: warning: objtool: _RNvMs1_NtCs3yuwAp0waWO_4core3fmtNtB5_10ArgumentV110from_usize+0x3: relocation to !ENDBR: _RNvYNCNvNtCs3yuwAp0waWO_4core3fmt12USIZE_MARKER0INtNtNtB8_3ops8function6FnOnceTRjQNtB6_9FormatterEE9call_onceB8_+0x0
   vmlinux.o: warning: objtool: _RNvNtCs3yuwAp0waWO_4core3fmt5write+0xd7: relocation to !ENDBR: _RNvYNCNvNtCs3yuwAp0waWO_4core3fmt12USIZE_MARKER0INtNtNtB8_3ops8function6FnOnceTRjQNtB6_9FormatterEE9call_onceB8_+0x0
   vmlinux.o: warning: objtool: _RNvNtCs3yuwAp0waWO_4core3fmt5write+0x121: relocation to !ENDBR: _RNvYNCNvNtCs3yuwAp0waWO_4core3fmt12USIZE_MARKER0INtNtNtB8_3ops8function6FnOnceTRjQNtB6_9FormatterEE9call_onceB8_+0x0
   vmlinux.o: warning: objtool: _RNvNtNtCs3yuwAp0waWO_4core5slice5index29slice_start_index_len_fail_rt+0x18: relocation to !ENDBR: _RNvXs5_NtNtNtCs3yuwAp0waWO_4core3fmt3num3impyNtB9_7Display3fmt+0x0
   vmlinux.o: warning: objtool: _RNvNtNtCs3yuwAp0waWO_4core5slice5index29slice_start_index_len_fail_rt+0x2b: relocation to !ENDBR: _RNvXs5_NtNtNtCs3yuwAp0waWO_4core3fmt3num3impyNtB9_7Display3fmt+0x0
   vmlinux.o: warning: objtool: _RNvNtNtCs3yuwAp0waWO_4core5slice5index27slice_end_index_len_fail_rt+0x18: relocation to !ENDBR: _RNvXs5_NtNtNtCs3yuwAp0waWO_4core3fmt3num3impyNtB9_7Display3fmt+0x0
   vmlinux.o: warning: objtool: _RNvNtNtCs3yuwAp0waWO_4core5slice5index27slice_end_index_len_fail_rt+0x2b: relocation to !ENDBR: _RNvXs5_NtNtNtCs3yuwAp0waWO_4core3fmt3num3impyNtB9_7Display3fmt+0x0
   vmlinux.o: warning: objtool: _RNvNtNtCs3yuwAp0waWO_4core5slice5index25slice_index_order_fail_rt+0x18: relocation to !ENDBR: _RNvXs5_NtNtNtCs3yuwAp0waWO_4core3fmt3num3impyNtB9_7Display3fmt+0x0
   vmlinux.o: warning: objtool: _RNvNtNtCs3yuwAp0waWO_4core5slice5index25slice_index_order_fail_rt+0x2b: relocation to !ENDBR: _RNvXs5_NtNtNtCs3yuwAp0waWO_4core3fmt3num3impyNtB9_7Display3fmt+0x0
   vmlinux.o: warning: objtool: _RNvXs_NtNtCs3yuwAp0waWO_4core3str5errorNtB4_9Utf8ErrorNtNtB8_3fmt7Display3fmt+0x1b: relocation to !ENDBR: _RNvXs_NtNtNtCs3yuwAp0waWO_4core3fmt3num3imphNtB8_7Display3fmt+0x0
   vmlinux.o: warning: objtool: _RNvXs_NtNtCs3yuwAp0waWO_4core3str5errorNtB4_9Utf8ErrorNtNtB8_3fmt7Display3fmt+0x29: relocation to !ENDBR: _RNvXs5_NtNtNtCs3yuwAp0waWO_4core3fmt3num3impyNtB9_7Display3fmt+0x0
   vmlinux.o: warning: objtool: _RNvXs_NtNtCs3yuwAp0waWO_4core3str5errorNtB4_9Utf8ErrorNtNtB8_3fmt7Display3fmt+0x6f: relocation to !ENDBR: _RNvXs5_NtNtNtCs3yuwAp0waWO_4core3fmt3num3impyNtB9_7Display3fmt+0x0
   vmlinux.o: warning: objtool: _RNvXs1_NtNtCs3yuwAp0waWO_4core3str5lossyNtB5_9Utf8LossyNtNtB9_3fmt5Debug3fmt+0x42a: relocation to !ENDBR: _RNvXsC_NtNtCs3yuwAp0waWO_4core3fmt3numaNtB7_8LowerHex3fmt+0x0
   vmlinux.o: warning: objtool: _RNvNtCs3yuwAp0waWO_4core3str19slice_error_fail_rt+0xd4: relocation to !ENDBR: _RNvXs5_NtNtNtCs3yuwAp0waWO_4core3fmt3num3impyNtB9_7Display3fmt+0x0
   vmlinux.o: warning: objtool: _RNvNtCs3yuwAp0waWO_4core3str19slice_error_fail_rt+0xea: relocation to !ENDBR: _RNvXs5_NtNtNtCs3yuwAp0waWO_4core3fmt3num3impyNtB9_7Display3fmt+0x0
   vmlinux.o: warning: objtool: _RNvNtCs3yuwAp0waWO_4core3str19slice_error_fail_rt+0xfd: relocation to !ENDBR: _RNvXsR_NtCs3yuwAp0waWO_4core3fmtReNtB5_7Display3fmtB7_+0x0
   vmlinux.o: warning: objtool: _RNvNtCs3yuwAp0waWO_4core3str19slice_error_fail_rt+0x116: relocation to !ENDBR: _RNvXsR_NtCs3yuwAp0waWO_4core3fmtReNtB5_7Display3fmtB7_+0x0
   vmlinux.o: warning: objtool: _RNvNtCs3yuwAp0waWO_4core3str19slice_error_fail_rt+0x17f: relocation to !ENDBR: _RNvXs5_NtNtNtCs3yuwAp0waWO_4core3fmt3num3impyNtB9_7Display3fmt+0x0
   vmlinux.o: warning: objtool: _RNvNtCs3yuwAp0waWO_4core3str19slice_error_fail_rt+0x192: relocation to !ENDBR: _RNvXsR_NtCs3yuwAp0waWO_4core3fmtReNtB5_7Display3fmtB7_+0x0
   vmlinux.o: warning: objtool: _RNvNtCs3yuwAp0waWO_4core3str19slice_error_fail_rt+0x1a8: relocation to !ENDBR: _RNvXsR_NtCs3yuwAp0waWO_4core3fmtReNtB5_7Display3fmtB7_+0x0
   vmlinux.o: warning: objtool: _RNvNtCs3yuwAp0waWO_4core3str19slice_error_fail_rt+0x3bf: relocation to !ENDBR: _RNvXs5_NtNtNtCs3yuwAp0waWO_4core3fmt3num3impyNtB9_7Display3fmt+0x0
   vmlinux.o: warning: objtool: _RNvNtCs3yuwAp0waWO_4core3str19slice_error_fail_rt+0x3d2: relocation to !ENDBR: _RNvXsg_NtCs3yuwAp0waWO_4core3fmtcNtB5_5Debug3fmt+0x0
   vmlinux.o: warning: objtool: _RNvNtCs3yuwAp0waWO_4core3str19slice_error_fail_rt+0x3e8: relocation to !ENDBR: _RNvXs_NtNtCs3yuwAp0waWO_4core3ops5rangeINtB4_5RangejENtNtB8_3fmt5Debug3fmtB8_+0x0
   vmlinux.o: warning: objtool: _RNvNtCs3yuwAp0waWO_4core3str19slice_error_fail_rt+0x3fe: relocation to !ENDBR: _RNvXsR_NtCs3yuwAp0waWO_4core3fmtReNtB5_7Display3fmtB7_+0x0
   vmlinux.o: warning: objtool: _RNvNtCs3yuwAp0waWO_4core3str19slice_error_fail_rt+0x41a: relocation to !ENDBR: _RNvXsR_NtCs3yuwAp0waWO_4core3fmtReNtB5_7Display3fmtB7_+0x0
   vmlinux.o: warning: objtool: _RNCNvNvXsa_NtCs3yuwAp0waWO_4core4timeNtB9_8DurationNtNtBb_3fmt5Debug3fmt11fmt_decimals_0Bb_+0x1f: relocation to !ENDBR: _RNvXsR_NtCs3yuwAp0waWO_4core3fmtReNtB5_7Display3fmtB7_+0x0
   vmlinux.o: warning: objtool: _RNCNvNvXsa_NtCs3yuwAp0waWO_4core4timeNtB9_8DurationNtNtBb_3fmt5Debug3fmt11fmt_decimals_0Bb_+0x2d: relocation to !ENDBR: _RNvXs5_NtNtNtCs3yuwAp0waWO_4core3fmt3num3impyNtB9_7Display3fmt+0x0
   vmlinux.o: warning: objtool: _RNCNvNvXsa_NtCs3yuwAp0waWO_4core4timeNtB9_8DurationNtNtBb_3fmt5Debug3fmt11fmt_decimals_0Bb_+0xd5: relocation to !ENDBR: _RNvXsR_NtCs3yuwAp0waWO_4core3fmtReNtB5_7Display3fmtB7_+0x0
   vmlinux.o: warning: objtool: _RNCNvNvXsa_NtCs3yuwAp0waWO_4core4timeNtB9_8DurationNtNtBb_3fmt5Debug3fmt11fmt_decimals_0Bb_+0xe8: relocation to !ENDBR: _RNvYNCNvNtCs3yuwAp0waWO_4core3fmt12USIZE_MARKER0INtNtNtB8_3ops8function6FnOnceTRjQNtB6_9FormatterEE9call_onceB8_+0x0
   vmlinux.o: warning: objtool: _RNCNvNvXsa_NtCs3yuwAp0waWO_4core4timeNtB9_8DurationNtNtBb_3fmt5Debug3fmt11fmt_decimals_0Bb_+0x145: relocation to !ENDBR: _RNvXsR_NtCs3yuwAp0waWO_4core3fmtReNtB5_7Display3fmtB7_+0x0
   vmlinux.o: warning: objtool: _RNvXso_NtNtCs3yuwAp0waWO_4core3fmt3numNtB5_6BinaryNtB5_12GenericRadix5digit+0x1f: relocation to !ENDBR: _RNvXs_NtNtNtCs3yuwAp0waWO_4core3fmt3num3imphNtB8_7Display3fmt+0x0
   vmlinux.o: warning: objtool: _RNvXso_NtNtCs3yuwAp0waWO_4core3fmt3numNtB5_6BinaryNtB5_12GenericRadix5digit+0x32: relocation to !ENDBR: _RNvXs_NtNtNtCs3yuwAp0waWO_4core3fmt3num3imphNtB8_7Display3fmt+0x0
   vmlinux.o: warning: objtool: _RNvXsp_NtNtCs3yuwAp0waWO_4core3fmt3numNtB5_5OctalNtB5_12GenericRadix5digit+0x1f: relocation to !ENDBR: _RNvXs_NtNtNtCs3yuwAp0waWO_4core3fmt3num3imphNtB8_7Display3fmt+0x0
   vmlinux.o: warning: objtool: _RNvXsp_NtNtCs3yuwAp0waWO_4core3fmt3numNtB5_5OctalNtB5_12GenericRadix5digit+0x32: relocation to !ENDBR: _RNvXs_NtNtNtCs3yuwAp0waWO_4core3fmt3num3imphNtB8_7Display3fmt+0x0
   vmlinux.o: warning: objtool: _RNvXsq_NtNtCs3yuwAp0waWO_4core3fmt3numNtB5_8LowerHexNtB5_12GenericRadix5digit+0x26: relocation to !ENDBR: _RNvXs_NtNtNtCs3yuwAp0waWO_4core3fmt3num3imphNtB8_7Display3fmt+0x0
   vmlinux.o: warning: objtool: _RNvXsq_NtNtCs3yuwAp0waWO_4core3fmt3numNtB5_8LowerHexNtB5_12GenericRadix5digit+0x39: relocation to !ENDBR: _RNvXs_NtNtNtCs3yuwAp0waWO_4core3fmt3num3imphNtB8_7Display3fmt+0x0
   vmlinux.o: warning: objtool: _RNvXsr_NtNtCs3yuwAp0waWO_4core3fmt3numNtB5_8UpperHexNtB5_12GenericRadix5digit+0x26: relocation to !ENDBR: _RNvXs_NtNtNtCs3yuwAp0waWO_4core3fmt3num3imphNtB8_7Display3fmt+0x0
   vmlinux.o: warning: objtool: _RNvXsr_NtNtCs3yuwAp0waWO_4core3fmt3numNtB5_8UpperHexNtB5_12GenericRadix5digit+0x39: relocation to !ENDBR: _RNvXs_NtNtNtCs3yuwAp0waWO_4core3fmt3num3imphNtB8_7Display3fmt+0x0
   vmlinux.o: warning: objtool: _RNvXsP_NtCs3yuwAp0waWO_4core3fmtRNtNtNtB7_3mem11valid_align10ValidAlignNtB5_5Debug3fmtB7_+0x21: relocation to !ENDBR: _RNvXs2G_NtNtCs3yuwAp0waWO_4core3num7nonzeroNtB6_12NonZeroUsizeNtNtBa_3fmt5Debug3fmt+0x0
   vmlinux.o: warning: objtool: _RNvXsP_NtCs3yuwAp0waWO_4core3fmtRNtNtNtB7_3mem11valid_align10ValidAlignNtB5_5Debug3fmtB7_+0x34: relocation to !ENDBR: _RNvXs1m_NtNtCs3yuwAp0waWO_4core3fmt3nummNtB8_5Debug3fmt+0x0
   vmlinux.o: warning: objtool: rust_begin_unwind+0x10: relocation to !ENDBR: _RNvXsR_NtCs3yuwAp0waWO_4core3fmtRNtNtNtB7_5panic10panic_info9PanicInfoNtB5_7Display3fmtCsfATHBUcknU9_6kernel+0x0
>> vmlinux.o: warning: objtool: _RINvNtCs3yuwAp0waWO_4core3ptr13drop_in_placeINtNtB4_6option6OptionNtCsdVu6umiBwhr_12rust_minimal11RustMinimalEEB14_+0x1b: relocation to !ENDBR: _RNvXsm_NtCsdvv6pRyacSq_5alloc3vecINtB5_3VeclENtNtCs3yuwAp0waWO_4core3fmt5Debug3fmtCsdVu6umiBwhr_12rust_minimal+0x0
>> vmlinux.o: warning: objtool: _RNvXCsdVu6umiBwhr_12rust_minimalNtB2_11RustMinimalNtCsfATHBUcknU9_6kernel6Module4init+0x67: relocation to !ENDBR: _RNvXsd_NtCs3yuwAp0waWO_4core3fmtbNtB5_7Display3fmt+0x0
>> vmlinux.o: warning: objtool: _RNvXs_CsdVu6umiBwhr_12rust_minimalNtB4_11RustMinimalNtNtNtCs3yuwAp0waWO_4core3ops4drop4Drop4drop+0x9: relocation to !ENDBR: _RNvXsm_NtCsdvv6pRyacSq_5alloc3vecINtB5_3VeclENtNtCs3yuwAp0waWO_4core3fmt5Debug3fmtCsdVu6umiBwhr_12rust_minimal+0x0
   vmlinux.o: warning: objtool: _RNvNtCs3yuwAp0waWO_4core9panicking18panic_bounds_check+0x18: relocation to !ENDBR: _RNvXs5_NtNtNtCs3yuwAp0waWO_4core3fmt3num3impyNtB9_7Display3fmt+0x0
   vmlinux.o: warning: objtool: _RNvNtCs3yuwAp0waWO_4core9panicking18panic_bounds_check+0x2b: relocation to !ENDBR: _RNvXs5_NtNtNtCs3yuwAp0waWO_4core3fmt3num3impyNtB9_7Display3fmt+0x0
   vmlinux.o: warning: objtool: _RNvNtCs3yuwAp0waWO_4core6result13unwrap_failed+0x22: relocation to !ENDBR: _RNvXsR_NtCs3yuwAp0waWO_4core3fmtReNtB5_7Display3fmtB7_+0x0
   vmlinux.o: warning: objtool: _RNvNtCs3yuwAp0waWO_4core6result13unwrap_failed+0x35: relocation to !ENDBR: _RNvXsP_NtCs3yuwAp0waWO_4core3fmtRDNtB5_5DebugEL_Bw_3fmtB7_+0x0
   vmlinux.o: warning: objtool: _RNvNvMNtCs3yuwAp0waWO_4core5sliceSp15copy_from_slice17len_mismatch_fail+0x18: relocation to !ENDBR: _RNvXs5_NtNtNtCs3yuwAp0waWO_4core3fmt3num3impyNtB9_7Display3fmt+0x0
   vmlinux.o: warning: objtool: _RNvNvMNtCs3yuwAp0waWO_4core5sliceSp15copy_from_slice17len_mismatch_fail+0x2b: relocation to !ENDBR: _RNvXs5_NtNtNtCs3yuwAp0waWO_4core3fmt3num3impyNtB9_7Display3fmt+0x0
   vmlinux.o: warning: objtool: _RNvNvMs_NtCsdvv6pRyacSq_5alloc3vecINtB6_3VecppE11swap_remove13assert_failed+0x18: relocation to !ENDBR: _RNvXs5_NtNtNtCs3yuwAp0waWO_4core3fmt3num3impyNtB9_7Display3fmt+0x0
   vmlinux.o: warning: objtool: _RNvNvMs_NtCsdvv6pRyacSq_5alloc3vecINtB6_3VecppE11swap_remove13assert_failed+0x2b: relocation to !ENDBR: _RNvXs5_NtNtNtCs3yuwAp0waWO_4core3fmt3num3impyNtB9_7Display3fmt+0x0
   vmlinux.o: warning: objtool: _RNvNvMs_NtCsdvv6pRyacSq_5alloc3vecINtB6_3VecppE6remove13assert_failed+0x18: relocation to !ENDBR: _RNvXs5_NtNtNtCs3yuwAp0waWO_4core3fmt3num3impyNtB9_7Display3fmt+0x0
   vmlinux.o: warning: objtool: _RNvNvMs_NtCsdvv6pRyacSq_5alloc3vecINtB6_3VecppE6remove13assert_failed+0x2b: relocation to !ENDBR: _RNvXs5_NtNtNtCs3yuwAp0waWO_4core3fmt3num3impyNtB9_7Display3fmt+0x0
   vmlinux.o: warning: objtool: .rodata+0x69a00: data relocation to !ENDBR: _RNvNtCs3yuwAp0waWO_4core5ascii14escape_default+0x7c
   vmlinux.o: warning: objtool: .rodata+0x69a08: data relocation to !ENDBR: _RNvNtCs3yuwAp0waWO_4core5ascii14escape_default+0x19
   vmlinux.o: warning: objtool: .rodata+0x69a10: data relocation to !ENDBR: _RNvNtCs3yuwAp0waWO_4core5ascii14escape_default+0x2d
   vmlinux.o: warning: objtool: .rodata+0x69a18: data relocation to !ENDBR: _RNvNtCs3yuwAp0waWO_4core5ascii14escape_default+0x2d
   vmlinux.o: warning: objtool: .rodata+0x69a20: data relocation to !ENDBR: _RNvNtCs3yuwAp0waWO_4core5ascii14escape_default+0x3c
   vmlinux.o: warning: objtool: .rodata+0x69a28: data relocation to !ENDBR: _RNvNtCs3yuwAp0waWO_4core5ascii14escape_default+0x2d
   vmlinux.o: warning: objtool: .rodata+0x69a30: data relocation to !ENDBR: _RNvNtCs3yuwAp0waWO_4core5ascii14escape_default+0x2d
   vmlinux.o: warning: objtool: .rodata+0x69a38: data relocation to !ENDBR: _RNvNtCs3yuwAp0waWO_4core5ascii14escape_default+0x2d
   vmlinux.o: warning: objtool: .rodata+0x69a40: data relocation to !ENDBR: _RNvNtCs3yuwAp0waWO_4core5ascii14escape_default+0x2d
   vmlinux.o: warning: objtool: .rodata+0x69a48: data relocation to !ENDBR: _RNvNtCs3yuwAp0waWO_4core5ascii14escape_default+0x2d
   vmlinux.o: warning: objtool: .rodata+0x69a50: data relocation to !ENDBR: _RNvNtCs3yuwAp0waWO_4core5ascii14escape_default+0x2d
   vmlinux.o: warning: objtool: .rodata+0x69a58: data relocation to !ENDBR: _RNvNtCs3yuwAp0waWO_4core5ascii14escape_default+0x2d
   vmlinux.o: warning: objtool: .rodata+0x69a60: data relocation to !ENDBR: _RNvNtCs3yuwAp0waWO_4core5ascii14escape_default+0x2d
   vmlinux.o: warning: objtool: .rodata+0x69a68: data relocation to !ENDBR: _RNvNtCs3yuwAp0waWO_4core5ascii14escape_default+0x2d
   vmlinux.o: warning: objtool: .rodata+0x69a70: data relocation to !ENDBR: _RNvNtCs3yuwAp0waWO_4core5ascii14escape_default+0x2d
   vmlinux.o: warning: objtool: .rodata+0x69a78: data relocation to !ENDBR: _RNvNtCs3yuwAp0waWO_4core5ascii14escape_default+0x2d
   vmlinux.o: warning: objtool: .rodata+0x69a80: data relocation to !ENDBR: _RNvNtCs3yuwAp0waWO_4core5ascii14escape_default+0x2d
   vmlinux.o: warning: objtool: .rodata+0x69a88: data relocation to !ENDBR: _RNvNtCs3yuwAp0waWO_4core5ascii14escape_default+0x2d
   vmlinux.o: warning: objtool: .rodata+0x69a90: data relocation to !ENDBR: _RNvNtCs3yuwAp0waWO_4core5ascii14escape_default+0x2d
   vmlinux.o: warning: objtool: .rodata+0x69a98: data relocation to !ENDBR: _RNvNtCs3yuwAp0waWO_4core5ascii14escape_default+0x2d
   vmlinux.o: warning: objtool: .rodata+0x69aa0: data relocation to !ENDBR: _RNvNtCs3yuwAp0waWO_4core5ascii14escape_default+0x2d
   vmlinux.o: warning: objtool: .rodata+0x69aa8: data relocation to !ENDBR: _RNvNtCs3yuwAp0waWO_4core5ascii14escape_default+0x2d
   vmlinux.o: warning: objtool: .rodata+0x69ab0: data relocation to !ENDBR: _RNvNtCs3yuwAp0waWO_4core5ascii14escape_default+0x2d
   vmlinux.o: warning: objtool: .rodata+0x69ab8: data relocation to !ENDBR: _RNvNtCs3yuwAp0waWO_4core5ascii14escape_default+0x2d
   vmlinux.o: warning: objtool: .rodata+0x69ac0: data relocation to !ENDBR: _RNvNtCs3yuwAp0waWO_4core5ascii14escape_default+0x2d
   vmlinux.o: warning: objtool: .rodata+0x69ac8: data relocation to !ENDBR: _RNvNtCs3yuwAp0waWO_4core5ascii14escape_default+0x43
   vmlinux.o: warning: objtool: .rodata+0x69ad0: data relocation to !ENDBR: _RNvNtCs3yuwAp0waWO_4core5ascii14escape_default+0x2d
   vmlinux.o: warning: objtool: .rodata+0x69ad8: data relocation to !ENDBR: _RNvNtCs3yuwAp0waWO_4core5ascii14escape_default+0x2d
   vmlinux.o: warning: objtool: .rodata+0x69ae0: data relocation to !ENDBR: _RNvNtCs3yuwAp0waWO_4core5ascii14escape_default+0x2d
   vmlinux.o: warning: objtool: .rodata+0x69ae8: data relocation to !ENDBR: _RNvNtCs3yuwAp0waWO_4core5ascii14escape_default+0x2d
   vmlinux.o: warning: objtool: .rodata+0x69af0: data relocation to !ENDBR: _RNvNtCs3yuwAp0waWO_4core5ascii14escape_default+0x4a
   vmlinux.o: warning: objtool: .rodata+0x69af8: data relocation to !ENDBR: _RNvXNtCs3yuwAp0waWO_4core4charNtB2_13EscapeUnicodeNtNtNtNtB4_4iter6traits8iterator8Iterator4next+0x80
   vmlinux.o: warning: objtool: .rodata+0x69b00: data relocation to !ENDBR: _RNvXNtCs3yuwAp0waWO_4core4charNtB2_13EscapeUnicodeNtNtNtNtB4_4iter6traits8iterator8Iterator4next+0x11
   vmlinux.o: warning: objtool: .rodata+0x69b08: data relocation to !ENDBR: _RNvXNtCs3yuwAp0waWO_4core4charNtB2_13EscapeUnicodeNtNtNtNtB4_4iter6traits8iterator8Iterator4next+0x1c
   vmlinux.o: warning: objtool: .rodata+0x69b10: data relocation to !ENDBR: _RNvXNtCs3yuwAp0waWO_4core4charNtB2_13EscapeUnicodeNtNtNtNtB4_4iter6traits8iterator8Iterator4next+0x61
   vmlinux.o: warning: objtool: .rodata+0x69b18: data relocation to !ENDBR: _RNvXNtCs3yuwAp0waWO_4core4charNtB2_13EscapeUnicodeNtNtNtNtB4_4iter6traits8iterator8Iterator4next+0x6c
   vmlinux.o: warning: objtool: .rodata+0x69b20: data relocation to !ENDBR: _RNvXNtCs3yuwAp0waWO_4core4charNtB2_13EscapeUnicodeNtNtNtNtB4_4iter6traits8iterator8Iterator4next+0x77
   vmlinux.o: warning: objtool: .rodata+0x69b28: data relocation to !ENDBR: _RNvXs1_NtCs3yuwAp0waWO_4core4charNtB5_13EscapeUnicodeNtNtB7_3fmt7Display3fmt+0xaa
   vmlinux.o: warning: objtool: .rodata+0x69b30: data relocation to !ENDBR: _RNvXs1_NtCs3yuwAp0waWO_4core4charNtB5_13EscapeUnicodeNtNtB7_3fmt7Display3fmt+0x2a
   vmlinux.o: warning: objtool: .rodata+0x69b38: data relocation to !ENDBR: _RNvXs1_NtCs3yuwAp0waWO_4core4charNtB5_13EscapeUnicodeNtNtB7_3fmt7Display3fmt+0x4e
   vmlinux.o: warning: objtool: .rodata+0x69b40: data relocation to !ENDBR: _RNvXs1_NtCs3yuwAp0waWO_4core4charNtB5_13EscapeUnicodeNtNtB7_3fmt7Display3fmt+0x22
   vmlinux.o: warning: objtool: .rodata+0x69b48: data relocation to !ENDBR: _RNvXs1_NtCs3yuwAp0waWO_4core4charNtB5_13EscapeUnicodeNtNtB7_3fmt7Display3fmt+0x93
   vmlinux.o: warning: objtool: .rodata+0x69b50: data relocation to !ENDBR: _RNvXs1_NtCs3yuwAp0waWO_4core4charNtB5_13EscapeUnicodeNtNtB7_3fmt7Display3fmt+0x9d
   vmlinux.o: warning: objtool: .rodata+0x69b58: data relocation to !ENDBR: _RNvXs2_NtCs3yuwAp0waWO_4core4charNtB5_13EscapeDefaultNtNtNtNtB7_4iter6traits8iterator8Iterator4next+0x17
   vmlinux.o: warning: objtool: .rodata+0x69b60: data relocation to !ENDBR: _RNvXs2_NtCs3yuwAp0waWO_4core4charNtB5_13EscapeDefaultNtNtNtNtB7_4iter6traits8iterator8Iterator4next+0xe
   vmlinux.o: warning: objtool: .rodata+0x69b68: data relocation to !ENDBR: _RNvXs2_NtCs3yuwAp0waWO_4core4charNtB5_13EscapeDefaultNtNtNtNtB7_4iter6traits8iterator8Iterator4next+0x18
   vmlinux.o: warning: objtool: .rodata+0x69b70: data relocation to !ENDBR: _RNvXs2_NtCs3yuwAp0waWO_4core4charNtB5_13EscapeDefaultNtNtNtNtB7_4iter6traits8iterator8Iterator4next+0x24
   vmlinux.o: warning: objtool: .rodata+0x69b78: data relocation to !ENDBR: _RNvXs2_NtCs3yuwAp0waWO_4core4charNtB5_13EscapeDefaultNtNtNtNtB7_4iter6traits8iterator8Iterator3nth+0x7d
   vmlinux.o: warning: objtool: .rodata+0x69b80: data relocation to !ENDBR: _RNvXs2_NtCs3yuwAp0waWO_4core4charNtB5_13EscapeDefaultNtNtNtNtB7_4iter6traits8iterator8Iterator3nth+0x19
   vmlinux.o: warning: objtool: .rodata+0x69b88: data relocation to !ENDBR: _RNvXs2_NtCs3yuwAp0waWO_4core4charNtB5_13EscapeDefaultNtNtNtNtB7_4iter6traits8iterator8Iterator3nth+0x30
   vmlinux.o: warning: objtool: .rodata+0x69b90: data relocation to !ENDBR: _RNvXs2_NtCs3yuwAp0waWO_4core4charNtB5_13EscapeDefaultNtNtNtNtB7_4iter6traits8iterator8Iterator3nth+0x47
   vmlinux.o: warning: objtool: .rodata+0x69b98: data relocation to !ENDBR: _RNvXs5_NtCs3yuwAp0waWO_4core4charNtB5_13EscapeDefaultNtNtB7_3fmt7Display3fmt+0x3f
   vmlinux.o: warning: objtool: .rodata+0x69ba0: data relocation to !ENDBR: _RNvXs5_NtCs3yuwAp0waWO_4core4charNtB5_13EscapeDefaultNtNtB7_3fmt7Display3fmt+0x16
   vmlinux.o: warning: objtool: .rodata+0x69ba8: data relocation to !ENDBR: _RNvXs5_NtCs3yuwAp0waWO_4core4charNtB5_13EscapeDefaultNtNtB7_3fmt7Display3fmt+0x21
   vmlinux.o: warning: objtool: .rodata+0x69bb0: data relocation to !ENDBR: _RNvXs5_NtCs3yuwAp0waWO_4core4charNtB5_13EscapeDefaultNtNtB7_3fmt7Display3fmt+0x2c
   vmlinux.o: warning: objtool: .rodata+0x69bb8: data relocation to !ENDBR: _RNvXs5_NtCs3yuwAp0waWO_4core4charNtB5_13EscapeDefaultNtNtB7_3fmt7Display3fmt+0x112
   vmlinux.o: warning: objtool: .rodata+0x69bc0: data relocation to !ENDBR: _RNvXs5_NtCs3yuwAp0waWO_4core4charNtB5_13EscapeDefaultNtNtB7_3fmt7Display3fmt+0x50
   vmlinux.o: warning: objtool: .rodata+0x69bc8: data relocation to !ENDBR: _RNvXs5_NtCs3yuwAp0waWO_4core4charNtB5_13EscapeDefaultNtNtB7_3fmt7Display3fmt+0x55
   vmlinux.o: warning: objtool: .rodata+0x69bd0: data relocation to !ENDBR: _RNvXs5_NtCs3yuwAp0waWO_4core4charNtB5_13EscapeDefaultNtNtB7_3fmt7Display3fmt+0x7e
   vmlinux.o: warning: objtool: .rodata+0x69bd8: data relocation to !ENDBR: _RNvXs5_NtCs3yuwAp0waWO_4core4charNtB5_13EscapeDefaultNtNtB7_3fmt7Display3fmt+0x112
   vmlinux.o: warning: objtool: .rodata+0x69be0: data relocation to !ENDBR: _RNvXs5_NtCs3yuwAp0waWO_4core4charNtB5_13EscapeDefaultNtNtB7_3fmt7Display3fmt+0x55
   vmlinux.o: warning: objtool: .rodata+0x69be8: data relocation to !ENDBR: _RNvXs5_NtCs3yuwAp0waWO_4core4charNtB5_13EscapeDefaultNtNtB7_3fmt7Display3fmt+0x96
   vmlinux.o: warning: objtool: .rodata+0x69bf0: data relocation to !ENDBR: _RNvXs5_NtCs3yuwAp0waWO_4core4charNtB5_13EscapeDefaultNtNtB7_3fmt7Display3fmt+0xec
   vmlinux.o: warning: objtool: .rodata+0x69bf8: data relocation to !ENDBR: _RNvXs5_NtCs3yuwAp0waWO_4core4charNtB5_13EscapeDefaultNtNtB7_3fmt7Display3fmt+0xf8
   vmlinux.o: warning: objtool: .rodata+0x69c00: data relocation to !ENDBR: _RNvXs5_NtCs3yuwAp0waWO_4core4charNtB5_13EscapeDefaultNtNtB7_3fmt7Display3fmt+0x104
   vmlinux.o: warning: objtool: .rodata+0x69c08: data relocation to !ENDBR: _RNvXs6_NtCs3yuwAp0waWO_4core4charNtB5_11EscapeDebugNtNtNtNtB7_4iter6traits8iterator8Iterator4next+0x17
   vmlinux.o: warning: objtool: .rodata+0x69c10: data relocation to !ENDBR: _RNvXs6_NtCs3yuwAp0waWO_4core4charNtB5_11EscapeDebugNtNtNtNtB7_4iter6traits8iterator8Iterator4next+0xe
   vmlinux.o: warning: objtool: .rodata+0x69c18: data relocation to !ENDBR: _RNvXs6_NtCs3yuwAp0waWO_4core4charNtB5_11EscapeDebugNtNtNtNtB7_4iter6traits8iterator8Iterator4next+0x18
   vmlinux.o: warning: objtool: .rodata+0x69c20: data relocation to !ENDBR: _RNvXs6_NtCs3yuwAp0waWO_4core4charNtB5_11EscapeDebugNtNtNtNtB7_4iter6traits8iterator8Iterator4next+0x24
   vmlinux.o: warning: objtool: .rodata+0x69c28: data relocation to !ENDBR: _RNvXsa_NtCs3yuwAp0waWO_4core4charNtB5_11ToLowercaseNtNtNtNtB7_4iter6traits8iterator8Iterator4next+0xe
   vmlinux.o: warning: objtool: .rodata+0x69c30: data relocation to !ENDBR: _RNvXsa_NtCs3yuwAp0waWO_4core4charNtB5_11ToLowercaseNtNtNtNtB7_4iter6traits8iterator8Iterator4next+0x2a
   vmlinux.o: warning: objtool: .rodata+0x69c38: data relocation to !ENDBR: _RNvXsa_NtCs3yuwAp0waWO_4core4charNtB5_11ToLowercaseNtNtNtNtB7_4iter6traits8iterator8Iterator4next+0x20
   vmlinux.o: warning: objtool: .rodata+0x69c40: data relocation to !ENDBR: _RNvXsa_NtCs3yuwAp0waWO_4core4charNtB5_11ToLowercaseNtNtNtNtB7_4iter6traits8iterator8Iterator4next+0x29
   vmlinux.o: warning: objtool: .rodata+0x69c48: data relocation to !ENDBR: _RNvXsb_NtCs3yuwAp0waWO_4core4charNtB5_11ToLowercaseNtNtNtNtB7_4iter6traits12double_ended19DoubleEndedIterator9next_back+0xe
   vmlinux.o: warning: objtool: .rodata+0x69c50: data relocation to !ENDBR: _RNvXsb_NtCs3yuwAp0waWO_4core4charNtB5_11ToLowercaseNtNtNtNtB7_4iter6traits12double_ended19DoubleEndedIterator9next_back+0x19
   vmlinux.o: warning: objtool: .rodata+0x69c58: data relocation to !ENDBR: _RNvXsb_NtCs3yuwAp0waWO_4core4charNtB5_11ToLowercaseNtNtNtNtB7_4iter6traits12double_ended19DoubleEndedIterator9next_back+0x24
   vmlinux.o: warning: objtool: .rodata+0x69c60: data relocation to !ENDBR: _RNvXsb_NtCs3yuwAp0waWO_4core4charNtB5_11ToLowercaseNtNtNtNtB7_4iter6traits12double_ended19DoubleEndedIterator9next_back+0x31
   vmlinux.o: warning: objtool: .rodata+0x69c68: data relocation to !ENDBR: _RNvXsj_NtCs3yuwAp0waWO_4core4charNtB5_15CaseMappingIterNtNtNtNtB7_4iter6traits8iterator8Iterator4next+0xe
   vmlinux.o: warning: objtool: .rodata+0x69c70: data relocation to !ENDBR: _RNvXsj_NtCs3yuwAp0waWO_4core4charNtB5_15CaseMappingIterNtNtNtNtB7_4iter6traits8iterator8Iterator4next+0x2a
   vmlinux.o: warning: objtool: .rodata+0x69c78: data relocation to !ENDBR: _RNvXsj_NtCs3yuwAp0waWO_4core4charNtB5_15CaseMappingIterNtNtNtNtB7_4iter6traits8iterator8Iterator4next+0x20
   vmlinux.o: warning: objtool: .rodata+0x69c80: data relocation to !ENDBR: _RNvXsj_NtCs3yuwAp0waWO_4core4charNtB5_15CaseMappingIterNtNtNtNtB7_4iter6traits8iterator8Iterator4next+0x29
   vmlinux.o: warning: objtool: .rodata+0x69c88: data relocation to !ENDBR: _RNvXsk_NtCs3yuwAp0waWO_4core4charNtB5_15CaseMappingIterNtNtNtNtB7_4iter6traits12double_ended19DoubleEndedIterator9next_back+0xe
   vmlinux.o: warning: objtool: .rodata+0x69c90: data relocation to !ENDBR: _RNvXsk_NtCs3yuwAp0waWO_4core4charNtB5_15CaseMappingIterNtNtNtNtB7_4iter6traits12double_ended19DoubleEndedIterator9next_back+0x19
   vmlinux.o: warning: objtool: .rodata+0x69c98: data relocation to !ENDBR: _RNvXsk_NtCs3yuwAp0waWO_4core4charNtB5_15CaseMappingIterNtNtNtNtB7_4iter6traits12double_ended19DoubleEndedIterator9next_back+0x24
   vmlinux.o: warning: objtool: .rodata+0x69ca0: data relocation to !ENDBR: _RNvXsk_NtCs3yuwAp0waWO_4core4charNtB5_15CaseMappingIterNtNtNtNtB7_4iter6traits12double_ended19DoubleEndedIterator9next_back+0x31
   vmlinux.o: warning: objtool: .rodata+0x69ca8: data relocation to !ENDBR: _RNvXsl_NtCs3yuwAp0waWO_4core4charNtB5_15CaseMappingIterNtNtB7_3fmt7Display3fmt+0x13
   vmlinux.o: warning: objtool: .rodata+0x69cb0: data relocation to !ENDBR: _RNvXsl_NtCs3yuwAp0waWO_4core4charNtB5_15CaseMappingIterNtNtB7_3fmt7Display3fmt+0x4d
   vmlinux.o: warning: objtool: .rodata+0x69cb8: data relocation to !ENDBR: _RNvXsl_NtCs3yuwAp0waWO_4core4charNtB5_15CaseMappingIterNtNtB7_3fmt7Display3fmt+0x7e
   vmlinux.o: warning: objtool: .rodata+0x69cc0: data relocation to !ENDBR: _RNvXsl_NtCs3yuwAp0waWO_4core4charNtB5_15CaseMappingIterNtNtB7_3fmt7Display3fmt+0x73
   vmlinux.o: warning: objtool: .rodata+0x69cc8: data relocation to !ENDBR: _RNvXsm_NtCs3yuwAp0waWO_4core4charNtB5_11ToLowercaseNtNtB7_3fmt7Display3fmt+0x13
--
   vmlinux.o: warning: objtool: .rodata+0x6f240: data relocation to !ENDBR: _RINvNtCs3yuwAp0waWO_4core3ptr13drop_in_placeINtNtNtB4_3str4iter13SplitInternalNtBL_12IsWhitespaceEEB4_+0x0
   vmlinux.o: warning: objtool: .rodata+0x6f258: data relocation to !ENDBR: _RNvXsP_NtCs3yuwAp0waWO_4core3fmtRINtNtNtNtB7_4iter8adapters7flatten7FlattenINtNtB7_6option8IntoIterNtNtB7_4char11EscapeDebugEENtB5_5Debug3fmtB7_+0x0
   vmlinux.o: warning: objtool: .rodata+0x6f260: data relocation to !ENDBR: _RINvNtCs3yuwAp0waWO_4core3ptr13drop_in_placeINtNtNtB4_3str4iter13SplitInternalNtBL_12IsWhitespaceEEB4_+0x0
   vmlinux.o: warning: objtool: .rodata+0x6f278: data relocation to !ENDBR: _RNvXsP_NtCs3yuwAp0waWO_4core3fmtRNtNtB7_4char11EscapeDebugNtB5_5Debug3fmtB7_+0x0
   vmlinux.o: warning: objtool: .rodata+0x6f280: data relocation to !ENDBR: _RINvNtCs3yuwAp0waWO_4core3ptr13drop_in_placeINtNtNtB4_3str4iter13SplitInternalNtBL_12IsWhitespaceEEB4_+0x0
   vmlinux.o: warning: objtool: .rodata+0x6f298: data relocation to !ENDBR: _RNvXsP_NtCs3yuwAp0waWO_4core3fmtRRNtB5_9ArgumentsNtB5_5Debug3fmtB7_+0x0
   vmlinux.o: warning: objtool: .rodata+0x6f2a8: data relocation to !ENDBR: _RINvNtCs3yuwAp0waWO_4core3ptr13drop_in_placeINtNtNtB4_3str4iter13SplitInternalNtBL_12IsWhitespaceEEB4_+0x0
   vmlinux.o: warning: objtool: .rodata+0x6f2c0: data relocation to !ENDBR: _RNvXsP_NtCs3yuwAp0waWO_4core3fmtRINtNtB7_6option4ItemNtNtB7_4char11EscapeDebugENtB5_5Debug3fmtB7_+0x0
   vmlinux.o: warning: objtool: .rodata+0x6f2c8: data relocation to !ENDBR: _RINvNtCs3yuwAp0waWO_4core3ptr13drop_in_placeINtNtNtB4_3str4iter13SplitInternalNtBL_12IsWhitespaceEEB4_+0x0
   vmlinux.o: warning: objtool: .rodata+0x6f2e0: data relocation to !ENDBR: _RNvXsP_NtCs3yuwAp0waWO_4core3fmtRReNtB5_5Debug3fmtB7_+0x0
   vmlinux.o: warning: objtool: .rodata+0x6f2e8: data relocation to !ENDBR: _RINvNtCs3yuwAp0waWO_4core3ptr13drop_in_placeINtNtNtB4_3str4iter13SplitInternalNtBL_12IsWhitespaceEEB4_+0x0
   vmlinux.o: warning: objtool: .rodata+0x6f300: data relocation to !ENDBR: _RNvXsP_NtCs3yuwAp0waWO_4core3fmtRmNtB5_5Debug3fmtB7_+0x0
   vmlinux.o: warning: objtool: .rodata+0x6f320: data relocation to !ENDBR: _RINvNtCs3yuwAp0waWO_4core3ptr13drop_in_placeINtNtNtB4_3str4iter13SplitInternalNtBL_12IsWhitespaceEEB4_+0x0
   vmlinux.o: warning: objtool: .rodata+0x6f338: data relocation to !ENDBR: _RNvXsP_NtCs3yuwAp0waWO_4core3fmtRRDNtNtB7_3any3AnyNtNtB7_6marker4SendEL_NtB5_5Debug3fmtB7_+0x0
   vmlinux.o: warning: objtool: .rodata+0x6f348: data relocation to !ENDBR: _RINvNtCs3yuwAp0waWO_4core3ptr13drop_in_placeINtNtNtB4_3str4iter13SplitInternalNtBL_12IsWhitespaceEEB4_+0x0
   vmlinux.o: warning: objtool: .rodata+0x6f360: data relocation to !ENDBR: _RNvXsP_NtCs3yuwAp0waWO_4core3fmtRINtNtB7_6option6OptionRNtB5_9ArgumentsENtB5_5Debug3fmtB7_+0x0
   vmlinux.o: warning: objtool: .rodata+0x6f368: data relocation to !ENDBR: _RINvNtCs3yuwAp0waWO_4core3ptr13drop_in_placeINtNtNtB4_3str4iter13SplitInternalNtBL_12IsWhitespaceEEB4_+0x0
   vmlinux.o: warning: objtool: .rodata+0x6f380: data relocation to !ENDBR: _RNvXsP_NtCs3yuwAp0waWO_4core3fmtRRNtNtNtB7_5panic8location8LocationNtB5_5Debug3fmtB7_+0x0
   vmlinux.o: warning: objtool: .rodata+0x6f398: data relocation to !ENDBR: _RINvNtCs3yuwAp0waWO_4core3ptr13drop_in_placeINtNtNtB4_3str4iter13SplitInternalNtBL_12IsWhitespaceEEB4_+0x0
   vmlinux.o: warning: objtool: .rodata+0x6f3b0: data relocation to !ENDBR: _RNvXsP_NtCs3yuwAp0waWO_4core3fmtRbNtB5_5Debug3fmtB7_+0x0
   vmlinux.o: warning: objtool: .rodata+0x6f600: data relocation to !ENDBR: _RINvNtCs3yuwAp0waWO_4core3ptr13drop_in_placeINtNtNtB4_3str4iter13SplitInternalNtBL_12IsWhitespaceEEB4_+0x0
   vmlinux.o: warning: objtool: .rodata+0x6f618: data relocation to !ENDBR: _RNvXsP_NtCs3yuwAp0waWO_4core3fmtRINtNtNtB7_4hash3sip6HasherNtBy_11Sip13RoundsENtB5_5Debug3fmtB7_+0x0
   vmlinux.o: warning: objtool: .rodata+0x6f630: data relocation to !ENDBR: _RINvNtCs3yuwAp0waWO_4core3ptr13drop_in_placeINtNtNtB4_3str4iter13SplitInternalNtBL_12IsWhitespaceEEB4_+0x0
   vmlinux.o: warning: objtool: .rodata+0x6f648: data relocation to !ENDBR: _RNvXsP_NtCs3yuwAp0waWO_4core3fmtRINtNtNtB7_4hash3sip6HasherNtBy_11Sip24RoundsENtB5_5Debug3fmtB7_+0x0
   vmlinux.o: warning: objtool: .rodata+0x6f660: data relocation to !ENDBR: _RINvNtCs3yuwAp0waWO_4core3ptr13drop_in_placeINtNtNtB4_3str4iter13SplitInternalNtBL_12IsWhitespaceEEB4_+0x0
   vmlinux.o: warning: objtool: .rodata+0x6f678: data relocation to !ENDBR: _RNvXsP_NtCs3yuwAp0waWO_4core3fmtRNtNtNtB7_4hash3sip11SipHasher24NtB5_5Debug3fmtB7_+0x0
   vmlinux.o: warning: objtool: .rodata+0x6f690: data relocation to !ENDBR: _RINvNtCs3yuwAp0waWO_4core3ptr13drop_in_placeINtNtNtB4_3str4iter13SplitInternalNtBL_12IsWhitespaceEEB4_+0x0
   vmlinux.o: warning: objtool: .rodata+0x6f6a8: data relocation to !ENDBR: _RNvXsP_NtCs3yuwAp0waWO_4core3fmtRNtNtNtB7_4hash3sip5StateNtB5_5Debug3fmtB7_+0x0
   vmlinux.o: warning: objtool: .rodata+0x6f6b8: data relocation to !ENDBR: _RINvNtCs3yuwAp0waWO_4core3ptr13drop_in_placeINtNtNtB4_3str4iter13SplitInternalNtBL_12IsWhitespaceEEB4_+0x0
   vmlinux.o: warning: objtool: .rodata+0x6f6d0: data relocation to !ENDBR: _RNvXsP_NtCs3yuwAp0waWO_4core3fmtRINtNtB7_6marker11PhantomDataNtNtNtB7_4hash3sip11Sip13RoundsENtB5_5Debug3fmtB7_+0x0
   vmlinux.o: warning: objtool: .rodata+0x6f718: data relocation to !ENDBR: _RINvNtCs3yuwAp0waWO_4core3ptr13drop_in_placeINtNtNtB4_3str4iter13SplitInternalNtBL_12IsWhitespaceEEB4_+0x0
   vmlinux.o: warning: objtool: .rodata+0x6f730: data relocation to !ENDBR: _RNvXsP_NtCs3yuwAp0waWO_4core3fmtRINtNtB7_6option6OptionhENtB5_5Debug3fmtB7_+0x0
   vmlinux.o: warning: objtool: .rodata+0x6f760: data relocation to !ENDBR: _RINvNtCs3yuwAp0waWO_4core3ptr13drop_in_placeINtNtNtB4_3str4iter13SplitInternalNtBL_12IsWhitespaceEEB4_+0x0
   vmlinux.o: warning: objtool: .rodata+0x6f778: data relocation to !ENDBR: _RNvXsP_NtCs3yuwAp0waWO_4core3fmtRNtNtNtB7_3str4iter5CharsNtB5_5Debug3fmtB7_+0x0
   vmlinux.o: warning: objtool: .rodata+0x6f788: data relocation to !ENDBR: _RINvNtCs3yuwAp0waWO_4core3ptr13drop_in_placeINtNtNtB4_3str4iter13SplitInternalNtBL_12IsWhitespaceEEB4_+0x0
   vmlinux.o: warning: objtool: .rodata+0x6f7a0: data relocation to !ENDBR: _RNvXsP_NtCs3yuwAp0waWO_4core3fmtRINtNtNtNtB7_4iter8adapters6copied6CopiedINtNtNtB7_5slice4iter4IterhEENtB5_5Debug3fmtB7_+0x0
   vmlinux.o: warning: objtool: .rodata+0x6f7a8: data relocation to !ENDBR: _RINvNtCs3yuwAp0waWO_4core3ptr13drop_in_placeINtNtNtB4_3str4iter13SplitInternalNtBL_12IsWhitespaceEEB4_+0x0
   vmlinux.o: warning: objtool: .rodata+0x6f7c0: data relocation to !ENDBR: _RNvXse_NtNtCs3yuwAp0waWO_4core3str4iterINtB5_13SplitInternalNtB7_12IsWhitespaceENtNtB9_3fmt5Debug3fmtB9_+0x0
   vmlinux.o: warning: objtool: .rodata+0x6f7d8: data relocation to !ENDBR: _RINvNtCs3yuwAp0waWO_4core3ptr13drop_in_placeINtNtNtB4_3str4iter13SplitInternalNtBL_12IsWhitespaceEEB4_+0x0
   vmlinux.o: warning: objtool: .rodata+0x6f7f0: data relocation to !ENDBR: _RNvXse_NtNtCs3yuwAp0waWO_4core3str4iterINtB5_13SplitInternalcENtNtB9_3fmt5Debug3fmtB9_+0x0
   vmlinux.o: warning: objtool: .rodata+0x6f800: data relocation to !ENDBR: _RINvNtCs3yuwAp0waWO_4core3ptr13drop_in_placeINtNtNtB4_3str4iter13SplitInternalNtBL_12IsWhitespaceEEB4_+0x0
   vmlinux.o: warning: objtool: .rodata+0x6f818: data relocation to !ENDBR: _RNvXsP_NtCs3yuwAp0waWO_4core3fmtRINtNtNtNtB7_4iter8adapters3map3MapINtNtNtB7_3str4iter15SplitTerminatorcENtB18_11LinesAnyMapENtB5_5Debug3fmtB7_+0x0
   vmlinux.o: warning: objtool: .rodata+0x6f820: data relocation to !ENDBR: _RINvNtCs3yuwAp0waWO_4core3ptr13drop_in_placeINtNtNtB4_3str4iter13SplitInternalNtBL_12IsWhitespaceEEB4_+0x0
   vmlinux.o: warning: objtool: .rodata+0x6f838: data relocation to !ENDBR: _RNvXsP_NtCs3yuwAp0waWO_4core3fmtRNtNtNtB7_3str4iter5LinesNtB5_5Debug3fmtB7_+0x0
   vmlinux.o: warning: objtool: .rodata+0x6f850: data relocation to !ENDBR: _RINvNtCs3yuwAp0waWO_4core3ptr13drop_in_placeINtNtNtB4_3str4iter13SplitInternalNtBL_12IsWhitespaceEEB4_+0x0
   vmlinux.o: warning: objtool: .rodata+0x6f868: data relocation to !ENDBR: _RNvXsP_NtCs3yuwAp0waWO_4core3fmtRINtNtNtNtB7_4iter8adapters6filter6FilterINtNtNtB7_3str4iter5SplitNtB1e_12IsWhitespaceENtB1e_10IsNotEmptyENtB5_5Debug3fmtB7_+0x0
   vmlinux.o: warning: objtool: .rodata+0x6f888: data relocation to !ENDBR: _RINvNtCs3yuwAp0waWO_4core3ptr13drop_in_placeINtNtNtB4_3str4iter13SplitInternalNtBL_12IsWhitespaceEEB4_+0x0
   vmlinux.o: warning: objtool: .rodata+0x6f8a0: data relocation to !ENDBR: _RNvXsP_NtCs3yuwAp0waWO_4core3fmtRINtNtNtNtB7_4iter8adapters3map3MapINtNtBA_6filter6FilterINtNtNtB7_5slice4iter5SplithNtNtB7_3str17IsAsciiWhitespaceENtB1T_15BytesIsNotEmptyENtB1T_16UnsafeBytesToStrENtB5_5Debug3fmtB7_+0x0
   vmlinux.o: warning: objtool: .rodata+0x6f8a8: data relocation to !ENDBR: _RINvNtCs3yuwAp0waWO_4core3ptr13drop_in_placeINtNtNtB4_3str4iter13SplitInternalNtBL_12IsWhitespaceEEB4_+0x0
   vmlinux.o: warning: objtool: .rodata+0x6f8c0: data relocation to !ENDBR: _RNvXsP_NtCs3yuwAp0waWO_4core3fmtRINtNtNtNtB7_4iter8adapters5chain5ChainINtNtBA_7flatten7FlattenINtNtB7_6option8IntoIterNtNtB7_4char11EscapeDebugEEINtB1a_7FlatMapNtNtNtB7_3str4iter5CharsB1T_NtB2D_23CharEscapeDebugContinueEENtB5_5Debug3fmtB7_+0x0
   vmlinux.o: warning: objtool: .rodata+0x6f8c8: data relocation to !ENDBR: _RINvNtCs3yuwAp0waWO_4core3ptr13drop_in_placeINtNtNtB4_3str4iter13SplitInternalNtBL_12IsWhitespaceEEB4_+0x0
   vmlinux.o: warning: objtool: .rodata+0x6f8e0: data relocation to !ENDBR: _RNvXsP_NtCs3yuwAp0waWO_4core3fmtRINtNtNtNtB7_4iter8adapters7flatten7FlatMapNtNtNtB7_3str4iter5CharsNtNtB7_4char13EscapeDefaultNtB1f_17CharEscapeDefaultENtB5_5Debug3fmtB7_+0x0
   vmlinux.o: warning: objtool: .rodata+0x6f8e8: data relocation to !ENDBR: _RINvNtCs3yuwAp0waWO_4core3ptr13drop_in_placeINtNtNtB4_3str4iter13SplitInternalNtBL_12IsWhitespaceEEB4_+0x0
   vmlinux.o: warning: objtool: .rodata+0x6f900: data relocation to !ENDBR: _RNvXsP_NtCs3yuwAp0waWO_4core3fmtRINtNtNtNtB7_4iter8adapters7flatten7FlatMapNtNtNtB7_3str4iter5CharsNtNtB7_4char13EscapeUnicodeNtB1f_17CharEscapeUnicodeENtB5_5Debug3fmtB7_+0x0
   vmlinux.o: warning: objtool: .rodata+0x6f948: data relocation to !ENDBR: _RINvNtCs3yuwAp0waWO_4core3ptr13drop_in_placeINtNtNtB4_3str4iter13SplitInternalNtBL_12IsWhitespaceEEB4_+0x0
   vmlinux.o: warning: objtool: .rodata+0x6f960: data relocation to !ENDBR: _RNvXsP_NtCs3yuwAp0waWO_4core3fmtRAhj4_NtB5_5Debug3fmtB7_+0x0
   vmlinux.o: warning: objtool: .rodata+0x6f988: data relocation to !ENDBR: _RINvNtCs3yuwAp0waWO_4core3ptr13drop_in_placeINtNtNtB4_3str4iter13SplitInternalNtBL_12IsWhitespaceEEB4_+0x0
   vmlinux.o: warning: objtool: .rodata+0x6f9a0: data relocation to !ENDBR: _RNvXsP_NtCs3yuwAp0waWO_4core3fmtRRScNtB5_5Debug3fmtB7_+0x0
   vmlinux.o: warning: objtool: .rodata+0x6f9a8: data relocation to !ENDBR: _RINvNtCs3yuwAp0waWO_4core3ptr13drop_in_placeINtNtNtB4_3str4iter13SplitInternalNtBL_12IsWhitespaceEEB4_+0x0
   vmlinux.o: warning: objtool: .rodata+0x6f9c0: data relocation to !ENDBR: _RNvXsP_NtCs3yuwAp0waWO_4core3fmtRNtNtNtB7_3str4iter11CharIndicesNtB5_5Debug3fmtB7_+0x0
   vmlinux.o: warning: objtool: .rodata+0x6f9e0: data relocation to !ENDBR: _RINvNtCs3yuwAp0waWO_4core3ptr13drop_in_placeINtNtNtB4_3str4iter13SplitInternalNtBL_12IsWhitespaceEEB4_+0x0
   vmlinux.o: warning: objtool: .rodata+0x6f9f8: data relocation to !ENDBR: _RNvXsP_NtCs3yuwAp0waWO_4core3fmtRINtNtNtB7_3str7pattern19MultiCharEqSearcherRScENtB5_5Debug3fmtB7_+0x0
   vmlinux.o: warning: objtool: .rodata+0x6fa10: data relocation to !ENDBR: _RINvNtCs3yuwAp0waWO_4core3ptr13drop_in_placeINtNtNtB4_3str4iter13SplitInternalNtBL_12IsWhitespaceEEB4_+0x0
   vmlinux.o: warning: objtool: .rodata+0x6fa28: data relocation to !ENDBR: _RNvXsP_NtCs3yuwAp0waWO_4core3fmtRNtNtNtB7_3str7pattern15StrSearcherImplNtB5_5Debug3fmtB7_+0x0
   vmlinux.o: warning: objtool: .rodata+0x6fa38: data relocation to !ENDBR: _RINvNtCs3yuwAp0waWO_4core3ptr13drop_in_placeINtNtNtB4_3str4iter13SplitInternalNtBL_12IsWhitespaceEEB4_+0x0
   vmlinux.o: warning: objtool: .rodata+0x6fa50: data relocation to !ENDBR: _RNvXsP_NtCs3yuwAp0waWO_4core3fmtRNtNtNtB7_3str7pattern14TwoWaySearcherNtB5_5Debug3fmtB7_+0x0
   vmlinux.o: warning: objtool: .rodata+0x6fa58: data relocation to !ENDBR: _RINvNtCs3yuwAp0waWO_4core3ptr13drop_in_placeINtNtNtB4_3str4iter13SplitInternalNtBL_12IsWhitespaceEEB4_+0x0
   vmlinux.o: warning: objtool: .rodata+0x6fa70: data relocation to !ENDBR: _RNvXsP_NtCs3yuwAp0waWO_4core3fmtRNtNtNtB7_3str7pattern11EmptyNeedleNtB5_5Debug3fmtB7_+0x0
   vmlinux.o: warning: objtool: .rodata+0x6fb08: data relocation to !ENDBR: _RINvNtCs3yuwAp0waWO_4core3ptr13drop_in_placeINtNtNtB4_3str4iter13SplitInternalNtBL_12IsWhitespaceEEB4_+0x0
   vmlinux.o: warning: objtool: .rodata+0x6fb20: data relocation to !ENDBR: _RNvXsP_NtCs3yuwAp0waWO_4core3fmtRNtNtB7_4time22FromFloatSecsErrorKindNtB5_5Debug3fmtB7_+0x0
   vmlinux.o: warning: objtool: .rodata+0x7cba8: data relocation to !ENDBR: _RINvNtCs3yuwAp0waWO_4core3ptr13drop_in_placeINtNtNtB4_3str4iter13SplitInternalNtBL_12IsWhitespaceEEB4_+0x0
   vmlinux.o: warning: objtool: .rodata+0x7cbc0: data relocation to !ENDBR: _RNvXsP_NtCs3yuwAp0waWO_4core3fmtRINtNtNtB7_3ptr8non_null7NonNullNtNtNtB7_4task4wake7ContextENtB5_5Debug3fmtB7_+0x0
   vmlinux.o: warning: objtool: .rodata+0x7cbc8: data relocation to !ENDBR: _RINvNtCs3yuwAp0waWO_4core3ptr13drop_in_placeINtNtNtB4_3str4iter13SplitInternalNtBL_12IsWhitespaceEEB4_+0x0
   vmlinux.o: warning: objtool: .rodata+0x7cbe0: data relocation to !ENDBR: _RNvXsP_NtCs3yuwAp0waWO_4core3fmtRPuNtB5_5Debug3fmtB7_+0x0
   vmlinux.o: warning: objtool: .rodata+0x7cbe8: data relocation to !ENDBR: _RINvNtCs3yuwAp0waWO_4core3ptr13drop_in_placeINtNtNtB4_3str4iter13SplitInternalNtBL_12IsWhitespaceEEB4_+0x0
   vmlinux.o: warning: objtool: .rodata+0x7cc00: data relocation to !ENDBR: _RNvXsP_NtCs3yuwAp0waWO_4core3fmtRRNtNtNtB7_4task4wake14RawWakerVTableNtB5_5Debug3fmtB7_+0x0
   vmlinux.o: warning: objtool: .rodata+0x7cc20: data relocation to !ENDBR: _RINvNtCs3yuwAp0waWO_4core3ptr13drop_in_placeINtNtNtB4_3str4iter13SplitInternalNtBL_12IsWhitespaceEEB4_+0x0
   vmlinux.o: warning: objtool: .rodata+0x7cc38: data relocation to !ENDBR: _RNvXsP_NtCs3yuwAp0waWO_4core3fmtRFUPuENtNtNtB7_4task4wake8RawWakerNtB5_5Debug3fmtB7_+0x0
   vmlinux.o: warning: objtool: .rodata+0x7cc58: data relocation to !ENDBR: _RINvNtCs3yuwAp0waWO_4core3ptr13drop_in_placeINtNtNtB4_3str4iter13SplitInternalNtBL_12IsWhitespaceEEB4_+0x0
   vmlinux.o: warning: objtool: .rodata+0x7cc70: data relocation to !ENDBR: _RNvXsP_NtCs3yuwAp0waWO_4core3fmtRNtNtNtB7_3mem11valid_align10ValidAlignNtB5_5Debug3fmtB7_+0x0
   vmlinux.o: warning: objtool: .rodata+0x7cc90: data relocation to !ENDBR: _RINvNtCs3yuwAp0waWO_4core3ptr13drop_in_placeINtNtNtB4_3str4iter13SplitInternalNtBL_12IsWhitespaceEEB4_+0x0
   vmlinux.o: warning: objtool: .rodata+0x7cca8: data relocation to !ENDBR: _RNvXsP_NtCs3yuwAp0waWO_4core3fmtRaNtB5_5Debug3fmtB7_+0x0
   vmlinux.o: warning: objtool: .rodata+0x7ccc0: data relocation to !ENDBR: _RINvNtCs3yuwAp0waWO_4core3ptr13drop_in_placeINtNtNtB4_3str4iter13SplitInternalNtBL_12IsWhitespaceEEB4_+0x0
   vmlinux.o: warning: objtool: .rodata+0x7ccd8: data relocation to !ENDBR: _RNvXsP_NtCs3yuwAp0waWO_4core3fmtRsNtB5_5Debug3fmtB7_+0x0
   vmlinux.o: warning: objtool: .rodata+0x7cd00: data relocation to !ENDBR: _RINvNtCs3yuwAp0waWO_4core3ptr13drop_in_placeINtNtNtB4_3str4iter13SplitInternalNtBL_12IsWhitespaceEEB4_+0x0
   vmlinux.o: warning: objtool: .rodata+0x7cd18: data relocation to !ENDBR: _RNvXsP_NtCs3yuwAp0waWO_4core3fmtRxNtB5_5Debug3fmtB7_+0x0
   vmlinux.o: warning: objtool: .rodata+0x7cd28: data relocation to !ENDBR: _RINvNtCs3yuwAp0waWO_4core3ptr13drop_in_placeINtNtNtB4_3str4iter13SplitInternalNtBL_12IsWhitespaceEEB4_+0x0
   vmlinux.o: warning: objtool: .rodata+0x7cd40: data relocation to !ENDBR: _RNvXsP_NtCs3yuwAp0waWO_4core3fmtRfNtB5_5Debug3fmtB7_+0x0
   vmlinux.o: warning: objtool: .rodata+0x7cd50: data relocation to !ENDBR: _RINvNtCs3yuwAp0waWO_4core3ptr13drop_in_placeINtNtNtB4_3str4iter13SplitInternalNtBL_12IsWhitespaceEEB4_+0x0
   vmlinux.o: warning: objtool: .rodata+0x7cd68: data relocation to !ENDBR: _RNvXsP_NtCs3yuwAp0waWO_4core3fmtRdNtB5_5Debug3fmtB7_+0x0
   vmlinux.o: warning: objtool: .rodata+0x7d1a0: data relocation to !ENDBR: _RINvNtCs3yuwAp0waWO_4core3ptr13drop_in_placeRNtNtCsdvv6pRyacSq_5alloc11collections19TryReserveErrorKindEBL_+0x0
   vmlinux.o: warning: objtool: .rodata+0x7d1b8: data relocation to !ENDBR: _RNvXsP_NtCs3yuwAp0waWO_4core3fmtRNtNtCsdvv6pRyacSq_5alloc11collections19TryReserveErrorKindNtB5_5Debug3fmtBz_+0x0
   vmlinux.o: warning: objtool: .rodata+0x7d1d0: data relocation to !ENDBR: _RINvNtCs3yuwAp0waWO_4core3ptr13drop_in_placeRNtNtCsdvv6pRyacSq_5alloc11collections19TryReserveErrorKindEBL_+0x0
   vmlinux.o: warning: objtool: .rodata+0x7d1e8: data relocation to !ENDBR: _RNvXsP_NtCs3yuwAp0waWO_4core3fmtRNtNtNtB7_5alloc6layout6LayoutNtB5_5Debug3fmtCsdvv6pRyacSq_5alloc+0x0
   vmlinux.o: warning: objtool: .rodata+0x7d200: data relocation to !ENDBR: _RINvNtCs3yuwAp0waWO_4core3ptr13drop_in_placeRNtNtCsdvv6pRyacSq_5alloc11collections19TryReserveErrorKindEBL_+0x0
   vmlinux.o: warning: objtool: .rodata+0x7d218: data relocation to !ENDBR: _RNvXsP_NtCs3yuwAp0waWO_4core3fmtRuNtB5_5Debug3fmtCsdvv6pRyacSq_5alloc+0x0
   vmlinux.o: warning: objtool: .rodata+0x7d220: data relocation to !ENDBR: _RINvNtCs3yuwAp0waWO_4core3ptr13drop_in_placeQNtNtCsfATHBUcknU9_6kernel3str12RawFormatterEBL_+0x0
   vmlinux.o: warning: objtool: .rodata+0x7d238: data relocation to !ENDBR: _RNvXNtCs3yuwAp0waWO_4core3fmtQNtNtCsfATHBUcknU9_6kernel3str12RawFormatterNtB2_5Write9write_strBw_+0x0
   vmlinux.o: warning: objtool: .rodata+0x7d240: data relocation to !ENDBR: _RNvXNtCs3yuwAp0waWO_4core3fmtQNtNtCsfATHBUcknU9_6kernel3str12RawFormatterNtB2_5Write10write_charBw_+0x0
   vmlinux.o: warning: objtool: .rodata+0x7d248: data relocation to !ENDBR: _RNvXNtCs3yuwAp0waWO_4core3fmtQNtNtCsfATHBUcknU9_6kernel3str12RawFormatterNtB2_5Write9write_fmtBw_+0x0
>> vmlinux.o: warning: objtool: .rodata+0xebf30: data relocation to !ENDBR: _RINvNtCs3yuwAp0waWO_4core3ptr13drop_in_placeRlECsdVu6umiBwhr_12rust_minimal+0x0
>> vmlinux.o: warning: objtool: .rodata+0xebf48: data relocation to !ENDBR: _RNvXsP_NtCs3yuwAp0waWO_4core3fmtRlNtB5_5Debug3fmtCsdVu6umiBwhr_12rust_minimal+0x0
>> vmlinux.o: warning: objtool: .initcall6.init+0x34c: data relocation to !ENDBR: __rust_minimal_init+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvNtCs3yuwAp0waWO_4core3str19slice_error_fail_rt+0x0: data relocation to !ENDBR: _RNvNtCs3yuwAp0waWO_4core3str19slice_error_fail_rt+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvNtNtCs3yuwAp0waWO_4core5slice5index25slice_index_order_fail_rt+0x0: data relocation to !ENDBR: _RNvNtNtCs3yuwAp0waWO_4core5slice5index25slice_index_order_fail_rt+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvNtNtCs3yuwAp0waWO_4core5slice5index27slice_end_index_len_fail_rt+0x0: data relocation to !ENDBR: _RNvNtNtCs3yuwAp0waWO_4core5slice5index27slice_end_index_len_fail_rt+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvNtNtCs3yuwAp0waWO_4core5slice5index29slice_start_index_len_fail_rt+0x0: data relocation to !ENDBR: _RNvNtNtCs3yuwAp0waWO_4core5slice5index29slice_start_index_len_fail_rt+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvMNtCs3yuwAp0waWO_4core3f32f8classify+0x0: data relocation to !ENDBR: _RNvMNtCs3yuwAp0waWO_4core3f32f8classify+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvMNtCs3yuwAp0waWO_4core3f32f16partial_classify+0x0: data relocation to !ENDBR: _RNvMNtCs3yuwAp0waWO_4core3f32f16partial_classify+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvMNtCs3yuwAp0waWO_4core3f32f13classify_bits+0x0: data relocation to !ENDBR: _RNvMNtCs3yuwAp0waWO_4core3f32f13classify_bits+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvNvMNtCs3yuwAp0waWO_4core3f32f7to_bits13ct_f32_to_u32+0x0: data relocation to !ENDBR: _RNvNvMNtCs3yuwAp0waWO_4core3f32f7to_bits13ct_f32_to_u32+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvNtCs3yuwAp0waWO_4core9panicking9panic_fmt+0x0: data relocation to !ENDBR: _RNvNtCs3yuwAp0waWO_4core9panicking9panic_fmt+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvNvMNtCs3yuwAp0waWO_4core3f32f9from_bits13ct_u32_to_f32+0x0: data relocation to !ENDBR: _RNvNvMNtCs3yuwAp0waWO_4core3f32f9from_bits13ct_u32_to_f32+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvMNtCs3yuwAp0waWO_4core3f64d8classify+0x0: data relocation to !ENDBR: _RNvMNtCs3yuwAp0waWO_4core3f64d8classify+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvMNtCs3yuwAp0waWO_4core3f64d16partial_classify+0x0: data relocation to !ENDBR: _RNvMNtCs3yuwAp0waWO_4core3f64d16partial_classify+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvMNtCs3yuwAp0waWO_4core3f64d13classify_bits+0x0: data relocation to !ENDBR: _RNvMNtCs3yuwAp0waWO_4core3f64d13classify_bits+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvNvMNtCs3yuwAp0waWO_4core3f64d7to_bits13ct_f64_to_u64+0x0: data relocation to !ENDBR: _RNvNvMNtCs3yuwAp0waWO_4core3f64d7to_bits13ct_f64_to_u64+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvNvMNtCs3yuwAp0waWO_4core3f64d9from_bits13ct_u64_to_f64+0x0: data relocation to !ENDBR: _RNvNvMNtCs3yuwAp0waWO_4core3f64d9from_bits13ct_u64_to_f64+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvMNtNtCs3yuwAp0waWO_4core3num3fmtNtB2_4Part3len+0x0: data relocation to !ENDBR: _RNvMNtNtCs3yuwAp0waWO_4core3num3fmtNtB2_4Part3len+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvMNtNtCs3yuwAp0waWO_4core3num3fmtNtB2_4Part5write+0x0: data relocation to !ENDBR: _RNvMNtNtCs3yuwAp0waWO_4core3num3fmtNtB2_4Part5write+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvNtNtCs3yuwAp0waWO_4core5slice5index24slice_end_index_len_fail+0x0: data relocation to !ENDBR: _RNvNtNtCs3yuwAp0waWO_4core5slice5index24slice_end_index_len_fail+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvMs_NtNtCs3yuwAp0waWO_4core3num3fmtNtB4_9Formatted3len+0x0: data relocation to !ENDBR: _RNvMs_NtNtCs3yuwAp0waWO_4core3num3fmtNtB4_9Formatted3len+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvNtCs3yuwAp0waWO_4core9panicking5panic+0x0: data relocation to !ENDBR: _RNvNtCs3yuwAp0waWO_4core9panicking5panic+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvMs_NtNtCs3yuwAp0waWO_4core3num3fmtNtB4_9Formatted5write+0x0: data relocation to !ENDBR: _RNvMs_NtNtCs3yuwAp0waWO_4core3num3fmtNtB4_9Formatted5write+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvNtNtCs3yuwAp0waWO_4core5slice5index26slice_start_index_len_fail+0x0: data relocation to !ENDBR: _RNvNtNtCs3yuwAp0waWO_4core5slice5index26slice_start_index_len_fail+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvMNtNtCs3yuwAp0waWO_4core3num5errorNtB2_15TryFromIntError13___description+0x0: data relocation to !ENDBR: _RNvMNtNtCs3yuwAp0waWO_4core3num5errorNtB2_15TryFromIntError13___description+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvXs_NtNtCs3yuwAp0waWO_4core3num5errorNtB4_15TryFromIntErrorNtNtB8_3fmt7Display3fmt+0x0: data relocation to !ENDBR: _RNvXs_NtNtCs3yuwAp0waWO_4core3num5errorNtB4_15TryFromIntErrorNtNtB8_3fmt7Display3fmt+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvMs7_NtCs3yuwAp0waWO_4core3fmtNtB5_9Formatter3pad+0x0: data relocation to !ENDBR: _RNvMs7_NtCs3yuwAp0waWO_4core3fmtNtB5_9Formatter3pad+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvMs2_NtNtCs3yuwAp0waWO_4core3num5errorNtB5_13ParseIntError4kind+0x0: data relocation to !ENDBR: _RNvMs2_NtNtCs3yuwAp0waWO_4core3num5errorNtB5_13ParseIntError4kind+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvMs2_NtNtCs3yuwAp0waWO_4core3num5errorNtB5_13ParseIntError13___description+0x0: data relocation to !ENDBR: _RNvMs2_NtNtCs3yuwAp0waWO_4core3num5errorNtB5_13ParseIntError13___description+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvXs3_NtNtCs3yuwAp0waWO_4core3num5errorNtB5_13ParseIntErrorNtNtB9_3fmt7Display3fmt+0x0: data relocation to !ENDBR: _RNvXs3_NtNtCs3yuwAp0waWO_4core3num5errorNtB5_13ParseIntErrorNtNtB9_3fmt7Display3fmt+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvXs3_NtNtNtCs3yuwAp0waWO_4core3fmt3num3impmNtB9_7Display3fmt+0x0: data relocation to !ENDBR: _RNvXs3_NtNtNtCs3yuwAp0waWO_4core3fmt3num3impmNtB9_7Display3fmt+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvXs_NtNtCs3yuwAp0waWO_4core3mem11valid_alignNtB4_10ValidAlignNtNtB8_3fmt5Debug3fmt+0x0: data relocation to !ENDBR: _RNvXs_NtNtCs3yuwAp0waWO_4core3mem11valid_alignNtB4_10ValidAlignNtNtB8_3fmt5Debug3fmt+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvNtCs3yuwAp0waWO_4core3fmt5write+0x0: data relocation to !ENDBR: _RNvNtCs3yuwAp0waWO_4core3fmt5write+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvXs3_NtNtCs3yuwAp0waWO_4core3cmp5implszNtB7_9PartialEq2eq+0x0: data relocation to !ENDBR: _RNvXs3_NtNtCs3yuwAp0waWO_4core3cmp5implszNtB7_9PartialEq2eq+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvXs5_NtNtCs3yuwAp0waWO_4core3cmp5implszNtB7_10PartialOrd11partial_cmp+0x0: data relocation to !ENDBR: _RNvXs5_NtNtCs3yuwAp0waWO_4core3cmp5implszNtB7_10PartialOrd11partial_cmp+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvXsa_NtCs3yuwAp0waWO_4core7convertNtB5_10InfallibleNtNtB7_5clone5Clone5clone+0x0: data relocation to !ENDBR: _RNvXsa_NtCs3yuwAp0waWO_4core7convertNtB5_10InfallibleNtNtB7_5clone5Clone5clone+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvXNtNtCs3yuwAp0waWO_4core3ops5rangeNtB2_9RangeFullNtNtB6_3fmt5Debug3fmt+0x0: data relocation to !ENDBR: _RNvXNtNtCs3yuwAp0waWO_4core3ops5rangeNtB2_9RangeFullNtNtB6_3fmt5Debug3fmt+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvXs0_NtCs3yuwAp0waWO_4core3anyDNtB5_3AnyNtNtB7_6marker4SendEL_NtNtB7_3fmt5Debug3fmt+0x0: data relocation to !ENDBR: _RNvXs0_NtCs3yuwAp0waWO_4core3anyDNtB5_3AnyNtNtB7_6marker4SendEL_NtNtB7_3fmt5Debug3fmt+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvXs1_NtCs3yuwAp0waWO_4core3anyDNtB5_3AnyNtNtB7_6marker4SendNtBG_4SyncEL_NtNtB7_3fmt5Debug3fmt+0x0: data relocation to !ENDBR: _RNvXs1_NtCs3yuwAp0waWO_4core3anyDNtB5_3AnyNtNtB7_6marker4SendNtBG_4SyncEL_NtNtB7_3fmt5Debug3fmt+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvXs0_NtCs3yuwAp0waWO_4core5arrayNtB5_17TryFromSliceErrorINtNtB7_7convert4FromNtBX_10InfallibleE4from+0x0: data relocation to !ENDBR: _RNvXs0_NtCs3yuwAp0waWO_4core5arrayNtB5_17TryFromSliceErrorINtNtB7_7convert4FromNtBX_10InfallibleE4from+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvNtCs3yuwAp0waWO_4core5ascii14escape_default+0x0: data relocation to !ENDBR: _RNvNtCs3yuwAp0waWO_4core5ascii14escape_default+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvXNtCs3yuwAp0waWO_4core5asciiNtB2_13EscapeDefaultNtNtNtNtB4_4iter6traits8iterator8Iterator9size_hint+0x0: data relocation to !ENDBR: _RNvXNtCs3yuwAp0waWO_4core5asciiNtB2_13EscapeDefaultNtNtNtNtB4_4iter6traits8iterator8Iterator9size_hint+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvXNtCs3yuwAp0waWO_4core5asciiNtB2_13EscapeDefaultNtNtNtNtB4_4iter6traits8iterator8Iterator4last+0x0: data relocation to !ENDBR: _RNvXNtCs3yuwAp0waWO_4core5asciiNtB2_13EscapeDefaultNtNtNtNtB4_4iter6traits8iterator8Iterator4last+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvNtCs3yuwAp0waWO_4core9panicking18panic_bounds_check+0x0: data relocation to !ENDBR: _RNvNtCs3yuwAp0waWO_4core9panicking18panic_bounds_check+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvXs_NtCs3yuwAp0waWO_4core5asciiNtB4_13EscapeDefaultNtNtNtNtB6_4iter6traits12double_ended19DoubleEndedIterator9next_back+0x0: data relocation to !ENDBR: _RNvXs_NtCs3yuwAp0waWO_4core5asciiNtB4_13EscapeDefaultNtNtNtNtB6_4iter6traits12double_ended19DoubleEndedIterator9next_back+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvXs2_NtCs3yuwAp0waWO_4core5asciiNtB5_13EscapeDefaultNtNtB7_3fmt7Display3fmt+0x0: data relocation to !ENDBR: _RNvXs2_NtCs3yuwAp0waWO_4core5asciiNtB5_13EscapeDefaultNtNtB7_3fmt7Display3fmt+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvNtNtCs3yuwAp0waWO_4core5slice5index22slice_index_order_fail+0x0: data relocation to !ENDBR: _RNvNtNtCs3yuwAp0waWO_4core5slice5index22slice_index_order_fail+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvXs3_NtCs3yuwAp0waWO_4core5asciiNtB5_13EscapeDefaultNtNtB7_3fmt5Debug3fmt+0x0: data relocation to !ENDBR: _RNvXs3_NtCs3yuwAp0waWO_4core5asciiNtB5_13EscapeDefaultNtNtB7_3fmt5Debug3fmt+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvXse_NtCs3yuwAp0waWO_4core4cellNtB5_11BorrowErrorNtNtB7_3fmt5Debug3fmt+0x0: data relocation to !ENDBR: _RNvXse_NtCs3yuwAp0waWO_4core4cellNtB5_11BorrowErrorNtNtB7_3fmt5Debug3fmt+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvXsf_NtCs3yuwAp0waWO_4core4cellNtB5_11BorrowErrorNtNtB7_3fmt7Display3fmt+0x0: data relocation to !ENDBR: _RNvXsf_NtCs3yuwAp0waWO_4core4cellNtB5_11BorrowErrorNtNtB7_3fmt7Display3fmt+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvXsg_NtCs3yuwAp0waWO_4core4cellNtB5_14BorrowMutErrorNtNtB7_3fmt5Debug3fmt+0x0: data relocation to !ENDBR: _RNvXsg_NtCs3yuwAp0waWO_4core4cellNtB5_14BorrowMutErrorNtNtB7_3fmt5Debug3fmt+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvXsh_NtCs3yuwAp0waWO_4core4cellNtB5_14BorrowMutErrorNtNtB7_3fmt7Display3fmt+0x0: data relocation to !ENDBR: _RNvXsh_NtCs3yuwAp0waWO_4core4cellNtB5_14BorrowMutErrorNtNtB7_3fmt7Display3fmt+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvMs3_NtNtCs3yuwAp0waWO_4core4char7convertNtB5_14ParseCharError13___description+0x0: data relocation to !ENDBR: _RNvMs3_NtNtCs3yuwAp0waWO_4core4char7convertNtB5_14ParseCharError13___description+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvXs4_NtNtCs3yuwAp0waWO_4core4char7convertNtB5_14ParseCharErrorNtNtB9_3fmt7Display3fmt+0x0: data relocation to !ENDBR: _RNvXs4_NtNtCs3yuwAp0waWO_4core4char7convertNtB5_14ParseCharErrorNtNtB9_3fmt7Display3fmt+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvXs7_NtNtCs3yuwAp0waWO_4core4char7convertNtB5_16CharTryFromErrorNtNtB9_3fmt7Display3fmt+0x0: data relocation to !ENDBR: _RNvXs7_NtNtCs3yuwAp0waWO_4core4char7convertNtB5_16CharTryFromErrorNtNtB9_3fmt7Display3fmt+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvMs_NtNtCs3yuwAp0waWO_4core4char6decodeNtB4_16DecodeUtf16Error18unpaired_surrogate+0x0: data relocation to !ENDBR: _RNvMs_NtNtCs3yuwAp0waWO_4core4char6decodeNtB4_16DecodeUtf16Error18unpaired_surrogate+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvXs0_NtNtCs3yuwAp0waWO_4core4char6decodeNtB5_16DecodeUtf16ErrorNtNtB9_3fmt7Display3fmt+0x0: data relocation to !ENDBR: _RNvXs0_NtNtCs3yuwAp0waWO_4core4char6decodeNtB5_16DecodeUtf16ErrorNtNtB9_3fmt7Display3fmt+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvXsK_NtNtCs3yuwAp0waWO_4core3fmt3numsNtB7_8LowerHex3fmt+0x0: data relocation to !ENDBR: _RNvXsK_NtNtCs3yuwAp0waWO_4core3fmt3numsNtB7_8LowerHex3fmt+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvXNtCs3yuwAp0waWO_4core4charNtB2_13EscapeUnicodeNtNtNtNtB4_4iter6traits8iterator8Iterator4next+0x0: data relocation to !ENDBR: _RNvXNtCs3yuwAp0waWO_4core4charNtB2_13EscapeUnicodeNtNtNtNtB4_4iter6traits8iterator8Iterator4next+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvXNtCs3yuwAp0waWO_4core4charNtB2_13EscapeUnicodeNtNtNtNtB4_4iter6traits8iterator8Iterator4last+0x0: data relocation to !ENDBR: _RNvXNtCs3yuwAp0waWO_4core4charNtB2_13EscapeUnicodeNtNtNtNtB4_4iter6traits8iterator8Iterator4last+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvXs1_NtCs3yuwAp0waWO_4core4charNtB5_13EscapeUnicodeNtNtB7_3fmt7Display3fmt+0x0: data relocation to !ENDBR: _RNvXs1_NtCs3yuwAp0waWO_4core4charNtB5_13EscapeUnicodeNtNtB7_3fmt7Display3fmt+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvXs2_NtCs3yuwAp0waWO_4core4charNtB5_13EscapeDefaultNtNtNtNtB7_4iter6traits8iterator8Iterator4next+0x0: data relocation to !ENDBR: _RNvXs2_NtCs3yuwAp0waWO_4core4charNtB5_13EscapeDefaultNtNtNtNtB7_4iter6traits8iterator8Iterator4next+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvXs2_NtCs3yuwAp0waWO_4core4charNtB5_13EscapeDefaultNtNtNtNtB7_4iter6traits8iterator8Iterator3nth+0x0: data relocation to !ENDBR: _RNvXs2_NtCs3yuwAp0waWO_4core4charNtB5_13EscapeDefaultNtNtNtNtB7_4iter6traits8iterator8Iterator3nth+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvXs2_NtCs3yuwAp0waWO_4core4charNtB5_13EscapeDefaultNtNtNtNtB7_4iter6traits8iterator8Iterator4last+0x0: data relocation to !ENDBR: _RNvXs2_NtCs3yuwAp0waWO_4core4charNtB5_13EscapeDefaultNtNtNtNtB7_4iter6traits8iterator8Iterator4last+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvXs3_NtCs3yuwAp0waWO_4core4charNtB5_13EscapeDefaultNtNtNtNtB7_4iter6traits10exact_size17ExactSizeIterator3len+0x0: data relocation to !ENDBR: _RNvXs3_NtCs3yuwAp0waWO_4core4charNtB5_13EscapeDefaultNtNtNtNtB7_4iter6traits10exact_size17ExactSizeIterator3len+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvXs5_NtCs3yuwAp0waWO_4core4charNtB5_13EscapeDefaultNtNtB7_3fmt7Display3fmt+0x0: data relocation to !ENDBR: _RNvXs5_NtCs3yuwAp0waWO_4core4charNtB5_13EscapeDefaultNtNtB7_3fmt7Display3fmt+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvXs6_NtCs3yuwAp0waWO_4core4charNtB5_11EscapeDebugNtNtNtNtB7_4iter6traits8iterator8Iterator4next+0x0: data relocation to !ENDBR: _RNvXs6_NtCs3yuwAp0waWO_4core4charNtB5_11EscapeDebugNtNtNtNtB7_4iter6traits8iterator8Iterator4next+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvXs6_NtCs3yuwAp0waWO_4core4charNtB5_11EscapeDebugNtNtNtNtB7_4iter6traits8iterator8Iterator9size_hint+0x0: data relocation to !ENDBR: _RNvXs6_NtCs3yuwAp0waWO_4core4charNtB5_11EscapeDebugNtNtNtNtB7_4iter6traits8iterator8Iterator9size_hint+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvXs9_NtCs3yuwAp0waWO_4core4charNtB5_11EscapeDebugNtNtB7_3fmt7Display3fmt+0x0: data relocation to !ENDBR: _RNvXs9_NtCs3yuwAp0waWO_4core4charNtB5_11EscapeDebugNtNtB7_3fmt7Display3fmt+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvXsa_NtCs3yuwAp0waWO_4core4charNtB5_11ToLowercaseNtNtNtNtB7_4iter6traits8iterator8Iterator4next+0x0: data relocation to !ENDBR: _RNvXsa_NtCs3yuwAp0waWO_4core4charNtB5_11ToLowercaseNtNtNtNtB7_4iter6traits8iterator8Iterator4next+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvXsa_NtCs3yuwAp0waWO_4core4charNtB5_11ToLowercaseNtNtNtNtB7_4iter6traits8iterator8Iterator9size_hint+0x0: data relocation to !ENDBR: _RNvXsa_NtCs3yuwAp0waWO_4core4charNtB5_11ToLowercaseNtNtNtNtB7_4iter6traits8iterator8Iterator9size_hint+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvXsb_NtCs3yuwAp0waWO_4core4charNtB5_11ToLowercaseNtNtNtNtB7_4iter6traits12double_ended19DoubleEndedIterator9next_back+0x0: data relocation to !ENDBR: _RNvXsb_NtCs3yuwAp0waWO_4core4charNtB5_11ToLowercaseNtNtNtNtB7_4iter6traits12double_ended19DoubleEndedIterator9next_back+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvMsi_NtCs3yuwAp0waWO_4core4charNtB5_15CaseMappingIter3new+0x0: data relocation to !ENDBR: _RNvMsi_NtCs3yuwAp0waWO_4core4charNtB5_15CaseMappingIter3new+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvXsj_NtCs3yuwAp0waWO_4core4charNtB5_15CaseMappingIterNtNtNtNtB7_4iter6traits8iterator8Iterator4next+0x0: data relocation to !ENDBR: _RNvXsj_NtCs3yuwAp0waWO_4core4charNtB5_15CaseMappingIterNtNtNtNtB7_4iter6traits8iterator8Iterator4next+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvXsj_NtCs3yuwAp0waWO_4core4charNtB5_15CaseMappingIterNtNtNtNtB7_4iter6traits8iterator8Iterator9size_hint+0x0: data relocation to !ENDBR: _RNvXsj_NtCs3yuwAp0waWO_4core4charNtB5_15CaseMappingIterNtNtNtNtB7_4iter6traits8iterator8Iterator9size_hint+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvXsk_NtCs3yuwAp0waWO_4core4charNtB5_15CaseMappingIterNtNtNtNtB7_4iter6traits12double_ended19DoubleEndedIterator9next_back+0x0: data relocation to !ENDBR: _RNvXsk_NtCs3yuwAp0waWO_4core4charNtB5_15CaseMappingIterNtNtNtNtB7_4iter6traits12double_ended19DoubleEndedIterator9next_back+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvXsl_NtCs3yuwAp0waWO_4core4charNtB5_15CaseMappingIterNtNtB7_3fmt7Display3fmt+0x0: data relocation to !ENDBR: _RNvXsl_NtCs3yuwAp0waWO_4core4charNtB5_15CaseMappingIterNtNtB7_3fmt7Display3fmt+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvXsm_NtCs3yuwAp0waWO_4core4charNtB5_11ToLowercaseNtNtB7_3fmt7Display3fmt+0x0: data relocation to !ENDBR: _RNvXsm_NtCs3yuwAp0waWO_4core4charNtB5_11ToLowercaseNtNtB7_3fmt7Display3fmt+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvXso_NtCs3yuwAp0waWO_4core4charNtB5_16TryFromCharErrorNtNtB7_3fmt7Display3fmt+0x0: data relocation to !ENDBR: _RNvXso_NtCs3yuwAp0waWO_4core4charNtB5_16TryFromCharErrorNtNtB7_3fmt7Display3fmt+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvMNtNtCs3yuwAp0waWO_4core3ffi5c_strNtB2_21FromBytesWithNulError13___description+0x0: data relocation to !ENDBR: _RNvMNtNtCs3yuwAp0waWO_4core3ffi5c_strNtB2_21FromBytesWithNulError13___description+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvXs_NtNtCs3yuwAp0waWO_4core3ffi5c_strNtB4_22FromBytesUntilNulErrorNtNtB8_3fmt7Display3fmt+0x0: data relocation to !ENDBR: _RNvXs_NtNtCs3yuwAp0waWO_4core3ffi5c_strNtB4_22FromBytesUntilNulErrorNtNtB8_3fmt7Display3fmt+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvXs0_NtNtCs3yuwAp0waWO_4core3ffi5c_strNtB5_4CStrNtNtB9_3fmt5Debug3fmt+0x0: data relocation to !ENDBR: _RNvXs0_NtNtCs3yuwAp0waWO_4core3ffi5c_strNtB5_4CStrNtNtB9_3fmt5Debug3fmt+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvXs1_NtNtCs3yuwAp0waWO_4core3ffi5c_strRNtB5_4CStrNtNtB9_7default7Default7default+0x0: data relocation to !ENDBR: _RNvXs1_NtNtCs3yuwAp0waWO_4core3ffi5c_strRNtB5_4CStrNtNtB9_7default7Default7default+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvXs2_NtNtCs3yuwAp0waWO_4core3ffi5c_strNtB5_21FromBytesWithNulErrorNtNtB9_3fmt7Display3fmt+0x0: data relocation to !ENDBR: _RNvXs2_NtNtCs3yuwAp0waWO_4core3ffi5c_strNtB5_21FromBytesWithNulErrorNtNtB9_3fmt7Display3fmt+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvXs5_NtNtNtCs3yuwAp0waWO_4core3fmt3num3impyNtB9_7Display3fmt+0x0: data relocation to !ENDBR: _RNvXs5_NtNtNtCs3yuwAp0waWO_4core3fmt3num3impyNtB9_7Display3fmt+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvMs3_NtNtCs3yuwAp0waWO_4core3ffi5c_strNtB5_4CStr20from_bytes_until_nul+0x0: data relocation to !ENDBR: _RNvMs3_NtNtCs3yuwAp0waWO_4core3ffi5c_strNtB5_4CStr20from_bytes_until_nul+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvNtNtCs3yuwAp0waWO_4core5slice6memchr19memchr_general_case+0x0: data relocation to !ENDBR: _RNvNtNtCs3yuwAp0waWO_4core5slice6memchr19memchr_general_case+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvMs3_NtNtCs3yuwAp0waWO_4core3ffi5c_strNtB5_4CStr19from_bytes_with_nul+0x0: data relocation to !ENDBR: _RNvMs3_NtNtCs3yuwAp0waWO_4core3ffi5c_strNtB5_4CStr19from_bytes_with_nul+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvMs3_NtNtCs3yuwAp0waWO_4core3ffi5c_strNtB5_4CStr6to_str+0x0: data relocation to !ENDBR: _RNvMs3_NtNtCs3yuwAp0waWO_4core3ffi5c_strNtB5_4CStr6to_str+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvNtNtCs3yuwAp0waWO_4core3str8converts9from_utf8+0x0: data relocation to !ENDBR: _RNvNtNtCs3yuwAp0waWO_4core3str8converts9from_utf8+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvXs4_NtNtCs3yuwAp0waWO_4core3ffi5c_strNtB5_4CStrNtNtB9_3cmp9PartialEq2eq+0x0: data relocation to !ENDBR: _RNvXs4_NtNtCs3yuwAp0waWO_4core3ffi5c_strNtB5_4CStrNtNtB9_3cmp9PartialEq2eq+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvXs6_NtNtCs3yuwAp0waWO_4core3ffi5c_strNtB5_4CStrNtNtB9_3cmp10PartialOrd11partial_cmp+0x0: data relocation to !ENDBR: _RNvXs6_NtNtCs3yuwAp0waWO_4core3ffi5c_strNtB5_4CStrNtNtB9_3cmp10PartialOrd11partial_cmp+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvXs7_NtNtCs3yuwAp0waWO_4core3ffi5c_strNtB5_4CStrNtNtB9_3cmp3Ord3cmp+0x0: data relocation to !ENDBR: _RNvXs7_NtNtCs3yuwAp0waWO_4core3ffi5c_strNtB5_4CStrNtNtB9_3cmp3Ord3cmp+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvXs8_NtNtCs3yuwAp0waWO_4core3ffi5c_strNtB5_4CStrINtNtNtB9_3ops5index5IndexINtNtBR_5range9RangeFromjEE5index+0x0: data relocation to !ENDBR: _RNvXs8_NtNtCs3yuwAp0waWO_4core3ffi5c_strNtB5_4CStrINtNtNtB9_3ops5index5IndexINtNtBR_5range9RangeFromjEE5index+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvXNtCs3yuwAp0waWO_4core3ffiNtB2_6c_voidNtNtB4_3fmt5Debug3fmt+0x0: data relocation to !ENDBR: _RNvXNtCs3yuwAp0waWO_4core3ffiNtB2_6c_voidNtNtB4_3fmt5Debug3fmt+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvXs6_NtCs3yuwAp0waWO_4core3ffiNtB5_10VaListImplNtNtNtB7_3ops4drop4Drop4drop+0x0: data relocation to !ENDBR: _RNvXs6_NtCs3yuwAp0waWO_4core3ffiNtB5_10VaListImplNtNtNtB7_3ops4drop4Drop4drop+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvMs1_NtNtCs3yuwAp0waWO_4core3fmt8buildersNtB5_11DebugStruct5field+0x0: data relocation to !ENDBR: _RNvMs1_NtNtCs3yuwAp0waWO_4core3fmt8buildersNtB5_11DebugStruct5field+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvXs_NtNtNtCs3yuwAp0waWO_4core4iter6traits7collectuINtB4_6ExtenduE10extend_one+0x0: data relocation to !ENDBR: _RNvXs_NtNtNtCs3yuwAp0waWO_4core4iter6traits7collectuINtB4_6ExtenduE10extend_one+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvNtCs3yuwAp0waWO_4core6option13expect_failed+0x0: data relocation to !ENDBR: _RNvNtCs3yuwAp0waWO_4core6option13expect_failed+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvMs_NtNtCs3yuwAp0waWO_4core5panic8locationNtB4_8Location20internal_constructor+0x0: data relocation to !ENDBR: _RNvMs_NtNtCs3yuwAp0waWO_4core5panic8locationNtB4_8Location20internal_constructor+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvXs0_NtNtCs3yuwAp0waWO_4core5panic8locationNtB5_8LocationNtNtB9_3fmt7Display3fmt+0x0: data relocation to !ENDBR: _RNvXs0_NtNtCs3yuwAp0waWO_4core5panic8locationNtB5_8LocationNtNtB9_3fmt7Display3fmt+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvMNtNtCs3yuwAp0waWO_4core5panic10panic_infoNtB2_9PanicInfo7payload+0x0: data relocation to !ENDBR: _RNvMNtNtCs3yuwAp0waWO_4core5panic10panic_infoNtB2_9PanicInfo7payload+0x0


objdump-func vmlinux.o _RINvNtCs3yuwAp0waWO_4core3ptr13drop_in_placeINtNtB4_6option6OptionNtCsdVu6umiBwhr_12rust_minimal11RustMinimalEEB14_:
0000 0000000000b93450 <_RINvNtCs3yuwAp0waWO_4core3ptr13drop_in_placeINtNtB4_6option6OptionNtCsdVu6umiBwhr_12rust_minimal11RustMinimalEEB14_>:
0000   b93450:	48 83 ec 48          	sub    $0x48,%rsp
0004   b93454:	48 83 3d 00 00 00 00 00 	cmpq   $0x0,0x0(%rip)        # b9345c <_RINvNtCs3yuwAp0waWO_4core3ptr13drop_in_placeINtNtB4_6option6OptionNtCsdVu6umiBwhr_12rust_minimal11RustMinimalEEB14_+0xc>	b93457: R_X86_64_PC32	.bss+0x25be43
000c   b9345c:	0f 84 d4 00 00 00    	je     b93536 <_RINvNtCs3yuwAp0waWO_4core3ptr13drop_in_placeINtNtB4_6option6OptionNtCsdVu6umiBwhr_12rust_minimal11RustMinimalEEB14_+0xe6>
0012   b93462:	48 c7 44 24 38 00 00 00 00 	movq   $0x0,0x38(%rsp)	b93467: R_X86_64_32S	.bss+0x25be48
001b   b9346b:	48 c7 44 24 40 00 00 00 00 	movq   $0x0,0x40(%rsp)	b93470: R_X86_64_32S	.text+0xb93710
0024   b93474:	48 c7 44 24 08 00 00 00 00 	movq   $0x0,0x8(%rsp)	b93479: R_X86_64_32S	.rodata+0xec0b0
002d   b9347d:	48 c7 44 24 10 02 00 00 00 	movq   $0x2,0x10(%rsp)
0036   b93486:	48 c7 44 24 18 00 00 00 00 	movq   $0x0,0x18(%rsp)
003f   b9348f:	48 8d 44 24 38       	lea    0x38(%rsp),%rax
0044   b93494:	48 89 44 24 28       	mov    %rax,0x28(%rsp)
0049   b93499:	48 c7 44 24 30 01 00 00 00 	movq   $0x1,0x30(%rsp)
0052   b934a2:	48 8d 4c 24 08       	lea    0x8(%rsp),%rcx
0057   b934a7:	ba 0d 00 00 00       	mov    $0xd,%edx
005c   b934ac:	48 c7 c7 00 00 00 00 	mov    $0x0,%rdi	b934af: R_X86_64_32S	_RNvNtNtCsfATHBUcknU9_6kernel5print14format_strings4INFO
0063   b934b3:	48 c7 c6 00 00 00 00 	mov    $0x0,%rsi	b934b6: R_X86_64_32S	.rodata+0xec038
006a   b934ba:	e8 00 00 00 00       	call   b934bf <_RINvNtCs3yuwAp0waWO_4core3ptr13drop_in_placeINtNtB4_6option6OptionNtCsdVu6umiBwhr_12rust_minimal11RustMinimalEEB14_+0x6f>	b934bb: R_X86_64_PLT32	_RNvNtCsfATHBUcknU9_6kernel5print11call_printk-0x4
006f   b934bf:	48 c7 44 24 08 00 00 00 00 	movq   $0x0,0x8(%rsp)	b934c4: R_X86_64_32S	.rodata+0xec0f0
0078   b934c8:	48 c7 44 24 10 01 00 00 00 	movq   $0x1,0x10(%rsp)
0081   b934d1:	48 c7 44 24 18 00 00 00 00 	movq   $0x0,0x18(%rsp)
008a   b934da:	48 c7 44 24 28 00 00 00 00 	movq   $0x0,0x28(%rsp)	b934df: R_X86_64_32S	.rodata+0xebff0
0093   b934e3:	48 c7 44 24 30 00 00 00 00 	movq   $0x0,0x30(%rsp)
009c   b934ec:	48 8d 4c 24 08       	lea    0x8(%rsp),%rcx
00a1   b934f1:	ba 0d 00 00 00       	mov    $0xd,%edx
00a6   b934f6:	48 c7 c7 00 00 00 00 	mov    $0x0,%rdi	b934f9: R_X86_64_32S	_RNvNtNtCsfATHBUcknU9_6kernel5print14format_strings4INFO
00ad   b934fd:	48 c7 c6 00 00 00 00 	mov    $0x0,%rsi	b93500: R_X86_64_32S	.rodata+0xec038
00b4   b93504:	e8 00 00 00 00       	call   b93509 <_RINvNtCs3yuwAp0waWO_4core3ptr13drop_in_placeINtNtB4_6option6OptionNtCsdVu6umiBwhr_12rust_minimal11RustMinimalEEB14_+0xb9>	b93505: R_X86_64_PLT32	_RNvNtCsfATHBUcknU9_6kernel5print11call_printk-0x4
00b9   b93509:	48 8b 05 00 00 00 00 	mov    0x0(%rip),%rax        # b93510 <_RINvNtCs3yuwAp0waWO_4core3ptr13drop_in_placeINtNtB4_6option6OptionNtCsdVu6umiBwhr_12rust_minimal11RustMinimalEEB14_+0xc0>	b9350c: R_X86_64_PC32	.bss+0x25be4c
00c0   b93510:	48 85 c0             	test   %rax,%rax
00c3   b93513:	74 21                	je     b93536 <_RINvNtCs3yuwAp0waWO_4core3ptr13drop_in_placeINtNtB4_6option6OptionNtCsdVu6umiBwhr_12rust_minimal11RustMinimalEEB14_+0xe6>
00c5   b93515:	b9 04 00 00 00       	mov    $0x4,%ecx
00ca   b9351a:	48 f7 e1             	mul    %rcx
00cd   b9351d:	48 85 c0             	test   %rax,%rax
00d0   b93520:	74 14                	je     b93536 <_RINvNtCs3yuwAp0waWO_4core3ptr13drop_in_placeINtNtB4_6option6OptionNtCsdVu6umiBwhr_12rust_minimal11RustMinimalEEB14_+0xe6>
00d2   b93522:	48 8b 3d 00 00 00 00 	mov    0x0(%rip),%rdi        # b93529 <_RINvNtCs3yuwAp0waWO_4core3ptr13drop_in_placeINtNtB4_6option6OptionNtCsdVu6umiBwhr_12rust_minimal11RustMinimalEEB14_+0xd9>	b93525: R_X86_64_PC32	.bss+0x25be44
00d9   b93529:	ba 04 00 00 00       	mov    $0x4,%edx
00de   b9352e:	48 89 c6             	mov    %rax,%rsi
00e1   b93531:	e8 00 00 00 00       	call   b93536 <_RINvNtCs3yuwAp0waWO_4core3ptr13drop_in_placeINtNtB4_6option6OptionNtCsdVu6umiBwhr_12rust_minimal11RustMinimalEEB14_+0xe6>	b93532: R_X86_64_PLT32	__rust_dealloc-0x4
00e6   b93536:	48 83 c4 48          	add    $0x48,%rsp
00ea   b9353a:	c3                   	ret
00eb   b9353b:	0f 1f 44 00 00       	nopl   0x0(%rax,%rax,1)

-- 
0-DAY CI Kernel Test Service
https://01.org/lkp

[-- Attachment #2: config --]
[-- Type: text/plain, Size: 165105 bytes --]

#
# Automatically generated file; DO NOT EDIT.
# Linux/x86_64 6.0.0-rc7 Kernel Configuration
#
CONFIG_CC_VERSION_TEXT="clang version 14.0.6 (git://gitmirror/llvm_project f28c006a5895fc0e329fe15fead81e37457cb1d1)"
CONFIG_GCC_VERSION=0
CONFIG_CC_IS_CLANG=y
CONFIG_CLANG_VERSION=140006
CONFIG_AS_IS_LLVM=y
CONFIG_AS_VERSION=140006
CONFIG_LD_VERSION=0
CONFIG_LD_IS_LLD=y
CONFIG_LLD_VERSION=140006
CONFIG_RUST_IS_AVAILABLE=y
CONFIG_CC_CAN_LINK=y
CONFIG_CC_CAN_LINK_STATIC=y
CONFIG_CC_HAS_ASM_GOTO_OUTPUT=y
CONFIG_TOOLS_SUPPORT_RELR=y
CONFIG_CC_HAS_ASM_INLINE=y
CONFIG_CC_HAS_NO_PROFILE_FN_ATTR=y
CONFIG_PAHOLE_VERSION=123
CONFIG_CONSTRUCTORS=y
CONFIG_IRQ_WORK=y
CONFIG_BUILDTIME_TABLE_SORT=y
CONFIG_THREAD_INFO_IN_TASK=y

#
# General setup
#
CONFIG_INIT_ENV_ARG_LIMIT=32
# CONFIG_COMPILE_TEST is not set
# CONFIG_WERROR is not set
CONFIG_LOCALVERSION=""
CONFIG_LOCALVERSION_AUTO=y
CONFIG_BUILD_SALT=""
CONFIG_HAVE_KERNEL_GZIP=y
CONFIG_HAVE_KERNEL_BZIP2=y
CONFIG_HAVE_KERNEL_LZMA=y
CONFIG_HAVE_KERNEL_XZ=y
CONFIG_HAVE_KERNEL_LZO=y
CONFIG_HAVE_KERNEL_LZ4=y
CONFIG_HAVE_KERNEL_ZSTD=y
CONFIG_KERNEL_GZIP=y
# CONFIG_KERNEL_BZIP2 is not set
# CONFIG_KERNEL_LZMA is not set
# CONFIG_KERNEL_XZ is not set
# CONFIG_KERNEL_LZO is not set
# CONFIG_KERNEL_LZ4 is not set
# CONFIG_KERNEL_ZSTD is not set
CONFIG_DEFAULT_INIT=""
CONFIG_DEFAULT_HOSTNAME="(none)"
CONFIG_SYSVIPC=y
CONFIG_SYSVIPC_SYSCTL=y
CONFIG_SYSVIPC_COMPAT=y
CONFIG_POSIX_MQUEUE=y
CONFIG_POSIX_MQUEUE_SYSCTL=y
# CONFIG_WATCH_QUEUE is not set
CONFIG_CROSS_MEMORY_ATTACH=y
# CONFIG_USELIB is not set
CONFIG_AUDIT=y
CONFIG_HAVE_ARCH_AUDITSYSCALL=y
CONFIG_AUDITSYSCALL=y

#
# IRQ subsystem
#
CONFIG_GENERIC_IRQ_PROBE=y
CONFIG_GENERIC_IRQ_SHOW=y
CONFIG_GENERIC_IRQ_EFFECTIVE_AFF_MASK=y
CONFIG_GENERIC_PENDING_IRQ=y
CONFIG_GENERIC_IRQ_MIGRATION=y
CONFIG_GENERIC_IRQ_INJECTION=y
CONFIG_HARDIRQS_SW_RESEND=y
CONFIG_IRQ_DOMAIN=y
CONFIG_IRQ_DOMAIN_HIERARCHY=y
CONFIG_GENERIC_MSI_IRQ=y
CONFIG_GENERIC_MSI_IRQ_DOMAIN=y
CONFIG_IRQ_MSI_IOMMU=y
CONFIG_GENERIC_IRQ_MATRIX_ALLOCATOR=y
CONFIG_GENERIC_IRQ_RESERVATION_MODE=y
CONFIG_IRQ_FORCED_THREADING=y
CONFIG_SPARSE_IRQ=y
# CONFIG_GENERIC_IRQ_DEBUGFS is not set
# end of IRQ subsystem

CONFIG_CLOCKSOURCE_WATCHDOG=y
CONFIG_ARCH_CLOCKSOURCE_INIT=y
CONFIG_CLOCKSOURCE_VALIDATE_LAST_CYCLE=y
CONFIG_GENERIC_TIME_VSYSCALL=y
CONFIG_GENERIC_CLOCKEVENTS=y
CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y
CONFIG_GENERIC_CLOCKEVENTS_MIN_ADJUST=y
CONFIG_GENERIC_CMOS_UPDATE=y
CONFIG_HAVE_POSIX_CPU_TIMERS_TASK_WORK=y
CONFIG_POSIX_CPU_TIMERS_TASK_WORK=y
CONFIG_CONTEXT_TRACKING=y
CONFIG_CONTEXT_TRACKING_IDLE=y

#
# Timers subsystem
#
CONFIG_TICK_ONESHOT=y
CONFIG_NO_HZ_COMMON=y
# CONFIG_HZ_PERIODIC is not set
# CONFIG_NO_HZ_IDLE is not set
CONFIG_NO_HZ_FULL=y
CONFIG_CONTEXT_TRACKING_USER=y
# CONFIG_CONTEXT_TRACKING_USER_FORCE is not set
CONFIG_NO_HZ=y
CONFIG_HIGH_RES_TIMERS=y
CONFIG_CLOCKSOURCE_WATCHDOG_MAX_SKEW_US=100
# end of Timers subsystem

CONFIG_BPF=y
CONFIG_HAVE_EBPF_JIT=y
CONFIG_ARCH_WANT_DEFAULT_BPF_JIT=y

#
# BPF subsystem
#
CONFIG_BPF_SYSCALL=y
CONFIG_BPF_JIT=y
CONFIG_BPF_JIT_ALWAYS_ON=y
CONFIG_BPF_JIT_DEFAULT_ON=y
CONFIG_BPF_UNPRIV_DEFAULT_OFF=y
# CONFIG_BPF_PRELOAD is not set
# CONFIG_BPF_LSM is not set
# end of BPF subsystem

CONFIG_PREEMPT_VOLUNTARY_BUILD=y
# CONFIG_PREEMPT_NONE is not set
CONFIG_PREEMPT_VOLUNTARY=y
# CONFIG_PREEMPT is not set
CONFIG_PREEMPT_COUNT=y
# CONFIG_PREEMPT_DYNAMIC is not set
# CONFIG_SCHED_CORE is not set

#
# CPU/Task time and stats accounting
#
CONFIG_VIRT_CPU_ACCOUNTING=y
CONFIG_VIRT_CPU_ACCOUNTING_GEN=y
CONFIG_IRQ_TIME_ACCOUNTING=y
CONFIG_HAVE_SCHED_AVG_IRQ=y
CONFIG_BSD_PROCESS_ACCT=y
CONFIG_BSD_PROCESS_ACCT_V3=y
CONFIG_TASKSTATS=y
CONFIG_TASK_DELAY_ACCT=y
CONFIG_TASK_XACCT=y
CONFIG_TASK_IO_ACCOUNTING=y
# CONFIG_PSI is not set
# end of CPU/Task time and stats accounting

CONFIG_CPU_ISOLATION=y

#
# RCU Subsystem
#
CONFIG_TREE_RCU=y
# CONFIG_RCU_EXPERT is not set
CONFIG_SRCU=y
CONFIG_TREE_SRCU=y
CONFIG_TASKS_RCU_GENERIC=y
CONFIG_TASKS_RUDE_RCU=y
CONFIG_TASKS_TRACE_RCU=y
CONFIG_RCU_STALL_COMMON=y
CONFIG_RCU_NEED_SEGCBLIST=y
CONFIG_RCU_NOCB_CPU=y
# CONFIG_RCU_NOCB_CPU_DEFAULT_ALL is not set
# end of RCU Subsystem

CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
# CONFIG_IKHEADERS is not set
CONFIG_LOG_BUF_SHIFT=20
CONFIG_LOG_CPU_MAX_BUF_SHIFT=12
CONFIG_PRINTK_SAFE_LOG_BUF_SHIFT=13
# CONFIG_PRINTK_INDEX is not set
CONFIG_HAVE_UNSTABLE_SCHED_CLOCK=y

#
# Scheduler features
#
# CONFIG_UCLAMP_TASK is not set
# end of Scheduler features

CONFIG_ARCH_SUPPORTS_NUMA_BALANCING=y
CONFIG_ARCH_WANT_BATCHED_UNMAP_TLB_FLUSH=y
CONFIG_CC_HAS_INT128=y
CONFIG_CC_IMPLICIT_FALLTHROUGH="-Wimplicit-fallthrough"
CONFIG_GCC12_NO_ARRAY_BOUNDS=y
CONFIG_ARCH_SUPPORTS_INT128=y
CONFIG_NUMA_BALANCING=y
CONFIG_NUMA_BALANCING_DEFAULT_ENABLED=y
CONFIG_CGROUPS=y
CONFIG_PAGE_COUNTER=y
# CONFIG_CGROUP_FAVOR_DYNMODS is not set
CONFIG_MEMCG=y
CONFIG_MEMCG_SWAP=y
CONFIG_MEMCG_KMEM=y
CONFIG_BLK_CGROUP=y
CONFIG_CGROUP_WRITEBACK=y
CONFIG_CGROUP_SCHED=y
CONFIG_FAIR_GROUP_SCHED=y
CONFIG_CFS_BANDWIDTH=y
# CONFIG_RT_GROUP_SCHED is not set
CONFIG_CGROUP_PIDS=y
CONFIG_CGROUP_RDMA=y
CONFIG_CGROUP_FREEZER=y
CONFIG_CGROUP_HUGETLB=y
CONFIG_CPUSETS=y
CONFIG_PROC_PID_CPUSET=y
CONFIG_CGROUP_DEVICE=y
CONFIG_CGROUP_CPUACCT=y
CONFIG_CGROUP_PERF=y
# CONFIG_CGROUP_BPF is not set
# CONFIG_CGROUP_MISC is not set
# CONFIG_CGROUP_DEBUG is not set
CONFIG_SOCK_CGROUP_DATA=y
CONFIG_NAMESPACES=y
CONFIG_UTS_NS=y
CONFIG_TIME_NS=y
CONFIG_IPC_NS=y
CONFIG_USER_NS=y
CONFIG_PID_NS=y
CONFIG_NET_NS=y
# CONFIG_CHECKPOINT_RESTORE is not set
CONFIG_SCHED_AUTOGROUP=y
# CONFIG_SYSFS_DEPRECATED is not set
CONFIG_RELAY=y
CONFIG_BLK_DEV_INITRD=y
CONFIG_INITRAMFS_SOURCE=""
CONFIG_RD_GZIP=y
CONFIG_RD_BZIP2=y
CONFIG_RD_LZMA=y
CONFIG_RD_XZ=y
CONFIG_RD_LZO=y
CONFIG_RD_LZ4=y
CONFIG_RD_ZSTD=y
# CONFIG_BOOT_CONFIG is not set
CONFIG_INITRAMFS_PRESERVE_MTIME=y
CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
CONFIG_LD_ORPHAN_WARN=y
CONFIG_SYSCTL=y
CONFIG_HAVE_UID16=y
CONFIG_SYSCTL_EXCEPTION_TRACE=y
CONFIG_HAVE_PCSPKR_PLATFORM=y
# CONFIG_EXPERT is not set
CONFIG_UID16=y
CONFIG_MULTIUSER=y
CONFIG_SGETMASK_SYSCALL=y
CONFIG_SYSFS_SYSCALL=y
CONFIG_FHANDLE=y
CONFIG_POSIX_TIMERS=y
CONFIG_PRINTK=y
CONFIG_BUG=y
CONFIG_ELF_CORE=y
CONFIG_PCSPKR_PLATFORM=y
CONFIG_BASE_FULL=y
CONFIG_FUTEX=y
CONFIG_FUTEX_PI=y
CONFIG_EPOLL=y
CONFIG_SIGNALFD=y
CONFIG_TIMERFD=y
CONFIG_EVENTFD=y
CONFIG_SHMEM=y
CONFIG_AIO=y
CONFIG_IO_URING=y
CONFIG_ADVISE_SYSCALLS=y
CONFIG_MEMBARRIER=y
CONFIG_KALLSYMS=y
CONFIG_KALLSYMS_ALL=y
CONFIG_KALLSYMS_ABSOLUTE_PERCPU=y
CONFIG_KALLSYMS_BASE_RELATIVE=y
CONFIG_ARCH_HAS_MEMBARRIER_SYNC_CORE=y
CONFIG_KCMP=y
CONFIG_RSEQ=y
# CONFIG_EMBEDDED is not set
CONFIG_HAVE_PERF_EVENTS=y
CONFIG_GUEST_PERF_EVENTS=y

#
# Kernel Performance Events And Counters
#
CONFIG_PERF_EVENTS=y
# CONFIG_DEBUG_PERF_USE_VMALLOC is not set
# end of Kernel Performance Events And Counters

CONFIG_SYSTEM_DATA_VERIFICATION=y
CONFIG_PROFILING=y
CONFIG_RUST=y
CONFIG_RUSTC_VERSION_TEXT="rustc 1.62.0 (a8314ef7d 2022-06-27)"
CONFIG_BINDGEN_VERSION_TEXT="bindgen 0.56.0"
CONFIG_TRACEPOINTS=y
# end of General setup

CONFIG_64BIT=y
CONFIG_X86_64=y
CONFIG_X86=y
CONFIG_INSTRUCTION_DECODER=y
CONFIG_OUTPUT_FORMAT="elf64-x86-64"
CONFIG_LOCKDEP_SUPPORT=y
CONFIG_STACKTRACE_SUPPORT=y
CONFIG_MMU=y
CONFIG_ARCH_MMAP_RND_BITS_MIN=28
CONFIG_ARCH_MMAP_RND_BITS_MAX=32
CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MIN=8
CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MAX=16
CONFIG_GENERIC_ISA_DMA=y
CONFIG_GENERIC_BUG=y
CONFIG_GENERIC_BUG_RELATIVE_POINTERS=y
CONFIG_ARCH_MAY_HAVE_PC_FDC=y
CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_ARCH_HAS_CPU_RELAX=y
CONFIG_ARCH_HIBERNATION_POSSIBLE=y
CONFIG_ARCH_NR_GPIO=1024
CONFIG_ARCH_SUSPEND_POSSIBLE=y
CONFIG_AUDIT_ARCH=y
CONFIG_HAVE_INTEL_TXT=y
CONFIG_X86_64_SMP=y
CONFIG_ARCH_SUPPORTS_UPROBES=y
CONFIG_FIX_EARLYCON_MEM=y
CONFIG_DYNAMIC_PHYSICAL_MASK=y
CONFIG_PGTABLE_LEVELS=5
CONFIG_CC_HAS_SANE_STACKPROTECTOR=y

#
# Processor type and features
#
CONFIG_SMP=y
CONFIG_X86_FEATURE_NAMES=y
CONFIG_X86_X2APIC=y
CONFIG_X86_MPPARSE=y
# CONFIG_GOLDFISH is not set
# CONFIG_X86_CPU_RESCTRL is not set
CONFIG_X86_EXTENDED_PLATFORM=y
# CONFIG_X86_NUMACHIP is not set
# CONFIG_X86_VSMP is not set
CONFIG_X86_UV=y
# CONFIG_X86_GOLDFISH is not set
# CONFIG_X86_INTEL_MID is not set
CONFIG_X86_INTEL_LPSS=y
# CONFIG_X86_AMD_PLATFORM_DEVICE is not set
CONFIG_IOSF_MBI=y
# CONFIG_IOSF_MBI_DEBUG is not set
CONFIG_X86_SUPPORTS_MEMORY_FAILURE=y
# CONFIG_SCHED_OMIT_FRAME_POINTER is not set
CONFIG_HYPERVISOR_GUEST=y
CONFIG_PARAVIRT=y
# CONFIG_PARAVIRT_DEBUG is not set
CONFIG_PARAVIRT_SPINLOCKS=y
CONFIG_X86_HV_CALLBACK_VECTOR=y
# CONFIG_XEN is not set
CONFIG_KVM_GUEST=y
CONFIG_ARCH_CPUIDLE_HALTPOLL=y
# CONFIG_PVH is not set
CONFIG_PARAVIRT_TIME_ACCOUNTING=y
CONFIG_PARAVIRT_CLOCK=y
# CONFIG_JAILHOUSE_GUEST is not set
# CONFIG_ACRN_GUEST is not set
CONFIG_INTEL_TDX_GUEST=y
# CONFIG_MK8 is not set
# CONFIG_MPSC is not set
# CONFIG_MCORE2 is not set
# CONFIG_MATOM is not set
CONFIG_GENERIC_CPU=y
CONFIG_X86_INTERNODE_CACHE_SHIFT=6
CONFIG_X86_L1_CACHE_SHIFT=6
CONFIG_X86_TSC=y
CONFIG_X86_CMPXCHG64=y
CONFIG_X86_CMOV=y
CONFIG_X86_MINIMUM_CPU_FAMILY=64
CONFIG_X86_DEBUGCTLMSR=y
CONFIG_IA32_FEAT_CTL=y
CONFIG_X86_VMX_FEATURE_NAMES=y
CONFIG_CPU_SUP_INTEL=y
CONFIG_CPU_SUP_AMD=y
CONFIG_CPU_SUP_HYGON=y
CONFIG_CPU_SUP_CENTAUR=y
CONFIG_CPU_SUP_ZHAOXIN=y
CONFIG_HPET_TIMER=y
CONFIG_HPET_EMULATE_RTC=y
CONFIG_DMI=y
# CONFIG_GART_IOMMU is not set
CONFIG_BOOT_VESA_SUPPORT=y
CONFIG_MAXSMP=y
CONFIG_NR_CPUS_RANGE_BEGIN=8192
CONFIG_NR_CPUS_RANGE_END=8192
CONFIG_NR_CPUS_DEFAULT=8192
CONFIG_NR_CPUS=8192
CONFIG_SCHED_CLUSTER=y
CONFIG_SCHED_SMT=y
CONFIG_SCHED_MC=y
CONFIG_SCHED_MC_PRIO=y
CONFIG_X86_LOCAL_APIC=y
CONFIG_X86_IO_APIC=y
CONFIG_X86_REROUTE_FOR_BROKEN_BOOT_IRQS=y
CONFIG_X86_MCE=y
CONFIG_X86_MCELOG_LEGACY=y
CONFIG_X86_MCE_INTEL=y
# CONFIG_X86_MCE_AMD is not set
CONFIG_X86_MCE_THRESHOLD=y
CONFIG_X86_MCE_INJECT=m

#
# Performance monitoring
#
CONFIG_PERF_EVENTS_INTEL_UNCORE=m
CONFIG_PERF_EVENTS_INTEL_RAPL=m
CONFIG_PERF_EVENTS_INTEL_CSTATE=m
# CONFIG_PERF_EVENTS_AMD_POWER is not set
# CONFIG_PERF_EVENTS_AMD_UNCORE is not set
# CONFIG_PERF_EVENTS_AMD_BRS is not set
# end of Performance monitoring

CONFIG_X86_16BIT=y
CONFIG_X86_ESPFIX64=y
CONFIG_X86_VSYSCALL_EMULATION=y
CONFIG_X86_IOPL_IOPERM=y
CONFIG_MICROCODE=y
CONFIG_MICROCODE_INTEL=y
# CONFIG_MICROCODE_AMD is not set
CONFIG_MICROCODE_LATE_LOADING=y
CONFIG_X86_MSR=y
CONFIG_X86_CPUID=y
CONFIG_X86_5LEVEL=y
CONFIG_X86_DIRECT_GBPAGES=y
# CONFIG_X86_CPA_STATISTICS is not set
CONFIG_X86_MEM_ENCRYPT=y
# CONFIG_AMD_MEM_ENCRYPT is not set
CONFIG_NUMA=y
# CONFIG_AMD_NUMA is not set
CONFIG_X86_64_ACPI_NUMA=y
CONFIG_NUMA_EMU=y
CONFIG_NODES_SHIFT=10
CONFIG_ARCH_SPARSEMEM_ENABLE=y
CONFIG_ARCH_SPARSEMEM_DEFAULT=y
# CONFIG_ARCH_MEMORY_PROBE is not set
CONFIG_ARCH_PROC_KCORE_TEXT=y
CONFIG_ILLEGAL_POINTER_VALUE=0xdead000000000000
CONFIG_X86_PMEM_LEGACY_DEVICE=y
CONFIG_X86_PMEM_LEGACY=m
CONFIG_X86_CHECK_BIOS_CORRUPTION=y
# CONFIG_X86_BOOTPARAM_MEMORY_CORRUPTION_CHECK is not set
CONFIG_MTRR=y
CONFIG_MTRR_SANITIZER=y
CONFIG_MTRR_SANITIZER_ENABLE_DEFAULT=1
CONFIG_MTRR_SANITIZER_SPARE_REG_NR_DEFAULT=1
CONFIG_X86_PAT=y
CONFIG_ARCH_USES_PG_UNCACHED=y
CONFIG_X86_UMIP=y
CONFIG_CC_HAS_IBT=y
CONFIG_X86_KERNEL_IBT=y
CONFIG_X86_INTEL_MEMORY_PROTECTION_KEYS=y
CONFIG_X86_INTEL_TSX_MODE_OFF=y
# CONFIG_X86_INTEL_TSX_MODE_ON is not set
# CONFIG_X86_INTEL_TSX_MODE_AUTO is not set
# CONFIG_X86_SGX is not set
CONFIG_EFI=y
CONFIG_EFI_STUB=y
CONFIG_EFI_MIXED=y
# CONFIG_HZ_100 is not set
# CONFIG_HZ_250 is not set
# CONFIG_HZ_300 is not set
CONFIG_HZ_1000=y
CONFIG_HZ=1000
CONFIG_SCHED_HRTICK=y
CONFIG_KEXEC=y
CONFIG_KEXEC_FILE=y
CONFIG_ARCH_HAS_KEXEC_PURGATORY=y
# CONFIG_KEXEC_SIG is not set
CONFIG_CRASH_DUMP=y
CONFIG_KEXEC_JUMP=y
CONFIG_PHYSICAL_START=0x1000000
CONFIG_RELOCATABLE=y
# CONFIG_RANDOMIZE_BASE is not set
CONFIG_PHYSICAL_ALIGN=0x200000
CONFIG_DYNAMIC_MEMORY_LAYOUT=y
CONFIG_HOTPLUG_CPU=y
CONFIG_BOOTPARAM_HOTPLUG_CPU0=y
# CONFIG_DEBUG_HOTPLUG_CPU0 is not set
# CONFIG_COMPAT_VDSO is not set
CONFIG_LEGACY_VSYSCALL_XONLY=y
# CONFIG_LEGACY_VSYSCALL_NONE is not set
# CONFIG_CMDLINE_BOOL is not set
CONFIG_MODIFY_LDT_SYSCALL=y
# CONFIG_STRICT_SIGALTSTACK_SIZE is not set
CONFIG_HAVE_LIVEPATCH=y
CONFIG_LIVEPATCH=y
# end of Processor type and features

CONFIG_SPECULATION_MITIGATIONS=y
CONFIG_PAGE_TABLE_ISOLATION=y
CONFIG_RETPOLINE=y
CONFIG_CPU_IBPB_ENTRY=y
CONFIG_CPU_IBRS_ENTRY=y
CONFIG_ARCH_HAS_ADD_PAGES=y
CONFIG_ARCH_MHP_MEMMAP_ON_MEMORY_ENABLE=y

#
# Power management and ACPI options
#
CONFIG_ARCH_HIBERNATION_HEADER=y
CONFIG_SUSPEND=y
CONFIG_SUSPEND_FREEZER=y
CONFIG_HIBERNATE_CALLBACKS=y
CONFIG_HIBERNATION=y
CONFIG_HIBERNATION_SNAPSHOT_DEV=y
CONFIG_PM_STD_PARTITION=""
CONFIG_PM_SLEEP=y
CONFIG_PM_SLEEP_SMP=y
# CONFIG_PM_AUTOSLEEP is not set
# CONFIG_PM_USERSPACE_AUTOSLEEP is not set
# CONFIG_PM_WAKELOCKS is not set
CONFIG_PM=y
CONFIG_PM_DEBUG=y
# CONFIG_PM_ADVANCED_DEBUG is not set
# CONFIG_PM_TEST_SUSPEND is not set
CONFIG_PM_SLEEP_DEBUG=y
# CONFIG_PM_TRACE_RTC is not set
CONFIG_PM_CLK=y
# CONFIG_WQ_POWER_EFFICIENT_DEFAULT is not set
# CONFIG_ENERGY_MODEL is not set
CONFIG_ARCH_SUPPORTS_ACPI=y
CONFIG_ACPI=y
CONFIG_ACPI_LEGACY_TABLES_LOOKUP=y
CONFIG_ARCH_MIGHT_HAVE_ACPI_PDC=y
CONFIG_ACPI_SYSTEM_POWER_STATES_SUPPORT=y
# CONFIG_ACPI_DEBUGGER is not set
CONFIG_ACPI_SPCR_TABLE=y
# CONFIG_ACPI_FPDT is not set
CONFIG_ACPI_LPIT=y
CONFIG_ACPI_SLEEP=y
CONFIG_ACPI_REV_OVERRIDE_POSSIBLE=y
CONFIG_ACPI_EC_DEBUGFS=m
CONFIG_ACPI_AC=y
CONFIG_ACPI_BATTERY=y
CONFIG_ACPI_BUTTON=y
CONFIG_ACPI_VIDEO=m
CONFIG_ACPI_FAN=y
CONFIG_ACPI_TAD=m
CONFIG_ACPI_DOCK=y
CONFIG_ACPI_CPU_FREQ_PSS=y
CONFIG_ACPI_PROCESSOR_CSTATE=y
CONFIG_ACPI_PROCESSOR_IDLE=y
CONFIG_ACPI_CPPC_LIB=y
CONFIG_ACPI_PROCESSOR=y
CONFIG_ACPI_IPMI=m
CONFIG_ACPI_HOTPLUG_CPU=y
CONFIG_ACPI_PROCESSOR_AGGREGATOR=m
CONFIG_ACPI_THERMAL=y
CONFIG_ACPI_PLATFORM_PROFILE=m
CONFIG_ARCH_HAS_ACPI_TABLE_UPGRADE=y
CONFIG_ACPI_TABLE_UPGRADE=y
# CONFIG_ACPI_DEBUG is not set
CONFIG_ACPI_PCI_SLOT=y
CONFIG_ACPI_CONTAINER=y
CONFIG_ACPI_HOTPLUG_MEMORY=y
CONFIG_ACPI_HOTPLUG_IOAPIC=y
CONFIG_ACPI_SBS=m
CONFIG_ACPI_HED=y
# CONFIG_ACPI_CUSTOM_METHOD is not set
CONFIG_ACPI_BGRT=y
CONFIG_ACPI_NFIT=m
# CONFIG_NFIT_SECURITY_DEBUG is not set
CONFIG_ACPI_NUMA=y
# CONFIG_ACPI_HMAT is not set
CONFIG_HAVE_ACPI_APEI=y
CONFIG_HAVE_ACPI_APEI_NMI=y
CONFIG_ACPI_APEI=y
CONFIG_ACPI_APEI_GHES=y
CONFIG_ACPI_APEI_PCIEAER=y
CONFIG_ACPI_APEI_MEMORY_FAILURE=y
CONFIG_ACPI_APEI_EINJ=m
# CONFIG_ACPI_APEI_ERST_DEBUG is not set
# CONFIG_ACPI_DPTF is not set
CONFIG_ACPI_WATCHDOG=y
CONFIG_ACPI_EXTLOG=m
CONFIG_ACPI_ADXL=y
# CONFIG_ACPI_CONFIGFS is not set
# CONFIG_ACPI_PFRUT is not set
CONFIG_ACPI_PCC=y
CONFIG_PMIC_OPREGION=y
CONFIG_ACPI_PRMT=y
CONFIG_X86_PM_TIMER=y

#
# CPU Frequency scaling
#
CONFIG_CPU_FREQ=y
CONFIG_CPU_FREQ_GOV_ATTR_SET=y
CONFIG_CPU_FREQ_GOV_COMMON=y
CONFIG_CPU_FREQ_STAT=y
CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y
# CONFIG_CPU_FREQ_DEFAULT_GOV_POWERSAVE is not set
# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set
# CONFIG_CPU_FREQ_DEFAULT_GOV_SCHEDUTIL is not set
CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
CONFIG_CPU_FREQ_GOV_POWERSAVE=y
CONFIG_CPU_FREQ_GOV_USERSPACE=y
CONFIG_CPU_FREQ_GOV_ONDEMAND=y
CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y
CONFIG_CPU_FREQ_GOV_SCHEDUTIL=y

#
# CPU frequency scaling drivers
#
CONFIG_X86_INTEL_PSTATE=y
# CONFIG_X86_PCC_CPUFREQ is not set
# CONFIG_X86_AMD_PSTATE is not set
CONFIG_X86_ACPI_CPUFREQ=m
CONFIG_X86_ACPI_CPUFREQ_CPB=y
# CONFIG_X86_POWERNOW_K8 is not set
# CONFIG_X86_AMD_FREQ_SENSITIVITY is not set
# CONFIG_X86_SPEEDSTEP_CENTRINO is not set
CONFIG_X86_P4_CLOCKMOD=m

#
# shared options
#
CONFIG_X86_SPEEDSTEP_LIB=m
# end of CPU Frequency scaling

#
# CPU Idle
#
CONFIG_CPU_IDLE=y
# CONFIG_CPU_IDLE_GOV_LADDER is not set
CONFIG_CPU_IDLE_GOV_MENU=y
# CONFIG_CPU_IDLE_GOV_TEO is not set
# CONFIG_CPU_IDLE_GOV_HALTPOLL is not set
CONFIG_HALTPOLL_CPUIDLE=y
# end of CPU Idle

CONFIG_INTEL_IDLE=y
# end of Power management and ACPI options

#
# Bus options (PCI etc.)
#
CONFIG_PCI_DIRECT=y
CONFIG_PCI_MMCONFIG=y
CONFIG_MMCONF_FAM10H=y
CONFIG_ISA_DMA_API=y
CONFIG_AMD_NB=y
# end of Bus options (PCI etc.)

#
# Binary Emulations
#
CONFIG_IA32_EMULATION=y
CONFIG_COMPAT_32=y
CONFIG_COMPAT=y
CONFIG_COMPAT_FOR_U64_ALIGNMENT=y
# end of Binary Emulations

CONFIG_HAVE_KVM=y
CONFIG_HAVE_KVM_PFNCACHE=y
CONFIG_HAVE_KVM_IRQCHIP=y
CONFIG_HAVE_KVM_IRQFD=y
CONFIG_HAVE_KVM_IRQ_ROUTING=y
CONFIG_HAVE_KVM_DIRTY_RING=y
CONFIG_HAVE_KVM_EVENTFD=y
CONFIG_KVM_MMIO=y
CONFIG_KVM_ASYNC_PF=y
CONFIG_HAVE_KVM_MSI=y
CONFIG_HAVE_KVM_CPU_RELAX_INTERCEPT=y
CONFIG_KVM_VFIO=y
CONFIG_KVM_GENERIC_DIRTYLOG_READ_PROTECT=y
CONFIG_KVM_COMPAT=y
CONFIG_HAVE_KVM_IRQ_BYPASS=y
CONFIG_HAVE_KVM_NO_POLL=y
CONFIG_KVM_XFER_TO_GUEST_WORK=y
CONFIG_HAVE_KVM_PM_NOTIFIER=y
CONFIG_VIRTUALIZATION=y
CONFIG_KVM=m
CONFIG_KVM_INTEL=m
# CONFIG_KVM_AMD is not set
# CONFIG_KVM_XEN is not set
CONFIG_AS_AVX512=y
CONFIG_AS_SHA1_NI=y
CONFIG_AS_SHA256_NI=y
CONFIG_AS_TPAUSE=y

#
# General architecture-dependent options
#
CONFIG_CRASH_CORE=y
CONFIG_KEXEC_CORE=y
CONFIG_HOTPLUG_SMT=y
CONFIG_GENERIC_ENTRY=y
CONFIG_KPROBES=y
CONFIG_JUMP_LABEL=y
# CONFIG_STATIC_KEYS_SELFTEST is not set
# CONFIG_STATIC_CALL_SELFTEST is not set
CONFIG_OPTPROBES=y
CONFIG_KPROBES_ON_FTRACE=y
CONFIG_UPROBES=y
CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y
CONFIG_ARCH_USE_BUILTIN_BSWAP=y
CONFIG_KRETPROBES=y
CONFIG_KRETPROBE_ON_RETHOOK=y
CONFIG_USER_RETURN_NOTIFIER=y
CONFIG_HAVE_IOREMAP_PROT=y
CONFIG_HAVE_KPROBES=y
CONFIG_HAVE_KRETPROBES=y
CONFIG_HAVE_OPTPROBES=y
CONFIG_HAVE_KPROBES_ON_FTRACE=y
CONFIG_ARCH_CORRECT_STACKTRACE_ON_KRETPROBE=y
CONFIG_HAVE_FUNCTION_ERROR_INJECTION=y
CONFIG_HAVE_NMI=y
CONFIG_TRACE_IRQFLAGS_SUPPORT=y
CONFIG_TRACE_IRQFLAGS_NMI_SUPPORT=y
CONFIG_HAVE_ARCH_TRACEHOOK=y
CONFIG_HAVE_DMA_CONTIGUOUS=y
CONFIG_GENERIC_SMP_IDLE_THREAD=y
CONFIG_ARCH_HAS_FORTIFY_SOURCE=y
CONFIG_ARCH_HAS_SET_MEMORY=y
CONFIG_ARCH_HAS_SET_DIRECT_MAP=y
CONFIG_HAVE_ARCH_THREAD_STRUCT_WHITELIST=y
CONFIG_ARCH_WANTS_DYNAMIC_TASK_STRUCT=y
CONFIG_ARCH_WANTS_NO_INSTR=y
CONFIG_HAVE_ASM_MODVERSIONS=y
CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y
CONFIG_HAVE_RSEQ=y
CONFIG_HAVE_RUST=y
CONFIG_HAVE_FUNCTION_ARG_ACCESS_API=y
CONFIG_HAVE_HW_BREAKPOINT=y
CONFIG_HAVE_MIXED_BREAKPOINTS_REGS=y
CONFIG_HAVE_USER_RETURN_NOTIFIER=y
CONFIG_HAVE_PERF_EVENTS_NMI=y
CONFIG_HAVE_HARDLOCKUP_DETECTOR_PERF=y
CONFIG_HAVE_PERF_REGS=y
CONFIG_HAVE_PERF_USER_STACK_DUMP=y
CONFIG_HAVE_ARCH_JUMP_LABEL=y
CONFIG_HAVE_ARCH_JUMP_LABEL_RELATIVE=y
CONFIG_MMU_GATHER_TABLE_FREE=y
CONFIG_MMU_GATHER_RCU_TABLE_FREE=y
CONFIG_MMU_GATHER_MERGE_VMAS=y
CONFIG_ARCH_HAVE_NMI_SAFE_CMPXCHG=y
CONFIG_HAVE_ALIGNED_STRUCT_PAGE=y
CONFIG_HAVE_CMPXCHG_LOCAL=y
CONFIG_HAVE_CMPXCHG_DOUBLE=y
CONFIG_ARCH_WANT_COMPAT_IPC_PARSE_VERSION=y
CONFIG_ARCH_WANT_OLD_COMPAT_IPC=y
CONFIG_HAVE_ARCH_SECCOMP=y
CONFIG_HAVE_ARCH_SECCOMP_FILTER=y
CONFIG_SECCOMP=y
CONFIG_SECCOMP_FILTER=y
# CONFIG_SECCOMP_CACHE_DEBUG is not set
CONFIG_HAVE_ARCH_STACKLEAK=y
CONFIG_HAVE_STACKPROTECTOR=y
CONFIG_STACKPROTECTOR=y
CONFIG_STACKPROTECTOR_STRONG=y
CONFIG_ARCH_SUPPORTS_LTO_CLANG=y
CONFIG_ARCH_SUPPORTS_LTO_CLANG_THIN=y
CONFIG_HAS_LTO_CLANG=y
CONFIG_LTO_NONE=y
# CONFIG_LTO_CLANG_FULL is not set
# CONFIG_LTO_CLANG_THIN is not set
CONFIG_HAVE_ARCH_WITHIN_STACK_FRAMES=y
CONFIG_HAVE_CONTEXT_TRACKING_USER=y
CONFIG_HAVE_CONTEXT_TRACKING_USER_OFFSTACK=y
CONFIG_HAVE_VIRT_CPU_ACCOUNTING_GEN=y
CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y
CONFIG_HAVE_MOVE_PUD=y
CONFIG_HAVE_MOVE_PMD=y
CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE=y
CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE_PUD=y
CONFIG_HAVE_ARCH_HUGE_VMAP=y
CONFIG_HAVE_ARCH_HUGE_VMALLOC=y
CONFIG_ARCH_WANT_HUGE_PMD_SHARE=y
CONFIG_HAVE_ARCH_SOFT_DIRTY=y
CONFIG_HAVE_MOD_ARCH_SPECIFIC=y
CONFIG_MODULES_USE_ELF_RELA=y
CONFIG_HAVE_IRQ_EXIT_ON_IRQ_STACK=y
CONFIG_HAVE_SOFTIRQ_ON_OWN_STACK=y
CONFIG_SOFTIRQ_ON_OWN_STACK=y
CONFIG_ARCH_HAS_ELF_RANDOMIZE=y
CONFIG_HAVE_ARCH_MMAP_RND_BITS=y
CONFIG_HAVE_EXIT_THREAD=y
CONFIG_ARCH_MMAP_RND_BITS=28
CONFIG_HAVE_ARCH_MMAP_RND_COMPAT_BITS=y
CONFIG_ARCH_MMAP_RND_COMPAT_BITS=8
CONFIG_HAVE_ARCH_COMPAT_MMAP_BASES=y
CONFIG_PAGE_SIZE_LESS_THAN_64KB=y
CONFIG_PAGE_SIZE_LESS_THAN_256KB=y
CONFIG_HAVE_OBJTOOL=y
CONFIG_HAVE_JUMP_LABEL_HACK=y
CONFIG_HAVE_NOINSTR_HACK=y
CONFIG_HAVE_NOINSTR_VALIDATION=y
CONFIG_HAVE_UACCESS_VALIDATION=y
CONFIG_HAVE_STACK_VALIDATION=y
CONFIG_HAVE_RELIABLE_STACKTRACE=y
CONFIG_OLD_SIGSUSPEND3=y
CONFIG_COMPAT_OLD_SIGACTION=y
CONFIG_COMPAT_32BIT_TIME=y
CONFIG_HAVE_ARCH_VMAP_STACK=y
CONFIG_VMAP_STACK=y
CONFIG_HAVE_ARCH_RANDOMIZE_KSTACK_OFFSET=y
CONFIG_RANDOMIZE_KSTACK_OFFSET=y
# CONFIG_RANDOMIZE_KSTACK_OFFSET_DEFAULT is not set
CONFIG_ARCH_HAS_STRICT_KERNEL_RWX=y
CONFIG_STRICT_KERNEL_RWX=y
CONFIG_ARCH_HAS_STRICT_MODULE_RWX=y
CONFIG_STRICT_MODULE_RWX=y
CONFIG_HAVE_ARCH_PREL32_RELOCATIONS=y
CONFIG_ARCH_USE_MEMREMAP_PROT=y
# CONFIG_LOCK_EVENT_COUNTS is not set
CONFIG_ARCH_HAS_MEM_ENCRYPT=y
CONFIG_ARCH_HAS_CC_PLATFORM=y
CONFIG_HAVE_STATIC_CALL=y
CONFIG_HAVE_STATIC_CALL_INLINE=y
CONFIG_HAVE_PREEMPT_DYNAMIC=y
CONFIG_HAVE_PREEMPT_DYNAMIC_CALL=y
CONFIG_ARCH_WANT_LD_ORPHAN_WARN=y
CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC=y
CONFIG_ARCH_SUPPORTS_PAGE_TABLE_CHECK=y
CONFIG_ARCH_HAS_ELFCORE_COMPAT=y
CONFIG_ARCH_HAS_PARANOID_L1D_FLUSH=y
CONFIG_DYNAMIC_SIGFRAME=y

#
# GCOV-based kernel profiling
#
# CONFIG_GCOV_KERNEL is not set
CONFIG_ARCH_HAS_GCOV_PROFILE_ALL=y
# end of GCOV-based kernel profiling

CONFIG_HAVE_GCC_PLUGINS=y
# end of General architecture-dependent options

CONFIG_RT_MUTEXES=y
CONFIG_BASE_SMALL=0
CONFIG_MODULE_SIG_FORMAT=y
CONFIG_MODULES=y
CONFIG_MODULE_FORCE_LOAD=y
CONFIG_MODULE_UNLOAD=y
# CONFIG_MODULE_FORCE_UNLOAD is not set
# CONFIG_MODULE_UNLOAD_TAINT_TRACKING is not set
# CONFIG_MODVERSIONS is not set
# CONFIG_MODULE_SRCVERSION_ALL is not set
CONFIG_MODULE_SIG=y
# CONFIG_MODULE_SIG_FORCE is not set
CONFIG_MODULE_SIG_ALL=y
# CONFIG_MODULE_SIG_SHA1 is not set
# CONFIG_MODULE_SIG_SHA224 is not set
CONFIG_MODULE_SIG_SHA256=y
# CONFIG_MODULE_SIG_SHA384 is not set
# CONFIG_MODULE_SIG_SHA512 is not set
CONFIG_MODULE_SIG_HASH="sha256"
CONFIG_MODULE_COMPRESS_NONE=y
# CONFIG_MODULE_COMPRESS_GZIP is not set
# CONFIG_MODULE_COMPRESS_XZ is not set
# CONFIG_MODULE_COMPRESS_ZSTD is not set
# CONFIG_MODULE_ALLOW_MISSING_NAMESPACE_IMPORTS is not set
CONFIG_MODPROBE_PATH="/sbin/modprobe"
CONFIG_MODULES_TREE_LOOKUP=y
CONFIG_BLOCK=y
CONFIG_BLOCK_LEGACY_AUTOLOAD=y
CONFIG_BLK_CGROUP_RWSTAT=y
CONFIG_BLK_DEV_BSG_COMMON=y
CONFIG_BLK_ICQ=y
CONFIG_BLK_DEV_BSGLIB=y
CONFIG_BLK_DEV_INTEGRITY=y
CONFIG_BLK_DEV_INTEGRITY_T10=m
# CONFIG_BLK_DEV_ZONED is not set
CONFIG_BLK_DEV_THROTTLING=y
# CONFIG_BLK_DEV_THROTTLING_LOW is not set
CONFIG_BLK_WBT=y
CONFIG_BLK_WBT_MQ=y
# CONFIG_BLK_CGROUP_IOLATENCY is not set
# CONFIG_BLK_CGROUP_IOCOST is not set
# CONFIG_BLK_CGROUP_IOPRIO is not set
CONFIG_BLK_DEBUG_FS=y
# CONFIG_BLK_SED_OPAL is not set
# CONFIG_BLK_INLINE_ENCRYPTION is not set

#
# Partition Types
#
# CONFIG_PARTITION_ADVANCED is not set
CONFIG_MSDOS_PARTITION=y
CONFIG_EFI_PARTITION=y
# end of Partition Types

CONFIG_BLOCK_COMPAT=y
CONFIG_BLK_MQ_PCI=y
CONFIG_BLK_MQ_VIRTIO=y
CONFIG_BLK_PM=y
CONFIG_BLOCK_HOLDER_DEPRECATED=y
CONFIG_BLK_MQ_STACKING=y

#
# IO Schedulers
#
CONFIG_MQ_IOSCHED_DEADLINE=y
CONFIG_MQ_IOSCHED_KYBER=y
CONFIG_IOSCHED_BFQ=y
CONFIG_BFQ_GROUP_IOSCHED=y
# CONFIG_BFQ_CGROUP_DEBUG is not set
# end of IO Schedulers

CONFIG_PREEMPT_NOTIFIERS=y
CONFIG_PADATA=y
CONFIG_ASN1=y
CONFIG_INLINE_SPIN_UNLOCK_IRQ=y
CONFIG_INLINE_READ_UNLOCK=y
CONFIG_INLINE_READ_UNLOCK_IRQ=y
CONFIG_INLINE_WRITE_UNLOCK=y
CONFIG_INLINE_WRITE_UNLOCK_IRQ=y
CONFIG_ARCH_SUPPORTS_ATOMIC_RMW=y
CONFIG_MUTEX_SPIN_ON_OWNER=y
CONFIG_RWSEM_SPIN_ON_OWNER=y
CONFIG_LOCK_SPIN_ON_OWNER=y
CONFIG_ARCH_USE_QUEUED_SPINLOCKS=y
CONFIG_QUEUED_SPINLOCKS=y
CONFIG_ARCH_USE_QUEUED_RWLOCKS=y
CONFIG_QUEUED_RWLOCKS=y
CONFIG_ARCH_HAS_NON_OVERLAPPING_ADDRESS_SPACE=y
CONFIG_ARCH_HAS_SYNC_CORE_BEFORE_USERMODE=y
CONFIG_ARCH_HAS_SYSCALL_WRAPPER=y
CONFIG_FREEZER=y

#
# Executable file formats
#
CONFIG_BINFMT_ELF=y
CONFIG_COMPAT_BINFMT_ELF=y
CONFIG_ELFCORE=y
CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS=y
CONFIG_BINFMT_SCRIPT=y
CONFIG_BINFMT_MISC=m
CONFIG_COREDUMP=y
# end of Executable file formats

#
# Memory Management options
#
CONFIG_ZPOOL=y
CONFIG_SWAP=y
CONFIG_ZSWAP=y
# CONFIG_ZSWAP_DEFAULT_ON is not set
# CONFIG_ZSWAP_COMPRESSOR_DEFAULT_DEFLATE is not set
CONFIG_ZSWAP_COMPRESSOR_DEFAULT_LZO=y
# CONFIG_ZSWAP_COMPRESSOR_DEFAULT_842 is not set
# CONFIG_ZSWAP_COMPRESSOR_DEFAULT_LZ4 is not set
# CONFIG_ZSWAP_COMPRESSOR_DEFAULT_LZ4HC is not set
# CONFIG_ZSWAP_COMPRESSOR_DEFAULT_ZSTD is not set
CONFIG_ZSWAP_COMPRESSOR_DEFAULT="lzo"
CONFIG_ZSWAP_ZPOOL_DEFAULT_ZBUD=y
# CONFIG_ZSWAP_ZPOOL_DEFAULT_Z3FOLD is not set
# CONFIG_ZSWAP_ZPOOL_DEFAULT_ZSMALLOC is not set
CONFIG_ZSWAP_ZPOOL_DEFAULT="zbud"
CONFIG_ZBUD=y
# CONFIG_Z3FOLD is not set
CONFIG_ZSMALLOC=y
CONFIG_ZSMALLOC_STAT=y

#
# SLAB allocator options
#
# CONFIG_SLAB is not set
CONFIG_SLUB=y
CONFIG_SLAB_MERGE_DEFAULT=y
CONFIG_SLAB_FREELIST_RANDOM=y
# CONFIG_SLAB_FREELIST_HARDENED is not set
# CONFIG_SLUB_STATS is not set
CONFIG_SLUB_CPU_PARTIAL=y
# end of SLAB allocator options

CONFIG_SHUFFLE_PAGE_ALLOCATOR=y
# CONFIG_COMPAT_BRK is not set
CONFIG_SPARSEMEM=y
CONFIG_SPARSEMEM_EXTREME=y
CONFIG_SPARSEMEM_VMEMMAP_ENABLE=y
CONFIG_SPARSEMEM_VMEMMAP=y
CONFIG_HAVE_FAST_GUP=y
CONFIG_NUMA_KEEP_MEMINFO=y
CONFIG_MEMORY_ISOLATION=y
CONFIG_EXCLUSIVE_SYSTEM_RAM=y
CONFIG_HAVE_BOOTMEM_INFO_NODE=y
CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
CONFIG_ARCH_ENABLE_MEMORY_HOTREMOVE=y
CONFIG_MEMORY_HOTPLUG=y
# CONFIG_MEMORY_HOTPLUG_DEFAULT_ONLINE is not set
CONFIG_MEMORY_HOTREMOVE=y
CONFIG_MHP_MEMMAP_ON_MEMORY=y
CONFIG_SPLIT_PTLOCK_CPUS=4
CONFIG_ARCH_ENABLE_SPLIT_PMD_PTLOCK=y
CONFIG_MEMORY_BALLOON=y
CONFIG_BALLOON_COMPACTION=y
CONFIG_COMPACTION=y
CONFIG_PAGE_REPORTING=y
CONFIG_MIGRATION=y
CONFIG_DEVICE_MIGRATION=y
CONFIG_ARCH_ENABLE_HUGEPAGE_MIGRATION=y
CONFIG_ARCH_ENABLE_THP_MIGRATION=y
CONFIG_CONTIG_ALLOC=y
CONFIG_PHYS_ADDR_T_64BIT=y
CONFIG_MMU_NOTIFIER=y
CONFIG_KSM=y
CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
CONFIG_ARCH_SUPPORTS_MEMORY_FAILURE=y
CONFIG_MEMORY_FAILURE=y
CONFIG_HWPOISON_INJECT=m
CONFIG_ARCH_WANT_GENERAL_HUGETLB=y
CONFIG_ARCH_WANTS_THP_SWAP=y
CONFIG_TRANSPARENT_HUGEPAGE=y
CONFIG_TRANSPARENT_HUGEPAGE_ALWAYS=y
# CONFIG_TRANSPARENT_HUGEPAGE_MADVISE is not set
CONFIG_THP_SWAP=y
# CONFIG_READ_ONLY_THP_FOR_FS is not set
CONFIG_NEED_PER_CPU_EMBED_FIRST_CHUNK=y
CONFIG_NEED_PER_CPU_PAGE_FIRST_CHUNK=y
CONFIG_USE_PERCPU_NUMA_NODE_ID=y
CONFIG_HAVE_SETUP_PER_CPU_AREA=y
CONFIG_FRONTSWAP=y
# CONFIG_CMA is not set
CONFIG_GENERIC_EARLY_IOREMAP=y
CONFIG_DEFERRED_STRUCT_PAGE_INIT=y
CONFIG_PAGE_IDLE_FLAG=y
CONFIG_IDLE_PAGE_TRACKING=y
CONFIG_ARCH_HAS_CACHE_LINE_SIZE=y
CONFIG_ARCH_HAS_CURRENT_STACK_POINTER=y
CONFIG_ARCH_HAS_PTE_DEVMAP=y
CONFIG_ZONE_DMA=y
CONFIG_ZONE_DMA32=y
CONFIG_ZONE_DEVICE=y
CONFIG_GET_FREE_REGION=y
CONFIG_DEVICE_PRIVATE=y
CONFIG_VMAP_PFN=y
CONFIG_ARCH_USES_HIGH_VMA_FLAGS=y
CONFIG_ARCH_HAS_PKEYS=y
CONFIG_VM_EVENT_COUNTERS=y
# CONFIG_PERCPU_STATS is not set
# CONFIG_GUP_TEST is not set
CONFIG_ARCH_HAS_PTE_SPECIAL=y
CONFIG_SECRETMEM=y
# CONFIG_ANON_VMA_NAME is not set
# CONFIG_USERFAULTFD is not set

#
# Data Access Monitoring
#
# CONFIG_DAMON is not set
# end of Data Access Monitoring
# end of Memory Management options

CONFIG_NET=y
CONFIG_NET_INGRESS=y
CONFIG_NET_EGRESS=y
CONFIG_SKB_EXTENSIONS=y

#
# Networking options
#
CONFIG_PACKET=y
CONFIG_PACKET_DIAG=m
CONFIG_UNIX=y
CONFIG_UNIX_SCM=y
CONFIG_AF_UNIX_OOB=y
CONFIG_UNIX_DIAG=m
CONFIG_TLS=m
CONFIG_TLS_DEVICE=y
# CONFIG_TLS_TOE is not set
CONFIG_XFRM=y
CONFIG_XFRM_OFFLOAD=y
CONFIG_XFRM_ALGO=y
CONFIG_XFRM_USER=y
# CONFIG_XFRM_USER_COMPAT is not set
# CONFIG_XFRM_INTERFACE is not set
CONFIG_XFRM_SUB_POLICY=y
CONFIG_XFRM_MIGRATE=y
CONFIG_XFRM_STATISTICS=y
CONFIG_XFRM_AH=m
CONFIG_XFRM_ESP=m
CONFIG_XFRM_IPCOMP=m
CONFIG_NET_KEY=m
CONFIG_NET_KEY_MIGRATE=y
CONFIG_XDP_SOCKETS=y
# CONFIG_XDP_SOCKETS_DIAG is not set
CONFIG_INET=y
CONFIG_IP_MULTICAST=y
CONFIG_IP_ADVANCED_ROUTER=y
CONFIG_IP_FIB_TRIE_STATS=y
CONFIG_IP_MULTIPLE_TABLES=y
CONFIG_IP_ROUTE_MULTIPATH=y
CONFIG_IP_ROUTE_VERBOSE=y
CONFIG_IP_ROUTE_CLASSID=y
CONFIG_IP_PNP=y
CONFIG_IP_PNP_DHCP=y
# CONFIG_IP_PNP_BOOTP is not set
# CONFIG_IP_PNP_RARP is not set
CONFIG_NET_IPIP=m
CONFIG_NET_IPGRE_DEMUX=m
CONFIG_NET_IP_TUNNEL=m
CONFIG_NET_IPGRE=m
CONFIG_NET_IPGRE_BROADCAST=y
CONFIG_IP_MROUTE_COMMON=y
CONFIG_IP_MROUTE=y
CONFIG_IP_MROUTE_MULTIPLE_TABLES=y
CONFIG_IP_PIMSM_V1=y
CONFIG_IP_PIMSM_V2=y
CONFIG_SYN_COOKIES=y
CONFIG_NET_IPVTI=m
CONFIG_NET_UDP_TUNNEL=m
# CONFIG_NET_FOU is not set
# CONFIG_NET_FOU_IP_TUNNELS is not set
CONFIG_INET_AH=m
CONFIG_INET_ESP=m
CONFIG_INET_ESP_OFFLOAD=m
# CONFIG_INET_ESPINTCP is not set
CONFIG_INET_IPCOMP=m
CONFIG_INET_XFRM_TUNNEL=m
CONFIG_INET_TUNNEL=m
CONFIG_INET_DIAG=m
CONFIG_INET_TCP_DIAG=m
CONFIG_INET_UDP_DIAG=m
CONFIG_INET_RAW_DIAG=m
# CONFIG_INET_DIAG_DESTROY is not set
CONFIG_TCP_CONG_ADVANCED=y
CONFIG_TCP_CONG_BIC=m
CONFIG_TCP_CONG_CUBIC=y
CONFIG_TCP_CONG_WESTWOOD=m
CONFIG_TCP_CONG_HTCP=m
CONFIG_TCP_CONG_HSTCP=m
CONFIG_TCP_CONG_HYBLA=m
CONFIG_TCP_CONG_VEGAS=m
CONFIG_TCP_CONG_NV=m
CONFIG_TCP_CONG_SCALABLE=m
CONFIG_TCP_CONG_LP=m
CONFIG_TCP_CONG_VENO=m
CONFIG_TCP_CONG_YEAH=m
CONFIG_TCP_CONG_ILLINOIS=m
CONFIG_TCP_CONG_DCTCP=m
# CONFIG_TCP_CONG_CDG is not set
CONFIG_TCP_CONG_BBR=m
CONFIG_DEFAULT_CUBIC=y
# CONFIG_DEFAULT_RENO is not set
CONFIG_DEFAULT_TCP_CONG="cubic"
CONFIG_TCP_MD5SIG=y
CONFIG_IPV6=y
CONFIG_IPV6_ROUTER_PREF=y
CONFIG_IPV6_ROUTE_INFO=y
CONFIG_IPV6_OPTIMISTIC_DAD=y
CONFIG_INET6_AH=m
CONFIG_INET6_ESP=m
CONFIG_INET6_ESP_OFFLOAD=m
# CONFIG_INET6_ESPINTCP is not set
CONFIG_INET6_IPCOMP=m
CONFIG_IPV6_MIP6=m
# CONFIG_IPV6_ILA is not set
CONFIG_INET6_XFRM_TUNNEL=m
CONFIG_INET6_TUNNEL=m
CONFIG_IPV6_VTI=m
CONFIG_IPV6_SIT=m
CONFIG_IPV6_SIT_6RD=y
CONFIG_IPV6_NDISC_NODETYPE=y
CONFIG_IPV6_TUNNEL=m
CONFIG_IPV6_GRE=m
CONFIG_IPV6_MULTIPLE_TABLES=y
# CONFIG_IPV6_SUBTREES is not set
CONFIG_IPV6_MROUTE=y
CONFIG_IPV6_MROUTE_MULTIPLE_TABLES=y
CONFIG_IPV6_PIMSM_V2=y
# CONFIG_IPV6_SEG6_LWTUNNEL is not set
# CONFIG_IPV6_SEG6_HMAC is not set
# CONFIG_IPV6_RPL_LWTUNNEL is not set
# CONFIG_IPV6_IOAM6_LWTUNNEL is not set
CONFIG_NETLABEL=y
# CONFIG_MPTCP is not set
CONFIG_NETWORK_SECMARK=y
CONFIG_NET_PTP_CLASSIFY=y
CONFIG_NETWORK_PHY_TIMESTAMPING=y
CONFIG_NETFILTER=y
CONFIG_NETFILTER_ADVANCED=y
CONFIG_BRIDGE_NETFILTER=m

#
# Core Netfilter Configuration
#
CONFIG_NETFILTER_INGRESS=y
CONFIG_NETFILTER_EGRESS=y
CONFIG_NETFILTER_SKIP_EGRESS=y
CONFIG_NETFILTER_NETLINK=m
CONFIG_NETFILTER_FAMILY_BRIDGE=y
CONFIG_NETFILTER_FAMILY_ARP=y
# CONFIG_NETFILTER_NETLINK_HOOK is not set
# CONFIG_NETFILTER_NETLINK_ACCT is not set
CONFIG_NETFILTER_NETLINK_QUEUE=m
CONFIG_NETFILTER_NETLINK_LOG=m
CONFIG_NETFILTER_NETLINK_OSF=m
CONFIG_NF_CONNTRACK=m
CONFIG_NF_LOG_SYSLOG=m
CONFIG_NETFILTER_CONNCOUNT=m
CONFIG_NF_CONNTRACK_MARK=y
CONFIG_NF_CONNTRACK_SECMARK=y
CONFIG_NF_CONNTRACK_ZONES=y
CONFIG_NF_CONNTRACK_PROCFS=y
CONFIG_NF_CONNTRACK_EVENTS=y
CONFIG_NF_CONNTRACK_TIMEOUT=y
CONFIG_NF_CONNTRACK_TIMESTAMP=y
CONFIG_NF_CONNTRACK_LABELS=y
CONFIG_NF_CT_PROTO_DCCP=y
CONFIG_NF_CT_PROTO_GRE=y
CONFIG_NF_CT_PROTO_SCTP=y
CONFIG_NF_CT_PROTO_UDPLITE=y
CONFIG_NF_CONNTRACK_AMANDA=m
CONFIG_NF_CONNTRACK_FTP=m
CONFIG_NF_CONNTRACK_H323=m
CONFIG_NF_CONNTRACK_IRC=m
CONFIG_NF_CONNTRACK_BROADCAST=m
CONFIG_NF_CONNTRACK_NETBIOS_NS=m
CONFIG_NF_CONNTRACK_SNMP=m
CONFIG_NF_CONNTRACK_PPTP=m
CONFIG_NF_CONNTRACK_SANE=m
CONFIG_NF_CONNTRACK_SIP=m
CONFIG_NF_CONNTRACK_TFTP=m
CONFIG_NF_CT_NETLINK=m
CONFIG_NF_CT_NETLINK_TIMEOUT=m
CONFIG_NF_CT_NETLINK_HELPER=m
CONFIG_NETFILTER_NETLINK_GLUE_CT=y
CONFIG_NF_NAT=m
CONFIG_NF_NAT_AMANDA=m
CONFIG_NF_NAT_FTP=m
CONFIG_NF_NAT_IRC=m
CONFIG_NF_NAT_SIP=m
CONFIG_NF_NAT_TFTP=m
CONFIG_NF_NAT_REDIRECT=y
CONFIG_NF_NAT_MASQUERADE=y
CONFIG_NETFILTER_SYNPROXY=m
CONFIG_NF_TABLES=m
CONFIG_NF_TABLES_INET=y
CONFIG_NF_TABLES_NETDEV=y
CONFIG_NFT_NUMGEN=m
CONFIG_NFT_CT=m
CONFIG_NFT_CONNLIMIT=m
CONFIG_NFT_LOG=m
CONFIG_NFT_LIMIT=m
CONFIG_NFT_MASQ=m
CONFIG_NFT_REDIR=m
CONFIG_NFT_NAT=m
# CONFIG_NFT_TUNNEL is not set
# CONFIG_NFT_OBJREF is not set
CONFIG_NFT_QUEUE=m
CONFIG_NFT_QUOTA=m
CONFIG_NFT_REJECT=m
CONFIG_NFT_REJECT_INET=m
CONFIG_NFT_COMPAT=m
CONFIG_NFT_HASH=m
CONFIG_NFT_FIB=m
CONFIG_NFT_FIB_INET=m
# CONFIG_NFT_XFRM is not set
CONFIG_NFT_SOCKET=m
# CONFIG_NFT_OSF is not set
# CONFIG_NFT_TPROXY is not set
# CONFIG_NFT_SYNPROXY is not set
CONFIG_NF_DUP_NETDEV=m
CONFIG_NFT_DUP_NETDEV=m
CONFIG_NFT_FWD_NETDEV=m
CONFIG_NFT_FIB_NETDEV=m
# CONFIG_NFT_REJECT_NETDEV is not set
# CONFIG_NF_FLOW_TABLE is not set
CONFIG_NETFILTER_XTABLES=y
CONFIG_NETFILTER_XTABLES_COMPAT=y

#
# Xtables combined modules
#
CONFIG_NETFILTER_XT_MARK=m
CONFIG_NETFILTER_XT_CONNMARK=m
CONFIG_NETFILTER_XT_SET=m

#
# Xtables targets
#
CONFIG_NETFILTER_XT_TARGET_AUDIT=m
CONFIG_NETFILTER_XT_TARGET_CHECKSUM=m
CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
CONFIG_NETFILTER_XT_TARGET_CONNMARK=m
CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=m
CONFIG_NETFILTER_XT_TARGET_CT=m
CONFIG_NETFILTER_XT_TARGET_DSCP=m
CONFIG_NETFILTER_XT_TARGET_HL=m
CONFIG_NETFILTER_XT_TARGET_HMARK=m
CONFIG_NETFILTER_XT_TARGET_IDLETIMER=m
# CONFIG_NETFILTER_XT_TARGET_LED is not set
CONFIG_NETFILTER_XT_TARGET_LOG=m
CONFIG_NETFILTER_XT_TARGET_MARK=m
CONFIG_NETFILTER_XT_NAT=m
CONFIG_NETFILTER_XT_TARGET_NETMAP=m
CONFIG_NETFILTER_XT_TARGET_NFLOG=m
CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m
CONFIG_NETFILTER_XT_TARGET_NOTRACK=m
CONFIG_NETFILTER_XT_TARGET_RATEEST=m
CONFIG_NETFILTER_XT_TARGET_REDIRECT=m
CONFIG_NETFILTER_XT_TARGET_MASQUERADE=m
CONFIG_NETFILTER_XT_TARGET_TEE=m
CONFIG_NETFILTER_XT_TARGET_TPROXY=m
CONFIG_NETFILTER_XT_TARGET_TRACE=m
CONFIG_NETFILTER_XT_TARGET_SECMARK=m
CONFIG_NETFILTER_XT_TARGET_TCPMSS=m
CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP=m

#
# Xtables matches
#
CONFIG_NETFILTER_XT_MATCH_ADDRTYPE=m
CONFIG_NETFILTER_XT_MATCH_BPF=m
CONFIG_NETFILTER_XT_MATCH_CGROUP=m
CONFIG_NETFILTER_XT_MATCH_CLUSTER=m
CONFIG_NETFILTER_XT_MATCH_COMMENT=m
CONFIG_NETFILTER_XT_MATCH_CONNBYTES=m
CONFIG_NETFILTER_XT_MATCH_CONNLABEL=m
CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=m
CONFIG_NETFILTER_XT_MATCH_CONNMARK=m
CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m
CONFIG_NETFILTER_XT_MATCH_CPU=m
CONFIG_NETFILTER_XT_MATCH_DCCP=m
CONFIG_NETFILTER_XT_MATCH_DEVGROUP=m
CONFIG_NETFILTER_XT_MATCH_DSCP=m
CONFIG_NETFILTER_XT_MATCH_ECN=m
CONFIG_NETFILTER_XT_MATCH_ESP=m
CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=m
CONFIG_NETFILTER_XT_MATCH_HELPER=m
CONFIG_NETFILTER_XT_MATCH_HL=m
# CONFIG_NETFILTER_XT_MATCH_IPCOMP is not set
CONFIG_NETFILTER_XT_MATCH_IPRANGE=m
CONFIG_NETFILTER_XT_MATCH_IPVS=m
# CONFIG_NETFILTER_XT_MATCH_L2TP is not set
CONFIG_NETFILTER_XT_MATCH_LENGTH=m
CONFIG_NETFILTER_XT_MATCH_LIMIT=m
CONFIG_NETFILTER_XT_MATCH_MAC=m
CONFIG_NETFILTER_XT_MATCH_MARK=m
CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m
# CONFIG_NETFILTER_XT_MATCH_NFACCT is not set
CONFIG_NETFILTER_XT_MATCH_OSF=m
CONFIG_NETFILTER_XT_MATCH_OWNER=m
CONFIG_NETFILTER_XT_MATCH_POLICY=m
CONFIG_NETFILTER_XT_MATCH_PHYSDEV=m
CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m
CONFIG_NETFILTER_XT_MATCH_QUOTA=m
CONFIG_NETFILTER_XT_MATCH_RATEEST=m
CONFIG_NETFILTER_XT_MATCH_REALM=m
CONFIG_NETFILTER_XT_MATCH_RECENT=m
CONFIG_NETFILTER_XT_MATCH_SCTP=m
CONFIG_NETFILTER_XT_MATCH_SOCKET=m
CONFIG_NETFILTER_XT_MATCH_STATE=m
CONFIG_NETFILTER_XT_MATCH_STATISTIC=m
CONFIG_NETFILTER_XT_MATCH_STRING=m
CONFIG_NETFILTER_XT_MATCH_TCPMSS=m
# CONFIG_NETFILTER_XT_MATCH_TIME is not set
# CONFIG_NETFILTER_XT_MATCH_U32 is not set
# end of Core Netfilter Configuration

CONFIG_IP_SET=m
CONFIG_IP_SET_MAX=256
CONFIG_IP_SET_BITMAP_IP=m
CONFIG_IP_SET_BITMAP_IPMAC=m
CONFIG_IP_SET_BITMAP_PORT=m
CONFIG_IP_SET_HASH_IP=m
CONFIG_IP_SET_HASH_IPMARK=m
CONFIG_IP_SET_HASH_IPPORT=m
CONFIG_IP_SET_HASH_IPPORTIP=m
CONFIG_IP_SET_HASH_IPPORTNET=m
CONFIG_IP_SET_HASH_IPMAC=m
CONFIG_IP_SET_HASH_MAC=m
CONFIG_IP_SET_HASH_NETPORTNET=m
CONFIG_IP_SET_HASH_NET=m
CONFIG_IP_SET_HASH_NETNET=m
CONFIG_IP_SET_HASH_NETPORT=m
CONFIG_IP_SET_HASH_NETIFACE=m
CONFIG_IP_SET_LIST_SET=m
CONFIG_IP_VS=m
CONFIG_IP_VS_IPV6=y
# CONFIG_IP_VS_DEBUG is not set
CONFIG_IP_VS_TAB_BITS=12

#
# IPVS transport protocol load balancing support
#
CONFIG_IP_VS_PROTO_TCP=y
CONFIG_IP_VS_PROTO_UDP=y
CONFIG_IP_VS_PROTO_AH_ESP=y
CONFIG_IP_VS_PROTO_ESP=y
CONFIG_IP_VS_PROTO_AH=y
CONFIG_IP_VS_PROTO_SCTP=y

#
# IPVS scheduler
#
CONFIG_IP_VS_RR=m
CONFIG_IP_VS_WRR=m
CONFIG_IP_VS_LC=m
CONFIG_IP_VS_WLC=m
CONFIG_IP_VS_FO=m
CONFIG_IP_VS_OVF=m
CONFIG_IP_VS_LBLC=m
CONFIG_IP_VS_LBLCR=m
CONFIG_IP_VS_DH=m
CONFIG_IP_VS_SH=m
# CONFIG_IP_VS_MH is not set
CONFIG_IP_VS_SED=m
CONFIG_IP_VS_NQ=m
# CONFIG_IP_VS_TWOS is not set

#
# IPVS SH scheduler
#
CONFIG_IP_VS_SH_TAB_BITS=8

#
# IPVS MH scheduler
#
CONFIG_IP_VS_MH_TAB_INDEX=12

#
# IPVS application helper
#
CONFIG_IP_VS_FTP=m
CONFIG_IP_VS_NFCT=y
CONFIG_IP_VS_PE_SIP=m

#
# IP: Netfilter Configuration
#
CONFIG_NF_DEFRAG_IPV4=m
CONFIG_NF_SOCKET_IPV4=m
CONFIG_NF_TPROXY_IPV4=m
CONFIG_NF_TABLES_IPV4=y
CONFIG_NFT_REJECT_IPV4=m
CONFIG_NFT_DUP_IPV4=m
CONFIG_NFT_FIB_IPV4=m
CONFIG_NF_TABLES_ARP=y
CONFIG_NF_DUP_IPV4=m
CONFIG_NF_LOG_ARP=m
CONFIG_NF_LOG_IPV4=m
CONFIG_NF_REJECT_IPV4=m
CONFIG_NF_NAT_SNMP_BASIC=m
CONFIG_NF_NAT_PPTP=m
CONFIG_NF_NAT_H323=m
CONFIG_IP_NF_IPTABLES=m
CONFIG_IP_NF_MATCH_AH=m
CONFIG_IP_NF_MATCH_ECN=m
CONFIG_IP_NF_MATCH_RPFILTER=m
CONFIG_IP_NF_MATCH_TTL=m
CONFIG_IP_NF_FILTER=m
CONFIG_IP_NF_TARGET_REJECT=m
CONFIG_IP_NF_TARGET_SYNPROXY=m
CONFIG_IP_NF_NAT=m
CONFIG_IP_NF_TARGET_MASQUERADE=m
CONFIG_IP_NF_TARGET_NETMAP=m
CONFIG_IP_NF_TARGET_REDIRECT=m
CONFIG_IP_NF_MANGLE=m
# CONFIG_IP_NF_TARGET_CLUSTERIP is not set
CONFIG_IP_NF_TARGET_ECN=m
CONFIG_IP_NF_TARGET_TTL=m
CONFIG_IP_NF_RAW=m
CONFIG_IP_NF_SECURITY=m
CONFIG_IP_NF_ARPTABLES=m
CONFIG_IP_NF_ARPFILTER=m
CONFIG_IP_NF_ARP_MANGLE=m
# end of IP: Netfilter Configuration

#
# IPv6: Netfilter Configuration
#
CONFIG_NF_SOCKET_IPV6=m
CONFIG_NF_TPROXY_IPV6=m
CONFIG_NF_TABLES_IPV6=y
CONFIG_NFT_REJECT_IPV6=m
CONFIG_NFT_DUP_IPV6=m
CONFIG_NFT_FIB_IPV6=m
CONFIG_NF_DUP_IPV6=m
CONFIG_NF_REJECT_IPV6=m
CONFIG_NF_LOG_IPV6=m
CONFIG_IP6_NF_IPTABLES=m
CONFIG_IP6_NF_MATCH_AH=m
CONFIG_IP6_NF_MATCH_EUI64=m
CONFIG_IP6_NF_MATCH_FRAG=m
CONFIG_IP6_NF_MATCH_OPTS=m
CONFIG_IP6_NF_MATCH_HL=m
CONFIG_IP6_NF_MATCH_IPV6HEADER=m
CONFIG_IP6_NF_MATCH_MH=m
CONFIG_IP6_NF_MATCH_RPFILTER=m
CONFIG_IP6_NF_MATCH_RT=m
# CONFIG_IP6_NF_MATCH_SRH is not set
# CONFIG_IP6_NF_TARGET_HL is not set
CONFIG_IP6_NF_FILTER=m
CONFIG_IP6_NF_TARGET_REJECT=m
CONFIG_IP6_NF_TARGET_SYNPROXY=m
CONFIG_IP6_NF_MANGLE=m
CONFIG_IP6_NF_RAW=m
CONFIG_IP6_NF_SECURITY=m
CONFIG_IP6_NF_NAT=m
CONFIG_IP6_NF_TARGET_MASQUERADE=m
CONFIG_IP6_NF_TARGET_NPT=m
# end of IPv6: Netfilter Configuration

CONFIG_NF_DEFRAG_IPV6=m
CONFIG_NF_TABLES_BRIDGE=m
# CONFIG_NFT_BRIDGE_META is not set
CONFIG_NFT_BRIDGE_REJECT=m
# CONFIG_NF_CONNTRACK_BRIDGE is not set
CONFIG_BRIDGE_NF_EBTABLES=m
CONFIG_BRIDGE_EBT_BROUTE=m
CONFIG_BRIDGE_EBT_T_FILTER=m
CONFIG_BRIDGE_EBT_T_NAT=m
CONFIG_BRIDGE_EBT_802_3=m
CONFIG_BRIDGE_EBT_AMONG=m
CONFIG_BRIDGE_EBT_ARP=m
CONFIG_BRIDGE_EBT_IP=m
CONFIG_BRIDGE_EBT_IP6=m
CONFIG_BRIDGE_EBT_LIMIT=m
CONFIG_BRIDGE_EBT_MARK=m
CONFIG_BRIDGE_EBT_PKTTYPE=m
CONFIG_BRIDGE_EBT_STP=m
CONFIG_BRIDGE_EBT_VLAN=m
CONFIG_BRIDGE_EBT_ARPREPLY=m
CONFIG_BRIDGE_EBT_DNAT=m
CONFIG_BRIDGE_EBT_MARK_T=m
CONFIG_BRIDGE_EBT_REDIRECT=m
CONFIG_BRIDGE_EBT_SNAT=m
CONFIG_BRIDGE_EBT_LOG=m
CONFIG_BRIDGE_EBT_NFLOG=m
# CONFIG_BPFILTER is not set
CONFIG_IP_DCCP=y
CONFIG_INET_DCCP_DIAG=m

#
# DCCP CCIDs Configuration
#
# CONFIG_IP_DCCP_CCID2_DEBUG is not set
CONFIG_IP_DCCP_CCID3=y
# CONFIG_IP_DCCP_CCID3_DEBUG is not set
CONFIG_IP_DCCP_TFRC_LIB=y
# end of DCCP CCIDs Configuration

#
# DCCP Kernel Hacking
#
# CONFIG_IP_DCCP_DEBUG is not set
# end of DCCP Kernel Hacking

CONFIG_IP_SCTP=m
# CONFIG_SCTP_DBG_OBJCNT is not set
# CONFIG_SCTP_DEFAULT_COOKIE_HMAC_MD5 is not set
CONFIG_SCTP_DEFAULT_COOKIE_HMAC_SHA1=y
# CONFIG_SCTP_DEFAULT_COOKIE_HMAC_NONE is not set
CONFIG_SCTP_COOKIE_HMAC_MD5=y
CONFIG_SCTP_COOKIE_HMAC_SHA1=y
CONFIG_INET_SCTP_DIAG=m
# CONFIG_RDS is not set
CONFIG_TIPC=m
CONFIG_TIPC_MEDIA_UDP=y
CONFIG_TIPC_CRYPTO=y
CONFIG_TIPC_DIAG=m
CONFIG_ATM=m
CONFIG_ATM_CLIP=m
# CONFIG_ATM_CLIP_NO_ICMP is not set
CONFIG_ATM_LANE=m
# CONFIG_ATM_MPOA is not set
CONFIG_ATM_BR2684=m
# CONFIG_ATM_BR2684_IPFILTER is not set
CONFIG_L2TP=m
CONFIG_L2TP_DEBUGFS=m
CONFIG_L2TP_V3=y
CONFIG_L2TP_IP=m
CONFIG_L2TP_ETH=m
CONFIG_STP=m
CONFIG_GARP=m
CONFIG_MRP=m
CONFIG_BRIDGE=m
CONFIG_BRIDGE_IGMP_SNOOPING=y
CONFIG_BRIDGE_VLAN_FILTERING=y
# CONFIG_BRIDGE_MRP is not set
# CONFIG_BRIDGE_CFM is not set
# CONFIG_NET_DSA is not set
CONFIG_VLAN_8021Q=m
CONFIG_VLAN_8021Q_GVRP=y
CONFIG_VLAN_8021Q_MVRP=y
# CONFIG_DECNET is not set
CONFIG_LLC=m
# CONFIG_LLC2 is not set
# CONFIG_ATALK is not set
# CONFIG_X25 is not set
# CONFIG_LAPB is not set
# CONFIG_PHONET is not set
CONFIG_6LOWPAN=m
# CONFIG_6LOWPAN_DEBUGFS is not set
# CONFIG_6LOWPAN_NHC is not set
# CONFIG_IEEE802154 is not set
CONFIG_NET_SCHED=y

#
# Queueing/Scheduling
#
CONFIG_NET_SCH_CBQ=m
CONFIG_NET_SCH_HTB=m
CONFIG_NET_SCH_HFSC=m
CONFIG_NET_SCH_ATM=m
CONFIG_NET_SCH_PRIO=m
CONFIG_NET_SCH_MULTIQ=m
CONFIG_NET_SCH_RED=m
CONFIG_NET_SCH_SFB=m
CONFIG_NET_SCH_SFQ=m
CONFIG_NET_SCH_TEQL=m
CONFIG_NET_SCH_TBF=m
# CONFIG_NET_SCH_CBS is not set
# CONFIG_NET_SCH_ETF is not set
# CONFIG_NET_SCH_TAPRIO is not set
CONFIG_NET_SCH_GRED=m
CONFIG_NET_SCH_DSMARK=m
CONFIG_NET_SCH_NETEM=m
CONFIG_NET_SCH_DRR=m
CONFIG_NET_SCH_MQPRIO=m
# CONFIG_NET_SCH_SKBPRIO is not set
CONFIG_NET_SCH_CHOKE=m
CONFIG_NET_SCH_QFQ=m
CONFIG_NET_SCH_CODEL=m
CONFIG_NET_SCH_FQ_CODEL=y
# CONFIG_NET_SCH_CAKE is not set
CONFIG_NET_SCH_FQ=m
CONFIG_NET_SCH_HHF=m
CONFIG_NET_SCH_PIE=m
# CONFIG_NET_SCH_FQ_PIE is not set
CONFIG_NET_SCH_INGRESS=m
CONFIG_NET_SCH_PLUG=m
# CONFIG_NET_SCH_ETS is not set
CONFIG_NET_SCH_DEFAULT=y
# CONFIG_DEFAULT_FQ is not set
# CONFIG_DEFAULT_CODEL is not set
CONFIG_DEFAULT_FQ_CODEL=y
# CONFIG_DEFAULT_SFQ is not set
# CONFIG_DEFAULT_PFIFO_FAST is not set
CONFIG_DEFAULT_NET_SCH="fq_codel"

#
# Classification
#
CONFIG_NET_CLS=y
CONFIG_NET_CLS_BASIC=m
CONFIG_NET_CLS_TCINDEX=m
CONFIG_NET_CLS_ROUTE4=m
CONFIG_NET_CLS_FW=m
CONFIG_NET_CLS_U32=m
CONFIG_CLS_U32_PERF=y
CONFIG_CLS_U32_MARK=y
CONFIG_NET_CLS_RSVP=m
CONFIG_NET_CLS_RSVP6=m
CONFIG_NET_CLS_FLOW=m
CONFIG_NET_CLS_CGROUP=y
CONFIG_NET_CLS_BPF=m
CONFIG_NET_CLS_FLOWER=m
CONFIG_NET_CLS_MATCHALL=m
CONFIG_NET_EMATCH=y
CONFIG_NET_EMATCH_STACK=32
CONFIG_NET_EMATCH_CMP=m
CONFIG_NET_EMATCH_NBYTE=m
CONFIG_NET_EMATCH_U32=m
CONFIG_NET_EMATCH_META=m
CONFIG_NET_EMATCH_TEXT=m
# CONFIG_NET_EMATCH_CANID is not set
CONFIG_NET_EMATCH_IPSET=m
# CONFIG_NET_EMATCH_IPT is not set
CONFIG_NET_CLS_ACT=y
CONFIG_NET_ACT_POLICE=m
CONFIG_NET_ACT_GACT=m
CONFIG_GACT_PROB=y
CONFIG_NET_ACT_MIRRED=m
CONFIG_NET_ACT_SAMPLE=m
# CONFIG_NET_ACT_IPT is not set
CONFIG_NET_ACT_NAT=m
CONFIG_NET_ACT_PEDIT=m
CONFIG_NET_ACT_SIMP=m
CONFIG_NET_ACT_SKBEDIT=m
CONFIG_NET_ACT_CSUM=m
# CONFIG_NET_ACT_MPLS is not set
CONFIG_NET_ACT_VLAN=m
CONFIG_NET_ACT_BPF=m
# CONFIG_NET_ACT_CONNMARK is not set
# CONFIG_NET_ACT_CTINFO is not set
CONFIG_NET_ACT_SKBMOD=m
# CONFIG_NET_ACT_IFE is not set
CONFIG_NET_ACT_TUNNEL_KEY=m
# CONFIG_NET_ACT_GATE is not set
# CONFIG_NET_TC_SKB_EXT is not set
CONFIG_NET_SCH_FIFO=y
CONFIG_DCB=y
CONFIG_DNS_RESOLVER=m
# CONFIG_BATMAN_ADV is not set
CONFIG_OPENVSWITCH=m
CONFIG_OPENVSWITCH_GRE=m
CONFIG_VSOCKETS=m
CONFIG_VSOCKETS_DIAG=m
CONFIG_VSOCKETS_LOOPBACK=m
CONFIG_VMWARE_VMCI_VSOCKETS=m
CONFIG_VIRTIO_VSOCKETS=m
CONFIG_VIRTIO_VSOCKETS_COMMON=m
CONFIG_NETLINK_DIAG=m
CONFIG_MPLS=y
CONFIG_NET_MPLS_GSO=y
CONFIG_MPLS_ROUTING=m
CONFIG_MPLS_IPTUNNEL=m
CONFIG_NET_NSH=y
# CONFIG_HSR is not set
CONFIG_NET_SWITCHDEV=y
CONFIG_NET_L3_MASTER_DEV=y
# CONFIG_QRTR is not set
# CONFIG_NET_NCSI is not set
CONFIG_PCPU_DEV_REFCNT=y
CONFIG_RPS=y
CONFIG_RFS_ACCEL=y
CONFIG_SOCK_RX_QUEUE_MAPPING=y
CONFIG_XPS=y
CONFIG_CGROUP_NET_PRIO=y
CONFIG_CGROUP_NET_CLASSID=y
CONFIG_NET_RX_BUSY_POLL=y
CONFIG_BQL=y
CONFIG_NET_FLOW_LIMIT=y

#
# Network testing
#
CONFIG_NET_PKTGEN=m
CONFIG_NET_DROP_MONITOR=y
# end of Network testing
# end of Networking options

# CONFIG_HAMRADIO is not set
CONFIG_CAN=m
CONFIG_CAN_RAW=m
CONFIG_CAN_BCM=m
CONFIG_CAN_GW=m
# CONFIG_CAN_J1939 is not set
# CONFIG_CAN_ISOTP is not set
# CONFIG_BT is not set
# CONFIG_AF_RXRPC is not set
# CONFIG_AF_KCM is not set
CONFIG_STREAM_PARSER=y
# CONFIG_MCTP is not set
CONFIG_FIB_RULES=y
CONFIG_WIRELESS=y
CONFIG_CFG80211=m
# CONFIG_NL80211_TESTMODE is not set
# CONFIG_CFG80211_DEVELOPER_WARNINGS is not set
CONFIG_CFG80211_REQUIRE_SIGNED_REGDB=y
CONFIG_CFG80211_USE_KERNEL_REGDB_KEYS=y
CONFIG_CFG80211_DEFAULT_PS=y
# CONFIG_CFG80211_DEBUGFS is not set
CONFIG_CFG80211_CRDA_SUPPORT=y
# CONFIG_CFG80211_WEXT is not set
CONFIG_MAC80211=m
CONFIG_MAC80211_HAS_RC=y
CONFIG_MAC80211_RC_MINSTREL=y
CONFIG_MAC80211_RC_DEFAULT_MINSTREL=y
CONFIG_MAC80211_RC_DEFAULT="minstrel_ht"
# CONFIG_MAC80211_MESH is not set
CONFIG_MAC80211_LEDS=y
CONFIG_MAC80211_DEBUGFS=y
# CONFIG_MAC80211_MESSAGE_TRACING is not set
# CONFIG_MAC80211_DEBUG_MENU is not set
CONFIG_MAC80211_STA_HASH_MAX_SIZE=0
CONFIG_RFKILL=m
CONFIG_RFKILL_LEDS=y
CONFIG_RFKILL_INPUT=y
# CONFIG_RFKILL_GPIO is not set
CONFIG_NET_9P=y
CONFIG_NET_9P_FD=y
CONFIG_NET_9P_VIRTIO=y
# CONFIG_NET_9P_DEBUG is not set
# CONFIG_CAIF is not set
CONFIG_CEPH_LIB=m
# CONFIG_CEPH_LIB_PRETTYDEBUG is not set
CONFIG_CEPH_LIB_USE_DNS_RESOLVER=y
# CONFIG_NFC is not set
CONFIG_PSAMPLE=m
# CONFIG_NET_IFE is not set
CONFIG_LWTUNNEL=y
CONFIG_LWTUNNEL_BPF=y
CONFIG_DST_CACHE=y
CONFIG_GRO_CELLS=y
CONFIG_SOCK_VALIDATE_XMIT=y
CONFIG_NET_SELFTESTS=y
CONFIG_NET_SOCK_MSG=y
CONFIG_PAGE_POOL=y
# CONFIG_PAGE_POOL_STATS is not set
CONFIG_FAILOVER=m
CONFIG_ETHTOOL_NETLINK=y

#
# Device Drivers
#
CONFIG_HAVE_EISA=y
# CONFIG_EISA is not set
CONFIG_HAVE_PCI=y
CONFIG_PCI=y
CONFIG_PCI_DOMAINS=y
CONFIG_PCIEPORTBUS=y
CONFIG_HOTPLUG_PCI_PCIE=y
CONFIG_PCIEAER=y
CONFIG_PCIEAER_INJECT=m
CONFIG_PCIE_ECRC=y
CONFIG_PCIEASPM=y
CONFIG_PCIEASPM_DEFAULT=y
# CONFIG_PCIEASPM_POWERSAVE is not set
# CONFIG_PCIEASPM_POWER_SUPERSAVE is not set
# CONFIG_PCIEASPM_PERFORMANCE is not set
CONFIG_PCIE_PME=y
CONFIG_PCIE_DPC=y
# CONFIG_PCIE_PTM is not set
# CONFIG_PCIE_EDR is not set
CONFIG_PCI_MSI=y
CONFIG_PCI_MSI_IRQ_DOMAIN=y
CONFIG_PCI_QUIRKS=y
# CONFIG_PCI_DEBUG is not set
# CONFIG_PCI_REALLOC_ENABLE_AUTO is not set
CONFIG_PCI_STUB=y
CONFIG_PCI_PF_STUB=m
CONFIG_PCI_ATS=y
CONFIG_PCI_LOCKLESS_CONFIG=y
CONFIG_PCI_IOV=y
CONFIG_PCI_PRI=y
CONFIG_PCI_PASID=y
# CONFIG_PCI_P2PDMA is not set
CONFIG_PCI_LABEL=y
CONFIG_VGA_ARB=y
CONFIG_VGA_ARB_MAX_GPUS=64
CONFIG_HOTPLUG_PCI=y
CONFIG_HOTPLUG_PCI_ACPI=y
CONFIG_HOTPLUG_PCI_ACPI_IBM=m
# CONFIG_HOTPLUG_PCI_CPCI is not set
CONFIG_HOTPLUG_PCI_SHPC=y

#
# PCI controller drivers
#
CONFIG_VMD=y

#
# DesignWare PCI Core Support
#
# CONFIG_PCIE_DW_PLAT_HOST is not set
# CONFIG_PCI_MESON is not set
# end of DesignWare PCI Core Support

#
# Mobiveil PCIe Core Support
#
# end of Mobiveil PCIe Core Support

#
# Cadence PCIe controllers support
#
# end of Cadence PCIe controllers support
# end of PCI controller drivers

#
# PCI Endpoint
#
# CONFIG_PCI_ENDPOINT is not set
# end of PCI Endpoint

#
# PCI switch controller drivers
#
# CONFIG_PCI_SW_SWITCHTEC is not set
# end of PCI switch controller drivers

# CONFIG_CXL_BUS is not set
# CONFIG_PCCARD is not set
# CONFIG_RAPIDIO is not set

#
# Generic Driver Options
#
CONFIG_AUXILIARY_BUS=y
# CONFIG_UEVENT_HELPER is not set
CONFIG_DEVTMPFS=y
CONFIG_DEVTMPFS_MOUNT=y
# CONFIG_DEVTMPFS_SAFE is not set
CONFIG_STANDALONE=y
CONFIG_PREVENT_FIRMWARE_BUILD=y

#
# Firmware loader
#
CONFIG_FW_LOADER=y
CONFIG_FW_LOADER_PAGED_BUF=y
CONFIG_FW_LOADER_SYSFS=y
CONFIG_EXTRA_FIRMWARE=""
CONFIG_FW_LOADER_USER_HELPER=y
# CONFIG_FW_LOADER_USER_HELPER_FALLBACK is not set
# CONFIG_FW_LOADER_COMPRESS is not set
CONFIG_FW_CACHE=y
# CONFIG_FW_UPLOAD is not set
# end of Firmware loader

CONFIG_ALLOW_DEV_COREDUMP=y
# CONFIG_DEBUG_DRIVER is not set
# CONFIG_DEBUG_DEVRES is not set
# CONFIG_DEBUG_TEST_DRIVER_REMOVE is not set
# CONFIG_TEST_ASYNC_DRIVER_PROBE is not set
CONFIG_GENERIC_CPU_AUTOPROBE=y
CONFIG_GENERIC_CPU_VULNERABILITIES=y
CONFIG_REGMAP=y
CONFIG_REGMAP_I2C=m
CONFIG_REGMAP_SPI=m
CONFIG_DMA_SHARED_BUFFER=y
# CONFIG_DMA_FENCE_TRACE is not set
# end of Generic Driver Options

#
# Bus devices
#
# CONFIG_MHI_BUS is not set
# CONFIG_MHI_BUS_EP is not set
# end of Bus devices

CONFIG_CONNECTOR=y
CONFIG_PROC_EVENTS=y

#
# Firmware Drivers
#

#
# ARM System Control and Management Interface Protocol
#
# end of ARM System Control and Management Interface Protocol

CONFIG_EDD=m
# CONFIG_EDD_OFF is not set
CONFIG_FIRMWARE_MEMMAP=y
CONFIG_DMIID=y
CONFIG_DMI_SYSFS=y
CONFIG_DMI_SCAN_MACHINE_NON_EFI_FALLBACK=y
# CONFIG_ISCSI_IBFT is not set
CONFIG_FW_CFG_SYSFS=y
# CONFIG_FW_CFG_SYSFS_CMDLINE is not set
CONFIG_SYSFB=y
# CONFIG_SYSFB_SIMPLEFB is not set
# CONFIG_GOOGLE_FIRMWARE is not set

#
# EFI (Extensible Firmware Interface) Support
#
CONFIG_EFI_ESRT=y
CONFIG_EFI_VARS_PSTORE=y
CONFIG_EFI_VARS_PSTORE_DEFAULT_DISABLE=y
CONFIG_EFI_RUNTIME_MAP=y
# CONFIG_EFI_FAKE_MEMMAP is not set
CONFIG_EFI_DXE_MEM_ATTRIBUTES=y
CONFIG_EFI_RUNTIME_WRAPPERS=y
CONFIG_EFI_GENERIC_STUB_INITRD_CMDLINE_LOADER=y
# CONFIG_EFI_BOOTLOADER_CONTROL is not set
# CONFIG_EFI_CAPSULE_LOADER is not set
# CONFIG_EFI_TEST is not set
# CONFIG_APPLE_PROPERTIES is not set
# CONFIG_RESET_ATTACK_MITIGATION is not set
# CONFIG_EFI_RCI2_TABLE is not set
# CONFIG_EFI_DISABLE_PCI_DMA is not set
CONFIG_EFI_EARLYCON=y
CONFIG_EFI_CUSTOM_SSDT_OVERLAYS=y
# CONFIG_EFI_DISABLE_RUNTIME is not set
# CONFIG_EFI_COCO_SECRET is not set
# end of EFI (Extensible Firmware Interface) Support

CONFIG_UEFI_CPER=y
CONFIG_UEFI_CPER_X86=y

#
# Tegra firmware driver
#
# end of Tegra firmware driver
# end of Firmware Drivers

# CONFIG_GNSS is not set
# CONFIG_MTD is not set
# CONFIG_OF is not set
CONFIG_ARCH_MIGHT_HAVE_PC_PARPORT=y
CONFIG_PARPORT=m
CONFIG_PARPORT_PC=m
CONFIG_PARPORT_SERIAL=m
# CONFIG_PARPORT_PC_FIFO is not set
# CONFIG_PARPORT_PC_SUPERIO is not set
# CONFIG_PARPORT_AX88796 is not set
CONFIG_PARPORT_1284=y
CONFIG_PNP=y
# CONFIG_PNP_DEBUG_MESSAGES is not set

#
# Protocols
#
CONFIG_PNPACPI=y
CONFIG_BLK_DEV=y
CONFIG_BLK_DEV_NULL_BLK=m
# CONFIG_BLK_DEV_FD is not set
CONFIG_CDROM=m
# CONFIG_PARIDE is not set
# CONFIG_BLK_DEV_PCIESSD_MTIP32XX is not set
# CONFIG_ZRAM is not set
CONFIG_BLK_DEV_LOOP=m
CONFIG_BLK_DEV_LOOP_MIN_COUNT=0
# CONFIG_BLK_DEV_DRBD is not set
CONFIG_BLK_DEV_NBD=m
CONFIG_BLK_DEV_RAM=m
CONFIG_BLK_DEV_RAM_COUNT=16
CONFIG_BLK_DEV_RAM_SIZE=16384
# CONFIG_CDROM_PKTCDVD is not set
# CONFIG_ATA_OVER_ETH is not set
CONFIG_VIRTIO_BLK=m
CONFIG_BLK_DEV_RBD=m
# CONFIG_BLK_DEV_UBLK is not set

#
# NVME Support
#
CONFIG_NVME_CORE=m
CONFIG_BLK_DEV_NVME=m
CONFIG_NVME_MULTIPATH=y
# CONFIG_NVME_VERBOSE_ERRORS is not set
# CONFIG_NVME_HWMON is not set
CONFIG_NVME_FABRICS=m
# CONFIG_NVME_FC is not set
# CONFIG_NVME_TCP is not set
# CONFIG_NVME_AUTH is not set
CONFIG_NVME_TARGET=m
# CONFIG_NVME_TARGET_PASSTHRU is not set
CONFIG_NVME_TARGET_LOOP=m
CONFIG_NVME_TARGET_FC=m
# CONFIG_NVME_TARGET_TCP is not set
# CONFIG_NVME_TARGET_AUTH is not set
# end of NVME Support

#
# Misc devices
#
CONFIG_SENSORS_LIS3LV02D=m
# CONFIG_AD525X_DPOT is not set
# CONFIG_DUMMY_IRQ is not set
# CONFIG_IBM_ASM is not set
# CONFIG_PHANTOM is not set
CONFIG_TIFM_CORE=m
CONFIG_TIFM_7XX1=m
# CONFIG_ICS932S401 is not set
CONFIG_ENCLOSURE_SERVICES=m
CONFIG_SGI_XP=m
CONFIG_HP_ILO=m
CONFIG_SGI_GRU=m
# CONFIG_SGI_GRU_DEBUG is not set
CONFIG_APDS9802ALS=m
CONFIG_ISL29003=m
CONFIG_ISL29020=m
CONFIG_SENSORS_TSL2550=m
CONFIG_SENSORS_BH1770=m
CONFIG_SENSORS_APDS990X=m
# CONFIG_HMC6352 is not set
# CONFIG_DS1682 is not set
CONFIG_VMWARE_BALLOON=m
# CONFIG_LATTICE_ECP3_CONFIG is not set
# CONFIG_SRAM is not set
# CONFIG_DW_XDATA_PCIE is not set
# CONFIG_PCI_ENDPOINT_TEST is not set
# CONFIG_XILINX_SDFEC is not set
CONFIG_MISC_RTSX=m
# CONFIG_C2PORT is not set

#
# EEPROM support
#
# CONFIG_EEPROM_AT24 is not set
# CONFIG_EEPROM_AT25 is not set
CONFIG_EEPROM_LEGACY=m
CONFIG_EEPROM_MAX6875=m
CONFIG_EEPROM_93CX6=m
# CONFIG_EEPROM_93XX46 is not set
# CONFIG_EEPROM_IDT_89HPESX is not set
# CONFIG_EEPROM_EE1004 is not set
# end of EEPROM support

CONFIG_CB710_CORE=m
# CONFIG_CB710_DEBUG is not set
CONFIG_CB710_DEBUG_ASSUMPTIONS=y

#
# Texas Instruments shared transport line discipline
#
# CONFIG_TI_ST is not set
# end of Texas Instruments shared transport line discipline

CONFIG_SENSORS_LIS3_I2C=m
CONFIG_ALTERA_STAPL=m
CONFIG_INTEL_MEI=m
CONFIG_INTEL_MEI_ME=m
# CONFIG_INTEL_MEI_TXE is not set
# CONFIG_INTEL_MEI_GSC is not set
# CONFIG_INTEL_MEI_HDCP is not set
# CONFIG_INTEL_MEI_PXP is not set
CONFIG_VMWARE_VMCI=m
# CONFIG_GENWQE is not set
# CONFIG_ECHO is not set
# CONFIG_BCM_VK is not set
# CONFIG_MISC_ALCOR_PCI is not set
CONFIG_MISC_RTSX_PCI=m
# CONFIG_MISC_RTSX_USB is not set
# CONFIG_HABANA_AI is not set
# CONFIG_UACCE is not set
CONFIG_PVPANIC=y
# CONFIG_PVPANIC_MMIO is not set
# CONFIG_PVPANIC_PCI is not set
# end of Misc devices

#
# SCSI device support
#
CONFIG_SCSI_MOD=y
CONFIG_RAID_ATTRS=m
CONFIG_SCSI_COMMON=y
CONFIG_SCSI=y
CONFIG_SCSI_DMA=y
CONFIG_SCSI_NETLINK=y
CONFIG_SCSI_PROC_FS=y

#
# SCSI support type (disk, tape, CD-ROM)
#
CONFIG_BLK_DEV_SD=m
CONFIG_CHR_DEV_ST=m
CONFIG_BLK_DEV_SR=m
CONFIG_CHR_DEV_SG=m
CONFIG_BLK_DEV_BSG=y
CONFIG_CHR_DEV_SCH=m
CONFIG_SCSI_ENCLOSURE=m
CONFIG_SCSI_CONSTANTS=y
CONFIG_SCSI_LOGGING=y
CONFIG_SCSI_SCAN_ASYNC=y

#
# SCSI Transports
#
CONFIG_SCSI_SPI_ATTRS=m
CONFIG_SCSI_FC_ATTRS=m
CONFIG_SCSI_ISCSI_ATTRS=m
CONFIG_SCSI_SAS_ATTRS=m
CONFIG_SCSI_SAS_LIBSAS=m
CONFIG_SCSI_SAS_ATA=y
CONFIG_SCSI_SAS_HOST_SMP=y
CONFIG_SCSI_SRP_ATTRS=m
# end of SCSI Transports

CONFIG_SCSI_LOWLEVEL=y
# CONFIG_ISCSI_TCP is not set
# CONFIG_ISCSI_BOOT_SYSFS is not set
# CONFIG_SCSI_CXGB3_ISCSI is not set
# CONFIG_SCSI_CXGB4_ISCSI is not set
# CONFIG_SCSI_BNX2_ISCSI is not set
# CONFIG_BE2ISCSI is not set
# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
# CONFIG_SCSI_HPSA is not set
# CONFIG_SCSI_3W_9XXX is not set
# CONFIG_SCSI_3W_SAS is not set
# CONFIG_SCSI_ACARD is not set
# CONFIG_SCSI_AACRAID is not set
# CONFIG_SCSI_AIC7XXX is not set
# CONFIG_SCSI_AIC79XX is not set
# CONFIG_SCSI_AIC94XX is not set
# CONFIG_SCSI_MVSAS is not set
# CONFIG_SCSI_MVUMI is not set
# CONFIG_SCSI_ADVANSYS is not set
# CONFIG_SCSI_ARCMSR is not set
# CONFIG_SCSI_ESAS2R is not set
# CONFIG_MEGARAID_NEWGEN is not set
# CONFIG_MEGARAID_LEGACY is not set
# CONFIG_MEGARAID_SAS is not set
CONFIG_SCSI_MPT3SAS=m
CONFIG_SCSI_MPT2SAS_MAX_SGE=128
CONFIG_SCSI_MPT3SAS_MAX_SGE=128
# CONFIG_SCSI_MPT2SAS is not set
# CONFIG_SCSI_MPI3MR is not set
# CONFIG_SCSI_SMARTPQI is not set
# CONFIG_SCSI_HPTIOP is not set
# CONFIG_SCSI_BUSLOGIC is not set
# CONFIG_SCSI_MYRB is not set
# CONFIG_SCSI_MYRS is not set
# CONFIG_VMWARE_PVSCSI is not set
# CONFIG_LIBFC is not set
# CONFIG_SCSI_SNIC is not set
# CONFIG_SCSI_DMX3191D is not set
# CONFIG_SCSI_FDOMAIN_PCI is not set
CONFIG_SCSI_ISCI=m
# CONFIG_SCSI_IPS is not set
# CONFIG_SCSI_INITIO is not set
# CONFIG_SCSI_INIA100 is not set
# CONFIG_SCSI_PPA is not set
# CONFIG_SCSI_IMM is not set
# CONFIG_SCSI_STEX is not set
# CONFIG_SCSI_SYM53C8XX_2 is not set
# CONFIG_SCSI_IPR is not set
# CONFIG_SCSI_QLOGIC_1280 is not set
# CONFIG_SCSI_QLA_FC is not set
# CONFIG_SCSI_QLA_ISCSI is not set
# CONFIG_SCSI_LPFC is not set
# CONFIG_SCSI_EFCT is not set
# CONFIG_SCSI_DC395x is not set
# CONFIG_SCSI_AM53C974 is not set
# CONFIG_SCSI_WD719X is not set
CONFIG_SCSI_DEBUG=m
# CONFIG_SCSI_PMCRAID is not set
# CONFIG_SCSI_PM8001 is not set
# CONFIG_SCSI_BFA_FC is not set
# CONFIG_SCSI_VIRTIO is not set
# CONFIG_SCSI_CHELSIO_FCOE is not set
CONFIG_SCSI_DH=y
CONFIG_SCSI_DH_RDAC=y
CONFIG_SCSI_DH_HP_SW=y
CONFIG_SCSI_DH_EMC=y
CONFIG_SCSI_DH_ALUA=y
# end of SCSI device support

CONFIG_ATA=m
CONFIG_SATA_HOST=y
CONFIG_PATA_TIMINGS=y
CONFIG_ATA_VERBOSE_ERROR=y
CONFIG_ATA_FORCE=y
CONFIG_ATA_ACPI=y
# CONFIG_SATA_ZPODD is not set
CONFIG_SATA_PMP=y

#
# Controllers with non-SFF native interface
#
CONFIG_SATA_AHCI=m
CONFIG_SATA_MOBILE_LPM_POLICY=0
CONFIG_SATA_AHCI_PLATFORM=m
# CONFIG_SATA_INIC162X is not set
# CONFIG_SATA_ACARD_AHCI is not set
# CONFIG_SATA_SIL24 is not set
CONFIG_ATA_SFF=y

#
# SFF controllers with custom DMA interface
#
# CONFIG_PDC_ADMA is not set
# CONFIG_SATA_QSTOR is not set
# CONFIG_SATA_SX4 is not set
CONFIG_ATA_BMDMA=y

#
# SATA SFF controllers with BMDMA
#
CONFIG_ATA_PIIX=m
# CONFIG_SATA_DWC is not set
# CONFIG_SATA_MV is not set
# CONFIG_SATA_NV is not set
# CONFIG_SATA_PROMISE is not set
# CONFIG_SATA_SIL is not set
# CONFIG_SATA_SIS is not set
# CONFIG_SATA_SVW is not set
# CONFIG_SATA_ULI is not set
# CONFIG_SATA_VIA is not set
# CONFIG_SATA_VITESSE is not set

#
# PATA SFF controllers with BMDMA
#
# CONFIG_PATA_ALI is not set
# CONFIG_PATA_AMD is not set
# CONFIG_PATA_ARTOP is not set
# CONFIG_PATA_ATIIXP is not set
# CONFIG_PATA_ATP867X is not set
# CONFIG_PATA_CMD64X is not set
# CONFIG_PATA_CYPRESS is not set
# CONFIG_PATA_EFAR is not set
# CONFIG_PATA_HPT366 is not set
# CONFIG_PATA_HPT37X is not set
# CONFIG_PATA_HPT3X2N is not set
# CONFIG_PATA_HPT3X3 is not set
# CONFIG_PATA_IT8213 is not set
# CONFIG_PATA_IT821X is not set
# CONFIG_PATA_JMICRON is not set
# CONFIG_PATA_MARVELL is not set
# CONFIG_PATA_NETCELL is not set
# CONFIG_PATA_NINJA32 is not set
# CONFIG_PATA_NS87415 is not set
# CONFIG_PATA_OLDPIIX is not set
# CONFIG_PATA_OPTIDMA is not set
# CONFIG_PATA_PDC2027X is not set
# CONFIG_PATA_PDC_OLD is not set
# CONFIG_PATA_RADISYS is not set
# CONFIG_PATA_RDC is not set
# CONFIG_PATA_SCH is not set
# CONFIG_PATA_SERVERWORKS is not set
# CONFIG_PATA_SIL680 is not set
# CONFIG_PATA_SIS is not set
# CONFIG_PATA_TOSHIBA is not set
# CONFIG_PATA_TRIFLEX is not set
# CONFIG_PATA_VIA is not set
# CONFIG_PATA_WINBOND is not set

#
# PIO-only SFF controllers
#
# CONFIG_PATA_CMD640_PCI is not set
# CONFIG_PATA_MPIIX is not set
# CONFIG_PATA_NS87410 is not set
# CONFIG_PATA_OPTI is not set
# CONFIG_PATA_RZ1000 is not set

#
# Generic fallback / legacy drivers
#
# CONFIG_PATA_ACPI is not set
CONFIG_ATA_GENERIC=m
# CONFIG_PATA_LEGACY is not set
CONFIG_MD=y
CONFIG_BLK_DEV_MD=y
CONFIG_MD_AUTODETECT=y
CONFIG_MD_LINEAR=m
CONFIG_MD_RAID0=m
CONFIG_MD_RAID1=m
CONFIG_MD_RAID10=m
CONFIG_MD_RAID456=m
# CONFIG_MD_MULTIPATH is not set
CONFIG_MD_FAULTY=m
CONFIG_MD_CLUSTER=m
# CONFIG_BCACHE is not set
CONFIG_BLK_DEV_DM_BUILTIN=y
CONFIG_BLK_DEV_DM=m
CONFIG_DM_DEBUG=y
CONFIG_DM_BUFIO=m
# CONFIG_DM_DEBUG_BLOCK_MANAGER_LOCKING is not set
CONFIG_DM_BIO_PRISON=m
CONFIG_DM_PERSISTENT_DATA=m
# CONFIG_DM_UNSTRIPED is not set
CONFIG_DM_CRYPT=m
CONFIG_DM_SNAPSHOT=m
CONFIG_DM_THIN_PROVISIONING=m
CONFIG_DM_CACHE=m
CONFIG_DM_CACHE_SMQ=m
CONFIG_DM_WRITECACHE=m
# CONFIG_DM_EBS is not set
CONFIG_DM_ERA=m
# CONFIG_DM_CLONE is not set
CONFIG_DM_MIRROR=m
CONFIG_DM_LOG_USERSPACE=m
CONFIG_DM_RAID=m
CONFIG_DM_ZERO=m
CONFIG_DM_MULTIPATH=m
CONFIG_DM_MULTIPATH_QL=m
CONFIG_DM_MULTIPATH_ST=m
# CONFIG_DM_MULTIPATH_HST is not set
# CONFIG_DM_MULTIPATH_IOA is not set
CONFIG_DM_DELAY=m
# CONFIG_DM_DUST is not set
CONFIG_DM_UEVENT=y
CONFIG_DM_FLAKEY=m
CONFIG_DM_VERITY=m
# CONFIG_DM_VERITY_VERIFY_ROOTHASH_SIG is not set
# CONFIG_DM_VERITY_FEC is not set
CONFIG_DM_SWITCH=m
CONFIG_DM_LOG_WRITES=m
CONFIG_DM_INTEGRITY=m
CONFIG_DM_AUDIT=y
CONFIG_TARGET_CORE=m
CONFIG_TCM_IBLOCK=m
CONFIG_TCM_FILEIO=m
CONFIG_TCM_PSCSI=m
CONFIG_TCM_USER2=m
CONFIG_LOOPBACK_TARGET=m
CONFIG_ISCSI_TARGET=m
# CONFIG_SBP_TARGET is not set
# CONFIG_FUSION is not set

#
# IEEE 1394 (FireWire) support
#
CONFIG_FIREWIRE=m
CONFIG_FIREWIRE_OHCI=m
CONFIG_FIREWIRE_SBP2=m
CONFIG_FIREWIRE_NET=m
# CONFIG_FIREWIRE_NOSY is not set
# end of IEEE 1394 (FireWire) support

CONFIG_MACINTOSH_DRIVERS=y
CONFIG_MAC_EMUMOUSEBTN=y
CONFIG_NETDEVICES=y
CONFIG_MII=y
CONFIG_NET_CORE=y
# CONFIG_BONDING is not set
# CONFIG_DUMMY is not set
# CONFIG_WIREGUARD is not set
# CONFIG_EQUALIZER is not set
# CONFIG_NET_FC is not set
# CONFIG_IFB is not set
# CONFIG_NET_TEAM is not set
# CONFIG_MACVLAN is not set
# CONFIG_IPVLAN is not set
# CONFIG_VXLAN is not set
# CONFIG_GENEVE is not set
# CONFIG_BAREUDP is not set
# CONFIG_GTP is not set
# CONFIG_AMT is not set
# CONFIG_MACSEC is not set
CONFIG_NETCONSOLE=m
CONFIG_NETCONSOLE_DYNAMIC=y
CONFIG_NETPOLL=y
CONFIG_NET_POLL_CONTROLLER=y
CONFIG_TUN=m
# CONFIG_TUN_VNET_CROSS_LE is not set
# CONFIG_VETH is not set
CONFIG_VIRTIO_NET=m
# CONFIG_NLMON is not set
# CONFIG_NET_VRF is not set
# CONFIG_VSOCKMON is not set
# CONFIG_ARCNET is not set
CONFIG_ATM_DRIVERS=y
# CONFIG_ATM_DUMMY is not set
# CONFIG_ATM_TCP is not set
# CONFIG_ATM_LANAI is not set
# CONFIG_ATM_ENI is not set
# CONFIG_ATM_NICSTAR is not set
# CONFIG_ATM_IDT77252 is not set
# CONFIG_ATM_IA is not set
# CONFIG_ATM_FORE200E is not set
# CONFIG_ATM_HE is not set
# CONFIG_ATM_SOLOS is not set
CONFIG_ETHERNET=y
CONFIG_MDIO=y
# CONFIG_NET_VENDOR_3COM is not set
CONFIG_NET_VENDOR_ADAPTEC=y
# CONFIG_ADAPTEC_STARFIRE is not set
CONFIG_NET_VENDOR_AGERE=y
# CONFIG_ET131X is not set
CONFIG_NET_VENDOR_ALACRITECH=y
# CONFIG_SLICOSS is not set
CONFIG_NET_VENDOR_ALTEON=y
# CONFIG_ACENIC is not set
# CONFIG_ALTERA_TSE is not set
CONFIG_NET_VENDOR_AMAZON=y
# CONFIG_ENA_ETHERNET is not set
# CONFIG_NET_VENDOR_AMD is not set
CONFIG_NET_VENDOR_AQUANTIA=y
# CONFIG_AQTION is not set
CONFIG_NET_VENDOR_ARC=y
CONFIG_NET_VENDOR_ASIX=y
# CONFIG_SPI_AX88796C is not set
CONFIG_NET_VENDOR_ATHEROS=y
# CONFIG_ATL2 is not set
# CONFIG_ATL1 is not set
# CONFIG_ATL1E is not set
# CONFIG_ATL1C is not set
# CONFIG_ALX is not set
# CONFIG_CX_ECAT is not set
CONFIG_NET_VENDOR_BROADCOM=y
# CONFIG_B44 is not set
# CONFIG_BCMGENET is not set
# CONFIG_BNX2 is not set
# CONFIG_CNIC is not set
# CONFIG_TIGON3 is not set
# CONFIG_BNX2X is not set
# CONFIG_SYSTEMPORT is not set
# CONFIG_BNXT is not set
CONFIG_NET_VENDOR_CADENCE=y
# CONFIG_MACB is not set
CONFIG_NET_VENDOR_CAVIUM=y
# CONFIG_THUNDER_NIC_PF is not set
# CONFIG_THUNDER_NIC_VF is not set
# CONFIG_THUNDER_NIC_BGX is not set
# CONFIG_THUNDER_NIC_RGX is not set
CONFIG_CAVIUM_PTP=y
# CONFIG_LIQUIDIO is not set
# CONFIG_LIQUIDIO_VF is not set
CONFIG_NET_VENDOR_CHELSIO=y
# CONFIG_CHELSIO_T1 is not set
# CONFIG_CHELSIO_T3 is not set
# CONFIG_CHELSIO_T4 is not set
# CONFIG_CHELSIO_T4VF is not set
CONFIG_NET_VENDOR_CISCO=y
# CONFIG_ENIC is not set
CONFIG_NET_VENDOR_CORTINA=y
CONFIG_NET_VENDOR_DAVICOM=y
# CONFIG_DM9051 is not set
# CONFIG_DNET is not set
CONFIG_NET_VENDOR_DEC=y
# CONFIG_NET_TULIP is not set
CONFIG_NET_VENDOR_DLINK=y
# CONFIG_DL2K is not set
# CONFIG_SUNDANCE is not set
CONFIG_NET_VENDOR_EMULEX=y
# CONFIG_BE2NET is not set
CONFIG_NET_VENDOR_ENGLEDER=y
# CONFIG_TSNEP is not set
CONFIG_NET_VENDOR_EZCHIP=y
CONFIG_NET_VENDOR_FUNGIBLE=y
# CONFIG_FUN_ETH is not set
CONFIG_NET_VENDOR_GOOGLE=y
# CONFIG_GVE is not set
CONFIG_NET_VENDOR_HUAWEI=y
# CONFIG_HINIC is not set
CONFIG_NET_VENDOR_I825XX=y
CONFIG_NET_VENDOR_INTEL=y
# CONFIG_E100 is not set
CONFIG_E1000=y
CONFIG_E1000E=y
CONFIG_E1000E_HWTS=y
CONFIG_IGB=y
CONFIG_IGB_HWMON=y
# CONFIG_IGBVF is not set
# CONFIG_IXGB is not set
CONFIG_IXGBE=y
CONFIG_IXGBE_HWMON=y
# CONFIG_IXGBE_DCB is not set
# CONFIG_IXGBE_IPSEC is not set
# CONFIG_IXGBEVF is not set
CONFIG_I40E=y
# CONFIG_I40E_DCB is not set
# CONFIG_I40EVF is not set
# CONFIG_ICE is not set
# CONFIG_FM10K is not set
CONFIG_IGC=y
CONFIG_NET_VENDOR_WANGXUN=y
# CONFIG_TXGBE is not set
# CONFIG_JME is not set
CONFIG_NET_VENDOR_LITEX=y
CONFIG_NET_VENDOR_MARVELL=y
# CONFIG_MVMDIO is not set
# CONFIG_SKGE is not set
# CONFIG_SKY2 is not set
# CONFIG_OCTEON_EP is not set
# CONFIG_PRESTERA is not set
CONFIG_NET_VENDOR_MELLANOX=y
# CONFIG_MLX4_EN is not set
# CONFIG_MLX5_CORE is not set
# CONFIG_MLXSW_CORE is not set
# CONFIG_MLXFW is not set
CONFIG_NET_VENDOR_MICREL=y
# CONFIG_KS8842 is not set
# CONFIG_KS8851 is not set
# CONFIG_KS8851_MLL is not set
# CONFIG_KSZ884X_PCI is not set
CONFIG_NET_VENDOR_MICROCHIP=y
# CONFIG_ENC28J60 is not set
# CONFIG_ENCX24J600 is not set
# CONFIG_LAN743X is not set
CONFIG_NET_VENDOR_MICROSEMI=y
CONFIG_NET_VENDOR_MICROSOFT=y
CONFIG_NET_VENDOR_MYRI=y
# CONFIG_MYRI10GE is not set
# CONFIG_FEALNX is not set
CONFIG_NET_VENDOR_NI=y
# CONFIG_NI_XGE_MANAGEMENT_ENET is not set
CONFIG_NET_VENDOR_NATSEMI=y
# CONFIG_NATSEMI is not set
# CONFIG_NS83820 is not set
CONFIG_NET_VENDOR_NETERION=y
# CONFIG_S2IO is not set
CONFIG_NET_VENDOR_NETRONOME=y
# CONFIG_NFP is not set
CONFIG_NET_VENDOR_8390=y
# CONFIG_NE2K_PCI is not set
CONFIG_NET_VENDOR_NVIDIA=y
# CONFIG_FORCEDETH is not set
CONFIG_NET_VENDOR_OKI=y
# CONFIG_ETHOC is not set
CONFIG_NET_VENDOR_PACKET_ENGINES=y
# CONFIG_HAMACHI is not set
# CONFIG_YELLOWFIN is not set
CONFIG_NET_VENDOR_PENSANDO=y
# CONFIG_IONIC is not set
CONFIG_NET_VENDOR_QLOGIC=y
# CONFIG_QLA3XXX is not set
# CONFIG_QLCNIC is not set
# CONFIG_NETXEN_NIC is not set
# CONFIG_QED is not set
CONFIG_NET_VENDOR_BROCADE=y
# CONFIG_BNA is not set
CONFIG_NET_VENDOR_QUALCOMM=y
# CONFIG_QCOM_EMAC is not set
# CONFIG_RMNET is not set
CONFIG_NET_VENDOR_RDC=y
# CONFIG_R6040 is not set
CONFIG_NET_VENDOR_REALTEK=y
# CONFIG_ATP is not set
# CONFIG_8139CP is not set
# CONFIG_8139TOO is not set
CONFIG_R8169=y
CONFIG_NET_VENDOR_RENESAS=y
CONFIG_NET_VENDOR_ROCKER=y
# CONFIG_ROCKER is not set
CONFIG_NET_VENDOR_SAMSUNG=y
# CONFIG_SXGBE_ETH is not set
CONFIG_NET_VENDOR_SEEQ=y
CONFIG_NET_VENDOR_SILAN=y
# CONFIG_SC92031 is not set
CONFIG_NET_VENDOR_SIS=y
# CONFIG_SIS900 is not set
# CONFIG_SIS190 is not set
CONFIG_NET_VENDOR_SOLARFLARE=y
# CONFIG_SFC is not set
# CONFIG_SFC_FALCON is not set
# CONFIG_SFC_SIENA is not set
CONFIG_NET_VENDOR_SMSC=y
# CONFIG_EPIC100 is not set
# CONFIG_SMSC911X is not set
# CONFIG_SMSC9420 is not set
CONFIG_NET_VENDOR_SOCIONEXT=y
CONFIG_NET_VENDOR_STMICRO=y
# CONFIG_STMMAC_ETH is not set
CONFIG_NET_VENDOR_SUN=y
# CONFIG_HAPPYMEAL is not set
# CONFIG_SUNGEM is not set
# CONFIG_CASSINI is not set
# CONFIG_NIU is not set
CONFIG_NET_VENDOR_SYNOPSYS=y
# CONFIG_DWC_XLGMAC is not set
CONFIG_NET_VENDOR_TEHUTI=y
# CONFIG_TEHUTI is not set
CONFIG_NET_VENDOR_TI=y
# CONFIG_TI_CPSW_PHY_SEL is not set
# CONFIG_TLAN is not set
CONFIG_NET_VENDOR_VERTEXCOM=y
# CONFIG_MSE102X is not set
CONFIG_NET_VENDOR_VIA=y
# CONFIG_VIA_RHINE is not set
# CONFIG_VIA_VELOCITY is not set
CONFIG_NET_VENDOR_WIZNET=y
# CONFIG_WIZNET_W5100 is not set
# CONFIG_WIZNET_W5300 is not set
CONFIG_NET_VENDOR_XILINX=y
# CONFIG_XILINX_EMACLITE is not set
# CONFIG_XILINX_AXI_EMAC is not set
# CONFIG_XILINX_LL_TEMAC is not set
# CONFIG_FDDI is not set
# CONFIG_HIPPI is not set
# CONFIG_NET_SB1000 is not set
CONFIG_PHYLIB=y
CONFIG_SWPHY=y
# CONFIG_LED_TRIGGER_PHY is not set
CONFIG_FIXED_PHY=y

#
# MII PHY device drivers
#
# CONFIG_AMD_PHY is not set
# CONFIG_ADIN_PHY is not set
# CONFIG_ADIN1100_PHY is not set
# CONFIG_AQUANTIA_PHY is not set
CONFIG_AX88796B_PHY=y
# CONFIG_BROADCOM_PHY is not set
# CONFIG_BCM54140_PHY is not set
# CONFIG_BCM7XXX_PHY is not set
# CONFIG_BCM84881_PHY is not set
# CONFIG_BCM87XX_PHY is not set
# CONFIG_CICADA_PHY is not set
# CONFIG_CORTINA_PHY is not set
# CONFIG_DAVICOM_PHY is not set
# CONFIG_ICPLUS_PHY is not set
# CONFIG_LXT_PHY is not set
# CONFIG_INTEL_XWAY_PHY is not set
# CONFIG_LSI_ET1011C_PHY is not set
# CONFIG_MARVELL_PHY is not set
# CONFIG_MARVELL_10G_PHY is not set
# CONFIG_MARVELL_88X2222_PHY is not set
# CONFIG_MAXLINEAR_GPHY is not set
# CONFIG_MEDIATEK_GE_PHY is not set
# CONFIG_MICREL_PHY is not set
# CONFIG_MICROCHIP_PHY is not set
# CONFIG_MICROCHIP_T1_PHY is not set
# CONFIG_MICROSEMI_PHY is not set
# CONFIG_MOTORCOMM_PHY is not set
# CONFIG_NATIONAL_PHY is not set
# CONFIG_NXP_C45_TJA11XX_PHY is not set
# CONFIG_NXP_TJA11XX_PHY is not set
# CONFIG_QSEMI_PHY is not set
CONFIG_REALTEK_PHY=y
# CONFIG_RENESAS_PHY is not set
# CONFIG_ROCKCHIP_PHY is not set
# CONFIG_SMSC_PHY is not set
# CONFIG_STE10XP is not set
# CONFIG_TERANETICS_PHY is not set
# CONFIG_DP83822_PHY is not set
# CONFIG_DP83TC811_PHY is not set
# CONFIG_DP83848_PHY is not set
# CONFIG_DP83867_PHY is not set
# CONFIG_DP83869_PHY is not set
# CONFIG_DP83TD510_PHY is not set
# CONFIG_VITESSE_PHY is not set
# CONFIG_XILINX_GMII2RGMII is not set
# CONFIG_MICREL_KS8995MA is not set
CONFIG_CAN_DEV=m
CONFIG_CAN_VCAN=m
# CONFIG_CAN_VXCAN is not set
CONFIG_CAN_NETLINK=y
CONFIG_CAN_CALC_BITTIMING=y
# CONFIG_CAN_CAN327 is not set
# CONFIG_CAN_KVASER_PCIEFD is not set
CONFIG_CAN_SLCAN=m
CONFIG_CAN_C_CAN=m
CONFIG_CAN_C_CAN_PLATFORM=m
CONFIG_CAN_C_CAN_PCI=m
CONFIG_CAN_CC770=m
# CONFIG_CAN_CC770_ISA is not set
CONFIG_CAN_CC770_PLATFORM=m
# CONFIG_CAN_CTUCANFD_PCI is not set
# CONFIG_CAN_IFI_CANFD is not set
# CONFIG_CAN_M_CAN is not set
# CONFIG_CAN_PEAK_PCIEFD is not set
CONFIG_CAN_SJA1000=m
CONFIG_CAN_EMS_PCI=m
# CONFIG_CAN_F81601 is not set
CONFIG_CAN_KVASER_PCI=m
CONFIG_CAN_PEAK_PCI=m
CONFIG_CAN_PEAK_PCIEC=y
CONFIG_CAN_PLX_PCI=m
# CONFIG_CAN_SJA1000_ISA is not set
# CONFIG_CAN_SJA1000_PLATFORM is not set
CONFIG_CAN_SOFTING=m

#
# CAN SPI interfaces
#
# CONFIG_CAN_HI311X is not set
# CONFIG_CAN_MCP251X is not set
# CONFIG_CAN_MCP251XFD is not set
# end of CAN SPI interfaces

#
# CAN USB interfaces
#
# CONFIG_CAN_8DEV_USB is not set
# CONFIG_CAN_EMS_USB is not set
# CONFIG_CAN_ESD_USB is not set
# CONFIG_CAN_ETAS_ES58X is not set
# CONFIG_CAN_GS_USB is not set
# CONFIG_CAN_KVASER_USB is not set
# CONFIG_CAN_MCBA_USB is not set
# CONFIG_CAN_PEAK_USB is not set
# CONFIG_CAN_UCAN is not set
# end of CAN USB interfaces

# CONFIG_CAN_DEBUG_DEVICES is not set
CONFIG_MDIO_DEVICE=y
CONFIG_MDIO_BUS=y
CONFIG_FWNODE_MDIO=y
CONFIG_ACPI_MDIO=y
CONFIG_MDIO_DEVRES=y
# CONFIG_MDIO_BITBANG is not set
# CONFIG_MDIO_BCM_UNIMAC is not set
# CONFIG_MDIO_MVUSB is not set
# CONFIG_MDIO_THUNDER is not set

#
# MDIO Multiplexers
#

#
# PCS device drivers
#
# end of PCS device drivers

# CONFIG_PLIP is not set
# CONFIG_PPP is not set
# CONFIG_SLIP is not set
CONFIG_USB_NET_DRIVERS=y
# CONFIG_USB_CATC is not set
# CONFIG_USB_KAWETH is not set
# CONFIG_USB_PEGASUS is not set
# CONFIG_USB_RTL8150 is not set
CONFIG_USB_RTL8152=y
# CONFIG_USB_LAN78XX is not set
CONFIG_USB_USBNET=y
CONFIG_USB_NET_AX8817X=y
CONFIG_USB_NET_AX88179_178A=y
# CONFIG_USB_NET_CDCETHER is not set
# CONFIG_USB_NET_CDC_EEM is not set
# CONFIG_USB_NET_CDC_NCM is not set
# CONFIG_USB_NET_HUAWEI_CDC_NCM is not set
# CONFIG_USB_NET_CDC_MBIM is not set
# CONFIG_USB_NET_DM9601 is not set
# CONFIG_USB_NET_SR9700 is not set
# CONFIG_USB_NET_SR9800 is not set
# CONFIG_USB_NET_SMSC75XX is not set
# CONFIG_USB_NET_SMSC95XX is not set
# CONFIG_USB_NET_GL620A is not set
# CONFIG_USB_NET_NET1080 is not set
# CONFIG_USB_NET_PLUSB is not set
# CONFIG_USB_NET_MCS7830 is not set
# CONFIG_USB_NET_RNDIS_HOST is not set
# CONFIG_USB_NET_CDC_SUBSET is not set
# CONFIG_USB_NET_ZAURUS is not set
# CONFIG_USB_NET_CX82310_ETH is not set
# CONFIG_USB_NET_KALMIA is not set
# CONFIG_USB_NET_QMI_WWAN is not set
# CONFIG_USB_HSO is not set
# CONFIG_USB_NET_INT51X1 is not set
# CONFIG_USB_IPHETH is not set
# CONFIG_USB_SIERRA_NET is not set
# CONFIG_USB_NET_CH9200 is not set
# CONFIG_USB_NET_AQC111 is not set
CONFIG_WLAN=y
CONFIG_WLAN_VENDOR_ADMTEK=y
# CONFIG_ADM8211 is not set
CONFIG_WLAN_VENDOR_ATH=y
# CONFIG_ATH_DEBUG is not set
# CONFIG_ATH5K is not set
# CONFIG_ATH5K_PCI is not set
# CONFIG_ATH9K is not set
# CONFIG_ATH9K_HTC is not set
# CONFIG_CARL9170 is not set
# CONFIG_ATH6KL is not set
# CONFIG_AR5523 is not set
# CONFIG_WIL6210 is not set
# CONFIG_ATH10K is not set
# CONFIG_WCN36XX is not set
# CONFIG_ATH11K is not set
CONFIG_WLAN_VENDOR_ATMEL=y
# CONFIG_ATMEL is not set
# CONFIG_AT76C50X_USB is not set
CONFIG_WLAN_VENDOR_BROADCOM=y
# CONFIG_B43 is not set
# CONFIG_B43LEGACY is not set
# CONFIG_BRCMSMAC is not set
# CONFIG_BRCMFMAC is not set
CONFIG_WLAN_VENDOR_CISCO=y
# CONFIG_AIRO is not set
CONFIG_WLAN_VENDOR_INTEL=y
# CONFIG_IPW2100 is not set
# CONFIG_IPW2200 is not set
# CONFIG_IWL4965 is not set
# CONFIG_IWL3945 is not set
# CONFIG_IWLWIFI is not set
CONFIG_WLAN_VENDOR_INTERSIL=y
# CONFIG_HOSTAP is not set
# CONFIG_HERMES is not set
# CONFIG_P54_COMMON is not set
CONFIG_WLAN_VENDOR_MARVELL=y
# CONFIG_LIBERTAS is not set
# CONFIG_LIBERTAS_THINFIRM is not set
# CONFIG_MWIFIEX is not set
# CONFIG_MWL8K is not set
# CONFIG_WLAN_VENDOR_MEDIATEK is not set
CONFIG_WLAN_VENDOR_MICROCHIP=y
# CONFIG_WILC1000_SDIO is not set
# CONFIG_WILC1000_SPI is not set
CONFIG_WLAN_VENDOR_PURELIFI=y
# CONFIG_PLFXLC is not set
CONFIG_WLAN_VENDOR_RALINK=y
# CONFIG_RT2X00 is not set
CONFIG_WLAN_VENDOR_REALTEK=y
# CONFIG_RTL8180 is not set
# CONFIG_RTL8187 is not set
CONFIG_RTL_CARDS=m
# CONFIG_RTL8192CE is not set
# CONFIG_RTL8192SE is not set
# CONFIG_RTL8192DE is not set
# CONFIG_RTL8723AE is not set
# CONFIG_RTL8723BE is not set
# CONFIG_RTL8188EE is not set
# CONFIG_RTL8192EE is not set
# CONFIG_RTL8821AE is not set
# CONFIG_RTL8192CU is not set
# CONFIG_RTL8XXXU is not set
# CONFIG_RTW88 is not set
# CONFIG_RTW89 is not set
CONFIG_WLAN_VENDOR_RSI=y
# CONFIG_RSI_91X is not set
CONFIG_WLAN_VENDOR_SILABS=y
# CONFIG_WFX is not set
CONFIG_WLAN_VENDOR_ST=y
# CONFIG_CW1200 is not set
CONFIG_WLAN_VENDOR_TI=y
# CONFIG_WL1251 is not set
# CONFIG_WL12XX is not set
# CONFIG_WL18XX is not set
# CONFIG_WLCORE is not set
CONFIG_WLAN_VENDOR_ZYDAS=y
# CONFIG_USB_ZD1201 is not set
# CONFIG_ZD1211RW is not set
CONFIG_WLAN_VENDOR_QUANTENNA=y
# CONFIG_QTNFMAC_PCIE is not set
# CONFIG_MAC80211_HWSIM is not set
# CONFIG_USB_NET_RNDIS_WLAN is not set
# CONFIG_VIRT_WIFI is not set
# CONFIG_WAN is not set

#
# Wireless WAN
#
# CONFIG_WWAN is not set
# end of Wireless WAN

# CONFIG_VMXNET3 is not set
# CONFIG_FUJITSU_ES is not set
# CONFIG_NETDEVSIM is not set
CONFIG_NET_FAILOVER=m
# CONFIG_ISDN is not set

#
# Input device support
#
CONFIG_INPUT=y
CONFIG_INPUT_LEDS=y
CONFIG_INPUT_FF_MEMLESS=m
CONFIG_INPUT_SPARSEKMAP=m
# CONFIG_INPUT_MATRIXKMAP is not set
CONFIG_INPUT_VIVALDIFMAP=y

#
# Userland interfaces
#
CONFIG_INPUT_MOUSEDEV=y
# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
CONFIG_INPUT_JOYDEV=m
CONFIG_INPUT_EVDEV=y
# CONFIG_INPUT_EVBUG is not set

#
# Input Device Drivers
#
CONFIG_INPUT_KEYBOARD=y
# CONFIG_KEYBOARD_ADP5588 is not set
# CONFIG_KEYBOARD_ADP5589 is not set
# CONFIG_KEYBOARD_APPLESPI is not set
CONFIG_KEYBOARD_ATKBD=y
# CONFIG_KEYBOARD_QT1050 is not set
# CONFIG_KEYBOARD_QT1070 is not set
# CONFIG_KEYBOARD_QT2160 is not set
# CONFIG_KEYBOARD_DLINK_DIR685 is not set
# CONFIG_KEYBOARD_LKKBD is not set
# CONFIG_KEYBOARD_GPIO is not set
# CONFIG_KEYBOARD_GPIO_POLLED is not set
# CONFIG_KEYBOARD_TCA6416 is not set
# CONFIG_KEYBOARD_TCA8418 is not set
# CONFIG_KEYBOARD_MATRIX is not set
# CONFIG_KEYBOARD_LM8323 is not set
# CONFIG_KEYBOARD_LM8333 is not set
# CONFIG_KEYBOARD_MAX7359 is not set
# CONFIG_KEYBOARD_MCS is not set
# CONFIG_KEYBOARD_MPR121 is not set
# CONFIG_KEYBOARD_NEWTON is not set
# CONFIG_KEYBOARD_OPENCORES is not set
# CONFIG_KEYBOARD_SAMSUNG is not set
# CONFIG_KEYBOARD_STOWAWAY is not set
# CONFIG_KEYBOARD_SUNKBD is not set
# CONFIG_KEYBOARD_TM2_TOUCHKEY is not set
# CONFIG_KEYBOARD_XTKBD is not set
# CONFIG_KEYBOARD_CYPRESS_SF is not set
CONFIG_INPUT_MOUSE=y
CONFIG_MOUSE_PS2=y
CONFIG_MOUSE_PS2_ALPS=y
CONFIG_MOUSE_PS2_BYD=y
CONFIG_MOUSE_PS2_LOGIPS2PP=y
CONFIG_MOUSE_PS2_SYNAPTICS=y
CONFIG_MOUSE_PS2_SYNAPTICS_SMBUS=y
CONFIG_MOUSE_PS2_CYPRESS=y
CONFIG_MOUSE_PS2_LIFEBOOK=y
CONFIG_MOUSE_PS2_TRACKPOINT=y
CONFIG_MOUSE_PS2_ELANTECH=y
CONFIG_MOUSE_PS2_ELANTECH_SMBUS=y
CONFIG_MOUSE_PS2_SENTELIC=y
# CONFIG_MOUSE_PS2_TOUCHKIT is not set
CONFIG_MOUSE_PS2_FOCALTECH=y
CONFIG_MOUSE_PS2_VMMOUSE=y
CONFIG_MOUSE_PS2_SMBUS=y
CONFIG_MOUSE_SERIAL=m
# CONFIG_MOUSE_APPLETOUCH is not set
# CONFIG_MOUSE_BCM5974 is not set
CONFIG_MOUSE_CYAPA=m
CONFIG_MOUSE_ELAN_I2C=m
CONFIG_MOUSE_ELAN_I2C_I2C=y
CONFIG_MOUSE_ELAN_I2C_SMBUS=y
CONFIG_MOUSE_VSXXXAA=m
# CONFIG_MOUSE_GPIO is not set
CONFIG_MOUSE_SYNAPTICS_I2C=m
# CONFIG_MOUSE_SYNAPTICS_USB is not set
# CONFIG_INPUT_JOYSTICK is not set
# CONFIG_INPUT_TABLET is not set
# CONFIG_INPUT_TOUCHSCREEN is not set
# CONFIG_INPUT_MISC is not set
CONFIG_RMI4_CORE=m
CONFIG_RMI4_I2C=m
CONFIG_RMI4_SPI=m
CONFIG_RMI4_SMB=m
CONFIG_RMI4_F03=y
CONFIG_RMI4_F03_SERIO=m
CONFIG_RMI4_2D_SENSOR=y
CONFIG_RMI4_F11=y
CONFIG_RMI4_F12=y
CONFIG_RMI4_F30=y
CONFIG_RMI4_F34=y
# CONFIG_RMI4_F3A is not set
CONFIG_RMI4_F55=y

#
# Hardware I/O ports
#
CONFIG_SERIO=y
CONFIG_ARCH_MIGHT_HAVE_PC_SERIO=y
CONFIG_SERIO_I8042=y
CONFIG_SERIO_SERPORT=y
# CONFIG_SERIO_CT82C710 is not set
# CONFIG_SERIO_PARKBD is not set
# CONFIG_SERIO_PCIPS2 is not set
CONFIG_SERIO_LIBPS2=y
CONFIG_SERIO_RAW=m
CONFIG_SERIO_ALTERA_PS2=m
# CONFIG_SERIO_PS2MULT is not set
CONFIG_SERIO_ARC_PS2=m
# CONFIG_SERIO_GPIO_PS2 is not set
# CONFIG_USERIO is not set
# CONFIG_GAMEPORT is not set
# end of Hardware I/O ports
# end of Input device support

#
# Character devices
#
CONFIG_TTY=y
CONFIG_VT=y
CONFIG_CONSOLE_TRANSLATIONS=y
CONFIG_VT_CONSOLE=y
CONFIG_VT_CONSOLE_SLEEP=y
CONFIG_HW_CONSOLE=y
CONFIG_VT_HW_CONSOLE_BINDING=y
CONFIG_UNIX98_PTYS=y
# CONFIG_LEGACY_PTYS is not set
CONFIG_LDISC_AUTOLOAD=y

#
# Serial drivers
#
CONFIG_SERIAL_EARLYCON=y
CONFIG_SERIAL_8250=y
# CONFIG_SERIAL_8250_DEPRECATED_OPTIONS is not set
CONFIG_SERIAL_8250_PNP=y
# CONFIG_SERIAL_8250_16550A_VARIANTS is not set
# CONFIG_SERIAL_8250_FINTEK is not set
CONFIG_SERIAL_8250_CONSOLE=y
CONFIG_SERIAL_8250_DMA=y
CONFIG_SERIAL_8250_PCI=y
CONFIG_SERIAL_8250_EXAR=y
CONFIG_SERIAL_8250_NR_UARTS=64
CONFIG_SERIAL_8250_RUNTIME_UARTS=4
CONFIG_SERIAL_8250_EXTENDED=y
CONFIG_SERIAL_8250_MANY_PORTS=y
CONFIG_SERIAL_8250_SHARE_IRQ=y
# CONFIG_SERIAL_8250_DETECT_IRQ is not set
CONFIG_SERIAL_8250_RSA=y
CONFIG_SERIAL_8250_DWLIB=y
CONFIG_SERIAL_8250_DW=y
# CONFIG_SERIAL_8250_RT288X is not set
CONFIG_SERIAL_8250_LPSS=y
CONFIG_SERIAL_8250_MID=y
CONFIG_SERIAL_8250_PERICOM=y

#
# Non-8250 serial port support
#
# CONFIG_SERIAL_MAX3100 is not set
# CONFIG_SERIAL_MAX310X is not set
# CONFIG_SERIAL_UARTLITE is not set
CONFIG_SERIAL_CORE=y
CONFIG_SERIAL_CORE_CONSOLE=y
CONFIG_SERIAL_JSM=m
# CONFIG_SERIAL_LANTIQ is not set
# CONFIG_SERIAL_SCCNXP is not set
# CONFIG_SERIAL_SC16IS7XX is not set
# CONFIG_SERIAL_ALTERA_JTAGUART is not set
# CONFIG_SERIAL_ALTERA_UART is not set
CONFIG_SERIAL_ARC=m
CONFIG_SERIAL_ARC_NR_PORTS=1
# CONFIG_SERIAL_RP2 is not set
# CONFIG_SERIAL_FSL_LPUART is not set
# CONFIG_SERIAL_FSL_LINFLEXUART is not set
# CONFIG_SERIAL_SPRD is not set
# end of Serial drivers

CONFIG_SERIAL_MCTRL_GPIO=y
CONFIG_SERIAL_NONSTANDARD=y
# CONFIG_MOXA_INTELLIO is not set
# CONFIG_MOXA_SMARTIO is not set
CONFIG_SYNCLINK_GT=m
CONFIG_N_HDLC=m
CONFIG_N_GSM=m
CONFIG_NOZOMI=m
# CONFIG_NULL_TTY is not set
CONFIG_HVC_DRIVER=y
# CONFIG_SERIAL_DEV_BUS is not set
CONFIG_PRINTER=m
# CONFIG_LP_CONSOLE is not set
CONFIG_PPDEV=m
CONFIG_VIRTIO_CONSOLE=m
CONFIG_IPMI_HANDLER=m
CONFIG_IPMI_DMI_DECODE=y
CONFIG_IPMI_PLAT_DATA=y
CONFIG_IPMI_PANIC_EVENT=y
CONFIG_IPMI_PANIC_STRING=y
CONFIG_IPMI_DEVICE_INTERFACE=m
CONFIG_IPMI_SI=m
CONFIG_IPMI_SSIF=m
CONFIG_IPMI_WATCHDOG=m
CONFIG_IPMI_POWEROFF=m
CONFIG_HW_RANDOM=y
CONFIG_HW_RANDOM_TIMERIOMEM=m
CONFIG_HW_RANDOM_INTEL=m
# CONFIG_HW_RANDOM_AMD is not set
# CONFIG_HW_RANDOM_BA431 is not set
CONFIG_HW_RANDOM_VIA=m
CONFIG_HW_RANDOM_VIRTIO=y
# CONFIG_HW_RANDOM_XIPHERA is not set
# CONFIG_APPLICOM is not set
# CONFIG_MWAVE is not set
CONFIG_DEVMEM=y
CONFIG_NVRAM=y
CONFIG_DEVPORT=y
CONFIG_HPET=y
CONFIG_HPET_MMAP=y
# CONFIG_HPET_MMAP_DEFAULT is not set
CONFIG_HANGCHECK_TIMER=m
CONFIG_UV_MMTIMER=m
CONFIG_TCG_TPM=y
CONFIG_HW_RANDOM_TPM=y
CONFIG_TCG_TIS_CORE=y
CONFIG_TCG_TIS=y
# CONFIG_TCG_TIS_SPI is not set
# CONFIG_TCG_TIS_I2C is not set
# CONFIG_TCG_TIS_I2C_CR50 is not set
CONFIG_TCG_TIS_I2C_ATMEL=m
CONFIG_TCG_TIS_I2C_INFINEON=m
CONFIG_TCG_TIS_I2C_NUVOTON=m
CONFIG_TCG_NSC=m
CONFIG_TCG_ATMEL=m
CONFIG_TCG_INFINEON=m
CONFIG_TCG_CRB=y
# CONFIG_TCG_VTPM_PROXY is not set
CONFIG_TCG_TIS_ST33ZP24=m
CONFIG_TCG_TIS_ST33ZP24_I2C=m
# CONFIG_TCG_TIS_ST33ZP24_SPI is not set
CONFIG_TELCLOCK=m
# CONFIG_XILLYBUS is not set
# CONFIG_XILLYUSB is not set
CONFIG_RANDOM_TRUST_CPU=y
CONFIG_RANDOM_TRUST_BOOTLOADER=y
# end of Character devices

#
# I2C support
#
CONFIG_I2C=y
CONFIG_ACPI_I2C_OPREGION=y
CONFIG_I2C_BOARDINFO=y
CONFIG_I2C_COMPAT=y
CONFIG_I2C_CHARDEV=m
CONFIG_I2C_MUX=m

#
# Multiplexer I2C Chip support
#
# CONFIG_I2C_MUX_GPIO is not set
# CONFIG_I2C_MUX_LTC4306 is not set
# CONFIG_I2C_MUX_PCA9541 is not set
# CONFIG_I2C_MUX_PCA954x is not set
# CONFIG_I2C_MUX_REG is not set
CONFIG_I2C_MUX_MLXCPLD=m
# end of Multiplexer I2C Chip support

CONFIG_I2C_HELPER_AUTO=y
CONFIG_I2C_SMBUS=y
CONFIG_I2C_ALGOBIT=y
CONFIG_I2C_ALGOPCA=m

#
# I2C Hardware Bus support
#

#
# PC SMBus host controller drivers
#
# CONFIG_I2C_ALI1535 is not set
# CONFIG_I2C_ALI1563 is not set
# CONFIG_I2C_ALI15X3 is not set
# CONFIG_I2C_AMD756 is not set
# CONFIG_I2C_AMD8111 is not set
# CONFIG_I2C_AMD_MP2 is not set
CONFIG_I2C_I801=y
CONFIG_I2C_ISCH=m
CONFIG_I2C_ISMT=m
CONFIG_I2C_PIIX4=m
CONFIG_I2C_NFORCE2=m
CONFIG_I2C_NFORCE2_S4985=m
# CONFIG_I2C_NVIDIA_GPU is not set
# CONFIG_I2C_SIS5595 is not set
# CONFIG_I2C_SIS630 is not set
CONFIG_I2C_SIS96X=m
CONFIG_I2C_VIA=m
CONFIG_I2C_VIAPRO=m

#
# ACPI drivers
#
CONFIG_I2C_SCMI=m

#
# I2C system bus drivers (mostly embedded / system-on-chip)
#
# CONFIG_I2C_CBUS_GPIO is not set
CONFIG_I2C_DESIGNWARE_CORE=m
# CONFIG_I2C_DESIGNWARE_SLAVE is not set
CONFIG_I2C_DESIGNWARE_PLATFORM=m
# CONFIG_I2C_DESIGNWARE_AMDPSP is not set
CONFIG_I2C_DESIGNWARE_BAYTRAIL=y
# CONFIG_I2C_DESIGNWARE_PCI is not set
# CONFIG_I2C_EMEV2 is not set
# CONFIG_I2C_GPIO is not set
# CONFIG_I2C_OCORES is not set
CONFIG_I2C_PCA_PLATFORM=m
CONFIG_I2C_SIMTEC=m
# CONFIG_I2C_XILINX is not set

#
# External I2C/SMBus adapter drivers
#
# CONFIG_I2C_DIOLAN_U2C is not set
# CONFIG_I2C_CP2615 is not set
CONFIG_I2C_PARPORT=m
# CONFIG_I2C_ROBOTFUZZ_OSIF is not set
# CONFIG_I2C_TAOS_EVM is not set
# CONFIG_I2C_TINY_USB is not set

#
# Other I2C/SMBus bus drivers
#
CONFIG_I2C_MLXCPLD=m
# CONFIG_I2C_VIRTIO is not set
# end of I2C Hardware Bus support

CONFIG_I2C_STUB=m
# CONFIG_I2C_SLAVE is not set
# CONFIG_I2C_DEBUG_CORE is not set
# CONFIG_I2C_DEBUG_ALGO is not set
# CONFIG_I2C_DEBUG_BUS is not set
# end of I2C support

# CONFIG_I3C is not set
CONFIG_SPI=y
# CONFIG_SPI_DEBUG is not set
CONFIG_SPI_MASTER=y
# CONFIG_SPI_MEM is not set

#
# SPI Master Controller Drivers
#
# CONFIG_SPI_ALTERA is not set
# CONFIG_SPI_AXI_SPI_ENGINE is not set
# CONFIG_SPI_BITBANG is not set
# CONFIG_SPI_BUTTERFLY is not set
# CONFIG_SPI_CADENCE is not set
# CONFIG_SPI_DESIGNWARE is not set
# CONFIG_SPI_NXP_FLEXSPI is not set
# CONFIG_SPI_GPIO is not set
# CONFIG_SPI_LM70_LLP is not set
# CONFIG_SPI_MICROCHIP_CORE is not set
# CONFIG_SPI_LANTIQ_SSC is not set
# CONFIG_SPI_OC_TINY is not set
# CONFIG_SPI_PXA2XX is not set
# CONFIG_SPI_ROCKCHIP is not set
# CONFIG_SPI_SC18IS602 is not set
# CONFIG_SPI_SIFIVE is not set
# CONFIG_SPI_MXIC is not set
# CONFIG_SPI_XCOMM is not set
# CONFIG_SPI_XILINX is not set
# CONFIG_SPI_ZYNQMP_GQSPI is not set
# CONFIG_SPI_AMD is not set

#
# SPI Multiplexer support
#
# CONFIG_SPI_MUX is not set

#
# SPI Protocol Masters
#
# CONFIG_SPI_SPIDEV is not set
# CONFIG_SPI_LOOPBACK_TEST is not set
# CONFIG_SPI_TLE62X0 is not set
# CONFIG_SPI_SLAVE is not set
CONFIG_SPI_DYNAMIC=y
# CONFIG_SPMI is not set
# CONFIG_HSI is not set
CONFIG_PPS=y
# CONFIG_PPS_DEBUG is not set

#
# PPS clients support
#
# CONFIG_PPS_CLIENT_KTIMER is not set
CONFIG_PPS_CLIENT_LDISC=m
CONFIG_PPS_CLIENT_PARPORT=m
CONFIG_PPS_CLIENT_GPIO=m

#
# PPS generators support
#

#
# PTP clock support
#
CONFIG_PTP_1588_CLOCK=y
CONFIG_PTP_1588_CLOCK_OPTIONAL=y
# CONFIG_DP83640_PHY is not set
# CONFIG_PTP_1588_CLOCK_INES is not set
CONFIG_PTP_1588_CLOCK_KVM=m
# CONFIG_PTP_1588_CLOCK_IDT82P33 is not set
# CONFIG_PTP_1588_CLOCK_IDTCM is not set
# CONFIG_PTP_1588_CLOCK_VMW is not set
# end of PTP clock support

CONFIG_PINCTRL=y
# CONFIG_DEBUG_PINCTRL is not set
# CONFIG_PINCTRL_AMD is not set
# CONFIG_PINCTRL_MCP23S08 is not set
# CONFIG_PINCTRL_SX150X is not set

#
# Intel pinctrl drivers
#
# CONFIG_PINCTRL_BAYTRAIL is not set
# CONFIG_PINCTRL_CHERRYVIEW is not set
# CONFIG_PINCTRL_LYNXPOINT is not set
# CONFIG_PINCTRL_ALDERLAKE is not set
# CONFIG_PINCTRL_BROXTON is not set
# CONFIG_PINCTRL_CANNONLAKE is not set
# CONFIG_PINCTRL_CEDARFORK is not set
# CONFIG_PINCTRL_DENVERTON is not set
# CONFIG_PINCTRL_ELKHARTLAKE is not set
# CONFIG_PINCTRL_EMMITSBURG is not set
# CONFIG_PINCTRL_GEMINILAKE is not set
# CONFIG_PINCTRL_ICELAKE is not set
# CONFIG_PINCTRL_JASPERLAKE is not set
# CONFIG_PINCTRL_LAKEFIELD is not set
# CONFIG_PINCTRL_LEWISBURG is not set
# CONFIG_PINCTRL_METEORLAKE is not set
# CONFIG_PINCTRL_SUNRISEPOINT is not set
# CONFIG_PINCTRL_TIGERLAKE is not set
# end of Intel pinctrl drivers

#
# Renesas pinctrl drivers
#
# end of Renesas pinctrl drivers

CONFIG_GPIOLIB=y
CONFIG_GPIOLIB_FASTPATH_LIMIT=512
CONFIG_GPIO_ACPI=y
# CONFIG_DEBUG_GPIO is not set
CONFIG_GPIO_CDEV=y
CONFIG_GPIO_CDEV_V1=y

#
# Memory mapped GPIO drivers
#
# CONFIG_GPIO_AMDPT is not set
# CONFIG_GPIO_DWAPB is not set
# CONFIG_GPIO_EXAR is not set
# CONFIG_GPIO_GENERIC_PLATFORM is not set
CONFIG_GPIO_ICH=m
# CONFIG_GPIO_MB86S7X is not set
# CONFIG_GPIO_VX855 is not set
# CONFIG_GPIO_AMD_FCH is not set
# end of Memory mapped GPIO drivers

#
# Port-mapped I/O GPIO drivers
#
# CONFIG_GPIO_F7188X is not set
# CONFIG_GPIO_IT87 is not set
# CONFIG_GPIO_SCH is not set
# CONFIG_GPIO_SCH311X is not set
# CONFIG_GPIO_WINBOND is not set
# CONFIG_GPIO_WS16C48 is not set
# end of Port-mapped I/O GPIO drivers

#
# I2C GPIO expanders
#
# CONFIG_GPIO_ADP5588 is not set
# CONFIG_GPIO_MAX7300 is not set
# CONFIG_GPIO_MAX732X is not set
# CONFIG_GPIO_PCA953X is not set
# CONFIG_GPIO_PCA9570 is not set
# CONFIG_GPIO_PCF857X is not set
# CONFIG_GPIO_TPIC2810 is not set
# end of I2C GPIO expanders

#
# MFD GPIO expanders
#
# end of MFD GPIO expanders

#
# PCI GPIO expanders
#
# CONFIG_GPIO_AMD8111 is not set
# CONFIG_GPIO_BT8XX is not set
# CONFIG_GPIO_ML_IOH is not set
# CONFIG_GPIO_PCI_IDIO_16 is not set
# CONFIG_GPIO_PCIE_IDIO_24 is not set
# CONFIG_GPIO_RDC321X is not set
# end of PCI GPIO expanders

#
# SPI GPIO expanders
#
# CONFIG_GPIO_MAX3191X is not set
# CONFIG_GPIO_MAX7301 is not set
# CONFIG_GPIO_MC33880 is not set
# CONFIG_GPIO_PISOSR is not set
# CONFIG_GPIO_XRA1403 is not set
# end of SPI GPIO expanders

#
# USB GPIO expanders
#
# end of USB GPIO expanders

#
# Virtual GPIO drivers
#
# CONFIG_GPIO_AGGREGATOR is not set
# CONFIG_GPIO_MOCKUP is not set
# CONFIG_GPIO_VIRTIO is not set
# CONFIG_GPIO_SIM is not set
# end of Virtual GPIO drivers

# CONFIG_W1 is not set
CONFIG_POWER_RESET=y
# CONFIG_POWER_RESET_RESTART is not set
CONFIG_POWER_SUPPLY=y
# CONFIG_POWER_SUPPLY_DEBUG is not set
CONFIG_POWER_SUPPLY_HWMON=y
# CONFIG_PDA_POWER is not set
# CONFIG_IP5XXX_POWER is not set
# CONFIG_TEST_POWER is not set
# CONFIG_CHARGER_ADP5061 is not set
# CONFIG_BATTERY_CW2015 is not set
# CONFIG_BATTERY_DS2780 is not set
# CONFIG_BATTERY_DS2781 is not set
# CONFIG_BATTERY_DS2782 is not set
# CONFIG_BATTERY_SAMSUNG_SDI is not set
# CONFIG_BATTERY_SBS is not set
# CONFIG_CHARGER_SBS is not set
# CONFIG_MANAGER_SBS is not set
# CONFIG_BATTERY_BQ27XXX is not set
# CONFIG_BATTERY_MAX17040 is not set
# CONFIG_BATTERY_MAX17042 is not set
# CONFIG_CHARGER_MAX8903 is not set
# CONFIG_CHARGER_LP8727 is not set
# CONFIG_CHARGER_GPIO is not set
# CONFIG_CHARGER_LT3651 is not set
# CONFIG_CHARGER_LTC4162L is not set
# CONFIG_CHARGER_MAX77976 is not set
# CONFIG_CHARGER_BQ2415X is not set
# CONFIG_CHARGER_BQ24257 is not set
# CONFIG_CHARGER_BQ24735 is not set
# CONFIG_CHARGER_BQ2515X is not set
# CONFIG_CHARGER_BQ25890 is not set
# CONFIG_CHARGER_BQ25980 is not set
# CONFIG_CHARGER_BQ256XX is not set
# CONFIG_BATTERY_GAUGE_LTC2941 is not set
# CONFIG_BATTERY_GOLDFISH is not set
# CONFIG_BATTERY_RT5033 is not set
# CONFIG_CHARGER_RT9455 is not set
# CONFIG_CHARGER_BD99954 is not set
# CONFIG_BATTERY_UG3105 is not set
CONFIG_HWMON=y
CONFIG_HWMON_VID=m
# CONFIG_HWMON_DEBUG_CHIP is not set

#
# Native drivers
#
CONFIG_SENSORS_ABITUGURU=m
CONFIG_SENSORS_ABITUGURU3=m
# CONFIG_SENSORS_AD7314 is not set
CONFIG_SENSORS_AD7414=m
CONFIG_SENSORS_AD7418=m
CONFIG_SENSORS_ADM1025=m
CONFIG_SENSORS_ADM1026=m
CONFIG_SENSORS_ADM1029=m
CONFIG_SENSORS_ADM1031=m
# CONFIG_SENSORS_ADM1177 is not set
CONFIG_SENSORS_ADM9240=m
CONFIG_SENSORS_ADT7X10=m
# CONFIG_SENSORS_ADT7310 is not set
CONFIG_SENSORS_ADT7410=m
CONFIG_SENSORS_ADT7411=m
CONFIG_SENSORS_ADT7462=m
CONFIG_SENSORS_ADT7470=m
CONFIG_SENSORS_ADT7475=m
# CONFIG_SENSORS_AHT10 is not set
# CONFIG_SENSORS_AQUACOMPUTER_D5NEXT is not set
# CONFIG_SENSORS_AS370 is not set
CONFIG_SENSORS_ASC7621=m
# CONFIG_SENSORS_AXI_FAN_CONTROL is not set
CONFIG_SENSORS_K8TEMP=m
CONFIG_SENSORS_K10TEMP=m
CONFIG_SENSORS_FAM15H_POWER=m
CONFIG_SENSORS_APPLESMC=m
CONFIG_SENSORS_ASB100=m
# CONFIG_SENSORS_ASPEED is not set
CONFIG_SENSORS_ATXP1=m
# CONFIG_SENSORS_CORSAIR_CPRO is not set
# CONFIG_SENSORS_CORSAIR_PSU is not set
# CONFIG_SENSORS_DRIVETEMP is not set
CONFIG_SENSORS_DS620=m
CONFIG_SENSORS_DS1621=m
# CONFIG_SENSORS_DELL_SMM is not set
CONFIG_SENSORS_I5K_AMB=m
CONFIG_SENSORS_F71805F=m
CONFIG_SENSORS_F71882FG=m
CONFIG_SENSORS_F75375S=m
CONFIG_SENSORS_FSCHMD=m
# CONFIG_SENSORS_FTSTEUTATES is not set
CONFIG_SENSORS_GL518SM=m
CONFIG_SENSORS_GL520SM=m
CONFIG_SENSORS_G760A=m
# CONFIG_SENSORS_G762 is not set
# CONFIG_SENSORS_HIH6130 is not set
CONFIG_SENSORS_IBMAEM=m
CONFIG_SENSORS_IBMPEX=m
CONFIG_SENSORS_I5500=m
CONFIG_SENSORS_CORETEMP=m
CONFIG_SENSORS_IT87=m
CONFIG_SENSORS_JC42=m
# CONFIG_SENSORS_POWR1220 is not set
CONFIG_SENSORS_LINEAGE=m
# CONFIG_SENSORS_LTC2945 is not set
# CONFIG_SENSORS_LTC2947_I2C is not set
# CONFIG_SENSORS_LTC2947_SPI is not set
# CONFIG_SENSORS_LTC2990 is not set
# CONFIG_SENSORS_LTC2992 is not set
CONFIG_SENSORS_LTC4151=m
CONFIG_SENSORS_LTC4215=m
# CONFIG_SENSORS_LTC4222 is not set
CONFIG_SENSORS_LTC4245=m
# CONFIG_SENSORS_LTC4260 is not set
CONFIG_SENSORS_LTC4261=m
# CONFIG_SENSORS_MAX1111 is not set
# CONFIG_SENSORS_MAX127 is not set
CONFIG_SENSORS_MAX16065=m
CONFIG_SENSORS_MAX1619=m
CONFIG_SENSORS_MAX1668=m
CONFIG_SENSORS_MAX197=m
# CONFIG_SENSORS_MAX31722 is not set
# CONFIG_SENSORS_MAX31730 is not set
# CONFIG_SENSORS_MAX6620 is not set
# CONFIG_SENSORS_MAX6621 is not set
CONFIG_SENSORS_MAX6639=m
CONFIG_SENSORS_MAX6650=m
CONFIG_SENSORS_MAX6697=m
# CONFIG_SENSORS_MAX31790 is not set
CONFIG_SENSORS_MCP3021=m
# CONFIG_SENSORS_MLXREG_FAN is not set
# CONFIG_SENSORS_TC654 is not set
# CONFIG_SENSORS_TPS23861 is not set
# CONFIG_SENSORS_MR75203 is not set
# CONFIG_SENSORS_ADCXX is not set
CONFIG_SENSORS_LM63=m
# CONFIG_SENSORS_LM70 is not set
CONFIG_SENSORS_LM73=m
CONFIG_SENSORS_LM75=m
CONFIG_SENSORS_LM77=m
CONFIG_SENSORS_LM78=m
CONFIG_SENSORS_LM80=m
CONFIG_SENSORS_LM83=m
CONFIG_SENSORS_LM85=m
CONFIG_SENSORS_LM87=m
CONFIG_SENSORS_LM90=m
CONFIG_SENSORS_LM92=m
CONFIG_SENSORS_LM93=m
CONFIG_SENSORS_LM95234=m
CONFIG_SENSORS_LM95241=m
CONFIG_SENSORS_LM95245=m
CONFIG_SENSORS_PC87360=m
CONFIG_SENSORS_PC87427=m
# CONFIG_SENSORS_NCT6683 is not set
CONFIG_SENSORS_NCT6775_CORE=m
CONFIG_SENSORS_NCT6775=m
# CONFIG_SENSORS_NCT6775_I2C is not set
# CONFIG_SENSORS_NCT7802 is not set
# CONFIG_SENSORS_NCT7904 is not set
# CONFIG_SENSORS_NPCM7XX is not set
# CONFIG_SENSORS_NZXT_KRAKEN2 is not set
# CONFIG_SENSORS_NZXT_SMART2 is not set
CONFIG_SENSORS_PCF8591=m
CONFIG_PMBUS=m
CONFIG_SENSORS_PMBUS=m
# CONFIG_SENSORS_ADM1266 is not set
CONFIG_SENSORS_ADM1275=m
# CONFIG_SENSORS_BEL_PFE is not set
# CONFIG_SENSORS_BPA_RS600 is not set
# CONFIG_SENSORS_DELTA_AHE50DC_FAN is not set
# CONFIG_SENSORS_FSP_3Y is not set
# CONFIG_SENSORS_IBM_CFFPS is not set
# CONFIG_SENSORS_DPS920AB is not set
# CONFIG_SENSORS_INSPUR_IPSPS is not set
# CONFIG_SENSORS_IR35221 is not set
# CONFIG_SENSORS_IR36021 is not set
# CONFIG_SENSORS_IR38064 is not set
# CONFIG_SENSORS_IRPS5401 is not set
# CONFIG_SENSORS_ISL68137 is not set
CONFIG_SENSORS_LM25066=m
# CONFIG_SENSORS_LT7182S is not set
CONFIG_SENSORS_LTC2978=m
# CONFIG_SENSORS_LTC3815 is not set
# CONFIG_SENSORS_MAX15301 is not set
CONFIG_SENSORS_MAX16064=m
# CONFIG_SENSORS_MAX16601 is not set
# CONFIG_SENSORS_MAX20730 is not set
# CONFIG_SENSORS_MAX20751 is not set
# CONFIG_SENSORS_MAX31785 is not set
CONFIG_SENSORS_MAX34440=m
CONFIG_SENSORS_MAX8688=m
# CONFIG_SENSORS_MP2888 is not set
# CONFIG_SENSORS_MP2975 is not set
# CONFIG_SENSORS_MP5023 is not set
# CONFIG_SENSORS_PIM4328 is not set
# CONFIG_SENSORS_PLI1209BC is not set
# CONFIG_SENSORS_PM6764TR is not set
# CONFIG_SENSORS_PXE1610 is not set
# CONFIG_SENSORS_Q54SJ108A2 is not set
# CONFIG_SENSORS_STPDDC60 is not set
# CONFIG_SENSORS_TPS40422 is not set
# CONFIG_SENSORS_TPS53679 is not set
CONFIG_SENSORS_UCD9000=m
CONFIG_SENSORS_UCD9200=m
# CONFIG_SENSORS_XDPE152 is not set
# CONFIG_SENSORS_XDPE122 is not set
CONFIG_SENSORS_ZL6100=m
# CONFIG_SENSORS_SBTSI is not set
# CONFIG_SENSORS_SBRMI is not set
CONFIG_SENSORS_SHT15=m
CONFIG_SENSORS_SHT21=m
# CONFIG_SENSORS_SHT3x is not set
# CONFIG_SENSORS_SHT4x is not set
# CONFIG_SENSORS_SHTC1 is not set
CONFIG_SENSORS_SIS5595=m
# CONFIG_SENSORS_SY7636A is not set
CONFIG_SENSORS_DME1737=m
CONFIG_SENSORS_EMC1403=m
# CONFIG_SENSORS_EMC2103 is not set
CONFIG_SENSORS_EMC6W201=m
CONFIG_SENSORS_SMSC47M1=m
CONFIG_SENSORS_SMSC47M192=m
CONFIG_SENSORS_SMSC47B397=m
CONFIG_SENSORS_SCH56XX_COMMON=m
CONFIG_SENSORS_SCH5627=m
CONFIG_SENSORS_SCH5636=m
# CONFIG_SENSORS_STTS751 is not set
# CONFIG_SENSORS_SMM665 is not set
# CONFIG_SENSORS_ADC128D818 is not set
CONFIG_SENSORS_ADS7828=m
# CONFIG_SENSORS_ADS7871 is not set
CONFIG_SENSORS_AMC6821=m
CONFIG_SENSORS_INA209=m
CONFIG_SENSORS_INA2XX=m
# CONFIG_SENSORS_INA238 is not set
# CONFIG_SENSORS_INA3221 is not set
# CONFIG_SENSORS_TC74 is not set
CONFIG_SENSORS_THMC50=m
CONFIG_SENSORS_TMP102=m
# CONFIG_SENSORS_TMP103 is not set
# CONFIG_SENSORS_TMP108 is not set
CONFIG_SENSORS_TMP401=m
CONFIG_SENSORS_TMP421=m
# CONFIG_SENSORS_TMP464 is not set
# CONFIG_SENSORS_TMP513 is not set
CONFIG_SENSORS_VIA_CPUTEMP=m
CONFIG_SENSORS_VIA686A=m
CONFIG_SENSORS_VT1211=m
CONFIG_SENSORS_VT8231=m
# CONFIG_SENSORS_W83773G is not set
CONFIG_SENSORS_W83781D=m
CONFIG_SENSORS_W83791D=m
CONFIG_SENSORS_W83792D=m
CONFIG_SENSORS_W83793=m
CONFIG_SENSORS_W83795=m
# CONFIG_SENSORS_W83795_FANCTRL is not set
CONFIG_SENSORS_W83L785TS=m
CONFIG_SENSORS_W83L786NG=m
CONFIG_SENSORS_W83627HF=m
CONFIG_SENSORS_W83627EHF=m
# CONFIG_SENSORS_XGENE is not set

#
# ACPI drivers
#
CONFIG_SENSORS_ACPI_POWER=m
CONFIG_SENSORS_ATK0110=m
# CONFIG_SENSORS_ASUS_WMI is not set
# CONFIG_SENSORS_ASUS_WMI_EC is not set
# CONFIG_SENSORS_ASUS_EC is not set
CONFIG_THERMAL=y
# CONFIG_THERMAL_NETLINK is not set
# CONFIG_THERMAL_STATISTICS is not set
CONFIG_THERMAL_EMERGENCY_POWEROFF_DELAY_MS=0
CONFIG_THERMAL_HWMON=y
CONFIG_THERMAL_WRITABLE_TRIPS=y
CONFIG_THERMAL_DEFAULT_GOV_STEP_WISE=y
# CONFIG_THERMAL_DEFAULT_GOV_FAIR_SHARE is not set
# CONFIG_THERMAL_DEFAULT_GOV_USER_SPACE is not set
CONFIG_THERMAL_GOV_FAIR_SHARE=y
CONFIG_THERMAL_GOV_STEP_WISE=y
CONFIG_THERMAL_GOV_BANG_BANG=y
CONFIG_THERMAL_GOV_USER_SPACE=y
# CONFIG_THERMAL_EMULATION is not set

#
# Intel thermal drivers
#
CONFIG_INTEL_POWERCLAMP=m
CONFIG_X86_THERMAL_VECTOR=y
CONFIG_X86_PKG_TEMP_THERMAL=m
# CONFIG_INTEL_SOC_DTS_THERMAL is not set

#
# ACPI INT340X thermal drivers
#
# CONFIG_INT340X_THERMAL is not set
# end of ACPI INT340X thermal drivers

CONFIG_INTEL_PCH_THERMAL=m
# CONFIG_INTEL_TCC_COOLING is not set
# CONFIG_INTEL_MENLOW is not set
# CONFIG_INTEL_HFI_THERMAL is not set
# end of Intel thermal drivers

CONFIG_WATCHDOG=y
CONFIG_WATCHDOG_CORE=y
# CONFIG_WATCHDOG_NOWAYOUT is not set
CONFIG_WATCHDOG_HANDLE_BOOT_ENABLED=y
CONFIG_WATCHDOG_OPEN_TIMEOUT=0
CONFIG_WATCHDOG_SYSFS=y
# CONFIG_WATCHDOG_HRTIMER_PRETIMEOUT is not set

#
# Watchdog Pretimeout Governors
#
# CONFIG_WATCHDOG_PRETIMEOUT_GOV is not set

#
# Watchdog Device Drivers
#
CONFIG_SOFT_WATCHDOG=m
CONFIG_WDAT_WDT=m
# CONFIG_XILINX_WATCHDOG is not set
# CONFIG_ZIIRAVE_WATCHDOG is not set
# CONFIG_MLX_WDT is not set
# CONFIG_CADENCE_WATCHDOG is not set
# CONFIG_DW_WATCHDOG is not set
# CONFIG_MAX63XX_WATCHDOG is not set
# CONFIG_ACQUIRE_WDT is not set
# CONFIG_ADVANTECH_WDT is not set
CONFIG_ALIM1535_WDT=m
CONFIG_ALIM7101_WDT=m
# CONFIG_EBC_C384_WDT is not set
CONFIG_F71808E_WDT=m
# CONFIG_SP5100_TCO is not set
CONFIG_SBC_FITPC2_WATCHDOG=m
# CONFIG_EUROTECH_WDT is not set
CONFIG_IB700_WDT=m
CONFIG_IBMASR=m
# CONFIG_WAFER_WDT is not set
CONFIG_I6300ESB_WDT=y
CONFIG_IE6XX_WDT=m
CONFIG_ITCO_WDT=y
CONFIG_ITCO_VENDOR_SUPPORT=y
CONFIG_IT8712F_WDT=m
CONFIG_IT87_WDT=m
CONFIG_HP_WATCHDOG=m
CONFIG_HPWDT_NMI_DECODING=y
# CONFIG_SC1200_WDT is not set
# CONFIG_PC87413_WDT is not set
CONFIG_NV_TCO=m
# CONFIG_60XX_WDT is not set
# CONFIG_CPU5_WDT is not set
CONFIG_SMSC_SCH311X_WDT=m
# CONFIG_SMSC37B787_WDT is not set
# CONFIG_TQMX86_WDT is not set
CONFIG_VIA_WDT=m
CONFIG_W83627HF_WDT=m
CONFIG_W83877F_WDT=m
CONFIG_W83977F_WDT=m
CONFIG_MACHZ_WDT=m
# CONFIG_SBC_EPX_C3_WATCHDOG is not set
CONFIG_INTEL_MEI_WDT=m
# CONFIG_NI903X_WDT is not set
# CONFIG_NIC7018_WDT is not set
# CONFIG_MEN_A21_WDT is not set

#
# PCI-based Watchdog Cards
#
CONFIG_PCIPCWATCHDOG=m
CONFIG_WDTPCI=m

#
# USB-based Watchdog Cards
#
# CONFIG_USBPCWATCHDOG is not set
CONFIG_SSB_POSSIBLE=y
# CONFIG_SSB is not set
CONFIG_BCMA_POSSIBLE=y
CONFIG_BCMA=m
CONFIG_BCMA_HOST_PCI_POSSIBLE=y
CONFIG_BCMA_HOST_PCI=y
# CONFIG_BCMA_HOST_SOC is not set
CONFIG_BCMA_DRIVER_PCI=y
CONFIG_BCMA_DRIVER_GMAC_CMN=y
CONFIG_BCMA_DRIVER_GPIO=y
# CONFIG_BCMA_DEBUG is not set

#
# Multifunction device drivers
#
CONFIG_MFD_CORE=y
# CONFIG_MFD_AS3711 is not set
# CONFIG_PMIC_ADP5520 is not set
# CONFIG_MFD_AAT2870_CORE is not set
# CONFIG_MFD_BCM590XX is not set
# CONFIG_MFD_BD9571MWV is not set
# CONFIG_MFD_AXP20X_I2C is not set
# CONFIG_MFD_MADERA is not set
# CONFIG_PMIC_DA903X is not set
# CONFIG_MFD_DA9052_SPI is not set
# CONFIG_MFD_DA9052_I2C is not set
# CONFIG_MFD_DA9055 is not set
# CONFIG_MFD_DA9062 is not set
# CONFIG_MFD_DA9063 is not set
# CONFIG_MFD_DA9150 is not set
# CONFIG_MFD_DLN2 is not set
# CONFIG_MFD_MC13XXX_SPI is not set
# CONFIG_MFD_MC13XXX_I2C is not set
# CONFIG_MFD_MP2629 is not set
# CONFIG_HTC_PASIC3 is not set
# CONFIG_HTC_I2CPLD is not set
# CONFIG_MFD_INTEL_QUARK_I2C_GPIO is not set
CONFIG_LPC_ICH=y
CONFIG_LPC_SCH=m
CONFIG_MFD_INTEL_LPSS=y
CONFIG_MFD_INTEL_LPSS_ACPI=y
CONFIG_MFD_INTEL_LPSS_PCI=y
# CONFIG_MFD_INTEL_PMC_BXT is not set
# CONFIG_MFD_IQS62X is not set
# CONFIG_MFD_JANZ_CMODIO is not set
# CONFIG_MFD_KEMPLD is not set
# CONFIG_MFD_88PM800 is not set
# CONFIG_MFD_88PM805 is not set
# CONFIG_MFD_88PM860X is not set
# CONFIG_MFD_MAX14577 is not set
# CONFIG_MFD_MAX77693 is not set
# CONFIG_MFD_MAX77843 is not set
# CONFIG_MFD_MAX8907 is not set
# CONFIG_MFD_MAX8925 is not set
# CONFIG_MFD_MAX8997 is not set
# CONFIG_MFD_MAX8998 is not set
# CONFIG_MFD_MT6360 is not set
# CONFIG_MFD_MT6397 is not set
# CONFIG_MFD_MENF21BMC is not set
# CONFIG_EZX_PCAP is not set
# CONFIG_MFD_VIPERBOARD is not set
# CONFIG_MFD_RETU is not set
# CONFIG_MFD_PCF50633 is not set
# CONFIG_MFD_RDC321X is not set
# CONFIG_MFD_RT4831 is not set
# CONFIG_MFD_RT5033 is not set
# CONFIG_MFD_RC5T583 is not set
# CONFIG_MFD_SI476X_CORE is not set
# CONFIG_MFD_SIMPLE_MFD_I2C is not set
CONFIG_MFD_SM501=m
CONFIG_MFD_SM501_GPIO=y
# CONFIG_MFD_SKY81452 is not set
# CONFIG_MFD_SYSCON is not set
# CONFIG_MFD_TI_AM335X_TSCADC is not set
# CONFIG_MFD_LP3943 is not set
# CONFIG_MFD_LP8788 is not set
# CONFIG_MFD_TI_LMU is not set
# CONFIG_MFD_PALMAS is not set
# CONFIG_TPS6105X is not set
# CONFIG_TPS65010 is not set
# CONFIG_TPS6507X is not set
# CONFIG_MFD_TPS65086 is not set
# CONFIG_MFD_TPS65090 is not set
# CONFIG_MFD_TI_LP873X is not set
# CONFIG_MFD_TPS6586X is not set
# CONFIG_MFD_TPS65910 is not set
# CONFIG_MFD_TPS65912_I2C is not set
# CONFIG_MFD_TPS65912_SPI is not set
# CONFIG_TWL4030_CORE is not set
# CONFIG_TWL6040_CORE is not set
# CONFIG_MFD_WL1273_CORE is not set
# CONFIG_MFD_LM3533 is not set
# CONFIG_MFD_TQMX86 is not set
CONFIG_MFD_VX855=m
# CONFIG_MFD_ARIZONA_I2C is not set
# CONFIG_MFD_ARIZONA_SPI is not set
# CONFIG_MFD_WM8400 is not set
# CONFIG_MFD_WM831X_I2C is not set
# CONFIG_MFD_WM831X_SPI is not set
# CONFIG_MFD_WM8350_I2C is not set
# CONFIG_MFD_WM8994 is not set
# CONFIG_MFD_ATC260X_I2C is not set
# CONFIG_MFD_INTEL_M10_BMC is not set
# end of Multifunction device drivers

# CONFIG_REGULATOR is not set
CONFIG_RC_CORE=m
CONFIG_LIRC=y
CONFIG_RC_MAP=m
CONFIG_RC_DECODERS=y
CONFIG_IR_IMON_DECODER=m
CONFIG_IR_JVC_DECODER=m
CONFIG_IR_MCE_KBD_DECODER=m
CONFIG_IR_NEC_DECODER=m
CONFIG_IR_RC5_DECODER=m
CONFIG_IR_RC6_DECODER=m
# CONFIG_IR_RCMM_DECODER is not set
CONFIG_IR_SANYO_DECODER=m
# CONFIG_IR_SHARP_DECODER is not set
CONFIG_IR_SONY_DECODER=m
# CONFIG_IR_XMP_DECODER is not set
CONFIG_RC_DEVICES=y
CONFIG_IR_ENE=m
CONFIG_IR_FINTEK=m
# CONFIG_IR_IGORPLUGUSB is not set
# CONFIG_IR_IGUANA is not set
# CONFIG_IR_IMON is not set
# CONFIG_IR_IMON_RAW is not set
CONFIG_IR_ITE_CIR=m
# CONFIG_IR_MCEUSB is not set
CONFIG_IR_NUVOTON=m
# CONFIG_IR_REDRAT3 is not set
CONFIG_IR_SERIAL=m
CONFIG_IR_SERIAL_TRANSMITTER=y
# CONFIG_IR_STREAMZAP is not set
# CONFIG_IR_TOY is not set
# CONFIG_IR_TTUSBIR is not set
CONFIG_IR_WINBOND_CIR=m
# CONFIG_RC_ATI_REMOTE is not set
# CONFIG_RC_LOOPBACK is not set
# CONFIG_RC_XBOX_DVD is not set

#
# CEC support
#
# CONFIG_MEDIA_CEC_SUPPORT is not set
# end of CEC support

CONFIG_MEDIA_SUPPORT=m
CONFIG_MEDIA_SUPPORT_FILTER=y
CONFIG_MEDIA_SUBDRV_AUTOSELECT=y

#
# Media device types
#
# CONFIG_MEDIA_CAMERA_SUPPORT is not set
# CONFIG_MEDIA_ANALOG_TV_SUPPORT is not set
# CONFIG_MEDIA_DIGITAL_TV_SUPPORT is not set
# CONFIG_MEDIA_RADIO_SUPPORT is not set
# CONFIG_MEDIA_SDR_SUPPORT is not set
# CONFIG_MEDIA_PLATFORM_SUPPORT is not set
# CONFIG_MEDIA_TEST_SUPPORT is not set
# end of Media device types

#
# Media drivers
#

#
# Drivers filtered as selected at 'Filter media drivers'
#

#
# Media drivers
#
# CONFIG_MEDIA_USB_SUPPORT is not set
# CONFIG_MEDIA_PCI_SUPPORT is not set
# end of Media drivers

CONFIG_MEDIA_HIDE_ANCILLARY_SUBDRV=y

#
# Media ancillary drivers
#
# end of Media ancillary drivers

#
# Graphics support
#
CONFIG_APERTURE_HELPERS=y
# CONFIG_AGP is not set
CONFIG_INTEL_GTT=m
CONFIG_VGA_SWITCHEROO=y
CONFIG_DRM=m
CONFIG_DRM_MIPI_DSI=y
# CONFIG_DRM_DEBUG_SELFTEST is not set
CONFIG_DRM_KMS_HELPER=m
CONFIG_DRM_FBDEV_EMULATION=y
CONFIG_DRM_FBDEV_OVERALLOC=100
CONFIG_DRM_LOAD_EDID_FIRMWARE=y
CONFIG_DRM_DISPLAY_HELPER=m
CONFIG_DRM_DISPLAY_DP_HELPER=y
CONFIG_DRM_DISPLAY_HDCP_HELPER=y
CONFIG_DRM_DISPLAY_HDMI_HELPER=y
CONFIG_DRM_DP_AUX_CHARDEV=y
# CONFIG_DRM_DP_CEC is not set
CONFIG_DRM_TTM=m
CONFIG_DRM_BUDDY=m
CONFIG_DRM_VRAM_HELPER=m
CONFIG_DRM_TTM_HELPER=m
CONFIG_DRM_GEM_SHMEM_HELPER=m

#
# I2C encoder or helper chips
#
CONFIG_DRM_I2C_CH7006=m
CONFIG_DRM_I2C_SIL164=m
# CONFIG_DRM_I2C_NXP_TDA998X is not set
# CONFIG_DRM_I2C_NXP_TDA9950 is not set
# end of I2C encoder or helper chips

#
# ARM devices
#
# end of ARM devices

# CONFIG_DRM_RADEON is not set
# CONFIG_DRM_AMDGPU is not set
# CONFIG_DRM_NOUVEAU is not set
CONFIG_DRM_I915=m
CONFIG_DRM_I915_FORCE_PROBE=""
CONFIG_DRM_I915_CAPTURE_ERROR=y
CONFIG_DRM_I915_COMPRESS_ERROR=y
CONFIG_DRM_I915_USERPTR=y
# CONFIG_DRM_I915_GVT_KVMGT is not set
CONFIG_DRM_I915_REQUEST_TIMEOUT=20000
CONFIG_DRM_I915_FENCE_TIMEOUT=10000
CONFIG_DRM_I915_USERFAULT_AUTOSUSPEND=250
CONFIG_DRM_I915_HEARTBEAT_INTERVAL=2500
CONFIG_DRM_I915_PREEMPT_TIMEOUT=640
CONFIG_DRM_I915_MAX_REQUEST_BUSYWAIT=8000
CONFIG_DRM_I915_STOP_TIMEOUT=100
CONFIG_DRM_I915_TIMESLICE_DURATION=1
# CONFIG_DRM_VGEM is not set
# CONFIG_DRM_VKMS is not set
# CONFIG_DRM_VMWGFX is not set
CONFIG_DRM_GMA500=m
# CONFIG_DRM_UDL is not set
CONFIG_DRM_AST=m
# CONFIG_DRM_MGAG200 is not set
CONFIG_DRM_QXL=m
CONFIG_DRM_VIRTIO_GPU=m
CONFIG_DRM_PANEL=y

#
# Display Panels
#
# CONFIG_DRM_PANEL_RASPBERRYPI_TOUCHSCREEN is not set
# CONFIG_DRM_PANEL_WIDECHIPS_WS2401 is not set
# end of Display Panels

CONFIG_DRM_BRIDGE=y
CONFIG_DRM_PANEL_BRIDGE=y

#
# Display Interface Bridges
#
# CONFIG_DRM_ANALOGIX_ANX78XX is not set
# end of Display Interface Bridges

# CONFIG_DRM_ETNAVIV is not set
CONFIG_DRM_BOCHS=m
CONFIG_DRM_CIRRUS_QEMU=m
# CONFIG_DRM_GM12U320 is not set
# CONFIG_DRM_PANEL_MIPI_DBI is not set
# CONFIG_DRM_SIMPLEDRM is not set
# CONFIG_TINYDRM_HX8357D is not set
# CONFIG_TINYDRM_ILI9163 is not set
# CONFIG_TINYDRM_ILI9225 is not set
# CONFIG_TINYDRM_ILI9341 is not set
# CONFIG_TINYDRM_ILI9486 is not set
# CONFIG_TINYDRM_MI0283QT is not set
# CONFIG_TINYDRM_REPAPER is not set
# CONFIG_TINYDRM_ST7586 is not set
# CONFIG_TINYDRM_ST7735R is not set
# CONFIG_DRM_VBOXVIDEO is not set
# CONFIG_DRM_GUD is not set
# CONFIG_DRM_SSD130X is not set
# CONFIG_DRM_LEGACY is not set
CONFIG_DRM_PANEL_ORIENTATION_QUIRKS=y
CONFIG_DRM_NOMODESET=y
CONFIG_DRM_PRIVACY_SCREEN=y

#
# Frame buffer Devices
#
CONFIG_FB_CMDLINE=y
CONFIG_FB_NOTIFY=y
CONFIG_FB=y
# CONFIG_FIRMWARE_EDID is not set
CONFIG_FB_CFB_FILLRECT=y
CONFIG_FB_CFB_COPYAREA=y
CONFIG_FB_CFB_IMAGEBLIT=y
CONFIG_FB_SYS_FILLRECT=m
CONFIG_FB_SYS_COPYAREA=m
CONFIG_FB_SYS_IMAGEBLIT=m
# CONFIG_FB_FOREIGN_ENDIAN is not set
CONFIG_FB_SYS_FOPS=m
CONFIG_FB_DEFERRED_IO=y
# CONFIG_FB_MODE_HELPERS is not set
CONFIG_FB_TILEBLITTING=y

#
# Frame buffer hardware drivers
#
# CONFIG_FB_CIRRUS is not set
# CONFIG_FB_PM2 is not set
# CONFIG_FB_CYBER2000 is not set
# CONFIG_FB_ARC is not set
# CONFIG_FB_ASILIANT is not set
# CONFIG_FB_IMSTT is not set
# CONFIG_FB_VGA16 is not set
# CONFIG_FB_UVESA is not set
CONFIG_FB_VESA=y
CONFIG_FB_EFI=y
# CONFIG_FB_N411 is not set
# CONFIG_FB_HGA is not set
# CONFIG_FB_OPENCORES is not set
# CONFIG_FB_S1D13XXX is not set
# CONFIG_FB_NVIDIA is not set
# CONFIG_FB_RIVA is not set
# CONFIG_FB_I740 is not set
# CONFIG_FB_LE80578 is not set
# CONFIG_FB_MATROX is not set
# CONFIG_FB_RADEON is not set
# CONFIG_FB_ATY128 is not set
# CONFIG_FB_ATY is not set
# CONFIG_FB_S3 is not set
# CONFIG_FB_SAVAGE is not set
# CONFIG_FB_SIS is not set
# CONFIG_FB_VIA is not set
# CONFIG_FB_NEOMAGIC is not set
# CONFIG_FB_KYRO is not set
# CONFIG_FB_3DFX is not set
# CONFIG_FB_VOODOO1 is not set
# CONFIG_FB_VT8623 is not set
# CONFIG_FB_TRIDENT is not set
# CONFIG_FB_ARK is not set
# CONFIG_FB_PM3 is not set
# CONFIG_FB_CARMINE is not set
# CONFIG_FB_SM501 is not set
# CONFIG_FB_SMSCUFX is not set
# CONFIG_FB_UDL is not set
# CONFIG_FB_IBM_GXT4500 is not set
# CONFIG_FB_VIRTUAL is not set
# CONFIG_FB_METRONOME is not set
# CONFIG_FB_MB862XX is not set
# CONFIG_FB_SIMPLE is not set
# CONFIG_FB_SSD1307 is not set
# CONFIG_FB_SM712 is not set
# end of Frame buffer Devices

#
# Backlight & LCD device support
#
CONFIG_LCD_CLASS_DEVICE=m
# CONFIG_LCD_L4F00242T03 is not set
# CONFIG_LCD_LMS283GF05 is not set
# CONFIG_LCD_LTV350QV is not set
# CONFIG_LCD_ILI922X is not set
# CONFIG_LCD_ILI9320 is not set
# CONFIG_LCD_TDO24M is not set
# CONFIG_LCD_VGG2432A4 is not set
CONFIG_LCD_PLATFORM=m
# CONFIG_LCD_AMS369FG06 is not set
# CONFIG_LCD_LMS501KF03 is not set
# CONFIG_LCD_HX8357 is not set
# CONFIG_LCD_OTM3225A is not set
CONFIG_BACKLIGHT_CLASS_DEVICE=y
# CONFIG_BACKLIGHT_KTD253 is not set
# CONFIG_BACKLIGHT_PWM is not set
CONFIG_BACKLIGHT_APPLE=m
# CONFIG_BACKLIGHT_QCOM_WLED is not set
# CONFIG_BACKLIGHT_SAHARA is not set
# CONFIG_BACKLIGHT_ADP8860 is not set
# CONFIG_BACKLIGHT_ADP8870 is not set
# CONFIG_BACKLIGHT_LM3630A is not set
# CONFIG_BACKLIGHT_LM3639 is not set
CONFIG_BACKLIGHT_LP855X=m
# CONFIG_BACKLIGHT_GPIO is not set
# CONFIG_BACKLIGHT_LV5207LP is not set
# CONFIG_BACKLIGHT_BD6107 is not set
# CONFIG_BACKLIGHT_ARCXCNN is not set
# end of Backlight & LCD device support

CONFIG_HDMI=y

#
# Console display driver support
#
CONFIG_VGA_CONSOLE=y
CONFIG_DUMMY_CONSOLE=y
CONFIG_DUMMY_CONSOLE_COLUMNS=80
CONFIG_DUMMY_CONSOLE_ROWS=25
CONFIG_FRAMEBUFFER_CONSOLE=y
# CONFIG_FRAMEBUFFER_CONSOLE_LEGACY_ACCELERATION is not set
CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y
CONFIG_FRAMEBUFFER_CONSOLE_ROTATION=y
# CONFIG_FRAMEBUFFER_CONSOLE_DEFERRED_TAKEOVER is not set
# end of Console display driver support

CONFIG_LOGO=y
# CONFIG_LOGO_LINUX_MONO is not set
# CONFIG_LOGO_LINUX_VGA16 is not set
CONFIG_LOGO_LINUX_CLUT224=y
# end of Graphics support

# CONFIG_SOUND is not set

#
# HID support
#
CONFIG_HID=y
CONFIG_HID_BATTERY_STRENGTH=y
CONFIG_HIDRAW=y
CONFIG_UHID=m
CONFIG_HID_GENERIC=y

#
# Special HID drivers
#
CONFIG_HID_A4TECH=m
# CONFIG_HID_ACCUTOUCH is not set
CONFIG_HID_ACRUX=m
# CONFIG_HID_ACRUX_FF is not set
CONFIG_HID_APPLE=m
# CONFIG_HID_APPLEIR is not set
CONFIG_HID_ASUS=m
CONFIG_HID_AUREAL=m
CONFIG_HID_BELKIN=m
# CONFIG_HID_BETOP_FF is not set
# CONFIG_HID_BIGBEN_FF is not set
CONFIG_HID_CHERRY=m
# CONFIG_HID_CHICONY is not set
# CONFIG_HID_CORSAIR is not set
# CONFIG_HID_COUGAR is not set
# CONFIG_HID_MACALLY is not set
CONFIG_HID_CMEDIA=m
# CONFIG_HID_CP2112 is not set
# CONFIG_HID_CREATIVE_SB0540 is not set
CONFIG_HID_CYPRESS=m
CONFIG_HID_DRAGONRISE=m
# CONFIG_DRAGONRISE_FF is not set
# CONFIG_HID_EMS_FF is not set
# CONFIG_HID_ELAN is not set
CONFIG_HID_ELECOM=m
# CONFIG_HID_ELO is not set
CONFIG_HID_EZKEY=m
# CONFIG_HID_FT260 is not set
CONFIG_HID_GEMBIRD=m
CONFIG_HID_GFRM=m
# CONFIG_HID_GLORIOUS is not set
# CONFIG_HID_HOLTEK is not set
# CONFIG_HID_VIVALDI is not set
# CONFIG_HID_GT683R is not set
CONFIG_HID_KEYTOUCH=m
CONFIG_HID_KYE=m
# CONFIG_HID_UCLOGIC is not set
CONFIG_HID_WALTOP=m
# CONFIG_HID_VIEWSONIC is not set
# CONFIG_HID_XIAOMI is not set
CONFIG_HID_GYRATION=m
CONFIG_HID_ICADE=m
CONFIG_HID_ITE=m
CONFIG_HID_JABRA=m
CONFIG_HID_TWINHAN=m
CONFIG_HID_KENSINGTON=m
CONFIG_HID_LCPOWER=m
CONFIG_HID_LED=m
CONFIG_HID_LENOVO=m
# CONFIG_HID_LETSKETCH is not set
CONFIG_HID_LOGITECH=m
CONFIG_HID_LOGITECH_DJ=m
CONFIG_HID_LOGITECH_HIDPP=m
# CONFIG_LOGITECH_FF is not set
# CONFIG_LOGIRUMBLEPAD2_FF is not set
# CONFIG_LOGIG940_FF is not set
# CONFIG_LOGIWHEELS_FF is not set
CONFIG_HID_MAGICMOUSE=y
# CONFIG_HID_MALTRON is not set
# CONFIG_HID_MAYFLASH is not set
# CONFIG_HID_MEGAWORLD_FF is not set
# CONFIG_HID_REDRAGON is not set
CONFIG_HID_MICROSOFT=m
CONFIG_HID_MONTEREY=m
CONFIG_HID_MULTITOUCH=m
# CONFIG_HID_NINTENDO is not set
CONFIG_HID_NTI=m
# CONFIG_HID_NTRIG is not set
CONFIG_HID_ORTEK=m
CONFIG_HID_PANTHERLORD=m
# CONFIG_PANTHERLORD_FF is not set
# CONFIG_HID_PENMOUNT is not set
CONFIG_HID_PETALYNX=m
CONFIG_HID_PICOLCD=m
CONFIG_HID_PICOLCD_FB=y
CONFIG_HID_PICOLCD_BACKLIGHT=y
CONFIG_HID_PICOLCD_LCD=y
CONFIG_HID_PICOLCD_LEDS=y
CONFIG_HID_PICOLCD_CIR=y
CONFIG_HID_PLANTRONICS=m
# CONFIG_HID_RAZER is not set
CONFIG_HID_PRIMAX=m
# CONFIG_HID_RETRODE is not set
# CONFIG_HID_ROCCAT is not set
CONFIG_HID_SAITEK=m
CONFIG_HID_SAMSUNG=m
# CONFIG_HID_SEMITEK is not set
# CONFIG_HID_SIGMAMICRO is not set
# CONFIG_HID_SONY is not set
CONFIG_HID_SPEEDLINK=m
# CONFIG_HID_STEAM is not set
CONFIG_HID_STEELSERIES=m
CONFIG_HID_SUNPLUS=m
CONFIG_HID_RMI=m
CONFIG_HID_GREENASIA=m
# CONFIG_GREENASIA_FF is not set
CONFIG_HID_SMARTJOYPLUS=m
# CONFIG_SMARTJOYPLUS_FF is not set
CONFIG_HID_TIVO=m
CONFIG_HID_TOPSEED=m
CONFIG_HID_THINGM=m
CONFIG_HID_THRUSTMASTER=m
# CONFIG_THRUSTMASTER_FF is not set
# CONFIG_HID_UDRAW_PS3 is not set
# CONFIG_HID_U2FZERO is not set
# CONFIG_HID_WACOM is not set
CONFIG_HID_WIIMOTE=m
CONFIG_HID_XINMO=m
CONFIG_HID_ZEROPLUS=m
# CONFIG_ZEROPLUS_FF is not set
CONFIG_HID_ZYDACRON=m
CONFIG_HID_SENSOR_HUB=y
CONFIG_HID_SENSOR_CUSTOM_SENSOR=m
CONFIG_HID_ALPS=m
# CONFIG_HID_MCP2221 is not set
# end of Special HID drivers

#
# USB HID support
#
CONFIG_USB_HID=y
# CONFIG_HID_PID is not set
# CONFIG_USB_HIDDEV is not set
# end of USB HID support

#
# I2C HID support
#
# CONFIG_I2C_HID_ACPI is not set
# end of I2C HID support

#
# Intel ISH HID support
#
CONFIG_INTEL_ISH_HID=m
# CONFIG_INTEL_ISH_FIRMWARE_DOWNLOADER is not set
# end of Intel ISH HID support

#
# AMD SFH HID Support
#
# CONFIG_AMD_SFH_HID is not set
# end of AMD SFH HID Support
# end of HID support

CONFIG_USB_OHCI_LITTLE_ENDIAN=y
CONFIG_USB_SUPPORT=y
CONFIG_USB_COMMON=y
# CONFIG_USB_LED_TRIG is not set
# CONFIG_USB_ULPI_BUS is not set
# CONFIG_USB_CONN_GPIO is not set
CONFIG_USB_ARCH_HAS_HCD=y
CONFIG_USB=y
CONFIG_USB_PCI=y
CONFIG_USB_ANNOUNCE_NEW_DEVICES=y

#
# Miscellaneous USB options
#
CONFIG_USB_DEFAULT_PERSIST=y
# CONFIG_USB_FEW_INIT_RETRIES is not set
# CONFIG_USB_DYNAMIC_MINORS is not set
# CONFIG_USB_OTG is not set
# CONFIG_USB_OTG_PRODUCTLIST is not set
CONFIG_USB_LEDS_TRIGGER_USBPORT=y
CONFIG_USB_AUTOSUSPEND_DELAY=2
CONFIG_USB_MON=y

#
# USB Host Controller Drivers
#
# CONFIG_USB_C67X00_HCD is not set
CONFIG_USB_XHCI_HCD=y
# CONFIG_USB_XHCI_DBGCAP is not set
CONFIG_USB_XHCI_PCI=y
# CONFIG_USB_XHCI_PCI_RENESAS is not set
# CONFIG_USB_XHCI_PLATFORM is not set
CONFIG_USB_EHCI_HCD=y
CONFIG_USB_EHCI_ROOT_HUB_TT=y
CONFIG_USB_EHCI_TT_NEWSCHED=y
CONFIG_USB_EHCI_PCI=y
# CONFIG_USB_EHCI_FSL is not set
# CONFIG_USB_EHCI_HCD_PLATFORM is not set
# CONFIG_USB_OXU210HP_HCD is not set
# CONFIG_USB_ISP116X_HCD is not set
# CONFIG_USB_FOTG210_HCD is not set
# CONFIG_USB_MAX3421_HCD is not set
CONFIG_USB_OHCI_HCD=y
CONFIG_USB_OHCI_HCD_PCI=y
# CONFIG_USB_OHCI_HCD_PLATFORM is not set
CONFIG_USB_UHCI_HCD=y
# CONFIG_USB_SL811_HCD is not set
# CONFIG_USB_R8A66597_HCD is not set
# CONFIG_USB_HCD_BCMA is not set
# CONFIG_USB_HCD_TEST_MODE is not set

#
# USB Device Class drivers
#
# CONFIG_USB_ACM is not set
# CONFIG_USB_PRINTER is not set
# CONFIG_USB_WDM is not set
# CONFIG_USB_TMC is not set

#
# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may
#

#
# also be needed; see USB_STORAGE Help for more info
#
CONFIG_USB_STORAGE=m
# CONFIG_USB_STORAGE_DEBUG is not set
# CONFIG_USB_STORAGE_REALTEK is not set
# CONFIG_USB_STORAGE_DATAFAB is not set
# CONFIG_USB_STORAGE_FREECOM is not set
# CONFIG_USB_STORAGE_ISD200 is not set
# CONFIG_USB_STORAGE_USBAT is not set
# CONFIG_USB_STORAGE_SDDR09 is not set
# CONFIG_USB_STORAGE_SDDR55 is not set
# CONFIG_USB_STORAGE_JUMPSHOT is not set
# CONFIG_USB_STORAGE_ALAUDA is not set
# CONFIG_USB_STORAGE_ONETOUCH is not set
# CONFIG_USB_STORAGE_KARMA is not set
# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set
# CONFIG_USB_STORAGE_ENE_UB6250 is not set
# CONFIG_USB_UAS is not set

#
# USB Imaging devices
#
# CONFIG_USB_MDC800 is not set
# CONFIG_USB_MICROTEK is not set
# CONFIG_USBIP_CORE is not set
# CONFIG_USB_CDNS_SUPPORT is not set
# CONFIG_USB_MUSB_HDRC is not set
# CONFIG_USB_DWC3 is not set
# CONFIG_USB_DWC2 is not set
# CONFIG_USB_CHIPIDEA is not set
# CONFIG_USB_ISP1760 is not set

#
# USB port drivers
#
# CONFIG_USB_USS720 is not set
CONFIG_USB_SERIAL=m
CONFIG_USB_SERIAL_GENERIC=y
# CONFIG_USB_SERIAL_SIMPLE is not set
# CONFIG_USB_SERIAL_AIRCABLE is not set
# CONFIG_USB_SERIAL_ARK3116 is not set
# CONFIG_USB_SERIAL_BELKIN is not set
# CONFIG_USB_SERIAL_CH341 is not set
# CONFIG_USB_SERIAL_WHITEHEAT is not set
# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
# CONFIG_USB_SERIAL_CP210X is not set
# CONFIG_USB_SERIAL_CYPRESS_M8 is not set
# CONFIG_USB_SERIAL_EMPEG is not set
# CONFIG_USB_SERIAL_FTDI_SIO is not set
# CONFIG_USB_SERIAL_VISOR is not set
# CONFIG_USB_SERIAL_IPAQ is not set
# CONFIG_USB_SERIAL_IR is not set
# CONFIG_USB_SERIAL_EDGEPORT is not set
# CONFIG_USB_SERIAL_EDGEPORT_TI is not set
# CONFIG_USB_SERIAL_F81232 is not set
# CONFIG_USB_SERIAL_F8153X is not set
# CONFIG_USB_SERIAL_GARMIN is not set
# CONFIG_USB_SERIAL_IPW is not set
# CONFIG_USB_SERIAL_IUU is not set
# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
# CONFIG_USB_SERIAL_KEYSPAN is not set
# CONFIG_USB_SERIAL_KLSI is not set
# CONFIG_USB_SERIAL_KOBIL_SCT is not set
# CONFIG_USB_SERIAL_MCT_U232 is not set
# CONFIG_USB_SERIAL_METRO is not set
# CONFIG_USB_SERIAL_MOS7720 is not set
# CONFIG_USB_SERIAL_MOS7840 is not set
# CONFIG_USB_SERIAL_MXUPORT is not set
# CONFIG_USB_SERIAL_NAVMAN is not set
# CONFIG_USB_SERIAL_PL2303 is not set
# CONFIG_USB_SERIAL_OTI6858 is not set
# CONFIG_USB_SERIAL_QCAUX is not set
# CONFIG_USB_SERIAL_QUALCOMM is not set
# CONFIG_USB_SERIAL_SPCP8X5 is not set
# CONFIG_USB_SERIAL_SAFE is not set
# CONFIG_USB_SERIAL_SIERRAWIRELESS is not set
# CONFIG_USB_SERIAL_SYMBOL is not set
# CONFIG_USB_SERIAL_TI is not set
# CONFIG_USB_SERIAL_CYBERJACK is not set
# CONFIG_USB_SERIAL_OPTION is not set
# CONFIG_USB_SERIAL_OMNINET is not set
# CONFIG_USB_SERIAL_OPTICON is not set
# CONFIG_USB_SERIAL_XSENS_MT is not set
# CONFIG_USB_SERIAL_WISHBONE is not set
# CONFIG_USB_SERIAL_SSU100 is not set
# CONFIG_USB_SERIAL_QT2 is not set
# CONFIG_USB_SERIAL_UPD78F0730 is not set
# CONFIG_USB_SERIAL_XR is not set
CONFIG_USB_SERIAL_DEBUG=m

#
# USB Miscellaneous drivers
#
# CONFIG_USB_EMI62 is not set
# CONFIG_USB_EMI26 is not set
# CONFIG_USB_ADUTUX is not set
# CONFIG_USB_SEVSEG is not set
# CONFIG_USB_LEGOTOWER is not set
# CONFIG_USB_LCD is not set
# CONFIG_USB_CYPRESS_CY7C63 is not set
# CONFIG_USB_CYTHERM is not set
# CONFIG_USB_IDMOUSE is not set
# CONFIG_USB_FTDI_ELAN is not set
# CONFIG_USB_APPLEDISPLAY is not set
# CONFIG_APPLE_MFI_FASTCHARGE is not set
# CONFIG_USB_SISUSBVGA is not set
# CONFIG_USB_LD is not set
# CONFIG_USB_TRANCEVIBRATOR is not set
# CONFIG_USB_IOWARRIOR is not set
# CONFIG_USB_TEST is not set
# CONFIG_USB_EHSET_TEST_FIXTURE is not set
# CONFIG_USB_ISIGHTFW is not set
# CONFIG_USB_YUREX is not set
# CONFIG_USB_EZUSB_FX2 is not set
# CONFIG_USB_HUB_USB251XB is not set
# CONFIG_USB_HSIC_USB3503 is not set
# CONFIG_USB_HSIC_USB4604 is not set
# CONFIG_USB_LINK_LAYER_TEST is not set
# CONFIG_USB_CHAOSKEY is not set
# CONFIG_USB_ATM is not set

#
# USB Physical Layer drivers
#
# CONFIG_NOP_USB_XCEIV is not set
# CONFIG_USB_GPIO_VBUS is not set
# CONFIG_USB_ISP1301 is not set
# end of USB Physical Layer drivers

# CONFIG_USB_GADGET is not set
CONFIG_TYPEC=y
# CONFIG_TYPEC_TCPM is not set
CONFIG_TYPEC_UCSI=y
# CONFIG_UCSI_CCG is not set
CONFIG_UCSI_ACPI=y
# CONFIG_UCSI_STM32G0 is not set
# CONFIG_TYPEC_TPS6598X is not set
# CONFIG_TYPEC_RT1719 is not set
# CONFIG_TYPEC_STUSB160X is not set
# CONFIG_TYPEC_WUSB3801 is not set

#
# USB Type-C Multiplexer/DeMultiplexer Switch support
#
# CONFIG_TYPEC_MUX_FSA4480 is not set
# CONFIG_TYPEC_MUX_PI3USB30532 is not set
# end of USB Type-C Multiplexer/DeMultiplexer Switch support

#
# USB Type-C Alternate Mode drivers
#
# CONFIG_TYPEC_DP_ALTMODE is not set
# end of USB Type-C Alternate Mode drivers

# CONFIG_USB_ROLE_SWITCH is not set
CONFIG_MMC=m
CONFIG_MMC_BLOCK=m
CONFIG_MMC_BLOCK_MINORS=8
CONFIG_SDIO_UART=m
# CONFIG_MMC_TEST is not set

#
# MMC/SD/SDIO Host Controller Drivers
#
# CONFIG_MMC_DEBUG is not set
CONFIG_MMC_SDHCI=m
CONFIG_MMC_SDHCI_IO_ACCESSORS=y
CONFIG_MMC_SDHCI_PCI=m
CONFIG_MMC_RICOH_MMC=y
CONFIG_MMC_SDHCI_ACPI=m
CONFIG_MMC_SDHCI_PLTFM=m
# CONFIG_MMC_SDHCI_F_SDH30 is not set
# CONFIG_MMC_WBSD is not set
# CONFIG_MMC_TIFM_SD is not set
# CONFIG_MMC_SPI is not set
# CONFIG_MMC_CB710 is not set
# CONFIG_MMC_VIA_SDMMC is not set
# CONFIG_MMC_VUB300 is not set
# CONFIG_MMC_USHC is not set
# CONFIG_MMC_USDHI6ROL0 is not set
# CONFIG_MMC_REALTEK_PCI is not set
CONFIG_MMC_CQHCI=m
# CONFIG_MMC_HSQ is not set
# CONFIG_MMC_TOSHIBA_PCI is not set
# CONFIG_MMC_MTK is not set
# CONFIG_MMC_SDHCI_XENON is not set
# CONFIG_SCSI_UFSHCD is not set
# CONFIG_MEMSTICK is not set
CONFIG_NEW_LEDS=y
CONFIG_LEDS_CLASS=y
# CONFIG_LEDS_CLASS_FLASH is not set
# CONFIG_LEDS_CLASS_MULTICOLOR is not set
# CONFIG_LEDS_BRIGHTNESS_HW_CHANGED is not set

#
# LED drivers
#
# CONFIG_LEDS_APU is not set
CONFIG_LEDS_LM3530=m
# CONFIG_LEDS_LM3532 is not set
# CONFIG_LEDS_LM3642 is not set
# CONFIG_LEDS_PCA9532 is not set
# CONFIG_LEDS_GPIO is not set
CONFIG_LEDS_LP3944=m
# CONFIG_LEDS_LP3952 is not set
# CONFIG_LEDS_LP50XX is not set
# CONFIG_LEDS_PCA955X is not set
# CONFIG_LEDS_PCA963X is not set
# CONFIG_LEDS_DAC124S085 is not set
# CONFIG_LEDS_PWM is not set
# CONFIG_LEDS_BD2802 is not set
CONFIG_LEDS_INTEL_SS4200=m
CONFIG_LEDS_LT3593=m
# CONFIG_LEDS_TCA6507 is not set
# CONFIG_LEDS_TLC591XX is not set
# CONFIG_LEDS_LM355x is not set
# CONFIG_LEDS_IS31FL319X is not set

#
# LED driver for blink(1) USB RGB LED is under Special HID drivers (HID_THINGM)
#
CONFIG_LEDS_BLINKM=m
CONFIG_LEDS_MLXCPLD=m
# CONFIG_LEDS_MLXREG is not set
# CONFIG_LEDS_USER is not set
# CONFIG_LEDS_NIC78BX is not set
# CONFIG_LEDS_TI_LMU_COMMON is not set

#
# Flash and Torch LED drivers
#

#
# RGB LED drivers
#

#
# LED Triggers
#
CONFIG_LEDS_TRIGGERS=y
CONFIG_LEDS_TRIGGER_TIMER=m
CONFIG_LEDS_TRIGGER_ONESHOT=m
# CONFIG_LEDS_TRIGGER_DISK is not set
CONFIG_LEDS_TRIGGER_HEARTBEAT=m
CONFIG_LEDS_TRIGGER_BACKLIGHT=m
# CONFIG_LEDS_TRIGGER_CPU is not set
# CONFIG_LEDS_TRIGGER_ACTIVITY is not set
CONFIG_LEDS_TRIGGER_GPIO=m
CONFIG_LEDS_TRIGGER_DEFAULT_ON=m

#
# iptables trigger is under Netfilter config (LED target)
#
CONFIG_LEDS_TRIGGER_TRANSIENT=m
CONFIG_LEDS_TRIGGER_CAMERA=m
# CONFIG_LEDS_TRIGGER_PANIC is not set
# CONFIG_LEDS_TRIGGER_NETDEV is not set
# CONFIG_LEDS_TRIGGER_PATTERN is not set
CONFIG_LEDS_TRIGGER_AUDIO=m
# CONFIG_LEDS_TRIGGER_TTY is not set

#
# Simple LED drivers
#
# CONFIG_ACCESSIBILITY is not set
# CONFIG_INFINIBAND is not set
CONFIG_EDAC_ATOMIC_SCRUB=y
CONFIG_EDAC_SUPPORT=y
CONFIG_EDAC=y
CONFIG_EDAC_LEGACY_SYSFS=y
# CONFIG_EDAC_DEBUG is not set
CONFIG_EDAC_GHES=y
CONFIG_EDAC_E752X=m
CONFIG_EDAC_I82975X=m
CONFIG_EDAC_I3000=m
CONFIG_EDAC_I3200=m
CONFIG_EDAC_IE31200=m
CONFIG_EDAC_X38=m
CONFIG_EDAC_I5400=m
CONFIG_EDAC_I7CORE=m
# CONFIG_EDAC_I5000 is not set
CONFIG_EDAC_I5100=m
CONFIG_EDAC_I7300=m
CONFIG_EDAC_SBRIDGE=m
CONFIG_EDAC_SKX=m
# CONFIG_EDAC_I10NM is not set
CONFIG_EDAC_PND2=m
# CONFIG_EDAC_IGEN6 is not set
CONFIG_RTC_LIB=y
CONFIG_RTC_MC146818_LIB=y
CONFIG_RTC_CLASS=y
CONFIG_RTC_HCTOSYS=y
CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
# CONFIG_RTC_SYSTOHC is not set
# CONFIG_RTC_DEBUG is not set
CONFIG_RTC_NVMEM=y

#
# RTC interfaces
#
CONFIG_RTC_INTF_SYSFS=y
CONFIG_RTC_INTF_PROC=y
CONFIG_RTC_INTF_DEV=y
# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
# CONFIG_RTC_DRV_TEST is not set

#
# I2C RTC drivers
#
# CONFIG_RTC_DRV_ABB5ZES3 is not set
# CONFIG_RTC_DRV_ABEOZ9 is not set
# CONFIG_RTC_DRV_ABX80X is not set
CONFIG_RTC_DRV_DS1307=m
# CONFIG_RTC_DRV_DS1307_CENTURY is not set
CONFIG_RTC_DRV_DS1374=m
# CONFIG_RTC_DRV_DS1374_WDT is not set
CONFIG_RTC_DRV_DS1672=m
CONFIG_RTC_DRV_MAX6900=m
CONFIG_RTC_DRV_RS5C372=m
CONFIG_RTC_DRV_ISL1208=m
CONFIG_RTC_DRV_ISL12022=m
CONFIG_RTC_DRV_X1205=m
CONFIG_RTC_DRV_PCF8523=m
# CONFIG_RTC_DRV_PCF85063 is not set
# CONFIG_RTC_DRV_PCF85363 is not set
CONFIG_RTC_DRV_PCF8563=m
CONFIG_RTC_DRV_PCF8583=m
CONFIG_RTC_DRV_M41T80=m
CONFIG_RTC_DRV_M41T80_WDT=y
CONFIG_RTC_DRV_BQ32K=m
# CONFIG_RTC_DRV_S35390A is not set
CONFIG_RTC_DRV_FM3130=m
# CONFIG_RTC_DRV_RX8010 is not set
CONFIG_RTC_DRV_RX8581=m
CONFIG_RTC_DRV_RX8025=m
CONFIG_RTC_DRV_EM3027=m
# CONFIG_RTC_DRV_RV3028 is not set
# CONFIG_RTC_DRV_RV3032 is not set
# CONFIG_RTC_DRV_RV8803 is not set
# CONFIG_RTC_DRV_SD3078 is not set

#
# SPI RTC drivers
#
# CONFIG_RTC_DRV_M41T93 is not set
# CONFIG_RTC_DRV_M41T94 is not set
# CONFIG_RTC_DRV_DS1302 is not set
# CONFIG_RTC_DRV_DS1305 is not set
# CONFIG_RTC_DRV_DS1343 is not set
# CONFIG_RTC_DRV_DS1347 is not set
# CONFIG_RTC_DRV_DS1390 is not set
# CONFIG_RTC_DRV_MAX6916 is not set
# CONFIG_RTC_DRV_R9701 is not set
CONFIG_RTC_DRV_RX4581=m
# CONFIG_RTC_DRV_RS5C348 is not set
# CONFIG_RTC_DRV_MAX6902 is not set
# CONFIG_RTC_DRV_PCF2123 is not set
# CONFIG_RTC_DRV_MCP795 is not set
CONFIG_RTC_I2C_AND_SPI=y

#
# SPI and I2C RTC drivers
#
CONFIG_RTC_DRV_DS3232=m
CONFIG_RTC_DRV_DS3232_HWMON=y
# CONFIG_RTC_DRV_PCF2127 is not set
CONFIG_RTC_DRV_RV3029C2=m
# CONFIG_RTC_DRV_RV3029_HWMON is not set
# CONFIG_RTC_DRV_RX6110 is not set

#
# Platform RTC drivers
#
CONFIG_RTC_DRV_CMOS=y
CONFIG_RTC_DRV_DS1286=m
CONFIG_RTC_DRV_DS1511=m
CONFIG_RTC_DRV_DS1553=m
# CONFIG_RTC_DRV_DS1685_FAMILY is not set
CONFIG_RTC_DRV_DS1742=m
CONFIG_RTC_DRV_DS2404=m
CONFIG_RTC_DRV_STK17TA8=m
# CONFIG_RTC_DRV_M48T86 is not set
CONFIG_RTC_DRV_M48T35=m
CONFIG_RTC_DRV_M48T59=m
CONFIG_RTC_DRV_MSM6242=m
CONFIG_RTC_DRV_BQ4802=m
CONFIG_RTC_DRV_RP5C01=m
CONFIG_RTC_DRV_V3020=m

#
# on-CPU RTC drivers
#
# CONFIG_RTC_DRV_FTRTC010 is not set

#
# HID Sensor RTC drivers
#
# CONFIG_RTC_DRV_GOLDFISH is not set
CONFIG_DMADEVICES=y
# CONFIG_DMADEVICES_DEBUG is not set

#
# DMA Devices
#
CONFIG_DMA_ENGINE=y
CONFIG_DMA_VIRTUAL_CHANNELS=y
CONFIG_DMA_ACPI=y
# CONFIG_ALTERA_MSGDMA is not set
CONFIG_INTEL_IDMA64=m
# CONFIG_INTEL_IDXD is not set
# CONFIG_INTEL_IDXD_COMPAT is not set
CONFIG_INTEL_IOATDMA=m
# CONFIG_PLX_DMA is not set
# CONFIG_AMD_PTDMA is not set
# CONFIG_QCOM_HIDMA_MGMT is not set
# CONFIG_QCOM_HIDMA is not set
CONFIG_DW_DMAC_CORE=y
CONFIG_DW_DMAC=m
CONFIG_DW_DMAC_PCI=y
# CONFIG_DW_EDMA is not set
# CONFIG_DW_EDMA_PCIE is not set
CONFIG_HSU_DMA=y
# CONFIG_SF_PDMA is not set
# CONFIG_INTEL_LDMA is not set

#
# DMA Clients
#
CONFIG_ASYNC_TX_DMA=y
CONFIG_DMATEST=m
CONFIG_DMA_ENGINE_RAID=y

#
# DMABUF options
#
CONFIG_SYNC_FILE=y
# CONFIG_SW_SYNC is not set
# CONFIG_UDMABUF is not set
# CONFIG_DMABUF_MOVE_NOTIFY is not set
# CONFIG_DMABUF_DEBUG is not set
# CONFIG_DMABUF_SELFTESTS is not set
# CONFIG_DMABUF_HEAPS is not set
# CONFIG_DMABUF_SYSFS_STATS is not set
# end of DMABUF options

CONFIG_DCA=m
# CONFIG_AUXDISPLAY is not set
# CONFIG_PANEL is not set
CONFIG_UIO=m
CONFIG_UIO_CIF=m
CONFIG_UIO_PDRV_GENIRQ=m
# CONFIG_UIO_DMEM_GENIRQ is not set
CONFIG_UIO_AEC=m
CONFIG_UIO_SERCOS3=m
CONFIG_UIO_PCI_GENERIC=m
# CONFIG_UIO_NETX is not set
# CONFIG_UIO_PRUSS is not set
# CONFIG_UIO_MF624 is not set
CONFIG_VFIO=m
CONFIG_VFIO_IOMMU_TYPE1=m
CONFIG_VFIO_VIRQFD=m
CONFIG_VFIO_NOIOMMU=y
CONFIG_VFIO_PCI_CORE=m
CONFIG_VFIO_PCI_MMAP=y
CONFIG_VFIO_PCI_INTX=y
CONFIG_VFIO_PCI=m
# CONFIG_VFIO_PCI_VGA is not set
# CONFIG_VFIO_PCI_IGD is not set
CONFIG_VFIO_MDEV=m
CONFIG_IRQ_BYPASS_MANAGER=m
# CONFIG_VIRT_DRIVERS is not set
CONFIG_VIRTIO_ANCHOR=y
CONFIG_VIRTIO=y
CONFIG_VIRTIO_PCI_LIB=y
CONFIG_VIRTIO_PCI_LIB_LEGACY=y
CONFIG_VIRTIO_MENU=y
CONFIG_VIRTIO_PCI=y
CONFIG_VIRTIO_PCI_LEGACY=y
# CONFIG_VIRTIO_PMEM is not set
CONFIG_VIRTIO_BALLOON=m
# CONFIG_VIRTIO_MEM is not set
CONFIG_VIRTIO_INPUT=m
# CONFIG_VIRTIO_MMIO is not set
CONFIG_VIRTIO_DMA_SHARED_BUFFER=m
# CONFIG_VDPA is not set
CONFIG_VHOST_IOTLB=m
CONFIG_VHOST=m
CONFIG_VHOST_MENU=y
CONFIG_VHOST_NET=m
# CONFIG_VHOST_SCSI is not set
CONFIG_VHOST_VSOCK=m
# CONFIG_VHOST_CROSS_ENDIAN_LEGACY is not set

#
# Microsoft Hyper-V guest support
#
# CONFIG_HYPERV is not set
# end of Microsoft Hyper-V guest support

# CONFIG_GREYBUS is not set
# CONFIG_COMEDI is not set
# CONFIG_STAGING is not set
# CONFIG_CHROME_PLATFORMS is not set
CONFIG_MELLANOX_PLATFORM=y
CONFIG_MLXREG_HOTPLUG=m
# CONFIG_MLXREG_IO is not set
# CONFIG_MLXREG_LC is not set
# CONFIG_NVSW_SN2201 is not set
CONFIG_SURFACE_PLATFORMS=y
# CONFIG_SURFACE3_WMI is not set
# CONFIG_SURFACE_3_POWER_OPREGION is not set
# CONFIG_SURFACE_GPE is not set
# CONFIG_SURFACE_HOTPLUG is not set
# CONFIG_SURFACE_PRO3_BUTTON is not set
CONFIG_X86_PLATFORM_DEVICES=y
CONFIG_ACPI_WMI=m
CONFIG_WMI_BMOF=m
# CONFIG_HUAWEI_WMI is not set
# CONFIG_UV_SYSFS is not set
CONFIG_MXM_WMI=m
# CONFIG_PEAQ_WMI is not set
# CONFIG_NVIDIA_WMI_EC_BACKLIGHT is not set
# CONFIG_XIAOMI_WMI is not set
# CONFIG_GIGABYTE_WMI is not set
# CONFIG_YOGABOOK_WMI is not set
CONFIG_ACERHDF=m
# CONFIG_ACER_WIRELESS is not set
CONFIG_ACER_WMI=m
# CONFIG_AMD_PMC is not set
# CONFIG_AMD_HSMP is not set
# CONFIG_ADV_SWBUTTON is not set
CONFIG_APPLE_GMUX=m
CONFIG_ASUS_LAPTOP=m
# CONFIG_ASUS_WIRELESS is not set
CONFIG_ASUS_WMI=m
CONFIG_ASUS_NB_WMI=m
# CONFIG_ASUS_TF103C_DOCK is not set
# CONFIG_MERAKI_MX100 is not set
CONFIG_EEEPC_LAPTOP=m
CONFIG_EEEPC_WMI=m
# CONFIG_X86_PLATFORM_DRIVERS_DELL is not set
CONFIG_AMILO_RFKILL=m
CONFIG_FUJITSU_LAPTOP=m
CONFIG_FUJITSU_TABLET=m
# CONFIG_GPD_POCKET_FAN is not set
# CONFIG_HP_ACCEL is not set
# CONFIG_WIRELESS_HOTKEY is not set
# CONFIG_HP_WMI is not set
# CONFIG_IBM_RTL is not set
CONFIG_IDEAPAD_LAPTOP=m
CONFIG_SENSORS_HDAPS=m
CONFIG_THINKPAD_ACPI=m
# CONFIG_THINKPAD_ACPI_DEBUGFACILITIES is not set
# CONFIG_THINKPAD_ACPI_DEBUG is not set
# CONFIG_THINKPAD_ACPI_UNSAFE_LEDS is not set
CONFIG_THINKPAD_ACPI_VIDEO=y
CONFIG_THINKPAD_ACPI_HOTKEY_POLL=y
# CONFIG_THINKPAD_LMI is not set
# CONFIG_INTEL_ATOMISP2_PM is not set
# CONFIG_INTEL_SAR_INT1092 is not set
CONFIG_INTEL_PMC_CORE=m

#
# Intel Speed Select Technology interface support
#
# CONFIG_INTEL_SPEED_SELECT_INTERFACE is not set
# end of Intel Speed Select Technology interface support

CONFIG_INTEL_WMI=y
# CONFIG_INTEL_WMI_SBL_FW_UPDATE is not set
CONFIG_INTEL_WMI_THUNDERBOLT=m

#
# Intel Uncore Frequency Control
#
# CONFIG_INTEL_UNCORE_FREQ_CONTROL is not set
# end of Intel Uncore Frequency Control

CONFIG_INTEL_HID_EVENT=m
CONFIG_INTEL_VBTN=m
# CONFIG_INTEL_INT0002_VGPIO is not set
CONFIG_INTEL_OAKTRAIL=m
# CONFIG_INTEL_ISHTP_ECLITE is not set
# CONFIG_INTEL_PUNIT_IPC is not set
CONFIG_INTEL_RST=m
# CONFIG_INTEL_SMARTCONNECT is not set
CONFIG_INTEL_TURBO_MAX_3=y
# CONFIG_INTEL_VSEC is not set
CONFIG_MSI_LAPTOP=m
CONFIG_MSI_WMI=m
# CONFIG_PCENGINES_APU2 is not set
# CONFIG_BARCO_P50_GPIO is not set
CONFIG_SAMSUNG_LAPTOP=m
CONFIG_SAMSUNG_Q10=m
CONFIG_TOSHIBA_BT_RFKILL=m
# CONFIG_TOSHIBA_HAPS is not set
# CONFIG_TOSHIBA_WMI is not set
CONFIG_ACPI_CMPC=m
CONFIG_COMPAL_LAPTOP=m
# CONFIG_LG_LAPTOP is not set
CONFIG_PANASONIC_LAPTOP=m
CONFIG_SONY_LAPTOP=m
CONFIG_SONYPI_COMPAT=y
# CONFIG_SYSTEM76_ACPI is not set
CONFIG_TOPSTAR_LAPTOP=m
# CONFIG_SERIAL_MULTI_INSTANTIATE is not set
CONFIG_MLX_PLATFORM=m
CONFIG_INTEL_IPS=m
# CONFIG_INTEL_SCU_PCI is not set
# CONFIG_INTEL_SCU_PLATFORM is not set
# CONFIG_SIEMENS_SIMATIC_IPC is not set
# CONFIG_WINMATE_FM07_KEYS is not set
CONFIG_P2SB=y
CONFIG_HAVE_CLK=y
CONFIG_HAVE_CLK_PREPARE=y
CONFIG_COMMON_CLK=y
# CONFIG_LMK04832 is not set
# CONFIG_COMMON_CLK_MAX9485 is not set
# CONFIG_COMMON_CLK_SI5341 is not set
# CONFIG_COMMON_CLK_SI5351 is not set
# CONFIG_COMMON_CLK_SI544 is not set
# CONFIG_COMMON_CLK_CDCE706 is not set
# CONFIG_COMMON_CLK_CS2000_CP is not set
# CONFIG_COMMON_CLK_PWM is not set
# CONFIG_XILINX_VCU is not set
CONFIG_HWSPINLOCK=y

#
# Clock Source drivers
#
CONFIG_CLKEVT_I8253=y
CONFIG_I8253_LOCK=y
CONFIG_CLKBLD_I8253=y
# end of Clock Source drivers

CONFIG_MAILBOX=y
CONFIG_PCC=y
# CONFIG_ALTERA_MBOX is not set
CONFIG_IOMMU_IOVA=y
CONFIG_IOASID=y
CONFIG_IOMMU_API=y
CONFIG_IOMMU_SUPPORT=y

#
# Generic IOMMU Pagetable Support
#
# end of Generic IOMMU Pagetable Support

# CONFIG_IOMMU_DEBUGFS is not set
# CONFIG_IOMMU_DEFAULT_DMA_STRICT is not set
CONFIG_IOMMU_DEFAULT_DMA_LAZY=y
# CONFIG_IOMMU_DEFAULT_PASSTHROUGH is not set
CONFIG_IOMMU_DMA=y
CONFIG_IOMMU_SVA=y
# CONFIG_AMD_IOMMU is not set
CONFIG_DMAR_TABLE=y
CONFIG_INTEL_IOMMU=y
CONFIG_INTEL_IOMMU_SVM=y
# CONFIG_INTEL_IOMMU_DEFAULT_ON is not set
CONFIG_INTEL_IOMMU_FLOPPY_WA=y
CONFIG_INTEL_IOMMU_SCALABLE_MODE_DEFAULT_ON=y
CONFIG_IRQ_REMAP=y
# CONFIG_VIRTIO_IOMMU is not set

#
# Remoteproc drivers
#
# CONFIG_REMOTEPROC is not set
# end of Remoteproc drivers

#
# Rpmsg drivers
#
# CONFIG_RPMSG_QCOM_GLINK_RPM is not set
# CONFIG_RPMSG_VIRTIO is not set
# end of Rpmsg drivers

# CONFIG_SOUNDWIRE is not set

#
# SOC (System On Chip) specific Drivers
#

#
# Amlogic SoC drivers
#
# end of Amlogic SoC drivers

#
# Broadcom SoC drivers
#
# end of Broadcom SoC drivers

#
# NXP/Freescale QorIQ SoC drivers
#
# end of NXP/Freescale QorIQ SoC drivers

#
# fujitsu SoC drivers
#
# end of fujitsu SoC drivers

#
# i.MX SoC drivers
#
# end of i.MX SoC drivers

#
# Enable LiteX SoC Builder specific drivers
#
# end of Enable LiteX SoC Builder specific drivers

#
# Qualcomm SoC drivers
#
# end of Qualcomm SoC drivers

# CONFIG_SOC_TI is not set

#
# Xilinx SoC drivers
#
# end of Xilinx SoC drivers
# end of SOC (System On Chip) specific Drivers

# CONFIG_PM_DEVFREQ is not set
# CONFIG_EXTCON is not set
# CONFIG_MEMORY is not set
# CONFIG_IIO is not set
CONFIG_NTB=m
# CONFIG_NTB_MSI is not set
# CONFIG_NTB_AMD is not set
# CONFIG_NTB_IDT is not set
# CONFIG_NTB_INTEL is not set
# CONFIG_NTB_EPF is not set
# CONFIG_NTB_SWITCHTEC is not set
# CONFIG_NTB_PINGPONG is not set
# CONFIG_NTB_TOOL is not set
# CONFIG_NTB_PERF is not set
# CONFIG_NTB_TRANSPORT is not set
CONFIG_PWM=y
CONFIG_PWM_SYSFS=y
# CONFIG_PWM_DEBUG is not set
# CONFIG_PWM_CLK is not set
# CONFIG_PWM_DWC is not set
CONFIG_PWM_LPSS=m
CONFIG_PWM_LPSS_PCI=m
CONFIG_PWM_LPSS_PLATFORM=m
# CONFIG_PWM_PCA9685 is not set

#
# IRQ chip support
#
# end of IRQ chip support

# CONFIG_IPACK_BUS is not set
# CONFIG_RESET_CONTROLLER is not set

#
# PHY Subsystem
#
# CONFIG_GENERIC_PHY is not set
# CONFIG_USB_LGM_PHY is not set
# CONFIG_PHY_CAN_TRANSCEIVER is not set

#
# PHY drivers for Broadcom platforms
#
# CONFIG_BCM_KONA_USB2_PHY is not set
# end of PHY drivers for Broadcom platforms

# CONFIG_PHY_PXA_28NM_HSIC is not set
# CONFIG_PHY_PXA_28NM_USB2 is not set
# CONFIG_PHY_INTEL_LGM_EMMC is not set
# end of PHY Subsystem

CONFIG_POWERCAP=y
CONFIG_INTEL_RAPL_CORE=m
CONFIG_INTEL_RAPL=m
# CONFIG_IDLE_INJECT is not set
# CONFIG_MCB is not set

#
# Performance monitor support
#
# end of Performance monitor support

CONFIG_RAS=y
# CONFIG_RAS_CEC is not set
# CONFIG_USB4 is not set

#
# Android
#
# CONFIG_ANDROID_BINDER_IPC is not set
# end of Android

CONFIG_LIBNVDIMM=m
CONFIG_BLK_DEV_PMEM=m
CONFIG_ND_CLAIM=y
CONFIG_ND_BTT=m
CONFIG_BTT=y
CONFIG_ND_PFN=m
CONFIG_NVDIMM_PFN=y
CONFIG_NVDIMM_DAX=y
CONFIG_NVDIMM_KEYS=y
CONFIG_DAX=y
CONFIG_DEV_DAX=m
CONFIG_DEV_DAX_PMEM=m
CONFIG_DEV_DAX_KMEM=m
CONFIG_NVMEM=y
CONFIG_NVMEM_SYSFS=y
# CONFIG_NVMEM_RMEM is not set

#
# HW tracing support
#
CONFIG_STM=m
# CONFIG_STM_PROTO_BASIC is not set
# CONFIG_STM_PROTO_SYS_T is not set
CONFIG_STM_DUMMY=m
CONFIG_STM_SOURCE_CONSOLE=m
CONFIG_STM_SOURCE_HEARTBEAT=m
CONFIG_STM_SOURCE_FTRACE=m
CONFIG_INTEL_TH=m
CONFIG_INTEL_TH_PCI=m
CONFIG_INTEL_TH_ACPI=m
CONFIG_INTEL_TH_GTH=m
CONFIG_INTEL_TH_STH=m
CONFIG_INTEL_TH_MSU=m
CONFIG_INTEL_TH_PTI=m
# CONFIG_INTEL_TH_DEBUG is not set
# end of HW tracing support

# CONFIG_FPGA is not set
# CONFIG_TEE is not set
# CONFIG_SIOX is not set
# CONFIG_SLIMBUS is not set
# CONFIG_INTERCONNECT is not set
# CONFIG_COUNTER is not set
# CONFIG_MOST is not set
# CONFIG_PECI is not set
# CONFIG_HTE is not set
# end of Device Drivers

#
# File systems
#
CONFIG_DCACHE_WORD_ACCESS=y
# CONFIG_VALIDATE_FS_PARSER is not set
CONFIG_FS_IOMAP=y
CONFIG_EXT2_FS=m
# CONFIG_EXT2_FS_XATTR is not set
# CONFIG_EXT3_FS is not set
CONFIG_EXT4_FS=y
CONFIG_EXT4_FS_POSIX_ACL=y
CONFIG_EXT4_FS_SECURITY=y
# CONFIG_EXT4_DEBUG is not set
CONFIG_JBD2=y
# CONFIG_JBD2_DEBUG is not set
CONFIG_FS_MBCACHE=y
# CONFIG_REISERFS_FS is not set
# CONFIG_JFS_FS is not set
CONFIG_XFS_FS=m
CONFIG_XFS_SUPPORT_V4=y
CONFIG_XFS_QUOTA=y
CONFIG_XFS_POSIX_ACL=y
CONFIG_XFS_RT=y
CONFIG_XFS_ONLINE_SCRUB=y
# CONFIG_XFS_ONLINE_REPAIR is not set
CONFIG_XFS_DEBUG=y
CONFIG_XFS_ASSERT_FATAL=y
CONFIG_GFS2_FS=m
CONFIG_GFS2_FS_LOCKING_DLM=y
CONFIG_OCFS2_FS=m
CONFIG_OCFS2_FS_O2CB=m
CONFIG_OCFS2_FS_USERSPACE_CLUSTER=m
CONFIG_OCFS2_FS_STATS=y
CONFIG_OCFS2_DEBUG_MASKLOG=y
# CONFIG_OCFS2_DEBUG_FS is not set
CONFIG_BTRFS_FS=m
CONFIG_BTRFS_FS_POSIX_ACL=y
# CONFIG_BTRFS_FS_CHECK_INTEGRITY is not set
# CONFIG_BTRFS_FS_RUN_SANITY_TESTS is not set
# CONFIG_BTRFS_DEBUG is not set
# CONFIG_BTRFS_ASSERT is not set
# CONFIG_BTRFS_FS_REF_VERIFY is not set
# CONFIG_NILFS2_FS is not set
CONFIG_F2FS_FS=m
CONFIG_F2FS_STAT_FS=y
CONFIG_F2FS_FS_XATTR=y
CONFIG_F2FS_FS_POSIX_ACL=y
# CONFIG_F2FS_FS_SECURITY is not set
# CONFIG_F2FS_CHECK_FS is not set
# CONFIG_F2FS_FAULT_INJECTION is not set
# CONFIG_F2FS_FS_COMPRESSION is not set
CONFIG_F2FS_IOSTAT=y
# CONFIG_F2FS_UNFAIR_RWSEM is not set
CONFIG_FS_DAX=y
CONFIG_FS_DAX_PMD=y
CONFIG_FS_POSIX_ACL=y
CONFIG_EXPORTFS=y
CONFIG_EXPORTFS_BLOCK_OPS=y
CONFIG_FILE_LOCKING=y
CONFIG_FS_ENCRYPTION=y
CONFIG_FS_ENCRYPTION_ALGS=y
# CONFIG_FS_VERITY is not set
CONFIG_FSNOTIFY=y
CONFIG_DNOTIFY=y
CONFIG_INOTIFY_USER=y
CONFIG_FANOTIFY=y
CONFIG_FANOTIFY_ACCESS_PERMISSIONS=y
CONFIG_QUOTA=y
CONFIG_QUOTA_NETLINK_INTERFACE=y
CONFIG_PRINT_QUOTA_WARNING=y
# CONFIG_QUOTA_DEBUG is not set
CONFIG_QUOTA_TREE=y
# CONFIG_QFMT_V1 is not set
CONFIG_QFMT_V2=y
CONFIG_QUOTACTL=y
CONFIG_AUTOFS4_FS=y
CONFIG_AUTOFS_FS=y
CONFIG_FUSE_FS=m
CONFIG_CUSE=m
# CONFIG_VIRTIO_FS is not set
CONFIG_OVERLAY_FS=m
# CONFIG_OVERLAY_FS_REDIRECT_DIR is not set
# CONFIG_OVERLAY_FS_REDIRECT_ALWAYS_FOLLOW is not set
# CONFIG_OVERLAY_FS_INDEX is not set
# CONFIG_OVERLAY_FS_XINO_AUTO is not set
# CONFIG_OVERLAY_FS_METACOPY is not set

#
# Caches
#
CONFIG_NETFS_SUPPORT=m
CONFIG_NETFS_STATS=y
CONFIG_FSCACHE=m
CONFIG_FSCACHE_STATS=y
# CONFIG_FSCACHE_DEBUG is not set
CONFIG_CACHEFILES=m
# CONFIG_CACHEFILES_DEBUG is not set
# CONFIG_CACHEFILES_ERROR_INJECTION is not set
# CONFIG_CACHEFILES_ONDEMAND is not set
# end of Caches

#
# CD-ROM/DVD Filesystems
#
CONFIG_ISO9660_FS=m
CONFIG_JOLIET=y
CONFIG_ZISOFS=y
CONFIG_UDF_FS=m
# end of CD-ROM/DVD Filesystems

#
# DOS/FAT/EXFAT/NT Filesystems
#
CONFIG_FAT_FS=m
CONFIG_MSDOS_FS=m
CONFIG_VFAT_FS=m
CONFIG_FAT_DEFAULT_CODEPAGE=437
CONFIG_FAT_DEFAULT_IOCHARSET="ascii"
# CONFIG_FAT_DEFAULT_UTF8 is not set
# CONFIG_EXFAT_FS is not set
# CONFIG_NTFS_FS is not set
# CONFIG_NTFS3_FS is not set
# end of DOS/FAT/EXFAT/NT Filesystems

#
# Pseudo filesystems
#
CONFIG_PROC_FS=y
CONFIG_PROC_KCORE=y
CONFIG_PROC_VMCORE=y
CONFIG_PROC_VMCORE_DEVICE_DUMP=y
CONFIG_PROC_SYSCTL=y
CONFIG_PROC_PAGE_MONITOR=y
CONFIG_PROC_CHILDREN=y
CONFIG_PROC_PID_ARCH_STATUS=y
CONFIG_KERNFS=y
CONFIG_SYSFS=y
CONFIG_TMPFS=y
CONFIG_TMPFS_POSIX_ACL=y
CONFIG_TMPFS_XATTR=y
# CONFIG_TMPFS_INODE64 is not set
CONFIG_HUGETLBFS=y
CONFIG_HUGETLB_PAGE=y
CONFIG_ARCH_WANT_HUGETLB_PAGE_OPTIMIZE_VMEMMAP=y
CONFIG_HUGETLB_PAGE_OPTIMIZE_VMEMMAP=y
# CONFIG_HUGETLB_PAGE_OPTIMIZE_VMEMMAP_DEFAULT_ON is not set
CONFIG_MEMFD_CREATE=y
CONFIG_ARCH_HAS_GIGANTIC_PAGE=y
CONFIG_CONFIGFS_FS=y
CONFIG_EFIVAR_FS=y
# end of Pseudo filesystems

CONFIG_MISC_FILESYSTEMS=y
# CONFIG_ORANGEFS_FS is not set
# CONFIG_ADFS_FS is not set
# CONFIG_AFFS_FS is not set
# CONFIG_ECRYPT_FS is not set
# CONFIG_HFS_FS is not set
# CONFIG_HFSPLUS_FS is not set
# CONFIG_BEFS_FS is not set
# CONFIG_BFS_FS is not set
# CONFIG_EFS_FS is not set
CONFIG_CRAMFS=m
CONFIG_CRAMFS_BLOCKDEV=y
CONFIG_SQUASHFS=m
# CONFIG_SQUASHFS_FILE_CACHE is not set
CONFIG_SQUASHFS_FILE_DIRECT=y
CONFIG_SQUASHFS_DECOMP_SINGLE=y
# CONFIG_SQUASHFS_DECOMP_MULTI is not set
# CONFIG_SQUASHFS_DECOMP_MULTI_PERCPU is not set
CONFIG_SQUASHFS_XATTR=y
CONFIG_SQUASHFS_ZLIB=y
# CONFIG_SQUASHFS_LZ4 is not set
CONFIG_SQUASHFS_LZO=y
CONFIG_SQUASHFS_XZ=y
# CONFIG_SQUASHFS_ZSTD is not set
# CONFIG_SQUASHFS_4K_DEVBLK_SIZE is not set
# CONFIG_SQUASHFS_EMBEDDED is not set
CONFIG_SQUASHFS_FRAGMENT_CACHE_SIZE=3
# CONFIG_VXFS_FS is not set
# CONFIG_MINIX_FS is not set
# CONFIG_OMFS_FS is not set
# CONFIG_HPFS_FS is not set
# CONFIG_QNX4FS_FS is not set
# CONFIG_QNX6FS_FS is not set
# CONFIG_ROMFS_FS is not set
CONFIG_PSTORE=y
CONFIG_PSTORE_DEFAULT_KMSG_BYTES=10240
CONFIG_PSTORE_DEFLATE_COMPRESS=y
# CONFIG_PSTORE_LZO_COMPRESS is not set
# CONFIG_PSTORE_LZ4_COMPRESS is not set
# CONFIG_PSTORE_LZ4HC_COMPRESS is not set
# CONFIG_PSTORE_842_COMPRESS is not set
# CONFIG_PSTORE_ZSTD_COMPRESS is not set
CONFIG_PSTORE_COMPRESS=y
CONFIG_PSTORE_DEFLATE_COMPRESS_DEFAULT=y
CONFIG_PSTORE_COMPRESS_DEFAULT="deflate"
# CONFIG_PSTORE_CONSOLE is not set
# CONFIG_PSTORE_PMSG is not set
# CONFIG_PSTORE_FTRACE is not set
CONFIG_PSTORE_RAM=m
# CONFIG_PSTORE_BLK is not set
# CONFIG_SYSV_FS is not set
# CONFIG_UFS_FS is not set
# CONFIG_EROFS_FS is not set
CONFIG_NETWORK_FILESYSTEMS=y
CONFIG_NFS_FS=y
# CONFIG_NFS_V2 is not set
CONFIG_NFS_V3=y
CONFIG_NFS_V3_ACL=y
CONFIG_NFS_V4=m
# CONFIG_NFS_SWAP is not set
CONFIG_NFS_V4_1=y
CONFIG_NFS_V4_2=y
CONFIG_PNFS_FILE_LAYOUT=m
CONFIG_PNFS_BLOCK=m
CONFIG_PNFS_FLEXFILE_LAYOUT=m
CONFIG_NFS_V4_1_IMPLEMENTATION_ID_DOMAIN="kernel.org"
# CONFIG_NFS_V4_1_MIGRATION is not set
CONFIG_NFS_V4_SECURITY_LABEL=y
CONFIG_ROOT_NFS=y
# CONFIG_NFS_USE_LEGACY_DNS is not set
CONFIG_NFS_USE_KERNEL_DNS=y
CONFIG_NFS_DEBUG=y
CONFIG_NFS_DISABLE_UDP_SUPPORT=y
CONFIG_NFS_V4_2_READ_PLUS=y
CONFIG_NFSD=m
CONFIG_NFSD_V2_ACL=y
CONFIG_NFSD_V3_ACL=y
CONFIG_NFSD_V4=y
CONFIG_NFSD_PNFS=y
# CONFIG_NFSD_BLOCKLAYOUT is not set
CONFIG_NFSD_SCSILAYOUT=y
# CONFIG_NFSD_FLEXFILELAYOUT is not set
# CONFIG_NFSD_V4_2_INTER_SSC is not set
CONFIG_NFSD_V4_SECURITY_LABEL=y
CONFIG_GRACE_PERIOD=y
CONFIG_LOCKD=y
CONFIG_LOCKD_V4=y
CONFIG_NFS_ACL_SUPPORT=y
CONFIG_NFS_COMMON=y
CONFIG_NFS_V4_2_SSC_HELPER=y
CONFIG_SUNRPC=y
CONFIG_SUNRPC_GSS=m
CONFIG_SUNRPC_BACKCHANNEL=y
CONFIG_RPCSEC_GSS_KRB5=m
# CONFIG_SUNRPC_DISABLE_INSECURE_ENCTYPES is not set
CONFIG_SUNRPC_DEBUG=y
CONFIG_CEPH_FS=m
# CONFIG_CEPH_FSCACHE is not set
CONFIG_CEPH_FS_POSIX_ACL=y
# CONFIG_CEPH_FS_SECURITY_LABEL is not set
CONFIG_CIFS=m
CONFIG_CIFS_STATS2=y
CONFIG_CIFS_ALLOW_INSECURE_LEGACY=y
CONFIG_CIFS_UPCALL=y
CONFIG_CIFS_XATTR=y
CONFIG_CIFS_POSIX=y
CONFIG_CIFS_DEBUG=y
# CONFIG_CIFS_DEBUG2 is not set
# CONFIG_CIFS_DEBUG_DUMP_KEYS is not set
CONFIG_CIFS_DFS_UPCALL=y
# CONFIG_CIFS_SWN_UPCALL is not set
# CONFIG_CIFS_FSCACHE is not set
# CONFIG_SMB_SERVER is not set
CONFIG_SMBFS_COMMON=m
# CONFIG_CODA_FS is not set
# CONFIG_AFS_FS is not set
# CONFIG_9P_FS is not set
CONFIG_NLS=y
CONFIG_NLS_DEFAULT="utf8"
CONFIG_NLS_CODEPAGE_437=y
CONFIG_NLS_CODEPAGE_737=m
CONFIG_NLS_CODEPAGE_775=m
CONFIG_NLS_CODEPAGE_850=m
CONFIG_NLS_CODEPAGE_852=m
CONFIG_NLS_CODEPAGE_855=m
CONFIG_NLS_CODEPAGE_857=m
CONFIG_NLS_CODEPAGE_860=m
CONFIG_NLS_CODEPAGE_861=m
CONFIG_NLS_CODEPAGE_862=m
CONFIG_NLS_CODEPAGE_863=m
CONFIG_NLS_CODEPAGE_864=m
CONFIG_NLS_CODEPAGE_865=m
CONFIG_NLS_CODEPAGE_866=m
CONFIG_NLS_CODEPAGE_869=m
CONFIG_NLS_CODEPAGE_936=m
CONFIG_NLS_CODEPAGE_950=m
CONFIG_NLS_CODEPAGE_932=m
CONFIG_NLS_CODEPAGE_949=m
CONFIG_NLS_CODEPAGE_874=m
CONFIG_NLS_ISO8859_8=m
CONFIG_NLS_CODEPAGE_1250=m
CONFIG_NLS_CODEPAGE_1251=m
CONFIG_NLS_ASCII=y
CONFIG_NLS_ISO8859_1=m
CONFIG_NLS_ISO8859_2=m
CONFIG_NLS_ISO8859_3=m
CONFIG_NLS_ISO8859_4=m
CONFIG_NLS_ISO8859_5=m
CONFIG_NLS_ISO8859_6=m
CONFIG_NLS_ISO8859_7=m
CONFIG_NLS_ISO8859_9=m
CONFIG_NLS_ISO8859_13=m
CONFIG_NLS_ISO8859_14=m
CONFIG_NLS_ISO8859_15=m
CONFIG_NLS_KOI8_R=m
CONFIG_NLS_KOI8_U=m
CONFIG_NLS_MAC_ROMAN=m
CONFIG_NLS_MAC_CELTIC=m
CONFIG_NLS_MAC_CENTEURO=m
CONFIG_NLS_MAC_CROATIAN=m
CONFIG_NLS_MAC_CYRILLIC=m
CONFIG_NLS_MAC_GAELIC=m
CONFIG_NLS_MAC_GREEK=m
CONFIG_NLS_MAC_ICELAND=m
CONFIG_NLS_MAC_INUIT=m
CONFIG_NLS_MAC_ROMANIAN=m
CONFIG_NLS_MAC_TURKISH=m
CONFIG_NLS_UTF8=m
CONFIG_DLM=m
# CONFIG_DLM_DEPRECATED_API is not set
CONFIG_DLM_DEBUG=y
# CONFIG_UNICODE is not set
CONFIG_IO_WQ=y
# end of File systems

#
# Security options
#
CONFIG_KEYS=y
# CONFIG_KEYS_REQUEST_CACHE is not set
CONFIG_PERSISTENT_KEYRINGS=y
CONFIG_TRUSTED_KEYS=y
CONFIG_TRUSTED_KEYS_TPM=y
CONFIG_ENCRYPTED_KEYS=y
# CONFIG_USER_DECRYPTED_DATA is not set
# CONFIG_KEY_DH_OPERATIONS is not set
# CONFIG_SECURITY_DMESG_RESTRICT is not set
CONFIG_SECURITY=y
CONFIG_SECURITYFS=y
CONFIG_SECURITY_NETWORK=y
CONFIG_SECURITY_NETWORK_XFRM=y
CONFIG_SECURITY_PATH=y
CONFIG_INTEL_TXT=y
CONFIG_HAVE_HARDENED_USERCOPY_ALLOCATOR=y
CONFIG_HARDENED_USERCOPY=y
CONFIG_FORTIFY_SOURCE=y
# CONFIG_STATIC_USERMODEHELPER is not set
# CONFIG_SECURITY_SELINUX is not set
# CONFIG_SECURITY_SMACK is not set
# CONFIG_SECURITY_TOMOYO is not set
CONFIG_SECURITY_APPARMOR=y
# CONFIG_SECURITY_APPARMOR_DEBUG is not set
CONFIG_SECURITY_APPARMOR_INTROSPECT_POLICY=y
CONFIG_SECURITY_APPARMOR_HASH=y
CONFIG_SECURITY_APPARMOR_HASH_DEFAULT=y
CONFIG_SECURITY_APPARMOR_EXPORT_BINARY=y
CONFIG_SECURITY_APPARMOR_PARANOID_LOAD=y
# CONFIG_SECURITY_LOADPIN is not set
CONFIG_SECURITY_YAMA=y
# CONFIG_SECURITY_SAFESETID is not set
# CONFIG_SECURITY_LOCKDOWN_LSM is not set
# CONFIG_SECURITY_LANDLOCK is not set
CONFIG_INTEGRITY=y
CONFIG_INTEGRITY_SIGNATURE=y
CONFIG_INTEGRITY_ASYMMETRIC_KEYS=y
CONFIG_INTEGRITY_TRUSTED_KEYRING=y
# CONFIG_INTEGRITY_PLATFORM_KEYRING is not set
CONFIG_INTEGRITY_AUDIT=y
# CONFIG_IMA is not set
# CONFIG_IMA_SECURE_AND_OR_TRUSTED_BOOT is not set
# CONFIG_EVM is not set
CONFIG_DEFAULT_SECURITY_APPARMOR=y
# CONFIG_DEFAULT_SECURITY_DAC is not set
CONFIG_LSM="landlock,lockdown,yama,loadpin,safesetid,integrity,apparmor,selinux,smack,tomoyo,bpf"

#
# Kernel hardening options
#

#
# Memory initialization
#
CONFIG_CC_HAS_AUTO_VAR_INIT_PATTERN=y
CONFIG_CC_HAS_AUTO_VAR_INIT_ZERO=y
# CONFIG_INIT_STACK_NONE is not set
# CONFIG_INIT_STACK_ALL_PATTERN is not set
CONFIG_INIT_STACK_ALL_ZERO=y
# CONFIG_INIT_ON_ALLOC_DEFAULT_ON is not set
# CONFIG_INIT_ON_FREE_DEFAULT_ON is not set
# end of Memory initialization

CONFIG_RANDSTRUCT_NONE=y
# end of Kernel hardening options
# end of Security options

CONFIG_XOR_BLOCKS=m
CONFIG_ASYNC_CORE=m
CONFIG_ASYNC_MEMCPY=m
CONFIG_ASYNC_XOR=m
CONFIG_ASYNC_PQ=m
CONFIG_ASYNC_RAID6_RECOV=m
CONFIG_CRYPTO=y

#
# Crypto core or helper
#
CONFIG_CRYPTO_ALGAPI=y
CONFIG_CRYPTO_ALGAPI2=y
CONFIG_CRYPTO_AEAD=y
CONFIG_CRYPTO_AEAD2=y
CONFIG_CRYPTO_SKCIPHER=y
CONFIG_CRYPTO_SKCIPHER2=y
CONFIG_CRYPTO_HASH=y
CONFIG_CRYPTO_HASH2=y
CONFIG_CRYPTO_RNG=y
CONFIG_CRYPTO_RNG2=y
CONFIG_CRYPTO_RNG_DEFAULT=y
CONFIG_CRYPTO_AKCIPHER2=y
CONFIG_CRYPTO_AKCIPHER=y
CONFIG_CRYPTO_KPP2=y
CONFIG_CRYPTO_KPP=m
CONFIG_CRYPTO_ACOMP2=y
CONFIG_CRYPTO_MANAGER=y
CONFIG_CRYPTO_MANAGER2=y
CONFIG_CRYPTO_USER=m
CONFIG_CRYPTO_MANAGER_DISABLE_TESTS=y
CONFIG_CRYPTO_GF128MUL=y
CONFIG_CRYPTO_NULL=y
CONFIG_CRYPTO_NULL2=y
CONFIG_CRYPTO_PCRYPT=m
CONFIG_CRYPTO_CRYPTD=y
CONFIG_CRYPTO_AUTHENC=m
# CONFIG_CRYPTO_TEST is not set
CONFIG_CRYPTO_SIMD=y

#
# Public-key cryptography
#
CONFIG_CRYPTO_RSA=y
CONFIG_CRYPTO_DH=m
# CONFIG_CRYPTO_DH_RFC7919_GROUPS is not set
CONFIG_CRYPTO_ECC=m
CONFIG_CRYPTO_ECDH=m
# CONFIG_CRYPTO_ECDSA is not set
# CONFIG_CRYPTO_ECRDSA is not set
# CONFIG_CRYPTO_SM2 is not set
# CONFIG_CRYPTO_CURVE25519 is not set
# CONFIG_CRYPTO_CURVE25519_X86 is not set

#
# Authenticated Encryption with Associated Data
#
CONFIG_CRYPTO_CCM=m
CONFIG_CRYPTO_GCM=y
# CONFIG_CRYPTO_CHACHA20POLY1305 is not set
# CONFIG_CRYPTO_AEGIS128 is not set
# CONFIG_CRYPTO_AEGIS128_AESNI_SSE2 is not set
CONFIG_CRYPTO_SEQIV=y
CONFIG_CRYPTO_ECHAINIV=m

#
# Block modes
#
CONFIG_CRYPTO_CBC=y
CONFIG_CRYPTO_CFB=y
CONFIG_CRYPTO_CTR=y
CONFIG_CRYPTO_CTS=m
CONFIG_CRYPTO_ECB=y
CONFIG_CRYPTO_LRW=m
CONFIG_CRYPTO_OFB=m
CONFIG_CRYPTO_PCBC=m
CONFIG_CRYPTO_XTS=m
# CONFIG_CRYPTO_KEYWRAP is not set
# CONFIG_CRYPTO_NHPOLY1305_SSE2 is not set
# CONFIG_CRYPTO_NHPOLY1305_AVX2 is not set
# CONFIG_CRYPTO_ADIANTUM is not set
# CONFIG_CRYPTO_HCTR2 is not set
CONFIG_CRYPTO_ESSIV=m

#
# Hash modes
#
CONFIG_CRYPTO_CMAC=m
CONFIG_CRYPTO_HMAC=y
CONFIG_CRYPTO_XCBC=m
CONFIG_CRYPTO_VMAC=m

#
# Digest
#
CONFIG_CRYPTO_CRC32C=y
CONFIG_CRYPTO_CRC32C_INTEL=m
CONFIG_CRYPTO_CRC32=m
CONFIG_CRYPTO_CRC32_PCLMUL=m
CONFIG_CRYPTO_XXHASH=m
CONFIG_CRYPTO_BLAKE2B=m
# CONFIG_CRYPTO_BLAKE2S_X86 is not set
CONFIG_CRYPTO_CRCT10DIF=y
CONFIG_CRYPTO_CRCT10DIF_PCLMUL=m
CONFIG_CRYPTO_CRC64_ROCKSOFT=m
CONFIG_CRYPTO_GHASH=y
# CONFIG_CRYPTO_POLYVAL_CLMUL_NI is not set
# CONFIG_CRYPTO_POLY1305 is not set
# CONFIG_CRYPTO_POLY1305_X86_64 is not set
CONFIG_CRYPTO_MD4=m
CONFIG_CRYPTO_MD5=y
CONFIG_CRYPTO_MICHAEL_MIC=m
CONFIG_CRYPTO_RMD160=m
CONFIG_CRYPTO_SHA1=y
CONFIG_CRYPTO_SHA1_SSSE3=y
CONFIG_CRYPTO_SHA256_SSSE3=y
CONFIG_CRYPTO_SHA512_SSSE3=m
CONFIG_CRYPTO_SHA256=y
CONFIG_CRYPTO_SHA512=y
CONFIG_CRYPTO_SHA3=m
# CONFIG_CRYPTO_SM3_GENERIC is not set
# CONFIG_CRYPTO_SM3_AVX_X86_64 is not set
# CONFIG_CRYPTO_STREEBOG is not set
CONFIG_CRYPTO_WP512=m
CONFIG_CRYPTO_GHASH_CLMUL_NI_INTEL=m

#
# Ciphers
#
CONFIG_CRYPTO_AES=y
# CONFIG_CRYPTO_AES_TI is not set
CONFIG_CRYPTO_AES_NI_INTEL=y
CONFIG_CRYPTO_ANUBIS=m
CONFIG_CRYPTO_ARC4=m
CONFIG_CRYPTO_BLOWFISH=m
CONFIG_CRYPTO_BLOWFISH_COMMON=m
CONFIG_CRYPTO_BLOWFISH_X86_64=m
CONFIG_CRYPTO_CAMELLIA=m
CONFIG_CRYPTO_CAMELLIA_X86_64=m
CONFIG_CRYPTO_CAMELLIA_AESNI_AVX_X86_64=m
CONFIG_CRYPTO_CAMELLIA_AESNI_AVX2_X86_64=m
CONFIG_CRYPTO_CAST_COMMON=m
CONFIG_CRYPTO_CAST5=m
CONFIG_CRYPTO_CAST5_AVX_X86_64=m
CONFIG_CRYPTO_CAST6=m
CONFIG_CRYPTO_CAST6_AVX_X86_64=m
CONFIG_CRYPTO_DES=m
# CONFIG_CRYPTO_DES3_EDE_X86_64 is not set
CONFIG_CRYPTO_FCRYPT=m
CONFIG_CRYPTO_KHAZAD=m
CONFIG_CRYPTO_CHACHA20=m
CONFIG_CRYPTO_CHACHA20_X86_64=m
CONFIG_CRYPTO_SEED=m
# CONFIG_CRYPTO_ARIA is not set
CONFIG_CRYPTO_SERPENT=m
CONFIG_CRYPTO_SERPENT_SSE2_X86_64=m
CONFIG_CRYPTO_SERPENT_AVX_X86_64=m
CONFIG_CRYPTO_SERPENT_AVX2_X86_64=m
# CONFIG_CRYPTO_SM4_GENERIC is not set
# CONFIG_CRYPTO_SM4_AESNI_AVX_X86_64 is not set
# CONFIG_CRYPTO_SM4_AESNI_AVX2_X86_64 is not set
CONFIG_CRYPTO_TEA=m
CONFIG_CRYPTO_TWOFISH=m
CONFIG_CRYPTO_TWOFISH_COMMON=m
CONFIG_CRYPTO_TWOFISH_X86_64=m
CONFIG_CRYPTO_TWOFISH_X86_64_3WAY=m
CONFIG_CRYPTO_TWOFISH_AVX_X86_64=m

#
# Compression
#
CONFIG_CRYPTO_DEFLATE=y
CONFIG_CRYPTO_LZO=y
# CONFIG_CRYPTO_842 is not set
# CONFIG_CRYPTO_LZ4 is not set
# CONFIG_CRYPTO_LZ4HC is not set
# CONFIG_CRYPTO_ZSTD is not set

#
# Random Number Generation
#
CONFIG_CRYPTO_ANSI_CPRNG=m
CONFIG_CRYPTO_DRBG_MENU=y
CONFIG_CRYPTO_DRBG_HMAC=y
CONFIG_CRYPTO_DRBG_HASH=y
CONFIG_CRYPTO_DRBG_CTR=y
CONFIG_CRYPTO_DRBG=y
CONFIG_CRYPTO_JITTERENTROPY=y
CONFIG_CRYPTO_USER_API=y
CONFIG_CRYPTO_USER_API_HASH=y
CONFIG_CRYPTO_USER_API_SKCIPHER=y
CONFIG_CRYPTO_USER_API_RNG=y
# CONFIG_CRYPTO_USER_API_RNG_CAVP is not set
CONFIG_CRYPTO_USER_API_AEAD=y
CONFIG_CRYPTO_USER_API_ENABLE_OBSOLETE=y
# CONFIG_CRYPTO_STATS is not set
CONFIG_CRYPTO_HASH_INFO=y
CONFIG_CRYPTO_HW=y
CONFIG_CRYPTO_DEV_PADLOCK=m
CONFIG_CRYPTO_DEV_PADLOCK_AES=m
CONFIG_CRYPTO_DEV_PADLOCK_SHA=m
# CONFIG_CRYPTO_DEV_ATMEL_ECC is not set
# CONFIG_CRYPTO_DEV_ATMEL_SHA204A is not set
CONFIG_CRYPTO_DEV_CCP=y
CONFIG_CRYPTO_DEV_CCP_DD=m
CONFIG_CRYPTO_DEV_SP_CCP=y
CONFIG_CRYPTO_DEV_CCP_CRYPTO=m
CONFIG_CRYPTO_DEV_SP_PSP=y
# CONFIG_CRYPTO_DEV_CCP_DEBUGFS is not set
CONFIG_CRYPTO_DEV_QAT=m
CONFIG_CRYPTO_DEV_QAT_DH895xCC=m
CONFIG_CRYPTO_DEV_QAT_C3XXX=m
CONFIG_CRYPTO_DEV_QAT_C62X=m
# CONFIG_CRYPTO_DEV_QAT_4XXX is not set
CONFIG_CRYPTO_DEV_QAT_DH895xCCVF=m
CONFIG_CRYPTO_DEV_QAT_C3XXXVF=m
CONFIG_CRYPTO_DEV_QAT_C62XVF=m
CONFIG_CRYPTO_DEV_NITROX=m
CONFIG_CRYPTO_DEV_NITROX_CNN55XX=m
# CONFIG_CRYPTO_DEV_VIRTIO is not set
# CONFIG_CRYPTO_DEV_SAFEXCEL is not set
# CONFIG_CRYPTO_DEV_AMLOGIC_GXL is not set
CONFIG_ASYMMETRIC_KEY_TYPE=y
CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE=y
CONFIG_X509_CERTIFICATE_PARSER=y
# CONFIG_PKCS8_PRIVATE_KEY_PARSER is not set
CONFIG_PKCS7_MESSAGE_PARSER=y
# CONFIG_PKCS7_TEST_KEY is not set
CONFIG_SIGNED_PE_FILE_VERIFICATION=y
# CONFIG_FIPS_SIGNATURE_SELFTEST is not set

#
# Certificates for signature checking
#
CONFIG_MODULE_SIG_KEY="certs/signing_key.pem"
CONFIG_MODULE_SIG_KEY_TYPE_RSA=y
# CONFIG_MODULE_SIG_KEY_TYPE_ECDSA is not set
CONFIG_SYSTEM_TRUSTED_KEYRING=y
CONFIG_SYSTEM_TRUSTED_KEYS=""
# CONFIG_SYSTEM_EXTRA_CERTIFICATE is not set
# CONFIG_SECONDARY_TRUSTED_KEYRING is not set
CONFIG_SYSTEM_BLACKLIST_KEYRING=y
CONFIG_SYSTEM_BLACKLIST_HASH_LIST=""
# CONFIG_SYSTEM_REVOCATION_LIST is not set
# CONFIG_SYSTEM_BLACKLIST_AUTH_UPDATE is not set
# end of Certificates for signature checking

CONFIG_BINARY_PRINTF=y

#
# Library routines
#
CONFIG_RAID6_PQ=m
CONFIG_RAID6_PQ_BENCHMARK=y
# CONFIG_PACKING is not set
CONFIG_BITREVERSE=y
CONFIG_GENERIC_STRNCPY_FROM_USER=y
CONFIG_GENERIC_STRNLEN_USER=y
CONFIG_GENERIC_NET_UTILS=y
CONFIG_CORDIC=m
# CONFIG_PRIME_NUMBERS is not set
CONFIG_RATIONAL=y
CONFIG_GENERIC_PCI_IOMAP=y
CONFIG_GENERIC_IOMAP=y
CONFIG_ARCH_USE_CMPXCHG_LOCKREF=y
CONFIG_ARCH_HAS_FAST_MULTIPLIER=y
CONFIG_ARCH_USE_SYM_ANNOTATIONS=y

#
# Crypto library routines
#
CONFIG_CRYPTO_LIB_AES=y
CONFIG_CRYPTO_LIB_ARC4=m
CONFIG_CRYPTO_LIB_BLAKE2S_GENERIC=y
CONFIG_CRYPTO_ARCH_HAVE_LIB_CHACHA=m
CONFIG_CRYPTO_LIB_CHACHA_GENERIC=m
# CONFIG_CRYPTO_LIB_CHACHA is not set
# CONFIG_CRYPTO_LIB_CURVE25519 is not set
CONFIG_CRYPTO_LIB_DES=m
CONFIG_CRYPTO_LIB_POLY1305_RSIZE=11
# CONFIG_CRYPTO_LIB_POLY1305 is not set
# CONFIG_CRYPTO_LIB_CHACHA20POLY1305 is not set
CONFIG_CRYPTO_LIB_SHA1=y
CONFIG_CRYPTO_LIB_SHA256=y
# end of Crypto library routines

CONFIG_LIB_MEMNEQ=y
CONFIG_CRC_CCITT=y
CONFIG_CRC16=y
CONFIG_CRC_T10DIF=y
CONFIG_CRC64_ROCKSOFT=m
CONFIG_CRC_ITU_T=m
CONFIG_CRC32=y
# CONFIG_CRC32_SELFTEST is not set
CONFIG_CRC32_SLICEBY8=y
# CONFIG_CRC32_SLICEBY4 is not set
# CONFIG_CRC32_SARWATE is not set
# CONFIG_CRC32_BIT is not set
CONFIG_CRC64=m
# CONFIG_CRC4 is not set
CONFIG_CRC7=m
CONFIG_LIBCRC32C=m
CONFIG_CRC8=m
CONFIG_XXHASH=y
# CONFIG_RANDOM32_SELFTEST is not set
CONFIG_ZLIB_INFLATE=y
CONFIG_ZLIB_DEFLATE=y
CONFIG_LZO_COMPRESS=y
CONFIG_LZO_DECOMPRESS=y
CONFIG_LZ4_DECOMPRESS=y
CONFIG_ZSTD_COMPRESS=m
CONFIG_ZSTD_DECOMPRESS=y
CONFIG_XZ_DEC=y
CONFIG_XZ_DEC_X86=y
CONFIG_XZ_DEC_POWERPC=y
CONFIG_XZ_DEC_IA64=y
CONFIG_XZ_DEC_ARM=y
CONFIG_XZ_DEC_ARMTHUMB=y
CONFIG_XZ_DEC_SPARC=y
# CONFIG_XZ_DEC_MICROLZMA is not set
CONFIG_XZ_DEC_BCJ=y
# CONFIG_XZ_DEC_TEST is not set
CONFIG_DECOMPRESS_GZIP=y
CONFIG_DECOMPRESS_BZIP2=y
CONFIG_DECOMPRESS_LZMA=y
CONFIG_DECOMPRESS_XZ=y
CONFIG_DECOMPRESS_LZO=y
CONFIG_DECOMPRESS_LZ4=y
CONFIG_DECOMPRESS_ZSTD=y
CONFIG_GENERIC_ALLOCATOR=y
CONFIG_REED_SOLOMON=m
CONFIG_REED_SOLOMON_ENC8=y
CONFIG_REED_SOLOMON_DEC8=y
CONFIG_TEXTSEARCH=y
CONFIG_TEXTSEARCH_KMP=m
CONFIG_TEXTSEARCH_BM=m
CONFIG_TEXTSEARCH_FSM=m
CONFIG_INTERVAL_TREE=y
CONFIG_XARRAY_MULTI=y
CONFIG_ASSOCIATIVE_ARRAY=y
CONFIG_HAS_IOMEM=y
CONFIG_HAS_IOPORT_MAP=y
CONFIG_HAS_DMA=y
CONFIG_DMA_OPS=y
CONFIG_NEED_SG_DMA_LENGTH=y
CONFIG_NEED_DMA_MAP_STATE=y
CONFIG_ARCH_DMA_ADDR_T_64BIT=y
CONFIG_ARCH_HAS_FORCE_DMA_UNENCRYPTED=y
CONFIG_SWIOTLB=y
# CONFIG_DMA_API_DEBUG is not set
# CONFIG_DMA_MAP_BENCHMARK is not set
CONFIG_SGL_ALLOC=y
CONFIG_CHECK_SIGNATURE=y
CONFIG_CPUMASK_OFFSTACK=y
CONFIG_CPU_RMAP=y
CONFIG_DQL=y
CONFIG_GLOB=y
# CONFIG_GLOB_SELFTEST is not set
CONFIG_NLATTR=y
CONFIG_CLZ_TAB=y
CONFIG_IRQ_POLL=y
CONFIG_MPILIB=y
CONFIG_SIGNATURE=y
CONFIG_OID_REGISTRY=y
CONFIG_UCS2_STRING=y
CONFIG_HAVE_GENERIC_VDSO=y
CONFIG_GENERIC_GETTIMEOFDAY=y
CONFIG_GENERIC_VDSO_TIME_NS=y
CONFIG_FONT_SUPPORT=y
# CONFIG_FONTS is not set
CONFIG_FONT_8x8=y
CONFIG_FONT_8x16=y
CONFIG_SG_POOL=y
CONFIG_ARCH_HAS_PMEM_API=y
CONFIG_MEMREGION=y
CONFIG_ARCH_HAS_UACCESS_FLUSHCACHE=y
CONFIG_ARCH_HAS_COPY_MC=y
CONFIG_ARCH_STACKWALK=y
CONFIG_STACKDEPOT=y
CONFIG_SBITMAP=y
# end of Library routines

CONFIG_ASN1_ENCODER=y

#
# Kernel hacking
#

#
# printk and dmesg options
#
CONFIG_PRINTK_TIME=y
CONFIG_PRINTK_CALLER=y
# CONFIG_STACKTRACE_BUILD_ID is not set
CONFIG_CONSOLE_LOGLEVEL_DEFAULT=7
CONFIG_CONSOLE_LOGLEVEL_QUIET=4
CONFIG_MESSAGE_LOGLEVEL_DEFAULT=4
CONFIG_BOOT_PRINTK_DELAY=y
CONFIG_DYNAMIC_DEBUG=y
CONFIG_DYNAMIC_DEBUG_CORE=y
CONFIG_SYMBOLIC_ERRNAME=y
CONFIG_DEBUG_BUGVERBOSE=y
# end of printk and dmesg options

CONFIG_DEBUG_KERNEL=y
CONFIG_DEBUG_MISC=y

#
# Compile-time checks and compiler options
#
CONFIG_DEBUG_INFO=y
# CONFIG_DEBUG_INFO_NONE is not set
# CONFIG_DEBUG_INFO_DWARF_TOOLCHAIN_DEFAULT is not set
CONFIG_DEBUG_INFO_DWARF4=y
# CONFIG_DEBUG_INFO_DWARF5 is not set
# CONFIG_DEBUG_INFO_REDUCED is not set
# CONFIG_DEBUG_INFO_SPLIT is not set
# CONFIG_DEBUG_INFO_BTF is not set
CONFIG_PAHOLE_HAS_SPLIT_BTF=y
CONFIG_PAHOLE_HAS_BTF_TAG=y
# CONFIG_GDB_SCRIPTS is not set
CONFIG_FRAME_WARN=2048
CONFIG_STRIP_ASM_SYMS=y
# CONFIG_HEADERS_INSTALL is not set
CONFIG_SECTION_MISMATCH_WARN_ONLY=y
CONFIG_OBJTOOL=y
# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set
# end of Compile-time checks and compiler options

#
# Generic Kernel Debugging Instruments
#
CONFIG_MAGIC_SYSRQ=y
CONFIG_MAGIC_SYSRQ_DEFAULT_ENABLE=0x1
CONFIG_MAGIC_SYSRQ_SERIAL=y
CONFIG_MAGIC_SYSRQ_SERIAL_SEQUENCE=""
CONFIG_DEBUG_FS=y
CONFIG_DEBUG_FS_ALLOW_ALL=y
# CONFIG_DEBUG_FS_DISALLOW_MOUNT is not set
# CONFIG_DEBUG_FS_ALLOW_NONE is not set
CONFIG_HAVE_ARCH_KGDB=y
# CONFIG_KGDB is not set
CONFIG_ARCH_HAS_UBSAN_SANITIZE_ALL=y
# CONFIG_UBSAN is not set
CONFIG_HAVE_ARCH_KCSAN=y
CONFIG_HAVE_KCSAN_COMPILER=y
# CONFIG_KCSAN is not set
# end of Generic Kernel Debugging Instruments

#
# Networking Debugging
#
# CONFIG_NET_DEV_REFCNT_TRACKER is not set
# CONFIG_NET_NS_REFCNT_TRACKER is not set
# CONFIG_DEBUG_NET is not set
# end of Networking Debugging

#
# Memory Debugging
#
# CONFIG_PAGE_EXTENSION is not set
# CONFIG_DEBUG_PAGEALLOC is not set
CONFIG_SLUB_DEBUG=y
# CONFIG_SLUB_DEBUG_ON is not set
# CONFIG_PAGE_OWNER is not set
# CONFIG_PAGE_TABLE_CHECK is not set
# CONFIG_PAGE_POISONING is not set
# CONFIG_DEBUG_PAGE_REF is not set
# CONFIG_DEBUG_RODATA_TEST is not set
CONFIG_ARCH_HAS_DEBUG_WX=y
# CONFIG_DEBUG_WX is not set
CONFIG_GENERIC_PTDUMP=y
# CONFIG_PTDUMP_DEBUGFS is not set
# CONFIG_DEBUG_OBJECTS is not set
# CONFIG_SHRINKER_DEBUG is not set
CONFIG_HAVE_DEBUG_KMEMLEAK=y
# CONFIG_DEBUG_KMEMLEAK is not set
# CONFIG_DEBUG_STACK_USAGE is not set
# CONFIG_SCHED_STACK_END_CHECK is not set
CONFIG_ARCH_HAS_DEBUG_VM_PGTABLE=y
# CONFIG_DEBUG_VM is not set
# CONFIG_DEBUG_VM_PGTABLE is not set
CONFIG_ARCH_HAS_DEBUG_VIRTUAL=y
# CONFIG_DEBUG_VIRTUAL is not set
CONFIG_DEBUG_MEMORY_INIT=y
# CONFIG_DEBUG_PER_CPU_MAPS is not set
CONFIG_HAVE_ARCH_KASAN=y
CONFIG_HAVE_ARCH_KASAN_VMALLOC=y
CONFIG_CC_HAS_KASAN_GENERIC=y
CONFIG_CC_HAS_KASAN_SW_TAGS=y
CONFIG_CC_HAS_WORKING_NOSANITIZE_ADDRESS=y
# CONFIG_KASAN is not set
CONFIG_HAVE_ARCH_KFENCE=y
# CONFIG_KFENCE is not set
# end of Memory Debugging

CONFIG_DEBUG_SHIRQ=y

#
# Debug Oops, Lockups and Hangs
#
CONFIG_PANIC_ON_OOPS=y
CONFIG_PANIC_ON_OOPS_VALUE=1
CONFIG_PANIC_TIMEOUT=0
CONFIG_LOCKUP_DETECTOR=y
CONFIG_SOFTLOCKUP_DETECTOR=y
# CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set
CONFIG_HARDLOCKUP_DETECTOR_PERF=y
CONFIG_HARDLOCKUP_CHECK_TIMESTAMP=y
CONFIG_HARDLOCKUP_DETECTOR=y
CONFIG_BOOTPARAM_HARDLOCKUP_PANIC=y
CONFIG_DETECT_HUNG_TASK=y
CONFIG_DEFAULT_HUNG_TASK_TIMEOUT=480
# CONFIG_BOOTPARAM_HUNG_TASK_PANIC is not set
CONFIG_WQ_WATCHDOG=y
# CONFIG_TEST_LOCKUP is not set
# end of Debug Oops, Lockups and Hangs

#
# Scheduler Debugging
#
CONFIG_SCHED_DEBUG=y
CONFIG_SCHED_INFO=y
CONFIG_SCHEDSTATS=y
# end of Scheduler Debugging

# CONFIG_DEBUG_TIMEKEEPING is not set

#
# Lock Debugging (spinlocks, mutexes, etc...)
#
CONFIG_LOCK_DEBUGGING_SUPPORT=y
# CONFIG_PROVE_LOCKING is not set
# CONFIG_LOCK_STAT is not set
# CONFIG_DEBUG_RT_MUTEXES is not set
# CONFIG_DEBUG_SPINLOCK is not set
# CONFIG_DEBUG_MUTEXES is not set
# CONFIG_DEBUG_WW_MUTEX_SLOWPATH is not set
# CONFIG_DEBUG_RWSEMS is not set
# CONFIG_DEBUG_LOCK_ALLOC is not set
CONFIG_DEBUG_ATOMIC_SLEEP=y
# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
# CONFIG_LOCK_TORTURE_TEST is not set
# CONFIG_WW_MUTEX_SELFTEST is not set
# CONFIG_SCF_TORTURE_TEST is not set
# CONFIG_CSD_LOCK_WAIT_DEBUG is not set
# end of Lock Debugging (spinlocks, mutexes, etc...)

# CONFIG_DEBUG_IRQFLAGS is not set
CONFIG_STACKTRACE=y
# CONFIG_WARN_ALL_UNSEEDED_RANDOM is not set
# CONFIG_DEBUG_KOBJECT is not set

#
# Debug kernel data structures
#
CONFIG_DEBUG_LIST=y
# CONFIG_DEBUG_PLIST is not set
# CONFIG_DEBUG_SG is not set
# CONFIG_DEBUG_NOTIFIERS is not set
CONFIG_BUG_ON_DATA_CORRUPTION=y
# end of Debug kernel data structures

# CONFIG_DEBUG_CREDENTIALS is not set

#
# RCU Debugging
#
# CONFIG_RCU_SCALE_TEST is not set
# CONFIG_RCU_TORTURE_TEST is not set
# CONFIG_RCU_REF_SCALE_TEST is not set
CONFIG_RCU_CPU_STALL_TIMEOUT=60
CONFIG_RCU_EXP_CPU_STALL_TIMEOUT=0
# CONFIG_RCU_TRACE is not set
# CONFIG_RCU_EQS_DEBUG is not set
# end of RCU Debugging

# CONFIG_DEBUG_WQ_FORCE_RR_CPU is not set
# CONFIG_CPU_HOTPLUG_STATE_CONTROL is not set
CONFIG_LATENCYTOP=y
CONFIG_USER_STACKTRACE_SUPPORT=y
CONFIG_NOP_TRACER=y
CONFIG_HAVE_RETHOOK=y
CONFIG_RETHOOK=y
CONFIG_HAVE_FUNCTION_TRACER=y
CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
CONFIG_HAVE_DYNAMIC_FTRACE=y
CONFIG_HAVE_DYNAMIC_FTRACE_WITH_REGS=y
CONFIG_HAVE_DYNAMIC_FTRACE_WITH_DIRECT_CALLS=y
CONFIG_HAVE_DYNAMIC_FTRACE_WITH_ARGS=y
CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
CONFIG_HAVE_SYSCALL_TRACEPOINTS=y
CONFIG_HAVE_FENTRY=y
CONFIG_HAVE_OBJTOOL_MCOUNT=y
CONFIG_HAVE_C_RECORDMCOUNT=y
CONFIG_HAVE_BUILDTIME_MCOUNT_SORT=y
CONFIG_BUILDTIME_MCOUNT_SORT=y
CONFIG_TRACER_MAX_TRACE=y
CONFIG_TRACE_CLOCK=y
CONFIG_RING_BUFFER=y
CONFIG_EVENT_TRACING=y
CONFIG_CONTEXT_SWITCH_TRACER=y
CONFIG_TRACING=y
CONFIG_GENERIC_TRACER=y
CONFIG_TRACING_SUPPORT=y
CONFIG_FTRACE=y
# CONFIG_BOOTTIME_TRACING is not set
CONFIG_FUNCTION_TRACER=y
CONFIG_FUNCTION_GRAPH_TRACER=y
CONFIG_DYNAMIC_FTRACE=y
CONFIG_DYNAMIC_FTRACE_WITH_REGS=y
CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS=y
CONFIG_DYNAMIC_FTRACE_WITH_ARGS=y
# CONFIG_FPROBE is not set
CONFIG_FUNCTION_PROFILER=y
CONFIG_STACK_TRACER=y
# CONFIG_IRQSOFF_TRACER is not set
CONFIG_SCHED_TRACER=y
CONFIG_HWLAT_TRACER=y
# CONFIG_OSNOISE_TRACER is not set
# CONFIG_TIMERLAT_TRACER is not set
# CONFIG_MMIOTRACE is not set
CONFIG_FTRACE_SYSCALLS=y
CONFIG_TRACER_SNAPSHOT=y
# CONFIG_TRACER_SNAPSHOT_PER_CPU_SWAP is not set
CONFIG_BRANCH_PROFILE_NONE=y
# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set
# CONFIG_BLK_DEV_IO_TRACE is not set
CONFIG_KPROBE_EVENTS=y
# CONFIG_KPROBE_EVENTS_ON_NOTRACE is not set
CONFIG_UPROBE_EVENTS=y
CONFIG_BPF_EVENTS=y
CONFIG_DYNAMIC_EVENTS=y
CONFIG_PROBE_EVENTS=y
CONFIG_BPF_KPROBE_OVERRIDE=y
CONFIG_FTRACE_MCOUNT_RECORD=y
CONFIG_FTRACE_MCOUNT_USE_OBJTOOL=y
CONFIG_TRACING_MAP=y
CONFIG_SYNTH_EVENTS=y
CONFIG_HIST_TRIGGERS=y
# CONFIG_TRACE_EVENT_INJECT is not set
# CONFIG_TRACEPOINT_BENCHMARK is not set
CONFIG_RING_BUFFER_BENCHMARK=m
# CONFIG_TRACE_EVAL_MAP_FILE is not set
# CONFIG_FTRACE_RECORD_RECURSION is not set
# CONFIG_FTRACE_STARTUP_TEST is not set
# CONFIG_FTRACE_SORT_STARTUP_TEST is not set
# CONFIG_RING_BUFFER_STARTUP_TEST is not set
# CONFIG_RING_BUFFER_VALIDATE_TIME_DELTAS is not set
# CONFIG_PREEMPTIRQ_DELAY_TEST is not set
# CONFIG_SYNTH_EVENT_GEN_TEST is not set
# CONFIG_KPROBE_EVENT_GEN_TEST is not set
# CONFIG_HIST_TRIGGERS_DEBUG is not set
# CONFIG_RV is not set
CONFIG_PROVIDE_OHCI1394_DMA_INIT=y
CONFIG_SAMPLES=y
# CONFIG_SAMPLE_AUXDISPLAY is not set
# CONFIG_SAMPLE_TRACE_EVENTS is not set
# CONFIG_SAMPLE_TRACE_CUSTOM_EVENTS is not set
# CONFIG_SAMPLE_TRACE_PRINTK is not set
# CONFIG_SAMPLE_FTRACE_DIRECT is not set
# CONFIG_SAMPLE_FTRACE_DIRECT_MULTI is not set
# CONFIG_SAMPLE_TRACE_ARRAY is not set
# CONFIG_SAMPLE_KOBJECT is not set
# CONFIG_SAMPLE_KPROBES is not set
# CONFIG_SAMPLE_HW_BREAKPOINT is not set
# CONFIG_SAMPLE_KFIFO is not set
# CONFIG_SAMPLE_LIVEPATCH is not set
# CONFIG_SAMPLE_CONFIGFS is not set
# CONFIG_SAMPLE_VFIO_MDEV_MTTY is not set
# CONFIG_SAMPLE_VFIO_MDEV_MDPY is not set
# CONFIG_SAMPLE_VFIO_MDEV_MDPY_FB is not set
# CONFIG_SAMPLE_VFIO_MDEV_MBOCHS is not set
# CONFIG_SAMPLE_WATCHDOG is not set
CONFIG_SAMPLES_RUST=y
CONFIG_SAMPLE_RUST_MINIMAL=y
CONFIG_SAMPLE_RUST_HOSTPROGS=y
CONFIG_HAVE_SAMPLE_FTRACE_DIRECT=y
CONFIG_HAVE_SAMPLE_FTRACE_DIRECT_MULTI=y
CONFIG_ARCH_HAS_DEVMEM_IS_ALLOWED=y
CONFIG_STRICT_DEVMEM=y
# CONFIG_IO_STRICT_DEVMEM is not set

#
# x86 Debugging
#
CONFIG_EARLY_PRINTK_USB=y
CONFIG_X86_VERBOSE_BOOTUP=y
CONFIG_EARLY_PRINTK=y
CONFIG_EARLY_PRINTK_DBGP=y
CONFIG_EARLY_PRINTK_USB_XDBC=y
# CONFIG_EFI_PGT_DUMP is not set
# CONFIG_DEBUG_TLBFLUSH is not set
CONFIG_HAVE_MMIOTRACE_SUPPORT=y
# CONFIG_X86_DECODER_SELFTEST is not set
CONFIG_IO_DELAY_0X80=y
# CONFIG_IO_DELAY_0XED is not set
# CONFIG_IO_DELAY_UDELAY is not set
# CONFIG_IO_DELAY_NONE is not set
CONFIG_DEBUG_BOOT_PARAMS=y
# CONFIG_CPA_DEBUG is not set
# CONFIG_DEBUG_ENTRY is not set
# CONFIG_DEBUG_NMI_SELFTEST is not set
# CONFIG_X86_DEBUG_FPU is not set
# CONFIG_PUNIT_ATOM_DEBUG is not set
CONFIG_UNWINDER_ORC=y
# CONFIG_UNWINDER_FRAME_POINTER is not set
# end of x86 Debugging

#
# Kernel Testing and Coverage
#
# CONFIG_KUNIT is not set
# CONFIG_NOTIFIER_ERROR_INJECTION is not set
CONFIG_FUNCTION_ERROR_INJECTION=y
# CONFIG_FAULT_INJECTION is not set
CONFIG_ARCH_HAS_KCOV=y
CONFIG_CC_HAS_SANCOV_TRACE_PC=y
# CONFIG_KCOV is not set
CONFIG_RUNTIME_TESTING_MENU=y
# CONFIG_LKDTM is not set
# CONFIG_TEST_MIN_HEAP is not set
# CONFIG_TEST_DIV64 is not set
# CONFIG_BACKTRACE_SELF_TEST is not set
# CONFIG_TEST_REF_TRACKER is not set
# CONFIG_RBTREE_TEST is not set
# CONFIG_REED_SOLOMON_TEST is not set
# CONFIG_INTERVAL_TREE_TEST is not set
# CONFIG_PERCPU_TEST is not set
# CONFIG_ATOMIC64_SELFTEST is not set
# CONFIG_ASYNC_RAID6_TEST is not set
# CONFIG_TEST_HEXDUMP is not set
# CONFIG_STRING_SELFTEST is not set
# CONFIG_TEST_STRING_HELPERS is not set
# CONFIG_TEST_STRSCPY is not set
# CONFIG_TEST_KSTRTOX is not set
# CONFIG_TEST_PRINTF is not set
# CONFIG_TEST_SCANF is not set
# CONFIG_TEST_BITMAP is not set
# CONFIG_TEST_UUID is not set
# CONFIG_TEST_XARRAY is not set
# CONFIG_TEST_RHASHTABLE is not set
# CONFIG_TEST_SIPHASH is not set
# CONFIG_TEST_IDA is not set
# CONFIG_TEST_LKM is not set
# CONFIG_TEST_BITOPS is not set
# CONFIG_TEST_VMALLOC is not set
# CONFIG_TEST_USER_COPY is not set
# CONFIG_TEST_BPF is not set
# CONFIG_TEST_BLACKHOLE_DEV is not set
# CONFIG_FIND_BIT_BENCHMARK is not set
# CONFIG_TEST_FIRMWARE is not set
# CONFIG_TEST_SYSCTL is not set
# CONFIG_TEST_UDELAY is not set
# CONFIG_TEST_STATIC_KEYS is not set
# CONFIG_TEST_KMOD is not set
# CONFIG_TEST_MEMCAT_P is not set
# CONFIG_TEST_LIVEPATCH is not set
# CONFIG_TEST_MEMINIT is not set
# CONFIG_TEST_HMM is not set
# CONFIG_TEST_FREE_PAGES is not set
# CONFIG_TEST_FPU is not set
# CONFIG_TEST_CLOCKSOURCE_WATCHDOG is not set
CONFIG_ARCH_USE_MEMTEST=y
# CONFIG_MEMTEST is not set
# end of Kernel Testing and Coverage

#
# Rust hacking
#
# CONFIG_RUST_DEBUG_ASSERTIONS is not set
CONFIG_RUST_OVERFLOW_CHECKS=y
# end of Rust hacking
# end of Kernel hacking

^ permalink raw reply	[relevance 1%]

* [PULL] Networking for v6.2-rc1
@ 2022-12-20 20:30  3% Jakub Kicinski
  0 siblings, 0 replies; 77+ results
From: Jakub Kicinski @ 2022-12-20 20:30 UTC (permalink / raw)
  To: torvalds; +Cc: kuba, davem, netdev, linux-kernel, pabeni

Hi Linus!

Traffic is winding down significantly so let us pass our fixes to you
earlier than the usual Thu schedule.

We have a fix for the BPF issue we were looking at before 6.1 final,
no surprises there. RxRPC fixes were merged relatively late so there's
an outpour of follow ups. Last one worth mentioning is the tree-wide
fix for network file systems / in-tree socket users, to prevent nested
networking calls from corrupting socket memory allocator.

Happy holidays (and unless something urgent happens) - till next year!


The following changes since commit 7e68dd7d07a28faa2e6574dd6b9dbd90cdeaae91:

  Merge tag 'net-next-6.2' of git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net-next (2022-12-13 15:47:48 -0800)

are available in the Git repository at:

  git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net.git tags/net-6.2-rc1

for you to fetch changes up to 19e72b064fc32cd58f6fc0b1eb64ac2e4f770e76:

  net: fec: check the return value of build_skb() (2022-12-20 11:33:24 -0800)

----------------------------------------------------------------
Including fixes from bpf, netfilter and can.

Current release - regressions:

 - bpf: synchronize dispatcher update with bpf_dispatcher_xdp_func

 - rxrpc:
  - fix security setting propagation
  - fix null-deref in rxrpc_unuse_local()
  - fix switched parameters in peer tracing

Current release - new code bugs:

 - rxrpc:
   - fix I/O thread startup getting skipped
   - fix locking issues in rxrpc_put_peer_locked()
   - fix I/O thread stop
   - fix uninitialised variable in rxperf server
   - fix the return value of rxrpc_new_incoming_call()

 - microchip: vcap: fix initialization of value and mask

 - nfp: fix unaligned io read of capabilities word

Previous releases - regressions:

 - stop in-kernel socket users from corrupting socket's task_frag

 - stream: purge sk_error_queue in sk_stream_kill_queues()

 - openvswitch: fix flow lookup to use unmasked key

 - dsa: mv88e6xxx: avoid reg_lock deadlock in mv88e6xxx_setup_port()

 - devlink:
   - hold region lock when flushing snapshots
   - protect devlink dump by the instance lock

Previous releases - always broken:

 - bpf:
   - prevent leak of lsm program after failed attach
   - resolve fext program type when checking map compatibility

 - skbuff: account for tail adjustment during pull operations

 - macsec: fix net device access prior to holding a lock

 - bonding: switch back when high prio link up

 - netfilter: flowtable: really fix NAT IPv6 offload

 - enetc: avoid buffer leaks on xdp_do_redirect() failure

 - unix: fix race in SOCK_SEQPACKET's unix_dgram_sendmsg()

 - dsa: microchip: remove IRQF_TRIGGER_FALLING in request_threaded_irq

Signed-off-by: Jakub Kicinski <kuba@kernel.org>

----------------------------------------------------------------
Arnd Bergmann (1):
      net: ethernet: ti: am65-cpsw: fix CONFIG_PM #ifdef

Arun Ramadoss (1):
      net: dsa: microchip: remove IRQF_TRIGGER_FALLING in request_threaded_irq

Benjamin Coddington (2):
      Treewide: Stop corrupting socket's task_frag
      net: simplify sk_page_frag

Biju Das (1):
      ravb: Fix "failed to switch device to config mode" message during unbind

Christophe JAILLET (1):
      myri10ge: Fix an error handling path in myri10ge_probe()

Cong Wang (1):
      net_sched: reject TCF_EM_SIMPLE case for complex ematch module

Daniel Golle (1):
      net: dsa: mt7530: remove redundant assignment

David Howells (9):
      rxrpc: Fix missing unlock in rxrpc_do_sendmsg()
      rxrpc: Fix security setting propagation
      rxrpc: Fix NULL deref in rxrpc_unuse_local()
      rxrpc: Fix I/O thread startup getting skipped
      rxrpc: Fix locking issues in rxrpc_put_peer_locked()
      rxrpc: Fix switched parameters in peer tracing
      rxrpc: Fix I/O thread stop
      rxrpc: rxperf: Fix uninitialised variable
      rxrpc: Fix the return value of rxrpc_new_incoming_call()

David S. Miller (3):
      Merge branch 'devlink-fixes'
      Merge branch '1GbE' of git://git.kernel.org/pub/scm/linux/kernel/git/tnguy/net-queue
      Merge branch 'rxrpc-fixes'

Donald Hunter (1):
      docs/bpf: Reword docs for BPF_MAP_TYPE_SK_STORAGE

Eelco Chaudron (1):
      openvswitch: Fix flow lookup to use unmasked key

Emeel Hakim (1):
      net: macsec: fix net device access prior to holding a lock

Eric Dumazet (1):
      net: stream: purge sk_error_queue in sk_stream_kill_queues()

Gaosheng Cui (1):
      net: stmmac: fix errno when create_singlethread_workqueue() fails

Guillaume Nault (1):
      net: Introduce sk_use_task_frag in struct sock.

Haibo Chen (1):
      can: flexcan: avoid unbalanced pm_runtime_enable warning

Hangbin Liu (2):
      bonding: add missed __rcu annotation for curr_active_slave
      bonding: do failover when high prio link up

Horatiu Vultur (1):
      net: microchip: vcap: Fix initialization of value and mask

Huanhuan Wang (1):
      nfp: fix unaligned io read of capabilities word

Jakub Kicinski (10):
      Merge branch 'bonding-fix-high-prio-not-effect-issue'
      Merge branch 'misdn-don-t-call-dev_kfree_skb-kfree_skb-under-spin_lock_irqsave'
      Merge git://git.kernel.org/pub/scm/linux/kernel/git/netfilter/nf
      devlink: hold region lock when flushing snapshots
      selftests: devlink: fix the fd redirect in dummy_reporter_test
      selftests: devlink: add a warning for interfaces coming up
      Merge tag 'for-netdev' of https://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf
      devlink: protect devlink dump by the instance lock
      Merge branch 'stop-corrupting-socket-s-task_frag'
      Merge tag 'linux-can-fixes-for-6.2-20221219' of git://git.kernel.org/pub/scm/linux/kernel/git/mkl/linux-can

Jeremy Kerr (1):
      mctp: serial: Fix starting value for frame check sequence

Jiri Olsa (1):
      bpf: Synchronize dispatcher update with bpf_dispatcher_xdp_func

Jiri Slaby (SUSE) (1):
      wireguard: timers: cast enum limits members to int in prints

Kirill Tkhai (1):
      unix: Fix race in SOCK_SEQPACKET's unix_dgram_sendmsg()

Li Qiong (1):
      ipvs: add a 'default' case in do_ip_vs_set_ctl()

Li Zetao (1):
      r6040: Fix kmemleak in probe and remove

Liang Li (1):
      selftests: bonding: add bonding prio option test

Marc Kleine-Budde (1):
      can: kvaser_usb: hydra: help gcc-13 to figure out cmd_len

Matt Johnston (1):
      mctp: Remove device type check at unregister

Milan Landaverde (1):
      bpf: prevent leak of lsm program after failed attach

Minsuk Kang (1):
      nfc: pn533: Clear nfc_target before being used

Muhammad Husaini Zulkifli (1):
      igc: Add checking for basetime less than zero

Qingfang DENG (1):
      netfilter: flowtable: really fix NAT IPv6 offload

Song Liu (1):
      selftests/bpf: Select CONFIG_FUNCTION_ERROR_INJECTION

Sriram Yagnaraman (1):
      netfilter: conntrack: document sctp timeouts

Subash Abhinov Kasiviswanathan (1):
      skbuff: Account for tail adjustment during pull operations

Tan Tee Min (3):
      igc: allow BaseTime 0 enrollment for Qbv
      igc: recalculate Qbv end_time by considering cycle time
      igc: Set Qbv start_time and end_time to end_time if not being configured in GCL

Toke Høiland-Jørgensen (2):
      bpf: Resolve fext program type when checking map compatibility
      selftests/bpf: Add a test for using a cpumap from an freplace-to-XDP program

Tony Nguyen (1):
      igb: Initialize mailbox message for VF reset

Vincent Mailhol (1):
      Documentation: devlink: add missing toc entry for etas_es58x devlink doc

Vinicius Costa Gomes (2):
      igc: Enhance Qbv scheduling by using first flag bit
      igc: Use strict cycles for Qbv scheduling

Vladimir Oltean (2):
      net: enetc: avoid buffer leaks on xdp_do_redirect() failure
      net: dsa: mv88e6xxx: avoid reg_lock deadlock in mv88e6xxx_setup_port()

Wei Fang (1):
      net: fec: check the return value of build_skb()

Yang Yingliang (3):
      mISDN: hfcsusb: don't call dev_kfree_skb/kfree_skb() under spin_lock_irqsave()
      mISDN: hfcpci: don't call dev_kfree_skb/kfree_skb() under spin_lock_irqsave()
      mISDN: hfcmulti: don't call dev_kfree_skb/kfree_skb() under spin_lock_irqsave()

Yonghong Song (1):
      selftests/bpf: Fix a selftest compilation error with CONFIG_SMP=n

 Documentation/bpf/map_sk_storage.rst               |  56 ++---
 Documentation/networking/devlink/index.rst         |   1 +
 Documentation/networking/nf_conntrack-sysctl.rst   |  33 +++
 drivers/block/drbd/drbd_receiver.c                 |   3 +
 drivers/block/nbd.c                                |   1 +
 drivers/isdn/hardware/mISDN/hfcmulti.c             |  19 +-
 drivers/isdn/hardware/mISDN/hfcpci.c               |  13 +-
 drivers/isdn/hardware/mISDN/hfcsusb.c              |  12 +-
 drivers/net/bonding/bond_main.c                    |  24 +-
 drivers/net/can/flexcan/flexcan-core.c             |  12 +-
 drivers/net/can/usb/kvaser_usb/kvaser_usb_hydra.c  |  33 ++-
 drivers/net/dsa/microchip/ksz_common.c             |   3 +-
 drivers/net/dsa/mt7530.c                           |   3 -
 drivers/net/dsa/mv88e6xxx/chip.c                   |   9 +-
 drivers/net/ethernet/freescale/enetc/enetc.c       |  35 +--
 drivers/net/ethernet/freescale/fec_main.c          |   8 +
 drivers/net/ethernet/intel/igb/igb_main.c          |   2 +-
 drivers/net/ethernet/intel/igc/igc.h               |   3 +
 drivers/net/ethernet/intel/igc/igc_defines.h       |   2 +
 drivers/net/ethernet/intel/igc/igc_main.c          | 210 +++++++++++++++---
 drivers/net/ethernet/intel/igc/igc_tsn.c           |  13 +-
 .../net/ethernet/microchip/vcap/vcap_api_debugfs.c |   2 +
 drivers/net/ethernet/myricom/myri10ge/myri10ge.c   |   1 +
 .../net/ethernet/netronome/nfp/nfp_net_common.c    |   2 +-
 drivers/net/ethernet/rdc/r6040.c                   |   5 +-
 drivers/net/ethernet/renesas/ravb_main.c           |   2 +-
 drivers/net/ethernet/stmicro/stmmac/stmmac_main.c  |   1 +
 drivers/net/ethernet/ti/am65-cpsw-nuss.c           |   4 +-
 drivers/net/macsec.c                               |  34 +--
 drivers/net/mctp/mctp-serial.c                     |   6 +-
 drivers/net/wireguard/timers.c                     |   8 +-
 drivers/nfc/pn533/pn533.c                          |   4 +
 drivers/nvme/host/tcp.c                            |   1 +
 drivers/scsi/iscsi_tcp.c                           |   1 +
 drivers/usb/usbip/usbip_common.c                   |   1 +
 fs/cifs/connect.c                                  |   1 +
 fs/dlm/lowcomms.c                                  |   2 +
 fs/ocfs2/cluster/tcp.c                             |   1 +
 include/net/sock.h                                 |  10 +-
 include/trace/events/rxrpc.h                       |   2 +-
 kernel/bpf/core.c                                  |   5 +-
 kernel/bpf/dispatcher.c                            |   5 +
 kernel/bpf/syscall.c                               |   6 +-
 net/9p/trans_fd.c                                  |   1 +
 net/ceph/messenger.c                               |   1 +
 net/core/devlink.c                                 |   5 +
 net/core/skbuff.c                                  |   3 +
 net/core/sock.c                                    |   1 +
 net/core/stream.c                                  |   6 +
 net/mctp/device.c                                  |  14 +-
 net/netfilter/ipvs/ip_vs_ctl.c                     |   5 +
 net/netfilter/nf_flow_table_offload.c              |   6 +-
 net/openvswitch/datapath.c                         |  25 ++-
 net/rxrpc/ar-internal.h                            |   8 +-
 net/rxrpc/call_accept.c                            |  18 +-
 net/rxrpc/call_object.c                            |   1 +
 net/rxrpc/conn_client.c                            |   2 -
 net/rxrpc/io_thread.c                              |  10 +-
 net/rxrpc/local_object.c                           |   5 +-
 net/rxrpc/peer_event.c                             |  10 +-
 net/rxrpc/peer_object.c                            |  23 +-
 net/rxrpc/rxperf.c                                 |   2 +-
 net/rxrpc/security.c                               |   6 +-
 net/rxrpc/sendmsg.c                                |   2 +-
 net/sched/ematch.c                                 |   2 +
 net/sunrpc/xprtsock.c                              |   3 +
 net/unix/af_unix.c                                 |  11 +-
 net/xfrm/espintcp.c                                |   1 +
 tools/testing/selftests/bpf/config                 |   1 +
 .../selftests/bpf/prog_tests/fexit_bpf2bpf.c       |  48 ++++
 .../testing/selftests/bpf/progs/freplace_progmap.c |  24 ++
 tools/testing/selftests/bpf/progs/rcu_read_lock.c  |   8 +-
 .../selftests/bpf/progs/task_kfunc_failure.c       |   2 +-
 .../testing/selftests/drivers/net/bonding/Makefile |   3 +-
 .../selftests/drivers/net/bonding/option_prio.sh   | 245 +++++++++++++++++++++
 .../selftests/drivers/net/netdevsim/devlink.sh     |   4 +-
 .../drivers/net/netdevsim/devlink_trap.sh          |  13 ++
 77 files changed, 861 insertions(+), 257 deletions(-)
 create mode 100644 tools/testing/selftests/bpf/progs/freplace_progmap.c
 create mode 100755 tools/testing/selftests/drivers/net/bonding/option_prio.sh

^ permalink raw reply	[relevance 3%]

* vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvMs_NtCsfATHBUcknU9_6kernel3strNtB4_4CStr19from_bytes_with_nul+0x0: data relocation to !ENDBR: _RNvMs_NtCsfATHBUcknU9_6kernel3strNtB4_4CStr19from_bytes_with_nul+0x0
@ 2022-12-21 13:27  1% kernel test robot
  0 siblings, 0 replies; 77+ results
From: kernel test robot @ 2022-12-21 13:27 UTC (permalink / raw)
  Cc: oe-kbuild-all, llvm

[-- Attachment #1: Type: text/plain, Size: 34768 bytes --]

CC: linux-kernel@vger.kernel.org
TO: Gary Guo <gary@garyguo.net>
CC: Miguel Ojeda <ojeda@kernel.org>
CC: Alex Gaynor <alex.gaynor@gmail.com>
CC: Milan Landaverde <milan@mdaverde.com>

tree:   https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git master
head:   b6bb9676f2165d518b35ba3bea5f1fcfc0d969bf
commit: d126d2380131dfbc880f5b5f0e3015e9bef6fa1c rust: str: add `CStr` type
date:   3 weeks ago
config: x86_64-rhel-8.3-rust
compiler: clang version 14.0.6 (https://github.com/llvm/llvm-project f28c006a5895fc0e329fe15fead81e37457cb1d1)
reproduce (this is a W=1 build):
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=d126d2380131dfbc880f5b5f0e3015e9bef6fa1c
        git remote add linus https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
        git fetch --no-tags linus master
        git checkout d126d2380131dfbc880f5b5f0e3015e9bef6fa1c
        # save the config file
        mkdir build_dir && cp config build_dir/.config
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross W=1 O=build_dir ARCH=x86_64 olddefconfig
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross W=1 O=build_dir ARCH=x86_64 SHELL=/bin/bash

If you fix the issue, kindly add following tag where applicable
| Reported-by: kernel test robot <lkp@intel.com>

All warnings (new ones prefixed by >>):

   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvXs3c_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB6_5folioNtNtCs3yuwAp0waWO_4core7default7Default7default+0x0: data relocation to !ENDBR: _RNvXs3c_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB6_5folioNtNtCs3yuwAp0waWO_4core7default7Default7default+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvXs3d_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB6_15page_frag_cacheNtNtCs3yuwAp0waWO_4core7default7Default7default+0x0: data relocation to !ENDBR: _RNvXs3d_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB6_15page_frag_cacheNtNtCs3yuwAp0waWO_4core7default7Default7default+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvXs3e_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB6_9vm_regionNtNtCs3yuwAp0waWO_4core7default7Default7default+0x0: data relocation to !ENDBR: _RNvXs3e_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB6_9vm_regionNtNtCs3yuwAp0waWO_4core7default7Default7default+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvXs3g_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB6_42vm_area_struct__bindgen_ty_1__bindgen_ty_1NtNtCs3yuwAp0waWO_4core7default7Default7default+0x0: data relocation to !ENDBR: _RNvXs3g_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB6_42vm_area_struct__bindgen_ty_1__bindgen_ty_1NtNtCs3yuwAp0waWO_4core7default7Default7default+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvXs3h_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB6_28vm_area_struct__bindgen_ty_1NtNtCs3yuwAp0waWO_4core7default7Default7default+0x0: data relocation to !ENDBR: _RNvXs3h_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB6_28vm_area_struct__bindgen_ty_1NtNtCs3yuwAp0waWO_4core7default7Default7default+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvXs3i_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB6_14vm_area_structNtNtCs3yuwAp0waWO_4core7default7Default7default+0x0: data relocation to !ENDBR: _RNvXs3i_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB6_14vm_area_structNtNtCs3yuwAp0waWO_4core7default7Default7default+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvXs3j_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB6_23mm_struct__bindgen_ty_1NtNtCs3yuwAp0waWO_4core7default7Default7default+0x0: data relocation to !ENDBR: _RNvXs3j_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB6_23mm_struct__bindgen_ty_1NtNtCs3yuwAp0waWO_4core7default7Default7default+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvXs3k_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB6_9mm_structNtNtCs3yuwAp0waWO_4core7default7Default7default+0x0: data relocation to !ENDBR: _RNvXs3k_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB6_9mm_structNtNtCs3yuwAp0waWO_4core7default7Default7default+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvXs3l_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB6_12vma_iteratorNtNtCs3yuwAp0waWO_4core7default7Default7default+0x0: data relocation to !ENDBR: _RNvXs3l_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB6_12vma_iteratorNtNtCs3yuwAp0waWO_4core7default7Default7default+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvXs3n_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB6_9free_areaNtNtCs3yuwAp0waWO_4core7default7Default7default+0x0: data relocation to !ENDBR: _RNvXs3n_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB6_9free_areaNtNtCs3yuwAp0waWO_4core7default7Default7default+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvXs3o_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB6_6lruvecNtNtCs3yuwAp0waWO_4core7default7Default7default+0x0: data relocation to !ENDBR: _RNvXs3o_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB6_6lruvecNtNtCs3yuwAp0waWO_4core7default7Default7default+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvXs3p_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB6_13per_cpu_pagesNtNtCs3yuwAp0waWO_4core7default7Default7default+0x0: data relocation to !ENDBR: _RNvXs3p_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB6_13per_cpu_pagesNtNtCs3yuwAp0waWO_4core7default7Default7default+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvXs3q_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB6_16per_cpu_nodestatNtNtCs3yuwAp0waWO_4core7default7Default7default+0x0: data relocation to !ENDBR: _RNvXs3q_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB6_16per_cpu_nodestatNtNtCs3yuwAp0waWO_4core7default7Default7default+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvXs3r_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB6_4zoneNtNtCs3yuwAp0waWO_4core7default7Default7default+0x0: data relocation to !ENDBR: _RNvXs3r_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB6_4zoneNtNtCs3yuwAp0waWO_4core7default7Default7default+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvXs3t_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB6_8zonelistNtNtCs3yuwAp0waWO_4core7default7Default7default+0x0: data relocation to !ENDBR: _RNvXs3t_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB6_8zonelistNtNtCs3yuwAp0waWO_4core7default7Default7default+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvXs3u_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB6_14deferred_splitNtNtCs3yuwAp0waWO_4core7default7Default7default+0x0: data relocation to !ENDBR: _RNvXs3u_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB6_14deferred_splitNtNtCs3yuwAp0waWO_4core7default7Default7default+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvXs3v_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB6_11pglist_dataNtNtCs3yuwAp0waWO_4core7default7Default7default+0x0: data relocation to !ENDBR: _RNvXs3v_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB6_11pglist_dataNtNtCs3yuwAp0waWO_4core7default7Default7default+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvXs3w_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB6_10mhp_paramsNtNtCs3yuwAp0waWO_4core7default7Default7default+0x0: data relocation to !ENDBR: _RNvXs3w_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB6_10mhp_paramsNtNtCs3yuwAp0waWO_4core7default7Default7default+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvXs3z_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB6_12cpu_topologyNtNtCs3yuwAp0waWO_4core7default7Default7default+0x0: data relocation to !ENDBR: _RNvXs3z_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB6_12cpu_topologyNtNtCs3yuwAp0waWO_4core7default7Default7default+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvXs3A_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB6_19x86_legacy_featuresNtNtCs3yuwAp0waWO_4core7default7Default7default+0x0: data relocation to !ENDBR: _RNvXs3A_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB6_19x86_legacy_featuresNtNtCs3yuwAp0waWO_4core7default7Default7default+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvXs3B_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB6_16x86_platform_opsNtNtCs3yuwAp0waWO_4core7default7Default7default+0x0: data relocation to !ENDBR: _RNvXs3B_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB6_16x86_platform_opsNtNtCs3yuwAp0waWO_4core7default7Default7default+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvXs3L_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB6_25local_apic__bindgen_ty_20NtNtCs3yuwAp0waWO_4core7default7Default7default+0x0: data relocation to !ENDBR: _RNvXs3L_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB6_25local_apic__bindgen_ty_20NtNtCs3yuwAp0waWO_4core7default7Default7default+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvXs3P_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB6_25local_apic__bindgen_ty_29NtNtCs3yuwAp0waWO_4core7default7Default7default+0x0: data relocation to !ENDBR: _RNvXs3P_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB6_25local_apic__bindgen_ty_29NtNtCs3yuwAp0waWO_4core7default7Default7default+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvXs3Y_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB6_11physid_maskNtNtCs3yuwAp0waWO_4core7default7Default7default+0x0: data relocation to !ENDBR: _RNvXs3Y_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB6_11physid_maskNtNtCs3yuwAp0waWO_4core7default7Default7default+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvXs3Z_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB6_15percpu_ref_dataNtNtCs3yuwAp0waWO_4core7default7Default7default+0x0: data relocation to !ENDBR: _RNvXs3Z_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB6_15percpu_ref_dataNtNtCs3yuwAp0waWO_4core7default7Default7default+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvXs42_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB6_13___va_list_tagNtNtCs3yuwAp0waWO_4core7default7Default7default+0x0: data relocation to !ENDBR: _RNvXs42_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB6_13___va_list_tagNtNtCs3yuwAp0waWO_4core7default7Default7default+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvXs1q_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB6_30mpx_bndcsr_state__bindgen_ty_1NtNtCs3yuwAp0waWO_4core7default7Default7default+0x0: data relocation to !ENDBR: _RNvXs1o_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB6_11reg_512_bitNtNtCs3yuwAp0waWO_4core7default7Default7default+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvXsI_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB5_31edd_device_params__bindgen_ty_2NtNtCs3yuwAp0waWO_4core7default7Default7default+0x0: data relocation to !ENDBR: _RNvXs2N_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB6_25arch_uprobe__bindgen_ty_1NtNtCs3yuwAp0waWO_4core7default7Default7default+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvXs3X_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB6_10local_apicNtNtCs3yuwAp0waWO_4core7default7Default7default+0x0: data relocation to !ENDBR: _RNvXs1p_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB6_13reg_1024_byteNtNtCs3yuwAp0waWO_4core7default7Default7default+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvXsf_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB5_10hlist_nodeNtNtCs3yuwAp0waWO_4core7default7Default7default+0x0: data relocation to !ENDBR: _RNvXs10_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB6_13math_emu_infoNtNtCs3yuwAp0waWO_4core7default7Default7default+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvXsg_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB5_13callback_headNtNtCs3yuwAp0waWO_4core7default7Default7default+0x0: data relocation to !ENDBR: _RNvXs10_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB6_13math_emu_infoNtNtCs3yuwAp0waWO_4core7default7Default7default+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvXsi_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB5_9qspinlockNtNtCs3yuwAp0waWO_4core7default7Default7default+0x0: data relocation to !ENDBR: _RNvXs1P_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB6_32___call_single_node__bindgen_ty_1NtNtCs3yuwAp0waWO_4core7default7Default7default+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvXsj_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB5_21qrwlock__bindgen_ty_1NtNtCs3yuwAp0waWO_4core7default7Default7default+0x0: data relocation to !ENDBR: _RNvXs1P_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB6_32___call_single_node__bindgen_ty_1NtNtCs3yuwAp0waWO_4core7default7Default7default+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvXsk_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB5_7qrwlockNtNtCs3yuwAp0waWO_4core7default7Default7default+0x0: data relocation to !ENDBR: _RNvXs19_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB6_17msr__bindgen_ty_1NtNtCs3yuwAp0waWO_4core7default7Default7default+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvXsl_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB5_12raw_spinlockNtNtCs3yuwAp0waWO_4core7default7Default7default+0x0: data relocation to !ENDBR: _RNvXs1P_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB6_32___call_single_node__bindgen_ty_1NtNtCs3yuwAp0waWO_4core7default7Default7default+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvXsn_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB5_9va_formatNtNtCs3yuwAp0waWO_4core7default7Default7default+0x0: data relocation to !ENDBR: _RNvXs10_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB6_13math_emu_infoNtNtCs3yuwAp0waWO_4core7default7Default7default+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvXso_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB5_24static_key__bindgen_ty_1NtNtCs3yuwAp0waWO_4core7default7Default7default+0x0: data relocation to !ENDBR: _RNvXs19_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB6_17msr__bindgen_ty_1NtNtCs3yuwAp0waWO_4core7default7Default7default+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvXsx_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB5_32ddebug_class_param__bindgen_ty_1NtNtCs3yuwAp0waWO_4core7default7Default7default+0x0: data relocation to !ENDBR: _RNvXs19_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB6_17msr__bindgen_ty_1NtNtCs3yuwAp0waWO_4core7default7Default7default+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvXsz_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB5_29static_call_key__bindgen_ty_1NtNtCs3yuwAp0waWO_4core7default7Default7default+0x0: data relocation to !ENDBR: _RNvXs19_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB6_17msr__bindgen_ty_1NtNtCs3yuwAp0waWO_4core7default7Default7default+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvXse_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB5_10hlist_headNtNtCs3yuwAp0waWO_4core7default7Default7default+0x0: data relocation to !ENDBR: _RNvXs19_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB6_17msr__bindgen_ty_1NtNtCs3yuwAp0waWO_4core7default7Default7default+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvXsH_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB5_31edd_device_params__bindgen_ty_1NtNtCs3yuwAp0waWO_4core7default7Default7default+0x0: data relocation to !ENDBR: _RNvXs19_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB6_17msr__bindgen_ty_1NtNtCs3yuwAp0waWO_4core7default7Default7default+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvXsU_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB5_20paravirt_callee_saveNtNtCs3yuwAp0waWO_4core7default7Default7default+0x0: data relocation to !ENDBR: _RNvXs19_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB6_17msr__bindgen_ty_1NtNtCs3yuwAp0waWO_4core7default7Default7default+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvXsV_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB5_7pv_infoNtNtCs3yuwAp0waWO_4core7default7Default7default+0x0: data relocation to !ENDBR: _RNvXs19_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB6_17msr__bindgen_ty_1NtNtCs3yuwAp0waWO_4core7default7Default7default+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvXsd_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB5_9list_headNtNtCs3yuwAp0waWO_4core7default7Default7default+0x0: data relocation to !ENDBR: _RNvXs10_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB6_13math_emu_infoNtNtCs3yuwAp0waWO_4core7default7Default7default+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvXsC_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB5_55restart_block__bindgen_ty_1__bindgen_ty_2__bindgen_ty_1NtNtCs3yuwAp0waWO_4core7default7Default7default+0x0: data relocation to !ENDBR: _RNvXs19_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB6_17msr__bindgen_ty_1NtNtCs3yuwAp0waWO_4core7default7Default7default+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvXs1a_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB6_3msrNtNtCs3yuwAp0waWO_4core7default7Default7default+0x0: data relocation to !ENDBR: _RNvXs19_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB6_17msr__bindgen_ty_1NtNtCs3yuwAp0waWO_4core7default7Default7default+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvXs1f_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB6_17trace_print_flagsNtNtCs3yuwAp0waWO_4core7default7Default7default+0x0: data relocation to !ENDBR: _RNvXs10_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB6_13math_emu_infoNtNtCs3yuwAp0waWO_4core7default7Default7default+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvXs1g_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB6_21trace_print_flags_u64NtNtCs3yuwAp0waWO_4core7default7Default7default+0x0: data relocation to !ENDBR: _RNvXs10_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB6_13math_emu_infoNtNtCs3yuwAp0waWO_4core7default7Default7default+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvXs1N_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB6_10llist_headNtNtCs3yuwAp0waWO_4core7default7Default7default+0x0: data relocation to !ENDBR: _RNvXs19_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB6_17msr__bindgen_ty_1NtNtCs3yuwAp0waWO_4core7default7Default7default+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvXs1O_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB6_10llist_nodeNtNtCs3yuwAp0waWO_4core7default7Default7default+0x0: data relocation to !ENDBR: _RNvXs19_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB6_17msr__bindgen_ty_1NtNtCs3yuwAp0waWO_4core7default7Default7default+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvXsh_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB5_23qspinlock__bindgen_ty_1NtNtCs3yuwAp0waWO_4core7default7Default7default+0x0: data relocation to !ENDBR: _RNvXs1P_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB6_32___call_single_node__bindgen_ty_1NtNtCs3yuwAp0waWO_4core7default7Default7default+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvXs1S_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB6_22spinlock__bindgen_ty_1NtNtCs3yuwAp0waWO_4core7default7Default7default+0x0: data relocation to !ENDBR: _RNvXs1P_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB6_32___call_single_node__bindgen_ty_1NtNtCs3yuwAp0waWO_4core7default7Default7default+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvXs1T_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB6_8rwlock_tNtNtCs3yuwAp0waWO_4core7default7Default7default+0x0: data relocation to !ENDBR: _RNvXs19_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB6_17msr__bindgen_ty_1NtNtCs3yuwAp0waWO_4core7default7Default7default+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvXs24_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB6_7rb_rootNtNtCs3yuwAp0waWO_4core7default7Default7default+0x0: data relocation to !ENDBR: _RNvXs19_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB6_17msr__bindgen_ty_1NtNtCs3yuwAp0waWO_4core7default7Default7default+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvXs2b_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB6_13maple_topiaryNtNtCs3yuwAp0waWO_4core7default7Default7default+0x0: data relocation to !ENDBR: _RNvXs10_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB6_13math_emu_infoNtNtCs3yuwAp0waWO_4core7default7Default7default+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvXs2c_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB6_24maple_tree__bindgen_ty_1NtNtCs3yuwAp0waWO_4core7default7Default7default+0x0: data relocation to !ENDBR: _RNvXs1P_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB6_32___call_single_node__bindgen_ty_1NtNtCs3yuwAp0waWO_4core7default7Default7default+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvXs2u_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB6_19system_counterval_tNtNtCs3yuwAp0waWO_4core7default7Default7default+0x0: data relocation to !ENDBR: _RNvXs10_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB6_13math_emu_infoNtNtCs3yuwAp0waWO_4core7default7Default7default+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvXs2L_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB6_17raw_notifier_headNtNtCs3yuwAp0waWO_4core7default7Default7default+0x0: data relocation to !ENDBR: _RNvXs19_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB6_17msr__bindgen_ty_1NtNtCs3yuwAp0waWO_4core7default7Default7default+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvXs2O_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB6_25arch_uprobe__bindgen_ty_2NtNtCs3yuwAp0waWO_4core7default7Default7default+0x0: data relocation to !ENDBR: _RNvXs19_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB6_17msr__bindgen_ty_1NtNtCs3yuwAp0waWO_4core7default7Default7default+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvXs2U_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB6_13uprobes_stateNtNtCs3yuwAp0waWO_4core7default7Default7default+0x0: data relocation to !ENDBR: _RNvXs19_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB6_17msr__bindgen_ty_1NtNtCs3yuwAp0waWO_4core7default7Default7default+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvXs2W_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB6_60page__bindgen_ty_1__bindgen_ty_1__bindgen_ty_1__bindgen_ty_1NtNtCs3yuwAp0waWO_4core7default7Default7default+0x0: data relocation to !ENDBR: _RNvXs1c_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB6_13msr_regs_infoNtNtCs3yuwAp0waWO_4core7default7Default7default+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvXs2Z_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB6_46page__bindgen_ty_1__bindgen_ty_2__bindgen_ty_1NtNtCs3yuwAp0waWO_4core7default7Default7default+0x0: data relocation to !ENDBR: _RNvXs19_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB6_17msr__bindgen_ty_1NtNtCs3yuwAp0waWO_4core7default7Default7default+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvXs32_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB6_46page__bindgen_ty_1__bindgen_ty_5__bindgen_ty_1NtNtCs3yuwAp0waWO_4core7default7Default7default+0x0: data relocation to !ENDBR: _RNvXs19_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB6_17msr__bindgen_ty_1NtNtCs3yuwAp0waWO_4core7default7Default7default+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvXs34_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB6_32page__bindgen_ty_1__bindgen_ty_6NtNtCs3yuwAp0waWO_4core7default7Default7default+0x0: data relocation to !ENDBR: _RNvXs10_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB6_13math_emu_infoNtNtCs3yuwAp0waWO_4core7default7Default7default+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvXs36_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB6_18page__bindgen_ty_2NtNtCs3yuwAp0waWO_4core7default7Default7default+0x0: data relocation to !ENDBR: _RNvXs1P_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB6_32___call_single_node__bindgen_ty_1NtNtCs3yuwAp0waWO_4core7default7Default7default+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvXs38_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB6_61folio__bindgen_ty_1__bindgen_ty_1__bindgen_ty_1__bindgen_ty_1NtNtCs3yuwAp0waWO_4core7default7Default7default+0x0: data relocation to !ENDBR: _RNvXs1c_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB6_13msr_regs_infoNtNtCs3yuwAp0waWO_4core7default7Default7default+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvXs3s_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB6_7zonerefNtNtCs3yuwAp0waWO_4core7default7Default7default+0x0: data relocation to !ENDBR: _RNvXs1c_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB6_13msr_regs_infoNtNtCs3yuwAp0waWO_4core7default7Default7default+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvXs3x_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB6_11mem_sectionNtNtCs3yuwAp0waWO_4core7default7Default7default+0x0: data relocation to !ENDBR: _RNvXs10_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB6_13math_emu_infoNtNtCs3yuwAp0waWO_4core7default7Default7default+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvXs3y_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB6_15scale_freq_dataNtNtCs3yuwAp0waWO_4core7default7Default7default+0x0: data relocation to !ENDBR: _RNvXs1e_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB6_10saved_msrsNtNtCs3yuwAp0waWO_4core7default7Default7default+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvXs3N_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB6_39local_apic__bindgen_ty_29__bindgen_ty_1NtNtCs3yuwAp0waWO_4core7default7Default7default+0x0: data relocation to !ENDBR: _RNvXs19_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB6_17msr__bindgen_ty_1NtNtCs3yuwAp0waWO_4core7default7Default7default+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvXs41_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB6_10percpu_refNtNtCs3yuwAp0waWO_4core7default7Default7default+0x0: data relocation to !ENDBR: _RNvXs10_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB6_13math_emu_infoNtNtCs3yuwAp0waWO_4core7default7Default7default+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvXsr_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB5_16static_key_falseNtNtCs3yuwAp0waWO_4core7default7Default7default+0x0: data relocation to !ENDBR: _RNvXsq_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB5_15static_key_trueNtNtCs3yuwAp0waWO_4core7default7Default7default+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvXss_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB5_21__ddebug__bindgen_ty_1NtNtCs3yuwAp0waWO_4core7default7Default7default+0x0: data relocation to !ENDBR: _RNvXs1k_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB6_26fxregs_state__bindgen_ty_1NtNtCs3yuwAp0waWO_4core7default7Default7default+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvXs14_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB6_25__fpstate_64__bindgen_ty_1NtNtCs3yuwAp0waWO_4core7default7Default7default+0x0: data relocation to !ENDBR: _RNvXs12_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB6_25__fpstate_32__bindgen_ty_2NtNtCs3yuwAp0waWO_4core7default7Default7default+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvXsa_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB5_32ftrace_branch_data__bindgen_ty_1NtNtCs3yuwAp0waWO_4core7default7Default7default+0x0: data relocation to !ENDBR: _RNvXs1k_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB6_26fxregs_state__bindgen_ty_1NtNtCs3yuwAp0waWO_4core7default7Default7default+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvXsw_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB5_12__ddebug_infoNtNtCs3yuwAp0waWO_4core7default7Default7default+0x0: data relocation to !ENDBR: _RNvXs1W_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB6_20optimistic_spin_nodeNtNtCs3yuwAp0waWO_4core7default7Default7default+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvXs2i_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB6_10ma_topiaryNtNtCs3yuwAp0waWO_4core7default7Default7default+0x0: data relocation to !ENDBR: _RNvXs23_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB6_7rb_nodeNtNtCs3yuwAp0waWO_4core7default7Default7default+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvXs2D_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB6_10rcu_cblistNtNtCs3yuwAp0waWO_4core7default7Default7default+0x0: data relocation to !ENDBR: _RNvXs23_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB6_7rb_nodeNtNtCs3yuwAp0waWO_4core7default7Default7default+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvXs2I_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB6_14notifier_blockNtNtCs3yuwAp0waWO_4core7default7Default7default+0x0: data relocation to !ENDBR: _RNvXs1h_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB6_15tracepoint_funcNtNtCs3yuwAp0waWO_4core7default7Default7default+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvXs2Q_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB6_39uprobe_task__bindgen_ty_1__bindgen_ty_2NtNtCs3yuwAp0waWO_4core7default7Default7default+0x0: data relocation to !ENDBR: _RNvXs1M_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB6_16preempt_notifierNtNtCs3yuwAp0waWO_4core7default7Default7default+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvXs2X_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB6_46page__bindgen_ty_1__bindgen_ty_1__bindgen_ty_1NtNtCs3yuwAp0waWO_4core7default7Default7default+0x0: data relocation to !ENDBR: _RNvXs1k_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB6_26fxregs_state__bindgen_ty_1NtNtCs3yuwAp0waWO_4core7default7Default7default+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvXsF_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB5_27restart_block__bindgen_ty_1NtNtCs3yuwAp0waWO_4core7default7Default7default+0x0: data relocation to !ENDBR: _RNvXs35_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB6_18page__bindgen_ty_1NtNtCs3yuwAp0waWO_4core7default7Default7default+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvXs39_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB6_47folio__bindgen_ty_1__bindgen_ty_1__bindgen_ty_1NtNtCs3yuwAp0waWO_4core7default7Default7default+0x0: data relocation to !ENDBR: _RNvXs1k_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB6_26fxregs_state__bindgen_ty_1NtNtCs3yuwAp0waWO_4core7default7Default7default+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvXs3m_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB6_18vm_special_mappingNtNtCs3yuwAp0waWO_4core7default7Default7default+0x0: data relocation to !ENDBR: _RNvXs2p_NtCs3XUU1alqrUZ_8bindings12bindings_rawNtB6_15uprobe_consumerNtNtCs3yuwAp0waWO_4core7default7Default7default+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvXNtCsfATHBUcknU9_6kernel9allocatorNtB2_15KernelAllocatorNtNtNtCs3yuwAp0waWO_4core5alloc6global11GlobalAlloc5alloc+0x0: data relocation to !ENDBR: _RNvXNtCsfATHBUcknU9_6kernel9allocatorNtB2_15KernelAllocatorNtNtNtCs3yuwAp0waWO_4core5alloc6global11GlobalAlloc5alloc+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvXNtCsfATHBUcknU9_6kernel9allocatorNtB2_15KernelAllocatorNtNtNtCs3yuwAp0waWO_4core5alloc6global11GlobalAlloc7dealloc+0x0: data relocation to !ENDBR: _RNvXNtCsfATHBUcknU9_6kernel9allocatorNtB2_15KernelAllocatorNtNtNtCs3yuwAp0waWO_4core5alloc6global11GlobalAlloc7dealloc+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+__rust_alloc+0x0: data relocation to !ENDBR: __rust_alloc+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+__rust_dealloc+0x0: data relocation to !ENDBR: __rust_dealloc+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+__rust_realloc+0x0: data relocation to !ENDBR: __rust_realloc+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+__rust_alloc_zeroed+0x0: data relocation to !ENDBR: __rust_alloc_zeroed+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvMNtCsfATHBUcknU9_6kernel5errorNtB2_5Error15to_kernel_errno+0x0: data relocation to !ENDBR: _RNvMNtCsfATHBUcknU9_6kernel5errorNtB2_5Error15to_kernel_errno+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvXs0_NtCsfATHBUcknU9_6kernel5errorNtB5_5ErrorINtNtCs3yuwAp0waWO_4core7convert4FromNtNtNtBO_3num5error15TryFromIntErrorE4from+0x0: data relocation to !ENDBR: _RNvXs0_NtCsfATHBUcknU9_6kernel5errorNtB5_5ErrorINtNtCs3yuwAp0waWO_4core7convert4FromNtNtNtBO_3num5error15TryFromIntErrorE4from+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvXs1_NtCsfATHBUcknU9_6kernel5errorNtB5_5ErrorINtNtCs3yuwAp0waWO_4core7convert4FromNtNtNtBO_3str5error9Utf8ErrorE4from+0x0: data relocation to !ENDBR: _RNvXs1_NtCsfATHBUcknU9_6kernel5errorNtB5_5ErrorINtNtCs3yuwAp0waWO_4core7convert4FromNtNtNtBO_3str5error9Utf8ErrorE4from+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvXs2_NtCsfATHBUcknU9_6kernel5errorNtB5_5ErrorINtNtCs3yuwAp0waWO_4core7convert4FromNtNtCsdvv6pRyacSq_5alloc11collections15TryReserveErrorE4from+0x0: data relocation to !ENDBR: _RNvXs2_NtCsfATHBUcknU9_6kernel5errorNtB5_5ErrorINtNtCs3yuwAp0waWO_4core7convert4FromNtNtCsdvv6pRyacSq_5alloc11collections15TryReserveErrorE4from+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvXs3_NtCsfATHBUcknU9_6kernel5errorNtB5_5ErrorINtNtCs3yuwAp0waWO_4core7convert4FromNtNtNtBO_5alloc6layout11LayoutErrorE4from+0x0: data relocation to !ENDBR: _RNvXs3_NtCsfATHBUcknU9_6kernel5errorNtB5_5ErrorINtNtCs3yuwAp0waWO_4core7convert4FromNtNtNtBO_5alloc6layout11LayoutErrorE4from+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvXs5_NtCsfATHBUcknU9_6kernel5errorNtB5_5ErrorINtNtCs3yuwAp0waWO_4core7convert4FromNtBM_10InfallibleE4from+0x0: data relocation to !ENDBR: _RNvXs5_NtCsfATHBUcknU9_6kernel5errorNtB5_5ErrorINtNtCs3yuwAp0waWO_4core7convert4FromNtBM_10InfallibleE4from+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+rust_fmt_argument+0x0: data relocation to !ENDBR: rust_fmt_argument+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvNtNtCsfATHBUcknU9_6kernel5print14format_strings8generate+0x0: data relocation to !ENDBR: _RNvNtNtCsfATHBUcknU9_6kernel5print14format_strings8generate+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvNtCsfATHBUcknU9_6kernel5print11call_printk+0x0: data relocation to !ENDBR: _RNvNtCsfATHBUcknU9_6kernel5print11call_printk+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvNtCsfATHBUcknU9_6kernel5print16call_printk_cont+0x0: data relocation to !ENDBR: _RNvNtCsfATHBUcknU9_6kernel5print16call_printk_cont+0x0
>> vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvMs_NtCsfATHBUcknU9_6kernel3strNtB4_4CStr19from_bytes_with_nul+0x0: data relocation to !ENDBR: _RNvMs_NtCsfATHBUcknU9_6kernel3strNtB4_4CStr19from_bytes_with_nul+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvXs1_NtCsfATHBUcknU9_6kernel3strNtB5_12RawFormatterNtNtCs3yuwAp0waWO_4core3fmt5Write9write_str+0x0: data relocation to !ENDBR: _RNvXs1_NtCsfATHBUcknU9_6kernel3strNtB5_12RawFormatterNtNtCs3yuwAp0waWO_4core3fmt5Write9write_str+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvMs_CsfATHBUcknU9_6kernelNtB4_10ThisModule8from_ptr+0x0: data relocation to !ENDBR: _RNvMs_CsfATHBUcknU9_6kernelNtB4_10ThisModule8from_ptr+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+rust_begin_unwind+0x0: data relocation to !ENDBR: rust_begin_unwind+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+__rg_alloc+0x0: data relocation to !ENDBR: __rg_alloc+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+__rg_dealloc+0x0: data relocation to !ENDBR: __rg_dealloc+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+__rg_realloc+0x0: data relocation to !ENDBR: __rg_realloc+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+__rg_alloc_zeroed+0x0: data relocation to !ENDBR: __rg_alloc_zeroed+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvXs2_NtCsfATHBUcknU9_6kernel3strNtB5_16CStrConvertErrorNtNtCs3yuwAp0waWO_4core3fmt5Debug3fmt+0x0: data relocation to !ENDBR: _RNvXs2_NtCsfATHBUcknU9_6kernel3strNtB5_16CStrConvertErrorNtNtCs3yuwAp0waWO_4core3fmt5Debug3fmt+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvXs_NtCsfATHBUcknU9_6kernel5errorNtB4_5ErrorINtNtCs3yuwAp0waWO_4core7convert4FromNtNtBN_5alloc10AllocErrorE4from+0x0: data relocation to !ENDBR: _RNvXs3_NtCsfATHBUcknU9_6kernel5errorNtB5_5ErrorINtNtCs3yuwAp0waWO_4core7convert4FromNtNtNtBO_5alloc6layout11LayoutErrorE4from+0x0
   vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvXs4_NtCsfATHBUcknU9_6kernel5errorNtB5_5ErrorINtNtCs3yuwAp0waWO_4core7convert4FromNtNtBO_3fmt5ErrorE4from+0x0: data relocation to !ENDBR: _RNvXs0_NtCsfATHBUcknU9_6kernel5errorNtB5_5ErrorINtNtCs3yuwAp0waWO_4core7convert4FromNtNtNtBO_3num5error15TryFromIntErrorE4from+0x0


objdump-func vmlinux.o ___ksymtab_gpl:

-- 
0-DAY CI Kernel Test Service
https://01.org/lkp

[-- Attachment #2: config --]
[-- Type: text/plain, Size: 166824 bytes --]

#
# Automatically generated file; DO NOT EDIT.
# Linux/x86_64 6.1.0-rc4 Kernel Configuration
#
CONFIG_CC_VERSION_TEXT="clang version 14.0.6 (git://gitmirror/llvm_project f28c006a5895fc0e329fe15fead81e37457cb1d1)"
CONFIG_GCC_VERSION=0
CONFIG_CC_IS_CLANG=y
CONFIG_CLANG_VERSION=140006
CONFIG_AS_IS_LLVM=y
CONFIG_AS_VERSION=140006
CONFIG_LD_VERSION=0
CONFIG_LD_IS_LLD=y
CONFIG_LLD_VERSION=140006
CONFIG_RUST_IS_AVAILABLE=y
CONFIG_CC_CAN_LINK=y
CONFIG_CC_CAN_LINK_STATIC=y
CONFIG_CC_HAS_ASM_GOTO_OUTPUT=y
CONFIG_TOOLS_SUPPORT_RELR=y
CONFIG_CC_HAS_ASM_INLINE=y
CONFIG_CC_HAS_NO_PROFILE_FN_ATTR=y
CONFIG_PAHOLE_VERSION=123
CONFIG_CONSTRUCTORS=y
CONFIG_IRQ_WORK=y
CONFIG_BUILDTIME_TABLE_SORT=y
CONFIG_THREAD_INFO_IN_TASK=y

#
# General setup
#
CONFIG_INIT_ENV_ARG_LIMIT=32
# CONFIG_COMPILE_TEST is not set
# CONFIG_WERROR is not set
CONFIG_LOCALVERSION=""
CONFIG_LOCALVERSION_AUTO=y
CONFIG_BUILD_SALT=""
CONFIG_HAVE_KERNEL_GZIP=y
CONFIG_HAVE_KERNEL_BZIP2=y
CONFIG_HAVE_KERNEL_LZMA=y
CONFIG_HAVE_KERNEL_XZ=y
CONFIG_HAVE_KERNEL_LZO=y
CONFIG_HAVE_KERNEL_LZ4=y
CONFIG_HAVE_KERNEL_ZSTD=y
CONFIG_KERNEL_GZIP=y
# CONFIG_KERNEL_BZIP2 is not set
# CONFIG_KERNEL_LZMA is not set
# CONFIG_KERNEL_XZ is not set
# CONFIG_KERNEL_LZO is not set
# CONFIG_KERNEL_LZ4 is not set
# CONFIG_KERNEL_ZSTD is not set
CONFIG_DEFAULT_INIT=""
CONFIG_DEFAULT_HOSTNAME="(none)"
CONFIG_SYSVIPC=y
CONFIG_SYSVIPC_SYSCTL=y
CONFIG_SYSVIPC_COMPAT=y
CONFIG_POSIX_MQUEUE=y
CONFIG_POSIX_MQUEUE_SYSCTL=y
# CONFIG_WATCH_QUEUE is not set
CONFIG_CROSS_MEMORY_ATTACH=y
# CONFIG_USELIB is not set
CONFIG_AUDIT=y
CONFIG_HAVE_ARCH_AUDITSYSCALL=y
CONFIG_AUDITSYSCALL=y

#
# IRQ subsystem
#
CONFIG_GENERIC_IRQ_PROBE=y
CONFIG_GENERIC_IRQ_SHOW=y
CONFIG_GENERIC_IRQ_EFFECTIVE_AFF_MASK=y
CONFIG_GENERIC_PENDING_IRQ=y
CONFIG_GENERIC_IRQ_MIGRATION=y
CONFIG_GENERIC_IRQ_INJECTION=y
CONFIG_HARDIRQS_SW_RESEND=y
CONFIG_IRQ_DOMAIN=y
CONFIG_IRQ_DOMAIN_HIERARCHY=y
CONFIG_GENERIC_MSI_IRQ=y
CONFIG_GENERIC_MSI_IRQ_DOMAIN=y
CONFIG_IRQ_MSI_IOMMU=y
CONFIG_GENERIC_IRQ_MATRIX_ALLOCATOR=y
CONFIG_GENERIC_IRQ_RESERVATION_MODE=y
CONFIG_IRQ_FORCED_THREADING=y
CONFIG_SPARSE_IRQ=y
# CONFIG_GENERIC_IRQ_DEBUGFS is not set
# end of IRQ subsystem

CONFIG_CLOCKSOURCE_WATCHDOG=y
CONFIG_ARCH_CLOCKSOURCE_INIT=y
CONFIG_CLOCKSOURCE_VALIDATE_LAST_CYCLE=y
CONFIG_GENERIC_TIME_VSYSCALL=y
CONFIG_GENERIC_CLOCKEVENTS=y
CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y
CONFIG_GENERIC_CLOCKEVENTS_MIN_ADJUST=y
CONFIG_GENERIC_CMOS_UPDATE=y
CONFIG_HAVE_POSIX_CPU_TIMERS_TASK_WORK=y
CONFIG_POSIX_CPU_TIMERS_TASK_WORK=y
CONFIG_CONTEXT_TRACKING=y
CONFIG_CONTEXT_TRACKING_IDLE=y

#
# Timers subsystem
#
CONFIG_TICK_ONESHOT=y
CONFIG_NO_HZ_COMMON=y
# CONFIG_HZ_PERIODIC is not set
# CONFIG_NO_HZ_IDLE is not set
CONFIG_NO_HZ_FULL=y
CONFIG_CONTEXT_TRACKING_USER=y
# CONFIG_CONTEXT_TRACKING_USER_FORCE is not set
CONFIG_NO_HZ=y
CONFIG_HIGH_RES_TIMERS=y
CONFIG_CLOCKSOURCE_WATCHDOG_MAX_SKEW_US=100
# end of Timers subsystem

CONFIG_BPF=y
CONFIG_HAVE_EBPF_JIT=y
CONFIG_ARCH_WANT_DEFAULT_BPF_JIT=y

#
# BPF subsystem
#
CONFIG_BPF_SYSCALL=y
CONFIG_BPF_JIT=y
CONFIG_BPF_JIT_ALWAYS_ON=y
CONFIG_BPF_JIT_DEFAULT_ON=y
CONFIG_BPF_UNPRIV_DEFAULT_OFF=y
# CONFIG_BPF_PRELOAD is not set
# CONFIG_BPF_LSM is not set
# end of BPF subsystem

CONFIG_PREEMPT_VOLUNTARY_BUILD=y
# CONFIG_PREEMPT_NONE is not set
CONFIG_PREEMPT_VOLUNTARY=y
# CONFIG_PREEMPT is not set
CONFIG_PREEMPT_COUNT=y
# CONFIG_PREEMPT_DYNAMIC is not set
# CONFIG_SCHED_CORE is not set

#
# CPU/Task time and stats accounting
#
CONFIG_VIRT_CPU_ACCOUNTING=y
CONFIG_VIRT_CPU_ACCOUNTING_GEN=y
CONFIG_IRQ_TIME_ACCOUNTING=y
CONFIG_HAVE_SCHED_AVG_IRQ=y
CONFIG_BSD_PROCESS_ACCT=y
CONFIG_BSD_PROCESS_ACCT_V3=y
CONFIG_TASKSTATS=y
CONFIG_TASK_DELAY_ACCT=y
CONFIG_TASK_XACCT=y
CONFIG_TASK_IO_ACCOUNTING=y
# CONFIG_PSI is not set
# end of CPU/Task time and stats accounting

CONFIG_CPU_ISOLATION=y

#
# RCU Subsystem
#
CONFIG_TREE_RCU=y
# CONFIG_RCU_EXPERT is not set
CONFIG_SRCU=y
CONFIG_TREE_SRCU=y
CONFIG_TASKS_RCU_GENERIC=y
CONFIG_TASKS_RUDE_RCU=y
CONFIG_TASKS_TRACE_RCU=y
CONFIG_RCU_STALL_COMMON=y
CONFIG_RCU_NEED_SEGCBLIST=y
CONFIG_RCU_NOCB_CPU=y
# CONFIG_RCU_NOCB_CPU_DEFAULT_ALL is not set
# end of RCU Subsystem

CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
# CONFIG_IKHEADERS is not set
CONFIG_LOG_BUF_SHIFT=20
CONFIG_LOG_CPU_MAX_BUF_SHIFT=12
CONFIG_PRINTK_SAFE_LOG_BUF_SHIFT=13
# CONFIG_PRINTK_INDEX is not set
CONFIG_HAVE_UNSTABLE_SCHED_CLOCK=y

#
# Scheduler features
#
# CONFIG_UCLAMP_TASK is not set
# end of Scheduler features

CONFIG_ARCH_SUPPORTS_NUMA_BALANCING=y
CONFIG_ARCH_WANT_BATCHED_UNMAP_TLB_FLUSH=y
CONFIG_CC_HAS_INT128=y
CONFIG_CC_IMPLICIT_FALLTHROUGH="-Wimplicit-fallthrough"
CONFIG_GCC12_NO_ARRAY_BOUNDS=y
CONFIG_ARCH_SUPPORTS_INT128=y
CONFIG_NUMA_BALANCING=y
CONFIG_NUMA_BALANCING_DEFAULT_ENABLED=y
CONFIG_CGROUPS=y
CONFIG_PAGE_COUNTER=y
# CONFIG_CGROUP_FAVOR_DYNMODS is not set
CONFIG_MEMCG=y
CONFIG_MEMCG_KMEM=y
CONFIG_BLK_CGROUP=y
CONFIG_CGROUP_WRITEBACK=y
CONFIG_CGROUP_SCHED=y
CONFIG_FAIR_GROUP_SCHED=y
CONFIG_CFS_BANDWIDTH=y
# CONFIG_RT_GROUP_SCHED is not set
CONFIG_CGROUP_PIDS=y
CONFIG_CGROUP_RDMA=y
CONFIG_CGROUP_FREEZER=y
CONFIG_CGROUP_HUGETLB=y
CONFIG_CPUSETS=y
CONFIG_PROC_PID_CPUSET=y
CONFIG_CGROUP_DEVICE=y
CONFIG_CGROUP_CPUACCT=y
CONFIG_CGROUP_PERF=y
# CONFIG_CGROUP_BPF is not set
# CONFIG_CGROUP_MISC is not set
# CONFIG_CGROUP_DEBUG is not set
CONFIG_SOCK_CGROUP_DATA=y
CONFIG_NAMESPACES=y
CONFIG_UTS_NS=y
CONFIG_TIME_NS=y
CONFIG_IPC_NS=y
CONFIG_USER_NS=y
CONFIG_PID_NS=y
CONFIG_NET_NS=y
# CONFIG_CHECKPOINT_RESTORE is not set
CONFIG_SCHED_AUTOGROUP=y
# CONFIG_SYSFS_DEPRECATED is not set
CONFIG_RELAY=y
CONFIG_BLK_DEV_INITRD=y
CONFIG_INITRAMFS_SOURCE=""
CONFIG_RD_GZIP=y
CONFIG_RD_BZIP2=y
CONFIG_RD_LZMA=y
CONFIG_RD_XZ=y
CONFIG_RD_LZO=y
CONFIG_RD_LZ4=y
CONFIG_RD_ZSTD=y
# CONFIG_BOOT_CONFIG is not set
CONFIG_INITRAMFS_PRESERVE_MTIME=y
CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
CONFIG_LD_ORPHAN_WARN=y
CONFIG_SYSCTL=y
CONFIG_HAVE_UID16=y
CONFIG_SYSCTL_EXCEPTION_TRACE=y
CONFIG_HAVE_PCSPKR_PLATFORM=y
# CONFIG_EXPERT is not set
CONFIG_UID16=y
CONFIG_MULTIUSER=y
CONFIG_SGETMASK_SYSCALL=y
CONFIG_SYSFS_SYSCALL=y
CONFIG_FHANDLE=y
CONFIG_POSIX_TIMERS=y
CONFIG_PRINTK=y
CONFIG_BUG=y
CONFIG_ELF_CORE=y
CONFIG_PCSPKR_PLATFORM=y
CONFIG_BASE_FULL=y
CONFIG_FUTEX=y
CONFIG_FUTEX_PI=y
CONFIG_EPOLL=y
CONFIG_SIGNALFD=y
CONFIG_TIMERFD=y
CONFIG_EVENTFD=y
CONFIG_SHMEM=y
CONFIG_AIO=y
CONFIG_IO_URING=y
CONFIG_ADVISE_SYSCALLS=y
CONFIG_MEMBARRIER=y
CONFIG_KALLSYMS=y
CONFIG_KALLSYMS_ALL=y
CONFIG_KALLSYMS_ABSOLUTE_PERCPU=y
CONFIG_KALLSYMS_BASE_RELATIVE=y
CONFIG_ARCH_HAS_MEMBARRIER_SYNC_CORE=y
CONFIG_KCMP=y
CONFIG_RSEQ=y
# CONFIG_EMBEDDED is not set
CONFIG_HAVE_PERF_EVENTS=y
CONFIG_GUEST_PERF_EVENTS=y

#
# Kernel Performance Events And Counters
#
CONFIG_PERF_EVENTS=y
# CONFIG_DEBUG_PERF_USE_VMALLOC is not set
# end of Kernel Performance Events And Counters

CONFIG_SYSTEM_DATA_VERIFICATION=y
CONFIG_PROFILING=y
CONFIG_RUST=y
CONFIG_RUSTC_VERSION_TEXT="rustc 1.62.0 (a8314ef7d 2022-06-27)"
CONFIG_BINDGEN_VERSION_TEXT="bindgen 0.56.0"
CONFIG_TRACEPOINTS=y
# end of General setup

CONFIG_64BIT=y
CONFIG_X86_64=y
CONFIG_X86=y
CONFIG_INSTRUCTION_DECODER=y
CONFIG_OUTPUT_FORMAT="elf64-x86-64"
CONFIG_LOCKDEP_SUPPORT=y
CONFIG_STACKTRACE_SUPPORT=y
CONFIG_MMU=y
CONFIG_ARCH_MMAP_RND_BITS_MIN=28
CONFIG_ARCH_MMAP_RND_BITS_MAX=32
CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MIN=8
CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MAX=16
CONFIG_GENERIC_ISA_DMA=y
CONFIG_GENERIC_BUG=y
CONFIG_GENERIC_BUG_RELATIVE_POINTERS=y
CONFIG_ARCH_MAY_HAVE_PC_FDC=y
CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_ARCH_HAS_CPU_RELAX=y
CONFIG_ARCH_HIBERNATION_POSSIBLE=y
CONFIG_ARCH_NR_GPIO=1024
CONFIG_ARCH_SUSPEND_POSSIBLE=y
CONFIG_AUDIT_ARCH=y
CONFIG_HAVE_INTEL_TXT=y
CONFIG_X86_64_SMP=y
CONFIG_ARCH_SUPPORTS_UPROBES=y
CONFIG_FIX_EARLYCON_MEM=y
CONFIG_DYNAMIC_PHYSICAL_MASK=y
CONFIG_PGTABLE_LEVELS=5
CONFIG_CC_HAS_SANE_STACKPROTECTOR=y

#
# Processor type and features
#
CONFIG_SMP=y
CONFIG_X86_FEATURE_NAMES=y
CONFIG_X86_X2APIC=y
CONFIG_X86_MPPARSE=y
# CONFIG_GOLDFISH is not set
# CONFIG_X86_CPU_RESCTRL is not set
CONFIG_X86_EXTENDED_PLATFORM=y
# CONFIG_X86_NUMACHIP is not set
# CONFIG_X86_VSMP is not set
CONFIG_X86_UV=y
# CONFIG_X86_GOLDFISH is not set
# CONFIG_X86_INTEL_MID is not set
CONFIG_X86_INTEL_LPSS=y
# CONFIG_X86_AMD_PLATFORM_DEVICE is not set
CONFIG_IOSF_MBI=y
# CONFIG_IOSF_MBI_DEBUG is not set
CONFIG_X86_SUPPORTS_MEMORY_FAILURE=y
# CONFIG_SCHED_OMIT_FRAME_POINTER is not set
CONFIG_HYPERVISOR_GUEST=y
CONFIG_PARAVIRT=y
# CONFIG_PARAVIRT_DEBUG is not set
CONFIG_PARAVIRT_SPINLOCKS=y
CONFIG_X86_HV_CALLBACK_VECTOR=y
# CONFIG_XEN is not set
CONFIG_KVM_GUEST=y
CONFIG_ARCH_CPUIDLE_HALTPOLL=y
# CONFIG_PVH is not set
CONFIG_PARAVIRT_TIME_ACCOUNTING=y
CONFIG_PARAVIRT_CLOCK=y
# CONFIG_JAILHOUSE_GUEST is not set
# CONFIG_ACRN_GUEST is not set
CONFIG_INTEL_TDX_GUEST=y
# CONFIG_MK8 is not set
# CONFIG_MPSC is not set
# CONFIG_MCORE2 is not set
# CONFIG_MATOM is not set
CONFIG_GENERIC_CPU=y
CONFIG_X86_INTERNODE_CACHE_SHIFT=6
CONFIG_X86_L1_CACHE_SHIFT=6
CONFIG_X86_TSC=y
CONFIG_X86_CMPXCHG64=y
CONFIG_X86_CMOV=y
CONFIG_X86_MINIMUM_CPU_FAMILY=64
CONFIG_X86_DEBUGCTLMSR=y
CONFIG_IA32_FEAT_CTL=y
CONFIG_X86_VMX_FEATURE_NAMES=y
CONFIG_CPU_SUP_INTEL=y
CONFIG_CPU_SUP_AMD=y
CONFIG_CPU_SUP_HYGON=y
CONFIG_CPU_SUP_CENTAUR=y
CONFIG_CPU_SUP_ZHAOXIN=y
CONFIG_HPET_TIMER=y
CONFIG_HPET_EMULATE_RTC=y
CONFIG_DMI=y
# CONFIG_GART_IOMMU is not set
CONFIG_BOOT_VESA_SUPPORT=y
CONFIG_MAXSMP=y
CONFIG_NR_CPUS_RANGE_BEGIN=8192
CONFIG_NR_CPUS_RANGE_END=8192
CONFIG_NR_CPUS_DEFAULT=8192
CONFIG_NR_CPUS=8192
CONFIG_SCHED_CLUSTER=y
CONFIG_SCHED_SMT=y
CONFIG_SCHED_MC=y
CONFIG_SCHED_MC_PRIO=y
CONFIG_X86_LOCAL_APIC=y
CONFIG_X86_IO_APIC=y
CONFIG_X86_REROUTE_FOR_BROKEN_BOOT_IRQS=y
CONFIG_X86_MCE=y
CONFIG_X86_MCELOG_LEGACY=y
CONFIG_X86_MCE_INTEL=y
# CONFIG_X86_MCE_AMD is not set
CONFIG_X86_MCE_THRESHOLD=y
CONFIG_X86_MCE_INJECT=m

#
# Performance monitoring
#
CONFIG_PERF_EVENTS_INTEL_UNCORE=m
CONFIG_PERF_EVENTS_INTEL_RAPL=m
CONFIG_PERF_EVENTS_INTEL_CSTATE=m
# CONFIG_PERF_EVENTS_AMD_POWER is not set
# CONFIG_PERF_EVENTS_AMD_UNCORE is not set
# CONFIG_PERF_EVENTS_AMD_BRS is not set
# end of Performance monitoring

CONFIG_X86_16BIT=y
CONFIG_X86_ESPFIX64=y
CONFIG_X86_VSYSCALL_EMULATION=y
CONFIG_X86_IOPL_IOPERM=y
CONFIG_MICROCODE=y
CONFIG_MICROCODE_INTEL=y
# CONFIG_MICROCODE_AMD is not set
CONFIG_MICROCODE_LATE_LOADING=y
CONFIG_X86_MSR=y
CONFIG_X86_CPUID=y
CONFIG_X86_5LEVEL=y
CONFIG_X86_DIRECT_GBPAGES=y
# CONFIG_X86_CPA_STATISTICS is not set
CONFIG_X86_MEM_ENCRYPT=y
# CONFIG_AMD_MEM_ENCRYPT is not set
CONFIG_NUMA=y
# CONFIG_AMD_NUMA is not set
CONFIG_X86_64_ACPI_NUMA=y
CONFIG_NUMA_EMU=y
CONFIG_NODES_SHIFT=10
CONFIG_ARCH_SPARSEMEM_ENABLE=y
CONFIG_ARCH_SPARSEMEM_DEFAULT=y
# CONFIG_ARCH_MEMORY_PROBE is not set
CONFIG_ARCH_PROC_KCORE_TEXT=y
CONFIG_ILLEGAL_POINTER_VALUE=0xdead000000000000
CONFIG_X86_PMEM_LEGACY_DEVICE=y
CONFIG_X86_PMEM_LEGACY=m
CONFIG_X86_CHECK_BIOS_CORRUPTION=y
# CONFIG_X86_BOOTPARAM_MEMORY_CORRUPTION_CHECK is not set
CONFIG_MTRR=y
CONFIG_MTRR_SANITIZER=y
CONFIG_MTRR_SANITIZER_ENABLE_DEFAULT=1
CONFIG_MTRR_SANITIZER_SPARE_REG_NR_DEFAULT=1
CONFIG_X86_PAT=y
CONFIG_ARCH_USES_PG_UNCACHED=y
CONFIG_X86_UMIP=y
CONFIG_CC_HAS_IBT=y
CONFIG_X86_KERNEL_IBT=y
CONFIG_X86_INTEL_MEMORY_PROTECTION_KEYS=y
CONFIG_X86_INTEL_TSX_MODE_OFF=y
# CONFIG_X86_INTEL_TSX_MODE_ON is not set
# CONFIG_X86_INTEL_TSX_MODE_AUTO is not set
# CONFIG_X86_SGX is not set
CONFIG_EFI=y
CONFIG_EFI_STUB=y
CONFIG_EFI_MIXED=y
# CONFIG_HZ_100 is not set
# CONFIG_HZ_250 is not set
# CONFIG_HZ_300 is not set
CONFIG_HZ_1000=y
CONFIG_HZ=1000
CONFIG_SCHED_HRTICK=y
CONFIG_KEXEC=y
CONFIG_KEXEC_FILE=y
CONFIG_ARCH_HAS_KEXEC_PURGATORY=y
# CONFIG_KEXEC_SIG is not set
CONFIG_CRASH_DUMP=y
CONFIG_KEXEC_JUMP=y
CONFIG_PHYSICAL_START=0x1000000
CONFIG_RELOCATABLE=y
# CONFIG_RANDOMIZE_BASE is not set
CONFIG_PHYSICAL_ALIGN=0x200000
CONFIG_DYNAMIC_MEMORY_LAYOUT=y
CONFIG_HOTPLUG_CPU=y
CONFIG_BOOTPARAM_HOTPLUG_CPU0=y
# CONFIG_DEBUG_HOTPLUG_CPU0 is not set
# CONFIG_COMPAT_VDSO is not set
CONFIG_LEGACY_VSYSCALL_XONLY=y
# CONFIG_LEGACY_VSYSCALL_NONE is not set
# CONFIG_CMDLINE_BOOL is not set
CONFIG_MODIFY_LDT_SYSCALL=y
# CONFIG_STRICT_SIGALTSTACK_SIZE is not set
CONFIG_HAVE_LIVEPATCH=y
CONFIG_LIVEPATCH=y
# end of Processor type and features

CONFIG_SPECULATION_MITIGATIONS=y
CONFIG_PAGE_TABLE_ISOLATION=y
CONFIG_RETPOLINE=y
CONFIG_CPU_IBPB_ENTRY=y
CONFIG_CPU_IBRS_ENTRY=y
CONFIG_ARCH_HAS_ADD_PAGES=y
CONFIG_ARCH_MHP_MEMMAP_ON_MEMORY_ENABLE=y

#
# Power management and ACPI options
#
CONFIG_ARCH_HIBERNATION_HEADER=y
CONFIG_SUSPEND=y
CONFIG_SUSPEND_FREEZER=y
CONFIG_HIBERNATE_CALLBACKS=y
CONFIG_HIBERNATION=y
CONFIG_HIBERNATION_SNAPSHOT_DEV=y
CONFIG_PM_STD_PARTITION=""
CONFIG_PM_SLEEP=y
CONFIG_PM_SLEEP_SMP=y
# CONFIG_PM_AUTOSLEEP is not set
# CONFIG_PM_USERSPACE_AUTOSLEEP is not set
# CONFIG_PM_WAKELOCKS is not set
CONFIG_PM=y
CONFIG_PM_DEBUG=y
# CONFIG_PM_ADVANCED_DEBUG is not set
# CONFIG_PM_TEST_SUSPEND is not set
CONFIG_PM_SLEEP_DEBUG=y
# CONFIG_PM_TRACE_RTC is not set
CONFIG_PM_CLK=y
# CONFIG_WQ_POWER_EFFICIENT_DEFAULT is not set
# CONFIG_ENERGY_MODEL is not set
CONFIG_ARCH_SUPPORTS_ACPI=y
CONFIG_ACPI=y
CONFIG_ACPI_LEGACY_TABLES_LOOKUP=y
CONFIG_ARCH_MIGHT_HAVE_ACPI_PDC=y
CONFIG_ACPI_SYSTEM_POWER_STATES_SUPPORT=y
# CONFIG_ACPI_DEBUGGER is not set
CONFIG_ACPI_SPCR_TABLE=y
# CONFIG_ACPI_FPDT is not set
CONFIG_ACPI_LPIT=y
CONFIG_ACPI_SLEEP=y
CONFIG_ACPI_REV_OVERRIDE_POSSIBLE=y
CONFIG_ACPI_EC_DEBUGFS=m
CONFIG_ACPI_AC=y
CONFIG_ACPI_BATTERY=y
CONFIG_ACPI_BUTTON=y
CONFIG_ACPI_VIDEO=m
CONFIG_ACPI_FAN=y
CONFIG_ACPI_TAD=m
CONFIG_ACPI_DOCK=y
CONFIG_ACPI_CPU_FREQ_PSS=y
CONFIG_ACPI_PROCESSOR_CSTATE=y
CONFIG_ACPI_PROCESSOR_IDLE=y
CONFIG_ACPI_CPPC_LIB=y
CONFIG_ACPI_PROCESSOR=y
CONFIG_ACPI_IPMI=m
CONFIG_ACPI_HOTPLUG_CPU=y
CONFIG_ACPI_PROCESSOR_AGGREGATOR=m
CONFIG_ACPI_THERMAL=y
CONFIG_ACPI_PLATFORM_PROFILE=m
CONFIG_ARCH_HAS_ACPI_TABLE_UPGRADE=y
CONFIG_ACPI_TABLE_UPGRADE=y
# CONFIG_ACPI_DEBUG is not set
CONFIG_ACPI_PCI_SLOT=y
CONFIG_ACPI_CONTAINER=y
CONFIG_ACPI_HOTPLUG_MEMORY=y
CONFIG_ACPI_HOTPLUG_IOAPIC=y
CONFIG_ACPI_SBS=m
CONFIG_ACPI_HED=y
# CONFIG_ACPI_CUSTOM_METHOD is not set
CONFIG_ACPI_BGRT=y
CONFIG_ACPI_NFIT=m
# CONFIG_NFIT_SECURITY_DEBUG is not set
CONFIG_ACPI_NUMA=y
# CONFIG_ACPI_HMAT is not set
CONFIG_HAVE_ACPI_APEI=y
CONFIG_HAVE_ACPI_APEI_NMI=y
CONFIG_ACPI_APEI=y
CONFIG_ACPI_APEI_GHES=y
CONFIG_ACPI_APEI_PCIEAER=y
CONFIG_ACPI_APEI_MEMORY_FAILURE=y
CONFIG_ACPI_APEI_EINJ=m
# CONFIG_ACPI_APEI_ERST_DEBUG is not set
# CONFIG_ACPI_DPTF is not set
CONFIG_ACPI_WATCHDOG=y
CONFIG_ACPI_EXTLOG=m
CONFIG_ACPI_ADXL=y
# CONFIG_ACPI_CONFIGFS is not set
# CONFIG_ACPI_PFRUT is not set
CONFIG_ACPI_PCC=y
CONFIG_PMIC_OPREGION=y
CONFIG_ACPI_PRMT=y
CONFIG_X86_PM_TIMER=y

#
# CPU Frequency scaling
#
CONFIG_CPU_FREQ=y
CONFIG_CPU_FREQ_GOV_ATTR_SET=y
CONFIG_CPU_FREQ_GOV_COMMON=y
CONFIG_CPU_FREQ_STAT=y
CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y
# CONFIG_CPU_FREQ_DEFAULT_GOV_POWERSAVE is not set
# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set
# CONFIG_CPU_FREQ_DEFAULT_GOV_SCHEDUTIL is not set
CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
CONFIG_CPU_FREQ_GOV_POWERSAVE=y
CONFIG_CPU_FREQ_GOV_USERSPACE=y
CONFIG_CPU_FREQ_GOV_ONDEMAND=y
CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y
CONFIG_CPU_FREQ_GOV_SCHEDUTIL=y

#
# CPU frequency scaling drivers
#
CONFIG_X86_INTEL_PSTATE=y
# CONFIG_X86_PCC_CPUFREQ is not set
# CONFIG_X86_AMD_PSTATE is not set
# CONFIG_X86_AMD_PSTATE_UT is not set
CONFIG_X86_ACPI_CPUFREQ=m
CONFIG_X86_ACPI_CPUFREQ_CPB=y
# CONFIG_X86_POWERNOW_K8 is not set
# CONFIG_X86_AMD_FREQ_SENSITIVITY is not set
# CONFIG_X86_SPEEDSTEP_CENTRINO is not set
CONFIG_X86_P4_CLOCKMOD=m

#
# shared options
#
CONFIG_X86_SPEEDSTEP_LIB=m
# end of CPU Frequency scaling

#
# CPU Idle
#
CONFIG_CPU_IDLE=y
# CONFIG_CPU_IDLE_GOV_LADDER is not set
CONFIG_CPU_IDLE_GOV_MENU=y
# CONFIG_CPU_IDLE_GOV_TEO is not set
# CONFIG_CPU_IDLE_GOV_HALTPOLL is not set
CONFIG_HALTPOLL_CPUIDLE=y
# end of CPU Idle

CONFIG_INTEL_IDLE=y
# end of Power management and ACPI options

#
# Bus options (PCI etc.)
#
CONFIG_PCI_DIRECT=y
CONFIG_PCI_MMCONFIG=y
CONFIG_MMCONF_FAM10H=y
CONFIG_ISA_DMA_API=y
CONFIG_AMD_NB=y
# end of Bus options (PCI etc.)

#
# Binary Emulations
#
CONFIG_IA32_EMULATION=y
CONFIG_COMPAT_32=y
CONFIG_COMPAT=y
CONFIG_COMPAT_FOR_U64_ALIGNMENT=y
# end of Binary Emulations

CONFIG_HAVE_KVM=y
CONFIG_HAVE_KVM_PFNCACHE=y
CONFIG_HAVE_KVM_IRQCHIP=y
CONFIG_HAVE_KVM_IRQFD=y
CONFIG_HAVE_KVM_IRQ_ROUTING=y
CONFIG_HAVE_KVM_DIRTY_RING=y
CONFIG_HAVE_KVM_DIRTY_RING_TSO=y
CONFIG_HAVE_KVM_DIRTY_RING_ACQ_REL=y
CONFIG_HAVE_KVM_EVENTFD=y
CONFIG_KVM_MMIO=y
CONFIG_KVM_ASYNC_PF=y
CONFIG_HAVE_KVM_MSI=y
CONFIG_HAVE_KVM_CPU_RELAX_INTERCEPT=y
CONFIG_KVM_VFIO=y
CONFIG_KVM_GENERIC_DIRTYLOG_READ_PROTECT=y
CONFIG_KVM_COMPAT=y
CONFIG_HAVE_KVM_IRQ_BYPASS=y
CONFIG_HAVE_KVM_NO_POLL=y
CONFIG_KVM_XFER_TO_GUEST_WORK=y
CONFIG_HAVE_KVM_PM_NOTIFIER=y
CONFIG_VIRTUALIZATION=y
CONFIG_KVM=m
CONFIG_KVM_INTEL=m
# CONFIG_KVM_AMD is not set
# CONFIG_KVM_XEN is not set
CONFIG_AS_AVX512=y
CONFIG_AS_SHA1_NI=y
CONFIG_AS_SHA256_NI=y
CONFIG_AS_TPAUSE=y

#
# General architecture-dependent options
#
CONFIG_CRASH_CORE=y
CONFIG_KEXEC_CORE=y
CONFIG_HOTPLUG_SMT=y
CONFIG_GENERIC_ENTRY=y
CONFIG_KPROBES=y
CONFIG_JUMP_LABEL=y
# CONFIG_STATIC_KEYS_SELFTEST is not set
# CONFIG_STATIC_CALL_SELFTEST is not set
CONFIG_OPTPROBES=y
CONFIG_KPROBES_ON_FTRACE=y
CONFIG_UPROBES=y
CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y
CONFIG_ARCH_USE_BUILTIN_BSWAP=y
CONFIG_KRETPROBES=y
CONFIG_KRETPROBE_ON_RETHOOK=y
CONFIG_USER_RETURN_NOTIFIER=y
CONFIG_HAVE_IOREMAP_PROT=y
CONFIG_HAVE_KPROBES=y
CONFIG_HAVE_KRETPROBES=y
CONFIG_HAVE_OPTPROBES=y
CONFIG_HAVE_KPROBES_ON_FTRACE=y
CONFIG_ARCH_CORRECT_STACKTRACE_ON_KRETPROBE=y
CONFIG_HAVE_FUNCTION_ERROR_INJECTION=y
CONFIG_HAVE_NMI=y
CONFIG_TRACE_IRQFLAGS_SUPPORT=y
CONFIG_TRACE_IRQFLAGS_NMI_SUPPORT=y
CONFIG_HAVE_ARCH_TRACEHOOK=y
CONFIG_HAVE_DMA_CONTIGUOUS=y
CONFIG_GENERIC_SMP_IDLE_THREAD=y
CONFIG_ARCH_HAS_FORTIFY_SOURCE=y
CONFIG_ARCH_HAS_SET_MEMORY=y
CONFIG_ARCH_HAS_SET_DIRECT_MAP=y
CONFIG_HAVE_ARCH_THREAD_STRUCT_WHITELIST=y
CONFIG_ARCH_WANTS_DYNAMIC_TASK_STRUCT=y
CONFIG_ARCH_WANTS_NO_INSTR=y
CONFIG_HAVE_ASM_MODVERSIONS=y
CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y
CONFIG_HAVE_RSEQ=y
CONFIG_HAVE_RUST=y
CONFIG_HAVE_FUNCTION_ARG_ACCESS_API=y
CONFIG_HAVE_HW_BREAKPOINT=y
CONFIG_HAVE_MIXED_BREAKPOINTS_REGS=y
CONFIG_HAVE_USER_RETURN_NOTIFIER=y
CONFIG_HAVE_PERF_EVENTS_NMI=y
CONFIG_HAVE_HARDLOCKUP_DETECTOR_PERF=y
CONFIG_HAVE_PERF_REGS=y
CONFIG_HAVE_PERF_USER_STACK_DUMP=y
CONFIG_HAVE_ARCH_JUMP_LABEL=y
CONFIG_HAVE_ARCH_JUMP_LABEL_RELATIVE=y
CONFIG_MMU_GATHER_TABLE_FREE=y
CONFIG_MMU_GATHER_RCU_TABLE_FREE=y
CONFIG_MMU_GATHER_MERGE_VMAS=y
CONFIG_ARCH_HAVE_NMI_SAFE_CMPXCHG=y
CONFIG_HAVE_ALIGNED_STRUCT_PAGE=y
CONFIG_HAVE_CMPXCHG_LOCAL=y
CONFIG_HAVE_CMPXCHG_DOUBLE=y
CONFIG_ARCH_WANT_COMPAT_IPC_PARSE_VERSION=y
CONFIG_ARCH_WANT_OLD_COMPAT_IPC=y
CONFIG_HAVE_ARCH_SECCOMP=y
CONFIG_HAVE_ARCH_SECCOMP_FILTER=y
CONFIG_SECCOMP=y
CONFIG_SECCOMP_FILTER=y
# CONFIG_SECCOMP_CACHE_DEBUG is not set
CONFIG_HAVE_ARCH_STACKLEAK=y
CONFIG_HAVE_STACKPROTECTOR=y
CONFIG_STACKPROTECTOR=y
CONFIG_STACKPROTECTOR_STRONG=y
CONFIG_ARCH_SUPPORTS_LTO_CLANG=y
CONFIG_ARCH_SUPPORTS_LTO_CLANG_THIN=y
CONFIG_HAS_LTO_CLANG=y
CONFIG_LTO_NONE=y
# CONFIG_LTO_CLANG_FULL is not set
# CONFIG_LTO_CLANG_THIN is not set
CONFIG_ARCH_SUPPORTS_CFI_CLANG=y
CONFIG_HAVE_ARCH_WITHIN_STACK_FRAMES=y
CONFIG_HAVE_CONTEXT_TRACKING_USER=y
CONFIG_HAVE_CONTEXT_TRACKING_USER_OFFSTACK=y
CONFIG_HAVE_VIRT_CPU_ACCOUNTING_GEN=y
CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y
CONFIG_HAVE_MOVE_PUD=y
CONFIG_HAVE_MOVE_PMD=y
CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE=y
CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE_PUD=y
CONFIG_HAVE_ARCH_HUGE_VMAP=y
CONFIG_HAVE_ARCH_HUGE_VMALLOC=y
CONFIG_ARCH_WANT_HUGE_PMD_SHARE=y
CONFIG_HAVE_ARCH_SOFT_DIRTY=y
CONFIG_HAVE_MOD_ARCH_SPECIFIC=y
CONFIG_MODULES_USE_ELF_RELA=y
CONFIG_HAVE_IRQ_EXIT_ON_IRQ_STACK=y
CONFIG_HAVE_SOFTIRQ_ON_OWN_STACK=y
CONFIG_SOFTIRQ_ON_OWN_STACK=y
CONFIG_ARCH_HAS_ELF_RANDOMIZE=y
CONFIG_HAVE_ARCH_MMAP_RND_BITS=y
CONFIG_HAVE_EXIT_THREAD=y
CONFIG_ARCH_MMAP_RND_BITS=28
CONFIG_HAVE_ARCH_MMAP_RND_COMPAT_BITS=y
CONFIG_ARCH_MMAP_RND_COMPAT_BITS=8
CONFIG_HAVE_ARCH_COMPAT_MMAP_BASES=y
CONFIG_PAGE_SIZE_LESS_THAN_64KB=y
CONFIG_PAGE_SIZE_LESS_THAN_256KB=y
CONFIG_HAVE_OBJTOOL=y
CONFIG_HAVE_JUMP_LABEL_HACK=y
CONFIG_HAVE_NOINSTR_HACK=y
CONFIG_HAVE_NOINSTR_VALIDATION=y
CONFIG_HAVE_UACCESS_VALIDATION=y
CONFIG_HAVE_STACK_VALIDATION=y
CONFIG_HAVE_RELIABLE_STACKTRACE=y
CONFIG_OLD_SIGSUSPEND3=y
CONFIG_COMPAT_OLD_SIGACTION=y
CONFIG_COMPAT_32BIT_TIME=y
CONFIG_HAVE_ARCH_VMAP_STACK=y
CONFIG_VMAP_STACK=y
CONFIG_HAVE_ARCH_RANDOMIZE_KSTACK_OFFSET=y
CONFIG_RANDOMIZE_KSTACK_OFFSET=y
# CONFIG_RANDOMIZE_KSTACK_OFFSET_DEFAULT is not set
CONFIG_ARCH_HAS_STRICT_KERNEL_RWX=y
CONFIG_STRICT_KERNEL_RWX=y
CONFIG_ARCH_HAS_STRICT_MODULE_RWX=y
CONFIG_STRICT_MODULE_RWX=y
CONFIG_HAVE_ARCH_PREL32_RELOCATIONS=y
CONFIG_ARCH_USE_MEMREMAP_PROT=y
# CONFIG_LOCK_EVENT_COUNTS is not set
CONFIG_ARCH_HAS_MEM_ENCRYPT=y
CONFIG_ARCH_HAS_CC_PLATFORM=y
CONFIG_HAVE_STATIC_CALL=y
CONFIG_HAVE_STATIC_CALL_INLINE=y
CONFIG_HAVE_PREEMPT_DYNAMIC=y
CONFIG_HAVE_PREEMPT_DYNAMIC_CALL=y
CONFIG_ARCH_WANT_LD_ORPHAN_WARN=y
CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC=y
CONFIG_ARCH_SUPPORTS_PAGE_TABLE_CHECK=y
CONFIG_ARCH_HAS_ELFCORE_COMPAT=y
CONFIG_ARCH_HAS_PARANOID_L1D_FLUSH=y
CONFIG_DYNAMIC_SIGFRAME=y
CONFIG_ARCH_HAS_NONLEAF_PMD_YOUNG=y

#
# GCOV-based kernel profiling
#
# CONFIG_GCOV_KERNEL is not set
CONFIG_ARCH_HAS_GCOV_PROFILE_ALL=y
# end of GCOV-based kernel profiling

CONFIG_HAVE_GCC_PLUGINS=y
# end of General architecture-dependent options

CONFIG_RT_MUTEXES=y
CONFIG_BASE_SMALL=0
CONFIG_MODULE_SIG_FORMAT=y
CONFIG_MODULES=y
CONFIG_MODULE_FORCE_LOAD=y
CONFIG_MODULE_UNLOAD=y
# CONFIG_MODULE_FORCE_UNLOAD is not set
# CONFIG_MODULE_UNLOAD_TAINT_TRACKING is not set
# CONFIG_MODVERSIONS is not set
# CONFIG_MODULE_SRCVERSION_ALL is not set
CONFIG_MODULE_SIG=y
# CONFIG_MODULE_SIG_FORCE is not set
CONFIG_MODULE_SIG_ALL=y
# CONFIG_MODULE_SIG_SHA1 is not set
# CONFIG_MODULE_SIG_SHA224 is not set
CONFIG_MODULE_SIG_SHA256=y
# CONFIG_MODULE_SIG_SHA384 is not set
# CONFIG_MODULE_SIG_SHA512 is not set
CONFIG_MODULE_SIG_HASH="sha256"
CONFIG_MODULE_COMPRESS_NONE=y
# CONFIG_MODULE_COMPRESS_GZIP is not set
# CONFIG_MODULE_COMPRESS_XZ is not set
# CONFIG_MODULE_COMPRESS_ZSTD is not set
# CONFIG_MODULE_ALLOW_MISSING_NAMESPACE_IMPORTS is not set
CONFIG_MODPROBE_PATH="/sbin/modprobe"
CONFIG_MODULES_TREE_LOOKUP=y
CONFIG_BLOCK=y
CONFIG_BLOCK_LEGACY_AUTOLOAD=y
CONFIG_BLK_CGROUP_RWSTAT=y
CONFIG_BLK_DEV_BSG_COMMON=y
CONFIG_BLK_ICQ=y
CONFIG_BLK_DEV_BSGLIB=y
CONFIG_BLK_DEV_INTEGRITY=y
CONFIG_BLK_DEV_INTEGRITY_T10=m
# CONFIG_BLK_DEV_ZONED is not set
CONFIG_BLK_DEV_THROTTLING=y
# CONFIG_BLK_DEV_THROTTLING_LOW is not set
CONFIG_BLK_WBT=y
CONFIG_BLK_WBT_MQ=y
# CONFIG_BLK_CGROUP_IOLATENCY is not set
# CONFIG_BLK_CGROUP_IOCOST is not set
# CONFIG_BLK_CGROUP_IOPRIO is not set
CONFIG_BLK_DEBUG_FS=y
# CONFIG_BLK_SED_OPAL is not set
# CONFIG_BLK_INLINE_ENCRYPTION is not set

#
# Partition Types
#
# CONFIG_PARTITION_ADVANCED is not set
CONFIG_MSDOS_PARTITION=y
CONFIG_EFI_PARTITION=y
# end of Partition Types

CONFIG_BLOCK_COMPAT=y
CONFIG_BLK_MQ_PCI=y
CONFIG_BLK_MQ_VIRTIO=y
CONFIG_BLK_PM=y
CONFIG_BLOCK_HOLDER_DEPRECATED=y
CONFIG_BLK_MQ_STACKING=y

#
# IO Schedulers
#
CONFIG_MQ_IOSCHED_DEADLINE=y
CONFIG_MQ_IOSCHED_KYBER=y
CONFIG_IOSCHED_BFQ=y
CONFIG_BFQ_GROUP_IOSCHED=y
# CONFIG_BFQ_CGROUP_DEBUG is not set
# end of IO Schedulers

CONFIG_PREEMPT_NOTIFIERS=y
CONFIG_PADATA=y
CONFIG_ASN1=y
CONFIG_INLINE_SPIN_UNLOCK_IRQ=y
CONFIG_INLINE_READ_UNLOCK=y
CONFIG_INLINE_READ_UNLOCK_IRQ=y
CONFIG_INLINE_WRITE_UNLOCK=y
CONFIG_INLINE_WRITE_UNLOCK_IRQ=y
CONFIG_ARCH_SUPPORTS_ATOMIC_RMW=y
CONFIG_MUTEX_SPIN_ON_OWNER=y
CONFIG_RWSEM_SPIN_ON_OWNER=y
CONFIG_LOCK_SPIN_ON_OWNER=y
CONFIG_ARCH_USE_QUEUED_SPINLOCKS=y
CONFIG_QUEUED_SPINLOCKS=y
CONFIG_ARCH_USE_QUEUED_RWLOCKS=y
CONFIG_QUEUED_RWLOCKS=y
CONFIG_ARCH_HAS_NON_OVERLAPPING_ADDRESS_SPACE=y
CONFIG_ARCH_HAS_SYNC_CORE_BEFORE_USERMODE=y
CONFIG_ARCH_HAS_SYSCALL_WRAPPER=y
CONFIG_FREEZER=y

#
# Executable file formats
#
CONFIG_BINFMT_ELF=y
CONFIG_COMPAT_BINFMT_ELF=y
CONFIG_ELFCORE=y
CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS=y
CONFIG_BINFMT_SCRIPT=y
CONFIG_BINFMT_MISC=m
CONFIG_COREDUMP=y
# end of Executable file formats

#
# Memory Management options
#
CONFIG_ZPOOL=y
CONFIG_SWAP=y
CONFIG_ZSWAP=y
# CONFIG_ZSWAP_DEFAULT_ON is not set
# CONFIG_ZSWAP_COMPRESSOR_DEFAULT_DEFLATE is not set
CONFIG_ZSWAP_COMPRESSOR_DEFAULT_LZO=y
# CONFIG_ZSWAP_COMPRESSOR_DEFAULT_842 is not set
# CONFIG_ZSWAP_COMPRESSOR_DEFAULT_LZ4 is not set
# CONFIG_ZSWAP_COMPRESSOR_DEFAULT_LZ4HC is not set
# CONFIG_ZSWAP_COMPRESSOR_DEFAULT_ZSTD is not set
CONFIG_ZSWAP_COMPRESSOR_DEFAULT="lzo"
CONFIG_ZSWAP_ZPOOL_DEFAULT_ZBUD=y
# CONFIG_ZSWAP_ZPOOL_DEFAULT_Z3FOLD is not set
# CONFIG_ZSWAP_ZPOOL_DEFAULT_ZSMALLOC is not set
CONFIG_ZSWAP_ZPOOL_DEFAULT="zbud"
CONFIG_ZBUD=y
# CONFIG_Z3FOLD is not set
CONFIG_ZSMALLOC=y
CONFIG_ZSMALLOC_STAT=y

#
# SLAB allocator options
#
# CONFIG_SLAB is not set
CONFIG_SLUB=y
CONFIG_SLAB_MERGE_DEFAULT=y
CONFIG_SLAB_FREELIST_RANDOM=y
# CONFIG_SLAB_FREELIST_HARDENED is not set
# CONFIG_SLUB_STATS is not set
CONFIG_SLUB_CPU_PARTIAL=y
# end of SLAB allocator options

CONFIG_SHUFFLE_PAGE_ALLOCATOR=y
# CONFIG_COMPAT_BRK is not set
CONFIG_SPARSEMEM=y
CONFIG_SPARSEMEM_EXTREME=y
CONFIG_SPARSEMEM_VMEMMAP_ENABLE=y
CONFIG_SPARSEMEM_VMEMMAP=y
CONFIG_HAVE_FAST_GUP=y
CONFIG_NUMA_KEEP_MEMINFO=y
CONFIG_MEMORY_ISOLATION=y
CONFIG_EXCLUSIVE_SYSTEM_RAM=y
CONFIG_HAVE_BOOTMEM_INFO_NODE=y
CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
CONFIG_ARCH_ENABLE_MEMORY_HOTREMOVE=y
CONFIG_MEMORY_HOTPLUG=y
# CONFIG_MEMORY_HOTPLUG_DEFAULT_ONLINE is not set
CONFIG_MEMORY_HOTREMOVE=y
CONFIG_MHP_MEMMAP_ON_MEMORY=y
CONFIG_SPLIT_PTLOCK_CPUS=4
CONFIG_ARCH_ENABLE_SPLIT_PMD_PTLOCK=y
CONFIG_MEMORY_BALLOON=y
CONFIG_BALLOON_COMPACTION=y
CONFIG_COMPACTION=y
CONFIG_COMPACT_UNEVICTABLE_DEFAULT=1
CONFIG_PAGE_REPORTING=y
CONFIG_MIGRATION=y
CONFIG_DEVICE_MIGRATION=y
CONFIG_ARCH_ENABLE_HUGEPAGE_MIGRATION=y
CONFIG_ARCH_ENABLE_THP_MIGRATION=y
CONFIG_CONTIG_ALLOC=y
CONFIG_PHYS_ADDR_T_64BIT=y
CONFIG_MMU_NOTIFIER=y
CONFIG_KSM=y
CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
CONFIG_ARCH_SUPPORTS_MEMORY_FAILURE=y
CONFIG_MEMORY_FAILURE=y
CONFIG_HWPOISON_INJECT=m
CONFIG_ARCH_WANT_GENERAL_HUGETLB=y
CONFIG_ARCH_WANTS_THP_SWAP=y
CONFIG_TRANSPARENT_HUGEPAGE=y
CONFIG_TRANSPARENT_HUGEPAGE_ALWAYS=y
# CONFIG_TRANSPARENT_HUGEPAGE_MADVISE is not set
CONFIG_THP_SWAP=y
# CONFIG_READ_ONLY_THP_FOR_FS is not set
CONFIG_NEED_PER_CPU_EMBED_FIRST_CHUNK=y
CONFIG_NEED_PER_CPU_PAGE_FIRST_CHUNK=y
CONFIG_USE_PERCPU_NUMA_NODE_ID=y
CONFIG_HAVE_SETUP_PER_CPU_AREA=y
CONFIG_FRONTSWAP=y
# CONFIG_CMA is not set
CONFIG_GENERIC_EARLY_IOREMAP=y
CONFIG_DEFERRED_STRUCT_PAGE_INIT=y
CONFIG_PAGE_IDLE_FLAG=y
CONFIG_IDLE_PAGE_TRACKING=y
CONFIG_ARCH_HAS_CACHE_LINE_SIZE=y
CONFIG_ARCH_HAS_CURRENT_STACK_POINTER=y
CONFIG_ARCH_HAS_PTE_DEVMAP=y
CONFIG_ZONE_DMA=y
CONFIG_ZONE_DMA32=y
CONFIG_ZONE_DEVICE=y
CONFIG_GET_FREE_REGION=y
CONFIG_DEVICE_PRIVATE=y
CONFIG_VMAP_PFN=y
CONFIG_ARCH_USES_HIGH_VMA_FLAGS=y
CONFIG_ARCH_HAS_PKEYS=y
CONFIG_VM_EVENT_COUNTERS=y
# CONFIG_PERCPU_STATS is not set
# CONFIG_GUP_TEST is not set
CONFIG_ARCH_HAS_PTE_SPECIAL=y
CONFIG_SECRETMEM=y
# CONFIG_ANON_VMA_NAME is not set
# CONFIG_USERFAULTFD is not set
# CONFIG_LRU_GEN is not set

#
# Data Access Monitoring
#
# CONFIG_DAMON is not set
# end of Data Access Monitoring
# end of Memory Management options

CONFIG_NET=y
CONFIG_NET_INGRESS=y
CONFIG_NET_EGRESS=y
CONFIG_SKB_EXTENSIONS=y

#
# Networking options
#
CONFIG_PACKET=y
CONFIG_PACKET_DIAG=m
CONFIG_UNIX=y
CONFIG_UNIX_SCM=y
CONFIG_AF_UNIX_OOB=y
CONFIG_UNIX_DIAG=m
CONFIG_TLS=m
CONFIG_TLS_DEVICE=y
# CONFIG_TLS_TOE is not set
CONFIG_XFRM=y
CONFIG_XFRM_OFFLOAD=y
CONFIG_XFRM_ALGO=y
CONFIG_XFRM_USER=y
# CONFIG_XFRM_USER_COMPAT is not set
# CONFIG_XFRM_INTERFACE is not set
CONFIG_XFRM_SUB_POLICY=y
CONFIG_XFRM_MIGRATE=y
CONFIG_XFRM_STATISTICS=y
CONFIG_XFRM_AH=m
CONFIG_XFRM_ESP=m
CONFIG_XFRM_IPCOMP=m
CONFIG_NET_KEY=m
CONFIG_NET_KEY_MIGRATE=y
CONFIG_XDP_SOCKETS=y
# CONFIG_XDP_SOCKETS_DIAG is not set
CONFIG_INET=y
CONFIG_IP_MULTICAST=y
CONFIG_IP_ADVANCED_ROUTER=y
CONFIG_IP_FIB_TRIE_STATS=y
CONFIG_IP_MULTIPLE_TABLES=y
CONFIG_IP_ROUTE_MULTIPATH=y
CONFIG_IP_ROUTE_VERBOSE=y
CONFIG_IP_ROUTE_CLASSID=y
CONFIG_IP_PNP=y
CONFIG_IP_PNP_DHCP=y
# CONFIG_IP_PNP_BOOTP is not set
# CONFIG_IP_PNP_RARP is not set
CONFIG_NET_IPIP=m
CONFIG_NET_IPGRE_DEMUX=m
CONFIG_NET_IP_TUNNEL=m
CONFIG_NET_IPGRE=m
CONFIG_NET_IPGRE_BROADCAST=y
CONFIG_IP_MROUTE_COMMON=y
CONFIG_IP_MROUTE=y
CONFIG_IP_MROUTE_MULTIPLE_TABLES=y
CONFIG_IP_PIMSM_V1=y
CONFIG_IP_PIMSM_V2=y
CONFIG_SYN_COOKIES=y
CONFIG_NET_IPVTI=m
CONFIG_NET_UDP_TUNNEL=m
# CONFIG_NET_FOU is not set
# CONFIG_NET_FOU_IP_TUNNELS is not set
CONFIG_INET_AH=m
CONFIG_INET_ESP=m
CONFIG_INET_ESP_OFFLOAD=m
# CONFIG_INET_ESPINTCP is not set
CONFIG_INET_IPCOMP=m
CONFIG_INET_XFRM_TUNNEL=m
CONFIG_INET_TUNNEL=m
CONFIG_INET_DIAG=m
CONFIG_INET_TCP_DIAG=m
CONFIG_INET_UDP_DIAG=m
CONFIG_INET_RAW_DIAG=m
# CONFIG_INET_DIAG_DESTROY is not set
CONFIG_TCP_CONG_ADVANCED=y
CONFIG_TCP_CONG_BIC=m
CONFIG_TCP_CONG_CUBIC=y
CONFIG_TCP_CONG_WESTWOOD=m
CONFIG_TCP_CONG_HTCP=m
CONFIG_TCP_CONG_HSTCP=m
CONFIG_TCP_CONG_HYBLA=m
CONFIG_TCP_CONG_VEGAS=m
CONFIG_TCP_CONG_NV=m
CONFIG_TCP_CONG_SCALABLE=m
CONFIG_TCP_CONG_LP=m
CONFIG_TCP_CONG_VENO=m
CONFIG_TCP_CONG_YEAH=m
CONFIG_TCP_CONG_ILLINOIS=m
CONFIG_TCP_CONG_DCTCP=m
# CONFIG_TCP_CONG_CDG is not set
CONFIG_TCP_CONG_BBR=m
CONFIG_DEFAULT_CUBIC=y
# CONFIG_DEFAULT_RENO is not set
CONFIG_DEFAULT_TCP_CONG="cubic"
CONFIG_TCP_MD5SIG=y
CONFIG_IPV6=y
CONFIG_IPV6_ROUTER_PREF=y
CONFIG_IPV6_ROUTE_INFO=y
CONFIG_IPV6_OPTIMISTIC_DAD=y
CONFIG_INET6_AH=m
CONFIG_INET6_ESP=m
CONFIG_INET6_ESP_OFFLOAD=m
# CONFIG_INET6_ESPINTCP is not set
CONFIG_INET6_IPCOMP=m
CONFIG_IPV6_MIP6=m
# CONFIG_IPV6_ILA is not set
CONFIG_INET6_XFRM_TUNNEL=m
CONFIG_INET6_TUNNEL=m
CONFIG_IPV6_VTI=m
CONFIG_IPV6_SIT=m
CONFIG_IPV6_SIT_6RD=y
CONFIG_IPV6_NDISC_NODETYPE=y
CONFIG_IPV6_TUNNEL=m
CONFIG_IPV6_GRE=m
CONFIG_IPV6_MULTIPLE_TABLES=y
# CONFIG_IPV6_SUBTREES is not set
CONFIG_IPV6_MROUTE=y
CONFIG_IPV6_MROUTE_MULTIPLE_TABLES=y
CONFIG_IPV6_PIMSM_V2=y
# CONFIG_IPV6_SEG6_LWTUNNEL is not set
# CONFIG_IPV6_SEG6_HMAC is not set
# CONFIG_IPV6_RPL_LWTUNNEL is not set
# CONFIG_IPV6_IOAM6_LWTUNNEL is not set
CONFIG_NETLABEL=y
# CONFIG_MPTCP is not set
CONFIG_NETWORK_SECMARK=y
CONFIG_NET_PTP_CLASSIFY=y
CONFIG_NETWORK_PHY_TIMESTAMPING=y
CONFIG_NETFILTER=y
CONFIG_NETFILTER_ADVANCED=y
CONFIG_BRIDGE_NETFILTER=m

#
# Core Netfilter Configuration
#
CONFIG_NETFILTER_INGRESS=y
CONFIG_NETFILTER_EGRESS=y
CONFIG_NETFILTER_SKIP_EGRESS=y
CONFIG_NETFILTER_NETLINK=m
CONFIG_NETFILTER_FAMILY_BRIDGE=y
CONFIG_NETFILTER_FAMILY_ARP=y
# CONFIG_NETFILTER_NETLINK_HOOK is not set
# CONFIG_NETFILTER_NETLINK_ACCT is not set
CONFIG_NETFILTER_NETLINK_QUEUE=m
CONFIG_NETFILTER_NETLINK_LOG=m
CONFIG_NETFILTER_NETLINK_OSF=m
CONFIG_NF_CONNTRACK=m
CONFIG_NF_LOG_SYSLOG=m
CONFIG_NETFILTER_CONNCOUNT=m
CONFIG_NF_CONNTRACK_MARK=y
CONFIG_NF_CONNTRACK_SECMARK=y
CONFIG_NF_CONNTRACK_ZONES=y
CONFIG_NF_CONNTRACK_PROCFS=y
CONFIG_NF_CONNTRACK_EVENTS=y
CONFIG_NF_CONNTRACK_TIMEOUT=y
CONFIG_NF_CONNTRACK_TIMESTAMP=y
CONFIG_NF_CONNTRACK_LABELS=y
CONFIG_NF_CT_PROTO_DCCP=y
CONFIG_NF_CT_PROTO_GRE=y
CONFIG_NF_CT_PROTO_SCTP=y
CONFIG_NF_CT_PROTO_UDPLITE=y
CONFIG_NF_CONNTRACK_AMANDA=m
CONFIG_NF_CONNTRACK_FTP=m
CONFIG_NF_CONNTRACK_H323=m
CONFIG_NF_CONNTRACK_IRC=m
CONFIG_NF_CONNTRACK_BROADCAST=m
CONFIG_NF_CONNTRACK_NETBIOS_NS=m
CONFIG_NF_CONNTRACK_SNMP=m
CONFIG_NF_CONNTRACK_PPTP=m
CONFIG_NF_CONNTRACK_SANE=m
CONFIG_NF_CONNTRACK_SIP=m
CONFIG_NF_CONNTRACK_TFTP=m
CONFIG_NF_CT_NETLINK=m
CONFIG_NF_CT_NETLINK_TIMEOUT=m
CONFIG_NF_CT_NETLINK_HELPER=m
CONFIG_NETFILTER_NETLINK_GLUE_CT=y
CONFIG_NF_NAT=m
CONFIG_NF_NAT_AMANDA=m
CONFIG_NF_NAT_FTP=m
CONFIG_NF_NAT_IRC=m
CONFIG_NF_NAT_SIP=m
CONFIG_NF_NAT_TFTP=m
CONFIG_NF_NAT_REDIRECT=y
CONFIG_NF_NAT_MASQUERADE=y
CONFIG_NETFILTER_SYNPROXY=m
CONFIG_NF_TABLES=m
CONFIG_NF_TABLES_INET=y
CONFIG_NF_TABLES_NETDEV=y
CONFIG_NFT_NUMGEN=m
CONFIG_NFT_CT=m
CONFIG_NFT_CONNLIMIT=m
CONFIG_NFT_LOG=m
CONFIG_NFT_LIMIT=m
CONFIG_NFT_MASQ=m
CONFIG_NFT_REDIR=m
CONFIG_NFT_NAT=m
# CONFIG_NFT_TUNNEL is not set
# CONFIG_NFT_OBJREF is not set
CONFIG_NFT_QUEUE=m
CONFIG_NFT_QUOTA=m
CONFIG_NFT_REJECT=m
CONFIG_NFT_REJECT_INET=m
CONFIG_NFT_COMPAT=m
CONFIG_NFT_HASH=m
CONFIG_NFT_FIB=m
CONFIG_NFT_FIB_INET=m
# CONFIG_NFT_XFRM is not set
CONFIG_NFT_SOCKET=m
# CONFIG_NFT_OSF is not set
# CONFIG_NFT_TPROXY is not set
# CONFIG_NFT_SYNPROXY is not set
CONFIG_NF_DUP_NETDEV=m
CONFIG_NFT_DUP_NETDEV=m
CONFIG_NFT_FWD_NETDEV=m
CONFIG_NFT_FIB_NETDEV=m
# CONFIG_NFT_REJECT_NETDEV is not set
# CONFIG_NF_FLOW_TABLE is not set
CONFIG_NETFILTER_XTABLES=y
CONFIG_NETFILTER_XTABLES_COMPAT=y

#
# Xtables combined modules
#
CONFIG_NETFILTER_XT_MARK=m
CONFIG_NETFILTER_XT_CONNMARK=m
CONFIG_NETFILTER_XT_SET=m

#
# Xtables targets
#
CONFIG_NETFILTER_XT_TARGET_AUDIT=m
CONFIG_NETFILTER_XT_TARGET_CHECKSUM=m
CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
CONFIG_NETFILTER_XT_TARGET_CONNMARK=m
CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=m
CONFIG_NETFILTER_XT_TARGET_CT=m
CONFIG_NETFILTER_XT_TARGET_DSCP=m
CONFIG_NETFILTER_XT_TARGET_HL=m
CONFIG_NETFILTER_XT_TARGET_HMARK=m
CONFIG_NETFILTER_XT_TARGET_IDLETIMER=m
# CONFIG_NETFILTER_XT_TARGET_LED is not set
CONFIG_NETFILTER_XT_TARGET_LOG=m
CONFIG_NETFILTER_XT_TARGET_MARK=m
CONFIG_NETFILTER_XT_NAT=m
CONFIG_NETFILTER_XT_TARGET_NETMAP=m
CONFIG_NETFILTER_XT_TARGET_NFLOG=m
CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m
CONFIG_NETFILTER_XT_TARGET_NOTRACK=m
CONFIG_NETFILTER_XT_TARGET_RATEEST=m
CONFIG_NETFILTER_XT_TARGET_REDIRECT=m
CONFIG_NETFILTER_XT_TARGET_MASQUERADE=m
CONFIG_NETFILTER_XT_TARGET_TEE=m
CONFIG_NETFILTER_XT_TARGET_TPROXY=m
CONFIG_NETFILTER_XT_TARGET_TRACE=m
CONFIG_NETFILTER_XT_TARGET_SECMARK=m
CONFIG_NETFILTER_XT_TARGET_TCPMSS=m
CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP=m

#
# Xtables matches
#
CONFIG_NETFILTER_XT_MATCH_ADDRTYPE=m
CONFIG_NETFILTER_XT_MATCH_BPF=m
CONFIG_NETFILTER_XT_MATCH_CGROUP=m
CONFIG_NETFILTER_XT_MATCH_CLUSTER=m
CONFIG_NETFILTER_XT_MATCH_COMMENT=m
CONFIG_NETFILTER_XT_MATCH_CONNBYTES=m
CONFIG_NETFILTER_XT_MATCH_CONNLABEL=m
CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=m
CONFIG_NETFILTER_XT_MATCH_CONNMARK=m
CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m
CONFIG_NETFILTER_XT_MATCH_CPU=m
CONFIG_NETFILTER_XT_MATCH_DCCP=m
CONFIG_NETFILTER_XT_MATCH_DEVGROUP=m
CONFIG_NETFILTER_XT_MATCH_DSCP=m
CONFIG_NETFILTER_XT_MATCH_ECN=m
CONFIG_NETFILTER_XT_MATCH_ESP=m
CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=m
CONFIG_NETFILTER_XT_MATCH_HELPER=m
CONFIG_NETFILTER_XT_MATCH_HL=m
# CONFIG_NETFILTER_XT_MATCH_IPCOMP is not set
CONFIG_NETFILTER_XT_MATCH_IPRANGE=m
CONFIG_NETFILTER_XT_MATCH_IPVS=m
# CONFIG_NETFILTER_XT_MATCH_L2TP is not set
CONFIG_NETFILTER_XT_MATCH_LENGTH=m
CONFIG_NETFILTER_XT_MATCH_LIMIT=m
CONFIG_NETFILTER_XT_MATCH_MAC=m
CONFIG_NETFILTER_XT_MATCH_MARK=m
CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m
# CONFIG_NETFILTER_XT_MATCH_NFACCT is not set
CONFIG_NETFILTER_XT_MATCH_OSF=m
CONFIG_NETFILTER_XT_MATCH_OWNER=m
CONFIG_NETFILTER_XT_MATCH_POLICY=m
CONFIG_NETFILTER_XT_MATCH_PHYSDEV=m
CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m
CONFIG_NETFILTER_XT_MATCH_QUOTA=m
CONFIG_NETFILTER_XT_MATCH_RATEEST=m
CONFIG_NETFILTER_XT_MATCH_REALM=m
CONFIG_NETFILTER_XT_MATCH_RECENT=m
CONFIG_NETFILTER_XT_MATCH_SCTP=m
CONFIG_NETFILTER_XT_MATCH_SOCKET=m
CONFIG_NETFILTER_XT_MATCH_STATE=m
CONFIG_NETFILTER_XT_MATCH_STATISTIC=m
CONFIG_NETFILTER_XT_MATCH_STRING=m
CONFIG_NETFILTER_XT_MATCH_TCPMSS=m
# CONFIG_NETFILTER_XT_MATCH_TIME is not set
# CONFIG_NETFILTER_XT_MATCH_U32 is not set
# end of Core Netfilter Configuration

CONFIG_IP_SET=m
CONFIG_IP_SET_MAX=256
CONFIG_IP_SET_BITMAP_IP=m
CONFIG_IP_SET_BITMAP_IPMAC=m
CONFIG_IP_SET_BITMAP_PORT=m
CONFIG_IP_SET_HASH_IP=m
CONFIG_IP_SET_HASH_IPMARK=m
CONFIG_IP_SET_HASH_IPPORT=m
CONFIG_IP_SET_HASH_IPPORTIP=m
CONFIG_IP_SET_HASH_IPPORTNET=m
CONFIG_IP_SET_HASH_IPMAC=m
CONFIG_IP_SET_HASH_MAC=m
CONFIG_IP_SET_HASH_NETPORTNET=m
CONFIG_IP_SET_HASH_NET=m
CONFIG_IP_SET_HASH_NETNET=m
CONFIG_IP_SET_HASH_NETPORT=m
CONFIG_IP_SET_HASH_NETIFACE=m
CONFIG_IP_SET_LIST_SET=m
CONFIG_IP_VS=m
CONFIG_IP_VS_IPV6=y
# CONFIG_IP_VS_DEBUG is not set
CONFIG_IP_VS_TAB_BITS=12

#
# IPVS transport protocol load balancing support
#
CONFIG_IP_VS_PROTO_TCP=y
CONFIG_IP_VS_PROTO_UDP=y
CONFIG_IP_VS_PROTO_AH_ESP=y
CONFIG_IP_VS_PROTO_ESP=y
CONFIG_IP_VS_PROTO_AH=y
CONFIG_IP_VS_PROTO_SCTP=y

#
# IPVS scheduler
#
CONFIG_IP_VS_RR=m
CONFIG_IP_VS_WRR=m
CONFIG_IP_VS_LC=m
CONFIG_IP_VS_WLC=m
CONFIG_IP_VS_FO=m
CONFIG_IP_VS_OVF=m
CONFIG_IP_VS_LBLC=m
CONFIG_IP_VS_LBLCR=m
CONFIG_IP_VS_DH=m
CONFIG_IP_VS_SH=m
# CONFIG_IP_VS_MH is not set
CONFIG_IP_VS_SED=m
CONFIG_IP_VS_NQ=m
# CONFIG_IP_VS_TWOS is not set

#
# IPVS SH scheduler
#
CONFIG_IP_VS_SH_TAB_BITS=8

#
# IPVS MH scheduler
#
CONFIG_IP_VS_MH_TAB_INDEX=12

#
# IPVS application helper
#
CONFIG_IP_VS_FTP=m
CONFIG_IP_VS_NFCT=y
CONFIG_IP_VS_PE_SIP=m

#
# IP: Netfilter Configuration
#
CONFIG_NF_DEFRAG_IPV4=m
CONFIG_NF_SOCKET_IPV4=m
CONFIG_NF_TPROXY_IPV4=m
CONFIG_NF_TABLES_IPV4=y
CONFIG_NFT_REJECT_IPV4=m
CONFIG_NFT_DUP_IPV4=m
CONFIG_NFT_FIB_IPV4=m
CONFIG_NF_TABLES_ARP=y
CONFIG_NF_DUP_IPV4=m
CONFIG_NF_LOG_ARP=m
CONFIG_NF_LOG_IPV4=m
CONFIG_NF_REJECT_IPV4=m
CONFIG_NF_NAT_SNMP_BASIC=m
CONFIG_NF_NAT_PPTP=m
CONFIG_NF_NAT_H323=m
CONFIG_IP_NF_IPTABLES=m
CONFIG_IP_NF_MATCH_AH=m
CONFIG_IP_NF_MATCH_ECN=m
CONFIG_IP_NF_MATCH_RPFILTER=m
CONFIG_IP_NF_MATCH_TTL=m
CONFIG_IP_NF_FILTER=m
CONFIG_IP_NF_TARGET_REJECT=m
CONFIG_IP_NF_TARGET_SYNPROXY=m
CONFIG_IP_NF_NAT=m
CONFIG_IP_NF_TARGET_MASQUERADE=m
CONFIG_IP_NF_TARGET_NETMAP=m
CONFIG_IP_NF_TARGET_REDIRECT=m
CONFIG_IP_NF_MANGLE=m
# CONFIG_IP_NF_TARGET_CLUSTERIP is not set
CONFIG_IP_NF_TARGET_ECN=m
CONFIG_IP_NF_TARGET_TTL=m
CONFIG_IP_NF_RAW=m
CONFIG_IP_NF_SECURITY=m
CONFIG_IP_NF_ARPTABLES=m
CONFIG_IP_NF_ARPFILTER=m
CONFIG_IP_NF_ARP_MANGLE=m
# end of IP: Netfilter Configuration

#
# IPv6: Netfilter Configuration
#
CONFIG_NF_SOCKET_IPV6=m
CONFIG_NF_TPROXY_IPV6=m
CONFIG_NF_TABLES_IPV6=y
CONFIG_NFT_REJECT_IPV6=m
CONFIG_NFT_DUP_IPV6=m
CONFIG_NFT_FIB_IPV6=m
CONFIG_NF_DUP_IPV6=m
CONFIG_NF_REJECT_IPV6=m
CONFIG_NF_LOG_IPV6=m
CONFIG_IP6_NF_IPTABLES=m
CONFIG_IP6_NF_MATCH_AH=m
CONFIG_IP6_NF_MATCH_EUI64=m
CONFIG_IP6_NF_MATCH_FRAG=m
CONFIG_IP6_NF_MATCH_OPTS=m
CONFIG_IP6_NF_MATCH_HL=m
CONFIG_IP6_NF_MATCH_IPV6HEADER=m
CONFIG_IP6_NF_MATCH_MH=m
CONFIG_IP6_NF_MATCH_RPFILTER=m
CONFIG_IP6_NF_MATCH_RT=m
# CONFIG_IP6_NF_MATCH_SRH is not set
# CONFIG_IP6_NF_TARGET_HL is not set
CONFIG_IP6_NF_FILTER=m
CONFIG_IP6_NF_TARGET_REJECT=m
CONFIG_IP6_NF_TARGET_SYNPROXY=m
CONFIG_IP6_NF_MANGLE=m
CONFIG_IP6_NF_RAW=m
CONFIG_IP6_NF_SECURITY=m
CONFIG_IP6_NF_NAT=m
CONFIG_IP6_NF_TARGET_MASQUERADE=m
CONFIG_IP6_NF_TARGET_NPT=m
# end of IPv6: Netfilter Configuration

CONFIG_NF_DEFRAG_IPV6=m
CONFIG_NF_TABLES_BRIDGE=m
# CONFIG_NFT_BRIDGE_META is not set
CONFIG_NFT_BRIDGE_REJECT=m
# CONFIG_NF_CONNTRACK_BRIDGE is not set
CONFIG_BRIDGE_NF_EBTABLES=m
CONFIG_BRIDGE_EBT_BROUTE=m
CONFIG_BRIDGE_EBT_T_FILTER=m
CONFIG_BRIDGE_EBT_T_NAT=m
CONFIG_BRIDGE_EBT_802_3=m
CONFIG_BRIDGE_EBT_AMONG=m
CONFIG_BRIDGE_EBT_ARP=m
CONFIG_BRIDGE_EBT_IP=m
CONFIG_BRIDGE_EBT_IP6=m
CONFIG_BRIDGE_EBT_LIMIT=m
CONFIG_BRIDGE_EBT_MARK=m
CONFIG_BRIDGE_EBT_PKTTYPE=m
CONFIG_BRIDGE_EBT_STP=m
CONFIG_BRIDGE_EBT_VLAN=m
CONFIG_BRIDGE_EBT_ARPREPLY=m
CONFIG_BRIDGE_EBT_DNAT=m
CONFIG_BRIDGE_EBT_MARK_T=m
CONFIG_BRIDGE_EBT_REDIRECT=m
CONFIG_BRIDGE_EBT_SNAT=m
CONFIG_BRIDGE_EBT_LOG=m
CONFIG_BRIDGE_EBT_NFLOG=m
# CONFIG_BPFILTER is not set
CONFIG_IP_DCCP=y
CONFIG_INET_DCCP_DIAG=m

#
# DCCP CCIDs Configuration
#
# CONFIG_IP_DCCP_CCID2_DEBUG is not set
CONFIG_IP_DCCP_CCID3=y
# CONFIG_IP_DCCP_CCID3_DEBUG is not set
CONFIG_IP_DCCP_TFRC_LIB=y
# end of DCCP CCIDs Configuration

#
# DCCP Kernel Hacking
#
# CONFIG_IP_DCCP_DEBUG is not set
# end of DCCP Kernel Hacking

CONFIG_IP_SCTP=m
# CONFIG_SCTP_DBG_OBJCNT is not set
# CONFIG_SCTP_DEFAULT_COOKIE_HMAC_MD5 is not set
CONFIG_SCTP_DEFAULT_COOKIE_HMAC_SHA1=y
# CONFIG_SCTP_DEFAULT_COOKIE_HMAC_NONE is not set
CONFIG_SCTP_COOKIE_HMAC_MD5=y
CONFIG_SCTP_COOKIE_HMAC_SHA1=y
CONFIG_INET_SCTP_DIAG=m
# CONFIG_RDS is not set
CONFIG_TIPC=m
CONFIG_TIPC_MEDIA_UDP=y
CONFIG_TIPC_CRYPTO=y
CONFIG_TIPC_DIAG=m
CONFIG_ATM=m
CONFIG_ATM_CLIP=m
# CONFIG_ATM_CLIP_NO_ICMP is not set
CONFIG_ATM_LANE=m
# CONFIG_ATM_MPOA is not set
CONFIG_ATM_BR2684=m
# CONFIG_ATM_BR2684_IPFILTER is not set
CONFIG_L2TP=m
CONFIG_L2TP_DEBUGFS=m
CONFIG_L2TP_V3=y
CONFIG_L2TP_IP=m
CONFIG_L2TP_ETH=m
CONFIG_STP=m
CONFIG_GARP=m
CONFIG_MRP=m
CONFIG_BRIDGE=m
CONFIG_BRIDGE_IGMP_SNOOPING=y
CONFIG_BRIDGE_VLAN_FILTERING=y
# CONFIG_BRIDGE_MRP is not set
# CONFIG_BRIDGE_CFM is not set
# CONFIG_NET_DSA is not set
CONFIG_VLAN_8021Q=m
CONFIG_VLAN_8021Q_GVRP=y
CONFIG_VLAN_8021Q_MVRP=y
CONFIG_LLC=m
# CONFIG_LLC2 is not set
# CONFIG_ATALK is not set
# CONFIG_X25 is not set
# CONFIG_LAPB is not set
# CONFIG_PHONET is not set
CONFIG_6LOWPAN=m
# CONFIG_6LOWPAN_DEBUGFS is not set
# CONFIG_6LOWPAN_NHC is not set
# CONFIG_IEEE802154 is not set
CONFIG_NET_SCHED=y

#
# Queueing/Scheduling
#
CONFIG_NET_SCH_CBQ=m
CONFIG_NET_SCH_HTB=m
CONFIG_NET_SCH_HFSC=m
CONFIG_NET_SCH_ATM=m
CONFIG_NET_SCH_PRIO=m
CONFIG_NET_SCH_MULTIQ=m
CONFIG_NET_SCH_RED=m
CONFIG_NET_SCH_SFB=m
CONFIG_NET_SCH_SFQ=m
CONFIG_NET_SCH_TEQL=m
CONFIG_NET_SCH_TBF=m
# CONFIG_NET_SCH_CBS is not set
# CONFIG_NET_SCH_ETF is not set
# CONFIG_NET_SCH_TAPRIO is not set
CONFIG_NET_SCH_GRED=m
CONFIG_NET_SCH_DSMARK=m
CONFIG_NET_SCH_NETEM=m
CONFIG_NET_SCH_DRR=m
CONFIG_NET_SCH_MQPRIO=m
# CONFIG_NET_SCH_SKBPRIO is not set
CONFIG_NET_SCH_CHOKE=m
CONFIG_NET_SCH_QFQ=m
CONFIG_NET_SCH_CODEL=m
CONFIG_NET_SCH_FQ_CODEL=y
# CONFIG_NET_SCH_CAKE is not set
CONFIG_NET_SCH_FQ=m
CONFIG_NET_SCH_HHF=m
CONFIG_NET_SCH_PIE=m
# CONFIG_NET_SCH_FQ_PIE is not set
CONFIG_NET_SCH_INGRESS=m
CONFIG_NET_SCH_PLUG=m
# CONFIG_NET_SCH_ETS is not set
CONFIG_NET_SCH_DEFAULT=y
# CONFIG_DEFAULT_FQ is not set
# CONFIG_DEFAULT_CODEL is not set
CONFIG_DEFAULT_FQ_CODEL=y
# CONFIG_DEFAULT_SFQ is not set
# CONFIG_DEFAULT_PFIFO_FAST is not set
CONFIG_DEFAULT_NET_SCH="fq_codel"

#
# Classification
#
CONFIG_NET_CLS=y
CONFIG_NET_CLS_BASIC=m
CONFIG_NET_CLS_TCINDEX=m
CONFIG_NET_CLS_ROUTE4=m
CONFIG_NET_CLS_FW=m
CONFIG_NET_CLS_U32=m
CONFIG_CLS_U32_PERF=y
CONFIG_CLS_U32_MARK=y
CONFIG_NET_CLS_RSVP=m
CONFIG_NET_CLS_RSVP6=m
CONFIG_NET_CLS_FLOW=m
CONFIG_NET_CLS_CGROUP=y
CONFIG_NET_CLS_BPF=m
CONFIG_NET_CLS_FLOWER=m
CONFIG_NET_CLS_MATCHALL=m
CONFIG_NET_EMATCH=y
CONFIG_NET_EMATCH_STACK=32
CONFIG_NET_EMATCH_CMP=m
CONFIG_NET_EMATCH_NBYTE=m
CONFIG_NET_EMATCH_U32=m
CONFIG_NET_EMATCH_META=m
CONFIG_NET_EMATCH_TEXT=m
# CONFIG_NET_EMATCH_CANID is not set
CONFIG_NET_EMATCH_IPSET=m
# CONFIG_NET_EMATCH_IPT is not set
CONFIG_NET_CLS_ACT=y
CONFIG_NET_ACT_POLICE=m
CONFIG_NET_ACT_GACT=m
CONFIG_GACT_PROB=y
CONFIG_NET_ACT_MIRRED=m
CONFIG_NET_ACT_SAMPLE=m
# CONFIG_NET_ACT_IPT is not set
CONFIG_NET_ACT_NAT=m
CONFIG_NET_ACT_PEDIT=m
CONFIG_NET_ACT_SIMP=m
CONFIG_NET_ACT_SKBEDIT=m
CONFIG_NET_ACT_CSUM=m
# CONFIG_NET_ACT_MPLS is not set
CONFIG_NET_ACT_VLAN=m
CONFIG_NET_ACT_BPF=m
# CONFIG_NET_ACT_CONNMARK is not set
# CONFIG_NET_ACT_CTINFO is not set
CONFIG_NET_ACT_SKBMOD=m
# CONFIG_NET_ACT_IFE is not set
CONFIG_NET_ACT_TUNNEL_KEY=m
# CONFIG_NET_ACT_GATE is not set
# CONFIG_NET_TC_SKB_EXT is not set
CONFIG_NET_SCH_FIFO=y
CONFIG_DCB=y
CONFIG_DNS_RESOLVER=m
# CONFIG_BATMAN_ADV is not set
CONFIG_OPENVSWITCH=m
CONFIG_OPENVSWITCH_GRE=m
CONFIG_VSOCKETS=m
CONFIG_VSOCKETS_DIAG=m
CONFIG_VSOCKETS_LOOPBACK=m
CONFIG_VMWARE_VMCI_VSOCKETS=m
CONFIG_VIRTIO_VSOCKETS=m
CONFIG_VIRTIO_VSOCKETS_COMMON=m
CONFIG_NETLINK_DIAG=m
CONFIG_MPLS=y
CONFIG_NET_MPLS_GSO=y
CONFIG_MPLS_ROUTING=m
CONFIG_MPLS_IPTUNNEL=m
CONFIG_NET_NSH=y
# CONFIG_HSR is not set
CONFIG_NET_SWITCHDEV=y
CONFIG_NET_L3_MASTER_DEV=y
# CONFIG_QRTR is not set
# CONFIG_NET_NCSI is not set
CONFIG_PCPU_DEV_REFCNT=y
CONFIG_RPS=y
CONFIG_RFS_ACCEL=y
CONFIG_SOCK_RX_QUEUE_MAPPING=y
CONFIG_XPS=y
CONFIG_CGROUP_NET_PRIO=y
CONFIG_CGROUP_NET_CLASSID=y
CONFIG_NET_RX_BUSY_POLL=y
CONFIG_BQL=y
CONFIG_NET_FLOW_LIMIT=y

#
# Network testing
#
CONFIG_NET_PKTGEN=m
CONFIG_NET_DROP_MONITOR=y
# end of Network testing
# end of Networking options

# CONFIG_HAMRADIO is not set
CONFIG_CAN=m
CONFIG_CAN_RAW=m
CONFIG_CAN_BCM=m
CONFIG_CAN_GW=m
# CONFIG_CAN_J1939 is not set
# CONFIG_CAN_ISOTP is not set
# CONFIG_BT is not set
# CONFIG_AF_RXRPC is not set
# CONFIG_AF_KCM is not set
CONFIG_STREAM_PARSER=y
# CONFIG_MCTP is not set
CONFIG_FIB_RULES=y
CONFIG_WIRELESS=y
CONFIG_CFG80211=m
# CONFIG_NL80211_TESTMODE is not set
# CONFIG_CFG80211_DEVELOPER_WARNINGS is not set
CONFIG_CFG80211_REQUIRE_SIGNED_REGDB=y
CONFIG_CFG80211_USE_KERNEL_REGDB_KEYS=y
CONFIG_CFG80211_DEFAULT_PS=y
# CONFIG_CFG80211_DEBUGFS is not set
CONFIG_CFG80211_CRDA_SUPPORT=y
# CONFIG_CFG80211_WEXT is not set
CONFIG_MAC80211=m
CONFIG_MAC80211_HAS_RC=y
CONFIG_MAC80211_RC_MINSTREL=y
CONFIG_MAC80211_RC_DEFAULT_MINSTREL=y
CONFIG_MAC80211_RC_DEFAULT="minstrel_ht"
# CONFIG_MAC80211_MESH is not set
CONFIG_MAC80211_LEDS=y
CONFIG_MAC80211_DEBUGFS=y
# CONFIG_MAC80211_MESSAGE_TRACING is not set
# CONFIG_MAC80211_DEBUG_MENU is not set
CONFIG_MAC80211_STA_HASH_MAX_SIZE=0
CONFIG_RFKILL=m
CONFIG_RFKILL_LEDS=y
CONFIG_RFKILL_INPUT=y
# CONFIG_RFKILL_GPIO is not set
CONFIG_NET_9P=y
CONFIG_NET_9P_FD=y
CONFIG_NET_9P_VIRTIO=y
# CONFIG_NET_9P_DEBUG is not set
# CONFIG_CAIF is not set
CONFIG_CEPH_LIB=m
# CONFIG_CEPH_LIB_PRETTYDEBUG is not set
CONFIG_CEPH_LIB_USE_DNS_RESOLVER=y
# CONFIG_NFC is not set
CONFIG_PSAMPLE=m
# CONFIG_NET_IFE is not set
CONFIG_LWTUNNEL=y
CONFIG_LWTUNNEL_BPF=y
CONFIG_DST_CACHE=y
CONFIG_GRO_CELLS=y
CONFIG_SOCK_VALIDATE_XMIT=y
CONFIG_NET_SELFTESTS=y
CONFIG_NET_SOCK_MSG=y
CONFIG_PAGE_POOL=y
# CONFIG_PAGE_POOL_STATS is not set
CONFIG_FAILOVER=m
CONFIG_ETHTOOL_NETLINK=y

#
# Device Drivers
#
CONFIG_HAVE_EISA=y
# CONFIG_EISA is not set
CONFIG_HAVE_PCI=y
CONFIG_PCI=y
CONFIG_PCI_DOMAINS=y
CONFIG_PCIEPORTBUS=y
CONFIG_HOTPLUG_PCI_PCIE=y
CONFIG_PCIEAER=y
CONFIG_PCIEAER_INJECT=m
CONFIG_PCIE_ECRC=y
CONFIG_PCIEASPM=y
CONFIG_PCIEASPM_DEFAULT=y
# CONFIG_PCIEASPM_POWERSAVE is not set
# CONFIG_PCIEASPM_POWER_SUPERSAVE is not set
# CONFIG_PCIEASPM_PERFORMANCE is not set
CONFIG_PCIE_PME=y
CONFIG_PCIE_DPC=y
# CONFIG_PCIE_PTM is not set
# CONFIG_PCIE_EDR is not set
CONFIG_PCI_MSI=y
CONFIG_PCI_MSI_IRQ_DOMAIN=y
CONFIG_PCI_QUIRKS=y
# CONFIG_PCI_DEBUG is not set
# CONFIG_PCI_REALLOC_ENABLE_AUTO is not set
CONFIG_PCI_STUB=y
CONFIG_PCI_PF_STUB=m
CONFIG_PCI_ATS=y
CONFIG_PCI_LOCKLESS_CONFIG=y
CONFIG_PCI_IOV=y
CONFIG_PCI_PRI=y
CONFIG_PCI_PASID=y
# CONFIG_PCI_P2PDMA is not set
CONFIG_PCI_LABEL=y
CONFIG_VGA_ARB=y
CONFIG_VGA_ARB_MAX_GPUS=64
CONFIG_HOTPLUG_PCI=y
CONFIG_HOTPLUG_PCI_ACPI=y
CONFIG_HOTPLUG_PCI_ACPI_IBM=m
# CONFIG_HOTPLUG_PCI_CPCI is not set
CONFIG_HOTPLUG_PCI_SHPC=y

#
# PCI controller drivers
#
CONFIG_VMD=y

#
# DesignWare PCI Core Support
#
# CONFIG_PCIE_DW_PLAT_HOST is not set
# CONFIG_PCI_MESON is not set
# end of DesignWare PCI Core Support

#
# Mobiveil PCIe Core Support
#
# end of Mobiveil PCIe Core Support

#
# Cadence PCIe controllers support
#
# end of Cadence PCIe controllers support
# end of PCI controller drivers

#
# PCI Endpoint
#
# CONFIG_PCI_ENDPOINT is not set
# end of PCI Endpoint

#
# PCI switch controller drivers
#
# CONFIG_PCI_SW_SWITCHTEC is not set
# end of PCI switch controller drivers

# CONFIG_CXL_BUS is not set
# CONFIG_PCCARD is not set
# CONFIG_RAPIDIO is not set

#
# Generic Driver Options
#
CONFIG_AUXILIARY_BUS=y
# CONFIG_UEVENT_HELPER is not set
CONFIG_DEVTMPFS=y
CONFIG_DEVTMPFS_MOUNT=y
# CONFIG_DEVTMPFS_SAFE is not set
CONFIG_STANDALONE=y
CONFIG_PREVENT_FIRMWARE_BUILD=y

#
# Firmware loader
#
CONFIG_FW_LOADER=y
CONFIG_FW_LOADER_PAGED_BUF=y
CONFIG_FW_LOADER_SYSFS=y
CONFIG_EXTRA_FIRMWARE=""
CONFIG_FW_LOADER_USER_HELPER=y
# CONFIG_FW_LOADER_USER_HELPER_FALLBACK is not set
# CONFIG_FW_LOADER_COMPRESS is not set
CONFIG_FW_CACHE=y
# CONFIG_FW_UPLOAD is not set
# end of Firmware loader

CONFIG_ALLOW_DEV_COREDUMP=y
# CONFIG_DEBUG_DRIVER is not set
# CONFIG_DEBUG_DEVRES is not set
# CONFIG_DEBUG_TEST_DRIVER_REMOVE is not set
# CONFIG_TEST_ASYNC_DRIVER_PROBE is not set
CONFIG_GENERIC_CPU_AUTOPROBE=y
CONFIG_GENERIC_CPU_VULNERABILITIES=y
CONFIG_REGMAP=y
CONFIG_REGMAP_I2C=m
CONFIG_REGMAP_SPI=m
CONFIG_DMA_SHARED_BUFFER=y
# CONFIG_DMA_FENCE_TRACE is not set
# end of Generic Driver Options

#
# Bus devices
#
# CONFIG_MHI_BUS is not set
# CONFIG_MHI_BUS_EP is not set
# end of Bus devices

CONFIG_CONNECTOR=y
CONFIG_PROC_EVENTS=y

#
# Firmware Drivers
#

#
# ARM System Control and Management Interface Protocol
#
# end of ARM System Control and Management Interface Protocol

CONFIG_EDD=m
# CONFIG_EDD_OFF is not set
CONFIG_FIRMWARE_MEMMAP=y
CONFIG_DMIID=y
CONFIG_DMI_SYSFS=y
CONFIG_DMI_SCAN_MACHINE_NON_EFI_FALLBACK=y
# CONFIG_ISCSI_IBFT is not set
CONFIG_FW_CFG_SYSFS=y
# CONFIG_FW_CFG_SYSFS_CMDLINE is not set
CONFIG_SYSFB=y
# CONFIG_SYSFB_SIMPLEFB is not set
# CONFIG_GOOGLE_FIRMWARE is not set

#
# EFI (Extensible Firmware Interface) Support
#
CONFIG_EFI_ESRT=y
CONFIG_EFI_VARS_PSTORE=y
CONFIG_EFI_VARS_PSTORE_DEFAULT_DISABLE=y
CONFIG_EFI_RUNTIME_MAP=y
# CONFIG_EFI_FAKE_MEMMAP is not set
CONFIG_EFI_DXE_MEM_ATTRIBUTES=y
CONFIG_EFI_RUNTIME_WRAPPERS=y
CONFIG_EFI_GENERIC_STUB_INITRD_CMDLINE_LOADER=y
# CONFIG_EFI_BOOTLOADER_CONTROL is not set
# CONFIG_EFI_CAPSULE_LOADER is not set
# CONFIG_EFI_TEST is not set
# CONFIG_APPLE_PROPERTIES is not set
# CONFIG_RESET_ATTACK_MITIGATION is not set
# CONFIG_EFI_RCI2_TABLE is not set
# CONFIG_EFI_DISABLE_PCI_DMA is not set
CONFIG_EFI_EARLYCON=y
CONFIG_EFI_CUSTOM_SSDT_OVERLAYS=y
# CONFIG_EFI_DISABLE_RUNTIME is not set
# CONFIG_EFI_COCO_SECRET is not set
# end of EFI (Extensible Firmware Interface) Support

CONFIG_UEFI_CPER=y
CONFIG_UEFI_CPER_X86=y

#
# Tegra firmware driver
#
# end of Tegra firmware driver
# end of Firmware Drivers

# CONFIG_GNSS is not set
# CONFIG_MTD is not set
# CONFIG_OF is not set
CONFIG_ARCH_MIGHT_HAVE_PC_PARPORT=y
CONFIG_PARPORT=m
CONFIG_PARPORT_PC=m
CONFIG_PARPORT_SERIAL=m
# CONFIG_PARPORT_PC_FIFO is not set
# CONFIG_PARPORT_PC_SUPERIO is not set
# CONFIG_PARPORT_AX88796 is not set
CONFIG_PARPORT_1284=y
CONFIG_PNP=y
# CONFIG_PNP_DEBUG_MESSAGES is not set

#
# Protocols
#
CONFIG_PNPACPI=y
CONFIG_BLK_DEV=y
CONFIG_BLK_DEV_NULL_BLK=m
# CONFIG_BLK_DEV_FD is not set
CONFIG_CDROM=m
# CONFIG_PARIDE is not set
# CONFIG_BLK_DEV_PCIESSD_MTIP32XX is not set
# CONFIG_ZRAM is not set
CONFIG_BLK_DEV_LOOP=m
CONFIG_BLK_DEV_LOOP_MIN_COUNT=0
# CONFIG_BLK_DEV_DRBD is not set
CONFIG_BLK_DEV_NBD=m
CONFIG_BLK_DEV_RAM=m
CONFIG_BLK_DEV_RAM_COUNT=16
CONFIG_BLK_DEV_RAM_SIZE=16384
# CONFIG_CDROM_PKTCDVD is not set
# CONFIG_ATA_OVER_ETH is not set
CONFIG_VIRTIO_BLK=m
CONFIG_BLK_DEV_RBD=m
# CONFIG_BLK_DEV_UBLK is not set

#
# NVME Support
#
CONFIG_NVME_CORE=m
CONFIG_BLK_DEV_NVME=m
CONFIG_NVME_MULTIPATH=y
# CONFIG_NVME_VERBOSE_ERRORS is not set
# CONFIG_NVME_HWMON is not set
CONFIG_NVME_FABRICS=m
# CONFIG_NVME_FC is not set
# CONFIG_NVME_TCP is not set
# CONFIG_NVME_AUTH is not set
CONFIG_NVME_TARGET=m
# CONFIG_NVME_TARGET_PASSTHRU is not set
CONFIG_NVME_TARGET_LOOP=m
CONFIG_NVME_TARGET_FC=m
# CONFIG_NVME_TARGET_TCP is not set
# CONFIG_NVME_TARGET_AUTH is not set
# end of NVME Support

#
# Misc devices
#
CONFIG_SENSORS_LIS3LV02D=m
# CONFIG_AD525X_DPOT is not set
# CONFIG_DUMMY_IRQ is not set
# CONFIG_IBM_ASM is not set
# CONFIG_PHANTOM is not set
CONFIG_TIFM_CORE=m
CONFIG_TIFM_7XX1=m
# CONFIG_ICS932S401 is not set
CONFIG_ENCLOSURE_SERVICES=m
CONFIG_SGI_XP=m
CONFIG_HP_ILO=m
CONFIG_SGI_GRU=m
# CONFIG_SGI_GRU_DEBUG is not set
CONFIG_APDS9802ALS=m
CONFIG_ISL29003=m
CONFIG_ISL29020=m
CONFIG_SENSORS_TSL2550=m
CONFIG_SENSORS_BH1770=m
CONFIG_SENSORS_APDS990X=m
# CONFIG_HMC6352 is not set
# CONFIG_DS1682 is not set
CONFIG_VMWARE_BALLOON=m
# CONFIG_LATTICE_ECP3_CONFIG is not set
# CONFIG_SRAM is not set
# CONFIG_DW_XDATA_PCIE is not set
# CONFIG_PCI_ENDPOINT_TEST is not set
# CONFIG_XILINX_SDFEC is not set
CONFIG_MISC_RTSX=m
# CONFIG_C2PORT is not set

#
# EEPROM support
#
# CONFIG_EEPROM_AT24 is not set
# CONFIG_EEPROM_AT25 is not set
CONFIG_EEPROM_LEGACY=m
CONFIG_EEPROM_MAX6875=m
CONFIG_EEPROM_93CX6=m
# CONFIG_EEPROM_93XX46 is not set
# CONFIG_EEPROM_IDT_89HPESX is not set
# CONFIG_EEPROM_EE1004 is not set
# end of EEPROM support

CONFIG_CB710_CORE=m
# CONFIG_CB710_DEBUG is not set
CONFIG_CB710_DEBUG_ASSUMPTIONS=y

#
# Texas Instruments shared transport line discipline
#
# CONFIG_TI_ST is not set
# end of Texas Instruments shared transport line discipline

CONFIG_SENSORS_LIS3_I2C=m
CONFIG_ALTERA_STAPL=m
CONFIG_INTEL_MEI=m
CONFIG_INTEL_MEI_ME=m
# CONFIG_INTEL_MEI_TXE is not set
# CONFIG_INTEL_MEI_GSC is not set
# CONFIG_INTEL_MEI_HDCP is not set
# CONFIG_INTEL_MEI_PXP is not set
CONFIG_VMWARE_VMCI=m
# CONFIG_GENWQE is not set
# CONFIG_ECHO is not set
# CONFIG_BCM_VK is not set
# CONFIG_MISC_ALCOR_PCI is not set
CONFIG_MISC_RTSX_PCI=m
# CONFIG_MISC_RTSX_USB is not set
# CONFIG_HABANA_AI is not set
# CONFIG_UACCE is not set
CONFIG_PVPANIC=y
# CONFIG_PVPANIC_MMIO is not set
# CONFIG_PVPANIC_PCI is not set
# CONFIG_GP_PCI1XXXX is not set
# end of Misc devices

#
# SCSI device support
#
CONFIG_SCSI_MOD=y
CONFIG_RAID_ATTRS=m
CONFIG_SCSI_COMMON=y
CONFIG_SCSI=y
CONFIG_SCSI_DMA=y
CONFIG_SCSI_NETLINK=y
CONFIG_SCSI_PROC_FS=y

#
# SCSI support type (disk, tape, CD-ROM)
#
CONFIG_BLK_DEV_SD=m
CONFIG_CHR_DEV_ST=m
CONFIG_BLK_DEV_SR=m
CONFIG_CHR_DEV_SG=m
CONFIG_BLK_DEV_BSG=y
CONFIG_CHR_DEV_SCH=m
CONFIG_SCSI_ENCLOSURE=m
CONFIG_SCSI_CONSTANTS=y
CONFIG_SCSI_LOGGING=y
CONFIG_SCSI_SCAN_ASYNC=y

#
# SCSI Transports
#
CONFIG_SCSI_SPI_ATTRS=m
CONFIG_SCSI_FC_ATTRS=m
CONFIG_SCSI_ISCSI_ATTRS=m
CONFIG_SCSI_SAS_ATTRS=m
CONFIG_SCSI_SAS_LIBSAS=m
CONFIG_SCSI_SAS_ATA=y
CONFIG_SCSI_SAS_HOST_SMP=y
CONFIG_SCSI_SRP_ATTRS=m
# end of SCSI Transports

CONFIG_SCSI_LOWLEVEL=y
# CONFIG_ISCSI_TCP is not set
# CONFIG_ISCSI_BOOT_SYSFS is not set
# CONFIG_SCSI_CXGB3_ISCSI is not set
# CONFIG_SCSI_CXGB4_ISCSI is not set
# CONFIG_SCSI_BNX2_ISCSI is not set
# CONFIG_BE2ISCSI is not set
# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
# CONFIG_SCSI_HPSA is not set
# CONFIG_SCSI_3W_9XXX is not set
# CONFIG_SCSI_3W_SAS is not set
# CONFIG_SCSI_ACARD is not set
# CONFIG_SCSI_AACRAID is not set
# CONFIG_SCSI_AIC7XXX is not set
# CONFIG_SCSI_AIC79XX is not set
# CONFIG_SCSI_AIC94XX is not set
# CONFIG_SCSI_MVSAS is not set
# CONFIG_SCSI_MVUMI is not set
# CONFIG_SCSI_ADVANSYS is not set
# CONFIG_SCSI_ARCMSR is not set
# CONFIG_SCSI_ESAS2R is not set
# CONFIG_MEGARAID_NEWGEN is not set
# CONFIG_MEGARAID_LEGACY is not set
# CONFIG_MEGARAID_SAS is not set
CONFIG_SCSI_MPT3SAS=m
CONFIG_SCSI_MPT2SAS_MAX_SGE=128
CONFIG_SCSI_MPT3SAS_MAX_SGE=128
# CONFIG_SCSI_MPT2SAS is not set
# CONFIG_SCSI_MPI3MR is not set
# CONFIG_SCSI_SMARTPQI is not set
# CONFIG_SCSI_HPTIOP is not set
# CONFIG_SCSI_BUSLOGIC is not set
# CONFIG_SCSI_MYRB is not set
# CONFIG_SCSI_MYRS is not set
# CONFIG_VMWARE_PVSCSI is not set
# CONFIG_LIBFC is not set
# CONFIG_SCSI_SNIC is not set
# CONFIG_SCSI_DMX3191D is not set
# CONFIG_SCSI_FDOMAIN_PCI is not set
CONFIG_SCSI_ISCI=m
# CONFIG_SCSI_IPS is not set
# CONFIG_SCSI_INITIO is not set
# CONFIG_SCSI_INIA100 is not set
# CONFIG_SCSI_PPA is not set
# CONFIG_SCSI_IMM is not set
# CONFIG_SCSI_STEX is not set
# CONFIG_SCSI_SYM53C8XX_2 is not set
# CONFIG_SCSI_IPR is not set
# CONFIG_SCSI_QLOGIC_1280 is not set
# CONFIG_SCSI_QLA_FC is not set
# CONFIG_SCSI_QLA_ISCSI is not set
# CONFIG_SCSI_LPFC is not set
# CONFIG_SCSI_EFCT is not set
# CONFIG_SCSI_DC395x is not set
# CONFIG_SCSI_AM53C974 is not set
# CONFIG_SCSI_WD719X is not set
CONFIG_SCSI_DEBUG=m
# CONFIG_SCSI_PMCRAID is not set
# CONFIG_SCSI_PM8001 is not set
# CONFIG_SCSI_BFA_FC is not set
# CONFIG_SCSI_VIRTIO is not set
# CONFIG_SCSI_CHELSIO_FCOE is not set
CONFIG_SCSI_DH=y
CONFIG_SCSI_DH_RDAC=y
CONFIG_SCSI_DH_HP_SW=y
CONFIG_SCSI_DH_EMC=y
CONFIG_SCSI_DH_ALUA=y
# end of SCSI device support

CONFIG_ATA=m
CONFIG_SATA_HOST=y
CONFIG_PATA_TIMINGS=y
CONFIG_ATA_VERBOSE_ERROR=y
CONFIG_ATA_FORCE=y
CONFIG_ATA_ACPI=y
# CONFIG_SATA_ZPODD is not set
CONFIG_SATA_PMP=y

#
# Controllers with non-SFF native interface
#
CONFIG_SATA_AHCI=m
CONFIG_SATA_MOBILE_LPM_POLICY=0
CONFIG_SATA_AHCI_PLATFORM=m
# CONFIG_AHCI_DWC is not set
# CONFIG_SATA_INIC162X is not set
# CONFIG_SATA_ACARD_AHCI is not set
# CONFIG_SATA_SIL24 is not set
CONFIG_ATA_SFF=y

#
# SFF controllers with custom DMA interface
#
# CONFIG_PDC_ADMA is not set
# CONFIG_SATA_QSTOR is not set
# CONFIG_SATA_SX4 is not set
CONFIG_ATA_BMDMA=y

#
# SATA SFF controllers with BMDMA
#
CONFIG_ATA_PIIX=m
# CONFIG_SATA_DWC is not set
# CONFIG_SATA_MV is not set
# CONFIG_SATA_NV is not set
# CONFIG_SATA_PROMISE is not set
# CONFIG_SATA_SIL is not set
# CONFIG_SATA_SIS is not set
# CONFIG_SATA_SVW is not set
# CONFIG_SATA_ULI is not set
# CONFIG_SATA_VIA is not set
# CONFIG_SATA_VITESSE is not set

#
# PATA SFF controllers with BMDMA
#
# CONFIG_PATA_ALI is not set
# CONFIG_PATA_AMD is not set
# CONFIG_PATA_ARTOP is not set
# CONFIG_PATA_ATIIXP is not set
# CONFIG_PATA_ATP867X is not set
# CONFIG_PATA_CMD64X is not set
# CONFIG_PATA_CYPRESS is not set
# CONFIG_PATA_EFAR is not set
# CONFIG_PATA_HPT366 is not set
# CONFIG_PATA_HPT37X is not set
# CONFIG_PATA_HPT3X2N is not set
# CONFIG_PATA_HPT3X3 is not set
# CONFIG_PATA_IT8213 is not set
# CONFIG_PATA_IT821X is not set
# CONFIG_PATA_JMICRON is not set
# CONFIG_PATA_MARVELL is not set
# CONFIG_PATA_NETCELL is not set
# CONFIG_PATA_NINJA32 is not set
# CONFIG_PATA_NS87415 is not set
# CONFIG_PATA_OLDPIIX is not set
# CONFIG_PATA_OPTIDMA is not set
# CONFIG_PATA_PDC2027X is not set
# CONFIG_PATA_PDC_OLD is not set
# CONFIG_PATA_RADISYS is not set
# CONFIG_PATA_RDC is not set
# CONFIG_PATA_SCH is not set
# CONFIG_PATA_SERVERWORKS is not set
# CONFIG_PATA_SIL680 is not set
# CONFIG_PATA_SIS is not set
# CONFIG_PATA_TOSHIBA is not set
# CONFIG_PATA_TRIFLEX is not set
# CONFIG_PATA_VIA is not set
# CONFIG_PATA_WINBOND is not set

#
# PIO-only SFF controllers
#
# CONFIG_PATA_CMD640_PCI is not set
# CONFIG_PATA_MPIIX is not set
# CONFIG_PATA_NS87410 is not set
# CONFIG_PATA_OPTI is not set
# CONFIG_PATA_RZ1000 is not set

#
# Generic fallback / legacy drivers
#
# CONFIG_PATA_ACPI is not set
CONFIG_ATA_GENERIC=m
# CONFIG_PATA_LEGACY is not set
CONFIG_MD=y
CONFIG_BLK_DEV_MD=y
CONFIG_MD_AUTODETECT=y
CONFIG_MD_LINEAR=m
CONFIG_MD_RAID0=m
CONFIG_MD_RAID1=m
CONFIG_MD_RAID10=m
CONFIG_MD_RAID456=m
# CONFIG_MD_MULTIPATH is not set
CONFIG_MD_FAULTY=m
CONFIG_MD_CLUSTER=m
# CONFIG_BCACHE is not set
CONFIG_BLK_DEV_DM_BUILTIN=y
CONFIG_BLK_DEV_DM=m
CONFIG_DM_DEBUG=y
CONFIG_DM_BUFIO=m
# CONFIG_DM_DEBUG_BLOCK_MANAGER_LOCKING is not set
CONFIG_DM_BIO_PRISON=m
CONFIG_DM_PERSISTENT_DATA=m
# CONFIG_DM_UNSTRIPED is not set
CONFIG_DM_CRYPT=m
CONFIG_DM_SNAPSHOT=m
CONFIG_DM_THIN_PROVISIONING=m
CONFIG_DM_CACHE=m
CONFIG_DM_CACHE_SMQ=m
CONFIG_DM_WRITECACHE=m
# CONFIG_DM_EBS is not set
CONFIG_DM_ERA=m
# CONFIG_DM_CLONE is not set
CONFIG_DM_MIRROR=m
CONFIG_DM_LOG_USERSPACE=m
CONFIG_DM_RAID=m
CONFIG_DM_ZERO=m
CONFIG_DM_MULTIPATH=m
CONFIG_DM_MULTIPATH_QL=m
CONFIG_DM_MULTIPATH_ST=m
# CONFIG_DM_MULTIPATH_HST is not set
# CONFIG_DM_MULTIPATH_IOA is not set
CONFIG_DM_DELAY=m
# CONFIG_DM_DUST is not set
CONFIG_DM_UEVENT=y
CONFIG_DM_FLAKEY=m
CONFIG_DM_VERITY=m
# CONFIG_DM_VERITY_VERIFY_ROOTHASH_SIG is not set
# CONFIG_DM_VERITY_FEC is not set
CONFIG_DM_SWITCH=m
CONFIG_DM_LOG_WRITES=m
CONFIG_DM_INTEGRITY=m
CONFIG_DM_AUDIT=y
CONFIG_TARGET_CORE=m
CONFIG_TCM_IBLOCK=m
CONFIG_TCM_FILEIO=m
CONFIG_TCM_PSCSI=m
CONFIG_TCM_USER2=m
CONFIG_LOOPBACK_TARGET=m
CONFIG_ISCSI_TARGET=m
# CONFIG_SBP_TARGET is not set
# CONFIG_FUSION is not set

#
# IEEE 1394 (FireWire) support
#
CONFIG_FIREWIRE=m
CONFIG_FIREWIRE_OHCI=m
CONFIG_FIREWIRE_SBP2=m
CONFIG_FIREWIRE_NET=m
# CONFIG_FIREWIRE_NOSY is not set
# end of IEEE 1394 (FireWire) support

CONFIG_MACINTOSH_DRIVERS=y
CONFIG_MAC_EMUMOUSEBTN=y
CONFIG_NETDEVICES=y
CONFIG_MII=y
CONFIG_NET_CORE=y
# CONFIG_BONDING is not set
# CONFIG_DUMMY is not set
# CONFIG_WIREGUARD is not set
# CONFIG_EQUALIZER is not set
# CONFIG_NET_FC is not set
# CONFIG_IFB is not set
# CONFIG_NET_TEAM is not set
# CONFIG_MACVLAN is not set
# CONFIG_IPVLAN is not set
# CONFIG_VXLAN is not set
# CONFIG_GENEVE is not set
# CONFIG_BAREUDP is not set
# CONFIG_GTP is not set
# CONFIG_AMT is not set
# CONFIG_MACSEC is not set
CONFIG_NETCONSOLE=m
CONFIG_NETCONSOLE_DYNAMIC=y
CONFIG_NETPOLL=y
CONFIG_NET_POLL_CONTROLLER=y
CONFIG_TUN=m
# CONFIG_TUN_VNET_CROSS_LE is not set
# CONFIG_VETH is not set
CONFIG_VIRTIO_NET=m
# CONFIG_NLMON is not set
# CONFIG_NET_VRF is not set
# CONFIG_VSOCKMON is not set
# CONFIG_ARCNET is not set
CONFIG_ATM_DRIVERS=y
# CONFIG_ATM_DUMMY is not set
# CONFIG_ATM_TCP is not set
# CONFIG_ATM_LANAI is not set
# CONFIG_ATM_ENI is not set
# CONFIG_ATM_NICSTAR is not set
# CONFIG_ATM_IDT77252 is not set
# CONFIG_ATM_IA is not set
# CONFIG_ATM_FORE200E is not set
# CONFIG_ATM_HE is not set
# CONFIG_ATM_SOLOS is not set
CONFIG_ETHERNET=y
CONFIG_MDIO=y
# CONFIG_NET_VENDOR_3COM is not set
CONFIG_NET_VENDOR_ADAPTEC=y
# CONFIG_ADAPTEC_STARFIRE is not set
CONFIG_NET_VENDOR_AGERE=y
# CONFIG_ET131X is not set
CONFIG_NET_VENDOR_ALACRITECH=y
# CONFIG_SLICOSS is not set
CONFIG_NET_VENDOR_ALTEON=y
# CONFIG_ACENIC is not set
# CONFIG_ALTERA_TSE is not set
CONFIG_NET_VENDOR_AMAZON=y
# CONFIG_ENA_ETHERNET is not set
# CONFIG_NET_VENDOR_AMD is not set
CONFIG_NET_VENDOR_AQUANTIA=y
# CONFIG_AQTION is not set
CONFIG_NET_VENDOR_ARC=y
CONFIG_NET_VENDOR_ASIX=y
# CONFIG_SPI_AX88796C is not set
CONFIG_NET_VENDOR_ATHEROS=y
# CONFIG_ATL2 is not set
# CONFIG_ATL1 is not set
# CONFIG_ATL1E is not set
# CONFIG_ATL1C is not set
# CONFIG_ALX is not set
# CONFIG_CX_ECAT is not set
CONFIG_NET_VENDOR_BROADCOM=y
# CONFIG_B44 is not set
# CONFIG_BCMGENET is not set
# CONFIG_BNX2 is not set
# CONFIG_CNIC is not set
# CONFIG_TIGON3 is not set
# CONFIG_BNX2X is not set
# CONFIG_SYSTEMPORT is not set
# CONFIG_BNXT is not set
CONFIG_NET_VENDOR_CADENCE=y
# CONFIG_MACB is not set
CONFIG_NET_VENDOR_CAVIUM=y
# CONFIG_THUNDER_NIC_PF is not set
# CONFIG_THUNDER_NIC_VF is not set
# CONFIG_THUNDER_NIC_BGX is not set
# CONFIG_THUNDER_NIC_RGX is not set
CONFIG_CAVIUM_PTP=y
# CONFIG_LIQUIDIO is not set
# CONFIG_LIQUIDIO_VF is not set
CONFIG_NET_VENDOR_CHELSIO=y
# CONFIG_CHELSIO_T1 is not set
# CONFIG_CHELSIO_T3 is not set
# CONFIG_CHELSIO_T4 is not set
# CONFIG_CHELSIO_T4VF is not set
CONFIG_NET_VENDOR_CISCO=y
# CONFIG_ENIC is not set
CONFIG_NET_VENDOR_CORTINA=y
CONFIG_NET_VENDOR_DAVICOM=y
# CONFIG_DM9051 is not set
# CONFIG_DNET is not set
CONFIG_NET_VENDOR_DEC=y
# CONFIG_NET_TULIP is not set
CONFIG_NET_VENDOR_DLINK=y
# CONFIG_DL2K is not set
# CONFIG_SUNDANCE is not set
CONFIG_NET_VENDOR_EMULEX=y
# CONFIG_BE2NET is not set
CONFIG_NET_VENDOR_ENGLEDER=y
# CONFIG_TSNEP is not set
CONFIG_NET_VENDOR_EZCHIP=y
CONFIG_NET_VENDOR_FUNGIBLE=y
# CONFIG_FUN_ETH is not set
CONFIG_NET_VENDOR_GOOGLE=y
# CONFIG_GVE is not set
CONFIG_NET_VENDOR_HUAWEI=y
# CONFIG_HINIC is not set
CONFIG_NET_VENDOR_I825XX=y
CONFIG_NET_VENDOR_INTEL=y
# CONFIG_E100 is not set
CONFIG_E1000=y
CONFIG_E1000E=y
CONFIG_E1000E_HWTS=y
CONFIG_IGB=y
CONFIG_IGB_HWMON=y
# CONFIG_IGBVF is not set
# CONFIG_IXGB is not set
CONFIG_IXGBE=y
CONFIG_IXGBE_HWMON=y
# CONFIG_IXGBE_DCB is not set
# CONFIG_IXGBE_IPSEC is not set
# CONFIG_IXGBEVF is not set
CONFIG_I40E=y
# CONFIG_I40E_DCB is not set
# CONFIG_I40EVF is not set
# CONFIG_ICE is not set
# CONFIG_FM10K is not set
CONFIG_IGC=y
CONFIG_NET_VENDOR_WANGXUN=y
# CONFIG_NGBE is not set
# CONFIG_TXGBE is not set
# CONFIG_JME is not set
CONFIG_NET_VENDOR_ADI=y
# CONFIG_ADIN1110 is not set
CONFIG_NET_VENDOR_LITEX=y
CONFIG_NET_VENDOR_MARVELL=y
# CONFIG_MVMDIO is not set
# CONFIG_SKGE is not set
# CONFIG_SKY2 is not set
# CONFIG_OCTEON_EP is not set
# CONFIG_PRESTERA is not set
CONFIG_NET_VENDOR_MELLANOX=y
# CONFIG_MLX4_EN is not set
# CONFIG_MLX5_CORE is not set
# CONFIG_MLXSW_CORE is not set
# CONFIG_MLXFW is not set
CONFIG_NET_VENDOR_MICREL=y
# CONFIG_KS8842 is not set
# CONFIG_KS8851 is not set
# CONFIG_KS8851_MLL is not set
# CONFIG_KSZ884X_PCI is not set
CONFIG_NET_VENDOR_MICROCHIP=y
# CONFIG_ENC28J60 is not set
# CONFIG_ENCX24J600 is not set
# CONFIG_LAN743X is not set
CONFIG_NET_VENDOR_MICROSEMI=y
CONFIG_NET_VENDOR_MICROSOFT=y
CONFIG_NET_VENDOR_MYRI=y
# CONFIG_MYRI10GE is not set
# CONFIG_FEALNX is not set
CONFIG_NET_VENDOR_NI=y
# CONFIG_NI_XGE_MANAGEMENT_ENET is not set
CONFIG_NET_VENDOR_NATSEMI=y
# CONFIG_NATSEMI is not set
# CONFIG_NS83820 is not set
CONFIG_NET_VENDOR_NETERION=y
# CONFIG_S2IO is not set
CONFIG_NET_VENDOR_NETRONOME=y
# CONFIG_NFP is not set
CONFIG_NET_VENDOR_8390=y
# CONFIG_NE2K_PCI is not set
CONFIG_NET_VENDOR_NVIDIA=y
# CONFIG_FORCEDETH is not set
CONFIG_NET_VENDOR_OKI=y
# CONFIG_ETHOC is not set
CONFIG_NET_VENDOR_PACKET_ENGINES=y
# CONFIG_HAMACHI is not set
# CONFIG_YELLOWFIN is not set
CONFIG_NET_VENDOR_PENSANDO=y
# CONFIG_IONIC is not set
CONFIG_NET_VENDOR_QLOGIC=y
# CONFIG_QLA3XXX is not set
# CONFIG_QLCNIC is not set
# CONFIG_NETXEN_NIC is not set
# CONFIG_QED is not set
CONFIG_NET_VENDOR_BROCADE=y
# CONFIG_BNA is not set
CONFIG_NET_VENDOR_QUALCOMM=y
# CONFIG_QCOM_EMAC is not set
# CONFIG_RMNET is not set
CONFIG_NET_VENDOR_RDC=y
# CONFIG_R6040 is not set
CONFIG_NET_VENDOR_REALTEK=y
# CONFIG_ATP is not set
# CONFIG_8139CP is not set
# CONFIG_8139TOO is not set
CONFIG_R8169=y
CONFIG_NET_VENDOR_RENESAS=y
CONFIG_NET_VENDOR_ROCKER=y
# CONFIG_ROCKER is not set
CONFIG_NET_VENDOR_SAMSUNG=y
# CONFIG_SXGBE_ETH is not set
CONFIG_NET_VENDOR_SEEQ=y
CONFIG_NET_VENDOR_SILAN=y
# CONFIG_SC92031 is not set
CONFIG_NET_VENDOR_SIS=y
# CONFIG_SIS900 is not set
# CONFIG_SIS190 is not set
CONFIG_NET_VENDOR_SOLARFLARE=y
# CONFIG_SFC is not set
# CONFIG_SFC_FALCON is not set
# CONFIG_SFC_SIENA is not set
CONFIG_NET_VENDOR_SMSC=y
# CONFIG_EPIC100 is not set
# CONFIG_SMSC911X is not set
# CONFIG_SMSC9420 is not set
CONFIG_NET_VENDOR_SOCIONEXT=y
CONFIG_NET_VENDOR_STMICRO=y
# CONFIG_STMMAC_ETH is not set
CONFIG_NET_VENDOR_SUN=y
# CONFIG_HAPPYMEAL is not set
# CONFIG_SUNGEM is not set
# CONFIG_CASSINI is not set
# CONFIG_NIU is not set
CONFIG_NET_VENDOR_SYNOPSYS=y
# CONFIG_DWC_XLGMAC is not set
CONFIG_NET_VENDOR_TEHUTI=y
# CONFIG_TEHUTI is not set
CONFIG_NET_VENDOR_TI=y
# CONFIG_TI_CPSW_PHY_SEL is not set
# CONFIG_TLAN is not set
CONFIG_NET_VENDOR_VERTEXCOM=y
# CONFIG_MSE102X is not set
CONFIG_NET_VENDOR_VIA=y
# CONFIG_VIA_RHINE is not set
# CONFIG_VIA_VELOCITY is not set
CONFIG_NET_VENDOR_WIZNET=y
# CONFIG_WIZNET_W5100 is not set
# CONFIG_WIZNET_W5300 is not set
CONFIG_NET_VENDOR_XILINX=y
# CONFIG_XILINX_EMACLITE is not set
# CONFIG_XILINX_AXI_EMAC is not set
# CONFIG_XILINX_LL_TEMAC is not set
# CONFIG_FDDI is not set
# CONFIG_HIPPI is not set
# CONFIG_NET_SB1000 is not set
CONFIG_PHYLINK=y
CONFIG_PHYLIB=y
CONFIG_SWPHY=y
# CONFIG_LED_TRIGGER_PHY is not set
CONFIG_FIXED_PHY=y
# CONFIG_SFP is not set

#
# MII PHY device drivers
#
# CONFIG_AMD_PHY is not set
# CONFIG_ADIN_PHY is not set
# CONFIG_ADIN1100_PHY is not set
# CONFIG_AQUANTIA_PHY is not set
CONFIG_AX88796B_PHY=y
# CONFIG_BROADCOM_PHY is not set
# CONFIG_BCM54140_PHY is not set
# CONFIG_BCM7XXX_PHY is not set
# CONFIG_BCM84881_PHY is not set
# CONFIG_BCM87XX_PHY is not set
# CONFIG_CICADA_PHY is not set
# CONFIG_CORTINA_PHY is not set
# CONFIG_DAVICOM_PHY is not set
# CONFIG_ICPLUS_PHY is not set
# CONFIG_LXT_PHY is not set
# CONFIG_INTEL_XWAY_PHY is not set
# CONFIG_LSI_ET1011C_PHY is not set
# CONFIG_MARVELL_PHY is not set
# CONFIG_MARVELL_10G_PHY is not set
# CONFIG_MARVELL_88X2222_PHY is not set
# CONFIG_MAXLINEAR_GPHY is not set
# CONFIG_MEDIATEK_GE_PHY is not set
# CONFIG_MICREL_PHY is not set
# CONFIG_MICROCHIP_PHY is not set
# CONFIG_MICROCHIP_T1_PHY is not set
# CONFIG_MICROSEMI_PHY is not set
# CONFIG_MOTORCOMM_PHY is not set
# CONFIG_NATIONAL_PHY is not set
# CONFIG_NXP_C45_TJA11XX_PHY is not set
# CONFIG_NXP_TJA11XX_PHY is not set
# CONFIG_QSEMI_PHY is not set
CONFIG_REALTEK_PHY=y
# CONFIG_RENESAS_PHY is not set
# CONFIG_ROCKCHIP_PHY is not set
# CONFIG_SMSC_PHY is not set
# CONFIG_STE10XP is not set
# CONFIG_TERANETICS_PHY is not set
# CONFIG_DP83822_PHY is not set
# CONFIG_DP83TC811_PHY is not set
# CONFIG_DP83848_PHY is not set
# CONFIG_DP83867_PHY is not set
# CONFIG_DP83869_PHY is not set
# CONFIG_DP83TD510_PHY is not set
# CONFIG_VITESSE_PHY is not set
# CONFIG_XILINX_GMII2RGMII is not set
# CONFIG_MICREL_KS8995MA is not set
# CONFIG_PSE_CONTROLLER is not set
CONFIG_CAN_DEV=m
CONFIG_CAN_VCAN=m
# CONFIG_CAN_VXCAN is not set
CONFIG_CAN_NETLINK=y
CONFIG_CAN_CALC_BITTIMING=y
# CONFIG_CAN_CAN327 is not set
# CONFIG_CAN_KVASER_PCIEFD is not set
CONFIG_CAN_SLCAN=m
CONFIG_CAN_C_CAN=m
CONFIG_CAN_C_CAN_PLATFORM=m
CONFIG_CAN_C_CAN_PCI=m
CONFIG_CAN_CC770=m
# CONFIG_CAN_CC770_ISA is not set
CONFIG_CAN_CC770_PLATFORM=m
# CONFIG_CAN_CTUCANFD_PCI is not set
# CONFIG_CAN_IFI_CANFD is not set
# CONFIG_CAN_M_CAN is not set
# CONFIG_CAN_PEAK_PCIEFD is not set
CONFIG_CAN_SJA1000=m
CONFIG_CAN_EMS_PCI=m
# CONFIG_CAN_F81601 is not set
CONFIG_CAN_KVASER_PCI=m
CONFIG_CAN_PEAK_PCI=m
CONFIG_CAN_PEAK_PCIEC=y
CONFIG_CAN_PLX_PCI=m
# CONFIG_CAN_SJA1000_ISA is not set
# CONFIG_CAN_SJA1000_PLATFORM is not set
CONFIG_CAN_SOFTING=m

#
# CAN SPI interfaces
#
# CONFIG_CAN_HI311X is not set
# CONFIG_CAN_MCP251X is not set
# CONFIG_CAN_MCP251XFD is not set
# end of CAN SPI interfaces

#
# CAN USB interfaces
#
# CONFIG_CAN_8DEV_USB is not set
# CONFIG_CAN_EMS_USB is not set
# CONFIG_CAN_ESD_USB is not set
# CONFIG_CAN_ETAS_ES58X is not set
# CONFIG_CAN_GS_USB is not set
# CONFIG_CAN_KVASER_USB is not set
# CONFIG_CAN_MCBA_USB is not set
# CONFIG_CAN_PEAK_USB is not set
# CONFIG_CAN_UCAN is not set
# end of CAN USB interfaces

# CONFIG_CAN_DEBUG_DEVICES is not set
CONFIG_MDIO_DEVICE=y
CONFIG_MDIO_BUS=y
CONFIG_FWNODE_MDIO=y
CONFIG_ACPI_MDIO=y
CONFIG_MDIO_DEVRES=y
# CONFIG_MDIO_BITBANG is not set
# CONFIG_MDIO_BCM_UNIMAC is not set
# CONFIG_MDIO_MVUSB is not set
# CONFIG_MDIO_THUNDER is not set

#
# MDIO Multiplexers
#

#
# PCS device drivers
#
# end of PCS device drivers

# CONFIG_PLIP is not set
# CONFIG_PPP is not set
# CONFIG_SLIP is not set
CONFIG_USB_NET_DRIVERS=y
# CONFIG_USB_CATC is not set
# CONFIG_USB_KAWETH is not set
# CONFIG_USB_PEGASUS is not set
# CONFIG_USB_RTL8150 is not set
CONFIG_USB_RTL8152=y
# CONFIG_USB_LAN78XX is not set
CONFIG_USB_USBNET=y
CONFIG_USB_NET_AX8817X=y
CONFIG_USB_NET_AX88179_178A=y
# CONFIG_USB_NET_CDCETHER is not set
# CONFIG_USB_NET_CDC_EEM is not set
# CONFIG_USB_NET_CDC_NCM is not set
# CONFIG_USB_NET_HUAWEI_CDC_NCM is not set
# CONFIG_USB_NET_CDC_MBIM is not set
# CONFIG_USB_NET_DM9601 is not set
# CONFIG_USB_NET_SR9700 is not set
# CONFIG_USB_NET_SR9800 is not set
# CONFIG_USB_NET_SMSC75XX is not set
# CONFIG_USB_NET_SMSC95XX is not set
# CONFIG_USB_NET_GL620A is not set
# CONFIG_USB_NET_NET1080 is not set
# CONFIG_USB_NET_PLUSB is not set
# CONFIG_USB_NET_MCS7830 is not set
# CONFIG_USB_NET_RNDIS_HOST is not set
# CONFIG_USB_NET_CDC_SUBSET is not set
# CONFIG_USB_NET_ZAURUS is not set
# CONFIG_USB_NET_CX82310_ETH is not set
# CONFIG_USB_NET_KALMIA is not set
# CONFIG_USB_NET_QMI_WWAN is not set
# CONFIG_USB_HSO is not set
# CONFIG_USB_NET_INT51X1 is not set
# CONFIG_USB_IPHETH is not set
# CONFIG_USB_SIERRA_NET is not set
# CONFIG_USB_NET_CH9200 is not set
# CONFIG_USB_NET_AQC111 is not set
CONFIG_WLAN=y
CONFIG_WLAN_VENDOR_ADMTEK=y
# CONFIG_ADM8211 is not set
CONFIG_WLAN_VENDOR_ATH=y
# CONFIG_ATH_DEBUG is not set
# CONFIG_ATH5K is not set
# CONFIG_ATH5K_PCI is not set
# CONFIG_ATH9K is not set
# CONFIG_ATH9K_HTC is not set
# CONFIG_CARL9170 is not set
# CONFIG_ATH6KL is not set
# CONFIG_AR5523 is not set
# CONFIG_WIL6210 is not set
# CONFIG_ATH10K is not set
# CONFIG_WCN36XX is not set
# CONFIG_ATH11K is not set
CONFIG_WLAN_VENDOR_ATMEL=y
# CONFIG_ATMEL is not set
# CONFIG_AT76C50X_USB is not set
CONFIG_WLAN_VENDOR_BROADCOM=y
# CONFIG_B43 is not set
# CONFIG_B43LEGACY is not set
# CONFIG_BRCMSMAC is not set
# CONFIG_BRCMFMAC is not set
CONFIG_WLAN_VENDOR_CISCO=y
# CONFIG_AIRO is not set
CONFIG_WLAN_VENDOR_INTEL=y
# CONFIG_IPW2100 is not set
# CONFIG_IPW2200 is not set
# CONFIG_IWL4965 is not set
# CONFIG_IWL3945 is not set
# CONFIG_IWLWIFI is not set
CONFIG_WLAN_VENDOR_INTERSIL=y
# CONFIG_HOSTAP is not set
# CONFIG_HERMES is not set
# CONFIG_P54_COMMON is not set
CONFIG_WLAN_VENDOR_MARVELL=y
# CONFIG_LIBERTAS is not set
# CONFIG_LIBERTAS_THINFIRM is not set
# CONFIG_MWIFIEX is not set
# CONFIG_MWL8K is not set
# CONFIG_WLAN_VENDOR_MEDIATEK is not set
CONFIG_WLAN_VENDOR_MICROCHIP=y
# CONFIG_WILC1000_SDIO is not set
# CONFIG_WILC1000_SPI is not set
CONFIG_WLAN_VENDOR_PURELIFI=y
# CONFIG_PLFXLC is not set
CONFIG_WLAN_VENDOR_RALINK=y
# CONFIG_RT2X00 is not set
CONFIG_WLAN_VENDOR_REALTEK=y
# CONFIG_RTL8180 is not set
# CONFIG_RTL8187 is not set
CONFIG_RTL_CARDS=m
# CONFIG_RTL8192CE is not set
# CONFIG_RTL8192SE is not set
# CONFIG_RTL8192DE is not set
# CONFIG_RTL8723AE is not set
# CONFIG_RTL8723BE is not set
# CONFIG_RTL8188EE is not set
# CONFIG_RTL8192EE is not set
# CONFIG_RTL8821AE is not set
# CONFIG_RTL8192CU is not set
# CONFIG_RTL8XXXU is not set
# CONFIG_RTW88 is not set
# CONFIG_RTW89 is not set
CONFIG_WLAN_VENDOR_RSI=y
# CONFIG_RSI_91X is not set
CONFIG_WLAN_VENDOR_SILABS=y
# CONFIG_WFX is not set
CONFIG_WLAN_VENDOR_ST=y
# CONFIG_CW1200 is not set
CONFIG_WLAN_VENDOR_TI=y
# CONFIG_WL1251 is not set
# CONFIG_WL12XX is not set
# CONFIG_WL18XX is not set
# CONFIG_WLCORE is not set
CONFIG_WLAN_VENDOR_ZYDAS=y
# CONFIG_USB_ZD1201 is not set
# CONFIG_ZD1211RW is not set
CONFIG_WLAN_VENDOR_QUANTENNA=y
# CONFIG_QTNFMAC_PCIE is not set
# CONFIG_MAC80211_HWSIM is not set
# CONFIG_USB_NET_RNDIS_WLAN is not set
# CONFIG_VIRT_WIFI is not set
# CONFIG_WAN is not set

#
# Wireless WAN
#
# CONFIG_WWAN is not set
# end of Wireless WAN

# CONFIG_VMXNET3 is not set
# CONFIG_FUJITSU_ES is not set
# CONFIG_NETDEVSIM is not set
CONFIG_NET_FAILOVER=m
# CONFIG_ISDN is not set

#
# Input device support
#
CONFIG_INPUT=y
CONFIG_INPUT_LEDS=y
CONFIG_INPUT_FF_MEMLESS=m
CONFIG_INPUT_SPARSEKMAP=m
# CONFIG_INPUT_MATRIXKMAP is not set
CONFIG_INPUT_VIVALDIFMAP=y

#
# Userland interfaces
#
CONFIG_INPUT_MOUSEDEV=y
# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
CONFIG_INPUT_JOYDEV=m
CONFIG_INPUT_EVDEV=y
# CONFIG_INPUT_EVBUG is not set

#
# Input Device Drivers
#
CONFIG_INPUT_KEYBOARD=y
# CONFIG_KEYBOARD_ADP5588 is not set
# CONFIG_KEYBOARD_ADP5589 is not set
# CONFIG_KEYBOARD_APPLESPI is not set
CONFIG_KEYBOARD_ATKBD=y
# CONFIG_KEYBOARD_QT1050 is not set
# CONFIG_KEYBOARD_QT1070 is not set
# CONFIG_KEYBOARD_QT2160 is not set
# CONFIG_KEYBOARD_DLINK_DIR685 is not set
# CONFIG_KEYBOARD_LKKBD is not set
# CONFIG_KEYBOARD_GPIO is not set
# CONFIG_KEYBOARD_GPIO_POLLED is not set
# CONFIG_KEYBOARD_TCA6416 is not set
# CONFIG_KEYBOARD_TCA8418 is not set
# CONFIG_KEYBOARD_MATRIX is not set
# CONFIG_KEYBOARD_LM8323 is not set
# CONFIG_KEYBOARD_LM8333 is not set
# CONFIG_KEYBOARD_MAX7359 is not set
# CONFIG_KEYBOARD_MCS is not set
# CONFIG_KEYBOARD_MPR121 is not set
# CONFIG_KEYBOARD_NEWTON is not set
# CONFIG_KEYBOARD_OPENCORES is not set
# CONFIG_KEYBOARD_SAMSUNG is not set
# CONFIG_KEYBOARD_STOWAWAY is not set
# CONFIG_KEYBOARD_SUNKBD is not set
# CONFIG_KEYBOARD_TM2_TOUCHKEY is not set
# CONFIG_KEYBOARD_XTKBD is not set
# CONFIG_KEYBOARD_CYPRESS_SF is not set
CONFIG_INPUT_MOUSE=y
CONFIG_MOUSE_PS2=y
CONFIG_MOUSE_PS2_ALPS=y
CONFIG_MOUSE_PS2_BYD=y
CONFIG_MOUSE_PS2_LOGIPS2PP=y
CONFIG_MOUSE_PS2_SYNAPTICS=y
CONFIG_MOUSE_PS2_SYNAPTICS_SMBUS=y
CONFIG_MOUSE_PS2_CYPRESS=y
CONFIG_MOUSE_PS2_LIFEBOOK=y
CONFIG_MOUSE_PS2_TRACKPOINT=y
CONFIG_MOUSE_PS2_ELANTECH=y
CONFIG_MOUSE_PS2_ELANTECH_SMBUS=y
CONFIG_MOUSE_PS2_SENTELIC=y
# CONFIG_MOUSE_PS2_TOUCHKIT is not set
CONFIG_MOUSE_PS2_FOCALTECH=y
CONFIG_MOUSE_PS2_VMMOUSE=y
CONFIG_MOUSE_PS2_SMBUS=y
CONFIG_MOUSE_SERIAL=m
# CONFIG_MOUSE_APPLETOUCH is not set
# CONFIG_MOUSE_BCM5974 is not set
CONFIG_MOUSE_CYAPA=m
CONFIG_MOUSE_ELAN_I2C=m
CONFIG_MOUSE_ELAN_I2C_I2C=y
CONFIG_MOUSE_ELAN_I2C_SMBUS=y
CONFIG_MOUSE_VSXXXAA=m
# CONFIG_MOUSE_GPIO is not set
CONFIG_MOUSE_SYNAPTICS_I2C=m
# CONFIG_MOUSE_SYNAPTICS_USB is not set
# CONFIG_INPUT_JOYSTICK is not set
# CONFIG_INPUT_TABLET is not set
# CONFIG_INPUT_TOUCHSCREEN is not set
# CONFIG_INPUT_MISC is not set
CONFIG_RMI4_CORE=m
CONFIG_RMI4_I2C=m
CONFIG_RMI4_SPI=m
CONFIG_RMI4_SMB=m
CONFIG_RMI4_F03=y
CONFIG_RMI4_F03_SERIO=m
CONFIG_RMI4_2D_SENSOR=y
CONFIG_RMI4_F11=y
CONFIG_RMI4_F12=y
CONFIG_RMI4_F30=y
CONFIG_RMI4_F34=y
# CONFIG_RMI4_F3A is not set
CONFIG_RMI4_F55=y

#
# Hardware I/O ports
#
CONFIG_SERIO=y
CONFIG_ARCH_MIGHT_HAVE_PC_SERIO=y
CONFIG_SERIO_I8042=y
CONFIG_SERIO_SERPORT=y
# CONFIG_SERIO_CT82C710 is not set
# CONFIG_SERIO_PARKBD is not set
# CONFIG_SERIO_PCIPS2 is not set
CONFIG_SERIO_LIBPS2=y
CONFIG_SERIO_RAW=m
CONFIG_SERIO_ALTERA_PS2=m
# CONFIG_SERIO_PS2MULT is not set
CONFIG_SERIO_ARC_PS2=m
# CONFIG_SERIO_GPIO_PS2 is not set
# CONFIG_USERIO is not set
# CONFIG_GAMEPORT is not set
# end of Hardware I/O ports
# end of Input device support

#
# Character devices
#
CONFIG_TTY=y
CONFIG_VT=y
CONFIG_CONSOLE_TRANSLATIONS=y
CONFIG_VT_CONSOLE=y
CONFIG_VT_CONSOLE_SLEEP=y
CONFIG_HW_CONSOLE=y
CONFIG_VT_HW_CONSOLE_BINDING=y
CONFIG_UNIX98_PTYS=y
# CONFIG_LEGACY_PTYS is not set
CONFIG_LDISC_AUTOLOAD=y

#
# Serial drivers
#
CONFIG_SERIAL_EARLYCON=y
CONFIG_SERIAL_8250=y
# CONFIG_SERIAL_8250_DEPRECATED_OPTIONS is not set
CONFIG_SERIAL_8250_PNP=y
# CONFIG_SERIAL_8250_16550A_VARIANTS is not set
# CONFIG_SERIAL_8250_FINTEK is not set
CONFIG_SERIAL_8250_CONSOLE=y
CONFIG_SERIAL_8250_DMA=y
CONFIG_SERIAL_8250_PCI=y
CONFIG_SERIAL_8250_EXAR=y
CONFIG_SERIAL_8250_NR_UARTS=64
CONFIG_SERIAL_8250_RUNTIME_UARTS=4
CONFIG_SERIAL_8250_EXTENDED=y
CONFIG_SERIAL_8250_MANY_PORTS=y
CONFIG_SERIAL_8250_SHARE_IRQ=y
# CONFIG_SERIAL_8250_DETECT_IRQ is not set
CONFIG_SERIAL_8250_RSA=y
CONFIG_SERIAL_8250_DWLIB=y
CONFIG_SERIAL_8250_DW=y
# CONFIG_SERIAL_8250_RT288X is not set
CONFIG_SERIAL_8250_LPSS=y
CONFIG_SERIAL_8250_MID=y
CONFIG_SERIAL_8250_PERICOM=y

#
# Non-8250 serial port support
#
# CONFIG_SERIAL_MAX3100 is not set
# CONFIG_SERIAL_MAX310X is not set
# CONFIG_SERIAL_UARTLITE is not set
CONFIG_SERIAL_CORE=y
CONFIG_SERIAL_CORE_CONSOLE=y
CONFIG_SERIAL_JSM=m
# CONFIG_SERIAL_LANTIQ is not set
# CONFIG_SERIAL_SCCNXP is not set
# CONFIG_SERIAL_SC16IS7XX is not set
# CONFIG_SERIAL_ALTERA_JTAGUART is not set
# CONFIG_SERIAL_ALTERA_UART is not set
CONFIG_SERIAL_ARC=m
CONFIG_SERIAL_ARC_NR_PORTS=1
# CONFIG_SERIAL_RP2 is not set
# CONFIG_SERIAL_FSL_LPUART is not set
# CONFIG_SERIAL_FSL_LINFLEXUART is not set
# CONFIG_SERIAL_SPRD is not set
# end of Serial drivers

CONFIG_SERIAL_MCTRL_GPIO=y
CONFIG_SERIAL_NONSTANDARD=y
# CONFIG_MOXA_INTELLIO is not set
# CONFIG_MOXA_SMARTIO is not set
CONFIG_SYNCLINK_GT=m
CONFIG_N_HDLC=m
CONFIG_N_GSM=m
CONFIG_NOZOMI=m
# CONFIG_NULL_TTY is not set
CONFIG_HVC_DRIVER=y
# CONFIG_SERIAL_DEV_BUS is not set
CONFIG_PRINTER=m
# CONFIG_LP_CONSOLE is not set
CONFIG_PPDEV=m
CONFIG_VIRTIO_CONSOLE=m
CONFIG_IPMI_HANDLER=m
CONFIG_IPMI_DMI_DECODE=y
CONFIG_IPMI_PLAT_DATA=y
CONFIG_IPMI_PANIC_EVENT=y
CONFIG_IPMI_PANIC_STRING=y
CONFIG_IPMI_DEVICE_INTERFACE=m
CONFIG_IPMI_SI=m
CONFIG_IPMI_SSIF=m
CONFIG_IPMI_WATCHDOG=m
CONFIG_IPMI_POWEROFF=m
CONFIG_HW_RANDOM=y
CONFIG_HW_RANDOM_TIMERIOMEM=m
CONFIG_HW_RANDOM_INTEL=m
# CONFIG_HW_RANDOM_AMD is not set
# CONFIG_HW_RANDOM_BA431 is not set
CONFIG_HW_RANDOM_VIA=m
CONFIG_HW_RANDOM_VIRTIO=y
# CONFIG_HW_RANDOM_XIPHERA is not set
# CONFIG_APPLICOM is not set
# CONFIG_MWAVE is not set
CONFIG_DEVMEM=y
CONFIG_NVRAM=y
CONFIG_DEVPORT=y
CONFIG_HPET=y
CONFIG_HPET_MMAP=y
# CONFIG_HPET_MMAP_DEFAULT is not set
CONFIG_HANGCHECK_TIMER=m
CONFIG_UV_MMTIMER=m
CONFIG_TCG_TPM=y
CONFIG_HW_RANDOM_TPM=y
CONFIG_TCG_TIS_CORE=y
CONFIG_TCG_TIS=y
# CONFIG_TCG_TIS_SPI is not set
# CONFIG_TCG_TIS_I2C is not set
# CONFIG_TCG_TIS_I2C_CR50 is not set
CONFIG_TCG_TIS_I2C_ATMEL=m
CONFIG_TCG_TIS_I2C_INFINEON=m
CONFIG_TCG_TIS_I2C_NUVOTON=m
CONFIG_TCG_NSC=m
CONFIG_TCG_ATMEL=m
CONFIG_TCG_INFINEON=m
CONFIG_TCG_CRB=y
# CONFIG_TCG_VTPM_PROXY is not set
CONFIG_TCG_TIS_ST33ZP24=m
CONFIG_TCG_TIS_ST33ZP24_I2C=m
# CONFIG_TCG_TIS_ST33ZP24_SPI is not set
CONFIG_TELCLOCK=m
# CONFIG_XILLYBUS is not set
# CONFIG_XILLYUSB is not set
CONFIG_RANDOM_TRUST_CPU=y
CONFIG_RANDOM_TRUST_BOOTLOADER=y
# end of Character devices

#
# I2C support
#
CONFIG_I2C=y
CONFIG_ACPI_I2C_OPREGION=y
CONFIG_I2C_BOARDINFO=y
CONFIG_I2C_COMPAT=y
CONFIG_I2C_CHARDEV=m
CONFIG_I2C_MUX=m

#
# Multiplexer I2C Chip support
#
# CONFIG_I2C_MUX_GPIO is not set
# CONFIG_I2C_MUX_LTC4306 is not set
# CONFIG_I2C_MUX_PCA9541 is not set
# CONFIG_I2C_MUX_PCA954x is not set
# CONFIG_I2C_MUX_REG is not set
CONFIG_I2C_MUX_MLXCPLD=m
# end of Multiplexer I2C Chip support

CONFIG_I2C_HELPER_AUTO=y
CONFIG_I2C_SMBUS=y
CONFIG_I2C_ALGOBIT=y
CONFIG_I2C_ALGOPCA=m

#
# I2C Hardware Bus support
#

#
# PC SMBus host controller drivers
#
# CONFIG_I2C_ALI1535 is not set
# CONFIG_I2C_ALI1563 is not set
# CONFIG_I2C_ALI15X3 is not set
# CONFIG_I2C_AMD756 is not set
# CONFIG_I2C_AMD8111 is not set
# CONFIG_I2C_AMD_MP2 is not set
CONFIG_I2C_I801=y
CONFIG_I2C_ISCH=m
CONFIG_I2C_ISMT=m
CONFIG_I2C_PIIX4=m
CONFIG_I2C_NFORCE2=m
CONFIG_I2C_NFORCE2_S4985=m
# CONFIG_I2C_NVIDIA_GPU is not set
# CONFIG_I2C_SIS5595 is not set
# CONFIG_I2C_SIS630 is not set
CONFIG_I2C_SIS96X=m
CONFIG_I2C_VIA=m
CONFIG_I2C_VIAPRO=m

#
# ACPI drivers
#
CONFIG_I2C_SCMI=m

#
# I2C system bus drivers (mostly embedded / system-on-chip)
#
# CONFIG_I2C_CBUS_GPIO is not set
CONFIG_I2C_DESIGNWARE_CORE=m
# CONFIG_I2C_DESIGNWARE_SLAVE is not set
CONFIG_I2C_DESIGNWARE_PLATFORM=m
# CONFIG_I2C_DESIGNWARE_AMDPSP is not set
CONFIG_I2C_DESIGNWARE_BAYTRAIL=y
# CONFIG_I2C_DESIGNWARE_PCI is not set
# CONFIG_I2C_EMEV2 is not set
# CONFIG_I2C_GPIO is not set
# CONFIG_I2C_OCORES is not set
CONFIG_I2C_PCA_PLATFORM=m
CONFIG_I2C_SIMTEC=m
# CONFIG_I2C_XILINX is not set

#
# External I2C/SMBus adapter drivers
#
# CONFIG_I2C_DIOLAN_U2C is not set
# CONFIG_I2C_CP2615 is not set
CONFIG_I2C_PARPORT=m
# CONFIG_I2C_PCI1XXXX is not set
# CONFIG_I2C_ROBOTFUZZ_OSIF is not set
# CONFIG_I2C_TAOS_EVM is not set
# CONFIG_I2C_TINY_USB is not set

#
# Other I2C/SMBus bus drivers
#
CONFIG_I2C_MLXCPLD=m
# CONFIG_I2C_VIRTIO is not set
# end of I2C Hardware Bus support

CONFIG_I2C_STUB=m
# CONFIG_I2C_SLAVE is not set
# CONFIG_I2C_DEBUG_CORE is not set
# CONFIG_I2C_DEBUG_ALGO is not set
# CONFIG_I2C_DEBUG_BUS is not set
# end of I2C support

# CONFIG_I3C is not set
CONFIG_SPI=y
# CONFIG_SPI_DEBUG is not set
CONFIG_SPI_MASTER=y
# CONFIG_SPI_MEM is not set

#
# SPI Master Controller Drivers
#
# CONFIG_SPI_ALTERA is not set
# CONFIG_SPI_AXI_SPI_ENGINE is not set
# CONFIG_SPI_BITBANG is not set
# CONFIG_SPI_BUTTERFLY is not set
# CONFIG_SPI_CADENCE is not set
# CONFIG_SPI_DESIGNWARE is not set
# CONFIG_SPI_NXP_FLEXSPI is not set
# CONFIG_SPI_GPIO is not set
# CONFIG_SPI_LM70_LLP is not set
# CONFIG_SPI_MICROCHIP_CORE is not set
# CONFIG_SPI_MICROCHIP_CORE_QSPI is not set
# CONFIG_SPI_LANTIQ_SSC is not set
# CONFIG_SPI_OC_TINY is not set
# CONFIG_SPI_PXA2XX is not set
# CONFIG_SPI_ROCKCHIP is not set
# CONFIG_SPI_SC18IS602 is not set
# CONFIG_SPI_SIFIVE is not set
# CONFIG_SPI_MXIC is not set
# CONFIG_SPI_XCOMM is not set
# CONFIG_SPI_XILINX is not set
# CONFIG_SPI_ZYNQMP_GQSPI is not set
# CONFIG_SPI_AMD is not set

#
# SPI Multiplexer support
#
# CONFIG_SPI_MUX is not set

#
# SPI Protocol Masters
#
# CONFIG_SPI_SPIDEV is not set
# CONFIG_SPI_LOOPBACK_TEST is not set
# CONFIG_SPI_TLE62X0 is not set
# CONFIG_SPI_SLAVE is not set
CONFIG_SPI_DYNAMIC=y
# CONFIG_SPMI is not set
# CONFIG_HSI is not set
CONFIG_PPS=y
# CONFIG_PPS_DEBUG is not set

#
# PPS clients support
#
# CONFIG_PPS_CLIENT_KTIMER is not set
CONFIG_PPS_CLIENT_LDISC=m
CONFIG_PPS_CLIENT_PARPORT=m
CONFIG_PPS_CLIENT_GPIO=m

#
# PPS generators support
#

#
# PTP clock support
#
CONFIG_PTP_1588_CLOCK=y
CONFIG_PTP_1588_CLOCK_OPTIONAL=y
# CONFIG_DP83640_PHY is not set
# CONFIG_PTP_1588_CLOCK_INES is not set
CONFIG_PTP_1588_CLOCK_KVM=m
# CONFIG_PTP_1588_CLOCK_IDT82P33 is not set
# CONFIG_PTP_1588_CLOCK_IDTCM is not set
# CONFIG_PTP_1588_CLOCK_VMW is not set
# end of PTP clock support

CONFIG_PINCTRL=y
# CONFIG_DEBUG_PINCTRL is not set
# CONFIG_PINCTRL_AMD is not set
# CONFIG_PINCTRL_CY8C95X0 is not set
# CONFIG_PINCTRL_MCP23S08 is not set
# CONFIG_PINCTRL_SX150X is not set

#
# Intel pinctrl drivers
#
# CONFIG_PINCTRL_BAYTRAIL is not set
# CONFIG_PINCTRL_CHERRYVIEW is not set
# CONFIG_PINCTRL_LYNXPOINT is not set
# CONFIG_PINCTRL_ALDERLAKE is not set
# CONFIG_PINCTRL_BROXTON is not set
# CONFIG_PINCTRL_CANNONLAKE is not set
# CONFIG_PINCTRL_CEDARFORK is not set
# CONFIG_PINCTRL_DENVERTON is not set
# CONFIG_PINCTRL_ELKHARTLAKE is not set
# CONFIG_PINCTRL_EMMITSBURG is not set
# CONFIG_PINCTRL_GEMINILAKE is not set
# CONFIG_PINCTRL_ICELAKE is not set
# CONFIG_PINCTRL_JASPERLAKE is not set
# CONFIG_PINCTRL_LAKEFIELD is not set
# CONFIG_PINCTRL_LEWISBURG is not set
# CONFIG_PINCTRL_METEORLAKE is not set
# CONFIG_PINCTRL_SUNRISEPOINT is not set
# CONFIG_PINCTRL_TIGERLAKE is not set
# end of Intel pinctrl drivers

#
# Renesas pinctrl drivers
#
# end of Renesas pinctrl drivers

CONFIG_GPIOLIB=y
CONFIG_GPIOLIB_FASTPATH_LIMIT=512
CONFIG_GPIO_ACPI=y
# CONFIG_DEBUG_GPIO is not set
CONFIG_GPIO_CDEV=y
CONFIG_GPIO_CDEV_V1=y

#
# Memory mapped GPIO drivers
#
# CONFIG_GPIO_AMDPT is not set
# CONFIG_GPIO_DWAPB is not set
# CONFIG_GPIO_EXAR is not set
# CONFIG_GPIO_GENERIC_PLATFORM is not set
CONFIG_GPIO_ICH=m
# CONFIG_GPIO_MB86S7X is not set
# CONFIG_GPIO_VX855 is not set
# CONFIG_GPIO_AMD_FCH is not set
# end of Memory mapped GPIO drivers

#
# Port-mapped I/O GPIO drivers
#
# CONFIG_GPIO_F7188X is not set
# CONFIG_GPIO_IT87 is not set
# CONFIG_GPIO_SCH is not set
# CONFIG_GPIO_SCH311X is not set
# CONFIG_GPIO_WINBOND is not set
# CONFIG_GPIO_WS16C48 is not set
# end of Port-mapped I/O GPIO drivers

#
# I2C GPIO expanders
#
# CONFIG_GPIO_MAX7300 is not set
# CONFIG_GPIO_MAX732X is not set
# CONFIG_GPIO_PCA953X is not set
# CONFIG_GPIO_PCA9570 is not set
# CONFIG_GPIO_PCF857X is not set
# CONFIG_GPIO_TPIC2810 is not set
# end of I2C GPIO expanders

#
# MFD GPIO expanders
#
# end of MFD GPIO expanders

#
# PCI GPIO expanders
#
# CONFIG_GPIO_AMD8111 is not set
# CONFIG_GPIO_BT8XX is not set
# CONFIG_GPIO_ML_IOH is not set
# CONFIG_GPIO_PCI_IDIO_16 is not set
# CONFIG_GPIO_PCIE_IDIO_24 is not set
# CONFIG_GPIO_RDC321X is not set
# end of PCI GPIO expanders

#
# SPI GPIO expanders
#
# CONFIG_GPIO_MAX3191X is not set
# CONFIG_GPIO_MAX7301 is not set
# CONFIG_GPIO_MC33880 is not set
# CONFIG_GPIO_PISOSR is not set
# CONFIG_GPIO_XRA1403 is not set
# end of SPI GPIO expanders

#
# USB GPIO expanders
#
# end of USB GPIO expanders

#
# Virtual GPIO drivers
#
# CONFIG_GPIO_AGGREGATOR is not set
# CONFIG_GPIO_MOCKUP is not set
# CONFIG_GPIO_VIRTIO is not set
# CONFIG_GPIO_SIM is not set
# end of Virtual GPIO drivers

# CONFIG_W1 is not set
CONFIG_POWER_RESET=y
# CONFIG_POWER_RESET_RESTART is not set
CONFIG_POWER_SUPPLY=y
# CONFIG_POWER_SUPPLY_DEBUG is not set
CONFIG_POWER_SUPPLY_HWMON=y
# CONFIG_PDA_POWER is not set
# CONFIG_IP5XXX_POWER is not set
# CONFIG_TEST_POWER is not set
# CONFIG_CHARGER_ADP5061 is not set
# CONFIG_BATTERY_CW2015 is not set
# CONFIG_BATTERY_DS2780 is not set
# CONFIG_BATTERY_DS2781 is not set
# CONFIG_BATTERY_DS2782 is not set
# CONFIG_BATTERY_SAMSUNG_SDI is not set
# CONFIG_BATTERY_SBS is not set
# CONFIG_CHARGER_SBS is not set
# CONFIG_MANAGER_SBS is not set
# CONFIG_BATTERY_BQ27XXX is not set
# CONFIG_BATTERY_MAX17040 is not set
# CONFIG_BATTERY_MAX17042 is not set
# CONFIG_CHARGER_MAX8903 is not set
# CONFIG_CHARGER_LP8727 is not set
# CONFIG_CHARGER_GPIO is not set
# CONFIG_CHARGER_LT3651 is not set
# CONFIG_CHARGER_LTC4162L is not set
# CONFIG_CHARGER_MAX77976 is not set
# CONFIG_CHARGER_BQ2415X is not set
# CONFIG_CHARGER_BQ24257 is not set
# CONFIG_CHARGER_BQ24735 is not set
# CONFIG_CHARGER_BQ2515X is not set
# CONFIG_CHARGER_BQ25890 is not set
# CONFIG_CHARGER_BQ25980 is not set
# CONFIG_CHARGER_BQ256XX is not set
# CONFIG_BATTERY_GAUGE_LTC2941 is not set
# CONFIG_BATTERY_GOLDFISH is not set
# CONFIG_BATTERY_RT5033 is not set
# CONFIG_CHARGER_RT9455 is not set
# CONFIG_CHARGER_BD99954 is not set
# CONFIG_BATTERY_UG3105 is not set
CONFIG_HWMON=y
CONFIG_HWMON_VID=m
# CONFIG_HWMON_DEBUG_CHIP is not set

#
# Native drivers
#
CONFIG_SENSORS_ABITUGURU=m
CONFIG_SENSORS_ABITUGURU3=m
# CONFIG_SENSORS_AD7314 is not set
CONFIG_SENSORS_AD7414=m
CONFIG_SENSORS_AD7418=m
CONFIG_SENSORS_ADM1025=m
CONFIG_SENSORS_ADM1026=m
CONFIG_SENSORS_ADM1029=m
CONFIG_SENSORS_ADM1031=m
# CONFIG_SENSORS_ADM1177 is not set
CONFIG_SENSORS_ADM9240=m
CONFIG_SENSORS_ADT7X10=m
# CONFIG_SENSORS_ADT7310 is not set
CONFIG_SENSORS_ADT7410=m
CONFIG_SENSORS_ADT7411=m
CONFIG_SENSORS_ADT7462=m
CONFIG_SENSORS_ADT7470=m
CONFIG_SENSORS_ADT7475=m
# CONFIG_SENSORS_AHT10 is not set
# CONFIG_SENSORS_AQUACOMPUTER_D5NEXT is not set
# CONFIG_SENSORS_AS370 is not set
CONFIG_SENSORS_ASC7621=m
# CONFIG_SENSORS_AXI_FAN_CONTROL is not set
CONFIG_SENSORS_K8TEMP=m
CONFIG_SENSORS_K10TEMP=m
CONFIG_SENSORS_FAM15H_POWER=m
CONFIG_SENSORS_APPLESMC=m
CONFIG_SENSORS_ASB100=m
CONFIG_SENSORS_ATXP1=m
# CONFIG_SENSORS_CORSAIR_CPRO is not set
# CONFIG_SENSORS_CORSAIR_PSU is not set
# CONFIG_SENSORS_DRIVETEMP is not set
CONFIG_SENSORS_DS620=m
CONFIG_SENSORS_DS1621=m
# CONFIG_SENSORS_DELL_SMM is not set
CONFIG_SENSORS_I5K_AMB=m
CONFIG_SENSORS_F71805F=m
CONFIG_SENSORS_F71882FG=m
CONFIG_SENSORS_F75375S=m
CONFIG_SENSORS_FSCHMD=m
# CONFIG_SENSORS_FTSTEUTATES is not set
CONFIG_SENSORS_GL518SM=m
CONFIG_SENSORS_GL520SM=m
CONFIG_SENSORS_G760A=m
# CONFIG_SENSORS_G762 is not set
# CONFIG_SENSORS_HIH6130 is not set
CONFIG_SENSORS_IBMAEM=m
CONFIG_SENSORS_IBMPEX=m
CONFIG_SENSORS_I5500=m
CONFIG_SENSORS_CORETEMP=m
CONFIG_SENSORS_IT87=m
CONFIG_SENSORS_JC42=m
# CONFIG_SENSORS_POWR1220 is not set
CONFIG_SENSORS_LINEAGE=m
# CONFIG_SENSORS_LTC2945 is not set
# CONFIG_SENSORS_LTC2947_I2C is not set
# CONFIG_SENSORS_LTC2947_SPI is not set
# CONFIG_SENSORS_LTC2990 is not set
# CONFIG_SENSORS_LTC2992 is not set
CONFIG_SENSORS_LTC4151=m
CONFIG_SENSORS_LTC4215=m
# CONFIG_SENSORS_LTC4222 is not set
CONFIG_SENSORS_LTC4245=m
# CONFIG_SENSORS_LTC4260 is not set
CONFIG_SENSORS_LTC4261=m
# CONFIG_SENSORS_MAX1111 is not set
# CONFIG_SENSORS_MAX127 is not set
CONFIG_SENSORS_MAX16065=m
CONFIG_SENSORS_MAX1619=m
CONFIG_SENSORS_MAX1668=m
CONFIG_SENSORS_MAX197=m
# CONFIG_SENSORS_MAX31722 is not set
# CONFIG_SENSORS_MAX31730 is not set
# CONFIG_SENSORS_MAX31760 is not set
# CONFIG_SENSORS_MAX6620 is not set
# CONFIG_SENSORS_MAX6621 is not set
CONFIG_SENSORS_MAX6639=m
CONFIG_SENSORS_MAX6650=m
CONFIG_SENSORS_MAX6697=m
# CONFIG_SENSORS_MAX31790 is not set
CONFIG_SENSORS_MCP3021=m
# CONFIG_SENSORS_MLXREG_FAN is not set
# CONFIG_SENSORS_TC654 is not set
# CONFIG_SENSORS_TPS23861 is not set
# CONFIG_SENSORS_MR75203 is not set
# CONFIG_SENSORS_ADCXX is not set
CONFIG_SENSORS_LM63=m
# CONFIG_SENSORS_LM70 is not set
CONFIG_SENSORS_LM73=m
CONFIG_SENSORS_LM75=m
CONFIG_SENSORS_LM77=m
CONFIG_SENSORS_LM78=m
CONFIG_SENSORS_LM80=m
CONFIG_SENSORS_LM83=m
CONFIG_SENSORS_LM85=m
CONFIG_SENSORS_LM87=m
CONFIG_SENSORS_LM90=m
CONFIG_SENSORS_LM92=m
CONFIG_SENSORS_LM93=m
CONFIG_SENSORS_LM95234=m
CONFIG_SENSORS_LM95241=m
CONFIG_SENSORS_LM95245=m
CONFIG_SENSORS_PC87360=m
CONFIG_SENSORS_PC87427=m
# CONFIG_SENSORS_NCT6683 is not set
CONFIG_SENSORS_NCT6775_CORE=m
CONFIG_SENSORS_NCT6775=m
# CONFIG_SENSORS_NCT6775_I2C is not set
# CONFIG_SENSORS_NCT7802 is not set
# CONFIG_SENSORS_NCT7904 is not set
# CONFIG_SENSORS_NPCM7XX is not set
# CONFIG_SENSORS_NZXT_KRAKEN2 is not set
# CONFIG_SENSORS_NZXT_SMART2 is not set
CONFIG_SENSORS_PCF8591=m
CONFIG_PMBUS=m
CONFIG_SENSORS_PMBUS=m
# CONFIG_SENSORS_ADM1266 is not set
CONFIG_SENSORS_ADM1275=m
# CONFIG_SENSORS_BEL_PFE is not set
# CONFIG_SENSORS_BPA_RS600 is not set
# CONFIG_SENSORS_DELTA_AHE50DC_FAN is not set
# CONFIG_SENSORS_FSP_3Y is not set
# CONFIG_SENSORS_IBM_CFFPS is not set
# CONFIG_SENSORS_DPS920AB is not set
# CONFIG_SENSORS_INSPUR_IPSPS is not set
# CONFIG_SENSORS_IR35221 is not set
# CONFIG_SENSORS_IR36021 is not set
# CONFIG_SENSORS_IR38064 is not set
# CONFIG_SENSORS_IRPS5401 is not set
# CONFIG_SENSORS_ISL68137 is not set
CONFIG_SENSORS_LM25066=m
# CONFIG_SENSORS_LT7182S is not set
CONFIG_SENSORS_LTC2978=m
# CONFIG_SENSORS_LTC3815 is not set
# CONFIG_SENSORS_MAX15301 is not set
CONFIG_SENSORS_MAX16064=m
# CONFIG_SENSORS_MAX16601 is not set
# CONFIG_SENSORS_MAX20730 is not set
# CONFIG_SENSORS_MAX20751 is not set
# CONFIG_SENSORS_MAX31785 is not set
CONFIG_SENSORS_MAX34440=m
CONFIG_SENSORS_MAX8688=m
# CONFIG_SENSORS_MP2888 is not set
# CONFIG_SENSORS_MP2975 is not set
# CONFIG_SENSORS_MP5023 is not set
# CONFIG_SENSORS_PIM4328 is not set
# CONFIG_SENSORS_PLI1209BC is not set
# CONFIG_SENSORS_PM6764TR is not set
# CONFIG_SENSORS_PXE1610 is not set
# CONFIG_SENSORS_Q54SJ108A2 is not set
# CONFIG_SENSORS_STPDDC60 is not set
# CONFIG_SENSORS_TPS40422 is not set
# CONFIG_SENSORS_TPS53679 is not set
# CONFIG_SENSORS_TPS546D24 is not set
CONFIG_SENSORS_UCD9000=m
CONFIG_SENSORS_UCD9200=m
# CONFIG_SENSORS_XDPE152 is not set
# CONFIG_SENSORS_XDPE122 is not set
CONFIG_SENSORS_ZL6100=m
# CONFIG_SENSORS_SBTSI is not set
# CONFIG_SENSORS_SBRMI is not set
CONFIG_SENSORS_SHT15=m
CONFIG_SENSORS_SHT21=m
# CONFIG_SENSORS_SHT3x is not set
# CONFIG_SENSORS_SHT4x is not set
# CONFIG_SENSORS_SHTC1 is not set
CONFIG_SENSORS_SIS5595=m
CONFIG_SENSORS_DME1737=m
CONFIG_SENSORS_EMC1403=m
# CONFIG_SENSORS_EMC2103 is not set
# CONFIG_SENSORS_EMC2305 is not set
CONFIG_SENSORS_EMC6W201=m
CONFIG_SENSORS_SMSC47M1=m
CONFIG_SENSORS_SMSC47M192=m
CONFIG_SENSORS_SMSC47B397=m
CONFIG_SENSORS_SCH56XX_COMMON=m
CONFIG_SENSORS_SCH5627=m
CONFIG_SENSORS_SCH5636=m
# CONFIG_SENSORS_STTS751 is not set
# CONFIG_SENSORS_SMM665 is not set
# CONFIG_SENSORS_ADC128D818 is not set
CONFIG_SENSORS_ADS7828=m
# CONFIG_SENSORS_ADS7871 is not set
CONFIG_SENSORS_AMC6821=m
CONFIG_SENSORS_INA209=m
CONFIG_SENSORS_INA2XX=m
# CONFIG_SENSORS_INA238 is not set
# CONFIG_SENSORS_INA3221 is not set
# CONFIG_SENSORS_TC74 is not set
CONFIG_SENSORS_THMC50=m
CONFIG_SENSORS_TMP102=m
# CONFIG_SENSORS_TMP103 is not set
# CONFIG_SENSORS_TMP108 is not set
CONFIG_SENSORS_TMP401=m
CONFIG_SENSORS_TMP421=m
# CONFIG_SENSORS_TMP464 is not set
# CONFIG_SENSORS_TMP513 is not set
CONFIG_SENSORS_VIA_CPUTEMP=m
CONFIG_SENSORS_VIA686A=m
CONFIG_SENSORS_VT1211=m
CONFIG_SENSORS_VT8231=m
# CONFIG_SENSORS_W83773G is not set
CONFIG_SENSORS_W83781D=m
CONFIG_SENSORS_W83791D=m
CONFIG_SENSORS_W83792D=m
CONFIG_SENSORS_W83793=m
CONFIG_SENSORS_W83795=m
# CONFIG_SENSORS_W83795_FANCTRL is not set
CONFIG_SENSORS_W83L785TS=m
CONFIG_SENSORS_W83L786NG=m
CONFIG_SENSORS_W83627HF=m
CONFIG_SENSORS_W83627EHF=m
# CONFIG_SENSORS_XGENE is not set

#
# ACPI drivers
#
CONFIG_SENSORS_ACPI_POWER=m
CONFIG_SENSORS_ATK0110=m
# CONFIG_SENSORS_ASUS_WMI is not set
# CONFIG_SENSORS_ASUS_EC is not set
CONFIG_THERMAL=y
# CONFIG_THERMAL_NETLINK is not set
# CONFIG_THERMAL_STATISTICS is not set
CONFIG_THERMAL_EMERGENCY_POWEROFF_DELAY_MS=0
CONFIG_THERMAL_HWMON=y
CONFIG_THERMAL_WRITABLE_TRIPS=y
CONFIG_THERMAL_DEFAULT_GOV_STEP_WISE=y
# CONFIG_THERMAL_DEFAULT_GOV_FAIR_SHARE is not set
# CONFIG_THERMAL_DEFAULT_GOV_USER_SPACE is not set
CONFIG_THERMAL_GOV_FAIR_SHARE=y
CONFIG_THERMAL_GOV_STEP_WISE=y
CONFIG_THERMAL_GOV_BANG_BANG=y
CONFIG_THERMAL_GOV_USER_SPACE=y
# CONFIG_THERMAL_EMULATION is not set

#
# Intel thermal drivers
#
CONFIG_INTEL_POWERCLAMP=m
CONFIG_X86_THERMAL_VECTOR=y
CONFIG_X86_PKG_TEMP_THERMAL=m
# CONFIG_INTEL_SOC_DTS_THERMAL is not set

#
# ACPI INT340X thermal drivers
#
# CONFIG_INT340X_THERMAL is not set
# end of ACPI INT340X thermal drivers

CONFIG_INTEL_PCH_THERMAL=m
# CONFIG_INTEL_TCC_COOLING is not set
# CONFIG_INTEL_MENLOW is not set
# CONFIG_INTEL_HFI_THERMAL is not set
# end of Intel thermal drivers

CONFIG_WATCHDOG=y
CONFIG_WATCHDOG_CORE=y
# CONFIG_WATCHDOG_NOWAYOUT is not set
CONFIG_WATCHDOG_HANDLE_BOOT_ENABLED=y
CONFIG_WATCHDOG_OPEN_TIMEOUT=0
CONFIG_WATCHDOG_SYSFS=y
# CONFIG_WATCHDOG_HRTIMER_PRETIMEOUT is not set

#
# Watchdog Pretimeout Governors
#
# CONFIG_WATCHDOG_PRETIMEOUT_GOV is not set

#
# Watchdog Device Drivers
#
CONFIG_SOFT_WATCHDOG=m
CONFIG_WDAT_WDT=m
# CONFIG_XILINX_WATCHDOG is not set
# CONFIG_ZIIRAVE_WATCHDOG is not set
# CONFIG_MLX_WDT is not set
# CONFIG_CADENCE_WATCHDOG is not set
# CONFIG_DW_WATCHDOG is not set
# CONFIG_MAX63XX_WATCHDOG is not set
# CONFIG_ACQUIRE_WDT is not set
# CONFIG_ADVANTECH_WDT is not set
CONFIG_ALIM1535_WDT=m
CONFIG_ALIM7101_WDT=m
# CONFIG_EBC_C384_WDT is not set
# CONFIG_EXAR_WDT is not set
CONFIG_F71808E_WDT=m
# CONFIG_SP5100_TCO is not set
CONFIG_SBC_FITPC2_WATCHDOG=m
# CONFIG_EUROTECH_WDT is not set
CONFIG_IB700_WDT=m
CONFIG_IBMASR=m
# CONFIG_WAFER_WDT is not set
CONFIG_I6300ESB_WDT=y
CONFIG_IE6XX_WDT=m
CONFIG_ITCO_WDT=y
CONFIG_ITCO_VENDOR_SUPPORT=y
CONFIG_IT8712F_WDT=m
CONFIG_IT87_WDT=m
CONFIG_HP_WATCHDOG=m
CONFIG_HPWDT_NMI_DECODING=y
# CONFIG_SC1200_WDT is not set
# CONFIG_PC87413_WDT is not set
CONFIG_NV_TCO=m
# CONFIG_60XX_WDT is not set
# CONFIG_CPU5_WDT is not set
CONFIG_SMSC_SCH311X_WDT=m
# CONFIG_SMSC37B787_WDT is not set
# CONFIG_TQMX86_WDT is not set
CONFIG_VIA_WDT=m
CONFIG_W83627HF_WDT=m
CONFIG_W83877F_WDT=m
CONFIG_W83977F_WDT=m
CONFIG_MACHZ_WDT=m
# CONFIG_SBC_EPX_C3_WATCHDOG is not set
CONFIG_INTEL_MEI_WDT=m
# CONFIG_NI903X_WDT is not set
# CONFIG_NIC7018_WDT is not set
# CONFIG_MEN_A21_WDT is not set

#
# PCI-based Watchdog Cards
#
CONFIG_PCIPCWATCHDOG=m
CONFIG_WDTPCI=m

#
# USB-based Watchdog Cards
#
# CONFIG_USBPCWATCHDOG is not set
CONFIG_SSB_POSSIBLE=y
# CONFIG_SSB is not set
CONFIG_BCMA_POSSIBLE=y
CONFIG_BCMA=m
CONFIG_BCMA_HOST_PCI_POSSIBLE=y
CONFIG_BCMA_HOST_PCI=y
# CONFIG_BCMA_HOST_SOC is not set
CONFIG_BCMA_DRIVER_PCI=y
CONFIG_BCMA_DRIVER_GMAC_CMN=y
CONFIG_BCMA_DRIVER_GPIO=y
# CONFIG_BCMA_DEBUG is not set

#
# Multifunction device drivers
#
CONFIG_MFD_CORE=y
# CONFIG_MFD_AS3711 is not set
# CONFIG_PMIC_ADP5520 is not set
# CONFIG_MFD_AAT2870_CORE is not set
# CONFIG_MFD_BCM590XX is not set
# CONFIG_MFD_BD9571MWV is not set
# CONFIG_MFD_AXP20X_I2C is not set
# CONFIG_MFD_MADERA is not set
# CONFIG_PMIC_DA903X is not set
# CONFIG_MFD_DA9052_SPI is not set
# CONFIG_MFD_DA9052_I2C is not set
# CONFIG_MFD_DA9055 is not set
# CONFIG_MFD_DA9062 is not set
# CONFIG_MFD_DA9063 is not set
# CONFIG_MFD_DA9150 is not set
# CONFIG_MFD_DLN2 is not set
# CONFIG_MFD_MC13XXX_SPI is not set
# CONFIG_MFD_MC13XXX_I2C is not set
# CONFIG_MFD_MP2629 is not set
# CONFIG_HTC_PASIC3 is not set
# CONFIG_HTC_I2CPLD is not set
# CONFIG_MFD_INTEL_QUARK_I2C_GPIO is not set
CONFIG_LPC_ICH=y
CONFIG_LPC_SCH=m
CONFIG_MFD_INTEL_LPSS=y
CONFIG_MFD_INTEL_LPSS_ACPI=y
CONFIG_MFD_INTEL_LPSS_PCI=y
# CONFIG_MFD_INTEL_PMC_BXT is not set
# CONFIG_MFD_IQS62X is not set
# CONFIG_MFD_JANZ_CMODIO is not set
# CONFIG_MFD_KEMPLD is not set
# CONFIG_MFD_88PM800 is not set
# CONFIG_MFD_88PM805 is not set
# CONFIG_MFD_88PM860X is not set
# CONFIG_MFD_MAX14577 is not set
# CONFIG_MFD_MAX77693 is not set
# CONFIG_MFD_MAX77843 is not set
# CONFIG_MFD_MAX8907 is not set
# CONFIG_MFD_MAX8925 is not set
# CONFIG_MFD_MAX8997 is not set
# CONFIG_MFD_MAX8998 is not set
# CONFIG_MFD_MT6360 is not set
# CONFIG_MFD_MT6370 is not set
# CONFIG_MFD_MT6397 is not set
# CONFIG_MFD_MENF21BMC is not set
# CONFIG_MFD_OCELOT is not set
# CONFIG_EZX_PCAP is not set
# CONFIG_MFD_VIPERBOARD is not set
# CONFIG_MFD_RETU is not set
# CONFIG_MFD_PCF50633 is not set
# CONFIG_MFD_SY7636A is not set
# CONFIG_MFD_RDC321X is not set
# CONFIG_MFD_RT4831 is not set
# CONFIG_MFD_RT5033 is not set
# CONFIG_MFD_RT5120 is not set
# CONFIG_MFD_RC5T583 is not set
# CONFIG_MFD_SI476X_CORE is not set
CONFIG_MFD_SM501=m
CONFIG_MFD_SM501_GPIO=y
# CONFIG_MFD_SKY81452 is not set
# CONFIG_MFD_SYSCON is not set
# CONFIG_MFD_TI_AM335X_TSCADC is not set
# CONFIG_MFD_LP3943 is not set
# CONFIG_MFD_LP8788 is not set
# CONFIG_MFD_TI_LMU is not set
# CONFIG_MFD_PALMAS is not set
# CONFIG_TPS6105X is not set
# CONFIG_TPS65010 is not set
# CONFIG_TPS6507X is not set
# CONFIG_MFD_TPS65086 is not set
# CONFIG_MFD_TPS65090 is not set
# CONFIG_MFD_TI_LP873X is not set
# CONFIG_MFD_TPS6586X is not set
# CONFIG_MFD_TPS65910 is not set
# CONFIG_MFD_TPS65912_I2C is not set
# CONFIG_MFD_TPS65912_SPI is not set
# CONFIG_TWL4030_CORE is not set
# CONFIG_TWL6040_CORE is not set
# CONFIG_MFD_WL1273_CORE is not set
# CONFIG_MFD_LM3533 is not set
# CONFIG_MFD_TQMX86 is not set
CONFIG_MFD_VX855=m
# CONFIG_MFD_ARIZONA_I2C is not set
# CONFIG_MFD_ARIZONA_SPI is not set
# CONFIG_MFD_WM8400 is not set
# CONFIG_MFD_WM831X_I2C is not set
# CONFIG_MFD_WM831X_SPI is not set
# CONFIG_MFD_WM8350_I2C is not set
# CONFIG_MFD_WM8994 is not set
# CONFIG_MFD_ATC260X_I2C is not set
# CONFIG_MFD_INTEL_M10_BMC is not set
# end of Multifunction device drivers

# CONFIG_REGULATOR is not set
CONFIG_RC_CORE=m
CONFIG_LIRC=y
CONFIG_RC_MAP=m
CONFIG_RC_DECODERS=y
CONFIG_IR_IMON_DECODER=m
CONFIG_IR_JVC_DECODER=m
CONFIG_IR_MCE_KBD_DECODER=m
CONFIG_IR_NEC_DECODER=m
CONFIG_IR_RC5_DECODER=m
CONFIG_IR_RC6_DECODER=m
# CONFIG_IR_RCMM_DECODER is not set
CONFIG_IR_SANYO_DECODER=m
# CONFIG_IR_SHARP_DECODER is not set
CONFIG_IR_SONY_DECODER=m
# CONFIG_IR_XMP_DECODER is not set
CONFIG_RC_DEVICES=y
CONFIG_IR_ENE=m
CONFIG_IR_FINTEK=m
# CONFIG_IR_IGORPLUGUSB is not set
# CONFIG_IR_IGUANA is not set
# CONFIG_IR_IMON is not set
# CONFIG_IR_IMON_RAW is not set
CONFIG_IR_ITE_CIR=m
# CONFIG_IR_MCEUSB is not set
CONFIG_IR_NUVOTON=m
# CONFIG_IR_REDRAT3 is not set
CONFIG_IR_SERIAL=m
CONFIG_IR_SERIAL_TRANSMITTER=y
# CONFIG_IR_STREAMZAP is not set
# CONFIG_IR_TOY is not set
# CONFIG_IR_TTUSBIR is not set
CONFIG_IR_WINBOND_CIR=m
# CONFIG_RC_ATI_REMOTE is not set
# CONFIG_RC_LOOPBACK is not set
# CONFIG_RC_XBOX_DVD is not set

#
# CEC support
#
# CONFIG_MEDIA_CEC_SUPPORT is not set
# end of CEC support

CONFIG_MEDIA_SUPPORT=m
CONFIG_MEDIA_SUPPORT_FILTER=y
CONFIG_MEDIA_SUBDRV_AUTOSELECT=y

#
# Media device types
#
# CONFIG_MEDIA_CAMERA_SUPPORT is not set
# CONFIG_MEDIA_ANALOG_TV_SUPPORT is not set
# CONFIG_MEDIA_DIGITAL_TV_SUPPORT is not set
# CONFIG_MEDIA_RADIO_SUPPORT is not set
# CONFIG_MEDIA_SDR_SUPPORT is not set
# CONFIG_MEDIA_PLATFORM_SUPPORT is not set
# CONFIG_MEDIA_TEST_SUPPORT is not set
# end of Media device types

#
# Media drivers
#

#
# Drivers filtered as selected at 'Filter media drivers'
#

#
# Media drivers
#
# CONFIG_MEDIA_USB_SUPPORT is not set
# CONFIG_MEDIA_PCI_SUPPORT is not set
# end of Media drivers

CONFIG_MEDIA_HIDE_ANCILLARY_SUBDRV=y

#
# Media ancillary drivers
#
# end of Media ancillary drivers

#
# Graphics support
#
CONFIG_APERTURE_HELPERS=y
# CONFIG_AGP is not set
CONFIG_INTEL_GTT=m
CONFIG_VGA_SWITCHEROO=y
CONFIG_DRM=m
CONFIG_DRM_MIPI_DSI=y
CONFIG_DRM_USE_DYNAMIC_DEBUG=y
CONFIG_DRM_KMS_HELPER=m
CONFIG_DRM_FBDEV_EMULATION=y
CONFIG_DRM_FBDEV_OVERALLOC=100
CONFIG_DRM_LOAD_EDID_FIRMWARE=y
CONFIG_DRM_DISPLAY_HELPER=m
CONFIG_DRM_DISPLAY_DP_HELPER=y
CONFIG_DRM_DISPLAY_HDCP_HELPER=y
CONFIG_DRM_DISPLAY_HDMI_HELPER=y
CONFIG_DRM_DP_AUX_CHARDEV=y
# CONFIG_DRM_DP_CEC is not set
CONFIG_DRM_TTM=m
CONFIG_DRM_BUDDY=m
CONFIG_DRM_VRAM_HELPER=m
CONFIG_DRM_TTM_HELPER=m
CONFIG_DRM_GEM_SHMEM_HELPER=m

#
# I2C encoder or helper chips
#
CONFIG_DRM_I2C_CH7006=m
CONFIG_DRM_I2C_SIL164=m
# CONFIG_DRM_I2C_NXP_TDA998X is not set
# CONFIG_DRM_I2C_NXP_TDA9950 is not set
# end of I2C encoder or helper chips

#
# ARM devices
#
# end of ARM devices

# CONFIG_DRM_RADEON is not set
# CONFIG_DRM_AMDGPU is not set
# CONFIG_DRM_NOUVEAU is not set
CONFIG_DRM_I915=m
CONFIG_DRM_I915_FORCE_PROBE=""
CONFIG_DRM_I915_CAPTURE_ERROR=y
CONFIG_DRM_I915_COMPRESS_ERROR=y
CONFIG_DRM_I915_USERPTR=y
# CONFIG_DRM_I915_GVT_KVMGT is not set
CONFIG_DRM_I915_REQUEST_TIMEOUT=20000
CONFIG_DRM_I915_FENCE_TIMEOUT=10000
CONFIG_DRM_I915_USERFAULT_AUTOSUSPEND=250
CONFIG_DRM_I915_HEARTBEAT_INTERVAL=2500
CONFIG_DRM_I915_PREEMPT_TIMEOUT=640
CONFIG_DRM_I915_MAX_REQUEST_BUSYWAIT=8000
CONFIG_DRM_I915_STOP_TIMEOUT=100
CONFIG_DRM_I915_TIMESLICE_DURATION=1
# CONFIG_DRM_VGEM is not set
# CONFIG_DRM_VKMS is not set
# CONFIG_DRM_VMWGFX is not set
CONFIG_DRM_GMA500=m
# CONFIG_DRM_UDL is not set
CONFIG_DRM_AST=m
# CONFIG_DRM_MGAG200 is not set
CONFIG_DRM_QXL=m
CONFIG_DRM_VIRTIO_GPU=m
CONFIG_DRM_PANEL=y

#
# Display Panels
#
# CONFIG_DRM_PANEL_RASPBERRYPI_TOUCHSCREEN is not set
# CONFIG_DRM_PANEL_WIDECHIPS_WS2401 is not set
# end of Display Panels

CONFIG_DRM_BRIDGE=y
CONFIG_DRM_PANEL_BRIDGE=y

#
# Display Interface Bridges
#
# CONFIG_DRM_ANALOGIX_ANX78XX is not set
# end of Display Interface Bridges

# CONFIG_DRM_ETNAVIV is not set
CONFIG_DRM_BOCHS=m
CONFIG_DRM_CIRRUS_QEMU=m
# CONFIG_DRM_GM12U320 is not set
# CONFIG_DRM_PANEL_MIPI_DBI is not set
# CONFIG_DRM_SIMPLEDRM is not set
# CONFIG_TINYDRM_HX8357D is not set
# CONFIG_TINYDRM_ILI9163 is not set
# CONFIG_TINYDRM_ILI9225 is not set
# CONFIG_TINYDRM_ILI9341 is not set
# CONFIG_TINYDRM_ILI9486 is not set
# CONFIG_TINYDRM_MI0283QT is not set
# CONFIG_TINYDRM_REPAPER is not set
# CONFIG_TINYDRM_ST7586 is not set
# CONFIG_TINYDRM_ST7735R is not set
# CONFIG_DRM_VBOXVIDEO is not set
# CONFIG_DRM_GUD is not set
# CONFIG_DRM_SSD130X is not set
# CONFIG_DRM_LEGACY is not set
CONFIG_DRM_PANEL_ORIENTATION_QUIRKS=y
CONFIG_DRM_NOMODESET=y
CONFIG_DRM_PRIVACY_SCREEN=y

#
# Frame buffer Devices
#
CONFIG_FB_CMDLINE=y
CONFIG_FB_NOTIFY=y
CONFIG_FB=y
# CONFIG_FIRMWARE_EDID is not set
CONFIG_FB_CFB_FILLRECT=y
CONFIG_FB_CFB_COPYAREA=y
CONFIG_FB_CFB_IMAGEBLIT=y
CONFIG_FB_SYS_FILLRECT=m
CONFIG_FB_SYS_COPYAREA=m
CONFIG_FB_SYS_IMAGEBLIT=m
# CONFIG_FB_FOREIGN_ENDIAN is not set
CONFIG_FB_SYS_FOPS=m
CONFIG_FB_DEFERRED_IO=y
# CONFIG_FB_MODE_HELPERS is not set
CONFIG_FB_TILEBLITTING=y

#
# Frame buffer hardware drivers
#
# CONFIG_FB_CIRRUS is not set
# CONFIG_FB_PM2 is not set
# CONFIG_FB_CYBER2000 is not set
# CONFIG_FB_ARC is not set
# CONFIG_FB_ASILIANT is not set
# CONFIG_FB_IMSTT is not set
# CONFIG_FB_VGA16 is not set
# CONFIG_FB_UVESA is not set
CONFIG_FB_VESA=y
CONFIG_FB_EFI=y
# CONFIG_FB_N411 is not set
# CONFIG_FB_HGA is not set
# CONFIG_FB_OPENCORES is not set
# CONFIG_FB_S1D13XXX is not set
# CONFIG_FB_NVIDIA is not set
# CONFIG_FB_RIVA is not set
# CONFIG_FB_I740 is not set
# CONFIG_FB_LE80578 is not set
# CONFIG_FB_MATROX is not set
# CONFIG_FB_RADEON is not set
# CONFIG_FB_ATY128 is not set
# CONFIG_FB_ATY is not set
# CONFIG_FB_S3 is not set
# CONFIG_FB_SAVAGE is not set
# CONFIG_FB_SIS is not set
# CONFIG_FB_VIA is not set
# CONFIG_FB_NEOMAGIC is not set
# CONFIG_FB_KYRO is not set
# CONFIG_FB_3DFX is not set
# CONFIG_FB_VOODOO1 is not set
# CONFIG_FB_VT8623 is not set
# CONFIG_FB_TRIDENT is not set
# CONFIG_FB_ARK is not set
# CONFIG_FB_PM3 is not set
# CONFIG_FB_CARMINE is not set
# CONFIG_FB_SM501 is not set
# CONFIG_FB_SMSCUFX is not set
# CONFIG_FB_UDL is not set
# CONFIG_FB_IBM_GXT4500 is not set
# CONFIG_FB_VIRTUAL is not set
# CONFIG_FB_METRONOME is not set
# CONFIG_FB_MB862XX is not set
# CONFIG_FB_SIMPLE is not set
# CONFIG_FB_SSD1307 is not set
# CONFIG_FB_SM712 is not set
# end of Frame buffer Devices

#
# Backlight & LCD device support
#
CONFIG_LCD_CLASS_DEVICE=m
# CONFIG_LCD_L4F00242T03 is not set
# CONFIG_LCD_LMS283GF05 is not set
# CONFIG_LCD_LTV350QV is not set
# CONFIG_LCD_ILI922X is not set
# CONFIG_LCD_ILI9320 is not set
# CONFIG_LCD_TDO24M is not set
# CONFIG_LCD_VGG2432A4 is not set
CONFIG_LCD_PLATFORM=m
# CONFIG_LCD_AMS369FG06 is not set
# CONFIG_LCD_LMS501KF03 is not set
# CONFIG_LCD_HX8357 is not set
# CONFIG_LCD_OTM3225A is not set
CONFIG_BACKLIGHT_CLASS_DEVICE=y
# CONFIG_BACKLIGHT_KTD253 is not set
# CONFIG_BACKLIGHT_PWM is not set
CONFIG_BACKLIGHT_APPLE=m
# CONFIG_BACKLIGHT_QCOM_WLED is not set
# CONFIG_BACKLIGHT_SAHARA is not set
# CONFIG_BACKLIGHT_ADP8860 is not set
# CONFIG_BACKLIGHT_ADP8870 is not set
# CONFIG_BACKLIGHT_LM3630A is not set
# CONFIG_BACKLIGHT_LM3639 is not set
CONFIG_BACKLIGHT_LP855X=m
# CONFIG_BACKLIGHT_GPIO is not set
# CONFIG_BACKLIGHT_LV5207LP is not set
# CONFIG_BACKLIGHT_BD6107 is not set
# CONFIG_BACKLIGHT_ARCXCNN is not set
# end of Backlight & LCD device support

CONFIG_HDMI=y

#
# Console display driver support
#
CONFIG_VGA_CONSOLE=y
CONFIG_DUMMY_CONSOLE=y
CONFIG_DUMMY_CONSOLE_COLUMNS=80
CONFIG_DUMMY_CONSOLE_ROWS=25
CONFIG_FRAMEBUFFER_CONSOLE=y
# CONFIG_FRAMEBUFFER_CONSOLE_LEGACY_ACCELERATION is not set
CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y
CONFIG_FRAMEBUFFER_CONSOLE_ROTATION=y
# CONFIG_FRAMEBUFFER_CONSOLE_DEFERRED_TAKEOVER is not set
# end of Console display driver support

CONFIG_LOGO=y
# CONFIG_LOGO_LINUX_MONO is not set
# CONFIG_LOGO_LINUX_VGA16 is not set
CONFIG_LOGO_LINUX_CLUT224=y
# end of Graphics support

# CONFIG_SOUND is not set

#
# HID support
#
CONFIG_HID=y
CONFIG_HID_BATTERY_STRENGTH=y
CONFIG_HIDRAW=y
CONFIG_UHID=m
CONFIG_HID_GENERIC=y

#
# Special HID drivers
#
CONFIG_HID_A4TECH=m
# CONFIG_HID_ACCUTOUCH is not set
CONFIG_HID_ACRUX=m
# CONFIG_HID_ACRUX_FF is not set
CONFIG_HID_APPLE=m
# CONFIG_HID_APPLEIR is not set
CONFIG_HID_ASUS=m
CONFIG_HID_AUREAL=m
CONFIG_HID_BELKIN=m
# CONFIG_HID_BETOP_FF is not set
# CONFIG_HID_BIGBEN_FF is not set
CONFIG_HID_CHERRY=m
# CONFIG_HID_CHICONY is not set
# CONFIG_HID_CORSAIR is not set
# CONFIG_HID_COUGAR is not set
# CONFIG_HID_MACALLY is not set
CONFIG_HID_CMEDIA=m
# CONFIG_HID_CP2112 is not set
# CONFIG_HID_CREATIVE_SB0540 is not set
CONFIG_HID_CYPRESS=m
CONFIG_HID_DRAGONRISE=m
# CONFIG_DRAGONRISE_FF is not set
# CONFIG_HID_EMS_FF is not set
# CONFIG_HID_ELAN is not set
CONFIG_HID_ELECOM=m
# CONFIG_HID_ELO is not set
CONFIG_HID_EZKEY=m
# CONFIG_HID_FT260 is not set
CONFIG_HID_GEMBIRD=m
CONFIG_HID_GFRM=m
# CONFIG_HID_GLORIOUS is not set
# CONFIG_HID_HOLTEK is not set
# CONFIG_HID_VIVALDI is not set
# CONFIG_HID_GT683R is not set
CONFIG_HID_KEYTOUCH=m
CONFIG_HID_KYE=m
# CONFIG_HID_UCLOGIC is not set
CONFIG_HID_WALTOP=m
# CONFIG_HID_VIEWSONIC is not set
# CONFIG_HID_VRC2 is not set
# CONFIG_HID_XIAOMI is not set
CONFIG_HID_GYRATION=m
CONFIG_HID_ICADE=m
CONFIG_HID_ITE=m
CONFIG_HID_JABRA=m
CONFIG_HID_TWINHAN=m
CONFIG_HID_KENSINGTON=m
CONFIG_HID_LCPOWER=m
CONFIG_HID_LED=m
CONFIG_HID_LENOVO=m
# CONFIG_HID_LETSKETCH is not set
CONFIG_HID_LOGITECH=m
CONFIG_HID_LOGITECH_DJ=m
CONFIG_HID_LOGITECH_HIDPP=m
# CONFIG_LOGITECH_FF is not set
# CONFIG_LOGIRUMBLEPAD2_FF is not set
# CONFIG_LOGIG940_FF is not set
# CONFIG_LOGIWHEELS_FF is not set
CONFIG_HID_MAGICMOUSE=y
# CONFIG_HID_MALTRON is not set
# CONFIG_HID_MAYFLASH is not set
# CONFIG_HID_MEGAWORLD_FF is not set
# CONFIG_HID_REDRAGON is not set
CONFIG_HID_MICROSOFT=m
CONFIG_HID_MONTEREY=m
CONFIG_HID_MULTITOUCH=m
# CONFIG_HID_NINTENDO is not set
CONFIG_HID_NTI=m
# CONFIG_HID_NTRIG is not set
CONFIG_HID_ORTEK=m
CONFIG_HID_PANTHERLORD=m
# CONFIG_PANTHERLORD_FF is not set
# CONFIG_HID_PENMOUNT is not set
CONFIG_HID_PETALYNX=m
CONFIG_HID_PICOLCD=m
CONFIG_HID_PICOLCD_FB=y
CONFIG_HID_PICOLCD_BACKLIGHT=y
CONFIG_HID_PICOLCD_LCD=y
CONFIG_HID_PICOLCD_LEDS=y
CONFIG_HID_PICOLCD_CIR=y
CONFIG_HID_PLANTRONICS=m
# CONFIG_HID_PXRC is not set
# CONFIG_HID_RAZER is not set
CONFIG_HID_PRIMAX=m
# CONFIG_HID_RETRODE is not set
# CONFIG_HID_ROCCAT is not set
CONFIG_HID_SAITEK=m
CONFIG_HID_SAMSUNG=m
# CONFIG_HID_SEMITEK is not set
# CONFIG_HID_SIGMAMICRO is not set
# CONFIG_HID_SONY is not set
CONFIG_HID_SPEEDLINK=m
# CONFIG_HID_STEAM is not set
CONFIG_HID_STEELSERIES=m
CONFIG_HID_SUNPLUS=m
CONFIG_HID_RMI=m
CONFIG_HID_GREENASIA=m
# CONFIG_GREENASIA_FF is not set
CONFIG_HID_SMARTJOYPLUS=m
# CONFIG_SMARTJOYPLUS_FF is not set
CONFIG_HID_TIVO=m
CONFIG_HID_TOPSEED=m
# CONFIG_HID_TOPRE is not set
CONFIG_HID_THINGM=m
CONFIG_HID_THRUSTMASTER=m
# CONFIG_THRUSTMASTER_FF is not set
# CONFIG_HID_UDRAW_PS3 is not set
# CONFIG_HID_U2FZERO is not set
# CONFIG_HID_WACOM is not set
CONFIG_HID_WIIMOTE=m
CONFIG_HID_XINMO=m
CONFIG_HID_ZEROPLUS=m
# CONFIG_ZEROPLUS_FF is not set
CONFIG_HID_ZYDACRON=m
CONFIG_HID_SENSOR_HUB=y
CONFIG_HID_SENSOR_CUSTOM_SENSOR=m
CONFIG_HID_ALPS=m
# CONFIG_HID_MCP2221 is not set
# end of Special HID drivers

#
# USB HID support
#
CONFIG_USB_HID=y
# CONFIG_HID_PID is not set
# CONFIG_USB_HIDDEV is not set
# end of USB HID support

#
# I2C HID support
#
# CONFIG_I2C_HID_ACPI is not set
# end of I2C HID support

#
# Intel ISH HID support
#
CONFIG_INTEL_ISH_HID=m
# CONFIG_INTEL_ISH_FIRMWARE_DOWNLOADER is not set
# end of Intel ISH HID support

#
# AMD SFH HID Support
#
# CONFIG_AMD_SFH_HID is not set
# end of AMD SFH HID Support
# end of HID support

CONFIG_USB_OHCI_LITTLE_ENDIAN=y
CONFIG_USB_SUPPORT=y
CONFIG_USB_COMMON=y
# CONFIG_USB_LED_TRIG is not set
# CONFIG_USB_ULPI_BUS is not set
# CONFIG_USB_CONN_GPIO is not set
CONFIG_USB_ARCH_HAS_HCD=y
CONFIG_USB=y
CONFIG_USB_PCI=y
CONFIG_USB_ANNOUNCE_NEW_DEVICES=y

#
# Miscellaneous USB options
#
CONFIG_USB_DEFAULT_PERSIST=y
# CONFIG_USB_FEW_INIT_RETRIES is not set
# CONFIG_USB_DYNAMIC_MINORS is not set
# CONFIG_USB_OTG is not set
# CONFIG_USB_OTG_PRODUCTLIST is not set
CONFIG_USB_LEDS_TRIGGER_USBPORT=y
CONFIG_USB_AUTOSUSPEND_DELAY=2
CONFIG_USB_MON=y

#
# USB Host Controller Drivers
#
# CONFIG_USB_C67X00_HCD is not set
CONFIG_USB_XHCI_HCD=y
# CONFIG_USB_XHCI_DBGCAP is not set
CONFIG_USB_XHCI_PCI=y
# CONFIG_USB_XHCI_PCI_RENESAS is not set
# CONFIG_USB_XHCI_PLATFORM is not set
CONFIG_USB_EHCI_HCD=y
CONFIG_USB_EHCI_ROOT_HUB_TT=y
CONFIG_USB_EHCI_TT_NEWSCHED=y
CONFIG_USB_EHCI_PCI=y
# CONFIG_USB_EHCI_FSL is not set
# CONFIG_USB_EHCI_HCD_PLATFORM is not set
# CONFIG_USB_OXU210HP_HCD is not set
# CONFIG_USB_ISP116X_HCD is not set
# CONFIG_USB_FOTG210_HCD is not set
# CONFIG_USB_MAX3421_HCD is not set
CONFIG_USB_OHCI_HCD=y
CONFIG_USB_OHCI_HCD_PCI=y
# CONFIG_USB_OHCI_HCD_PLATFORM is not set
CONFIG_USB_UHCI_HCD=y
# CONFIG_USB_SL811_HCD is not set
# CONFIG_USB_R8A66597_HCD is not set
# CONFIG_USB_HCD_BCMA is not set
# CONFIG_USB_HCD_TEST_MODE is not set

#
# USB Device Class drivers
#
# CONFIG_USB_ACM is not set
# CONFIG_USB_PRINTER is not set
# CONFIG_USB_WDM is not set
# CONFIG_USB_TMC is not set

#
# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may
#

#
# also be needed; see USB_STORAGE Help for more info
#
CONFIG_USB_STORAGE=m
# CONFIG_USB_STORAGE_DEBUG is not set
# CONFIG_USB_STORAGE_REALTEK is not set
# CONFIG_USB_STORAGE_DATAFAB is not set
# CONFIG_USB_STORAGE_FREECOM is not set
# CONFIG_USB_STORAGE_ISD200 is not set
# CONFIG_USB_STORAGE_USBAT is not set
# CONFIG_USB_STORAGE_SDDR09 is not set
# CONFIG_USB_STORAGE_SDDR55 is not set
# CONFIG_USB_STORAGE_JUMPSHOT is not set
# CONFIG_USB_STORAGE_ALAUDA is not set
# CONFIG_USB_STORAGE_ONETOUCH is not set
# CONFIG_USB_STORAGE_KARMA is not set
# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set
# CONFIG_USB_STORAGE_ENE_UB6250 is not set
# CONFIG_USB_UAS is not set

#
# USB Imaging devices
#
# CONFIG_USB_MDC800 is not set
# CONFIG_USB_MICROTEK is not set
# CONFIG_USBIP_CORE is not set
# CONFIG_USB_CDNS_SUPPORT is not set
# CONFIG_USB_MUSB_HDRC is not set
# CONFIG_USB_DWC3 is not set
# CONFIG_USB_DWC2 is not set
# CONFIG_USB_CHIPIDEA is not set
# CONFIG_USB_ISP1760 is not set

#
# USB port drivers
#
# CONFIG_USB_USS720 is not set
CONFIG_USB_SERIAL=m
CONFIG_USB_SERIAL_GENERIC=y
# CONFIG_USB_SERIAL_SIMPLE is not set
# CONFIG_USB_SERIAL_AIRCABLE is not set
# CONFIG_USB_SERIAL_ARK3116 is not set
# CONFIG_USB_SERIAL_BELKIN is not set
# CONFIG_USB_SERIAL_CH341 is not set
# CONFIG_USB_SERIAL_WHITEHEAT is not set
# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
# CONFIG_USB_SERIAL_CP210X is not set
# CONFIG_USB_SERIAL_CYPRESS_M8 is not set
# CONFIG_USB_SERIAL_EMPEG is not set
# CONFIG_USB_SERIAL_FTDI_SIO is not set
# CONFIG_USB_SERIAL_VISOR is not set
# CONFIG_USB_SERIAL_IPAQ is not set
# CONFIG_USB_SERIAL_IR is not set
# CONFIG_USB_SERIAL_EDGEPORT is not set
# CONFIG_USB_SERIAL_EDGEPORT_TI is not set
# CONFIG_USB_SERIAL_F81232 is not set
# CONFIG_USB_SERIAL_F8153X is not set
# CONFIG_USB_SERIAL_GARMIN is not set
# CONFIG_USB_SERIAL_IPW is not set
# CONFIG_USB_SERIAL_IUU is not set
# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
# CONFIG_USB_SERIAL_KEYSPAN is not set
# CONFIG_USB_SERIAL_KLSI is not set
# CONFIG_USB_SERIAL_KOBIL_SCT is not set
# CONFIG_USB_SERIAL_MCT_U232 is not set
# CONFIG_USB_SERIAL_METRO is not set
# CONFIG_USB_SERIAL_MOS7720 is not set
# CONFIG_USB_SERIAL_MOS7840 is not set
# CONFIG_USB_SERIAL_MXUPORT is not set
# CONFIG_USB_SERIAL_NAVMAN is not set
# CONFIG_USB_SERIAL_PL2303 is not set
# CONFIG_USB_SERIAL_OTI6858 is not set
# CONFIG_USB_SERIAL_QCAUX is not set
# CONFIG_USB_SERIAL_QUALCOMM is not set
# CONFIG_USB_SERIAL_SPCP8X5 is not set
# CONFIG_USB_SERIAL_SAFE is not set
# CONFIG_USB_SERIAL_SIERRAWIRELESS is not set
# CONFIG_USB_SERIAL_SYMBOL is not set
# CONFIG_USB_SERIAL_TI is not set
# CONFIG_USB_SERIAL_CYBERJACK is not set
# CONFIG_USB_SERIAL_OPTION is not set
# CONFIG_USB_SERIAL_OMNINET is not set
# CONFIG_USB_SERIAL_OPTICON is not set
# CONFIG_USB_SERIAL_XSENS_MT is not set
# CONFIG_USB_SERIAL_WISHBONE is not set
# CONFIG_USB_SERIAL_SSU100 is not set
# CONFIG_USB_SERIAL_QT2 is not set
# CONFIG_USB_SERIAL_UPD78F0730 is not set
# CONFIG_USB_SERIAL_XR is not set
CONFIG_USB_SERIAL_DEBUG=m

#
# USB Miscellaneous drivers
#
# CONFIG_USB_EMI62 is not set
# CONFIG_USB_EMI26 is not set
# CONFIG_USB_ADUTUX is not set
# CONFIG_USB_SEVSEG is not set
# CONFIG_USB_LEGOTOWER is not set
# CONFIG_USB_LCD is not set
# CONFIG_USB_CYPRESS_CY7C63 is not set
# CONFIG_USB_CYTHERM is not set
# CONFIG_USB_IDMOUSE is not set
# CONFIG_USB_FTDI_ELAN is not set
# CONFIG_USB_APPLEDISPLAY is not set
# CONFIG_APPLE_MFI_FASTCHARGE is not set
# CONFIG_USB_SISUSBVGA is not set
# CONFIG_USB_LD is not set
# CONFIG_USB_TRANCEVIBRATOR is not set
# CONFIG_USB_IOWARRIOR is not set
# CONFIG_USB_TEST is not set
# CONFIG_USB_EHSET_TEST_FIXTURE is not set
# CONFIG_USB_ISIGHTFW is not set
# CONFIG_USB_YUREX is not set
# CONFIG_USB_EZUSB_FX2 is not set
# CONFIG_USB_HUB_USB251XB is not set
# CONFIG_USB_HSIC_USB3503 is not set
# CONFIG_USB_HSIC_USB4604 is not set
# CONFIG_USB_LINK_LAYER_TEST is not set
# CONFIG_USB_CHAOSKEY is not set
# CONFIG_USB_ATM is not set

#
# USB Physical Layer drivers
#
# CONFIG_NOP_USB_XCEIV is not set
# CONFIG_USB_GPIO_VBUS is not set
# CONFIG_USB_ISP1301 is not set
# end of USB Physical Layer drivers

# CONFIG_USB_GADGET is not set
CONFIG_TYPEC=y
# CONFIG_TYPEC_TCPM is not set
CONFIG_TYPEC_UCSI=y
# CONFIG_UCSI_CCG is not set
CONFIG_UCSI_ACPI=y
# CONFIG_UCSI_STM32G0 is not set
# CONFIG_TYPEC_TPS6598X is not set
# CONFIG_TYPEC_RT1719 is not set
# CONFIG_TYPEC_STUSB160X is not set
# CONFIG_TYPEC_WUSB3801 is not set

#
# USB Type-C Multiplexer/DeMultiplexer Switch support
#
# CONFIG_TYPEC_MUX_FSA4480 is not set
# CONFIG_TYPEC_MUX_PI3USB30532 is not set
# end of USB Type-C Multiplexer/DeMultiplexer Switch support

#
# USB Type-C Alternate Mode drivers
#
# CONFIG_TYPEC_DP_ALTMODE is not set
# end of USB Type-C Alternate Mode drivers

# CONFIG_USB_ROLE_SWITCH is not set
CONFIG_MMC=m
CONFIG_MMC_BLOCK=m
CONFIG_MMC_BLOCK_MINORS=8
CONFIG_SDIO_UART=m
# CONFIG_MMC_TEST is not set

#
# MMC/SD/SDIO Host Controller Drivers
#
# CONFIG_MMC_DEBUG is not set
CONFIG_MMC_SDHCI=m
CONFIG_MMC_SDHCI_IO_ACCESSORS=y
CONFIG_MMC_SDHCI_PCI=m
CONFIG_MMC_RICOH_MMC=y
CONFIG_MMC_SDHCI_ACPI=m
CONFIG_MMC_SDHCI_PLTFM=m
# CONFIG_MMC_SDHCI_F_SDH30 is not set
# CONFIG_MMC_WBSD is not set
# CONFIG_MMC_TIFM_SD is not set
# CONFIG_MMC_SPI is not set
# CONFIG_MMC_CB710 is not set
# CONFIG_MMC_VIA_SDMMC is not set
# CONFIG_MMC_VUB300 is not set
# CONFIG_MMC_USHC is not set
# CONFIG_MMC_USDHI6ROL0 is not set
# CONFIG_MMC_REALTEK_PCI is not set
CONFIG_MMC_CQHCI=m
# CONFIG_MMC_HSQ is not set
# CONFIG_MMC_TOSHIBA_PCI is not set
# CONFIG_MMC_MTK is not set
# CONFIG_MMC_SDHCI_XENON is not set
# CONFIG_SCSI_UFSHCD is not set
# CONFIG_MEMSTICK is not set
CONFIG_NEW_LEDS=y
CONFIG_LEDS_CLASS=y
# CONFIG_LEDS_CLASS_FLASH is not set
# CONFIG_LEDS_CLASS_MULTICOLOR is not set
# CONFIG_LEDS_BRIGHTNESS_HW_CHANGED is not set

#
# LED drivers
#
# CONFIG_LEDS_APU is not set
CONFIG_LEDS_LM3530=m
# CONFIG_LEDS_LM3532 is not set
# CONFIG_LEDS_LM3642 is not set
# CONFIG_LEDS_PCA9532 is not set
# CONFIG_LEDS_GPIO is not set
CONFIG_LEDS_LP3944=m
# CONFIG_LEDS_LP3952 is not set
# CONFIG_LEDS_LP50XX is not set
# CONFIG_LEDS_PCA955X is not set
# CONFIG_LEDS_PCA963X is not set
# CONFIG_LEDS_DAC124S085 is not set
# CONFIG_LEDS_PWM is not set
# CONFIG_LEDS_BD2802 is not set
CONFIG_LEDS_INTEL_SS4200=m
CONFIG_LEDS_LT3593=m
# CONFIG_LEDS_TCA6507 is not set
# CONFIG_LEDS_TLC591XX is not set
# CONFIG_LEDS_LM355x is not set
# CONFIG_LEDS_IS31FL319X is not set

#
# LED driver for blink(1) USB RGB LED is under Special HID drivers (HID_THINGM)
#
CONFIG_LEDS_BLINKM=m
CONFIG_LEDS_MLXCPLD=m
# CONFIG_LEDS_MLXREG is not set
# CONFIG_LEDS_USER is not set
# CONFIG_LEDS_NIC78BX is not set
# CONFIG_LEDS_TI_LMU_COMMON is not set

#
# Flash and Torch LED drivers
#

#
# RGB LED drivers
#

#
# LED Triggers
#
CONFIG_LEDS_TRIGGERS=y
CONFIG_LEDS_TRIGGER_TIMER=m
CONFIG_LEDS_TRIGGER_ONESHOT=m
# CONFIG_LEDS_TRIGGER_DISK is not set
CONFIG_LEDS_TRIGGER_HEARTBEAT=m
CONFIG_LEDS_TRIGGER_BACKLIGHT=m
# CONFIG_LEDS_TRIGGER_CPU is not set
# CONFIG_LEDS_TRIGGER_ACTIVITY is not set
CONFIG_LEDS_TRIGGER_GPIO=m
CONFIG_LEDS_TRIGGER_DEFAULT_ON=m

#
# iptables trigger is under Netfilter config (LED target)
#
CONFIG_LEDS_TRIGGER_TRANSIENT=m
CONFIG_LEDS_TRIGGER_CAMERA=m
# CONFIG_LEDS_TRIGGER_PANIC is not set
# CONFIG_LEDS_TRIGGER_NETDEV is not set
# CONFIG_LEDS_TRIGGER_PATTERN is not set
CONFIG_LEDS_TRIGGER_AUDIO=m
# CONFIG_LEDS_TRIGGER_TTY is not set

#
# Simple LED drivers
#
# CONFIG_ACCESSIBILITY is not set
# CONFIG_INFINIBAND is not set
CONFIG_EDAC_ATOMIC_SCRUB=y
CONFIG_EDAC_SUPPORT=y
CONFIG_EDAC=y
CONFIG_EDAC_LEGACY_SYSFS=y
# CONFIG_EDAC_DEBUG is not set
CONFIG_EDAC_GHES=y
CONFIG_EDAC_E752X=m
CONFIG_EDAC_I82975X=m
CONFIG_EDAC_I3000=m
CONFIG_EDAC_I3200=m
CONFIG_EDAC_IE31200=m
CONFIG_EDAC_X38=m
CONFIG_EDAC_I5400=m
CONFIG_EDAC_I7CORE=m
# CONFIG_EDAC_I5000 is not set
CONFIG_EDAC_I5100=m
CONFIG_EDAC_I7300=m
CONFIG_EDAC_SBRIDGE=m
CONFIG_EDAC_SKX=m
# CONFIG_EDAC_I10NM is not set
CONFIG_EDAC_PND2=m
# CONFIG_EDAC_IGEN6 is not set
CONFIG_RTC_LIB=y
CONFIG_RTC_MC146818_LIB=y
CONFIG_RTC_CLASS=y
CONFIG_RTC_HCTOSYS=y
CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
# CONFIG_RTC_SYSTOHC is not set
# CONFIG_RTC_DEBUG is not set
CONFIG_RTC_NVMEM=y

#
# RTC interfaces
#
CONFIG_RTC_INTF_SYSFS=y
CONFIG_RTC_INTF_PROC=y
CONFIG_RTC_INTF_DEV=y
# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
# CONFIG_RTC_DRV_TEST is not set

#
# I2C RTC drivers
#
# CONFIG_RTC_DRV_ABB5ZES3 is not set
# CONFIG_RTC_DRV_ABEOZ9 is not set
# CONFIG_RTC_DRV_ABX80X is not set
CONFIG_RTC_DRV_DS1307=m
# CONFIG_RTC_DRV_DS1307_CENTURY is not set
CONFIG_RTC_DRV_DS1374=m
# CONFIG_RTC_DRV_DS1374_WDT is not set
CONFIG_RTC_DRV_DS1672=m
CONFIG_RTC_DRV_MAX6900=m
CONFIG_RTC_DRV_RS5C372=m
CONFIG_RTC_DRV_ISL1208=m
CONFIG_RTC_DRV_ISL12022=m
CONFIG_RTC_DRV_X1205=m
CONFIG_RTC_DRV_PCF8523=m
# CONFIG_RTC_DRV_PCF85063 is not set
# CONFIG_RTC_DRV_PCF85363 is not set
CONFIG_RTC_DRV_PCF8563=m
CONFIG_RTC_DRV_PCF8583=m
CONFIG_RTC_DRV_M41T80=m
CONFIG_RTC_DRV_M41T80_WDT=y
CONFIG_RTC_DRV_BQ32K=m
# CONFIG_RTC_DRV_S35390A is not set
CONFIG_RTC_DRV_FM3130=m
# CONFIG_RTC_DRV_RX8010 is not set
CONFIG_RTC_DRV_RX8581=m
CONFIG_RTC_DRV_RX8025=m
CONFIG_RTC_DRV_EM3027=m
# CONFIG_RTC_DRV_RV3028 is not set
# CONFIG_RTC_DRV_RV3032 is not set
# CONFIG_RTC_DRV_RV8803 is not set
# CONFIG_RTC_DRV_SD3078 is not set

#
# SPI RTC drivers
#
# CONFIG_RTC_DRV_M41T93 is not set
# CONFIG_RTC_DRV_M41T94 is not set
# CONFIG_RTC_DRV_DS1302 is not set
# CONFIG_RTC_DRV_DS1305 is not set
# CONFIG_RTC_DRV_DS1343 is not set
# CONFIG_RTC_DRV_DS1347 is not set
# CONFIG_RTC_DRV_DS1390 is not set
# CONFIG_RTC_DRV_MAX6916 is not set
# CONFIG_RTC_DRV_R9701 is not set
CONFIG_RTC_DRV_RX4581=m
# CONFIG_RTC_DRV_RS5C348 is not set
# CONFIG_RTC_DRV_MAX6902 is not set
# CONFIG_RTC_DRV_PCF2123 is not set
# CONFIG_RTC_DRV_MCP795 is not set
CONFIG_RTC_I2C_AND_SPI=y

#
# SPI and I2C RTC drivers
#
CONFIG_RTC_DRV_DS3232=m
CONFIG_RTC_DRV_DS3232_HWMON=y
# CONFIG_RTC_DRV_PCF2127 is not set
CONFIG_RTC_DRV_RV3029C2=m
# CONFIG_RTC_DRV_RV3029_HWMON is not set
# CONFIG_RTC_DRV_RX6110 is not set

#
# Platform RTC drivers
#
CONFIG_RTC_DRV_CMOS=y
CONFIG_RTC_DRV_DS1286=m
CONFIG_RTC_DRV_DS1511=m
CONFIG_RTC_DRV_DS1553=m
# CONFIG_RTC_DRV_DS1685_FAMILY is not set
CONFIG_RTC_DRV_DS1742=m
CONFIG_RTC_DRV_DS2404=m
CONFIG_RTC_DRV_STK17TA8=m
# CONFIG_RTC_DRV_M48T86 is not set
CONFIG_RTC_DRV_M48T35=m
CONFIG_RTC_DRV_M48T59=m
CONFIG_RTC_DRV_MSM6242=m
CONFIG_RTC_DRV_BQ4802=m
CONFIG_RTC_DRV_RP5C01=m
CONFIG_RTC_DRV_V3020=m

#
# on-CPU RTC drivers
#
# CONFIG_RTC_DRV_FTRTC010 is not set

#
# HID Sensor RTC drivers
#
# CONFIG_RTC_DRV_GOLDFISH is not set
CONFIG_DMADEVICES=y
# CONFIG_DMADEVICES_DEBUG is not set

#
# DMA Devices
#
CONFIG_DMA_ENGINE=y
CONFIG_DMA_VIRTUAL_CHANNELS=y
CONFIG_DMA_ACPI=y
# CONFIG_ALTERA_MSGDMA is not set
CONFIG_INTEL_IDMA64=m
# CONFIG_INTEL_IDXD is not set
# CONFIG_INTEL_IDXD_COMPAT is not set
CONFIG_INTEL_IOATDMA=m
# CONFIG_PLX_DMA is not set
# CONFIG_AMD_PTDMA is not set
# CONFIG_QCOM_HIDMA_MGMT is not set
# CONFIG_QCOM_HIDMA is not set
CONFIG_DW_DMAC_CORE=y
CONFIG_DW_DMAC=m
CONFIG_DW_DMAC_PCI=y
# CONFIG_DW_EDMA is not set
# CONFIG_DW_EDMA_PCIE is not set
CONFIG_HSU_DMA=y
# CONFIG_SF_PDMA is not set
# CONFIG_INTEL_LDMA is not set

#
# DMA Clients
#
CONFIG_ASYNC_TX_DMA=y
CONFIG_DMATEST=m
CONFIG_DMA_ENGINE_RAID=y

#
# DMABUF options
#
CONFIG_SYNC_FILE=y
# CONFIG_SW_SYNC is not set
# CONFIG_UDMABUF is not set
# CONFIG_DMABUF_MOVE_NOTIFY is not set
# CONFIG_DMABUF_DEBUG is not set
# CONFIG_DMABUF_SELFTESTS is not set
# CONFIG_DMABUF_HEAPS is not set
# CONFIG_DMABUF_SYSFS_STATS is not set
# end of DMABUF options

CONFIG_DCA=m
# CONFIG_AUXDISPLAY is not set
# CONFIG_PANEL is not set
CONFIG_UIO=m
CONFIG_UIO_CIF=m
CONFIG_UIO_PDRV_GENIRQ=m
# CONFIG_UIO_DMEM_GENIRQ is not set
CONFIG_UIO_AEC=m
CONFIG_UIO_SERCOS3=m
CONFIG_UIO_PCI_GENERIC=m
# CONFIG_UIO_NETX is not set
# CONFIG_UIO_PRUSS is not set
# CONFIG_UIO_MF624 is not set
CONFIG_VFIO=m
CONFIG_VFIO_IOMMU_TYPE1=m
CONFIG_VFIO_VIRQFD=m
CONFIG_VFIO_NOIOMMU=y
CONFIG_VFIO_PCI_CORE=m
CONFIG_VFIO_PCI_MMAP=y
CONFIG_VFIO_PCI_INTX=y
CONFIG_VFIO_PCI=m
# CONFIG_VFIO_PCI_VGA is not set
# CONFIG_VFIO_PCI_IGD is not set
CONFIG_VFIO_MDEV=m
CONFIG_IRQ_BYPASS_MANAGER=m
# CONFIG_VIRT_DRIVERS is not set
CONFIG_VIRTIO_ANCHOR=y
CONFIG_VIRTIO=y
CONFIG_VIRTIO_PCI_LIB=y
CONFIG_VIRTIO_PCI_LIB_LEGACY=y
CONFIG_VIRTIO_MENU=y
CONFIG_VIRTIO_PCI=y
CONFIG_VIRTIO_PCI_LEGACY=y
# CONFIG_VIRTIO_PMEM is not set
CONFIG_VIRTIO_BALLOON=m
# CONFIG_VIRTIO_MEM is not set
CONFIG_VIRTIO_INPUT=m
# CONFIG_VIRTIO_MMIO is not set
CONFIG_VIRTIO_DMA_SHARED_BUFFER=m
# CONFIG_VDPA is not set
CONFIG_VHOST_IOTLB=m
CONFIG_VHOST=m
CONFIG_VHOST_MENU=y
CONFIG_VHOST_NET=m
# CONFIG_VHOST_SCSI is not set
CONFIG_VHOST_VSOCK=m
# CONFIG_VHOST_CROSS_ENDIAN_LEGACY is not set

#
# Microsoft Hyper-V guest support
#
# CONFIG_HYPERV is not set
# end of Microsoft Hyper-V guest support

# CONFIG_GREYBUS is not set
# CONFIG_COMEDI is not set
# CONFIG_STAGING is not set
# CONFIG_CHROME_PLATFORMS is not set
CONFIG_MELLANOX_PLATFORM=y
CONFIG_MLXREG_HOTPLUG=m
# CONFIG_MLXREG_IO is not set
# CONFIG_MLXREG_LC is not set
# CONFIG_NVSW_SN2201 is not set
CONFIG_SURFACE_PLATFORMS=y
# CONFIG_SURFACE3_WMI is not set
# CONFIG_SURFACE_3_POWER_OPREGION is not set
# CONFIG_SURFACE_GPE is not set
# CONFIG_SURFACE_HOTPLUG is not set
# CONFIG_SURFACE_PRO3_BUTTON is not set
CONFIG_X86_PLATFORM_DEVICES=y
CONFIG_ACPI_WMI=m
CONFIG_WMI_BMOF=m
# CONFIG_HUAWEI_WMI is not set
# CONFIG_UV_SYSFS is not set
CONFIG_MXM_WMI=m
# CONFIG_PEAQ_WMI is not set
# CONFIG_NVIDIA_WMI_EC_BACKLIGHT is not set
# CONFIG_XIAOMI_WMI is not set
# CONFIG_GIGABYTE_WMI is not set
# CONFIG_YOGABOOK_WMI is not set
CONFIG_ACERHDF=m
# CONFIG_ACER_WIRELESS is not set
CONFIG_ACER_WMI=m
# CONFIG_AMD_PMF is not set
# CONFIG_AMD_PMC is not set
# CONFIG_AMD_HSMP is not set
# CONFIG_ADV_SWBUTTON is not set
CONFIG_APPLE_GMUX=m
CONFIG_ASUS_LAPTOP=m
# CONFIG_ASUS_WIRELESS is not set
CONFIG_ASUS_WMI=m
CONFIG_ASUS_NB_WMI=m
# CONFIG_ASUS_TF103C_DOCK is not set
# CONFIG_MERAKI_MX100 is not set
CONFIG_EEEPC_LAPTOP=m
CONFIG_EEEPC_WMI=m
# CONFIG_X86_PLATFORM_DRIVERS_DELL is not set
CONFIG_AMILO_RFKILL=m
CONFIG_FUJITSU_LAPTOP=m
CONFIG_FUJITSU_TABLET=m
# CONFIG_GPD_POCKET_FAN is not set
# CONFIG_HP_ACCEL is not set
# CONFIG_WIRELESS_HOTKEY is not set
# CONFIG_HP_WMI is not set
# CONFIG_IBM_RTL is not set
CONFIG_IDEAPAD_LAPTOP=m
CONFIG_SENSORS_HDAPS=m
CONFIG_THINKPAD_ACPI=m
# CONFIG_THINKPAD_ACPI_DEBUGFACILITIES is not set
# CONFIG_THINKPAD_ACPI_DEBUG is not set
# CONFIG_THINKPAD_ACPI_UNSAFE_LEDS is not set
CONFIG_THINKPAD_ACPI_VIDEO=y
CONFIG_THINKPAD_ACPI_HOTKEY_POLL=y
# CONFIG_THINKPAD_LMI is not set
# CONFIG_INTEL_ATOMISP2_PM is not set
# CONFIG_INTEL_SAR_INT1092 is not set
CONFIG_INTEL_PMC_CORE=m

#
# Intel Speed Select Technology interface support
#
# CONFIG_INTEL_SPEED_SELECT_INTERFACE is not set
# end of Intel Speed Select Technology interface support

CONFIG_INTEL_WMI=y
# CONFIG_INTEL_WMI_SBL_FW_UPDATE is not set
CONFIG_INTEL_WMI_THUNDERBOLT=m

#
# Intel Uncore Frequency Control
#
# CONFIG_INTEL_UNCORE_FREQ_CONTROL is not set
# end of Intel Uncore Frequency Control

CONFIG_INTEL_HID_EVENT=m
CONFIG_INTEL_VBTN=m
# CONFIG_INTEL_INT0002_VGPIO is not set
CONFIG_INTEL_OAKTRAIL=m
# CONFIG_INTEL_ISHTP_ECLITE is not set
# CONFIG_INTEL_PUNIT_IPC is not set
CONFIG_INTEL_RST=m
# CONFIG_INTEL_SMARTCONNECT is not set
CONFIG_INTEL_TURBO_MAX_3=y
# CONFIG_INTEL_VSEC is not set
CONFIG_MSI_LAPTOP=m
CONFIG_MSI_WMI=m
# CONFIG_PCENGINES_APU2 is not set
# CONFIG_BARCO_P50_GPIO is not set
CONFIG_SAMSUNG_LAPTOP=m
CONFIG_SAMSUNG_Q10=m
CONFIG_TOSHIBA_BT_RFKILL=m
# CONFIG_TOSHIBA_HAPS is not set
# CONFIG_TOSHIBA_WMI is not set
CONFIG_ACPI_CMPC=m
CONFIG_COMPAL_LAPTOP=m
# CONFIG_LG_LAPTOP is not set
CONFIG_PANASONIC_LAPTOP=m
CONFIG_SONY_LAPTOP=m
CONFIG_SONYPI_COMPAT=y
# CONFIG_SYSTEM76_ACPI is not set
CONFIG_TOPSTAR_LAPTOP=m
# CONFIG_SERIAL_MULTI_INSTANTIATE is not set
CONFIG_MLX_PLATFORM=m
CONFIG_INTEL_IPS=m
# CONFIG_INTEL_SCU_PCI is not set
# CONFIG_INTEL_SCU_PLATFORM is not set
# CONFIG_SIEMENS_SIMATIC_IPC is not set
# CONFIG_WINMATE_FM07_KEYS is not set
CONFIG_P2SB=y
CONFIG_HAVE_CLK=y
CONFIG_HAVE_CLK_PREPARE=y
CONFIG_COMMON_CLK=y
# CONFIG_LMK04832 is not set
# CONFIG_COMMON_CLK_MAX9485 is not set
# CONFIG_COMMON_CLK_SI5341 is not set
# CONFIG_COMMON_CLK_SI5351 is not set
# CONFIG_COMMON_CLK_SI544 is not set
# CONFIG_COMMON_CLK_CDCE706 is not set
# CONFIG_COMMON_CLK_CS2000_CP is not set
# CONFIG_COMMON_CLK_PWM is not set
# CONFIG_XILINX_VCU is not set
CONFIG_HWSPINLOCK=y

#
# Clock Source drivers
#
CONFIG_CLKEVT_I8253=y
CONFIG_I8253_LOCK=y
CONFIG_CLKBLD_I8253=y
# end of Clock Source drivers

CONFIG_MAILBOX=y
CONFIG_PCC=y
# CONFIG_ALTERA_MBOX is not set
CONFIG_IOMMU_IOVA=y
CONFIG_IOASID=y
CONFIG_IOMMU_API=y
CONFIG_IOMMU_SUPPORT=y

#
# Generic IOMMU Pagetable Support
#
# end of Generic IOMMU Pagetable Support

# CONFIG_IOMMU_DEBUGFS is not set
# CONFIG_IOMMU_DEFAULT_DMA_STRICT is not set
CONFIG_IOMMU_DEFAULT_DMA_LAZY=y
# CONFIG_IOMMU_DEFAULT_PASSTHROUGH is not set
CONFIG_IOMMU_DMA=y
CONFIG_IOMMU_SVA=y
# CONFIG_AMD_IOMMU is not set
CONFIG_DMAR_TABLE=y
CONFIG_INTEL_IOMMU=y
CONFIG_INTEL_IOMMU_SVM=y
# CONFIG_INTEL_IOMMU_DEFAULT_ON is not set
CONFIG_INTEL_IOMMU_FLOPPY_WA=y
CONFIG_INTEL_IOMMU_SCALABLE_MODE_DEFAULT_ON=y
CONFIG_IRQ_REMAP=y
# CONFIG_VIRTIO_IOMMU is not set

#
# Remoteproc drivers
#
# CONFIG_REMOTEPROC is not set
# end of Remoteproc drivers

#
# Rpmsg drivers
#
# CONFIG_RPMSG_QCOM_GLINK_RPM is not set
# CONFIG_RPMSG_VIRTIO is not set
# end of Rpmsg drivers

# CONFIG_SOUNDWIRE is not set

#
# SOC (System On Chip) specific Drivers
#

#
# Amlogic SoC drivers
#
# end of Amlogic SoC drivers

#
# Broadcom SoC drivers
#
# end of Broadcom SoC drivers

#
# NXP/Freescale QorIQ SoC drivers
#
# end of NXP/Freescale QorIQ SoC drivers

#
# fujitsu SoC drivers
#
# end of fujitsu SoC drivers

#
# i.MX SoC drivers
#
# end of i.MX SoC drivers

#
# Enable LiteX SoC Builder specific drivers
#
# end of Enable LiteX SoC Builder specific drivers

#
# Qualcomm SoC drivers
#
# end of Qualcomm SoC drivers

# CONFIG_SOC_TI is not set

#
# Xilinx SoC drivers
#
# end of Xilinx SoC drivers
# end of SOC (System On Chip) specific Drivers

# CONFIG_PM_DEVFREQ is not set
# CONFIG_EXTCON is not set
# CONFIG_MEMORY is not set
# CONFIG_IIO is not set
CONFIG_NTB=m
# CONFIG_NTB_MSI is not set
# CONFIG_NTB_AMD is not set
# CONFIG_NTB_IDT is not set
# CONFIG_NTB_INTEL is not set
# CONFIG_NTB_EPF is not set
# CONFIG_NTB_SWITCHTEC is not set
# CONFIG_NTB_PINGPONG is not set
# CONFIG_NTB_TOOL is not set
# CONFIG_NTB_PERF is not set
# CONFIG_NTB_TRANSPORT is not set
CONFIG_PWM=y
CONFIG_PWM_SYSFS=y
# CONFIG_PWM_DEBUG is not set
# CONFIG_PWM_CLK is not set
# CONFIG_PWM_DWC is not set
CONFIG_PWM_LPSS=m
CONFIG_PWM_LPSS_PCI=m
CONFIG_PWM_LPSS_PLATFORM=m
# CONFIG_PWM_PCA9685 is not set

#
# IRQ chip support
#
# end of IRQ chip support

# CONFIG_IPACK_BUS is not set
# CONFIG_RESET_CONTROLLER is not set

#
# PHY Subsystem
#
# CONFIG_GENERIC_PHY is not set
# CONFIG_USB_LGM_PHY is not set
# CONFIG_PHY_CAN_TRANSCEIVER is not set

#
# PHY drivers for Broadcom platforms
#
# CONFIG_BCM_KONA_USB2_PHY is not set
# end of PHY drivers for Broadcom platforms

# CONFIG_PHY_PXA_28NM_HSIC is not set
# CONFIG_PHY_PXA_28NM_USB2 is not set
# CONFIG_PHY_INTEL_LGM_EMMC is not set
# end of PHY Subsystem

CONFIG_POWERCAP=y
CONFIG_INTEL_RAPL_CORE=m
CONFIG_INTEL_RAPL=m
# CONFIG_IDLE_INJECT is not set
# CONFIG_MCB is not set

#
# Performance monitor support
#
# end of Performance monitor support

CONFIG_RAS=y
# CONFIG_RAS_CEC is not set
# CONFIG_USB4 is not set

#
# Android
#
# CONFIG_ANDROID_BINDER_IPC is not set
# end of Android

CONFIG_LIBNVDIMM=m
CONFIG_BLK_DEV_PMEM=m
CONFIG_ND_CLAIM=y
CONFIG_ND_BTT=m
CONFIG_BTT=y
CONFIG_ND_PFN=m
CONFIG_NVDIMM_PFN=y
CONFIG_NVDIMM_DAX=y
CONFIG_NVDIMM_KEYS=y
CONFIG_DAX=y
CONFIG_DEV_DAX=m
CONFIG_DEV_DAX_PMEM=m
CONFIG_DEV_DAX_KMEM=m
CONFIG_NVMEM=y
CONFIG_NVMEM_SYSFS=y
# CONFIG_NVMEM_RMEM is not set

#
# HW tracing support
#
CONFIG_STM=m
# CONFIG_STM_PROTO_BASIC is not set
# CONFIG_STM_PROTO_SYS_T is not set
CONFIG_STM_DUMMY=m
CONFIG_STM_SOURCE_CONSOLE=m
CONFIG_STM_SOURCE_HEARTBEAT=m
CONFIG_STM_SOURCE_FTRACE=m
CONFIG_INTEL_TH=m
CONFIG_INTEL_TH_PCI=m
CONFIG_INTEL_TH_ACPI=m
CONFIG_INTEL_TH_GTH=m
CONFIG_INTEL_TH_STH=m
CONFIG_INTEL_TH_MSU=m
CONFIG_INTEL_TH_PTI=m
# CONFIG_INTEL_TH_DEBUG is not set
# end of HW tracing support

# CONFIG_FPGA is not set
# CONFIG_TEE is not set
# CONFIG_SIOX is not set
# CONFIG_SLIMBUS is not set
# CONFIG_INTERCONNECT is not set
# CONFIG_COUNTER is not set
# CONFIG_MOST is not set
# CONFIG_PECI is not set
# CONFIG_HTE is not set
# end of Device Drivers

#
# File systems
#
CONFIG_DCACHE_WORD_ACCESS=y
# CONFIG_VALIDATE_FS_PARSER is not set
CONFIG_FS_IOMAP=y
CONFIG_EXT2_FS=m
# CONFIG_EXT2_FS_XATTR is not set
# CONFIG_EXT3_FS is not set
CONFIG_EXT4_FS=y
CONFIG_EXT4_FS_POSIX_ACL=y
CONFIG_EXT4_FS_SECURITY=y
# CONFIG_EXT4_DEBUG is not set
CONFIG_JBD2=y
# CONFIG_JBD2_DEBUG is not set
CONFIG_FS_MBCACHE=y
# CONFIG_REISERFS_FS is not set
# CONFIG_JFS_FS is not set
CONFIG_XFS_FS=m
CONFIG_XFS_SUPPORT_V4=y
CONFIG_XFS_QUOTA=y
CONFIG_XFS_POSIX_ACL=y
CONFIG_XFS_RT=y
CONFIG_XFS_ONLINE_SCRUB=y
# CONFIG_XFS_ONLINE_REPAIR is not set
CONFIG_XFS_DEBUG=y
CONFIG_XFS_ASSERT_FATAL=y
CONFIG_GFS2_FS=m
CONFIG_GFS2_FS_LOCKING_DLM=y
CONFIG_OCFS2_FS=m
CONFIG_OCFS2_FS_O2CB=m
CONFIG_OCFS2_FS_USERSPACE_CLUSTER=m
CONFIG_OCFS2_FS_STATS=y
CONFIG_OCFS2_DEBUG_MASKLOG=y
# CONFIG_OCFS2_DEBUG_FS is not set
CONFIG_BTRFS_FS=m
CONFIG_BTRFS_FS_POSIX_ACL=y
# CONFIG_BTRFS_FS_CHECK_INTEGRITY is not set
# CONFIG_BTRFS_FS_RUN_SANITY_TESTS is not set
# CONFIG_BTRFS_DEBUG is not set
# CONFIG_BTRFS_ASSERT is not set
# CONFIG_BTRFS_FS_REF_VERIFY is not set
# CONFIG_NILFS2_FS is not set
CONFIG_F2FS_FS=m
CONFIG_F2FS_STAT_FS=y
CONFIG_F2FS_FS_XATTR=y
CONFIG_F2FS_FS_POSIX_ACL=y
# CONFIG_F2FS_FS_SECURITY is not set
# CONFIG_F2FS_CHECK_FS is not set
# CONFIG_F2FS_FAULT_INJECTION is not set
# CONFIG_F2FS_FS_COMPRESSION is not set
CONFIG_F2FS_IOSTAT=y
# CONFIG_F2FS_UNFAIR_RWSEM is not set
CONFIG_FS_DAX=y
CONFIG_FS_DAX_PMD=y
CONFIG_FS_POSIX_ACL=y
CONFIG_EXPORTFS=y
CONFIG_EXPORTFS_BLOCK_OPS=y
CONFIG_FILE_LOCKING=y
CONFIG_FS_ENCRYPTION=y
CONFIG_FS_ENCRYPTION_ALGS=y
# CONFIG_FS_VERITY is not set
CONFIG_FSNOTIFY=y
CONFIG_DNOTIFY=y
CONFIG_INOTIFY_USER=y
CONFIG_FANOTIFY=y
CONFIG_FANOTIFY_ACCESS_PERMISSIONS=y
CONFIG_QUOTA=y
CONFIG_QUOTA_NETLINK_INTERFACE=y
CONFIG_PRINT_QUOTA_WARNING=y
# CONFIG_QUOTA_DEBUG is not set
CONFIG_QUOTA_TREE=y
# CONFIG_QFMT_V1 is not set
CONFIG_QFMT_V2=y
CONFIG_QUOTACTL=y
CONFIG_AUTOFS4_FS=y
CONFIG_AUTOFS_FS=y
CONFIG_FUSE_FS=m
CONFIG_CUSE=m
# CONFIG_VIRTIO_FS is not set
CONFIG_OVERLAY_FS=m
# CONFIG_OVERLAY_FS_REDIRECT_DIR is not set
# CONFIG_OVERLAY_FS_REDIRECT_ALWAYS_FOLLOW is not set
# CONFIG_OVERLAY_FS_INDEX is not set
# CONFIG_OVERLAY_FS_XINO_AUTO is not set
# CONFIG_OVERLAY_FS_METACOPY is not set

#
# Caches
#
CONFIG_NETFS_SUPPORT=m
CONFIG_NETFS_STATS=y
CONFIG_FSCACHE=m
CONFIG_FSCACHE_STATS=y
# CONFIG_FSCACHE_DEBUG is not set
CONFIG_CACHEFILES=m
# CONFIG_CACHEFILES_DEBUG is not set
# CONFIG_CACHEFILES_ERROR_INJECTION is not set
# CONFIG_CACHEFILES_ONDEMAND is not set
# end of Caches

#
# CD-ROM/DVD Filesystems
#
CONFIG_ISO9660_FS=m
CONFIG_JOLIET=y
CONFIG_ZISOFS=y
CONFIG_UDF_FS=m
# end of CD-ROM/DVD Filesystems

#
# DOS/FAT/EXFAT/NT Filesystems
#
CONFIG_FAT_FS=m
CONFIG_MSDOS_FS=m
CONFIG_VFAT_FS=m
CONFIG_FAT_DEFAULT_CODEPAGE=437
CONFIG_FAT_DEFAULT_IOCHARSET="ascii"
# CONFIG_FAT_DEFAULT_UTF8 is not set
# CONFIG_EXFAT_FS is not set
# CONFIG_NTFS_FS is not set
# CONFIG_NTFS3_FS is not set
# end of DOS/FAT/EXFAT/NT Filesystems

#
# Pseudo filesystems
#
CONFIG_PROC_FS=y
CONFIG_PROC_KCORE=y
CONFIG_PROC_VMCORE=y
CONFIG_PROC_VMCORE_DEVICE_DUMP=y
CONFIG_PROC_SYSCTL=y
CONFIG_PROC_PAGE_MONITOR=y
CONFIG_PROC_CHILDREN=y
CONFIG_PROC_PID_ARCH_STATUS=y
CONFIG_KERNFS=y
CONFIG_SYSFS=y
CONFIG_TMPFS=y
CONFIG_TMPFS_POSIX_ACL=y
CONFIG_TMPFS_XATTR=y
# CONFIG_TMPFS_INODE64 is not set
CONFIG_HUGETLBFS=y
CONFIG_HUGETLB_PAGE=y
CONFIG_ARCH_WANT_HUGETLB_PAGE_OPTIMIZE_VMEMMAP=y
CONFIG_HUGETLB_PAGE_OPTIMIZE_VMEMMAP=y
# CONFIG_HUGETLB_PAGE_OPTIMIZE_VMEMMAP_DEFAULT_ON is not set
CONFIG_MEMFD_CREATE=y
CONFIG_ARCH_HAS_GIGANTIC_PAGE=y
CONFIG_CONFIGFS_FS=y
CONFIG_EFIVAR_FS=y
# end of Pseudo filesystems

CONFIG_MISC_FILESYSTEMS=y
# CONFIG_ORANGEFS_FS is not set
# CONFIG_ADFS_FS is not set
# CONFIG_AFFS_FS is not set
# CONFIG_ECRYPT_FS is not set
# CONFIG_HFS_FS is not set
# CONFIG_HFSPLUS_FS is not set
# CONFIG_BEFS_FS is not set
# CONFIG_BFS_FS is not set
# CONFIG_EFS_FS is not set
CONFIG_CRAMFS=m
CONFIG_CRAMFS_BLOCKDEV=y
CONFIG_SQUASHFS=m
# CONFIG_SQUASHFS_FILE_CACHE is not set
CONFIG_SQUASHFS_FILE_DIRECT=y
CONFIG_SQUASHFS_DECOMP_SINGLE=y
# CONFIG_SQUASHFS_DECOMP_MULTI is not set
# CONFIG_SQUASHFS_DECOMP_MULTI_PERCPU is not set
CONFIG_SQUASHFS_XATTR=y
CONFIG_SQUASHFS_ZLIB=y
# CONFIG_SQUASHFS_LZ4 is not set
CONFIG_SQUASHFS_LZO=y
CONFIG_SQUASHFS_XZ=y
# CONFIG_SQUASHFS_ZSTD is not set
# CONFIG_SQUASHFS_4K_DEVBLK_SIZE is not set
# CONFIG_SQUASHFS_EMBEDDED is not set
CONFIG_SQUASHFS_FRAGMENT_CACHE_SIZE=3
# CONFIG_VXFS_FS is not set
# CONFIG_MINIX_FS is not set
# CONFIG_OMFS_FS is not set
# CONFIG_HPFS_FS is not set
# CONFIG_QNX4FS_FS is not set
# CONFIG_QNX6FS_FS is not set
# CONFIG_ROMFS_FS is not set
CONFIG_PSTORE=y
CONFIG_PSTORE_DEFAULT_KMSG_BYTES=10240
CONFIG_PSTORE_DEFLATE_COMPRESS=y
# CONFIG_PSTORE_LZO_COMPRESS is not set
# CONFIG_PSTORE_LZ4_COMPRESS is not set
# CONFIG_PSTORE_LZ4HC_COMPRESS is not set
# CONFIG_PSTORE_842_COMPRESS is not set
# CONFIG_PSTORE_ZSTD_COMPRESS is not set
CONFIG_PSTORE_COMPRESS=y
CONFIG_PSTORE_DEFLATE_COMPRESS_DEFAULT=y
CONFIG_PSTORE_COMPRESS_DEFAULT="deflate"
# CONFIG_PSTORE_CONSOLE is not set
# CONFIG_PSTORE_PMSG is not set
# CONFIG_PSTORE_FTRACE is not set
CONFIG_PSTORE_RAM=m
# CONFIG_PSTORE_BLK is not set
# CONFIG_SYSV_FS is not set
# CONFIG_UFS_FS is not set
# CONFIG_EROFS_FS is not set
CONFIG_NETWORK_FILESYSTEMS=y
CONFIG_NFS_FS=y
# CONFIG_NFS_V2 is not set
CONFIG_NFS_V3=y
CONFIG_NFS_V3_ACL=y
CONFIG_NFS_V4=m
# CONFIG_NFS_SWAP is not set
CONFIG_NFS_V4_1=y
CONFIG_NFS_V4_2=y
CONFIG_PNFS_FILE_LAYOUT=m
CONFIG_PNFS_BLOCK=m
CONFIG_PNFS_FLEXFILE_LAYOUT=m
CONFIG_NFS_V4_1_IMPLEMENTATION_ID_DOMAIN="kernel.org"
# CONFIG_NFS_V4_1_MIGRATION is not set
CONFIG_NFS_V4_SECURITY_LABEL=y
CONFIG_ROOT_NFS=y
# CONFIG_NFS_USE_LEGACY_DNS is not set
CONFIG_NFS_USE_KERNEL_DNS=y
CONFIG_NFS_DEBUG=y
CONFIG_NFS_DISABLE_UDP_SUPPORT=y
CONFIG_NFS_V4_2_READ_PLUS=y
CONFIG_NFSD=m
CONFIG_NFSD_V2_ACL=y
CONFIG_NFSD_V3_ACL=y
CONFIG_NFSD_V4=y
CONFIG_NFSD_PNFS=y
# CONFIG_NFSD_BLOCKLAYOUT is not set
CONFIG_NFSD_SCSILAYOUT=y
# CONFIG_NFSD_FLEXFILELAYOUT is not set
# CONFIG_NFSD_V4_2_INTER_SSC is not set
CONFIG_NFSD_V4_SECURITY_LABEL=y
CONFIG_GRACE_PERIOD=y
CONFIG_LOCKD=y
CONFIG_LOCKD_V4=y
CONFIG_NFS_ACL_SUPPORT=y
CONFIG_NFS_COMMON=y
CONFIG_NFS_V4_2_SSC_HELPER=y
CONFIG_SUNRPC=y
CONFIG_SUNRPC_GSS=m
CONFIG_SUNRPC_BACKCHANNEL=y
CONFIG_RPCSEC_GSS_KRB5=m
# CONFIG_SUNRPC_DISABLE_INSECURE_ENCTYPES is not set
CONFIG_SUNRPC_DEBUG=y
CONFIG_CEPH_FS=m
# CONFIG_CEPH_FSCACHE is not set
CONFIG_CEPH_FS_POSIX_ACL=y
# CONFIG_CEPH_FS_SECURITY_LABEL is not set
CONFIG_CIFS=m
CONFIG_CIFS_STATS2=y
CONFIG_CIFS_ALLOW_INSECURE_LEGACY=y
CONFIG_CIFS_UPCALL=y
CONFIG_CIFS_XATTR=y
CONFIG_CIFS_POSIX=y
CONFIG_CIFS_DEBUG=y
# CONFIG_CIFS_DEBUG2 is not set
# CONFIG_CIFS_DEBUG_DUMP_KEYS is not set
CONFIG_CIFS_DFS_UPCALL=y
# CONFIG_CIFS_SWN_UPCALL is not set
# CONFIG_CIFS_FSCACHE is not set
# CONFIG_SMB_SERVER is not set
CONFIG_SMBFS_COMMON=m
# CONFIG_CODA_FS is not set
# CONFIG_AFS_FS is not set
# CONFIG_9P_FS is not set
CONFIG_NLS=y
CONFIG_NLS_DEFAULT="utf8"
CONFIG_NLS_CODEPAGE_437=y
CONFIG_NLS_CODEPAGE_737=m
CONFIG_NLS_CODEPAGE_775=m
CONFIG_NLS_CODEPAGE_850=m
CONFIG_NLS_CODEPAGE_852=m
CONFIG_NLS_CODEPAGE_855=m
CONFIG_NLS_CODEPAGE_857=m
CONFIG_NLS_CODEPAGE_860=m
CONFIG_NLS_CODEPAGE_861=m
CONFIG_NLS_CODEPAGE_862=m
CONFIG_NLS_CODEPAGE_863=m
CONFIG_NLS_CODEPAGE_864=m
CONFIG_NLS_CODEPAGE_865=m
CONFIG_NLS_CODEPAGE_866=m
CONFIG_NLS_CODEPAGE_869=m
CONFIG_NLS_CODEPAGE_936=m
CONFIG_NLS_CODEPAGE_950=m
CONFIG_NLS_CODEPAGE_932=m
CONFIG_NLS_CODEPAGE_949=m
CONFIG_NLS_CODEPAGE_874=m
CONFIG_NLS_ISO8859_8=m
CONFIG_NLS_CODEPAGE_1250=m
CONFIG_NLS_CODEPAGE_1251=m
CONFIG_NLS_ASCII=y
CONFIG_NLS_ISO8859_1=m
CONFIG_NLS_ISO8859_2=m
CONFIG_NLS_ISO8859_3=m
CONFIG_NLS_ISO8859_4=m
CONFIG_NLS_ISO8859_5=m
CONFIG_NLS_ISO8859_6=m
CONFIG_NLS_ISO8859_7=m
CONFIG_NLS_ISO8859_9=m
CONFIG_NLS_ISO8859_13=m
CONFIG_NLS_ISO8859_14=m
CONFIG_NLS_ISO8859_15=m
CONFIG_NLS_KOI8_R=m
CONFIG_NLS_KOI8_U=m
CONFIG_NLS_MAC_ROMAN=m
CONFIG_NLS_MAC_CELTIC=m
CONFIG_NLS_MAC_CENTEURO=m
CONFIG_NLS_MAC_CROATIAN=m
CONFIG_NLS_MAC_CYRILLIC=m
CONFIG_NLS_MAC_GAELIC=m
CONFIG_NLS_MAC_GREEK=m
CONFIG_NLS_MAC_ICELAND=m
CONFIG_NLS_MAC_INUIT=m
CONFIG_NLS_MAC_ROMANIAN=m
CONFIG_NLS_MAC_TURKISH=m
CONFIG_NLS_UTF8=m
CONFIG_DLM=m
# CONFIG_DLM_DEPRECATED_API is not set
CONFIG_DLM_DEBUG=y
# CONFIG_UNICODE is not set
CONFIG_IO_WQ=y
# end of File systems

#
# Security options
#
CONFIG_KEYS=y
# CONFIG_KEYS_REQUEST_CACHE is not set
CONFIG_PERSISTENT_KEYRINGS=y
CONFIG_TRUSTED_KEYS=y
CONFIG_TRUSTED_KEYS_TPM=y
CONFIG_ENCRYPTED_KEYS=y
# CONFIG_USER_DECRYPTED_DATA is not set
# CONFIG_KEY_DH_OPERATIONS is not set
# CONFIG_SECURITY_DMESG_RESTRICT is not set
CONFIG_SECURITY=y
CONFIG_SECURITYFS=y
CONFIG_SECURITY_NETWORK=y
CONFIG_SECURITY_NETWORK_XFRM=y
CONFIG_SECURITY_PATH=y
CONFIG_INTEL_TXT=y
CONFIG_HAVE_HARDENED_USERCOPY_ALLOCATOR=y
CONFIG_HARDENED_USERCOPY=y
CONFIG_FORTIFY_SOURCE=y
# CONFIG_STATIC_USERMODEHELPER is not set
# CONFIG_SECURITY_SELINUX is not set
# CONFIG_SECURITY_SMACK is not set
# CONFIG_SECURITY_TOMOYO is not set
CONFIG_SECURITY_APPARMOR=y
# CONFIG_SECURITY_APPARMOR_DEBUG is not set
CONFIG_SECURITY_APPARMOR_INTROSPECT_POLICY=y
CONFIG_SECURITY_APPARMOR_HASH=y
CONFIG_SECURITY_APPARMOR_HASH_DEFAULT=y
CONFIG_SECURITY_APPARMOR_EXPORT_BINARY=y
CONFIG_SECURITY_APPARMOR_PARANOID_LOAD=y
# CONFIG_SECURITY_LOADPIN is not set
CONFIG_SECURITY_YAMA=y
# CONFIG_SECURITY_SAFESETID is not set
# CONFIG_SECURITY_LOCKDOWN_LSM is not set
# CONFIG_SECURITY_LANDLOCK is not set
CONFIG_INTEGRITY=y
CONFIG_INTEGRITY_SIGNATURE=y
CONFIG_INTEGRITY_ASYMMETRIC_KEYS=y
CONFIG_INTEGRITY_TRUSTED_KEYRING=y
# CONFIG_INTEGRITY_PLATFORM_KEYRING is not set
CONFIG_INTEGRITY_AUDIT=y
# CONFIG_IMA is not set
# CONFIG_IMA_SECURE_AND_OR_TRUSTED_BOOT is not set
# CONFIG_EVM is not set
CONFIG_DEFAULT_SECURITY_APPARMOR=y
# CONFIG_DEFAULT_SECURITY_DAC is not set
CONFIG_LSM="landlock,lockdown,yama,loadpin,safesetid,integrity,apparmor,selinux,smack,tomoyo,bpf"

#
# Kernel hardening options
#

#
# Memory initialization
#
CONFIG_CC_HAS_AUTO_VAR_INIT_PATTERN=y
CONFIG_CC_HAS_AUTO_VAR_INIT_ZERO_ENABLER=y
CONFIG_CC_HAS_AUTO_VAR_INIT_ZERO=y
# CONFIG_INIT_STACK_NONE is not set
# CONFIG_INIT_STACK_ALL_PATTERN is not set
CONFIG_INIT_STACK_ALL_ZERO=y
# CONFIG_INIT_ON_ALLOC_DEFAULT_ON is not set
# CONFIG_INIT_ON_FREE_DEFAULT_ON is not set
# end of Memory initialization

CONFIG_RANDSTRUCT_NONE=y
# end of Kernel hardening options
# end of Security options

CONFIG_XOR_BLOCKS=m
CONFIG_ASYNC_CORE=m
CONFIG_ASYNC_MEMCPY=m
CONFIG_ASYNC_XOR=m
CONFIG_ASYNC_PQ=m
CONFIG_ASYNC_RAID6_RECOV=m
CONFIG_CRYPTO=y

#
# Crypto core or helper
#
CONFIG_CRYPTO_ALGAPI=y
CONFIG_CRYPTO_ALGAPI2=y
CONFIG_CRYPTO_AEAD=y
CONFIG_CRYPTO_AEAD2=y
CONFIG_CRYPTO_SKCIPHER=y
CONFIG_CRYPTO_SKCIPHER2=y
CONFIG_CRYPTO_HASH=y
CONFIG_CRYPTO_HASH2=y
CONFIG_CRYPTO_RNG=y
CONFIG_CRYPTO_RNG2=y
CONFIG_CRYPTO_RNG_DEFAULT=y
CONFIG_CRYPTO_AKCIPHER2=y
CONFIG_CRYPTO_AKCIPHER=y
CONFIG_CRYPTO_KPP2=y
CONFIG_CRYPTO_KPP=m
CONFIG_CRYPTO_ACOMP2=y
CONFIG_CRYPTO_MANAGER=y
CONFIG_CRYPTO_MANAGER2=y
CONFIG_CRYPTO_USER=m
CONFIG_CRYPTO_MANAGER_DISABLE_TESTS=y
CONFIG_CRYPTO_GF128MUL=y
CONFIG_CRYPTO_NULL=y
CONFIG_CRYPTO_NULL2=y
CONFIG_CRYPTO_PCRYPT=m
CONFIG_CRYPTO_CRYPTD=y
CONFIG_CRYPTO_AUTHENC=m
# CONFIG_CRYPTO_TEST is not set
CONFIG_CRYPTO_SIMD=y
# end of Crypto core or helper

#
# Public-key cryptography
#
CONFIG_CRYPTO_RSA=y
CONFIG_CRYPTO_DH=m
# CONFIG_CRYPTO_DH_RFC7919_GROUPS is not set
CONFIG_CRYPTO_ECC=m
CONFIG_CRYPTO_ECDH=m
# CONFIG_CRYPTO_ECDSA is not set
# CONFIG_CRYPTO_ECRDSA is not set
# CONFIG_CRYPTO_SM2 is not set
# CONFIG_CRYPTO_CURVE25519 is not set
# end of Public-key cryptography

#
# Block ciphers
#
CONFIG_CRYPTO_AES=y
# CONFIG_CRYPTO_AES_TI is not set
CONFIG_CRYPTO_ANUBIS=m
# CONFIG_CRYPTO_ARIA is not set
CONFIG_CRYPTO_BLOWFISH=m
CONFIG_CRYPTO_BLOWFISH_COMMON=m
CONFIG_CRYPTO_CAMELLIA=m
CONFIG_CRYPTO_CAST_COMMON=m
CONFIG_CRYPTO_CAST5=m
CONFIG_CRYPTO_CAST6=m
CONFIG_CRYPTO_DES=m
CONFIG_CRYPTO_FCRYPT=m
CONFIG_CRYPTO_KHAZAD=m
CONFIG_CRYPTO_SEED=m
CONFIG_CRYPTO_SERPENT=m
# CONFIG_CRYPTO_SM4_GENERIC is not set
CONFIG_CRYPTO_TEA=m
CONFIG_CRYPTO_TWOFISH=m
CONFIG_CRYPTO_TWOFISH_COMMON=m
# end of Block ciphers

#
# Length-preserving ciphers and modes
#
# CONFIG_CRYPTO_ADIANTUM is not set
CONFIG_CRYPTO_ARC4=m
CONFIG_CRYPTO_CHACHA20=m
CONFIG_CRYPTO_CBC=y
CONFIG_CRYPTO_CFB=y
CONFIG_CRYPTO_CTR=y
CONFIG_CRYPTO_CTS=m
CONFIG_CRYPTO_ECB=y
# CONFIG_CRYPTO_HCTR2 is not set
# CONFIG_CRYPTO_KEYWRAP is not set
CONFIG_CRYPTO_LRW=m
CONFIG_CRYPTO_OFB=m
CONFIG_CRYPTO_PCBC=m
CONFIG_CRYPTO_XTS=m
# end of Length-preserving ciphers and modes

#
# AEAD (authenticated encryption with associated data) ciphers
#
# CONFIG_CRYPTO_AEGIS128 is not set
# CONFIG_CRYPTO_CHACHA20POLY1305 is not set
CONFIG_CRYPTO_CCM=m
CONFIG_CRYPTO_GCM=y
CONFIG_CRYPTO_SEQIV=y
CONFIG_CRYPTO_ECHAINIV=m
CONFIG_CRYPTO_ESSIV=m
# end of AEAD (authenticated encryption with associated data) ciphers

#
# Hashes, digests, and MACs
#
CONFIG_CRYPTO_BLAKE2B=m
CONFIG_CRYPTO_CMAC=m
CONFIG_CRYPTO_GHASH=y
CONFIG_CRYPTO_HMAC=y
CONFIG_CRYPTO_MD4=m
CONFIG_CRYPTO_MD5=y
CONFIG_CRYPTO_MICHAEL_MIC=m
# CONFIG_CRYPTO_POLY1305 is not set
CONFIG_CRYPTO_RMD160=m
CONFIG_CRYPTO_SHA1=y
CONFIG_CRYPTO_SHA256=y
CONFIG_CRYPTO_SHA512=y
CONFIG_CRYPTO_SHA3=m
# CONFIG_CRYPTO_SM3_GENERIC is not set
# CONFIG_CRYPTO_STREEBOG is not set
CONFIG_CRYPTO_VMAC=m
CONFIG_CRYPTO_WP512=m
CONFIG_CRYPTO_XCBC=m
CONFIG_CRYPTO_XXHASH=m
# end of Hashes, digests, and MACs

#
# CRCs (cyclic redundancy checks)
#
CONFIG_CRYPTO_CRC32C=y
CONFIG_CRYPTO_CRC32=m
CONFIG_CRYPTO_CRCT10DIF=y
CONFIG_CRYPTO_CRC64_ROCKSOFT=m
# end of CRCs (cyclic redundancy checks)

#
# Compression
#
CONFIG_CRYPTO_DEFLATE=y
CONFIG_CRYPTO_LZO=y
# CONFIG_CRYPTO_842 is not set
# CONFIG_CRYPTO_LZ4 is not set
# CONFIG_CRYPTO_LZ4HC is not set
# CONFIG_CRYPTO_ZSTD is not set
# end of Compression

#
# Random number generation
#
CONFIG_CRYPTO_ANSI_CPRNG=m
CONFIG_CRYPTO_DRBG_MENU=y
CONFIG_CRYPTO_DRBG_HMAC=y
CONFIG_CRYPTO_DRBG_HASH=y
CONFIG_CRYPTO_DRBG_CTR=y
CONFIG_CRYPTO_DRBG=y
CONFIG_CRYPTO_JITTERENTROPY=y
# end of Random number generation

#
# Userspace interface
#
CONFIG_CRYPTO_USER_API=y
CONFIG_CRYPTO_USER_API_HASH=y
CONFIG_CRYPTO_USER_API_SKCIPHER=y
CONFIG_CRYPTO_USER_API_RNG=y
# CONFIG_CRYPTO_USER_API_RNG_CAVP is not set
CONFIG_CRYPTO_USER_API_AEAD=y
CONFIG_CRYPTO_USER_API_ENABLE_OBSOLETE=y
# CONFIG_CRYPTO_STATS is not set
# end of Userspace interface

CONFIG_CRYPTO_HASH_INFO=y

#
# Accelerated Cryptographic Algorithms for CPU (x86)
#
# CONFIG_CRYPTO_CURVE25519_X86 is not set
CONFIG_CRYPTO_AES_NI_INTEL=y
CONFIG_CRYPTO_BLOWFISH_X86_64=m
CONFIG_CRYPTO_CAMELLIA_X86_64=m
CONFIG_CRYPTO_CAMELLIA_AESNI_AVX_X86_64=m
CONFIG_CRYPTO_CAMELLIA_AESNI_AVX2_X86_64=m
CONFIG_CRYPTO_CAST5_AVX_X86_64=m
CONFIG_CRYPTO_CAST6_AVX_X86_64=m
# CONFIG_CRYPTO_DES3_EDE_X86_64 is not set
CONFIG_CRYPTO_SERPENT_SSE2_X86_64=m
CONFIG_CRYPTO_SERPENT_AVX_X86_64=m
CONFIG_CRYPTO_SERPENT_AVX2_X86_64=m
# CONFIG_CRYPTO_SM4_AESNI_AVX_X86_64 is not set
# CONFIG_CRYPTO_SM4_AESNI_AVX2_X86_64 is not set
CONFIG_CRYPTO_TWOFISH_X86_64=m
CONFIG_CRYPTO_TWOFISH_X86_64_3WAY=m
CONFIG_CRYPTO_TWOFISH_AVX_X86_64=m
# CONFIG_CRYPTO_ARIA_AESNI_AVX_X86_64 is not set
CONFIG_CRYPTO_CHACHA20_X86_64=m
# CONFIG_CRYPTO_AEGIS128_AESNI_SSE2 is not set
# CONFIG_CRYPTO_NHPOLY1305_SSE2 is not set
# CONFIG_CRYPTO_NHPOLY1305_AVX2 is not set
# CONFIG_CRYPTO_BLAKE2S_X86 is not set
# CONFIG_CRYPTO_POLYVAL_CLMUL_NI is not set
# CONFIG_CRYPTO_POLY1305_X86_64 is not set
CONFIG_CRYPTO_SHA1_SSSE3=y
CONFIG_CRYPTO_SHA256_SSSE3=y
CONFIG_CRYPTO_SHA512_SSSE3=m
# CONFIG_CRYPTO_SM3_AVX_X86_64 is not set
CONFIG_CRYPTO_GHASH_CLMUL_NI_INTEL=m
CONFIG_CRYPTO_CRC32C_INTEL=m
CONFIG_CRYPTO_CRC32_PCLMUL=m
CONFIG_CRYPTO_CRCT10DIF_PCLMUL=m
# end of Accelerated Cryptographic Algorithms for CPU (x86)

CONFIG_CRYPTO_HW=y
CONFIG_CRYPTO_DEV_PADLOCK=m
CONFIG_CRYPTO_DEV_PADLOCK_AES=m
CONFIG_CRYPTO_DEV_PADLOCK_SHA=m
# CONFIG_CRYPTO_DEV_ATMEL_ECC is not set
# CONFIG_CRYPTO_DEV_ATMEL_SHA204A is not set
CONFIG_CRYPTO_DEV_CCP=y
CONFIG_CRYPTO_DEV_CCP_DD=m
CONFIG_CRYPTO_DEV_SP_CCP=y
CONFIG_CRYPTO_DEV_CCP_CRYPTO=m
CONFIG_CRYPTO_DEV_SP_PSP=y
# CONFIG_CRYPTO_DEV_CCP_DEBUGFS is not set
CONFIG_CRYPTO_DEV_QAT=m
CONFIG_CRYPTO_DEV_QAT_DH895xCC=m
CONFIG_CRYPTO_DEV_QAT_C3XXX=m
CONFIG_CRYPTO_DEV_QAT_C62X=m
# CONFIG_CRYPTO_DEV_QAT_4XXX is not set
CONFIG_CRYPTO_DEV_QAT_DH895xCCVF=m
CONFIG_CRYPTO_DEV_QAT_C3XXXVF=m
CONFIG_CRYPTO_DEV_QAT_C62XVF=m
CONFIG_CRYPTO_DEV_NITROX=m
CONFIG_CRYPTO_DEV_NITROX_CNN55XX=m
# CONFIG_CRYPTO_DEV_VIRTIO is not set
# CONFIG_CRYPTO_DEV_SAFEXCEL is not set
# CONFIG_CRYPTO_DEV_AMLOGIC_GXL is not set
CONFIG_ASYMMETRIC_KEY_TYPE=y
CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE=y
CONFIG_X509_CERTIFICATE_PARSER=y
# CONFIG_PKCS8_PRIVATE_KEY_PARSER is not set
CONFIG_PKCS7_MESSAGE_PARSER=y
# CONFIG_PKCS7_TEST_KEY is not set
CONFIG_SIGNED_PE_FILE_VERIFICATION=y
# CONFIG_FIPS_SIGNATURE_SELFTEST is not set

#
# Certificates for signature checking
#
CONFIG_MODULE_SIG_KEY="certs/signing_key.pem"
CONFIG_MODULE_SIG_KEY_TYPE_RSA=y
# CONFIG_MODULE_SIG_KEY_TYPE_ECDSA is not set
CONFIG_SYSTEM_TRUSTED_KEYRING=y
CONFIG_SYSTEM_TRUSTED_KEYS=""
# CONFIG_SYSTEM_EXTRA_CERTIFICATE is not set
# CONFIG_SECONDARY_TRUSTED_KEYRING is not set
CONFIG_SYSTEM_BLACKLIST_KEYRING=y
CONFIG_SYSTEM_BLACKLIST_HASH_LIST=""
# CONFIG_SYSTEM_REVOCATION_LIST is not set
# CONFIG_SYSTEM_BLACKLIST_AUTH_UPDATE is not set
# end of Certificates for signature checking

CONFIG_BINARY_PRINTF=y

#
# Library routines
#
CONFIG_RAID6_PQ=m
CONFIG_RAID6_PQ_BENCHMARK=y
# CONFIG_PACKING is not set
CONFIG_BITREVERSE=y
CONFIG_GENERIC_STRNCPY_FROM_USER=y
CONFIG_GENERIC_STRNLEN_USER=y
CONFIG_GENERIC_NET_UTILS=y
CONFIG_CORDIC=m
# CONFIG_PRIME_NUMBERS is not set
CONFIG_RATIONAL=y
CONFIG_GENERIC_PCI_IOMAP=y
CONFIG_GENERIC_IOMAP=y
CONFIG_ARCH_USE_CMPXCHG_LOCKREF=y
CONFIG_ARCH_HAS_FAST_MULTIPLIER=y
CONFIG_ARCH_USE_SYM_ANNOTATIONS=y

#
# Crypto library routines
#
CONFIG_CRYPTO_LIB_UTILS=y
CONFIG_CRYPTO_LIB_AES=y
CONFIG_CRYPTO_LIB_ARC4=m
CONFIG_CRYPTO_LIB_BLAKE2S_GENERIC=y
CONFIG_CRYPTO_ARCH_HAVE_LIB_CHACHA=m
CONFIG_CRYPTO_LIB_CHACHA_GENERIC=m
# CONFIG_CRYPTO_LIB_CHACHA is not set
# CONFIG_CRYPTO_LIB_CURVE25519 is not set
CONFIG_CRYPTO_LIB_DES=m
CONFIG_CRYPTO_LIB_POLY1305_RSIZE=11
# CONFIG_CRYPTO_LIB_POLY1305 is not set
# CONFIG_CRYPTO_LIB_CHACHA20POLY1305 is not set
CONFIG_CRYPTO_LIB_SHA1=y
CONFIG_CRYPTO_LIB_SHA256=y
# end of Crypto library routines

CONFIG_CRC_CCITT=y
CONFIG_CRC16=y
CONFIG_CRC_T10DIF=y
CONFIG_CRC64_ROCKSOFT=m
CONFIG_CRC_ITU_T=m
CONFIG_CRC32=y
# CONFIG_CRC32_SELFTEST is not set
CONFIG_CRC32_SLICEBY8=y
# CONFIG_CRC32_SLICEBY4 is not set
# CONFIG_CRC32_SARWATE is not set
# CONFIG_CRC32_BIT is not set
CONFIG_CRC64=m
# CONFIG_CRC4 is not set
CONFIG_CRC7=m
CONFIG_LIBCRC32C=m
CONFIG_CRC8=m
CONFIG_XXHASH=y
# CONFIG_RANDOM32_SELFTEST is not set
CONFIG_ZLIB_INFLATE=y
CONFIG_ZLIB_DEFLATE=y
CONFIG_LZO_COMPRESS=y
CONFIG_LZO_DECOMPRESS=y
CONFIG_LZ4_DECOMPRESS=y
CONFIG_ZSTD_COMMON=y
CONFIG_ZSTD_COMPRESS=m
CONFIG_ZSTD_DECOMPRESS=y
CONFIG_XZ_DEC=y
CONFIG_XZ_DEC_X86=y
CONFIG_XZ_DEC_POWERPC=y
CONFIG_XZ_DEC_IA64=y
CONFIG_XZ_DEC_ARM=y
CONFIG_XZ_DEC_ARMTHUMB=y
CONFIG_XZ_DEC_SPARC=y
# CONFIG_XZ_DEC_MICROLZMA is not set
CONFIG_XZ_DEC_BCJ=y
# CONFIG_XZ_DEC_TEST is not set
CONFIG_DECOMPRESS_GZIP=y
CONFIG_DECOMPRESS_BZIP2=y
CONFIG_DECOMPRESS_LZMA=y
CONFIG_DECOMPRESS_XZ=y
CONFIG_DECOMPRESS_LZO=y
CONFIG_DECOMPRESS_LZ4=y
CONFIG_DECOMPRESS_ZSTD=y
CONFIG_GENERIC_ALLOCATOR=y
CONFIG_REED_SOLOMON=m
CONFIG_REED_SOLOMON_ENC8=y
CONFIG_REED_SOLOMON_DEC8=y
CONFIG_TEXTSEARCH=y
CONFIG_TEXTSEARCH_KMP=m
CONFIG_TEXTSEARCH_BM=m
CONFIG_TEXTSEARCH_FSM=m
CONFIG_INTERVAL_TREE=y
CONFIG_XARRAY_MULTI=y
CONFIG_ASSOCIATIVE_ARRAY=y
CONFIG_HAS_IOMEM=y
CONFIG_HAS_IOPORT_MAP=y
CONFIG_HAS_DMA=y
CONFIG_DMA_OPS=y
CONFIG_NEED_SG_DMA_LENGTH=y
CONFIG_NEED_DMA_MAP_STATE=y
CONFIG_ARCH_DMA_ADDR_T_64BIT=y
CONFIG_ARCH_HAS_FORCE_DMA_UNENCRYPTED=y
CONFIG_SWIOTLB=y
# CONFIG_DMA_API_DEBUG is not set
# CONFIG_DMA_MAP_BENCHMARK is not set
CONFIG_SGL_ALLOC=y
CONFIG_CHECK_SIGNATURE=y
CONFIG_CPUMASK_OFFSTACK=y
# CONFIG_FORCE_NR_CPUS is not set
CONFIG_CPU_RMAP=y
CONFIG_DQL=y
CONFIG_GLOB=y
# CONFIG_GLOB_SELFTEST is not set
CONFIG_NLATTR=y
CONFIG_CLZ_TAB=y
CONFIG_IRQ_POLL=y
CONFIG_MPILIB=y
CONFIG_SIGNATURE=y
CONFIG_OID_REGISTRY=y
CONFIG_UCS2_STRING=y
CONFIG_HAVE_GENERIC_VDSO=y
CONFIG_GENERIC_GETTIMEOFDAY=y
CONFIG_GENERIC_VDSO_TIME_NS=y
CONFIG_FONT_SUPPORT=y
# CONFIG_FONTS is not set
CONFIG_FONT_8x8=y
CONFIG_FONT_8x16=y
CONFIG_SG_POOL=y
CONFIG_ARCH_HAS_PMEM_API=y
CONFIG_MEMREGION=y
CONFIG_ARCH_HAS_UACCESS_FLUSHCACHE=y
CONFIG_ARCH_HAS_COPY_MC=y
CONFIG_ARCH_STACKWALK=y
CONFIG_STACKDEPOT=y
CONFIG_SBITMAP=y
# end of Library routines

CONFIG_ASN1_ENCODER=y

#
# Kernel hacking
#

#
# printk and dmesg options
#
CONFIG_PRINTK_TIME=y
CONFIG_PRINTK_CALLER=y
# CONFIG_STACKTRACE_BUILD_ID is not set
CONFIG_CONSOLE_LOGLEVEL_DEFAULT=7
CONFIG_CONSOLE_LOGLEVEL_QUIET=4
CONFIG_MESSAGE_LOGLEVEL_DEFAULT=4
CONFIG_BOOT_PRINTK_DELAY=y
CONFIG_DYNAMIC_DEBUG=y
CONFIG_DYNAMIC_DEBUG_CORE=y
CONFIG_SYMBOLIC_ERRNAME=y
CONFIG_DEBUG_BUGVERBOSE=y
# end of printk and dmesg options

CONFIG_DEBUG_KERNEL=y
CONFIG_DEBUG_MISC=y

#
# Compile-time checks and compiler options
#
CONFIG_DEBUG_INFO=y
CONFIG_AS_HAS_NON_CONST_LEB128=y
# CONFIG_DEBUG_INFO_NONE is not set
# CONFIG_DEBUG_INFO_DWARF_TOOLCHAIN_DEFAULT is not set
CONFIG_DEBUG_INFO_DWARF4=y
# CONFIG_DEBUG_INFO_DWARF5 is not set
# CONFIG_DEBUG_INFO_REDUCED is not set
# CONFIG_DEBUG_INFO_SPLIT is not set
# CONFIG_DEBUG_INFO_BTF is not set
CONFIG_PAHOLE_HAS_SPLIT_BTF=y
CONFIG_PAHOLE_HAS_BTF_TAG=y
# CONFIG_GDB_SCRIPTS is not set
CONFIG_FRAME_WARN=2048
CONFIG_STRIP_ASM_SYMS=y
# CONFIG_HEADERS_INSTALL is not set
CONFIG_SECTION_MISMATCH_WARN_ONLY=y
CONFIG_OBJTOOL=y
# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set
# end of Compile-time checks and compiler options

#
# Generic Kernel Debugging Instruments
#
CONFIG_MAGIC_SYSRQ=y
CONFIG_MAGIC_SYSRQ_DEFAULT_ENABLE=0x1
CONFIG_MAGIC_SYSRQ_SERIAL=y
CONFIG_MAGIC_SYSRQ_SERIAL_SEQUENCE=""
CONFIG_DEBUG_FS=y
CONFIG_DEBUG_FS_ALLOW_ALL=y
# CONFIG_DEBUG_FS_DISALLOW_MOUNT is not set
# CONFIG_DEBUG_FS_ALLOW_NONE is not set
CONFIG_HAVE_ARCH_KGDB=y
# CONFIG_KGDB is not set
CONFIG_ARCH_HAS_UBSAN_SANITIZE_ALL=y
# CONFIG_UBSAN is not set
CONFIG_HAVE_ARCH_KCSAN=y
CONFIG_HAVE_KCSAN_COMPILER=y
# CONFIG_KCSAN is not set
# end of Generic Kernel Debugging Instruments

#
# Networking Debugging
#
# CONFIG_NET_DEV_REFCNT_TRACKER is not set
# CONFIG_NET_NS_REFCNT_TRACKER is not set
# CONFIG_DEBUG_NET is not set
# end of Networking Debugging

#
# Memory Debugging
#
# CONFIG_PAGE_EXTENSION is not set
# CONFIG_DEBUG_PAGEALLOC is not set
CONFIG_SLUB_DEBUG=y
# CONFIG_SLUB_DEBUG_ON is not set
# CONFIG_PAGE_OWNER is not set
# CONFIG_PAGE_TABLE_CHECK is not set
# CONFIG_PAGE_POISONING is not set
# CONFIG_DEBUG_PAGE_REF is not set
# CONFIG_DEBUG_RODATA_TEST is not set
CONFIG_ARCH_HAS_DEBUG_WX=y
# CONFIG_DEBUG_WX is not set
CONFIG_GENERIC_PTDUMP=y
# CONFIG_PTDUMP_DEBUGFS is not set
# CONFIG_DEBUG_OBJECTS is not set
# CONFIG_SHRINKER_DEBUG is not set
CONFIG_HAVE_DEBUG_KMEMLEAK=y
# CONFIG_DEBUG_KMEMLEAK is not set
# CONFIG_DEBUG_STACK_USAGE is not set
# CONFIG_SCHED_STACK_END_CHECK is not set
CONFIG_ARCH_HAS_DEBUG_VM_PGTABLE=y
# CONFIG_DEBUG_VM is not set
# CONFIG_DEBUG_VM_PGTABLE is not set
CONFIG_ARCH_HAS_DEBUG_VIRTUAL=y
# CONFIG_DEBUG_VIRTUAL is not set
CONFIG_DEBUG_MEMORY_INIT=y
# CONFIG_DEBUG_PER_CPU_MAPS is not set
CONFIG_HAVE_ARCH_KASAN=y
CONFIG_HAVE_ARCH_KASAN_VMALLOC=y
CONFIG_CC_HAS_KASAN_GENERIC=y
CONFIG_CC_HAS_KASAN_SW_TAGS=y
CONFIG_CC_HAS_WORKING_NOSANITIZE_ADDRESS=y
# CONFIG_KASAN is not set
CONFIG_HAVE_ARCH_KFENCE=y
# CONFIG_KFENCE is not set
CONFIG_HAVE_ARCH_KMSAN=y
CONFIG_HAVE_KMSAN_COMPILER=y
# CONFIG_KMSAN is not set
# end of Memory Debugging

CONFIG_DEBUG_SHIRQ=y

#
# Debug Oops, Lockups and Hangs
#
CONFIG_PANIC_ON_OOPS=y
CONFIG_PANIC_ON_OOPS_VALUE=1
CONFIG_PANIC_TIMEOUT=0
CONFIG_LOCKUP_DETECTOR=y
CONFIG_SOFTLOCKUP_DETECTOR=y
# CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set
CONFIG_HARDLOCKUP_DETECTOR_PERF=y
CONFIG_HARDLOCKUP_CHECK_TIMESTAMP=y
CONFIG_HARDLOCKUP_DETECTOR=y
CONFIG_BOOTPARAM_HARDLOCKUP_PANIC=y
CONFIG_DETECT_HUNG_TASK=y
CONFIG_DEFAULT_HUNG_TASK_TIMEOUT=480
# CONFIG_BOOTPARAM_HUNG_TASK_PANIC is not set
CONFIG_WQ_WATCHDOG=y
# CONFIG_TEST_LOCKUP is not set
# end of Debug Oops, Lockups and Hangs

#
# Scheduler Debugging
#
CONFIG_SCHED_DEBUG=y
CONFIG_SCHED_INFO=y
CONFIG_SCHEDSTATS=y
# end of Scheduler Debugging

# CONFIG_DEBUG_TIMEKEEPING is not set

#
# Lock Debugging (spinlocks, mutexes, etc...)
#
CONFIG_LOCK_DEBUGGING_SUPPORT=y
# CONFIG_PROVE_LOCKING is not set
# CONFIG_LOCK_STAT is not set
# CONFIG_DEBUG_RT_MUTEXES is not set
# CONFIG_DEBUG_SPINLOCK is not set
# CONFIG_DEBUG_MUTEXES is not set
# CONFIG_DEBUG_WW_MUTEX_SLOWPATH is not set
# CONFIG_DEBUG_RWSEMS is not set
# CONFIG_DEBUG_LOCK_ALLOC is not set
CONFIG_DEBUG_ATOMIC_SLEEP=y
# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
# CONFIG_LOCK_TORTURE_TEST is not set
# CONFIG_WW_MUTEX_SELFTEST is not set
# CONFIG_SCF_TORTURE_TEST is not set
# CONFIG_CSD_LOCK_WAIT_DEBUG is not set
# end of Lock Debugging (spinlocks, mutexes, etc...)

# CONFIG_DEBUG_IRQFLAGS is not set
CONFIG_STACKTRACE=y
# CONFIG_WARN_ALL_UNSEEDED_RANDOM is not set
# CONFIG_DEBUG_KOBJECT is not set

#
# Debug kernel data structures
#
CONFIG_DEBUG_LIST=y
# CONFIG_DEBUG_PLIST is not set
# CONFIG_DEBUG_SG is not set
# CONFIG_DEBUG_NOTIFIERS is not set
CONFIG_BUG_ON_DATA_CORRUPTION=y
# CONFIG_DEBUG_MAPLE_TREE is not set
# end of Debug kernel data structures

# CONFIG_DEBUG_CREDENTIALS is not set

#
# RCU Debugging
#
# CONFIG_RCU_SCALE_TEST is not set
# CONFIG_RCU_TORTURE_TEST is not set
# CONFIG_RCU_REF_SCALE_TEST is not set
CONFIG_RCU_CPU_STALL_TIMEOUT=60
CONFIG_RCU_EXP_CPU_STALL_TIMEOUT=0
# CONFIG_RCU_TRACE is not set
# CONFIG_RCU_EQS_DEBUG is not set
# end of RCU Debugging

# CONFIG_DEBUG_WQ_FORCE_RR_CPU is not set
# CONFIG_CPU_HOTPLUG_STATE_CONTROL is not set
CONFIG_LATENCYTOP=y
CONFIG_USER_STACKTRACE_SUPPORT=y
CONFIG_NOP_TRACER=y
CONFIG_HAVE_RETHOOK=y
CONFIG_RETHOOK=y
CONFIG_HAVE_FUNCTION_TRACER=y
CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
CONFIG_HAVE_DYNAMIC_FTRACE=y
CONFIG_HAVE_DYNAMIC_FTRACE_WITH_REGS=y
CONFIG_HAVE_DYNAMIC_FTRACE_WITH_DIRECT_CALLS=y
CONFIG_HAVE_DYNAMIC_FTRACE_WITH_ARGS=y
CONFIG_HAVE_DYNAMIC_FTRACE_NO_PATCHABLE=y
CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
CONFIG_HAVE_SYSCALL_TRACEPOINTS=y
CONFIG_HAVE_FENTRY=y
CONFIG_HAVE_OBJTOOL_MCOUNT=y
CONFIG_HAVE_C_RECORDMCOUNT=y
CONFIG_HAVE_BUILDTIME_MCOUNT_SORT=y
CONFIG_BUILDTIME_MCOUNT_SORT=y
CONFIG_TRACER_MAX_TRACE=y
CONFIG_TRACE_CLOCK=y
CONFIG_RING_BUFFER=y
CONFIG_EVENT_TRACING=y
CONFIG_CONTEXT_SWITCH_TRACER=y
CONFIG_TRACING=y
CONFIG_GENERIC_TRACER=y
CONFIG_TRACING_SUPPORT=y
CONFIG_FTRACE=y
# CONFIG_BOOTTIME_TRACING is not set
CONFIG_FUNCTION_TRACER=y
CONFIG_FUNCTION_GRAPH_TRACER=y
CONFIG_DYNAMIC_FTRACE=y
CONFIG_DYNAMIC_FTRACE_WITH_REGS=y
CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS=y
CONFIG_DYNAMIC_FTRACE_WITH_ARGS=y
# CONFIG_FPROBE is not set
CONFIG_FUNCTION_PROFILER=y
CONFIG_STACK_TRACER=y
# CONFIG_IRQSOFF_TRACER is not set
CONFIG_SCHED_TRACER=y
CONFIG_HWLAT_TRACER=y
# CONFIG_OSNOISE_TRACER is not set
# CONFIG_TIMERLAT_TRACER is not set
# CONFIG_MMIOTRACE is not set
CONFIG_FTRACE_SYSCALLS=y
CONFIG_TRACER_SNAPSHOT=y
# CONFIG_TRACER_SNAPSHOT_PER_CPU_SWAP is not set
CONFIG_BRANCH_PROFILE_NONE=y
# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set
# CONFIG_BLK_DEV_IO_TRACE is not set
CONFIG_KPROBE_EVENTS=y
# CONFIG_KPROBE_EVENTS_ON_NOTRACE is not set
CONFIG_UPROBE_EVENTS=y
CONFIG_BPF_EVENTS=y
CONFIG_DYNAMIC_EVENTS=y
CONFIG_PROBE_EVENTS=y
CONFIG_BPF_KPROBE_OVERRIDE=y
CONFIG_FTRACE_MCOUNT_RECORD=y
CONFIG_FTRACE_MCOUNT_USE_OBJTOOL=y
CONFIG_TRACING_MAP=y
CONFIG_SYNTH_EVENTS=y
CONFIG_HIST_TRIGGERS=y
# CONFIG_TRACE_EVENT_INJECT is not set
# CONFIG_TRACEPOINT_BENCHMARK is not set
CONFIG_RING_BUFFER_BENCHMARK=m
# CONFIG_TRACE_EVAL_MAP_FILE is not set
# CONFIG_FTRACE_RECORD_RECURSION is not set
# CONFIG_FTRACE_STARTUP_TEST is not set
# CONFIG_FTRACE_SORT_STARTUP_TEST is not set
# CONFIG_RING_BUFFER_STARTUP_TEST is not set
# CONFIG_RING_BUFFER_VALIDATE_TIME_DELTAS is not set
# CONFIG_PREEMPTIRQ_DELAY_TEST is not set
# CONFIG_SYNTH_EVENT_GEN_TEST is not set
# CONFIG_KPROBE_EVENT_GEN_TEST is not set
# CONFIG_HIST_TRIGGERS_DEBUG is not set
# CONFIG_RV is not set
CONFIG_PROVIDE_OHCI1394_DMA_INIT=y
CONFIG_SAMPLES=y
# CONFIG_SAMPLE_AUXDISPLAY is not set
# CONFIG_SAMPLE_TRACE_EVENTS is not set
# CONFIG_SAMPLE_TRACE_CUSTOM_EVENTS is not set
# CONFIG_SAMPLE_TRACE_PRINTK is not set
# CONFIG_SAMPLE_FTRACE_DIRECT is not set
# CONFIG_SAMPLE_FTRACE_DIRECT_MULTI is not set
# CONFIG_SAMPLE_TRACE_ARRAY is not set
# CONFIG_SAMPLE_KOBJECT is not set
# CONFIG_SAMPLE_KPROBES is not set
# CONFIG_SAMPLE_HW_BREAKPOINT is not set
# CONFIG_SAMPLE_KFIFO is not set
# CONFIG_SAMPLE_LIVEPATCH is not set
# CONFIG_SAMPLE_CONFIGFS is not set
# CONFIG_SAMPLE_VFIO_MDEV_MTTY is not set
# CONFIG_SAMPLE_VFIO_MDEV_MDPY is not set
# CONFIG_SAMPLE_VFIO_MDEV_MDPY_FB is not set
# CONFIG_SAMPLE_VFIO_MDEV_MBOCHS is not set
# CONFIG_SAMPLE_WATCHDOG is not set
CONFIG_SAMPLES_RUST=y
CONFIG_SAMPLE_RUST_MINIMAL=y
CONFIG_SAMPLE_RUST_PRINT=y
CONFIG_SAMPLE_RUST_HOSTPROGS=y
CONFIG_HAVE_SAMPLE_FTRACE_DIRECT=y
CONFIG_HAVE_SAMPLE_FTRACE_DIRECT_MULTI=y
CONFIG_ARCH_HAS_DEVMEM_IS_ALLOWED=y
CONFIG_STRICT_DEVMEM=y
# CONFIG_IO_STRICT_DEVMEM is not set

#
# x86 Debugging
#
CONFIG_EARLY_PRINTK_USB=y
CONFIG_X86_VERBOSE_BOOTUP=y
CONFIG_EARLY_PRINTK=y
CONFIG_EARLY_PRINTK_DBGP=y
CONFIG_EARLY_PRINTK_USB_XDBC=y
# CONFIG_EFI_PGT_DUMP is not set
# CONFIG_DEBUG_TLBFLUSH is not set
CONFIG_HAVE_MMIOTRACE_SUPPORT=y
# CONFIG_X86_DECODER_SELFTEST is not set
CONFIG_IO_DELAY_0X80=y
# CONFIG_IO_DELAY_0XED is not set
# CONFIG_IO_DELAY_UDELAY is not set
# CONFIG_IO_DELAY_NONE is not set
CONFIG_DEBUG_BOOT_PARAMS=y
# CONFIG_CPA_DEBUG is not set
# CONFIG_DEBUG_ENTRY is not set
# CONFIG_DEBUG_NMI_SELFTEST is not set
# CONFIG_X86_DEBUG_FPU is not set
# CONFIG_PUNIT_ATOM_DEBUG is not set
CONFIG_UNWINDER_ORC=y
# CONFIG_UNWINDER_FRAME_POINTER is not set
# end of x86 Debugging

#
# Kernel Testing and Coverage
#
# CONFIG_KUNIT is not set
# CONFIG_NOTIFIER_ERROR_INJECTION is not set
CONFIG_FUNCTION_ERROR_INJECTION=y
# CONFIG_FAULT_INJECTION is not set
CONFIG_ARCH_HAS_KCOV=y
CONFIG_CC_HAS_SANCOV_TRACE_PC=y
# CONFIG_KCOV is not set
CONFIG_RUNTIME_TESTING_MENU=y
# CONFIG_LKDTM is not set
# CONFIG_TEST_MIN_HEAP is not set
# CONFIG_TEST_DIV64 is not set
# CONFIG_BACKTRACE_SELF_TEST is not set
# CONFIG_TEST_REF_TRACKER is not set
# CONFIG_RBTREE_TEST is not set
# CONFIG_REED_SOLOMON_TEST is not set
# CONFIG_INTERVAL_TREE_TEST is not set
# CONFIG_PERCPU_TEST is not set
# CONFIG_ATOMIC64_SELFTEST is not set
# CONFIG_ASYNC_RAID6_TEST is not set
# CONFIG_TEST_HEXDUMP is not set
# CONFIG_STRING_SELFTEST is not set
# CONFIG_TEST_STRING_HELPERS is not set
# CONFIG_TEST_STRSCPY is not set
# CONFIG_TEST_KSTRTOX is not set
# CONFIG_TEST_PRINTF is not set
# CONFIG_TEST_SCANF is not set
# CONFIG_TEST_BITMAP is not set
# CONFIG_TEST_UUID is not set
# CONFIG_TEST_XARRAY is not set
# CONFIG_TEST_RHASHTABLE is not set
# CONFIG_TEST_SIPHASH is not set
# CONFIG_TEST_IDA is not set
# CONFIG_TEST_LKM is not set
# CONFIG_TEST_BITOPS is not set
# CONFIG_TEST_VMALLOC is not set
# CONFIG_TEST_USER_COPY is not set
# CONFIG_TEST_BPF is not set
# CONFIG_TEST_BLACKHOLE_DEV is not set
# CONFIG_FIND_BIT_BENCHMARK is not set
# CONFIG_TEST_FIRMWARE is not set
# CONFIG_TEST_SYSCTL is not set
# CONFIG_TEST_UDELAY is not set
# CONFIG_TEST_STATIC_KEYS is not set
# CONFIG_TEST_DYNAMIC_DEBUG is not set
# CONFIG_TEST_KMOD is not set
# CONFIG_TEST_MEMCAT_P is not set
# CONFIG_TEST_LIVEPATCH is not set
# CONFIG_TEST_MEMINIT is not set
# CONFIG_TEST_HMM is not set
# CONFIG_TEST_FREE_PAGES is not set
# CONFIG_TEST_FPU is not set
# CONFIG_TEST_CLOCKSOURCE_WATCHDOG is not set
CONFIG_ARCH_USE_MEMTEST=y
# CONFIG_MEMTEST is not set
# end of Kernel Testing and Coverage

#
# Rust hacking
#
# CONFIG_RUST_DEBUG_ASSERTIONS is not set
CONFIG_RUST_OVERFLOW_CHECKS=y
# end of Rust hacking
# end of Kernel hacking

^ permalink raw reply	[relevance 1%]

* [PATCH 6.0 0000/1073] 6.0.16-rc1 review
@ 2022-12-28 14:26  1% Greg Kroah-Hartman
  2022-12-28 14:40  8% ` [PATCH 6.0 0846/1073] bpf: prevent leak of lsm program after failed attach Greg Kroah-Hartman
  0 siblings, 1 reply; 77+ results
From: Greg Kroah-Hartman @ 2022-12-28 14:26 UTC (permalink / raw)
  To: stable
  Cc: Greg Kroah-Hartman, patches, linux-kernel, torvalds, akpm, linux,
	shuah, patches, lkft-triage, pavel, jonathanh, f.fainelli,
	sudipm.mukherjee, srw, rwarsow

This is the start of the stable review cycle for the 6.0.16 release.
There are 1073 patches in this series, all will be posted as a response
to this one.  If anyone has any issues with these being applied, please
let me know.

Responses should be made by Fri, 30 Dec 2022 14:41:34 +0000.
Anything received after that time might be too late.

The whole patch series can be found in one patch at:
	https://www.kernel.org/pub/linux/kernel/v6.x/stable-review/patch-6.0.16-rc1.gz
or in the git tree and branch at:
	git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable-rc.git linux-6.0.y
and the diffstat can be found below.

thanks,

greg k-h

-------------
Pseudo-Shortlog of commits:

Greg Kroah-Hartman <gregkh@linuxfoundation.org>
    Linux 6.0.16-rc1

ChenXiaoSong <chenxiaosong2@huawei.com>
    cifs: fix use-after-free on the link name

Paulo Alcantara <pc@cjr.nz>
    cifs: fix memory leaks in session setup

Zhang Xiaoxu <zhangxiaoxu5@huawei.com>
    cifs: Fix xid leak in cifs_get_file_info_unix()

Paulo Alcantara <pc@cjr.nz>
    cifs: fix double-fault crash during ntlmssp

Yassine Oudjana <y.oudjana@protonmail.com>
    extcon: usbc-tusb320: Call the Type-C IRQ handler only if a port is registered

Geert Uytterhoeven <geert+renesas@glider.be>
    clk: renesas: r8a779f0: Fix SD0H clock name

Martin Leung <Martin.Leung@amd.com>
    drm/amd/display: revert Disable DRR actions during state commit

Lin Ma <linma@zju.edu.cn>
    media: dvbdev: fix refcnt bug

Lin Ma <linma@zju.edu.cn>
    media: dvbdev: fix build warning due to comments

Gaosheng Cui <cuigaosheng1@huawei.com>
    net: stmmac: fix errno when create_singlethread_workqueue() fails

Pavel Begunkov <asml.silence@gmail.com>
    io_uring: remove iopoll spinlock

Pavel Begunkov <asml.silence@gmail.com>
    io_uring: protect cq_timeouts with timeout_lock

Pavel Begunkov <asml.silence@gmail.com>
    io_uring/net: fix cleanup after recycle

Pavel Begunkov <asml.silence@gmail.com>
    io_uring: improve io_double_lock_ctx fail handling

Pavel Begunkov <asml.silence@gmail.com>
    io_uring: add completion locking for iopoll

Arun Easi <aeasi@marvell.com>
    scsi: qla2xxx: Fix crash when I/O abort times out

David Hildenbrand <david@redhat.com>
    mm/gup: disallow FOLL_FORCE|FOLL_WRITE on hugetlb mappings

Filipe Manana <fdmanana@suse.com>
    btrfs: do not BUG_ON() on ENOMEM when dropping extent items for a range

Chen Zhongjin <chenzhongjin@huawei.com>
    ovl: fix use inode directly in rcu-walk mode

Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
    fbdev: fbcon: release buffer when fbcon_do_set_font() failed

Rickard x Andersson <rickaran@axis.com>
    gcov: add support for checksum field

Yuan Can <yuancan@huawei.com>
    floppy: Fix memory leak in do_floppy_init()

Johan Hovold <johan+linaro@kernel.org>
    regulator: core: fix deadlock on regulator enable

Rasmus Villemoes <linux@rasmusvillemoes.dk>
    iio: addac: ad74413r: fix integer promotion bug in ad74413_get_input_current_offset()

Rasmus Villemoes <linux@rasmusvillemoes.dk>
    iio: adc128s052: add proper .data members in adc128_of_match table

Nuno Sá <nuno.sa@analog.com>
    iio: adc: ad_sigma_delta: do not use internal iio_dev lock

Zeng Heng <zengheng4@huawei.com>
    iio: fix memory leak in iio_device_register_eventset()

Roberto Sassu <roberto.sassu@huawei.com>
    reiserfs: Add missing calls to reiserfs_security_free()

Nathan Chancellor <nathan@kernel.org>
    security: Restrict CONFIG_ZERO_CALL_USED_REGS to gcc or clang > 15.0.6

Schspa Shi <schspa@gmail.com>
    9p: set req refcount to zero to avoid uninitialized usage

Isaac J. Manjarres <isaacmanjarres@google.com>
    loop: Fix the max_loop commandline argument treatment when it is set to 0

Enrik Berkhan <Enrik.Berkhan@inka.de>
    HID: mcp2221: don't connect hidraw

Jason Gerecke <killertofu@gmail.com>
    HID: wacom: Ensure bootloader PID is usable in hidraw mode

Mathias Nyman <mathias.nyman@linux.intel.com>
    xhci: Prevent infinite loop in transaction errors recovery for streams

Ferry Toth <ftoth@exalondelft.nl>
    usb: dwc3: core: defer probe on ulpi_read_id timeout

Sven Peter <sven@svenpeter.dev>
    usb: dwc3: Fix race between dwc3_set_mode and __dwc3_set_mode

Li Jun <jun.li@nxp.com>
    clk: imx: imx8mp: add shared clk gate for usb suspend clk

Li Jun <jun.li@nxp.com>
    dt-bindings: clocks: imx8mp: Add ID for usb suspend clock

Johan Hovold <johan+linaro@kernel.org>
    arm64: dts: qcom: sm8250: fix USB-DP PHY registers

Johan Hovold <johan+linaro@kernel.org>
    arm64: dts: qcom: sm6350: fix USB-DP PHY registers

Chunfeng Yun <chunfeng.yun@mediatek.com>
    usb: xhci-mtk: fix leakage of shared hcd when fail to set wakeup irq

Pawel Laszczak <pawell@cadence.com>
    usb: cdnsp: fix lack of ZLP for ep0

Bastien Nocera <hadess@hadess.net>
    HID: logitech-hidpp: Guard FF init code against non-USB devices

Jiao Zhou <jiaozhou@google.com>
    ALSA: hda/hdmi: Add HP Device 0x8711 to force connect list

Edward Pacman <edward@edward-p.xyz>
    ALSA: hda/realtek: Add quirk for Lenovo TianYi510Pro-14IOB

wangdicheng <wangdicheng@kylinos.cn>
    ALSA: usb-audio: add the quirk for KT0206 device

Jeff LaBundy <jeff@labundy.com>
    Input: iqs7222 - add support for IQS7222A v1.13+

Jeff LaBundy <jeff@labundy.com>
    Input: iqs7222 - trim force communication command

Jeff LaBundy <jeff@labundy.com>
    dt-bindings: input: iqs7222: Add support for IQS7222A v1.13+

Jeff LaBundy <jeff@labundy.com>
    dt-bindings: input: iqs7222: Correct minimum slider size

Jeff LaBundy <jeff@labundy.com>
    dt-bindings: input: iqs7222: Reduce 'linux,code' to optional

Jeff LaBundy <jeff@labundy.com>
    Input: iqs7222 - avoid sending empty SYN_REPORT events

GUO Zihua <guozihua@huawei.com>
    ima: Simplify ima_lsm_copy_rule

John Stultz <jstultz@google.com>
    pstore: Make sure CONFIG_PSTORE_PMSG selects CONFIG_RT_MUTEXES

David Howells <dhowells@redhat.com>
    afs: Fix lost servers_outstanding count

Michael Petlan <mpetlan@redhat.com>
    perf test: Fix "all PMU test" to skip parametrized events

Sergio Paracuellos <sergio.paracuellos@gmail.com>
    MIPS: ralink: mt7621: avoid to init common ralink reset controller

Yang Jihong <yangjihong1@huawei.com>
    perf debug: Set debug_peo_args and redirect_to_stderr variable to correct values in perf_quiet_option()

Arnd Bergmann <arnd@arndb.de>
    drm/amd/pm: avoid large variable on kernel stack

John Stultz <jstultz@google.com>
    pstore: Switch pmsg_lock to an rt_mutex to avoid priority inversion

Kristina Martsenko <kristina.martsenko@arm.com>
    lkdtm: cfi: Make PAC test work with GCC 7 and 8

Kees Cook <keescook@chromium.org>
    LoadPin: Ignore the "contents" argument of the LSM hooks

Khaled Almahallawy <khaled.almahallawy@intel.com>
    drm/i915/display: Don't disable DDI/Transcoder when setting phy test pattern

Hans de Goede <hdegoede@redhat.com>
    ASoC: rt5670: Remove unbalanced pm_runtime_put()

Wang Jingjin <wangjingjin1@huawei.com>
    ASoC: rockchip: spdif: Add missing clk_disable_unprepare() in rk_spdif_runtime_resume()

Marek Szyprowski <m.szyprowski@samsung.com>
    ASoC: wm8994: Fix potential deadlock

Kai Vehmanen <kai.vehmanen@linux.intel.com>
    ALSA: hda/hdmi: fix stream-id config keep-alive for rt suspend

Jaroslav Kysela <perex@perex.cz>
    ALSA: hda/hdmi: Use only dynamic PCM device allocation

Kai Vehmanen <kai.vehmanen@linux.intel.com>
    ALSA: hda/hdmi: set default audio parameters for KAE silent-stream

Kai Vehmanen <kai.vehmanen@linux.intel.com>
    ALSA: hda/hdmi: fix i915 silent stream programming flow

Wang Yufen <wangyufen@huawei.com>
    ASoC: mediatek: mt8183: fix refcount leak in mt8183_mt6358_ts3a227_max98357_dev_probe()

Wang Jingjin <wangjingjin1@huawei.com>
    ASoC: rockchip: pdm: Add missing clk_disable_unprepare() in rockchip_pdm_runtime_resume()

Wang Yufen <wangyufen@huawei.com>
    ASoC: audio-graph-card: fix refcount leak of cpu_ep in __graph_for_each_link()

Wang Yufen <wangyufen@huawei.com>
    ASoC: mediatek: mt8173-rt5650-rt5514: fix refcount leak in mt8173_rt5650_rt5514_dev_probe()

Cezary Rojewski <cezary.rojewski@intel.com>
    ASoC: Intel: Skylake: Fix driver hang during shutdown

Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
    ALSA: hda: add snd_hdac_stop_streams() helper

Yang Yingliang <yangyingliang@huawei.com>
    ASoC: sof_es8336: fix possible use-after-free in sof_es8336_remove()

Yang Yingliang <yangyingliang@huawei.com>
    hwmon: (jc42) Fix missing unlock on error in jc42_write()

Wolfram Sang <wsa+renesas@sang-engineering.com>
    clk: renesas: r8a779f0: Add TMU and parent SASYNC clocks

Wolfram Sang <wsa+renesas@sang-engineering.com>
    clk: renesas: r8a779f0: Add SDH0 clock

Zhang Xiaoxu <zhangxiaoxu5@huawei.com>
    orangefs: Fix kmemleak in orangefs_{kernel,client}_debug_init()

Zhang Xiaoxu <zhangxiaoxu5@huawei.com>
    orangefs: Fix kmemleak in orangefs_sysfs_init()

Zhang Xiaoxu <zhangxiaoxu5@huawei.com>
    orangefs: Fix kmemleak in orangefs_prepare_debugfs_help_string()

Maurizio Lombardi <mlombard@redhat.com>
    scsi: target: iscsi: Fix a race condition between login_work and the login thread

Nathan Chancellor <nathan@kernel.org>
    drm/sti: Fix return type of sti_{dvo,hda,hdmi}_connector_mode_valid()

Nathan Chancellor <nathan@kernel.org>
    drm/fsl-dcu: Fix return type of fsl_dcu_drm_connector_mode_valid()

Kumar Meiyappan <Kumar.Meiyappan@microchip.com>
    scsi: smartpqi: Correct device removal for multi-actuator devices

Mike McGowen <mike.mcgowen@microchip.com>
    scsi: smartpqi: Add new controller PCI IDs

Hawkins Jiawei <yin31149@gmail.com>
    hugetlbfs: fix null-ptr-deref in hugetlbfs_parse_param()

Nathan Chancellor <nathan@kernel.org>
    scsi: elx: libefc: Fix second parameter type in state callbacks

Bjorn Helgaas <bhelgaas@google.com>
    Revert "PCI: Clear PCI_STATUS when setting up device"

Kai Ye <yekai13@huawei.com>
    crypto: hisilicon/qm - increase the memory of local variables

Bart Van Assche <bvanassche@acm.org>
    scsi: ufs: Reduce the START STOP UNIT timeout

Justin Tee <justin.tee@broadcom.com>
    scsi: lpfc: Fix hard lockup when reading the rx_monitor from debugfs

Zhiqi Song <songzhiqi1@huawei.com>
    crypto: hisilicon/hpre - fix resource leak in remove process

ChiYuan Huang <cy_huang@richtek.com>
    regulator: core: Fix resolve supply lookup issue

Sven Peter <sven@svenpeter.dev>
    Bluetooth: Add quirk to disable MWS Transport Configuration

Sven Peter <sven@svenpeter.dev>
    Bluetooth: Add quirk to disable extended scanning

Marek Vasut <marex@denx.de>
    Bluetooth: hci_bcm: Add CYW4373A0 support

ChiYuan Huang <cy_huang@richtek.com>
    regulator: core: Use different devices for resource allocation and DT lookup

Xiu Jianfeng <xiujianfeng@huawei.com>
    clk: st: Fix memory leak in st_of_quadfs_setup()

Shigeru Yoshida <syoshida@redhat.com>
    media: si470x: Fix use-after-free in si470x_int_in_callback()

Wolfram Sang <wsa+renesas@sang-engineering.com>
    mmc: renesas_sdhi: better reset from HS400 mode

Wolfram Sang <wsa+renesas@sang-engineering.com>
    mmc: renesas_sdhi: add quirk for broken register layout

Kunihiko Hayashi <hayashi.kunihiko@socionext.com>
    mmc: f-sdh30: Add quirks for broken timeout clock capability

Hawkins Jiawei <yin31149@gmail.com>
    nfs: fix possible null-ptr-deref when parsing param

James Hilliard <james.hilliard1@gmail.com>
    selftests/bpf: Fix conflicts with built-in functions in bpf_iter_ksym

Denis Pauk <pauk.denis@gmail.com>
    hwmon: (nct6775) add ASUS CROSSHAIR VIII/TUF/ProArt B550M

Lorenzo Bianconi <lorenzo@kernel.org>
    wifi: mt76: do not run mt76u_status_worker if the device is not running

Rui Zhang <zr.zhang@vivo.com>
    regulator: core: fix use_count leakage when handling boot-on

Andrii Nakryiko <andrii@kernel.org>
    libbpf: Avoid enum forward-declarations in public API in C++ mode

Artem Lukyanov <dukzcry@ya.ru>
    ASoC: amd: yc: Add Xiaomi Redmi Book Pro 14 2022 into DMI table

Alvin Lee <Alvin.Lee2@amd.com>
    drm/amd/display: Fix DTBCLK disable requests and SRC_SEL programming

Wesley Chalmers <Wesley.Chalmers@amd.com>
    drm/amd/display: Use the largest vready_offset in pipe group

Ye Bin <yebin10@huawei.com>
    blk-mq: fix possible memleak when register 'hctx' failed

Yunfei Dong <yunfei.dong@mediatek.com>
    media: mediatek: vcodec: Can't set dst buffer to done when lat decode error

Mazin Al Haddad <mazinalhaddad05@gmail.com>
    media: dvb-usb: fix memory leak in dvb_usb_adapter_init()

Lin Ma <linma@zju.edu.cn>
    media: dvbdev: adopts refcnt to avoid UAF

Yan Lei <yan_lei@dahuatech.com>
    media: dvb-frontends: fix leak of memory fw

Maxim Korotkov <korotkov.maxim.s@gmail.com>
    ethtool: avoiding integer overflow in ethtool_phys_id()

Stanislav Fomichev <sdf@google.com>
    bpf: Prevent decl_tag from being referenced in func_proto arg

Yonghong Song <yhs@fb.com>
    bpf: Fix a BTF_ID_LIST bug with CONFIG_DEBUG_INFO_BTF not set

Stanislav Fomichev <sdf@google.com>
    ppp: associate skb with a device at tx

Felix Fietkau <nbd@nbd.name>
    net: ethernet: mtk_eth_soc: drop packets to WDMA if the ring is full

Schspa Shi <schspa@gmail.com>
    mrp: introduce active flags to prevent UAF when applicant uninit

Eric Dumazet <edumazet@google.com>
    ipv6/sit: use DEV_STATS_INC() to avoid data-races

Eric Dumazet <edumazet@google.com>
    net: add atomic_long_t to net_device_stats fields

Sagi Grimberg <sagi@grimberg.me>
    nvme-auth: don't override ctrl keys before validation

Aurabindo Pillai <aurabindo.pillai@amd.com>
    drm/amd/display: fix array index out of bound error in bios parser

George Shen <george.shen@amd.com>
    drm/amd/display: Workaround to increase phantom pipe vactive in pipesplit

Jiang Li <jiang.li@ugreen.com>
    md/raid1: stop mdx_raid1 thread when raid1 array run failed

Xiao Ni <xni@redhat.com>
    md/raid0, raid10: Don't set discard sectors for request queue

Li Zhong <floridsleeves@gmail.com>
    drivers/md/md-bitmap: check the return value of md_bitmap_get_counter()

Nathan Chancellor <nathan@kernel.org>
    drm/mediatek: Fix return type of mtk_hdmi_bridge_mode_valid()

Ville Syrjälä <ville.syrjala@linux.intel.com>
    drm/sti: Use drm_mode_copy()

Ville Syrjälä <ville.syrjala@linux.intel.com>
    drm/rockchip: Use drm_mode_copy()

Ville Syrjälä <ville.syrjala@linux.intel.com>
    drm/msm: Use drm_mode_copy()

Wesley Chalmers <Wesley.Chalmers@amd.com>
    drm/amd/display: Disable DRR actions during state commit

Nathan Chancellor <nathan@kernel.org>
    s390/lcs: Fix return type of lcs_start_xmit()

Nathan Chancellor <nathan@kernel.org>
    s390/netiucv: Fix return type of netiucv_tx()

Nathan Chancellor <nathan@kernel.org>
    s390/ctcm: Fix return type of ctc{mp,}m_tx()

Nathan Chancellor <nathan@kernel.org>
    drm/amdgpu: Fix type of second parameter in odn_edit_dpm_table() callback

Nathan Chancellor <nathan@kernel.org>
    drm/amdgpu: Fix type of second parameter in trans_msg() callback

Kees Cook <keescook@chromium.org>
    igb: Do not free q_vector unless new one was allocated

José Expósito <jose.exposito89@gmail.com>
    HID: input: do not query XP-PEN Deco LW battery

Minsuk Kang <linuxlovemin@yonsei.ac.kr>
    wifi: brcmfmac: Fix potential shift-out-of-bounds in brcmf_fw_alloc_request()

Nathan Chancellor <nathan@kernel.org>
    hamradio: baycom_epp: Fix return type of baycom_send_packet()

Nathan Chancellor <nathan@kernel.org>
    net: ethernet: ti: Fix return type of netcp_ndo_start_xmit()

Stanislav Fomichev <sdf@google.com>
    bpf: make sure skb->len != 0 when redirecting to a tunneling device

Nathan Chancellor <nathan@kernel.org>
    drm/meson: Fix return type of meson_encoder_cvbs_mode_valid()

Jiri Slaby (SUSE) <jirislaby@kernel.org>
    qed (gcc13): use u16 for fid to be big enough

Rahul Bhattacharjee <quic_rbhattac@quicinc.com>
    wifi: ath11k: Fix qmi_msg_handler data structure initialization

Kerem Karabay <kekrby@gmail.com>
    HID: apple: enable APPLE_ISO_TILDE_QUIRK for the keyboards of Macs with the T2 chip

Kerem Karabay <kekrby@gmail.com>
    HID: apple: fix key translations where multiple quirks attempt to translate the same key

David Jeffery <djeffery@redhat.com>
    blk-mq: avoid double ->queue_rq() because of early timeout

Yuan Can <yuancan@huawei.com>
    drm/rockchip: use pm_runtime_resume_and_get() instead of pm_runtime_get_sync()

Hamza Mahfooz <hamza.mahfooz@amd.com>
    Revert "drm/amd/display: Limit max DSC target bpp for specific monitors"

Hamza Mahfooz <hamza.mahfooz@amd.com>
    drm/edid: add a quirk for two LG monitors to get them to work on 10bpc

gehao <gehao@kylinos.cn>
    drm/amd/display: prevent memory leak

Youghandhar Chintala <quic_youghand@quicinc.com>
    wifi: ath10k: Delay the unmapping of the buffer

Zhang Yuchen <zhangyuchen.lcr@bytedance.com>
    ipmi: fix memleak when unload ipmi driver

Amadeusz Sławiński <amadeuszx.slawinski@linux.intel.com>
    ASoC: Intel: avs: Add quirk for KBL-R RVP platform

Amadeusz Sławiński <amadeuszx.slawinski@linux.intel.com>
    ASoC: codecs: rt298: Add quirk for KBL-R RVP platform

Shigeru Yoshida <syoshida@redhat.com>
    wifi: ar5523: Fix use-after-free on ar5523_cmd() timed out

Fedor Pchelkin <pchelkin@ispras.ru>
    wifi: ath9k: verify the expected usb_endpoints are present

Wright Feng <wright.feng@cypress.com>
    brcmfmac: return error when getting invalid max_flowrings from dongle

Ming Qian <ming.qian@nxp.com>
    media: imx-jpeg: Disable useless interrupt to avoid kernel panic

Doug Brown <doug@schmorgal.com>
    drm/etnaviv: add missing quirks for GC300

ZhangPeng <zhangpeng362@huawei.com>
    hfs: fix OOB Read in __hfs_brec_find

Hans de Goede <hdegoede@redhat.com>
    ACPI: x86: Add skip i2c clients quirk for Medion Lifetab S10346

Hans de Goede <hdegoede@redhat.com>
    ACPI: x86: Add skip i2c clients quirk for Lenovo Yoga Tab 3 Pro (YT3-X90F)

Mateusz Jończyk <mat.jonczyk@o2.pl>
    x86/apic: Handle no CONFIG_X86_X2APIC on systems with x2APIC enabled by BIOS

Zheng Yejian <zhengyejian1@huawei.com>
    acct: fix potential integer overflow in encode_comp_t()

Ryusuke Konishi <konishi.ryusuke@gmail.com>
    nilfs2: fix shift-out-of-bounds due to too large exponent of block size

Ryusuke Konishi <konishi.ryusuke@gmail.com>
    nilfs2: fix shift-out-of-bounds/overflow in nilfs_sb2_bad_offset()

Rafael J. Wysocki <rafael.j.wysocki@intel.com>
    ACPICA: Fix error code path in acpi_ds_call_control_method()

Mia Kanashi <chad@redpilled.dev>
    ACPI: EC: Add quirk for the HP Pavilion Gaming 15-cx0041ur

Li Zhong <floridsleeves@gmail.com>
    ACPI: processor: idle: Check acpi_fetch_acpi_dev() return value

Hoi Pok Wu <wuhoipok@gmail.com>
    fs: jfs: fix shift-out-of-bounds in dbDiscardAG

Dr. David Alan Gilbert <linux@treblig.org>
    jfs: Fix fortify moan in symlink

Shigeru Yoshida <syoshida@redhat.com>
    udf: Avoid double brelse() in udf_rename()

Dongliang Mu <mudongliangabcd@gmail.com>
    fs: jfs: fix shift-out-of-bounds in dbAllocAG

Marijn Suijten <marijn.suijten@somainline.org>
    arm64: dts: qcom: sm6350: Add apps_smmu with streamID to SDHCI 1/2 nodes

Liu Shixin <liushixin2@huawei.com>
    binfmt_misc: fix shift-out-of-bounds in check_special_flags

Gaurav Kohli <gauravkohli@linux.microsoft.com>
    x86/hyperv: Remove unregister syscore call from Hyper-V cleanup

Guilherme G. Piccoli <gpiccoli@igalia.com>
    video: hyperv_fb: Avoid taking busy spinlock on panic path

Adriana Kobylak <anoo@us.ibm.com>
    ARM: dts: aspeed: rainier,everest: Move reserved memory regions

Mark Rutland <mark.rutland@arm.com>
    arm64: make is_ttbrX_addr() noinstr-safe

Zqiang <qiang1.zhang@intel.com>
    rcu: Fix __this_cpu_read() lockdep warning in rcu_force_quiescent_state()

Jiasheng Jiang <jiasheng@iscas.ac.cn>
    HID: amd_sfh: Add missing check for dma_alloc_coherent

Matt Johnston <matt@codeconstruct.com.au>
    mctp: Remove device type check at unregister

Jeremy Kerr <jk@codeconstruct.com.au>
    mctp: serial: Fix starting value for frame check sequence

Eric Dumazet <edumazet@google.com>
    net: stream: purge sk_error_queue in sk_stream_kill_queues()

Christophe JAILLET <christophe.jaillet@wanadoo.fr>
    myri10ge: Fix an error handling path in myri10ge_probe()

David Howells <dhowells@redhat.com>
    rxrpc: Fix missing unlock in rxrpc_do_sendmsg()

Cong Wang <cong.wang@bytedance.com>
    net_sched: reject TCF_EM_SIMPLE case for complex ematch module

Yang Yingliang <yangyingliang@huawei.com>
    mailbox: zynq-ipi: fix error handling while device_register() fails

Yang Yingliang <yangyingliang@huawei.com>
    mailbox: arm_mhuv2: Fix return value check in mhuv2_probe()

Conor Dooley <conor.dooley@microchip.com>
    mailbox: mpfs: read the system controller's status

Subash Abhinov Kasiviswanathan <quic_subashab@quicinc.com>
    skbuff: Account for tail adjustment during pull operations

Jakub Kicinski <kuba@kernel.org>
    devlink: protect devlink dump by the instance lock

Chen-Yu Tsai <wenst@chromium.org>
    arm64: dts: mt8183: Fix Mali GPU clock

Chun-Jie Chen <chun-jie.chen@mediatek.com>
    soc: mediatek: pm-domains: Fix the power glitch issue

Eelco Chaudron <echaudro@redhat.com>
    openvswitch: Fix flow lookup to use unmasked key

Jakub Kicinski <kuba@kernel.org>
    selftests: devlink: fix the fd redirect in dummy_reporter_test

Jakub Kicinski <kuba@kernel.org>
    devlink: hold region lock when flushing snapshots

GUO Zihua <guozihua@huawei.com>
    rtc: mxc_v2: Add missing clk_disable_unprepare()

Tan Tee Min <tee.min.tan@linux.intel.com>
    igc: Set Qbv start_time and end_time to end_time if not being configured in GCL

Tan Tee Min <tee.min.tan@linux.intel.com>
    igc: recalculate Qbv end_time by considering cycle time

Tan Tee Min <tee.min.tan@linux.intel.com>
    igc: allow BaseTime 0 enrollment for Qbv

Muhammad Husaini Zulkifli <muhammad.husaini.zulkifli@intel.com>
    igc: Add checking for basetime less than zero

Vinicius Costa Gomes <vinicius.gomes@intel.com>
    igc: Use strict cycles for Qbv scheduling

Vinicius Costa Gomes <vinicius.gomes@intel.com>
    igc: Enhance Qbv scheduling by using first flag bit

Vladimir Oltean <vladimir.oltean@nxp.com>
    net: dsa: mv88e6xxx: avoid reg_lock deadlock in mv88e6xxx_setup_port()

Ming Lei <ming.lei@redhat.com>
    block: fix use-after-free of q->q_usage_counter

Christoph Hellwig <hch@lst.de>
    block: mark blk_put_queue as potentially blocking

Christoph Hellwig <hch@lst.de>
    block: untangle request_queue refcounting from sysfs

Christoph Hellwig <hch@lst.de>
    block: fix error unwinding in blk_register_queue

Christoph Hellwig <hch@lst.de>
    block: factor out a blk_debugfs_remove helper

Christoph Hellwig <hch@lst.de>
    blk-crypto: pass a gendisk to blk_crypto_sysfs_{,un}register

Christoph Hellwig <hch@lst.de>
    blk-mq: move the srcu_struct used for quiescing to the tagset

Christoph Hellwig <hch@lst.de>
    blk-iocost: simplify ioc_name

Li Zetao <lizetao1@huawei.com>
    r6040: Fix kmemleak in probe and remove

Kirill Tkhai <tkhai@ya.ru>
    unix: Fix race in SOCK_SEQPACKET's unix_dgram_sendmsg()

Minsuk Kang <linuxlovemin@yonsei.ac.kr>
    nfc: pn533: Clear nfc_target before being used

Vladimir Oltean <vladimir.oltean@nxp.com>
    net: enetc: avoid buffer leaks on xdp_do_redirect() failure

Hans Verkuil <hverkuil-cisco@xs4all.nl>
    media: v4l2-ctrls-api.c: add back dropped ctrl->is_new = 1

Milan Landaverde <milan@mdaverde.com>
    bpf: prevent leak of lsm program after failed attach

Song Liu <song@kernel.org>
    selftests/bpf: Select CONFIG_FUNCTION_ERROR_INJECTION

Yu Kuai <yukuai3@huawei.com>
    block, bfq: fix possible uaf for 'bfqq->bic'

Yang Yingliang <yangyingliang@huawei.com>
    mISDN: hfcmulti: don't call dev_kfree_skb/kfree_skb() under spin_lock_irqsave()

Yang Yingliang <yangyingliang@huawei.com>
    mISDN: hfcpci: don't call dev_kfree_skb/kfree_skb() under spin_lock_irqsave()

Yang Yingliang <yangyingliang@huawei.com>
    mISDN: hfcsusb: don't call dev_kfree_skb/kfree_skb() under spin_lock_irqsave()

Hangbin Liu <liuhangbin@gmail.com>
    bonding: do failover when high prio link up

Hangbin Liu <liuhangbin@gmail.com>
    bonding: add missed __rcu annotation for curr_active_slave

Emeel Hakim <ehakim@nvidia.com>
    net: macsec: fix net device access prior to holding a lock

Dan Aloni <dan.aloni@vastdata.com>
    nfsd: under NFSv4.1, fix double svc_xprt_put on rpc_create failure

Dan Carpenter <error27@gmail.com>
    iommu/mediatek: Fix forever loop in error handling

Alexandre Belloni <alexandre.belloni@bootlin.com>
    rtc: pcf85063: fix pcf85063_clkout_control

Gaosheng Cui <cuigaosheng1@huawei.com>
    rtc: pic32: Move devm_rtc_allocate_device earlier in pic32_rtc_probe()

Gaosheng Cui <cuigaosheng1@huawei.com>
    rtc: st-lpc: Add missing clk_disable_unprepare in st_rtc_probe()

Qingfang DENG <dqfext@gmail.com>
    netfilter: flowtable: really fix NAT IPv6 offload

Yang Yingliang <yangyingliang@huawei.com>
    mfd: pm8008: Fix return value check in pm8008_probe()

Christophe JAILLET <christophe.jaillet@wanadoo.fr>
    mfd: qcom_rpm: Fix an error handling path in qcom_rpm_probe()

Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>
    mfd: bd957x: Fix Kconfig dependency on REGMAP_IRQ

Samuel Holland <samuel@sholland.org>
    mfd: axp20x: Do not sleep in the power off handler

Bryan O'Donoghue <bryan.odonoghue@linaro.org>
    dt-bindings: mfd: qcom,spmi-pmic: Drop PWM reg dependency

Nathan Lynch <nathanl@linux.ibm.com>
    powerpc/pseries/eeh: use correct API for error log size

Shang XiaoJing <shangxiaojing@huawei.com>
    remoteproc: qcom: q6v5: Fix missing clk_disable_unprepare() in q6v5_wcss_qcs404_power_on()

Yuan Can <yuancan@huawei.com>
    remoteproc: qcom_q6v5_pas: Fix missing of_node_put() in adsp_alloc_memory_region()

Luca Weiss <luca.weiss@fairphone.com>
    remoteproc: qcom_q6v5_pas: detach power domains on remove

Luca Weiss <luca.weiss@fairphone.com>
    remoteproc: qcom_q6v5_pas: disable wakeup on probe fail or remove

Shang XiaoJing <shangxiaojing@huawei.com>
    remoteproc: qcom: q6v5: Fix potential null-ptr-deref in q6v5_wcss_init_mmio()

Gaosheng Cui <cuigaosheng1@huawei.com>
    remoteproc: sysmon: fix memory leak in qcom_add_sysmon_subdev()

Anup Patel <apatel@ventanamicro.com>
    RISC-V: KVM: Fix reg_val check in kvm_riscv_vcpu_set_reg_config()

Daniel Golle <daniel@makrotopia.org>
    pwm: mediatek: always use bus clock for PWM on MT7622

xinlei lee <xinlei.lee@mediatek.com>
    pwm: mtk-disp: Fix the parameters calculated by the enabled flag of disp_pwm

Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
    pwm: sifive: Call pwm_sifive_update_clock() while mutex is held

Jason Gunthorpe <jgg@ziepe.ca>
    iommu/sun50i: Remove IOMMU_DOMAIN_IDENTITY

Guenter Roeck <groeck@chromium.org>
    iommu/mediatek: Validate number of phandles associated with "mediatek,larbs"

Yong Wu <yong.wu@mediatek.com>
    iommu/mediatek: Add error path for loop of mm_dts_parse

Yong Wu <yong.wu@mediatek.com>
    iommu/mediatek: Use component_match_add

Yong Wu <yong.wu@mediatek.com>
    iommu/mediatek: Add platform_device_put for recovering the device refcnt

Miaoqian Lin <linmq006@gmail.com>
    selftests/powerpc: Fix resource leaks

Kajol Jain <kjain@linux.ibm.com>
    powerpc/hv-gpci: Fix hv_gpci event list

Yang Yingliang <yangyingliang@huawei.com>
    powerpc/83xx/mpc832x_rdb: call platform_device_put() in error case in of_fsl_spi_probe()

Nicholas Piggin <npiggin@gmail.com>
    powerpc/perf: callchain validate kernel stack pointer bounds

Pali Rohár <pali@kernel.org>
    powerpc: dts: turris1x.dts: Add channel labels for temperature sensor

Li Huafei <lihuafei1@huawei.com>
    kprobes: Fix check for probe enabled in kill_kprobe()

Nayna Jain <nayna@linux.ibm.com>
    powerpc/pseries: fix plpks_read_var() code for different consumers

Nayna Jain <nayna@linux.ibm.com>
    powerpc/pseries: Return -EIO instead of -EINTR for H_ABORTED error

Nayna Jain <nayna@linux.ibm.com>
    powerpc/pseries: Fix the H_CALL error code in PLPKS driver

Nayna Jain <nayna@linux.ibm.com>
    powerpc/pseries: fix the object owners enum value in plpks driver

Yang Yingliang <yangyingliang@huawei.com>
    powerpc/xive: add missing iounmap() in error path in xive_spapr_populate_irq_data()

Gustavo A. R. Silva <gustavoars@kernel.org>
    powerpc/xmon: Fix -Wswitch-unreachable warning in bpt_cmds

Miaoqian Lin <linmq006@gmail.com>
    cxl: Fix refcount leak in cxl_calc_capp_routing

Christophe JAILLET <christophe.jaillet@wanadoo.fr>
    powerpc/52xx: Fix a resource leak in an error handling path

Xie Shaowen <studentxswpy@163.com>
    macintosh/macio-adb: check the return value of ioremap()

Yang Yingliang <yangyingliang@huawei.com>
    macintosh: fix possible memory leak in macio_add_one_device()

Yuan Can <yuancan@huawei.com>
    iommu/fsl_pamu: Fix resource leak in fsl_pamu_probe()

Yang Yingliang <yangyingliang@huawei.com>
    iommu/amd: Fix pci device refcount leak in ppr_notifier()

Yang Yingliang <yangyingliang@huawei.com>
    iommu/mediatek: Check return value after calling platform_get_resource()

Alexander Stein <alexander.stein@ew.tq-group.com>
    rtc: pcf85063: Fix reading alarm

Stefan Eichenberger <stefan.eichenberger@toradex.com>
    rtc: snvs: Allow a time difference on clock register read

Rafael J. Wysocki <rafael.j.wysocki@intel.com>
    rtc: cmos: Disable ACPI RTC event on removal

Rafael J. Wysocki <rafael.j.wysocki@intel.com>
    rtc: cmos: Rename ACPI-related functions

Rafael J. Wysocki <rafael.j.wysocki@intel.com>
    rtc: cmos: Eliminate forward declarations of some functions

Rafael J. Wysocki <rafael.j.wysocki@intel.com>
    rtc: cmos: Call rtc_wake_setup() from cmos_do_probe()

Rafael J. Wysocki <rafael.j.wysocki@intel.com>
    rtc: cmos: Call cmos_wake_setup() from cmos_do_probe()

Shang XiaoJing <shangxiaojing@huawei.com>
    rtc: class: Fix potential memleak in devm_rtc_allocate_device()

Yushan Zhou <katrinzhou@tencent.com>
    rtc: rzn1: Check return value in rzn1_rtc_probe

Fenghua Yu <fenghua.yu@intel.com>
    dmaengine: idxd: Fix crc_val field for completion record

Abdun Nihaal <abdun.nihaal@gmail.com>
    fs/ntfs3: Fix slab-out-of-bounds read in ntfs_trim_fs

Manivannan Sadhasivam <mani@kernel.org>
    phy: qcom-qmp-pcie: Fix sm8450_qmp_gen4x2_pcie_pcs_tbl[] register names

Jon Hunter <jonathanh@nvidia.com>
    pwm: tegra: Ensure the clock rate is not less than needed

Jon Hunter <jonathanh@nvidia.com>
    pwm: tegra: Improve required rate calculation

Matt Redfearn <matt.redfearn@mips.com>
    include/uapi/linux/swab: Fix potentially missing __always_inline

Justin Chen <justinpopo6@gmail.com>
    phy: usb: Fix clock imbalance for suspend/resume

Justin Chen <justinpopo6@gmail.com>
    phy: usb: Use slow clock for wake enabled suspend

Al Cooper <alcooperx@gmail.com>
    phy: usb: s2 WoL wakeup_count not incremented for USB->Eth devices

Michael Riesch <michael.riesch@wolfvision.net>
    iommu/rockchip: fix permission bits in page table entries v2

Jernej Skrabec <jernej.skrabec@gmail.com>
    iommu/sun50i: Implement .iotlb_sync_map

Jernej Skrabec <jernej.skrabec@gmail.com>
    iommu/sun50i: Fix flush size

Jernej Skrabec <jernej.skrabec@gmail.com>
    iommu/sun50i: Fix R/W permission check

Jernej Skrabec <jernej.skrabec@gmail.com>
    iommu/sun50i: Consider all fault sources for reset

Jernej Skrabec <jernej.skrabec@gmail.com>
    iommu/sun50i: Fix reset release

Niklas Schnelle <schnelle@linux.ibm.com>
    iommu/s390: Fix duplicate domain attachments

Johan Hovold <johan+linaro@kernel.org>
    phy: qcom-qmp-pcie: fix ipq8074-gen3 initialisation

Martin Povišer <povik+lin@cutebit.org>
    dmaengine: apple-admac: Allocate cache SRAM to channels

Martin Povišer <povik+lin@cutebit.org>
    dmaengine: apple-admac: Do not use devres for IRQs

Johan Hovold <johan+linaro@kernel.org>
    phy: qcom-qmp-pcie: drop bogus register update

Pali Rohár <pali@kernel.org>
    phy: marvell: phy-mvebu-a3700-comphy: Reset COMPHY registers before USB 3.0 power on

Dan Carpenter <dan.carpenter@oracle.com>
    fs/ntfs3: Harden against integer overflows

Shigeru Yoshida <syoshida@redhat.com>
    fs/ntfs3: Avoid UBSAN error on true_sectors_per_clst()

Arnd Bergmann <arnd@arndb.de>
    RDMA/siw: Fix pointer cast warning

Namhyung Kim <namhyung@kernel.org>
    perf stat: Do not delay the workload with --delay

Ard Biesheuvel <ardb@kernel.org>
    ftrace: Allow WITH_ARGS flavour of graph tracer with shadow call stack

Namhyung Kim <namhyung@kernel.org>
    perf off_cpu: Fix a typo in BTF tracepoint name, it should be 'btf_trace_sched_switch'

Luca Weiss <luca@z3ntu.xyz>
    leds: is31fl319x: Fix setting current limit for is31fl319{0,1,3}

ruanjinjie <ruanjinjie@huawei.com>
    power: supply: fix null pointer dereferencing in power_supply_get_battery_info

Hans de Goede <hdegoede@redhat.com>
    power: supply: bq25890: Ensure pump_express_work is cancelled on remove

Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
    power: supply: bq25890: Convert to i2c's .probe_new()

Marek Vasut <marex@denx.de>
    power: supply: bq25890: Factor out regulator registration code

Yuan Can <yuancan@huawei.com>
    power: supply: ab8500: Fix error handling in ab8500_charger_init()

Yuan Can <yuancan@huawei.com>
    HSI: omap_ssi_core: Fix error handling in ssi_init()

Shang XiaoJing <shangxiaojing@huawei.com>
    power: supply: cw2015: Fix potential null-ptr-deref in cw_bat_probe()

Zheyu Ma <zheyuma97@gmail.com>
    power: supply: cw2015: Use device managed API to simplify the code

Zhang Qilong <zhangqilong3@huawei.com>
    power: supply: z2_battery: Fix possible memleak in z2_batt_probe()

Ajay Kaher <akaher@vmware.com>
    perf symbol: correction while adjusting symbol

Leo Yan <leo.yan@linaro.org>
    perf trace: Handle failure when trace point folder is missed

Leo Yan <leo.yan@linaro.org>
    perf trace: Use macro RAW_SYSCALL_ARGS_NUM to replace number

Leo Yan <leo.yan@linaro.org>
    perf trace: Return error if a system call doesn't exist

Mika Westerberg <mika.westerberg@linux.intel.com>
    watchdog: iTCO_wdt: Set NO_REBOOT if the watchdog is not already running

Zeng Heng <zengheng4@huawei.com>
    power: supply: fix residue sysfs file in error handle route of __power_supply_register()

Yang Yingliang <yangyingliang@huawei.com>
    HSI: omap_ssi_core: fix possible memory leak in ssi_probe()

Yang Yingliang <yangyingliang@huawei.com>
    HSI: omap_ssi_core: fix unbalanced pm_runtime_disable()

Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
    led: qcom-lpg: Fix sleeping in atomic

Christophe JAILLET <christophe.jaillet@wanadoo.fr>
    fbdev: uvesafb: Fixes an error handling path in uvesafb_probe()

Randy Dunlap <rdunlap@infradead.org>
    fbdev: uvesafb: don't build on UML

Randy Dunlap <rdunlap@infradead.org>
    fbdev: geode: don't build on UML

Gaosheng Cui <cuigaosheng1@huawei.com>
    fbdev: ep93xx-fb: Add missing clk_disable_unprepare in ep93xxfb_probe()

Xiongfeng Wang <wangxiongfeng2@huawei.com>
    fbdev: vermilion: decrease reference count in error path

Shang XiaoJing <shangxiaojing@huawei.com>
    fbdev: via: Fix error in via_core_init()

Yang Yingliang <yangyingliang@huawei.com>
    fbdev: pm2fb: fix missing pci_disable_device()

Andy Shevchenko <andriy.shevchenko@linux.intel.com>
    fbdev: ssd1307fb: Drop optional dependency

Bjorn Andersson <andersson@kernel.org>
    thermal/drivers/qcom/lmh: Fix irq handler return value

Luca Weiss <luca.weiss@fairphone.com>
    thermal/drivers/qcom/temp-alarm: Fix inaccurate warning for gen2

Keerthy <j-keerthy@ti.com>
    thermal/drivers/k3_j72xx_bandgap: Fix the debug print message

Marcus Folkesson <marcus.folkesson@gmail.com>
    thermal/drivers/imx8mm_thermal: Validate temperature range

Shang XiaoJing <shangxiaojing@huawei.com>
    samples: vfio-mdev: Fix missing pci_disable_device() in mdpy_fb_probe()

Xiu Jianfeng <xiujianfeng@huawei.com>
    ksmbd: Fix resource leak in ksmbd_session_rpc_open()

Zheng Yejian <zhengyejian1@huawei.com>
    tracing/hist: Fix issue of losting command info in error_log

Yang Yingliang <yangyingliang@huawei.com>
    usb: typec: wusb3801: fix fwnode refcount leak in wusb3801_probe()

Jiasheng Jiang <jiasheng@iscas.ac.cn>
    usb: storage: Add check for kcalloc

Zheyu Ma <zheyuma97@gmail.com>
    i2c: ismt: Fix an out-of-bounds bug in ismt_access()

Yang Yingliang <yangyingliang@huawei.com>
    i2c: mux: reg: check return value after calling platform_get_resource()

Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
    gpiolib: protect the GPIO device against being dropped while in use by user-space

Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
    gpiolib: cdev: fix NULL-pointer dereferences

Chen Zhongjin <chenzhongjin@huawei.com>
    vme: Fix error not catched in fake_init()

YueHaibing <yuehaibing@huawei.com>
    staging: rtl8192e: Fix potential use-after-free in rtllib_rx_Monitor()

Dan Carpenter <error27@gmail.com>
    staging: rtl8192u: Fix use after free in ieee80211_rx()

Hui Tang <tanghui20@huawei.com>
    i2c: pxa-pci: fix missing pci_disable_device() on error in ce4100_i2c_probe

Yang Yingliang <yangyingliang@huawei.com>
    chardev: fix error handling in cdev_device_add()

Yang Yingliang <yangyingliang@huawei.com>
    mcb: mcb-parse: fix error handing in chameleon_parse_gdd()

Zhengchao Shao <shaozhengchao@huawei.com>
    drivers: mcb: fix resource leak in mcb_probe()

John Keeping <john@metanate.com>
    usb: gadget: f_hid: fix refcount leak on error path

John Keeping <john@metanate.com>
    usb: gadget: f_hid: fix f_hidg lifetime vs cdev

Yang Yingliang <yangyingliang@huawei.com>
    usb: core: hcd: Fix return value check in usb_hcd_setup_local_mem()

Yang Yingliang <yangyingliang@huawei.com>
    usb: roles: fix of node refcount leak in usb_role_switch_is_parent()

Beau Belgrave <beaub@linux.microsoft.com>
    tracing/user_events: Fix call print_fmt leak

Yang Shen <shenyang39@huawei.com>
    coresight: trbe: remove cpuhp instance node before remove cpuhp state

Fabrice Gasnier <fabrice.gasnier@foss.st.com>
    counter: stm32-lptimer-cnt: fix the check on arr and cmp registers update

Ramona Bolboaca <ramona.bolboaca@analog.com>
    iio: adis: add '__adis_enable_irq()' implementation

Cosmin Tanislav <cosmin.tanislav@analog.com>
    iio: temperature: ltc2983: make bulk write buffer DMA-safe

Yang Yingliang <yangyingliang@huawei.com>
    cxl: fix possible null-ptr-deref in cxl_pci_init_afu|adapter()

Yang Yingliang <yangyingliang@huawei.com>
    cxl: fix possible null-ptr-deref in cxl_guest_init_afu|adapter()

Yang Yingliang <yangyingliang@huawei.com>
    firmware: raspberrypi: fix possible memory leak in rpi_firmware_probe()

Zheng Wang <zyytlz.wz@163.com>
    misc: sgi-gru: fix use-after-free error in gru_set_context_option, gru_fault and gru_handle_user_call_os

ruanjinjie <ruanjinjie@huawei.com>
    misc: tifm: fix possible memory leak in tifm_7xx1_switch_media()

Yang Yingliang <yangyingliang@huawei.com>
    ocxl: fix pci device refcount leak when calling get_function_0()

Yang Yingliang <yangyingliang@huawei.com>
    misc: ocxl: fix possible name leak in ocxl_file_register_afu()

Zhengchao Shao <shaozhengchao@huawei.com>
    test_firmware: fix memory leak in test_firmware_init()

Yuan Can <yuancan@huawei.com>
    serial: sunsab: Fix error handling in sunsab_init()

Gabriel Somlo <gsomlo@gmail.com>
    serial: altera_uart: fix locking in polling mode

Jiri Slaby <jirislaby@kernel.org>
    tty: serial: altera_uart_{r,t}x_chars() need only uart_port

Jiri Slaby <jirislaby@kernel.org>
    tty: serial: clean up stop-tx part in altera_uart_tx_chars()

Xiongfeng Wang <wangxiongfeng2@huawei.com>
    serial: pch: Fix PCI device refcount leak in pch_request_dma()

Valentin Caron <valentin.caron@foss.st.com>
    serial: stm32: move dma_request_chan() before clk_prepare_enable()

delisun <delisun@pateo.com.cn>
    serial: pl011: Do not clear RX FIFO & RX interrupt in unthrottle.

Jiamei Xie <jiamei.xie@arm.com>
    serial: amba-pl011: avoid SBSA UART accessing DMACR register

Jiantao Zhang <water.zhangjiantao@huawei.com>
    USB: gadget: Fix use-after-free during usb config switch

Marek Vasut <marex@denx.de>
    extcon: usbc-tusb320: Update state on probe even if no IRQ pending

Marek Vasut <marex@denx.de>
    extcon: usbc-tusb320: Add USB TYPE-C support

Marek Vasut <marex@denx.de>
    extcon: usbc-tusb320: Factor out extcon into dedicated functions

Tony Lindgren <tony@atomide.com>
    usb: musb: omap2430: Fix probe regression for missing resources

Sven Peter <sven@svenpeter.dev>
    usb: typec: tipd: Fix typec_unregister_port error paths

Sven Peter <sven@svenpeter.dev>
    usb: typec: tipd: Fix spurious fwnode_handle_put in error path

Sven Peter <sven@svenpeter.dev>
    usb: typec: tipd: Cleanup resources if devm_tps6598_psy_register fails

Yang Yingliang <yangyingliang@huawei.com>
    usb: typec: tcpci: fix of node refcount leak in tcpci_register_port()

Sven Peter <sven@svenpeter.dev>
    usb: typec: Check for ops->exit instead of ops->enter in altmode_exit

Gaosheng Cui <cuigaosheng1@huawei.com>
    staging: vme_user: Fix possible UAF in tsi148_dma_list_add

Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
    interconnect: qcom: sc7180: fix dropped const of qcom_icc_bcm

Linus Walleij <linus.walleij@linaro.org>
    usb: fotg210-udc: Fix ages old endianness issues

Rafael Mendonca <rafaelmendsr@gmail.com>
    uio: uio_dmem_genirq: Fix deadlock between irq config and handling

Rafael Mendonca <rafaelmendsr@gmail.com>
    uio: uio_dmem_genirq: Fix missing unlock in irq configuration

Rafael Mendonca <rafaelmendsr@gmail.com>
    vfio: platform: Do not pass return buffer to ACPI _RST method

Yang Yingliang <yangyingliang@huawei.com>
    class: fix possible memory leak in __class_register()

Duoming Zhou <duoming@zju.edu.cn>
    drivers: staging: r8188eu: Fix sleep-in-atomic-context bug in rtw_join_timeout_handler

Yuan Can <yuancan@huawei.com>
    serial: 8250_bcm7271: Fix error handling in brcmuart_init()

Kartik <kkartik@nvidia.com>
    serial: tegra: Read DMA status before terminating

Yang Yingliang <yangyingliang@huawei.com>
    drivers: dio: fix possible memory leak in dio_init()

Alexandre Ghiti <alexghiti@rivosinc.com>
    riscv: Fix P4D_SHIFT definition for 3-level page table mode

Yangtao Li <frank.li@vivo.com>
    f2fs: fix iostat parameter for discard

Palmer Dabbelt <palmer@rivosinc.com>
    RISC-V: Align the shadow stack

Dragos Tatulea <dtatulea@nvidia.com>
    IB/IPoIB: Fix queue count inconsistency for PKEY child interfaces

Xiongfeng Wang <wangxiongfeng2@huawei.com>
    hwrng: geode - Fix PCI device refcount leak

Xiongfeng Wang <wangxiongfeng2@huawei.com>
    hwrng: amd - Fix PCI device refcount leak

Gaosheng Cui <cuigaosheng1@huawei.com>
    crypto: img-hash - Fix variable dereferenced before check 'hdev->req'

Samuel Holland <samuel@sholland.org>
    riscv: Fix crash during early errata patching

Anup Patel <apatel@ventanamicro.com>
    RISC-V: Fix MEMREMAP_WB for systems with Svpbmt

Andrew Bresticker <abrestic@rivosinc.com>
    RISC-V: Fix unannoted hardirqs-on in return to userspace slow-path

Chengchang Tang <tangchengchang@huawei.com>
    RDMA/hns: Fix XRC caps on HIP08

Chengchang Tang <tangchengchang@huawei.com>
    RDMA/hns: Fix error code of CMD

Chengchang Tang <tangchengchang@huawei.com>
    RDMA/hns: Fix page size cap from firmware

Chengchang Tang <tangchengchang@huawei.com>
    RDMA/hns: Fix PBL page MTR find

Chengchang Tang <tangchengchang@huawei.com>
    RDMA/hns: Fix AH attr queried by query_qp

Yixing Liu <liuyixing1@huawei.com>
    RDMA/hns: Fix the gid problem caused by free mr

Wenpeng Liang <liangwenpeng@huawei.com>
    RDMA/hns: Remove redundant DFX file and DFX ops structure

Zhang Xiaoxu <zhangxiaoxu5@huawei.com>
    orangefs: Fix sysfs not cleanup when dev init failed

Francisco Munoz <francisco.munoz.ruiz@linux.intel.com>
    PCI: vmd: Fix secondary bus reset for Intel bridges

Wang Yufen <wangyufen@huawei.com>
    RDMA/srp: Fix error return code in srp_parse_options()

Wang Yufen <wangyufen@huawei.com>
    RDMA/hfi1: Fix error return code in parse_platform_config()

Randy Dunlap <rdunlap@infradead.org>
    RDMA: Disable IB HW for UML

Tong Tiangen <tongtiangen@huawei.com>
    riscv/mm: add arch hook arch_clear_hugepage_flags

Shang XiaoJing <shangxiaojing@huawei.com>
    crypto: omap-sham - Use pm_runtime_resume_and_get() in omap_sham_probe()

Christophe JAILLET <christophe.jaillet@wanadoo.fr>
    crypto: amlogic - Remove kcalloc without check

Wang Yufen <wangyufen@huawei.com>
    crypto: qat - fix error return code in adf_probe

Mark Zhang <markzhang@nvidia.com>
    RDMA/nldev: Fix failure to send large messages

Yonggil Song <yonggil.song@samsung.com>
    f2fs: avoid victim selection from previous victim section

Sheng Yong <shengyong@oppo.com>
    f2fs: fix to enable compress for newly created file if extension matches

Sheng Yong <shengyong@oppo.com>
    f2fs: set zstd compress level correctly

Yuan Can <yuancan@huawei.com>
    RDMA/nldev: Add checks for nla_nest_start() in fill_stat_counter_qps()

Bart Van Assche <bvanassche@acm.org>
    scsi: ufs: core: Fix the polling implementation

Jie Zhan <zhanjie9@hisilicon.com>
    scsi: hisi_sas: Fix SATA devices missing issue during I_T nexus reset

Jie Zhan <zhanjie9@hisilicon.com>
    scsi: libsas: Add smp_ata_check_ready_type()

Gaosheng Cui <cuigaosheng1@huawei.com>
    scsi: snic: Fix possible UAF in snic_tgt_create()

Chen Zhongjin <chenzhongjin@huawei.com>
    scsi: fcoe: Fix transport not deattached when fcoe_if_init() fails

Shang XiaoJing <shangxiaojing@huawei.com>
    scsi: ipr: Fix WARNING in ipr_init()

Yang Yingliang <yangyingliang@huawei.com>
    scsi: scsi_debug: Fix possible name leak in sdebug_add_host_helper()

Yang Yingliang <yangyingliang@huawei.com>
    scsi: fcoe: Fix possible name leak when device_register() fails

Harshit Mogalapalli <harshit.m.mogalapalli@oracle.com>
    scsi: scsi_debug: Fix a warning in resp_report_zones()

Harshit Mogalapalli <harshit.m.mogalapalli@oracle.com>
    scsi: scsi_debug: Fix a warning in resp_verify()

Chen Zhongjin <chenzhongjin@huawei.com>
    scsi: efct: Fix possible memleak in efct_device_init()

Yang Yingliang <yangyingliang@huawei.com>
    scsi: hpsa: Fix possible memory leak in hpsa_add_sas_device()

Yang Yingliang <yangyingliang@huawei.com>
    scsi: hpsa: Fix error handling in hpsa_add_sas_host()

Yang Yingliang <yangyingliang@huawei.com>
    scsi: mpt3sas: Fix possible resource leaks in mpt3sas_transport_port_add()

Daniel Jordan <daniel.m.jordan@oracle.com>
    padata: Fix list iterator in padata_do_serial()

Daniel Jordan <daniel.m.jordan@oracle.com>
    padata: Always leave BHs disabled when running ->parallel()

Zhang Yiqun <zhangyiqun@phytium.com.cn>
    crypto: tcrypt - Fix multibuffer skcipher speed test mem leak

Yuan Can <yuancan@huawei.com>
    scsi: hpsa: Fix possible memory leak in hpsa_init_one()

Frank Li <frank.li@nxp.com>
    PCI: endpoint: pci-epf-vntb: Fix call pci_epc_mem_free_addr() in error path

Serge Semin <Sergey.Semin@baikalelectronics.ru>
    dt-bindings: visconti-pcie: Fix interrupts array max constraints

Serge Semin <Sergey.Semin@baikalelectronics.ru>
    dt-bindings: imx6q-pcie: Fix clock names for imx6sx and imx8mq

Zhang Xiaoxu <zhangxiaoxu5@huawei.com>
    RDMA/rxe: Fix NULL-ptr-deref in rxe_qp_do_cleanup() when socket create failed

Zhengchao Shao <shaozhengchao@huawei.com>
    RDMA/hns: fix memory leak in hns_roce_alloc_mr()

Mustafa Ismail <mustafa.ismail@intel.com>
    RDMA/irdma: Initialize net_type before checking it

Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
    crypto: ccree - Make cc_debugfs_global_fini() available for module init function

Xiongfeng Wang <wangxiongfeng2@huawei.com>
    RDMA/hfi: Decrease PCI device reference count in error path

Zeng Heng <zengheng4@huawei.com>
    PCI: Check for alloc failure in pci_request_irq()

Luoyouming <luoyouming@huawei.com>
    RDMA/hns: Fix incorrect sge nums calculation

Luoyouming <luoyouming@huawei.com>
    RDMA/hns: Fix ext_sge num error when post send

Luoyouming <luoyouming@huawei.com>
    RDMA/hns: Repacing 'dseg_len' by macros in fill_ext_sge_inl_data()

Li Zhijian <lizhijian@fujitsu.com>
    RDMA/rxe: Fix mr->map double free

Xiongfeng Wang <wangxiongfeng2@huawei.com>
    crypto: hisilicon/qm - add missing pci_dev_put() in q_num_set()

Herbert Xu <herbert@gondor.apana.org.au>
    crypto: cryptd - Use request context instead of stack for sub-request

Gaosheng Cui <cuigaosheng1@huawei.com>
    crypto: ccree - Remove debugfs when platform_driver_register failed

Harshit Mogalapalli <harshit.m.mogalapalli@oracle.com>
    scsi: scsi_debug: Fix a warning in resp_write_scat()

Mustafa Ismail <mustafa.ismail@intel.com>
    RDMA/irdma: Do not request 2-level PBLEs for CQ alloc

Mustafa Ismail <mustafa.ismail@intel.com>
    RDMA/irdma: Fix RQ completion opcode

Mustafa Ismail <mustafa.ismail@intel.com>
    RDMA/irdma: Fix inline for multiple SGE's

Bernard Metzler <bmt@zurich.ibm.com>
    RDMA/siw: Set defined status for work completion with undefined status

Mark Zhang <markzhang@nvidia.com>
    RDMA/nldev: Return "-EAGAIN" if the cm_id isn't from expected port

Mark Zhang <markzhang@nvidia.com>
    RDMA/core: Make sure "ib_port" is valid when access sysfs node

Mark Zhang <markzhang@nvidia.com>
    RDMA/restrack: Release MR restrack when delete

Sascha Hauer <s.hauer@pengutronix.de>
    PCI: imx6: Initialize PHY before deasserting core reset

Nirmal Patel <nirmal.patel@linux.intel.com>
    PCI: vmd: Disable MSI remapping after suspend

Leonid Ravich <lravich@gmail.com>
    IB/mad: Don't call to function that might sleep while in atomic context

Bernard Metzler <bmt@zurich.ibm.com>
    RDMA/siw: Fix immediate work request flush to completion queue

Bart Van Assche <bvanassche@acm.org>
    scsi: qla2xxx: Fix set-but-not-used variable warnings

Shiraz Saleem <shiraz.saleem@intel.com>
    RDMA/irdma: Report the correct link speed

Chao Yu <chao@kernel.org>
    f2fs: fix to destroy sbi->post_read_wq in error path of f2fs_fill_super()

Mukesh Ojha <quic_mojha@quicinc.com>
    f2fs: fix the assign logic of iocb

Jaegeuk Kim <jaegeuk@kernel.org>
    f2fs: allow to set compression for inlined file

Dongdong Zhang <zhangdongdong1@oppo.com>
    f2fs: fix normal discard process

Chao Yu <chao@kernel.org>
    f2fs: fix to invalidate dcc->f2fs_issue_discard in error path

Kees Cook <keescook@chromium.org>
    fortify: Do not cast to "unsigned char"

Kees Cook <keescook@chromium.org>
    fortify: Use SIZE_MAX instead of (size_t)-1

Xiu Jianfeng <xiujianfeng@huawei.com>
    apparmor: Fix memleak in alloc_ns()

Corentin Labbe <clabbe@baylibre.com>
    crypto: rockchip - rework by using crypto_engine

Corentin Labbe <clabbe@baylibre.com>
    crypto: rockchip - remove non-aligned handling

Corentin Labbe <clabbe@baylibre.com>
    crypto: rockchip - better handle cipher key

Corentin Labbe <clabbe@baylibre.com>
    crypto: rockchip - add fallback for ahash

Corentin Labbe <clabbe@baylibre.com>
    crypto: rockchip - add fallback for cipher

Corentin Labbe <clabbe@baylibre.com>
    crypto: rockchip - do not store mode globally

Corentin Labbe <clabbe@baylibre.com>
    crypto: rockchip - do not do custom power management

Zhang Qilong <zhangqilong3@huawei.com>
    f2fs: Fix the race condition of resize flag between resizefs

Kunihiko Hayashi <hayashi.kunihiko@socionext.com>
    PCI: pci-epf-test: Register notifier if only core_init_notifier is enabled

Leon Romanovsky <leon@kernel.org>
    RDMA/core: Fix order of nldev_exit call

Vidya Sagar <vidyas@nvidia.com>
    PCI: dwc: Fix n_fts[] array overrun

Xiu Jianfeng <xiujianfeng@huawei.com>
    apparmor: Use pointer to struct aa_label for lbs_cred

Bart Van Assche <bvanassche@acm.org>
    scsi: core: Fix a race between scsi_done() and scsi_timeout()

Robert Elliott <elliott@hpe.com>
    crypto: tcrypt - fix return value for multiple subtests

Natalia Petrova <n.petrova@fintech.ru>
    crypto: nitrox - avoid double free on error path in nitrox_sriov_init()

Corentin Labbe <clabbe@baylibre.com>
    crypto: sun8i-ss - use dma_addr instead u32

Weili Qian <qianweili@huawei.com>
    crypto: hisilicon/qm - re-enable communicate interrupt before notifying PF

Weili Qian <qianweili@huawei.com>
    crypto: hisilicon/qm - get hardware features from hardware registers

Weili Qian <qianweili@huawei.com>
    crypto: hisilicon/qm - fix missing destroy qp_idr

John Johansen <john.johansen@canonical.com>
    apparmor: Fix regression in stacking due to label flags

John Johansen <john.johansen@canonical.com>
    apparmor: Fix abi check to include v8 abi

John Johansen <john.johansen@canonical.com>
    apparmor: fix lockdep warning when removing a namespace

Gaosheng Cui <cuigaosheng1@huawei.com>
    apparmor: fix a memleak in multi_transaction_new()

Vladimir Oltean <vladimir.oltean@nxp.com>
    net: dsa: tag_8021q: avoid leaking ctx on dsa_tag_8021q_register() error path

Bartosz Staszewski <bartoszx.staszewski@intel.com>
    i40e: Fix the inability to attach XDP program on downed interface

Piergiorgio Beruto <piergiorgio.beruto@gmail.com>
    stmmac: fix potential division by 0

Yang Yingliang <yangyingliang@huawei.com>
    Bluetooth: RFCOMM: don't call kfree_skb() under spin_lock_irqsave()

Yang Yingliang <yangyingliang@huawei.com>
    Bluetooth: hci_core: don't call kfree_skb() under spin_lock_irqsave()

Yang Yingliang <yangyingliang@huawei.com>
    Bluetooth: hci_bcsp: don't call kfree_skb() under spin_lock_irqsave()

Yang Yingliang <yangyingliang@huawei.com>
    Bluetooth: hci_h5: don't call kfree_skb() under spin_lock_irqsave()

Yang Yingliang <yangyingliang@huawei.com>
    Bluetooth: hci_ll: don't call kfree_skb() under spin_lock_irqsave()

Yang Yingliang <yangyingliang@huawei.com>
    Bluetooth: hci_qca: don't call kfree_skb() under spin_lock_irqsave()

Yang Yingliang <yangyingliang@huawei.com>
    Bluetooth: btusb: don't call kfree_skb() under spin_lock_irqsave()

Wang ShaoBo <bobo.shaobowang@huawei.com>
    Bluetooth: btintel: Fix missing free skb in btintel_setup_combined()

Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
    Bluetooth: hci_conn: Fix crash on hci_create_cis_sync

Christophe JAILLET <christophe.jaillet@wanadoo.fr>
    Bluetooth: Fix EALREADY and ELOOP cases in bt_status()

Inga Stotland <inga.stotland@intel.com>
    Bluetooth: MGMT: Fix error report for ADD_EXT_ADV_PARAMS

Yang Yingliang <yangyingliang@huawei.com>
    Bluetooth: hci_core: fix error handling in hci_register_dev()

Firo Yang <firo.yang@suse.com>
    sctp: sysctl: make extra pointers netns aware

Eric Pilmore <epilmore@gigaio.com>
    ntb_netdev: Use dev_kfree_skb_any() in interrupt context

Jerry Ray <jerry.ray@microchip.com>
    net: lan9303: Fix read error execution path

Roger Quadros <rogerq@kernel.org>
    net: ethernet: ti: am65-cpsw: Fix PM runtime leakage in am65_cpsw_nuss_ndo_slave_open()

Markus Schneider-Pargmann <msp@baylibre.com>
    can: tcan4x5x: Fix use of register error status mask

Vivek Yadav <vivek.2311@samsung.com>
    can: m_can: Call the RAM init directly from m_can_chip_config

Markus Schneider-Pargmann <msp@baylibre.com>
    can: tcan4x5x: Remove invalid write in clear_interrupts

Tom Lendacky <thomas.lendacky@amd.com>
    net: amd-xgbe: Check only the minimum speed for active/passive cables

Tom Lendacky <thomas.lendacky@amd.com>
    net: amd-xgbe: Fix logic around active and passive cables

Yang Yingliang <yangyingliang@huawei.com>
    af_unix: call proto_unregister() in the error path in af_unix_init()

Richard Gobert <richardbgobert@gmail.com>
    net: setsockopt: fix IPV6_UNICAST_IF option for connected sockets

Yang Yingliang <yangyingliang@huawei.com>
    net: amd: lance: don't call dev_kfree_skb() under spin_lock_irqsave()

Yang Yingliang <yangyingliang@huawei.com>
    hamradio: don't call dev_kfree_skb() under spin_lock_irqsave()

Yang Yingliang <yangyingliang@huawei.com>
    net: ethernet: dnet: don't call dev_kfree_skb() under spin_lock_irqsave()

Yang Yingliang <yangyingliang@huawei.com>
    net: emaclite: don't call dev_kfree_skb() under spin_lock_irqsave()

Yang Yingliang <yangyingliang@huawei.com>
    net: apple: bmac: don't call dev_kfree_skb() under spin_lock_irqsave()

Yang Yingliang <yangyingliang@huawei.com>
    net: apple: mace: don't call dev_kfree_skb() under spin_lock_irqsave()

Hangbin Liu <liuhangbin@gmail.com>
    net/tunnel: wait until all sk_user_data reader finish before releasing the sock

Li Zetao <lizetao1@huawei.com>
    net: farsync: Fix kmemleak when rmmods farsync

Yang Yingliang <yangyingliang@huawei.com>
    ethernet: s2io: don't call dev_kfree_skb() under spin_lock_irqsave()

ruanjinjie <ruanjinjie@huawei.com>
    of: overlay: fix null pointer dereferencing in find_dup_cset_node_entry() and find_dup_cset_prop()

Julian Anastasov <ja@ssi.bg>
    ipvs: use u64_stats_t for the per-cpu counters

Thomas Gleixner <tglx@linutronix.de>
    net: Remove the obsolte u64_stats_fetch_*_irq() users (net).

Yuan Can <yuancan@huawei.com>
    drivers: net: qlcnic: Fix potential memory leak in qlcnic_sriov_init()

Gaosheng Cui <cuigaosheng1@huawei.com>
    net: stmmac: fix possible memory leak in stmmac_dvr_probe()

Zhang Changzhong <zhangchangzhong@huawei.com>
    net: stmmac: selftests: fix potential memleak in stmmac_test_arpoffload()

Yongqiang Liu <liuyongqiang13@huawei.com>
    net: defxx: Fix missing err handling in dfx_init()

Artem Chernyshev <artem.chernyshev@red-soft.ru>
    net: vmw_vsock: vmci: Check memcpy_from_msg()

Xiu Jianfeng <xiujianfeng@huawei.com>
    clk: socfpga: Fix memory leak in socfpga_gate_init()

Björn Töpel <bjorn@rivosinc.com>
    bpf: Do not zero-extend kfunc return values

Yang Jihong <yangjihong1@huawei.com>
    blktrace: Fix output non-blktrace event when blk_classic option enabled

Wang Yufen <wangyufen@huawei.com>
    wifi: brcmfmac: Fix error return code in brcmf_sdio_download_firmware()

Bitterblue Smith <rtl8821cerfe2@gmail.com>
    wifi: rtl8xxxu: Fix the channel width reporting

Bitterblue Smith <rtl8821cerfe2@gmail.com>
    wifi: rtl8xxxu: Add __packed to struct rtl8723bu_c2h

Kris Bahnsen <kris@embeddedTS.com>
    spi: spi-gpio: Don't set MOSI as an input if not 3WIRE mode

Xiu Jianfeng <xiujianfeng@huawei.com>
    clk: samsung: Fix memory leak in _samsung_clk_register_pll()

Geert Uytterhoeven <geert+renesas@glider.be>
    media: staging: stkwebcam: Restore MEDIA_{USB,CAMERA}_SUPPORT dependencies

Jiasheng Jiang <jiasheng@iscas.ac.cn>
    media: coda: Add check for kmalloc

Jiasheng Jiang <jiasheng@iscas.ac.cn>
    media: coda: Add check for dcoda_iram_alloc

Liang He <windhl@126.com>
    media: c8sectpfe: Add of_node_put() when breaking out of loop

Yuan Can <yuancan@huawei.com>
    regulator: qcom-labibb: Fix missing of_node_put() in qcom_labibb_regulator_probe()

Zhen Lei <thunder.leizhen@huawei.com>
    mmc: core: Normalize the error handling branch in sd_read_ext_regs()

Jiasheng Jiang <jiasheng@iscas.ac.cn>
    memstick/ms_block: Add check for alloc_ordered_workqueue

Wolfram Sang <wsa+renesas@sang-engineering.com>
    mmc: renesas_sdhi: alway populate SCC pointer

Yang Yingliang <yangyingliang@huawei.com>
    mmc: mmci: fix return value check of mmc_add_host()

Yang Yingliang <yangyingliang@huawei.com>
    mmc: wbsd: fix return value check of mmc_add_host()

Yang Yingliang <yangyingliang@huawei.com>
    mmc: via-sdmmc: fix return value check of mmc_add_host()

Yang Yingliang <yangyingliang@huawei.com>
    mmc: meson-gx: fix return value check of mmc_add_host()

Yang Yingliang <yangyingliang@huawei.com>
    mmc: omap_hsmmc: fix return value check of mmc_add_host()

Yang Yingliang <yangyingliang@huawei.com>
    mmc: atmel-mci: fix return value check of mmc_add_host()

Gabriel Somlo <gsomlo@gmail.com>
    mmc: litex_mmc: ensure `host->irq == 0` if polling

Yang Yingliang <yangyingliang@huawei.com>
    mmc: wmt-sdmmc: fix return value check of mmc_add_host()

Yang Yingliang <yangyingliang@huawei.com>
    mmc: vub300: fix return value check of mmc_add_host()

Yang Yingliang <yangyingliang@huawei.com>
    mmc: toshsd: fix return value check of mmc_add_host()

Yang Yingliang <yangyingliang@huawei.com>
    mmc: rtsx_usb_sdmmc: fix return value check of mmc_add_host()

Yang Yingliang <yangyingliang@huawei.com>
    mmc: rtsx_pci: fix return value check of mmc_add_host()

Yang Yingliang <yangyingliang@huawei.com>
    mmc: pxamci: fix return value check of mmc_add_host()

Yang Yingliang <yangyingliang@huawei.com>
    mmc: mxcmmc: fix return value check of mmc_add_host()

Yang Yingliang <yangyingliang@huawei.com>
    mmc: moxart: fix return value check of mmc_add_host()

Yang Yingliang <yangyingliang@huawei.com>
    mmc: alcor: fix return value check of mmc_add_host()

Miaoqian Lin <linmq006@gmail.com>
    bpftool: Fix memory leak in do_build_table_cb

Pu Lehui <pulehui@huawei.com>
    riscv, bpf: Emit fixed-length instructions for BPF_PSEUDO_FUNC

Trond Myklebust <trond.myklebust@hammerspace.com>
    NFSv4.x: Fail client initialisation if state manager thread can't run

Anna Schumaker <Anna.Schumaker@Netapp.com>
    NFS: Allow very small rsize & wsize again

Anna Schumaker <Anna.Schumaker@Netapp.com>
    NFSv4.2: Set the correct size scratch buffer for decoding READ_PLUS

Wang ShaoBo <bobo.shaobowang@huawei.com>
    SUNRPC: Fix missing release socket in rpc_sockname()

Zhang Xiaoxu <zhangxiaoxu5@huawei.com>
    xprtrdma: Fix regbuf data not freed in rpcrdma_req_create()

Gaosheng Cui <cuigaosheng1@huawei.com>
    pinctrl: thunderbay: fix possible memory leak in thunderbay_build_functions()

Gaosheng Cui <cuigaosheng1@huawei.com>
    ALSA: mts64: fix possible null-ptr-defer in snd_mts64_interrupt

Guoniu.zhou <guoniu.zhou@nxp.com>
    media: ov5640: set correct default link frequency

Liu Shixin <liushixin2@huawei.com>
    media: saa7164: fix missing pci_disable_device()

Takashi Iwai <tiwai@suse.de>
    ALSA: pcm: Set missing stop_operating flag at undoing trigger start

Eric Dumazet <edumazet@google.com>
    bpf, sockmap: fix race in sock_map_free()

Martin Blumenstingl <martin.blumenstingl@googlemail.com>
    hwmon: (jc42) Restore the min/max/critical temperatures on resume

Martin Blumenstingl <martin.blumenstingl@googlemail.com>
    hwmon: (jc42) Convert register access and caching to regmap/regcache

Yang Yingliang <yangyingliang@huawei.com>
    regulator: core: fix resource leak in regulator_register()

Chen Zhongjin <chenzhongjin@huawei.com>
    configfs: fix possible memory leak in configfs_create_dir()

Sebastian Andrzej Siewior <bigeasy@linutronix.de>
    hsr: Synchronize sequence number updates.

Sebastian Andrzej Siewior <bigeasy@linutronix.de>
    hsr: Synchronize sending frames to have always incremented outgoing seq nr.

Sebastian Andrzej Siewior <bigeasy@linutronix.de>
    hsr: Disable netpoll.

Sebastian Andrzej Siewior <bigeasy@linutronix.de>
    hsr: Avoid double remove of a node.

Sebastian Andrzej Siewior <bigeasy@linutronix.de>
    hsr: Add a rcu-read lock to hsr_forward_skb().

Sebastian Andrzej Siewior <bigeasy@linutronix.de>
    Revert "net: hsr: use hlist_head instead of list_head for mac addresses"

Christian Marangi <ansuelsmth@gmail.com>
    clk: qcom: clk-krait: fix wrong div2 functions

Douglas Anderson <dianders@chromium.org>
    clk: qcom: lpass-sc7180: Fix pm_runtime usage

Douglas Anderson <dianders@chromium.org>
    clk: qcom: lpass-sc7280: Fix pm_runtime usage

Taniya Das <quic_tdas@quicinc.com>
    clk: qcom: lpass: Add support for resets & external mclk for SC7280

Taniya Das <quic_tdas@quicinc.com>
    clk: qcom: lpass: Handle the regmap overlap of lpasscc and lpass_aon

Taniya Das <quic_tdas@quicinc.com>
    dt-bindings: clock: Add support for external MCLKs for LPASS on SC7280

Taniya Das <quic_tdas@quicinc.com>
    dt-bindings: clock: Add resets for LPASS audio clock controller for SC7280

Yang Yingliang <yangyingliang@huawei.com>
    regulator: core: fix module refcount leak in set_supply()

Xiongfeng Wang <wangxiongfeng2@huawei.com>
    mt76: mt7915: Fix PCI device refcount leak in mt7915_pci_init_hif2()

Deren Wu <deren.wu@mediatek.com>
    wifi: mt76: fix coverity overrun-call in mt76_get_txpower()

Nicolas Cavallari <nicolas.cavallari@green-communications.fr>
    wifi: mt76: mt7915: Fix chainmask calculation on mt7915 DBDC

Shayne Chen <shayne.chen@mediatek.com>
    wifi: mt76: mt7915: rework eeprom tx paths and streams init

Lorenzo Bianconi <lorenzo@kernel.org>
    wifi: mt76: mt7921: fix reporting of TX AGGR histogram

Lorenzo Bianconi <lorenzo@kernel.org>
    wifi: mt76: mt7915: fix reporting of TX AGGR histogram

Ryder Lee <ryder.lee@mediatek.com>
    wifi: mt76: mt7915: fix mt7915_mac_set_timing()

Sean Wang <sean.wang@mediatek.com>
    wifi: mt76: mt7921: fix antenna signal are way off in monitor mode

Chen Zhongjin <chenzhongjin@huawei.com>
    wifi: cfg80211: Fix not unregister reg_pdev when load_builtin_regdb_keys() fails

Íñigo Huguet <ihuguet@redhat.com>
    wifi: mac80211: fix maybe-unused warning

Zhengchao Shao <shaozhengchao@huawei.com>
    wifi: mac80211: fix memory leak in ieee80211_if_add()

Yuan Can <yuancan@huawei.com>
    wifi: nl80211: Add checks for nla_nest_start() in nl80211_send_iface()

Alexander Sverdlin <alexander.sverdlin@siemens.com>
    spi: spidev: mask SPI_CS_HIGH in SPI_IOC_RD_MODE

Dan Carpenter <error27@gmail.com>
    bonding: uninitialized variable in bond_miimon_inspect()

Pengcheng Yang <yangpc@wangsu.com>
    bpf, sockmap: Fix data loss caused by using apply_bytes on ingress redirect

Pengcheng Yang <yangpc@wangsu.com>
    bpf, sockmap: Fix missing BPF_F_INGRESS flag when using apply_bytes

Pengcheng Yang <yangpc@wangsu.com>
    bpf, sockmap: Fix repeated calls to sock_put() when msg has more_data

Randy Dunlap <rdunlap@infradead.org>
    Input: wistron_btns - disable on UML

Florian Westphal <fw@strlen.de>
    netfilter: conntrack: set icmpv6 redirects as RELATED

Xiu Jianfeng <xiujianfeng@huawei.com>
    clk: visconti: Fix memory leak in visconti_register_pll()

Zhang Qilong <zhangqilong3@huawei.com>
    ASoC: pcm512x: Fix PM disable depth imbalance in pcm512x_probe

Xia Fukun <xiafukun@huawei.com>
    drm/i915/bios: fix a memory leak in generate_lfp_data_ptrs

Konstantin Meskhidze <konstantin.meskhidze@huawei.com>
    drm/amdkfd: Fix memory leakage

Xiongfeng Wang <wangxiongfeng2@huawei.com>
    drm/amdgpu: Fix PCI device refcount leak in amdgpu_atrm_get_bios()

Xiongfeng Wang <wangxiongfeng2@huawei.com>
    drm/radeon: Fix PCI device refcount leak in radeon_atrm_get_bios()

Veerabadhran Gopalakrishnan <veerabadhran.gopalakrishnan@amd.com>
    amdgpu/nv.c: Corrected typo in the video capabilities resolution

Guchun Chen <guchun.chen@amd.com>
    drm/amd/pm/smu11: BACO is supported when it's in BACO state

Daniel Golle <daniel@makrotopia.org>
    clk: mediatek: fix dependency of MT7986 ADC clocks

Ricardo Ribalda <ribalda@chromium.org>
    ASoC: mediatek: mt8173: Enable IRQ when pdata is ready

zhichao.liu <zhichao.liu@mediatek.com>
    spi: mt65xx: Add dma max segment size declaration

Ben Greear <greearb@candelatech.com>
    wifi: iwlwifi: mvm: fix double free on tx path.

Bitterblue Smith <rtl8821cerfe2@gmail.com>
    wifi: rtl8xxxu: Fix use after rcu_read_unlock in rtl8xxxu_bss_info_changed

Ziyang Xuan <william.xuanziyang@huawei.com>
    wifi: plfxlc: fix potential memory leak in __lf_x_usb_enable_rx()

Liu Shixin <liushixin2@huawei.com>
    ALSA: asihpi: fix missing pci_disable_device()

Trond Myklebust <trond.myklebust@hammerspace.com>
    NFS: Fix an Oops in nfs_d_automount()

Trond Myklebust <trond.myklebust@hammerspace.com>
    NFSv4: Fix a deadlock between nfs4_open_recover_helper() and delegreturn

Trond Myklebust <trond.myklebust@hammerspace.com>
    NFSv4: Fix a credential leak in _nfs4_discover_trunking()

Trond Myklebust <trond.myklebust@hammerspace.com>
    NFSv4.2: Fix initialisation of struct nfs4_label

Trond Myklebust <trond.myklebust@hammerspace.com>
    NFSv4.2: Fix a memory stomp in decode_attr_security_label

Trond Myklebust <trond.myklebust@hammerspace.com>
    NFSv4.2: Always decode the security label

Trond Myklebust <trond.myklebust@hammerspace.com>
    NFSv4.2: Clear FATTR4_WORD2_SECURITY_LABEL when done decoding

Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
    drm/msm/mdp5: fix reading hw revision on db410c platform

Jiasheng Jiang <jiasheng@iscas.ac.cn>
    ASoC: mediatek: mtk-btcvsd: Add checks for write and read of mtk_btcvsd_snd

Dmitry Torokhov <dmitry.torokhov@gmail.com>
    ASoC: dt-bindings: wcd9335: fix reset line polarity in example

Zhang Zekun <zhangzekun11@huawei.com>
    drm/tegra: Add missing clk_disable_unprepare() in tegra_dc_probe()

Aakarsh Jain <aakarsh.jain@samsung.com>
    media: s5p-mfc: Add variant data for MFC v7 hardware for Exynos 3250 SoC

Yunfei Dong <yunfei.dong@mediatek.com>
    media: mediatek: vcodec: Core thread depends on core_list

Yunfei Dong <yunfei.dong@mediatek.com>
    media: mediatek: vcodec: Setting lat buf to lat_list when lat decode error

Yunfei Dong <yunfei.dong@mediatek.com>
    media: mediatek: vcodec: Fix h264 set lat buffer error

Yunfei Dong <yunfei.dong@mediatek.com>
    media: mediatek: vcodec: Fix getting NULL pointer for dst buffer

Ming Qian <ming.qian@nxp.com>
    media: amphion: lock and check m2m_ctx in event handler

Ming Qian <ming.qian@nxp.com>
    media: amphion: cancel vpu before release instance

Ming Qian <ming.qian@nxp.com>
    media: amphion: try to wakeup vpu core to avoid failure

Paul Kocialkowski <paul.kocialkowski@bootlin.com>
    media: sun8i-a83t-mipi-csi2: Register async subdev with no sensor attached

Paul Kocialkowski <paul.kocialkowski@bootlin.com>
    media: sun6i-mipi-csi2: Register async subdev with no sensor attached

Paul Kocialkowski <paul.kocialkowski@bootlin.com>
    media: sun8i-a83t-mipi-csi2: Require both pads to be connected for streaming

Paul Kocialkowski <paul.kocialkowski@bootlin.com>
    media: sun6i-mipi-csi2: Require both pads to be connected for streaming

Juergen Gross <jgross@suse.com>
    x86/boot: Skip realmode init code when running as Xen PV guest

Baisong Zhong <zhongbaisong@huawei.com>
    media: dvb-usb: az6027: fix null-ptr-deref in az6027_i2c_xfer()

Chen Zhongjin <chenzhongjin@huawei.com>
    media: dvb-core: Fix ignored return value in dvb_register_frontend()

ZhangPeng <zhangpeng362@huawei.com>
    pinctrl: pinconf-generic: add missing of_node_put()

Dario Binacchi <dario.binacchi@amarulasolutions.com>
    clk: imx8mn: fix imx8mn_enet_phy_sels clocks list

Dario Binacchi <dario.binacchi@amarulasolutions.com>
    clk: imx8mn: fix imx8mn_sai2_sels clocks list

Dario Binacchi <dario.binacchi@amarulasolutions.com>
    clk: imx: rename video_pll1 to video_pll

Dario Binacchi <dario.binacchi@amarulasolutions.com>
    clk: imx: replace osc_hdmi with dummy

Dario Binacchi <dario.binacchi@amarulasolutions.com>
    clk: imx8mn: rename vpu_pll to m7_alt_pll

Marek Vasut <marex@denx.de>
    media: mt9p031: Drop bogus v4l2_subdev_get_try_crop() call from mt9p031_init_cfg()

Laurent Pinchart <laurent.pinchart@ideasonboard.com>
    media: imx: imx7-media-csi: Clear BIT_MIPI_DOUBLE_CMPNT for <16b formats

Gautam Menghani <gautammenghani201@gmail.com>
    media: imon: fix a race condition in send_packet()

Chen Zhongjin <chenzhongjin@huawei.com>
    media: vimc: Fix wrong function called when vimc_init() fails

Yuan Can <yuancan@huawei.com>
    ASoC: qcom: Add checks for devm_kcalloc

Wang ShaoBo <bobo.shaobowang@huawei.com>
    drbd: destroy workqueue when drbd device was freed

Wang ShaoBo <bobo.shaobowang@huawei.com>
    drbd: remove call to memset before free device/resource/connection

Zheng Yongjun <zhengyongjun3@huawei.com>
    mtd: maps: pxa2xx-flash: fix memory leak in probe

Shang XiaoJing <shangxiaojing@huawei.com>
    mtd: core: Fix refcount error in del_mtd_device()

Jonathan Toppins <jtoppins@redhat.com>
    bonding: fix link recovery in mode 2 when updelay is nonzero

Stanislav Fomichev <sdf@google.com>
    selftests/bpf: Mount debugfs in setns_by_fd

Stanislav Fomichev <sdf@google.com>
    selftests/bpf: Make sure zero-len skbs aren't redirectable

Jani Nikula <jani.nikula@intel.com>
    drm/i915/guc: make default_lists const data

Yang Yingliang <yangyingliang@huawei.com>
    drm/amdgpu: fix pci device refcount leak

Xiu Jianfeng <xiujianfeng@huawei.com>
    clk: rockchip: Fix memory leak in rockchip_clk_register_pll()

Wang ShaoBo <bobo.shaobowang@huawei.com>
    regulator: core: use kfree_const() to free space conditionally

Baisong Zhong <zhongbaisong@huawei.com>
    ALSA: seq: fix undefined behavior in bit shift for SNDRV_SEQ_FILTER_USE_EVENT

Baisong Zhong <zhongbaisong@huawei.com>
    ALSA: pcm: fix undefined behavior in bit shift for SNDRV_PCM_RATE_KNOT

Cezary Rojewski <cezary.rojewski@intel.com>
    ASoC: Intel: avs: Lock substream before snd_pcm_stop()

Zong-Zhe Yang <kevin_yang@realtek.com>
    wifi: rtw89: fix physts IE page check

ZhangPeng <zhangpeng362@huawei.com>
    pinctrl: k210: call of_node_put()

Giulio Benetti <giulio.benetti@benettiengineering.com>
    clk: imx: imxrt1050: fix IMXRT1050_CLK_LCDIF_APB offsets

Marcus Folkesson <marcus.folkesson@gmail.com>
    HID: hid-sensor-custom: set fixed size for custom attributes

Stanislav Fomichev <sdf@google.com>
    bpf: Move skb->len == 0 checks into __bpf_redirect

Peng Fan <peng.fan@nxp.com>
    clk: imx93: correct enet clock

Peng Fan <peng.fan@nxp.com>
    clk: imx93: unmap anatop base in error handling path

Dmitry Torokhov <dmitry.torokhov@gmail.com>
    HID: i2c: let RMI devices decide what constitutes wakeup event

Haibo Chen <haibo.chen@nxp.com>
    clk: imx93: correct the flexspi1 clock setting

Allen-KH Cheng <allen-kh.cheng@mediatek.com>
    mtd: spi-nor: Fix the number of bytes for the dummy cycles

Michael Walle <michael@walle.cc>
    mtd: spi-nor: hide jedec_id sysfs attribute if not present

Kuniyuki Iwashima <kuniyu@amazon.com>
    net: Return errno in sk->sk_prot->get_port().

Kuniyuki Iwashima <kuniyu@amazon.com>
    udp: Clean up some functions.

Lorenzo Bianconi <lorenzo@kernel.org>
    net: ethernet: mtk_eth_soc: fix RSTCTRL_PPE{0,1} definitions

Christoph Hellwig <hch@lst.de>
    media: videobuf-dma-contig: use dma_mmap_coherent

Yuan Can <yuancan@huawei.com>
    media: amphion: Fix error handling in vpu_driver_init()

Yuan Can <yuancan@huawei.com>
    media: platform: exynos4-is: Fix error handling in fimc_md_init()

Yang Yingliang <yangyingliang@huawei.com>
    media: solo6x10: fix possible memory leak in solo_sysfs_init()

Chen Zhongjin <chenzhongjin@huawei.com>
    media: vidtv: Fix use-after-free in vidtv_bridge_dvb_init()

Ming Qian <ming.qian@nxp.com>
    media: amphion: apply vb2_queue_error instead of setting manually

Ming Qian <ming.qian@nxp.com>
    media: amphion: add lock around vdec_g_fmt

Lorenzo Bianconi <lorenzo@kernel.org>
    net: ethernet: mtk_eth_soc: do not overwrite mtu configuration running reset routine

Douglas Anderson <dianders@chromium.org>
    Input: elants_i2c - properly handle the reset GPIO when power is off

Hui Tang <tanghui20@huawei.com>
    mtd: lpddr2_nvm: Fix possible null-ptr-deref

Rob Clark <robdclark@chromium.org>
    drm/msm/a6xx: Fix speed-bin detection vs probe-defer

Xiu Jianfeng <xiujianfeng@huawei.com>
    wifi: ath10k: Fix return value in ath10k_pci_init()

Wang Yufen <wangyufen@huawei.com>
    selftests/bpf: fix memory leak of lsm_cgroup

Christoph Hellwig <hch@lst.de>
    dm: track per-add_disk holder relations in DM

Yu Kuai <yukuai3@huawei.com>
    dm: make sure create and remove dm device won't race with open and close table

Christoph Hellwig <hch@lst.de>
    dm: cleanup close_table_device

Christoph Hellwig <hch@lst.de>
    dm: cleanup open_table_device

Christoph Hellwig <hch@lst.de>
    block: clear ->slave_dir when dropping the main slave_dir reference

Xiu Jianfeng <xiujianfeng@huawei.com>
    ima: Fix misuse of dereference of pointer in template_desc_init_fields()

GUO Zihua <guozihua@huawei.com>
    integrity: Fix memory leakage in keyring allocation error path

Brian Starkey <brian.starkey@arm.com>
    drm/fourcc: Fix vsub/hsub for Q410 and Q401

Konrad Dybcio <konrad.dybcio@linaro.org>
    regulator: qcom-rpmh: Fix PMR735a S3 regulator spec

Christophe JAILLET <christophe.jaillet@wanadoo.fr>
    wifi: rtw89: Fix some error handling path in rtw89_core_sta_assoc()

Joel Granados <j.granados@samsung.com>
    nvme: return err on nvme_init_non_mdts_limits fail

Dan Carpenter <error27@gmail.com>
    amdgpu/pm: prevent array underflow in vega20_odn_edit_dpm_table()

Yang Yingliang <yangyingliang@huawei.com>
    regulator: core: fix unbalanced of node refcount in regulator_dev_lookup()

Christoph Hellwig <hch@lst.de>
    nvmet: only allocate a single slab for bvecs

Zeng Heng <zengheng4@huawei.com>
    ASoC: pxa: fix null-pointer dereference in filter()

Xinlei Lee <xinlei.lee@mediatek.com>
    drm/mediatek: Modify dpi power on/off sequence.

Yang Jihong <yangjihong1@huawei.com>
    selftests/bpf: Fix xdp_synproxy compilation failure in 32-bit arch

Randy Dunlap <rdunlap@infradead.org>
    ASoC: codecs: wsa883x: use correct header file

Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
    ASoC: codecs: wsa883x: Use proper shutdown GPIO polarity

Miaoqian Lin <linmq006@gmail.com>
    module: Fix NULL vs IS_ERR checking for module_get_next_page

Johannes Berg <johannes.berg@intel.com>
    wifi: iwlwifi: mei: fix potential NULL-ptr deref after clone

Avraham Stern <avraham.stern@intel.com>
    wifi: iwlwifi: mei: avoid blocking sap messages handling due to rtnl lock

Emmanuel Grumbach <emmanuel.grumbach@intel.com>
    wifi: iwlwifi: mei: fix tx DHCP packet for devices with new Tx API

Emmanuel Grumbach <emmanuel.grumbach@intel.com>
    wifi: iwlwifi: mei: don't send SAP commands if AMT is disabled

Avraham Stern <avraham.stern@intel.com>
    wifi: iwlwifi: mei: make sure ownership confirmed message is sent

Sam Shih <sam.shih@mediatek.com>
    pinctrl: mediatek: fix the pinconf register offset of some pins

Frank Wunderlich <frank-w@public-files.de>
    dt-bindings: pinctrl: update uart/mmc bindings for MT7986 SoC

Hanjun Guo <guohanjun@huawei.com>
    drm/radeon: Add the missed acpi_put_table() to fix memory leak

Khazhismel Kumykov <khazhy@chromium.org>
    bfq: fix waker_bfqq inconsistency crash

Christoph Böhmwalder <christoph.boehmwalder@linbit.com>
    drbd: use blk_queue_max_discard_sectors helper

Yassine Oudjana <y.oudjana@protonmail.com>
    regmap-irq: Use the new num_config_regs property in regmap_add_irq_chip_fwnode

Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
    drm: rcar-du: Drop leftovers dependencies from Kconfig

Ping-Ke Shih <pkshih@realtek.com>
    wifi: rtw89: use u32_encode_bits() to fill MAC quota value

Marek Vasut <marex@denx.de>
    drm: lcdif: Set and enable FIFO Panic threshold

David Howells <dhowells@redhat.com>
    rxrpc: Fix ack.bufferSize to be 0 when generating an ack

David Howells <dhowells@redhat.com>
    net, proc: Provide PROC_FS=n fallback for proc_create_net_single_write()

Cole Robinson <crobinso@redhat.com>
    virt/sev-guest: Add a MODULE_ALIAS

Wolfram Sang <wsa+renesas@sang-engineering.com>
    clk: renesas: r8a779f0: Fix SCIF parent clocks

Wolfram Sang <wsa+renesas@sang-engineering.com>
    clk: renesas: r8a779f0: Fix HSCIF parent clocks

Vladimir Zapolskiy <vladimir.zapolskiy@linaro.org>
    media: camss: Do not attach an already attached power domain on MSM8916 platform

Vladimir Zapolskiy <vladimir.zapolskiy@linaro.org>
    media: camss: Clean up received buffers on failed start of streaming

Marek Vasut <marex@denx.de>
    wifi: rsi: Fix handling of 802.3 EAPOL frames sent via control port

Randy Dunlap <rdunlap@infradead.org>
    Input: joystick - fix Kconfig warning for JOYSTICK_ADC

Gaosheng Cui <cuigaosheng1@huawei.com>
    mtd: core: fix possible resource leak in init_mtd()

Zhang Xiaoxu <zhangxiaoxu5@huawei.com>
    mtd: Fix device name leak when register device failed in add_mtd_device()

Manivannan Sadhasivam <mani@kernel.org>
    clk: qcom: gcc-sm8250: Use retention mode for USB GDSCs

Konrad Dybcio <konrad.dybcio@somainline.org>
    clk: qcom: dispcc-sm6350: Add CLK_OPS_PARENT_ENABLE to pixel&byte src

Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
    clk: qcom: gcc-ipq806x: use parent_data for the last remaining entry

Andrii Nakryiko <andrii@kernel.org>
    bpf: propagate precision across all frames, not just the last one

Andrii Nakryiko <andrii@kernel.org>
    bpf: propagate precision in ALU/ALU64 operations

Yang Yingliang <yangyingliang@huawei.com>
    media: platform: exynos4-is: fix return value check in fimc_md_probe()

Liu Shixin <liushixin2@huawei.com>
    media: vivid: fix compose size exceed boundary

Andrzej Pietrasiewicz <andrzej.p@collabora.com>
    media: rkvdec: Add required padding

Marijn Suijten <marijn.suijten@somainline.org>
    drm/msm/dsi: Prevent signed BPG offsets from bleeding into adjacent bits

Marijn Suijten <marijn.suijten@somainline.org>
    drm/msm/dsi: Disallow 8 BPC DSC configuration for alternative BPC values

Marijn Suijten <marijn.suijten@somainline.org>
    drm/msm/dsi: Account for DSC's bits_per_pixel having 4 fractional bits

Marijn Suijten <marijn.suijten@somainline.org>
    drm/msm/dsi: Migrate to drm_dsc_compute_rc_parameters()

Marijn Suijten <marijn.suijten@somainline.org>
    drm/msm/dsi: Appropriately set dsc->mux_word_size based on bpc

Marijn Suijten <marijn.suijten@somainline.org>
    drm/msm/dsi: Reuse earlier computed dsc->slice_chunk_size

Marijn Suijten <marijn.suijten@somainline.org>
    drm/msm/dsi: Use DIV_ROUND_UP instead of conditional increment on modulo

Marijn Suijten <marijn.suijten@somainline.org>
    drm/msm/dsi: Remove repeated calculation of slice_per_intf

Marijn Suijten <marijn.suijten@somainline.org>
    drm/msm/dsi: Remove useless math in DSC calculations

Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
    drm/msm/dsi: use drm_dsc_config instead of msm_display_dsc_config

Marijn Suijten <marijn.suijten@somainline.org>
    drm/msm/dpu1: Account for DSC's bits_per_pixel having 4 fractional bits

Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
    drm/msm/dpu: use drm_dsc_config instead of msm_display_dsc_config

Kumar Kartikeya Dwivedi <memxor@gmail.com>
    bpf: Fix slot type check in check_stack_write_var_off

Kumar Kartikeya Dwivedi <memxor@gmail.com>
    bpf: Clobber stack slot when writing over spilled PTR_TO_BTF_ID

Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
    drm/msm/hdmi: use devres helper for runtime PM management

GUO Zihua <guozihua@huawei.com>
    ima: Handle -ESTALE returned by ima_filter_rule_match()

Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
    drm/msm/mdp5: stop overriding drvdata

Gaosheng Cui <cuigaosheng1@huawei.com>
    drm/ttm: fix undefined behavior in bit shift for TTM_TT_FLAG_PRIV_POPULATED

Marek Vasut <marex@denx.de>
    drm/panel/panel-sitronix-st7701: Remove panel on DSI attach failure

Jonathan Neuschäfer <j.neuschaefer@gmx.net>
    spi: Update reference to struct spi_controller

Marco Felsch <m.felsch@pengutronix.de>
    drm: lcdif: change burst size to 256B

Marek Vasut <marex@denx.de>
    clk: renesas: r9a06g032: Repair grave increment error

Zhang Qilong <zhangqilong3@huawei.com>
    drm/rockchip: lvds: fix PM usage counter unbalance in poweron

Haiyi Zhou <Haiyi.Zhou@amd.com>
    drm/amd/display: wait for vblank during pipe programming

Sakari Ailus <sakari.ailus@linux.intel.com>
    dw9768: Enable low-power probe on ACPI

Alan Previn <alan.previn.teres.alexis@intel.com>
    drm/i915/guc: Fix GuC error capture sizing estimation and reporting

Alan Previn <alan.previn.teres.alexis@intel.com>
    drm/i915/guc: Add error-capture init warnings when needed

John Harrison <John.C.Harrison@Intel.com>
    drm/i915/guc: Make GuC log sizes runtime configurable

John Harrison <John.C.Harrison@Intel.com>
    drm/i915/guc: Fix capture size warning and bump the size

Alan Previn <alan.previn.teres.alexis@intel.com>
    drm/i915/guc: Add a helper for log buffer size

Nícolas F. R. A. Prado <nfraprado@collabora.com>
    ASoC: dt-bindings: rt5682: Set sound-dai-cells to 1

Wolfram Sang <wsa+renesas@sang-engineering.com>
    clk: renesas: r8a779a0: Fix SD0H clock name

Jimmy Assarsson <extja@kvaser.com>
    can: kvaser_usb: Compare requested bittiming parameters with actual parameters in do_set_{,data}_bittiming

Jimmy Assarsson <extja@kvaser.com>
    can: kvaser_usb: Add struct kvaser_usb_busparams

Anssi Hannula <anssi.hannula@bitwise.fi>
    can: kvaser_usb_leaf: Fix bogus restart events

Anssi Hannula <anssi.hannula@bitwise.fi>
    can: kvaser_usb_leaf: Fix wrong CAN state after stopping

Anssi Hannula <anssi.hannula@bitwise.fi>
    can: kvaser_usb_leaf: Fix improved state not being reported

Anssi Hannula <anssi.hannula@bitwise.fi>
    can: kvaser_usb_leaf: Set Warning state even without bus errors

Jimmy Assarsson <extja@kvaser.com>
    can: kvaser_usb: kvaser_usb_leaf: Handle CMD_ERROR_EVENT

Jimmy Assarsson <extja@kvaser.com>
    can: kvaser_usb: kvaser_usb_leaf: Rename {leaf,usbcan}_cmd_error_event to {leaf,usbcan}_cmd_can_error_event

Jimmy Assarsson <extja@kvaser.com>
    can: kvaser_usb: kvaser_usb_leaf: Get capabilities from device

Alan Maguire <alan.maguire@oracle.com>
    libbpf: Btf dedup identical struct test needs check for nested structs/arrays

Marek Szyprowski <m.szyprowski@samsung.com>
    media: exynos4-is: don't rely on the v4l2_async_subdev internals

Rafael Mendonca <rafaelmendsr@gmail.com>
    media: i2c: ov5648: Free V4L2 fwnode data on unbind

Kuniyuki Iwashima <kuniyu@amazon.com>
    soreuseport: Fix socket selection for SO_INCOMING_CPU.

Tang Bin <tangbin@cmss.chinamobile.com>
    venus: pm_helpers: Fix error check in vcodec_domains_get()

Ricardo Ribalda <ribalda@chromium.org>
    media: i2c: ad5820: Fix error path

Rafael Mendonca <rafaelmendsr@gmail.com>
    media: i2c: hi846: Fix memory leak in hi846_parse_dt()

John Harrison <John.C.Harrison@Intel.com>
    drm/i915: Fix compute pre-emption w/a to apply to compute engines

John Harrison <John.C.Harrison@Intel.com>
    drm/i915/guc: Limit scheduling properties to avoid overflow

Yunfei Dong <yunfei.dong@mediatek.com>
    media: mediatek: vcodec: fix h264 cavlc bitstream fail

Jernej Skrabec <jernej.skrabec@gmail.com>
    media: cedrus: hevc: Fix offset adjustments

Jernej Skrabec <jernej.skrabec@gmail.com>
    media: v4l2-ioctl.c: Unify YCbCr/YUV terms in format descriptions

Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
    media: adv748x: afe: Select input port when initializing AFE

Ming Qian <ming.qian@nxp.com>
    media: amphion: reset instance if it's aborted before codec header parsed

Jiasheng Jiang <jiasheng@iscas.ac.cn>
    media: coda: jpeg: Add check for kmalloc

Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
    media: v4l2-ctrls: Fix off-by-one error in integer menu control check

Jeff LaBundy <jeff@labundy.com>
    Input: iqs7222 - protect against undefined slider size

Jeff LaBundy <jeff@labundy.com>
    Input: iqs7222 - report malformed properties

Jeff LaBundy <jeff@labundy.com>
    Input: iqs7222 - drop unused device node references

Jeff LaBundy <jeff@labundy.com>
    Input: iqs7222 - set all ULP entry masks by default

Pin-yen Lin <treapking@chromium.org>
    drm/bridge: it6505: Initialize AUX channel in it6505_i2c_probe

Gerhard Engleder <gerhard@engleder-embedded.com>
    samples/bpf: Fix MAC address swapping in xdp2_kern

Gerhard Engleder <gerhard@engleder-embedded.com>
    samples/bpf: Fix map iteration in xdp1_user

Sean Anderson <sean.anderson@seco.com>
    powerpc: dts: t208x: Mark MAC1 and MAC2 as 10G

Rafael Mendonca <rafaelmendsr@gmail.com>
    drm/amdgpu/powerplay/psm: Fix memory leak in power state init

Andrew Jeffery <andrew@aj.id.au>
    ipmi: kcs: Poll OBF briefly to reduce OBE latency

Cezary Rojewski <cezary.rojewski@intel.com>
    ASoC: Intel: avs: Fix potential RX buffer overflow

Cezary Rojewski <cezary.rojewski@intel.com>
    ASoC: Intel: avs: Fix DMA mask assignment

Yang Yingliang <yangyingliang@huawei.com>
    pinctrl: ocelot: add missing destroy_workqueue() in error path in ocelot_pinctrl_probe()

Niklas Cassel <niklas.cassel@wdc.com>
    ata: libata: fix NCQ autosense logic

Laurent Pinchart <laurent.pinchart@ideasonboard.com>
    drm: lcdif: Switch to limited range for RGB to YUV conversion

Shung-Hsi Yu <shung-hsi.yu@suse.com>
    libbpf: Fix null-pointer dereference in find_prog_by_sec_insn()

Shung-Hsi Yu <shung-hsi.yu@suse.com>
    libbpf: Deal with section with no data gracefully

Shung-Hsi Yu <shung-hsi.yu@suse.com>
    libbpf: Use elf_getshdrnum() instead of e_shnum

Andrii Nakryiko <andrii@kernel.org>
    libbpf: Reject legacy 'maps' ELF section

Xu Kuohai <xukuohai@huawei.com>
    selftest/bpf: Fix error usage of ASSERT_OK in xdp_adjust_tail.c

Xu Kuohai <xukuohai@huawei.com>
    selftests/bpf: Fix error failure of case test_xdp_adjust_tail_grow

Xu Kuohai <xukuohai@huawei.com>
    selftest/bpf: Fix memory leak in kprobe_multi_test

Xu Kuohai <xukuohai@huawei.com>
    selftests/bpf: Fix memory leak caused by not destroying skeleton

Yonghong Song <yhs@fb.com>
    selftests/bpf: Add struct argument tests with fentry/fexit programs.

Xu Kuohai <xukuohai@huawei.com>
    libbpf: Fix memory leak in parse_usdt_arg()

Xu Kuohai <xukuohai@huawei.com>
    libbpf: Fix use-after-free in btf_dump_name_dups

Abhinav Kumar <quic_abhinavk@quicinc.com>
    drm/bridge: adv7533: remove dynamic lane switching from adv7533 bridge

Aditya Kumar Singh <quic_adisi@quicinc.com>
    wifi: ath11k: fix firmware assert during bandwidth change for peer sta

Aditya Kumar Singh <quic_adisi@quicinc.com>
    wifi: ath11k: move firmware stats out of debugfs

Bitterblue Smith <rtl8821cerfe2@gmail.com>
    wifi: rtl8xxxu: Fix reading the vendor of combo chips

Fedor Pchelkin <pchelkin@ispras.ru>
    wifi: ath9k: hif_usb: Fix use-after-free in ath9k_hif_usb_reg_in_cb()

Fedor Pchelkin <pchelkin@ispras.ru>
    wifi: ath9k: hif_usb: fix memory leak of urbs in ath9k_hif_usb_dealloc_tx_urbs()

Thomas Zimmermann <tzimmermann@suse.de>
    drm/atomic-helper: Don't allocate new plane state in CRTC check

Johannes Berg <johannes.berg@intel.com>
    wifi: mac80211: fix ifdef symbol name

Johannes Berg <johannes.berg@intel.com>
    wifi: mac80211: check link ID in auth/assoc continuation

Johannes Berg <johannes.berg@intel.com>
    wifi: mac80211: mlme: fix null-ptr deref on failed assoc

Johannes Berg <johannes.berg@intel.com>
    wifi: fix multi-link element subelement iteration

James Hurley <jahurley@nvidia.com>
    platform/mellanox: mlxbf-pmc: Fix event typo

Zhengchao Shao <shaozhengchao@huawei.com>
    ipc: fix memory leak in init_mqueue_fs()

Cai Xinchen <caixinchen1@huawei.com>
    rapidio: devices: fix missing put_device in mport_cdev_open

ZhangPeng <zhangpeng362@huawei.com>
    hfs: Fix OOB Write in hfs_asc2mac

Gavrilov Ilia <Ilia.Gavrilov@infotecs.ru>
    relay: fix type mismatch when allocating memory in relay_create_buf()

Zhang Qilong <zhangqilong3@huawei.com>
    eventfd: change int to __u64 in eventfd_signal() ifndef CONFIG_EVENTFD

Wang Weiyang <wangweiyang2@huawei.com>
    rapidio: fix possible UAF when kfifo_alloc() fails

Chen Zhongjin <chenzhongjin@huawei.com>
    fs: sysv: Fix sysv_nblocks() returns wrong value

Brian Foster <bfoster@redhat.com>
    NFSD: pass range end to vfs_fsync_range() instead of count

Jeff Layton <jlayton@kernel.org>
    nfsd: return error if nfs4_setacl fails

Trond Myklebust <trond.myklebust@hammerspace.com>
    lockd: set other missing fields when unlocking files

Ladislav Michl <ladis@linux-mips.org>
    MIPS: OCTEON: warn only once if deprecated link status is being used

Anastasia Belova <abelova@astralinux.ru>
    MIPS: BCM63xx: Add check for NULL for clk in clk_enable

Yang Yingliang <yangyingliang@huawei.com>
    platform/x86: intel_scu_ipc: fix possible name leak in __intel_scu_ipc_register()

Yu Liao <liaoyu15@huawei.com>
    platform/x86: mxm-wmi: fix memleak in mxm_wmi_call_mx[ds|mx]()

Victor Ding <victording@chromium.org>
    platform/chrome: cros_ec_typec: zero out stale pointers

Prashant Malani <pmalani@chromium.org>
    platform/chrome: cros_ec_typec: Get retimer handle

Prashant Malani <pmalani@chromium.org>
    platform/chrome: cros_ec_typec: Cleanup switch handle return paths

Gao Xiang <xiang@kernel.org>
    erofs: validate the extent length for uncompressed pclusters

Yue Hu <huyue2@coolpad.com>
    erofs: support interlaced uncompressed data for compressed files

Gao Xiang <xiang@kernel.org>
    erofs: fix missing unmap if z_erofs_get_extent_compressedlen() fails

Chen Zhongjin <chenzhongjin@huawei.com>
    erofs: Fix pcluster memleak when its block address is zero

Rafael J. Wysocki <rafael.j.wysocki@intel.com>
    PM: runtime: Do not call __rpm_callback() from rpm_idle()

Harshit Mogalapalli <harshit.m.mogalapalli@oracle.com>
    xen/privcmd: Fix a possible warning in privcmd_ioctl_mmap_resource()

Xiu Jianfeng <xiujianfeng@huawei.com>
    x86/xen: Fix memory leak in xen_init_lock_cpu()

Xiu Jianfeng <xiujianfeng@huawei.com>
    x86/xen: Fix memory leak in xen_smp_intr_init{_pv}()

Oleg Nesterov <oleg@redhat.com>
    uprobes/x86: Allow to probe a NOP instruction with 0x66 prefix

Li Zetao <lizetao1@huawei.com>
    ACPICA: Fix use-after-free in acpi_ut_copy_ipackage_to_ipackage()

Yang Yingliang <yangyingliang@huawei.com>
    clocksource/drivers/timer-ti-dm: Fix missing clk_disable_unprepare in dmtimer_systimer_init_clock()

Tony Lindgren <tony@atomide.com>
    clocksource/drivers/timer-ti-dm: Fix warning for omap_timer_match

Vincent Donnefort <vdonnefort@google.com>
    cpu/hotplug: Do not bail-out in DYING/STARTING sections

Phil Auld <pauld@redhat.com>
    cpu/hotplug: Make target_store() a nop when target == state

Alexey Izbyshev <izbyshev@ispras.ru>
    futex: Resend potentially swallowed owner death notification

John Thomson <git@johnthomson.fastmail.com.au>
    mips: ralink: mt7621: do not use kzalloc too early

John Thomson <git@johnthomson.fastmail.com.au>
    mips: ralink: mt7621: soc queries and tests as functions

John Thomson <git@johnthomson.fastmail.com.au>
    mips: ralink: mt7621: define MT7621_SYSC_BASE with __iomem

Wolfram Sang <wsa+renesas@sang-engineering.com>
    clocksource/drivers/sh_cmt: Access registers according to spec

Yang Yingliang <yangyingliang@huawei.com>
    rapidio: rio: fix possible name leak in rio_register_mport()

Yang Yingliang <yangyingliang@huawei.com>
    rapidio: fix possible name leaks when rio_add_device() fails

Li Zetao <ocfs2-devel@oss.oracle.com>
    ocfs2: fix memory leak in ocfs2_mount_volume()

Akinobu Mita <akinobu.mita@gmail.com>
    debugfs: fix error when writing negative value to atomic_t debugfs file

Akinobu Mita <akinobu.mita@gmail.com>
    lib/notifier-error-inject: fix error when writing -errno to debugfs file

Akinobu Mita <akinobu.mita@gmail.com>
    libfs: add DEFINE_SIMPLE_ATTRIBUTE_SIGNED for signed value

Xiongfeng Wang <wangxiongfeng2@huawei.com>
    cpufreq: amd_freq_sensitivity: Add missing pci_dev_put()

Yang Yingliang <yangyingliang@huawei.com>
    genirq/irqdesc: Don't try to remove non-existing sysfs files

Jeff Layton <jlayton@kernel.org>
    nfsd: don't call nfsd_file_put from client states seqfile display

Chuck Lever <chuck.lever@oracle.com>
    NFSD: Finish converting the NFSv3 GETACL result encoder

Chuck Lever <chuck.lever@oracle.com>
    NFSD: Finish converting the NFSv2 GETACL result encoder

Yang Yingliang <yangyingliang@huawei.com>
    EDAC/i10nm: fix refcount leak in pci_get_dev_wrapper()

Liu Peibao <liupeibao@loongson.cn>
    irqchip/loongson-liointc: Fix improper error handling in liointc_init()

Wei Yongjun <weiyongjun1@huawei.com>
    irqchip/wpcm450: Fix memory leak in wpcm450_aic_of_init()

Shang XiaoJing <shangxiaojing@huawei.com>
    irqchip: gic-pm: Use pm_runtime_resume_and_get() in gic_probe()

Jianmin Lv <lvjianmin@loongson.cn>
    irqchip/loongson-pch-pic: Fix translate callback for DT path

Yang Yingliang <yangyingliang@huawei.com>
    thermal: core: fix some possible name leaks in error paths

Yuan Can <yuancan@huawei.com>
    platform/chrome: cros_usbpd_notify: Fix error handling in cros_usbpd_notify_init()

Xiongfeng Wang <wangxiongfeng2@huawei.com>
    perf/x86/intel/uncore: Fix reference count leak in __uncore_imc_init_box()

Xiongfeng Wang <wangxiongfeng2@huawei.com>
    perf/x86/intel/uncore: Fix reference count leak in snr_uncore_mmio_map()

Xiongfeng Wang <wangxiongfeng2@huawei.com>
    perf/x86/intel/uncore: Fix reference count leak in hswep_has_limit_sbox()

Xiongfeng Wang <wangxiongfeng2@huawei.com>
    perf/x86/intel/uncore: Fix reference count leak in sad_cfg_iio_topology()

Wang ShaoBo <bobo.shaobowang@huawei.com>
    ACPI: pfr_update: use ACPI_FREE() to free acpi_object

Wang ShaoBo <bobo.shaobowang@huawei.com>
    ACPI: pfr_telemetry: use ACPI_FREE() to free acpi_object

Huisong Li <lihuisong@huawei.com>
    mailbox: pcc: Reset pcc_chan_count to zero in case of PCC probe failure

Yang Yingliang <yangyingliang@huawei.com>
    PNP: fix name memory leak in pnp_alloc_dev()

Zhao Gongyi <zhaogongyi@huawei.com>
    selftests/efivarfs: Add checking of the test return value

Yang Yingliang <yangyingliang@huawei.com>
    MIPS: vpe-cmp: fix possible memory leak while module exiting

Yang Yingliang <yangyingliang@huawei.com>
    MIPS: vpe-mt: fix possible memory leak while module exiting

Manivannan Sadhasivam <mani@kernel.org>
    cpufreq: qcom-hw: Fix the frequency returned by cpufreq_driver->get()

YueHaibing <yuehaibing@huawei.com>
    selftests: cgroup: fix unsigned comparison with less than zero

Shang XiaoJing <shangxiaojing@huawei.com>
    ocfs2: fix memory leak in ocfs2_stack_glue_init()

Gaosheng Cui <cuigaosheng1@huawei.com>
    lib/fonts: fix undefined behavior in bit shift for get_default_font

Alexey Dobriyan <adobriyan@gmail.com>
    proc: fixup uptime selftest

Barnabás Pőcze <pobrn@protonmail.com>
    timerqueue: Use rb_entry_safe() in timerqueue_getnext()

Barnabás Pőcze <pobrn@protonmail.com>
    platform/x86: huawei-wmi: fix return value calculation

wuchi <wuchi.zero@gmail.com>
    lib/debugobjects: fix stat count and optimize debug_objects_mem_init

Chen Zhongjin <chenzhongjin@huawei.com>
    perf: Fix possible memleak in pmu_dev_alloc()

Yipeng Zou <zouyipeng@huawei.com>
    selftests/ftrace: event_triggers: wait longer for test_event_enable

Xiongfeng Wang <wangxiongfeng2@huawei.com>
    ACPI: irq: Fix some kernel-doc issues

Guilherme G. Piccoli <gpiccoli@igalia.com>
    x86/split_lock: Add sysctl to control the misery mode

Chen Hui <judy.chenhui@huawei.com>
    cpufreq: qcom-hw: Fix memory leak in qcom_cpufreq_hw_read_lut()

Ondrej Mosnacek <omosnace@redhat.com>
    fs: don't audit the capability check in simple_xattr_list()

xiongxin <xiongxin@kylinos.cn>
    PM: hibernate: Fix mistake in kerneldoc comment

Reinette Chatre <reinette.chatre@intel.com>
    x86/sgx: Reduce delay and interference of enclave release

Hao Lee <haolee.swjtu@gmail.com>
    sched/psi: Fix possible missing or delayed pending event

Al Viro <viro@zeniv.linux.org.uk>
    alpha: fix syscall entry in !AUDUT_SYSCALL case

Al Viro <viro@zeniv.linux.org.uk>
    alpha: fix TIF_NOTIFY_SIGNAL handling

Ulf Hansson <ulf.hansson@linaro.org>
    cpuidle: dt: Return the correct numbers of parsed idle states

Qais Yousef <qais.yousef@arm.com>
    sched/uclamp: Cater for uclamp in find_energy_efficient_cpu()'s early exit condition

Qais Yousef <qais.yousef@arm.com>
    sched/uclamp: Make cpu_overutilized() use util_fits_cpu()

Qais Yousef <qais.yousef@arm.com>
    sched/uclamp: Make asym_fits_capacity() use util_fits_cpu()

Dietmar Eggemann <dietmar.eggemann@arm.com>
    sched/core: Introduce sched_asym_cpucap_active()

Qais Yousef <qais.yousef@arm.com>
    sched/uclamp: Make select_idle_capacity() use util_fits_cpu()

Qais Yousef <qais.yousef@arm.com>
    sched/uclamp: Fix fits_capacity() check in feec()

Qais Yousef <qais.yousef@arm.com>
    sched/uclamp: Make task_fits_capacity() use util_fits_cpu()

Qais Yousef <qais.yousef@arm.com>
    sched/uclamp: Fix relationship between uclamp and migration margin

Amir Goldstein <amir73il@gmail.com>
    ovl: remove privs in ovl_fallocate()

Amir Goldstein <amir73il@gmail.com>
    ovl: remove privs in ovl_copyfile()

Michael Kelley <mikelley@microsoft.com>
    tpm/tpm_crb: Fix error message in __crb_relinquish_locality()

Yuan Can <yuancan@huawei.com>
    tpm/tpm_ftpm_tee: Fix error handling in ftpm_mod_init()

Eddie James <eajames@linux.ibm.com>
    tpm: Add flag to use default cancellation policy

Eddie James <eajames@linux.ibm.com>
    tpm: tis_i2c: Fix sanity check interrupt enable mask

Janne Grunau <j@jannau.net>
    arch: arm64: apple: t8103: Use standard "iommu" node name

Stephen Boyd <swboyd@chromium.org>
    pstore: Avoid kcore oops by vmap()ing with VM_IOREMAP

Doug Brown <doug@schmorgal.com>
    ARM: mmp: fix timer_read delay

Wang Yufen <wangyufen@huawei.com>
    pstore/ram: Fix error return code in ramoops_probe()

Kuniyuki Iwashima <kuniyu@amazon.com>
    seccomp: Move copy_seccomp() to no failure path.

Yicong Yang <yangyicong@hisilicon.com>
    drivers/perf: hisi: Fix some event id for hisi-pcie-pmu

Sven Peter <sven@svenpeter.dev>
    soc: apple: rtkit: Stop casting function pointer signatures

Sven Peter <sven@svenpeter.dev>
    soc: apple: sart: Stop casting function pointer signatures

Pali Rohár <pali@kernel.org>
    arm64: dts: armada-3720-turris-mox: Add missing interrupt for RTC

Pali Rohár <pali@kernel.org>
    ARM: dts: armada-39x: Fix compatible string for gpios

Pali Rohár <pali@kernel.org>
    ARM: dts: armada-38x: Fix compatible string for gpios

Pali Rohár <pali@kernel.org>
    ARM: dts: turris-omnia: Add switch port 6 node

Pali Rohár <pali@kernel.org>
    ARM: dts: turris-omnia: Add ethernet aliases

Pali Rohár <pali@kernel.org>
    ARM: dts: armada-39x: Fix assigned-addresses for every PCIe Root Port

Pali Rohár <pali@kernel.org>
    ARM: dts: armada-38x: Fix assigned-addresses for every PCIe Root Port

Pali Rohár <pali@kernel.org>
    ARM: dts: armada-375: Fix assigned-addresses for every PCIe Root Port

Pali Rohár <pali@kernel.org>
    ARM: dts: armada-xp: Fix assigned-addresses for every PCIe Root Port

Pali Rohár <pali@kernel.org>
    ARM: dts: armada-370: Fix assigned-addresses for every PCIe Root Port

Pali Rohár <pali@kernel.org>
    ARM: dts: dove: Fix assigned-addresses for every PCIe Root Port

AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
    arm64: dts: mediatek: mt6797: Fix 26M oscillator unit name

AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
    arm64: dts: mediatek: pumpkin-common: Fix devicetree warnings

AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
    arm64: dts: mt2712-evb: Fix usb vbus regulators unit names

AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
    arm64: dts: mt2712-evb: Fix vproc fixed regulators unit names

AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
    arm64: dts: mt2712e: Fix unit address for pinctrl node

AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
    arm64: dts: mt2712e: Fix unit_address_vs_reg warning for oscillators

AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
    arm64: dts: mt6779: Fix devicetree build warnings

AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
    arm64: dts: mt7896a: Fix unit_address_vs_reg warning for oscillator

AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
    arm64: dts: mediatek: mt8195: Fix CPUs capacity-dmips-mhz

Jonathan Neuschäfer <j.neuschaefer@gmx.net>
    ARM: dts: nuvoton: Remove bogus unit addresses from fixed-partition nodes

Keerthy <j-keerthy@ti.com>
    arm64: dts: ti: k3-j721s2: Fix the interrupt ranges property for main & wkup gpio intr

Jayesh Choudhary <j-choudhary@ti.com>
    arm64: dts: ti: k3-j721e-main: Drop dma-coherent in crypto node

Jayesh Choudhary <j-choudhary@ti.com>
    arm64: dts: ti: k3-am65-main: Drop dma-coherent in crypto node

Shang XiaoJing <shangxiaojing@huawei.com>
    perf/smmuv3: Fix hotplug callback leak in arm_smmu_pmu_init()

Shang XiaoJing <shangxiaojing@huawei.com>
    perf/arm_dmc620: Fix hotplug callback leak in dmc620_pmu_init()

Yuan Can <yuancan@huawei.com>
    drivers: perf: marvell_cn10k: Fix hotplug callback leak in tad_pmu_init()

Yuan Can <yuancan@huawei.com>
    perf: arm_dsu: Fix hotplug callback leak in dsu_pmu_init()

Mark Rutland <mark.rutland@arm.com>
    arm64: mm: kfence: only handle translation faults

Zhang Qilong <zhangqilong3@huawei.com>
    soc: ti: smartreflex: Fix PM disable depth imbalance in omap_sr_probe

Zhang Qilong <zhangqilong3@huawei.com>
    soc: ti: knav_qmss_queue: Fix PM disable depth imbalance in knav_queue_probe

Kory Maincent <kory.maincent@bootlin.com>
    arm: dts: spear600: Fix clcd interrupt

Frank Wunderlich <frank-w@public-files.de>
    arm64: dts: mt7986: fix trng node name

Conor Dooley <conor.dooley@microchip.com>
    dt-bindings: pwm: fix microchip corePWM's pwm-cells

Fabrizio Castro <fabrizio.castro.jz@renesas.com>
    arm64: dts: renesas: r9a09g011: Fix unit address format error

Wolfram Sang <wsa+renesas@sang-engineering.com>
    arm64: dts: renesas: r8a779f0: Fix SCIF "brg_int" clock

Wolfram Sang <wsa+renesas@sang-engineering.com>
    arm64: dts: renesas: r8a779f0: Fix HSCIF "brg_int" clock

Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
    arm64: dts: qcom: sm6125: fix SDHCI CQE reg names

Marijn Suijten <marijn.suijten@somainline.org>
    arm64: dts: qcom: pm6350: Include header for KEY_POWER

Jiasheng Jiang <jiasheng@iscas.ac.cn>
    soc: qcom: apr: Add check for idr_alloc and of_property_read_string_index

Johan Hovold <johan+linaro@kernel.org>
    arm64: dts: qcom: sm6350: drop bogus DP PHY clock

Johan Hovold <johan+linaro@kernel.org>
    arm64: dts: qcom: sm8250: drop bogus DP PHY clock

Dmitry Torokhov <dmitry.torokhov@gmail.com>
    arm64: dts: qcom: sm8250-mtp: fix reset line polarity

Dmitry Torokhov <dmitry.torokhov@gmail.com>
    arm64: dts: qcom: msm8996: fix sound card reset line polarity

Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
    arm64: dts: qcom: use GPIO flags for tlmm

Johan Hovold <johan+linaro@kernel.org>
    arm64: dts: qcom: sm8450: fix UFS PHY registers

Johan Hovold <johan+linaro@kernel.org>
    arm64: dts: qcom: sm8350: fix UFS PHY registers

Johan Hovold <johan+linaro@kernel.org>
    arm64: dts: qcom: sm8250: fix UFS PHY registers

Johan Hovold <johan+linaro@kernel.org>
    arm64: dts: qcom: sm8150: fix UFS PHY registers

Luca Weiss <luca.weiss@fairphone.com>
    soc: qcom: llcc: make irq truly optional

Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
    arm64: dts: qcom: sc7180-trogdor-homestar: fully configure secondary I2S pins

Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
    arm64: dts: qcom: sm8250: correct LPASS pin pull down

Marijn Suijten <marijn.suijten@somainline.org>
    arm64: dts: qcom: pm660: Use unique ADC5_VCOIN address in node name

Georgi Vlaev <g-vlaev@ti.com>
    firmware: ti_sci: Fix polled mode during system suspend

Chen Jiahao <chenjiahao16@huawei.com>
    drivers: soc: ti: knav_qmss_queue: Mark knav_acc_firmwares as static

Marek Vasut <marex@denx.de>
    ARM: dts: stm32: Fix AV96 WLAN regulator gpio property

Marek Vasut <marex@denx.de>
    ARM: dts: stm32: Drop stm32mp15xc.dtsi from Avenger96

Marco Elver <elver@google.com>
    objtool, kcsan: Add volatile read/write instrumentation to whitelist

Cong Dang <cong.dang.xn@renesas.com>
    memory: renesas-rpc-if: Clear HS bit during hardware initialization

Padmanabhan Rajanbabu <p.rajanbabu@samsung.com>
    arm64: dts: fsd: fix drive strength values as per FSD HW UM

Padmanabhan Rajanbabu <p.rajanbabu@samsung.com>
    arm64: dts: fsd: fix drive strength macros as per FSD HW UM

Stephan Gerhold <stephan.gerhold@kernkonzept.com>
    arm64: dts: qcom: msm8916: Drop MSS fallback compatible

Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
    arm64: dts: qcom: sdm845-cheza: fix AP suspend pin bias

Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
    arm64: dts: qcom: sdm630: fix UART1 pin bias

Luca Weiss <luca@z3ntu.xyz>
    ARM: dts: qcom: apq8064: fix coresight compatible

Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
    arm64: dts: qcom: msm8996: fix GPU OPP table

Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
    arm64: dts: qcom: msm8996: fix supported-hw in cpufreq OPP tables

Yassine Oudjana <y.oudjana@protonmail.com>
    arm64: dts: qcom: msm8996: Add MSM8996 Pro support

Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
    arm64: dts: qcom: sdm845-xiaomi-polaris: fix codec pin conf name

Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
    arm64: dts: qcom: sm8250-sony-xperia-edo: fix touchscreen bias-disable

Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
    arm64: dts: qcom: ipq6018-cp01-c1: use BLSPI1 pins

Geert Uytterhoeven <geert+renesas@glider.be>
    arm64: dts: renesas: r8a779g0: Fix HSCIF0 "brg_int" clock

Paulo Alcantara <pc@cjr.nz>
    cifs: fix oops during encryption

Paulo Alcantara <pc@cjr.nz>
    cifs: improve symlink handling for smb2+

Enzo Matsumiya <ematsumiya@suse.de>
    cifs: replace kfree() with kfree_sensitive() for sensitive data

Ivaylo Dimitrov <ivo.g.dimitrov.75@gmail.com>
    usb: musb: remove extra check in musb_gadget_vbus_draw

Martin Kaiser <martin@kaiser.cx>
    staging: r8188eu: fix led register settings

Martin Kaiser <martin@kaiser.cx>
    staging: r8188eu: don't check bSurpriseRemoved in SwLedOff

Martin Kaiser <martin@kaiser.cx>
    staging: r8188eu: remove duplicate bSurpriseRemoved check


-------------

Diffstat:

 .../ABI/testing/sysfs-bus-spi-devices-spi-nor      |   3 +
 Documentation/admin-guide/sysctl/kernel.rst        |  23 +
 .../bindings/clock/qcom,sc7280-lpasscorecc.yaml    |  19 +-
 .../devicetree/bindings/input/azoteq,iqs7222.yaml  |  25 +-
 .../devicetree/bindings/mfd/qcom,spmi-pmic.yaml    |   8 +-
 .../devicetree/bindings/pci/fsl,imx6q-pcie.yaml    |  46 +-
 .../bindings/pci/toshiba,visconti-pcie.yaml        |   7 +-
 .../bindings/pinctrl/mediatek,mt7986-pinctrl.yaml  |  46 +-
 .../devicetree/bindings/pwm/microchip,corepwm.yaml |   4 +-
 .../devicetree/bindings/sound/qcom,wcd9335.txt     |   2 +-
 Documentation/devicetree/bindings/sound/rt5682.txt |   2 +-
 Documentation/driver-api/spi.rst                   |   4 +-
 Documentation/fault-injection/fault-injection.rst  |  10 +-
 Makefile                                           |   4 +-
 arch/Kconfig                                       |   2 +-
 arch/alpha/include/asm/thread_info.h               |   2 +-
 arch/alpha/kernel/entry.S                          |   4 +-
 arch/arm/boot/dts/armada-370.dtsi                  |   2 +-
 arch/arm/boot/dts/armada-375.dtsi                  |   2 +-
 arch/arm/boot/dts/armada-380.dtsi                  |   4 +-
 arch/arm/boot/dts/armada-385-turris-omnia.dts      |  18 +-
 arch/arm/boot/dts/armada-385.dtsi                  |   6 +-
 arch/arm/boot/dts/armada-38x.dtsi                  |   4 +-
 arch/arm/boot/dts/armada-39x.dtsi                  |  10 +-
 arch/arm/boot/dts/armada-xp-mv78230.dtsi           |   8 +-
 arch/arm/boot/dts/armada-xp-mv78260.dtsi           |  16 +-
 arch/arm/boot/dts/aspeed-bmc-ibm-everest.dts       |  17 +-
 arch/arm/boot/dts/aspeed-bmc-ibm-rainier.dts       |  16 +-
 arch/arm/boot/dts/dove.dtsi                        |   2 +-
 arch/arm/boot/dts/nuvoton-npcm730-gbs.dts          |   2 +-
 arch/arm/boot/dts/nuvoton-npcm730-gsj.dts          |   2 +-
 arch/arm/boot/dts/nuvoton-npcm730-kudo.dts         |   6 +-
 arch/arm/boot/dts/nuvoton-npcm750-evb.dts          |   4 +-
 .../boot/dts/nuvoton-npcm750-runbmc-olympus.dts    |   6 +-
 arch/arm/boot/dts/qcom-apq8064.dtsi                |   2 +-
 arch/arm/boot/dts/spear600.dtsi                    |   2 +-
 arch/arm/boot/dts/stm32mp157a-dhcor-avenger96.dts  |   1 -
 arch/arm/boot/dts/stm32mp15xx-dhcor-avenger96.dtsi |   2 +-
 arch/arm/mach-mmp/time.c                           |  11 +-
 arch/arm64/boot/dts/apple/t8103.dtsi               |   6 +-
 .../boot/dts/marvell/armada-3720-turris-mox.dts    |   3 +
 arch/arm64/boot/dts/mediatek/mt2712-evb.dts        |  12 +-
 arch/arm64/boot/dts/mediatek/mt2712e.dtsi          |  22 +-
 arch/arm64/boot/dts/mediatek/mt6779.dtsi           |   8 +-
 arch/arm64/boot/dts/mediatek/mt6797.dtsi           |   2 +-
 arch/arm64/boot/dts/mediatek/mt7986a.dtsi          |   4 +-
 arch/arm64/boot/dts/mediatek/mt8183.dtsi           |   2 +-
 arch/arm64/boot/dts/mediatek/mt8195.dtsi           |   8 +-
 arch/arm64/boot/dts/mediatek/pumpkin-common.dtsi   |   6 +-
 arch/arm64/boot/dts/qcom/apq8096-ifc6640.dts       |   2 +-
 arch/arm64/boot/dts/qcom/ipq6018-cp01-c1.dts       |   2 +
 arch/arm64/boot/dts/qcom/msm8916.dtsi              |   2 +-
 .../dts/qcom/msm8994-sony-xperia-kitakami.dtsi     |   2 +-
 arch/arm64/boot/dts/qcom/msm8994.dtsi              |   3 +-
 arch/arm64/boot/dts/qcom/msm8996.dtsi              | 115 +++--
 arch/arm64/boot/dts/qcom/msm8996pro.dtsi           | 266 +++++++++++
 arch/arm64/boot/dts/qcom/pm6350.dtsi               |   1 +
 arch/arm64/boot/dts/qcom/pm660.dtsi                |   2 +-
 .../boot/dts/qcom/sc7180-trogdor-homestar.dtsi     |   6 +
 arch/arm64/boot/dts/qcom/sdm630.dtsi               |   2 +-
 arch/arm64/boot/dts/qcom/sdm845-cheza.dtsi         |   4 +-
 arch/arm64/boot/dts/qcom/sdm845-db845c.dts         |   4 +-
 .../boot/dts/qcom/sdm845-xiaomi-beryllium.dts      |   2 +-
 arch/arm64/boot/dts/qcom/sdm845-xiaomi-polaris.dts |   6 +-
 .../boot/dts/qcom/sdm850-lenovo-yoga-c630.dts      |   2 +-
 arch/arm64/boot/dts/qcom/sdm850-samsung-w737.dts   |   2 +-
 arch/arm64/boot/dts/qcom/sm6125.dtsi               |   2 +-
 arch/arm64/boot/dts/qcom/sm6350.dtsi               |  10 +-
 arch/arm64/boot/dts/qcom/sm8150.dtsi               |  10 +-
 arch/arm64/boot/dts/qcom/sm8250-mtp.dts            |   2 +-
 .../boot/dts/qcom/sm8250-sony-xperia-edo.dtsi      |   2 +-
 arch/arm64/boot/dts/qcom/sm8250.dtsi               |  20 +-
 arch/arm64/boot/dts/qcom/sm8350.dtsi               |  10 +-
 arch/arm64/boot/dts/qcom/sm8450.dtsi               |  10 +-
 arch/arm64/boot/dts/renesas/r8a779f0.dtsi          |  16 +-
 arch/arm64/boot/dts/renesas/r8a779g0.dtsi          |   2 +-
 arch/arm64/boot/dts/renesas/r9a09g011.dtsi         |   2 +-
 arch/arm64/boot/dts/tesla/fsd-pinctrl.dtsi         |  34 +-
 arch/arm64/boot/dts/tesla/fsd-pinctrl.h            |   6 +-
 arch/arm64/boot/dts/ti/k3-am65-main.dtsi           |   1 -
 arch/arm64/boot/dts/ti/k3-j721e-main.dtsi          |   1 -
 arch/arm64/boot/dts/ti/k3-j721s2-main.dtsi         |   2 +-
 arch/arm64/boot/dts/ti/k3-j721s2-mcu-wakeup.dtsi   |   2 +-
 arch/arm64/include/asm/processor.h                 |   4 +-
 arch/arm64/mm/fault.c                              |   8 +-
 arch/mips/bcm63xx/clk.c                            |   2 +
 .../cavium-octeon/executive/cvmx-helper-board.c    |   2 +-
 arch/mips/cavium-octeon/executive/cvmx-helper.c    |   2 +-
 arch/mips/include/asm/mach-ralink/mt7621.h         |   4 +-
 arch/mips/kernel/vpe-cmp.c                         |   4 +-
 arch/mips/kernel/vpe-mt.c                          |   4 +-
 arch/mips/ralink/mt7621.c                          |  97 ++--
 arch/mips/ralink/of.c                              |   4 +-
 arch/powerpc/boot/dts/fsl/qoriq-fman3-0-10g-2.dtsi |  44 ++
 arch/powerpc/boot/dts/fsl/qoriq-fman3-0-10g-3.dtsi |  44 ++
 arch/powerpc/boot/dts/fsl/t2081si-post.dtsi        |   4 +-
 arch/powerpc/boot/dts/turris1x.dts                 |  14 +
 arch/powerpc/include/asm/hvcall.h                  |   3 +-
 arch/powerpc/perf/callchain.c                      |   1 +
 arch/powerpc/perf/hv-gpci-requests.h               |   4 +
 arch/powerpc/perf/hv-gpci.c                        |  35 +-
 arch/powerpc/perf/hv-gpci.h                        |   1 +
 arch/powerpc/perf/req-gen/perf.h                   |  20 +
 arch/powerpc/platforms/52xx/mpc52xx_lpbfifo.c      |   1 +
 arch/powerpc/platforms/83xx/mpc832x_rdb.c          |   2 +-
 arch/powerpc/platforms/pseries/eeh_pseries.c       |  11 +-
 arch/powerpc/platforms/pseries/plpks.c             |  32 +-
 arch/powerpc/platforms/pseries/plpks.h             |   2 +-
 arch/powerpc/sysdev/xive/spapr.c                   |   1 +
 arch/powerpc/xmon/xmon.c                           |   7 +-
 arch/riscv/include/asm/hugetlb.h                   |   6 +
 arch/riscv/include/asm/io.h                        |   5 +
 arch/riscv/include/asm/pgtable-64.h                |   6 +-
 arch/riscv/kernel/entry.S                          |  18 +-
 arch/riscv/kernel/signal.c                         |  34 +-
 arch/riscv/kernel/traps.c                          |   2 +-
 arch/riscv/kvm/vcpu.c                              |  11 +-
 arch/riscv/mm/physaddr.c                           |   2 +-
 arch/riscv/net/bpf_jit_comp64.c                    |  29 +-
 arch/x86/Kconfig                                   |   4 +-
 arch/x86/events/intel/uncore_snb.c                 |   3 +
 arch/x86/events/intel/uncore_snbep.c               |   5 +
 arch/x86/hyperv/hv_init.c                          |   2 -
 arch/x86/include/asm/apic.h                        |   3 +-
 arch/x86/include/asm/realmode.h                    |   1 +
 arch/x86/include/asm/x86_init.h                    |   4 +
 arch/x86/kernel/apic/apic.c                        |  13 +-
 arch/x86/kernel/cpu/intel.c                        |  63 ++-
 arch/x86/kernel/cpu/sgx/encl.c                     |  23 +-
 arch/x86/kernel/setup.c                            |   2 +-
 arch/x86/kernel/uprobes.c                          |   4 +-
 arch/x86/kernel/x86_init.c                         |   3 +
 arch/x86/realmode/init.c                           |   8 +-
 arch/x86/xen/enlighten_pv.c                        |   2 +
 arch/x86/xen/smp.c                                 |  24 +-
 arch/x86/xen/smp_pv.c                              |  12 +-
 arch/x86/xen/spinlock.c                            |   6 +-
 block/bfq-iosched.c                                |  16 +-
 block/blk-core.c                                   |  72 +--
 block/blk-crypto-internal.h                        |  10 +-
 block/blk-crypto-sysfs.c                           |  11 +-
 block/blk-ia-ranges.c                              |   3 +-
 block/blk-iocost.c                                 |  14 +-
 block/blk-mq-sysfs.c                               |  11 +-
 block/blk-mq.c                                     |  89 +++-
 block/blk-mq.h                                     |  14 +-
 block/blk-sysfs.c                                  | 134 ++----
 block/blk.h                                        |  13 +-
 block/bsg.c                                        |  11 +-
 block/elevator.c                                   |   2 +-
 block/genhd.c                                      |   4 +-
 crypto/cryptd.c                                    |  36 +-
 crypto/tcrypt.c                                    | 265 +++++------
 drivers/acpi/acpica/dsmethod.c                     |  10 +-
 drivers/acpi/acpica/utcopy.c                       |   7 -
 drivers/acpi/ec.c                                  |  10 +
 drivers/acpi/irq.c                                 |   5 +-
 drivers/acpi/pfr_telemetry.c                       |   6 +-
 drivers/acpi/pfr_update.c                          |   6 +-
 drivers/acpi/processor_idle.c                      |   3 +
 drivers/acpi/x86/utils.c                           |  24 +-
 drivers/ata/libata-sata.c                          |  11 +-
 drivers/base/class.c                               |   5 +
 drivers/base/power/runtime.c                       |  12 +-
 drivers/base/regmap/regmap-irq.c                   |  15 +-
 drivers/block/drbd/drbd_main.c                     |   9 +-
 drivers/block/drbd/drbd_nl.c                       |  10 +-
 drivers/block/floppy.c                             |   4 +-
 drivers/block/loop.c                               |  28 +-
 drivers/bluetooth/btintel.c                        |   5 +-
 drivers/bluetooth/btusb.c                          |   6 +-
 drivers/bluetooth/hci_bcm.c                        |  13 +-
 drivers/bluetooth/hci_bcsp.c                       |   2 +-
 drivers/bluetooth/hci_h5.c                         |   2 +-
 drivers/bluetooth/hci_ll.c                         |   2 +-
 drivers/bluetooth/hci_qca.c                        |   2 +-
 drivers/char/hw_random/amd-rng.c                   |  18 +-
 drivers/char/hw_random/geode-rng.c                 |  36 +-
 drivers/char/ipmi/ipmi_msghandler.c                |   8 +-
 drivers/char/ipmi/kcs_bmc_aspeed.c                 |  24 +-
 drivers/char/tpm/tpm_crb.c                         |   2 +-
 drivers/char/tpm/tpm_ftpm_tee.c                    |   8 +-
 drivers/char/tpm/tpm_tis_core.c                    |  20 +-
 drivers/char/tpm/tpm_tis_core.h                    |   1 +
 drivers/char/tpm/tpm_tis_i2c.c                     |   3 +-
 drivers/clk/imx/clk-imx8mn.c                       | 116 ++---
 drivers/clk/imx/clk-imx8mp.c                       |   4 +-
 drivers/clk/imx/clk-imx93.c                        |  19 +-
 drivers/clk/imx/clk-imxrt1050.c                    |   2 +-
 drivers/clk/mediatek/clk-mt7986-infracfg.c         |   2 +-
 drivers/clk/qcom/clk-krait.c                       |   2 +
 drivers/clk/qcom/dispcc-sm6350.c                   |   4 +-
 drivers/clk/qcom/gcc-ipq806x.c                     |   4 +-
 drivers/clk/qcom/gcc-sm8250.c                      |   4 +-
 drivers/clk/qcom/lpassaudiocc-sc7280.c             | 117 +++--
 drivers/clk/qcom/lpasscc-sc7280.c                  |  44 --
 drivers/clk/qcom/lpasscorecc-sc7180.c              |  24 +-
 drivers/clk/qcom/lpasscorecc-sc7280.c              |  33 ++
 drivers/clk/renesas/r8a779a0-cpg-mssr.c            |   2 +-
 drivers/clk/renesas/r8a779f0-cpg-mssr.c            |  29 +-
 drivers/clk/renesas/r9a06g032-clocks.c             |   3 +-
 drivers/clk/rockchip/clk-pll.c                     |   1 +
 drivers/clk/samsung/clk-pll.c                      |   1 +
 drivers/clk/socfpga/clk-gate.c                     |   5 +-
 drivers/clk/st/clkgen-fsyn.c                       |   5 +-
 drivers/clk/visconti/pll.c                         |   1 +
 drivers/clocksource/sh_cmt.c                       |  88 ++--
 drivers/clocksource/timer-ti-dm-systimer.c         |   4 +-
 drivers/clocksource/timer-ti-dm.c                  |   2 +-
 drivers/counter/stm32-lptimer-cnt.c                |   2 +-
 drivers/cpufreq/amd_freq_sensitivity.c             |   2 +
 drivers/cpufreq/qcom-cpufreq-hw.c                  |  43 +-
 drivers/cpuidle/dt_idle_states.c                   |   2 +-
 drivers/crypto/Kconfig                             |   5 +
 .../crypto/allwinner/sun8i-ss/sun8i-ss-cipher.c    |   2 +-
 drivers/crypto/amlogic/amlogic-gxl-core.c          |   1 -
 drivers/crypto/amlogic/amlogic-gxl.h               |   2 +-
 drivers/crypto/cavium/nitrox/nitrox_mbx.c          |   1 +
 drivers/crypto/ccree/cc_debugfs.c                  |   2 +-
 drivers/crypto/ccree/cc_driver.c                   |  10 +-
 drivers/crypto/hisilicon/hpre/hpre_main.c          |  14 +-
 drivers/crypto/hisilicon/qm.c                      | 208 ++++++---
 drivers/crypto/hisilicon/sec2/sec_main.c           |   4 +-
 drivers/crypto/hisilicon/zip/zip_main.c            |   4 +-
 drivers/crypto/img-hash.c                          |   8 +-
 drivers/crypto/omap-sham.c                         |   2 +-
 drivers/crypto/qat/qat_4xxx/adf_drv.c              |   1 +
 drivers/crypto/rockchip/rk3288_crypto.c            | 193 +-------
 drivers/crypto/rockchip/rk3288_crypto.h            |  53 +--
 drivers/crypto/rockchip/rk3288_crypto_ahash.c      | 197 ++++----
 drivers/crypto/rockchip/rk3288_crypto_skcipher.c   | 413 +++++++++-------
 drivers/dio/dio.c                                  |   8 +
 drivers/dma/apple-admac.c                          | 129 ++++-
 drivers/edac/i10nm_base.c                          |   3 +-
 drivers/extcon/Kconfig                             |   2 +-
 drivers/extcon/extcon-usbc-tusb320.c               | 247 ++++++++--
 drivers/firmware/raspberrypi.c                     |   1 +
 drivers/firmware/ti_sci.c                          |   5 +-
 drivers/gpio/gpiolib-cdev.c                        | 204 +++++++-
 drivers/gpio/gpiolib.c                             |   4 +
 drivers/gpio/gpiolib.h                             |   5 +
 drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c   |   2 +-
 drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c           |   1 +
 drivers/gpu/drm/amd/amdgpu/amdgpu_device.c         |   4 +
 drivers/gpu/drm/amd/amdgpu/amdgpu_virt.h           |   5 +-
 drivers/gpu/drm/amd/amdgpu/nv.c                    |  28 +-
 drivers/gpu/drm/amd/amdgpu/soc15.c                 |  24 +-
 drivers/gpu/drm/amd/amdgpu/soc21.c                 |   2 +-
 .../drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c  |  35 --
 drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c |  16 +-
 .../amd/display/dc/clk_mgr/dcn32/dcn32_clk_mgr.c   |   2 +-
 .../gpu/drm/amd/display/dc/dce60/dce60_resource.c  |   3 +
 .../gpu/drm/amd/display/dc/dce80/dce80_resource.c  |   2 +
 .../drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c  |  30 +-
 drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c |  35 +-
 drivers/gpu/drm/amd/display/dc/dcn32/dcn32_dccg.c  |   6 +-
 .../gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c   |   7 +
 drivers/gpu/drm/amd/include/kgd_pp_interface.h     |   3 +-
 drivers/gpu/drm/amd/pm/powerplay/amd_powerplay.c   |   3 +-
 drivers/gpu/drm/amd/pm/powerplay/hwmgr/pp_psm.c    |   2 +
 .../gpu/drm/amd/pm/powerplay/hwmgr/vega20_hwmgr.c  |   3 +-
 drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c     |   4 +
 .../gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c   |  21 +-
 drivers/gpu/drm/bridge/adv7511/adv7511.h           |   3 +-
 drivers/gpu/drm/bridge/adv7511/adv7511_drv.c       |  18 +-
 drivers/gpu/drm/bridge/adv7511/adv7533.c           |  25 +-
 drivers/gpu/drm/bridge/ite-it6505.c                |   8 +-
 drivers/gpu/drm/drm_atomic_helper.c                |  10 +-
 drivers/gpu/drm/drm_edid.c                         |  12 +
 drivers/gpu/drm/drm_fourcc.c                       |   8 +-
 drivers/gpu/drm/etnaviv/etnaviv_gpu.c              |  11 +-
 drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c          |   5 +-
 drivers/gpu/drm/i915/display/intel_bios.c          |   2 +-
 drivers/gpu/drm/i915/display/intel_dp.c            |  59 ---
 drivers/gpu/drm/i915/gt/intel_engine.h             |   6 +
 drivers/gpu/drm/i915/gt/intel_engine_cs.c          |  91 +++-
 drivers/gpu/drm/i915/gt/sysfs_engines.c            |  25 +-
 drivers/gpu/drm/i915/gt/uc/intel_guc.c             |  53 +--
 drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c     | 147 ++++--
 drivers/gpu/drm/i915/gt/uc/intel_guc_capture.h     |   1 -
 drivers/gpu/drm/i915/gt/uc/intel_guc_fwif.h        |  21 +
 drivers/gpu/drm/i915/gt/uc/intel_guc_log.c         | 227 +++++++--
 drivers/gpu/drm/i915/gt/uc/intel_guc_log.h         |  42 +-
 drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c  |   8 +
 drivers/gpu/drm/i915/i915_params.c                 |  12 +
 drivers/gpu/drm/i915/i915_params.h                 |   3 +
 drivers/gpu/drm/mediatek/mtk_dpi.c                 |  12 +-
 drivers/gpu/drm/mediatek/mtk_hdmi.c                |   7 +-
 drivers/gpu/drm/meson/meson_encoder_cvbs.c         |   7 +-
 drivers/gpu/drm/msm/adreno/a6xx_gpu.c              |  12 +-
 drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c        |  25 +-
 drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h        |   2 +-
 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.c         |  79 ++--
 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.h         |   4 +-
 drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c           |  27 +-
 drivers/gpu/drm/msm/dp/dp_display.c                |   2 +-
 drivers/gpu/drm/msm/dsi/dsi.c                      |   2 +-
 drivers/gpu/drm/msm/dsi/dsi.h                      |   2 +-
 drivers/gpu/drm/msm/dsi/dsi_host.c                 | 204 +++-----
 drivers/gpu/drm/msm/hdmi/hdmi.c                    |   2 +-
 drivers/gpu/drm/msm/msm_drv.h                      |   9 +-
 drivers/gpu/drm/mxsfb/lcdif_kms.c                  |  48 +-
 drivers/gpu/drm/mxsfb/lcdif_regs.h                 |   5 +
 drivers/gpu/drm/panel/panel-sitronix-st7701.c      |  10 +-
 drivers/gpu/drm/radeon/radeon_bios.c               |  19 +-
 drivers/gpu/drm/rcar-du/Kconfig                    |   2 -
 drivers/gpu/drm/rockchip/cdn-dp-core.c             |   2 +-
 drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c    |   2 +-
 drivers/gpu/drm/rockchip/inno_hdmi.c               |   2 +-
 drivers/gpu/drm/rockchip/rk3066_hdmi.c             |   2 +-
 drivers/gpu/drm/rockchip/rockchip_drm_vop.c        |   4 +-
 drivers/gpu/drm/rockchip/rockchip_drm_vop2.c       |   2 +-
 drivers/gpu/drm/rockchip/rockchip_lvds.c           |  10 +-
 drivers/gpu/drm/sti/sti_dvo.c                      |   7 +-
 drivers/gpu/drm/sti/sti_hda.c                      |   7 +-
 drivers/gpu/drm/sti/sti_hdmi.c                     |   7 +-
 drivers/gpu/drm/tegra/dc.c                         |   4 +-
 drivers/hid/amd-sfh-hid/amd_sfh_client.c           |   4 +
 drivers/hid/hid-apple.c                            | 118 +++--
 drivers/hid/hid-input.c                            |   6 +
 drivers/hid/hid-logitech-hidpp.c                   |  11 +-
 drivers/hid/hid-mcp2221.c                          |  12 +-
 drivers/hid/hid-rmi.c                              |   2 +
 drivers/hid/hid-sensor-custom.c                    |   2 +-
 drivers/hid/i2c-hid/i2c-hid-core.c                 |   3 +-
 drivers/hid/wacom_sys.c                            |   8 +
 drivers/hid/wacom_wac.c                            |   4 +
 drivers/hid/wacom_wac.h                            |   1 +
 drivers/hsi/controllers/omap_ssi_core.c            |  14 +-
 drivers/hv/ring_buffer.c                           |  13 +
 drivers/hwmon/Kconfig                              |   1 +
 drivers/hwmon/jc42.c                               | 243 ++++++----
 drivers/hwmon/nct6775-platform.c                   |   7 +
 drivers/hwtracing/coresight/coresight-trbe.c       |   1 +
 drivers/i2c/busses/i2c-ismt.c                      |   3 +
 drivers/i2c/busses/i2c-pxa-pci.c                   |  10 +-
 drivers/i2c/muxes/i2c-mux-reg.c                    |   5 +-
 drivers/iio/adc/ad_sigma_delta.c                   |   8 +-
 drivers/iio/adc/ti-adc128s052.c                    |  14 +-
 drivers/iio/addac/ad74413r.c                       |   2 +-
 drivers/iio/imu/adis.c                             |  28 +-
 drivers/iio/industrialio-event.c                   |   4 +-
 drivers/iio/temperature/ltc2983.c                  |  10 +-
 drivers/infiniband/Kconfig                         |   2 +
 drivers/infiniband/core/device.c                   |   2 +-
 drivers/infiniband/core/mad.c                      |   5 -
 drivers/infiniband/core/nldev.c                    |   6 +-
 drivers/infiniband/core/restrack.c                 |   2 -
 drivers/infiniband/core/sysfs.c                    |  17 +-
 drivers/infiniband/hw/hfi1/affinity.c              |   2 +
 drivers/infiniband/hw/hfi1/firmware.c              |   6 +
 drivers/infiniband/hw/hns/Makefile                 |   2 +-
 drivers/infiniband/hw/hns/hns_roce_device.h        |  13 +-
 drivers/infiniband/hw/hns/hns_roce_hw_v2.c         | 257 +++++++---
 drivers/infiniband/hw/hns/hns_roce_hw_v2.h         |  14 +-
 drivers/infiniband/hw/hns/hns_roce_hw_v2_dfx.c     |  34 --
 drivers/infiniband/hw/hns/hns_roce_main.c          |  24 +-
 drivers/infiniband/hw/hns/hns_roce_mr.c            |   4 +-
 drivers/infiniband/hw/hns/hns_roce_qp.c            | 107 ++++-
 drivers/infiniband/hw/hns/hns_roce_restrack.c      |  35 +-
 drivers/infiniband/hw/irdma/uk.c                   | 170 ++++---
 drivers/infiniband/hw/irdma/user.h                 |  20 +-
 drivers/infiniband/hw/irdma/utils.c                |   2 +
 drivers/infiniband/hw/irdma/verbs.c                | 145 ++----
 drivers/infiniband/hw/irdma/verbs.h                |  53 +++
 drivers/infiniband/sw/rxe/rxe_mr.c                 |   9 +-
 drivers/infiniband/sw/rxe/rxe_qp.c                 |   6 +-
 drivers/infiniband/sw/siw/siw_cq.c                 |  24 +-
 drivers/infiniband/sw/siw/siw_qp_tx.c              |   2 +-
 drivers/infiniband/sw/siw/siw_verbs.c              |  40 +-
 drivers/infiniband/ulp/ipoib/ipoib_netlink.c       |   7 +
 drivers/infiniband/ulp/srp/ib_srp.c                |  96 +++-
 drivers/input/joystick/Kconfig                     |   1 +
 drivers/input/misc/Kconfig                         |   2 +-
 drivers/input/misc/iqs7222.c                       | 520 ++++++++++++---------
 drivers/input/touchscreen/elants_i2c.c             |   9 +-
 drivers/interconnect/qcom/sc7180.c                 |   2 +-
 drivers/iommu/amd/iommu_v2.c                       |   1 +
 drivers/iommu/fsl_pamu.c                           |   2 +-
 drivers/iommu/mtk_iommu.c                          |  53 ++-
 drivers/iommu/rockchip-iommu.c                     |  10 +-
 drivers/iommu/s390-iommu.c                         | 106 ++---
 drivers/iommu/sun50i-iommu.c                       |  89 +++-
 drivers/irqchip/irq-gic-pm.c                       |   2 +-
 drivers/irqchip/irq-loongson-liointc.c             |   5 +-
 drivers/irqchip/irq-loongson-pch-pic.c             |   3 +
 drivers/irqchip/irq-wpcm450-aic.c                  |   1 +
 drivers/isdn/hardware/mISDN/hfcmulti.c             |  19 +-
 drivers/isdn/hardware/mISDN/hfcpci.c               |  13 +-
 drivers/isdn/hardware/mISDN/hfcsusb.c              |  12 +-
 drivers/leds/leds-is31fl319x.c                     |   3 +-
 drivers/leds/rgb/leds-qcom-lpg.c                   |  18 +-
 drivers/macintosh/macio-adb.c                      |   4 +
 drivers/macintosh/macio_asic.c                     |   2 +-
 drivers/mailbox/arm_mhuv2.c                        |   4 +-
 drivers/mailbox/mailbox-mpfs.c                     |  31 +-
 drivers/mailbox/pcc.c                              |   1 +
 drivers/mailbox/zynqmp-ipi-mailbox.c               |   4 +-
 drivers/mcb/mcb-core.c                             |   4 +-
 drivers/mcb/mcb-parse.c                            |   2 +-
 drivers/md/dm.c                                    | 123 +++--
 drivers/md/md-bitmap.c                             |  27 +-
 drivers/md/raid0.c                                 |   1 -
 drivers/md/raid1.c                                 |   1 +
 drivers/md/raid10.c                                |   2 -
 drivers/media/dvb-core/dvb_ca_en50221.c            |   2 +-
 drivers/media/dvb-core/dvb_frontend.c              |  10 +-
 drivers/media/dvb-core/dvbdev.c                    |  32 +-
 drivers/media/dvb-frontends/bcm3510.c              |   1 +
 drivers/media/i2c/ad5820.c                         |  10 +-
 drivers/media/i2c/adv748x/adv748x-afe.c            |   4 +
 drivers/media/i2c/dw9768.c                         |  33 +-
 drivers/media/i2c/hi846.c                          |  14 +-
 drivers/media/i2c/mt9p031.c                        |   1 -
 drivers/media/i2c/ov5640.c                         |   3 +-
 drivers/media/i2c/ov5648.c                         |   1 +
 drivers/media/pci/saa7164/saa7164-core.c           |   4 +-
 drivers/media/pci/solo6x10/solo6x10-core.c         |   1 +
 drivers/media/platform/amphion/vdec.c              |  15 +-
 drivers/media/platform/amphion/vpu.h               |   1 +
 drivers/media/platform/amphion/vpu_cmds.c          |  39 +-
 drivers/media/platform/amphion/vpu_drv.c           |   6 +-
 drivers/media/platform/amphion/vpu_malone.c        |   1 +
 drivers/media/platform/amphion/vpu_msgs.c          |   2 +
 drivers/media/platform/amphion/vpu_v4l2.c          |  30 +-
 drivers/media/platform/amphion/vpu_windsor.c       |   1 +
 drivers/media/platform/chips-media/coda-bit.c      |  14 +-
 drivers/media/platform/chips-media/coda-jpeg.c     |  10 +-
 .../mediatek/vcodec/mtk_vcodec_dec_stateless.c     |  13 +-
 .../mediatek/vcodec/vdec/vdec_h264_req_multi_if.c  |  60 ++-
 .../mediatek/vcodec/vdec/vdec_vp9_req_lat_if.c     |  15 +-
 .../platform/mediatek/vcodec/vdec_msg_queue.c      |   2 +-
 drivers/media/platform/nxp/imx-jpeg/mxc-jpeg-hw.c  |   4 +-
 drivers/media/platform/qcom/camss/camss-video.c    |   3 +-
 drivers/media/platform/qcom/camss/camss.c          |  11 +
 drivers/media/platform/qcom/venus/pm_helpers.c     |   4 +-
 .../media/platform/samsung/exynos4-is/fimc-core.c  |   2 +-
 .../media/platform/samsung/exynos4-is/media-dev.c  |  12 +-
 drivers/media/platform/samsung/s5p-mfc/s5p_mfc.c   |  17 +-
 .../platform/st/sti/c8sectpfe/c8sectpfe-core.c     |   1 +
 .../sunxi/sun6i-mipi-csi2/sun6i_mipi_csi2.c        |  23 +-
 .../sun8i-a83t-mipi-csi2/sun8i_a83t_mipi_csi2.c    |  23 +-
 drivers/media/radio/si470x/radio-si470x-usb.c      |   4 +-
 drivers/media/rc/imon.c                            |   6 +-
 drivers/media/test-drivers/vidtv/vidtv_bridge.c    |  22 +-
 drivers/media/test-drivers/vimc/vimc-core.c        |   2 +-
 drivers/media/test-drivers/vivid/vivid-vid-cap.c   |   1 +
 drivers/media/usb/dvb-usb/az6027.c                 |   4 +
 drivers/media/usb/dvb-usb/dvb-usb-init.c           |   4 +-
 drivers/media/v4l2-core/v4l2-ctrls-api.c           |   1 +
 drivers/media/v4l2-core/v4l2-ctrls-core.c          |   2 +-
 drivers/media/v4l2-core/v4l2-ioctl.c               |  34 +-
 drivers/media/v4l2-core/videobuf-dma-contig.c      |  22 +-
 drivers/memory/renesas-rpc-if.c                    |   3 +
 drivers/memstick/core/ms_block.c                   |   9 +-
 drivers/mfd/Kconfig                                |   1 +
 drivers/mfd/axp20x.c                               |   2 +-
 drivers/mfd/qcom-pm8008.c                          |   4 +-
 drivers/mfd/qcom_rpm.c                             |   4 +-
 drivers/misc/cxl/guest.c                           |  24 +-
 drivers/misc/cxl/pci.c                             |  21 +-
 drivers/misc/lkdtm/cfi.c                           |   6 +-
 drivers/misc/ocxl/config.c                         |  20 +-
 drivers/misc/ocxl/file.c                           |   7 +-
 drivers/misc/sgi-gru/grufault.c                    |  13 +-
 drivers/misc/sgi-gru/grumain.c                     |  22 +-
 drivers/misc/sgi-gru/grutables.h                   |   2 +-
 drivers/misc/tifm_7xx1.c                           |   2 +-
 drivers/mmc/core/sd.c                              |  11 +-
 drivers/mmc/host/alcor.c                           |   5 +-
 drivers/mmc/host/atmel-mci.c                       |   9 +-
 drivers/mmc/host/litex_mmc.c                       |   1 +
 drivers/mmc/host/meson-gx-mmc.c                    |   4 +-
 drivers/mmc/host/mmci.c                            |   4 +-
 drivers/mmc/host/moxart-mmc.c                      |   4 +-
 drivers/mmc/host/mxcmmc.c                          |   4 +-
 drivers/mmc/host/omap_hsmmc.c                      |   4 +-
 drivers/mmc/host/pxamci.c                          |   7 +-
 drivers/mmc/host/renesas_sdhi.h                    |   1 +
 drivers/mmc/host/renesas_sdhi_core.c               |  14 +-
 drivers/mmc/host/renesas_sdhi_internal_dmac.c      |   4 +-
 drivers/mmc/host/rtsx_pci_sdmmc.c                  |   9 +-
 drivers/mmc/host/rtsx_usb_sdmmc.c                  |  11 +-
 drivers/mmc/host/sdhci_f_sdh30.c                   |   3 +
 drivers/mmc/host/toshsd.c                          |   6 +-
 drivers/mmc/host/via-sdmmc.c                       |   4 +-
 drivers/mmc/host/vub300.c                          |  11 +-
 drivers/mmc/host/wbsd.c                            |  12 +-
 drivers/mmc/host/wmt-sdmmc.c                       |   6 +-
 drivers/mtd/lpddr/lpddr2_nvm.c                     |   2 +
 drivers/mtd/maps/pxa2xx-flash.c                    |   2 +
 drivers/mtd/mtdcore.c                              |   9 +-
 drivers/mtd/spi-nor/core.c                         |   3 +-
 drivers/mtd/spi-nor/sysfs.c                        |  14 +
 drivers/net/bonding/bond_main.c                    |  37 +-
 drivers/net/can/m_can/m_can.c                      |  32 +-
 drivers/net/can/m_can/m_can_platform.c             |   4 -
 drivers/net/can/m_can/tcan4x5x-core.c              |  18 +-
 drivers/net/can/usb/kvaser_usb/kvaser_usb.h        |  30 +-
 drivers/net/can/usb/kvaser_usb/kvaser_usb_core.c   | 115 ++++-
 drivers/net/can/usb/kvaser_usb/kvaser_usb_hydra.c  | 160 +++++--
 drivers/net/can/usb/kvaser_usb/kvaser_usb_leaf.c   | 437 +++++++++++++++--
 drivers/net/dsa/lan9303-core.c                     |   4 +-
 drivers/net/dsa/mv88e6xxx/chip.c                   |   9 +-
 drivers/net/ethernet/amd/atarilance.c              |   2 +-
 drivers/net/ethernet/amd/lance.c                   |   2 +-
 drivers/net/ethernet/amd/xgbe/xgbe-phy-v2.c        |  23 +-
 drivers/net/ethernet/apple/bmac.c                  |   2 +-
 drivers/net/ethernet/apple/mace.c                  |   2 +-
 drivers/net/ethernet/dnet.c                        |   4 +-
 drivers/net/ethernet/freescale/enetc/enetc.c       |  35 +-
 drivers/net/ethernet/intel/i40e/i40e_main.c        |  36 +-
 drivers/net/ethernet/intel/igb/igb_main.c          |   8 +-
 drivers/net/ethernet/intel/igc/igc.h               |   3 +
 drivers/net/ethernet/intel/igc/igc_defines.h       |   2 +
 drivers/net/ethernet/intel/igc/igc_main.c          | 210 +++++++--
 drivers/net/ethernet/intel/igc/igc_tsn.c           |  13 +-
 drivers/net/ethernet/mediatek/mtk_eth_soc.c        |  71 +--
 drivers/net/ethernet/mediatek/mtk_eth_soc.h        |  11 +-
 drivers/net/ethernet/myricom/myri10ge/myri10ge.c   |   1 +
 drivers/net/ethernet/neterion/s2io.c               |   2 +-
 drivers/net/ethernet/qlogic/qed/qed_debug.c        |   3 +-
 .../ethernet/qlogic/qlcnic/qlcnic_sriov_common.c   |   2 +
 drivers/net/ethernet/rdc/r6040.c                   |   5 +-
 .../net/ethernet/stmicro/stmmac/stmmac_hwtstamp.c  |   3 +-
 drivers/net/ethernet/stmicro/stmmac/stmmac_main.c  |   4 +-
 drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.h   |   2 +-
 .../net/ethernet/stmicro/stmmac/stmmac_selftests.c |   8 +-
 drivers/net/ethernet/ti/am65-cpsw-nuss.c           |  10 +-
 drivers/net/ethernet/ti/netcp_core.c               |   2 +-
 drivers/net/ethernet/xilinx/xilinx_emaclite.c      |   2 +-
 drivers/net/fddi/defxx.c                           |  22 +-
 drivers/net/hamradio/baycom_epp.c                  |   2 +-
 drivers/net/hamradio/scc.c                         |   6 +-
 drivers/net/macsec.c                               |  34 +-
 drivers/net/mctp/mctp-serial.c                     |   6 +-
 drivers/net/ntb_netdev.c                           |   4 +-
 drivers/net/ppp/ppp_generic.c                      |   2 +
 drivers/net/wan/farsync.c                          |   2 +
 drivers/net/wireless/ath/ar5523/ar5523.c           |   6 +
 drivers/net/wireless/ath/ath10k/core.c             |  16 +
 drivers/net/wireless/ath/ath10k/htc.c              |   9 +
 drivers/net/wireless/ath/ath10k/hw.h               |   2 +
 drivers/net/wireless/ath/ath10k/pci.c              |  20 +-
 drivers/net/wireless/ath/ath11k/core.c             |  46 ++
 drivers/net/wireless/ath/ath11k/core.h             |  14 +-
 drivers/net/wireless/ath/ath11k/debugfs.c          | 139 ++----
 drivers/net/wireless/ath/ath11k/debugfs.h          |   6 +-
 drivers/net/wireless/ath/ath11k/mac.c              | 122 +++--
 drivers/net/wireless/ath/ath11k/qmi.c              |   3 +
 drivers/net/wireless/ath/ath11k/wmi.c              |  48 +-
 drivers/net/wireless/ath/ath9k/hif_usb.c           |  46 +-
 .../broadcom/brcm80211/brcmfmac/firmware.c         |   5 +
 .../wireless/broadcom/brcm80211/brcmfmac/pcie.c    |   6 +-
 .../wireless/broadcom/brcm80211/brcmfmac/sdio.c    |   1 +
 drivers/net/wireless/intel/iwlwifi/mei/iwl-mei.h   |   7 +-
 drivers/net/wireless/intel/iwlwifi/mei/main.c      | 172 ++++---
 drivers/net/wireless/intel/iwlwifi/mei/net.c       |  10 +-
 drivers/net/wireless/intel/iwlwifi/mvm/fw.c        |   2 +
 drivers/net/wireless/intel/iwlwifi/mvm/mvm.h       |   4 +-
 drivers/net/wireless/intel/iwlwifi/mvm/ops.c       |   2 +-
 drivers/net/wireless/intel/iwlwifi/mvm/tx.c        |  20 +-
 drivers/net/wireless/mediatek/mt76/mt76.h          |   3 +-
 drivers/net/wireless/mediatek/mt76/mt7915/eeprom.c |  58 +--
 drivers/net/wireless/mediatek/mt76/mt7915/eeprom.h |   5 -
 drivers/net/wireless/mediatek/mt76/mt7915/mac.c    |  23 +-
 drivers/net/wireless/mediatek/mt76/mt7915/pci.c    |  13 +-
 drivers/net/wireless/mediatek/mt76/mt7921/mac.c    |  34 +-
 drivers/net/wireless/mediatek/mt76/usb.c           |  11 +-
 drivers/net/wireless/purelifi/plfxlc/usb.c         |   1 +
 drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h   |   2 +-
 .../net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c  |  28 +-
 drivers/net/wireless/realtek/rtw89/core.c          |   2 +-
 drivers/net/wireless/realtek/rtw89/mac.c           |   6 +-
 drivers/net/wireless/realtek/rtw89/phy.c           |   2 +-
 drivers/net/wireless/rsi/rsi_91x_core.c            |   4 +-
 drivers/net/wireless/rsi/rsi_91x_hal.c             |   6 +-
 drivers/nfc/pn533/pn533.c                          |   4 +
 drivers/nvme/host/core.c                           |  14 +-
 drivers/nvme/target/core.c                         |  22 +-
 drivers/nvme/target/io-cmd-file.c                  |  16 +-
 drivers/nvme/target/nvmet.h                        |   3 +-
 drivers/of/overlay.c                               |   4 +-
 drivers/pci/controller/dwc/pci-imx6.c              |  13 +-
 drivers/pci/controller/dwc/pcie-designware.c       |   2 +-
 drivers/pci/controller/vmd.c                       |  27 +-
 drivers/pci/endpoint/functions/pci-epf-test.c      |   2 +-
 drivers/pci/endpoint/functions/pci-epf-vntb.c      |   2 +-
 drivers/pci/irq.c                                  |   2 +
 drivers/pci/probe.c                                |   3 -
 drivers/perf/arm_dmc620_pmu.c                      |   8 +-
 drivers/perf/arm_dsu_pmu.c                         |   6 +-
 drivers/perf/arm_smmuv3_pmu.c                      |   8 +-
 drivers/perf/hisilicon/hisi_pcie_pmu.c             |   8 +-
 drivers/perf/marvell_cn10k_tad_pmu.c               |   6 +-
 drivers/phy/broadcom/phy-brcm-usb-init-synopsys.c  |   9 +-
 drivers/phy/broadcom/phy-brcm-usb-init.h           |   1 -
 drivers/phy/broadcom/phy-brcm-usb.c                |  14 +-
 drivers/phy/marvell/phy-mvebu-a3700-comphy.c       |   3 +
 drivers/phy/qualcomm/phy-qcom-qmp-pcie.c           |  15 +-
 drivers/phy/qualcomm/phy-qcom-qmp-pcs-v5_20.h      |  14 +
 drivers/phy/qualcomm/phy-qcom-qmp.h                |   1 +
 drivers/pinctrl/mediatek/pinctrl-mt7986.c          |  24 +-
 drivers/pinctrl/pinconf-generic.c                  |   4 +-
 drivers/pinctrl/pinctrl-k210.c                     |   4 +-
 drivers/pinctrl/pinctrl-ocelot.c                   |  20 +-
 drivers/pinctrl/pinctrl-thunderbay.c               |   8 +-
 drivers/platform/chrome/cros_ec_typec.c            |  53 ++-
 drivers/platform/chrome/cros_usbpd_notify.c        |   6 +-
 drivers/platform/mellanox/mlxbf-pmc.c              |   2 +-
 drivers/platform/x86/huawei-wmi.c                  |  20 +-
 .../platform/x86/intel/int3472/clk_and_regulator.c |   3 +-
 drivers/platform/x86/intel_scu_ipc.c               |   2 +-
 drivers/platform/x86/mxm-wmi.c                     |   8 +-
 drivers/pnp/core.c                                 |   4 +-
 drivers/power/supply/ab8500_charger.c              |   9 +-
 drivers/power/supply/bq25890_charger.c             |  71 ++-
 drivers/power/supply/cw2015_battery.c              |  17 +-
 drivers/power/supply/power_supply_core.c           |   7 +-
 drivers/power/supply/z2_battery.c                  |   6 +-
 drivers/pwm/pwm-mediatek.c                         |   2 +-
 drivers/pwm/pwm-mtk-disp.c                         |   5 +-
 drivers/pwm/pwm-sifive.c                           |   5 +-
 drivers/pwm/pwm-tegra.c                            |  15 +-
 drivers/rapidio/devices/rio_mport_cdev.c           |  15 +-
 drivers/rapidio/rio-scan.c                         |   8 +-
 drivers/rapidio/rio.c                              |   9 +-
 drivers/regulator/core.c                           |  25 +-
 drivers/regulator/devres.c                         |   2 +-
 drivers/regulator/of_regulator.c                   |   2 +-
 drivers/regulator/qcom-labibb-regulator.c          |   1 +
 drivers/regulator/qcom-rpmh-regulator.c            |   2 +-
 drivers/regulator/stm32-vrefbuf.c                  |   2 +-
 drivers/remoteproc/qcom_q6v5_pas.c                 |   4 +
 drivers/remoteproc/qcom_q6v5_wcss.c                |   6 +-
 drivers/remoteproc/qcom_sysmon.c                   |   5 +-
 drivers/rtc/class.c                                |   4 +-
 drivers/rtc/rtc-cmos.c                             | 378 +++++++--------
 drivers/rtc/rtc-mxc_v2.c                           |   4 +-
 drivers/rtc/rtc-pcf85063.c                         |  10 +-
 drivers/rtc/rtc-pic32.c                            |   8 +-
 drivers/rtc/rtc-rzn1.c                             |   4 +-
 drivers/rtc/rtc-snvs.c                             |  16 +-
 drivers/rtc/rtc-st-lpc.c                           |   1 +
 drivers/s390/net/ctcm_main.c                       |  11 +-
 drivers/s390/net/lcs.c                             |   8 +-
 drivers/s390/net/netiucv.c                         |   9 +-
 drivers/scsi/elx/efct/efct_driver.c                |   1 +
 drivers/scsi/elx/libefc/efclib.h                   |   6 +-
 drivers/scsi/fcoe/fcoe.c                           |   1 +
 drivers/scsi/fcoe/fcoe_sysfs.c                     |  19 +-
 drivers/scsi/hisi_sas/hisi_sas_main.c              |   8 +-
 drivers/scsi/hpsa.c                                |   9 +-
 drivers/scsi/ipr.c                                 |  10 +-
 drivers/scsi/libsas/sas_ata.c                      |  25 +
 drivers/scsi/libsas/sas_expander.c                 |   4 +-
 drivers/scsi/libsas/sas_internal.h                 |   2 +
 drivers/scsi/lpfc/lpfc_sli.c                       |   6 +-
 drivers/scsi/mpt3sas/mpt3sas_transport.c           |   2 +
 drivers/scsi/qla2xxx/qla_def.h                     |  22 +-
 drivers/scsi/qla2xxx/qla_init.c                    |  20 +-
 drivers/scsi/qla2xxx/qla_inline.h                  |   4 +-
 drivers/scsi/qla2xxx/qla_os.c                      |   4 +-
 drivers/scsi/scsi_debug.c                          |  11 +-
 drivers/scsi/scsi_error.c                          |  14 +-
 drivers/scsi/smartpqi/smartpqi.h                   |   2 +-
 drivers/scsi/smartpqi/smartpqi_init.c              |  77 ++-
 drivers/scsi/snic/snic_disc.c                      |   3 +
 drivers/soc/apple/rtkit.c                          |   7 +-
 drivers/soc/apple/sart.c                           |   7 +-
 drivers/soc/mediatek/mtk-pm-domains.c              |   2 +-
 drivers/soc/qcom/apr.c                             |  15 +-
 drivers/soc/qcom/llcc-qcom.c                       |   2 +-
 drivers/soc/ti/knav_qmss_queue.c                   |   3 +-
 drivers/soc/ti/smartreflex.c                       |   1 +
 drivers/spi/spi-gpio.c                             |  16 +-
 drivers/spi/spi-mt65xx.c                           |   5 +
 drivers/spi/spidev.c                               |  21 +-
 drivers/staging/media/imx/imx7-media-csi.c         |   6 +-
 drivers/staging/media/rkvdec/rkvdec-vp9.c          |   3 +
 drivers/staging/media/stkwebcam/Kconfig            |   2 +-
 drivers/staging/media/sunxi/cedrus/cedrus_h265.c   |  25 +-
 drivers/staging/media/sunxi/cedrus/cedrus_regs.h   |   2 +
 drivers/staging/r8188eu/core/rtw_led.c             |  29 +-
 drivers/staging/r8188eu/core/rtw_pwrctrl.c         |   2 +-
 drivers/staging/rtl8192e/rtllib_rx.c               |   2 +-
 drivers/staging/rtl8192u/ieee80211/ieee80211_rx.c  |   4 +-
 drivers/staging/vme_user/vme_fake.c                |   2 +
 drivers/staging/vme_user/vme_tsi148.c              |   1 +
 drivers/target/iscsi/iscsi_target_nego.c           |  12 +-
 drivers/thermal/imx8mm_thermal.c                   |   8 +-
 drivers/thermal/k3_j72xx_bandgap.c                 |   2 +-
 drivers/thermal/qcom/lmh.c                         |   2 +-
 drivers/thermal/qcom/qcom-spmi-temp-alarm.c        |   3 +-
 drivers/thermal/thermal_core.c                     |  18 +-
 drivers/tty/serial/8250/8250_bcm7271.c             |  10 +-
 drivers/tty/serial/altera_uart.c                   |  21 +-
 drivers/tty/serial/amba-pl011.c                    |  14 +-
 drivers/tty/serial/pch_uart.c                      |   4 +
 drivers/tty/serial/serial-tegra.c                  |   6 +-
 drivers/tty/serial/stm32-usart.c                   |  47 +-
 drivers/tty/serial/sunsab.c                        |   8 +-
 drivers/ufs/core/ufshcd.c                          |  37 +-
 drivers/uio/uio_dmem_genirq.c                      |  13 +-
 drivers/usb/cdns3/cdnsp-ring.c                     |  42 +-
 drivers/usb/core/hcd.c                             |   6 +-
 drivers/usb/dwc3/core.c                            |  23 +-
 drivers/usb/gadget/function/f_hid.c                |  53 ++-
 drivers/usb/gadget/udc/core.c                      |  12 +-
 drivers/usb/gadget/udc/fotg210-udc.c               |  12 +-
 drivers/usb/host/xhci-mtk.c                        |   1 -
 drivers/usb/host/xhci-ring.c                       |  14 +-
 drivers/usb/host/xhci.h                            |   2 +-
 drivers/usb/musb/musb_gadget.c                     |   2 -
 drivers/usb/musb/omap2430.c                        |  54 +++
 drivers/usb/roles/class.c                          |   5 +-
 drivers/usb/storage/alauda.c                       |   2 +
 drivers/usb/typec/bus.c                            |   2 +-
 drivers/usb/typec/tcpm/tcpci.c                     |   5 +-
 drivers/usb/typec/tipd/core.c                      |  11 +-
 drivers/usb/typec/wusb3801.c                       |   2 +-
 drivers/vfio/platform/vfio_platform_common.c       |   3 +-
 drivers/video/fbdev/Kconfig                        |   2 +-
 drivers/video/fbdev/core/fbcon.c                   |   3 +-
 drivers/video/fbdev/ep93xx-fb.c                    |   4 +-
 drivers/video/fbdev/geode/Kconfig                  |   1 +
 drivers/video/fbdev/hyperv_fb.c                    |   8 +-
 drivers/video/fbdev/pm2fb.c                        |   9 +-
 drivers/video/fbdev/uvesafb.c                      |   1 +
 drivers/video/fbdev/vermilion/vermilion.c          |   4 +-
 drivers/video/fbdev/via/via-core.c                 |   9 +-
 drivers/virt/coco/sev-guest/sev-guest.c            |   1 +
 drivers/watchdog/iTCO_wdt.c                        |  21 +-
 drivers/xen/privcmd.c                              |   2 +-
 fs/afs/fs_probe.c                                  |   5 +-
 fs/binfmt_misc.c                                   |   8 +-
 fs/btrfs/file.c                                    |  10 +-
 fs/char_dev.c                                      |   2 +-
 fs/cifs/cifsencrypt.c                              |  12 +-
 fs/cifs/cifsfs.c                                   |  31 +-
 fs/cifs/cifsglob.h                                 | 114 ++++-
 fs/cifs/cifsproto.h                                |  17 +-
 fs/cifs/connect.c                                  |   6 +-
 fs/cifs/dir.c                                      |  30 +-
 fs/cifs/file.c                                     |  41 +-
 fs/cifs/fs_context.c                               |  12 +-
 fs/cifs/inode.c                                    | 167 ++++---
 fs/cifs/link.c                                     | 107 +----
 fs/cifs/misc.c                                     |   6 +-
 fs/cifs/readdir.c                                  |   2 +
 fs/cifs/sess.c                                     |  30 +-
 fs/cifs/smb1ops.c                                  |  56 ++-
 fs/cifs/smb2file.c                                 | 127 ++++-
 fs/cifs/smb2inode.c                                | 169 +++----
 fs/cifs/smb2ops.c                                  | 252 ++++------
 fs/cifs/smb2pdu.c                                  |  20 +-
 fs/cifs/smb2pdu.h                                  |   3 +
 fs/cifs/smb2proto.h                                |  22 +-
 fs/configfs/dir.c                                  |   2 +
 fs/debugfs/file.c                                  |  28 +-
 fs/erofs/decompressor.c                            |  47 +-
 fs/erofs/erofs_fs.h                                |   2 +
 fs/erofs/internal.h                                |   1 +
 fs/erofs/zdata.c                                   |   3 +-
 fs/erofs/zmap.c                                    |  25 +-
 fs/f2fs/compress.c                                 |   2 +-
 fs/f2fs/f2fs.h                                     |   2 +-
 fs/f2fs/file.c                                     |   4 +
 fs/f2fs/gc.c                                       |  10 +-
 fs/f2fs/namei.c                                    | 329 +++++++------
 fs/f2fs/segment.c                                  |   8 +-
 fs/f2fs/super.c                                    |   2 +-
 fs/hfs/inode.c                                     |   2 +
 fs/hfs/trans.c                                     |   2 +-
 fs/hugetlbfs/inode.c                               |   6 +-
 fs/jfs/jfs_dmap.c                                  |  27 +-
 fs/jfs/namei.c                                     |   2 +-
 fs/ksmbd/mgmt/user_session.c                       |   8 +-
 fs/libfs.c                                         |  22 +-
 fs/lockd/svcsubs.c                                 |  17 +-
 fs/nfs/fs_context.c                                |   6 +
 fs/nfs/internal.h                                  |   6 +-
 fs/nfs/namespace.c                                 |   2 +-
 fs/nfs/nfs42xdr.c                                  |   2 +-
 fs/nfs/nfs4proc.c                                  |  38 +-
 fs/nfs/nfs4state.c                                 |   2 +
 fs/nfs/nfs4xdr.c                                   |  22 +-
 fs/nfsd/nfs2acl.c                                  |  10 -
 fs/nfsd/nfs3acl.c                                  |  30 +-
 fs/nfsd/nfs4callback.c                             |   4 +-
 fs/nfsd/nfs4proc.c                                 |   7 +-
 fs/nfsd/nfs4state.c                                |  51 +-
 fs/nilfs2/the_nilfs.c                              |  73 ++-
 fs/ntfs3/bitmap.c                                  |   2 +-
 fs/ntfs3/super.c                                   |   2 +-
 fs/ntfs3/xattr.c                                   |   2 +-
 fs/ocfs2/journal.c                                 |   2 +-
 fs/ocfs2/journal.h                                 |   1 +
 fs/ocfs2/stackglue.c                               |   8 +-
 fs/ocfs2/super.c                                   |   5 +-
 fs/orangefs/orangefs-debugfs.c                     |  29 +-
 fs/orangefs/orangefs-mod.c                         |   8 +-
 fs/orangefs/orangefs-sysfs.c                       |  71 ++-
 fs/overlayfs/file.c                                |  28 +-
 fs/overlayfs/super.c                               |   7 +-
 fs/pstore/Kconfig                                  |   1 +
 fs/pstore/pmsg.c                                   |   7 +-
 fs/pstore/ram.c                                    |   2 +
 fs/pstore/ram_core.c                               |   6 +-
 fs/reiserfs/namei.c                                |   4 +
 fs/reiserfs/xattr_security.c                       |   2 +-
 fs/sysv/itree.c                                    |   2 +-
 fs/udf/namei.c                                     |   8 +-
 fs/xattr.c                                         |   2 +-
 include/drm/drm_connector.h                        |   6 +
 include/drm/ttm/ttm_tt.h                           |   2 +-
 include/dt-bindings/clock/imx8mn-clock.h           |  24 +-
 include/dt-bindings/clock/imx8mp-clock.h           |   3 +-
 .../dt-bindings/clock/qcom,lpassaudiocc-sc7280.h   |   5 +
 .../dt-bindings/clock/qcom,lpasscorecc-sc7280.h    |   2 +
 include/linux/blk-mq.h                             |   4 +
 include/linux/blkdev.h                             |  15 +-
 include/linux/btf_ids.h                            |   2 +-
 include/linux/debugfs.h                            |  19 +-
 include/linux/eventfd.h                            |   2 +-
 include/linux/fortify-string.h                     |  31 +-
 include/linux/fs.h                                 |  12 +-
 include/linux/hisi_acc_qm.h                        |  37 +-
 include/linux/hyperv.h                             |   2 +
 include/linux/ieee80211.h                          |   2 +-
 include/linux/iio/imu/adis.h                       |  13 +-
 include/linux/netdevice.h                          |  58 ++-
 include/linux/proc_fs.h                            |   2 +
 include/linux/regulator/driver.h                   |   3 +-
 include/linux/skmsg.h                              |   1 +
 include/linux/timerqueue.h                         |   2 +-
 include/media/dvbdev.h                             |  32 +-
 include/net/bluetooth/hci.h                        |  20 +
 include/net/bluetooth/hci_core.h                   |   7 +-
 include/net/dst.h                                  |   5 +-
 include/net/ip_vs.h                                |  10 +-
 include/net/mrp.h                                  |   1 +
 include/net/sock_reuseport.h                       |   2 +
 include/net/tcp.h                                  |   4 +-
 include/scsi/sas_ata.h                             |   6 +
 include/sound/hda_codec.h                          |   2 +-
 include/sound/hdaudio.h                            |   1 +
 include/sound/pcm.h                                |  36 +-
 include/trace/events/f2fs.h                        |  34 +-
 include/trace/events/ib_mad.h                      |  13 +-
 include/uapi/linux/idxd.h                          |   2 +-
 include/uapi/linux/swab.h                          |   2 +-
 include/uapi/rdma/hns-abi.h                        |  15 +
 include/uapi/sound/asequencer.h                    |   8 +-
 io_uring/msg_ring.c                                |   2 +
 io_uring/net.c                                     |   2 +-
 io_uring/timeout.c                                 |   4 +-
 ipc/mqueue.c                                       |   6 +-
 kernel/acct.c                                      |   2 +
 kernel/bpf/btf.c                                   |   5 +
 kernel/bpf/syscall.c                               |   6 +-
 kernel/bpf/verifier.c                              | 108 +++--
 kernel/cpu.c                                       |  60 ++-
 kernel/events/core.c                               |   8 +-
 kernel/fork.c                                      |  17 +-
 kernel/futex/core.c                                |  26 +-
 kernel/gcov/gcc_4_7.c                              |   5 +
 kernel/irq/internals.h                             |   2 +
 kernel/irq/irqdesc.c                               |  15 +-
 kernel/kprobes.c                                   |  16 +-
 kernel/module/decompress.c                         |   8 +-
 kernel/padata.c                                    |  15 +-
 kernel/power/snapshot.c                            |   4 +-
 kernel/rcu/tree.c                                  |   2 +-
 kernel/relay.c                                     |   4 +-
 kernel/sched/core.c                                |  10 +-
 kernel/sched/cpudeadline.c                         |   2 +-
 kernel/sched/deadline.c                            |   4 +-
 kernel/sched/fair.c                                | 231 +++++++--
 kernel/sched/psi.c                                 |   8 +-
 kernel/sched/rt.c                                  |   4 +-
 kernel/sched/sched.h                               |  56 ++-
 kernel/trace/blktrace.c                            |   3 +-
 kernel/trace/trace_events_hist.c                   |   2 +-
 kernel/trace/trace_events_user.c                   |   1 +
 lib/debugobjects.c                                 |  10 +
 lib/fonts/fonts.c                                  |   4 +-
 lib/notifier-error-inject.c                        |   2 +-
 lib/test_firmware.c                                |   1 +
 mm/gup.c                                           |   3 +
 net/802/mrp.c                                      |  18 +-
 net/8021q/vlan_dev.c                               |   4 +-
 net/9p/client.c                                    |   5 +
 net/bluetooth/hci_conn.c                           |   2 +-
 net/bluetooth/hci_core.c                           |   4 +-
 net/bluetooth/hci_sync.c                           |   2 +-
 net/bluetooth/lib.c                                |   4 +-
 net/bluetooth/mgmt.c                               |   2 +-
 net/bluetooth/rfcomm/core.c                        |   2 +-
 net/bpf/test_run.c                                 |   3 -
 net/bridge/br_multicast.c                          |   4 +-
 net/bridge/br_vlan.c                               |   4 +-
 net/core/dev.c                                     |  18 +-
 net/core/devlink.c                                 |   9 +-
 net/core/drop_monitor.c                            |   8 +-
 net/core/filter.c                                  |  11 +-
 net/core/gen_stats.c                               |  16 +-
 net/core/skbuff.c                                  |   3 +
 net/core/skmsg.c                                   |   9 +-
 net/core/sock.c                                    |   2 +-
 net/core/sock_map.c                                |   2 +
 net/core/sock_reuseport.c                          |  94 +++-
 net/core/stream.c                                  |   6 +
 net/dsa/slave.c                                    |   4 +-
 net/dsa/tag_8021q.c                                |  11 +-
 net/ethtool/ioctl.c                                |   3 +-
 net/hsr/hsr_debugfs.c                              |  40 +-
 net/hsr/hsr_device.c                               |  32 +-
 net/hsr/hsr_forward.c                              |  14 +-
 net/hsr/hsr_framereg.c                             | 222 ++++-----
 net/hsr/hsr_framereg.h                             |  17 +-
 net/hsr/hsr_main.h                                 |   9 +-
 net/hsr/hsr_netlink.c                              |   4 +-
 net/ipv4/af_inet.c                                 |   8 +-
 net/ipv4/inet_connection_sock.c                    |   5 +-
 net/ipv4/ping.c                                    |   2 +-
 net/ipv4/tcp_bpf.c                                 |  19 +-
 net/ipv4/udp.c                                     |  39 +-
 net/ipv4/udp_tunnel_core.c                         |   1 +
 net/ipv6/af_inet6.c                                |   4 +-
 net/ipv6/datagram.c                                |  15 +-
 net/ipv6/seg6_local.c                              |   4 +-
 net/ipv6/sit.c                                     |  22 +-
 net/ipv6/udp.c                                     |  12 +-
 net/mac80211/cfg.c                                 |   2 +-
 net/mac80211/ieee80211_i.h                         |   1 +
 net/mac80211/iface.c                               |   1 +
 net/mac80211/mlme.c                                |  15 +-
 net/mac80211/sta_info.c                            |   8 +-
 net/mac80211/tx.c                                  |   2 +-
 net/mctp/device.c                                  |  14 +-
 net/mpls/af_mpls.c                                 |   4 +-
 net/netfilter/ipvs/ip_vs_core.c                    |  30 +-
 net/netfilter/ipvs/ip_vs_ctl.c                     |  14 +-
 net/netfilter/ipvs/ip_vs_est.c                     |  20 +-
 net/netfilter/nf_conntrack_proto_icmpv6.c          |  53 +++
 net/netfilter/nf_flow_table_offload.c              |   6 +-
 net/netfilter/nf_tables_api.c                      |   4 +-
 net/openvswitch/datapath.c                         |  29 +-
 net/openvswitch/flow_table.c                       |   9 +-
 net/rxrpc/output.c                                 |   2 +-
 net/rxrpc/sendmsg.c                                |   2 +-
 net/sched/ematch.c                                 |   2 +
 net/sctp/sysctl.c                                  |  73 +--
 net/sunrpc/clnt.c                                  |   2 +-
 net/sunrpc/xprtrdma/verbs.c                        |   2 +-
 net/tls/tls_sw.c                                   |   6 +-
 net/unix/af_unix.c                                 |  12 +-
 net/vmw_vsock/vmci_transport.c                     |   6 +-
 net/wireless/nl80211.c                             |   3 +
 net/wireless/reg.c                                 |   4 +-
 samples/bpf/xdp1_user.c                            |   2 +-
 samples/bpf/xdp2_kern.c                            |   4 +
 samples/vfio-mdev/mdpy-fb.c                        |   8 +-
 security/Kconfig.hardening                         |   3 +
 security/apparmor/apparmorfs.c                     |   4 +-
 security/apparmor/label.c                          |  12 +-
 security/apparmor/lsm.c                            |   4 +-
 security/apparmor/policy.c                         |   2 +-
 security/apparmor/policy_ns.c                      |   2 +-
 security/apparmor/policy_unpack.c                  |   2 +-
 security/integrity/digsig.c                        |   6 +-
 security/integrity/ima/ima_policy.c                |  51 +-
 security/integrity/ima/ima_template.c              |   4 +-
 security/loadpin/loadpin.c                         |  30 +-
 sound/core/pcm_native.c                            |   4 +-
 sound/drivers/mts64.c                              |   3 +
 sound/hda/hdac_stream.c                            |  17 +-
 sound/pci/asihpi/hpioctl.c                         |   2 +-
 sound/pci/hda/hda_codec.c                          |   3 +-
 sound/pci/hda/hda_controller.c                     |   4 +-
 sound/pci/hda/patch_hdmi.c                         | 273 ++++++-----
 sound/pci/hda/patch_realtek.c                      |  27 ++
 sound/soc/amd/yc/acp6x-mach.c                      |   7 +
 sound/soc/codecs/hda.c                             |   3 -
 sound/soc/codecs/hdac_hda.c                        |   3 -
 sound/soc/codecs/pcm512x.c                         |   8 +-
 sound/soc/codecs/rt298.c                           |   7 +
 sound/soc/codecs/rt5670.c                          |   2 -
 sound/soc/codecs/wm8994.c                          |   5 +
 sound/soc/codecs/wsa883x.c                         |   6 +-
 sound/soc/generic/audio-graph-card.c               |   4 +-
 sound/soc/intel/avs/boards/rt298.c                 |  24 +-
 sound/soc/intel/avs/core.c                         |   2 +-
 sound/soc/intel/avs/ipc.c                          |   6 +-
 sound/soc/intel/boards/sof_es8336.c                |   2 +-
 sound/soc/intel/skylake/skl.c                      |   5 +-
 sound/soc/mediatek/common/mtk-btcvsd.c             |   6 +-
 sound/soc/mediatek/mt8173/mt8173-afe-pcm.c         |  20 +-
 sound/soc/mediatek/mt8173/mt8173-rt5650-rt5514.c   |   7 +-
 .../mt8183/mt8183-mt6358-ts3a227-max98357.c        |  14 +-
 sound/soc/pxa/mmp-pcm.c                            |   2 +-
 sound/soc/qcom/lpass-sc7180.c                      |   3 +
 sound/soc/rockchip/rockchip_pdm.c                  |   1 +
 sound/soc/rockchip/rockchip_spdif.c                |   1 +
 sound/usb/quirks-table.h                           |   2 +
 tools/bpf/bpftool/common.c                         |   1 +
 tools/lib/bpf/bpf.h                                |   7 +
 tools/lib/bpf/btf.c                                |   8 +-
 tools/lib/bpf/btf_dump.c                           |  29 +-
 tools/lib/bpf/libbpf.c                             |  30 +-
 tools/lib/bpf/usdt.c                               |  11 +-
 tools/objtool/check.c                              |  10 +
 tools/perf/builtin-stat.c                          |  33 +-
 tools/perf/builtin-trace.c                         |  32 +-
 tools/perf/tests/shell/stat_all_pmu.sh             |  13 +-
 tools/perf/util/bpf_off_cpu.c                      |   2 +-
 tools/perf/util/debug.c                            |   4 +
 tools/perf/util/symbol-elf.c                       |   2 +-
 .../selftests/bpf/bpf_testmod/bpf_testmod.c        |  48 ++
 tools/testing/selftests/bpf/config                 |   1 +
 tools/testing/selftests/bpf/network_helpers.c      |   4 +
 tools/testing/selftests/bpf/prog_tests/empty_skb.c | 146 ++++++
 .../selftests/bpf/prog_tests/kprobe_multi_test.c   |  26 +-
 .../testing/selftests/bpf/prog_tests/lsm_cgroup.c  |  17 +-
 tools/testing/selftests/bpf/prog_tests/map_kptr.c  |   3 +-
 .../selftests/bpf/prog_tests/tracing_struct.c      |  64 +++
 .../selftests/bpf/prog_tests/xdp_adjust_tail.c     |   7 +-
 .../selftests/bpf/prog_tests/xdp_do_redirect.c     |   2 +-
 .../selftests/bpf/prog_tests/xdp_synproxy.c        |   2 +-
 tools/testing/selftests/bpf/progs/bpf_iter_ksym.c  |   6 +-
 tools/testing/selftests/bpf/progs/empty_skb.c      |  37 ++
 tools/testing/selftests/bpf/progs/lsm_cgroup.c     |   8 +
 tools/testing/selftests/bpf/progs/tracing_struct.c | 120 +++++
 tools/testing/selftests/bpf/xdp_synproxy.c         |   5 +-
 tools/testing/selftests/cgroup/cgroup_util.c       |   5 +-
 .../selftests/drivers/net/netdevsim/devlink.sh     |   4 +-
 tools/testing/selftests/efivarfs/efivarfs.sh       |   5 +
 .../ftrace/test.d/ftrace/func_event_triggers.tc    |  15 +-
 .../selftests/netfilter/conntrack_icmp_related.sh  |  36 +-
 .../selftests/powerpc/dscr/dscr_sysfs_test.c       |   5 +-
 tools/testing/selftests/proc/proc-uptime-002.c     |   3 +-
 1042 files changed, 13129 insertions(+), 6952 deletions(-)



^ permalink raw reply	[relevance 1%]

* [PATCH 6.1 0000/1146] 6.1.2-rc1 review
@ 2022-12-28 14:25  1% Greg Kroah-Hartman
  2022-12-28 14:40  8% ` [PATCH 6.1 0896/1146] bpf: prevent leak of lsm program after failed attach Greg Kroah-Hartman
  0 siblings, 1 reply; 77+ results
From: Greg Kroah-Hartman @ 2022-12-28 14:25 UTC (permalink / raw)
  To: stable
  Cc: Greg Kroah-Hartman, patches, linux-kernel, torvalds, akpm, linux,
	shuah, patches, lkft-triage, pavel, jonathanh, f.fainelli,
	sudipm.mukherjee, srw, rwarsow

This is the start of the stable review cycle for the 6.1.2 release.
There are 1146 patches in this series, all will be posted as a response
to this one.  If anyone has any issues with these being applied, please
let me know.

Responses should be made by Fri, 30 Dec 2022 14:41:29 +0000.
Anything received after that time might be too late.

The whole patch series can be found in one patch at:
	https://www.kernel.org/pub/linux/kernel/v6.x/stable-review/patch-6.1.2-rc1.gz
or in the git tree and branch at:
	git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable-rc.git linux-6.1.y
and the diffstat can be found below.

thanks,

greg k-h

-------------
Pseudo-Shortlog of commits:

Greg Kroah-Hartman <gregkh@linuxfoundation.org>
    Linux 6.1.2-rc1

Martin Leung <Martin.Leung@amd.com>
    drm/amd/display: revert Disable DRR actions during state commit

Lin Ma <linma@zju.edu.cn>
    media: dvbdev: fix refcnt bug

Lin Ma <linma@zju.edu.cn>
    media: dvbdev: fix build warning due to comments

Gaosheng Cui <cuigaosheng1@huawei.com>
    net: stmmac: fix errno when create_singlethread_workqueue() fails

Pavel Begunkov <asml.silence@gmail.com>
    io_uring: remove iopoll spinlock

Pavel Begunkov <asml.silence@gmail.com>
    io_uring: protect cq_timeouts with timeout_lock

Pavel Begunkov <asml.silence@gmail.com>
    io_uring/net: fix cleanup after recycle

Jens Axboe <axboe@kernel.dk>
    io_uring/net: ensure compat import handlers clear free_iov

Pavel Begunkov <asml.silence@gmail.com>
    io_uring: improve io_double_lock_ctx fail handling

Pavel Begunkov <asml.silence@gmail.com>
    io_uring: dont remove file from msg_ring reqs

Pavel Begunkov <asml.silence@gmail.com>
    io_uring: add completion locking for iopoll

Stefan Metzmacher <metze@samba.org>
    io_uring/net: introduce IORING_SEND_ZC_REPORT_USAGE flag

Tejun Heo <tj@kernel.org>
    blk-iolatency: Fix memory leak on add_disk() failures

Arun Easi <aeasi@marvell.com>
    scsi: qla2xxx: Fix crash when I/O abort times out

David Hildenbrand <david@redhat.com>
    mm/gup: disallow FOLL_FORCE|FOLL_WRITE on hugetlb mappings

Filipe Manana <fdmanana@suse.com>
    btrfs: do not BUG_ON() on ENOMEM when dropping extent items for a range

Chen Zhongjin <chenzhongjin@huawei.com>
    ovl: fix use inode directly in rcu-walk mode

Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
    fbdev: fbcon: release buffer when fbcon_do_set_font() failed

Liam Howlett <liam.howlett@oracle.com>
    maple_tree: fix mas_spanning_rebalance() on insufficient data

Liam Howlett <liam.howlett@oracle.com>
    test_maple_tree: add test for mas_spanning_rebalance() on insufficient data

Rickard x Andersson <rickaran@axis.com>
    gcov: add support for checksum field

Yuan Can <yuancan@huawei.com>
    floppy: Fix memory leak in do_floppy_init()

Christophe Leroy <christophe.leroy@csgroup.eu>
    spi: fsl_spi: Don't change speed while chipselect is active

Johan Hovold <johan+linaro@kernel.org>
    regulator: core: fix deadlock on regulator enable

Rasmus Villemoes <linux@rasmusvillemoes.dk>
    iio: addac: ad74413r: fix integer promotion bug in ad74413_get_input_current_offset()

Rasmus Villemoes <linux@rasmusvillemoes.dk>
    iio: adc128s052: add proper .data members in adc128_of_match table

Nuno Sá <nuno.sa@analog.com>
    iio: adc: ad_sigma_delta: do not use internal iio_dev lock

Zeng Heng <zengheng4@huawei.com>
    iio: fix memory leak in iio_device_register_eventset()

Roberto Sassu <roberto.sassu@huawei.com>
    reiserfs: Add missing calls to reiserfs_security_free()

Nathan Chancellor <nathan@kernel.org>
    security: Restrict CONFIG_ZERO_CALL_USED_REGS to gcc or clang > 15.0.6

Schspa Shi <schspa@gmail.com>
    9p: set req refcount to zero to avoid uninitialized usage

Isaac J. Manjarres <isaacmanjarres@google.com>
    loop: Fix the max_loop commandline argument treatment when it is set to 0

Enrik Berkhan <Enrik.Berkhan@inka.de>
    HID: mcp2221: don't connect hidraw

Jason Gerecke <killertofu@gmail.com>
    HID: wacom: Ensure bootloader PID is usable in hidraw mode

Mathias Nyman <mathias.nyman@linux.intel.com>
    xhci: Prevent infinite loop in transaction errors recovery for streams

Miaoqian Lin <linmq006@gmail.com>
    usb: dwc3: qcom: Fix memory leak in dwc3_qcom_interconnect_init

Ferry Toth <ftoth@exalondelft.nl>
    usb: dwc3: core: defer probe on ulpi_read_id timeout

Sven Peter <sven@svenpeter.dev>
    usb: dwc3: Fix race between dwc3_set_mode and __dwc3_set_mode

Li Jun <jun.li@nxp.com>
    clk: imx: imx8mp: add shared clk gate for usb suspend clk

Li Jun <jun.li@nxp.com>
    dt-bindings: clocks: imx8mp: Add ID for usb suspend clock

Johan Hovold <johan+linaro@kernel.org>
    arm64: dts: qcom: sm8250: fix USB-DP PHY registers

Johan Hovold <johan+linaro@kernel.org>
    arm64: dts: qcom: sm6350: fix USB-DP PHY registers

Chunfeng Yun <chunfeng.yun@mediatek.com>
    usb: xhci-mtk: fix leakage of shared hcd when fail to set wakeup irq

Pawel Laszczak <pawell@cadence.com>
    usb: cdnsp: fix lack of ZLP for ep0

Bastien Nocera <hadess@hadess.net>
    HID: logitech-hidpp: Guard FF init code against non-USB devices

Jiao Zhou <jiaozhou@google.com>
    ALSA: hda/hdmi: Add HP Device 0x8711 to force connect list

Edward Pacman <edward@edward-p.xyz>
    ALSA: hda/realtek: Add quirk for Lenovo TianYi510Pro-14IOB

wangdicheng <wangdicheng@kylinos.cn>
    ALSA: usb-audio: add the quirk for KT0206 device

Takashi Iwai <tiwai@suse.de>
    ALSA: usb-audio: Workaround for XRUN at prepare

Jeff LaBundy <jeff@labundy.com>
    dt-bindings: input: iqs7222: Add support for IQS7222A v1.13+

Jeff LaBundy <jeff@labundy.com>
    dt-bindings: input: iqs7222: Correct minimum slider size

Jeff LaBundy <jeff@labundy.com>
    dt-bindings: input: iqs7222: Reduce 'linux,code' to optional

Jeff LaBundy <jeff@labundy.com>
    Input: iqs7222 - add support for IQS7222A v1.13+

Jeff LaBundy <jeff@labundy.com>
    Input: iqs7222 - report malformed properties

Jeff LaBundy <jeff@labundy.com>
    Input: iqs7222 - drop unused device node references

GUO Zihua <guozihua@huawei.com>
    ima: Simplify ima_lsm_copy_rule

John Stultz <jstultz@google.com>
    pstore: Make sure CONFIG_PSTORE_PMSG selects CONFIG_RT_MUTEXES

Sami Tolvanen <samitolvanen@google.com>
    cfi: Fix CFI failure with KASAN

David Howells <dhowells@redhat.com>
    afs: Fix lost servers_outstanding count

Michael Petlan <mpetlan@redhat.com>
    perf test: Fix "all PMU test" to skip parametrized events

Sergio Paracuellos <sergio.paracuellos@gmail.com>
    MIPS: ralink: mt7621: avoid to init common ralink reset controller

Yang Jihong <yangjihong1@huawei.com>
    perf probe: Check -v and -q options in the right place

James Clark <james.clark@arm.com>
    perf tools: Make quiet mode consistent between tools

Yang Jihong <yangjihong1@huawei.com>
    perf debug: Set debug_peo_args and redirect_to_stderr variable to correct values in perf_quiet_option()

Arnd Bergmann <arnd@arndb.de>
    drm/amd/pm: avoid large variable on kernel stack

John Stultz <jstultz@google.com>
    pstore: Switch pmsg_lock to an rt_mutex to avoid priority inversion

Kristina Martsenko <kristina.martsenko@arm.com>
    lkdtm: cfi: Make PAC test work with GCC 7 and 8

Kees Cook <keescook@chromium.org>
    LoadPin: Ignore the "contents" argument of the LSM hooks

Khaled Almahallawy <khaled.almahallawy@intel.com>
    drm/i915/display: Don't disable DDI/Transcoder when setting phy test pattern

Hans de Goede <hdegoede@redhat.com>
    ASoC: rt5670: Remove unbalanced pm_runtime_put()

Wang Jingjin <wangjingjin1@huawei.com>
    ASoC: rockchip: spdif: Add missing clk_disable_unprepare() in rk_spdif_runtime_resume()

Marek Szyprowski <m.szyprowski@samsung.com>
    ASoC: wm8994: Fix potential deadlock

Kai Vehmanen <kai.vehmanen@linux.intel.com>
    ALSA: hda/hdmi: fix stream-id config keep-alive for rt suspend

Kai Vehmanen <kai.vehmanen@linux.intel.com>
    ALSA: hda/hdmi: set default audio parameters for KAE silent-stream

Kai Vehmanen <kai.vehmanen@linux.intel.com>
    ALSA: hda/hdmi: fix i915 silent stream programming flow

Wang Yufen <wangyufen@huawei.com>
    ASoC: mediatek: mt8183: fix refcount leak in mt8183_mt6358_ts3a227_max98357_dev_probe()

Wang Jingjin <wangjingjin1@huawei.com>
    ASoC: rockchip: pdm: Add missing clk_disable_unprepare() in rockchip_pdm_runtime_resume()

Wang Yufen <wangyufen@huawei.com>
    ASoC: audio-graph-card: fix refcount leak of cpu_ep in __graph_for_each_link()

Wang Yufen <wangyufen@huawei.com>
    ASoC: mediatek: mt8173-rt5650-rt5514: fix refcount leak in mt8173_rt5650_rt5514_dev_probe()

Cezary Rojewski <cezary.rojewski@intel.com>
    ASoC: Intel: Skylake: Fix driver hang during shutdown

Yang Yingliang <yangyingliang@huawei.com>
    ASoC: sof_es8336: fix possible use-after-free in sof_es8336_remove()

Yang Yingliang <yangyingliang@huawei.com>
    hwmon: (jc42) Fix missing unlock on error in jc42_write()

Zhang Xiaoxu <zhangxiaoxu5@huawei.com>
    orangefs: Fix kmemleak in orangefs_{kernel,client}_debug_init()

Zhang Xiaoxu <zhangxiaoxu5@huawei.com>
    orangefs: Fix kmemleak in orangefs_sysfs_init()

Zhang Xiaoxu <zhangxiaoxu5@huawei.com>
    orangefs: Fix kmemleak in orangefs_prepare_debugfs_help_string()

Maurizio Lombardi <mlombard@redhat.com>
    scsi: target: iscsi: Fix a race condition between login_work and the login thread

Nathan Chancellor <nathan@kernel.org>
    drm/sti: Fix return type of sti_{dvo,hda,hdmi}_connector_mode_valid()

Nathan Chancellor <nathan@kernel.org>
    drm/fsl-dcu: Fix return type of fsl_dcu_drm_connector_mode_valid()

Kumar Meiyappan <Kumar.Meiyappan@microchip.com>
    scsi: smartpqi: Correct device removal for multi-actuator devices

Mike McGowen <mike.mcgowen@microchip.com>
    scsi: smartpqi: Add new controller PCI IDs

Hawkins Jiawei <yin31149@gmail.com>
    hugetlbfs: fix null-ptr-deref in hugetlbfs_parse_param()

Nathan Chancellor <nathan@kernel.org>
    scsi: elx: libefc: Fix second parameter type in state callbacks

Bjorn Helgaas <bhelgaas@google.com>
    Revert "PCI: Clear PCI_STATUS when setting up device"

Kai Ye <yekai13@huawei.com>
    crypto: hisilicon/qm - increase the memory of local variables

Bart Van Assche <bvanassche@acm.org>
    scsi: ufs: Reduce the START STOP UNIT timeout

Justin Tee <justin.tee@broadcom.com>
    scsi: lpfc: Fix hard lockup when reading the rx_monitor from debugfs

Zhiqi Song <songzhiqi1@huawei.com>
    crypto: hisilicon/hpre - fix resource leak in remove process

ChiYuan Huang <cy_huang@richtek.com>
    regulator: core: Fix resolve supply lookup issue

Sven Peter <sven@svenpeter.dev>
    Bluetooth: Add quirk to disable MWS Transport Configuration

Sven Peter <sven@svenpeter.dev>
    Bluetooth: Add quirk to disable extended scanning

Marek Vasut <marex@denx.de>
    Bluetooth: hci_bcm: Add CYW4373A0 support

Jacob Keller <jacob.e.keller@intel.com>
    ice: synchronize the misc IRQ when tearing down Tx tracker

ChiYuan Huang <cy_huang@richtek.com>
    regulator: core: Use different devices for resource allocation and DT lookup

Xiu Jianfeng <xiujianfeng@huawei.com>
    clk: st: Fix memory leak in st_of_quadfs_setup()

Shigeru Yoshida <syoshida@redhat.com>
    media: si470x: Fix use-after-free in si470x_int_in_callback()

Prathamesh Shete <pshete@nvidia.com>
    mmc: sdhci-tegra: Issue CMD and DAT resets together

Wolfram Sang <wsa+renesas@sang-engineering.com>
    mmc: renesas_sdhi: better reset from HS400 mode

Wolfram Sang <wsa+renesas@sang-engineering.com>
    mmc: renesas_sdhi: add quirk for broken register layout

Kunihiko Hayashi <hayashi.kunihiko@socionext.com>
    mmc: f-sdh30: Add quirks for broken timeout clock capability

Hawkins Jiawei <yin31149@gmail.com>
    nfs: fix possible null-ptr-deref when parsing param

James Hilliard <james.hilliard1@gmail.com>
    selftests/bpf: Fix conflicts with built-in functions in bpf_iter_ksym

Denis Pauk <pauk.denis@gmail.com>
    hwmon: (nct6775) add ASUS CROSSHAIR VIII/TUF/ProArt B550M

Lorenzo Bianconi <lorenzo@kernel.org>
    wifi: mt76: do not run mt76u_status_worker if the device is not running

Rui Zhang <zr.zhang@vivo.com>
    regulator: core: fix use_count leakage when handling boot-on

Andrii Nakryiko <andrii@kernel.org>
    libbpf: Avoid enum forward-declarations in public API in C++ mode

Artem Lukyanov <dukzcry@ya.ru>
    ASoC: amd: yc: Add Xiaomi Redmi Book Pro 14 2022 into DMI table

Alvin Lee <Alvin.Lee2@amd.com>
    drm/amd/display: Fix DTBCLK disable requests and SRC_SEL programming

Wesley Chalmers <Wesley.Chalmers@amd.com>
    drm/amd/display: Use the largest vready_offset in pipe group

Liang He <windhl@126.com>
    drm/amdgpu: Fix potential double free and null pointer dereference

John Keeping <john@metanate.com>
    ALSA: usb-audio: Add quirk for Tascam Model 12

Ye Bin <yebin10@huawei.com>
    blk-mq: fix possible memleak when register 'hctx' failed

Yunfei Dong <yunfei.dong@mediatek.com>
    media: mediatek: vcodec: Can't set dst buffer to done when lat decode error

Mazin Al Haddad <mazinalhaddad05@gmail.com>
    media: dvb-usb: fix memory leak in dvb_usb_adapter_init()

Lin Ma <linma@zju.edu.cn>
    media: dvbdev: adopts refcnt to avoid UAF

Yan Lei <yan_lei@dahuatech.com>
    media: dvb-frontends: fix leak of memory fw

Maxim Korotkov <korotkov.maxim.s@gmail.com>
    ethtool: avoiding integer overflow in ethtool_phys_id()

Stanislav Fomichev <sdf@google.com>
    bpf: Prevent decl_tag from being referenced in func_proto arg

Yonghong Song <yhs@fb.com>
    bpf: Fix a BTF_ID_LIST bug with CONFIG_DEBUG_INFO_BTF not set

Ilya Bakoulin <Ilya.Bakoulin@amd.com>
    drm/amd/display: Fix display corruption w/ VSR enable

Stanislav Fomichev <sdf@google.com>
    ppp: associate skb with a device at tx

Kees Cook <keescook@chromium.org>
    bpf/verifier: Use kmalloc_size_roundup() to match ksize() usage

Felix Fietkau <nbd@nbd.name>
    net: ethernet: mtk_eth_soc: drop packets to WDMA if the ring is full

Schspa Shi <schspa@gmail.com>
    mrp: introduce active flags to prevent UAF when applicant uninit

Eric Dumazet <edumazet@google.com>
    ipv6/sit: use DEV_STATS_INC() to avoid data-races

Eric Dumazet <edumazet@google.com>
    net: add atomic_long_t to net_device_stats fields

Sagi Grimberg <sagi@grimberg.me>
    nvme-auth: don't override ctrl keys before validation

Aurabindo Pillai <aurabindo.pillai@amd.com>
    drm/amd/display: fix array index out of bound error in bios parser

George Shen <george.shen@amd.com>
    drm/amd/display: Workaround to increase phantom pipe vactive in pipesplit

Jiang Li <jiang.li@ugreen.com>
    md/raid1: stop mdx_raid1 thread when raid1 array run failed

Xiao Ni <xni@redhat.com>
    md/raid0, raid10: Don't set discard sectors for request queue

Li Zhong <floridsleeves@gmail.com>
    drivers/md/md-bitmap: check the return value of md_bitmap_get_counter()

Nathan Chancellor <nathan@kernel.org>
    drm/mediatek: Fix return type of mtk_hdmi_bridge_mode_valid()

Ville Syrjälä <ville.syrjala@linux.intel.com>
    drm/sti: Use drm_mode_copy()

Ville Syrjälä <ville.syrjala@linux.intel.com>
    drm/rockchip: Use drm_mode_copy()

Ville Syrjälä <ville.syrjala@linux.intel.com>
    drm/msm: Use drm_mode_copy()

Wesley Chalmers <Wesley.Chalmers@amd.com>
    drm/amd/display: Disable DRR actions during state commit

Alvin Lee <Alvin.Lee2@amd.com>
    drm/amd/display: Use min transition for SubVP into MPO

Nathan Chancellor <nathan@kernel.org>
    s390/lcs: Fix return type of lcs_start_xmit()

Nathan Chancellor <nathan@kernel.org>
    s390/netiucv: Fix return type of netiucv_tx()

Nathan Chancellor <nathan@kernel.org>
    s390/ctcm: Fix return type of ctc{mp,}m_tx()

Nathan Chancellor <nathan@kernel.org>
    drm/amdgpu: Fix type of second parameter in odn_edit_dpm_table() callback

Nathan Chancellor <nathan@kernel.org>
    drm/amdgpu: Fix type of second parameter in trans_msg() callback

Kees Cook <keescook@chromium.org>
    igb: Do not free q_vector unless new one was allocated

José Expósito <jose.exposito89@gmail.com>
    HID: uclogic: Add support for XP-PEN Deco LW

José Expósito <jose.exposito89@gmail.com>
    HID: input: do not query XP-PEN Deco LW battery

Jisoo Jang <jisoo.jang@yonsei.ac.kr>
    wifi: brcmfmac: Fix potential NULL pointer dereference in 'brcmf_c_preinit_dcmds()'

Minsuk Kang <linuxlovemin@yonsei.ac.kr>
    wifi: brcmfmac: Fix potential shift-out-of-bounds in brcmf_fw_alloc_request()

Nathan Chancellor <nathan@kernel.org>
    hamradio: baycom_epp: Fix return type of baycom_send_packet()

Nathan Chancellor <nathan@kernel.org>
    net: ethernet: ti: Fix return type of netcp_ndo_start_xmit()

Stanislav Fomichev <sdf@google.com>
    bpf: make sure skb->len != 0 when redirecting to a tunneling device

Nathan Chancellor <nathan@kernel.org>
    drm/meson: Fix return type of meson_encoder_cvbs_mode_valid()

Jiri Slaby (SUSE) <jirislaby@kernel.org>
    qed (gcc13): use u16 for fid to be big enough

Rahul Bhattacharjee <quic_rbhattac@quicinc.com>
    wifi: ath11k: Fix qmi_msg_handler data structure initialization

Kerem Karabay <kekrby@gmail.com>
    HID: apple: enable APPLE_ISO_TILDE_QUIRK for the keyboards of Macs with the T2 chip

Kerem Karabay <kekrby@gmail.com>
    HID: apple: fix key translations where multiple quirks attempt to translate the same key

David Jeffery <djeffery@redhat.com>
    blk-mq: avoid double ->queue_rq() because of early timeout

Yuan Can <yuancan@huawei.com>
    drm/rockchip: use pm_runtime_resume_and_get() instead of pm_runtime_get_sync()

Hamza Mahfooz <hamza.mahfooz@amd.com>
    Revert "drm/amd/display: Limit max DSC target bpp for specific monitors"

Hamza Mahfooz <hamza.mahfooz@amd.com>
    drm/edid: add a quirk for two LG monitors to get them to work on 10bpc

gehao <gehao@kylinos.cn>
    drm/amd/display: prevent memory leak

zhikzhai <zhikai.zhai@amd.com>
    drm/amd/display: skip commit minimal transition state

Kees Cook <keescook@chromium.org>
    bnx2: Use kmalloc_size_roundup() to match ksize() usage

Kees Cook <keescook@chromium.org>
    openvswitch: Use kmalloc_size_roundup() to match ksize() usage

Youghandhar Chintala <quic_youghand@quicinc.com>
    wifi: ath10k: Delay the unmapping of the buffer

Zhang Yuchen <zhangyuchen.lcr@bytedance.com>
    ipmi: fix memleak when unload ipmi driver

Amadeusz Sławiński <amadeuszx.slawinski@linux.intel.com>
    ASoC: Intel: avs: Add quirk for KBL-R RVP platform

Amadeusz Sławiński <amadeuszx.slawinski@linux.intel.com>
    ASoC: codecs: rt298: Add quirk for KBL-R RVP platform

Shigeru Yoshida <syoshida@redhat.com>
    wifi: ar5523: Fix use-after-free on ar5523_cmd() timed out

Fedor Pchelkin <pchelkin@ispras.ru>
    wifi: ath9k: verify the expected usb_endpoints are present

Wright Feng <wright.feng@cypress.com>
    brcmfmac: return error when getting invalid max_flowrings from dongle

Ming Qian <ming.qian@nxp.com>
    media: imx-jpeg: Disable useless interrupt to avoid kernel panic

Doug Brown <doug@schmorgal.com>
    drm/etnaviv: add missing quirks for GC300

ZhangPeng <zhangpeng362@huawei.com>
    hfs: fix OOB Read in __hfs_brec_find

Hans de Goede <hdegoede@redhat.com>
    ACPI: x86: Add skip i2c clients quirk for Medion Lifetab S10346

Josef Bacik <josef@toxicpanda.com>
    btrfs: do not panic if we can't allocate a prealloc extent state

Hans de Goede <hdegoede@redhat.com>
    ACPI: x86: Add skip i2c clients quirk for Lenovo Yoga Tab 3 Pro (YT3-X90F)

Mateusz Jończyk <mat.jonczyk@o2.pl>
    x86/apic: Handle no CONFIG_X86_X2APIC on systems with x2APIC enabled by BIOS

Zheng Yejian <zhengyejian1@huawei.com>
    acct: fix potential integer overflow in encode_comp_t()

Ryusuke Konishi <konishi.ryusuke@gmail.com>
    nilfs2: fix shift-out-of-bounds due to too large exponent of block size

Ryusuke Konishi <konishi.ryusuke@gmail.com>
    nilfs2: fix shift-out-of-bounds/overflow in nilfs_sb2_bad_offset()

Hans de Goede <hdegoede@redhat.com>
    ACPI: video: Add force_native quirk for Sony Vaio VPCY11S1E

Hans de Goede <hdegoede@redhat.com>
    ACPI: video: Add force_vendor quirk for Sony Vaio PCG-FRV35

Hans de Goede <hdegoede@redhat.com>
    ACPI: video: Change Sony Vaio VPCEH3U1E quirk to force_native

Hans de Goede <hdegoede@redhat.com>
    ACPI: video: Change GIGABYTE GB-BXBT-2807 quirk to force_none

Guenter Roeck <linux@roeck-us.net>
    thermal/core: Ensure that thermal device is registered in thermal_zone_get_temp

Rafael J. Wysocki <rafael.j.wysocki@intel.com>
    ACPICA: Fix error code path in acpi_ds_call_control_method()

Mia Kanashi <chad@redpilled.dev>
    ACPI: EC: Add quirk for the HP Pavilion Gaming 15-cx0041ur

Li Zhong <floridsleeves@gmail.com>
    ACPI: processor: idle: Check acpi_fetch_acpi_dev() return value

Hoi Pok Wu <wuhoipok@gmail.com>
    fs: jfs: fix shift-out-of-bounds in dbDiscardAG

Dr. David Alan Gilbert <linux@treblig.org>
    jfs: Fix fortify moan in symlink

Shigeru Yoshida <syoshida@redhat.com>
    udf: Avoid double brelse() in udf_rename()

Dongliang Mu <mudongliangabcd@gmail.com>
    fs: jfs: fix shift-out-of-bounds in dbAllocAG

Marijn Suijten <marijn.suijten@somainline.org>
    arm64: dts: qcom: sm6350: Add apps_smmu with streamID to SDHCI 1/2 nodes

Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
    arm64: dts: qcom: sm8450: disable SDHCI SDR104/SDR50 on all boards

Liu Shixin <liushixin2@huawei.com>
    binfmt_misc: fix shift-out-of-bounds in check_special_flags

Gaurav Kohli <gauravkohli@linux.microsoft.com>
    x86/hyperv: Remove unregister syscore call from Hyper-V cleanup

Guilherme G. Piccoli <gpiccoli@igalia.com>
    video: hyperv_fb: Avoid taking busy spinlock on panic path

Adriana Kobylak <anoo@us.ibm.com>
    ARM: dts: aspeed: rainier,everest: Move reserved memory regions

Mark Rutland <mark.rutland@arm.com>
    arm64: make is_ttbrX_addr() noinstr-safe

Zqiang <qiang1.zhang@intel.com>
    rcu: Fix __this_cpu_read() lockdep warning in rcu_force_quiescent_state()

Wei Fang <wei.fang@nxp.com>
    net: fec: check the return value of build_skb()

Jiasheng Jiang <jiasheng@iscas.ac.cn>
    HID: amd_sfh: Add missing check for dma_alloc_coherent

Matt Johnston <matt@codeconstruct.com.au>
    mctp: Remove device type check at unregister

Arun Ramadoss <arun.ramadoss@microchip.com>
    net: dsa: microchip: remove IRQF_TRIGGER_FALLING in request_threaded_irq

Paulo Alcantara <pc@cjr.nz>
    cifs: don't leak -ENOMEM in smb2_open_file()

Jeremy Kerr <jk@codeconstruct.com.au>
    mctp: serial: Fix starting value for frame check sequence

Eric Dumazet <edumazet@google.com>
    net: stream: purge sk_error_queue in sk_stream_kill_queues()

Christophe JAILLET <christophe.jaillet@wanadoo.fr>
    myri10ge: Fix an error handling path in myri10ge_probe()

David Howells <dhowells@redhat.com>
    rxrpc: Fix missing unlock in rxrpc_do_sendmsg()

Cong Wang <cong.wang@bytedance.com>
    net_sched: reject TCF_EM_SIMPLE case for complex ematch module

Yang Yingliang <yangyingliang@huawei.com>
    mailbox: zynq-ipi: fix error handling while device_register() fails

Yang Yingliang <yangyingliang@huawei.com>
    mailbox: arm_mhuv2: Fix return value check in mhuv2_probe()

Conor Dooley <conor.dooley@microchip.com>
    mailbox: mpfs: read the system controller's status

Subash Abhinov Kasiviswanathan <quic_subashab@quicinc.com>
    skbuff: Account for tail adjustment during pull operations

Jakub Kicinski <kuba@kernel.org>
    devlink: protect devlink dump by the instance lock

Chen-Yu Tsai <wenst@chromium.org>
    arm64: dts: mt8183: Fix Mali GPU clock

Chun-Jie Chen <chun-jie.chen@mediatek.com>
    soc: mediatek: pm-domains: Fix the power glitch issue

Eelco Chaudron <echaudro@redhat.com>
    openvswitch: Fix flow lookup to use unmasked key

Jakub Kicinski <kuba@kernel.org>
    selftests: devlink: fix the fd redirect in dummy_reporter_test

Jakub Kicinski <kuba@kernel.org>
    devlink: hold region lock when flushing snapshots

GUO Zihua <guozihua@huawei.com>
    rtc: mxc_v2: Add missing clk_disable_unprepare()

Tan Tee Min <tee.min.tan@linux.intel.com>
    igc: Set Qbv start_time and end_time to end_time if not being configured in GCL

Tan Tee Min <tee.min.tan@linux.intel.com>
    igc: recalculate Qbv end_time by considering cycle time

Tan Tee Min <tee.min.tan@linux.intel.com>
    igc: allow BaseTime 0 enrollment for Qbv

Muhammad Husaini Zulkifli <muhammad.husaini.zulkifli@intel.com>
    igc: Add checking for basetime less than zero

Vinicius Costa Gomes <vinicius.gomes@intel.com>
    igc: Use strict cycles for Qbv scheduling

Vinicius Costa Gomes <vinicius.gomes@intel.com>
    igc: Enhance Qbv scheduling by using first flag bit

Vladimir Oltean <vladimir.oltean@nxp.com>
    net: dsa: mv88e6xxx: avoid reg_lock deadlock in mv88e6xxx_setup_port()

Ming Lei <ming.lei@redhat.com>
    block: fix use-after-free of q->q_usage_counter

Christoph Hellwig <hch@lst.de>
    block: mark blk_put_queue as potentially blocking

Christoph Hellwig <hch@lst.de>
    block: untangle request_queue refcounting from sysfs

Christoph Hellwig <hch@lst.de>
    block: fix error unwinding in blk_register_queue

Christoph Hellwig <hch@lst.de>
    block: factor out a blk_debugfs_remove helper

Christoph Hellwig <hch@lst.de>
    blk-crypto: pass a gendisk to blk_crypto_sysfs_{,un}register

Christoph Hellwig <hch@lst.de>
    blk-mq: move the srcu_struct used for quiescing to the tagset

Li Zetao <lizetao1@huawei.com>
    r6040: Fix kmemleak in probe and remove

Kirill Tkhai <tkhai@ya.ru>
    unix: Fix race in SOCK_SEQPACKET's unix_dgram_sendmsg()

Minsuk Kang <linuxlovemin@yonsei.ac.kr>
    nfc: pn533: Clear nfc_target before being used

Vladimir Oltean <vladimir.oltean@nxp.com>
    net: enetc: avoid buffer leaks on xdp_do_redirect() failure

Hans Verkuil <hverkuil-cisco@xs4all.nl>
    media: v4l2-ctrls-api.c: add back dropped ctrl->is_new = 1

Milan Landaverde <milan@mdaverde.com>
    bpf: prevent leak of lsm program after failed attach

Song Liu <song@kernel.org>
    selftests/bpf: Select CONFIG_FUNCTION_ERROR_INJECTION

Yu Kuai <yukuai3@huawei.com>
    block, bfq: fix possible uaf for 'bfqq->bic'

Yang Yingliang <yangyingliang@huawei.com>
    mISDN: hfcmulti: don't call dev_kfree_skb/kfree_skb() under spin_lock_irqsave()

Yang Yingliang <yangyingliang@huawei.com>
    mISDN: hfcpci: don't call dev_kfree_skb/kfree_skb() under spin_lock_irqsave()

Yang Yingliang <yangyingliang@huawei.com>
    mISDN: hfcsusb: don't call dev_kfree_skb/kfree_skb() under spin_lock_irqsave()

Hangbin Liu <liuhangbin@gmail.com>
    bonding: do failover when high prio link up

Hangbin Liu <liuhangbin@gmail.com>
    bonding: add missed __rcu annotation for curr_active_slave

Emeel Hakim <ehakim@nvidia.com>
    net: macsec: fix net device access prior to holding a lock

Dan Aloni <dan.aloni@vastdata.com>
    nfsd: under NFSv4.1, fix double svc_xprt_put on rpc_create failure

Dan Carpenter <error27@gmail.com>
    iommu/mediatek: Fix forever loop in error handling

Alexandre Belloni <alexandre.belloni@bootlin.com>
    rtc: pcf85063: fix pcf85063_clkout_control

Gaosheng Cui <cuigaosheng1@huawei.com>
    rtc: pic32: Move devm_rtc_allocate_device earlier in pic32_rtc_probe()

Gaosheng Cui <cuigaosheng1@huawei.com>
    rtc: st-lpc: Add missing clk_disable_unprepare in st_rtc_probe()

Qingfang DENG <dqfext@gmail.com>
    netfilter: flowtable: really fix NAT IPv6 offload

Yang Yingliang <yangyingliang@huawei.com>
    mfd: pm8008: Fix return value check in pm8008_probe()

Christophe JAILLET <christophe.jaillet@wanadoo.fr>
    mfd: qcom_rpm: Fix an error handling path in qcom_rpm_probe()

Matti Vaittinen <mazziesaccount@gmail.com>
    mfd: bd957x: Fix Kconfig dependency on REGMAP_IRQ

Samuel Holland <samuel@sholland.org>
    mfd: axp20x: Do not sleep in the power off handler

Bryan O'Donoghue <bryan.odonoghue@linaro.org>
    dt-bindings: mfd: qcom,spmi-pmic: Drop PWM reg dependency

Nathan Lynch <nathanl@linux.ibm.com>
    powerpc/pseries/eeh: use correct API for error log size

Shang XiaoJing <shangxiaojing@huawei.com>
    remoteproc: qcom: q6v5: Fix missing clk_disable_unprepare() in q6v5_wcss_qcs404_power_on()

Yuan Can <yuancan@huawei.com>
    remoteproc: qcom_q6v5_pas: Fix missing of_node_put() in adsp_alloc_memory_region()

Luca Weiss <luca.weiss@fairphone.com>
    remoteproc: qcom_q6v5_pas: detach power domains on remove

Luca Weiss <luca.weiss@fairphone.com>
    remoteproc: qcom_q6v5_pas: disable wakeup on probe fail or remove

Shang XiaoJing <shangxiaojing@huawei.com>
    remoteproc: qcom: q6v5: Fix potential null-ptr-deref in q6v5_wcss_init_mmio()

Gaosheng Cui <cuigaosheng1@huawei.com>
    remoteproc: sysmon: fix memory leak in qcom_add_sysmon_subdev()

Anup Patel <apatel@ventanamicro.com>
    RISC-V: KVM: Fix reg_val check in kvm_riscv_vcpu_set_reg_config()

Daniel Golle <daniel@makrotopia.org>
    pwm: mediatek: always use bus clock for PWM on MT7622

xinlei lee <xinlei.lee@mediatek.com>
    pwm: mtk-disp: Fix the parameters calculated by the enabled flag of disp_pwm

Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
    pwm: sifive: Call pwm_sifive_update_clock() while mutex is held

Jason Gunthorpe <jgg@ziepe.ca>
    iommu/sun50i: Remove IOMMU_DOMAIN_IDENTITY

Guenter Roeck <groeck@chromium.org>
    iommu/mediatek: Validate number of phandles associated with "mediatek,larbs"

Yong Wu <yong.wu@mediatek.com>
    iommu/mediatek: Add error path for loop of mm_dts_parse

Yong Wu <yong.wu@mediatek.com>
    iommu/mediatek: Use component_match_add

Yong Wu <yong.wu@mediatek.com>
    iommu/mediatek: Add platform_device_put for recovering the device refcnt

Miaoqian Lin <linmq006@gmail.com>
    selftests/powerpc: Fix resource leaks

Kajol Jain <kjain@linux.ibm.com>
    powerpc/hv-gpci: Fix hv_gpci event list

Yang Yingliang <yangyingliang@huawei.com>
    powerpc/83xx/mpc832x_rdb: call platform_device_put() in error case in of_fsl_spi_probe()

Nicholas Piggin <npiggin@gmail.com>
    powerpc/perf: callchain validate kernel stack pointer bounds

Pali Rohár <pali@kernel.org>
    powerpc: dts: turris1x.dts: Add channel labels for temperature sensor

Li Huafei <lihuafei1@huawei.com>
    kprobes: Fix check for probe enabled in kill_kprobe()

Nayna Jain <nayna@linux.ibm.com>
    powerpc/pseries: fix plpks_read_var() code for different consumers

Nayna Jain <nayna@linux.ibm.com>
    powerpc/pseries: Return -EIO instead of -EINTR for H_ABORTED error

Nayna Jain <nayna@linux.ibm.com>
    powerpc/pseries: Fix the H_CALL error code in PLPKS driver

Nayna Jain <nayna@linux.ibm.com>
    powerpc/pseries: fix the object owners enum value in plpks driver

Yang Yingliang <yangyingliang@huawei.com>
    powerpc/xive: add missing iounmap() in error path in xive_spapr_populate_irq_data()

Gustavo A. R. Silva <gustavoars@kernel.org>
    powerpc/xmon: Fix -Wswitch-unreachable warning in bpt_cmds

Miaoqian Lin <linmq006@gmail.com>
    cxl: Fix refcount leak in cxl_calc_capp_routing

Christophe JAILLET <christophe.jaillet@wanadoo.fr>
    powerpc/52xx: Fix a resource leak in an error handling path

Xie Shaowen <studentxswpy@163.com>
    macintosh/macio-adb: check the return value of ioremap()

Yang Yingliang <yangyingliang@huawei.com>
    macintosh: fix possible memory leak in macio_add_one_device()

Yuan Can <yuancan@huawei.com>
    iommu/fsl_pamu: Fix resource leak in fsl_pamu_probe()

Yang Yingliang <yangyingliang@huawei.com>
    iommu/amd: Fix pci device refcount leak in ppr_notifier()

Robin Murphy <robin.murphy@arm.com>
    iommu: Avoid races around device probe

Yang Yingliang <yangyingliang@huawei.com>
    iommu/mediatek: Check return value after calling platform_get_resource()

Alexander Stein <alexander.stein@ew.tq-group.com>
    rtc: pcf85063: Fix reading alarm

Stefan Eichenberger <stefan.eichenberger@toradex.com>
    rtc: snvs: Allow a time difference on clock register read

Rafael J. Wysocki <rafael.j.wysocki@intel.com>
    rtc: cmos: Disable ACPI RTC event on removal

Rafael J. Wysocki <rafael.j.wysocki@intel.com>
    rtc: cmos: Rename ACPI-related functions

Rafael J. Wysocki <rafael.j.wysocki@intel.com>
    rtc: cmos: Eliminate forward declarations of some functions

Rafael J. Wysocki <rafael.j.wysocki@intel.com>
    rtc: cmos: Call rtc_wake_setup() from cmos_do_probe()

Rafael J. Wysocki <rafael.j.wysocki@intel.com>
    rtc: cmos: Call cmos_wake_setup() from cmos_do_probe()

Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
    rtc: pcf2127: Convert to .probe_new()

Shang XiaoJing <shangxiaojing@huawei.com>
    rtc: class: Fix potential memleak in devm_rtc_allocate_device()

Yushan Zhou <katrinzhou@tencent.com>
    rtc: rzn1: Check return value in rzn1_rtc_probe

Fenghua Yu <fenghua.yu@intel.com>
    dmaengine: idxd: Fix crc_val field for completion record

Abdun Nihaal <abdun.nihaal@gmail.com>
    fs/ntfs3: Fix slab-out-of-bounds read in ntfs_trim_fs

Manivannan Sadhasivam <mani@kernel.org>
    phy: qcom-qmp-pcie: Fix sm8450_qmp_gen4x2_pcie_pcs_tbl[] register names

Manivannan Sadhasivam <mani@kernel.org>
    phy: qcom-qmp-pcie: Fix high latency with 4x2 PHY when ASPM is enabled

Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
    phy: qcom-qmp-pcie: Support SM8450 PCIe1 PHY in EP mode

Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
    phy: qcom-qmp-pcie: support separate tables for EP mode

Christian Marangi <ansuelsmth@gmail.com>
    phy: qcom-qmp-pcie: split pcs_misc init cfg for ipq8074 pcs table

Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
    phy: qcom-qmp-pcie: split register tables into common and extra parts

Jon Hunter <jonathanh@nvidia.com>
    pwm: tegra: Ensure the clock rate is not less than needed

Jon Hunter <jonathanh@nvidia.com>
    pwm: tegra: Improve required rate calculation

Matt Redfearn <matt.redfearn@mips.com>
    include/uapi/linux/swab: Fix potentially missing __always_inline

Justin Chen <justinpopo6@gmail.com>
    phy: usb: Fix clock imbalance for suspend/resume

Justin Chen <justinpopo6@gmail.com>
    phy: usb: Use slow clock for wake enabled suspend

Al Cooper <alcooperx@gmail.com>
    phy: usb: s2 WoL wakeup_count not incremented for USB->Eth devices

Johan Hovold <johan+linaro@kernel.org>
    phy: qcom-qmp-usb: fix sc8280xp PCS_USB offset

Xiaochen Shen <xiaochen.shen@intel.com>
    dmaengine: idxd: Make read buffer sysfs attributes invisible for Intel IAA

Michael Riesch <michael.riesch@wolfvision.net>
    iommu/rockchip: fix permission bits in page table entries v2

Jernej Skrabec <jernej.skrabec@gmail.com>
    iommu/sun50i: Implement .iotlb_sync_map

Jernej Skrabec <jernej.skrabec@gmail.com>
    iommu/sun50i: Fix flush size

Jernej Skrabec <jernej.skrabec@gmail.com>
    iommu/sun50i: Fix R/W permission check

Jernej Skrabec <jernej.skrabec@gmail.com>
    iommu/sun50i: Consider all fault sources for reset

Jernej Skrabec <jernej.skrabec@gmail.com>
    iommu/sun50i: Fix reset release

Niklas Schnelle <schnelle@linux.ibm.com>
    iommu/s390: Fix duplicate domain attachments

Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
    phy: qcom-qmp-usb: correct registers layout for IPQ8074 USB3 PHY

Johan Hovold <johan+linaro@kernel.org>
    phy: qcom-qmp-usb: drop start and pwrdn-ctrl abstraction

Johan Hovold <johan+linaro@kernel.org>
    phy: qcom-qmp-usb: clean up status polling

Johan Hovold <johan+linaro@kernel.org>
    phy: qcom-qmp-usb: drop power-down delay config

Johan Hovold <johan+linaro@kernel.org>
    phy: qcom-qmp-usb: drop sc8280xp power-down delay

Johan Hovold <johan+linaro@kernel.org>
    phy: qcom-qmp-usb: clean up power-down handling

Johan Hovold <johan+linaro@kernel.org>
    phy: qcom-qmp-pcie: fix ipq6018 initialisation

Johan Hovold <johan+linaro@kernel.org>
    phy: qcom-qmp-pcie: fix ipq8074-gen3 initialisation

Johan Hovold <johan+linaro@kernel.org>
    phy: qcom-qmp-pcie: fix sc8180x initialisation

Johan Hovold <johan+linaro@kernel.org>
    phy: qcom-qmp-pcie: replace power-down delay

Johan Hovold <johan+linaro@kernel.org>
    phy: qcom-qmp-pcie: drop power-down delay config

Shengjiu Wang <shengjiu.wang@nxp.com>
    remoteproc: core: Auto select rproc-virtio device id

Martin Povišer <povik+lin@cutebit.org>
    dmaengine: apple-admac: Allocate cache SRAM to channels

Xiaochen Shen <xiaochen.shen@intel.com>
    dmaengine: idxd: Make max batch size attributes in sysfs invisible for Intel IAA

Johan Hovold <johan+linaro@kernel.org>
    phy: qcom-qmp-pcie: drop bogus register update

Pali Rohár <pali@kernel.org>
    phy: marvell: phy-mvebu-a3700-comphy: Reset COMPHY registers before USB 3.0 power on

Dan Carpenter <error27@gmail.com>
    fs/ntfs3: Harden against integer overflows

Shigeru Yoshida <syoshida@redhat.com>
    fs/ntfs3: Avoid UBSAN error on true_sectors_per_clst()

Arnd Bergmann <arnd@arndb.de>
    RDMA/siw: Fix pointer cast warning

Namhyung Kim <namhyung@kernel.org>
    perf stat: Do not delay the workload with --delay

Ard Biesheuvel <ardb@kernel.org>
    ftrace: Allow WITH_ARGS flavour of graph tracer with shadow call stack

Namhyung Kim <namhyung@kernel.org>
    perf off_cpu: Fix a typo in BTF tracepoint name, it should be 'btf_trace_sched_switch'

Luca Weiss <luca@z3ntu.xyz>
    leds: is31fl319x: Fix setting current limit for is31fl319{0,1,3}

Andreas Gruenbacher <agruenba@redhat.com>
    gfs2: Partially revert gfs2_inode_lookup change

ruanjinjie <ruanjinjie@huawei.com>
    power: supply: fix null pointer dereferencing in power_supply_get_battery_info

James Clark <james.clark@arm.com>
    perf branch: Fix interpretation of branch records

Hans de Goede <hdegoede@redhat.com>
    power: supply: bq25890: Ensure pump_express_work is cancelled on remove

Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
    power: supply: bq25890: Convert to i2c's .probe_new()

Marek Vasut <marex@denx.de>
    power: supply: bq25890: Factor out regulator registration code

Qiheng Lin <linqiheng@huawei.com>
    power: supply: Fix refcount leak in rk817_charger_probe

Yuan Can <yuancan@huawei.com>
    power: supply: ab8500: Fix error handling in ab8500_charger_init()

Yuan Can <yuancan@huawei.com>
    HSI: omap_ssi_core: Fix error handling in ssi_init()

Shang XiaoJing <shangxiaojing@huawei.com>
    power: supply: cw2015: Fix potential null-ptr-deref in cw_bat_probe()

Zhang Qilong <zhangqilong3@huawei.com>
    power: supply: z2_battery: Fix possible memleak in z2_batt_probe()

Ajay Kaher <akaher@vmware.com>
    perf symbol: correction while adjusting symbol

Leo Yan <leo.yan@linaro.org>
    perf trace: Handle failure when trace point folder is missed

Leo Yan <leo.yan@linaro.org>
    perf trace: Use macro RAW_SYSCALL_ARGS_NUM to replace number

Leo Yan <leo.yan@linaro.org>
    perf trace: Return error if a system call doesn't exist

Mika Westerberg <mika.westerberg@linux.intel.com>
    watchdog: iTCO_wdt: Set NO_REBOOT if the watchdog is not already running

Zeng Heng <zengheng4@huawei.com>
    power: supply: fix residue sysfs file in error handle route of __power_supply_register()

Yang Yingliang <yangyingliang@huawei.com>
    HSI: omap_ssi_core: fix possible memory leak in ssi_probe()

Yang Yingliang <yangyingliang@huawei.com>
    HSI: omap_ssi_core: fix unbalanced pm_runtime_disable()

Namhyung Kim <namhyung@kernel.org>
    perf stat: Move common code in print_metric_headers()

Namhyung Kim <namhyung@kernel.org>
    perf stat: Use evsel__is_hybrid() more

James Clark <james.clark@arm.com>
    perf tools: Fix "kernel lock contention analysis" test by not printing warnings in quiet mode

Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
    led: qcom-lpg: Fix sleeping in atomic

Christophe JAILLET <christophe.jaillet@wanadoo.fr>
    fbdev: uvesafb: Fixes an error handling path in uvesafb_probe()

Randy Dunlap <rdunlap@infradead.org>
    fbdev: uvesafb: don't build on UML

Randy Dunlap <rdunlap@infradead.org>
    fbdev: geode: don't build on UML

Gaosheng Cui <cuigaosheng1@huawei.com>
    fbdev: ep93xx-fb: Add missing clk_disable_unprepare in ep93xxfb_probe()

Xiongfeng Wang <wangxiongfeng2@huawei.com>
    fbdev: vermilion: decrease reference count in error path

Shang XiaoJing <shangxiaojing@huawei.com>
    fbdev: via: Fix error in via_core_init()

Yang Yingliang <yangyingliang@huawei.com>
    fbdev: pm2fb: fix missing pci_disable_device()

Andy Shevchenko <andriy.shevchenko@linux.intel.com>
    fbdev: ssd1307fb: Drop optional dependency

Bjorn Andersson <andersson@kernel.org>
    thermal/drivers/qcom/lmh: Fix irq handler return value

Luca Weiss <luca.weiss@fairphone.com>
    thermal/drivers/qcom/temp-alarm: Fix inaccurate warning for gen2

Ido Schimmel <idosch@nvidia.com>
    thermal/of: Fix memory leak on thermal_of_zone_register() failure

Keerthy <j-keerthy@ti.com>
    thermal/drivers/k3_j72xx_bandgap: Fix the debug print message

Marcus Folkesson <marcus.folkesson@gmail.com>
    thermal/drivers/imx8mm_thermal: Validate temperature range

Shang XiaoJing <shangxiaojing@huawei.com>
    samples: vfio-mdev: Fix missing pci_disable_device() in mdpy_fb_probe()

Xiu Jianfeng <xiujianfeng@huawei.com>
    ksmbd: Fix resource leak in ksmbd_session_rpc_open()

Zheng Yejian <zhengyejian1@huawei.com>
    tracing/hist: Fix issue of losting command info in error_log

Yang Yingliang <yangyingliang@huawei.com>
    usb: typec: wusb3801: fix fwnode refcount leak in wusb3801_probe()

Jiasheng Jiang <jiasheng@iscas.ac.cn>
    usb: storage: Add check for kcalloc

Zheyu Ma <zheyuma97@gmail.com>
    i2c: ismt: Fix an out-of-bounds bug in ismt_access()

Yang Yingliang <yangyingliang@huawei.com>
    i2c: mux: reg: check return value after calling platform_get_resource()

Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
    gpiolib: protect the GPIO device against being dropped while in use by user-space

Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
    gpiolib: cdev: fix NULL-pointer dereferences

Chen Zhongjin <chenzhongjin@huawei.com>
    vme: Fix error not catched in fake_init()

YueHaibing <yuehaibing@huawei.com>
    staging: rtl8192e: Fix potential use-after-free in rtllib_rx_Monitor()

Dan Carpenter <error27@gmail.com>
    staging: rtl8192u: Fix use after free in ieee80211_rx()

Hui Tang <tanghui20@huawei.com>
    i2c: pxa-pci: fix missing pci_disable_device() on error in ce4100_i2c_probe

Joao Martins <joao.m.martins@oracle.com>
    vfio/iova_bitmap: refactor iova_bitmap_set() to better handle page boundaries

Yang Yingliang <yangyingliang@huawei.com>
    chardev: fix error handling in cdev_device_add()

Yang Yingliang <yangyingliang@huawei.com>
    mcb: mcb-parse: fix error handing in chameleon_parse_gdd()

Zhengchao Shao <shaozhengchao@huawei.com>
    drivers: mcb: fix resource leak in mcb_probe()

John Keeping <john@metanate.com>
    usb: gadget: f_hid: fix refcount leak on error path

John Keeping <john@metanate.com>
    usb: gadget: f_hid: fix f_hidg lifetime vs cdev

Yang Yingliang <yangyingliang@huawei.com>
    usb: core: hcd: Fix return value check in usb_hcd_setup_local_mem()

Yang Yingliang <yangyingliang@huawei.com>
    usb: roles: fix of node refcount leak in usb_role_switch_is_parent()

Beau Belgrave <beaub@linux.microsoft.com>
    tracing/user_events: Fix call print_fmt leak

Mike Leach <mike.leach@linaro.org>
    coresight: cti: Fix null pointer error on CTI init before ETM

Yang Shen <shenyang39@huawei.com>
    coresight: trbe: remove cpuhp instance node before remove cpuhp state

Fabrice Gasnier <fabrice.gasnier@foss.st.com>
    counter: stm32-lptimer-cnt: fix the check on arr and cmp registers update

Ramona Bolboaca <ramona.bolboaca@analog.com>
    iio: adis: add '__adis_enable_irq()' implementation

Cosmin Tanislav <cosmin.tanislav@analog.com>
    iio: temperature: ltc2983: make bulk write buffer DMA-safe

Yang Yingliang <yangyingliang@huawei.com>
    cxl: fix possible null-ptr-deref in cxl_pci_init_afu|adapter()

Yang Yingliang <yangyingliang@huawei.com>
    cxl: fix possible null-ptr-deref in cxl_guest_init_afu|adapter()

Yang Yingliang <yangyingliang@huawei.com>
    firmware: raspberrypi: fix possible memory leak in rpi_firmware_probe()

Zheng Wang <zyytlz.wz@163.com>
    misc: sgi-gru: fix use-after-free error in gru_set_context_option, gru_fault and gru_handle_user_call_os

ruanjinjie <ruanjinjie@huawei.com>
    misc: tifm: fix possible memory leak in tifm_7xx1_switch_media()

Yang Yingliang <yangyingliang@huawei.com>
    ocxl: fix pci device refcount leak when calling get_function_0()

Yang Yingliang <yangyingliang@huawei.com>
    misc: ocxl: fix possible name leak in ocxl_file_register_afu()

Zhengchao Shao <shaozhengchao@huawei.com>
    test_firmware: fix memory leak in test_firmware_init()

Yang Yingliang <yangyingliang@huawei.com>
    habanalabs: fix return value check in hl_fw_get_sec_attest_data()

Yuan Can <yuancan@huawei.com>
    serial: sunsab: Fix error handling in sunsab_init()

Gabriel Somlo <gsomlo@gmail.com>
    serial: altera_uart: fix locking in polling mode

Xiongfeng Wang <wangxiongfeng2@huawei.com>
    serial: pch: Fix PCI device refcount leak in pch_request_dma()

Valentin Caron <valentin.caron@foss.st.com>
    serial: stm32: move dma_request_chan() before clk_prepare_enable()

delisun <delisun@pateo.com.cn>
    serial: pl011: Do not clear RX FIFO & RX interrupt in unthrottle.

Jiamei Xie <jiamei.xie@arm.com>
    serial: amba-pl011: avoid SBSA UART accessing DMACR register

Jiantao Zhang <water.zhangjiantao@huawei.com>
    USB: gadget: Fix use-after-free during usb config switch

Marek Vasut <marex@denx.de>
    extcon: usbc-tusb320: Update state on probe even if no IRQ pending

Tony Lindgren <tony@atomide.com>
    usb: musb: omap2430: Fix probe regression for missing resources

Sven Peter <sven@svenpeter.dev>
    usb: typec: tipd: Fix typec_unregister_port error paths

Sven Peter <sven@svenpeter.dev>
    usb: typec: tipd: Fix spurious fwnode_handle_put in error path

Sven Peter <sven@svenpeter.dev>
    usb: typec: tipd: Cleanup resources if devm_tps6598_psy_register fails

Yang Yingliang <yangyingliang@huawei.com>
    usb: typec: tcpci: fix of node refcount leak in tcpci_register_port()

Sven Peter <sven@svenpeter.dev>
    usb: typec: Check for ops->exit instead of ops->enter in altmode_exit

Gaosheng Cui <cuigaosheng1@huawei.com>
    staging: vme_user: Fix possible UAF in tsi148_dma_list_add

Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
    interconnect: qcom: sc7180: fix dropped const of qcom_icc_bcm

Linus Walleij <linus.walleij@linaro.org>
    usb: fotg210-udc: Fix ages old endianness issues

Rafael Mendonca <rafaelmendsr@gmail.com>
    uio: uio_dmem_genirq: Fix deadlock between irq config and handling

Rafael Mendonca <rafaelmendsr@gmail.com>
    uio: uio_dmem_genirq: Fix missing unlock in irq configuration

Joao Martins <joao.m.martins@oracle.com>
    vfio/iova_bitmap: Fix PAGE_SIZE unaligned bitmaps

Rafael Mendonca <rafaelmendsr@gmail.com>
    vfio: platform: Do not pass return buffer to ACPI _RST method

Yang Yingliang <yangyingliang@huawei.com>
    class: fix possible memory leak in __class_register()

Duoming Zhou <duoming@zju.edu.cn>
    drivers: staging: r8188eu: Fix sleep-in-atomic-context bug in rtw_join_timeout_handler

Yuan Can <yuancan@huawei.com>
    serial: 8250_bcm7271: Fix error handling in brcmuart_init()

Kartik <kkartik@nvidia.com>
    serial: tegra: Read DMA status before terminating

Yang Yingliang <yangyingliang@huawei.com>
    drivers: dio: fix possible memory leak in dio_init()

Alexandre Ghiti <alexghiti@rivosinc.com>
    riscv: Fix P4D_SHIFT definition for 3-level page table mode

Yangtao Li <frank.li@vivo.com>
    f2fs: fix iostat parameter for discard

Palmer Dabbelt <palmer@rivosinc.com>
    RISC-V: Align the shadow stack

Dragos Tatulea <dtatulea@nvidia.com>
    IB/IPoIB: Fix queue count inconsistency for PKEY child interfaces

Xiongfeng Wang <wangxiongfeng2@huawei.com>
    hwrng: geode - Fix PCI device refcount leak

Xiongfeng Wang <wangxiongfeng2@huawei.com>
    hwrng: amd - Fix PCI device refcount leak

Gaosheng Cui <cuigaosheng1@huawei.com>
    crypto: img-hash - Fix variable dereferenced before check 'hdev->req'

Samuel Holland <samuel@sholland.org>
    riscv: Fix crash during early errata patching

Anup Patel <apatel@ventanamicro.com>
    RISC-V: Fix MEMREMAP_WB for systems with Svpbmt

Andrew Bresticker <abrestic@rivosinc.com>
    RISC-V: Fix unannoted hardirqs-on in return to userspace slow-path

Chengchang Tang <tangchengchang@huawei.com>
    RDMA/hns: Fix XRC caps on HIP08

Chengchang Tang <tangchengchang@huawei.com>
    RDMA/hns: Fix error code of CMD

Chengchang Tang <tangchengchang@huawei.com>
    RDMA/hns: Fix page size cap from firmware

Chengchang Tang <tangchengchang@huawei.com>
    RDMA/hns: Fix PBL page MTR find

Chengchang Tang <tangchengchang@huawei.com>
    RDMA/hns: Fix AH attr queried by query_qp

Yixing Liu <liuyixing1@huawei.com>
    RDMA/hns: Fix the gid problem caused by free mr

Zhang Xiaoxu <zhangxiaoxu5@huawei.com>
    orangefs: Fix sysfs not cleanup when dev init failed

Francisco Munoz <francisco.munoz.ruiz@linux.intel.com>
    PCI: vmd: Fix secondary bus reset for Intel bridges

Wang Yufen <wangyufen@huawei.com>
    RDMA/srp: Fix error return code in srp_parse_options()

Wang Yufen <wangyufen@huawei.com>
    RDMA/hfi1: Fix error return code in parse_platform_config()

Randy Dunlap <rdunlap@infradead.org>
    RDMA: Disable IB HW for UML

Tong Tiangen <tongtiangen@huawei.com>
    riscv/mm: add arch hook arch_clear_hugepage_flags

Shang XiaoJing <shangxiaojing@huawei.com>
    crypto: omap-sham - Use pm_runtime_resume_and_get() in omap_sham_probe()

Christophe JAILLET <christophe.jaillet@wanadoo.fr>
    crypto: amlogic - Remove kcalloc without check

Wang Yufen <wangyufen@huawei.com>
    crypto: qat - fix error return code in adf_probe

Mark Zhang <markzhang@nvidia.com>
    RDMA/nldev: Fix failure to send large messages

Yonggil Song <yonggil.song@samsung.com>
    f2fs: avoid victim selection from previous victim section

Sheng Yong <shengyong@oppo.com>
    f2fs: fix to enable compress for newly created file if extension matches

Sheng Yong <shengyong@oppo.com>
    f2fs: set zstd compress level correctly

Yuan Can <yuancan@huawei.com>
    RDMA/nldev: Add checks for nla_nest_start() in fill_stat_counter_qps()

Bart Van Assche <bvanassche@acm.org>
    scsi: ufs: core: Fix the polling implementation

Gaosheng Cui <cuigaosheng1@huawei.com>
    scsi: snic: Fix possible UAF in snic_tgt_create()

Chen Zhongjin <chenzhongjin@huawei.com>
    scsi: fcoe: Fix transport not deattached when fcoe_if_init() fails

Shang XiaoJing <shangxiaojing@huawei.com>
    scsi: ipr: Fix WARNING in ipr_init()

Yang Yingliang <yangyingliang@huawei.com>
    scsi: scsi_debug: Fix possible name leak in sdebug_add_host_helper()

Yang Yingliang <yangyingliang@huawei.com>
    scsi: fcoe: Fix possible name leak when device_register() fails

Harshit Mogalapalli <harshit.m.mogalapalli@oracle.com>
    scsi: scsi_debug: Fix a warning in resp_report_zones()

Harshit Mogalapalli <harshit.m.mogalapalli@oracle.com>
    scsi: scsi_debug: Fix a warning in resp_verify()

Chen Zhongjin <chenzhongjin@huawei.com>
    scsi: efct: Fix possible memleak in efct_device_init()

Yang Yingliang <yangyingliang@huawei.com>
    scsi: hpsa: Fix possible memory leak in hpsa_add_sas_device()

Yang Yingliang <yangyingliang@huawei.com>
    scsi: hpsa: Fix error handling in hpsa_add_sas_host()

Yang Yingliang <yangyingliang@huawei.com>
    scsi: mpt3sas: Fix possible resource leaks in mpt3sas_transport_port_add()

Weili Qian <qianweili@huawei.com>
    crypto: hisilicon/qm - fix 'QM_XEQ_DEPTH_CAP' mask value

Eric Biggers <ebiggers@google.com>
    crypto: arm64/sm3 - fix possible crash with CFI enabled

Tianjia Zhang <tianjia.zhang@linux.alibaba.com>
    crypto: arm64/sm3 - add NEON assembly implementation

Eric Biggers <ebiggers@google.com>
    crypto: x86/sm4 - fix crash with CFI enabled

Eric Biggers <ebiggers@google.com>
    crypto: x86/sm3 - fix possible crash with CFI enabled

Eric Biggers <ebiggers@google.com>
    crypto: x86/sha512 - fix possible crash with CFI enabled

Eric Biggers <ebiggers@google.com>
    crypto: x86/sha256 - fix possible crash with CFI enabled

Eric Biggers <ebiggers@google.com>
    crypto: x86/sha1 - fix possible crash with CFI enabled

Eric Biggers <ebiggers@google.com>
    crypto: x86/aria - fix crash with CFI enabled

Eric Biggers <ebiggers@google.com>
    crypto: x86/aegis128 - fix possible crash with CFI enabled

Daniel Jordan <daniel.m.jordan@oracle.com>
    padata: Fix list iterator in padata_do_serial()

Daniel Jordan <daniel.m.jordan@oracle.com>
    padata: Always leave BHs disabled when running ->parallel()

Zhang Yiqun <zhangyiqun@phytium.com.cn>
    crypto: tcrypt - Fix multibuffer skcipher speed test mem leak

Yuan Can <yuancan@huawei.com>
    scsi: hpsa: Fix possible memory leak in hpsa_init_one()

Frank Li <frank.li@nxp.com>
    PCI: endpoint: pci-epf-vntb: Fix call pci_epc_mem_free_addr() in error path

Serge Semin <Sergey.Semin@baikalelectronics.ru>
    dt-bindings: visconti-pcie: Fix interrupts array max constraints

Serge Semin <Sergey.Semin@baikalelectronics.ru>
    dt-bindings: imx6q-pcie: Fix clock names for imx6sx and imx8mq

Zhang Xiaoxu <zhangxiaoxu5@huawei.com>
    RDMA/rxe: Fix NULL-ptr-deref in rxe_qp_do_cleanup() when socket create failed

Zhengchao Shao <shaozhengchao@huawei.com>
    RDMA/hns: fix memory leak in hns_roce_alloc_mr()

Mustafa Ismail <mustafa.ismail@intel.com>
    RDMA/irdma: Initialize net_type before checking it

Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
    crypto: ccree - Make cc_debugfs_global_fini() available for module init function

Xiongfeng Wang <wangxiongfeng2@huawei.com>
    RDMA/hfi: Decrease PCI device reference count in error path

Zeng Heng <zengheng4@huawei.com>
    PCI: Check for alloc failure in pci_request_irq()

Luoyouming <luoyouming@huawei.com>
    RDMA/hns: Fix incorrect sge nums calculation

Luoyouming <luoyouming@huawei.com>
    RDMA/hns: Fix ext_sge num error when post send

Li Zhijian <lizhijian@fujitsu.com>
    RDMA/rxe: Fix mr->map double free

Xiongfeng Wang <wangxiongfeng2@huawei.com>
    crypto: hisilicon/qm - add missing pci_dev_put() in q_num_set()

Herbert Xu <herbert@gondor.apana.org.au>
    crypto: cryptd - Use request context instead of stack for sub-request

Gaosheng Cui <cuigaosheng1@huawei.com>
    crypto: ccree - Remove debugfs when platform_driver_register failed

Harshit Mogalapalli <harshit.m.mogalapalli@oracle.com>
    scsi: scsi_debug: Fix a warning in resp_write_scat()

Mustafa Ismail <mustafa.ismail@intel.com>
    RDMA/irdma: Do not request 2-level PBLEs for CQ alloc

Mustafa Ismail <mustafa.ismail@intel.com>
    RDMA/irdma: Fix RQ completion opcode

Mustafa Ismail <mustafa.ismail@intel.com>
    RDMA/irdma: Fix inline for multiple SGE's

Bernard Metzler <bmt@zurich.ibm.com>
    RDMA/siw: Set defined status for work completion with undefined status

Mark Zhang <markzhang@nvidia.com>
    RDMA/nldev: Return "-EAGAIN" if the cm_id isn't from expected port

Mark Zhang <markzhang@nvidia.com>
    RDMA/core: Make sure "ib_port" is valid when access sysfs node

Mark Zhang <markzhang@nvidia.com>
    RDMA/restrack: Release MR restrack when delete

Chao Yu <chao@kernel.org>
    f2fs: fix to avoid accessing uninitialized spinlock

Sascha Hauer <s.hauer@pengutronix.de>
    PCI: imx6: Initialize PHY before deasserting core reset

Nirmal Patel <nirmal.patel@linux.intel.com>
    PCI: vmd: Disable MSI remapping after suspend

Leonid Ravich <lravich@gmail.com>
    IB/mad: Don't call to function that might sleep while in atomic context

Bernard Metzler <bmt@zurich.ibm.com>
    RDMA/siw: Fix immediate work request flush to completion queue

Bart Van Assche <bvanassche@acm.org>
    scsi: qla2xxx: Fix set-but-not-used variable warnings

Shiraz Saleem <shiraz.saleem@intel.com>
    RDMA/irdma: Report the correct link speed

Chao Yu <chao@kernel.org>
    f2fs: fix to destroy sbi->post_read_wq in error path of f2fs_fill_super()

Mukesh Ojha <quic_mojha@quicinc.com>
    f2fs: fix the assign logic of iocb

Jaegeuk Kim <jaegeuk@kernel.org>
    f2fs: allow to set compression for inlined file

Dongdong Zhang <zhangdongdong1@oppo.com>
    f2fs: fix normal discard process

Yangtao Li <frank.li@vivo.com>
    f2fs: fix gc mode when gc_urgent_high_remaining is 1

Chao Yu <chao@kernel.org>
    f2fs: fix to invalidate dcc->f2fs_issue_discard in error path

Kees Cook <keescook@chromium.org>
    fortify: Do not cast to "unsigned char"

Xiu Jianfeng <xiujianfeng@huawei.com>
    apparmor: Fix memleak in alloc_ns()

Corentin Labbe <clabbe@baylibre.com>
    crypto: rockchip - rework by using crypto_engine

Corentin Labbe <clabbe@baylibre.com>
    crypto: rockchip - remove non-aligned handling

Corentin Labbe <clabbe@baylibre.com>
    crypto: rockchip - better handle cipher key

Corentin Labbe <clabbe@baylibre.com>
    crypto: rockchip - add fallback for ahash

Corentin Labbe <clabbe@baylibre.com>
    crypto: rockchip - add fallback for cipher

Corentin Labbe <clabbe@baylibre.com>
    crypto: rockchip - do not store mode globally

Corentin Labbe <clabbe@baylibre.com>
    crypto: rockchip - do not do custom power management

Zhang Qilong <zhangqilong3@huawei.com>
    f2fs: Fix the race condition of resize flag between resizefs

Kunihiko Hayashi <hayashi.kunihiko@socionext.com>
    PCI: pci-epf-test: Register notifier if only core_init_notifier is enabled

Leon Romanovsky <leon@kernel.org>
    RDMA/core: Fix order of nldev_exit call

Vidya Sagar <vidyas@nvidia.com>
    PCI: dwc: Fix n_fts[] array overrun

Xiu Jianfeng <xiujianfeng@huawei.com>
    apparmor: Use pointer to struct aa_label for lbs_cred

Bart Van Assche <bvanassche@acm.org>
    scsi: core: Fix a race between scsi_done() and scsi_timeout()

Robert Elliott <elliott@hpe.com>
    crypto: tcrypt - fix return value for multiple subtests

Natalia Petrova <n.petrova@fintech.ru>
    crypto: nitrox - avoid double free on error path in nitrox_sriov_init()

Corentin Labbe <clabbe@baylibre.com>
    crypto: sun8i-ss - use dma_addr instead u32

Weili Qian <qianweili@huawei.com>
    crypto: hisilicon/qm - re-enable communicate interrupt before notifying PF

Weili Qian <qianweili@huawei.com>
    crypto: hisilicon/qm - fix incorrect parameters usage

John Johansen <john.johansen@canonical.com>
    apparmor: Fix regression in stacking due to label flags

John Johansen <john.johansen@canonical.com>
    apparmor: Fix abi check to include v8 abi

John Johansen <john.johansen@canonical.com>
    apparmor: fix lockdep warning when removing a namespace

Gaosheng Cui <cuigaosheng1@huawei.com>
    apparmor: fix a memleak in multi_transaction_new()

Vladimir Oltean <vladimir.oltean@nxp.com>
    net: dsa: tag_8021q: avoid leaking ctx on dsa_tag_8021q_register() error path

Bartosz Staszewski <bartoszx.staszewski@intel.com>
    i40e: Fix the inability to attach XDP program on downed interface

Piergiorgio Beruto <piergiorgio.beruto@gmail.com>
    stmmac: fix potential division by 0

Christophe JAILLET <christophe.jaillet@wanadoo.fr>
    octeontx2-af: cn10k: mcs: Fix a resource leak in the probe and remove functions

Yang Yingliang <yangyingliang@huawei.com>
    Bluetooth: RFCOMM: don't call kfree_skb() under spin_lock_irqsave()

Yang Yingliang <yangyingliang@huawei.com>
    Bluetooth: hci_core: don't call kfree_skb() under spin_lock_irqsave()

Yang Yingliang <yangyingliang@huawei.com>
    Bluetooth: hci_bcsp: don't call kfree_skb() under spin_lock_irqsave()

Yang Yingliang <yangyingliang@huawei.com>
    Bluetooth: hci_h5: don't call kfree_skb() under spin_lock_irqsave()

Yang Yingliang <yangyingliang@huawei.com>
    Bluetooth: hci_ll: don't call kfree_skb() under spin_lock_irqsave()

Yang Yingliang <yangyingliang@huawei.com>
    Bluetooth: hci_qca: don't call kfree_skb() under spin_lock_irqsave()

Yang Yingliang <yangyingliang@huawei.com>
    Bluetooth: btusb: don't call kfree_skb() under spin_lock_irqsave()

Wang ShaoBo <bobo.shaobowang@huawei.com>
    Bluetooth: btintel: Fix missing free skb in btintel_setup_combined()

Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
    Bluetooth: hci_conn: Fix crash on hci_create_cis_sync

Christophe JAILLET <christophe.jaillet@wanadoo.fr>
    Bluetooth: Fix EALREADY and ELOOP cases in bt_status()

Inga Stotland <inga.stotland@intel.com>
    Bluetooth: MGMT: Fix error report for ADD_EXT_ADV_PARAMS

Yang Yingliang <yangyingliang@huawei.com>
    Bluetooth: hci_core: fix error handling in hci_register_dev()

Firo Yang <firo.yang@suse.com>
    sctp: sysctl: make extra pointers netns aware

Eric Pilmore <epilmore@gigaio.com>
    ntb_netdev: Use dev_kfree_skb_any() in interrupt context

Jerry Ray <jerry.ray@microchip.com>
    net: lan9303: Fix read error execution path

Roger Quadros <rogerq@kernel.org>
    net: ethernet: ti: am65-cpsw: Fix PM runtime leakage in am65_cpsw_nuss_ndo_slave_open()

Markus Schneider-Pargmann <msp@baylibre.com>
    can: tcan4x5x: Fix use of register error status mask

Vivek Yadav <vivek.2311@samsung.com>
    can: m_can: Call the RAM init directly from m_can_chip_config

Markus Schneider-Pargmann <msp@baylibre.com>
    can: tcan4x5x: Remove invalid write in clear_interrupts

Tom Lendacky <thomas.lendacky@amd.com>
    net: amd-xgbe: Check only the minimum speed for active/passive cables

Tom Lendacky <thomas.lendacky@amd.com>
    net: amd-xgbe: Fix logic around active and passive cables

Yang Yingliang <yangyingliang@huawei.com>
    af_unix: call proto_unregister() in the error path in af_unix_init()

Richard Gobert <richardbgobert@gmail.com>
    net: setsockopt: fix IPV6_UNICAST_IF option for connected sockets

Yang Yingliang <yangyingliang@huawei.com>
    net: amd: lance: don't call dev_kfree_skb() under spin_lock_irqsave()

Yang Yingliang <yangyingliang@huawei.com>
    hamradio: don't call dev_kfree_skb() under spin_lock_irqsave()

Yang Yingliang <yangyingliang@huawei.com>
    net: ethernet: dnet: don't call dev_kfree_skb() under spin_lock_irqsave()

Yang Yingliang <yangyingliang@huawei.com>
    net: emaclite: don't call dev_kfree_skb() under spin_lock_irqsave()

Yang Yingliang <yangyingliang@huawei.com>
    net: apple: bmac: don't call dev_kfree_skb() under spin_lock_irqsave()

Yang Yingliang <yangyingliang@huawei.com>
    net: apple: mace: don't call dev_kfree_skb() under spin_lock_irqsave()

Hangbin Liu <liuhangbin@gmail.com>
    net/tunnel: wait until all sk_user_data reader finish before releasing the sock

Li Zetao <lizetao1@huawei.com>
    net: farsync: Fix kmemleak when rmmods farsync

Yang Yingliang <yangyingliang@huawei.com>
    ethernet: s2io: don't call dev_kfree_skb() under spin_lock_irqsave()

ruanjinjie <ruanjinjie@huawei.com>
    of: overlay: fix null pointer dereferencing in find_dup_cset_node_entry() and find_dup_cset_prop()

Julian Anastasov <ja@ssi.bg>
    ipvs: use u64_stats_t for the per-cpu counters

Yuan Can <yuancan@huawei.com>
    drivers: net: qlcnic: Fix potential memory leak in qlcnic_sriov_init()

Gaosheng Cui <cuigaosheng1@huawei.com>
    net: stmmac: fix possible memory leak in stmmac_dvr_probe()

Zhang Changzhong <zhangchangzhong@huawei.com>
    net: stmmac: selftests: fix potential memleak in stmmac_test_arpoffload()

Yongqiang Liu <liuyongqiang13@huawei.com>
    net: defxx: Fix missing err handling in dfx_init()

Artem Chernyshev <artem.chernyshev@red-soft.ru>
    net: vmw_vsock: vmci: Check memcpy_from_msg()

Xiu Jianfeng <xiujianfeng@huawei.com>
    clk: socfpga: Fix memory leak in socfpga_gate_init()

Björn Töpel <bjorn@rivosinc.com>
    bpf: Do not zero-extend kfunc return values

Yang Jihong <yangjihong1@huawei.com>
    blktrace: Fix output non-blktrace event when blk_classic option enabled

Wang Yufen <wangyufen@huawei.com>
    wifi: brcmfmac: Fix error return code in brcmf_sdio_download_firmware()

Bitterblue Smith <rtl8821cerfe2@gmail.com>
    wifi: rtl8xxxu: Fix the channel width reporting

Bitterblue Smith <rtl8821cerfe2@gmail.com>
    wifi: rtl8xxxu: Add __packed to struct rtl8723bu_c2h

Kris Bahnsen <kris@embeddedTS.com>
    spi: spi-gpio: Don't set MOSI as an input if not 3WIRE mode

Xiu Jianfeng <xiujianfeng@huawei.com>
    clk: samsung: Fix memory leak in _samsung_clk_register_pll()

Geert Uytterhoeven <geert+renesas@glider.be>
    media: staging: stkwebcam: Restore MEDIA_{USB,CAMERA}_SUPPORT dependencies

Jiasheng Jiang <jiasheng@iscas.ac.cn>
    media: coda: Add check for kmalloc

Jiasheng Jiang <jiasheng@iscas.ac.cn>
    media: coda: Add check for dcoda_iram_alloc

Liang He <windhl@126.com>
    media: c8sectpfe: Add of_node_put() when breaking out of loop

Yuan Can <yuancan@huawei.com>
    regulator: qcom-labibb: Fix missing of_node_put() in qcom_labibb_regulator_probe()

Christoph Hellwig <hch@lst.de>
    nvme: pass nr_maps explicitly to nvme_alloc_io_tag_set

Zhen Lei <thunder.leizhen@huawei.com>
    mmc: core: Normalize the error handling branch in sd_read_ext_regs()

Jiasheng Jiang <jiasheng@iscas.ac.cn>
    memstick/ms_block: Add check for alloc_ordered_workqueue

Wolfram Sang <wsa+renesas@sang-engineering.com>
    mmc: renesas_sdhi: alway populate SCC pointer

Yang Yingliang <yangyingliang@huawei.com>
    mmc: mmci: fix return value check of mmc_add_host()

Yang Yingliang <yangyingliang@huawei.com>
    mmc: wbsd: fix return value check of mmc_add_host()

Yang Yingliang <yangyingliang@huawei.com>
    mmc: via-sdmmc: fix return value check of mmc_add_host()

Yang Yingliang <yangyingliang@huawei.com>
    mmc: meson-gx: fix return value check of mmc_add_host()

Yang Yingliang <yangyingliang@huawei.com>
    mmc: omap_hsmmc: fix return value check of mmc_add_host()

Yang Yingliang <yangyingliang@huawei.com>
    mmc: atmel-mci: fix return value check of mmc_add_host()

Gabriel Somlo <gsomlo@gmail.com>
    mmc: litex_mmc: ensure `host->irq == 0` if polling

Yang Yingliang <yangyingliang@huawei.com>
    mmc: wmt-sdmmc: fix return value check of mmc_add_host()

Yang Yingliang <yangyingliang@huawei.com>
    mmc: vub300: fix return value check of mmc_add_host()

Yang Yingliang <yangyingliang@huawei.com>
    mmc: toshsd: fix return value check of mmc_add_host()

Yang Yingliang <yangyingliang@huawei.com>
    mmc: rtsx_usb_sdmmc: fix return value check of mmc_add_host()

Yang Yingliang <yangyingliang@huawei.com>
    mmc: rtsx_pci: fix return value check of mmc_add_host()

Yang Yingliang <yangyingliang@huawei.com>
    mmc: pxamci: fix return value check of mmc_add_host()

Yang Yingliang <yangyingliang@huawei.com>
    mmc: mxcmmc: fix return value check of mmc_add_host()

Yang Yingliang <yangyingliang@huawei.com>
    mmc: moxart: fix return value check of mmc_add_host()

Yang Yingliang <yangyingliang@huawei.com>
    mmc: alcor: fix return value check of mmc_add_host()

Xingjiang Qiao <nanpuyue@gmail.com>
    hwmon: (emc2305) fix pwm never being able to set lower

Xingjiang Qiao <nanpuyue@gmail.com>
    hwmon: (emc2305) fix unable to probe emc2301/2/3

Miaoqian Lin <linmq006@gmail.com>
    bpftool: Fix memory leak in do_build_table_cb

Pu Lehui <pulehui@huawei.com>
    riscv, bpf: Emit fixed-length instructions for BPF_PSEUDO_FUNC

Trond Myklebust <trond.myklebust@hammerspace.com>
    NFSv4.x: Fail client initialisation if state manager thread can't run

Anna Schumaker <Anna.Schumaker@Netapp.com>
    NFS: Allow very small rsize & wsize again

Anna Schumaker <Anna.Schumaker@Netapp.com>
    NFSv4.2: Set the correct size scratch buffer for decoding READ_PLUS

Wang ShaoBo <bobo.shaobowang@huawei.com>
    SUNRPC: Fix missing release socket in rpc_sockname()

Zhang Xiaoxu <zhangxiaoxu5@huawei.com>
    xprtrdma: Fix regbuf data not freed in rpcrdma_req_create()

Gaosheng Cui <cuigaosheng1@huawei.com>
    pinctrl: thunderbay: fix possible memory leak in thunderbay_build_functions()

Gaosheng Cui <cuigaosheng1@huawei.com>
    ALSA: mts64: fix possible null-ptr-defer in snd_mts64_interrupt

Guoniu.zhou <guoniu.zhou@nxp.com>
    media: ov5640: set correct default link frequency

Liu Shixin <liushixin2@huawei.com>
    media: saa7164: fix missing pci_disable_device()

Takashi Iwai <tiwai@suse.de>
    ALSA: pcm: Set missing stop_operating flag at undoing trigger start

Eric Dumazet <edumazet@google.com>
    bpf, sockmap: fix race in sock_map_free()

Toke Høiland-Jørgensen <toke@redhat.com>
    bpf: Add dummy type reference to nf_conn___init to fix type deduplication

Martin Blumenstingl <martin.blumenstingl@googlemail.com>
    hwmon: (jc42) Restore the min/max/critical temperatures on resume

Martin Blumenstingl <martin.blumenstingl@googlemail.com>
    hwmon: (jc42) Convert register access and caching to regmap/regcache

Yang Yingliang <yangyingliang@huawei.com>
    regulator: core: fix resource leak in regulator_register()

Chen Zhongjin <chenzhongjin@huawei.com>
    configfs: fix possible memory leak in configfs_create_dir()

Sebastian Andrzej Siewior <bigeasy@linutronix.de>
    hsr: Synchronize sequence number updates.

Sebastian Andrzej Siewior <bigeasy@linutronix.de>
    hsr: Synchronize sending frames to have always incremented outgoing seq nr.

Sebastian Andrzej Siewior <bigeasy@linutronix.de>
    hsr: Disable netpoll.

Sebastian Andrzej Siewior <bigeasy@linutronix.de>
    hsr: Avoid double remove of a node.

Sebastian Andrzej Siewior <bigeasy@linutronix.de>
    hsr: Add a rcu-read lock to hsr_forward_skb().

Sebastian Andrzej Siewior <bigeasy@linutronix.de>
    Revert "net: hsr: use hlist_head instead of list_head for mac addresses"

Christian Marangi <ansuelsmth@gmail.com>
    clk: qcom: clk-krait: fix wrong div2 functions

Douglas Anderson <dianders@chromium.org>
    clk: qcom: lpass-sc7180: Fix pm_runtime usage

Douglas Anderson <dianders@chromium.org>
    clk: qcom: lpass-sc7280: Fix pm_runtime usage

Yang Yingliang <yangyingliang@huawei.com>
    regulator: core: fix module refcount leak in set_supply()

Xiongfeng Wang <wangxiongfeng2@huawei.com>
    mt76: mt7915: Fix PCI device refcount leak in mt7915_pci_init_hif2()

Deren Wu <deren.wu@mediatek.com>
    wifi: mt76: do not send firmware FW_FEATURE_NON_DL region

Deren Wu <deren.wu@mediatek.com>
    wifi: mt76: mt7921: Add missing __packed annotation of struct mt7921_clc

Deren Wu <deren.wu@mediatek.com>
    wifi: mt76: fix coverity overrun-call in mt76_get_txpower()

YN Chen <YN.Chen@mediatek.com>
    wifi: mt76: mt7921: fix wrong power after multiple SAR set

Nicolas Cavallari <nicolas.cavallari@green-communications.fr>
    wifi: mt76: mt7915: Fix chainmask calculation on mt7915 DBDC

Shayne Chen <shayne.chen@mediatek.com>
    wifi: mt76: mt7915: rework eeprom tx paths and streams init

Lorenzo Bianconi <lorenzo@kernel.org>
    wifi: mt76: mt7921: fix reporting of TX AGGR histogram

Lorenzo Bianconi <lorenzo@kernel.org>
    wifi: mt76: mt7915: fix reporting of TX AGGR histogram

Ryder Lee <ryder.lee@mediatek.com>
    wifi: mt76: mt7915: fix mt7915_mac_set_timing()

Sean Wang <sean.wang@mediatek.com>
    wifi: mt76: mt7921: fix antenna signal are way off in monitor mode

Chen Zhongjin <chenzhongjin@huawei.com>
    wifi: cfg80211: Fix not unregister reg_pdev when load_builtin_regdb_keys() fails

Íñigo Huguet <ihuguet@redhat.com>
    wifi: mac80211: fix maybe-unused warning

Zhengchao Shao <shaozhengchao@huawei.com>
    wifi: mac80211: fix memory leak in ieee80211_if_add()

Yuan Can <yuancan@huawei.com>
    wifi: nl80211: Add checks for nla_nest_start() in nl80211_send_iface()

Alexander Sverdlin <alexander.sverdlin@siemens.com>
    spi: spidev: mask SPI_CS_HIGH in SPI_IOC_RD_MODE

Dan Carpenter <error27@gmail.com>
    bonding: uninitialized variable in bond_miimon_inspect()

Pengcheng Yang <yangpc@wangsu.com>
    bpf, sockmap: Fix data loss caused by using apply_bytes on ingress redirect

Pengcheng Yang <yangpc@wangsu.com>
    bpf, sockmap: Fix missing BPF_F_INGRESS flag when using apply_bytes

Pengcheng Yang <yangpc@wangsu.com>
    bpf, sockmap: Fix repeated calls to sock_put() when msg has more_data

Randy Dunlap <rdunlap@infradead.org>
    Input: wistron_btns - disable on UML

Florian Westphal <fw@strlen.de>
    netfilter: conntrack: set icmpv6 redirects as RELATED

Xiu Jianfeng <xiujianfeng@huawei.com>
    clk: visconti: Fix memory leak in visconti_register_pll()

Zhang Qilong <zhangqilong3@huawei.com>
    ASoC: pcm512x: Fix PM disable depth imbalance in pcm512x_probe

Xia Fukun <xiafukun@huawei.com>
    drm/i915/bios: fix a memory leak in generate_lfp_data_ptrs

Konstantin Meskhidze <konstantin.meskhidze@huawei.com>
    drm/amdkfd: Fix memory leakage

Xiongfeng Wang <wangxiongfeng2@huawei.com>
    drm/amdgpu: Fix PCI device refcount leak in amdgpu_atrm_get_bios()

Xiongfeng Wang <wangxiongfeng2@huawei.com>
    drm/radeon: Fix PCI device refcount leak in radeon_atrm_get_bios()

Veerabadhran Gopalakrishnan <veerabadhran.gopalakrishnan@amd.com>
    amdgpu/nv.c: Corrected typo in the video capabilities resolution

Guchun Chen <guchun.chen@amd.com>
    drm/amd/pm/smu11: BACO is supported when it's in BACO state

Daniel Golle <daniel@makrotopia.org>
    clk: mediatek: fix dependency of MT7986 ADC clocks

Ricardo Ribalda <ribalda@chromium.org>
    ASoC: mediatek: mt8173: Enable IRQ when pdata is ready

Ben Greear <greearb@candelatech.com>
    wifi: iwlwifi: mvm: fix double free on tx path.

Bitterblue Smith <rtl8821cerfe2@gmail.com>
    wifi: rtl8xxxu: Fix use after rcu_read_unlock in rtl8xxxu_bss_info_changed

Ziyang Xuan <william.xuanziyang@huawei.com>
    wifi: plfxlc: fix potential memory leak in __lf_x_usb_enable_rx()

Liu Shixin <liushixin2@huawei.com>
    ALSA: asihpi: fix missing pci_disable_device()

Trond Myklebust <trond.myklebust@hammerspace.com>
    NFS: Fix an Oops in nfs_d_automount()

Trond Myklebust <trond.myklebust@hammerspace.com>
    NFSv4: Fix a deadlock between nfs4_open_recover_helper() and delegreturn

Trond Myklebust <trond.myklebust@hammerspace.com>
    NFSv4: Fix a credential leak in _nfs4_discover_trunking()

Trond Myklebust <trond.myklebust@hammerspace.com>
    NFSv4.2: Fix initialisation of struct nfs4_label

Trond Myklebust <trond.myklebust@hammerspace.com>
    NFSv4.2: Fix a memory stomp in decode_attr_security_label

Trond Myklebust <trond.myklebust@hammerspace.com>
    NFSv4.2: Always decode the security label

Trond Myklebust <trond.myklebust@hammerspace.com>
    NFSv4.2: Clear FATTR4_WORD2_SECURITY_LABEL when done decoding

Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
    drm/msm/mdp5: fix reading hw revision on db410c platform

Jiasheng Jiang <jiasheng@iscas.ac.cn>
    ASoC: mediatek: mtk-btcvsd: Add checks for write and read of mtk_btcvsd_snd

Dmitry Torokhov <dmitry.torokhov@gmail.com>
    ASoC: dt-bindings: wcd9335: fix reset line polarity in example

Zhang Zekun <zhangzekun11@huawei.com>
    drm/tegra: Add missing clk_disable_unprepare() in tegra_dc_probe()

Aakarsh Jain <aakarsh.jain@samsung.com>
    media: s5p-mfc: Add variant data for MFC v7 hardware for Exynos 3250 SoC

Yunfei Dong <yunfei.dong@mediatek.com>
    media: mediatek: vcodec: Core thread depends on core_list

Yunfei Dong <yunfei.dong@mediatek.com>
    media: mediatek: vcodec: Setting lat buf to lat_list when lat decode error

Yunfei Dong <yunfei.dong@mediatek.com>
    media: mediatek: vcodec: Fix h264 set lat buffer error

Yunfei Dong <yunfei.dong@mediatek.com>
    media: mediatek: vcodec: Fix getting NULL pointer for dst buffer

Ming Qian <ming.qian@nxp.com>
    media: amphion: lock and check m2m_ctx in event handler

Ming Qian <ming.qian@nxp.com>
    media: amphion: cancel vpu before release instance

Ming Qian <ming.qian@nxp.com>
    media: amphion: try to wakeup vpu core to avoid failure

Paul Kocialkowski <paul.kocialkowski@bootlin.com>
    media: sun8i-a83t-mipi-csi2: Register async subdev with no sensor attached

Paul Kocialkowski <paul.kocialkowski@bootlin.com>
    media: sun6i-mipi-csi2: Register async subdev with no sensor attached

Paul Kocialkowski <paul.kocialkowski@bootlin.com>
    media: sun8i-a83t-mipi-csi2: Require both pads to be connected for streaming

Paul Kocialkowski <paul.kocialkowski@bootlin.com>
    media: sun6i-mipi-csi2: Require both pads to be connected for streaming

Juergen Gross <jgross@suse.com>
    x86/boot: Skip realmode init code when running as Xen PV guest

Baisong Zhong <zhongbaisong@huawei.com>
    media: dvb-usb: az6027: fix null-ptr-deref in az6027_i2c_xfer()

Chen Zhongjin <chenzhongjin@huawei.com>
    media: dvb-core: Fix ignored return value in dvb_register_frontend()

ZhangPeng <zhangpeng362@huawei.com>
    pinctrl: pinconf-generic: add missing of_node_put()

Dario Binacchi <dario.binacchi@amarulasolutions.com>
    clk: imx8mn: fix imx8mn_enet_phy_sels clocks list

Dario Binacchi <dario.binacchi@amarulasolutions.com>
    clk: imx8mn: fix imx8mn_sai2_sels clocks list

Dario Binacchi <dario.binacchi@amarulasolutions.com>
    clk: imx: rename video_pll1 to video_pll

Dario Binacchi <dario.binacchi@amarulasolutions.com>
    clk: imx: replace osc_hdmi with dummy

Dario Binacchi <dario.binacchi@amarulasolutions.com>
    clk: imx8mn: rename vpu_pll to m7_alt_pll

Marek Vasut <marex@denx.de>
    media: mt9p031: Drop bogus v4l2_subdev_get_try_crop() call from mt9p031_init_cfg()

Laurent Pinchart <laurent.pinchart@ideasonboard.com>
    media: imx: imx7-media-csi: Clear BIT_MIPI_DOUBLE_CMPNT for <16b formats

Gautam Menghani <gautammenghani201@gmail.com>
    media: imon: fix a race condition in send_packet()

Chen Zhongjin <chenzhongjin@huawei.com>
    media: vimc: Fix wrong function called when vimc_init() fails

Jiaxin Yu <jiaxin.yu@mediatek.com>
    ASoC: mediatek: mt8186: Correct I2S shared clocks

Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
    ASoC: qcom: cleanup and fix dependency of QCOM_COMMON

Yuan Can <yuancan@huawei.com>
    ASoC: qcom: Add checks for devm_kcalloc

Wang ShaoBo <bobo.shaobowang@huawei.com>
    drbd: destroy workqueue when drbd device was freed

Wang ShaoBo <bobo.shaobowang@huawei.com>
    drbd: remove call to memset before free device/resource/connection

Zheng Yongjun <zhengyongjun3@huawei.com>
    mtd: maps: pxa2xx-flash: fix memory leak in probe

Shang XiaoJing <shangxiaojing@huawei.com>
    mtd: core: Fix refcount error in del_mtd_device()

Hui Tang <tanghui20@huawei.com>
    clk: microchip: check for null return of devm_kzalloc()

Jonathan Toppins <jtoppins@redhat.com>
    bonding: fix link recovery in mode 2 when updelay is nonzero

Stanislav Fomichev <sdf@google.com>
    selftests/bpf: Mount debugfs in setns_by_fd

Stanislav Fomichev <sdf@google.com>
    selftests/bpf: Make sure zero-len skbs aren't redirectable

Jani Nikula <jani.nikula@intel.com>
    drm/i915/guc: make default_lists const data

Yang Yingliang <yangyingliang@huawei.com>
    drm/amdgpu: fix pci device refcount leak

Xiu Jianfeng <xiujianfeng@huawei.com>
    clk: rockchip: Fix memory leak in rockchip_clk_register_pll()

Wang ShaoBo <bobo.shaobowang@huawei.com>
    regulator: core: use kfree_const() to free space conditionally

Baisong Zhong <zhongbaisong@huawei.com>
    ALSA: seq: fix undefined behavior in bit shift for SNDRV_SEQ_FILTER_USE_EVENT

Baisong Zhong <zhongbaisong@huawei.com>
    ALSA: pcm: fix undefined behavior in bit shift for SNDRV_PCM_RATE_KNOT

Cezary Rojewski <cezary.rojewski@intel.com>
    ASoC: Intel: avs: Lock substream before snd_pcm_stop()

Lili Li <lili.li@intel.com>
    ASoC: Intel: Skylake: Fix Kconfig dependency

Zong-Zhe Yang <kevin_yang@realtek.com>
    wifi: rtw89: fix physts IE page check

ZhangPeng <zhangpeng362@huawei.com>
    pinctrl: k210: call of_node_put()

Giulio Benetti <giulio.benetti@benettiengineering.com>
    clk: imx: imxrt1050: fix IMXRT1050_CLK_LCDIF_APB offsets

Marcus Folkesson <marcus.folkesson@gmail.com>
    HID: hid-sensor-custom: set fixed size for custom attributes

Stanislav Fomichev <sdf@google.com>
    bpf: Move skb->len == 0 checks into __bpf_redirect

Peng Fan <peng.fan@nxp.com>
    clk: imx93: correct enet clock

Peng Fan <peng.fan@nxp.com>
    clk: imx93: unmap anatop base in error handling path

Dmitry Torokhov <dmitry.torokhov@gmail.com>
    HID: i2c: let RMI devices decide what constitutes wakeup event

Hou Tao <houtao1@huawei.com>
    bpf: Pin the start cgroup in cgroup_iter_seq_init()

Haibo Chen <haibo.chen@nxp.com>
    clk: imx93: correct the flexspi1 clock setting

Allen-KH Cheng <allen-kh.cheng@mediatek.com>
    mtd: spi-nor: Fix the number of bytes for the dummy cycles

Michael Walle <michael@walle.cc>
    mtd: spi-nor: hide jedec_id sysfs attribute if not present

Kuniyuki Iwashima <kuniyu@amazon.com>
    net: Return errno in sk->sk_prot->get_port().

Kuniyuki Iwashima <kuniyu@amazon.com>
    udp: Clean up some functions.

Lorenzo Bianconi <lorenzo@kernel.org>
    net: ethernet: mtk_eth_soc: fix RSTCTRL_PPE{0,1} definitions

Christoph Hellwig <hch@lst.de>
    media: videobuf-dma-contig: use dma_mmap_coherent

Yuan Can <yuancan@huawei.com>
    media: amphion: Fix error handling in vpu_driver_init()

Yuan Can <yuancan@huawei.com>
    media: platform: exynos4-is: Fix error handling in fimc_md_init()

Yang Yingliang <yangyingliang@huawei.com>
    media: solo6x10: fix possible memory leak in solo_sysfs_init()

Chen Zhongjin <chenzhongjin@huawei.com>
    media: vidtv: Fix use-after-free in vidtv_bridge_dvb_init()

Ming Qian <ming.qian@nxp.com>
    media: amphion: apply vb2_queue_error instead of setting manually

Ming Qian <ming.qian@nxp.com>
    media: amphion: add lock around vdec_g_fmt

Lorenzo Bianconi <lorenzo@kernel.org>
    net: ethernet: mtk_eth_soc: do not overwrite mtu configuration running reset routine

Gaosheng Cui <cuigaosheng1@huawei.com>
    ASoC: amd: acp: Fix possible UAF in acp_dma_open

Douglas Anderson <dianders@chromium.org>
    Input: elants_i2c - properly handle the reset GPIO when power is off

Hui Tang <tanghui20@huawei.com>
    mtd: lpddr2_nvm: Fix possible null-ptr-deref

Rob Clark <robdclark@chromium.org>
    drm/msm/a6xx: Fix speed-bin detection vs probe-defer

Xiu Jianfeng <xiujianfeng@huawei.com>
    wifi: ath10k: Fix return value in ath10k_pci_init()

Wang Yufen <wangyufen@huawei.com>
    selftests/bpf: fix memory leak of lsm_cgroup

Christoph Hellwig <hch@lst.de>
    dm: track per-add_disk holder relations in DM

Yu Kuai <yukuai3@huawei.com>
    dm: make sure create and remove dm device won't race with open and close table

Christoph Hellwig <hch@lst.de>
    dm: cleanup close_table_device

Christoph Hellwig <hch@lst.de>
    dm: cleanup open_table_device

Christoph Hellwig <hch@lst.de>
    block: clear ->slave_dir when dropping the main slave_dir reference

Xiu Jianfeng <xiujianfeng@huawei.com>
    ima: Fix misuse of dereference of pointer in template_desc_init_fields()

GUO Zihua <guozihua@huawei.com>
    integrity: Fix memory leakage in keyring allocation error path

Takashi Iwai <tiwai@suse.de>
    ALSA: memalloc: Allocate more contiguous pages for fallback case

Brian Starkey <brian.starkey@arm.com>
    drm/fourcc: Fix vsub/hsub for Q410 and Q401

Konrad Dybcio <konrad.dybcio@linaro.org>
    regulator: qcom-rpmh: Fix PMR735a S3 regulator spec

Christophe JAILLET <christophe.jaillet@wanadoo.fr>
    wifi: rtw89: Fix some error handling path in rtw89_core_sta_assoc()

Joel Granados <j.granados@samsung.com>
    nvme: return err on nvme_init_non_mdts_limits fail

Dan Carpenter <error27@gmail.com>
    amdgpu/pm: prevent array underflow in vega20_odn_edit_dpm_table()

Yang Yingliang <yangyingliang@huawei.com>
    regulator: core: fix unbalanced of node refcount in regulator_dev_lookup()

Christoph Hellwig <hch@lst.de>
    nvmet: only allocate a single slab for bvecs

Zeng Heng <zengheng4@huawei.com>
    ASoC: pxa: fix null-pointer dereference in filter()

Xinlei Lee <xinlei.lee@mediatek.com>
    drm/mediatek: Modify dpi power on/off sequence.

Martin KaFai Lau <martin.lau@kernel.org>
    selftests/bpf: Fix incorrect ASSERT in the tcp_hdr_options test

Yang Jihong <yangjihong1@huawei.com>
    selftests/bpf: Fix xdp_synproxy compilation failure in 32-bit arch

Randy Dunlap <rdunlap@infradead.org>
    ASoC: codecs: wsa883x: use correct header file

Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
    ASoC: codecs: wsa883x: Use proper shutdown GPIO polarity

Miaoqian Lin <linmq006@gmail.com>
    module: Fix NULL vs IS_ERR checking for module_get_next_page

Johannes Berg <johannes.berg@intel.com>
    wifi: iwlwifi: mei: fix potential NULL-ptr deref after clone

Avraham Stern <avraham.stern@intel.com>
    wifi: iwlwifi: mei: avoid blocking sap messages handling due to rtnl lock

Emmanuel Grumbach <emmanuel.grumbach@intel.com>
    wifi: iwlwifi: mei: fix tx DHCP packet for devices with new Tx API

Emmanuel Grumbach <emmanuel.grumbach@intel.com>
    wifi: iwlwifi: mei: don't send SAP commands if AMT is disabled

Avraham Stern <avraham.stern@intel.com>
    wifi: iwlwifi: mei: make sure ownership confirmed message is sent

Sam Shih <sam.shih@mediatek.com>
    pinctrl: mediatek: fix the pinconf register offset of some pins

Frank Wunderlich <frank-w@public-files.de>
    dt-bindings: pinctrl: update uart/mmc bindings for MT7986 SoC

Hanjun Guo <guohanjun@huawei.com>
    drm/radeon: Add the missed acpi_put_table() to fix memory leak

Khazhismel Kumykov <khazhy@chromium.org>
    bfq: fix waker_bfqq inconsistency crash

Christoph Böhmwalder <christoph.boehmwalder@linbit.com>
    drbd: use blk_queue_max_discard_sectors helper

Yassine Oudjana <y.oudjana@protonmail.com>
    regmap-irq: Use the new num_config_regs property in regmap_add_irq_chip_fwnode

Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
    drm: rcar-du: Drop leftovers dependencies from Kconfig

Ping-Ke Shih <pkshih@realtek.com>
    wifi: rtw89: use u32_encode_bits() to fill MAC quota value

Marek Vasut <marex@denx.de>
    drm: lcdif: Set and enable FIFO Panic threshold

David Howells <dhowells@redhat.com>
    rxrpc: Fix ack.bufferSize to be 0 when generating an ack

David Howells <dhowells@redhat.com>
    net, proc: Provide PROC_FS=n fallback for proc_create_net_single_write()

Cole Robinson <crobinso@redhat.com>
    virt/sev-guest: Add a MODULE_ALIAS

Wolfram Sang <wsa+renesas@sang-engineering.com>
    clk: renesas: r8a779f0: Fix SCIF parent clocks

Wolfram Sang <wsa+renesas@sang-engineering.com>
    clk: renesas: r8a779f0: Fix HSCIF parent clocks

Vladimir Zapolskiy <vladimir.zapolskiy@linaro.org>
    media: camss: Do not attach an already attached power domain on MSM8916 platform

Vladimir Zapolskiy <vladimir.zapolskiy@linaro.org>
    media: camss: Clean up received buffers on failed start of streaming

Marek Vasut <marex@denx.de>
    wifi: rsi: Fix handling of 802.3 EAPOL frames sent via control port

Randy Dunlap <rdunlap@infradead.org>
    Input: joystick - fix Kconfig warning for JOYSTICK_ADC

Gaosheng Cui <cuigaosheng1@huawei.com>
    mtd: core: fix possible resource leak in init_mtd()

Zhang Xiaoxu <zhangxiaoxu5@huawei.com>
    mtd: Fix device name leak when register device failed in add_mtd_device()

Manivannan Sadhasivam <mani@kernel.org>
    clk: qcom: gcc-sm8250: Use retention mode for USB GDSCs

Konrad Dybcio <konrad.dybcio@somainline.org>
    clk: qcom: dispcc-sm6350: Add CLK_OPS_PARENT_ENABLE to pixel&byte src

Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
    clk: qcom: gcc-ipq806x: use parent_data for the last remaining entry

Andrii Nakryiko <andrii@kernel.org>
    bpf: propagate precision across all frames, not just the last one

Andrii Nakryiko <andrii@kernel.org>
    bpf: propagate precision in ALU/ALU64 operations

Yang Yingliang <yangyingliang@huawei.com>
    media: platform: exynos4-is: fix return value check in fimc_md_probe()

Liu Shixin <liushixin2@huawei.com>
    media: vivid: fix compose size exceed boundary

Andrzej Pietrasiewicz <andrzej.p@collabora.com>
    media: rkvdec: Add required padding

Moudy Ho <moudy.ho@mediatek.com>
    media: platform: mtk-mdp3: fix error handling in mdp_probe()

Moudy Ho <moudy.ho@mediatek.com>
    media: platform: mtk-mdp3: fix error handling about components clock_on

Moudy Ho <moudy.ho@mediatek.com>
    media: platform: mtk-mdp3: fix error handling in mdp_cmdq_send()

Marijn Suijten <marijn.suijten@somainline.org>
    drm/msm/dsi: Prevent signed BPG offsets from bleeding into adjacent bits

Marijn Suijten <marijn.suijten@somainline.org>
    drm/msm/dsi: Disallow 8 BPC DSC configuration for alternative BPC values

Marijn Suijten <marijn.suijten@somainline.org>
    drm/msm/dsi: Account for DSC's bits_per_pixel having 4 fractional bits

Marijn Suijten <marijn.suijten@somainline.org>
    drm/msm/dsi: Migrate to drm_dsc_compute_rc_parameters()

Marijn Suijten <marijn.suijten@somainline.org>
    drm/msm/dsi: Appropriately set dsc->mux_word_size based on bpc

Marijn Suijten <marijn.suijten@somainline.org>
    drm/msm/dsi: Reuse earlier computed dsc->slice_chunk_size

Marijn Suijten <marijn.suijten@somainline.org>
    drm/msm/dsi: Use DIV_ROUND_UP instead of conditional increment on modulo

Marijn Suijten <marijn.suijten@somainline.org>
    drm/msm/dsi: Remove repeated calculation of slice_per_intf

Marijn Suijten <marijn.suijten@somainline.org>
    drm/msm/dsi: Remove useless math in DSC calculations

Marijn Suijten <marijn.suijten@somainline.org>
    drm/msm/dpu1: Account for DSC's bits_per_pixel having 4 fractional bits

Kumar Kartikeya Dwivedi <memxor@gmail.com>
    bpf: Fix slot type check in check_stack_write_var_off

Kumar Kartikeya Dwivedi <memxor@gmail.com>
    bpf: Clobber stack slot when writing over spilled PTR_TO_BTF_ID

Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
    drm/msm/hdmi: use devres helper for runtime PM management

GUO Zihua <guozihua@huawei.com>
    ima: Handle -ESTALE returned by ima_filter_rule_match()

Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
    drm/msm/mdp5: stop overriding drvdata

Gaosheng Cui <cuigaosheng1@huawei.com>
    drm/ttm: fix undefined behavior in bit shift for TTM_TT_FLAG_PRIV_POPULATED

Marek Vasut <marex@denx.de>
    drm/panel/panel-sitronix-st7701: Remove panel on DSI attach failure

Jonathan Neuschäfer <j.neuschaefer@gmx.net>
    spi: Update reference to struct spi_controller

Marek Vasut <marex@denx.de>
    drm/panel/panel-sitronix-st7701: Fix RTNI calculation

Marco Felsch <m.felsch@pengutronix.de>
    drm: lcdif: change burst size to 256B

Marek Vasut <marex@denx.de>
    clk: renesas: r9a06g032: Repair grave increment error

Anshuman Gupta <anshuman.gupta@intel.com>
    drm/i915/dgfx: Grab wakeref at i915_ttm_unmap_virtual

Anshuman Gupta <anshuman.gupta@intel.com>
    drm/i915: Encapsulate lmem rpm stuff in intel_runtime_pm

Nirmoy Das <nirmoy.das@intel.com>
    drm/i915: Refactor ttm ghost obj detection

Tvrtko Ursulin <tvrtko.ursulin@intel.com>
    drm/i915: Handle all GTs on driver (un)load paths

Zhang Qilong <zhangqilong3@huawei.com>
    drm/rockchip: lvds: fix PM usage counter unbalance in poweron

Haiyi Zhou <Haiyi.Zhou@amd.com>
    drm/amd/display: wait for vblank during pipe programming

Sakari Ailus <sakari.ailus@linux.intel.com>
    dw9768: Enable low-power probe on ACPI

Alan Previn <alan.previn.teres.alexis@intel.com>
    drm/i915/guc: Fix GuC error capture sizing estimation and reporting

Alan Previn <alan.previn.teres.alexis@intel.com>
    drm/i915/guc: Add error-capture init warnings when needed

Nícolas F. R. A. Prado <nfraprado@collabora.com>
    ASoC: dt-bindings: rt5682: Set sound-dai-cells to 1

Wolfram Sang <wsa+renesas@sang-engineering.com>
    clk: renesas: r8a779a0: Fix SD0H clock name

Geert Uytterhoeven <geert+renesas@glider.be>
    clk: renesas: r8a779f0: Fix SD0H clock name

Jimmy Assarsson <extja@kvaser.com>
    can: kvaser_usb: Compare requested bittiming parameters with actual parameters in do_set_{,data}_bittiming

Jimmy Assarsson <extja@kvaser.com>
    can: kvaser_usb: Add struct kvaser_usb_busparams

Anssi Hannula <anssi.hannula@bitwise.fi>
    can: kvaser_usb_leaf: Fix bogus restart events

Anssi Hannula <anssi.hannula@bitwise.fi>
    can: kvaser_usb_leaf: Fix wrong CAN state after stopping

Anssi Hannula <anssi.hannula@bitwise.fi>
    can: kvaser_usb_leaf: Fix improved state not being reported

Anssi Hannula <anssi.hannula@bitwise.fi>
    can: kvaser_usb_leaf: Set Warning state even without bus errors

Jimmy Assarsson <extja@kvaser.com>
    can: kvaser_usb: kvaser_usb_leaf: Handle CMD_ERROR_EVENT

Jimmy Assarsson <extja@kvaser.com>
    can: kvaser_usb: kvaser_usb_leaf: Rename {leaf,usbcan}_cmd_error_event to {leaf,usbcan}_cmd_can_error_event

Jimmy Assarsson <extja@kvaser.com>
    can: kvaser_usb: kvaser_usb_leaf: Get capabilities from device

Alan Maguire <alan.maguire@oracle.com>
    libbpf: Btf dedup identical struct test needs check for nested structs/arrays

Marek Szyprowski <m.szyprowski@samsung.com>
    media: exynos4-is: don't rely on the v4l2_async_subdev internals

Rafael Mendonca <rafaelmendsr@gmail.com>
    media: i2c: ov5648: Free V4L2 fwnode data on unbind

Kuniyuki Iwashima <kuniyu@amazon.com>
    soreuseport: Fix socket selection for SO_INCOMING_CPU.

Tang Bin <tangbin@cmss.chinamobile.com>
    venus: pm_helpers: Fix error check in vcodec_domains_get()

Ricardo Ribalda <ribalda@chromium.org>
    media: i2c: ad5820: Fix error path

Rafael Mendonca <rafaelmendsr@gmail.com>
    media: i2c: hi846: Fix memory leak in hi846_parse_dt()

John Harrison <John.C.Harrison@Intel.com>
    drm/i915: Fix compute pre-emption w/a to apply to compute engines

John Harrison <John.C.Harrison@Intel.com>
    drm/i915/guc: Limit scheduling properties to avoid overflow

Yunfei Dong <yunfei.dong@mediatek.com>
    media: mediatek: vcodec: fix h264 cavlc bitstream fail

Jernej Skrabec <jernej.skrabec@gmail.com>
    media: cedrus: hevc: Fix offset adjustments

Jernej Skrabec <jernej.skrabec@gmail.com>
    media: v4l2-ioctl.c: Unify YCbCr/YUV terms in format descriptions

Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
    media: adv748x: afe: Select input port when initializing AFE

Ming Qian <ming.qian@nxp.com>
    media: amphion: reset instance if it's aborted before codec header parsed

Jiasheng Jiang <jiasheng@iscas.ac.cn>
    media: coda: jpeg: Add check for kmalloc

Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
    media: v4l2-ctrls: Fix off-by-one error in integer menu control check

Jeff LaBundy <jeff@labundy.com>
    Input: iqs7222 - protect against undefined slider size

Pin-yen Lin <treapking@chromium.org>
    drm/bridge: it6505: Initialize AUX channel in it6505_i2c_probe

Wang Yufen <wangyufen@huawei.com>
    selftests/bpf: fix missing BPF object files

Gerhard Engleder <gerhard@engleder-embedded.com>
    samples/bpf: Fix MAC address swapping in xdp2_kern

Gerhard Engleder <gerhard@engleder-embedded.com>
    samples/bpf: Fix map iteration in xdp1_user

Alexandru Tachici <alexandru.tachici@analog.com>
    net: ethernet: adi: adin1110: Fix SPI transfers

Sean Anderson <sean.anderson@seco.com>
    powerpc: dts: t208x: Mark MAC1 and MAC2 as 10G

Rafael Mendonca <rafaelmendsr@gmail.com>
    drm/amdgpu/powerplay/psm: Fix memory leak in power state init

Asher Song <Asher.Song@amd.com>
    drm/amdgpu: Revert "drm/amdgpu: getting fan speed pwm for vega10 properly"

Andrew Jeffery <andrew@aj.id.au>
    ipmi: kcs: Poll OBF briefly to reduce OBE latency

Cezary Rojewski <cezary.rojewski@intel.com>
    ASoC: Intel: avs: Fix potential RX buffer overflow

Cezary Rojewski <cezary.rojewski@intel.com>
    ASoC: Intel: avs: Fix DMA mask assignment

Yang Yingliang <yangyingliang@huawei.com>
    pinctrl: ocelot: add missing destroy_workqueue() in error path in ocelot_pinctrl_probe()

Niklas Cassel <niklas.cassel@wdc.com>
    ata: libata: fix NCQ autosense logic

Laurent Pinchart <laurent.pinchart@ideasonboard.com>
    drm: lcdif: Switch to limited range for RGB to YUV conversion

Shung-Hsi Yu <shung-hsi.yu@suse.com>
    libbpf: Fix null-pointer dereference in find_prog_by_sec_insn()

Shung-Hsi Yu <shung-hsi.yu@suse.com>
    libbpf: Deal with section with no data gracefully

Shung-Hsi Yu <shung-hsi.yu@suse.com>
    libbpf: Use elf_getshdrnum() instead of e_shnum

Xu Kuohai <xukuohai@huawei.com>
    selftest/bpf: Fix error usage of ASSERT_OK in xdp_adjust_tail.c

Xu Kuohai <xukuohai@huawei.com>
    selftests/bpf: Fix error failure of case test_xdp_adjust_tail_grow

Xu Kuohai <xukuohai@huawei.com>
    selftest/bpf: Fix memory leak in kprobe_multi_test

Xu Kuohai <xukuohai@huawei.com>
    selftests/bpf: Fix memory leak caused by not destroying skeleton

Xu Kuohai <xukuohai@huawei.com>
    libbpf: Fix memory leak in parse_usdt_arg()

Xu Kuohai <xukuohai@huawei.com>
    libbpf: Fix use-after-free in btf_dump_name_dups

Abhinav Kumar <quic_abhinavk@quicinc.com>
    drm/bridge: adv7533: remove dynamic lane switching from adv7533 bridge

Aditya Kumar Singh <quic_adisi@quicinc.com>
    wifi: ath11k: fix firmware assert during bandwidth change for peer sta

Bitterblue Smith <rtl8821cerfe2@gmail.com>
    wifi: rtl8xxxu: Fix reading the vendor of combo chips

Fedor Pchelkin <pchelkin@ispras.ru>
    wifi: ath9k: hif_usb: Fix use-after-free in ath9k_hif_usb_reg_in_cb()

Fedor Pchelkin <pchelkin@ispras.ru>
    wifi: ath9k: hif_usb: fix memory leak of urbs in ath9k_hif_usb_dealloc_tx_urbs()

Thomas Zimmermann <tzimmermann@suse.de>
    drm/atomic-helper: Don't allocate new plane state in CRTC check

Johannes Berg <johannes.berg@intel.com>
    wifi: mac80211: fix ifdef symbol name

Johannes Berg <johannes.berg@intel.com>
    wifi: mac80211: check link ID in auth/assoc continuation

Johannes Berg <johannes.berg@intel.com>
    wifi: mac80211: mlme: fix null-ptr deref on failed assoc

Johannes Berg <johannes.berg@intel.com>
    wifi: fix multi-link element subelement iteration

Jiri Olsa <jolsa@kernel.org>
    selftests/bpf: Add missing bpf_iter_vma_offset__destroy call

James Hurley <jahurley@nvidia.com>
    platform/mellanox: mlxbf-pmc: Fix event typo

Zhengchao Shao <shaozhengchao@huawei.com>
    ipc: fix memory leak in init_mqueue_fs()

Cai Xinchen <caixinchen1@huawei.com>
    rapidio: devices: fix missing put_device in mport_cdev_open

ZhangPeng <zhangpeng362@huawei.com>
    hfs: Fix OOB Write in hfs_asc2mac

Gavrilov Ilia <Ilia.Gavrilov@infotecs.ru>
    relay: fix type mismatch when allocating memory in relay_create_buf()

Zhang Qilong <zhangqilong3@huawei.com>
    eventfd: change int to __u64 in eventfd_signal() ifndef CONFIG_EVENTFD

Wang Weiyang <wangweiyang2@huawei.com>
    rapidio: fix possible UAF when kfifo_alloc() fails

Chen Zhongjin <chenzhongjin@huawei.com>
    fs: sysv: Fix sysv_nblocks() returns wrong value

Brian Foster <bfoster@redhat.com>
    NFSD: pass range end to vfs_fsync_range() instead of count

Jeff Layton <jlayton@kernel.org>
    nfsd: return error if nfs4_setacl fails

Trond Myklebust <trond.myklebust@hammerspace.com>
    lockd: set other missing fields when unlocking files

Ladislav Michl <ladis@linux-mips.org>
    MIPS: OCTEON: warn only once if deprecated link status is being used

Anastasia Belova <abelova@astralinux.ru>
    MIPS: BCM63xx: Add check for NULL for clk in clk_enable

Yang Yingliang <yangyingliang@huawei.com>
    platform/x86: intel_scu_ipc: fix possible name leak in __intel_scu_ipc_register()

Yu Liao <liaoyu15@huawei.com>
    platform/x86: mxm-wmi: fix memleak in mxm_wmi_call_mx[ds|mx]()

Victor Ding <victording@chromium.org>
    platform/chrome: cros_ec_typec: zero out stale pointers

Gao Xiang <xiang@kernel.org>
    erofs: validate the extent length for uncompressed pclusters

Gao Xiang <xiang@kernel.org>
    erofs: fix missing unmap if z_erofs_get_extent_compressedlen() fails

Chen Zhongjin <chenzhongjin@huawei.com>
    erofs: Fix pcluster memleak when its block address is zero

Hou Tao <houtao1@huawei.com>
    erofs: check the uniqueness of fsid in shared domain in advance

Rafael J. Wysocki <rafael.j.wysocki@intel.com>
    PM: runtime: Do not call __rpm_callback() from rpm_idle()

Harshit Mogalapalli <harshit.m.mogalapalli@oracle.com>
    xen/privcmd: Fix a possible warning in privcmd_ioctl_mmap_resource()

Xiu Jianfeng <xiujianfeng@huawei.com>
    x86/xen: Fix memory leak in xen_init_lock_cpu()

Xiu Jianfeng <xiujianfeng@huawei.com>
    x86/xen: Fix memory leak in xen_smp_intr_init{_pv}()

Oleg Nesterov <oleg@redhat.com>
    uprobes/x86: Allow to probe a NOP instruction with 0x66 prefix

Li Zetao <lizetao1@huawei.com>
    ACPICA: Fix use-after-free in acpi_ut_copy_ipackage_to_ipackage()

Yang Yingliang <yangyingliang@huawei.com>
    clocksource/drivers/timer-ti-dm: Fix missing clk_disable_unprepare in dmtimer_systimer_init_clock()

Tony Lindgren <tony@atomide.com>
    clocksource/drivers/timer-ti-dm: Fix warning for omap_timer_match

Vincent Donnefort <vdonnefort@google.com>
    cpu/hotplug: Do not bail-out in DYING/STARTING sections

Phil Auld <pauld@redhat.com>
    cpu/hotplug: Make target_store() a nop when target == state

Alexey Izbyshev <izbyshev@ispras.ru>
    futex: Resend potentially swallowed owner death notification

Wolfram Sang <wsa+renesas@sang-engineering.com>
    clocksource/drivers/sh_cmt: Access registers according to spec

Yang Yingliang <yangyingliang@huawei.com>
    rapidio: rio: fix possible name leak in rio_register_mport()

Yang Yingliang <yangyingliang@huawei.com>
    rapidio: fix possible name leaks when rio_add_device() fails

Li Zetao <ocfs2-devel@oss.oracle.com>
    ocfs2: fix memory leak in ocfs2_mount_volume()

Akinobu Mita <akinobu.mita@gmail.com>
    debugfs: fix error when writing negative value to atomic_t debugfs file

Akinobu Mita <akinobu.mita@gmail.com>
    lib/notifier-error-inject: fix error when writing -errno to debugfs file

Akinobu Mita <akinobu.mita@gmail.com>
    libfs: add DEFINE_SIMPLE_ATTRIBUTE_SIGNED for signed value

Xiongfeng Wang <wangxiongfeng2@huawei.com>
    cpufreq: amd_freq_sensitivity: Add missing pci_dev_put()

Yang Yingliang <yangyingliang@huawei.com>
    genirq/irqdesc: Don't try to remove non-existing sysfs files

Jeff Layton <jlayton@kernel.org>
    nfsd: don't call nfsd_file_put from client states seqfile display

Chuck Lever <chuck.lever@oracle.com>
    NFSD: Finish converting the NFSv3 GETACL result encoder

Chuck Lever <chuck.lever@oracle.com>
    NFSD: Finish converting the NFSv2 GETACL result encoder

Yang Yingliang <yangyingliang@huawei.com>
    EDAC/i10nm: fix refcount leak in pci_get_dev_wrapper()

Liu Peibao <liupeibao@loongson.cn>
    irqchip/loongson-liointc: Fix improper error handling in liointc_init()

Wei Yongjun <weiyongjun1@huawei.com>
    irqchip/wpcm450: Fix memory leak in wpcm450_aic_of_init()

Shang XiaoJing <shangxiaojing@huawei.com>
    irqchip: gic-pm: Use pm_runtime_resume_and_get() in gic_probe()

Jianmin Lv <lvjianmin@loongson.cn>
    irqchip/loongson-pch-pic: Fix translate callback for DT path

Yang Yingliang <yangyingliang@huawei.com>
    thermal: core: fix some possible name leaks in error paths

Yuan Can <yuancan@huawei.com>
    platform/chrome: cros_usbpd_notify: Fix error handling in cros_usbpd_notify_init()

Xiongfeng Wang <wangxiongfeng2@huawei.com>
    perf/x86/intel/uncore: Fix reference count leak in __uncore_imc_init_box()

Xiongfeng Wang <wangxiongfeng2@huawei.com>
    perf/x86/intel/uncore: Fix reference count leak in snr_uncore_mmio_map()

Xiongfeng Wang <wangxiongfeng2@huawei.com>
    perf/x86/intel/uncore: Fix reference count leak in hswep_has_limit_sbox()

Xiongfeng Wang <wangxiongfeng2@huawei.com>
    perf/x86/intel/uncore: Fix reference count leak in sad_cfg_iio_topology()

Wang ShaoBo <bobo.shaobowang@huawei.com>
    ACPI: pfr_update: use ACPI_FREE() to free acpi_object

Wang ShaoBo <bobo.shaobowang@huawei.com>
    ACPI: pfr_telemetry: use ACPI_FREE() to free acpi_object

Huisong Li <lihuisong@huawei.com>
    mailbox: pcc: Reset pcc_chan_count to zero in case of PCC probe failure

Yang Yingliang <yangyingliang@huawei.com>
    PNP: fix name memory leak in pnp_alloc_dev()

Zhao Gongyi <zhaogongyi@huawei.com>
    selftests/efivarfs: Add checking of the test return value

Yang Yingliang <yangyingliang@huawei.com>
    MIPS: vpe-cmp: fix possible memory leak while module exiting

Yang Yingliang <yangyingliang@huawei.com>
    MIPS: vpe-mt: fix possible memory leak while module exiting

Manivannan Sadhasivam <mani@kernel.org>
    cpufreq: qcom-hw: Fix the frequency returned by cpufreq_driver->get()

YueHaibing <yuehaibing@huawei.com>
    selftests: cgroup: fix unsigned comparison with less than zero

Shang XiaoJing <shangxiaojing@huawei.com>
    ocfs2: fix memory leak in ocfs2_stack_glue_init()

Gaosheng Cui <cuigaosheng1@huawei.com>
    lib/fonts: fix undefined behavior in bit shift for get_default_font

Alexey Dobriyan <adobriyan@gmail.com>
    proc: fixup uptime selftest

Barnabás Pőcze <pobrn@protonmail.com>
    timerqueue: Use rb_entry_safe() in timerqueue_getnext()

Barnabás Pőcze <pobrn@protonmail.com>
    platform/x86: huawei-wmi: fix return value calculation

wuchi <wuchi.zero@gmail.com>
    lib/debugobjects: fix stat count and optimize debug_objects_mem_init

Chen Zhongjin <chenzhongjin@huawei.com>
    perf: Fix possible memleak in pmu_dev_alloc()

Yipeng Zou <zouyipeng@huawei.com>
    selftests/ftrace: event_triggers: wait longer for test_event_enable

Xiongfeng Wang <wangxiongfeng2@huawei.com>
    ACPI: irq: Fix some kernel-doc issues

Guilherme G. Piccoli <gpiccoli@igalia.com>
    x86/split_lock: Add sysctl to control the misery mode

Chen Hui <judy.chenhui@huawei.com>
    cpufreq: qcom-hw: Fix memory leak in qcom_cpufreq_hw_read_lut()

Ondrej Mosnacek <omosnace@redhat.com>
    fs: don't audit the capability check in simple_xattr_list()

xiongxin <xiongxin@kylinos.cn>
    PM: hibernate: Fix mistake in kerneldoc comment

Reinette Chatre <reinette.chatre@intel.com>
    x86/sgx: Reduce delay and interference of enclave release

Hao Lee <haolee.swjtu@gmail.com>
    sched/psi: Fix possible missing or delayed pending event

Al Viro <viro@zeniv.linux.org.uk>
    alpha: fix syscall entry in !AUDUT_SYSCALL case

Al Viro <viro@zeniv.linux.org.uk>
    alpha: fix TIF_NOTIFY_SIGNAL handling

Ulf Hansson <ulf.hansson@linaro.org>
    cpuidle: dt: Return the correct numbers of parsed idle states

Qais Yousef <qyousef@layalina.io>
    sched/uclamp: Cater for uclamp in find_energy_efficient_cpu()'s early exit condition

Qais Yousef <qyousef@layalina.io>
    sched/uclamp: Make cpu_overutilized() use util_fits_cpu()

Qais Yousef <qyousef@layalina.io>
    sched/uclamp: Make asym_fits_capacity() use util_fits_cpu()

Qais Yousef <qyousef@layalina.io>
    sched/uclamp: Make select_idle_capacity() use util_fits_cpu()

Qais Yousef <qyousef@layalina.io>
    sched/uclamp: Fix fits_capacity() check in feec()

Qais Yousef <qyousef@layalina.io>
    sched/uclamp: Make task_fits_capacity() use util_fits_cpu()

Qais Yousef <qyousef@layalina.io>
    sched/uclamp: Fix relationship between uclamp and migration margin

Amir Goldstein <amir73il@gmail.com>
    ovl: remove privs in ovl_fallocate()

Amir Goldstein <amir73il@gmail.com>
    ovl: remove privs in ovl_copyfile()

Michael Kelley <mikelley@microsoft.com>
    tpm/tpm_crb: Fix error message in __crb_relinquish_locality()

Yuan Can <yuancan@huawei.com>
    tpm/tpm_ftpm_tee: Fix error handling in ftpm_mod_init()

Eddie James <eajames@linux.ibm.com>
    tpm: Add flag to use default cancellation policy

Eddie James <eajames@linux.ibm.com>
    tpm: tis_i2c: Fix sanity check interrupt enable mask

Janne Grunau <j@jannau.net>
    arch: arm64: apple: t8103: Use standard "iommu" node name

Stephen Boyd <swboyd@chromium.org>
    pstore: Avoid kcore oops by vmap()ing with VM_IOREMAP

Doug Brown <doug@schmorgal.com>
    ARM: mmp: fix timer_read delay

Wang Yufen <wangyufen@huawei.com>
    pstore/ram: Fix error return code in ramoops_probe()

Kuniyuki Iwashima <kuniyu@amazon.com>
    seccomp: Move copy_seccomp() to no failure path.

Yicong Yang <yangyicong@hisilicon.com>
    drivers/perf: hisi: Fix some event id for hisi-pcie-pmu

Sven Peter <sven@svenpeter.dev>
    soc: apple: rtkit: Stop casting function pointer signatures

Sven Peter <sven@svenpeter.dev>
    soc: apple: sart: Stop casting function pointer signatures

Pali Rohár <pali@kernel.org>
    arm64: dts: armada-3720-turris-mox: Add missing interrupt for RTC

Pali Rohár <pali@kernel.org>
    ARM: dts: armada-39x: Fix compatible string for gpios

Pali Rohár <pali@kernel.org>
    ARM: dts: armada-38x: Fix compatible string for gpios

Pali Rohár <pali@kernel.org>
    ARM: dts: turris-omnia: Add switch port 6 node

Pali Rohár <pali@kernel.org>
    ARM: dts: turris-omnia: Add ethernet aliases

Pali Rohár <pali@kernel.org>
    ARM: dts: armada-39x: Fix assigned-addresses for every PCIe Root Port

Pali Rohár <pali@kernel.org>
    ARM: dts: armada-38x: Fix assigned-addresses for every PCIe Root Port

Pali Rohár <pali@kernel.org>
    ARM: dts: armada-375: Fix assigned-addresses for every PCIe Root Port

Pali Rohár <pali@kernel.org>
    ARM: dts: armada-xp: Fix assigned-addresses for every PCIe Root Port

Pali Rohár <pali@kernel.org>
    ARM: dts: armada-370: Fix assigned-addresses for every PCIe Root Port

Pali Rohár <pali@kernel.org>
    ARM: dts: dove: Fix assigned-addresses for every PCIe Root Port

Frank Wunderlich <frank-w@public-files.de>
    arm64: dts: mt7986: move wed_pcie node

Vidya Sagar <vidyas@nvidia.com>
    arm64: tegra: Fix non-prefetchable aperture of PCIe C3 controller

Vidya Sagar <vidyas@nvidia.com>
    arm64: tegra: Fix Prefetchable aperture ranges of Tegra234 PCIe controllers

AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
    arm64: dts: mediatek: mt6797: Fix 26M oscillator unit name

AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
    arm64: dts: mediatek: pumpkin-common: Fix devicetree warnings

AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
    arm64: dts: mt2712-evb: Fix usb vbus regulators unit names

AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
    arm64: dts: mt2712-evb: Fix vproc fixed regulators unit names

AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
    arm64: dts: mt2712e: Fix unit address for pinctrl node

AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
    arm64: dts: mt2712e: Fix unit_address_vs_reg warning for oscillators

AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
    arm64: dts: mt6779: Fix devicetree build warnings

AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
    arm64: dts: mt7896a: Fix unit_address_vs_reg warning for oscillator

AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
    arm64: dts: mediatek: mt8195: Fix CPUs capacity-dmips-mhz

Jonathan Neuschäfer <j.neuschaefer@gmx.net>
    ARM: dts: nuvoton: Remove bogus unit addresses from fixed-partition nodes

Conor Dooley <conor.dooley@microchip.com>
    riscv: dts: microchip: remove pcie node from the sev kit

Keerthy <j-keerthy@ti.com>
    arm64: dts: ti: k3-j721s2: Fix the interrupt ranges property for main & wkup gpio intr

Jayesh Choudhary <j-choudhary@ti.com>
    arm64: dts: ti: k3-j7200-mcu-wakeup: Drop dma-coherent in crypto node

Jayesh Choudhary <j-choudhary@ti.com>
    arm64: dts: ti: k3-j721e-main: Drop dma-coherent in crypto node

Jayesh Choudhary <j-choudhary@ti.com>
    arm64: dts: ti: k3-am65-main: Drop dma-coherent in crypto node

Shang XiaoJing <shangxiaojing@huawei.com>
    perf/smmuv3: Fix hotplug callback leak in arm_smmu_pmu_init()

Shang XiaoJing <shangxiaojing@huawei.com>
    perf/arm_dmc620: Fix hotplug callback leak in dmc620_pmu_init()

Yuan Can <yuancan@huawei.com>
    drivers: perf: marvell_cn10k: Fix hotplug callback leak in tad_pmu_init()

Yuan Can <yuancan@huawei.com>
    perf: arm_dsu: Fix hotplug callback leak in dsu_pmu_init()

Mark Rutland <mark.rutland@arm.com>
    arm64: mm: kfence: only handle translation faults

Zhang Qilong <zhangqilong3@huawei.com>
    soc: ti: smartreflex: Fix PM disable depth imbalance in omap_sr_probe

Zhang Qilong <zhangqilong3@huawei.com>
    soc: ti: knav_qmss_queue: Fix PM disable depth imbalance in knav_queue_probe

Conor Dooley <conor.dooley@microchip.com>
    riscv: dts: microchip: fix the icicle's #pwm-cells

Kory Maincent <kory.maincent@bootlin.com>
    arm: dts: spear600: Fix clcd interrupt

Sibi Sankar <quic_sibis@quicinc.com>
    arm64: dts: qcom: sc7280: Mark all Qualcomm reference boards as LTE

Sumit Gupta <sumitg@nvidia.com>
    soc/tegra: cbb: Check firewall before enabling error reporting

Sumit Gupta <sumitg@nvidia.com>
    soc/tegra: cbb: Add checks for potential out of bound errors

Sumit Gupta <sumitg@nvidia.com>
    soc/tegra: cbb: Update slave maps for Tegra234

Sumit Gupta <sumitg@nvidia.com>
    soc/tegra: cbb: Use correct master_id mask for CBB NOC in Tegra194

Frank Wunderlich <frank-w@public-files.de>
    arm64: dts: mt7986: fix trng node name

Yang Yingliang <yangyingliang@huawei.com>
    soc: sifive: ccache: fix missing of_node_put() in sifive_ccache_init()

Yang Yingliang <yangyingliang@huawei.com>
    soc: sifive: ccache: fix missing free_irq() in error path in sifive_ccache_init()

Yang Yingliang <yangyingliang@huawei.com>
    soc: sifive: ccache: fix missing iounmap() in error path in sifive_ccache_init()

Conor Dooley <conor.dooley@microchip.com>
    dt-bindings: pwm: fix microchip corePWM's pwm-cells

Fabrizio Castro <fabrizio.castro.jz@renesas.com>
    arm64: dts: renesas: r9a09g011: Fix I2C SoC specific strings

Fabrizio Castro <fabrizio.castro.jz@renesas.com>
    arm64: dts: renesas: r9a09g011: Fix unit address format error

Wolfram Sang <wsa+renesas@sang-engineering.com>
    arm64: dts: renesas: r8a779f0: Fix SCIF "brg_int" clock

Wolfram Sang <wsa+renesas@sang-engineering.com>
    arm64: dts: renesas: r8a779f0: Fix HSCIF "brg_int" clock

Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
    arm64: dts: qcom: sm6125: fix SDHCI CQE reg names

Marijn Suijten <marijn.suijten@somainline.org>
    arm64: dts: qcom: pm6350: Include header for KEY_POWER

Jiasheng Jiang <jiasheng@iscas.ac.cn>
    soc: qcom: apr: Add check for idr_alloc and of_property_read_string_index

Johan Hovold <johan+linaro@kernel.org>
    arm64: dts: qcom: sm6350: drop bogus DP PHY clock

Johan Hovold <johan+linaro@kernel.org>
    arm64: dts: qcom: sm8250: drop bogus DP PHY clock

Dmitry Torokhov <dmitry.torokhov@gmail.com>
    arm64: dts: qcom: sc7280: fix codec reset line polarity for CRD 1.0/2.0

Dmitry Torokhov <dmitry.torokhov@gmail.com>
    arm64: dts: qcom: sc7280: fix codec reset line polarity for CRD 3.0/3.1

Dmitry Torokhov <dmitry.torokhov@gmail.com>
    arm64: dts: qcom: sm8250-mtp: fix reset line polarity

Dmitry Torokhov <dmitry.torokhov@gmail.com>
    arm64: dts: qcom: msm8996: fix sound card reset line polarity

Johan Hovold <johan+linaro@kernel.org>
    arm64: dts: qcom: sm8450: fix UFS PHY registers

Johan Hovold <johan+linaro@kernel.org>
    arm64: dts: qcom: sm8350: fix UFS PHY registers

Johan Hovold <johan+linaro@kernel.org>
    arm64: dts: qcom: sm8250: fix UFS PHY registers

Johan Hovold <johan+linaro@kernel.org>
    arm64: dts: qcom: sm8150: fix UFS PHY registers

Luca Weiss <luca.weiss@fairphone.com>
    soc: qcom: llcc: make irq truly optional

Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
    arm64: dts: qcom: sc7180-trogdor-homestar: fully configure secondary I2S pins

Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
    arm64: dts: qcom: sm8250: correct LPASS pin pull down

Marijn Suijten <marijn.suijten@somainline.org>
    arm64: dts: qcom: pm660: Use unique ADC5_VCOIN address in node name

Conor Dooley <conor.dooley@microchip.com>
    riscv: dts: microchip: fix memory node unit address for icicle

Georgi Vlaev <g-vlaev@ti.com>
    firmware: ti_sci: Fix polled mode during system suspend

Chen Jiahao <chenjiahao16@huawei.com>
    drivers: soc: ti: knav_qmss_queue: Mark knav_acc_firmwares as static

Marek Vasut <marex@denx.de>
    ARM: dts: stm32: Fix AV96 WLAN regulator gpio property

Marek Vasut <marex@denx.de>
    ARM: dts: stm32: Drop stm32mp15xc.dtsi from Avenger96

Marco Elver <elver@google.com>
    objtool, kcsan: Add volatile read/write instrumentation to whitelist

Cong Dang <cong.dang.xn@renesas.com>
    memory: renesas-rpc-if: Clear HS bit during hardware initialization

Padmanabhan Rajanbabu <p.rajanbabu@samsung.com>
    arm64: dts: fsd: fix drive strength values as per FSD HW UM

Padmanabhan Rajanbabu <p.rajanbabu@samsung.com>
    arm64: dts: fsd: fix drive strength macros as per FSD HW UM

Stephan Gerhold <stephan.gerhold@kernkonzept.com>
    arm64: dts: qcom: msm8916: Drop MSS fallback compatible

Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
    arm64: dts: qcom: sdm845-cheza: fix AP suspend pin bias

Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
    arm64: dts: qcom: sdm630: fix UART1 pin bias

Luca Weiss <luca@z3ntu.xyz>
    ARM: dts: qcom: apq8064: fix coresight compatible

Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
    arm64: dts: qcom: msm8996: fix GPU OPP table

Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
    arm64: dts: qcom: msm8996: fix supported-hw in cpufreq OPP tables

Yassine Oudjana <y.oudjana@protonmail.com>
    arm64: dts: qcom: msm8996: Add MSM8996 Pro support

Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
    arm64: dts: qcom: sdm845-xiaomi-polaris: fix codec pin conf name

Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
    arm64: dts: qcom: sm8250-sony-xperia-edo: fix touchscreen bias-disable

Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
    arm64: dts: qcom: ipq6018-cp01-c1: use BLSPI1 pins

Geert Uytterhoeven <geert+renesas@glider.be>
    arm64: dts: renesas: r8a779g0: Fix HSCIF0 "brg_int" clock

Ivaylo Dimitrov <ivo.g.dimitrov.75@gmail.com>
    usb: musb: remove extra check in musb_gadget_vbus_draw

Dmitry Torokhov <dmitry.torokhov@gmail.com>
    MIPS: DTS: CI20: fix reset line polarity of the ethernet controller


-------------

Diffstat:

 Documentation/ABI/stable/sysfs-driver-dma-idxd     |  12 +
 .../ABI/testing/sysfs-bus-spi-devices-spi-nor      |   3 +
 Documentation/admin-guide/sysctl/kernel.rst        |  23 +
 .../devicetree/bindings/input/azoteq,iqs7222.yaml  |  25 +-
 .../devicetree/bindings/mfd/qcom,spmi-pmic.yaml    |   8 +-
 .../devicetree/bindings/pci/fsl,imx6q-pcie.yaml    |  46 +-
 .../bindings/pci/toshiba,visconti-pcie.yaml        |   7 +-
 .../bindings/pinctrl/mediatek,mt7986-pinctrl.yaml  |  46 +-
 .../devicetree/bindings/pwm/microchip,corepwm.yaml |   4 +-
 .../devicetree/bindings/sound/qcom,wcd9335.txt     |   2 +-
 Documentation/devicetree/bindings/sound/rt5682.txt |   2 +-
 Documentation/driver-api/spi.rst                   |   4 +-
 Documentation/fault-injection/fault-injection.rst  |  10 +-
 Makefile                                           |   4 +-
 arch/Kconfig                                       |   2 +-
 arch/alpha/include/asm/thread_info.h               |   2 +-
 arch/alpha/kernel/entry.S                          |   4 +-
 arch/arm/boot/dts/armada-370.dtsi                  |   2 +-
 arch/arm/boot/dts/armada-375.dtsi                  |   2 +-
 arch/arm/boot/dts/armada-380.dtsi                  |   4 +-
 arch/arm/boot/dts/armada-385-turris-omnia.dts      |  18 +-
 arch/arm/boot/dts/armada-385.dtsi                  |   6 +-
 arch/arm/boot/dts/armada-38x.dtsi                  |   4 +-
 arch/arm/boot/dts/armada-39x.dtsi                  |  10 +-
 arch/arm/boot/dts/armada-xp-mv78230.dtsi           |   8 +-
 arch/arm/boot/dts/armada-xp-mv78260.dtsi           |  16 +-
 arch/arm/boot/dts/aspeed-bmc-ibm-everest.dts       |  17 +-
 arch/arm/boot/dts/aspeed-bmc-ibm-rainier.dts       |  16 +-
 arch/arm/boot/dts/dove.dtsi                        |   2 +-
 arch/arm/boot/dts/nuvoton-npcm730-gbs.dts          |   2 +-
 arch/arm/boot/dts/nuvoton-npcm730-gsj.dts          |   2 +-
 arch/arm/boot/dts/nuvoton-npcm730-kudo.dts         |   6 +-
 arch/arm/boot/dts/nuvoton-npcm750-evb.dts          |   4 +-
 .../boot/dts/nuvoton-npcm750-runbmc-olympus.dts    |   6 +-
 arch/arm/boot/dts/qcom-apq8064.dtsi                |   2 +-
 arch/arm/boot/dts/spear600.dtsi                    |   2 +-
 arch/arm/boot/dts/stm32mp157a-dhcor-avenger96.dts  |   1 -
 arch/arm/boot/dts/stm32mp15xx-dhcor-avenger96.dtsi |   2 +-
 arch/arm/mach-mmp/time.c                           |  11 +-
 arch/arm64/boot/dts/apple/t8103.dtsi               |   6 +-
 .../boot/dts/marvell/armada-3720-turris-mox.dts    |   3 +
 arch/arm64/boot/dts/mediatek/mt2712-evb.dts        |  12 +-
 arch/arm64/boot/dts/mediatek/mt2712e.dtsi          |  22 +-
 arch/arm64/boot/dts/mediatek/mt6779.dtsi           |   8 +-
 arch/arm64/boot/dts/mediatek/mt6797.dtsi           |   2 +-
 arch/arm64/boot/dts/mediatek/mt7986a.dtsi          |  16 +-
 arch/arm64/boot/dts/mediatek/mt8183.dtsi           |   2 +-
 arch/arm64/boot/dts/mediatek/mt8195.dtsi           |   8 +-
 arch/arm64/boot/dts/mediatek/pumpkin-common.dtsi   |   6 +-
 arch/arm64/boot/dts/nvidia/tegra234.dtsi           |   8 +-
 arch/arm64/boot/dts/qcom/ipq6018-cp01-c1.dts       |   2 +
 arch/arm64/boot/dts/qcom/msm8916.dtsi              |   2 +-
 arch/arm64/boot/dts/qcom/msm8996.dtsi              | 114 ++--
 arch/arm64/boot/dts/qcom/msm8996pro.dtsi           | 266 +++++++++
 arch/arm64/boot/dts/qcom/pm6350.dtsi               |   1 +
 arch/arm64/boot/dts/qcom/pm660.dtsi                |   2 +-
 .../boot/dts/qcom/sc7180-trogdor-homestar.dtsi     |   6 +
 arch/arm64/boot/dts/qcom/sc7280-idp.dts            |   1 -
 arch/arm64/boot/dts/qcom/sc7280-idp.dtsi           |   3 +-
 arch/arm64/boot/dts/qcom/sc7280-qcard.dtsi         |   2 +-
 arch/arm64/boot/dts/qcom/sdm630.dtsi               |   2 +-
 arch/arm64/boot/dts/qcom/sdm845-cheza.dtsi         |   4 +-
 arch/arm64/boot/dts/qcom/sdm845-xiaomi-polaris.dts |   2 +-
 arch/arm64/boot/dts/qcom/sm6125.dtsi               |   2 +-
 arch/arm64/boot/dts/qcom/sm6350.dtsi               |  10 +-
 arch/arm64/boot/dts/qcom/sm8150.dtsi               |  10 +-
 arch/arm64/boot/dts/qcom/sm8250-mtp.dts            |   2 +-
 .../boot/dts/qcom/sm8250-sony-xperia-edo.dtsi      |   2 +-
 arch/arm64/boot/dts/qcom/sm8250.dtsi               |  20 +-
 arch/arm64/boot/dts/qcom/sm8350.dtsi               |  10 +-
 .../dts/qcom/sm8450-sony-xperia-nagara-pdx223.dts  |   2 -
 arch/arm64/boot/dts/qcom/sm8450.dtsi               |  13 +-
 arch/arm64/boot/dts/renesas/r8a779f0.dtsi          |  16 +-
 arch/arm64/boot/dts/renesas/r8a779g0.dtsi          |   2 +-
 arch/arm64/boot/dts/renesas/r9a09g011.dtsi         |   6 +-
 arch/arm64/boot/dts/tesla/fsd-pinctrl.dtsi         |  34 +-
 arch/arm64/boot/dts/tesla/fsd-pinctrl.h            |   6 +-
 arch/arm64/boot/dts/ti/k3-am65-main.dtsi           |   1 -
 arch/arm64/boot/dts/ti/k3-j7200-mcu-wakeup.dtsi    |   1 -
 arch/arm64/boot/dts/ti/k3-j721e-main.dtsi          |   1 -
 arch/arm64/boot/dts/ti/k3-j721s2-main.dtsi         |   2 +-
 arch/arm64/boot/dts/ti/k3-j721s2-mcu-wakeup.dtsi   |   2 +-
 arch/arm64/crypto/Kconfig                          |  11 +
 arch/arm64/crypto/Makefile                         |   3 +
 arch/arm64/crypto/sm3-neon-core.S                  | 601 ++++++++++++++++++++
 arch/arm64/crypto/sm3-neon-glue.c                  | 103 ++++
 arch/arm64/include/asm/processor.h                 |   4 +-
 arch/arm64/mm/fault.c                              |   8 +-
 arch/mips/bcm63xx/clk.c                            |   2 +
 arch/mips/boot/dts/ingenic/ci20.dts                |   2 +-
 .../cavium-octeon/executive/cvmx-helper-board.c    |   2 +-
 arch/mips/cavium-octeon/executive/cvmx-helper.c    |   2 +-
 arch/mips/kernel/vpe-cmp.c                         |   4 +-
 arch/mips/kernel/vpe-mt.c                          |   4 +-
 arch/mips/ralink/of.c                              |   4 +-
 arch/powerpc/boot/dts/fsl/qoriq-fman3-0-10g-2.dtsi |  44 ++
 arch/powerpc/boot/dts/fsl/qoriq-fman3-0-10g-3.dtsi |  44 ++
 arch/powerpc/boot/dts/fsl/t2081si-post.dtsi        |   4 +-
 arch/powerpc/boot/dts/turris1x.dts                 |  14 +
 arch/powerpc/include/asm/hvcall.h                  |   3 +-
 arch/powerpc/perf/callchain.c                      |   1 +
 arch/powerpc/perf/hv-gpci-requests.h               |   4 +
 arch/powerpc/perf/hv-gpci.c                        |  35 +-
 arch/powerpc/perf/hv-gpci.h                        |   1 +
 arch/powerpc/perf/req-gen/perf.h                   |  20 +
 arch/powerpc/platforms/52xx/mpc52xx_lpbfifo.c      |   1 +
 arch/powerpc/platforms/83xx/mpc832x_rdb.c          |   2 +-
 arch/powerpc/platforms/pseries/eeh_pseries.c       |  11 +-
 arch/powerpc/platforms/pseries/plpks.c             |  32 +-
 arch/powerpc/platforms/pseries/plpks.h             |   2 +-
 arch/powerpc/sysdev/xive/spapr.c                   |   1 +
 arch/powerpc/xmon/xmon.c                           |   7 +-
 .../boot/dts/microchip/mpfs-icicle-kit-fabric.dtsi |   2 +-
 arch/riscv/boot/dts/microchip/mpfs-icicle-kit.dts  |   2 +-
 .../boot/dts/microchip/mpfs-sev-kit-fabric.dtsi    |  29 -
 arch/riscv/include/asm/hugetlb.h                   |   6 +
 arch/riscv/include/asm/io.h                        |   5 +
 arch/riscv/include/asm/pgtable-64.h                |   6 +-
 arch/riscv/kernel/entry.S                          |  18 +-
 arch/riscv/kernel/signal.c                         |  34 +-
 arch/riscv/kernel/traps.c                          |   2 +-
 arch/riscv/kvm/vcpu.c                              |  11 +-
 arch/riscv/mm/physaddr.c                           |   2 +-
 arch/riscv/net/bpf_jit_comp64.c                    |  29 +-
 arch/x86/Kconfig                                   |   4 +-
 arch/x86/crypto/aegis128-aesni-asm.S               |   9 +-
 arch/x86/crypto/aria-aesni-avx-asm_64.S            |  13 +-
 arch/x86/crypto/sha1_ni_asm.S                      |   3 +-
 arch/x86/crypto/sha1_ssse3_asm.S                   |   3 +-
 arch/x86/crypto/sha256-avx-asm.S                   |   3 +-
 arch/x86/crypto/sha256-avx2-asm.S                  |   3 +-
 arch/x86/crypto/sha256-ssse3-asm.S                 |   3 +-
 arch/x86/crypto/sha256_ni_asm.S                    |   3 +-
 arch/x86/crypto/sha512-avx-asm.S                   |   3 +-
 arch/x86/crypto/sha512-avx2-asm.S                  |   3 +-
 arch/x86/crypto/sha512-ssse3-asm.S                 |   3 +-
 arch/x86/crypto/sm3-avx-asm_64.S                   |   3 +-
 arch/x86/crypto/sm4-aesni-avx-asm_64.S             |   7 +-
 arch/x86/crypto/sm4-aesni-avx2-asm_64.S            |   7 +-
 arch/x86/events/intel/uncore_snb.c                 |   3 +
 arch/x86/events/intel/uncore_snbep.c               |   5 +
 arch/x86/hyperv/hv_init.c                          |   2 -
 arch/x86/include/asm/apic.h                        |   3 +-
 arch/x86/include/asm/realmode.h                    |   1 +
 arch/x86/include/asm/x86_init.h                    |   4 +
 arch/x86/kernel/apic/apic.c                        |  13 +-
 arch/x86/kernel/cpu/intel.c                        |  63 ++-
 arch/x86/kernel/cpu/sgx/encl.c                     |  23 +-
 arch/x86/kernel/setup.c                            |   2 +-
 arch/x86/kernel/uprobes.c                          |   4 +-
 arch/x86/kernel/x86_init.c                         |   3 +
 arch/x86/realmode/init.c                           |   8 +-
 arch/x86/xen/enlighten_pv.c                        |   2 +
 arch/x86/xen/smp.c                                 |  24 +-
 arch/x86/xen/smp_pv.c                              |  12 +-
 arch/x86/xen/spinlock.c                            |   6 +-
 block/bfq-iosched.c                                |  16 +-
 block/blk-cgroup.c                                 |   2 +
 block/blk-core.c                                   |  72 +--
 block/blk-crypto-internal.h                        |  10 +-
 block/blk-crypto-sysfs.c                           |  11 +-
 block/blk-ia-ranges.c                              |   3 +-
 block/blk-mq-sysfs.c                               |  11 +-
 block/blk-mq.c                                     |  89 ++-
 block/blk-mq.h                                     |  14 +-
 block/blk-sysfs.c                                  | 134 ++---
 block/blk.h                                        |  13 +-
 block/bsg.c                                        |  11 +-
 block/elevator.c                                   |   2 +-
 block/genhd.c                                      |   4 +-
 crypto/cryptd.c                                    |  36 +-
 crypto/tcrypt.c                                    | 265 +++++----
 drivers/acpi/acpica/dsmethod.c                     |  10 +-
 drivers/acpi/acpica/utcopy.c                       |   7 -
 drivers/acpi/ec.c                                  |  10 +
 drivers/acpi/irq.c                                 |   5 +-
 drivers/acpi/pfr_telemetry.c                       |   6 +-
 drivers/acpi/pfr_update.c                          |   6 +-
 drivers/acpi/processor_idle.c                      |   3 +
 drivers/acpi/video_detect.c                        |  54 +-
 drivers/acpi/x86/utils.c                           |  24 +-
 drivers/ata/libata-sata.c                          |  11 +-
 drivers/base/class.c                               |   5 +
 drivers/base/power/runtime.c                       |  12 +-
 drivers/base/regmap/regmap-irq.c                   |  15 +-
 drivers/block/drbd/drbd_main.c                     |   9 +-
 drivers/block/drbd/drbd_nl.c                       |  10 +-
 drivers/block/floppy.c                             |   4 +-
 drivers/block/loop.c                               |  28 +-
 drivers/bluetooth/btintel.c                        |   5 +-
 drivers/bluetooth/btusb.c                          |   6 +-
 drivers/bluetooth/hci_bcm.c                        |  13 +-
 drivers/bluetooth/hci_bcsp.c                       |   2 +-
 drivers/bluetooth/hci_h5.c                         |   2 +-
 drivers/bluetooth/hci_ll.c                         |   2 +-
 drivers/bluetooth/hci_qca.c                        |   2 +-
 drivers/char/hw_random/amd-rng.c                   |  18 +-
 drivers/char/hw_random/geode-rng.c                 |  36 +-
 drivers/char/ipmi/ipmi_msghandler.c                |   8 +-
 drivers/char/ipmi/kcs_bmc_aspeed.c                 |  24 +-
 drivers/char/tpm/tpm_crb.c                         |   2 +-
 drivers/char/tpm/tpm_ftpm_tee.c                    |   8 +-
 drivers/char/tpm/tpm_tis_core.c                    |  20 +-
 drivers/char/tpm/tpm_tis_core.h                    |   1 +
 drivers/char/tpm/tpm_tis_i2c.c                     |   3 +-
 drivers/clk/imx/clk-imx8mn.c                       | 116 ++--
 drivers/clk/imx/clk-imx8mp.c                       |   4 +-
 drivers/clk/imx/clk-imx93.c                        |  19 +-
 drivers/clk/imx/clk-imxrt1050.c                    |   2 +-
 drivers/clk/mediatek/clk-mt7986-infracfg.c         |   2 +-
 drivers/clk/microchip/clk-mpfs-ccc.c               |   6 +
 drivers/clk/qcom/clk-krait.c                       |   2 +
 drivers/clk/qcom/dispcc-sm6350.c                   |   4 +-
 drivers/clk/qcom/gcc-ipq806x.c                     |   4 +-
 drivers/clk/qcom/gcc-sm8250.c                      |   4 +-
 drivers/clk/qcom/lpassaudiocc-sc7280.c             |  55 +-
 drivers/clk/qcom/lpasscorecc-sc7180.c              |  24 +-
 drivers/clk/renesas/r8a779a0-cpg-mssr.c            |   2 +-
 drivers/clk/renesas/r8a779f0-cpg-mssr.c            |  18 +-
 drivers/clk/renesas/r9a06g032-clocks.c             |   3 +-
 drivers/clk/rockchip/clk-pll.c                     |   1 +
 drivers/clk/samsung/clk-pll.c                      |   1 +
 drivers/clk/socfpga/clk-gate.c                     |   5 +-
 drivers/clk/st/clkgen-fsyn.c                       |   5 +-
 drivers/clk/visconti/pll.c                         |   1 +
 drivers/clocksource/sh_cmt.c                       |  88 +--
 drivers/clocksource/timer-ti-dm-systimer.c         |   4 +-
 drivers/clocksource/timer-ti-dm.c                  |   2 +-
 drivers/counter/stm32-lptimer-cnt.c                |   2 +-
 drivers/cpufreq/amd_freq_sensitivity.c             |   2 +
 drivers/cpufreq/qcom-cpufreq-hw.c                  |  43 +-
 drivers/cpuidle/dt_idle_states.c                   |   2 +-
 drivers/crypto/Kconfig                             |   5 +
 .../crypto/allwinner/sun8i-ss/sun8i-ss-cipher.c    |   2 +-
 drivers/crypto/amlogic/amlogic-gxl-core.c          |   1 -
 drivers/crypto/amlogic/amlogic-gxl.h               |   2 +-
 drivers/crypto/cavium/nitrox/nitrox_mbx.c          |   1 +
 drivers/crypto/ccree/cc_debugfs.c                  |   2 +-
 drivers/crypto/ccree/cc_driver.c                   |  10 +-
 drivers/crypto/hisilicon/hpre/hpre_main.c          |  10 +-
 drivers/crypto/hisilicon/qm.c                      |  11 +-
 drivers/crypto/img-hash.c                          |   8 +-
 drivers/crypto/omap-sham.c                         |   2 +-
 drivers/crypto/qat/qat_4xxx/adf_drv.c              |   1 +
 drivers/crypto/rockchip/rk3288_crypto.c            | 193 +------
 drivers/crypto/rockchip/rk3288_crypto.h            |  53 +-
 drivers/crypto/rockchip/rk3288_crypto_ahash.c      | 197 ++++---
 drivers/crypto/rockchip/rk3288_crypto_skcipher.c   | 413 ++++++++------
 drivers/dio/dio.c                                  |   8 +
 drivers/dma/apple-admac.c                          | 102 +++-
 drivers/dma/idxd/sysfs.c                           |  68 +++
 drivers/edac/i10nm_base.c                          |   3 +-
 drivers/extcon/extcon-usbc-tusb320.c               |  17 +-
 drivers/firmware/raspberrypi.c                     |   1 +
 drivers/firmware/ti_sci.c                          |   5 +-
 drivers/gpio/gpiolib-cdev.c                        | 204 ++++++-
 drivers/gpio/gpiolib.c                             |   4 +
 drivers/gpio/gpiolib.h                             |   5 +
 drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c   |   2 +-
 drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c           |   1 +
 drivers/gpu/drm/amd/amdgpu/amdgpu_device.c         |   9 +
 drivers/gpu/drm/amd/amdgpu/amdgpu_virt.h           |   5 +-
 drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.c           |   2 -
 drivers/gpu/drm/amd/amdgpu/nv.c                    |  28 +-
 drivers/gpu/drm/amd/amdgpu/soc15.c                 |  24 +-
 drivers/gpu/drm/amd/amdgpu/soc21.c                 |   2 +-
 .../drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c  |  35 --
 drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c |  16 +-
 .../amd/display/dc/clk_mgr/dcn32/dcn32_clk_mgr.c   |   2 +-
 drivers/gpu/drm/amd/display/dc/core/dc.c           |  65 ++-
 .../gpu/drm/amd/display/dc/dce60/dce60_resource.c  |   3 +
 .../gpu/drm/amd/display/dc/dce80/dce80_resource.c  |   2 +
 .../drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c  |  30 +-
 drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c |  35 +-
 drivers/gpu/drm/amd/display/dc/dcn32/dcn32_dccg.c  |   6 +-
 .../gpu/drm/amd/display/dc/dcn32/dcn32_resource.c  |   2 +-
 .../gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c   |   7 +
 drivers/gpu/drm/amd/include/kgd_pp_interface.h     |   3 +-
 drivers/gpu/drm/amd/pm/powerplay/amd_powerplay.c   |   3 +-
 drivers/gpu/drm/amd/pm/powerplay/hwmgr/pp_psm.c    |   2 +
 .../drm/amd/pm/powerplay/hwmgr/vega10_thermal.c    |  25 +-
 .../gpu/drm/amd/pm/powerplay/hwmgr/vega20_hwmgr.c  |   3 +-
 drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c     |   4 +
 .../gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c   |  21 +-
 drivers/gpu/drm/bridge/adv7511/adv7511.h           |   3 +-
 drivers/gpu/drm/bridge/adv7511/adv7511_drv.c       |  18 +-
 drivers/gpu/drm/bridge/adv7511/adv7533.c           |  25 +-
 drivers/gpu/drm/bridge/ite-it6505.c                |   8 +-
 drivers/gpu/drm/drm_atomic_helper.c                |  10 +-
 drivers/gpu/drm/drm_edid.c                         |  12 +
 drivers/gpu/drm/drm_fourcc.c                       |   8 +-
 drivers/gpu/drm/etnaviv/etnaviv_gpu.c              |  11 +-
 drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c          |   5 +-
 drivers/gpu/drm/i915/display/intel_bios.c          |   2 +-
 drivers/gpu/drm/i915/display/intel_dp.c            |  59 --
 drivers/gpu/drm/i915/gem/i915_gem_mman.c           |  21 +-
 drivers/gpu/drm/i915/gem/i915_gem_pm.c             |   2 +-
 drivers/gpu/drm/i915/gem/i915_gem_ttm.c            |  63 ++-
 drivers/gpu/drm/i915/gem/i915_gem_ttm.h            |  18 +-
 drivers/gpu/drm/i915/gem/i915_gem_ttm_move.c       |   2 +-
 drivers/gpu/drm/i915/gt/intel_engine.h             |   6 +
 drivers/gpu/drm/i915/gt/intel_engine_cs.c          |  91 ++-
 drivers/gpu/drm/i915/gt/intel_gt.c                 |   3 -
 drivers/gpu/drm/i915/gt/intel_gt_types.h           |  17 -
 drivers/gpu/drm/i915/gt/sysfs_engines.c            |  25 +-
 drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c     | 109 +++-
 drivers/gpu/drm/i915/gt/uc/intel_guc_fwif.h        |  21 +
 drivers/gpu/drm/i915/gt/uc/intel_guc_log.c         |   6 +-
 drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c  |   8 +
 drivers/gpu/drm/i915/i915_driver.c                 |   3 +-
 drivers/gpu/drm/i915/i915_gem.c                    |  45 +-
 drivers/gpu/drm/i915/intel_runtime_pm.c            |   5 +
 drivers/gpu/drm/i915/intel_runtime_pm.h            |  22 +
 drivers/gpu/drm/mediatek/mtk_dpi.c                 |  12 +-
 drivers/gpu/drm/mediatek/mtk_hdmi.c                |   7 +-
 drivers/gpu/drm/meson/meson_encoder_cvbs.c         |   7 +-
 drivers/gpu/drm/msm/adreno/a6xx_gpu.c              |  12 +-
 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.c         |  11 +-
 drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c           |  27 +-
 drivers/gpu/drm/msm/dp/dp_display.c                |   2 +-
 drivers/gpu/drm/msm/dsi/dsi_host.c                 | 121 ++--
 drivers/gpu/drm/msm/hdmi/hdmi.c                    |   2 +-
 drivers/gpu/drm/mxsfb/lcdif_kms.c                  |  48 +-
 drivers/gpu/drm/mxsfb/lcdif_regs.h                 |   5 +
 drivers/gpu/drm/panel/panel-sitronix-st7701.c      |  12 +-
 drivers/gpu/drm/radeon/radeon_bios.c               |  19 +-
 drivers/gpu/drm/rcar-du/Kconfig                    |   2 -
 drivers/gpu/drm/rockchip/cdn-dp-core.c             |   2 +-
 drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c    |   2 +-
 drivers/gpu/drm/rockchip/inno_hdmi.c               |   2 +-
 drivers/gpu/drm/rockchip/rk3066_hdmi.c             |   2 +-
 drivers/gpu/drm/rockchip/rockchip_drm_vop.c        |   4 +-
 drivers/gpu/drm/rockchip/rockchip_drm_vop2.c       |   2 +-
 drivers/gpu/drm/rockchip/rockchip_lvds.c           |  10 +-
 drivers/gpu/drm/sti/sti_dvo.c                      |   7 +-
 drivers/gpu/drm/sti/sti_hda.c                      |   7 +-
 drivers/gpu/drm/sti/sti_hdmi.c                     |   7 +-
 drivers/gpu/drm/tegra/dc.c                         |   4 +-
 drivers/hid/amd-sfh-hid/amd_sfh_client.c           |   4 +
 drivers/hid/hid-apple.c                            | 118 ++--
 drivers/hid/hid-input.c                            |   6 +
 drivers/hid/hid-logitech-hidpp.c                   |  11 +-
 drivers/hid/hid-mcp2221.c                          |  12 +-
 drivers/hid/hid-rmi.c                              |   2 +
 drivers/hid/hid-sensor-custom.c                    |   2 +-
 drivers/hid/hid-uclogic-params.c                   |  73 +++
 drivers/hid/hid-uclogic-rdesc.c                    |  34 ++
 drivers/hid/hid-uclogic-rdesc.h                    |   7 +
 drivers/hid/i2c-hid/i2c-hid-core.c                 |   3 +-
 drivers/hid/wacom_sys.c                            |   8 +
 drivers/hid/wacom_wac.c                            |   4 +
 drivers/hid/wacom_wac.h                            |   1 +
 drivers/hsi/controllers/omap_ssi_core.c            |  14 +-
 drivers/hv/ring_buffer.c                           |  13 +
 drivers/hwmon/Kconfig                              |   1 +
 drivers/hwmon/emc2305.c                            |  44 +-
 drivers/hwmon/jc42.c                               | 243 +++++----
 drivers/hwmon/nct6775-platform.c                   |   7 +
 drivers/hwtracing/coresight/coresight-cti-core.c   |   2 +-
 drivers/hwtracing/coresight/coresight-trbe.c       |   1 +
 drivers/i2c/busses/i2c-ismt.c                      |   3 +
 drivers/i2c/busses/i2c-pxa-pci.c                   |  10 +-
 drivers/i2c/muxes/i2c-mux-reg.c                    |   5 +-
 drivers/iio/adc/ad_sigma_delta.c                   |   8 +-
 drivers/iio/adc/ti-adc128s052.c                    |  14 +-
 drivers/iio/addac/ad74413r.c                       |   2 +-
 drivers/iio/imu/adis.c                             |  28 +-
 drivers/iio/industrialio-event.c                   |   4 +-
 drivers/iio/temperature/ltc2983.c                  |  10 +-
 drivers/infiniband/Kconfig                         |   2 +
 drivers/infiniband/core/device.c                   |   2 +-
 drivers/infiniband/core/mad.c                      |   5 -
 drivers/infiniband/core/nldev.c                    |   6 +-
 drivers/infiniband/core/restrack.c                 |   2 -
 drivers/infiniband/core/sysfs.c                    |  17 +-
 drivers/infiniband/hw/hfi1/affinity.c              |   2 +
 drivers/infiniband/hw/hfi1/firmware.c              |   6 +
 drivers/infiniband/hw/hns/hns_roce_device.h        |   3 +
 drivers/infiniband/hw/hns/hns_roce_hw_v2.c         | 217 ++++++--
 drivers/infiniband/hw/hns/hns_roce_hw_v2.h         |  13 +-
 drivers/infiniband/hw/hns/hns_roce_main.c          |  18 +-
 drivers/infiniband/hw/hns/hns_roce_mr.c            |   4 +-
 drivers/infiniband/hw/hns/hns_roce_qp.c            | 107 +++-
 drivers/infiniband/hw/irdma/uk.c                   | 170 +++---
 drivers/infiniband/hw/irdma/user.h                 |  20 +-
 drivers/infiniband/hw/irdma/utils.c                |   2 +
 drivers/infiniband/hw/irdma/verbs.c                | 145 ++---
 drivers/infiniband/hw/irdma/verbs.h                |  53 ++
 drivers/infiniband/sw/rxe/rxe_mr.c                 |   9 +-
 drivers/infiniband/sw/rxe/rxe_qp.c                 |   6 +-
 drivers/infiniband/sw/siw/siw_cq.c                 |  24 +-
 drivers/infiniband/sw/siw/siw_qp_tx.c              |   2 +-
 drivers/infiniband/sw/siw/siw_verbs.c              |  40 +-
 drivers/infiniband/ulp/ipoib/ipoib_netlink.c       |   7 +
 drivers/infiniband/ulp/srp/ib_srp.c                |  96 +++-
 drivers/input/joystick/Kconfig                     |   1 +
 drivers/input/misc/Kconfig                         |   2 +-
 drivers/input/misc/iqs7222.c                       | 504 ++++++++++-------
 drivers/input/touchscreen/elants_i2c.c             |   9 +-
 drivers/interconnect/qcom/sc7180.c                 |   2 +-
 drivers/iommu/amd/iommu_v2.c                       |   1 +
 drivers/iommu/fsl_pamu.c                           |   2 +-
 drivers/iommu/iommu.c                              |  28 +-
 drivers/iommu/mtk_iommu.c                          |  53 +-
 drivers/iommu/rockchip-iommu.c                     |  10 +-
 drivers/iommu/s390-iommu.c                         | 106 ++--
 drivers/iommu/sun50i-iommu.c                       |  89 ++-
 drivers/irqchip/irq-gic-pm.c                       |   2 +-
 drivers/irqchip/irq-loongson-liointc.c             |   5 +-
 drivers/irqchip/irq-loongson-pch-pic.c             |   3 +
 drivers/irqchip/irq-wpcm450-aic.c                  |   1 +
 drivers/isdn/hardware/mISDN/hfcmulti.c             |  19 +-
 drivers/isdn/hardware/mISDN/hfcpci.c               |  13 +-
 drivers/isdn/hardware/mISDN/hfcsusb.c              |  12 +-
 drivers/leds/leds-is31fl319x.c                     |   3 +-
 drivers/leds/rgb/leds-qcom-lpg.c                   |  18 +-
 drivers/macintosh/macio-adb.c                      |   4 +
 drivers/macintosh/macio_asic.c                     |   2 +-
 drivers/mailbox/arm_mhuv2.c                        |   4 +-
 drivers/mailbox/mailbox-mpfs.c                     |  31 +-
 drivers/mailbox/pcc.c                              |   1 +
 drivers/mailbox/zynqmp-ipi-mailbox.c               |   4 +-
 drivers/mcb/mcb-core.c                             |   4 +-
 drivers/mcb/mcb-parse.c                            |   2 +-
 drivers/md/dm.c                                    | 123 +++--
 drivers/md/md-bitmap.c                             |  27 +-
 drivers/md/raid0.c                                 |   1 -
 drivers/md/raid1.c                                 |   1 +
 drivers/md/raid10.c                                |   2 -
 drivers/media/dvb-core/dvb_ca_en50221.c            |   2 +-
 drivers/media/dvb-core/dvb_frontend.c              |  10 +-
 drivers/media/dvb-core/dvbdev.c                    |  32 +-
 drivers/media/dvb-frontends/bcm3510.c              |   1 +
 drivers/media/i2c/ad5820.c                         |  10 +-
 drivers/media/i2c/adv748x/adv748x-afe.c            |   4 +
 drivers/media/i2c/dw9768.c                         |  33 +-
 drivers/media/i2c/hi846.c                          |  14 +-
 drivers/media/i2c/mt9p031.c                        |   1 -
 drivers/media/i2c/ov5640.c                         |   3 +-
 drivers/media/i2c/ov5648.c                         |   1 +
 drivers/media/pci/saa7164/saa7164-core.c           |   4 +-
 drivers/media/pci/solo6x10/solo6x10-core.c         |   1 +
 drivers/media/platform/amphion/vdec.c              |  15 +-
 drivers/media/platform/amphion/vpu.h               |   1 +
 drivers/media/platform/amphion/vpu_cmds.c          |  39 +-
 drivers/media/platform/amphion/vpu_drv.c           |   6 +-
 drivers/media/platform/amphion/vpu_malone.c        |   1 +
 drivers/media/platform/amphion/vpu_msgs.c          |   2 +
 drivers/media/platform/amphion/vpu_v4l2.c          |  30 +-
 drivers/media/platform/amphion/vpu_windsor.c       |   1 +
 drivers/media/platform/chips-media/coda-bit.c      |  14 +-
 drivers/media/platform/chips-media/coda-jpeg.c     |  10 +-
 .../media/platform/mediatek/mdp3/mtk-mdp3-cmdq.c   |  51 +-
 .../media/platform/mediatek/mdp3/mtk-mdp3-comp.c   |  24 +-
 .../media/platform/mediatek/mdp3/mtk-mdp3-core.c   |  15 +-
 .../mediatek/vcodec/mtk_vcodec_dec_stateless.c     |  13 +-
 .../mediatek/vcodec/vdec/vdec_h264_req_multi_if.c  |  60 +-
 .../mediatek/vcodec/vdec/vdec_vp9_req_lat_if.c     |  15 +-
 .../platform/mediatek/vcodec/vdec_msg_queue.c      |   2 +-
 drivers/media/platform/nxp/imx-jpeg/mxc-jpeg-hw.c  |   4 +-
 drivers/media/platform/qcom/camss/camss-video.c    |   3 +-
 drivers/media/platform/qcom/camss/camss.c          |  11 +
 drivers/media/platform/qcom/venus/pm_helpers.c     |   4 +-
 .../media/platform/samsung/exynos4-is/fimc-core.c  |   2 +-
 .../media/platform/samsung/exynos4-is/media-dev.c  |  12 +-
 drivers/media/platform/samsung/s5p-mfc/s5p_mfc.c   |  17 +-
 .../platform/st/sti/c8sectpfe/c8sectpfe-core.c     |   1 +
 .../sunxi/sun6i-mipi-csi2/sun6i_mipi_csi2.c        |  23 +-
 .../sun8i-a83t-mipi-csi2/sun8i_a83t_mipi_csi2.c    |  23 +-
 drivers/media/radio/si470x/radio-si470x-usb.c      |   4 +-
 drivers/media/rc/imon.c                            |   6 +-
 drivers/media/test-drivers/vidtv/vidtv_bridge.c    |  22 +-
 drivers/media/test-drivers/vimc/vimc-core.c        |   2 +-
 drivers/media/test-drivers/vivid/vivid-vid-cap.c   |   1 +
 drivers/media/usb/dvb-usb/az6027.c                 |   4 +
 drivers/media/usb/dvb-usb/dvb-usb-init.c           |   4 +-
 drivers/media/v4l2-core/v4l2-ctrls-api.c           |   1 +
 drivers/media/v4l2-core/v4l2-ctrls-core.c          |   2 +-
 drivers/media/v4l2-core/v4l2-ioctl.c               |  34 +-
 drivers/media/v4l2-core/videobuf-dma-contig.c      |  22 +-
 drivers/memory/renesas-rpc-if.c                    |   3 +
 drivers/memstick/core/ms_block.c                   |   9 +-
 drivers/mfd/Kconfig                                |   1 +
 drivers/mfd/axp20x.c                               |   2 +-
 drivers/mfd/qcom-pm8008.c                          |   4 +-
 drivers/mfd/qcom_rpm.c                             |   4 +-
 drivers/misc/cxl/guest.c                           |  24 +-
 drivers/misc/cxl/pci.c                             |  21 +-
 drivers/misc/habanalabs/common/firmware_if.c       |   2 +-
 drivers/misc/lkdtm/cfi.c                           |   6 +-
 drivers/misc/ocxl/config.c                         |  20 +-
 drivers/misc/ocxl/file.c                           |   7 +-
 drivers/misc/sgi-gru/grufault.c                    |  13 +-
 drivers/misc/sgi-gru/grumain.c                     |  22 +-
 drivers/misc/sgi-gru/grutables.h                   |   2 +-
 drivers/misc/tifm_7xx1.c                           |   2 +-
 drivers/mmc/core/sd.c                              |  11 +-
 drivers/mmc/host/alcor.c                           |   5 +-
 drivers/mmc/host/atmel-mci.c                       |   9 +-
 drivers/mmc/host/litex_mmc.c                       |   1 +
 drivers/mmc/host/meson-gx-mmc.c                    |   4 +-
 drivers/mmc/host/mmci.c                            |   4 +-
 drivers/mmc/host/moxart-mmc.c                      |   4 +-
 drivers/mmc/host/mxcmmc.c                          |   4 +-
 drivers/mmc/host/omap_hsmmc.c                      |   4 +-
 drivers/mmc/host/pxamci.c                          |   7 +-
 drivers/mmc/host/renesas_sdhi.h                    |   1 +
 drivers/mmc/host/renesas_sdhi_core.c               |  14 +-
 drivers/mmc/host/renesas_sdhi_internal_dmac.c      |   4 +-
 drivers/mmc/host/rtsx_pci_sdmmc.c                  |   9 +-
 drivers/mmc/host/rtsx_usb_sdmmc.c                  |  11 +-
 drivers/mmc/host/sdhci-tegra.c                     |   3 +-
 drivers/mmc/host/sdhci.c                           |   5 +
 drivers/mmc/host/sdhci.h                           |   2 +
 drivers/mmc/host/sdhci_f_sdh30.c                   |   3 +
 drivers/mmc/host/toshsd.c                          |   6 +-
 drivers/mmc/host/via-sdmmc.c                       |   4 +-
 drivers/mmc/host/vub300.c                          |  11 +-
 drivers/mmc/host/wbsd.c                            |  12 +-
 drivers/mmc/host/wmt-sdmmc.c                       |   6 +-
 drivers/mtd/lpddr/lpddr2_nvm.c                     |   2 +
 drivers/mtd/maps/pxa2xx-flash.c                    |   2 +
 drivers/mtd/mtdcore.c                              |   9 +-
 drivers/mtd/spi-nor/core.c                         |   3 +-
 drivers/mtd/spi-nor/sysfs.c                        |  14 +
 drivers/net/bonding/bond_main.c                    |  37 +-
 drivers/net/can/m_can/m_can.c                      |  32 +-
 drivers/net/can/m_can/m_can_platform.c             |   4 -
 drivers/net/can/m_can/tcan4x5x-core.c              |  18 +-
 drivers/net/can/usb/kvaser_usb/kvaser_usb.h        |  30 +-
 drivers/net/can/usb/kvaser_usb/kvaser_usb_core.c   | 115 +++-
 drivers/net/can/usb/kvaser_usb/kvaser_usb_hydra.c  | 160 +++++-
 drivers/net/can/usb/kvaser_usb/kvaser_usb_leaf.c   | 437 +++++++++++++--
 drivers/net/dsa/lan9303-core.c                     |   4 +-
 drivers/net/dsa/microchip/ksz_common.c             |   3 +-
 drivers/net/dsa/mv88e6xxx/chip.c                   |   9 +-
 drivers/net/ethernet/adi/adin1110.c                |  37 +-
 drivers/net/ethernet/amd/atarilance.c              |   2 +-
 drivers/net/ethernet/amd/lance.c                   |   2 +-
 drivers/net/ethernet/amd/xgbe/xgbe-phy-v2.c        |  23 +-
 drivers/net/ethernet/apple/bmac.c                  |   2 +-
 drivers/net/ethernet/apple/mace.c                  |   2 +-
 drivers/net/ethernet/broadcom/bnx2.c               |   5 +-
 drivers/net/ethernet/dnet.c                        |   4 +-
 drivers/net/ethernet/freescale/enetc/enetc.c       |  35 +-
 drivers/net/ethernet/freescale/fec_main.c          |   8 +
 drivers/net/ethernet/intel/i40e/i40e_main.c        |  36 +-
 drivers/net/ethernet/intel/ice/ice_ptp.c           |  10 +-
 drivers/net/ethernet/intel/igb/igb_main.c          |   8 +-
 drivers/net/ethernet/intel/igc/igc.h               |   3 +
 drivers/net/ethernet/intel/igc/igc_defines.h       |   2 +
 drivers/net/ethernet/intel/igc/igc_main.c          | 210 ++++++-
 drivers/net/ethernet/intel/igc/igc_tsn.c           |  13 +-
 drivers/net/ethernet/marvell/octeontx2/af/mcs.c    |   6 +-
 drivers/net/ethernet/mediatek/mtk_eth_soc.c        |  71 ++-
 drivers/net/ethernet/mediatek/mtk_eth_soc.h        |  11 +-
 drivers/net/ethernet/myricom/myri10ge/myri10ge.c   |   1 +
 drivers/net/ethernet/neterion/s2io.c               |   2 +-
 drivers/net/ethernet/qlogic/qed/qed_debug.c        |   3 +-
 .../ethernet/qlogic/qlcnic/qlcnic_sriov_common.c   |   2 +
 drivers/net/ethernet/rdc/r6040.c                   |   5 +-
 .../net/ethernet/stmicro/stmmac/stmmac_hwtstamp.c  |   3 +-
 drivers/net/ethernet/stmicro/stmmac/stmmac_main.c  |   4 +-
 drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.h   |   2 +-
 .../net/ethernet/stmicro/stmmac/stmmac_selftests.c |   8 +-
 drivers/net/ethernet/ti/am65-cpsw-nuss.c           |  10 +-
 drivers/net/ethernet/ti/netcp_core.c               |   2 +-
 drivers/net/ethernet/xilinx/xilinx_emaclite.c      |   2 +-
 drivers/net/fddi/defxx.c                           |  22 +-
 drivers/net/hamradio/baycom_epp.c                  |   2 +-
 drivers/net/hamradio/scc.c                         |   6 +-
 drivers/net/macsec.c                               |  34 +-
 drivers/net/mctp/mctp-serial.c                     |   6 +-
 drivers/net/ntb_netdev.c                           |   4 +-
 drivers/net/ppp/ppp_generic.c                      |   2 +
 drivers/net/wan/farsync.c                          |   2 +
 drivers/net/wireless/ath/ar5523/ar5523.c           |   6 +
 drivers/net/wireless/ath/ath10k/core.c             |  16 +
 drivers/net/wireless/ath/ath10k/htc.c              |   9 +
 drivers/net/wireless/ath/ath10k/hw.h               |   2 +
 drivers/net/wireless/ath/ath10k/pci.c              |  20 +-
 drivers/net/wireless/ath/ath11k/core.h             |   2 +
 drivers/net/wireless/ath/ath11k/mac.c              | 122 +++--
 drivers/net/wireless/ath/ath11k/qmi.c              |   3 +
 drivers/net/wireless/ath/ath9k/hif_usb.c           |  46 +-
 .../wireless/broadcom/brcm80211/brcmfmac/common.c  |   8 +-
 .../broadcom/brcm80211/brcmfmac/firmware.c         |   5 +
 .../wireless/broadcom/brcm80211/brcmfmac/pcie.c    |   6 +-
 .../wireless/broadcom/brcm80211/brcmfmac/sdio.c    |   1 +
 drivers/net/wireless/intel/iwlwifi/mei/iwl-mei.h   |   7 +-
 drivers/net/wireless/intel/iwlwifi/mei/main.c      | 172 +++---
 drivers/net/wireless/intel/iwlwifi/mei/net.c       |  10 +-
 drivers/net/wireless/intel/iwlwifi/mvm/fw.c        |   2 +
 drivers/net/wireless/intel/iwlwifi/mvm/mvm.h       |   4 +-
 drivers/net/wireless/intel/iwlwifi/mvm/ops.c       |   2 +-
 drivers/net/wireless/intel/iwlwifi/mvm/tx.c        |  20 +-
 drivers/net/wireless/mediatek/mt76/mt76.h          |   3 +-
 .../net/wireless/mediatek/mt76/mt76_connac_mcu.c   |   4 +
 drivers/net/wireless/mediatek/mt76/mt7915/eeprom.c |  58 +-
 drivers/net/wireless/mediatek/mt76/mt7915/eeprom.h |   5 -
 drivers/net/wireless/mediatek/mt76/mt7915/mac.c    |  23 +-
 drivers/net/wireless/mediatek/mt76/mt7915/pci.c    |  13 +-
 drivers/net/wireless/mediatek/mt76/mt7921/init.c   |   1 +
 drivers/net/wireless/mediatek/mt76/mt7921/mac.c    |  34 +-
 drivers/net/wireless/mediatek/mt76/mt7921/main.c   |   6 +
 drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h |   4 +-
 drivers/net/wireless/mediatek/mt76/usb.c           |  11 +-
 drivers/net/wireless/purelifi/plfxlc/usb.c         |   1 +
 drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h   |   2 +-
 .../net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c  |  28 +-
 drivers/net/wireless/realtek/rtw89/core.c          |   2 +-
 drivers/net/wireless/realtek/rtw89/mac.c           |   6 +-
 drivers/net/wireless/realtek/rtw89/phy.c           |   2 +-
 drivers/net/wireless/rsi/rsi_91x_core.c            |   4 +-
 drivers/net/wireless/rsi/rsi_91x_hal.c             |   6 +-
 drivers/nfc/pn533/pn533.c                          |   4 +
 drivers/nvme/host/core.c                           |  19 +-
 drivers/nvme/host/fc.c                             |   2 +-
 drivers/nvme/host/nvme.h                           |   2 +-
 drivers/nvme/host/rdma.c                           |   4 +-
 drivers/nvme/host/tcp.c                            |   1 +
 drivers/nvme/target/core.c                         |  22 +-
 drivers/nvme/target/io-cmd-file.c                  |  16 +-
 drivers/nvme/target/loop.c                         |   2 +-
 drivers/nvme/target/nvmet.h                        |   3 +-
 drivers/of/overlay.c                               |   4 +-
 drivers/pci/controller/dwc/pci-imx6.c              |  13 +-
 drivers/pci/controller/dwc/pcie-designware.c       |   2 +-
 drivers/pci/controller/vmd.c                       |  27 +-
 drivers/pci/endpoint/functions/pci-epf-test.c      |   2 +-
 drivers/pci/endpoint/functions/pci-epf-vntb.c      |   2 +-
 drivers/pci/irq.c                                  |   2 +
 drivers/pci/probe.c                                |   3 -
 drivers/perf/arm_dmc620_pmu.c                      |   8 +-
 drivers/perf/arm_dsu_pmu.c                         |   6 +-
 drivers/perf/arm_smmuv3_pmu.c                      |   8 +-
 drivers/perf/hisilicon/hisi_pcie_pmu.c             |   8 +-
 drivers/perf/marvell_cn10k_tad_pmu.c               |   6 +-
 drivers/phy/broadcom/phy-brcm-usb-init-synopsys.c  |   9 +-
 drivers/phy/broadcom/phy-brcm-usb-init.h           |   1 -
 drivers/phy/broadcom/phy-brcm-usb.c                |  14 +-
 drivers/phy/marvell/phy-mvebu-a3700-comphy.c       |   3 +
 drivers/phy/qualcomm/phy-qcom-qmp-pcie.c           | 607 ++++++++++++---------
 drivers/phy/qualcomm/phy-qcom-qmp-pcs-pcie-v5_20.h |   2 +
 drivers/phy/qualcomm/phy-qcom-qmp-pcs-v5_20.h      |  14 +
 drivers/phy/qualcomm/phy-qcom-qmp-usb.c            | 142 +----
 drivers/phy/qualcomm/phy-qcom-qmp.h                |   1 +
 drivers/pinctrl/mediatek/pinctrl-mt7986.c          |  24 +-
 drivers/pinctrl/pinconf-generic.c                  |   4 +-
 drivers/pinctrl/pinctrl-k210.c                     |   4 +-
 drivers/pinctrl/pinctrl-ocelot.c                   |  20 +-
 drivers/pinctrl/pinctrl-thunderbay.c               |   8 +-
 drivers/platform/chrome/cros_ec_typec.c            |   3 +
 drivers/platform/chrome/cros_usbpd_notify.c        |   6 +-
 drivers/platform/mellanox/mlxbf-pmc.c              |   2 +-
 drivers/platform/x86/huawei-wmi.c                  |  20 +-
 .../platform/x86/intel/int3472/clk_and_regulator.c |   3 +-
 drivers/platform/x86/intel_scu_ipc.c               |   2 +-
 drivers/platform/x86/mxm-wmi.c                     |   8 +-
 drivers/pnp/core.c                                 |   4 +-
 drivers/power/supply/ab8500_charger.c              |   9 +-
 drivers/power/supply/bq25890_charger.c             |  71 ++-
 drivers/power/supply/cw2015_battery.c              |   3 +
 drivers/power/supply/power_supply_core.c           |   7 +-
 drivers/power/supply/rk817_charger.c               |   4 +-
 drivers/power/supply/z2_battery.c                  |   6 +-
 drivers/pwm/pwm-mediatek.c                         |   2 +-
 drivers/pwm/pwm-mtk-disp.c                         |   5 +-
 drivers/pwm/pwm-sifive.c                           |   5 +-
 drivers/pwm/pwm-tegra.c                            |  15 +-
 drivers/rapidio/devices/rio_mport_cdev.c           |  15 +-
 drivers/rapidio/rio-scan.c                         |   8 +-
 drivers/rapidio/rio.c                              |   9 +-
 drivers/regulator/core.c                           |  25 +-
 drivers/regulator/devres.c                         |   2 +-
 drivers/regulator/of_regulator.c                   |   2 +-
 drivers/regulator/qcom-labibb-regulator.c          |   1 +
 drivers/regulator/qcom-rpmh-regulator.c            |   2 +-
 drivers/regulator/stm32-vrefbuf.c                  |   2 +-
 drivers/remoteproc/qcom_q6v5_pas.c                 |   4 +
 drivers/remoteproc/qcom_q6v5_wcss.c                |   6 +-
 drivers/remoteproc/qcom_sysmon.c                   |   5 +-
 drivers/remoteproc/remoteproc_core.c               |   8 +-
 drivers/rtc/class.c                                |   4 +-
 drivers/rtc/rtc-cmos.c                             | 378 ++++++-------
 drivers/rtc/rtc-mxc_v2.c                           |   4 +-
 drivers/rtc/rtc-pcf2127.c                          |  22 +-
 drivers/rtc/rtc-pcf85063.c                         |  10 +-
 drivers/rtc/rtc-pic32.c                            |   8 +-
 drivers/rtc/rtc-rzn1.c                             |   4 +-
 drivers/rtc/rtc-snvs.c                             |  16 +-
 drivers/rtc/rtc-st-lpc.c                           |   1 +
 drivers/s390/net/ctcm_main.c                       |  11 +-
 drivers/s390/net/lcs.c                             |   8 +-
 drivers/s390/net/netiucv.c                         |   9 +-
 drivers/scsi/elx/efct/efct_driver.c                |   1 +
 drivers/scsi/elx/libefc/efclib.h                   |   6 +-
 drivers/scsi/fcoe/fcoe.c                           |   1 +
 drivers/scsi/fcoe/fcoe_sysfs.c                     |  19 +-
 drivers/scsi/hpsa.c                                |   9 +-
 drivers/scsi/ipr.c                                 |  10 +-
 drivers/scsi/lpfc/lpfc_sli.c                       |   6 +-
 drivers/scsi/mpt3sas/mpt3sas_transport.c           |   2 +
 drivers/scsi/qla2xxx/qla_def.h                     |  22 +-
 drivers/scsi/qla2xxx/qla_init.c                    |  20 +-
 drivers/scsi/qla2xxx/qla_inline.h                  |   4 +-
 drivers/scsi/qla2xxx/qla_os.c                      |   4 +-
 drivers/scsi/scsi_debug.c                          |  11 +-
 drivers/scsi/scsi_error.c                          |  14 +-
 drivers/scsi/smartpqi/smartpqi.h                   |   2 +-
 drivers/scsi/smartpqi/smartpqi_init.c              |  77 ++-
 drivers/scsi/snic/snic_disc.c                      |   3 +
 drivers/soc/apple/rtkit.c                          |   7 +-
 drivers/soc/apple/sart.c                           |   7 +-
 drivers/soc/mediatek/mtk-pm-domains.c              |   2 +-
 drivers/soc/qcom/apr.c                             |  15 +-
 drivers/soc/qcom/llcc-qcom.c                       |   2 +-
 drivers/soc/sifive/sifive_ccache.c                 |  33 +-
 drivers/soc/tegra/cbb/tegra194-cbb.c               |  14 +-
 drivers/soc/tegra/cbb/tegra234-cbb.c               | 170 ++++--
 drivers/soc/ti/knav_qmss_queue.c                   |   3 +-
 drivers/soc/ti/smartreflex.c                       |   1 +
 drivers/spi/spi-fsl-spi.c                          |  19 +-
 drivers/spi/spi-gpio.c                             |  16 +-
 drivers/spi/spidev.c                               |  21 +-
 drivers/staging/media/deprecated/stkwebcam/Kconfig |   2 +-
 drivers/staging/media/imx/imx7-media-csi.c         |   6 +-
 drivers/staging/media/rkvdec/rkvdec-vp9.c          |   3 +
 drivers/staging/media/sunxi/cedrus/cedrus_h265.c   |  25 +-
 drivers/staging/media/sunxi/cedrus/cedrus_regs.h   |   2 +
 drivers/staging/r8188eu/core/rtw_pwrctrl.c         |   2 +-
 drivers/staging/rtl8192e/rtllib_rx.c               |   2 +-
 drivers/staging/rtl8192u/ieee80211/ieee80211_rx.c  |   4 +-
 drivers/staging/vme_user/vme_fake.c                |   2 +
 drivers/staging/vme_user/vme_tsi148.c              |   1 +
 drivers/target/iscsi/iscsi_target_nego.c           |  12 +-
 drivers/thermal/imx8mm_thermal.c                   |   8 +-
 drivers/thermal/k3_j72xx_bandgap.c                 |   2 +-
 drivers/thermal/qcom/lmh.c                         |   2 +-
 drivers/thermal/qcom/qcom-spmi-temp-alarm.c        |   3 +-
 drivers/thermal/thermal_core.c                     |  18 +-
 drivers/thermal/thermal_helpers.c                  |   7 +-
 drivers/thermal/thermal_of.c                       |   8 +-
 drivers/tty/serial/8250/8250_bcm7271.c             |  10 +-
 drivers/tty/serial/altera_uart.c                   |   5 +-
 drivers/tty/serial/amba-pl011.c                    |  14 +-
 drivers/tty/serial/pch_uart.c                      |   4 +
 drivers/tty/serial/serial-tegra.c                  |   6 +-
 drivers/tty/serial/stm32-usart.c                   |  47 +-
 drivers/tty/serial/sunsab.c                        |   8 +-
 drivers/ufs/core/ufshcd.c                          |  37 +-
 drivers/uio/uio_dmem_genirq.c                      |  13 +-
 drivers/usb/cdns3/cdnsp-ring.c                     |  42 +-
 drivers/usb/core/hcd.c                             |   6 +-
 drivers/usb/dwc3/core.c                            |  23 +-
 drivers/usb/dwc3/dwc3-qcom.c                       |  13 +-
 drivers/usb/gadget/function/f_hid.c                |  53 +-
 drivers/usb/gadget/udc/core.c                      |  12 +-
 drivers/usb/gadget/udc/fotg210-udc.c               |  12 +-
 drivers/usb/host/xhci-mtk.c                        |   1 -
 drivers/usb/host/xhci-ring.c                       |  14 +-
 drivers/usb/host/xhci.h                            |   2 +-
 drivers/usb/musb/musb_gadget.c                     |   2 -
 drivers/usb/musb/omap2430.c                        |  54 ++
 drivers/usb/roles/class.c                          |   5 +-
 drivers/usb/storage/alauda.c                       |   2 +
 drivers/usb/typec/bus.c                            |   2 +-
 drivers/usb/typec/tcpm/tcpci.c                     |   5 +-
 drivers/usb/typec/tipd/core.c                      |  11 +-
 drivers/usb/typec/wusb3801.c                       |   2 +-
 drivers/vfio/iova_bitmap.c                         |  32 +-
 drivers/vfio/platform/vfio_platform_common.c       |   3 +-
 drivers/video/fbdev/Kconfig                        |   2 +-
 drivers/video/fbdev/core/fbcon.c                   |   3 +-
 drivers/video/fbdev/ep93xx-fb.c                    |   4 +-
 drivers/video/fbdev/geode/Kconfig                  |   1 +
 drivers/video/fbdev/hyperv_fb.c                    |   8 +-
 drivers/video/fbdev/pm2fb.c                        |   9 +-
 drivers/video/fbdev/uvesafb.c                      |   1 +
 drivers/video/fbdev/vermilion/vermilion.c          |   4 +-
 drivers/video/fbdev/via/via-core.c                 |   9 +-
 drivers/virt/coco/sev-guest/sev-guest.c            |   1 +
 drivers/watchdog/iTCO_wdt.c                        |  21 +-
 drivers/xen/privcmd.c                              |   2 +-
 fs/afs/fs_probe.c                                  |   5 +-
 fs/binfmt_misc.c                                   |   8 +-
 fs/btrfs/extent-io-tree.c                          |  22 +-
 fs/btrfs/file.c                                    |  10 +-
 fs/char_dev.c                                      |   2 +-
 fs/cifs/smb2file.c                                 |   4 +-
 fs/configfs/dir.c                                  |   2 +
 fs/debugfs/file.c                                  |  28 +-
 fs/erofs/fscache.c                                 |  47 +-
 fs/erofs/internal.h                                |  10 +-
 fs/erofs/super.c                                   |   2 +-
 fs/erofs/zdata.c                                   |   3 +-
 fs/erofs/zmap.c                                    |  11 +-
 fs/f2fs/compress.c                                 |   2 +-
 fs/f2fs/f2fs.h                                     |   2 +-
 fs/f2fs/file.c                                     |   4 +
 fs/f2fs/gc.c                                       |  29 +-
 fs/f2fs/namei.c                                    | 329 ++++++-----
 fs/f2fs/segment.c                                  |   8 +-
 fs/f2fs/super.c                                    |   8 +-
 fs/gfs2/glock.c                                    |   2 +
 fs/hfs/inode.c                                     |   2 +
 fs/hfs/trans.c                                     |   2 +-
 fs/hugetlbfs/inode.c                               |   6 +-
 fs/jfs/jfs_dmap.c                                  |  27 +-
 fs/jfs/namei.c                                     |   2 +-
 fs/ksmbd/mgmt/user_session.c                       |   8 +-
 fs/libfs.c                                         |  22 +-
 fs/lockd/svcsubs.c                                 |  17 +-
 fs/nfs/fs_context.c                                |   6 +
 fs/nfs/internal.h                                  |   6 +-
 fs/nfs/namespace.c                                 |   2 +-
 fs/nfs/nfs42xdr.c                                  |   2 +-
 fs/nfs/nfs4proc.c                                  |  38 +-
 fs/nfs/nfs4state.c                                 |   2 +
 fs/nfs/nfs4xdr.c                                   |  22 +-
 fs/nfsd/nfs2acl.c                                  |  10 -
 fs/nfsd/nfs3acl.c                                  |  30 +-
 fs/nfsd/nfs4callback.c                             |   4 +-
 fs/nfsd/nfs4proc.c                                 |   7 +-
 fs/nfsd/nfs4state.c                                |  51 +-
 fs/nilfs2/the_nilfs.c                              |  73 ++-
 fs/ntfs3/bitmap.c                                  |   2 +-
 fs/ntfs3/super.c                                   |   2 +-
 fs/ntfs3/xattr.c                                   |   2 +-
 fs/ocfs2/journal.c                                 |   2 +-
 fs/ocfs2/journal.h                                 |   1 +
 fs/ocfs2/stackglue.c                               |   8 +-
 fs/ocfs2/super.c                                   |   5 +-
 fs/orangefs/orangefs-debugfs.c                     |  29 +-
 fs/orangefs/orangefs-mod.c                         |   8 +-
 fs/orangefs/orangefs-sysfs.c                       |  71 ++-
 fs/overlayfs/file.c                                |  28 +-
 fs/overlayfs/super.c                               |   7 +-
 fs/pstore/Kconfig                                  |   1 +
 fs/pstore/pmsg.c                                   |   7 +-
 fs/pstore/ram.c                                    |   2 +
 fs/pstore/ram_core.c                               |   6 +-
 fs/reiserfs/namei.c                                |   4 +
 fs/reiserfs/xattr_security.c                       |   2 +-
 fs/sysv/itree.c                                    |   2 +-
 fs/udf/namei.c                                     |   8 +-
 fs/xattr.c                                         |   2 +-
 include/drm/drm_connector.h                        |   6 +
 include/drm/ttm/ttm_tt.h                           |   2 +-
 include/dt-bindings/clock/imx8mn-clock.h           |  24 +-
 include/dt-bindings/clock/imx8mp-clock.h           |   3 +-
 include/linux/blk-mq.h                             |   4 +
 include/linux/blkdev.h                             |  15 +-
 include/linux/btf_ids.h                            |   2 +-
 include/linux/debugfs.h                            |  19 +-
 include/linux/eventfd.h                            |   2 +-
 include/linux/fortify-string.h                     |   2 +-
 include/linux/fs.h                                 |  12 +-
 include/linux/hisi_acc_qm.h                        |   6 +-
 include/linux/hyperv.h                             |   2 +
 include/linux/ieee80211.h                          |   2 +-
 include/linux/iio/imu/adis.h                       |  13 +-
 include/linux/netdevice.h                          |  58 +-
 include/linux/proc_fs.h                            |   2 +
 include/linux/regulator/driver.h                   |   3 +-
 include/linux/skmsg.h                              |   1 +
 include/linux/timerqueue.h                         |   2 +-
 include/media/dvbdev.h                             |  32 +-
 include/net/bluetooth/hci.h                        |  20 +
 include/net/bluetooth/hci_core.h                   |   7 +-
 include/net/dst.h                                  |   5 +-
 include/net/ip_vs.h                                |  10 +-
 include/net/mrp.h                                  |   1 +
 include/net/sock_reuseport.h                       |   2 +
 include/net/tcp.h                                  |   4 +-
 include/sound/hda_codec.h                          |   1 +
 include/sound/pcm.h                                |  36 +-
 include/trace/events/f2fs.h                        |  34 +-
 include/trace/events/ib_mad.h                      |  13 +-
 include/uapi/linux/idxd.h                          |   2 +-
 include/uapi/linux/io_uring.h                      |  18 +
 include/uapi/linux/swab.h                          |   2 +-
 include/uapi/rdma/hns-abi.h                        |  15 +
 include/uapi/sound/asequencer.h                    |   8 +-
 io_uring/io_uring.c                                |   2 +-
 io_uring/msg_ring.c                                |   6 +-
 io_uring/net.c                                     |   9 +-
 io_uring/notif.c                                   |  12 +
 io_uring/notif.h                                   |   3 +
 io_uring/opdef.c                                   |   7 +
 io_uring/opdef.h                                   |   2 +
 io_uring/timeout.c                                 |   4 +-
 ipc/mqueue.c                                       |   6 +-
 kernel/Makefile                                    |   3 -
 kernel/acct.c                                      |   2 +
 kernel/bpf/btf.c                                   |   5 +
 kernel/bpf/cgroup_iter.c                           |  14 +
 kernel/bpf/syscall.c                               |   6 +-
 kernel/bpf/verifier.c                              | 120 ++--
 kernel/cpu.c                                       |  60 +-
 kernel/events/core.c                               |   8 +-
 kernel/fork.c                                      |  17 +-
 kernel/futex/core.c                                |  26 +-
 kernel/gcov/gcc_4_7.c                              |   5 +
 kernel/irq/internals.h                             |   2 +
 kernel/irq/irqdesc.c                               |  15 +-
 kernel/kprobes.c                                   |  16 +-
 kernel/module/decompress.c                         |   8 +-
 kernel/padata.c                                    |  15 +-
 kernel/power/snapshot.c                            |   4 +-
 kernel/rcu/tree.c                                  |   2 +-
 kernel/relay.c                                     |   4 +-
 kernel/sched/core.c                                |  10 +-
 kernel/sched/fair.c                                | 223 +++++++-
 kernel/sched/psi.c                                 |   8 +-
 kernel/sched/sched.h                               |  51 +-
 kernel/trace/blktrace.c                            |   3 +-
 kernel/trace/trace_events_hist.c                   |   2 +-
 kernel/trace/trace_events_user.c                   |   1 +
 lib/debugobjects.c                                 |  10 +
 lib/fonts/fonts.c                                  |   4 +-
 lib/maple_tree.c                                   |   4 +-
 lib/notifier-error-inject.c                        |   2 +-
 lib/test_firmware.c                                |   1 +
 lib/test_maple_tree.c                              |  23 +
 mm/gup.c                                           |   3 +
 net/802/mrp.c                                      |  18 +-
 net/9p/client.c                                    |   5 +
 net/bluetooth/hci_conn.c                           |   2 +-
 net/bluetooth/hci_core.c                           |   4 +-
 net/bluetooth/hci_sync.c                           |   2 +-
 net/bluetooth/lib.c                                |   4 +-
 net/bluetooth/mgmt.c                               |   2 +-
 net/bluetooth/rfcomm/core.c                        |   2 +-
 net/bpf/test_run.c                                 |   3 -
 net/core/dev.c                                     |  14 +-
 net/core/devlink.c                                 |   5 +
 net/core/filter.c                                  |  25 +-
 net/core/skbuff.c                                  |   3 +
 net/core/skmsg.c                                   |   9 +-
 net/core/sock.c                                    |   2 +-
 net/core/sock_map.c                                |   2 +
 net/core/sock_reuseport.c                          |  94 +++-
 net/core/stream.c                                  |   6 +
 net/dsa/tag_8021q.c                                |  11 +-
 net/ethtool/ioctl.c                                |   3 +-
 net/hsr/hsr_debugfs.c                              |  40 +-
 net/hsr/hsr_device.c                               |  32 +-
 net/hsr/hsr_forward.c                              |  14 +-
 net/hsr/hsr_framereg.c                             | 222 ++++----
 net/hsr/hsr_framereg.h                             |  17 +-
 net/hsr/hsr_main.h                                 |   9 +-
 net/hsr/hsr_netlink.c                              |   4 +-
 net/ipv4/af_inet.c                                 |   4 +-
 net/ipv4/inet_connection_sock.c                    |   7 +-
 net/ipv4/ping.c                                    |   2 +-
 net/ipv4/tcp_bpf.c                                 |  19 +-
 net/ipv4/udp.c                                     |  39 +-
 net/ipv4/udp_tunnel_core.c                         |   1 +
 net/ipv6/af_inet6.c                                |   4 +-
 net/ipv6/datagram.c                                |  15 +-
 net/ipv6/sit.c                                     |  22 +-
 net/ipv6/udp.c                                     |  12 +-
 net/mac80211/cfg.c                                 |   2 +-
 net/mac80211/ieee80211_i.h                         |   1 +
 net/mac80211/iface.c                               |   1 +
 net/mac80211/mlme.c                                |  15 +-
 net/mac80211/tx.c                                  |   2 +-
 net/mctp/device.c                                  |  14 +-
 net/netfilter/ipvs/ip_vs_core.c                    |  30 +-
 net/netfilter/ipvs/ip_vs_ctl.c                     |  10 +-
 net/netfilter/ipvs/ip_vs_est.c                     |  20 +-
 net/netfilter/nf_conntrack_proto_icmpv6.c          |  53 ++
 net/netfilter/nf_flow_table_offload.c              |   6 +-
 net/openvswitch/datapath.c                         |  25 +-
 net/openvswitch/flow_netlink.c                     |   2 +-
 net/rxrpc/output.c                                 |   2 +-
 net/rxrpc/sendmsg.c                                |   2 +-
 net/sched/ematch.c                                 |   2 +
 net/sctp/sysctl.c                                  |  73 ++-
 net/sunrpc/clnt.c                                  |   2 +-
 net/sunrpc/xprtrdma/verbs.c                        |   2 +-
 net/tls/tls_sw.c                                   |   6 +-
 net/unix/af_unix.c                                 |  12 +-
 net/vmw_vsock/vmci_transport.c                     |   6 +-
 net/wireless/nl80211.c                             |   3 +
 net/wireless/reg.c                                 |   4 +-
 samples/bpf/xdp1_user.c                            |   2 +-
 samples/bpf/xdp2_kern.c                            |   4 +
 samples/vfio-mdev/mdpy-fb.c                        |   8 +-
 security/Kconfig.hardening                         |   3 +
 security/apparmor/apparmorfs.c                     |   4 +-
 security/apparmor/label.c                          |  12 +-
 security/apparmor/lsm.c                            |   4 +-
 security/apparmor/policy.c                         |   2 +-
 security/apparmor/policy_ns.c                      |   2 +-
 security/apparmor/policy_unpack.c                  |   2 +-
 security/integrity/digsig.c                        |   6 +-
 security/integrity/ima/ima_policy.c                |  51 +-
 security/integrity/ima/ima_template.c              |   4 +-
 security/loadpin/loadpin.c                         |  30 +-
 sound/core/memalloc.c                              |  44 +-
 sound/core/pcm_native.c                            |   4 +-
 sound/drivers/mts64.c                              |   3 +
 sound/pci/asihpi/hpioctl.c                         |   2 +-
 sound/pci/hda/hda_codec.c                          |   3 +-
 sound/pci/hda/patch_hdmi.c                         | 120 +++-
 sound/pci/hda/patch_realtek.c                      |  27 +
 sound/soc/amd/acp/acp-platform.c                   |   8 +-
 sound/soc/amd/yc/acp6x-mach.c                      |   7 +
 sound/soc/codecs/pcm512x.c                         |   8 +-
 sound/soc/codecs/rt298.c                           |   7 +
 sound/soc/codecs/rt5670.c                          |   2 -
 sound/soc/codecs/wm8994.c                          |   5 +
 sound/soc/codecs/wsa883x.c                         |   6 +-
 sound/soc/generic/audio-graph-card.c               |   4 +-
 sound/soc/intel/Kconfig                            |   2 +-
 sound/soc/intel/avs/boards/rt298.c                 |  24 +-
 sound/soc/intel/avs/core.c                         |   2 +-
 sound/soc/intel/avs/ipc.c                          |   6 +-
 sound/soc/intel/boards/sof_es8336.c                |   2 +-
 sound/soc/intel/skylake/skl.c                      |   5 +-
 sound/soc/mediatek/common/mtk-btcvsd.c             |   6 +-
 sound/soc/mediatek/mt8173/mt8173-afe-pcm.c         |  20 +-
 sound/soc/mediatek/mt8173/mt8173-rt5650-rt5514.c   |   7 +-
 .../mt8183/mt8183-mt6358-ts3a227-max98357.c        |  14 +-
 .../mt8186/mt8186-mt6366-da7219-max98357.c         |   2 +-
 .../mediatek/mt8186/mt8186-mt6366-rt1019-rt5682s.c |   2 +-
 sound/soc/pxa/mmp-pcm.c                            |   2 +-
 sound/soc/qcom/Kconfig                             |  16 +-
 sound/soc/qcom/common.c                            |   2 -
 sound/soc/qcom/common.h                            |  23 -
 sound/soc/qcom/lpass-sc7180.c                      |   3 +
 sound/soc/rockchip/rockchip_pdm.c                  |   1 +
 sound/soc/rockchip/rockchip_spdif.c                |   1 +
 sound/usb/endpoint.c                               |   7 +
 sound/usb/pcm.c                                    |  13 +-
 sound/usb/quirks-table.h                           |   2 +
 sound/usb/quirks.c                                 |   2 +
 sound/usb/usbaudio.h                               |   4 +
 tools/bpf/bpftool/common.c                         |   1 +
 tools/lib/bpf/bpf.h                                |   7 +
 tools/lib/bpf/btf.c                                |   8 +-
 tools/lib/bpf/btf_dump.c                           |  29 +-
 tools/lib/bpf/libbpf.c                             |  22 +-
 tools/lib/bpf/usdt.c                               |  11 +-
 tools/objtool/check.c                              |  10 +
 tools/perf/Documentation/perf-annotate.txt         |   2 +-
 tools/perf/Documentation/perf-diff.txt             |   2 +-
 tools/perf/Documentation/perf-lock.txt             |   2 +-
 tools/perf/Documentation/perf-probe.txt            |   2 +-
 tools/perf/Documentation/perf-record.txt           |   2 +-
 tools/perf/Documentation/perf-report.txt           |   2 +-
 tools/perf/Documentation/perf-stat.txt             |   4 +-
 tools/perf/bench/numa.c                            |   9 +-
 tools/perf/builtin-annotate.c                      |   2 +-
 tools/perf/builtin-diff.c                          |   2 +-
 tools/perf/builtin-lock.c                          |   2 +-
 tools/perf/builtin-probe.c                         |  22 +-
 tools/perf/builtin-record.c                        |   2 +-
 tools/perf/builtin-report.c                        |   2 +-
 tools/perf/builtin-stat.c                          |  41 +-
 tools/perf/builtin-trace.c                         |  32 +-
 tools/perf/tests/shell/stat_all_pmu.sh             |  13 +-
 tools/perf/ui/util.c                               |   5 +
 tools/perf/util/bpf_off_cpu.c                      |   2 +-
 tools/perf/util/branch.h                           |   3 +-
 tools/perf/util/debug.c                            |   4 +
 tools/perf/util/stat-display.c                     |  33 +-
 tools/perf/util/stat.h                             |   1 -
 tools/perf/util/symbol-elf.c                       |   2 +-
 tools/testing/selftests/bpf/config                 |   1 +
 tools/testing/selftests/bpf/network_helpers.c      |   4 +
 tools/testing/selftests/bpf/prog_tests/bpf_iter.c  |  11 +-
 tools/testing/selftests/bpf/prog_tests/empty_skb.c | 146 +++++
 .../selftests/bpf/prog_tests/kprobe_multi_test.c   |  26 +-
 .../testing/selftests/bpf/prog_tests/lsm_cgroup.c  |  17 +-
 tools/testing/selftests/bpf/prog_tests/map_kptr.c  |   3 +-
 .../selftests/bpf/prog_tests/tcp_hdr_options.c     |   4 +-
 .../selftests/bpf/prog_tests/tracing_struct.c      |   3 +-
 .../selftests/bpf/prog_tests/xdp_adjust_tail.c     |   7 +-
 .../selftests/bpf/prog_tests/xdp_do_redirect.c     |   2 +-
 .../selftests/bpf/prog_tests/xdp_synproxy.c        |   2 +-
 tools/testing/selftests/bpf/progs/bpf_iter_ksym.c  |   6 +-
 tools/testing/selftests/bpf/progs/empty_skb.c      |  37 ++
 tools/testing/selftests/bpf/progs/lsm_cgroup.c     |   8 +
 .../testing/selftests/bpf/test_bpftool_metadata.sh |   7 +-
 tools/testing/selftests/bpf/test_flow_dissector.sh |   6 +-
 tools/testing/selftests/bpf/test_lwt_ip_encap.sh   |  17 +-
 tools/testing/selftests/bpf/test_lwt_seg6local.sh  |   9 +-
 tools/testing/selftests/bpf/test_tc_edt.sh         |   3 +-
 tools/testing/selftests/bpf/test_tc_tunnel.sh      |   5 +-
 tools/testing/selftests/bpf/test_tunnel.sh         |   5 +-
 tools/testing/selftests/bpf/test_xdp_meta.sh       |   9 +-
 tools/testing/selftests/bpf/test_xdp_vlan.sh       |   8 +-
 tools/testing/selftests/bpf/xdp_synproxy.c         |   5 +-
 tools/testing/selftests/cgroup/cgroup_util.c       |   5 +-
 .../selftests/drivers/net/netdevsim/devlink.sh     |   4 +-
 tools/testing/selftests/efivarfs/efivarfs.sh       |   5 +
 .../ftrace/test.d/ftrace/func_event_triggers.tc    |  15 +-
 .../selftests/netfilter/conntrack_icmp_related.sh  |  36 +-
 .../selftests/powerpc/dscr/dscr_sysfs_test.c       |   5 +-
 tools/testing/selftests/proc/proc-uptime-002.c     |   3 +-
 1103 files changed, 13134 insertions(+), 6488 deletions(-)



^ permalink raw reply	[relevance 1%]

* [PATCH 6.0 0846/1073] bpf: prevent leak of lsm program after failed attach
  2022-12-28 14:26  1% [PATCH 6.0 0000/1073] 6.0.16-rc1 review Greg Kroah-Hartman
@ 2022-12-28 14:40  8% ` Greg Kroah-Hartman
  0 siblings, 0 replies; 77+ results
From: Greg Kroah-Hartman @ 2022-12-28 14:40 UTC (permalink / raw)
  To: stable
  Cc: Greg Kroah-Hartman, patches, Milan Landaverde, Martin KaFai Lau,
	Daniel Borkmann, Stanislav Fomichev, Sasha Levin

From: Milan Landaverde <milan@mdaverde.com>

[ Upstream commit e89f3edffb860a0f54a9ed16deadb7a4a1fa3862 ]

In [0], we added the ability to bpf_prog_attach LSM programs to cgroups,
but in our validation to make sure the prog is meant to be attached to
BPF_LSM_CGROUP, we return too early if the check fails. This results in
lack of decrementing prog's refcnt (through bpf_prog_put)
leaving the LSM program alive past the point of the expected lifecycle.
This fix allows for the decrement to take place.

[0] https://lore.kernel.org/all/20220628174314.1216643-4-sdf@google.com/

Fixes: 69fd337a975c ("bpf: per-cgroup lsm flavor")
Signed-off-by: Milan Landaverde <milan@mdaverde.com>
Signed-off-by: Martin KaFai Lau <martin.lau@kernel.org>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Reviewed-by: Stanislav Fomichev <sdf@google.com>
Link: https://lore.kernel.org/r/20221213175714.31963-1-milan@mdaverde.com
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
 kernel/bpf/syscall.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c
index 0e758911d963..6b6fb7237ebe 100644
--- a/kernel/bpf/syscall.c
+++ b/kernel/bpf/syscall.c
@@ -3505,9 +3505,9 @@ static int bpf_prog_attach(const union bpf_attr *attr)
 	case BPF_PROG_TYPE_LSM:
 		if (ptype == BPF_PROG_TYPE_LSM &&
 		    prog->expected_attach_type != BPF_LSM_CGROUP)
-			return -EINVAL;
-
-		ret = cgroup_bpf_prog_attach(attr, ptype, prog);
+			ret = -EINVAL;
+		else
+			ret = cgroup_bpf_prog_attach(attr, ptype, prog);
 		break;
 	default:
 		ret = -EINVAL;
-- 
2.35.1




^ permalink raw reply related	[relevance 8%]

* [PATCH 6.1 0896/1146] bpf: prevent leak of lsm program after failed attach
  2022-12-28 14:25  1% [PATCH 6.1 0000/1146] 6.1.2-rc1 review Greg Kroah-Hartman
@ 2022-12-28 14:40  8% ` Greg Kroah-Hartman
  0 siblings, 0 replies; 77+ results
From: Greg Kroah-Hartman @ 2022-12-28 14:40 UTC (permalink / raw)
  To: stable
  Cc: Greg Kroah-Hartman, patches, Milan Landaverde, Martin KaFai Lau,
	Daniel Borkmann, Stanislav Fomichev, Sasha Levin

From: Milan Landaverde <milan@mdaverde.com>

[ Upstream commit e89f3edffb860a0f54a9ed16deadb7a4a1fa3862 ]

In [0], we added the ability to bpf_prog_attach LSM programs to cgroups,
but in our validation to make sure the prog is meant to be attached to
BPF_LSM_CGROUP, we return too early if the check fails. This results in
lack of decrementing prog's refcnt (through bpf_prog_put)
leaving the LSM program alive past the point of the expected lifecycle.
This fix allows for the decrement to take place.

[0] https://lore.kernel.org/all/20220628174314.1216643-4-sdf@google.com/

Fixes: 69fd337a975c ("bpf: per-cgroup lsm flavor")
Signed-off-by: Milan Landaverde <milan@mdaverde.com>
Signed-off-by: Martin KaFai Lau <martin.lau@kernel.org>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Reviewed-by: Stanislav Fomichev <sdf@google.com>
Link: https://lore.kernel.org/r/20221213175714.31963-1-milan@mdaverde.com
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
 kernel/bpf/syscall.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c
index 7b373a5e861f..439ed7e5a82b 100644
--- a/kernel/bpf/syscall.c
+++ b/kernel/bpf/syscall.c
@@ -3504,9 +3504,9 @@ static int bpf_prog_attach(const union bpf_attr *attr)
 	case BPF_PROG_TYPE_LSM:
 		if (ptype == BPF_PROG_TYPE_LSM &&
 		    prog->expected_attach_type != BPF_LSM_CGROUP)
-			return -EINVAL;
-
-		ret = cgroup_bpf_prog_attach(attr, ptype, prog);
+			ret = -EINVAL;
+		else
+			ret = cgroup_bpf_prog_attach(attr, ptype, prog);
 		break;
 	default:
 		ret = -EINVAL;
-- 
2.35.1




^ permalink raw reply related	[relevance 8%]

* [PATCH 6.0 0000/1066] 6.0.16-rc2 review
@ 2022-12-30  9:49  1% Greg Kroah-Hartman
  0 siblings, 0 replies; 77+ results
From: Greg Kroah-Hartman @ 2022-12-30  9:49 UTC (permalink / raw)
  To: stable
  Cc: Greg Kroah-Hartman, patches, linux-kernel, torvalds, akpm, linux,
	shuah, patches, lkft-triage, pavel, jonathanh, f.fainelli,
	sudipm.mukherjee, srw, rwarsow

This is the start of the stable review cycle for the 6.0.16 release.
There are 1066 patches in this series, all will be posted as a response
to this one.  If anyone has any issues with these being applied, please
let me know.

Responses should be made by Sun, 01 Jan 2023 09:38:41 +0000.
Anything received after that time might be too late.

The whole patch series can be found in one patch at:
	https://www.kernel.org/pub/linux/kernel/v6.x/stable-review/patch-6.0.16-rc2.gz
or in the git tree and branch at:
	git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable-rc.git linux-6.0.y
and the diffstat can be found below.

thanks,

greg k-h

-------------
Pseudo-Shortlog of commits:

Greg Kroah-Hartman <gregkh@linuxfoundation.org>
    Linux 6.0.16-rc2

Steven Price <steven.price@arm.com>
    pwm: tegra: Fix 32 bit build

Christophe JAILLET <christophe.jaillet@wanadoo.fr>
    mfd: qcom_rpm: Use devm_of_platform_populate() to simplify code

ChenXiaoSong <chenxiaosong2@huawei.com>
    cifs: fix use-after-free on the link name

Paulo Alcantara <pc@cjr.nz>
    cifs: fix memory leaks in session setup

Zhang Xiaoxu <zhangxiaoxu5@huawei.com>
    cifs: Fix xid leak in cifs_get_file_info_unix()

Paulo Alcantara <pc@cjr.nz>
    cifs: fix double-fault crash during ntlmssp

Yassine Oudjana <y.oudjana@protonmail.com>
    extcon: usbc-tusb320: Call the Type-C IRQ handler only if a port is registered

Geert Uytterhoeven <geert+renesas@glider.be>
    clk: renesas: r8a779f0: Fix SD0H clock name

Martin Leung <Martin.Leung@amd.com>
    drm/amd/display: revert Disable DRR actions during state commit

Lin Ma <linma@zju.edu.cn>
    media: dvbdev: fix refcnt bug

Lin Ma <linma@zju.edu.cn>
    media: dvbdev: fix build warning due to comments

Gaosheng Cui <cuigaosheng1@huawei.com>
    net: stmmac: fix errno when create_singlethread_workqueue() fails

Pavel Begunkov <asml.silence@gmail.com>
    io_uring: remove iopoll spinlock

Pavel Begunkov <asml.silence@gmail.com>
    io_uring: protect cq_timeouts with timeout_lock

Pavel Begunkov <asml.silence@gmail.com>
    io_uring/net: fix cleanup after recycle

Pavel Begunkov <asml.silence@gmail.com>
    io_uring: improve io_double_lock_ctx fail handling

Pavel Begunkov <asml.silence@gmail.com>
    io_uring: add completion locking for iopoll

Arun Easi <aeasi@marvell.com>
    scsi: qla2xxx: Fix crash when I/O abort times out

David Hildenbrand <david@redhat.com>
    mm/gup: disallow FOLL_FORCE|FOLL_WRITE on hugetlb mappings

Filipe Manana <fdmanana@suse.com>
    btrfs: do not BUG_ON() on ENOMEM when dropping extent items for a range

Chen Zhongjin <chenzhongjin@huawei.com>
    ovl: fix use inode directly in rcu-walk mode

Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
    fbdev: fbcon: release buffer when fbcon_do_set_font() failed

Rickard x Andersson <rickaran@axis.com>
    gcov: add support for checksum field

Yuan Can <yuancan@huawei.com>
    floppy: Fix memory leak in do_floppy_init()

Johan Hovold <johan+linaro@kernel.org>
    regulator: core: fix deadlock on regulator enable

Rasmus Villemoes <linux@rasmusvillemoes.dk>
    iio: addac: ad74413r: fix integer promotion bug in ad74413_get_input_current_offset()

Rasmus Villemoes <linux@rasmusvillemoes.dk>
    iio: adc128s052: add proper .data members in adc128_of_match table

Nuno Sá <nuno.sa@analog.com>
    iio: adc: ad_sigma_delta: do not use internal iio_dev lock

Zeng Heng <zengheng4@huawei.com>
    iio: fix memory leak in iio_device_register_eventset()

Roberto Sassu <roberto.sassu@huawei.com>
    reiserfs: Add missing calls to reiserfs_security_free()

Nathan Chancellor <nathan@kernel.org>
    security: Restrict CONFIG_ZERO_CALL_USED_REGS to gcc or clang > 15.0.6

Schspa Shi <schspa@gmail.com>
    9p: set req refcount to zero to avoid uninitialized usage

Isaac J. Manjarres <isaacmanjarres@google.com>
    loop: Fix the max_loop commandline argument treatment when it is set to 0

Enrik Berkhan <Enrik.Berkhan@inka.de>
    HID: mcp2221: don't connect hidraw

Jason Gerecke <killertofu@gmail.com>
    HID: wacom: Ensure bootloader PID is usable in hidraw mode

Mathias Nyman <mathias.nyman@linux.intel.com>
    xhci: Prevent infinite loop in transaction errors recovery for streams

Ferry Toth <ftoth@exalondelft.nl>
    usb: dwc3: core: defer probe on ulpi_read_id timeout

Sven Peter <sven@svenpeter.dev>
    usb: dwc3: Fix race between dwc3_set_mode and __dwc3_set_mode

Li Jun <jun.li@nxp.com>
    clk: imx: imx8mp: add shared clk gate for usb suspend clk

Li Jun <jun.li@nxp.com>
    dt-bindings: clocks: imx8mp: Add ID for usb suspend clock

Johan Hovold <johan+linaro@kernel.org>
    arm64: dts: qcom: sm8250: fix USB-DP PHY registers

Johan Hovold <johan+linaro@kernel.org>
    arm64: dts: qcom: sm6350: fix USB-DP PHY registers

Chunfeng Yun <chunfeng.yun@mediatek.com>
    usb: xhci-mtk: fix leakage of shared hcd when fail to set wakeup irq

Pawel Laszczak <pawell@cadence.com>
    usb: cdnsp: fix lack of ZLP for ep0

Bastien Nocera <hadess@hadess.net>
    HID: logitech-hidpp: Guard FF init code against non-USB devices

Jiao Zhou <jiaozhou@google.com>
    ALSA: hda/hdmi: Add HP Device 0x8711 to force connect list

Edward Pacman <edward@edward-p.xyz>
    ALSA: hda/realtek: Add quirk for Lenovo TianYi510Pro-14IOB

wangdicheng <wangdicheng@kylinos.cn>
    ALSA: usb-audio: add the quirk for KT0206 device

Jeff LaBundy <jeff@labundy.com>
    Input: iqs7222 - add support for IQS7222A v1.13+

Jeff LaBundy <jeff@labundy.com>
    Input: iqs7222 - trim force communication command

Jeff LaBundy <jeff@labundy.com>
    dt-bindings: input: iqs7222: Add support for IQS7222A v1.13+

Jeff LaBundy <jeff@labundy.com>
    dt-bindings: input: iqs7222: Correct minimum slider size

Jeff LaBundy <jeff@labundy.com>
    dt-bindings: input: iqs7222: Reduce 'linux,code' to optional

Jeff LaBundy <jeff@labundy.com>
    Input: iqs7222 - avoid sending empty SYN_REPORT events

GUO Zihua <guozihua@huawei.com>
    ima: Simplify ima_lsm_copy_rule

John Stultz <jstultz@google.com>
    pstore: Make sure CONFIG_PSTORE_PMSG selects CONFIG_RT_MUTEXES

David Howells <dhowells@redhat.com>
    afs: Fix lost servers_outstanding count

Michael Petlan <mpetlan@redhat.com>
    perf test: Fix "all PMU test" to skip parametrized events

Sergio Paracuellos <sergio.paracuellos@gmail.com>
    MIPS: ralink: mt7621: avoid to init common ralink reset controller

Yang Jihong <yangjihong1@huawei.com>
    perf debug: Set debug_peo_args and redirect_to_stderr variable to correct values in perf_quiet_option()

Arnd Bergmann <arnd@arndb.de>
    drm/amd/pm: avoid large variable on kernel stack

John Stultz <jstultz@google.com>
    pstore: Switch pmsg_lock to an rt_mutex to avoid priority inversion

Kristina Martsenko <kristina.martsenko@arm.com>
    lkdtm: cfi: Make PAC test work with GCC 7 and 8

Kees Cook <keescook@chromium.org>
    LoadPin: Ignore the "contents" argument of the LSM hooks

Khaled Almahallawy <khaled.almahallawy@intel.com>
    drm/i915/display: Don't disable DDI/Transcoder when setting phy test pattern

Hans de Goede <hdegoede@redhat.com>
    ASoC: rt5670: Remove unbalanced pm_runtime_put()

Wang Jingjin <wangjingjin1@huawei.com>
    ASoC: rockchip: spdif: Add missing clk_disable_unprepare() in rk_spdif_runtime_resume()

Marek Szyprowski <m.szyprowski@samsung.com>
    ASoC: wm8994: Fix potential deadlock

Kai Vehmanen <kai.vehmanen@linux.intel.com>
    ALSA: hda/hdmi: fix stream-id config keep-alive for rt suspend

Jaroslav Kysela <perex@perex.cz>
    ALSA: hda/hdmi: Use only dynamic PCM device allocation

Kai Vehmanen <kai.vehmanen@linux.intel.com>
    ALSA: hda/hdmi: set default audio parameters for KAE silent-stream

Kai Vehmanen <kai.vehmanen@linux.intel.com>
    ALSA: hda/hdmi: fix i915 silent stream programming flow

Wang Yufen <wangyufen@huawei.com>
    ASoC: mediatek: mt8183: fix refcount leak in mt8183_mt6358_ts3a227_max98357_dev_probe()

Wang Jingjin <wangjingjin1@huawei.com>
    ASoC: rockchip: pdm: Add missing clk_disable_unprepare() in rockchip_pdm_runtime_resume()

Wang Yufen <wangyufen@huawei.com>
    ASoC: audio-graph-card: fix refcount leak of cpu_ep in __graph_for_each_link()

Wang Yufen <wangyufen@huawei.com>
    ASoC: mediatek: mt8173-rt5650-rt5514: fix refcount leak in mt8173_rt5650_rt5514_dev_probe()

Cezary Rojewski <cezary.rojewski@intel.com>
    ASoC: Intel: Skylake: Fix driver hang during shutdown

Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
    ALSA: hda: add snd_hdac_stop_streams() helper

Yang Yingliang <yangyingliang@huawei.com>
    ASoC: sof_es8336: fix possible use-after-free in sof_es8336_remove()

Yang Yingliang <yangyingliang@huawei.com>
    hwmon: (jc42) Fix missing unlock on error in jc42_write()

Wolfram Sang <wsa+renesas@sang-engineering.com>
    clk: renesas: r8a779f0: Add TMU and parent SASYNC clocks

Wolfram Sang <wsa+renesas@sang-engineering.com>
    clk: renesas: r8a779f0: Add SDH0 clock

Zhang Xiaoxu <zhangxiaoxu5@huawei.com>
    orangefs: Fix kmemleak in orangefs_{kernel,client}_debug_init()

Zhang Xiaoxu <zhangxiaoxu5@huawei.com>
    orangefs: Fix kmemleak in orangefs_sysfs_init()

Zhang Xiaoxu <zhangxiaoxu5@huawei.com>
    orangefs: Fix kmemleak in orangefs_prepare_debugfs_help_string()

Maurizio Lombardi <mlombard@redhat.com>
    scsi: target: iscsi: Fix a race condition between login_work and the login thread

Nathan Chancellor <nathan@kernel.org>
    drm/sti: Fix return type of sti_{dvo,hda,hdmi}_connector_mode_valid()

Nathan Chancellor <nathan@kernel.org>
    drm/fsl-dcu: Fix return type of fsl_dcu_drm_connector_mode_valid()

Kumar Meiyappan <Kumar.Meiyappan@microchip.com>
    scsi: smartpqi: Correct device removal for multi-actuator devices

Mike McGowen <mike.mcgowen@microchip.com>
    scsi: smartpqi: Add new controller PCI IDs

Hawkins Jiawei <yin31149@gmail.com>
    hugetlbfs: fix null-ptr-deref in hugetlbfs_parse_param()

Nathan Chancellor <nathan@kernel.org>
    scsi: elx: libefc: Fix second parameter type in state callbacks

Bjorn Helgaas <bhelgaas@google.com>
    Revert "PCI: Clear PCI_STATUS when setting up device"

Kai Ye <yekai13@huawei.com>
    crypto: hisilicon/qm - increase the memory of local variables

Bart Van Assche <bvanassche@acm.org>
    scsi: ufs: Reduce the START STOP UNIT timeout

Justin Tee <justin.tee@broadcom.com>
    scsi: lpfc: Fix hard lockup when reading the rx_monitor from debugfs

Zhiqi Song <songzhiqi1@huawei.com>
    crypto: hisilicon/hpre - fix resource leak in remove process

ChiYuan Huang <cy_huang@richtek.com>
    regulator: core: Fix resolve supply lookup issue

Sven Peter <sven@svenpeter.dev>
    Bluetooth: Add quirk to disable MWS Transport Configuration

Sven Peter <sven@svenpeter.dev>
    Bluetooth: Add quirk to disable extended scanning

Marek Vasut <marex@denx.de>
    Bluetooth: hci_bcm: Add CYW4373A0 support

ChiYuan Huang <cy_huang@richtek.com>
    regulator: core: Use different devices for resource allocation and DT lookup

Xiu Jianfeng <xiujianfeng@huawei.com>
    clk: st: Fix memory leak in st_of_quadfs_setup()

Shigeru Yoshida <syoshida@redhat.com>
    media: si470x: Fix use-after-free in si470x_int_in_callback()

Wolfram Sang <wsa+renesas@sang-engineering.com>
    mmc: renesas_sdhi: better reset from HS400 mode

Wolfram Sang <wsa+renesas@sang-engineering.com>
    mmc: renesas_sdhi: add quirk for broken register layout

Kunihiko Hayashi <hayashi.kunihiko@socionext.com>
    mmc: f-sdh30: Add quirks for broken timeout clock capability

Hawkins Jiawei <yin31149@gmail.com>
    nfs: fix possible null-ptr-deref when parsing param

James Hilliard <james.hilliard1@gmail.com>
    selftests/bpf: Fix conflicts with built-in functions in bpf_iter_ksym

Denis Pauk <pauk.denis@gmail.com>
    hwmon: (nct6775) add ASUS CROSSHAIR VIII/TUF/ProArt B550M

Lorenzo Bianconi <lorenzo@kernel.org>
    wifi: mt76: do not run mt76u_status_worker if the device is not running

Rui Zhang <zr.zhang@vivo.com>
    regulator: core: fix use_count leakage when handling boot-on

Andrii Nakryiko <andrii@kernel.org>
    libbpf: Avoid enum forward-declarations in public API in C++ mode

Artem Lukyanov <dukzcry@ya.ru>
    ASoC: amd: yc: Add Xiaomi Redmi Book Pro 14 2022 into DMI table

Alvin Lee <Alvin.Lee2@amd.com>
    drm/amd/display: Fix DTBCLK disable requests and SRC_SEL programming

Wesley Chalmers <Wesley.Chalmers@amd.com>
    drm/amd/display: Use the largest vready_offset in pipe group

Ye Bin <yebin10@huawei.com>
    blk-mq: fix possible memleak when register 'hctx' failed

Yunfei Dong <yunfei.dong@mediatek.com>
    media: mediatek: vcodec: Can't set dst buffer to done when lat decode error

Mazin Al Haddad <mazinalhaddad05@gmail.com>
    media: dvb-usb: fix memory leak in dvb_usb_adapter_init()

Lin Ma <linma@zju.edu.cn>
    media: dvbdev: adopts refcnt to avoid UAF

Yan Lei <yan_lei@dahuatech.com>
    media: dvb-frontends: fix leak of memory fw

Maxim Korotkov <korotkov.maxim.s@gmail.com>
    ethtool: avoiding integer overflow in ethtool_phys_id()

Stanislav Fomichev <sdf@google.com>
    bpf: Prevent decl_tag from being referenced in func_proto arg

Yonghong Song <yhs@fb.com>
    bpf: Fix a BTF_ID_LIST bug with CONFIG_DEBUG_INFO_BTF not set

Stanislav Fomichev <sdf@google.com>
    ppp: associate skb with a device at tx

Felix Fietkau <nbd@nbd.name>
    net: ethernet: mtk_eth_soc: drop packets to WDMA if the ring is full

Schspa Shi <schspa@gmail.com>
    mrp: introduce active flags to prevent UAF when applicant uninit

Eric Dumazet <edumazet@google.com>
    ipv6/sit: use DEV_STATS_INC() to avoid data-races

Eric Dumazet <edumazet@google.com>
    net: add atomic_long_t to net_device_stats fields

Sagi Grimberg <sagi@grimberg.me>
    nvme-auth: don't override ctrl keys before validation

Aurabindo Pillai <aurabindo.pillai@amd.com>
    drm/amd/display: fix array index out of bound error in bios parser

George Shen <george.shen@amd.com>
    drm/amd/display: Workaround to increase phantom pipe vactive in pipesplit

Jiang Li <jiang.li@ugreen.com>
    md/raid1: stop mdx_raid1 thread when raid1 array run failed

Xiao Ni <xni@redhat.com>
    md/raid0, raid10: Don't set discard sectors for request queue

Li Zhong <floridsleeves@gmail.com>
    drivers/md/md-bitmap: check the return value of md_bitmap_get_counter()

Nathan Chancellor <nathan@kernel.org>
    drm/mediatek: Fix return type of mtk_hdmi_bridge_mode_valid()

Ville Syrjälä <ville.syrjala@linux.intel.com>
    drm/sti: Use drm_mode_copy()

Ville Syrjälä <ville.syrjala@linux.intel.com>
    drm/rockchip: Use drm_mode_copy()

Ville Syrjälä <ville.syrjala@linux.intel.com>
    drm/msm: Use drm_mode_copy()

Wesley Chalmers <Wesley.Chalmers@amd.com>
    drm/amd/display: Disable DRR actions during state commit

Nathan Chancellor <nathan@kernel.org>
    s390/lcs: Fix return type of lcs_start_xmit()

Nathan Chancellor <nathan@kernel.org>
    s390/netiucv: Fix return type of netiucv_tx()

Nathan Chancellor <nathan@kernel.org>
    s390/ctcm: Fix return type of ctc{mp,}m_tx()

Nathan Chancellor <nathan@kernel.org>
    drm/amdgpu: Fix type of second parameter in odn_edit_dpm_table() callback

Nathan Chancellor <nathan@kernel.org>
    drm/amdgpu: Fix type of second parameter in trans_msg() callback

Kees Cook <keescook@chromium.org>
    igb: Do not free q_vector unless new one was allocated

José Expósito <jose.exposito89@gmail.com>
    HID: input: do not query XP-PEN Deco LW battery

Minsuk Kang <linuxlovemin@yonsei.ac.kr>
    wifi: brcmfmac: Fix potential shift-out-of-bounds in brcmf_fw_alloc_request()

Nathan Chancellor <nathan@kernel.org>
    hamradio: baycom_epp: Fix return type of baycom_send_packet()

Nathan Chancellor <nathan@kernel.org>
    net: ethernet: ti: Fix return type of netcp_ndo_start_xmit()

Stanislav Fomichev <sdf@google.com>
    bpf: make sure skb->len != 0 when redirecting to a tunneling device

Nathan Chancellor <nathan@kernel.org>
    drm/meson: Fix return type of meson_encoder_cvbs_mode_valid()

Jiri Slaby (SUSE) <jirislaby@kernel.org>
    qed (gcc13): use u16 for fid to be big enough

Rahul Bhattacharjee <quic_rbhattac@quicinc.com>
    wifi: ath11k: Fix qmi_msg_handler data structure initialization

Kerem Karabay <kekrby@gmail.com>
    HID: apple: enable APPLE_ISO_TILDE_QUIRK for the keyboards of Macs with the T2 chip

Kerem Karabay <kekrby@gmail.com>
    HID: apple: fix key translations where multiple quirks attempt to translate the same key

David Jeffery <djeffery@redhat.com>
    blk-mq: avoid double ->queue_rq() because of early timeout

Yuan Can <yuancan@huawei.com>
    drm/rockchip: use pm_runtime_resume_and_get() instead of pm_runtime_get_sync()

Hamza Mahfooz <hamza.mahfooz@amd.com>
    Revert "drm/amd/display: Limit max DSC target bpp for specific monitors"

Hamza Mahfooz <hamza.mahfooz@amd.com>
    drm/edid: add a quirk for two LG monitors to get them to work on 10bpc

gehao <gehao@kylinos.cn>
    drm/amd/display: prevent memory leak

Youghandhar Chintala <quic_youghand@quicinc.com>
    wifi: ath10k: Delay the unmapping of the buffer

Zhang Yuchen <zhangyuchen.lcr@bytedance.com>
    ipmi: fix memleak when unload ipmi driver

Amadeusz Sławiński <amadeuszx.slawinski@linux.intel.com>
    ASoC: Intel: avs: Add quirk for KBL-R RVP platform

Amadeusz Sławiński <amadeuszx.slawinski@linux.intel.com>
    ASoC: codecs: rt298: Add quirk for KBL-R RVP platform

Shigeru Yoshida <syoshida@redhat.com>
    wifi: ar5523: Fix use-after-free on ar5523_cmd() timed out

Fedor Pchelkin <pchelkin@ispras.ru>
    wifi: ath9k: verify the expected usb_endpoints are present

Wright Feng <wright.feng@cypress.com>
    brcmfmac: return error when getting invalid max_flowrings from dongle

Ming Qian <ming.qian@nxp.com>
    media: imx-jpeg: Disable useless interrupt to avoid kernel panic

Doug Brown <doug@schmorgal.com>
    drm/etnaviv: add missing quirks for GC300

ZhangPeng <zhangpeng362@huawei.com>
    hfs: fix OOB Read in __hfs_brec_find

Hans de Goede <hdegoede@redhat.com>
    ACPI: x86: Add skip i2c clients quirk for Medion Lifetab S10346

Hans de Goede <hdegoede@redhat.com>
    ACPI: x86: Add skip i2c clients quirk for Lenovo Yoga Tab 3 Pro (YT3-X90F)

Mateusz Jończyk <mat.jonczyk@o2.pl>
    x86/apic: Handle no CONFIG_X86_X2APIC on systems with x2APIC enabled by BIOS

Zheng Yejian <zhengyejian1@huawei.com>
    acct: fix potential integer overflow in encode_comp_t()

Ryusuke Konishi <konishi.ryusuke@gmail.com>
    nilfs2: fix shift-out-of-bounds due to too large exponent of block size

Ryusuke Konishi <konishi.ryusuke@gmail.com>
    nilfs2: fix shift-out-of-bounds/overflow in nilfs_sb2_bad_offset()

Rafael J. Wysocki <rafael.j.wysocki@intel.com>
    ACPICA: Fix error code path in acpi_ds_call_control_method()

Mia Kanashi <chad@redpilled.dev>
    ACPI: EC: Add quirk for the HP Pavilion Gaming 15-cx0041ur

Li Zhong <floridsleeves@gmail.com>
    ACPI: processor: idle: Check acpi_fetch_acpi_dev() return value

Hoi Pok Wu <wuhoipok@gmail.com>
    fs: jfs: fix shift-out-of-bounds in dbDiscardAG

Dr. David Alan Gilbert <linux@treblig.org>
    jfs: Fix fortify moan in symlink

Shigeru Yoshida <syoshida@redhat.com>
    udf: Avoid double brelse() in udf_rename()

Dongliang Mu <mudongliangabcd@gmail.com>
    fs: jfs: fix shift-out-of-bounds in dbAllocAG

Marijn Suijten <marijn.suijten@somainline.org>
    arm64: dts: qcom: sm6350: Add apps_smmu with streamID to SDHCI 1/2 nodes

Liu Shixin <liushixin2@huawei.com>
    binfmt_misc: fix shift-out-of-bounds in check_special_flags

Gaurav Kohli <gauravkohli@linux.microsoft.com>
    x86/hyperv: Remove unregister syscore call from Hyper-V cleanup

Guilherme G. Piccoli <gpiccoli@igalia.com>
    video: hyperv_fb: Avoid taking busy spinlock on panic path

Adriana Kobylak <anoo@us.ibm.com>
    ARM: dts: aspeed: rainier,everest: Move reserved memory regions

Mark Rutland <mark.rutland@arm.com>
    arm64: make is_ttbrX_addr() noinstr-safe

Zqiang <qiang1.zhang@intel.com>
    rcu: Fix __this_cpu_read() lockdep warning in rcu_force_quiescent_state()

Jiasheng Jiang <jiasheng@iscas.ac.cn>
    HID: amd_sfh: Add missing check for dma_alloc_coherent

Matt Johnston <matt@codeconstruct.com.au>
    mctp: Remove device type check at unregister

Jeremy Kerr <jk@codeconstruct.com.au>
    mctp: serial: Fix starting value for frame check sequence

Eric Dumazet <edumazet@google.com>
    net: stream: purge sk_error_queue in sk_stream_kill_queues()

Christophe JAILLET <christophe.jaillet@wanadoo.fr>
    myri10ge: Fix an error handling path in myri10ge_probe()

David Howells <dhowells@redhat.com>
    rxrpc: Fix missing unlock in rxrpc_do_sendmsg()

Cong Wang <cong.wang@bytedance.com>
    net_sched: reject TCF_EM_SIMPLE case for complex ematch module

Yang Yingliang <yangyingliang@huawei.com>
    mailbox: zynq-ipi: fix error handling while device_register() fails

Yang Yingliang <yangyingliang@huawei.com>
    mailbox: arm_mhuv2: Fix return value check in mhuv2_probe()

Conor Dooley <conor.dooley@microchip.com>
    mailbox: mpfs: read the system controller's status

Subash Abhinov Kasiviswanathan <quic_subashab@quicinc.com>
    skbuff: Account for tail adjustment during pull operations

Jakub Kicinski <kuba@kernel.org>
    devlink: protect devlink dump by the instance lock

Chen-Yu Tsai <wenst@chromium.org>
    arm64: dts: mt8183: Fix Mali GPU clock

Chun-Jie Chen <chun-jie.chen@mediatek.com>
    soc: mediatek: pm-domains: Fix the power glitch issue

Eelco Chaudron <echaudro@redhat.com>
    openvswitch: Fix flow lookup to use unmasked key

Jakub Kicinski <kuba@kernel.org>
    selftests: devlink: fix the fd redirect in dummy_reporter_test

Jakub Kicinski <kuba@kernel.org>
    devlink: hold region lock when flushing snapshots

GUO Zihua <guozihua@huawei.com>
    rtc: mxc_v2: Add missing clk_disable_unprepare()

Tan Tee Min <tee.min.tan@linux.intel.com>
    igc: Set Qbv start_time and end_time to end_time if not being configured in GCL

Tan Tee Min <tee.min.tan@linux.intel.com>
    igc: recalculate Qbv end_time by considering cycle time

Tan Tee Min <tee.min.tan@linux.intel.com>
    igc: allow BaseTime 0 enrollment for Qbv

Muhammad Husaini Zulkifli <muhammad.husaini.zulkifli@intel.com>
    igc: Add checking for basetime less than zero

Vinicius Costa Gomes <vinicius.gomes@intel.com>
    igc: Use strict cycles for Qbv scheduling

Vinicius Costa Gomes <vinicius.gomes@intel.com>
    igc: Enhance Qbv scheduling by using first flag bit

Vladimir Oltean <vladimir.oltean@nxp.com>
    net: dsa: mv88e6xxx: avoid reg_lock deadlock in mv88e6xxx_setup_port()

Li Zetao <lizetao1@huawei.com>
    r6040: Fix kmemleak in probe and remove

Kirill Tkhai <tkhai@ya.ru>
    unix: Fix race in SOCK_SEQPACKET's unix_dgram_sendmsg()

Minsuk Kang <linuxlovemin@yonsei.ac.kr>
    nfc: pn533: Clear nfc_target before being used

Vladimir Oltean <vladimir.oltean@nxp.com>
    net: enetc: avoid buffer leaks on xdp_do_redirect() failure

Hans Verkuil <hverkuil-cisco@xs4all.nl>
    media: v4l2-ctrls-api.c: add back dropped ctrl->is_new = 1

Milan Landaverde <milan@mdaverde.com>
    bpf: prevent leak of lsm program after failed attach

Song Liu <song@kernel.org>
    selftests/bpf: Select CONFIG_FUNCTION_ERROR_INJECTION

Yu Kuai <yukuai3@huawei.com>
    block, bfq: fix possible uaf for 'bfqq->bic'

Yang Yingliang <yangyingliang@huawei.com>
    mISDN: hfcmulti: don't call dev_kfree_skb/kfree_skb() under spin_lock_irqsave()

Yang Yingliang <yangyingliang@huawei.com>
    mISDN: hfcpci: don't call dev_kfree_skb/kfree_skb() under spin_lock_irqsave()

Yang Yingliang <yangyingliang@huawei.com>
    mISDN: hfcsusb: don't call dev_kfree_skb/kfree_skb() under spin_lock_irqsave()

Hangbin Liu <liuhangbin@gmail.com>
    bonding: do failover when high prio link up

Hangbin Liu <liuhangbin@gmail.com>
    bonding: add missed __rcu annotation for curr_active_slave

Emeel Hakim <ehakim@nvidia.com>
    net: macsec: fix net device access prior to holding a lock

Dan Aloni <dan.aloni@vastdata.com>
    nfsd: under NFSv4.1, fix double svc_xprt_put on rpc_create failure

Dan Carpenter <error27@gmail.com>
    iommu/mediatek: Fix forever loop in error handling

Alexandre Belloni <alexandre.belloni@bootlin.com>
    rtc: pcf85063: fix pcf85063_clkout_control

Gaosheng Cui <cuigaosheng1@huawei.com>
    rtc: pic32: Move devm_rtc_allocate_device earlier in pic32_rtc_probe()

Gaosheng Cui <cuigaosheng1@huawei.com>
    rtc: st-lpc: Add missing clk_disable_unprepare in st_rtc_probe()

Qingfang DENG <dqfext@gmail.com>
    netfilter: flowtable: really fix NAT IPv6 offload

Yang Yingliang <yangyingliang@huawei.com>
    mfd: pm8008: Fix return value check in pm8008_probe()

Christophe JAILLET <christophe.jaillet@wanadoo.fr>
    mfd: qcom_rpm: Fix an error handling path in qcom_rpm_probe()

Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>
    mfd: bd957x: Fix Kconfig dependency on REGMAP_IRQ

Samuel Holland <samuel@sholland.org>
    mfd: axp20x: Do not sleep in the power off handler

Bryan O'Donoghue <bryan.odonoghue@linaro.org>
    dt-bindings: mfd: qcom,spmi-pmic: Drop PWM reg dependency

Nathan Lynch <nathanl@linux.ibm.com>
    powerpc/pseries/eeh: use correct API for error log size

Shang XiaoJing <shangxiaojing@huawei.com>
    remoteproc: qcom: q6v5: Fix missing clk_disable_unprepare() in q6v5_wcss_qcs404_power_on()

Yuan Can <yuancan@huawei.com>
    remoteproc: qcom_q6v5_pas: Fix missing of_node_put() in adsp_alloc_memory_region()

Luca Weiss <luca.weiss@fairphone.com>
    remoteproc: qcom_q6v5_pas: detach power domains on remove

Luca Weiss <luca.weiss@fairphone.com>
    remoteproc: qcom_q6v5_pas: disable wakeup on probe fail or remove

Shang XiaoJing <shangxiaojing@huawei.com>
    remoteproc: qcom: q6v5: Fix potential null-ptr-deref in q6v5_wcss_init_mmio()

Gaosheng Cui <cuigaosheng1@huawei.com>
    remoteproc: sysmon: fix memory leak in qcom_add_sysmon_subdev()

Anup Patel <apatel@ventanamicro.com>
    RISC-V: KVM: Fix reg_val check in kvm_riscv_vcpu_set_reg_config()

Daniel Golle <daniel@makrotopia.org>
    pwm: mediatek: always use bus clock for PWM on MT7622

xinlei lee <xinlei.lee@mediatek.com>
    pwm: mtk-disp: Fix the parameters calculated by the enabled flag of disp_pwm

Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
    pwm: sifive: Call pwm_sifive_update_clock() while mutex is held

Jason Gunthorpe <jgg@ziepe.ca>
    iommu/sun50i: Remove IOMMU_DOMAIN_IDENTITY

Guenter Roeck <groeck@chromium.org>
    iommu/mediatek: Validate number of phandles associated with "mediatek,larbs"

Yong Wu <yong.wu@mediatek.com>
    iommu/mediatek: Add error path for loop of mm_dts_parse

Yong Wu <yong.wu@mediatek.com>
    iommu/mediatek: Use component_match_add

Yong Wu <yong.wu@mediatek.com>
    iommu/mediatek: Add platform_device_put for recovering the device refcnt

Miaoqian Lin <linmq006@gmail.com>
    selftests/powerpc: Fix resource leaks

Kajol Jain <kjain@linux.ibm.com>
    powerpc/hv-gpci: Fix hv_gpci event list

Yang Yingliang <yangyingliang@huawei.com>
    powerpc/83xx/mpc832x_rdb: call platform_device_put() in error case in of_fsl_spi_probe()

Nicholas Piggin <npiggin@gmail.com>
    powerpc/perf: callchain validate kernel stack pointer bounds

Pali Rohár <pali@kernel.org>
    powerpc: dts: turris1x.dts: Add channel labels for temperature sensor

Li Huafei <lihuafei1@huawei.com>
    kprobes: Fix check for probe enabled in kill_kprobe()

Nayna Jain <nayna@linux.ibm.com>
    powerpc/pseries: fix plpks_read_var() code for different consumers

Nayna Jain <nayna@linux.ibm.com>
    powerpc/pseries: Return -EIO instead of -EINTR for H_ABORTED error

Nayna Jain <nayna@linux.ibm.com>
    powerpc/pseries: Fix the H_CALL error code in PLPKS driver

Nayna Jain <nayna@linux.ibm.com>
    powerpc/pseries: fix the object owners enum value in plpks driver

Yang Yingliang <yangyingliang@huawei.com>
    powerpc/xive: add missing iounmap() in error path in xive_spapr_populate_irq_data()

Gustavo A. R. Silva <gustavoars@kernel.org>
    powerpc/xmon: Fix -Wswitch-unreachable warning in bpt_cmds

Miaoqian Lin <linmq006@gmail.com>
    cxl: Fix refcount leak in cxl_calc_capp_routing

Christophe JAILLET <christophe.jaillet@wanadoo.fr>
    powerpc/52xx: Fix a resource leak in an error handling path

Xie Shaowen <studentxswpy@163.com>
    macintosh/macio-adb: check the return value of ioremap()

Yang Yingliang <yangyingliang@huawei.com>
    macintosh: fix possible memory leak in macio_add_one_device()

Yuan Can <yuancan@huawei.com>
    iommu/fsl_pamu: Fix resource leak in fsl_pamu_probe()

Yang Yingliang <yangyingliang@huawei.com>
    iommu/amd: Fix pci device refcount leak in ppr_notifier()

Yang Yingliang <yangyingliang@huawei.com>
    iommu/mediatek: Check return value after calling platform_get_resource()

Alexander Stein <alexander.stein@ew.tq-group.com>
    rtc: pcf85063: Fix reading alarm

Stefan Eichenberger <stefan.eichenberger@toradex.com>
    rtc: snvs: Allow a time difference on clock register read

Rafael J. Wysocki <rafael.j.wysocki@intel.com>
    rtc: cmos: Disable ACPI RTC event on removal

Rafael J. Wysocki <rafael.j.wysocki@intel.com>
    rtc: cmos: Rename ACPI-related functions

Rafael J. Wysocki <rafael.j.wysocki@intel.com>
    rtc: cmos: Eliminate forward declarations of some functions

Rafael J. Wysocki <rafael.j.wysocki@intel.com>
    rtc: cmos: Call rtc_wake_setup() from cmos_do_probe()

Rafael J. Wysocki <rafael.j.wysocki@intel.com>
    rtc: cmos: Call cmos_wake_setup() from cmos_do_probe()

Shang XiaoJing <shangxiaojing@huawei.com>
    rtc: class: Fix potential memleak in devm_rtc_allocate_device()

Yushan Zhou <katrinzhou@tencent.com>
    rtc: rzn1: Check return value in rzn1_rtc_probe

Fenghua Yu <fenghua.yu@intel.com>
    dmaengine: idxd: Fix crc_val field for completion record

Abdun Nihaal <abdun.nihaal@gmail.com>
    fs/ntfs3: Fix slab-out-of-bounds read in ntfs_trim_fs

Manivannan Sadhasivam <mani@kernel.org>
    phy: qcom-qmp-pcie: Fix sm8450_qmp_gen4x2_pcie_pcs_tbl[] register names

Jon Hunter <jonathanh@nvidia.com>
    pwm: tegra: Ensure the clock rate is not less than needed

Jon Hunter <jonathanh@nvidia.com>
    pwm: tegra: Improve required rate calculation

Matt Redfearn <matt.redfearn@mips.com>
    include/uapi/linux/swab: Fix potentially missing __always_inline

Justin Chen <justinpopo6@gmail.com>
    phy: usb: Fix clock imbalance for suspend/resume

Justin Chen <justinpopo6@gmail.com>
    phy: usb: Use slow clock for wake enabled suspend

Al Cooper <alcooperx@gmail.com>
    phy: usb: s2 WoL wakeup_count not incremented for USB->Eth devices

Michael Riesch <michael.riesch@wolfvision.net>
    iommu/rockchip: fix permission bits in page table entries v2

Jernej Skrabec <jernej.skrabec@gmail.com>
    iommu/sun50i: Implement .iotlb_sync_map

Jernej Skrabec <jernej.skrabec@gmail.com>
    iommu/sun50i: Fix flush size

Jernej Skrabec <jernej.skrabec@gmail.com>
    iommu/sun50i: Fix R/W permission check

Jernej Skrabec <jernej.skrabec@gmail.com>
    iommu/sun50i: Consider all fault sources for reset

Jernej Skrabec <jernej.skrabec@gmail.com>
    iommu/sun50i: Fix reset release

Niklas Schnelle <schnelle@linux.ibm.com>
    iommu/s390: Fix duplicate domain attachments

Johan Hovold <johan+linaro@kernel.org>
    phy: qcom-qmp-pcie: fix ipq8074-gen3 initialisation

Martin Povišer <povik+lin@cutebit.org>
    dmaengine: apple-admac: Allocate cache SRAM to channels

Martin Povišer <povik+lin@cutebit.org>
    dmaengine: apple-admac: Do not use devres for IRQs

Johan Hovold <johan+linaro@kernel.org>
    phy: qcom-qmp-pcie: drop bogus register update

Pali Rohár <pali@kernel.org>
    phy: marvell: phy-mvebu-a3700-comphy: Reset COMPHY registers before USB 3.0 power on

Dan Carpenter <dan.carpenter@oracle.com>
    fs/ntfs3: Harden against integer overflows

Shigeru Yoshida <syoshida@redhat.com>
    fs/ntfs3: Avoid UBSAN error on true_sectors_per_clst()

Arnd Bergmann <arnd@arndb.de>
    RDMA/siw: Fix pointer cast warning

Namhyung Kim <namhyung@kernel.org>
    perf stat: Do not delay the workload with --delay

Ard Biesheuvel <ardb@kernel.org>
    ftrace: Allow WITH_ARGS flavour of graph tracer with shadow call stack

Namhyung Kim <namhyung@kernel.org>
    perf off_cpu: Fix a typo in BTF tracepoint name, it should be 'btf_trace_sched_switch'

Luca Weiss <luca@z3ntu.xyz>
    leds: is31fl319x: Fix setting current limit for is31fl319{0,1,3}

ruanjinjie <ruanjinjie@huawei.com>
    power: supply: fix null pointer dereferencing in power_supply_get_battery_info

Hans de Goede <hdegoede@redhat.com>
    power: supply: bq25890: Ensure pump_express_work is cancelled on remove

Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
    power: supply: bq25890: Convert to i2c's .probe_new()

Marek Vasut <marex@denx.de>
    power: supply: bq25890: Factor out regulator registration code

Yuan Can <yuancan@huawei.com>
    power: supply: ab8500: Fix error handling in ab8500_charger_init()

Yuan Can <yuancan@huawei.com>
    HSI: omap_ssi_core: Fix error handling in ssi_init()

Shang XiaoJing <shangxiaojing@huawei.com>
    power: supply: cw2015: Fix potential null-ptr-deref in cw_bat_probe()

Zheyu Ma <zheyuma97@gmail.com>
    power: supply: cw2015: Use device managed API to simplify the code

Zhang Qilong <zhangqilong3@huawei.com>
    power: supply: z2_battery: Fix possible memleak in z2_batt_probe()

Ajay Kaher <akaher@vmware.com>
    perf symbol: correction while adjusting symbol

Leo Yan <leo.yan@linaro.org>
    perf trace: Handle failure when trace point folder is missed

Leo Yan <leo.yan@linaro.org>
    perf trace: Use macro RAW_SYSCALL_ARGS_NUM to replace number

Leo Yan <leo.yan@linaro.org>
    perf trace: Return error if a system call doesn't exist

Mika Westerberg <mika.westerberg@linux.intel.com>
    watchdog: iTCO_wdt: Set NO_REBOOT if the watchdog is not already running

Zeng Heng <zengheng4@huawei.com>
    power: supply: fix residue sysfs file in error handle route of __power_supply_register()

Yang Yingliang <yangyingliang@huawei.com>
    HSI: omap_ssi_core: fix possible memory leak in ssi_probe()

Yang Yingliang <yangyingliang@huawei.com>
    HSI: omap_ssi_core: fix unbalanced pm_runtime_disable()

Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
    led: qcom-lpg: Fix sleeping in atomic

Christophe JAILLET <christophe.jaillet@wanadoo.fr>
    fbdev: uvesafb: Fixes an error handling path in uvesafb_probe()

Randy Dunlap <rdunlap@infradead.org>
    fbdev: uvesafb: don't build on UML

Randy Dunlap <rdunlap@infradead.org>
    fbdev: geode: don't build on UML

Gaosheng Cui <cuigaosheng1@huawei.com>
    fbdev: ep93xx-fb: Add missing clk_disable_unprepare in ep93xxfb_probe()

Xiongfeng Wang <wangxiongfeng2@huawei.com>
    fbdev: vermilion: decrease reference count in error path

Shang XiaoJing <shangxiaojing@huawei.com>
    fbdev: via: Fix error in via_core_init()

Yang Yingliang <yangyingliang@huawei.com>
    fbdev: pm2fb: fix missing pci_disable_device()

Andy Shevchenko <andriy.shevchenko@linux.intel.com>
    fbdev: ssd1307fb: Drop optional dependency

Bjorn Andersson <andersson@kernel.org>
    thermal/drivers/qcom/lmh: Fix irq handler return value

Luca Weiss <luca.weiss@fairphone.com>
    thermal/drivers/qcom/temp-alarm: Fix inaccurate warning for gen2

Keerthy <j-keerthy@ti.com>
    thermal/drivers/k3_j72xx_bandgap: Fix the debug print message

Marcus Folkesson <marcus.folkesson@gmail.com>
    thermal/drivers/imx8mm_thermal: Validate temperature range

Shang XiaoJing <shangxiaojing@huawei.com>
    samples: vfio-mdev: Fix missing pci_disable_device() in mdpy_fb_probe()

Xiu Jianfeng <xiujianfeng@huawei.com>
    ksmbd: Fix resource leak in ksmbd_session_rpc_open()

Zheng Yejian <zhengyejian1@huawei.com>
    tracing/hist: Fix issue of losting command info in error_log

Yang Yingliang <yangyingliang@huawei.com>
    usb: typec: wusb3801: fix fwnode refcount leak in wusb3801_probe()

Jiasheng Jiang <jiasheng@iscas.ac.cn>
    usb: storage: Add check for kcalloc

Zheyu Ma <zheyuma97@gmail.com>
    i2c: ismt: Fix an out-of-bounds bug in ismt_access()

Yang Yingliang <yangyingliang@huawei.com>
    i2c: mux: reg: check return value after calling platform_get_resource()

Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
    gpiolib: protect the GPIO device against being dropped while in use by user-space

Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
    gpiolib: cdev: fix NULL-pointer dereferences

Chen Zhongjin <chenzhongjin@huawei.com>
    vme: Fix error not catched in fake_init()

YueHaibing <yuehaibing@huawei.com>
    staging: rtl8192e: Fix potential use-after-free in rtllib_rx_Monitor()

Dan Carpenter <error27@gmail.com>
    staging: rtl8192u: Fix use after free in ieee80211_rx()

Hui Tang <tanghui20@huawei.com>
    i2c: pxa-pci: fix missing pci_disable_device() on error in ce4100_i2c_probe

Yang Yingliang <yangyingliang@huawei.com>
    chardev: fix error handling in cdev_device_add()

Yang Yingliang <yangyingliang@huawei.com>
    mcb: mcb-parse: fix error handing in chameleon_parse_gdd()

Zhengchao Shao <shaozhengchao@huawei.com>
    drivers: mcb: fix resource leak in mcb_probe()

John Keeping <john@metanate.com>
    usb: gadget: f_hid: fix refcount leak on error path

John Keeping <john@metanate.com>
    usb: gadget: f_hid: fix f_hidg lifetime vs cdev

Yang Yingliang <yangyingliang@huawei.com>
    usb: core: hcd: Fix return value check in usb_hcd_setup_local_mem()

Yang Yingliang <yangyingliang@huawei.com>
    usb: roles: fix of node refcount leak in usb_role_switch_is_parent()

Beau Belgrave <beaub@linux.microsoft.com>
    tracing/user_events: Fix call print_fmt leak

Yang Shen <shenyang39@huawei.com>
    coresight: trbe: remove cpuhp instance node before remove cpuhp state

Fabrice Gasnier <fabrice.gasnier@foss.st.com>
    counter: stm32-lptimer-cnt: fix the check on arr and cmp registers update

Ramona Bolboaca <ramona.bolboaca@analog.com>
    iio: adis: add '__adis_enable_irq()' implementation

Cosmin Tanislav <cosmin.tanislav@analog.com>
    iio: temperature: ltc2983: make bulk write buffer DMA-safe

Yang Yingliang <yangyingliang@huawei.com>
    cxl: fix possible null-ptr-deref in cxl_pci_init_afu|adapter()

Yang Yingliang <yangyingliang@huawei.com>
    cxl: fix possible null-ptr-deref in cxl_guest_init_afu|adapter()

Yang Yingliang <yangyingliang@huawei.com>
    firmware: raspberrypi: fix possible memory leak in rpi_firmware_probe()

Zheng Wang <zyytlz.wz@163.com>
    misc: sgi-gru: fix use-after-free error in gru_set_context_option, gru_fault and gru_handle_user_call_os

ruanjinjie <ruanjinjie@huawei.com>
    misc: tifm: fix possible memory leak in tifm_7xx1_switch_media()

Yang Yingliang <yangyingliang@huawei.com>
    ocxl: fix pci device refcount leak when calling get_function_0()

Yang Yingliang <yangyingliang@huawei.com>
    misc: ocxl: fix possible name leak in ocxl_file_register_afu()

Zhengchao Shao <shaozhengchao@huawei.com>
    test_firmware: fix memory leak in test_firmware_init()

Yuan Can <yuancan@huawei.com>
    serial: sunsab: Fix error handling in sunsab_init()

Gabriel Somlo <gsomlo@gmail.com>
    serial: altera_uart: fix locking in polling mode

Jiri Slaby <jirislaby@kernel.org>
    tty: serial: altera_uart_{r,t}x_chars() need only uart_port

Jiri Slaby <jirislaby@kernel.org>
    tty: serial: clean up stop-tx part in altera_uart_tx_chars()

Xiongfeng Wang <wangxiongfeng2@huawei.com>
    serial: pch: Fix PCI device refcount leak in pch_request_dma()

Valentin Caron <valentin.caron@foss.st.com>
    serial: stm32: move dma_request_chan() before clk_prepare_enable()

delisun <delisun@pateo.com.cn>
    serial: pl011: Do not clear RX FIFO & RX interrupt in unthrottle.

Jiamei Xie <jiamei.xie@arm.com>
    serial: amba-pl011: avoid SBSA UART accessing DMACR register

Jiantao Zhang <water.zhangjiantao@huawei.com>
    USB: gadget: Fix use-after-free during usb config switch

Marek Vasut <marex@denx.de>
    extcon: usbc-tusb320: Update state on probe even if no IRQ pending

Marek Vasut <marex@denx.de>
    extcon: usbc-tusb320: Add USB TYPE-C support

Marek Vasut <marex@denx.de>
    extcon: usbc-tusb320: Factor out extcon into dedicated functions

Tony Lindgren <tony@atomide.com>
    usb: musb: omap2430: Fix probe regression for missing resources

Sven Peter <sven@svenpeter.dev>
    usb: typec: tipd: Fix typec_unregister_port error paths

Sven Peter <sven@svenpeter.dev>
    usb: typec: tipd: Fix spurious fwnode_handle_put in error path

Sven Peter <sven@svenpeter.dev>
    usb: typec: tipd: Cleanup resources if devm_tps6598_psy_register fails

Yang Yingliang <yangyingliang@huawei.com>
    usb: typec: tcpci: fix of node refcount leak in tcpci_register_port()

Sven Peter <sven@svenpeter.dev>
    usb: typec: Check for ops->exit instead of ops->enter in altmode_exit

Gaosheng Cui <cuigaosheng1@huawei.com>
    staging: vme_user: Fix possible UAF in tsi148_dma_list_add

Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
    interconnect: qcom: sc7180: fix dropped const of qcom_icc_bcm

Linus Walleij <linus.walleij@linaro.org>
    usb: fotg210-udc: Fix ages old endianness issues

Rafael Mendonca <rafaelmendsr@gmail.com>
    uio: uio_dmem_genirq: Fix deadlock between irq config and handling

Rafael Mendonca <rafaelmendsr@gmail.com>
    uio: uio_dmem_genirq: Fix missing unlock in irq configuration

Rafael Mendonca <rafaelmendsr@gmail.com>
    vfio: platform: Do not pass return buffer to ACPI _RST method

Yang Yingliang <yangyingliang@huawei.com>
    class: fix possible memory leak in __class_register()

Duoming Zhou <duoming@zju.edu.cn>
    drivers: staging: r8188eu: Fix sleep-in-atomic-context bug in rtw_join_timeout_handler

Yuan Can <yuancan@huawei.com>
    serial: 8250_bcm7271: Fix error handling in brcmuart_init()

Kartik <kkartik@nvidia.com>
    serial: tegra: Read DMA status before terminating

Yang Yingliang <yangyingliang@huawei.com>
    drivers: dio: fix possible memory leak in dio_init()

Alexandre Ghiti <alexghiti@rivosinc.com>
    riscv: Fix P4D_SHIFT definition for 3-level page table mode

Yangtao Li <frank.li@vivo.com>
    f2fs: fix iostat parameter for discard

Palmer Dabbelt <palmer@rivosinc.com>
    RISC-V: Align the shadow stack

Dragos Tatulea <dtatulea@nvidia.com>
    IB/IPoIB: Fix queue count inconsistency for PKEY child interfaces

Xiongfeng Wang <wangxiongfeng2@huawei.com>
    hwrng: geode - Fix PCI device refcount leak

Xiongfeng Wang <wangxiongfeng2@huawei.com>
    hwrng: amd - Fix PCI device refcount leak

Gaosheng Cui <cuigaosheng1@huawei.com>
    crypto: img-hash - Fix variable dereferenced before check 'hdev->req'

Samuel Holland <samuel@sholland.org>
    riscv: Fix crash during early errata patching

Anup Patel <apatel@ventanamicro.com>
    RISC-V: Fix MEMREMAP_WB for systems with Svpbmt

Andrew Bresticker <abrestic@rivosinc.com>
    RISC-V: Fix unannoted hardirqs-on in return to userspace slow-path

Chengchang Tang <tangchengchang@huawei.com>
    RDMA/hns: Fix XRC caps on HIP08

Chengchang Tang <tangchengchang@huawei.com>
    RDMA/hns: Fix error code of CMD

Chengchang Tang <tangchengchang@huawei.com>
    RDMA/hns: Fix page size cap from firmware

Chengchang Tang <tangchengchang@huawei.com>
    RDMA/hns: Fix PBL page MTR find

Chengchang Tang <tangchengchang@huawei.com>
    RDMA/hns: Fix AH attr queried by query_qp

Yixing Liu <liuyixing1@huawei.com>
    RDMA/hns: Fix the gid problem caused by free mr

Wenpeng Liang <liangwenpeng@huawei.com>
    RDMA/hns: Remove redundant DFX file and DFX ops structure

Zhang Xiaoxu <zhangxiaoxu5@huawei.com>
    orangefs: Fix sysfs not cleanup when dev init failed

Francisco Munoz <francisco.munoz.ruiz@linux.intel.com>
    PCI: vmd: Fix secondary bus reset for Intel bridges

Wang Yufen <wangyufen@huawei.com>
    RDMA/srp: Fix error return code in srp_parse_options()

Wang Yufen <wangyufen@huawei.com>
    RDMA/hfi1: Fix error return code in parse_platform_config()

Randy Dunlap <rdunlap@infradead.org>
    RDMA: Disable IB HW for UML

Tong Tiangen <tongtiangen@huawei.com>
    riscv/mm: add arch hook arch_clear_hugepage_flags

Shang XiaoJing <shangxiaojing@huawei.com>
    crypto: omap-sham - Use pm_runtime_resume_and_get() in omap_sham_probe()

Christophe JAILLET <christophe.jaillet@wanadoo.fr>
    crypto: amlogic - Remove kcalloc without check

Wang Yufen <wangyufen@huawei.com>
    crypto: qat - fix error return code in adf_probe

Mark Zhang <markzhang@nvidia.com>
    RDMA/nldev: Fix failure to send large messages

Yonggil Song <yonggil.song@samsung.com>
    f2fs: avoid victim selection from previous victim section

Sheng Yong <shengyong@oppo.com>
    f2fs: fix to enable compress for newly created file if extension matches

Sheng Yong <shengyong@oppo.com>
    f2fs: set zstd compress level correctly

Yuan Can <yuancan@huawei.com>
    RDMA/nldev: Add checks for nla_nest_start() in fill_stat_counter_qps()

Bart Van Assche <bvanassche@acm.org>
    scsi: ufs: core: Fix the polling implementation

Jie Zhan <zhanjie9@hisilicon.com>
    scsi: hisi_sas: Fix SATA devices missing issue during I_T nexus reset

Jie Zhan <zhanjie9@hisilicon.com>
    scsi: libsas: Add smp_ata_check_ready_type()

Gaosheng Cui <cuigaosheng1@huawei.com>
    scsi: snic: Fix possible UAF in snic_tgt_create()

Chen Zhongjin <chenzhongjin@huawei.com>
    scsi: fcoe: Fix transport not deattached when fcoe_if_init() fails

Shang XiaoJing <shangxiaojing@huawei.com>
    scsi: ipr: Fix WARNING in ipr_init()

Yang Yingliang <yangyingliang@huawei.com>
    scsi: scsi_debug: Fix possible name leak in sdebug_add_host_helper()

Yang Yingliang <yangyingliang@huawei.com>
    scsi: fcoe: Fix possible name leak when device_register() fails

Harshit Mogalapalli <harshit.m.mogalapalli@oracle.com>
    scsi: scsi_debug: Fix a warning in resp_report_zones()

Harshit Mogalapalli <harshit.m.mogalapalli@oracle.com>
    scsi: scsi_debug: Fix a warning in resp_verify()

Chen Zhongjin <chenzhongjin@huawei.com>
    scsi: efct: Fix possible memleak in efct_device_init()

Yang Yingliang <yangyingliang@huawei.com>
    scsi: hpsa: Fix possible memory leak in hpsa_add_sas_device()

Yang Yingliang <yangyingliang@huawei.com>
    scsi: hpsa: Fix error handling in hpsa_add_sas_host()

Yang Yingliang <yangyingliang@huawei.com>
    scsi: mpt3sas: Fix possible resource leaks in mpt3sas_transport_port_add()

Daniel Jordan <daniel.m.jordan@oracle.com>
    padata: Fix list iterator in padata_do_serial()

Daniel Jordan <daniel.m.jordan@oracle.com>
    padata: Always leave BHs disabled when running ->parallel()

Zhang Yiqun <zhangyiqun@phytium.com.cn>
    crypto: tcrypt - Fix multibuffer skcipher speed test mem leak

Yuan Can <yuancan@huawei.com>
    scsi: hpsa: Fix possible memory leak in hpsa_init_one()

Frank Li <frank.li@nxp.com>
    PCI: endpoint: pci-epf-vntb: Fix call pci_epc_mem_free_addr() in error path

Serge Semin <Sergey.Semin@baikalelectronics.ru>
    dt-bindings: visconti-pcie: Fix interrupts array max constraints

Serge Semin <Sergey.Semin@baikalelectronics.ru>
    dt-bindings: imx6q-pcie: Fix clock names for imx6sx and imx8mq

Zhang Xiaoxu <zhangxiaoxu5@huawei.com>
    RDMA/rxe: Fix NULL-ptr-deref in rxe_qp_do_cleanup() when socket create failed

Zhengchao Shao <shaozhengchao@huawei.com>
    RDMA/hns: fix memory leak in hns_roce_alloc_mr()

Mustafa Ismail <mustafa.ismail@intel.com>
    RDMA/irdma: Initialize net_type before checking it

Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
    crypto: ccree - Make cc_debugfs_global_fini() available for module init function

Xiongfeng Wang <wangxiongfeng2@huawei.com>
    RDMA/hfi: Decrease PCI device reference count in error path

Zeng Heng <zengheng4@huawei.com>
    PCI: Check for alloc failure in pci_request_irq()

Luoyouming <luoyouming@huawei.com>
    RDMA/hns: Fix incorrect sge nums calculation

Luoyouming <luoyouming@huawei.com>
    RDMA/hns: Fix ext_sge num error when post send

Luoyouming <luoyouming@huawei.com>
    RDMA/hns: Repacing 'dseg_len' by macros in fill_ext_sge_inl_data()

Li Zhijian <lizhijian@fujitsu.com>
    RDMA/rxe: Fix mr->map double free

Xiongfeng Wang <wangxiongfeng2@huawei.com>
    crypto: hisilicon/qm - add missing pci_dev_put() in q_num_set()

Herbert Xu <herbert@gondor.apana.org.au>
    crypto: cryptd - Use request context instead of stack for sub-request

Gaosheng Cui <cuigaosheng1@huawei.com>
    crypto: ccree - Remove debugfs when platform_driver_register failed

Harshit Mogalapalli <harshit.m.mogalapalli@oracle.com>
    scsi: scsi_debug: Fix a warning in resp_write_scat()

Mustafa Ismail <mustafa.ismail@intel.com>
    RDMA/irdma: Do not request 2-level PBLEs for CQ alloc

Mustafa Ismail <mustafa.ismail@intel.com>
    RDMA/irdma: Fix RQ completion opcode

Mustafa Ismail <mustafa.ismail@intel.com>
    RDMA/irdma: Fix inline for multiple SGE's

Bernard Metzler <bmt@zurich.ibm.com>
    RDMA/siw: Set defined status for work completion with undefined status

Mark Zhang <markzhang@nvidia.com>
    RDMA/nldev: Return "-EAGAIN" if the cm_id isn't from expected port

Mark Zhang <markzhang@nvidia.com>
    RDMA/core: Make sure "ib_port" is valid when access sysfs node

Mark Zhang <markzhang@nvidia.com>
    RDMA/restrack: Release MR restrack when delete

Sascha Hauer <s.hauer@pengutronix.de>
    PCI: imx6: Initialize PHY before deasserting core reset

Nirmal Patel <nirmal.patel@linux.intel.com>
    PCI: vmd: Disable MSI remapping after suspend

Leonid Ravich <lravich@gmail.com>
    IB/mad: Don't call to function that might sleep while in atomic context

Bernard Metzler <bmt@zurich.ibm.com>
    RDMA/siw: Fix immediate work request flush to completion queue

Bart Van Assche <bvanassche@acm.org>
    scsi: qla2xxx: Fix set-but-not-used variable warnings

Shiraz Saleem <shiraz.saleem@intel.com>
    RDMA/irdma: Report the correct link speed

Chao Yu <chao@kernel.org>
    f2fs: fix to destroy sbi->post_read_wq in error path of f2fs_fill_super()

Mukesh Ojha <quic_mojha@quicinc.com>
    f2fs: fix the assign logic of iocb

Jaegeuk Kim <jaegeuk@kernel.org>
    f2fs: allow to set compression for inlined file

Dongdong Zhang <zhangdongdong1@oppo.com>
    f2fs: fix normal discard process

Chao Yu <chao@kernel.org>
    f2fs: fix to invalidate dcc->f2fs_issue_discard in error path

Kees Cook <keescook@chromium.org>
    fortify: Do not cast to "unsigned char"

Kees Cook <keescook@chromium.org>
    fortify: Use SIZE_MAX instead of (size_t)-1

Xiu Jianfeng <xiujianfeng@huawei.com>
    apparmor: Fix memleak in alloc_ns()

Corentin Labbe <clabbe@baylibre.com>
    crypto: rockchip - rework by using crypto_engine

Corentin Labbe <clabbe@baylibre.com>
    crypto: rockchip - remove non-aligned handling

Corentin Labbe <clabbe@baylibre.com>
    crypto: rockchip - better handle cipher key

Corentin Labbe <clabbe@baylibre.com>
    crypto: rockchip - add fallback for ahash

Corentin Labbe <clabbe@baylibre.com>
    crypto: rockchip - add fallback for cipher

Corentin Labbe <clabbe@baylibre.com>
    crypto: rockchip - do not store mode globally

Corentin Labbe <clabbe@baylibre.com>
    crypto: rockchip - do not do custom power management

Zhang Qilong <zhangqilong3@huawei.com>
    f2fs: Fix the race condition of resize flag between resizefs

Kunihiko Hayashi <hayashi.kunihiko@socionext.com>
    PCI: pci-epf-test: Register notifier if only core_init_notifier is enabled

Leon Romanovsky <leon@kernel.org>
    RDMA/core: Fix order of nldev_exit call

Vidya Sagar <vidyas@nvidia.com>
    PCI: dwc: Fix n_fts[] array overrun

Xiu Jianfeng <xiujianfeng@huawei.com>
    apparmor: Use pointer to struct aa_label for lbs_cred

Bart Van Assche <bvanassche@acm.org>
    scsi: core: Fix a race between scsi_done() and scsi_timeout()

Robert Elliott <elliott@hpe.com>
    crypto: tcrypt - fix return value for multiple subtests

Natalia Petrova <n.petrova@fintech.ru>
    crypto: nitrox - avoid double free on error path in nitrox_sriov_init()

Corentin Labbe <clabbe@baylibre.com>
    crypto: sun8i-ss - use dma_addr instead u32

Weili Qian <qianweili@huawei.com>
    crypto: hisilicon/qm - re-enable communicate interrupt before notifying PF

Weili Qian <qianweili@huawei.com>
    crypto: hisilicon/qm - get hardware features from hardware registers

Weili Qian <qianweili@huawei.com>
    crypto: hisilicon/qm - fix missing destroy qp_idr

John Johansen <john.johansen@canonical.com>
    apparmor: Fix regression in stacking due to label flags

John Johansen <john.johansen@canonical.com>
    apparmor: Fix abi check to include v8 abi

John Johansen <john.johansen@canonical.com>
    apparmor: fix lockdep warning when removing a namespace

Gaosheng Cui <cuigaosheng1@huawei.com>
    apparmor: fix a memleak in multi_transaction_new()

Vladimir Oltean <vladimir.oltean@nxp.com>
    net: dsa: tag_8021q: avoid leaking ctx on dsa_tag_8021q_register() error path

Bartosz Staszewski <bartoszx.staszewski@intel.com>
    i40e: Fix the inability to attach XDP program on downed interface

Piergiorgio Beruto <piergiorgio.beruto@gmail.com>
    stmmac: fix potential division by 0

Yang Yingliang <yangyingliang@huawei.com>
    Bluetooth: RFCOMM: don't call kfree_skb() under spin_lock_irqsave()

Yang Yingliang <yangyingliang@huawei.com>
    Bluetooth: hci_core: don't call kfree_skb() under spin_lock_irqsave()

Yang Yingliang <yangyingliang@huawei.com>
    Bluetooth: hci_bcsp: don't call kfree_skb() under spin_lock_irqsave()

Yang Yingliang <yangyingliang@huawei.com>
    Bluetooth: hci_h5: don't call kfree_skb() under spin_lock_irqsave()

Yang Yingliang <yangyingliang@huawei.com>
    Bluetooth: hci_ll: don't call kfree_skb() under spin_lock_irqsave()

Yang Yingliang <yangyingliang@huawei.com>
    Bluetooth: hci_qca: don't call kfree_skb() under spin_lock_irqsave()

Yang Yingliang <yangyingliang@huawei.com>
    Bluetooth: btusb: don't call kfree_skb() under spin_lock_irqsave()

Wang ShaoBo <bobo.shaobowang@huawei.com>
    Bluetooth: btintel: Fix missing free skb in btintel_setup_combined()

Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
    Bluetooth: hci_conn: Fix crash on hci_create_cis_sync

Christophe JAILLET <christophe.jaillet@wanadoo.fr>
    Bluetooth: Fix EALREADY and ELOOP cases in bt_status()

Inga Stotland <inga.stotland@intel.com>
    Bluetooth: MGMT: Fix error report for ADD_EXT_ADV_PARAMS

Yang Yingliang <yangyingliang@huawei.com>
    Bluetooth: hci_core: fix error handling in hci_register_dev()

Firo Yang <firo.yang@suse.com>
    sctp: sysctl: make extra pointers netns aware

Eric Pilmore <epilmore@gigaio.com>
    ntb_netdev: Use dev_kfree_skb_any() in interrupt context

Jerry Ray <jerry.ray@microchip.com>
    net: lan9303: Fix read error execution path

Roger Quadros <rogerq@kernel.org>
    net: ethernet: ti: am65-cpsw: Fix PM runtime leakage in am65_cpsw_nuss_ndo_slave_open()

Markus Schneider-Pargmann <msp@baylibre.com>
    can: tcan4x5x: Fix use of register error status mask

Vivek Yadav <vivek.2311@samsung.com>
    can: m_can: Call the RAM init directly from m_can_chip_config

Markus Schneider-Pargmann <msp@baylibre.com>
    can: tcan4x5x: Remove invalid write in clear_interrupts

Tom Lendacky <thomas.lendacky@amd.com>
    net: amd-xgbe: Check only the minimum speed for active/passive cables

Tom Lendacky <thomas.lendacky@amd.com>
    net: amd-xgbe: Fix logic around active and passive cables

Yang Yingliang <yangyingliang@huawei.com>
    af_unix: call proto_unregister() in the error path in af_unix_init()

Richard Gobert <richardbgobert@gmail.com>
    net: setsockopt: fix IPV6_UNICAST_IF option for connected sockets

Yang Yingliang <yangyingliang@huawei.com>
    net: amd: lance: don't call dev_kfree_skb() under spin_lock_irqsave()

Yang Yingliang <yangyingliang@huawei.com>
    hamradio: don't call dev_kfree_skb() under spin_lock_irqsave()

Yang Yingliang <yangyingliang@huawei.com>
    net: ethernet: dnet: don't call dev_kfree_skb() under spin_lock_irqsave()

Yang Yingliang <yangyingliang@huawei.com>
    net: emaclite: don't call dev_kfree_skb() under spin_lock_irqsave()

Yang Yingliang <yangyingliang@huawei.com>
    net: apple: bmac: don't call dev_kfree_skb() under spin_lock_irqsave()

Yang Yingliang <yangyingliang@huawei.com>
    net: apple: mace: don't call dev_kfree_skb() under spin_lock_irqsave()

Hangbin Liu <liuhangbin@gmail.com>
    net/tunnel: wait until all sk_user_data reader finish before releasing the sock

Li Zetao <lizetao1@huawei.com>
    net: farsync: Fix kmemleak when rmmods farsync

Yang Yingliang <yangyingliang@huawei.com>
    ethernet: s2io: don't call dev_kfree_skb() under spin_lock_irqsave()

ruanjinjie <ruanjinjie@huawei.com>
    of: overlay: fix null pointer dereferencing in find_dup_cset_node_entry() and find_dup_cset_prop()

Julian Anastasov <ja@ssi.bg>
    ipvs: use u64_stats_t for the per-cpu counters

Thomas Gleixner <tglx@linutronix.de>
    net: Remove the obsolte u64_stats_fetch_*_irq() users (net).

Yuan Can <yuancan@huawei.com>
    drivers: net: qlcnic: Fix potential memory leak in qlcnic_sriov_init()

Gaosheng Cui <cuigaosheng1@huawei.com>
    net: stmmac: fix possible memory leak in stmmac_dvr_probe()

Zhang Changzhong <zhangchangzhong@huawei.com>
    net: stmmac: selftests: fix potential memleak in stmmac_test_arpoffload()

Yongqiang Liu <liuyongqiang13@huawei.com>
    net: defxx: Fix missing err handling in dfx_init()

Artem Chernyshev <artem.chernyshev@red-soft.ru>
    net: vmw_vsock: vmci: Check memcpy_from_msg()

Xiu Jianfeng <xiujianfeng@huawei.com>
    clk: socfpga: Fix memory leak in socfpga_gate_init()

Björn Töpel <bjorn@rivosinc.com>
    bpf: Do not zero-extend kfunc return values

Yang Jihong <yangjihong1@huawei.com>
    blktrace: Fix output non-blktrace event when blk_classic option enabled

Wang Yufen <wangyufen@huawei.com>
    wifi: brcmfmac: Fix error return code in brcmf_sdio_download_firmware()

Bitterblue Smith <rtl8821cerfe2@gmail.com>
    wifi: rtl8xxxu: Fix the channel width reporting

Bitterblue Smith <rtl8821cerfe2@gmail.com>
    wifi: rtl8xxxu: Add __packed to struct rtl8723bu_c2h

Kris Bahnsen <kris@embeddedTS.com>
    spi: spi-gpio: Don't set MOSI as an input if not 3WIRE mode

Xiu Jianfeng <xiujianfeng@huawei.com>
    clk: samsung: Fix memory leak in _samsung_clk_register_pll()

Geert Uytterhoeven <geert+renesas@glider.be>
    media: staging: stkwebcam: Restore MEDIA_{USB,CAMERA}_SUPPORT dependencies

Jiasheng Jiang <jiasheng@iscas.ac.cn>
    media: coda: Add check for kmalloc

Jiasheng Jiang <jiasheng@iscas.ac.cn>
    media: coda: Add check for dcoda_iram_alloc

Liang He <windhl@126.com>
    media: c8sectpfe: Add of_node_put() when breaking out of loop

Yuan Can <yuancan@huawei.com>
    regulator: qcom-labibb: Fix missing of_node_put() in qcom_labibb_regulator_probe()

Zhen Lei <thunder.leizhen@huawei.com>
    mmc: core: Normalize the error handling branch in sd_read_ext_regs()

Jiasheng Jiang <jiasheng@iscas.ac.cn>
    memstick/ms_block: Add check for alloc_ordered_workqueue

Wolfram Sang <wsa+renesas@sang-engineering.com>
    mmc: renesas_sdhi: alway populate SCC pointer

Yang Yingliang <yangyingliang@huawei.com>
    mmc: mmci: fix return value check of mmc_add_host()

Yang Yingliang <yangyingliang@huawei.com>
    mmc: wbsd: fix return value check of mmc_add_host()

Yang Yingliang <yangyingliang@huawei.com>
    mmc: via-sdmmc: fix return value check of mmc_add_host()

Yang Yingliang <yangyingliang@huawei.com>
    mmc: meson-gx: fix return value check of mmc_add_host()

Yang Yingliang <yangyingliang@huawei.com>
    mmc: omap_hsmmc: fix return value check of mmc_add_host()

Yang Yingliang <yangyingliang@huawei.com>
    mmc: atmel-mci: fix return value check of mmc_add_host()

Gabriel Somlo <gsomlo@gmail.com>
    mmc: litex_mmc: ensure `host->irq == 0` if polling

Yang Yingliang <yangyingliang@huawei.com>
    mmc: wmt-sdmmc: fix return value check of mmc_add_host()

Yang Yingliang <yangyingliang@huawei.com>
    mmc: vub300: fix return value check of mmc_add_host()

Yang Yingliang <yangyingliang@huawei.com>
    mmc: toshsd: fix return value check of mmc_add_host()

Yang Yingliang <yangyingliang@huawei.com>
    mmc: rtsx_usb_sdmmc: fix return value check of mmc_add_host()

Yang Yingliang <yangyingliang@huawei.com>
    mmc: rtsx_pci: fix return value check of mmc_add_host()

Yang Yingliang <yangyingliang@huawei.com>
    mmc: pxamci: fix return value check of mmc_add_host()

Yang Yingliang <yangyingliang@huawei.com>
    mmc: mxcmmc: fix return value check of mmc_add_host()

Yang Yingliang <yangyingliang@huawei.com>
    mmc: moxart: fix return value check of mmc_add_host()

Yang Yingliang <yangyingliang@huawei.com>
    mmc: alcor: fix return value check of mmc_add_host()

Miaoqian Lin <linmq006@gmail.com>
    bpftool: Fix memory leak in do_build_table_cb

Pu Lehui <pulehui@huawei.com>
    riscv, bpf: Emit fixed-length instructions for BPF_PSEUDO_FUNC

Trond Myklebust <trond.myklebust@hammerspace.com>
    NFSv4.x: Fail client initialisation if state manager thread can't run

Anna Schumaker <Anna.Schumaker@Netapp.com>
    NFS: Allow very small rsize & wsize again

Anna Schumaker <Anna.Schumaker@Netapp.com>
    NFSv4.2: Set the correct size scratch buffer for decoding READ_PLUS

Wang ShaoBo <bobo.shaobowang@huawei.com>
    SUNRPC: Fix missing release socket in rpc_sockname()

Zhang Xiaoxu <zhangxiaoxu5@huawei.com>
    xprtrdma: Fix regbuf data not freed in rpcrdma_req_create()

Gaosheng Cui <cuigaosheng1@huawei.com>
    pinctrl: thunderbay: fix possible memory leak in thunderbay_build_functions()

Gaosheng Cui <cuigaosheng1@huawei.com>
    ALSA: mts64: fix possible null-ptr-defer in snd_mts64_interrupt

Guoniu.zhou <guoniu.zhou@nxp.com>
    media: ov5640: set correct default link frequency

Liu Shixin <liushixin2@huawei.com>
    media: saa7164: fix missing pci_disable_device()

Takashi Iwai <tiwai@suse.de>
    ALSA: pcm: Set missing stop_operating flag at undoing trigger start

Eric Dumazet <edumazet@google.com>
    bpf, sockmap: fix race in sock_map_free()

Martin Blumenstingl <martin.blumenstingl@googlemail.com>
    hwmon: (jc42) Restore the min/max/critical temperatures on resume

Martin Blumenstingl <martin.blumenstingl@googlemail.com>
    hwmon: (jc42) Convert register access and caching to regmap/regcache

Yang Yingliang <yangyingliang@huawei.com>
    regulator: core: fix resource leak in regulator_register()

Chen Zhongjin <chenzhongjin@huawei.com>
    configfs: fix possible memory leak in configfs_create_dir()

Sebastian Andrzej Siewior <bigeasy@linutronix.de>
    hsr: Synchronize sequence number updates.

Sebastian Andrzej Siewior <bigeasy@linutronix.de>
    hsr: Synchronize sending frames to have always incremented outgoing seq nr.

Sebastian Andrzej Siewior <bigeasy@linutronix.de>
    hsr: Disable netpoll.

Sebastian Andrzej Siewior <bigeasy@linutronix.de>
    hsr: Avoid double remove of a node.

Sebastian Andrzej Siewior <bigeasy@linutronix.de>
    hsr: Add a rcu-read lock to hsr_forward_skb().

Sebastian Andrzej Siewior <bigeasy@linutronix.de>
    Revert "net: hsr: use hlist_head instead of list_head for mac addresses"

Christian Marangi <ansuelsmth@gmail.com>
    clk: qcom: clk-krait: fix wrong div2 functions

Douglas Anderson <dianders@chromium.org>
    clk: qcom: lpass-sc7180: Fix pm_runtime usage

Douglas Anderson <dianders@chromium.org>
    clk: qcom: lpass-sc7280: Fix pm_runtime usage

Taniya Das <quic_tdas@quicinc.com>
    clk: qcom: lpass: Add support for resets & external mclk for SC7280

Taniya Das <quic_tdas@quicinc.com>
    clk: qcom: lpass: Handle the regmap overlap of lpasscc and lpass_aon

Taniya Das <quic_tdas@quicinc.com>
    dt-bindings: clock: Add support for external MCLKs for LPASS on SC7280

Taniya Das <quic_tdas@quicinc.com>
    dt-bindings: clock: Add resets for LPASS audio clock controller for SC7280

Yang Yingliang <yangyingliang@huawei.com>
    regulator: core: fix module refcount leak in set_supply()

Xiongfeng Wang <wangxiongfeng2@huawei.com>
    mt76: mt7915: Fix PCI device refcount leak in mt7915_pci_init_hif2()

Deren Wu <deren.wu@mediatek.com>
    wifi: mt76: fix coverity overrun-call in mt76_get_txpower()

Nicolas Cavallari <nicolas.cavallari@green-communications.fr>
    wifi: mt76: mt7915: Fix chainmask calculation on mt7915 DBDC

Shayne Chen <shayne.chen@mediatek.com>
    wifi: mt76: mt7915: rework eeprom tx paths and streams init

Lorenzo Bianconi <lorenzo@kernel.org>
    wifi: mt76: mt7921: fix reporting of TX AGGR histogram

Lorenzo Bianconi <lorenzo@kernel.org>
    wifi: mt76: mt7915: fix reporting of TX AGGR histogram

Ryder Lee <ryder.lee@mediatek.com>
    wifi: mt76: mt7915: fix mt7915_mac_set_timing()

Sean Wang <sean.wang@mediatek.com>
    wifi: mt76: mt7921: fix antenna signal are way off in monitor mode

Chen Zhongjin <chenzhongjin@huawei.com>
    wifi: cfg80211: Fix not unregister reg_pdev when load_builtin_regdb_keys() fails

Íñigo Huguet <ihuguet@redhat.com>
    wifi: mac80211: fix maybe-unused warning

Zhengchao Shao <shaozhengchao@huawei.com>
    wifi: mac80211: fix memory leak in ieee80211_if_add()

Yuan Can <yuancan@huawei.com>
    wifi: nl80211: Add checks for nla_nest_start() in nl80211_send_iface()

Alexander Sverdlin <alexander.sverdlin@siemens.com>
    spi: spidev: mask SPI_CS_HIGH in SPI_IOC_RD_MODE

Dan Carpenter <error27@gmail.com>
    bonding: uninitialized variable in bond_miimon_inspect()

Pengcheng Yang <yangpc@wangsu.com>
    bpf, sockmap: Fix data loss caused by using apply_bytes on ingress redirect

Pengcheng Yang <yangpc@wangsu.com>
    bpf, sockmap: Fix missing BPF_F_INGRESS flag when using apply_bytes

Pengcheng Yang <yangpc@wangsu.com>
    bpf, sockmap: Fix repeated calls to sock_put() when msg has more_data

Randy Dunlap <rdunlap@infradead.org>
    Input: wistron_btns - disable on UML

Florian Westphal <fw@strlen.de>
    netfilter: conntrack: set icmpv6 redirects as RELATED

Xiu Jianfeng <xiujianfeng@huawei.com>
    clk: visconti: Fix memory leak in visconti_register_pll()

Zhang Qilong <zhangqilong3@huawei.com>
    ASoC: pcm512x: Fix PM disable depth imbalance in pcm512x_probe

Xia Fukun <xiafukun@huawei.com>
    drm/i915/bios: fix a memory leak in generate_lfp_data_ptrs

Konstantin Meskhidze <konstantin.meskhidze@huawei.com>
    drm/amdkfd: Fix memory leakage

Xiongfeng Wang <wangxiongfeng2@huawei.com>
    drm/amdgpu: Fix PCI device refcount leak in amdgpu_atrm_get_bios()

Xiongfeng Wang <wangxiongfeng2@huawei.com>
    drm/radeon: Fix PCI device refcount leak in radeon_atrm_get_bios()

Veerabadhran Gopalakrishnan <veerabadhran.gopalakrishnan@amd.com>
    amdgpu/nv.c: Corrected typo in the video capabilities resolution

Guchun Chen <guchun.chen@amd.com>
    drm/amd/pm/smu11: BACO is supported when it's in BACO state

Daniel Golle <daniel@makrotopia.org>
    clk: mediatek: fix dependency of MT7986 ADC clocks

Ricardo Ribalda <ribalda@chromium.org>
    ASoC: mediatek: mt8173: Enable IRQ when pdata is ready

zhichao.liu <zhichao.liu@mediatek.com>
    spi: mt65xx: Add dma max segment size declaration

Ben Greear <greearb@candelatech.com>
    wifi: iwlwifi: mvm: fix double free on tx path.

Bitterblue Smith <rtl8821cerfe2@gmail.com>
    wifi: rtl8xxxu: Fix use after rcu_read_unlock in rtl8xxxu_bss_info_changed

Ziyang Xuan <william.xuanziyang@huawei.com>
    wifi: plfxlc: fix potential memory leak in __lf_x_usb_enable_rx()

Liu Shixin <liushixin2@huawei.com>
    ALSA: asihpi: fix missing pci_disable_device()

Trond Myklebust <trond.myklebust@hammerspace.com>
    NFS: Fix an Oops in nfs_d_automount()

Trond Myklebust <trond.myklebust@hammerspace.com>
    NFSv4: Fix a deadlock between nfs4_open_recover_helper() and delegreturn

Trond Myklebust <trond.myklebust@hammerspace.com>
    NFSv4: Fix a credential leak in _nfs4_discover_trunking()

Trond Myklebust <trond.myklebust@hammerspace.com>
    NFSv4.2: Fix initialisation of struct nfs4_label

Trond Myklebust <trond.myklebust@hammerspace.com>
    NFSv4.2: Fix a memory stomp in decode_attr_security_label

Trond Myklebust <trond.myklebust@hammerspace.com>
    NFSv4.2: Always decode the security label

Trond Myklebust <trond.myklebust@hammerspace.com>
    NFSv4.2: Clear FATTR4_WORD2_SECURITY_LABEL when done decoding

Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
    drm/msm/mdp5: fix reading hw revision on db410c platform

Jiasheng Jiang <jiasheng@iscas.ac.cn>
    ASoC: mediatek: mtk-btcvsd: Add checks for write and read of mtk_btcvsd_snd

Dmitry Torokhov <dmitry.torokhov@gmail.com>
    ASoC: dt-bindings: wcd9335: fix reset line polarity in example

Zhang Zekun <zhangzekun11@huawei.com>
    drm/tegra: Add missing clk_disable_unprepare() in tegra_dc_probe()

Aakarsh Jain <aakarsh.jain@samsung.com>
    media: s5p-mfc: Add variant data for MFC v7 hardware for Exynos 3250 SoC

Yunfei Dong <yunfei.dong@mediatek.com>
    media: mediatek: vcodec: Core thread depends on core_list

Yunfei Dong <yunfei.dong@mediatek.com>
    media: mediatek: vcodec: Setting lat buf to lat_list when lat decode error

Yunfei Dong <yunfei.dong@mediatek.com>
    media: mediatek: vcodec: Fix h264 set lat buffer error

Yunfei Dong <yunfei.dong@mediatek.com>
    media: mediatek: vcodec: Fix getting NULL pointer for dst buffer

Ming Qian <ming.qian@nxp.com>
    media: amphion: lock and check m2m_ctx in event handler

Ming Qian <ming.qian@nxp.com>
    media: amphion: cancel vpu before release instance

Ming Qian <ming.qian@nxp.com>
    media: amphion: try to wakeup vpu core to avoid failure

Paul Kocialkowski <paul.kocialkowski@bootlin.com>
    media: sun8i-a83t-mipi-csi2: Register async subdev with no sensor attached

Paul Kocialkowski <paul.kocialkowski@bootlin.com>
    media: sun6i-mipi-csi2: Register async subdev with no sensor attached

Paul Kocialkowski <paul.kocialkowski@bootlin.com>
    media: sun8i-a83t-mipi-csi2: Require both pads to be connected for streaming

Paul Kocialkowski <paul.kocialkowski@bootlin.com>
    media: sun6i-mipi-csi2: Require both pads to be connected for streaming

Juergen Gross <jgross@suse.com>
    x86/boot: Skip realmode init code when running as Xen PV guest

Baisong Zhong <zhongbaisong@huawei.com>
    media: dvb-usb: az6027: fix null-ptr-deref in az6027_i2c_xfer()

Chen Zhongjin <chenzhongjin@huawei.com>
    media: dvb-core: Fix ignored return value in dvb_register_frontend()

ZhangPeng <zhangpeng362@huawei.com>
    pinctrl: pinconf-generic: add missing of_node_put()

Dario Binacchi <dario.binacchi@amarulasolutions.com>
    clk: imx8mn: fix imx8mn_enet_phy_sels clocks list

Dario Binacchi <dario.binacchi@amarulasolutions.com>
    clk: imx8mn: fix imx8mn_sai2_sels clocks list

Dario Binacchi <dario.binacchi@amarulasolutions.com>
    clk: imx: rename video_pll1 to video_pll

Dario Binacchi <dario.binacchi@amarulasolutions.com>
    clk: imx: replace osc_hdmi with dummy

Dario Binacchi <dario.binacchi@amarulasolutions.com>
    clk: imx8mn: rename vpu_pll to m7_alt_pll

Marek Vasut <marex@denx.de>
    media: mt9p031: Drop bogus v4l2_subdev_get_try_crop() call from mt9p031_init_cfg()

Laurent Pinchart <laurent.pinchart@ideasonboard.com>
    media: imx: imx7-media-csi: Clear BIT_MIPI_DOUBLE_CMPNT for <16b formats

Gautam Menghani <gautammenghani201@gmail.com>
    media: imon: fix a race condition in send_packet()

Chen Zhongjin <chenzhongjin@huawei.com>
    media: vimc: Fix wrong function called when vimc_init() fails

Yuan Can <yuancan@huawei.com>
    ASoC: qcom: Add checks for devm_kcalloc

Wang ShaoBo <bobo.shaobowang@huawei.com>
    drbd: destroy workqueue when drbd device was freed

Wang ShaoBo <bobo.shaobowang@huawei.com>
    drbd: remove call to memset before free device/resource/connection

Zheng Yongjun <zhengyongjun3@huawei.com>
    mtd: maps: pxa2xx-flash: fix memory leak in probe

Shang XiaoJing <shangxiaojing@huawei.com>
    mtd: core: Fix refcount error in del_mtd_device()

Jonathan Toppins <jtoppins@redhat.com>
    bonding: fix link recovery in mode 2 when updelay is nonzero

Stanislav Fomichev <sdf@google.com>
    selftests/bpf: Mount debugfs in setns_by_fd

Stanislav Fomichev <sdf@google.com>
    selftests/bpf: Make sure zero-len skbs aren't redirectable

Jani Nikula <jani.nikula@intel.com>
    drm/i915/guc: make default_lists const data

Yang Yingliang <yangyingliang@huawei.com>
    drm/amdgpu: fix pci device refcount leak

Xiu Jianfeng <xiujianfeng@huawei.com>
    clk: rockchip: Fix memory leak in rockchip_clk_register_pll()

Wang ShaoBo <bobo.shaobowang@huawei.com>
    regulator: core: use kfree_const() to free space conditionally

Baisong Zhong <zhongbaisong@huawei.com>
    ALSA: seq: fix undefined behavior in bit shift for SNDRV_SEQ_FILTER_USE_EVENT

Baisong Zhong <zhongbaisong@huawei.com>
    ALSA: pcm: fix undefined behavior in bit shift for SNDRV_PCM_RATE_KNOT

Cezary Rojewski <cezary.rojewski@intel.com>
    ASoC: Intel: avs: Lock substream before snd_pcm_stop()

Zong-Zhe Yang <kevin_yang@realtek.com>
    wifi: rtw89: fix physts IE page check

ZhangPeng <zhangpeng362@huawei.com>
    pinctrl: k210: call of_node_put()

Giulio Benetti <giulio.benetti@benettiengineering.com>
    clk: imx: imxrt1050: fix IMXRT1050_CLK_LCDIF_APB offsets

Marcus Folkesson <marcus.folkesson@gmail.com>
    HID: hid-sensor-custom: set fixed size for custom attributes

Stanislav Fomichev <sdf@google.com>
    bpf: Move skb->len == 0 checks into __bpf_redirect

Peng Fan <peng.fan@nxp.com>
    clk: imx93: correct enet clock

Peng Fan <peng.fan@nxp.com>
    clk: imx93: unmap anatop base in error handling path

Dmitry Torokhov <dmitry.torokhov@gmail.com>
    HID: i2c: let RMI devices decide what constitutes wakeup event

Haibo Chen <haibo.chen@nxp.com>
    clk: imx93: correct the flexspi1 clock setting

Allen-KH Cheng <allen-kh.cheng@mediatek.com>
    mtd: spi-nor: Fix the number of bytes for the dummy cycles

Michael Walle <michael@walle.cc>
    mtd: spi-nor: hide jedec_id sysfs attribute if not present

Kuniyuki Iwashima <kuniyu@amazon.com>
    net: Return errno in sk->sk_prot->get_port().

Kuniyuki Iwashima <kuniyu@amazon.com>
    udp: Clean up some functions.

Lorenzo Bianconi <lorenzo@kernel.org>
    net: ethernet: mtk_eth_soc: fix RSTCTRL_PPE{0,1} definitions

Christoph Hellwig <hch@lst.de>
    media: videobuf-dma-contig: use dma_mmap_coherent

Yuan Can <yuancan@huawei.com>
    media: amphion: Fix error handling in vpu_driver_init()

Yuan Can <yuancan@huawei.com>
    media: platform: exynos4-is: Fix error handling in fimc_md_init()

Yang Yingliang <yangyingliang@huawei.com>
    media: solo6x10: fix possible memory leak in solo_sysfs_init()

Chen Zhongjin <chenzhongjin@huawei.com>
    media: vidtv: Fix use-after-free in vidtv_bridge_dvb_init()

Ming Qian <ming.qian@nxp.com>
    media: amphion: apply vb2_queue_error instead of setting manually

Ming Qian <ming.qian@nxp.com>
    media: amphion: add lock around vdec_g_fmt

Lorenzo Bianconi <lorenzo@kernel.org>
    net: ethernet: mtk_eth_soc: do not overwrite mtu configuration running reset routine

Douglas Anderson <dianders@chromium.org>
    Input: elants_i2c - properly handle the reset GPIO when power is off

Hui Tang <tanghui20@huawei.com>
    mtd: lpddr2_nvm: Fix possible null-ptr-deref

Rob Clark <robdclark@chromium.org>
    drm/msm/a6xx: Fix speed-bin detection vs probe-defer

Xiu Jianfeng <xiujianfeng@huawei.com>
    wifi: ath10k: Fix return value in ath10k_pci_init()

Wang Yufen <wangyufen@huawei.com>
    selftests/bpf: fix memory leak of lsm_cgroup

Christoph Hellwig <hch@lst.de>
    dm: track per-add_disk holder relations in DM

Yu Kuai <yukuai3@huawei.com>
    dm: make sure create and remove dm device won't race with open and close table

Christoph Hellwig <hch@lst.de>
    dm: cleanup close_table_device

Christoph Hellwig <hch@lst.de>
    dm: cleanup open_table_device

Christoph Hellwig <hch@lst.de>
    block: clear ->slave_dir when dropping the main slave_dir reference

Xiu Jianfeng <xiujianfeng@huawei.com>
    ima: Fix misuse of dereference of pointer in template_desc_init_fields()

GUO Zihua <guozihua@huawei.com>
    integrity: Fix memory leakage in keyring allocation error path

Brian Starkey <brian.starkey@arm.com>
    drm/fourcc: Fix vsub/hsub for Q410 and Q401

Konrad Dybcio <konrad.dybcio@linaro.org>
    regulator: qcom-rpmh: Fix PMR735a S3 regulator spec

Christophe JAILLET <christophe.jaillet@wanadoo.fr>
    wifi: rtw89: Fix some error handling path in rtw89_core_sta_assoc()

Joel Granados <j.granados@samsung.com>
    nvme: return err on nvme_init_non_mdts_limits fail

Dan Carpenter <error27@gmail.com>
    amdgpu/pm: prevent array underflow in vega20_odn_edit_dpm_table()

Yang Yingliang <yangyingliang@huawei.com>
    regulator: core: fix unbalanced of node refcount in regulator_dev_lookup()

Christoph Hellwig <hch@lst.de>
    nvmet: only allocate a single slab for bvecs

Zeng Heng <zengheng4@huawei.com>
    ASoC: pxa: fix null-pointer dereference in filter()

Xinlei Lee <xinlei.lee@mediatek.com>
    drm/mediatek: Modify dpi power on/off sequence.

Yang Jihong <yangjihong1@huawei.com>
    selftests/bpf: Fix xdp_synproxy compilation failure in 32-bit arch

Randy Dunlap <rdunlap@infradead.org>
    ASoC: codecs: wsa883x: use correct header file

Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
    ASoC: codecs: wsa883x: Use proper shutdown GPIO polarity

Miaoqian Lin <linmq006@gmail.com>
    module: Fix NULL vs IS_ERR checking for module_get_next_page

Johannes Berg <johannes.berg@intel.com>
    wifi: iwlwifi: mei: fix potential NULL-ptr deref after clone

Avraham Stern <avraham.stern@intel.com>
    wifi: iwlwifi: mei: avoid blocking sap messages handling due to rtnl lock

Emmanuel Grumbach <emmanuel.grumbach@intel.com>
    wifi: iwlwifi: mei: fix tx DHCP packet for devices with new Tx API

Emmanuel Grumbach <emmanuel.grumbach@intel.com>
    wifi: iwlwifi: mei: don't send SAP commands if AMT is disabled

Avraham Stern <avraham.stern@intel.com>
    wifi: iwlwifi: mei: make sure ownership confirmed message is sent

Sam Shih <sam.shih@mediatek.com>
    pinctrl: mediatek: fix the pinconf register offset of some pins

Frank Wunderlich <frank-w@public-files.de>
    dt-bindings: pinctrl: update uart/mmc bindings for MT7986 SoC

Hanjun Guo <guohanjun@huawei.com>
    drm/radeon: Add the missed acpi_put_table() to fix memory leak

Khazhismel Kumykov <khazhy@chromium.org>
    bfq: fix waker_bfqq inconsistency crash

Christoph Böhmwalder <christoph.boehmwalder@linbit.com>
    drbd: use blk_queue_max_discard_sectors helper

Yassine Oudjana <y.oudjana@protonmail.com>
    regmap-irq: Use the new num_config_regs property in regmap_add_irq_chip_fwnode

Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
    drm: rcar-du: Drop leftovers dependencies from Kconfig

Ping-Ke Shih <pkshih@realtek.com>
    wifi: rtw89: use u32_encode_bits() to fill MAC quota value

Marek Vasut <marex@denx.de>
    drm: lcdif: Set and enable FIFO Panic threshold

David Howells <dhowells@redhat.com>
    rxrpc: Fix ack.bufferSize to be 0 when generating an ack

David Howells <dhowells@redhat.com>
    net, proc: Provide PROC_FS=n fallback for proc_create_net_single_write()

Cole Robinson <crobinso@redhat.com>
    virt/sev-guest: Add a MODULE_ALIAS

Wolfram Sang <wsa+renesas@sang-engineering.com>
    clk: renesas: r8a779f0: Fix SCIF parent clocks

Wolfram Sang <wsa+renesas@sang-engineering.com>
    clk: renesas: r8a779f0: Fix HSCIF parent clocks

Vladimir Zapolskiy <vladimir.zapolskiy@linaro.org>
    media: camss: Do not attach an already attached power domain on MSM8916 platform

Vladimir Zapolskiy <vladimir.zapolskiy@linaro.org>
    media: camss: Clean up received buffers on failed start of streaming

Marek Vasut <marex@denx.de>
    wifi: rsi: Fix handling of 802.3 EAPOL frames sent via control port

Randy Dunlap <rdunlap@infradead.org>
    Input: joystick - fix Kconfig warning for JOYSTICK_ADC

Gaosheng Cui <cuigaosheng1@huawei.com>
    mtd: core: fix possible resource leak in init_mtd()

Zhang Xiaoxu <zhangxiaoxu5@huawei.com>
    mtd: Fix device name leak when register device failed in add_mtd_device()

Manivannan Sadhasivam <mani@kernel.org>
    clk: qcom: gcc-sm8250: Use retention mode for USB GDSCs

Konrad Dybcio <konrad.dybcio@somainline.org>
    clk: qcom: dispcc-sm6350: Add CLK_OPS_PARENT_ENABLE to pixel&byte src

Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
    clk: qcom: gcc-ipq806x: use parent_data for the last remaining entry

Andrii Nakryiko <andrii@kernel.org>
    bpf: propagate precision across all frames, not just the last one

Andrii Nakryiko <andrii@kernel.org>
    bpf: propagate precision in ALU/ALU64 operations

Yang Yingliang <yangyingliang@huawei.com>
    media: platform: exynos4-is: fix return value check in fimc_md_probe()

Liu Shixin <liushixin2@huawei.com>
    media: vivid: fix compose size exceed boundary

Andrzej Pietrasiewicz <andrzej.p@collabora.com>
    media: rkvdec: Add required padding

Marijn Suijten <marijn.suijten@somainline.org>
    drm/msm/dsi: Prevent signed BPG offsets from bleeding into adjacent bits

Marijn Suijten <marijn.suijten@somainline.org>
    drm/msm/dsi: Disallow 8 BPC DSC configuration for alternative BPC values

Marijn Suijten <marijn.suijten@somainline.org>
    drm/msm/dsi: Account for DSC's bits_per_pixel having 4 fractional bits

Marijn Suijten <marijn.suijten@somainline.org>
    drm/msm/dsi: Migrate to drm_dsc_compute_rc_parameters()

Marijn Suijten <marijn.suijten@somainline.org>
    drm/msm/dsi: Appropriately set dsc->mux_word_size based on bpc

Marijn Suijten <marijn.suijten@somainline.org>
    drm/msm/dsi: Reuse earlier computed dsc->slice_chunk_size

Marijn Suijten <marijn.suijten@somainline.org>
    drm/msm/dsi: Use DIV_ROUND_UP instead of conditional increment on modulo

Marijn Suijten <marijn.suijten@somainline.org>
    drm/msm/dsi: Remove repeated calculation of slice_per_intf

Marijn Suijten <marijn.suijten@somainline.org>
    drm/msm/dsi: Remove useless math in DSC calculations

Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
    drm/msm/dsi: use drm_dsc_config instead of msm_display_dsc_config

Marijn Suijten <marijn.suijten@somainline.org>
    drm/msm/dpu1: Account for DSC's bits_per_pixel having 4 fractional bits

Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
    drm/msm/dpu: use drm_dsc_config instead of msm_display_dsc_config

Kumar Kartikeya Dwivedi <memxor@gmail.com>
    bpf: Fix slot type check in check_stack_write_var_off

Kumar Kartikeya Dwivedi <memxor@gmail.com>
    bpf: Clobber stack slot when writing over spilled PTR_TO_BTF_ID

Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
    drm/msm/hdmi: use devres helper for runtime PM management

GUO Zihua <guozihua@huawei.com>
    ima: Handle -ESTALE returned by ima_filter_rule_match()

Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
    drm/msm/mdp5: stop overriding drvdata

Gaosheng Cui <cuigaosheng1@huawei.com>
    drm/ttm: fix undefined behavior in bit shift for TTM_TT_FLAG_PRIV_POPULATED

Marek Vasut <marex@denx.de>
    drm/panel/panel-sitronix-st7701: Remove panel on DSI attach failure

Jonathan Neuschäfer <j.neuschaefer@gmx.net>
    spi: Update reference to struct spi_controller

Marco Felsch <m.felsch@pengutronix.de>
    drm: lcdif: change burst size to 256B

Marek Vasut <marex@denx.de>
    clk: renesas: r9a06g032: Repair grave increment error

Zhang Qilong <zhangqilong3@huawei.com>
    drm/rockchip: lvds: fix PM usage counter unbalance in poweron

Haiyi Zhou <Haiyi.Zhou@amd.com>
    drm/amd/display: wait for vblank during pipe programming

Sakari Ailus <sakari.ailus@linux.intel.com>
    dw9768: Enable low-power probe on ACPI

Alan Previn <alan.previn.teres.alexis@intel.com>
    drm/i915/guc: Fix GuC error capture sizing estimation and reporting

Alan Previn <alan.previn.teres.alexis@intel.com>
    drm/i915/guc: Add error-capture init warnings when needed

John Harrison <John.C.Harrison@Intel.com>
    drm/i915/guc: Make GuC log sizes runtime configurable

John Harrison <John.C.Harrison@Intel.com>
    drm/i915/guc: Fix capture size warning and bump the size

Alan Previn <alan.previn.teres.alexis@intel.com>
    drm/i915/guc: Add a helper for log buffer size

Nícolas F. R. A. Prado <nfraprado@collabora.com>
    ASoC: dt-bindings: rt5682: Set sound-dai-cells to 1

Wolfram Sang <wsa+renesas@sang-engineering.com>
    clk: renesas: r8a779a0: Fix SD0H clock name

Jimmy Assarsson <extja@kvaser.com>
    can: kvaser_usb: Compare requested bittiming parameters with actual parameters in do_set_{,data}_bittiming

Jimmy Assarsson <extja@kvaser.com>
    can: kvaser_usb: Add struct kvaser_usb_busparams

Anssi Hannula <anssi.hannula@bitwise.fi>
    can: kvaser_usb_leaf: Fix bogus restart events

Anssi Hannula <anssi.hannula@bitwise.fi>
    can: kvaser_usb_leaf: Fix wrong CAN state after stopping

Anssi Hannula <anssi.hannula@bitwise.fi>
    can: kvaser_usb_leaf: Fix improved state not being reported

Anssi Hannula <anssi.hannula@bitwise.fi>
    can: kvaser_usb_leaf: Set Warning state even without bus errors

Jimmy Assarsson <extja@kvaser.com>
    can: kvaser_usb: kvaser_usb_leaf: Handle CMD_ERROR_EVENT

Jimmy Assarsson <extja@kvaser.com>
    can: kvaser_usb: kvaser_usb_leaf: Rename {leaf,usbcan}_cmd_error_event to {leaf,usbcan}_cmd_can_error_event

Jimmy Assarsson <extja@kvaser.com>
    can: kvaser_usb: kvaser_usb_leaf: Get capabilities from device

Alan Maguire <alan.maguire@oracle.com>
    libbpf: Btf dedup identical struct test needs check for nested structs/arrays

Marek Szyprowski <m.szyprowski@samsung.com>
    media: exynos4-is: don't rely on the v4l2_async_subdev internals

Rafael Mendonca <rafaelmendsr@gmail.com>
    media: i2c: ov5648: Free V4L2 fwnode data on unbind

Kuniyuki Iwashima <kuniyu@amazon.com>
    soreuseport: Fix socket selection for SO_INCOMING_CPU.

Tang Bin <tangbin@cmss.chinamobile.com>
    venus: pm_helpers: Fix error check in vcodec_domains_get()

Ricardo Ribalda <ribalda@chromium.org>
    media: i2c: ad5820: Fix error path

Rafael Mendonca <rafaelmendsr@gmail.com>
    media: i2c: hi846: Fix memory leak in hi846_parse_dt()

John Harrison <John.C.Harrison@Intel.com>
    drm/i915: Fix compute pre-emption w/a to apply to compute engines

John Harrison <John.C.Harrison@Intel.com>
    drm/i915/guc: Limit scheduling properties to avoid overflow

Yunfei Dong <yunfei.dong@mediatek.com>
    media: mediatek: vcodec: fix h264 cavlc bitstream fail

Jernej Skrabec <jernej.skrabec@gmail.com>
    media: cedrus: hevc: Fix offset adjustments

Jernej Skrabec <jernej.skrabec@gmail.com>
    media: v4l2-ioctl.c: Unify YCbCr/YUV terms in format descriptions

Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
    media: adv748x: afe: Select input port when initializing AFE

Ming Qian <ming.qian@nxp.com>
    media: amphion: reset instance if it's aborted before codec header parsed

Jiasheng Jiang <jiasheng@iscas.ac.cn>
    media: coda: jpeg: Add check for kmalloc

Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
    media: v4l2-ctrls: Fix off-by-one error in integer menu control check

Jeff LaBundy <jeff@labundy.com>
    Input: iqs7222 - protect against undefined slider size

Jeff LaBundy <jeff@labundy.com>
    Input: iqs7222 - report malformed properties

Jeff LaBundy <jeff@labundy.com>
    Input: iqs7222 - drop unused device node references

Jeff LaBundy <jeff@labundy.com>
    Input: iqs7222 - set all ULP entry masks by default

Pin-yen Lin <treapking@chromium.org>
    drm/bridge: it6505: Initialize AUX channel in it6505_i2c_probe

Gerhard Engleder <gerhard@engleder-embedded.com>
    samples/bpf: Fix MAC address swapping in xdp2_kern

Gerhard Engleder <gerhard@engleder-embedded.com>
    samples/bpf: Fix map iteration in xdp1_user

Rafael Mendonca <rafaelmendsr@gmail.com>
    drm/amdgpu/powerplay/psm: Fix memory leak in power state init

Andrew Jeffery <andrew@aj.id.au>
    ipmi: kcs: Poll OBF briefly to reduce OBE latency

Cezary Rojewski <cezary.rojewski@intel.com>
    ASoC: Intel: avs: Fix potential RX buffer overflow

Cezary Rojewski <cezary.rojewski@intel.com>
    ASoC: Intel: avs: Fix DMA mask assignment

Yang Yingliang <yangyingliang@huawei.com>
    pinctrl: ocelot: add missing destroy_workqueue() in error path in ocelot_pinctrl_probe()

Niklas Cassel <niklas.cassel@wdc.com>
    ata: libata: fix NCQ autosense logic

Laurent Pinchart <laurent.pinchart@ideasonboard.com>
    drm: lcdif: Switch to limited range for RGB to YUV conversion

Shung-Hsi Yu <shung-hsi.yu@suse.com>
    libbpf: Fix null-pointer dereference in find_prog_by_sec_insn()

Shung-Hsi Yu <shung-hsi.yu@suse.com>
    libbpf: Deal with section with no data gracefully

Shung-Hsi Yu <shung-hsi.yu@suse.com>
    libbpf: Use elf_getshdrnum() instead of e_shnum

Andrii Nakryiko <andrii@kernel.org>
    libbpf: Reject legacy 'maps' ELF section

Xu Kuohai <xukuohai@huawei.com>
    selftest/bpf: Fix error usage of ASSERT_OK in xdp_adjust_tail.c

Xu Kuohai <xukuohai@huawei.com>
    selftests/bpf: Fix error failure of case test_xdp_adjust_tail_grow

Xu Kuohai <xukuohai@huawei.com>
    selftest/bpf: Fix memory leak in kprobe_multi_test

Xu Kuohai <xukuohai@huawei.com>
    selftests/bpf: Fix memory leak caused by not destroying skeleton

Yonghong Song <yhs@fb.com>
    selftests/bpf: Add struct argument tests with fentry/fexit programs.

Xu Kuohai <xukuohai@huawei.com>
    libbpf: Fix memory leak in parse_usdt_arg()

Xu Kuohai <xukuohai@huawei.com>
    libbpf: Fix use-after-free in btf_dump_name_dups

Abhinav Kumar <quic_abhinavk@quicinc.com>
    drm/bridge: adv7533: remove dynamic lane switching from adv7533 bridge

Aditya Kumar Singh <quic_adisi@quicinc.com>
    wifi: ath11k: fix firmware assert during bandwidth change for peer sta

Aditya Kumar Singh <quic_adisi@quicinc.com>
    wifi: ath11k: move firmware stats out of debugfs

Bitterblue Smith <rtl8821cerfe2@gmail.com>
    wifi: rtl8xxxu: Fix reading the vendor of combo chips

Fedor Pchelkin <pchelkin@ispras.ru>
    wifi: ath9k: hif_usb: Fix use-after-free in ath9k_hif_usb_reg_in_cb()

Fedor Pchelkin <pchelkin@ispras.ru>
    wifi: ath9k: hif_usb: fix memory leak of urbs in ath9k_hif_usb_dealloc_tx_urbs()

Thomas Zimmermann <tzimmermann@suse.de>
    drm/atomic-helper: Don't allocate new plane state in CRTC check

Johannes Berg <johannes.berg@intel.com>
    wifi: mac80211: fix ifdef symbol name

Johannes Berg <johannes.berg@intel.com>
    wifi: mac80211: check link ID in auth/assoc continuation

Johannes Berg <johannes.berg@intel.com>
    wifi: mac80211: mlme: fix null-ptr deref on failed assoc

Johannes Berg <johannes.berg@intel.com>
    wifi: fix multi-link element subelement iteration

James Hurley <jahurley@nvidia.com>
    platform/mellanox: mlxbf-pmc: Fix event typo

Zhengchao Shao <shaozhengchao@huawei.com>
    ipc: fix memory leak in init_mqueue_fs()

Cai Xinchen <caixinchen1@huawei.com>
    rapidio: devices: fix missing put_device in mport_cdev_open

ZhangPeng <zhangpeng362@huawei.com>
    hfs: Fix OOB Write in hfs_asc2mac

Gavrilov Ilia <Ilia.Gavrilov@infotecs.ru>
    relay: fix type mismatch when allocating memory in relay_create_buf()

Zhang Qilong <zhangqilong3@huawei.com>
    eventfd: change int to __u64 in eventfd_signal() ifndef CONFIG_EVENTFD

Wang Weiyang <wangweiyang2@huawei.com>
    rapidio: fix possible UAF when kfifo_alloc() fails

Chen Zhongjin <chenzhongjin@huawei.com>
    fs: sysv: Fix sysv_nblocks() returns wrong value

Brian Foster <bfoster@redhat.com>
    NFSD: pass range end to vfs_fsync_range() instead of count

Jeff Layton <jlayton@kernel.org>
    nfsd: return error if nfs4_setacl fails

Trond Myklebust <trond.myklebust@hammerspace.com>
    lockd: set other missing fields when unlocking files

Ladislav Michl <ladis@linux-mips.org>
    MIPS: OCTEON: warn only once if deprecated link status is being used

Anastasia Belova <abelova@astralinux.ru>
    MIPS: BCM63xx: Add check for NULL for clk in clk_enable

Yang Yingliang <yangyingliang@huawei.com>
    platform/x86: intel_scu_ipc: fix possible name leak in __intel_scu_ipc_register()

Yu Liao <liaoyu15@huawei.com>
    platform/x86: mxm-wmi: fix memleak in mxm_wmi_call_mx[ds|mx]()

Victor Ding <victording@chromium.org>
    platform/chrome: cros_ec_typec: zero out stale pointers

Prashant Malani <pmalani@chromium.org>
    platform/chrome: cros_ec_typec: Get retimer handle

Prashant Malani <pmalani@chromium.org>
    platform/chrome: cros_ec_typec: Cleanup switch handle return paths

Gao Xiang <xiang@kernel.org>
    erofs: validate the extent length for uncompressed pclusters

Yue Hu <huyue2@coolpad.com>
    erofs: support interlaced uncompressed data for compressed files

Gao Xiang <xiang@kernel.org>
    erofs: fix missing unmap if z_erofs_get_extent_compressedlen() fails

Chen Zhongjin <chenzhongjin@huawei.com>
    erofs: Fix pcluster memleak when its block address is zero

Rafael J. Wysocki <rafael.j.wysocki@intel.com>
    PM: runtime: Do not call __rpm_callback() from rpm_idle()

Harshit Mogalapalli <harshit.m.mogalapalli@oracle.com>
    xen/privcmd: Fix a possible warning in privcmd_ioctl_mmap_resource()

Xiu Jianfeng <xiujianfeng@huawei.com>
    x86/xen: Fix memory leak in xen_init_lock_cpu()

Xiu Jianfeng <xiujianfeng@huawei.com>
    x86/xen: Fix memory leak in xen_smp_intr_init{_pv}()

Oleg Nesterov <oleg@redhat.com>
    uprobes/x86: Allow to probe a NOP instruction with 0x66 prefix

Li Zetao <lizetao1@huawei.com>
    ACPICA: Fix use-after-free in acpi_ut_copy_ipackage_to_ipackage()

Yang Yingliang <yangyingliang@huawei.com>
    clocksource/drivers/timer-ti-dm: Fix missing clk_disable_unprepare in dmtimer_systimer_init_clock()

Tony Lindgren <tony@atomide.com>
    clocksource/drivers/timer-ti-dm: Fix warning for omap_timer_match

Vincent Donnefort <vdonnefort@google.com>
    cpu/hotplug: Do not bail-out in DYING/STARTING sections

Phil Auld <pauld@redhat.com>
    cpu/hotplug: Make target_store() a nop when target == state

Alexey Izbyshev <izbyshev@ispras.ru>
    futex: Resend potentially swallowed owner death notification

John Thomson <git@johnthomson.fastmail.com.au>
    mips: ralink: mt7621: do not use kzalloc too early

John Thomson <git@johnthomson.fastmail.com.au>
    mips: ralink: mt7621: soc queries and tests as functions

John Thomson <git@johnthomson.fastmail.com.au>
    mips: ralink: mt7621: define MT7621_SYSC_BASE with __iomem

Wolfram Sang <wsa+renesas@sang-engineering.com>
    clocksource/drivers/sh_cmt: Access registers according to spec

Yang Yingliang <yangyingliang@huawei.com>
    rapidio: rio: fix possible name leak in rio_register_mport()

Yang Yingliang <yangyingliang@huawei.com>
    rapidio: fix possible name leaks when rio_add_device() fails

Li Zetao <ocfs2-devel@oss.oracle.com>
    ocfs2: fix memory leak in ocfs2_mount_volume()

Akinobu Mita <akinobu.mita@gmail.com>
    debugfs: fix error when writing negative value to atomic_t debugfs file

Akinobu Mita <akinobu.mita@gmail.com>
    lib/notifier-error-inject: fix error when writing -errno to debugfs file

Akinobu Mita <akinobu.mita@gmail.com>
    libfs: add DEFINE_SIMPLE_ATTRIBUTE_SIGNED for signed value

Xiongfeng Wang <wangxiongfeng2@huawei.com>
    cpufreq: amd_freq_sensitivity: Add missing pci_dev_put()

Yang Yingliang <yangyingliang@huawei.com>
    genirq/irqdesc: Don't try to remove non-existing sysfs files

Jeff Layton <jlayton@kernel.org>
    nfsd: don't call nfsd_file_put from client states seqfile display

Chuck Lever <chuck.lever@oracle.com>
    NFSD: Finish converting the NFSv3 GETACL result encoder

Chuck Lever <chuck.lever@oracle.com>
    NFSD: Finish converting the NFSv2 GETACL result encoder

Yang Yingliang <yangyingliang@huawei.com>
    EDAC/i10nm: fix refcount leak in pci_get_dev_wrapper()

Liu Peibao <liupeibao@loongson.cn>
    irqchip/loongson-liointc: Fix improper error handling in liointc_init()

Wei Yongjun <weiyongjun1@huawei.com>
    irqchip/wpcm450: Fix memory leak in wpcm450_aic_of_init()

Shang XiaoJing <shangxiaojing@huawei.com>
    irqchip: gic-pm: Use pm_runtime_resume_and_get() in gic_probe()

Jianmin Lv <lvjianmin@loongson.cn>
    irqchip/loongson-pch-pic: Fix translate callback for DT path

Yang Yingliang <yangyingliang@huawei.com>
    thermal: core: fix some possible name leaks in error paths

Yuan Can <yuancan@huawei.com>
    platform/chrome: cros_usbpd_notify: Fix error handling in cros_usbpd_notify_init()

Xiongfeng Wang <wangxiongfeng2@huawei.com>
    perf/x86/intel/uncore: Fix reference count leak in __uncore_imc_init_box()

Xiongfeng Wang <wangxiongfeng2@huawei.com>
    perf/x86/intel/uncore: Fix reference count leak in snr_uncore_mmio_map()

Xiongfeng Wang <wangxiongfeng2@huawei.com>
    perf/x86/intel/uncore: Fix reference count leak in hswep_has_limit_sbox()

Xiongfeng Wang <wangxiongfeng2@huawei.com>
    perf/x86/intel/uncore: Fix reference count leak in sad_cfg_iio_topology()

Wang ShaoBo <bobo.shaobowang@huawei.com>
    ACPI: pfr_update: use ACPI_FREE() to free acpi_object

Wang ShaoBo <bobo.shaobowang@huawei.com>
    ACPI: pfr_telemetry: use ACPI_FREE() to free acpi_object

Huisong Li <lihuisong@huawei.com>
    mailbox: pcc: Reset pcc_chan_count to zero in case of PCC probe failure

Yang Yingliang <yangyingliang@huawei.com>
    PNP: fix name memory leak in pnp_alloc_dev()

Zhao Gongyi <zhaogongyi@huawei.com>
    selftests/efivarfs: Add checking of the test return value

Yang Yingliang <yangyingliang@huawei.com>
    MIPS: vpe-cmp: fix possible memory leak while module exiting

Yang Yingliang <yangyingliang@huawei.com>
    MIPS: vpe-mt: fix possible memory leak while module exiting

Manivannan Sadhasivam <mani@kernel.org>
    cpufreq: qcom-hw: Fix the frequency returned by cpufreq_driver->get()

YueHaibing <yuehaibing@huawei.com>
    selftests: cgroup: fix unsigned comparison with less than zero

Shang XiaoJing <shangxiaojing@huawei.com>
    ocfs2: fix memory leak in ocfs2_stack_glue_init()

Gaosheng Cui <cuigaosheng1@huawei.com>
    lib/fonts: fix undefined behavior in bit shift for get_default_font

Alexey Dobriyan <adobriyan@gmail.com>
    proc: fixup uptime selftest

Barnabás Pőcze <pobrn@protonmail.com>
    timerqueue: Use rb_entry_safe() in timerqueue_getnext()

Barnabás Pőcze <pobrn@protonmail.com>
    platform/x86: huawei-wmi: fix return value calculation

wuchi <wuchi.zero@gmail.com>
    lib/debugobjects: fix stat count and optimize debug_objects_mem_init

Chen Zhongjin <chenzhongjin@huawei.com>
    perf: Fix possible memleak in pmu_dev_alloc()

Yipeng Zou <zouyipeng@huawei.com>
    selftests/ftrace: event_triggers: wait longer for test_event_enable

Xiongfeng Wang <wangxiongfeng2@huawei.com>
    ACPI: irq: Fix some kernel-doc issues

Guilherme G. Piccoli <gpiccoli@igalia.com>
    x86/split_lock: Add sysctl to control the misery mode

Chen Hui <judy.chenhui@huawei.com>
    cpufreq: qcom-hw: Fix memory leak in qcom_cpufreq_hw_read_lut()

Ondrej Mosnacek <omosnace@redhat.com>
    fs: don't audit the capability check in simple_xattr_list()

xiongxin <xiongxin@kylinos.cn>
    PM: hibernate: Fix mistake in kerneldoc comment

Reinette Chatre <reinette.chatre@intel.com>
    x86/sgx: Reduce delay and interference of enclave release

Hao Lee <haolee.swjtu@gmail.com>
    sched/psi: Fix possible missing or delayed pending event

Al Viro <viro@zeniv.linux.org.uk>
    alpha: fix syscall entry in !AUDUT_SYSCALL case

Al Viro <viro@zeniv.linux.org.uk>
    alpha: fix TIF_NOTIFY_SIGNAL handling

Ulf Hansson <ulf.hansson@linaro.org>
    cpuidle: dt: Return the correct numbers of parsed idle states

Qais Yousef <qais.yousef@arm.com>
    sched/uclamp: Cater for uclamp in find_energy_efficient_cpu()'s early exit condition

Qais Yousef <qais.yousef@arm.com>
    sched/uclamp: Make cpu_overutilized() use util_fits_cpu()

Qais Yousef <qais.yousef@arm.com>
    sched/uclamp: Make asym_fits_capacity() use util_fits_cpu()

Dietmar Eggemann <dietmar.eggemann@arm.com>
    sched/core: Introduce sched_asym_cpucap_active()

Qais Yousef <qais.yousef@arm.com>
    sched/uclamp: Make select_idle_capacity() use util_fits_cpu()

Qais Yousef <qais.yousef@arm.com>
    sched/uclamp: Fix fits_capacity() check in feec()

Qais Yousef <qais.yousef@arm.com>
    sched/uclamp: Make task_fits_capacity() use util_fits_cpu()

Qais Yousef <qais.yousef@arm.com>
    sched/uclamp: Fix relationship between uclamp and migration margin

Amir Goldstein <amir73il@gmail.com>
    ovl: remove privs in ovl_fallocate()

Amir Goldstein <amir73il@gmail.com>
    ovl: remove privs in ovl_copyfile()

Michael Kelley <mikelley@microsoft.com>
    tpm/tpm_crb: Fix error message in __crb_relinquish_locality()

Yuan Can <yuancan@huawei.com>
    tpm/tpm_ftpm_tee: Fix error handling in ftpm_mod_init()

Eddie James <eajames@linux.ibm.com>
    tpm: Add flag to use default cancellation policy

Eddie James <eajames@linux.ibm.com>
    tpm: tis_i2c: Fix sanity check interrupt enable mask

Janne Grunau <j@jannau.net>
    arch: arm64: apple: t8103: Use standard "iommu" node name

Stephen Boyd <swboyd@chromium.org>
    pstore: Avoid kcore oops by vmap()ing with VM_IOREMAP

Doug Brown <doug@schmorgal.com>
    ARM: mmp: fix timer_read delay

Wang Yufen <wangyufen@huawei.com>
    pstore/ram: Fix error return code in ramoops_probe()

Kuniyuki Iwashima <kuniyu@amazon.com>
    seccomp: Move copy_seccomp() to no failure path.

Yicong Yang <yangyicong@hisilicon.com>
    drivers/perf: hisi: Fix some event id for hisi-pcie-pmu

Sven Peter <sven@svenpeter.dev>
    soc: apple: rtkit: Stop casting function pointer signatures

Sven Peter <sven@svenpeter.dev>
    soc: apple: sart: Stop casting function pointer signatures

Pali Rohár <pali@kernel.org>
    arm64: dts: armada-3720-turris-mox: Add missing interrupt for RTC

Pali Rohár <pali@kernel.org>
    ARM: dts: armada-39x: Fix compatible string for gpios

Pali Rohár <pali@kernel.org>
    ARM: dts: armada-38x: Fix compatible string for gpios

Pali Rohár <pali@kernel.org>
    ARM: dts: turris-omnia: Add switch port 6 node

Pali Rohár <pali@kernel.org>
    ARM: dts: turris-omnia: Add ethernet aliases

Pali Rohár <pali@kernel.org>
    ARM: dts: armada-39x: Fix assigned-addresses for every PCIe Root Port

Pali Rohár <pali@kernel.org>
    ARM: dts: armada-38x: Fix assigned-addresses for every PCIe Root Port

Pali Rohár <pali@kernel.org>
    ARM: dts: armada-375: Fix assigned-addresses for every PCIe Root Port

Pali Rohár <pali@kernel.org>
    ARM: dts: armada-xp: Fix assigned-addresses for every PCIe Root Port

Pali Rohár <pali@kernel.org>
    ARM: dts: armada-370: Fix assigned-addresses for every PCIe Root Port

Pali Rohár <pali@kernel.org>
    ARM: dts: dove: Fix assigned-addresses for every PCIe Root Port

AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
    arm64: dts: mediatek: mt6797: Fix 26M oscillator unit name

AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
    arm64: dts: mediatek: pumpkin-common: Fix devicetree warnings

AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
    arm64: dts: mt2712-evb: Fix usb vbus regulators unit names

AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
    arm64: dts: mt2712-evb: Fix vproc fixed regulators unit names

AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
    arm64: dts: mt2712e: Fix unit address for pinctrl node

AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
    arm64: dts: mt2712e: Fix unit_address_vs_reg warning for oscillators

AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
    arm64: dts: mt6779: Fix devicetree build warnings

AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
    arm64: dts: mt7896a: Fix unit_address_vs_reg warning for oscillator

AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
    arm64: dts: mediatek: mt8195: Fix CPUs capacity-dmips-mhz

Jonathan Neuschäfer <j.neuschaefer@gmx.net>
    ARM: dts: nuvoton: Remove bogus unit addresses from fixed-partition nodes

Keerthy <j-keerthy@ti.com>
    arm64: dts: ti: k3-j721s2: Fix the interrupt ranges property for main & wkup gpio intr

Jayesh Choudhary <j-choudhary@ti.com>
    arm64: dts: ti: k3-j721e-main: Drop dma-coherent in crypto node

Jayesh Choudhary <j-choudhary@ti.com>
    arm64: dts: ti: k3-am65-main: Drop dma-coherent in crypto node

Shang XiaoJing <shangxiaojing@huawei.com>
    perf/smmuv3: Fix hotplug callback leak in arm_smmu_pmu_init()

Shang XiaoJing <shangxiaojing@huawei.com>
    perf/arm_dmc620: Fix hotplug callback leak in dmc620_pmu_init()

Yuan Can <yuancan@huawei.com>
    drivers: perf: marvell_cn10k: Fix hotplug callback leak in tad_pmu_init()

Yuan Can <yuancan@huawei.com>
    perf: arm_dsu: Fix hotplug callback leak in dsu_pmu_init()

Mark Rutland <mark.rutland@arm.com>
    arm64: mm: kfence: only handle translation faults

Zhang Qilong <zhangqilong3@huawei.com>
    soc: ti: smartreflex: Fix PM disable depth imbalance in omap_sr_probe

Zhang Qilong <zhangqilong3@huawei.com>
    soc: ti: knav_qmss_queue: Fix PM disable depth imbalance in knav_queue_probe

Kory Maincent <kory.maincent@bootlin.com>
    arm: dts: spear600: Fix clcd interrupt

Frank Wunderlich <frank-w@public-files.de>
    arm64: dts: mt7986: fix trng node name

Conor Dooley <conor.dooley@microchip.com>
    dt-bindings: pwm: fix microchip corePWM's pwm-cells

Fabrizio Castro <fabrizio.castro.jz@renesas.com>
    arm64: dts: renesas: r9a09g011: Fix unit address format error

Wolfram Sang <wsa+renesas@sang-engineering.com>
    arm64: dts: renesas: r8a779f0: Fix SCIF "brg_int" clock

Wolfram Sang <wsa+renesas@sang-engineering.com>
    arm64: dts: renesas: r8a779f0: Fix HSCIF "brg_int" clock

Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
    arm64: dts: qcom: sm6125: fix SDHCI CQE reg names

Marijn Suijten <marijn.suijten@somainline.org>
    arm64: dts: qcom: pm6350: Include header for KEY_POWER

Jiasheng Jiang <jiasheng@iscas.ac.cn>
    soc: qcom: apr: Add check for idr_alloc and of_property_read_string_index

Johan Hovold <johan+linaro@kernel.org>
    arm64: dts: qcom: sm6350: drop bogus DP PHY clock

Johan Hovold <johan+linaro@kernel.org>
    arm64: dts: qcom: sm8250: drop bogus DP PHY clock

Dmitry Torokhov <dmitry.torokhov@gmail.com>
    arm64: dts: qcom: sm8250-mtp: fix reset line polarity

Dmitry Torokhov <dmitry.torokhov@gmail.com>
    arm64: dts: qcom: msm8996: fix sound card reset line polarity

Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
    arm64: dts: qcom: use GPIO flags for tlmm

Johan Hovold <johan+linaro@kernel.org>
    arm64: dts: qcom: sm8450: fix UFS PHY registers

Johan Hovold <johan+linaro@kernel.org>
    arm64: dts: qcom: sm8350: fix UFS PHY registers

Johan Hovold <johan+linaro@kernel.org>
    arm64: dts: qcom: sm8250: fix UFS PHY registers

Johan Hovold <johan+linaro@kernel.org>
    arm64: dts: qcom: sm8150: fix UFS PHY registers

Luca Weiss <luca.weiss@fairphone.com>
    soc: qcom: llcc: make irq truly optional

Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
    arm64: dts: qcom: sc7180-trogdor-homestar: fully configure secondary I2S pins

Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
    arm64: dts: qcom: sm8250: correct LPASS pin pull down

Marijn Suijten <marijn.suijten@somainline.org>
    arm64: dts: qcom: pm660: Use unique ADC5_VCOIN address in node name

Georgi Vlaev <g-vlaev@ti.com>
    firmware: ti_sci: Fix polled mode during system suspend

Chen Jiahao <chenjiahao16@huawei.com>
    drivers: soc: ti: knav_qmss_queue: Mark knav_acc_firmwares as static

Marek Vasut <marex@denx.de>
    ARM: dts: stm32: Fix AV96 WLAN regulator gpio property

Marek Vasut <marex@denx.de>
    ARM: dts: stm32: Drop stm32mp15xc.dtsi from Avenger96

Marco Elver <elver@google.com>
    objtool, kcsan: Add volatile read/write instrumentation to whitelist

Cong Dang <cong.dang.xn@renesas.com>
    memory: renesas-rpc-if: Clear HS bit during hardware initialization

Padmanabhan Rajanbabu <p.rajanbabu@samsung.com>
    arm64: dts: fsd: fix drive strength values as per FSD HW UM

Padmanabhan Rajanbabu <p.rajanbabu@samsung.com>
    arm64: dts: fsd: fix drive strength macros as per FSD HW UM

Stephan Gerhold <stephan.gerhold@kernkonzept.com>
    arm64: dts: qcom: msm8916: Drop MSS fallback compatible

Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
    arm64: dts: qcom: sdm845-cheza: fix AP suspend pin bias

Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
    arm64: dts: qcom: sdm630: fix UART1 pin bias

Luca Weiss <luca@z3ntu.xyz>
    ARM: dts: qcom: apq8064: fix coresight compatible

Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
    arm64: dts: qcom: msm8996: fix GPU OPP table

Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
    arm64: dts: qcom: msm8996: fix supported-hw in cpufreq OPP tables

Yassine Oudjana <y.oudjana@protonmail.com>
    arm64: dts: qcom: msm8996: Add MSM8996 Pro support

Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
    arm64: dts: qcom: sdm845-xiaomi-polaris: fix codec pin conf name

Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
    arm64: dts: qcom: sm8250-sony-xperia-edo: fix touchscreen bias-disable

Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
    arm64: dts: qcom: ipq6018-cp01-c1: use BLSPI1 pins

Geert Uytterhoeven <geert+renesas@glider.be>
    arm64: dts: renesas: r8a779g0: Fix HSCIF0 "brg_int" clock

Paulo Alcantara <pc@cjr.nz>
    cifs: fix oops during encryption

Paulo Alcantara <pc@cjr.nz>
    cifs: improve symlink handling for smb2+

Enzo Matsumiya <ematsumiya@suse.de>
    cifs: replace kfree() with kfree_sensitive() for sensitive data

Ivaylo Dimitrov <ivo.g.dimitrov.75@gmail.com>
    usb: musb: remove extra check in musb_gadget_vbus_draw

Martin Kaiser <martin@kaiser.cx>
    staging: r8188eu: fix led register settings

Martin Kaiser <martin@kaiser.cx>
    staging: r8188eu: don't check bSurpriseRemoved in SwLedOff

Martin Kaiser <martin@kaiser.cx>
    staging: r8188eu: remove duplicate bSurpriseRemoved check


-------------

Diffstat:

 .../ABI/testing/sysfs-bus-spi-devices-spi-nor      |   3 +
 Documentation/admin-guide/sysctl/kernel.rst        |  23 +
 .../bindings/clock/qcom,sc7280-lpasscorecc.yaml    |  19 +-
 .../devicetree/bindings/input/azoteq,iqs7222.yaml  |  25 +-
 .../devicetree/bindings/mfd/qcom,spmi-pmic.yaml    |   8 +-
 .../devicetree/bindings/pci/fsl,imx6q-pcie.yaml    |  46 +-
 .../bindings/pci/toshiba,visconti-pcie.yaml        |   7 +-
 .../bindings/pinctrl/mediatek,mt7986-pinctrl.yaml  |  46 +-
 .../devicetree/bindings/pwm/microchip,corepwm.yaml |   4 +-
 .../devicetree/bindings/sound/qcom,wcd9335.txt     |   2 +-
 Documentation/devicetree/bindings/sound/rt5682.txt |   2 +-
 Documentation/driver-api/spi.rst                   |   4 +-
 Documentation/fault-injection/fault-injection.rst  |  10 +-
 Makefile                                           |   4 +-
 arch/Kconfig                                       |   2 +-
 arch/alpha/include/asm/thread_info.h               |   2 +-
 arch/alpha/kernel/entry.S                          |   4 +-
 arch/arm/boot/dts/armada-370.dtsi                  |   2 +-
 arch/arm/boot/dts/armada-375.dtsi                  |   2 +-
 arch/arm/boot/dts/armada-380.dtsi                  |   4 +-
 arch/arm/boot/dts/armada-385-turris-omnia.dts      |  18 +-
 arch/arm/boot/dts/armada-385.dtsi                  |   6 +-
 arch/arm/boot/dts/armada-38x.dtsi                  |   4 +-
 arch/arm/boot/dts/armada-39x.dtsi                  |  10 +-
 arch/arm/boot/dts/armada-xp-mv78230.dtsi           |   8 +-
 arch/arm/boot/dts/armada-xp-mv78260.dtsi           |  16 +-
 arch/arm/boot/dts/aspeed-bmc-ibm-everest.dts       |  17 +-
 arch/arm/boot/dts/aspeed-bmc-ibm-rainier.dts       |  16 +-
 arch/arm/boot/dts/dove.dtsi                        |   2 +-
 arch/arm/boot/dts/nuvoton-npcm730-gbs.dts          |   2 +-
 arch/arm/boot/dts/nuvoton-npcm730-gsj.dts          |   2 +-
 arch/arm/boot/dts/nuvoton-npcm730-kudo.dts         |   6 +-
 arch/arm/boot/dts/nuvoton-npcm750-evb.dts          |   4 +-
 .../boot/dts/nuvoton-npcm750-runbmc-olympus.dts    |   6 +-
 arch/arm/boot/dts/qcom-apq8064.dtsi                |   2 +-
 arch/arm/boot/dts/spear600.dtsi                    |   2 +-
 arch/arm/boot/dts/stm32mp157a-dhcor-avenger96.dts  |   1 -
 arch/arm/boot/dts/stm32mp15xx-dhcor-avenger96.dtsi |   2 +-
 arch/arm/mach-mmp/time.c                           |  11 +-
 arch/arm64/boot/dts/apple/t8103.dtsi               |   6 +-
 .../boot/dts/marvell/armada-3720-turris-mox.dts    |   3 +
 arch/arm64/boot/dts/mediatek/mt2712-evb.dts        |  12 +-
 arch/arm64/boot/dts/mediatek/mt2712e.dtsi          |  22 +-
 arch/arm64/boot/dts/mediatek/mt6779.dtsi           |   8 +-
 arch/arm64/boot/dts/mediatek/mt6797.dtsi           |   2 +-
 arch/arm64/boot/dts/mediatek/mt7986a.dtsi          |   4 +-
 arch/arm64/boot/dts/mediatek/mt8183.dtsi           |   2 +-
 arch/arm64/boot/dts/mediatek/mt8195.dtsi           |   8 +-
 arch/arm64/boot/dts/mediatek/pumpkin-common.dtsi   |   6 +-
 arch/arm64/boot/dts/qcom/apq8096-ifc6640.dts       |   2 +-
 arch/arm64/boot/dts/qcom/ipq6018-cp01-c1.dts       |   2 +
 arch/arm64/boot/dts/qcom/msm8916.dtsi              |   2 +-
 .../dts/qcom/msm8994-sony-xperia-kitakami.dtsi     |   2 +-
 arch/arm64/boot/dts/qcom/msm8994.dtsi              |   3 +-
 arch/arm64/boot/dts/qcom/msm8996.dtsi              | 115 +++--
 arch/arm64/boot/dts/qcom/msm8996pro.dtsi           | 266 +++++++++++
 arch/arm64/boot/dts/qcom/pm6350.dtsi               |   1 +
 arch/arm64/boot/dts/qcom/pm660.dtsi                |   2 +-
 .../boot/dts/qcom/sc7180-trogdor-homestar.dtsi     |   6 +
 arch/arm64/boot/dts/qcom/sdm630.dtsi               |   2 +-
 arch/arm64/boot/dts/qcom/sdm845-cheza.dtsi         |   4 +-
 arch/arm64/boot/dts/qcom/sdm845-db845c.dts         |   4 +-
 .../boot/dts/qcom/sdm845-xiaomi-beryllium.dts      |   2 +-
 arch/arm64/boot/dts/qcom/sdm845-xiaomi-polaris.dts |   6 +-
 .../boot/dts/qcom/sdm850-lenovo-yoga-c630.dts      |   2 +-
 arch/arm64/boot/dts/qcom/sdm850-samsung-w737.dts   |   2 +-
 arch/arm64/boot/dts/qcom/sm6125.dtsi               |   2 +-
 arch/arm64/boot/dts/qcom/sm6350.dtsi               |  10 +-
 arch/arm64/boot/dts/qcom/sm8150.dtsi               |  10 +-
 arch/arm64/boot/dts/qcom/sm8250-mtp.dts            |   2 +-
 .../boot/dts/qcom/sm8250-sony-xperia-edo.dtsi      |   2 +-
 arch/arm64/boot/dts/qcom/sm8250.dtsi               |  20 +-
 arch/arm64/boot/dts/qcom/sm8350.dtsi               |  10 +-
 arch/arm64/boot/dts/qcom/sm8450.dtsi               |  10 +-
 arch/arm64/boot/dts/renesas/r8a779f0.dtsi          |  16 +-
 arch/arm64/boot/dts/renesas/r8a779g0.dtsi          |   2 +-
 arch/arm64/boot/dts/renesas/r9a09g011.dtsi         |   2 +-
 arch/arm64/boot/dts/tesla/fsd-pinctrl.dtsi         |  34 +-
 arch/arm64/boot/dts/tesla/fsd-pinctrl.h            |   6 +-
 arch/arm64/boot/dts/ti/k3-am65-main.dtsi           |   1 -
 arch/arm64/boot/dts/ti/k3-j721e-main.dtsi          |   1 -
 arch/arm64/boot/dts/ti/k3-j721s2-main.dtsi         |   2 +-
 arch/arm64/boot/dts/ti/k3-j721s2-mcu-wakeup.dtsi   |   2 +-
 arch/arm64/include/asm/processor.h                 |   4 +-
 arch/arm64/mm/fault.c                              |   8 +-
 arch/mips/bcm63xx/clk.c                            |   2 +
 .../cavium-octeon/executive/cvmx-helper-board.c    |   2 +-
 arch/mips/cavium-octeon/executive/cvmx-helper.c    |   2 +-
 arch/mips/include/asm/mach-ralink/mt7621.h         |   4 +-
 arch/mips/kernel/vpe-cmp.c                         |   4 +-
 arch/mips/kernel/vpe-mt.c                          |   4 +-
 arch/mips/ralink/mt7621.c                          |  97 ++--
 arch/mips/ralink/of.c                              |   4 +-
 arch/powerpc/boot/dts/turris1x.dts                 |  14 +
 arch/powerpc/include/asm/hvcall.h                  |   3 +-
 arch/powerpc/perf/callchain.c                      |   1 +
 arch/powerpc/perf/hv-gpci-requests.h               |   4 +
 arch/powerpc/perf/hv-gpci.c                        |  35 +-
 arch/powerpc/perf/hv-gpci.h                        |   1 +
 arch/powerpc/perf/req-gen/perf.h                   |  20 +
 arch/powerpc/platforms/52xx/mpc52xx_lpbfifo.c      |   1 +
 arch/powerpc/platforms/83xx/mpc832x_rdb.c          |   2 +-
 arch/powerpc/platforms/pseries/eeh_pseries.c       |  11 +-
 arch/powerpc/platforms/pseries/plpks.c             |  32 +-
 arch/powerpc/platforms/pseries/plpks.h             |   2 +-
 arch/powerpc/sysdev/xive/spapr.c                   |   1 +
 arch/powerpc/xmon/xmon.c                           |   7 +-
 arch/riscv/include/asm/hugetlb.h                   |   6 +
 arch/riscv/include/asm/io.h                        |   5 +
 arch/riscv/include/asm/pgtable-64.h                |   6 +-
 arch/riscv/kernel/entry.S                          |  18 +-
 arch/riscv/kernel/signal.c                         |  34 +-
 arch/riscv/kernel/traps.c                          |   2 +-
 arch/riscv/kvm/vcpu.c                              |  11 +-
 arch/riscv/mm/physaddr.c                           |   2 +-
 arch/riscv/net/bpf_jit_comp64.c                    |  29 +-
 arch/x86/Kconfig                                   |   4 +-
 arch/x86/events/intel/uncore_snb.c                 |   3 +
 arch/x86/events/intel/uncore_snbep.c               |   5 +
 arch/x86/hyperv/hv_init.c                          |   2 -
 arch/x86/include/asm/apic.h                        |   3 +-
 arch/x86/include/asm/realmode.h                    |   1 +
 arch/x86/include/asm/x86_init.h                    |   4 +
 arch/x86/kernel/apic/apic.c                        |  13 +-
 arch/x86/kernel/cpu/intel.c                        |  63 ++-
 arch/x86/kernel/cpu/sgx/encl.c                     |  23 +-
 arch/x86/kernel/setup.c                            |   2 +-
 arch/x86/kernel/uprobes.c                          |   4 +-
 arch/x86/kernel/x86_init.c                         |   3 +
 arch/x86/realmode/init.c                           |   8 +-
 arch/x86/xen/enlighten_pv.c                        |   2 +
 arch/x86/xen/smp.c                                 |  24 +-
 arch/x86/xen/smp_pv.c                              |  12 +-
 arch/x86/xen/spinlock.c                            |   6 +-
 block/bfq-iosched.c                                |  16 +-
 block/blk-mq-sysfs.c                               |  11 +-
 block/blk-mq.c                                     |  56 ++-
 block/genhd.c                                      |   2 +
 crypto/cryptd.c                                    |  36 +-
 crypto/tcrypt.c                                    | 265 +++++------
 drivers/acpi/acpica/dsmethod.c                     |  10 +-
 drivers/acpi/acpica/utcopy.c                       |   7 -
 drivers/acpi/ec.c                                  |  10 +
 drivers/acpi/irq.c                                 |   5 +-
 drivers/acpi/pfr_telemetry.c                       |   6 +-
 drivers/acpi/pfr_update.c                          |   6 +-
 drivers/acpi/processor_idle.c                      |   3 +
 drivers/acpi/x86/utils.c                           |  24 +-
 drivers/ata/libata-sata.c                          |  11 +-
 drivers/base/class.c                               |   5 +
 drivers/base/power/runtime.c                       |  12 +-
 drivers/base/regmap/regmap-irq.c                   |  15 +-
 drivers/block/drbd/drbd_main.c                     |   9 +-
 drivers/block/drbd/drbd_nl.c                       |  10 +-
 drivers/block/floppy.c                             |   4 +-
 drivers/block/loop.c                               |  28 +-
 drivers/bluetooth/btintel.c                        |   5 +-
 drivers/bluetooth/btusb.c                          |   6 +-
 drivers/bluetooth/hci_bcm.c                        |  13 +-
 drivers/bluetooth/hci_bcsp.c                       |   2 +-
 drivers/bluetooth/hci_h5.c                         |   2 +-
 drivers/bluetooth/hci_ll.c                         |   2 +-
 drivers/bluetooth/hci_qca.c                        |   2 +-
 drivers/char/hw_random/amd-rng.c                   |  18 +-
 drivers/char/hw_random/geode-rng.c                 |  36 +-
 drivers/char/ipmi/ipmi_msghandler.c                |   8 +-
 drivers/char/ipmi/kcs_bmc_aspeed.c                 |  24 +-
 drivers/char/tpm/tpm_crb.c                         |   2 +-
 drivers/char/tpm/tpm_ftpm_tee.c                    |   8 +-
 drivers/char/tpm/tpm_tis_core.c                    |  20 +-
 drivers/char/tpm/tpm_tis_core.h                    |   1 +
 drivers/char/tpm/tpm_tis_i2c.c                     |   3 +-
 drivers/clk/imx/clk-imx8mn.c                       | 116 ++---
 drivers/clk/imx/clk-imx8mp.c                       |   4 +-
 drivers/clk/imx/clk-imx93.c                        |  19 +-
 drivers/clk/imx/clk-imxrt1050.c                    |   2 +-
 drivers/clk/mediatek/clk-mt7986-infracfg.c         |   2 +-
 drivers/clk/qcom/clk-krait.c                       |   2 +
 drivers/clk/qcom/dispcc-sm6350.c                   |   4 +-
 drivers/clk/qcom/gcc-ipq806x.c                     |   4 +-
 drivers/clk/qcom/gcc-sm8250.c                      |   4 +-
 drivers/clk/qcom/lpassaudiocc-sc7280.c             | 117 +++--
 drivers/clk/qcom/lpasscc-sc7280.c                  |  44 --
 drivers/clk/qcom/lpasscorecc-sc7180.c              |  24 +-
 drivers/clk/qcom/lpasscorecc-sc7280.c              |  33 ++
 drivers/clk/renesas/r8a779a0-cpg-mssr.c            |   2 +-
 drivers/clk/renesas/r8a779f0-cpg-mssr.c            |  29 +-
 drivers/clk/renesas/r9a06g032-clocks.c             |   3 +-
 drivers/clk/rockchip/clk-pll.c                     |   1 +
 drivers/clk/samsung/clk-pll.c                      |   1 +
 drivers/clk/socfpga/clk-gate.c                     |   5 +-
 drivers/clk/st/clkgen-fsyn.c                       |   5 +-
 drivers/clk/visconti/pll.c                         |   1 +
 drivers/clocksource/sh_cmt.c                       |  88 ++--
 drivers/clocksource/timer-ti-dm-systimer.c         |   4 +-
 drivers/clocksource/timer-ti-dm.c                  |   2 +-
 drivers/counter/stm32-lptimer-cnt.c                |   2 +-
 drivers/cpufreq/amd_freq_sensitivity.c             |   2 +
 drivers/cpufreq/qcom-cpufreq-hw.c                  |  43 +-
 drivers/cpuidle/dt_idle_states.c                   |   2 +-
 drivers/crypto/Kconfig                             |   5 +
 .../crypto/allwinner/sun8i-ss/sun8i-ss-cipher.c    |   2 +-
 drivers/crypto/amlogic/amlogic-gxl-core.c          |   1 -
 drivers/crypto/amlogic/amlogic-gxl.h               |   2 +-
 drivers/crypto/cavium/nitrox/nitrox_mbx.c          |   1 +
 drivers/crypto/ccree/cc_debugfs.c                  |   2 +-
 drivers/crypto/ccree/cc_driver.c                   |  10 +-
 drivers/crypto/hisilicon/hpre/hpre_main.c          |  14 +-
 drivers/crypto/hisilicon/qm.c                      | 208 ++++++---
 drivers/crypto/hisilicon/sec2/sec_main.c           |   4 +-
 drivers/crypto/hisilicon/zip/zip_main.c            |   4 +-
 drivers/crypto/img-hash.c                          |   8 +-
 drivers/crypto/omap-sham.c                         |   2 +-
 drivers/crypto/qat/qat_4xxx/adf_drv.c              |   1 +
 drivers/crypto/rockchip/rk3288_crypto.c            | 193 +-------
 drivers/crypto/rockchip/rk3288_crypto.h            |  53 +--
 drivers/crypto/rockchip/rk3288_crypto_ahash.c      | 197 ++++----
 drivers/crypto/rockchip/rk3288_crypto_skcipher.c   | 413 +++++++++-------
 drivers/dio/dio.c                                  |   8 +
 drivers/dma/apple-admac.c                          | 129 ++++-
 drivers/edac/i10nm_base.c                          |   3 +-
 drivers/extcon/Kconfig                             |   2 +-
 drivers/extcon/extcon-usbc-tusb320.c               | 247 ++++++++--
 drivers/firmware/raspberrypi.c                     |   1 +
 drivers/firmware/ti_sci.c                          |   5 +-
 drivers/gpio/gpiolib-cdev.c                        | 204 +++++++-
 drivers/gpio/gpiolib.c                             |   4 +
 drivers/gpio/gpiolib.h                             |   5 +
 drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c   |   2 +-
 drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c           |   1 +
 drivers/gpu/drm/amd/amdgpu/amdgpu_device.c         |   4 +
 drivers/gpu/drm/amd/amdgpu/amdgpu_virt.h           |   5 +-
 drivers/gpu/drm/amd/amdgpu/nv.c                    |  28 +-
 drivers/gpu/drm/amd/amdgpu/soc15.c                 |  24 +-
 drivers/gpu/drm/amd/amdgpu/soc21.c                 |   2 +-
 .../drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c  |  35 --
 drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c |  16 +-
 .../amd/display/dc/clk_mgr/dcn32/dcn32_clk_mgr.c   |   2 +-
 .../gpu/drm/amd/display/dc/dce60/dce60_resource.c  |   3 +
 .../gpu/drm/amd/display/dc/dce80/dce80_resource.c  |   2 +
 .../drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c  |  30 +-
 drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c |  35 +-
 drivers/gpu/drm/amd/display/dc/dcn32/dcn32_dccg.c  |   6 +-
 .../gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c   |   7 +
 drivers/gpu/drm/amd/include/kgd_pp_interface.h     |   3 +-
 drivers/gpu/drm/amd/pm/powerplay/amd_powerplay.c   |   3 +-
 drivers/gpu/drm/amd/pm/powerplay/hwmgr/pp_psm.c    |   2 +
 .../gpu/drm/amd/pm/powerplay/hwmgr/vega20_hwmgr.c  |   3 +-
 drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c     |   4 +
 .../gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c   |  21 +-
 drivers/gpu/drm/bridge/adv7511/adv7511.h           |   3 +-
 drivers/gpu/drm/bridge/adv7511/adv7511_drv.c       |  18 +-
 drivers/gpu/drm/bridge/adv7511/adv7533.c           |  25 +-
 drivers/gpu/drm/bridge/ite-it6505.c                |   8 +-
 drivers/gpu/drm/drm_atomic_helper.c                |  10 +-
 drivers/gpu/drm/drm_edid.c                         |  12 +
 drivers/gpu/drm/drm_fourcc.c                       |   8 +-
 drivers/gpu/drm/etnaviv/etnaviv_gpu.c              |  11 +-
 drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c          |   5 +-
 drivers/gpu/drm/i915/display/intel_bios.c          |   2 +-
 drivers/gpu/drm/i915/display/intel_dp.c            |  59 ---
 drivers/gpu/drm/i915/gt/intel_engine.h             |   6 +
 drivers/gpu/drm/i915/gt/intel_engine_cs.c          |  91 +++-
 drivers/gpu/drm/i915/gt/sysfs_engines.c            |  25 +-
 drivers/gpu/drm/i915/gt/uc/intel_guc.c             |  53 +--
 drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c     | 147 ++++--
 drivers/gpu/drm/i915/gt/uc/intel_guc_capture.h     |   1 -
 drivers/gpu/drm/i915/gt/uc/intel_guc_fwif.h        |  21 +
 drivers/gpu/drm/i915/gt/uc/intel_guc_log.c         | 227 +++++++--
 drivers/gpu/drm/i915/gt/uc/intel_guc_log.h         |  42 +-
 drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c  |   8 +
 drivers/gpu/drm/i915/i915_params.c                 |  12 +
 drivers/gpu/drm/i915/i915_params.h                 |   3 +
 drivers/gpu/drm/mediatek/mtk_dpi.c                 |  12 +-
 drivers/gpu/drm/mediatek/mtk_hdmi.c                |   7 +-
 drivers/gpu/drm/meson/meson_encoder_cvbs.c         |   7 +-
 drivers/gpu/drm/msm/adreno/a6xx_gpu.c              |  12 +-
 drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c        |  25 +-
 drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h        |   2 +-
 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.c         |  79 ++--
 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.h         |   4 +-
 drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c           |  27 +-
 drivers/gpu/drm/msm/dp/dp_display.c                |   2 +-
 drivers/gpu/drm/msm/dsi/dsi.c                      |   2 +-
 drivers/gpu/drm/msm/dsi/dsi.h                      |   2 +-
 drivers/gpu/drm/msm/dsi/dsi_host.c                 | 204 +++-----
 drivers/gpu/drm/msm/hdmi/hdmi.c                    |   2 +-
 drivers/gpu/drm/msm/msm_drv.h                      |   9 +-
 drivers/gpu/drm/mxsfb/lcdif_kms.c                  |  48 +-
 drivers/gpu/drm/mxsfb/lcdif_regs.h                 |   5 +
 drivers/gpu/drm/panel/panel-sitronix-st7701.c      |  10 +-
 drivers/gpu/drm/radeon/radeon_bios.c               |  19 +-
 drivers/gpu/drm/rcar-du/Kconfig                    |   2 -
 drivers/gpu/drm/rockchip/cdn-dp-core.c             |   2 +-
 drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c    |   2 +-
 drivers/gpu/drm/rockchip/inno_hdmi.c               |   2 +-
 drivers/gpu/drm/rockchip/rk3066_hdmi.c             |   2 +-
 drivers/gpu/drm/rockchip/rockchip_drm_vop.c        |   4 +-
 drivers/gpu/drm/rockchip/rockchip_drm_vop2.c       |   2 +-
 drivers/gpu/drm/rockchip/rockchip_lvds.c           |  10 +-
 drivers/gpu/drm/sti/sti_dvo.c                      |   7 +-
 drivers/gpu/drm/sti/sti_hda.c                      |   7 +-
 drivers/gpu/drm/sti/sti_hdmi.c                     |   7 +-
 drivers/gpu/drm/tegra/dc.c                         |   4 +-
 drivers/hid/amd-sfh-hid/amd_sfh_client.c           |   4 +
 drivers/hid/hid-apple.c                            | 118 +++--
 drivers/hid/hid-input.c                            |   6 +
 drivers/hid/hid-logitech-hidpp.c                   |  11 +-
 drivers/hid/hid-mcp2221.c                          |  12 +-
 drivers/hid/hid-rmi.c                              |   2 +
 drivers/hid/hid-sensor-custom.c                    |   2 +-
 drivers/hid/i2c-hid/i2c-hid-core.c                 |   3 +-
 drivers/hid/wacom_sys.c                            |   8 +
 drivers/hid/wacom_wac.c                            |   4 +
 drivers/hid/wacom_wac.h                            |   1 +
 drivers/hsi/controllers/omap_ssi_core.c            |  14 +-
 drivers/hv/ring_buffer.c                           |  13 +
 drivers/hwmon/Kconfig                              |   1 +
 drivers/hwmon/jc42.c                               | 243 ++++++----
 drivers/hwmon/nct6775-platform.c                   |   7 +
 drivers/hwtracing/coresight/coresight-trbe.c       |   1 +
 drivers/i2c/busses/i2c-ismt.c                      |   3 +
 drivers/i2c/busses/i2c-pxa-pci.c                   |  10 +-
 drivers/i2c/muxes/i2c-mux-reg.c                    |   5 +-
 drivers/iio/adc/ad_sigma_delta.c                   |   8 +-
 drivers/iio/adc/ti-adc128s052.c                    |  14 +-
 drivers/iio/addac/ad74413r.c                       |   2 +-
 drivers/iio/imu/adis.c                             |  28 +-
 drivers/iio/industrialio-event.c                   |   4 +-
 drivers/iio/temperature/ltc2983.c                  |  10 +-
 drivers/infiniband/Kconfig                         |   2 +
 drivers/infiniband/core/device.c                   |   2 +-
 drivers/infiniband/core/mad.c                      |   5 -
 drivers/infiniband/core/nldev.c                    |   6 +-
 drivers/infiniband/core/restrack.c                 |   2 -
 drivers/infiniband/core/sysfs.c                    |  17 +-
 drivers/infiniband/hw/hfi1/affinity.c              |   2 +
 drivers/infiniband/hw/hfi1/firmware.c              |   6 +
 drivers/infiniband/hw/hns/Makefile                 |   2 +-
 drivers/infiniband/hw/hns/hns_roce_device.h        |  13 +-
 drivers/infiniband/hw/hns/hns_roce_hw_v2.c         | 257 +++++++---
 drivers/infiniband/hw/hns/hns_roce_hw_v2.h         |  14 +-
 drivers/infiniband/hw/hns/hns_roce_hw_v2_dfx.c     |  34 --
 drivers/infiniband/hw/hns/hns_roce_main.c          |  24 +-
 drivers/infiniband/hw/hns/hns_roce_mr.c            |   4 +-
 drivers/infiniband/hw/hns/hns_roce_qp.c            | 107 ++++-
 drivers/infiniband/hw/hns/hns_roce_restrack.c      |  35 +-
 drivers/infiniband/hw/irdma/uk.c                   | 170 ++++---
 drivers/infiniband/hw/irdma/user.h                 |  20 +-
 drivers/infiniband/hw/irdma/utils.c                |   2 +
 drivers/infiniband/hw/irdma/verbs.c                | 145 ++----
 drivers/infiniband/hw/irdma/verbs.h                |  53 +++
 drivers/infiniband/sw/rxe/rxe_mr.c                 |   9 +-
 drivers/infiniband/sw/rxe/rxe_qp.c                 |   6 +-
 drivers/infiniband/sw/siw/siw_cq.c                 |  24 +-
 drivers/infiniband/sw/siw/siw_qp_tx.c              |   2 +-
 drivers/infiniband/sw/siw/siw_verbs.c              |  40 +-
 drivers/infiniband/ulp/ipoib/ipoib_netlink.c       |   7 +
 drivers/infiniband/ulp/srp/ib_srp.c                |  96 +++-
 drivers/input/joystick/Kconfig                     |   1 +
 drivers/input/misc/Kconfig                         |   2 +-
 drivers/input/misc/iqs7222.c                       | 520 ++++++++++++---------
 drivers/input/touchscreen/elants_i2c.c             |   9 +-
 drivers/interconnect/qcom/sc7180.c                 |   2 +-
 drivers/iommu/amd/iommu_v2.c                       |   1 +
 drivers/iommu/fsl_pamu.c                           |   2 +-
 drivers/iommu/mtk_iommu.c                          |  53 ++-
 drivers/iommu/rockchip-iommu.c                     |  10 +-
 drivers/iommu/s390-iommu.c                         | 106 ++---
 drivers/iommu/sun50i-iommu.c                       |  89 +++-
 drivers/irqchip/irq-gic-pm.c                       |   2 +-
 drivers/irqchip/irq-loongson-liointc.c             |   5 +-
 drivers/irqchip/irq-loongson-pch-pic.c             |   3 +
 drivers/irqchip/irq-wpcm450-aic.c                  |   1 +
 drivers/isdn/hardware/mISDN/hfcmulti.c             |  19 +-
 drivers/isdn/hardware/mISDN/hfcpci.c               |  13 +-
 drivers/isdn/hardware/mISDN/hfcsusb.c              |  12 +-
 drivers/leds/leds-is31fl319x.c                     |   3 +-
 drivers/leds/rgb/leds-qcom-lpg.c                   |  18 +-
 drivers/macintosh/macio-adb.c                      |   4 +
 drivers/macintosh/macio_asic.c                     |   2 +-
 drivers/mailbox/arm_mhuv2.c                        |   4 +-
 drivers/mailbox/mailbox-mpfs.c                     |  31 +-
 drivers/mailbox/pcc.c                              |   1 +
 drivers/mailbox/zynqmp-ipi-mailbox.c               |   4 +-
 drivers/mcb/mcb-core.c                             |   4 +-
 drivers/mcb/mcb-parse.c                            |   2 +-
 drivers/md/dm.c                                    | 123 +++--
 drivers/md/md-bitmap.c                             |  27 +-
 drivers/md/raid0.c                                 |   1 -
 drivers/md/raid1.c                                 |   1 +
 drivers/md/raid10.c                                |   2 -
 drivers/media/dvb-core/dvb_ca_en50221.c            |   2 +-
 drivers/media/dvb-core/dvb_frontend.c              |  10 +-
 drivers/media/dvb-core/dvbdev.c                    |  32 +-
 drivers/media/dvb-frontends/bcm3510.c              |   1 +
 drivers/media/i2c/ad5820.c                         |  10 +-
 drivers/media/i2c/adv748x/adv748x-afe.c            |   4 +
 drivers/media/i2c/dw9768.c                         |  33 +-
 drivers/media/i2c/hi846.c                          |  14 +-
 drivers/media/i2c/mt9p031.c                        |   1 -
 drivers/media/i2c/ov5640.c                         |   3 +-
 drivers/media/i2c/ov5648.c                         |   1 +
 drivers/media/pci/saa7164/saa7164-core.c           |   4 +-
 drivers/media/pci/solo6x10/solo6x10-core.c         |   1 +
 drivers/media/platform/amphion/vdec.c              |  15 +-
 drivers/media/platform/amphion/vpu.h               |   1 +
 drivers/media/platform/amphion/vpu_cmds.c          |  39 +-
 drivers/media/platform/amphion/vpu_drv.c           |   6 +-
 drivers/media/platform/amphion/vpu_malone.c        |   1 +
 drivers/media/platform/amphion/vpu_msgs.c          |   2 +
 drivers/media/platform/amphion/vpu_v4l2.c          |  30 +-
 drivers/media/platform/amphion/vpu_windsor.c       |   1 +
 drivers/media/platform/chips-media/coda-bit.c      |  14 +-
 drivers/media/platform/chips-media/coda-jpeg.c     |  10 +-
 .../mediatek/vcodec/mtk_vcodec_dec_stateless.c     |  13 +-
 .../mediatek/vcodec/vdec/vdec_h264_req_multi_if.c  |  60 ++-
 .../mediatek/vcodec/vdec/vdec_vp9_req_lat_if.c     |  15 +-
 .../platform/mediatek/vcodec/vdec_msg_queue.c      |   2 +-
 drivers/media/platform/nxp/imx-jpeg/mxc-jpeg-hw.c  |   4 +-
 drivers/media/platform/qcom/camss/camss-video.c    |   3 +-
 drivers/media/platform/qcom/camss/camss.c          |  11 +
 drivers/media/platform/qcom/venus/pm_helpers.c     |   4 +-
 .../media/platform/samsung/exynos4-is/fimc-core.c  |   2 +-
 .../media/platform/samsung/exynos4-is/media-dev.c  |  12 +-
 drivers/media/platform/samsung/s5p-mfc/s5p_mfc.c   |  17 +-
 .../platform/st/sti/c8sectpfe/c8sectpfe-core.c     |   1 +
 .../sunxi/sun6i-mipi-csi2/sun6i_mipi_csi2.c        |  23 +-
 .../sun8i-a83t-mipi-csi2/sun8i_a83t_mipi_csi2.c    |  23 +-
 drivers/media/radio/si470x/radio-si470x-usb.c      |   4 +-
 drivers/media/rc/imon.c                            |   6 +-
 drivers/media/test-drivers/vidtv/vidtv_bridge.c    |  22 +-
 drivers/media/test-drivers/vimc/vimc-core.c        |   2 +-
 drivers/media/test-drivers/vivid/vivid-vid-cap.c   |   1 +
 drivers/media/usb/dvb-usb/az6027.c                 |   4 +
 drivers/media/usb/dvb-usb/dvb-usb-init.c           |   4 +-
 drivers/media/v4l2-core/v4l2-ctrls-api.c           |   1 +
 drivers/media/v4l2-core/v4l2-ctrls-core.c          |   2 +-
 drivers/media/v4l2-core/v4l2-ioctl.c               |  34 +-
 drivers/media/v4l2-core/videobuf-dma-contig.c      |  22 +-
 drivers/memory/renesas-rpc-if.c                    |   3 +
 drivers/memstick/core/ms_block.c                   |   9 +-
 drivers/mfd/Kconfig                                |   1 +
 drivers/mfd/axp20x.c                               |   2 +-
 drivers/mfd/qcom-pm8008.c                          |   4 +-
 drivers/mfd/qcom_rpm.c                             |  16 +-
 drivers/misc/cxl/guest.c                           |  24 +-
 drivers/misc/cxl/pci.c                             |  21 +-
 drivers/misc/lkdtm/cfi.c                           |   6 +-
 drivers/misc/ocxl/config.c                         |  20 +-
 drivers/misc/ocxl/file.c                           |   7 +-
 drivers/misc/sgi-gru/grufault.c                    |  13 +-
 drivers/misc/sgi-gru/grumain.c                     |  22 +-
 drivers/misc/sgi-gru/grutables.h                   |   2 +-
 drivers/misc/tifm_7xx1.c                           |   2 +-
 drivers/mmc/core/sd.c                              |  11 +-
 drivers/mmc/host/alcor.c                           |   5 +-
 drivers/mmc/host/atmel-mci.c                       |   9 +-
 drivers/mmc/host/litex_mmc.c                       |   1 +
 drivers/mmc/host/meson-gx-mmc.c                    |   4 +-
 drivers/mmc/host/mmci.c                            |   4 +-
 drivers/mmc/host/moxart-mmc.c                      |   4 +-
 drivers/mmc/host/mxcmmc.c                          |   4 +-
 drivers/mmc/host/omap_hsmmc.c                      |   4 +-
 drivers/mmc/host/pxamci.c                          |   7 +-
 drivers/mmc/host/renesas_sdhi.h                    |   1 +
 drivers/mmc/host/renesas_sdhi_core.c               |  14 +-
 drivers/mmc/host/renesas_sdhi_internal_dmac.c      |   4 +-
 drivers/mmc/host/rtsx_pci_sdmmc.c                  |   9 +-
 drivers/mmc/host/rtsx_usb_sdmmc.c                  |  11 +-
 drivers/mmc/host/sdhci_f_sdh30.c                   |   3 +
 drivers/mmc/host/toshsd.c                          |   6 +-
 drivers/mmc/host/via-sdmmc.c                       |   4 +-
 drivers/mmc/host/vub300.c                          |  11 +-
 drivers/mmc/host/wbsd.c                            |  12 +-
 drivers/mmc/host/wmt-sdmmc.c                       |   6 +-
 drivers/mtd/lpddr/lpddr2_nvm.c                     |   2 +
 drivers/mtd/maps/pxa2xx-flash.c                    |   2 +
 drivers/mtd/mtdcore.c                              |   9 +-
 drivers/mtd/spi-nor/core.c                         |   3 +-
 drivers/mtd/spi-nor/sysfs.c                        |  14 +
 drivers/net/bonding/bond_main.c                    |  37 +-
 drivers/net/can/m_can/m_can.c                      |  32 +-
 drivers/net/can/m_can/m_can_platform.c             |   4 -
 drivers/net/can/m_can/tcan4x5x-core.c              |  18 +-
 drivers/net/can/usb/kvaser_usb/kvaser_usb.h        |  30 +-
 drivers/net/can/usb/kvaser_usb/kvaser_usb_core.c   | 115 ++++-
 drivers/net/can/usb/kvaser_usb/kvaser_usb_hydra.c  | 160 +++++--
 drivers/net/can/usb/kvaser_usb/kvaser_usb_leaf.c   | 437 +++++++++++++++--
 drivers/net/dsa/lan9303-core.c                     |   4 +-
 drivers/net/dsa/mv88e6xxx/chip.c                   |   9 +-
 drivers/net/ethernet/amd/atarilance.c              |   2 +-
 drivers/net/ethernet/amd/lance.c                   |   2 +-
 drivers/net/ethernet/amd/xgbe/xgbe-phy-v2.c        |  23 +-
 drivers/net/ethernet/apple/bmac.c                  |   2 +-
 drivers/net/ethernet/apple/mace.c                  |   2 +-
 drivers/net/ethernet/dnet.c                        |   4 +-
 drivers/net/ethernet/freescale/enetc/enetc.c       |  35 +-
 drivers/net/ethernet/intel/i40e/i40e_main.c        |  36 +-
 drivers/net/ethernet/intel/igb/igb_main.c          |   8 +-
 drivers/net/ethernet/intel/igc/igc.h               |   3 +
 drivers/net/ethernet/intel/igc/igc_defines.h       |   2 +
 drivers/net/ethernet/intel/igc/igc_main.c          | 210 +++++++--
 drivers/net/ethernet/intel/igc/igc_tsn.c           |  13 +-
 drivers/net/ethernet/mediatek/mtk_eth_soc.c        |  71 +--
 drivers/net/ethernet/mediatek/mtk_eth_soc.h        |  11 +-
 drivers/net/ethernet/myricom/myri10ge/myri10ge.c   |   1 +
 drivers/net/ethernet/neterion/s2io.c               |   2 +-
 drivers/net/ethernet/qlogic/qed/qed_debug.c        |   3 +-
 .../ethernet/qlogic/qlcnic/qlcnic_sriov_common.c   |   2 +
 drivers/net/ethernet/rdc/r6040.c                   |   5 +-
 .../net/ethernet/stmicro/stmmac/stmmac_hwtstamp.c  |   3 +-
 drivers/net/ethernet/stmicro/stmmac/stmmac_main.c  |   4 +-
 drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.h   |   2 +-
 .../net/ethernet/stmicro/stmmac/stmmac_selftests.c |   8 +-
 drivers/net/ethernet/ti/am65-cpsw-nuss.c           |  10 +-
 drivers/net/ethernet/ti/netcp_core.c               |   2 +-
 drivers/net/ethernet/xilinx/xilinx_emaclite.c      |   2 +-
 drivers/net/fddi/defxx.c                           |  22 +-
 drivers/net/hamradio/baycom_epp.c                  |   2 +-
 drivers/net/hamradio/scc.c                         |   6 +-
 drivers/net/macsec.c                               |  34 +-
 drivers/net/mctp/mctp-serial.c                     |   6 +-
 drivers/net/ntb_netdev.c                           |   4 +-
 drivers/net/ppp/ppp_generic.c                      |   2 +
 drivers/net/wan/farsync.c                          |   2 +
 drivers/net/wireless/ath/ar5523/ar5523.c           |   6 +
 drivers/net/wireless/ath/ath10k/core.c             |  16 +
 drivers/net/wireless/ath/ath10k/htc.c              |   9 +
 drivers/net/wireless/ath/ath10k/hw.h               |   2 +
 drivers/net/wireless/ath/ath10k/pci.c              |  20 +-
 drivers/net/wireless/ath/ath11k/core.c             |  46 ++
 drivers/net/wireless/ath/ath11k/core.h             |  14 +-
 drivers/net/wireless/ath/ath11k/debugfs.c          | 139 ++----
 drivers/net/wireless/ath/ath11k/debugfs.h          |   6 +-
 drivers/net/wireless/ath/ath11k/mac.c              | 122 +++--
 drivers/net/wireless/ath/ath11k/qmi.c              |   3 +
 drivers/net/wireless/ath/ath11k/wmi.c              |  48 +-
 drivers/net/wireless/ath/ath9k/hif_usb.c           |  46 +-
 .../broadcom/brcm80211/brcmfmac/firmware.c         |   5 +
 .../wireless/broadcom/brcm80211/brcmfmac/pcie.c    |   6 +-
 .../wireless/broadcom/brcm80211/brcmfmac/sdio.c    |   1 +
 drivers/net/wireless/intel/iwlwifi/mei/iwl-mei.h   |   7 +-
 drivers/net/wireless/intel/iwlwifi/mei/main.c      | 172 ++++---
 drivers/net/wireless/intel/iwlwifi/mei/net.c       |  10 +-
 drivers/net/wireless/intel/iwlwifi/mvm/fw.c        |   2 +
 drivers/net/wireless/intel/iwlwifi/mvm/mvm.h       |   4 +-
 drivers/net/wireless/intel/iwlwifi/mvm/ops.c       |   2 +-
 drivers/net/wireless/intel/iwlwifi/mvm/tx.c        |  20 +-
 drivers/net/wireless/mediatek/mt76/mt76.h          |   3 +-
 drivers/net/wireless/mediatek/mt76/mt7915/eeprom.c |  58 +--
 drivers/net/wireless/mediatek/mt76/mt7915/eeprom.h |   5 -
 drivers/net/wireless/mediatek/mt76/mt7915/mac.c    |  23 +-
 drivers/net/wireless/mediatek/mt76/mt7915/pci.c    |  13 +-
 drivers/net/wireless/mediatek/mt76/mt7921/mac.c    |  34 +-
 drivers/net/wireless/mediatek/mt76/usb.c           |  11 +-
 drivers/net/wireless/purelifi/plfxlc/usb.c         |   1 +
 drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h   |   2 +-
 .../net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c  |  28 +-
 drivers/net/wireless/realtek/rtw89/core.c          |   2 +-
 drivers/net/wireless/realtek/rtw89/mac.c           |   6 +-
 drivers/net/wireless/realtek/rtw89/phy.c           |   2 +-
 drivers/net/wireless/rsi/rsi_91x_core.c            |   4 +-
 drivers/net/wireless/rsi/rsi_91x_hal.c             |   6 +-
 drivers/nfc/pn533/pn533.c                          |   4 +
 drivers/nvme/host/core.c                           |  14 +-
 drivers/nvme/target/core.c                         |  22 +-
 drivers/nvme/target/io-cmd-file.c                  |  16 +-
 drivers/nvme/target/nvmet.h                        |   3 +-
 drivers/of/overlay.c                               |   4 +-
 drivers/pci/controller/dwc/pci-imx6.c              |  13 +-
 drivers/pci/controller/dwc/pcie-designware.c       |   2 +-
 drivers/pci/controller/vmd.c                       |  27 +-
 drivers/pci/endpoint/functions/pci-epf-test.c      |   2 +-
 drivers/pci/endpoint/functions/pci-epf-vntb.c      |   2 +-
 drivers/pci/irq.c                                  |   2 +
 drivers/pci/probe.c                                |   3 -
 drivers/perf/arm_dmc620_pmu.c                      |   8 +-
 drivers/perf/arm_dsu_pmu.c                         |   6 +-
 drivers/perf/arm_smmuv3_pmu.c                      |   8 +-
 drivers/perf/hisilicon/hisi_pcie_pmu.c             |   8 +-
 drivers/perf/marvell_cn10k_tad_pmu.c               |   6 +-
 drivers/phy/broadcom/phy-brcm-usb-init-synopsys.c  |   9 +-
 drivers/phy/broadcom/phy-brcm-usb-init.h           |   1 -
 drivers/phy/broadcom/phy-brcm-usb.c                |  14 +-
 drivers/phy/marvell/phy-mvebu-a3700-comphy.c       |   3 +
 drivers/phy/qualcomm/phy-qcom-qmp-pcie.c           |  15 +-
 drivers/phy/qualcomm/phy-qcom-qmp-pcs-v5_20.h      |  14 +
 drivers/phy/qualcomm/phy-qcom-qmp.h                |   1 +
 drivers/pinctrl/mediatek/pinctrl-mt7986.c          |  24 +-
 drivers/pinctrl/pinconf-generic.c                  |   4 +-
 drivers/pinctrl/pinctrl-k210.c                     |   4 +-
 drivers/pinctrl/pinctrl-ocelot.c                   |  20 +-
 drivers/pinctrl/pinctrl-thunderbay.c               |   8 +-
 drivers/platform/chrome/cros_ec_typec.c            |  53 ++-
 drivers/platform/chrome/cros_usbpd_notify.c        |   6 +-
 drivers/platform/mellanox/mlxbf-pmc.c              |   2 +-
 drivers/platform/x86/huawei-wmi.c                  |  20 +-
 .../platform/x86/intel/int3472/clk_and_regulator.c |   3 +-
 drivers/platform/x86/intel_scu_ipc.c               |   2 +-
 drivers/platform/x86/mxm-wmi.c                     |   8 +-
 drivers/pnp/core.c                                 |   4 +-
 drivers/power/supply/ab8500_charger.c              |   9 +-
 drivers/power/supply/bq25890_charger.c             |  71 ++-
 drivers/power/supply/cw2015_battery.c              |  17 +-
 drivers/power/supply/power_supply_core.c           |   7 +-
 drivers/power/supply/z2_battery.c                  |   6 +-
 drivers/pwm/pwm-mediatek.c                         |   2 +-
 drivers/pwm/pwm-mtk-disp.c                         |   5 +-
 drivers/pwm/pwm-sifive.c                           |   5 +-
 drivers/pwm/pwm-tegra.c                            |  15 +-
 drivers/rapidio/devices/rio_mport_cdev.c           |  15 +-
 drivers/rapidio/rio-scan.c                         |   8 +-
 drivers/rapidio/rio.c                              |   9 +-
 drivers/regulator/core.c                           |  25 +-
 drivers/regulator/devres.c                         |   2 +-
 drivers/regulator/of_regulator.c                   |   2 +-
 drivers/regulator/qcom-labibb-regulator.c          |   1 +
 drivers/regulator/qcom-rpmh-regulator.c            |   2 +-
 drivers/regulator/stm32-vrefbuf.c                  |   2 +-
 drivers/remoteproc/qcom_q6v5_pas.c                 |   4 +
 drivers/remoteproc/qcom_q6v5_wcss.c                |   6 +-
 drivers/remoteproc/qcom_sysmon.c                   |   5 +-
 drivers/rtc/class.c                                |   4 +-
 drivers/rtc/rtc-cmos.c                             | 378 +++++++--------
 drivers/rtc/rtc-mxc_v2.c                           |   4 +-
 drivers/rtc/rtc-pcf85063.c                         |  10 +-
 drivers/rtc/rtc-pic32.c                            |   8 +-
 drivers/rtc/rtc-rzn1.c                             |   4 +-
 drivers/rtc/rtc-snvs.c                             |  16 +-
 drivers/rtc/rtc-st-lpc.c                           |   1 +
 drivers/s390/net/ctcm_main.c                       |  11 +-
 drivers/s390/net/lcs.c                             |   8 +-
 drivers/s390/net/netiucv.c                         |   9 +-
 drivers/scsi/elx/efct/efct_driver.c                |   1 +
 drivers/scsi/elx/libefc/efclib.h                   |   6 +-
 drivers/scsi/fcoe/fcoe.c                           |   1 +
 drivers/scsi/fcoe/fcoe_sysfs.c                     |  19 +-
 drivers/scsi/hisi_sas/hisi_sas_main.c              |   8 +-
 drivers/scsi/hpsa.c                                |   9 +-
 drivers/scsi/ipr.c                                 |  10 +-
 drivers/scsi/libsas/sas_ata.c                      |  25 +
 drivers/scsi/libsas/sas_expander.c                 |   4 +-
 drivers/scsi/libsas/sas_internal.h                 |   2 +
 drivers/scsi/lpfc/lpfc_sli.c                       |   6 +-
 drivers/scsi/mpt3sas/mpt3sas_transport.c           |   2 +
 drivers/scsi/qla2xxx/qla_def.h                     |  22 +-
 drivers/scsi/qla2xxx/qla_init.c                    |  20 +-
 drivers/scsi/qla2xxx/qla_inline.h                  |   4 +-
 drivers/scsi/qla2xxx/qla_os.c                      |   4 +-
 drivers/scsi/scsi_debug.c                          |  11 +-
 drivers/scsi/scsi_error.c                          |  14 +-
 drivers/scsi/smartpqi/smartpqi.h                   |   2 +-
 drivers/scsi/smartpqi/smartpqi_init.c              |  77 ++-
 drivers/scsi/snic/snic_disc.c                      |   3 +
 drivers/soc/apple/rtkit.c                          |   7 +-
 drivers/soc/apple/sart.c                           |   7 +-
 drivers/soc/mediatek/mtk-pm-domains.c              |   2 +-
 drivers/soc/qcom/apr.c                             |  15 +-
 drivers/soc/qcom/llcc-qcom.c                       |   2 +-
 drivers/soc/ti/knav_qmss_queue.c                   |   3 +-
 drivers/soc/ti/smartreflex.c                       |   1 +
 drivers/spi/spi-gpio.c                             |  16 +-
 drivers/spi/spi-mt65xx.c                           |   5 +
 drivers/spi/spidev.c                               |  21 +-
 drivers/staging/media/imx/imx7-media-csi.c         |   6 +-
 drivers/staging/media/rkvdec/rkvdec-vp9.c          |   3 +
 drivers/staging/media/stkwebcam/Kconfig            |   2 +-
 drivers/staging/media/sunxi/cedrus/cedrus_h265.c   |  25 +-
 drivers/staging/media/sunxi/cedrus/cedrus_regs.h   |   2 +
 drivers/staging/r8188eu/core/rtw_led.c             |  29 +-
 drivers/staging/r8188eu/core/rtw_pwrctrl.c         |   2 +-
 drivers/staging/rtl8192e/rtllib_rx.c               |   2 +-
 drivers/staging/rtl8192u/ieee80211/ieee80211_rx.c  |   4 +-
 drivers/staging/vme_user/vme_fake.c                |   2 +
 drivers/staging/vme_user/vme_tsi148.c              |   1 +
 drivers/target/iscsi/iscsi_target_nego.c           |  12 +-
 drivers/thermal/imx8mm_thermal.c                   |   8 +-
 drivers/thermal/k3_j72xx_bandgap.c                 |   2 +-
 drivers/thermal/qcom/lmh.c                         |   2 +-
 drivers/thermal/qcom/qcom-spmi-temp-alarm.c        |   3 +-
 drivers/thermal/thermal_core.c                     |  18 +-
 drivers/tty/serial/8250/8250_bcm7271.c             |  10 +-
 drivers/tty/serial/altera_uart.c                   |  21 +-
 drivers/tty/serial/amba-pl011.c                    |  14 +-
 drivers/tty/serial/pch_uart.c                      |   4 +
 drivers/tty/serial/serial-tegra.c                  |   6 +-
 drivers/tty/serial/stm32-usart.c                   |  47 +-
 drivers/tty/serial/sunsab.c                        |   8 +-
 drivers/ufs/core/ufshcd.c                          |  37 +-
 drivers/uio/uio_dmem_genirq.c                      |  13 +-
 drivers/usb/cdns3/cdnsp-ring.c                     |  42 +-
 drivers/usb/core/hcd.c                             |   6 +-
 drivers/usb/dwc3/core.c                            |  23 +-
 drivers/usb/gadget/function/f_hid.c                |  53 ++-
 drivers/usb/gadget/udc/core.c                      |  12 +-
 drivers/usb/gadget/udc/fotg210-udc.c               |  12 +-
 drivers/usb/host/xhci-mtk.c                        |   1 -
 drivers/usb/host/xhci-ring.c                       |  14 +-
 drivers/usb/host/xhci.h                            |   2 +-
 drivers/usb/musb/musb_gadget.c                     |   2 -
 drivers/usb/musb/omap2430.c                        |  54 +++
 drivers/usb/roles/class.c                          |   5 +-
 drivers/usb/storage/alauda.c                       |   2 +
 drivers/usb/typec/bus.c                            |   2 +-
 drivers/usb/typec/tcpm/tcpci.c                     |   5 +-
 drivers/usb/typec/tipd/core.c                      |  11 +-
 drivers/usb/typec/wusb3801.c                       |   2 +-
 drivers/vfio/platform/vfio_platform_common.c       |   3 +-
 drivers/video/fbdev/Kconfig                        |   2 +-
 drivers/video/fbdev/core/fbcon.c                   |   3 +-
 drivers/video/fbdev/ep93xx-fb.c                    |   4 +-
 drivers/video/fbdev/geode/Kconfig                  |   1 +
 drivers/video/fbdev/hyperv_fb.c                    |   8 +-
 drivers/video/fbdev/pm2fb.c                        |   9 +-
 drivers/video/fbdev/uvesafb.c                      |   1 +
 drivers/video/fbdev/vermilion/vermilion.c          |   4 +-
 drivers/video/fbdev/via/via-core.c                 |   9 +-
 drivers/virt/coco/sev-guest/sev-guest.c            |   1 +
 drivers/watchdog/iTCO_wdt.c                        |  21 +-
 drivers/xen/privcmd.c                              |   2 +-
 fs/afs/fs_probe.c                                  |   5 +-
 fs/binfmt_misc.c                                   |   8 +-
 fs/btrfs/file.c                                    |  10 +-
 fs/char_dev.c                                      |   2 +-
 fs/cifs/cifsencrypt.c                              |  12 +-
 fs/cifs/cifsfs.c                                   |  31 +-
 fs/cifs/cifsglob.h                                 | 114 ++++-
 fs/cifs/cifsproto.h                                |  17 +-
 fs/cifs/connect.c                                  |   6 +-
 fs/cifs/dir.c                                      |  30 +-
 fs/cifs/file.c                                     |  41 +-
 fs/cifs/fs_context.c                               |  12 +-
 fs/cifs/inode.c                                    | 167 ++++---
 fs/cifs/link.c                                     | 107 +----
 fs/cifs/misc.c                                     |   6 +-
 fs/cifs/readdir.c                                  |   2 +
 fs/cifs/sess.c                                     |  30 +-
 fs/cifs/smb1ops.c                                  |  56 ++-
 fs/cifs/smb2file.c                                 | 127 ++++-
 fs/cifs/smb2inode.c                                | 169 +++----
 fs/cifs/smb2ops.c                                  | 252 ++++------
 fs/cifs/smb2pdu.c                                  |  20 +-
 fs/cifs/smb2pdu.h                                  |   3 +
 fs/cifs/smb2proto.h                                |  22 +-
 fs/configfs/dir.c                                  |   2 +
 fs/debugfs/file.c                                  |  28 +-
 fs/erofs/decompressor.c                            |  47 +-
 fs/erofs/erofs_fs.h                                |   2 +
 fs/erofs/internal.h                                |   1 +
 fs/erofs/zdata.c                                   |   3 +-
 fs/erofs/zmap.c                                    |  25 +-
 fs/f2fs/compress.c                                 |   2 +-
 fs/f2fs/f2fs.h                                     |   2 +-
 fs/f2fs/file.c                                     |   4 +
 fs/f2fs/gc.c                                       |  10 +-
 fs/f2fs/namei.c                                    | 329 +++++++------
 fs/f2fs/segment.c                                  |   8 +-
 fs/f2fs/super.c                                    |   2 +-
 fs/hfs/inode.c                                     |   2 +
 fs/hfs/trans.c                                     |   2 +-
 fs/hugetlbfs/inode.c                               |   6 +-
 fs/jfs/jfs_dmap.c                                  |  27 +-
 fs/jfs/namei.c                                     |   2 +-
 fs/ksmbd/mgmt/user_session.c                       |   8 +-
 fs/libfs.c                                         |  22 +-
 fs/lockd/svcsubs.c                                 |  17 +-
 fs/nfs/fs_context.c                                |   6 +
 fs/nfs/internal.h                                  |   6 +-
 fs/nfs/namespace.c                                 |   2 +-
 fs/nfs/nfs42xdr.c                                  |   2 +-
 fs/nfs/nfs4proc.c                                  |  38 +-
 fs/nfs/nfs4state.c                                 |   2 +
 fs/nfs/nfs4xdr.c                                   |  22 +-
 fs/nfsd/nfs2acl.c                                  |  10 -
 fs/nfsd/nfs3acl.c                                  |  30 +-
 fs/nfsd/nfs4callback.c                             |   4 +-
 fs/nfsd/nfs4proc.c                                 |   7 +-
 fs/nfsd/nfs4state.c                                |  51 +-
 fs/nilfs2/the_nilfs.c                              |  73 ++-
 fs/ntfs3/bitmap.c                                  |   2 +-
 fs/ntfs3/super.c                                   |   2 +-
 fs/ntfs3/xattr.c                                   |   2 +-
 fs/ocfs2/journal.c                                 |   2 +-
 fs/ocfs2/journal.h                                 |   1 +
 fs/ocfs2/stackglue.c                               |   8 +-
 fs/ocfs2/super.c                                   |   5 +-
 fs/orangefs/orangefs-debugfs.c                     |  29 +-
 fs/orangefs/orangefs-mod.c                         |   8 +-
 fs/orangefs/orangefs-sysfs.c                       |  71 ++-
 fs/overlayfs/file.c                                |  28 +-
 fs/overlayfs/super.c                               |   7 +-
 fs/pstore/Kconfig                                  |   1 +
 fs/pstore/pmsg.c                                   |   7 +-
 fs/pstore/ram.c                                    |   2 +
 fs/pstore/ram_core.c                               |   6 +-
 fs/reiserfs/namei.c                                |   4 +
 fs/reiserfs/xattr_security.c                       |   2 +-
 fs/sysv/itree.c                                    |   2 +-
 fs/udf/namei.c                                     |   8 +-
 fs/xattr.c                                         |   2 +-
 include/drm/drm_connector.h                        |   6 +
 include/drm/ttm/ttm_tt.h                           |   2 +-
 include/dt-bindings/clock/imx8mn-clock.h           |  24 +-
 include/dt-bindings/clock/imx8mp-clock.h           |   3 +-
 .../dt-bindings/clock/qcom,lpassaudiocc-sc7280.h   |   5 +
 .../dt-bindings/clock/qcom,lpasscorecc-sc7280.h    |   2 +
 include/linux/btf_ids.h                            |   2 +-
 include/linux/debugfs.h                            |  19 +-
 include/linux/eventfd.h                            |   2 +-
 include/linux/fortify-string.h                     |  31 +-
 include/linux/fs.h                                 |  12 +-
 include/linux/hisi_acc_qm.h                        |  37 +-
 include/linux/hyperv.h                             |   2 +
 include/linux/ieee80211.h                          |   2 +-
 include/linux/iio/imu/adis.h                       |  13 +-
 include/linux/netdevice.h                          |  58 ++-
 include/linux/proc_fs.h                            |   2 +
 include/linux/regulator/driver.h                   |   3 +-
 include/linux/skmsg.h                              |   1 +
 include/linux/timerqueue.h                         |   2 +-
 include/media/dvbdev.h                             |  32 +-
 include/net/bluetooth/hci.h                        |  20 +
 include/net/bluetooth/hci_core.h                   |   7 +-
 include/net/dst.h                                  |   5 +-
 include/net/ip_vs.h                                |  10 +-
 include/net/mrp.h                                  |   1 +
 include/net/sock_reuseport.h                       |   2 +
 include/net/tcp.h                                  |   4 +-
 include/scsi/sas_ata.h                             |   6 +
 include/sound/hda_codec.h                          |   2 +-
 include/sound/hdaudio.h                            |   1 +
 include/sound/pcm.h                                |  36 +-
 include/trace/events/f2fs.h                        |  34 +-
 include/trace/events/ib_mad.h                      |  13 +-
 include/uapi/linux/idxd.h                          |   2 +-
 include/uapi/linux/swab.h                          |   2 +-
 include/uapi/rdma/hns-abi.h                        |  15 +
 include/uapi/sound/asequencer.h                    |   8 +-
 io_uring/msg_ring.c                                |   2 +
 io_uring/net.c                                     |   2 +-
 io_uring/timeout.c                                 |   4 +-
 ipc/mqueue.c                                       |   6 +-
 kernel/acct.c                                      |   2 +
 kernel/bpf/btf.c                                   |   5 +
 kernel/bpf/syscall.c                               |   6 +-
 kernel/bpf/verifier.c                              | 108 +++--
 kernel/cpu.c                                       |  60 ++-
 kernel/events/core.c                               |   8 +-
 kernel/fork.c                                      |  17 +-
 kernel/futex/core.c                                |  26 +-
 kernel/gcov/gcc_4_7.c                              |   5 +
 kernel/irq/internals.h                             |   2 +
 kernel/irq/irqdesc.c                               |  15 +-
 kernel/kprobes.c                                   |  16 +-
 kernel/module/decompress.c                         |   8 +-
 kernel/padata.c                                    |  15 +-
 kernel/power/snapshot.c                            |   4 +-
 kernel/rcu/tree.c                                  |   2 +-
 kernel/relay.c                                     |   4 +-
 kernel/sched/core.c                                |  10 +-
 kernel/sched/cpudeadline.c                         |   2 +-
 kernel/sched/deadline.c                            |   4 +-
 kernel/sched/fair.c                                | 231 +++++++--
 kernel/sched/psi.c                                 |   8 +-
 kernel/sched/rt.c                                  |   4 +-
 kernel/sched/sched.h                               |  56 ++-
 kernel/trace/blktrace.c                            |   3 +-
 kernel/trace/trace_events_hist.c                   |   2 +-
 kernel/trace/trace_events_user.c                   |   1 +
 lib/debugobjects.c                                 |  10 +
 lib/fonts/fonts.c                                  |   4 +-
 lib/notifier-error-inject.c                        |   2 +-
 lib/test_firmware.c                                |   1 +
 mm/gup.c                                           |   3 +
 net/802/mrp.c                                      |  18 +-
 net/8021q/vlan_dev.c                               |   4 +-
 net/9p/client.c                                    |   5 +
 net/bluetooth/hci_conn.c                           |   2 +-
 net/bluetooth/hci_core.c                           |   4 +-
 net/bluetooth/hci_sync.c                           |   2 +-
 net/bluetooth/lib.c                                |   4 +-
 net/bluetooth/mgmt.c                               |   2 +-
 net/bluetooth/rfcomm/core.c                        |   2 +-
 net/bpf/test_run.c                                 |   3 -
 net/bridge/br_multicast.c                          |   4 +-
 net/bridge/br_vlan.c                               |   4 +-
 net/core/dev.c                                     |  18 +-
 net/core/devlink.c                                 |   9 +-
 net/core/drop_monitor.c                            |   8 +-
 net/core/filter.c                                  |  11 +-
 net/core/gen_stats.c                               |  16 +-
 net/core/skbuff.c                                  |   3 +
 net/core/skmsg.c                                   |   9 +-
 net/core/sock.c                                    |   2 +-
 net/core/sock_map.c                                |   2 +
 net/core/sock_reuseport.c                          |  94 +++-
 net/core/stream.c                                  |   6 +
 net/dsa/slave.c                                    |   4 +-
 net/dsa/tag_8021q.c                                |  11 +-
 net/ethtool/ioctl.c                                |   3 +-
 net/hsr/hsr_debugfs.c                              |  40 +-
 net/hsr/hsr_device.c                               |  32 +-
 net/hsr/hsr_forward.c                              |  14 +-
 net/hsr/hsr_framereg.c                             | 222 ++++-----
 net/hsr/hsr_framereg.h                             |  17 +-
 net/hsr/hsr_main.h                                 |   9 +-
 net/hsr/hsr_netlink.c                              |   4 +-
 net/ipv4/af_inet.c                                 |   8 +-
 net/ipv4/inet_connection_sock.c                    |   5 +-
 net/ipv4/ping.c                                    |   2 +-
 net/ipv4/tcp_bpf.c                                 |  19 +-
 net/ipv4/udp.c                                     |  39 +-
 net/ipv4/udp_tunnel_core.c                         |   1 +
 net/ipv6/af_inet6.c                                |   4 +-
 net/ipv6/datagram.c                                |  15 +-
 net/ipv6/seg6_local.c                              |   4 +-
 net/ipv6/sit.c                                     |  22 +-
 net/ipv6/udp.c                                     |  12 +-
 net/mac80211/cfg.c                                 |   2 +-
 net/mac80211/ieee80211_i.h                         |   1 +
 net/mac80211/iface.c                               |   1 +
 net/mac80211/mlme.c                                |  15 +-
 net/mac80211/sta_info.c                            |   8 +-
 net/mac80211/tx.c                                  |   2 +-
 net/mctp/device.c                                  |  14 +-
 net/mpls/af_mpls.c                                 |   4 +-
 net/netfilter/ipvs/ip_vs_core.c                    |  30 +-
 net/netfilter/ipvs/ip_vs_ctl.c                     |  14 +-
 net/netfilter/ipvs/ip_vs_est.c                     |  20 +-
 net/netfilter/nf_conntrack_proto_icmpv6.c          |  53 +++
 net/netfilter/nf_flow_table_offload.c              |   6 +-
 net/netfilter/nf_tables_api.c                      |   4 +-
 net/openvswitch/datapath.c                         |  29 +-
 net/openvswitch/flow_table.c                       |   9 +-
 net/rxrpc/output.c                                 |   2 +-
 net/rxrpc/sendmsg.c                                |   2 +-
 net/sched/ematch.c                                 |   2 +
 net/sctp/sysctl.c                                  |  73 +--
 net/sunrpc/clnt.c                                  |   2 +-
 net/sunrpc/xprtrdma/verbs.c                        |   2 +-
 net/tls/tls_sw.c                                   |   6 +-
 net/unix/af_unix.c                                 |  12 +-
 net/vmw_vsock/vmci_transport.c                     |   6 +-
 net/wireless/nl80211.c                             |   3 +
 net/wireless/reg.c                                 |   4 +-
 samples/bpf/xdp1_user.c                            |   2 +-
 samples/bpf/xdp2_kern.c                            |   4 +
 samples/vfio-mdev/mdpy-fb.c                        |   8 +-
 security/Kconfig.hardening                         |   3 +
 security/apparmor/apparmorfs.c                     |   4 +-
 security/apparmor/label.c                          |  12 +-
 security/apparmor/lsm.c                            |   4 +-
 security/apparmor/policy.c                         |   2 +-
 security/apparmor/policy_ns.c                      |   2 +-
 security/apparmor/policy_unpack.c                  |   2 +-
 security/integrity/digsig.c                        |   6 +-
 security/integrity/ima/ima_policy.c                |  51 +-
 security/integrity/ima/ima_template.c              |   4 +-
 security/loadpin/loadpin.c                         |  30 +-
 sound/core/pcm_native.c                            |   4 +-
 sound/drivers/mts64.c                              |   3 +
 sound/hda/hdac_stream.c                            |  17 +-
 sound/pci/asihpi/hpioctl.c                         |   2 +-
 sound/pci/hda/hda_codec.c                          |   3 +-
 sound/pci/hda/hda_controller.c                     |   4 +-
 sound/pci/hda/patch_hdmi.c                         | 273 ++++++-----
 sound/pci/hda/patch_realtek.c                      |  27 ++
 sound/soc/amd/yc/acp6x-mach.c                      |   7 +
 sound/soc/codecs/hda.c                             |   3 -
 sound/soc/codecs/hdac_hda.c                        |   3 -
 sound/soc/codecs/pcm512x.c                         |   8 +-
 sound/soc/codecs/rt298.c                           |   7 +
 sound/soc/codecs/rt5670.c                          |   2 -
 sound/soc/codecs/wm8994.c                          |   5 +
 sound/soc/codecs/wsa883x.c                         |   6 +-
 sound/soc/generic/audio-graph-card.c               |   4 +-
 sound/soc/intel/avs/boards/rt298.c                 |  24 +-
 sound/soc/intel/avs/core.c                         |   2 +-
 sound/soc/intel/avs/ipc.c                          |   6 +-
 sound/soc/intel/boards/sof_es8336.c                |   2 +-
 sound/soc/intel/skylake/skl.c                      |   5 +-
 sound/soc/mediatek/common/mtk-btcvsd.c             |   6 +-
 sound/soc/mediatek/mt8173/mt8173-afe-pcm.c         |  20 +-
 sound/soc/mediatek/mt8173/mt8173-rt5650-rt5514.c   |   7 +-
 .../mt8183/mt8183-mt6358-ts3a227-max98357.c        |  14 +-
 sound/soc/pxa/mmp-pcm.c                            |   2 +-
 sound/soc/qcom/lpass-sc7180.c                      |   3 +
 sound/soc/rockchip/rockchip_pdm.c                  |   1 +
 sound/soc/rockchip/rockchip_spdif.c                |   1 +
 sound/usb/quirks-table.h                           |   2 +
 tools/bpf/bpftool/common.c                         |   1 +
 tools/lib/bpf/bpf.h                                |   7 +
 tools/lib/bpf/btf.c                                |   8 +-
 tools/lib/bpf/btf_dump.c                           |  29 +-
 tools/lib/bpf/libbpf.c                             |  30 +-
 tools/lib/bpf/usdt.c                               |  11 +-
 tools/objtool/check.c                              |  10 +
 tools/perf/builtin-stat.c                          |  33 +-
 tools/perf/builtin-trace.c                         |  32 +-
 tools/perf/tests/shell/stat_all_pmu.sh             |  13 +-
 tools/perf/util/bpf_off_cpu.c                      |   2 +-
 tools/perf/util/debug.c                            |   4 +
 tools/perf/util/symbol-elf.c                       |   2 +-
 .../selftests/bpf/bpf_testmod/bpf_testmod.c        |  48 ++
 tools/testing/selftests/bpf/config                 |   1 +
 tools/testing/selftests/bpf/network_helpers.c      |   4 +
 tools/testing/selftests/bpf/prog_tests/empty_skb.c | 146 ++++++
 .../selftests/bpf/prog_tests/kprobe_multi_test.c   |  26 +-
 .../testing/selftests/bpf/prog_tests/lsm_cgroup.c  |  17 +-
 tools/testing/selftests/bpf/prog_tests/map_kptr.c  |   3 +-
 .../selftests/bpf/prog_tests/tracing_struct.c      |  64 +++
 .../selftests/bpf/prog_tests/xdp_adjust_tail.c     |   7 +-
 .../selftests/bpf/prog_tests/xdp_do_redirect.c     |   2 +-
 .../selftests/bpf/prog_tests/xdp_synproxy.c        |   2 +-
 tools/testing/selftests/bpf/progs/bpf_iter_ksym.c  |   6 +-
 tools/testing/selftests/bpf/progs/empty_skb.c      |  37 ++
 tools/testing/selftests/bpf/progs/lsm_cgroup.c     |   8 +
 tools/testing/selftests/bpf/progs/tracing_struct.c | 120 +++++
 tools/testing/selftests/bpf/xdp_synproxy.c         |   5 +-
 tools/testing/selftests/cgroup/cgroup_util.c       |   5 +-
 .../selftests/drivers/net/netdevsim/devlink.sh     |   4 +-
 tools/testing/selftests/efivarfs/efivarfs.sh       |   5 +
 .../ftrace/test.d/ftrace/func_event_triggers.tc    |  15 +-
 .../selftests/netfilter/conntrack_icmp_related.sh  |  36 +-
 .../selftests/powerpc/dscr/dscr_sysfs_test.c       |   5 +-
 tools/testing/selftests/proc/proc-uptime-002.c     |   3 +-
 1027 files changed, 12883 insertions(+), 6780 deletions(-)



^ permalink raw reply	[relevance 1%]

* [PATCH 6.1 0000/1140] 6.1.2-rc2 review
@ 2022-12-30  9:49  1% Greg Kroah-Hartman
  0 siblings, 0 replies; 77+ results
From: Greg Kroah-Hartman @ 2022-12-30  9:49 UTC (permalink / raw)
  To: stable
  Cc: Greg Kroah-Hartman, patches, linux-kernel, torvalds, akpm, linux,
	shuah, patches, lkft-triage, pavel, jonathanh, f.fainelli,
	sudipm.mukherjee, srw, rwarsow

This is the start of the stable review cycle for the 6.1.2 release.
There are 1140 patches in this series, all will be posted as a response
to this one.  If anyone has any issues with these being applied, please
let me know.

Responses should be made by Sun, 01 Jan 2023 09:38:41 +0000.
Anything received after that time might be too late.

The whole patch series can be found in one patch at:
	https://www.kernel.org/pub/linux/kernel/v6.x/stable-review/patch-6.1.2-rc2.gz
or in the git tree and branch at:
	git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable-rc.git linux-6.1.y
and the diffstat can be found below.

thanks,

greg k-h

-------------
Pseudo-Shortlog of commits:

Greg Kroah-Hartman <gregkh@linuxfoundation.org>
    Linux 6.1.2-rc2

Steven Price <steven.price@arm.com>
    pwm: tegra: Fix 32 bit build

Christophe JAILLET <christophe.jaillet@wanadoo.fr>
    mfd: qcom_rpm: Use devm_of_platform_populate() to simplify code

Martin Leung <Martin.Leung@amd.com>
    drm/amd/display: revert Disable DRR actions during state commit

Lin Ma <linma@zju.edu.cn>
    media: dvbdev: fix refcnt bug

Lin Ma <linma@zju.edu.cn>
    media: dvbdev: fix build warning due to comments

Gaosheng Cui <cuigaosheng1@huawei.com>
    net: stmmac: fix errno when create_singlethread_workqueue() fails

Pavel Begunkov <asml.silence@gmail.com>
    io_uring: remove iopoll spinlock

Pavel Begunkov <asml.silence@gmail.com>
    io_uring: protect cq_timeouts with timeout_lock

Pavel Begunkov <asml.silence@gmail.com>
    io_uring/net: fix cleanup after recycle

Jens Axboe <axboe@kernel.dk>
    io_uring/net: ensure compat import handlers clear free_iov

Pavel Begunkov <asml.silence@gmail.com>
    io_uring: improve io_double_lock_ctx fail handling

Pavel Begunkov <asml.silence@gmail.com>
    io_uring: dont remove file from msg_ring reqs

Pavel Begunkov <asml.silence@gmail.com>
    io_uring: add completion locking for iopoll

Stefan Metzmacher <metze@samba.org>
    io_uring/net: introduce IORING_SEND_ZC_REPORT_USAGE flag

Tejun Heo <tj@kernel.org>
    blk-iolatency: Fix memory leak on add_disk() failures

Arun Easi <aeasi@marvell.com>
    scsi: qla2xxx: Fix crash when I/O abort times out

David Hildenbrand <david@redhat.com>
    mm/gup: disallow FOLL_FORCE|FOLL_WRITE on hugetlb mappings

Filipe Manana <fdmanana@suse.com>
    btrfs: do not BUG_ON() on ENOMEM when dropping extent items for a range

Chen Zhongjin <chenzhongjin@huawei.com>
    ovl: fix use inode directly in rcu-walk mode

Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
    fbdev: fbcon: release buffer when fbcon_do_set_font() failed

Liam Howlett <liam.howlett@oracle.com>
    maple_tree: fix mas_spanning_rebalance() on insufficient data

Liam Howlett <liam.howlett@oracle.com>
    test_maple_tree: add test for mas_spanning_rebalance() on insufficient data

Rickard x Andersson <rickaran@axis.com>
    gcov: add support for checksum field

Yuan Can <yuancan@huawei.com>
    floppy: Fix memory leak in do_floppy_init()

Christophe Leroy <christophe.leroy@csgroup.eu>
    spi: fsl_spi: Don't change speed while chipselect is active

Johan Hovold <johan+linaro@kernel.org>
    regulator: core: fix deadlock on regulator enable

Rasmus Villemoes <linux@rasmusvillemoes.dk>
    iio: addac: ad74413r: fix integer promotion bug in ad74413_get_input_current_offset()

Rasmus Villemoes <linux@rasmusvillemoes.dk>
    iio: adc128s052: add proper .data members in adc128_of_match table

Nuno Sá <nuno.sa@analog.com>
    iio: adc: ad_sigma_delta: do not use internal iio_dev lock

Zeng Heng <zengheng4@huawei.com>
    iio: fix memory leak in iio_device_register_eventset()

Roberto Sassu <roberto.sassu@huawei.com>
    reiserfs: Add missing calls to reiserfs_security_free()

Nathan Chancellor <nathan@kernel.org>
    security: Restrict CONFIG_ZERO_CALL_USED_REGS to gcc or clang > 15.0.6

Schspa Shi <schspa@gmail.com>
    9p: set req refcount to zero to avoid uninitialized usage

Isaac J. Manjarres <isaacmanjarres@google.com>
    loop: Fix the max_loop commandline argument treatment when it is set to 0

Enrik Berkhan <Enrik.Berkhan@inka.de>
    HID: mcp2221: don't connect hidraw

Jason Gerecke <killertofu@gmail.com>
    HID: wacom: Ensure bootloader PID is usable in hidraw mode

Mathias Nyman <mathias.nyman@linux.intel.com>
    xhci: Prevent infinite loop in transaction errors recovery for streams

Miaoqian Lin <linmq006@gmail.com>
    usb: dwc3: qcom: Fix memory leak in dwc3_qcom_interconnect_init

Ferry Toth <ftoth@exalondelft.nl>
    usb: dwc3: core: defer probe on ulpi_read_id timeout

Sven Peter <sven@svenpeter.dev>
    usb: dwc3: Fix race between dwc3_set_mode and __dwc3_set_mode

Li Jun <jun.li@nxp.com>
    clk: imx: imx8mp: add shared clk gate for usb suspend clk

Li Jun <jun.li@nxp.com>
    dt-bindings: clocks: imx8mp: Add ID for usb suspend clock

Johan Hovold <johan+linaro@kernel.org>
    arm64: dts: qcom: sm8250: fix USB-DP PHY registers

Johan Hovold <johan+linaro@kernel.org>
    arm64: dts: qcom: sm6350: fix USB-DP PHY registers

Chunfeng Yun <chunfeng.yun@mediatek.com>
    usb: xhci-mtk: fix leakage of shared hcd when fail to set wakeup irq

Pawel Laszczak <pawell@cadence.com>
    usb: cdnsp: fix lack of ZLP for ep0

Bastien Nocera <hadess@hadess.net>
    HID: logitech-hidpp: Guard FF init code against non-USB devices

Jiao Zhou <jiaozhou@google.com>
    ALSA: hda/hdmi: Add HP Device 0x8711 to force connect list

Edward Pacman <edward@edward-p.xyz>
    ALSA: hda/realtek: Add quirk for Lenovo TianYi510Pro-14IOB

wangdicheng <wangdicheng@kylinos.cn>
    ALSA: usb-audio: add the quirk for KT0206 device

Takashi Iwai <tiwai@suse.de>
    ALSA: usb-audio: Workaround for XRUN at prepare

Jeff LaBundy <jeff@labundy.com>
    dt-bindings: input: iqs7222: Add support for IQS7222A v1.13+

Jeff LaBundy <jeff@labundy.com>
    dt-bindings: input: iqs7222: Correct minimum slider size

Jeff LaBundy <jeff@labundy.com>
    dt-bindings: input: iqs7222: Reduce 'linux,code' to optional

Jeff LaBundy <jeff@labundy.com>
    Input: iqs7222 - add support for IQS7222A v1.13+

Jeff LaBundy <jeff@labundy.com>
    Input: iqs7222 - report malformed properties

Jeff LaBundy <jeff@labundy.com>
    Input: iqs7222 - drop unused device node references

GUO Zihua <guozihua@huawei.com>
    ima: Simplify ima_lsm_copy_rule

John Stultz <jstultz@google.com>
    pstore: Make sure CONFIG_PSTORE_PMSG selects CONFIG_RT_MUTEXES

Sami Tolvanen <samitolvanen@google.com>
    cfi: Fix CFI failure with KASAN

David Howells <dhowells@redhat.com>
    afs: Fix lost servers_outstanding count

Michael Petlan <mpetlan@redhat.com>
    perf test: Fix "all PMU test" to skip parametrized events

Sergio Paracuellos <sergio.paracuellos@gmail.com>
    MIPS: ralink: mt7621: avoid to init common ralink reset controller

Yang Jihong <yangjihong1@huawei.com>
    perf probe: Check -v and -q options in the right place

James Clark <james.clark@arm.com>
    perf tools: Make quiet mode consistent between tools

Yang Jihong <yangjihong1@huawei.com>
    perf debug: Set debug_peo_args and redirect_to_stderr variable to correct values in perf_quiet_option()

Arnd Bergmann <arnd@arndb.de>
    drm/amd/pm: avoid large variable on kernel stack

John Stultz <jstultz@google.com>
    pstore: Switch pmsg_lock to an rt_mutex to avoid priority inversion

Kristina Martsenko <kristina.martsenko@arm.com>
    lkdtm: cfi: Make PAC test work with GCC 7 and 8

Kees Cook <keescook@chromium.org>
    LoadPin: Ignore the "contents" argument of the LSM hooks

Khaled Almahallawy <khaled.almahallawy@intel.com>
    drm/i915/display: Don't disable DDI/Transcoder when setting phy test pattern

Hans de Goede <hdegoede@redhat.com>
    ASoC: rt5670: Remove unbalanced pm_runtime_put()

Wang Jingjin <wangjingjin1@huawei.com>
    ASoC: rockchip: spdif: Add missing clk_disable_unprepare() in rk_spdif_runtime_resume()

Marek Szyprowski <m.szyprowski@samsung.com>
    ASoC: wm8994: Fix potential deadlock

Kai Vehmanen <kai.vehmanen@linux.intel.com>
    ALSA: hda/hdmi: fix stream-id config keep-alive for rt suspend

Kai Vehmanen <kai.vehmanen@linux.intel.com>
    ALSA: hda/hdmi: set default audio parameters for KAE silent-stream

Kai Vehmanen <kai.vehmanen@linux.intel.com>
    ALSA: hda/hdmi: fix i915 silent stream programming flow

Wang Yufen <wangyufen@huawei.com>
    ASoC: mediatek: mt8183: fix refcount leak in mt8183_mt6358_ts3a227_max98357_dev_probe()

Wang Jingjin <wangjingjin1@huawei.com>
    ASoC: rockchip: pdm: Add missing clk_disable_unprepare() in rockchip_pdm_runtime_resume()

Wang Yufen <wangyufen@huawei.com>
    ASoC: audio-graph-card: fix refcount leak of cpu_ep in __graph_for_each_link()

Wang Yufen <wangyufen@huawei.com>
    ASoC: mediatek: mt8173-rt5650-rt5514: fix refcount leak in mt8173_rt5650_rt5514_dev_probe()

Cezary Rojewski <cezary.rojewski@intel.com>
    ASoC: Intel: Skylake: Fix driver hang during shutdown

Yang Yingliang <yangyingliang@huawei.com>
    ASoC: sof_es8336: fix possible use-after-free in sof_es8336_remove()

Yang Yingliang <yangyingliang@huawei.com>
    hwmon: (jc42) Fix missing unlock on error in jc42_write()

Zhang Xiaoxu <zhangxiaoxu5@huawei.com>
    orangefs: Fix kmemleak in orangefs_{kernel,client}_debug_init()

Zhang Xiaoxu <zhangxiaoxu5@huawei.com>
    orangefs: Fix kmemleak in orangefs_sysfs_init()

Zhang Xiaoxu <zhangxiaoxu5@huawei.com>
    orangefs: Fix kmemleak in orangefs_prepare_debugfs_help_string()

Maurizio Lombardi <mlombard@redhat.com>
    scsi: target: iscsi: Fix a race condition between login_work and the login thread

Nathan Chancellor <nathan@kernel.org>
    drm/sti: Fix return type of sti_{dvo,hda,hdmi}_connector_mode_valid()

Nathan Chancellor <nathan@kernel.org>
    drm/fsl-dcu: Fix return type of fsl_dcu_drm_connector_mode_valid()

Kumar Meiyappan <Kumar.Meiyappan@microchip.com>
    scsi: smartpqi: Correct device removal for multi-actuator devices

Mike McGowen <mike.mcgowen@microchip.com>
    scsi: smartpqi: Add new controller PCI IDs

Hawkins Jiawei <yin31149@gmail.com>
    hugetlbfs: fix null-ptr-deref in hugetlbfs_parse_param()

Nathan Chancellor <nathan@kernel.org>
    scsi: elx: libefc: Fix second parameter type in state callbacks

Bjorn Helgaas <bhelgaas@google.com>
    Revert "PCI: Clear PCI_STATUS when setting up device"

Kai Ye <yekai13@huawei.com>
    crypto: hisilicon/qm - increase the memory of local variables

Bart Van Assche <bvanassche@acm.org>
    scsi: ufs: Reduce the START STOP UNIT timeout

Justin Tee <justin.tee@broadcom.com>
    scsi: lpfc: Fix hard lockup when reading the rx_monitor from debugfs

Zhiqi Song <songzhiqi1@huawei.com>
    crypto: hisilicon/hpre - fix resource leak in remove process

ChiYuan Huang <cy_huang@richtek.com>
    regulator: core: Fix resolve supply lookup issue

Sven Peter <sven@svenpeter.dev>
    Bluetooth: Add quirk to disable MWS Transport Configuration

Sven Peter <sven@svenpeter.dev>
    Bluetooth: Add quirk to disable extended scanning

Marek Vasut <marex@denx.de>
    Bluetooth: hci_bcm: Add CYW4373A0 support

Jacob Keller <jacob.e.keller@intel.com>
    ice: synchronize the misc IRQ when tearing down Tx tracker

ChiYuan Huang <cy_huang@richtek.com>
    regulator: core: Use different devices for resource allocation and DT lookup

Xiu Jianfeng <xiujianfeng@huawei.com>
    clk: st: Fix memory leak in st_of_quadfs_setup()

Shigeru Yoshida <syoshida@redhat.com>
    media: si470x: Fix use-after-free in si470x_int_in_callback()

Prathamesh Shete <pshete@nvidia.com>
    mmc: sdhci-tegra: Issue CMD and DAT resets together

Wolfram Sang <wsa+renesas@sang-engineering.com>
    mmc: renesas_sdhi: better reset from HS400 mode

Wolfram Sang <wsa+renesas@sang-engineering.com>
    mmc: renesas_sdhi: add quirk for broken register layout

Kunihiko Hayashi <hayashi.kunihiko@socionext.com>
    mmc: f-sdh30: Add quirks for broken timeout clock capability

Hawkins Jiawei <yin31149@gmail.com>
    nfs: fix possible null-ptr-deref when parsing param

James Hilliard <james.hilliard1@gmail.com>
    selftests/bpf: Fix conflicts with built-in functions in bpf_iter_ksym

Denis Pauk <pauk.denis@gmail.com>
    hwmon: (nct6775) add ASUS CROSSHAIR VIII/TUF/ProArt B550M

Lorenzo Bianconi <lorenzo@kernel.org>
    wifi: mt76: do not run mt76u_status_worker if the device is not running

Rui Zhang <zr.zhang@vivo.com>
    regulator: core: fix use_count leakage when handling boot-on

Andrii Nakryiko <andrii@kernel.org>
    libbpf: Avoid enum forward-declarations in public API in C++ mode

Artem Lukyanov <dukzcry@ya.ru>
    ASoC: amd: yc: Add Xiaomi Redmi Book Pro 14 2022 into DMI table

Alvin Lee <Alvin.Lee2@amd.com>
    drm/amd/display: Fix DTBCLK disable requests and SRC_SEL programming

Wesley Chalmers <Wesley.Chalmers@amd.com>
    drm/amd/display: Use the largest vready_offset in pipe group

Liang He <windhl@126.com>
    drm/amdgpu: Fix potential double free and null pointer dereference

John Keeping <john@metanate.com>
    ALSA: usb-audio: Add quirk for Tascam Model 12

Ye Bin <yebin10@huawei.com>
    blk-mq: fix possible memleak when register 'hctx' failed

Yunfei Dong <yunfei.dong@mediatek.com>
    media: mediatek: vcodec: Can't set dst buffer to done when lat decode error

Mazin Al Haddad <mazinalhaddad05@gmail.com>
    media: dvb-usb: fix memory leak in dvb_usb_adapter_init()

Lin Ma <linma@zju.edu.cn>
    media: dvbdev: adopts refcnt to avoid UAF

Yan Lei <yan_lei@dahuatech.com>
    media: dvb-frontends: fix leak of memory fw

Maxim Korotkov <korotkov.maxim.s@gmail.com>
    ethtool: avoiding integer overflow in ethtool_phys_id()

Stanislav Fomichev <sdf@google.com>
    bpf: Prevent decl_tag from being referenced in func_proto arg

Yonghong Song <yhs@fb.com>
    bpf: Fix a BTF_ID_LIST bug with CONFIG_DEBUG_INFO_BTF not set

Ilya Bakoulin <Ilya.Bakoulin@amd.com>
    drm/amd/display: Fix display corruption w/ VSR enable

Stanislav Fomichev <sdf@google.com>
    ppp: associate skb with a device at tx

Kees Cook <keescook@chromium.org>
    bpf/verifier: Use kmalloc_size_roundup() to match ksize() usage

Felix Fietkau <nbd@nbd.name>
    net: ethernet: mtk_eth_soc: drop packets to WDMA if the ring is full

Schspa Shi <schspa@gmail.com>
    mrp: introduce active flags to prevent UAF when applicant uninit

Eric Dumazet <edumazet@google.com>
    ipv6/sit: use DEV_STATS_INC() to avoid data-races

Eric Dumazet <edumazet@google.com>
    net: add atomic_long_t to net_device_stats fields

Sagi Grimberg <sagi@grimberg.me>
    nvme-auth: don't override ctrl keys before validation

Aurabindo Pillai <aurabindo.pillai@amd.com>
    drm/amd/display: fix array index out of bound error in bios parser

George Shen <george.shen@amd.com>
    drm/amd/display: Workaround to increase phantom pipe vactive in pipesplit

Jiang Li <jiang.li@ugreen.com>
    md/raid1: stop mdx_raid1 thread when raid1 array run failed

Xiao Ni <xni@redhat.com>
    md/raid0, raid10: Don't set discard sectors for request queue

Li Zhong <floridsleeves@gmail.com>
    drivers/md/md-bitmap: check the return value of md_bitmap_get_counter()

Nathan Chancellor <nathan@kernel.org>
    drm/mediatek: Fix return type of mtk_hdmi_bridge_mode_valid()

Ville Syrjälä <ville.syrjala@linux.intel.com>
    drm/sti: Use drm_mode_copy()

Ville Syrjälä <ville.syrjala@linux.intel.com>
    drm/rockchip: Use drm_mode_copy()

Ville Syrjälä <ville.syrjala@linux.intel.com>
    drm/msm: Use drm_mode_copy()

Wesley Chalmers <Wesley.Chalmers@amd.com>
    drm/amd/display: Disable DRR actions during state commit

Alvin Lee <Alvin.Lee2@amd.com>
    drm/amd/display: Use min transition for SubVP into MPO

Nathan Chancellor <nathan@kernel.org>
    s390/lcs: Fix return type of lcs_start_xmit()

Nathan Chancellor <nathan@kernel.org>
    s390/netiucv: Fix return type of netiucv_tx()

Nathan Chancellor <nathan@kernel.org>
    s390/ctcm: Fix return type of ctc{mp,}m_tx()

Nathan Chancellor <nathan@kernel.org>
    drm/amdgpu: Fix type of second parameter in odn_edit_dpm_table() callback

Nathan Chancellor <nathan@kernel.org>
    drm/amdgpu: Fix type of second parameter in trans_msg() callback

Kees Cook <keescook@chromium.org>
    igb: Do not free q_vector unless new one was allocated

José Expósito <jose.exposito89@gmail.com>
    HID: uclogic: Add support for XP-PEN Deco LW

José Expósito <jose.exposito89@gmail.com>
    HID: input: do not query XP-PEN Deco LW battery

Jisoo Jang <jisoo.jang@yonsei.ac.kr>
    wifi: brcmfmac: Fix potential NULL pointer dereference in 'brcmf_c_preinit_dcmds()'

Minsuk Kang <linuxlovemin@yonsei.ac.kr>
    wifi: brcmfmac: Fix potential shift-out-of-bounds in brcmf_fw_alloc_request()

Nathan Chancellor <nathan@kernel.org>
    hamradio: baycom_epp: Fix return type of baycom_send_packet()

Nathan Chancellor <nathan@kernel.org>
    net: ethernet: ti: Fix return type of netcp_ndo_start_xmit()

Stanislav Fomichev <sdf@google.com>
    bpf: make sure skb->len != 0 when redirecting to a tunneling device

Nathan Chancellor <nathan@kernel.org>
    drm/meson: Fix return type of meson_encoder_cvbs_mode_valid()

Jiri Slaby (SUSE) <jirislaby@kernel.org>
    qed (gcc13): use u16 for fid to be big enough

Rahul Bhattacharjee <quic_rbhattac@quicinc.com>
    wifi: ath11k: Fix qmi_msg_handler data structure initialization

Kerem Karabay <kekrby@gmail.com>
    HID: apple: enable APPLE_ISO_TILDE_QUIRK for the keyboards of Macs with the T2 chip

Kerem Karabay <kekrby@gmail.com>
    HID: apple: fix key translations where multiple quirks attempt to translate the same key

David Jeffery <djeffery@redhat.com>
    blk-mq: avoid double ->queue_rq() because of early timeout

Yuan Can <yuancan@huawei.com>
    drm/rockchip: use pm_runtime_resume_and_get() instead of pm_runtime_get_sync()

Hamza Mahfooz <hamza.mahfooz@amd.com>
    Revert "drm/amd/display: Limit max DSC target bpp for specific monitors"

Hamza Mahfooz <hamza.mahfooz@amd.com>
    drm/edid: add a quirk for two LG monitors to get them to work on 10bpc

gehao <gehao@kylinos.cn>
    drm/amd/display: prevent memory leak

zhikzhai <zhikai.zhai@amd.com>
    drm/amd/display: skip commit minimal transition state

Kees Cook <keescook@chromium.org>
    bnx2: Use kmalloc_size_roundup() to match ksize() usage

Kees Cook <keescook@chromium.org>
    openvswitch: Use kmalloc_size_roundup() to match ksize() usage

Youghandhar Chintala <quic_youghand@quicinc.com>
    wifi: ath10k: Delay the unmapping of the buffer

Zhang Yuchen <zhangyuchen.lcr@bytedance.com>
    ipmi: fix memleak when unload ipmi driver

Amadeusz Sławiński <amadeuszx.slawinski@linux.intel.com>
    ASoC: Intel: avs: Add quirk for KBL-R RVP platform

Amadeusz Sławiński <amadeuszx.slawinski@linux.intel.com>
    ASoC: codecs: rt298: Add quirk for KBL-R RVP platform

Shigeru Yoshida <syoshida@redhat.com>
    wifi: ar5523: Fix use-after-free on ar5523_cmd() timed out

Fedor Pchelkin <pchelkin@ispras.ru>
    wifi: ath9k: verify the expected usb_endpoints are present

Wright Feng <wright.feng@cypress.com>
    brcmfmac: return error when getting invalid max_flowrings from dongle

Ming Qian <ming.qian@nxp.com>
    media: imx-jpeg: Disable useless interrupt to avoid kernel panic

Doug Brown <doug@schmorgal.com>
    drm/etnaviv: add missing quirks for GC300

ZhangPeng <zhangpeng362@huawei.com>
    hfs: fix OOB Read in __hfs_brec_find

Hans de Goede <hdegoede@redhat.com>
    ACPI: x86: Add skip i2c clients quirk for Medion Lifetab S10346

Josef Bacik <josef@toxicpanda.com>
    btrfs: do not panic if we can't allocate a prealloc extent state

Hans de Goede <hdegoede@redhat.com>
    ACPI: x86: Add skip i2c clients quirk for Lenovo Yoga Tab 3 Pro (YT3-X90F)

Mateusz Jończyk <mat.jonczyk@o2.pl>
    x86/apic: Handle no CONFIG_X86_X2APIC on systems with x2APIC enabled by BIOS

Zheng Yejian <zhengyejian1@huawei.com>
    acct: fix potential integer overflow in encode_comp_t()

Ryusuke Konishi <konishi.ryusuke@gmail.com>
    nilfs2: fix shift-out-of-bounds due to too large exponent of block size

Ryusuke Konishi <konishi.ryusuke@gmail.com>
    nilfs2: fix shift-out-of-bounds/overflow in nilfs_sb2_bad_offset()

Hans de Goede <hdegoede@redhat.com>
    ACPI: video: Add force_native quirk for Sony Vaio VPCY11S1E

Hans de Goede <hdegoede@redhat.com>
    ACPI: video: Add force_vendor quirk for Sony Vaio PCG-FRV35

Hans de Goede <hdegoede@redhat.com>
    ACPI: video: Change Sony Vaio VPCEH3U1E quirk to force_native

Hans de Goede <hdegoede@redhat.com>
    ACPI: video: Change GIGABYTE GB-BXBT-2807 quirk to force_none

Guenter Roeck <linux@roeck-us.net>
    thermal/core: Ensure that thermal device is registered in thermal_zone_get_temp

Rafael J. Wysocki <rafael.j.wysocki@intel.com>
    ACPICA: Fix error code path in acpi_ds_call_control_method()

Mia Kanashi <chad@redpilled.dev>
    ACPI: EC: Add quirk for the HP Pavilion Gaming 15-cx0041ur

Li Zhong <floridsleeves@gmail.com>
    ACPI: processor: idle: Check acpi_fetch_acpi_dev() return value

Hoi Pok Wu <wuhoipok@gmail.com>
    fs: jfs: fix shift-out-of-bounds in dbDiscardAG

Dr. David Alan Gilbert <linux@treblig.org>
    jfs: Fix fortify moan in symlink

Shigeru Yoshida <syoshida@redhat.com>
    udf: Avoid double brelse() in udf_rename()

Dongliang Mu <mudongliangabcd@gmail.com>
    fs: jfs: fix shift-out-of-bounds in dbAllocAG

Marijn Suijten <marijn.suijten@somainline.org>
    arm64: dts: qcom: sm6350: Add apps_smmu with streamID to SDHCI 1/2 nodes

Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
    arm64: dts: qcom: sm8450: disable SDHCI SDR104/SDR50 on all boards

Liu Shixin <liushixin2@huawei.com>
    binfmt_misc: fix shift-out-of-bounds in check_special_flags

Gaurav Kohli <gauravkohli@linux.microsoft.com>
    x86/hyperv: Remove unregister syscore call from Hyper-V cleanup

Guilherme G. Piccoli <gpiccoli@igalia.com>
    video: hyperv_fb: Avoid taking busy spinlock on panic path

Adriana Kobylak <anoo@us.ibm.com>
    ARM: dts: aspeed: rainier,everest: Move reserved memory regions

Mark Rutland <mark.rutland@arm.com>
    arm64: make is_ttbrX_addr() noinstr-safe

Zqiang <qiang1.zhang@intel.com>
    rcu: Fix __this_cpu_read() lockdep warning in rcu_force_quiescent_state()

Wei Fang <wei.fang@nxp.com>
    net: fec: check the return value of build_skb()

Jiasheng Jiang <jiasheng@iscas.ac.cn>
    HID: amd_sfh: Add missing check for dma_alloc_coherent

Matt Johnston <matt@codeconstruct.com.au>
    mctp: Remove device type check at unregister

Arun Ramadoss <arun.ramadoss@microchip.com>
    net: dsa: microchip: remove IRQF_TRIGGER_FALLING in request_threaded_irq

Paulo Alcantara <pc@cjr.nz>
    cifs: don't leak -ENOMEM in smb2_open_file()

Jeremy Kerr <jk@codeconstruct.com.au>
    mctp: serial: Fix starting value for frame check sequence

Eric Dumazet <edumazet@google.com>
    net: stream: purge sk_error_queue in sk_stream_kill_queues()

Christophe JAILLET <christophe.jaillet@wanadoo.fr>
    myri10ge: Fix an error handling path in myri10ge_probe()

David Howells <dhowells@redhat.com>
    rxrpc: Fix missing unlock in rxrpc_do_sendmsg()

Cong Wang <cong.wang@bytedance.com>
    net_sched: reject TCF_EM_SIMPLE case for complex ematch module

Yang Yingliang <yangyingliang@huawei.com>
    mailbox: zynq-ipi: fix error handling while device_register() fails

Yang Yingliang <yangyingliang@huawei.com>
    mailbox: arm_mhuv2: Fix return value check in mhuv2_probe()

Conor Dooley <conor.dooley@microchip.com>
    mailbox: mpfs: read the system controller's status

Subash Abhinov Kasiviswanathan <quic_subashab@quicinc.com>
    skbuff: Account for tail adjustment during pull operations

Jakub Kicinski <kuba@kernel.org>
    devlink: protect devlink dump by the instance lock

Chen-Yu Tsai <wenst@chromium.org>
    arm64: dts: mt8183: Fix Mali GPU clock

Chun-Jie Chen <chun-jie.chen@mediatek.com>
    soc: mediatek: pm-domains: Fix the power glitch issue

Eelco Chaudron <echaudro@redhat.com>
    openvswitch: Fix flow lookup to use unmasked key

Jakub Kicinski <kuba@kernel.org>
    selftests: devlink: fix the fd redirect in dummy_reporter_test

Jakub Kicinski <kuba@kernel.org>
    devlink: hold region lock when flushing snapshots

GUO Zihua <guozihua@huawei.com>
    rtc: mxc_v2: Add missing clk_disable_unprepare()

Tan Tee Min <tee.min.tan@linux.intel.com>
    igc: Set Qbv start_time and end_time to end_time if not being configured in GCL

Tan Tee Min <tee.min.tan@linux.intel.com>
    igc: recalculate Qbv end_time by considering cycle time

Tan Tee Min <tee.min.tan@linux.intel.com>
    igc: allow BaseTime 0 enrollment for Qbv

Muhammad Husaini Zulkifli <muhammad.husaini.zulkifli@intel.com>
    igc: Add checking for basetime less than zero

Vinicius Costa Gomes <vinicius.gomes@intel.com>
    igc: Use strict cycles for Qbv scheduling

Vinicius Costa Gomes <vinicius.gomes@intel.com>
    igc: Enhance Qbv scheduling by using first flag bit

Vladimir Oltean <vladimir.oltean@nxp.com>
    net: dsa: mv88e6xxx: avoid reg_lock deadlock in mv88e6xxx_setup_port()

Li Zetao <lizetao1@huawei.com>
    r6040: Fix kmemleak in probe and remove

Kirill Tkhai <tkhai@ya.ru>
    unix: Fix race in SOCK_SEQPACKET's unix_dgram_sendmsg()

Minsuk Kang <linuxlovemin@yonsei.ac.kr>
    nfc: pn533: Clear nfc_target before being used

Vladimir Oltean <vladimir.oltean@nxp.com>
    net: enetc: avoid buffer leaks on xdp_do_redirect() failure

Hans Verkuil <hverkuil-cisco@xs4all.nl>
    media: v4l2-ctrls-api.c: add back dropped ctrl->is_new = 1

Milan Landaverde <milan@mdaverde.com>
    bpf: prevent leak of lsm program after failed attach

Song Liu <song@kernel.org>
    selftests/bpf: Select CONFIG_FUNCTION_ERROR_INJECTION

Yu Kuai <yukuai3@huawei.com>
    block, bfq: fix possible uaf for 'bfqq->bic'

Yang Yingliang <yangyingliang@huawei.com>
    mISDN: hfcmulti: don't call dev_kfree_skb/kfree_skb() under spin_lock_irqsave()

Yang Yingliang <yangyingliang@huawei.com>
    mISDN: hfcpci: don't call dev_kfree_skb/kfree_skb() under spin_lock_irqsave()

Yang Yingliang <yangyingliang@huawei.com>
    mISDN: hfcsusb: don't call dev_kfree_skb/kfree_skb() under spin_lock_irqsave()

Hangbin Liu <liuhangbin@gmail.com>
    bonding: do failover when high prio link up

Hangbin Liu <liuhangbin@gmail.com>
    bonding: add missed __rcu annotation for curr_active_slave

Emeel Hakim <ehakim@nvidia.com>
    net: macsec: fix net device access prior to holding a lock

Dan Aloni <dan.aloni@vastdata.com>
    nfsd: under NFSv4.1, fix double svc_xprt_put on rpc_create failure

Dan Carpenter <error27@gmail.com>
    iommu/mediatek: Fix forever loop in error handling

Alexandre Belloni <alexandre.belloni@bootlin.com>
    rtc: pcf85063: fix pcf85063_clkout_control

Gaosheng Cui <cuigaosheng1@huawei.com>
    rtc: pic32: Move devm_rtc_allocate_device earlier in pic32_rtc_probe()

Gaosheng Cui <cuigaosheng1@huawei.com>
    rtc: st-lpc: Add missing clk_disable_unprepare in st_rtc_probe()

Qingfang DENG <dqfext@gmail.com>
    netfilter: flowtable: really fix NAT IPv6 offload

Yang Yingliang <yangyingliang@huawei.com>
    mfd: pm8008: Fix return value check in pm8008_probe()

Christophe JAILLET <christophe.jaillet@wanadoo.fr>
    mfd: qcom_rpm: Fix an error handling path in qcom_rpm_probe()

Matti Vaittinen <mazziesaccount@gmail.com>
    mfd: bd957x: Fix Kconfig dependency on REGMAP_IRQ

Samuel Holland <samuel@sholland.org>
    mfd: axp20x: Do not sleep in the power off handler

Bryan O'Donoghue <bryan.odonoghue@linaro.org>
    dt-bindings: mfd: qcom,spmi-pmic: Drop PWM reg dependency

Nathan Lynch <nathanl@linux.ibm.com>
    powerpc/pseries/eeh: use correct API for error log size

Shang XiaoJing <shangxiaojing@huawei.com>
    remoteproc: qcom: q6v5: Fix missing clk_disable_unprepare() in q6v5_wcss_qcs404_power_on()

Yuan Can <yuancan@huawei.com>
    remoteproc: qcom_q6v5_pas: Fix missing of_node_put() in adsp_alloc_memory_region()

Luca Weiss <luca.weiss@fairphone.com>
    remoteproc: qcom_q6v5_pas: detach power domains on remove

Luca Weiss <luca.weiss@fairphone.com>
    remoteproc: qcom_q6v5_pas: disable wakeup on probe fail or remove

Shang XiaoJing <shangxiaojing@huawei.com>
    remoteproc: qcom: q6v5: Fix potential null-ptr-deref in q6v5_wcss_init_mmio()

Gaosheng Cui <cuigaosheng1@huawei.com>
    remoteproc: sysmon: fix memory leak in qcom_add_sysmon_subdev()

Anup Patel <apatel@ventanamicro.com>
    RISC-V: KVM: Fix reg_val check in kvm_riscv_vcpu_set_reg_config()

Daniel Golle <daniel@makrotopia.org>
    pwm: mediatek: always use bus clock for PWM on MT7622

xinlei lee <xinlei.lee@mediatek.com>
    pwm: mtk-disp: Fix the parameters calculated by the enabled flag of disp_pwm

Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
    pwm: sifive: Call pwm_sifive_update_clock() while mutex is held

Jason Gunthorpe <jgg@ziepe.ca>
    iommu/sun50i: Remove IOMMU_DOMAIN_IDENTITY

Guenter Roeck <groeck@chromium.org>
    iommu/mediatek: Validate number of phandles associated with "mediatek,larbs"

Yong Wu <yong.wu@mediatek.com>
    iommu/mediatek: Add error path for loop of mm_dts_parse

Yong Wu <yong.wu@mediatek.com>
    iommu/mediatek: Use component_match_add

Yong Wu <yong.wu@mediatek.com>
    iommu/mediatek: Add platform_device_put for recovering the device refcnt

Miaoqian Lin <linmq006@gmail.com>
    selftests/powerpc: Fix resource leaks

Kajol Jain <kjain@linux.ibm.com>
    powerpc/hv-gpci: Fix hv_gpci event list

Yang Yingliang <yangyingliang@huawei.com>
    powerpc/83xx/mpc832x_rdb: call platform_device_put() in error case in of_fsl_spi_probe()

Nicholas Piggin <npiggin@gmail.com>
    powerpc/perf: callchain validate kernel stack pointer bounds

Pali Rohár <pali@kernel.org>
    powerpc: dts: turris1x.dts: Add channel labels for temperature sensor

Li Huafei <lihuafei1@huawei.com>
    kprobes: Fix check for probe enabled in kill_kprobe()

Nayna Jain <nayna@linux.ibm.com>
    powerpc/pseries: fix plpks_read_var() code for different consumers

Nayna Jain <nayna@linux.ibm.com>
    powerpc/pseries: Return -EIO instead of -EINTR for H_ABORTED error

Nayna Jain <nayna@linux.ibm.com>
    powerpc/pseries: Fix the H_CALL error code in PLPKS driver

Nayna Jain <nayna@linux.ibm.com>
    powerpc/pseries: fix the object owners enum value in plpks driver

Yang Yingliang <yangyingliang@huawei.com>
    powerpc/xive: add missing iounmap() in error path in xive_spapr_populate_irq_data()

Gustavo A. R. Silva <gustavoars@kernel.org>
    powerpc/xmon: Fix -Wswitch-unreachable warning in bpt_cmds

Miaoqian Lin <linmq006@gmail.com>
    cxl: Fix refcount leak in cxl_calc_capp_routing

Christophe JAILLET <christophe.jaillet@wanadoo.fr>
    powerpc/52xx: Fix a resource leak in an error handling path

Xie Shaowen <studentxswpy@163.com>
    macintosh/macio-adb: check the return value of ioremap()

Yang Yingliang <yangyingliang@huawei.com>
    macintosh: fix possible memory leak in macio_add_one_device()

Yuan Can <yuancan@huawei.com>
    iommu/fsl_pamu: Fix resource leak in fsl_pamu_probe()

Yang Yingliang <yangyingliang@huawei.com>
    iommu/amd: Fix pci device refcount leak in ppr_notifier()

Robin Murphy <robin.murphy@arm.com>
    iommu: Avoid races around device probe

Yang Yingliang <yangyingliang@huawei.com>
    iommu/mediatek: Check return value after calling platform_get_resource()

Alexander Stein <alexander.stein@ew.tq-group.com>
    rtc: pcf85063: Fix reading alarm

Stefan Eichenberger <stefan.eichenberger@toradex.com>
    rtc: snvs: Allow a time difference on clock register read

Rafael J. Wysocki <rafael.j.wysocki@intel.com>
    rtc: cmos: Disable ACPI RTC event on removal

Rafael J. Wysocki <rafael.j.wysocki@intel.com>
    rtc: cmos: Rename ACPI-related functions

Rafael J. Wysocki <rafael.j.wysocki@intel.com>
    rtc: cmos: Eliminate forward declarations of some functions

Rafael J. Wysocki <rafael.j.wysocki@intel.com>
    rtc: cmos: Call rtc_wake_setup() from cmos_do_probe()

Rafael J. Wysocki <rafael.j.wysocki@intel.com>
    rtc: cmos: Call cmos_wake_setup() from cmos_do_probe()

Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
    rtc: pcf2127: Convert to .probe_new()

Shang XiaoJing <shangxiaojing@huawei.com>
    rtc: class: Fix potential memleak in devm_rtc_allocate_device()

Yushan Zhou <katrinzhou@tencent.com>
    rtc: rzn1: Check return value in rzn1_rtc_probe

Fenghua Yu <fenghua.yu@intel.com>
    dmaengine: idxd: Fix crc_val field for completion record

Abdun Nihaal <abdun.nihaal@gmail.com>
    fs/ntfs3: Fix slab-out-of-bounds read in ntfs_trim_fs

Manivannan Sadhasivam <mani@kernel.org>
    phy: qcom-qmp-pcie: Fix sm8450_qmp_gen4x2_pcie_pcs_tbl[] register names

Manivannan Sadhasivam <mani@kernel.org>
    phy: qcom-qmp-pcie: Fix high latency with 4x2 PHY when ASPM is enabled

Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
    phy: qcom-qmp-pcie: Support SM8450 PCIe1 PHY in EP mode

Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
    phy: qcom-qmp-pcie: support separate tables for EP mode

Christian Marangi <ansuelsmth@gmail.com>
    phy: qcom-qmp-pcie: split pcs_misc init cfg for ipq8074 pcs table

Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
    phy: qcom-qmp-pcie: split register tables into common and extra parts

Jon Hunter <jonathanh@nvidia.com>
    pwm: tegra: Ensure the clock rate is not less than needed

Jon Hunter <jonathanh@nvidia.com>
    pwm: tegra: Improve required rate calculation

Matt Redfearn <matt.redfearn@mips.com>
    include/uapi/linux/swab: Fix potentially missing __always_inline

Justin Chen <justinpopo6@gmail.com>
    phy: usb: Fix clock imbalance for suspend/resume

Justin Chen <justinpopo6@gmail.com>
    phy: usb: Use slow clock for wake enabled suspend

Al Cooper <alcooperx@gmail.com>
    phy: usb: s2 WoL wakeup_count not incremented for USB->Eth devices

Johan Hovold <johan+linaro@kernel.org>
    phy: qcom-qmp-usb: fix sc8280xp PCS_USB offset

Xiaochen Shen <xiaochen.shen@intel.com>
    dmaengine: idxd: Make read buffer sysfs attributes invisible for Intel IAA

Michael Riesch <michael.riesch@wolfvision.net>
    iommu/rockchip: fix permission bits in page table entries v2

Jernej Skrabec <jernej.skrabec@gmail.com>
    iommu/sun50i: Implement .iotlb_sync_map

Jernej Skrabec <jernej.skrabec@gmail.com>
    iommu/sun50i: Fix flush size

Jernej Skrabec <jernej.skrabec@gmail.com>
    iommu/sun50i: Fix R/W permission check

Jernej Skrabec <jernej.skrabec@gmail.com>
    iommu/sun50i: Consider all fault sources for reset

Jernej Skrabec <jernej.skrabec@gmail.com>
    iommu/sun50i: Fix reset release

Niklas Schnelle <schnelle@linux.ibm.com>
    iommu/s390: Fix duplicate domain attachments

Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
    phy: qcom-qmp-usb: correct registers layout for IPQ8074 USB3 PHY

Johan Hovold <johan+linaro@kernel.org>
    phy: qcom-qmp-usb: drop start and pwrdn-ctrl abstraction

Johan Hovold <johan+linaro@kernel.org>
    phy: qcom-qmp-usb: clean up status polling

Johan Hovold <johan+linaro@kernel.org>
    phy: qcom-qmp-usb: drop power-down delay config

Johan Hovold <johan+linaro@kernel.org>
    phy: qcom-qmp-usb: drop sc8280xp power-down delay

Johan Hovold <johan+linaro@kernel.org>
    phy: qcom-qmp-usb: clean up power-down handling

Johan Hovold <johan+linaro@kernel.org>
    phy: qcom-qmp-pcie: fix ipq6018 initialisation

Johan Hovold <johan+linaro@kernel.org>
    phy: qcom-qmp-pcie: fix ipq8074-gen3 initialisation

Johan Hovold <johan+linaro@kernel.org>
    phy: qcom-qmp-pcie: fix sc8180x initialisation

Johan Hovold <johan+linaro@kernel.org>
    phy: qcom-qmp-pcie: replace power-down delay

Johan Hovold <johan+linaro@kernel.org>
    phy: qcom-qmp-pcie: drop power-down delay config

Shengjiu Wang <shengjiu.wang@nxp.com>
    remoteproc: core: Auto select rproc-virtio device id

Martin Povišer <povik+lin@cutebit.org>
    dmaengine: apple-admac: Allocate cache SRAM to channels

Xiaochen Shen <xiaochen.shen@intel.com>
    dmaengine: idxd: Make max batch size attributes in sysfs invisible for Intel IAA

Johan Hovold <johan+linaro@kernel.org>
    phy: qcom-qmp-pcie: drop bogus register update

Pali Rohár <pali@kernel.org>
    phy: marvell: phy-mvebu-a3700-comphy: Reset COMPHY registers before USB 3.0 power on

Dan Carpenter <error27@gmail.com>
    fs/ntfs3: Harden against integer overflows

Shigeru Yoshida <syoshida@redhat.com>
    fs/ntfs3: Avoid UBSAN error on true_sectors_per_clst()

Arnd Bergmann <arnd@arndb.de>
    RDMA/siw: Fix pointer cast warning

Namhyung Kim <namhyung@kernel.org>
    perf stat: Do not delay the workload with --delay

Ard Biesheuvel <ardb@kernel.org>
    ftrace: Allow WITH_ARGS flavour of graph tracer with shadow call stack

Namhyung Kim <namhyung@kernel.org>
    perf off_cpu: Fix a typo in BTF tracepoint name, it should be 'btf_trace_sched_switch'

Luca Weiss <luca@z3ntu.xyz>
    leds: is31fl319x: Fix setting current limit for is31fl319{0,1,3}

Andreas Gruenbacher <agruenba@redhat.com>
    gfs2: Partially revert gfs2_inode_lookup change

ruanjinjie <ruanjinjie@huawei.com>
    power: supply: fix null pointer dereferencing in power_supply_get_battery_info

James Clark <james.clark@arm.com>
    perf branch: Fix interpretation of branch records

Hans de Goede <hdegoede@redhat.com>
    power: supply: bq25890: Ensure pump_express_work is cancelled on remove

Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
    power: supply: bq25890: Convert to i2c's .probe_new()

Marek Vasut <marex@denx.de>
    power: supply: bq25890: Factor out regulator registration code

Qiheng Lin <linqiheng@huawei.com>
    power: supply: Fix refcount leak in rk817_charger_probe

Yuan Can <yuancan@huawei.com>
    power: supply: ab8500: Fix error handling in ab8500_charger_init()

Yuan Can <yuancan@huawei.com>
    HSI: omap_ssi_core: Fix error handling in ssi_init()

Shang XiaoJing <shangxiaojing@huawei.com>
    power: supply: cw2015: Fix potential null-ptr-deref in cw_bat_probe()

Zhang Qilong <zhangqilong3@huawei.com>
    power: supply: z2_battery: Fix possible memleak in z2_batt_probe()

Ajay Kaher <akaher@vmware.com>
    perf symbol: correction while adjusting symbol

Leo Yan <leo.yan@linaro.org>
    perf trace: Handle failure when trace point folder is missed

Leo Yan <leo.yan@linaro.org>
    perf trace: Use macro RAW_SYSCALL_ARGS_NUM to replace number

Leo Yan <leo.yan@linaro.org>
    perf trace: Return error if a system call doesn't exist

Mika Westerberg <mika.westerberg@linux.intel.com>
    watchdog: iTCO_wdt: Set NO_REBOOT if the watchdog is not already running

Zeng Heng <zengheng4@huawei.com>
    power: supply: fix residue sysfs file in error handle route of __power_supply_register()

Yang Yingliang <yangyingliang@huawei.com>
    HSI: omap_ssi_core: fix possible memory leak in ssi_probe()

Yang Yingliang <yangyingliang@huawei.com>
    HSI: omap_ssi_core: fix unbalanced pm_runtime_disable()

Namhyung Kim <namhyung@kernel.org>
    perf stat: Move common code in print_metric_headers()

Namhyung Kim <namhyung@kernel.org>
    perf stat: Use evsel__is_hybrid() more

James Clark <james.clark@arm.com>
    perf tools: Fix "kernel lock contention analysis" test by not printing warnings in quiet mode

Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
    led: qcom-lpg: Fix sleeping in atomic

Christophe JAILLET <christophe.jaillet@wanadoo.fr>
    fbdev: uvesafb: Fixes an error handling path in uvesafb_probe()

Randy Dunlap <rdunlap@infradead.org>
    fbdev: uvesafb: don't build on UML

Randy Dunlap <rdunlap@infradead.org>
    fbdev: geode: don't build on UML

Gaosheng Cui <cuigaosheng1@huawei.com>
    fbdev: ep93xx-fb: Add missing clk_disable_unprepare in ep93xxfb_probe()

Xiongfeng Wang <wangxiongfeng2@huawei.com>
    fbdev: vermilion: decrease reference count in error path

Shang XiaoJing <shangxiaojing@huawei.com>
    fbdev: via: Fix error in via_core_init()

Yang Yingliang <yangyingliang@huawei.com>
    fbdev: pm2fb: fix missing pci_disable_device()

Andy Shevchenko <andriy.shevchenko@linux.intel.com>
    fbdev: ssd1307fb: Drop optional dependency

Bjorn Andersson <andersson@kernel.org>
    thermal/drivers/qcom/lmh: Fix irq handler return value

Luca Weiss <luca.weiss@fairphone.com>
    thermal/drivers/qcom/temp-alarm: Fix inaccurate warning for gen2

Ido Schimmel <idosch@nvidia.com>
    thermal/of: Fix memory leak on thermal_of_zone_register() failure

Keerthy <j-keerthy@ti.com>
    thermal/drivers/k3_j72xx_bandgap: Fix the debug print message

Marcus Folkesson <marcus.folkesson@gmail.com>
    thermal/drivers/imx8mm_thermal: Validate temperature range

Shang XiaoJing <shangxiaojing@huawei.com>
    samples: vfio-mdev: Fix missing pci_disable_device() in mdpy_fb_probe()

Xiu Jianfeng <xiujianfeng@huawei.com>
    ksmbd: Fix resource leak in ksmbd_session_rpc_open()

Zheng Yejian <zhengyejian1@huawei.com>
    tracing/hist: Fix issue of losting command info in error_log

Yang Yingliang <yangyingliang@huawei.com>
    usb: typec: wusb3801: fix fwnode refcount leak in wusb3801_probe()

Jiasheng Jiang <jiasheng@iscas.ac.cn>
    usb: storage: Add check for kcalloc

Zheyu Ma <zheyuma97@gmail.com>
    i2c: ismt: Fix an out-of-bounds bug in ismt_access()

Yang Yingliang <yangyingliang@huawei.com>
    i2c: mux: reg: check return value after calling platform_get_resource()

Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
    gpiolib: protect the GPIO device against being dropped while in use by user-space

Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
    gpiolib: cdev: fix NULL-pointer dereferences

Chen Zhongjin <chenzhongjin@huawei.com>
    vme: Fix error not catched in fake_init()

YueHaibing <yuehaibing@huawei.com>
    staging: rtl8192e: Fix potential use-after-free in rtllib_rx_Monitor()

Dan Carpenter <error27@gmail.com>
    staging: rtl8192u: Fix use after free in ieee80211_rx()

Hui Tang <tanghui20@huawei.com>
    i2c: pxa-pci: fix missing pci_disable_device() on error in ce4100_i2c_probe

Joao Martins <joao.m.martins@oracle.com>
    vfio/iova_bitmap: refactor iova_bitmap_set() to better handle page boundaries

Yang Yingliang <yangyingliang@huawei.com>
    chardev: fix error handling in cdev_device_add()

Yang Yingliang <yangyingliang@huawei.com>
    mcb: mcb-parse: fix error handing in chameleon_parse_gdd()

Zhengchao Shao <shaozhengchao@huawei.com>
    drivers: mcb: fix resource leak in mcb_probe()

John Keeping <john@metanate.com>
    usb: gadget: f_hid: fix refcount leak on error path

John Keeping <john@metanate.com>
    usb: gadget: f_hid: fix f_hidg lifetime vs cdev

Yang Yingliang <yangyingliang@huawei.com>
    usb: core: hcd: Fix return value check in usb_hcd_setup_local_mem()

Yang Yingliang <yangyingliang@huawei.com>
    usb: roles: fix of node refcount leak in usb_role_switch_is_parent()

Beau Belgrave <beaub@linux.microsoft.com>
    tracing/user_events: Fix call print_fmt leak

Mike Leach <mike.leach@linaro.org>
    coresight: cti: Fix null pointer error on CTI init before ETM

Yang Shen <shenyang39@huawei.com>
    coresight: trbe: remove cpuhp instance node before remove cpuhp state

Fabrice Gasnier <fabrice.gasnier@foss.st.com>
    counter: stm32-lptimer-cnt: fix the check on arr and cmp registers update

Ramona Bolboaca <ramona.bolboaca@analog.com>
    iio: adis: add '__adis_enable_irq()' implementation

Cosmin Tanislav <cosmin.tanislav@analog.com>
    iio: temperature: ltc2983: make bulk write buffer DMA-safe

Yang Yingliang <yangyingliang@huawei.com>
    cxl: fix possible null-ptr-deref in cxl_pci_init_afu|adapter()

Yang Yingliang <yangyingliang@huawei.com>
    cxl: fix possible null-ptr-deref in cxl_guest_init_afu|adapter()

Yang Yingliang <yangyingliang@huawei.com>
    firmware: raspberrypi: fix possible memory leak in rpi_firmware_probe()

Zheng Wang <zyytlz.wz@163.com>
    misc: sgi-gru: fix use-after-free error in gru_set_context_option, gru_fault and gru_handle_user_call_os

ruanjinjie <ruanjinjie@huawei.com>
    misc: tifm: fix possible memory leak in tifm_7xx1_switch_media()

Yang Yingliang <yangyingliang@huawei.com>
    ocxl: fix pci device refcount leak when calling get_function_0()

Yang Yingliang <yangyingliang@huawei.com>
    misc: ocxl: fix possible name leak in ocxl_file_register_afu()

Zhengchao Shao <shaozhengchao@huawei.com>
    test_firmware: fix memory leak in test_firmware_init()

Yang Yingliang <yangyingliang@huawei.com>
    habanalabs: fix return value check in hl_fw_get_sec_attest_data()

Yuan Can <yuancan@huawei.com>
    serial: sunsab: Fix error handling in sunsab_init()

Gabriel Somlo <gsomlo@gmail.com>
    serial: altera_uart: fix locking in polling mode

Xiongfeng Wang <wangxiongfeng2@huawei.com>
    serial: pch: Fix PCI device refcount leak in pch_request_dma()

Valentin Caron <valentin.caron@foss.st.com>
    serial: stm32: move dma_request_chan() before clk_prepare_enable()

delisun <delisun@pateo.com.cn>
    serial: pl011: Do not clear RX FIFO & RX interrupt in unthrottle.

Jiamei Xie <jiamei.xie@arm.com>
    serial: amba-pl011: avoid SBSA UART accessing DMACR register

Jiantao Zhang <water.zhangjiantao@huawei.com>
    USB: gadget: Fix use-after-free during usb config switch

Marek Vasut <marex@denx.de>
    extcon: usbc-tusb320: Update state on probe even if no IRQ pending

Tony Lindgren <tony@atomide.com>
    usb: musb: omap2430: Fix probe regression for missing resources

Sven Peter <sven@svenpeter.dev>
    usb: typec: tipd: Fix typec_unregister_port error paths

Sven Peter <sven@svenpeter.dev>
    usb: typec: tipd: Fix spurious fwnode_handle_put in error path

Sven Peter <sven@svenpeter.dev>
    usb: typec: tipd: Cleanup resources if devm_tps6598_psy_register fails

Yang Yingliang <yangyingliang@huawei.com>
    usb: typec: tcpci: fix of node refcount leak in tcpci_register_port()

Sven Peter <sven@svenpeter.dev>
    usb: typec: Check for ops->exit instead of ops->enter in altmode_exit

Gaosheng Cui <cuigaosheng1@huawei.com>
    staging: vme_user: Fix possible UAF in tsi148_dma_list_add

Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
    interconnect: qcom: sc7180: fix dropped const of qcom_icc_bcm

Linus Walleij <linus.walleij@linaro.org>
    usb: fotg210-udc: Fix ages old endianness issues

Rafael Mendonca <rafaelmendsr@gmail.com>
    uio: uio_dmem_genirq: Fix deadlock between irq config and handling

Rafael Mendonca <rafaelmendsr@gmail.com>
    uio: uio_dmem_genirq: Fix missing unlock in irq configuration

Joao Martins <joao.m.martins@oracle.com>
    vfio/iova_bitmap: Fix PAGE_SIZE unaligned bitmaps

Rafael Mendonca <rafaelmendsr@gmail.com>
    vfio: platform: Do not pass return buffer to ACPI _RST method

Yang Yingliang <yangyingliang@huawei.com>
    class: fix possible memory leak in __class_register()

Duoming Zhou <duoming@zju.edu.cn>
    drivers: staging: r8188eu: Fix sleep-in-atomic-context bug in rtw_join_timeout_handler

Yuan Can <yuancan@huawei.com>
    serial: 8250_bcm7271: Fix error handling in brcmuart_init()

Kartik <kkartik@nvidia.com>
    serial: tegra: Read DMA status before terminating

Yang Yingliang <yangyingliang@huawei.com>
    drivers: dio: fix possible memory leak in dio_init()

Alexandre Ghiti <alexghiti@rivosinc.com>
    riscv: Fix P4D_SHIFT definition for 3-level page table mode

Yangtao Li <frank.li@vivo.com>
    f2fs: fix iostat parameter for discard

Palmer Dabbelt <palmer@rivosinc.com>
    RISC-V: Align the shadow stack

Dragos Tatulea <dtatulea@nvidia.com>
    IB/IPoIB: Fix queue count inconsistency for PKEY child interfaces

Xiongfeng Wang <wangxiongfeng2@huawei.com>
    hwrng: geode - Fix PCI device refcount leak

Xiongfeng Wang <wangxiongfeng2@huawei.com>
    hwrng: amd - Fix PCI device refcount leak

Gaosheng Cui <cuigaosheng1@huawei.com>
    crypto: img-hash - Fix variable dereferenced before check 'hdev->req'

Samuel Holland <samuel@sholland.org>
    riscv: Fix crash during early errata patching

Anup Patel <apatel@ventanamicro.com>
    RISC-V: Fix MEMREMAP_WB for systems with Svpbmt

Andrew Bresticker <abrestic@rivosinc.com>
    RISC-V: Fix unannoted hardirqs-on in return to userspace slow-path

Chengchang Tang <tangchengchang@huawei.com>
    RDMA/hns: Fix XRC caps on HIP08

Chengchang Tang <tangchengchang@huawei.com>
    RDMA/hns: Fix error code of CMD

Chengchang Tang <tangchengchang@huawei.com>
    RDMA/hns: Fix page size cap from firmware

Chengchang Tang <tangchengchang@huawei.com>
    RDMA/hns: Fix PBL page MTR find

Chengchang Tang <tangchengchang@huawei.com>
    RDMA/hns: Fix AH attr queried by query_qp

Yixing Liu <liuyixing1@huawei.com>
    RDMA/hns: Fix the gid problem caused by free mr

Zhang Xiaoxu <zhangxiaoxu5@huawei.com>
    orangefs: Fix sysfs not cleanup when dev init failed

Francisco Munoz <francisco.munoz.ruiz@linux.intel.com>
    PCI: vmd: Fix secondary bus reset for Intel bridges

Wang Yufen <wangyufen@huawei.com>
    RDMA/srp: Fix error return code in srp_parse_options()

Wang Yufen <wangyufen@huawei.com>
    RDMA/hfi1: Fix error return code in parse_platform_config()

Randy Dunlap <rdunlap@infradead.org>
    RDMA: Disable IB HW for UML

Tong Tiangen <tongtiangen@huawei.com>
    riscv/mm: add arch hook arch_clear_hugepage_flags

Shang XiaoJing <shangxiaojing@huawei.com>
    crypto: omap-sham - Use pm_runtime_resume_and_get() in omap_sham_probe()

Christophe JAILLET <christophe.jaillet@wanadoo.fr>
    crypto: amlogic - Remove kcalloc without check

Wang Yufen <wangyufen@huawei.com>
    crypto: qat - fix error return code in adf_probe

Mark Zhang <markzhang@nvidia.com>
    RDMA/nldev: Fix failure to send large messages

Yonggil Song <yonggil.song@samsung.com>
    f2fs: avoid victim selection from previous victim section

Sheng Yong <shengyong@oppo.com>
    f2fs: fix to enable compress for newly created file if extension matches

Sheng Yong <shengyong@oppo.com>
    f2fs: set zstd compress level correctly

Yuan Can <yuancan@huawei.com>
    RDMA/nldev: Add checks for nla_nest_start() in fill_stat_counter_qps()

Bart Van Assche <bvanassche@acm.org>
    scsi: ufs: core: Fix the polling implementation

Gaosheng Cui <cuigaosheng1@huawei.com>
    scsi: snic: Fix possible UAF in snic_tgt_create()

Chen Zhongjin <chenzhongjin@huawei.com>
    scsi: fcoe: Fix transport not deattached when fcoe_if_init() fails

Shang XiaoJing <shangxiaojing@huawei.com>
    scsi: ipr: Fix WARNING in ipr_init()

Yang Yingliang <yangyingliang@huawei.com>
    scsi: scsi_debug: Fix possible name leak in sdebug_add_host_helper()

Yang Yingliang <yangyingliang@huawei.com>
    scsi: fcoe: Fix possible name leak when device_register() fails

Harshit Mogalapalli <harshit.m.mogalapalli@oracle.com>
    scsi: scsi_debug: Fix a warning in resp_report_zones()

Harshit Mogalapalli <harshit.m.mogalapalli@oracle.com>
    scsi: scsi_debug: Fix a warning in resp_verify()

Chen Zhongjin <chenzhongjin@huawei.com>
    scsi: efct: Fix possible memleak in efct_device_init()

Yang Yingliang <yangyingliang@huawei.com>
    scsi: hpsa: Fix possible memory leak in hpsa_add_sas_device()

Yang Yingliang <yangyingliang@huawei.com>
    scsi: hpsa: Fix error handling in hpsa_add_sas_host()

Yang Yingliang <yangyingliang@huawei.com>
    scsi: mpt3sas: Fix possible resource leaks in mpt3sas_transport_port_add()

Weili Qian <qianweili@huawei.com>
    crypto: hisilicon/qm - fix 'QM_XEQ_DEPTH_CAP' mask value

Eric Biggers <ebiggers@google.com>
    crypto: arm64/sm3 - fix possible crash with CFI enabled

Tianjia Zhang <tianjia.zhang@linux.alibaba.com>
    crypto: arm64/sm3 - add NEON assembly implementation

Eric Biggers <ebiggers@google.com>
    crypto: x86/sm4 - fix crash with CFI enabled

Eric Biggers <ebiggers@google.com>
    crypto: x86/sm3 - fix possible crash with CFI enabled

Eric Biggers <ebiggers@google.com>
    crypto: x86/sha512 - fix possible crash with CFI enabled

Eric Biggers <ebiggers@google.com>
    crypto: x86/sha256 - fix possible crash with CFI enabled

Eric Biggers <ebiggers@google.com>
    crypto: x86/sha1 - fix possible crash with CFI enabled

Eric Biggers <ebiggers@google.com>
    crypto: x86/aria - fix crash with CFI enabled

Eric Biggers <ebiggers@google.com>
    crypto: x86/aegis128 - fix possible crash with CFI enabled

Daniel Jordan <daniel.m.jordan@oracle.com>
    padata: Fix list iterator in padata_do_serial()

Daniel Jordan <daniel.m.jordan@oracle.com>
    padata: Always leave BHs disabled when running ->parallel()

Zhang Yiqun <zhangyiqun@phytium.com.cn>
    crypto: tcrypt - Fix multibuffer skcipher speed test mem leak

Yuan Can <yuancan@huawei.com>
    scsi: hpsa: Fix possible memory leak in hpsa_init_one()

Frank Li <frank.li@nxp.com>
    PCI: endpoint: pci-epf-vntb: Fix call pci_epc_mem_free_addr() in error path

Serge Semin <Sergey.Semin@baikalelectronics.ru>
    dt-bindings: visconti-pcie: Fix interrupts array max constraints

Serge Semin <Sergey.Semin@baikalelectronics.ru>
    dt-bindings: imx6q-pcie: Fix clock names for imx6sx and imx8mq

Zhang Xiaoxu <zhangxiaoxu5@huawei.com>
    RDMA/rxe: Fix NULL-ptr-deref in rxe_qp_do_cleanup() when socket create failed

Zhengchao Shao <shaozhengchao@huawei.com>
    RDMA/hns: fix memory leak in hns_roce_alloc_mr()

Mustafa Ismail <mustafa.ismail@intel.com>
    RDMA/irdma: Initialize net_type before checking it

Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
    crypto: ccree - Make cc_debugfs_global_fini() available for module init function

Xiongfeng Wang <wangxiongfeng2@huawei.com>
    RDMA/hfi: Decrease PCI device reference count in error path

Zeng Heng <zengheng4@huawei.com>
    PCI: Check for alloc failure in pci_request_irq()

Luoyouming <luoyouming@huawei.com>
    RDMA/hns: Fix incorrect sge nums calculation

Luoyouming <luoyouming@huawei.com>
    RDMA/hns: Fix ext_sge num error when post send

Li Zhijian <lizhijian@fujitsu.com>
    RDMA/rxe: Fix mr->map double free

Xiongfeng Wang <wangxiongfeng2@huawei.com>
    crypto: hisilicon/qm - add missing pci_dev_put() in q_num_set()

Herbert Xu <herbert@gondor.apana.org.au>
    crypto: cryptd - Use request context instead of stack for sub-request

Gaosheng Cui <cuigaosheng1@huawei.com>
    crypto: ccree - Remove debugfs when platform_driver_register failed

Harshit Mogalapalli <harshit.m.mogalapalli@oracle.com>
    scsi: scsi_debug: Fix a warning in resp_write_scat()

Mustafa Ismail <mustafa.ismail@intel.com>
    RDMA/irdma: Do not request 2-level PBLEs for CQ alloc

Mustafa Ismail <mustafa.ismail@intel.com>
    RDMA/irdma: Fix RQ completion opcode

Mustafa Ismail <mustafa.ismail@intel.com>
    RDMA/irdma: Fix inline for multiple SGE's

Bernard Metzler <bmt@zurich.ibm.com>
    RDMA/siw: Set defined status for work completion with undefined status

Mark Zhang <markzhang@nvidia.com>
    RDMA/nldev: Return "-EAGAIN" if the cm_id isn't from expected port

Mark Zhang <markzhang@nvidia.com>
    RDMA/core: Make sure "ib_port" is valid when access sysfs node

Mark Zhang <markzhang@nvidia.com>
    RDMA/restrack: Release MR restrack when delete

Chao Yu <chao@kernel.org>
    f2fs: fix to avoid accessing uninitialized spinlock

Sascha Hauer <s.hauer@pengutronix.de>
    PCI: imx6: Initialize PHY before deasserting core reset

Nirmal Patel <nirmal.patel@linux.intel.com>
    PCI: vmd: Disable MSI remapping after suspend

Leonid Ravich <lravich@gmail.com>
    IB/mad: Don't call to function that might sleep while in atomic context

Bernard Metzler <bmt@zurich.ibm.com>
    RDMA/siw: Fix immediate work request flush to completion queue

Bart Van Assche <bvanassche@acm.org>
    scsi: qla2xxx: Fix set-but-not-used variable warnings

Shiraz Saleem <shiraz.saleem@intel.com>
    RDMA/irdma: Report the correct link speed

Chao Yu <chao@kernel.org>
    f2fs: fix to destroy sbi->post_read_wq in error path of f2fs_fill_super()

Mukesh Ojha <quic_mojha@quicinc.com>
    f2fs: fix the assign logic of iocb

Jaegeuk Kim <jaegeuk@kernel.org>
    f2fs: allow to set compression for inlined file

Dongdong Zhang <zhangdongdong1@oppo.com>
    f2fs: fix normal discard process

Yangtao Li <frank.li@vivo.com>
    f2fs: fix gc mode when gc_urgent_high_remaining is 1

Chao Yu <chao@kernel.org>
    f2fs: fix to invalidate dcc->f2fs_issue_discard in error path

Kees Cook <keescook@chromium.org>
    fortify: Do not cast to "unsigned char"

Xiu Jianfeng <xiujianfeng@huawei.com>
    apparmor: Fix memleak in alloc_ns()

Corentin Labbe <clabbe@baylibre.com>
    crypto: rockchip - rework by using crypto_engine

Corentin Labbe <clabbe@baylibre.com>
    crypto: rockchip - remove non-aligned handling

Corentin Labbe <clabbe@baylibre.com>
    crypto: rockchip - better handle cipher key

Corentin Labbe <clabbe@baylibre.com>
    crypto: rockchip - add fallback for ahash

Corentin Labbe <clabbe@baylibre.com>
    crypto: rockchip - add fallback for cipher

Corentin Labbe <clabbe@baylibre.com>
    crypto: rockchip - do not store mode globally

Corentin Labbe <clabbe@baylibre.com>
    crypto: rockchip - do not do custom power management

Zhang Qilong <zhangqilong3@huawei.com>
    f2fs: Fix the race condition of resize flag between resizefs

Kunihiko Hayashi <hayashi.kunihiko@socionext.com>
    PCI: pci-epf-test: Register notifier if only core_init_notifier is enabled

Leon Romanovsky <leon@kernel.org>
    RDMA/core: Fix order of nldev_exit call

Vidya Sagar <vidyas@nvidia.com>
    PCI: dwc: Fix n_fts[] array overrun

Xiu Jianfeng <xiujianfeng@huawei.com>
    apparmor: Use pointer to struct aa_label for lbs_cred

Bart Van Assche <bvanassche@acm.org>
    scsi: core: Fix a race between scsi_done() and scsi_timeout()

Robert Elliott <elliott@hpe.com>
    crypto: tcrypt - fix return value for multiple subtests

Natalia Petrova <n.petrova@fintech.ru>
    crypto: nitrox - avoid double free on error path in nitrox_sriov_init()

Corentin Labbe <clabbe@baylibre.com>
    crypto: sun8i-ss - use dma_addr instead u32

Weili Qian <qianweili@huawei.com>
    crypto: hisilicon/qm - re-enable communicate interrupt before notifying PF

Weili Qian <qianweili@huawei.com>
    crypto: hisilicon/qm - fix incorrect parameters usage

John Johansen <john.johansen@canonical.com>
    apparmor: Fix regression in stacking due to label flags

John Johansen <john.johansen@canonical.com>
    apparmor: Fix abi check to include v8 abi

John Johansen <john.johansen@canonical.com>
    apparmor: fix lockdep warning when removing a namespace

Gaosheng Cui <cuigaosheng1@huawei.com>
    apparmor: fix a memleak in multi_transaction_new()

Vladimir Oltean <vladimir.oltean@nxp.com>
    net: dsa: tag_8021q: avoid leaking ctx on dsa_tag_8021q_register() error path

Bartosz Staszewski <bartoszx.staszewski@intel.com>
    i40e: Fix the inability to attach XDP program on downed interface

Piergiorgio Beruto <piergiorgio.beruto@gmail.com>
    stmmac: fix potential division by 0

Christophe JAILLET <christophe.jaillet@wanadoo.fr>
    octeontx2-af: cn10k: mcs: Fix a resource leak in the probe and remove functions

Yang Yingliang <yangyingliang@huawei.com>
    Bluetooth: RFCOMM: don't call kfree_skb() under spin_lock_irqsave()

Yang Yingliang <yangyingliang@huawei.com>
    Bluetooth: hci_core: don't call kfree_skb() under spin_lock_irqsave()

Yang Yingliang <yangyingliang@huawei.com>
    Bluetooth: hci_bcsp: don't call kfree_skb() under spin_lock_irqsave()

Yang Yingliang <yangyingliang@huawei.com>
    Bluetooth: hci_h5: don't call kfree_skb() under spin_lock_irqsave()

Yang Yingliang <yangyingliang@huawei.com>
    Bluetooth: hci_ll: don't call kfree_skb() under spin_lock_irqsave()

Yang Yingliang <yangyingliang@huawei.com>
    Bluetooth: hci_qca: don't call kfree_skb() under spin_lock_irqsave()

Yang Yingliang <yangyingliang@huawei.com>
    Bluetooth: btusb: don't call kfree_skb() under spin_lock_irqsave()

Wang ShaoBo <bobo.shaobowang@huawei.com>
    Bluetooth: btintel: Fix missing free skb in btintel_setup_combined()

Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
    Bluetooth: hci_conn: Fix crash on hci_create_cis_sync

Christophe JAILLET <christophe.jaillet@wanadoo.fr>
    Bluetooth: Fix EALREADY and ELOOP cases in bt_status()

Inga Stotland <inga.stotland@intel.com>
    Bluetooth: MGMT: Fix error report for ADD_EXT_ADV_PARAMS

Yang Yingliang <yangyingliang@huawei.com>
    Bluetooth: hci_core: fix error handling in hci_register_dev()

Firo Yang <firo.yang@suse.com>
    sctp: sysctl: make extra pointers netns aware

Eric Pilmore <epilmore@gigaio.com>
    ntb_netdev: Use dev_kfree_skb_any() in interrupt context

Jerry Ray <jerry.ray@microchip.com>
    net: lan9303: Fix read error execution path

Roger Quadros <rogerq@kernel.org>
    net: ethernet: ti: am65-cpsw: Fix PM runtime leakage in am65_cpsw_nuss_ndo_slave_open()

Markus Schneider-Pargmann <msp@baylibre.com>
    can: tcan4x5x: Fix use of register error status mask

Vivek Yadav <vivek.2311@samsung.com>
    can: m_can: Call the RAM init directly from m_can_chip_config

Markus Schneider-Pargmann <msp@baylibre.com>
    can: tcan4x5x: Remove invalid write in clear_interrupts

Tom Lendacky <thomas.lendacky@amd.com>
    net: amd-xgbe: Check only the minimum speed for active/passive cables

Tom Lendacky <thomas.lendacky@amd.com>
    net: amd-xgbe: Fix logic around active and passive cables

Yang Yingliang <yangyingliang@huawei.com>
    af_unix: call proto_unregister() in the error path in af_unix_init()

Richard Gobert <richardbgobert@gmail.com>
    net: setsockopt: fix IPV6_UNICAST_IF option for connected sockets

Yang Yingliang <yangyingliang@huawei.com>
    net: amd: lance: don't call dev_kfree_skb() under spin_lock_irqsave()

Yang Yingliang <yangyingliang@huawei.com>
    hamradio: don't call dev_kfree_skb() under spin_lock_irqsave()

Yang Yingliang <yangyingliang@huawei.com>
    net: ethernet: dnet: don't call dev_kfree_skb() under spin_lock_irqsave()

Yang Yingliang <yangyingliang@huawei.com>
    net: emaclite: don't call dev_kfree_skb() under spin_lock_irqsave()

Yang Yingliang <yangyingliang@huawei.com>
    net: apple: bmac: don't call dev_kfree_skb() under spin_lock_irqsave()

Yang Yingliang <yangyingliang@huawei.com>
    net: apple: mace: don't call dev_kfree_skb() under spin_lock_irqsave()

Hangbin Liu <liuhangbin@gmail.com>
    net/tunnel: wait until all sk_user_data reader finish before releasing the sock

Li Zetao <lizetao1@huawei.com>
    net: farsync: Fix kmemleak when rmmods farsync

Yang Yingliang <yangyingliang@huawei.com>
    ethernet: s2io: don't call dev_kfree_skb() under spin_lock_irqsave()

ruanjinjie <ruanjinjie@huawei.com>
    of: overlay: fix null pointer dereferencing in find_dup_cset_node_entry() and find_dup_cset_prop()

Julian Anastasov <ja@ssi.bg>
    ipvs: use u64_stats_t for the per-cpu counters

Yuan Can <yuancan@huawei.com>
    drivers: net: qlcnic: Fix potential memory leak in qlcnic_sriov_init()

Gaosheng Cui <cuigaosheng1@huawei.com>
    net: stmmac: fix possible memory leak in stmmac_dvr_probe()

Zhang Changzhong <zhangchangzhong@huawei.com>
    net: stmmac: selftests: fix potential memleak in stmmac_test_arpoffload()

Yongqiang Liu <liuyongqiang13@huawei.com>
    net: defxx: Fix missing err handling in dfx_init()

Artem Chernyshev <artem.chernyshev@red-soft.ru>
    net: vmw_vsock: vmci: Check memcpy_from_msg()

Xiu Jianfeng <xiujianfeng@huawei.com>
    clk: socfpga: Fix memory leak in socfpga_gate_init()

Björn Töpel <bjorn@rivosinc.com>
    bpf: Do not zero-extend kfunc return values

Yang Jihong <yangjihong1@huawei.com>
    blktrace: Fix output non-blktrace event when blk_classic option enabled

Wang Yufen <wangyufen@huawei.com>
    wifi: brcmfmac: Fix error return code in brcmf_sdio_download_firmware()

Bitterblue Smith <rtl8821cerfe2@gmail.com>
    wifi: rtl8xxxu: Fix the channel width reporting

Bitterblue Smith <rtl8821cerfe2@gmail.com>
    wifi: rtl8xxxu: Add __packed to struct rtl8723bu_c2h

Kris Bahnsen <kris@embeddedTS.com>
    spi: spi-gpio: Don't set MOSI as an input if not 3WIRE mode

Xiu Jianfeng <xiujianfeng@huawei.com>
    clk: samsung: Fix memory leak in _samsung_clk_register_pll()

Geert Uytterhoeven <geert+renesas@glider.be>
    media: staging: stkwebcam: Restore MEDIA_{USB,CAMERA}_SUPPORT dependencies

Jiasheng Jiang <jiasheng@iscas.ac.cn>
    media: coda: Add check for kmalloc

Jiasheng Jiang <jiasheng@iscas.ac.cn>
    media: coda: Add check for dcoda_iram_alloc

Liang He <windhl@126.com>
    media: c8sectpfe: Add of_node_put() when breaking out of loop

Yuan Can <yuancan@huawei.com>
    regulator: qcom-labibb: Fix missing of_node_put() in qcom_labibb_regulator_probe()

Christoph Hellwig <hch@lst.de>
    nvme: pass nr_maps explicitly to nvme_alloc_io_tag_set

Zhen Lei <thunder.leizhen@huawei.com>
    mmc: core: Normalize the error handling branch in sd_read_ext_regs()

Jiasheng Jiang <jiasheng@iscas.ac.cn>
    memstick/ms_block: Add check for alloc_ordered_workqueue

Wolfram Sang <wsa+renesas@sang-engineering.com>
    mmc: renesas_sdhi: alway populate SCC pointer

Yang Yingliang <yangyingliang@huawei.com>
    mmc: mmci: fix return value check of mmc_add_host()

Yang Yingliang <yangyingliang@huawei.com>
    mmc: wbsd: fix return value check of mmc_add_host()

Yang Yingliang <yangyingliang@huawei.com>
    mmc: via-sdmmc: fix return value check of mmc_add_host()

Yang Yingliang <yangyingliang@huawei.com>
    mmc: meson-gx: fix return value check of mmc_add_host()

Yang Yingliang <yangyingliang@huawei.com>
    mmc: omap_hsmmc: fix return value check of mmc_add_host()

Yang Yingliang <yangyingliang@huawei.com>
    mmc: atmel-mci: fix return value check of mmc_add_host()

Gabriel Somlo <gsomlo@gmail.com>
    mmc: litex_mmc: ensure `host->irq == 0` if polling

Yang Yingliang <yangyingliang@huawei.com>
    mmc: wmt-sdmmc: fix return value check of mmc_add_host()

Yang Yingliang <yangyingliang@huawei.com>
    mmc: vub300: fix return value check of mmc_add_host()

Yang Yingliang <yangyingliang@huawei.com>
    mmc: toshsd: fix return value check of mmc_add_host()

Yang Yingliang <yangyingliang@huawei.com>
    mmc: rtsx_usb_sdmmc: fix return value check of mmc_add_host()

Yang Yingliang <yangyingliang@huawei.com>
    mmc: rtsx_pci: fix return value check of mmc_add_host()

Yang Yingliang <yangyingliang@huawei.com>
    mmc: pxamci: fix return value check of mmc_add_host()

Yang Yingliang <yangyingliang@huawei.com>
    mmc: mxcmmc: fix return value check of mmc_add_host()

Yang Yingliang <yangyingliang@huawei.com>
    mmc: moxart: fix return value check of mmc_add_host()

Yang Yingliang <yangyingliang@huawei.com>
    mmc: alcor: fix return value check of mmc_add_host()

Xingjiang Qiao <nanpuyue@gmail.com>
    hwmon: (emc2305) fix pwm never being able to set lower

Xingjiang Qiao <nanpuyue@gmail.com>
    hwmon: (emc2305) fix unable to probe emc2301/2/3

Miaoqian Lin <linmq006@gmail.com>
    bpftool: Fix memory leak in do_build_table_cb

Pu Lehui <pulehui@huawei.com>
    riscv, bpf: Emit fixed-length instructions for BPF_PSEUDO_FUNC

Trond Myklebust <trond.myklebust@hammerspace.com>
    NFSv4.x: Fail client initialisation if state manager thread can't run

Anna Schumaker <Anna.Schumaker@Netapp.com>
    NFS: Allow very small rsize & wsize again

Anna Schumaker <Anna.Schumaker@Netapp.com>
    NFSv4.2: Set the correct size scratch buffer for decoding READ_PLUS

Wang ShaoBo <bobo.shaobowang@huawei.com>
    SUNRPC: Fix missing release socket in rpc_sockname()

Zhang Xiaoxu <zhangxiaoxu5@huawei.com>
    xprtrdma: Fix regbuf data not freed in rpcrdma_req_create()

Gaosheng Cui <cuigaosheng1@huawei.com>
    pinctrl: thunderbay: fix possible memory leak in thunderbay_build_functions()

Gaosheng Cui <cuigaosheng1@huawei.com>
    ALSA: mts64: fix possible null-ptr-defer in snd_mts64_interrupt

Guoniu.zhou <guoniu.zhou@nxp.com>
    media: ov5640: set correct default link frequency

Liu Shixin <liushixin2@huawei.com>
    media: saa7164: fix missing pci_disable_device()

Takashi Iwai <tiwai@suse.de>
    ALSA: pcm: Set missing stop_operating flag at undoing trigger start

Eric Dumazet <edumazet@google.com>
    bpf, sockmap: fix race in sock_map_free()

Toke Høiland-Jørgensen <toke@redhat.com>
    bpf: Add dummy type reference to nf_conn___init to fix type deduplication

Martin Blumenstingl <martin.blumenstingl@googlemail.com>
    hwmon: (jc42) Restore the min/max/critical temperatures on resume

Martin Blumenstingl <martin.blumenstingl@googlemail.com>
    hwmon: (jc42) Convert register access and caching to regmap/regcache

Yang Yingliang <yangyingliang@huawei.com>
    regulator: core: fix resource leak in regulator_register()

Chen Zhongjin <chenzhongjin@huawei.com>
    configfs: fix possible memory leak in configfs_create_dir()

Sebastian Andrzej Siewior <bigeasy@linutronix.de>
    hsr: Synchronize sequence number updates.

Sebastian Andrzej Siewior <bigeasy@linutronix.de>
    hsr: Synchronize sending frames to have always incremented outgoing seq nr.

Sebastian Andrzej Siewior <bigeasy@linutronix.de>
    hsr: Disable netpoll.

Sebastian Andrzej Siewior <bigeasy@linutronix.de>
    hsr: Avoid double remove of a node.

Sebastian Andrzej Siewior <bigeasy@linutronix.de>
    hsr: Add a rcu-read lock to hsr_forward_skb().

Sebastian Andrzej Siewior <bigeasy@linutronix.de>
    Revert "net: hsr: use hlist_head instead of list_head for mac addresses"

Christian Marangi <ansuelsmth@gmail.com>
    clk: qcom: clk-krait: fix wrong div2 functions

Douglas Anderson <dianders@chromium.org>
    clk: qcom: lpass-sc7180: Fix pm_runtime usage

Douglas Anderson <dianders@chromium.org>
    clk: qcom: lpass-sc7280: Fix pm_runtime usage

Yang Yingliang <yangyingliang@huawei.com>
    regulator: core: fix module refcount leak in set_supply()

Xiongfeng Wang <wangxiongfeng2@huawei.com>
    mt76: mt7915: Fix PCI device refcount leak in mt7915_pci_init_hif2()

Deren Wu <deren.wu@mediatek.com>
    wifi: mt76: do not send firmware FW_FEATURE_NON_DL region

Deren Wu <deren.wu@mediatek.com>
    wifi: mt76: mt7921: Add missing __packed annotation of struct mt7921_clc

Deren Wu <deren.wu@mediatek.com>
    wifi: mt76: fix coverity overrun-call in mt76_get_txpower()

YN Chen <YN.Chen@mediatek.com>
    wifi: mt76: mt7921: fix wrong power after multiple SAR set

Nicolas Cavallari <nicolas.cavallari@green-communications.fr>
    wifi: mt76: mt7915: Fix chainmask calculation on mt7915 DBDC

Shayne Chen <shayne.chen@mediatek.com>
    wifi: mt76: mt7915: rework eeprom tx paths and streams init

Lorenzo Bianconi <lorenzo@kernel.org>
    wifi: mt76: mt7921: fix reporting of TX AGGR histogram

Lorenzo Bianconi <lorenzo@kernel.org>
    wifi: mt76: mt7915: fix reporting of TX AGGR histogram

Ryder Lee <ryder.lee@mediatek.com>
    wifi: mt76: mt7915: fix mt7915_mac_set_timing()

Sean Wang <sean.wang@mediatek.com>
    wifi: mt76: mt7921: fix antenna signal are way off in monitor mode

Chen Zhongjin <chenzhongjin@huawei.com>
    wifi: cfg80211: Fix not unregister reg_pdev when load_builtin_regdb_keys() fails

Íñigo Huguet <ihuguet@redhat.com>
    wifi: mac80211: fix maybe-unused warning

Zhengchao Shao <shaozhengchao@huawei.com>
    wifi: mac80211: fix memory leak in ieee80211_if_add()

Yuan Can <yuancan@huawei.com>
    wifi: nl80211: Add checks for nla_nest_start() in nl80211_send_iface()

Alexander Sverdlin <alexander.sverdlin@siemens.com>
    spi: spidev: mask SPI_CS_HIGH in SPI_IOC_RD_MODE

Dan Carpenter <error27@gmail.com>
    bonding: uninitialized variable in bond_miimon_inspect()

Pengcheng Yang <yangpc@wangsu.com>
    bpf, sockmap: Fix data loss caused by using apply_bytes on ingress redirect

Pengcheng Yang <yangpc@wangsu.com>
    bpf, sockmap: Fix missing BPF_F_INGRESS flag when using apply_bytes

Pengcheng Yang <yangpc@wangsu.com>
    bpf, sockmap: Fix repeated calls to sock_put() when msg has more_data

Randy Dunlap <rdunlap@infradead.org>
    Input: wistron_btns - disable on UML

Florian Westphal <fw@strlen.de>
    netfilter: conntrack: set icmpv6 redirects as RELATED

Xiu Jianfeng <xiujianfeng@huawei.com>
    clk: visconti: Fix memory leak in visconti_register_pll()

Zhang Qilong <zhangqilong3@huawei.com>
    ASoC: pcm512x: Fix PM disable depth imbalance in pcm512x_probe

Xia Fukun <xiafukun@huawei.com>
    drm/i915/bios: fix a memory leak in generate_lfp_data_ptrs

Konstantin Meskhidze <konstantin.meskhidze@huawei.com>
    drm/amdkfd: Fix memory leakage

Xiongfeng Wang <wangxiongfeng2@huawei.com>
    drm/amdgpu: Fix PCI device refcount leak in amdgpu_atrm_get_bios()

Xiongfeng Wang <wangxiongfeng2@huawei.com>
    drm/radeon: Fix PCI device refcount leak in radeon_atrm_get_bios()

Veerabadhran Gopalakrishnan <veerabadhran.gopalakrishnan@amd.com>
    amdgpu/nv.c: Corrected typo in the video capabilities resolution

Guchun Chen <guchun.chen@amd.com>
    drm/amd/pm/smu11: BACO is supported when it's in BACO state

Daniel Golle <daniel@makrotopia.org>
    clk: mediatek: fix dependency of MT7986 ADC clocks

Ricardo Ribalda <ribalda@chromium.org>
    ASoC: mediatek: mt8173: Enable IRQ when pdata is ready

Ben Greear <greearb@candelatech.com>
    wifi: iwlwifi: mvm: fix double free on tx path.

Bitterblue Smith <rtl8821cerfe2@gmail.com>
    wifi: rtl8xxxu: Fix use after rcu_read_unlock in rtl8xxxu_bss_info_changed

Ziyang Xuan <william.xuanziyang@huawei.com>
    wifi: plfxlc: fix potential memory leak in __lf_x_usb_enable_rx()

Liu Shixin <liushixin2@huawei.com>
    ALSA: asihpi: fix missing pci_disable_device()

Trond Myklebust <trond.myklebust@hammerspace.com>
    NFS: Fix an Oops in nfs_d_automount()

Trond Myklebust <trond.myklebust@hammerspace.com>
    NFSv4: Fix a deadlock between nfs4_open_recover_helper() and delegreturn

Trond Myklebust <trond.myklebust@hammerspace.com>
    NFSv4: Fix a credential leak in _nfs4_discover_trunking()

Trond Myklebust <trond.myklebust@hammerspace.com>
    NFSv4.2: Fix initialisation of struct nfs4_label

Trond Myklebust <trond.myklebust@hammerspace.com>
    NFSv4.2: Fix a memory stomp in decode_attr_security_label

Trond Myklebust <trond.myklebust@hammerspace.com>
    NFSv4.2: Always decode the security label

Trond Myklebust <trond.myklebust@hammerspace.com>
    NFSv4.2: Clear FATTR4_WORD2_SECURITY_LABEL when done decoding

Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
    drm/msm/mdp5: fix reading hw revision on db410c platform

Jiasheng Jiang <jiasheng@iscas.ac.cn>
    ASoC: mediatek: mtk-btcvsd: Add checks for write and read of mtk_btcvsd_snd

Dmitry Torokhov <dmitry.torokhov@gmail.com>
    ASoC: dt-bindings: wcd9335: fix reset line polarity in example

Zhang Zekun <zhangzekun11@huawei.com>
    drm/tegra: Add missing clk_disable_unprepare() in tegra_dc_probe()

Aakarsh Jain <aakarsh.jain@samsung.com>
    media: s5p-mfc: Add variant data for MFC v7 hardware for Exynos 3250 SoC

Yunfei Dong <yunfei.dong@mediatek.com>
    media: mediatek: vcodec: Core thread depends on core_list

Yunfei Dong <yunfei.dong@mediatek.com>
    media: mediatek: vcodec: Setting lat buf to lat_list when lat decode error

Yunfei Dong <yunfei.dong@mediatek.com>
    media: mediatek: vcodec: Fix h264 set lat buffer error

Yunfei Dong <yunfei.dong@mediatek.com>
    media: mediatek: vcodec: Fix getting NULL pointer for dst buffer

Ming Qian <ming.qian@nxp.com>
    media: amphion: lock and check m2m_ctx in event handler

Ming Qian <ming.qian@nxp.com>
    media: amphion: cancel vpu before release instance

Ming Qian <ming.qian@nxp.com>
    media: amphion: try to wakeup vpu core to avoid failure

Paul Kocialkowski <paul.kocialkowski@bootlin.com>
    media: sun8i-a83t-mipi-csi2: Register async subdev with no sensor attached

Paul Kocialkowski <paul.kocialkowski@bootlin.com>
    media: sun6i-mipi-csi2: Register async subdev with no sensor attached

Paul Kocialkowski <paul.kocialkowski@bootlin.com>
    media: sun8i-a83t-mipi-csi2: Require both pads to be connected for streaming

Paul Kocialkowski <paul.kocialkowski@bootlin.com>
    media: sun6i-mipi-csi2: Require both pads to be connected for streaming

Juergen Gross <jgross@suse.com>
    x86/boot: Skip realmode init code when running as Xen PV guest

Baisong Zhong <zhongbaisong@huawei.com>
    media: dvb-usb: az6027: fix null-ptr-deref in az6027_i2c_xfer()

Chen Zhongjin <chenzhongjin@huawei.com>
    media: dvb-core: Fix ignored return value in dvb_register_frontend()

ZhangPeng <zhangpeng362@huawei.com>
    pinctrl: pinconf-generic: add missing of_node_put()

Dario Binacchi <dario.binacchi@amarulasolutions.com>
    clk: imx8mn: fix imx8mn_enet_phy_sels clocks list

Dario Binacchi <dario.binacchi@amarulasolutions.com>
    clk: imx8mn: fix imx8mn_sai2_sels clocks list

Dario Binacchi <dario.binacchi@amarulasolutions.com>
    clk: imx: rename video_pll1 to video_pll

Dario Binacchi <dario.binacchi@amarulasolutions.com>
    clk: imx: replace osc_hdmi with dummy

Dario Binacchi <dario.binacchi@amarulasolutions.com>
    clk: imx8mn: rename vpu_pll to m7_alt_pll

Marek Vasut <marex@denx.de>
    media: mt9p031: Drop bogus v4l2_subdev_get_try_crop() call from mt9p031_init_cfg()

Laurent Pinchart <laurent.pinchart@ideasonboard.com>
    media: imx: imx7-media-csi: Clear BIT_MIPI_DOUBLE_CMPNT for <16b formats

Gautam Menghani <gautammenghani201@gmail.com>
    media: imon: fix a race condition in send_packet()

Chen Zhongjin <chenzhongjin@huawei.com>
    media: vimc: Fix wrong function called when vimc_init() fails

Jiaxin Yu <jiaxin.yu@mediatek.com>
    ASoC: mediatek: mt8186: Correct I2S shared clocks

Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
    ASoC: qcom: cleanup and fix dependency of QCOM_COMMON

Yuan Can <yuancan@huawei.com>
    ASoC: qcom: Add checks for devm_kcalloc

Wang ShaoBo <bobo.shaobowang@huawei.com>
    drbd: destroy workqueue when drbd device was freed

Wang ShaoBo <bobo.shaobowang@huawei.com>
    drbd: remove call to memset before free device/resource/connection

Zheng Yongjun <zhengyongjun3@huawei.com>
    mtd: maps: pxa2xx-flash: fix memory leak in probe

Shang XiaoJing <shangxiaojing@huawei.com>
    mtd: core: Fix refcount error in del_mtd_device()

Hui Tang <tanghui20@huawei.com>
    clk: microchip: check for null return of devm_kzalloc()

Jonathan Toppins <jtoppins@redhat.com>
    bonding: fix link recovery in mode 2 when updelay is nonzero

Stanislav Fomichev <sdf@google.com>
    selftests/bpf: Mount debugfs in setns_by_fd

Stanislav Fomichev <sdf@google.com>
    selftests/bpf: Make sure zero-len skbs aren't redirectable

Jani Nikula <jani.nikula@intel.com>
    drm/i915/guc: make default_lists const data

Yang Yingliang <yangyingliang@huawei.com>
    drm/amdgpu: fix pci device refcount leak

Xiu Jianfeng <xiujianfeng@huawei.com>
    clk: rockchip: Fix memory leak in rockchip_clk_register_pll()

Wang ShaoBo <bobo.shaobowang@huawei.com>
    regulator: core: use kfree_const() to free space conditionally

Baisong Zhong <zhongbaisong@huawei.com>
    ALSA: seq: fix undefined behavior in bit shift for SNDRV_SEQ_FILTER_USE_EVENT

Baisong Zhong <zhongbaisong@huawei.com>
    ALSA: pcm: fix undefined behavior in bit shift for SNDRV_PCM_RATE_KNOT

Cezary Rojewski <cezary.rojewski@intel.com>
    ASoC: Intel: avs: Lock substream before snd_pcm_stop()

Lili Li <lili.li@intel.com>
    ASoC: Intel: Skylake: Fix Kconfig dependency

Zong-Zhe Yang <kevin_yang@realtek.com>
    wifi: rtw89: fix physts IE page check

ZhangPeng <zhangpeng362@huawei.com>
    pinctrl: k210: call of_node_put()

Giulio Benetti <giulio.benetti@benettiengineering.com>
    clk: imx: imxrt1050: fix IMXRT1050_CLK_LCDIF_APB offsets

Marcus Folkesson <marcus.folkesson@gmail.com>
    HID: hid-sensor-custom: set fixed size for custom attributes

Stanislav Fomichev <sdf@google.com>
    bpf: Move skb->len == 0 checks into __bpf_redirect

Peng Fan <peng.fan@nxp.com>
    clk: imx93: correct enet clock

Peng Fan <peng.fan@nxp.com>
    clk: imx93: unmap anatop base in error handling path

Dmitry Torokhov <dmitry.torokhov@gmail.com>
    HID: i2c: let RMI devices decide what constitutes wakeup event

Hou Tao <houtao1@huawei.com>
    bpf: Pin the start cgroup in cgroup_iter_seq_init()

Haibo Chen <haibo.chen@nxp.com>
    clk: imx93: correct the flexspi1 clock setting

Allen-KH Cheng <allen-kh.cheng@mediatek.com>
    mtd: spi-nor: Fix the number of bytes for the dummy cycles

Michael Walle <michael@walle.cc>
    mtd: spi-nor: hide jedec_id sysfs attribute if not present

Kuniyuki Iwashima <kuniyu@amazon.com>
    net: Return errno in sk->sk_prot->get_port().

Kuniyuki Iwashima <kuniyu@amazon.com>
    udp: Clean up some functions.

Lorenzo Bianconi <lorenzo@kernel.org>
    net: ethernet: mtk_eth_soc: fix RSTCTRL_PPE{0,1} definitions

Christoph Hellwig <hch@lst.de>
    media: videobuf-dma-contig: use dma_mmap_coherent

Yuan Can <yuancan@huawei.com>
    media: amphion: Fix error handling in vpu_driver_init()

Yuan Can <yuancan@huawei.com>
    media: platform: exynos4-is: Fix error handling in fimc_md_init()

Yang Yingliang <yangyingliang@huawei.com>
    media: solo6x10: fix possible memory leak in solo_sysfs_init()

Chen Zhongjin <chenzhongjin@huawei.com>
    media: vidtv: Fix use-after-free in vidtv_bridge_dvb_init()

Ming Qian <ming.qian@nxp.com>
    media: amphion: apply vb2_queue_error instead of setting manually

Ming Qian <ming.qian@nxp.com>
    media: amphion: add lock around vdec_g_fmt

Lorenzo Bianconi <lorenzo@kernel.org>
    net: ethernet: mtk_eth_soc: do not overwrite mtu configuration running reset routine

Gaosheng Cui <cuigaosheng1@huawei.com>
    ASoC: amd: acp: Fix possible UAF in acp_dma_open

Douglas Anderson <dianders@chromium.org>
    Input: elants_i2c - properly handle the reset GPIO when power is off

Hui Tang <tanghui20@huawei.com>
    mtd: lpddr2_nvm: Fix possible null-ptr-deref

Rob Clark <robdclark@chromium.org>
    drm/msm/a6xx: Fix speed-bin detection vs probe-defer

Xiu Jianfeng <xiujianfeng@huawei.com>
    wifi: ath10k: Fix return value in ath10k_pci_init()

Wang Yufen <wangyufen@huawei.com>
    selftests/bpf: fix memory leak of lsm_cgroup

Christoph Hellwig <hch@lst.de>
    dm: track per-add_disk holder relations in DM

Yu Kuai <yukuai3@huawei.com>
    dm: make sure create and remove dm device won't race with open and close table

Christoph Hellwig <hch@lst.de>
    dm: cleanup close_table_device

Christoph Hellwig <hch@lst.de>
    dm: cleanup open_table_device

Christoph Hellwig <hch@lst.de>
    block: clear ->slave_dir when dropping the main slave_dir reference

Xiu Jianfeng <xiujianfeng@huawei.com>
    ima: Fix misuse of dereference of pointer in template_desc_init_fields()

GUO Zihua <guozihua@huawei.com>
    integrity: Fix memory leakage in keyring allocation error path

Takashi Iwai <tiwai@suse.de>
    ALSA: memalloc: Allocate more contiguous pages for fallback case

Brian Starkey <brian.starkey@arm.com>
    drm/fourcc: Fix vsub/hsub for Q410 and Q401

Konrad Dybcio <konrad.dybcio@linaro.org>
    regulator: qcom-rpmh: Fix PMR735a S3 regulator spec

Christophe JAILLET <christophe.jaillet@wanadoo.fr>
    wifi: rtw89: Fix some error handling path in rtw89_core_sta_assoc()

Joel Granados <j.granados@samsung.com>
    nvme: return err on nvme_init_non_mdts_limits fail

Dan Carpenter <error27@gmail.com>
    amdgpu/pm: prevent array underflow in vega20_odn_edit_dpm_table()

Yang Yingliang <yangyingliang@huawei.com>
    regulator: core: fix unbalanced of node refcount in regulator_dev_lookup()

Christoph Hellwig <hch@lst.de>
    nvmet: only allocate a single slab for bvecs

Zeng Heng <zengheng4@huawei.com>
    ASoC: pxa: fix null-pointer dereference in filter()

Xinlei Lee <xinlei.lee@mediatek.com>
    drm/mediatek: Modify dpi power on/off sequence.

Martin KaFai Lau <martin.lau@kernel.org>
    selftests/bpf: Fix incorrect ASSERT in the tcp_hdr_options test

Yang Jihong <yangjihong1@huawei.com>
    selftests/bpf: Fix xdp_synproxy compilation failure in 32-bit arch

Randy Dunlap <rdunlap@infradead.org>
    ASoC: codecs: wsa883x: use correct header file

Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
    ASoC: codecs: wsa883x: Use proper shutdown GPIO polarity

Miaoqian Lin <linmq006@gmail.com>
    module: Fix NULL vs IS_ERR checking for module_get_next_page

Johannes Berg <johannes.berg@intel.com>
    wifi: iwlwifi: mei: fix potential NULL-ptr deref after clone

Avraham Stern <avraham.stern@intel.com>
    wifi: iwlwifi: mei: avoid blocking sap messages handling due to rtnl lock

Emmanuel Grumbach <emmanuel.grumbach@intel.com>
    wifi: iwlwifi: mei: fix tx DHCP packet for devices with new Tx API

Emmanuel Grumbach <emmanuel.grumbach@intel.com>
    wifi: iwlwifi: mei: don't send SAP commands if AMT is disabled

Avraham Stern <avraham.stern@intel.com>
    wifi: iwlwifi: mei: make sure ownership confirmed message is sent

Sam Shih <sam.shih@mediatek.com>
    pinctrl: mediatek: fix the pinconf register offset of some pins

Frank Wunderlich <frank-w@public-files.de>
    dt-bindings: pinctrl: update uart/mmc bindings for MT7986 SoC

Hanjun Guo <guohanjun@huawei.com>
    drm/radeon: Add the missed acpi_put_table() to fix memory leak

Khazhismel Kumykov <khazhy@chromium.org>
    bfq: fix waker_bfqq inconsistency crash

Christoph Böhmwalder <christoph.boehmwalder@linbit.com>
    drbd: use blk_queue_max_discard_sectors helper

Yassine Oudjana <y.oudjana@protonmail.com>
    regmap-irq: Use the new num_config_regs property in regmap_add_irq_chip_fwnode

Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
    drm: rcar-du: Drop leftovers dependencies from Kconfig

Ping-Ke Shih <pkshih@realtek.com>
    wifi: rtw89: use u32_encode_bits() to fill MAC quota value

Marek Vasut <marex@denx.de>
    drm: lcdif: Set and enable FIFO Panic threshold

David Howells <dhowells@redhat.com>
    rxrpc: Fix ack.bufferSize to be 0 when generating an ack

David Howells <dhowells@redhat.com>
    net, proc: Provide PROC_FS=n fallback for proc_create_net_single_write()

Cole Robinson <crobinso@redhat.com>
    virt/sev-guest: Add a MODULE_ALIAS

Wolfram Sang <wsa+renesas@sang-engineering.com>
    clk: renesas: r8a779f0: Fix SCIF parent clocks

Wolfram Sang <wsa+renesas@sang-engineering.com>
    clk: renesas: r8a779f0: Fix HSCIF parent clocks

Vladimir Zapolskiy <vladimir.zapolskiy@linaro.org>
    media: camss: Do not attach an already attached power domain on MSM8916 platform

Vladimir Zapolskiy <vladimir.zapolskiy@linaro.org>
    media: camss: Clean up received buffers on failed start of streaming

Marek Vasut <marex@denx.de>
    wifi: rsi: Fix handling of 802.3 EAPOL frames sent via control port

Randy Dunlap <rdunlap@infradead.org>
    Input: joystick - fix Kconfig warning for JOYSTICK_ADC

Gaosheng Cui <cuigaosheng1@huawei.com>
    mtd: core: fix possible resource leak in init_mtd()

Zhang Xiaoxu <zhangxiaoxu5@huawei.com>
    mtd: Fix device name leak when register device failed in add_mtd_device()

Manivannan Sadhasivam <mani@kernel.org>
    clk: qcom: gcc-sm8250: Use retention mode for USB GDSCs

Konrad Dybcio <konrad.dybcio@somainline.org>
    clk: qcom: dispcc-sm6350: Add CLK_OPS_PARENT_ENABLE to pixel&byte src

Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
    clk: qcom: gcc-ipq806x: use parent_data for the last remaining entry

Andrii Nakryiko <andrii@kernel.org>
    bpf: propagate precision across all frames, not just the last one

Andrii Nakryiko <andrii@kernel.org>
    bpf: propagate precision in ALU/ALU64 operations

Yang Yingliang <yangyingliang@huawei.com>
    media: platform: exynos4-is: fix return value check in fimc_md_probe()

Liu Shixin <liushixin2@huawei.com>
    media: vivid: fix compose size exceed boundary

Andrzej Pietrasiewicz <andrzej.p@collabora.com>
    media: rkvdec: Add required padding

Moudy Ho <moudy.ho@mediatek.com>
    media: platform: mtk-mdp3: fix error handling in mdp_probe()

Moudy Ho <moudy.ho@mediatek.com>
    media: platform: mtk-mdp3: fix error handling about components clock_on

Moudy Ho <moudy.ho@mediatek.com>
    media: platform: mtk-mdp3: fix error handling in mdp_cmdq_send()

Marijn Suijten <marijn.suijten@somainline.org>
    drm/msm/dsi: Prevent signed BPG offsets from bleeding into adjacent bits

Marijn Suijten <marijn.suijten@somainline.org>
    drm/msm/dsi: Disallow 8 BPC DSC configuration for alternative BPC values

Marijn Suijten <marijn.suijten@somainline.org>
    drm/msm/dsi: Account for DSC's bits_per_pixel having 4 fractional bits

Marijn Suijten <marijn.suijten@somainline.org>
    drm/msm/dsi: Migrate to drm_dsc_compute_rc_parameters()

Marijn Suijten <marijn.suijten@somainline.org>
    drm/msm/dsi: Appropriately set dsc->mux_word_size based on bpc

Marijn Suijten <marijn.suijten@somainline.org>
    drm/msm/dsi: Reuse earlier computed dsc->slice_chunk_size

Marijn Suijten <marijn.suijten@somainline.org>
    drm/msm/dsi: Use DIV_ROUND_UP instead of conditional increment on modulo

Marijn Suijten <marijn.suijten@somainline.org>
    drm/msm/dsi: Remove repeated calculation of slice_per_intf

Marijn Suijten <marijn.suijten@somainline.org>
    drm/msm/dsi: Remove useless math in DSC calculations

Marijn Suijten <marijn.suijten@somainline.org>
    drm/msm/dpu1: Account for DSC's bits_per_pixel having 4 fractional bits

Kumar Kartikeya Dwivedi <memxor@gmail.com>
    bpf: Fix slot type check in check_stack_write_var_off

Kumar Kartikeya Dwivedi <memxor@gmail.com>
    bpf: Clobber stack slot when writing over spilled PTR_TO_BTF_ID

Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
    drm/msm/hdmi: use devres helper for runtime PM management

GUO Zihua <guozihua@huawei.com>
    ima: Handle -ESTALE returned by ima_filter_rule_match()

Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
    drm/msm/mdp5: stop overriding drvdata

Gaosheng Cui <cuigaosheng1@huawei.com>
    drm/ttm: fix undefined behavior in bit shift for TTM_TT_FLAG_PRIV_POPULATED

Marek Vasut <marex@denx.de>
    drm/panel/panel-sitronix-st7701: Remove panel on DSI attach failure

Jonathan Neuschäfer <j.neuschaefer@gmx.net>
    spi: Update reference to struct spi_controller

Marek Vasut <marex@denx.de>
    drm/panel/panel-sitronix-st7701: Fix RTNI calculation

Marco Felsch <m.felsch@pengutronix.de>
    drm: lcdif: change burst size to 256B

Marek Vasut <marex@denx.de>
    clk: renesas: r9a06g032: Repair grave increment error

Anshuman Gupta <anshuman.gupta@intel.com>
    drm/i915/dgfx: Grab wakeref at i915_ttm_unmap_virtual

Anshuman Gupta <anshuman.gupta@intel.com>
    drm/i915: Encapsulate lmem rpm stuff in intel_runtime_pm

Nirmoy Das <nirmoy.das@intel.com>
    drm/i915: Refactor ttm ghost obj detection

Tvrtko Ursulin <tvrtko.ursulin@intel.com>
    drm/i915: Handle all GTs on driver (un)load paths

Zhang Qilong <zhangqilong3@huawei.com>
    drm/rockchip: lvds: fix PM usage counter unbalance in poweron

Haiyi Zhou <Haiyi.Zhou@amd.com>
    drm/amd/display: wait for vblank during pipe programming

Sakari Ailus <sakari.ailus@linux.intel.com>
    dw9768: Enable low-power probe on ACPI

Alan Previn <alan.previn.teres.alexis@intel.com>
    drm/i915/guc: Fix GuC error capture sizing estimation and reporting

Alan Previn <alan.previn.teres.alexis@intel.com>
    drm/i915/guc: Add error-capture init warnings when needed

Nícolas F. R. A. Prado <nfraprado@collabora.com>
    ASoC: dt-bindings: rt5682: Set sound-dai-cells to 1

Wolfram Sang <wsa+renesas@sang-engineering.com>
    clk: renesas: r8a779a0: Fix SD0H clock name

Geert Uytterhoeven <geert+renesas@glider.be>
    clk: renesas: r8a779f0: Fix SD0H clock name

Jimmy Assarsson <extja@kvaser.com>
    can: kvaser_usb: Compare requested bittiming parameters with actual parameters in do_set_{,data}_bittiming

Jimmy Assarsson <extja@kvaser.com>
    can: kvaser_usb: Add struct kvaser_usb_busparams

Anssi Hannula <anssi.hannula@bitwise.fi>
    can: kvaser_usb_leaf: Fix bogus restart events

Anssi Hannula <anssi.hannula@bitwise.fi>
    can: kvaser_usb_leaf: Fix wrong CAN state after stopping

Anssi Hannula <anssi.hannula@bitwise.fi>
    can: kvaser_usb_leaf: Fix improved state not being reported

Anssi Hannula <anssi.hannula@bitwise.fi>
    can: kvaser_usb_leaf: Set Warning state even without bus errors

Jimmy Assarsson <extja@kvaser.com>
    can: kvaser_usb: kvaser_usb_leaf: Handle CMD_ERROR_EVENT

Jimmy Assarsson <extja@kvaser.com>
    can: kvaser_usb: kvaser_usb_leaf: Rename {leaf,usbcan}_cmd_error_event to {leaf,usbcan}_cmd_can_error_event

Jimmy Assarsson <extja@kvaser.com>
    can: kvaser_usb: kvaser_usb_leaf: Get capabilities from device

Alan Maguire <alan.maguire@oracle.com>
    libbpf: Btf dedup identical struct test needs check for nested structs/arrays

Marek Szyprowski <m.szyprowski@samsung.com>
    media: exynos4-is: don't rely on the v4l2_async_subdev internals

Rafael Mendonca <rafaelmendsr@gmail.com>
    media: i2c: ov5648: Free V4L2 fwnode data on unbind

Kuniyuki Iwashima <kuniyu@amazon.com>
    soreuseport: Fix socket selection for SO_INCOMING_CPU.

Tang Bin <tangbin@cmss.chinamobile.com>
    venus: pm_helpers: Fix error check in vcodec_domains_get()

Ricardo Ribalda <ribalda@chromium.org>
    media: i2c: ad5820: Fix error path

Rafael Mendonca <rafaelmendsr@gmail.com>
    media: i2c: hi846: Fix memory leak in hi846_parse_dt()

John Harrison <John.C.Harrison@Intel.com>
    drm/i915: Fix compute pre-emption w/a to apply to compute engines

John Harrison <John.C.Harrison@Intel.com>
    drm/i915/guc: Limit scheduling properties to avoid overflow

Yunfei Dong <yunfei.dong@mediatek.com>
    media: mediatek: vcodec: fix h264 cavlc bitstream fail

Jernej Skrabec <jernej.skrabec@gmail.com>
    media: cedrus: hevc: Fix offset adjustments

Jernej Skrabec <jernej.skrabec@gmail.com>
    media: v4l2-ioctl.c: Unify YCbCr/YUV terms in format descriptions

Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
    media: adv748x: afe: Select input port when initializing AFE

Ming Qian <ming.qian@nxp.com>
    media: amphion: reset instance if it's aborted before codec header parsed

Jiasheng Jiang <jiasheng@iscas.ac.cn>
    media: coda: jpeg: Add check for kmalloc

Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
    media: v4l2-ctrls: Fix off-by-one error in integer menu control check

Jeff LaBundy <jeff@labundy.com>
    Input: iqs7222 - protect against undefined slider size

Pin-yen Lin <treapking@chromium.org>
    drm/bridge: it6505: Initialize AUX channel in it6505_i2c_probe

Wang Yufen <wangyufen@huawei.com>
    selftests/bpf: fix missing BPF object files

Gerhard Engleder <gerhard@engleder-embedded.com>
    samples/bpf: Fix MAC address swapping in xdp2_kern

Gerhard Engleder <gerhard@engleder-embedded.com>
    samples/bpf: Fix map iteration in xdp1_user

Alexandru Tachici <alexandru.tachici@analog.com>
    net: ethernet: adi: adin1110: Fix SPI transfers

Rafael Mendonca <rafaelmendsr@gmail.com>
    drm/amdgpu/powerplay/psm: Fix memory leak in power state init

Asher Song <Asher.Song@amd.com>
    drm/amdgpu: Revert "drm/amdgpu: getting fan speed pwm for vega10 properly"

Andrew Jeffery <andrew@aj.id.au>
    ipmi: kcs: Poll OBF briefly to reduce OBE latency

Cezary Rojewski <cezary.rojewski@intel.com>
    ASoC: Intel: avs: Fix potential RX buffer overflow

Cezary Rojewski <cezary.rojewski@intel.com>
    ASoC: Intel: avs: Fix DMA mask assignment

Yang Yingliang <yangyingliang@huawei.com>
    pinctrl: ocelot: add missing destroy_workqueue() in error path in ocelot_pinctrl_probe()

Niklas Cassel <niklas.cassel@wdc.com>
    ata: libata: fix NCQ autosense logic

Laurent Pinchart <laurent.pinchart@ideasonboard.com>
    drm: lcdif: Switch to limited range for RGB to YUV conversion

Shung-Hsi Yu <shung-hsi.yu@suse.com>
    libbpf: Fix null-pointer dereference in find_prog_by_sec_insn()

Shung-Hsi Yu <shung-hsi.yu@suse.com>
    libbpf: Deal with section with no data gracefully

Shung-Hsi Yu <shung-hsi.yu@suse.com>
    libbpf: Use elf_getshdrnum() instead of e_shnum

Xu Kuohai <xukuohai@huawei.com>
    selftest/bpf: Fix error usage of ASSERT_OK in xdp_adjust_tail.c

Xu Kuohai <xukuohai@huawei.com>
    selftests/bpf: Fix error failure of case test_xdp_adjust_tail_grow

Xu Kuohai <xukuohai@huawei.com>
    selftest/bpf: Fix memory leak in kprobe_multi_test

Xu Kuohai <xukuohai@huawei.com>
    selftests/bpf: Fix memory leak caused by not destroying skeleton

Xu Kuohai <xukuohai@huawei.com>
    libbpf: Fix memory leak in parse_usdt_arg()

Xu Kuohai <xukuohai@huawei.com>
    libbpf: Fix use-after-free in btf_dump_name_dups

Abhinav Kumar <quic_abhinavk@quicinc.com>
    drm/bridge: adv7533: remove dynamic lane switching from adv7533 bridge

Aditya Kumar Singh <quic_adisi@quicinc.com>
    wifi: ath11k: fix firmware assert during bandwidth change for peer sta

Bitterblue Smith <rtl8821cerfe2@gmail.com>
    wifi: rtl8xxxu: Fix reading the vendor of combo chips

Fedor Pchelkin <pchelkin@ispras.ru>
    wifi: ath9k: hif_usb: Fix use-after-free in ath9k_hif_usb_reg_in_cb()

Fedor Pchelkin <pchelkin@ispras.ru>
    wifi: ath9k: hif_usb: fix memory leak of urbs in ath9k_hif_usb_dealloc_tx_urbs()

Thomas Zimmermann <tzimmermann@suse.de>
    drm/atomic-helper: Don't allocate new plane state in CRTC check

Johannes Berg <johannes.berg@intel.com>
    wifi: mac80211: fix ifdef symbol name

Johannes Berg <johannes.berg@intel.com>
    wifi: mac80211: check link ID in auth/assoc continuation

Johannes Berg <johannes.berg@intel.com>
    wifi: mac80211: mlme: fix null-ptr deref on failed assoc

Johannes Berg <johannes.berg@intel.com>
    wifi: fix multi-link element subelement iteration

Jiri Olsa <jolsa@kernel.org>
    selftests/bpf: Add missing bpf_iter_vma_offset__destroy call

James Hurley <jahurley@nvidia.com>
    platform/mellanox: mlxbf-pmc: Fix event typo

Zhengchao Shao <shaozhengchao@huawei.com>
    ipc: fix memory leak in init_mqueue_fs()

Cai Xinchen <caixinchen1@huawei.com>
    rapidio: devices: fix missing put_device in mport_cdev_open

ZhangPeng <zhangpeng362@huawei.com>
    hfs: Fix OOB Write in hfs_asc2mac

Gavrilov Ilia <Ilia.Gavrilov@infotecs.ru>
    relay: fix type mismatch when allocating memory in relay_create_buf()

Zhang Qilong <zhangqilong3@huawei.com>
    eventfd: change int to __u64 in eventfd_signal() ifndef CONFIG_EVENTFD

Wang Weiyang <wangweiyang2@huawei.com>
    rapidio: fix possible UAF when kfifo_alloc() fails

Chen Zhongjin <chenzhongjin@huawei.com>
    fs: sysv: Fix sysv_nblocks() returns wrong value

Brian Foster <bfoster@redhat.com>
    NFSD: pass range end to vfs_fsync_range() instead of count

Jeff Layton <jlayton@kernel.org>
    nfsd: return error if nfs4_setacl fails

Trond Myklebust <trond.myklebust@hammerspace.com>
    lockd: set other missing fields when unlocking files

Ladislav Michl <ladis@linux-mips.org>
    MIPS: OCTEON: warn only once if deprecated link status is being used

Anastasia Belova <abelova@astralinux.ru>
    MIPS: BCM63xx: Add check for NULL for clk in clk_enable

Yang Yingliang <yangyingliang@huawei.com>
    platform/x86: intel_scu_ipc: fix possible name leak in __intel_scu_ipc_register()

Yu Liao <liaoyu15@huawei.com>
    platform/x86: mxm-wmi: fix memleak in mxm_wmi_call_mx[ds|mx]()

Victor Ding <victording@chromium.org>
    platform/chrome: cros_ec_typec: zero out stale pointers

Gao Xiang <xiang@kernel.org>
    erofs: validate the extent length for uncompressed pclusters

Gao Xiang <xiang@kernel.org>
    erofs: fix missing unmap if z_erofs_get_extent_compressedlen() fails

Chen Zhongjin <chenzhongjin@huawei.com>
    erofs: Fix pcluster memleak when its block address is zero

Hou Tao <houtao1@huawei.com>
    erofs: check the uniqueness of fsid in shared domain in advance

Rafael J. Wysocki <rafael.j.wysocki@intel.com>
    PM: runtime: Do not call __rpm_callback() from rpm_idle()

Harshit Mogalapalli <harshit.m.mogalapalli@oracle.com>
    xen/privcmd: Fix a possible warning in privcmd_ioctl_mmap_resource()

Xiu Jianfeng <xiujianfeng@huawei.com>
    x86/xen: Fix memory leak in xen_init_lock_cpu()

Xiu Jianfeng <xiujianfeng@huawei.com>
    x86/xen: Fix memory leak in xen_smp_intr_init{_pv}()

Oleg Nesterov <oleg@redhat.com>
    uprobes/x86: Allow to probe a NOP instruction with 0x66 prefix

Li Zetao <lizetao1@huawei.com>
    ACPICA: Fix use-after-free in acpi_ut_copy_ipackage_to_ipackage()

Yang Yingliang <yangyingliang@huawei.com>
    clocksource/drivers/timer-ti-dm: Fix missing clk_disable_unprepare in dmtimer_systimer_init_clock()

Tony Lindgren <tony@atomide.com>
    clocksource/drivers/timer-ti-dm: Fix warning for omap_timer_match

Vincent Donnefort <vdonnefort@google.com>
    cpu/hotplug: Do not bail-out in DYING/STARTING sections

Phil Auld <pauld@redhat.com>
    cpu/hotplug: Make target_store() a nop when target == state

Alexey Izbyshev <izbyshev@ispras.ru>
    futex: Resend potentially swallowed owner death notification

Wolfram Sang <wsa+renesas@sang-engineering.com>
    clocksource/drivers/sh_cmt: Access registers according to spec

Yang Yingliang <yangyingliang@huawei.com>
    rapidio: rio: fix possible name leak in rio_register_mport()

Yang Yingliang <yangyingliang@huawei.com>
    rapidio: fix possible name leaks when rio_add_device() fails

Li Zetao <ocfs2-devel@oss.oracle.com>
    ocfs2: fix memory leak in ocfs2_mount_volume()

Akinobu Mita <akinobu.mita@gmail.com>
    debugfs: fix error when writing negative value to atomic_t debugfs file

Akinobu Mita <akinobu.mita@gmail.com>
    lib/notifier-error-inject: fix error when writing -errno to debugfs file

Akinobu Mita <akinobu.mita@gmail.com>
    libfs: add DEFINE_SIMPLE_ATTRIBUTE_SIGNED for signed value

Xiongfeng Wang <wangxiongfeng2@huawei.com>
    cpufreq: amd_freq_sensitivity: Add missing pci_dev_put()

Yang Yingliang <yangyingliang@huawei.com>
    genirq/irqdesc: Don't try to remove non-existing sysfs files

Jeff Layton <jlayton@kernel.org>
    nfsd: don't call nfsd_file_put from client states seqfile display

Chuck Lever <chuck.lever@oracle.com>
    NFSD: Finish converting the NFSv3 GETACL result encoder

Chuck Lever <chuck.lever@oracle.com>
    NFSD: Finish converting the NFSv2 GETACL result encoder

Yang Yingliang <yangyingliang@huawei.com>
    EDAC/i10nm: fix refcount leak in pci_get_dev_wrapper()

Liu Peibao <liupeibao@loongson.cn>
    irqchip/loongson-liointc: Fix improper error handling in liointc_init()

Wei Yongjun <weiyongjun1@huawei.com>
    irqchip/wpcm450: Fix memory leak in wpcm450_aic_of_init()

Shang XiaoJing <shangxiaojing@huawei.com>
    irqchip: gic-pm: Use pm_runtime_resume_and_get() in gic_probe()

Jianmin Lv <lvjianmin@loongson.cn>
    irqchip/loongson-pch-pic: Fix translate callback for DT path

Yang Yingliang <yangyingliang@huawei.com>
    thermal: core: fix some possible name leaks in error paths

Yuan Can <yuancan@huawei.com>
    platform/chrome: cros_usbpd_notify: Fix error handling in cros_usbpd_notify_init()

Xiongfeng Wang <wangxiongfeng2@huawei.com>
    perf/x86/intel/uncore: Fix reference count leak in __uncore_imc_init_box()

Xiongfeng Wang <wangxiongfeng2@huawei.com>
    perf/x86/intel/uncore: Fix reference count leak in snr_uncore_mmio_map()

Xiongfeng Wang <wangxiongfeng2@huawei.com>
    perf/x86/intel/uncore: Fix reference count leak in hswep_has_limit_sbox()

Xiongfeng Wang <wangxiongfeng2@huawei.com>
    perf/x86/intel/uncore: Fix reference count leak in sad_cfg_iio_topology()

Wang ShaoBo <bobo.shaobowang@huawei.com>
    ACPI: pfr_update: use ACPI_FREE() to free acpi_object

Wang ShaoBo <bobo.shaobowang@huawei.com>
    ACPI: pfr_telemetry: use ACPI_FREE() to free acpi_object

Huisong Li <lihuisong@huawei.com>
    mailbox: pcc: Reset pcc_chan_count to zero in case of PCC probe failure

Yang Yingliang <yangyingliang@huawei.com>
    PNP: fix name memory leak in pnp_alloc_dev()

Zhao Gongyi <zhaogongyi@huawei.com>
    selftests/efivarfs: Add checking of the test return value

Yang Yingliang <yangyingliang@huawei.com>
    MIPS: vpe-cmp: fix possible memory leak while module exiting

Yang Yingliang <yangyingliang@huawei.com>
    MIPS: vpe-mt: fix possible memory leak while module exiting

Manivannan Sadhasivam <mani@kernel.org>
    cpufreq: qcom-hw: Fix the frequency returned by cpufreq_driver->get()

YueHaibing <yuehaibing@huawei.com>
    selftests: cgroup: fix unsigned comparison with less than zero

Shang XiaoJing <shangxiaojing@huawei.com>
    ocfs2: fix memory leak in ocfs2_stack_glue_init()

Gaosheng Cui <cuigaosheng1@huawei.com>
    lib/fonts: fix undefined behavior in bit shift for get_default_font

Alexey Dobriyan <adobriyan@gmail.com>
    proc: fixup uptime selftest

Barnabás Pőcze <pobrn@protonmail.com>
    timerqueue: Use rb_entry_safe() in timerqueue_getnext()

Barnabás Pőcze <pobrn@protonmail.com>
    platform/x86: huawei-wmi: fix return value calculation

wuchi <wuchi.zero@gmail.com>
    lib/debugobjects: fix stat count and optimize debug_objects_mem_init

Chen Zhongjin <chenzhongjin@huawei.com>
    perf: Fix possible memleak in pmu_dev_alloc()

Yipeng Zou <zouyipeng@huawei.com>
    selftests/ftrace: event_triggers: wait longer for test_event_enable

Xiongfeng Wang <wangxiongfeng2@huawei.com>
    ACPI: irq: Fix some kernel-doc issues

Guilherme G. Piccoli <gpiccoli@igalia.com>
    x86/split_lock: Add sysctl to control the misery mode

Chen Hui <judy.chenhui@huawei.com>
    cpufreq: qcom-hw: Fix memory leak in qcom_cpufreq_hw_read_lut()

Ondrej Mosnacek <omosnace@redhat.com>
    fs: don't audit the capability check in simple_xattr_list()

xiongxin <xiongxin@kylinos.cn>
    PM: hibernate: Fix mistake in kerneldoc comment

Reinette Chatre <reinette.chatre@intel.com>
    x86/sgx: Reduce delay and interference of enclave release

Hao Lee <haolee.swjtu@gmail.com>
    sched/psi: Fix possible missing or delayed pending event

Al Viro <viro@zeniv.linux.org.uk>
    alpha: fix syscall entry in !AUDUT_SYSCALL case

Al Viro <viro@zeniv.linux.org.uk>
    alpha: fix TIF_NOTIFY_SIGNAL handling

Ulf Hansson <ulf.hansson@linaro.org>
    cpuidle: dt: Return the correct numbers of parsed idle states

Qais Yousef <qyousef@layalina.io>
    sched/uclamp: Cater for uclamp in find_energy_efficient_cpu()'s early exit condition

Qais Yousef <qyousef@layalina.io>
    sched/uclamp: Make cpu_overutilized() use util_fits_cpu()

Qais Yousef <qyousef@layalina.io>
    sched/uclamp: Make asym_fits_capacity() use util_fits_cpu()

Qais Yousef <qyousef@layalina.io>
    sched/uclamp: Make select_idle_capacity() use util_fits_cpu()

Qais Yousef <qyousef@layalina.io>
    sched/uclamp: Fix fits_capacity() check in feec()

Qais Yousef <qyousef@layalina.io>
    sched/uclamp: Make task_fits_capacity() use util_fits_cpu()

Qais Yousef <qyousef@layalina.io>
    sched/uclamp: Fix relationship between uclamp and migration margin

Amir Goldstein <amir73il@gmail.com>
    ovl: remove privs in ovl_fallocate()

Amir Goldstein <amir73il@gmail.com>
    ovl: remove privs in ovl_copyfile()

Michael Kelley <mikelley@microsoft.com>
    tpm/tpm_crb: Fix error message in __crb_relinquish_locality()

Yuan Can <yuancan@huawei.com>
    tpm/tpm_ftpm_tee: Fix error handling in ftpm_mod_init()

Eddie James <eajames@linux.ibm.com>
    tpm: Add flag to use default cancellation policy

Eddie James <eajames@linux.ibm.com>
    tpm: tis_i2c: Fix sanity check interrupt enable mask

Janne Grunau <j@jannau.net>
    arch: arm64: apple: t8103: Use standard "iommu" node name

Stephen Boyd <swboyd@chromium.org>
    pstore: Avoid kcore oops by vmap()ing with VM_IOREMAP

Doug Brown <doug@schmorgal.com>
    ARM: mmp: fix timer_read delay

Wang Yufen <wangyufen@huawei.com>
    pstore/ram: Fix error return code in ramoops_probe()

Kuniyuki Iwashima <kuniyu@amazon.com>
    seccomp: Move copy_seccomp() to no failure path.

Yicong Yang <yangyicong@hisilicon.com>
    drivers/perf: hisi: Fix some event id for hisi-pcie-pmu

Sven Peter <sven@svenpeter.dev>
    soc: apple: rtkit: Stop casting function pointer signatures

Sven Peter <sven@svenpeter.dev>
    soc: apple: sart: Stop casting function pointer signatures

Pali Rohár <pali@kernel.org>
    arm64: dts: armada-3720-turris-mox: Add missing interrupt for RTC

Pali Rohár <pali@kernel.org>
    ARM: dts: armada-39x: Fix compatible string for gpios

Pali Rohár <pali@kernel.org>
    ARM: dts: armada-38x: Fix compatible string for gpios

Pali Rohár <pali@kernel.org>
    ARM: dts: turris-omnia: Add switch port 6 node

Pali Rohár <pali@kernel.org>
    ARM: dts: turris-omnia: Add ethernet aliases

Pali Rohár <pali@kernel.org>
    ARM: dts: armada-39x: Fix assigned-addresses for every PCIe Root Port

Pali Rohár <pali@kernel.org>
    ARM: dts: armada-38x: Fix assigned-addresses for every PCIe Root Port

Pali Rohár <pali@kernel.org>
    ARM: dts: armada-375: Fix assigned-addresses for every PCIe Root Port

Pali Rohár <pali@kernel.org>
    ARM: dts: armada-xp: Fix assigned-addresses for every PCIe Root Port

Pali Rohár <pali@kernel.org>
    ARM: dts: armada-370: Fix assigned-addresses for every PCIe Root Port

Pali Rohár <pali@kernel.org>
    ARM: dts: dove: Fix assigned-addresses for every PCIe Root Port

Frank Wunderlich <frank-w@public-files.de>
    arm64: dts: mt7986: move wed_pcie node

Vidya Sagar <vidyas@nvidia.com>
    arm64: tegra: Fix non-prefetchable aperture of PCIe C3 controller

Vidya Sagar <vidyas@nvidia.com>
    arm64: tegra: Fix Prefetchable aperture ranges of Tegra234 PCIe controllers

AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
    arm64: dts: mediatek: mt6797: Fix 26M oscillator unit name

AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
    arm64: dts: mediatek: pumpkin-common: Fix devicetree warnings

AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
    arm64: dts: mt2712-evb: Fix usb vbus regulators unit names

AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
    arm64: dts: mt2712-evb: Fix vproc fixed regulators unit names

AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
    arm64: dts: mt2712e: Fix unit address for pinctrl node

AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
    arm64: dts: mt2712e: Fix unit_address_vs_reg warning for oscillators

AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
    arm64: dts: mt6779: Fix devicetree build warnings

AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
    arm64: dts: mt7896a: Fix unit_address_vs_reg warning for oscillator

AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
    arm64: dts: mediatek: mt8195: Fix CPUs capacity-dmips-mhz

Jonathan Neuschäfer <j.neuschaefer@gmx.net>
    ARM: dts: nuvoton: Remove bogus unit addresses from fixed-partition nodes

Conor Dooley <conor.dooley@microchip.com>
    riscv: dts: microchip: remove pcie node from the sev kit

Keerthy <j-keerthy@ti.com>
    arm64: dts: ti: k3-j721s2: Fix the interrupt ranges property for main & wkup gpio intr

Jayesh Choudhary <j-choudhary@ti.com>
    arm64: dts: ti: k3-j7200-mcu-wakeup: Drop dma-coherent in crypto node

Jayesh Choudhary <j-choudhary@ti.com>
    arm64: dts: ti: k3-j721e-main: Drop dma-coherent in crypto node

Jayesh Choudhary <j-choudhary@ti.com>
    arm64: dts: ti: k3-am65-main: Drop dma-coherent in crypto node

Shang XiaoJing <shangxiaojing@huawei.com>
    perf/smmuv3: Fix hotplug callback leak in arm_smmu_pmu_init()

Shang XiaoJing <shangxiaojing@huawei.com>
    perf/arm_dmc620: Fix hotplug callback leak in dmc620_pmu_init()

Yuan Can <yuancan@huawei.com>
    drivers: perf: marvell_cn10k: Fix hotplug callback leak in tad_pmu_init()

Yuan Can <yuancan@huawei.com>
    perf: arm_dsu: Fix hotplug callback leak in dsu_pmu_init()

Mark Rutland <mark.rutland@arm.com>
    arm64: mm: kfence: only handle translation faults

Zhang Qilong <zhangqilong3@huawei.com>
    soc: ti: smartreflex: Fix PM disable depth imbalance in omap_sr_probe

Zhang Qilong <zhangqilong3@huawei.com>
    soc: ti: knav_qmss_queue: Fix PM disable depth imbalance in knav_queue_probe

Conor Dooley <conor.dooley@microchip.com>
    riscv: dts: microchip: fix the icicle's #pwm-cells

Kory Maincent <kory.maincent@bootlin.com>
    arm: dts: spear600: Fix clcd interrupt

Sibi Sankar <quic_sibis@quicinc.com>
    arm64: dts: qcom: sc7280: Mark all Qualcomm reference boards as LTE

Sumit Gupta <sumitg@nvidia.com>
    soc/tegra: cbb: Check firewall before enabling error reporting

Sumit Gupta <sumitg@nvidia.com>
    soc/tegra: cbb: Add checks for potential out of bound errors

Sumit Gupta <sumitg@nvidia.com>
    soc/tegra: cbb: Update slave maps for Tegra234

Sumit Gupta <sumitg@nvidia.com>
    soc/tegra: cbb: Use correct master_id mask for CBB NOC in Tegra194

Frank Wunderlich <frank-w@public-files.de>
    arm64: dts: mt7986: fix trng node name

Yang Yingliang <yangyingliang@huawei.com>
    soc: sifive: ccache: fix missing of_node_put() in sifive_ccache_init()

Yang Yingliang <yangyingliang@huawei.com>
    soc: sifive: ccache: fix missing free_irq() in error path in sifive_ccache_init()

Yang Yingliang <yangyingliang@huawei.com>
    soc: sifive: ccache: fix missing iounmap() in error path in sifive_ccache_init()

Conor Dooley <conor.dooley@microchip.com>
    dt-bindings: pwm: fix microchip corePWM's pwm-cells

Fabrizio Castro <fabrizio.castro.jz@renesas.com>
    arm64: dts: renesas: r9a09g011: Fix I2C SoC specific strings

Fabrizio Castro <fabrizio.castro.jz@renesas.com>
    arm64: dts: renesas: r9a09g011: Fix unit address format error

Wolfram Sang <wsa+renesas@sang-engineering.com>
    arm64: dts: renesas: r8a779f0: Fix SCIF "brg_int" clock

Wolfram Sang <wsa+renesas@sang-engineering.com>
    arm64: dts: renesas: r8a779f0: Fix HSCIF "brg_int" clock

Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
    arm64: dts: qcom: sm6125: fix SDHCI CQE reg names

Marijn Suijten <marijn.suijten@somainline.org>
    arm64: dts: qcom: pm6350: Include header for KEY_POWER

Jiasheng Jiang <jiasheng@iscas.ac.cn>
    soc: qcom: apr: Add check for idr_alloc and of_property_read_string_index

Johan Hovold <johan+linaro@kernel.org>
    arm64: dts: qcom: sm6350: drop bogus DP PHY clock

Johan Hovold <johan+linaro@kernel.org>
    arm64: dts: qcom: sm8250: drop bogus DP PHY clock

Dmitry Torokhov <dmitry.torokhov@gmail.com>
    arm64: dts: qcom: sc7280: fix codec reset line polarity for CRD 1.0/2.0

Dmitry Torokhov <dmitry.torokhov@gmail.com>
    arm64: dts: qcom: sc7280: fix codec reset line polarity for CRD 3.0/3.1

Dmitry Torokhov <dmitry.torokhov@gmail.com>
    arm64: dts: qcom: sm8250-mtp: fix reset line polarity

Dmitry Torokhov <dmitry.torokhov@gmail.com>
    arm64: dts: qcom: msm8996: fix sound card reset line polarity

Johan Hovold <johan+linaro@kernel.org>
    arm64: dts: qcom: sm8450: fix UFS PHY registers

Johan Hovold <johan+linaro@kernel.org>
    arm64: dts: qcom: sm8350: fix UFS PHY registers

Johan Hovold <johan+linaro@kernel.org>
    arm64: dts: qcom: sm8250: fix UFS PHY registers

Johan Hovold <johan+linaro@kernel.org>
    arm64: dts: qcom: sm8150: fix UFS PHY registers

Luca Weiss <luca.weiss@fairphone.com>
    soc: qcom: llcc: make irq truly optional

Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
    arm64: dts: qcom: sc7180-trogdor-homestar: fully configure secondary I2S pins

Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
    arm64: dts: qcom: sm8250: correct LPASS pin pull down

Marijn Suijten <marijn.suijten@somainline.org>
    arm64: dts: qcom: pm660: Use unique ADC5_VCOIN address in node name

Conor Dooley <conor.dooley@microchip.com>
    riscv: dts: microchip: fix memory node unit address for icicle

Georgi Vlaev <g-vlaev@ti.com>
    firmware: ti_sci: Fix polled mode during system suspend

Chen Jiahao <chenjiahao16@huawei.com>
    drivers: soc: ti: knav_qmss_queue: Mark knav_acc_firmwares as static

Marek Vasut <marex@denx.de>
    ARM: dts: stm32: Fix AV96 WLAN regulator gpio property

Marek Vasut <marex@denx.de>
    ARM: dts: stm32: Drop stm32mp15xc.dtsi from Avenger96

Marco Elver <elver@google.com>
    objtool, kcsan: Add volatile read/write instrumentation to whitelist

Cong Dang <cong.dang.xn@renesas.com>
    memory: renesas-rpc-if: Clear HS bit during hardware initialization

Padmanabhan Rajanbabu <p.rajanbabu@samsung.com>
    arm64: dts: fsd: fix drive strength values as per FSD HW UM

Padmanabhan Rajanbabu <p.rajanbabu@samsung.com>
    arm64: dts: fsd: fix drive strength macros as per FSD HW UM

Stephan Gerhold <stephan.gerhold@kernkonzept.com>
    arm64: dts: qcom: msm8916: Drop MSS fallback compatible

Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
    arm64: dts: qcom: sdm845-cheza: fix AP suspend pin bias

Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
    arm64: dts: qcom: sdm630: fix UART1 pin bias

Luca Weiss <luca@z3ntu.xyz>
    ARM: dts: qcom: apq8064: fix coresight compatible

Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
    arm64: dts: qcom: msm8996: fix GPU OPP table

Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
    arm64: dts: qcom: msm8996: fix supported-hw in cpufreq OPP tables

Yassine Oudjana <y.oudjana@protonmail.com>
    arm64: dts: qcom: msm8996: Add MSM8996 Pro support

Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
    arm64: dts: qcom: sdm845-xiaomi-polaris: fix codec pin conf name

Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
    arm64: dts: qcom: sm8250-sony-xperia-edo: fix touchscreen bias-disable

Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
    arm64: dts: qcom: ipq6018-cp01-c1: use BLSPI1 pins

Geert Uytterhoeven <geert+renesas@glider.be>
    arm64: dts: renesas: r8a779g0: Fix HSCIF0 "brg_int" clock

Ivaylo Dimitrov <ivo.g.dimitrov.75@gmail.com>
    usb: musb: remove extra check in musb_gadget_vbus_draw

Dmitry Torokhov <dmitry.torokhov@gmail.com>
    MIPS: DTS: CI20: fix reset line polarity of the ethernet controller


-------------

Diffstat:

 Documentation/ABI/stable/sysfs-driver-dma-idxd     |  12 +
 .../ABI/testing/sysfs-bus-spi-devices-spi-nor      |   3 +
 Documentation/admin-guide/sysctl/kernel.rst        |  23 +
 .../devicetree/bindings/input/azoteq,iqs7222.yaml  |  25 +-
 .../devicetree/bindings/mfd/qcom,spmi-pmic.yaml    |   8 +-
 .../devicetree/bindings/pci/fsl,imx6q-pcie.yaml    |  46 +-
 .../bindings/pci/toshiba,visconti-pcie.yaml        |   7 +-
 .../bindings/pinctrl/mediatek,mt7986-pinctrl.yaml  |  46 +-
 .../devicetree/bindings/pwm/microchip,corepwm.yaml |   4 +-
 .../devicetree/bindings/sound/qcom,wcd9335.txt     |   2 +-
 Documentation/devicetree/bindings/sound/rt5682.txt |   2 +-
 Documentation/driver-api/spi.rst                   |   4 +-
 Documentation/fault-injection/fault-injection.rst  |  10 +-
 Makefile                                           |   4 +-
 arch/Kconfig                                       |   2 +-
 arch/alpha/include/asm/thread_info.h               |   2 +-
 arch/alpha/kernel/entry.S                          |   4 +-
 arch/arm/boot/dts/armada-370.dtsi                  |   2 +-
 arch/arm/boot/dts/armada-375.dtsi                  |   2 +-
 arch/arm/boot/dts/armada-380.dtsi                  |   4 +-
 arch/arm/boot/dts/armada-385-turris-omnia.dts      |  18 +-
 arch/arm/boot/dts/armada-385.dtsi                  |   6 +-
 arch/arm/boot/dts/armada-38x.dtsi                  |   4 +-
 arch/arm/boot/dts/armada-39x.dtsi                  |  10 +-
 arch/arm/boot/dts/armada-xp-mv78230.dtsi           |   8 +-
 arch/arm/boot/dts/armada-xp-mv78260.dtsi           |  16 +-
 arch/arm/boot/dts/aspeed-bmc-ibm-everest.dts       |  17 +-
 arch/arm/boot/dts/aspeed-bmc-ibm-rainier.dts       |  16 +-
 arch/arm/boot/dts/dove.dtsi                        |   2 +-
 arch/arm/boot/dts/nuvoton-npcm730-gbs.dts          |   2 +-
 arch/arm/boot/dts/nuvoton-npcm730-gsj.dts          |   2 +-
 arch/arm/boot/dts/nuvoton-npcm730-kudo.dts         |   6 +-
 arch/arm/boot/dts/nuvoton-npcm750-evb.dts          |   4 +-
 .../boot/dts/nuvoton-npcm750-runbmc-olympus.dts    |   6 +-
 arch/arm/boot/dts/qcom-apq8064.dtsi                |   2 +-
 arch/arm/boot/dts/spear600.dtsi                    |   2 +-
 arch/arm/boot/dts/stm32mp157a-dhcor-avenger96.dts  |   1 -
 arch/arm/boot/dts/stm32mp15xx-dhcor-avenger96.dtsi |   2 +-
 arch/arm/mach-mmp/time.c                           |  11 +-
 arch/arm64/boot/dts/apple/t8103.dtsi               |   6 +-
 .../boot/dts/marvell/armada-3720-turris-mox.dts    |   3 +
 arch/arm64/boot/dts/mediatek/mt2712-evb.dts        |  12 +-
 arch/arm64/boot/dts/mediatek/mt2712e.dtsi          |  22 +-
 arch/arm64/boot/dts/mediatek/mt6779.dtsi           |   8 +-
 arch/arm64/boot/dts/mediatek/mt6797.dtsi           |   2 +-
 arch/arm64/boot/dts/mediatek/mt7986a.dtsi          |  16 +-
 arch/arm64/boot/dts/mediatek/mt8183.dtsi           |   2 +-
 arch/arm64/boot/dts/mediatek/mt8195.dtsi           |   8 +-
 arch/arm64/boot/dts/mediatek/pumpkin-common.dtsi   |   6 +-
 arch/arm64/boot/dts/nvidia/tegra234.dtsi           |   8 +-
 arch/arm64/boot/dts/qcom/ipq6018-cp01-c1.dts       |   2 +
 arch/arm64/boot/dts/qcom/msm8916.dtsi              |   2 +-
 arch/arm64/boot/dts/qcom/msm8996.dtsi              | 114 ++--
 arch/arm64/boot/dts/qcom/msm8996pro.dtsi           | 266 +++++++++
 arch/arm64/boot/dts/qcom/pm6350.dtsi               |   1 +
 arch/arm64/boot/dts/qcom/pm660.dtsi                |   2 +-
 .../boot/dts/qcom/sc7180-trogdor-homestar.dtsi     |   6 +
 arch/arm64/boot/dts/qcom/sc7280-idp.dts            |   1 -
 arch/arm64/boot/dts/qcom/sc7280-idp.dtsi           |   3 +-
 arch/arm64/boot/dts/qcom/sc7280-qcard.dtsi         |   2 +-
 arch/arm64/boot/dts/qcom/sdm630.dtsi               |   2 +-
 arch/arm64/boot/dts/qcom/sdm845-cheza.dtsi         |   4 +-
 arch/arm64/boot/dts/qcom/sdm845-xiaomi-polaris.dts |   2 +-
 arch/arm64/boot/dts/qcom/sm6125.dtsi               |   2 +-
 arch/arm64/boot/dts/qcom/sm6350.dtsi               |  10 +-
 arch/arm64/boot/dts/qcom/sm8150.dtsi               |  10 +-
 arch/arm64/boot/dts/qcom/sm8250-mtp.dts            |   2 +-
 .../boot/dts/qcom/sm8250-sony-xperia-edo.dtsi      |   2 +-
 arch/arm64/boot/dts/qcom/sm8250.dtsi               |  20 +-
 arch/arm64/boot/dts/qcom/sm8350.dtsi               |  10 +-
 .../dts/qcom/sm8450-sony-xperia-nagara-pdx223.dts  |   2 -
 arch/arm64/boot/dts/qcom/sm8450.dtsi               |  13 +-
 arch/arm64/boot/dts/renesas/r8a779f0.dtsi          |  16 +-
 arch/arm64/boot/dts/renesas/r8a779g0.dtsi          |   2 +-
 arch/arm64/boot/dts/renesas/r9a09g011.dtsi         |   6 +-
 arch/arm64/boot/dts/tesla/fsd-pinctrl.dtsi         |  34 +-
 arch/arm64/boot/dts/tesla/fsd-pinctrl.h            |   6 +-
 arch/arm64/boot/dts/ti/k3-am65-main.dtsi           |   1 -
 arch/arm64/boot/dts/ti/k3-j7200-mcu-wakeup.dtsi    |   1 -
 arch/arm64/boot/dts/ti/k3-j721e-main.dtsi          |   1 -
 arch/arm64/boot/dts/ti/k3-j721s2-main.dtsi         |   2 +-
 arch/arm64/boot/dts/ti/k3-j721s2-mcu-wakeup.dtsi   |   2 +-
 arch/arm64/crypto/Kconfig                          |  11 +
 arch/arm64/crypto/Makefile                         |   3 +
 arch/arm64/crypto/sm3-neon-core.S                  | 601 ++++++++++++++++++++
 arch/arm64/crypto/sm3-neon-glue.c                  | 103 ++++
 arch/arm64/include/asm/processor.h                 |   4 +-
 arch/arm64/mm/fault.c                              |   8 +-
 arch/mips/bcm63xx/clk.c                            |   2 +
 arch/mips/boot/dts/ingenic/ci20.dts                |   2 +-
 .../cavium-octeon/executive/cvmx-helper-board.c    |   2 +-
 arch/mips/cavium-octeon/executive/cvmx-helper.c    |   2 +-
 arch/mips/kernel/vpe-cmp.c                         |   4 +-
 arch/mips/kernel/vpe-mt.c                          |   4 +-
 arch/mips/ralink/of.c                              |   4 +-
 arch/powerpc/boot/dts/turris1x.dts                 |  14 +
 arch/powerpc/include/asm/hvcall.h                  |   3 +-
 arch/powerpc/perf/callchain.c                      |   1 +
 arch/powerpc/perf/hv-gpci-requests.h               |   4 +
 arch/powerpc/perf/hv-gpci.c                        |  35 +-
 arch/powerpc/perf/hv-gpci.h                        |   1 +
 arch/powerpc/perf/req-gen/perf.h                   |  20 +
 arch/powerpc/platforms/52xx/mpc52xx_lpbfifo.c      |   1 +
 arch/powerpc/platforms/83xx/mpc832x_rdb.c          |   2 +-
 arch/powerpc/platforms/pseries/eeh_pseries.c       |  11 +-
 arch/powerpc/platforms/pseries/plpks.c             |  32 +-
 arch/powerpc/platforms/pseries/plpks.h             |   2 +-
 arch/powerpc/sysdev/xive/spapr.c                   |   1 +
 arch/powerpc/xmon/xmon.c                           |   7 +-
 .../boot/dts/microchip/mpfs-icicle-kit-fabric.dtsi |   2 +-
 arch/riscv/boot/dts/microchip/mpfs-icicle-kit.dts  |   2 +-
 .../boot/dts/microchip/mpfs-sev-kit-fabric.dtsi    |  29 -
 arch/riscv/include/asm/hugetlb.h                   |   6 +
 arch/riscv/include/asm/io.h                        |   5 +
 arch/riscv/include/asm/pgtable-64.h                |   6 +-
 arch/riscv/kernel/entry.S                          |  18 +-
 arch/riscv/kernel/signal.c                         |  34 +-
 arch/riscv/kernel/traps.c                          |   2 +-
 arch/riscv/kvm/vcpu.c                              |  11 +-
 arch/riscv/mm/physaddr.c                           |   2 +-
 arch/riscv/net/bpf_jit_comp64.c                    |  29 +-
 arch/x86/Kconfig                                   |   4 +-
 arch/x86/crypto/aegis128-aesni-asm.S               |   9 +-
 arch/x86/crypto/aria-aesni-avx-asm_64.S            |  13 +-
 arch/x86/crypto/sha1_ni_asm.S                      |   3 +-
 arch/x86/crypto/sha1_ssse3_asm.S                   |   3 +-
 arch/x86/crypto/sha256-avx-asm.S                   |   3 +-
 arch/x86/crypto/sha256-avx2-asm.S                  |   3 +-
 arch/x86/crypto/sha256-ssse3-asm.S                 |   3 +-
 arch/x86/crypto/sha256_ni_asm.S                    |   3 +-
 arch/x86/crypto/sha512-avx-asm.S                   |   3 +-
 arch/x86/crypto/sha512-avx2-asm.S                  |   3 +-
 arch/x86/crypto/sha512-ssse3-asm.S                 |   3 +-
 arch/x86/crypto/sm3-avx-asm_64.S                   |   3 +-
 arch/x86/crypto/sm4-aesni-avx-asm_64.S             |   7 +-
 arch/x86/crypto/sm4-aesni-avx2-asm_64.S            |   7 +-
 arch/x86/events/intel/uncore_snb.c                 |   3 +
 arch/x86/events/intel/uncore_snbep.c               |   5 +
 arch/x86/hyperv/hv_init.c                          |   2 -
 arch/x86/include/asm/apic.h                        |   3 +-
 arch/x86/include/asm/realmode.h                    |   1 +
 arch/x86/include/asm/x86_init.h                    |   4 +
 arch/x86/kernel/apic/apic.c                        |  13 +-
 arch/x86/kernel/cpu/intel.c                        |  63 ++-
 arch/x86/kernel/cpu/sgx/encl.c                     |  23 +-
 arch/x86/kernel/setup.c                            |   2 +-
 arch/x86/kernel/uprobes.c                          |   4 +-
 arch/x86/kernel/x86_init.c                         |   3 +
 arch/x86/realmode/init.c                           |   8 +-
 arch/x86/xen/enlighten_pv.c                        |   2 +
 arch/x86/xen/smp.c                                 |  24 +-
 arch/x86/xen/smp_pv.c                              |  12 +-
 arch/x86/xen/spinlock.c                            |   6 +-
 block/bfq-iosched.c                                |  16 +-
 block/blk-cgroup.c                                 |   2 +
 block/blk-mq-sysfs.c                               |  11 +-
 block/blk-mq.c                                     |  56 +-
 block/genhd.c                                      |   2 +
 crypto/cryptd.c                                    |  36 +-
 crypto/tcrypt.c                                    | 265 +++++----
 drivers/acpi/acpica/dsmethod.c                     |  10 +-
 drivers/acpi/acpica/utcopy.c                       |   7 -
 drivers/acpi/ec.c                                  |  10 +
 drivers/acpi/irq.c                                 |   5 +-
 drivers/acpi/pfr_telemetry.c                       |   6 +-
 drivers/acpi/pfr_update.c                          |   6 +-
 drivers/acpi/processor_idle.c                      |   3 +
 drivers/acpi/video_detect.c                        |  54 +-
 drivers/acpi/x86/utils.c                           |  24 +-
 drivers/ata/libata-sata.c                          |  11 +-
 drivers/base/class.c                               |   5 +
 drivers/base/power/runtime.c                       |  12 +-
 drivers/base/regmap/regmap-irq.c                   |  15 +-
 drivers/block/drbd/drbd_main.c                     |   9 +-
 drivers/block/drbd/drbd_nl.c                       |  10 +-
 drivers/block/floppy.c                             |   4 +-
 drivers/block/loop.c                               |  28 +-
 drivers/bluetooth/btintel.c                        |   5 +-
 drivers/bluetooth/btusb.c                          |   6 +-
 drivers/bluetooth/hci_bcm.c                        |  13 +-
 drivers/bluetooth/hci_bcsp.c                       |   2 +-
 drivers/bluetooth/hci_h5.c                         |   2 +-
 drivers/bluetooth/hci_ll.c                         |   2 +-
 drivers/bluetooth/hci_qca.c                        |   2 +-
 drivers/char/hw_random/amd-rng.c                   |  18 +-
 drivers/char/hw_random/geode-rng.c                 |  36 +-
 drivers/char/ipmi/ipmi_msghandler.c                |   8 +-
 drivers/char/ipmi/kcs_bmc_aspeed.c                 |  24 +-
 drivers/char/tpm/tpm_crb.c                         |   2 +-
 drivers/char/tpm/tpm_ftpm_tee.c                    |   8 +-
 drivers/char/tpm/tpm_tis_core.c                    |  20 +-
 drivers/char/tpm/tpm_tis_core.h                    |   1 +
 drivers/char/tpm/tpm_tis_i2c.c                     |   3 +-
 drivers/clk/imx/clk-imx8mn.c                       | 116 ++--
 drivers/clk/imx/clk-imx8mp.c                       |   4 +-
 drivers/clk/imx/clk-imx93.c                        |  19 +-
 drivers/clk/imx/clk-imxrt1050.c                    |   2 +-
 drivers/clk/mediatek/clk-mt7986-infracfg.c         |   2 +-
 drivers/clk/microchip/clk-mpfs-ccc.c               |   6 +
 drivers/clk/qcom/clk-krait.c                       |   2 +
 drivers/clk/qcom/dispcc-sm6350.c                   |   4 +-
 drivers/clk/qcom/gcc-ipq806x.c                     |   4 +-
 drivers/clk/qcom/gcc-sm8250.c                      |   4 +-
 drivers/clk/qcom/lpassaudiocc-sc7280.c             |  55 +-
 drivers/clk/qcom/lpasscorecc-sc7180.c              |  24 +-
 drivers/clk/renesas/r8a779a0-cpg-mssr.c            |   2 +-
 drivers/clk/renesas/r8a779f0-cpg-mssr.c            |  18 +-
 drivers/clk/renesas/r9a06g032-clocks.c             |   3 +-
 drivers/clk/rockchip/clk-pll.c                     |   1 +
 drivers/clk/samsung/clk-pll.c                      |   1 +
 drivers/clk/socfpga/clk-gate.c                     |   5 +-
 drivers/clk/st/clkgen-fsyn.c                       |   5 +-
 drivers/clk/visconti/pll.c                         |   1 +
 drivers/clocksource/sh_cmt.c                       |  88 +--
 drivers/clocksource/timer-ti-dm-systimer.c         |   4 +-
 drivers/clocksource/timer-ti-dm.c                  |   2 +-
 drivers/counter/stm32-lptimer-cnt.c                |   2 +-
 drivers/cpufreq/amd_freq_sensitivity.c             |   2 +
 drivers/cpufreq/qcom-cpufreq-hw.c                  |  43 +-
 drivers/cpuidle/dt_idle_states.c                   |   2 +-
 drivers/crypto/Kconfig                             |   5 +
 .../crypto/allwinner/sun8i-ss/sun8i-ss-cipher.c    |   2 +-
 drivers/crypto/amlogic/amlogic-gxl-core.c          |   1 -
 drivers/crypto/amlogic/amlogic-gxl.h               |   2 +-
 drivers/crypto/cavium/nitrox/nitrox_mbx.c          |   1 +
 drivers/crypto/ccree/cc_debugfs.c                  |   2 +-
 drivers/crypto/ccree/cc_driver.c                   |  10 +-
 drivers/crypto/hisilicon/hpre/hpre_main.c          |  10 +-
 drivers/crypto/hisilicon/qm.c                      |  11 +-
 drivers/crypto/img-hash.c                          |   8 +-
 drivers/crypto/omap-sham.c                         |   2 +-
 drivers/crypto/qat/qat_4xxx/adf_drv.c              |   1 +
 drivers/crypto/rockchip/rk3288_crypto.c            | 193 +------
 drivers/crypto/rockchip/rk3288_crypto.h            |  53 +-
 drivers/crypto/rockchip/rk3288_crypto_ahash.c      | 197 ++++---
 drivers/crypto/rockchip/rk3288_crypto_skcipher.c   | 413 ++++++++------
 drivers/dio/dio.c                                  |   8 +
 drivers/dma/apple-admac.c                          | 102 +++-
 drivers/dma/idxd/sysfs.c                           |  68 +++
 drivers/edac/i10nm_base.c                          |   3 +-
 drivers/extcon/extcon-usbc-tusb320.c               |  17 +-
 drivers/firmware/raspberrypi.c                     |   1 +
 drivers/firmware/ti_sci.c                          |   5 +-
 drivers/gpio/gpiolib-cdev.c                        | 204 ++++++-
 drivers/gpio/gpiolib.c                             |   4 +
 drivers/gpio/gpiolib.h                             |   5 +
 drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c   |   2 +-
 drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c           |   1 +
 drivers/gpu/drm/amd/amdgpu/amdgpu_device.c         |   9 +
 drivers/gpu/drm/amd/amdgpu/amdgpu_virt.h           |   5 +-
 drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.c           |   2 -
 drivers/gpu/drm/amd/amdgpu/nv.c                    |  28 +-
 drivers/gpu/drm/amd/amdgpu/soc15.c                 |  24 +-
 drivers/gpu/drm/amd/amdgpu/soc21.c                 |   2 +-
 .../drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c  |  35 --
 drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c |  16 +-
 .../amd/display/dc/clk_mgr/dcn32/dcn32_clk_mgr.c   |   2 +-
 drivers/gpu/drm/amd/display/dc/core/dc.c           |  65 ++-
 .../gpu/drm/amd/display/dc/dce60/dce60_resource.c  |   3 +
 .../gpu/drm/amd/display/dc/dce80/dce80_resource.c  |   2 +
 .../drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c  |  30 +-
 drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c |  35 +-
 drivers/gpu/drm/amd/display/dc/dcn32/dcn32_dccg.c  |   6 +-
 .../gpu/drm/amd/display/dc/dcn32/dcn32_resource.c  |   2 +-
 .../gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c   |   7 +
 drivers/gpu/drm/amd/include/kgd_pp_interface.h     |   3 +-
 drivers/gpu/drm/amd/pm/powerplay/amd_powerplay.c   |   3 +-
 drivers/gpu/drm/amd/pm/powerplay/hwmgr/pp_psm.c    |   2 +
 .../drm/amd/pm/powerplay/hwmgr/vega10_thermal.c    |  25 +-
 .../gpu/drm/amd/pm/powerplay/hwmgr/vega20_hwmgr.c  |   3 +-
 drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c     |   4 +
 .../gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c   |  21 +-
 drivers/gpu/drm/bridge/adv7511/adv7511.h           |   3 +-
 drivers/gpu/drm/bridge/adv7511/adv7511_drv.c       |  18 +-
 drivers/gpu/drm/bridge/adv7511/adv7533.c           |  25 +-
 drivers/gpu/drm/bridge/ite-it6505.c                |   8 +-
 drivers/gpu/drm/drm_atomic_helper.c                |  10 +-
 drivers/gpu/drm/drm_edid.c                         |  12 +
 drivers/gpu/drm/drm_fourcc.c                       |   8 +-
 drivers/gpu/drm/etnaviv/etnaviv_gpu.c              |  11 +-
 drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c          |   5 +-
 drivers/gpu/drm/i915/display/intel_bios.c          |   2 +-
 drivers/gpu/drm/i915/display/intel_dp.c            |  59 --
 drivers/gpu/drm/i915/gem/i915_gem_mman.c           |  21 +-
 drivers/gpu/drm/i915/gem/i915_gem_pm.c             |   2 +-
 drivers/gpu/drm/i915/gem/i915_gem_ttm.c            |  63 ++-
 drivers/gpu/drm/i915/gem/i915_gem_ttm.h            |  18 +-
 drivers/gpu/drm/i915/gem/i915_gem_ttm_move.c       |   2 +-
 drivers/gpu/drm/i915/gt/intel_engine.h             |   6 +
 drivers/gpu/drm/i915/gt/intel_engine_cs.c          |  91 ++-
 drivers/gpu/drm/i915/gt/intel_gt.c                 |   3 -
 drivers/gpu/drm/i915/gt/intel_gt_types.h           |  17 -
 drivers/gpu/drm/i915/gt/sysfs_engines.c            |  25 +-
 drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c     | 109 +++-
 drivers/gpu/drm/i915/gt/uc/intel_guc_fwif.h        |  21 +
 drivers/gpu/drm/i915/gt/uc/intel_guc_log.c         |   6 +-
 drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c  |   8 +
 drivers/gpu/drm/i915/i915_driver.c                 |   3 +-
 drivers/gpu/drm/i915/i915_gem.c                    |  45 +-
 drivers/gpu/drm/i915/intel_runtime_pm.c            |   5 +
 drivers/gpu/drm/i915/intel_runtime_pm.h            |  22 +
 drivers/gpu/drm/mediatek/mtk_dpi.c                 |  12 +-
 drivers/gpu/drm/mediatek/mtk_hdmi.c                |   7 +-
 drivers/gpu/drm/meson/meson_encoder_cvbs.c         |   7 +-
 drivers/gpu/drm/msm/adreno/a6xx_gpu.c              |  12 +-
 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.c         |  11 +-
 drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c           |  27 +-
 drivers/gpu/drm/msm/dp/dp_display.c                |   2 +-
 drivers/gpu/drm/msm/dsi/dsi_host.c                 | 121 ++--
 drivers/gpu/drm/msm/hdmi/hdmi.c                    |   2 +-
 drivers/gpu/drm/mxsfb/lcdif_kms.c                  |  48 +-
 drivers/gpu/drm/mxsfb/lcdif_regs.h                 |   5 +
 drivers/gpu/drm/panel/panel-sitronix-st7701.c      |  12 +-
 drivers/gpu/drm/radeon/radeon_bios.c               |  19 +-
 drivers/gpu/drm/rcar-du/Kconfig                    |   2 -
 drivers/gpu/drm/rockchip/cdn-dp-core.c             |   2 +-
 drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c    |   2 +-
 drivers/gpu/drm/rockchip/inno_hdmi.c               |   2 +-
 drivers/gpu/drm/rockchip/rk3066_hdmi.c             |   2 +-
 drivers/gpu/drm/rockchip/rockchip_drm_vop.c        |   4 +-
 drivers/gpu/drm/rockchip/rockchip_drm_vop2.c       |   2 +-
 drivers/gpu/drm/rockchip/rockchip_lvds.c           |  10 +-
 drivers/gpu/drm/sti/sti_dvo.c                      |   7 +-
 drivers/gpu/drm/sti/sti_hda.c                      |   7 +-
 drivers/gpu/drm/sti/sti_hdmi.c                     |   7 +-
 drivers/gpu/drm/tegra/dc.c                         |   4 +-
 drivers/hid/amd-sfh-hid/amd_sfh_client.c           |   4 +
 drivers/hid/hid-apple.c                            | 118 ++--
 drivers/hid/hid-input.c                            |   6 +
 drivers/hid/hid-logitech-hidpp.c                   |  11 +-
 drivers/hid/hid-mcp2221.c                          |  12 +-
 drivers/hid/hid-rmi.c                              |   2 +
 drivers/hid/hid-sensor-custom.c                    |   2 +-
 drivers/hid/hid-uclogic-params.c                   |  73 +++
 drivers/hid/hid-uclogic-rdesc.c                    |  34 ++
 drivers/hid/hid-uclogic-rdesc.h                    |   7 +
 drivers/hid/i2c-hid/i2c-hid-core.c                 |   3 +-
 drivers/hid/wacom_sys.c                            |   8 +
 drivers/hid/wacom_wac.c                            |   4 +
 drivers/hid/wacom_wac.h                            |   1 +
 drivers/hsi/controllers/omap_ssi_core.c            |  14 +-
 drivers/hv/ring_buffer.c                           |  13 +
 drivers/hwmon/Kconfig                              |   1 +
 drivers/hwmon/emc2305.c                            |  44 +-
 drivers/hwmon/jc42.c                               | 243 +++++----
 drivers/hwmon/nct6775-platform.c                   |   7 +
 drivers/hwtracing/coresight/coresight-cti-core.c   |   2 +-
 drivers/hwtracing/coresight/coresight-trbe.c       |   1 +
 drivers/i2c/busses/i2c-ismt.c                      |   3 +
 drivers/i2c/busses/i2c-pxa-pci.c                   |  10 +-
 drivers/i2c/muxes/i2c-mux-reg.c                    |   5 +-
 drivers/iio/adc/ad_sigma_delta.c                   |   8 +-
 drivers/iio/adc/ti-adc128s052.c                    |  14 +-
 drivers/iio/addac/ad74413r.c                       |   2 +-
 drivers/iio/imu/adis.c                             |  28 +-
 drivers/iio/industrialio-event.c                   |   4 +-
 drivers/iio/temperature/ltc2983.c                  |  10 +-
 drivers/infiniband/Kconfig                         |   2 +
 drivers/infiniband/core/device.c                   |   2 +-
 drivers/infiniband/core/mad.c                      |   5 -
 drivers/infiniband/core/nldev.c                    |   6 +-
 drivers/infiniband/core/restrack.c                 |   2 -
 drivers/infiniband/core/sysfs.c                    |  17 +-
 drivers/infiniband/hw/hfi1/affinity.c              |   2 +
 drivers/infiniband/hw/hfi1/firmware.c              |   6 +
 drivers/infiniband/hw/hns/hns_roce_device.h        |   3 +
 drivers/infiniband/hw/hns/hns_roce_hw_v2.c         | 217 ++++++--
 drivers/infiniband/hw/hns/hns_roce_hw_v2.h         |  13 +-
 drivers/infiniband/hw/hns/hns_roce_main.c          |  18 +-
 drivers/infiniband/hw/hns/hns_roce_mr.c            |   4 +-
 drivers/infiniband/hw/hns/hns_roce_qp.c            | 107 +++-
 drivers/infiniband/hw/irdma/uk.c                   | 170 +++---
 drivers/infiniband/hw/irdma/user.h                 |  20 +-
 drivers/infiniband/hw/irdma/utils.c                |   2 +
 drivers/infiniband/hw/irdma/verbs.c                | 145 ++---
 drivers/infiniband/hw/irdma/verbs.h                |  53 ++
 drivers/infiniband/sw/rxe/rxe_mr.c                 |   9 +-
 drivers/infiniband/sw/rxe/rxe_qp.c                 |   6 +-
 drivers/infiniband/sw/siw/siw_cq.c                 |  24 +-
 drivers/infiniband/sw/siw/siw_qp_tx.c              |   2 +-
 drivers/infiniband/sw/siw/siw_verbs.c              |  40 +-
 drivers/infiniband/ulp/ipoib/ipoib_netlink.c       |   7 +
 drivers/infiniband/ulp/srp/ib_srp.c                |  96 +++-
 drivers/input/joystick/Kconfig                     |   1 +
 drivers/input/misc/Kconfig                         |   2 +-
 drivers/input/misc/iqs7222.c                       | 504 ++++++++++-------
 drivers/input/touchscreen/elants_i2c.c             |   9 +-
 drivers/interconnect/qcom/sc7180.c                 |   2 +-
 drivers/iommu/amd/iommu_v2.c                       |   1 +
 drivers/iommu/fsl_pamu.c                           |   2 +-
 drivers/iommu/iommu.c                              |  28 +-
 drivers/iommu/mtk_iommu.c                          |  53 +-
 drivers/iommu/rockchip-iommu.c                     |  10 +-
 drivers/iommu/s390-iommu.c                         | 106 ++--
 drivers/iommu/sun50i-iommu.c                       |  89 ++-
 drivers/irqchip/irq-gic-pm.c                       |   2 +-
 drivers/irqchip/irq-loongson-liointc.c             |   5 +-
 drivers/irqchip/irq-loongson-pch-pic.c             |   3 +
 drivers/irqchip/irq-wpcm450-aic.c                  |   1 +
 drivers/isdn/hardware/mISDN/hfcmulti.c             |  19 +-
 drivers/isdn/hardware/mISDN/hfcpci.c               |  13 +-
 drivers/isdn/hardware/mISDN/hfcsusb.c              |  12 +-
 drivers/leds/leds-is31fl319x.c                     |   3 +-
 drivers/leds/rgb/leds-qcom-lpg.c                   |  18 +-
 drivers/macintosh/macio-adb.c                      |   4 +
 drivers/macintosh/macio_asic.c                     |   2 +-
 drivers/mailbox/arm_mhuv2.c                        |   4 +-
 drivers/mailbox/mailbox-mpfs.c                     |  31 +-
 drivers/mailbox/pcc.c                              |   1 +
 drivers/mailbox/zynqmp-ipi-mailbox.c               |   4 +-
 drivers/mcb/mcb-core.c                             |   4 +-
 drivers/mcb/mcb-parse.c                            |   2 +-
 drivers/md/dm.c                                    | 123 +++--
 drivers/md/md-bitmap.c                             |  27 +-
 drivers/md/raid0.c                                 |   1 -
 drivers/md/raid1.c                                 |   1 +
 drivers/md/raid10.c                                |   2 -
 drivers/media/dvb-core/dvb_ca_en50221.c            |   2 +-
 drivers/media/dvb-core/dvb_frontend.c              |  10 +-
 drivers/media/dvb-core/dvbdev.c                    |  32 +-
 drivers/media/dvb-frontends/bcm3510.c              |   1 +
 drivers/media/i2c/ad5820.c                         |  10 +-
 drivers/media/i2c/adv748x/adv748x-afe.c            |   4 +
 drivers/media/i2c/dw9768.c                         |  33 +-
 drivers/media/i2c/hi846.c                          |  14 +-
 drivers/media/i2c/mt9p031.c                        |   1 -
 drivers/media/i2c/ov5640.c                         |   3 +-
 drivers/media/i2c/ov5648.c                         |   1 +
 drivers/media/pci/saa7164/saa7164-core.c           |   4 +-
 drivers/media/pci/solo6x10/solo6x10-core.c         |   1 +
 drivers/media/platform/amphion/vdec.c              |  15 +-
 drivers/media/platform/amphion/vpu.h               |   1 +
 drivers/media/platform/amphion/vpu_cmds.c          |  39 +-
 drivers/media/platform/amphion/vpu_drv.c           |   6 +-
 drivers/media/platform/amphion/vpu_malone.c        |   1 +
 drivers/media/platform/amphion/vpu_msgs.c          |   2 +
 drivers/media/platform/amphion/vpu_v4l2.c          |  30 +-
 drivers/media/platform/amphion/vpu_windsor.c       |   1 +
 drivers/media/platform/chips-media/coda-bit.c      |  14 +-
 drivers/media/platform/chips-media/coda-jpeg.c     |  10 +-
 .../media/platform/mediatek/mdp3/mtk-mdp3-cmdq.c   |  51 +-
 .../media/platform/mediatek/mdp3/mtk-mdp3-comp.c   |  24 +-
 .../media/platform/mediatek/mdp3/mtk-mdp3-core.c   |  15 +-
 .../mediatek/vcodec/mtk_vcodec_dec_stateless.c     |  13 +-
 .../mediatek/vcodec/vdec/vdec_h264_req_multi_if.c  |  60 +-
 .../mediatek/vcodec/vdec/vdec_vp9_req_lat_if.c     |  15 +-
 .../platform/mediatek/vcodec/vdec_msg_queue.c      |   2 +-
 drivers/media/platform/nxp/imx-jpeg/mxc-jpeg-hw.c  |   4 +-
 drivers/media/platform/qcom/camss/camss-video.c    |   3 +-
 drivers/media/platform/qcom/camss/camss.c          |  11 +
 drivers/media/platform/qcom/venus/pm_helpers.c     |   4 +-
 .../media/platform/samsung/exynos4-is/fimc-core.c  |   2 +-
 .../media/platform/samsung/exynos4-is/media-dev.c  |  12 +-
 drivers/media/platform/samsung/s5p-mfc/s5p_mfc.c   |  17 +-
 .../platform/st/sti/c8sectpfe/c8sectpfe-core.c     |   1 +
 .../sunxi/sun6i-mipi-csi2/sun6i_mipi_csi2.c        |  23 +-
 .../sun8i-a83t-mipi-csi2/sun8i_a83t_mipi_csi2.c    |  23 +-
 drivers/media/radio/si470x/radio-si470x-usb.c      |   4 +-
 drivers/media/rc/imon.c                            |   6 +-
 drivers/media/test-drivers/vidtv/vidtv_bridge.c    |  22 +-
 drivers/media/test-drivers/vimc/vimc-core.c        |   2 +-
 drivers/media/test-drivers/vivid/vivid-vid-cap.c   |   1 +
 drivers/media/usb/dvb-usb/az6027.c                 |   4 +
 drivers/media/usb/dvb-usb/dvb-usb-init.c           |   4 +-
 drivers/media/v4l2-core/v4l2-ctrls-api.c           |   1 +
 drivers/media/v4l2-core/v4l2-ctrls-core.c          |   2 +-
 drivers/media/v4l2-core/v4l2-ioctl.c               |  34 +-
 drivers/media/v4l2-core/videobuf-dma-contig.c      |  22 +-
 drivers/memory/renesas-rpc-if.c                    |   3 +
 drivers/memstick/core/ms_block.c                   |   9 +-
 drivers/mfd/Kconfig                                |   1 +
 drivers/mfd/axp20x.c                               |   2 +-
 drivers/mfd/qcom-pm8008.c                          |   4 +-
 drivers/mfd/qcom_rpm.c                             |  16 +-
 drivers/misc/cxl/guest.c                           |  24 +-
 drivers/misc/cxl/pci.c                             |  21 +-
 drivers/misc/habanalabs/common/firmware_if.c       |   2 +-
 drivers/misc/lkdtm/cfi.c                           |   6 +-
 drivers/misc/ocxl/config.c                         |  20 +-
 drivers/misc/ocxl/file.c                           |   7 +-
 drivers/misc/sgi-gru/grufault.c                    |  13 +-
 drivers/misc/sgi-gru/grumain.c                     |  22 +-
 drivers/misc/sgi-gru/grutables.h                   |   2 +-
 drivers/misc/tifm_7xx1.c                           |   2 +-
 drivers/mmc/core/sd.c                              |  11 +-
 drivers/mmc/host/alcor.c                           |   5 +-
 drivers/mmc/host/atmel-mci.c                       |   9 +-
 drivers/mmc/host/litex_mmc.c                       |   1 +
 drivers/mmc/host/meson-gx-mmc.c                    |   4 +-
 drivers/mmc/host/mmci.c                            |   4 +-
 drivers/mmc/host/moxart-mmc.c                      |   4 +-
 drivers/mmc/host/mxcmmc.c                          |   4 +-
 drivers/mmc/host/omap_hsmmc.c                      |   4 +-
 drivers/mmc/host/pxamci.c                          |   7 +-
 drivers/mmc/host/renesas_sdhi.h                    |   1 +
 drivers/mmc/host/renesas_sdhi_core.c               |  14 +-
 drivers/mmc/host/renesas_sdhi_internal_dmac.c      |   4 +-
 drivers/mmc/host/rtsx_pci_sdmmc.c                  |   9 +-
 drivers/mmc/host/rtsx_usb_sdmmc.c                  |  11 +-
 drivers/mmc/host/sdhci-tegra.c                     |   3 +-
 drivers/mmc/host/sdhci.c                           |   5 +
 drivers/mmc/host/sdhci.h                           |   2 +
 drivers/mmc/host/sdhci_f_sdh30.c                   |   3 +
 drivers/mmc/host/toshsd.c                          |   6 +-
 drivers/mmc/host/via-sdmmc.c                       |   4 +-
 drivers/mmc/host/vub300.c                          |  11 +-
 drivers/mmc/host/wbsd.c                            |  12 +-
 drivers/mmc/host/wmt-sdmmc.c                       |   6 +-
 drivers/mtd/lpddr/lpddr2_nvm.c                     |   2 +
 drivers/mtd/maps/pxa2xx-flash.c                    |   2 +
 drivers/mtd/mtdcore.c                              |   9 +-
 drivers/mtd/spi-nor/core.c                         |   3 +-
 drivers/mtd/spi-nor/sysfs.c                        |  14 +
 drivers/net/bonding/bond_main.c                    |  37 +-
 drivers/net/can/m_can/m_can.c                      |  32 +-
 drivers/net/can/m_can/m_can_platform.c             |   4 -
 drivers/net/can/m_can/tcan4x5x-core.c              |  18 +-
 drivers/net/can/usb/kvaser_usb/kvaser_usb.h        |  30 +-
 drivers/net/can/usb/kvaser_usb/kvaser_usb_core.c   | 115 +++-
 drivers/net/can/usb/kvaser_usb/kvaser_usb_hydra.c  | 160 +++++-
 drivers/net/can/usb/kvaser_usb/kvaser_usb_leaf.c   | 437 +++++++++++++--
 drivers/net/dsa/lan9303-core.c                     |   4 +-
 drivers/net/dsa/microchip/ksz_common.c             |   3 +-
 drivers/net/dsa/mv88e6xxx/chip.c                   |   9 +-
 drivers/net/ethernet/adi/adin1110.c                |  37 +-
 drivers/net/ethernet/amd/atarilance.c              |   2 +-
 drivers/net/ethernet/amd/lance.c                   |   2 +-
 drivers/net/ethernet/amd/xgbe/xgbe-phy-v2.c        |  23 +-
 drivers/net/ethernet/apple/bmac.c                  |   2 +-
 drivers/net/ethernet/apple/mace.c                  |   2 +-
 drivers/net/ethernet/broadcom/bnx2.c               |   5 +-
 drivers/net/ethernet/dnet.c                        |   4 +-
 drivers/net/ethernet/freescale/enetc/enetc.c       |  35 +-
 drivers/net/ethernet/freescale/fec_main.c          |   8 +
 drivers/net/ethernet/intel/i40e/i40e_main.c        |  36 +-
 drivers/net/ethernet/intel/ice/ice_ptp.c           |  10 +-
 drivers/net/ethernet/intel/igb/igb_main.c          |   8 +-
 drivers/net/ethernet/intel/igc/igc.h               |   3 +
 drivers/net/ethernet/intel/igc/igc_defines.h       |   2 +
 drivers/net/ethernet/intel/igc/igc_main.c          | 210 ++++++-
 drivers/net/ethernet/intel/igc/igc_tsn.c           |  13 +-
 drivers/net/ethernet/marvell/octeontx2/af/mcs.c    |   6 +-
 drivers/net/ethernet/mediatek/mtk_eth_soc.c        |  71 ++-
 drivers/net/ethernet/mediatek/mtk_eth_soc.h        |  11 +-
 drivers/net/ethernet/myricom/myri10ge/myri10ge.c   |   1 +
 drivers/net/ethernet/neterion/s2io.c               |   2 +-
 drivers/net/ethernet/qlogic/qed/qed_debug.c        |   3 +-
 .../ethernet/qlogic/qlcnic/qlcnic_sriov_common.c   |   2 +
 drivers/net/ethernet/rdc/r6040.c                   |   5 +-
 .../net/ethernet/stmicro/stmmac/stmmac_hwtstamp.c  |   3 +-
 drivers/net/ethernet/stmicro/stmmac/stmmac_main.c  |   4 +-
 drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.h   |   2 +-
 .../net/ethernet/stmicro/stmmac/stmmac_selftests.c |   8 +-
 drivers/net/ethernet/ti/am65-cpsw-nuss.c           |  10 +-
 drivers/net/ethernet/ti/netcp_core.c               |   2 +-
 drivers/net/ethernet/xilinx/xilinx_emaclite.c      |   2 +-
 drivers/net/fddi/defxx.c                           |  22 +-
 drivers/net/hamradio/baycom_epp.c                  |   2 +-
 drivers/net/hamradio/scc.c                         |   6 +-
 drivers/net/macsec.c                               |  34 +-
 drivers/net/mctp/mctp-serial.c                     |   6 +-
 drivers/net/ntb_netdev.c                           |   4 +-
 drivers/net/ppp/ppp_generic.c                      |   2 +
 drivers/net/wan/farsync.c                          |   2 +
 drivers/net/wireless/ath/ar5523/ar5523.c           |   6 +
 drivers/net/wireless/ath/ath10k/core.c             |  16 +
 drivers/net/wireless/ath/ath10k/htc.c              |   9 +
 drivers/net/wireless/ath/ath10k/hw.h               |   2 +
 drivers/net/wireless/ath/ath10k/pci.c              |  20 +-
 drivers/net/wireless/ath/ath11k/core.h             |   2 +
 drivers/net/wireless/ath/ath11k/mac.c              | 122 +++--
 drivers/net/wireless/ath/ath11k/qmi.c              |   3 +
 drivers/net/wireless/ath/ath9k/hif_usb.c           |  46 +-
 .../wireless/broadcom/brcm80211/brcmfmac/common.c  |   8 +-
 .../broadcom/brcm80211/brcmfmac/firmware.c         |   5 +
 .../wireless/broadcom/brcm80211/brcmfmac/pcie.c    |   6 +-
 .../wireless/broadcom/brcm80211/brcmfmac/sdio.c    |   1 +
 drivers/net/wireless/intel/iwlwifi/mei/iwl-mei.h   |   7 +-
 drivers/net/wireless/intel/iwlwifi/mei/main.c      | 172 +++---
 drivers/net/wireless/intel/iwlwifi/mei/net.c       |  10 +-
 drivers/net/wireless/intel/iwlwifi/mvm/fw.c        |   2 +
 drivers/net/wireless/intel/iwlwifi/mvm/mvm.h       |   4 +-
 drivers/net/wireless/intel/iwlwifi/mvm/ops.c       |   2 +-
 drivers/net/wireless/intel/iwlwifi/mvm/tx.c        |  20 +-
 drivers/net/wireless/mediatek/mt76/mt76.h          |   3 +-
 .../net/wireless/mediatek/mt76/mt76_connac_mcu.c   |   4 +
 drivers/net/wireless/mediatek/mt76/mt7915/eeprom.c |  58 +-
 drivers/net/wireless/mediatek/mt76/mt7915/eeprom.h |   5 -
 drivers/net/wireless/mediatek/mt76/mt7915/mac.c    |  23 +-
 drivers/net/wireless/mediatek/mt76/mt7915/pci.c    |  13 +-
 drivers/net/wireless/mediatek/mt76/mt7921/init.c   |   1 +
 drivers/net/wireless/mediatek/mt76/mt7921/mac.c    |  34 +-
 drivers/net/wireless/mediatek/mt76/mt7921/main.c   |   6 +
 drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h |   4 +-
 drivers/net/wireless/mediatek/mt76/usb.c           |  11 +-
 drivers/net/wireless/purelifi/plfxlc/usb.c         |   1 +
 drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h   |   2 +-
 .../net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c  |  28 +-
 drivers/net/wireless/realtek/rtw89/core.c          |   2 +-
 drivers/net/wireless/realtek/rtw89/mac.c           |   6 +-
 drivers/net/wireless/realtek/rtw89/phy.c           |   2 +-
 drivers/net/wireless/rsi/rsi_91x_core.c            |   4 +-
 drivers/net/wireless/rsi/rsi_91x_hal.c             |   6 +-
 drivers/nfc/pn533/pn533.c                          |   4 +
 drivers/nvme/host/core.c                           |  19 +-
 drivers/nvme/host/fc.c                             |   2 +-
 drivers/nvme/host/nvme.h                           |   2 +-
 drivers/nvme/host/rdma.c                           |   4 +-
 drivers/nvme/host/tcp.c                            |   1 +
 drivers/nvme/target/core.c                         |  22 +-
 drivers/nvme/target/io-cmd-file.c                  |  16 +-
 drivers/nvme/target/loop.c                         |   2 +-
 drivers/nvme/target/nvmet.h                        |   3 +-
 drivers/of/overlay.c                               |   4 +-
 drivers/pci/controller/dwc/pci-imx6.c              |  13 +-
 drivers/pci/controller/dwc/pcie-designware.c       |   2 +-
 drivers/pci/controller/vmd.c                       |  27 +-
 drivers/pci/endpoint/functions/pci-epf-test.c      |   2 +-
 drivers/pci/endpoint/functions/pci-epf-vntb.c      |   2 +-
 drivers/pci/irq.c                                  |   2 +
 drivers/pci/probe.c                                |   3 -
 drivers/perf/arm_dmc620_pmu.c                      |   8 +-
 drivers/perf/arm_dsu_pmu.c                         |   6 +-
 drivers/perf/arm_smmuv3_pmu.c                      |   8 +-
 drivers/perf/hisilicon/hisi_pcie_pmu.c             |   8 +-
 drivers/perf/marvell_cn10k_tad_pmu.c               |   6 +-
 drivers/phy/broadcom/phy-brcm-usb-init-synopsys.c  |   9 +-
 drivers/phy/broadcom/phy-brcm-usb-init.h           |   1 -
 drivers/phy/broadcom/phy-brcm-usb.c                |  14 +-
 drivers/phy/marvell/phy-mvebu-a3700-comphy.c       |   3 +
 drivers/phy/qualcomm/phy-qcom-qmp-pcie.c           | 607 ++++++++++++---------
 drivers/phy/qualcomm/phy-qcom-qmp-pcs-pcie-v5_20.h |   2 +
 drivers/phy/qualcomm/phy-qcom-qmp-pcs-v5_20.h      |  14 +
 drivers/phy/qualcomm/phy-qcom-qmp-usb.c            | 142 +----
 drivers/phy/qualcomm/phy-qcom-qmp.h                |   1 +
 drivers/pinctrl/mediatek/pinctrl-mt7986.c          |  24 +-
 drivers/pinctrl/pinconf-generic.c                  |   4 +-
 drivers/pinctrl/pinctrl-k210.c                     |   4 +-
 drivers/pinctrl/pinctrl-ocelot.c                   |  20 +-
 drivers/pinctrl/pinctrl-thunderbay.c               |   8 +-
 drivers/platform/chrome/cros_ec_typec.c            |   3 +
 drivers/platform/chrome/cros_usbpd_notify.c        |   6 +-
 drivers/platform/mellanox/mlxbf-pmc.c              |   2 +-
 drivers/platform/x86/huawei-wmi.c                  |  20 +-
 .../platform/x86/intel/int3472/clk_and_regulator.c |   3 +-
 drivers/platform/x86/intel_scu_ipc.c               |   2 +-
 drivers/platform/x86/mxm-wmi.c                     |   8 +-
 drivers/pnp/core.c                                 |   4 +-
 drivers/power/supply/ab8500_charger.c              |   9 +-
 drivers/power/supply/bq25890_charger.c             |  71 ++-
 drivers/power/supply/cw2015_battery.c              |   3 +
 drivers/power/supply/power_supply_core.c           |   7 +-
 drivers/power/supply/rk817_charger.c               |   4 +-
 drivers/power/supply/z2_battery.c                  |   6 +-
 drivers/pwm/pwm-mediatek.c                         |   2 +-
 drivers/pwm/pwm-mtk-disp.c                         |   5 +-
 drivers/pwm/pwm-sifive.c                           |   5 +-
 drivers/pwm/pwm-tegra.c                            |  15 +-
 drivers/rapidio/devices/rio_mport_cdev.c           |  15 +-
 drivers/rapidio/rio-scan.c                         |   8 +-
 drivers/rapidio/rio.c                              |   9 +-
 drivers/regulator/core.c                           |  25 +-
 drivers/regulator/devres.c                         |   2 +-
 drivers/regulator/of_regulator.c                   |   2 +-
 drivers/regulator/qcom-labibb-regulator.c          |   1 +
 drivers/regulator/qcom-rpmh-regulator.c            |   2 +-
 drivers/regulator/stm32-vrefbuf.c                  |   2 +-
 drivers/remoteproc/qcom_q6v5_pas.c                 |   4 +
 drivers/remoteproc/qcom_q6v5_wcss.c                |   6 +-
 drivers/remoteproc/qcom_sysmon.c                   |   5 +-
 drivers/remoteproc/remoteproc_core.c               |   8 +-
 drivers/rtc/class.c                                |   4 +-
 drivers/rtc/rtc-cmos.c                             | 378 ++++++-------
 drivers/rtc/rtc-mxc_v2.c                           |   4 +-
 drivers/rtc/rtc-pcf2127.c                          |  22 +-
 drivers/rtc/rtc-pcf85063.c                         |  10 +-
 drivers/rtc/rtc-pic32.c                            |   8 +-
 drivers/rtc/rtc-rzn1.c                             |   4 +-
 drivers/rtc/rtc-snvs.c                             |  16 +-
 drivers/rtc/rtc-st-lpc.c                           |   1 +
 drivers/s390/net/ctcm_main.c                       |  11 +-
 drivers/s390/net/lcs.c                             |   8 +-
 drivers/s390/net/netiucv.c                         |   9 +-
 drivers/scsi/elx/efct/efct_driver.c                |   1 +
 drivers/scsi/elx/libefc/efclib.h                   |   6 +-
 drivers/scsi/fcoe/fcoe.c                           |   1 +
 drivers/scsi/fcoe/fcoe_sysfs.c                     |  19 +-
 drivers/scsi/hpsa.c                                |   9 +-
 drivers/scsi/ipr.c                                 |  10 +-
 drivers/scsi/lpfc/lpfc_sli.c                       |   6 +-
 drivers/scsi/mpt3sas/mpt3sas_transport.c           |   2 +
 drivers/scsi/qla2xxx/qla_def.h                     |  22 +-
 drivers/scsi/qla2xxx/qla_init.c                    |  20 +-
 drivers/scsi/qla2xxx/qla_inline.h                  |   4 +-
 drivers/scsi/qla2xxx/qla_os.c                      |   4 +-
 drivers/scsi/scsi_debug.c                          |  11 +-
 drivers/scsi/scsi_error.c                          |  14 +-
 drivers/scsi/smartpqi/smartpqi.h                   |   2 +-
 drivers/scsi/smartpqi/smartpqi_init.c              |  77 ++-
 drivers/scsi/snic/snic_disc.c                      |   3 +
 drivers/soc/apple/rtkit.c                          |   7 +-
 drivers/soc/apple/sart.c                           |   7 +-
 drivers/soc/mediatek/mtk-pm-domains.c              |   2 +-
 drivers/soc/qcom/apr.c                             |  15 +-
 drivers/soc/qcom/llcc-qcom.c                       |   2 +-
 drivers/soc/sifive/sifive_ccache.c                 |  33 +-
 drivers/soc/tegra/cbb/tegra194-cbb.c               |  14 +-
 drivers/soc/tegra/cbb/tegra234-cbb.c               | 170 ++++--
 drivers/soc/ti/knav_qmss_queue.c                   |   3 +-
 drivers/soc/ti/smartreflex.c                       |   1 +
 drivers/spi/spi-fsl-spi.c                          |  19 +-
 drivers/spi/spi-gpio.c                             |  16 +-
 drivers/spi/spidev.c                               |  21 +-
 drivers/staging/media/deprecated/stkwebcam/Kconfig |   2 +-
 drivers/staging/media/imx/imx7-media-csi.c         |   6 +-
 drivers/staging/media/rkvdec/rkvdec-vp9.c          |   3 +
 drivers/staging/media/sunxi/cedrus/cedrus_h265.c   |  25 +-
 drivers/staging/media/sunxi/cedrus/cedrus_regs.h   |   2 +
 drivers/staging/r8188eu/core/rtw_pwrctrl.c         |   2 +-
 drivers/staging/rtl8192e/rtllib_rx.c               |   2 +-
 drivers/staging/rtl8192u/ieee80211/ieee80211_rx.c  |   4 +-
 drivers/staging/vme_user/vme_fake.c                |   2 +
 drivers/staging/vme_user/vme_tsi148.c              |   1 +
 drivers/target/iscsi/iscsi_target_nego.c           |  12 +-
 drivers/thermal/imx8mm_thermal.c                   |   8 +-
 drivers/thermal/k3_j72xx_bandgap.c                 |   2 +-
 drivers/thermal/qcom/lmh.c                         |   2 +-
 drivers/thermal/qcom/qcom-spmi-temp-alarm.c        |   3 +-
 drivers/thermal/thermal_core.c                     |  18 +-
 drivers/thermal/thermal_helpers.c                  |   7 +-
 drivers/thermal/thermal_of.c                       |   8 +-
 drivers/tty/serial/8250/8250_bcm7271.c             |  10 +-
 drivers/tty/serial/altera_uart.c                   |   5 +-
 drivers/tty/serial/amba-pl011.c                    |  14 +-
 drivers/tty/serial/pch_uart.c                      |   4 +
 drivers/tty/serial/serial-tegra.c                  |   6 +-
 drivers/tty/serial/stm32-usart.c                   |  47 +-
 drivers/tty/serial/sunsab.c                        |   8 +-
 drivers/ufs/core/ufshcd.c                          |  37 +-
 drivers/uio/uio_dmem_genirq.c                      |  13 +-
 drivers/usb/cdns3/cdnsp-ring.c                     |  42 +-
 drivers/usb/core/hcd.c                             |   6 +-
 drivers/usb/dwc3/core.c                            |  23 +-
 drivers/usb/dwc3/dwc3-qcom.c                       |  13 +-
 drivers/usb/gadget/function/f_hid.c                |  53 +-
 drivers/usb/gadget/udc/core.c                      |  12 +-
 drivers/usb/gadget/udc/fotg210-udc.c               |  12 +-
 drivers/usb/host/xhci-mtk.c                        |   1 -
 drivers/usb/host/xhci-ring.c                       |  14 +-
 drivers/usb/host/xhci.h                            |   2 +-
 drivers/usb/musb/musb_gadget.c                     |   2 -
 drivers/usb/musb/omap2430.c                        |  54 ++
 drivers/usb/roles/class.c                          |   5 +-
 drivers/usb/storage/alauda.c                       |   2 +
 drivers/usb/typec/bus.c                            |   2 +-
 drivers/usb/typec/tcpm/tcpci.c                     |   5 +-
 drivers/usb/typec/tipd/core.c                      |  11 +-
 drivers/usb/typec/wusb3801.c                       |   2 +-
 drivers/vfio/iova_bitmap.c                         |  32 +-
 drivers/vfio/platform/vfio_platform_common.c       |   3 +-
 drivers/video/fbdev/Kconfig                        |   2 +-
 drivers/video/fbdev/core/fbcon.c                   |   3 +-
 drivers/video/fbdev/ep93xx-fb.c                    |   4 +-
 drivers/video/fbdev/geode/Kconfig                  |   1 +
 drivers/video/fbdev/hyperv_fb.c                    |   8 +-
 drivers/video/fbdev/pm2fb.c                        |   9 +-
 drivers/video/fbdev/uvesafb.c                      |   1 +
 drivers/video/fbdev/vermilion/vermilion.c          |   4 +-
 drivers/video/fbdev/via/via-core.c                 |   9 +-
 drivers/virt/coco/sev-guest/sev-guest.c            |   1 +
 drivers/watchdog/iTCO_wdt.c                        |  21 +-
 drivers/xen/privcmd.c                              |   2 +-
 fs/afs/fs_probe.c                                  |   5 +-
 fs/binfmt_misc.c                                   |   8 +-
 fs/btrfs/extent-io-tree.c                          |  22 +-
 fs/btrfs/file.c                                    |  10 +-
 fs/char_dev.c                                      |   2 +-
 fs/cifs/smb2file.c                                 |   4 +-
 fs/configfs/dir.c                                  |   2 +
 fs/debugfs/file.c                                  |  28 +-
 fs/erofs/fscache.c                                 |  47 +-
 fs/erofs/internal.h                                |  10 +-
 fs/erofs/super.c                                   |   2 +-
 fs/erofs/zdata.c                                   |   3 +-
 fs/erofs/zmap.c                                    |  11 +-
 fs/f2fs/compress.c                                 |   2 +-
 fs/f2fs/f2fs.h                                     |   2 +-
 fs/f2fs/file.c                                     |   4 +
 fs/f2fs/gc.c                                       |  29 +-
 fs/f2fs/namei.c                                    | 329 ++++++-----
 fs/f2fs/segment.c                                  |   8 +-
 fs/f2fs/super.c                                    |   8 +-
 fs/gfs2/glock.c                                    |   2 +
 fs/hfs/inode.c                                     |   2 +
 fs/hfs/trans.c                                     |   2 +-
 fs/hugetlbfs/inode.c                               |   6 +-
 fs/jfs/jfs_dmap.c                                  |  27 +-
 fs/jfs/namei.c                                     |   2 +-
 fs/ksmbd/mgmt/user_session.c                       |   8 +-
 fs/libfs.c                                         |  22 +-
 fs/lockd/svcsubs.c                                 |  17 +-
 fs/nfs/fs_context.c                                |   6 +
 fs/nfs/internal.h                                  |   6 +-
 fs/nfs/namespace.c                                 |   2 +-
 fs/nfs/nfs42xdr.c                                  |   2 +-
 fs/nfs/nfs4proc.c                                  |  38 +-
 fs/nfs/nfs4state.c                                 |   2 +
 fs/nfs/nfs4xdr.c                                   |  22 +-
 fs/nfsd/nfs2acl.c                                  |  10 -
 fs/nfsd/nfs3acl.c                                  |  30 +-
 fs/nfsd/nfs4callback.c                             |   4 +-
 fs/nfsd/nfs4proc.c                                 |   7 +-
 fs/nfsd/nfs4state.c                                |  51 +-
 fs/nilfs2/the_nilfs.c                              |  73 ++-
 fs/ntfs3/bitmap.c                                  |   2 +-
 fs/ntfs3/super.c                                   |   2 +-
 fs/ntfs3/xattr.c                                   |   2 +-
 fs/ocfs2/journal.c                                 |   2 +-
 fs/ocfs2/journal.h                                 |   1 +
 fs/ocfs2/stackglue.c                               |   8 +-
 fs/ocfs2/super.c                                   |   5 +-
 fs/orangefs/orangefs-debugfs.c                     |  29 +-
 fs/orangefs/orangefs-mod.c                         |   8 +-
 fs/orangefs/orangefs-sysfs.c                       |  71 ++-
 fs/overlayfs/file.c                                |  28 +-
 fs/overlayfs/super.c                               |   7 +-
 fs/pstore/Kconfig                                  |   1 +
 fs/pstore/pmsg.c                                   |   7 +-
 fs/pstore/ram.c                                    |   2 +
 fs/pstore/ram_core.c                               |   6 +-
 fs/reiserfs/namei.c                                |   4 +
 fs/reiserfs/xattr_security.c                       |   2 +-
 fs/sysv/itree.c                                    |   2 +-
 fs/udf/namei.c                                     |   8 +-
 fs/xattr.c                                         |   2 +-
 include/drm/drm_connector.h                        |   6 +
 include/drm/ttm/ttm_tt.h                           |   2 +-
 include/dt-bindings/clock/imx8mn-clock.h           |  24 +-
 include/dt-bindings/clock/imx8mp-clock.h           |   3 +-
 include/linux/btf_ids.h                            |   2 +-
 include/linux/debugfs.h                            |  19 +-
 include/linux/eventfd.h                            |   2 +-
 include/linux/fortify-string.h                     |   2 +-
 include/linux/fs.h                                 |  12 +-
 include/linux/hisi_acc_qm.h                        |   6 +-
 include/linux/hyperv.h                             |   2 +
 include/linux/ieee80211.h                          |   2 +-
 include/linux/iio/imu/adis.h                       |  13 +-
 include/linux/netdevice.h                          |  58 +-
 include/linux/proc_fs.h                            |   2 +
 include/linux/regulator/driver.h                   |   3 +-
 include/linux/skmsg.h                              |   1 +
 include/linux/timerqueue.h                         |   2 +-
 include/media/dvbdev.h                             |  32 +-
 include/net/bluetooth/hci.h                        |  20 +
 include/net/bluetooth/hci_core.h                   |   7 +-
 include/net/dst.h                                  |   5 +-
 include/net/ip_vs.h                                |  10 +-
 include/net/mrp.h                                  |   1 +
 include/net/sock_reuseport.h                       |   2 +
 include/net/tcp.h                                  |   4 +-
 include/sound/hda_codec.h                          |   1 +
 include/sound/pcm.h                                |  36 +-
 include/trace/events/f2fs.h                        |  34 +-
 include/trace/events/ib_mad.h                      |  13 +-
 include/uapi/linux/idxd.h                          |   2 +-
 include/uapi/linux/io_uring.h                      |  18 +
 include/uapi/linux/swab.h                          |   2 +-
 include/uapi/rdma/hns-abi.h                        |  15 +
 include/uapi/sound/asequencer.h                    |   8 +-
 io_uring/io_uring.c                                |   2 +-
 io_uring/msg_ring.c                                |   6 +-
 io_uring/net.c                                     |   9 +-
 io_uring/notif.c                                   |  12 +
 io_uring/notif.h                                   |   3 +
 io_uring/opdef.c                                   |   7 +
 io_uring/opdef.h                                   |   2 +
 io_uring/timeout.c                                 |   4 +-
 ipc/mqueue.c                                       |   6 +-
 kernel/Makefile                                    |   3 -
 kernel/acct.c                                      |   2 +
 kernel/bpf/btf.c                                   |   5 +
 kernel/bpf/cgroup_iter.c                           |  14 +
 kernel/bpf/syscall.c                               |   6 +-
 kernel/bpf/verifier.c                              | 120 ++--
 kernel/cpu.c                                       |  60 +-
 kernel/events/core.c                               |   8 +-
 kernel/fork.c                                      |  17 +-
 kernel/futex/core.c                                |  26 +-
 kernel/gcov/gcc_4_7.c                              |   5 +
 kernel/irq/internals.h                             |   2 +
 kernel/irq/irqdesc.c                               |  15 +-
 kernel/kprobes.c                                   |  16 +-
 kernel/module/decompress.c                         |   8 +-
 kernel/padata.c                                    |  15 +-
 kernel/power/snapshot.c                            |   4 +-
 kernel/rcu/tree.c                                  |   2 +-
 kernel/relay.c                                     |   4 +-
 kernel/sched/core.c                                |  10 +-
 kernel/sched/fair.c                                | 223 +++++++-
 kernel/sched/psi.c                                 |   8 +-
 kernel/sched/sched.h                               |  51 +-
 kernel/trace/blktrace.c                            |   3 +-
 kernel/trace/trace_events_hist.c                   |   2 +-
 kernel/trace/trace_events_user.c                   |   1 +
 lib/debugobjects.c                                 |  10 +
 lib/fonts/fonts.c                                  |   4 +-
 lib/maple_tree.c                                   |   4 +-
 lib/notifier-error-inject.c                        |   2 +-
 lib/test_firmware.c                                |   1 +
 lib/test_maple_tree.c                              |  23 +
 mm/gup.c                                           |   3 +
 net/802/mrp.c                                      |  18 +-
 net/9p/client.c                                    |   5 +
 net/bluetooth/hci_conn.c                           |   2 +-
 net/bluetooth/hci_core.c                           |   4 +-
 net/bluetooth/hci_sync.c                           |   2 +-
 net/bluetooth/lib.c                                |   4 +-
 net/bluetooth/mgmt.c                               |   2 +-
 net/bluetooth/rfcomm/core.c                        |   2 +-
 net/bpf/test_run.c                                 |   3 -
 net/core/dev.c                                     |  14 +-
 net/core/devlink.c                                 |   5 +
 net/core/filter.c                                  |  25 +-
 net/core/skbuff.c                                  |   3 +
 net/core/skmsg.c                                   |   9 +-
 net/core/sock.c                                    |   2 +-
 net/core/sock_map.c                                |   2 +
 net/core/sock_reuseport.c                          |  94 +++-
 net/core/stream.c                                  |   6 +
 net/dsa/tag_8021q.c                                |  11 +-
 net/ethtool/ioctl.c                                |   3 +-
 net/hsr/hsr_debugfs.c                              |  40 +-
 net/hsr/hsr_device.c                               |  32 +-
 net/hsr/hsr_forward.c                              |  14 +-
 net/hsr/hsr_framereg.c                             | 222 ++++----
 net/hsr/hsr_framereg.h                             |  17 +-
 net/hsr/hsr_main.h                                 |   9 +-
 net/hsr/hsr_netlink.c                              |   4 +-
 net/ipv4/af_inet.c                                 |   4 +-
 net/ipv4/inet_connection_sock.c                    |   7 +-
 net/ipv4/ping.c                                    |   2 +-
 net/ipv4/tcp_bpf.c                                 |  19 +-
 net/ipv4/udp.c                                     |  39 +-
 net/ipv4/udp_tunnel_core.c                         |   1 +
 net/ipv6/af_inet6.c                                |   4 +-
 net/ipv6/datagram.c                                |  15 +-
 net/ipv6/sit.c                                     |  22 +-
 net/ipv6/udp.c                                     |  12 +-
 net/mac80211/cfg.c                                 |   2 +-
 net/mac80211/ieee80211_i.h                         |   1 +
 net/mac80211/iface.c                               |   1 +
 net/mac80211/mlme.c                                |  15 +-
 net/mac80211/tx.c                                  |   2 +-
 net/mctp/device.c                                  |  14 +-
 net/netfilter/ipvs/ip_vs_core.c                    |  30 +-
 net/netfilter/ipvs/ip_vs_ctl.c                     |  10 +-
 net/netfilter/ipvs/ip_vs_est.c                     |  20 +-
 net/netfilter/nf_conntrack_proto_icmpv6.c          |  53 ++
 net/netfilter/nf_flow_table_offload.c              |   6 +-
 net/openvswitch/datapath.c                         |  25 +-
 net/openvswitch/flow_netlink.c                     |   2 +-
 net/rxrpc/output.c                                 |   2 +-
 net/rxrpc/sendmsg.c                                |   2 +-
 net/sched/ematch.c                                 |   2 +
 net/sctp/sysctl.c                                  |  73 ++-
 net/sunrpc/clnt.c                                  |   2 +-
 net/sunrpc/xprtrdma/verbs.c                        |   2 +-
 net/tls/tls_sw.c                                   |   6 +-
 net/unix/af_unix.c                                 |  12 +-
 net/vmw_vsock/vmci_transport.c                     |   6 +-
 net/wireless/nl80211.c                             |   3 +
 net/wireless/reg.c                                 |   4 +-
 samples/bpf/xdp1_user.c                            |   2 +-
 samples/bpf/xdp2_kern.c                            |   4 +
 samples/vfio-mdev/mdpy-fb.c                        |   8 +-
 security/Kconfig.hardening                         |   3 +
 security/apparmor/apparmorfs.c                     |   4 +-
 security/apparmor/label.c                          |  12 +-
 security/apparmor/lsm.c                            |   4 +-
 security/apparmor/policy.c                         |   2 +-
 security/apparmor/policy_ns.c                      |   2 +-
 security/apparmor/policy_unpack.c                  |   2 +-
 security/integrity/digsig.c                        |   6 +-
 security/integrity/ima/ima_policy.c                |  51 +-
 security/integrity/ima/ima_template.c              |   4 +-
 security/loadpin/loadpin.c                         |  30 +-
 sound/core/memalloc.c                              |  44 +-
 sound/core/pcm_native.c                            |   4 +-
 sound/drivers/mts64.c                              |   3 +
 sound/pci/asihpi/hpioctl.c                         |   2 +-
 sound/pci/hda/hda_codec.c                          |   3 +-
 sound/pci/hda/patch_hdmi.c                         | 120 +++-
 sound/pci/hda/patch_realtek.c                      |  27 +
 sound/soc/amd/acp/acp-platform.c                   |   8 +-
 sound/soc/amd/yc/acp6x-mach.c                      |   7 +
 sound/soc/codecs/pcm512x.c                         |   8 +-
 sound/soc/codecs/rt298.c                           |   7 +
 sound/soc/codecs/rt5670.c                          |   2 -
 sound/soc/codecs/wm8994.c                          |   5 +
 sound/soc/codecs/wsa883x.c                         |   6 +-
 sound/soc/generic/audio-graph-card.c               |   4 +-
 sound/soc/intel/Kconfig                            |   2 +-
 sound/soc/intel/avs/boards/rt298.c                 |  24 +-
 sound/soc/intel/avs/core.c                         |   2 +-
 sound/soc/intel/avs/ipc.c                          |   6 +-
 sound/soc/intel/boards/sof_es8336.c                |   2 +-
 sound/soc/intel/skylake/skl.c                      |   5 +-
 sound/soc/mediatek/common/mtk-btcvsd.c             |   6 +-
 sound/soc/mediatek/mt8173/mt8173-afe-pcm.c         |  20 +-
 sound/soc/mediatek/mt8173/mt8173-rt5650-rt5514.c   |   7 +-
 .../mt8183/mt8183-mt6358-ts3a227-max98357.c        |  14 +-
 .../mt8186/mt8186-mt6366-da7219-max98357.c         |   2 +-
 .../mediatek/mt8186/mt8186-mt6366-rt1019-rt5682s.c |   2 +-
 sound/soc/pxa/mmp-pcm.c                            |   2 +-
 sound/soc/qcom/Kconfig                             |  16 +-
 sound/soc/qcom/common.c                            |   2 -
 sound/soc/qcom/common.h                            |  23 -
 sound/soc/qcom/lpass-sc7180.c                      |   3 +
 sound/soc/rockchip/rockchip_pdm.c                  |   1 +
 sound/soc/rockchip/rockchip_spdif.c                |   1 +
 sound/usb/endpoint.c                               |   7 +
 sound/usb/pcm.c                                    |  13 +-
 sound/usb/quirks-table.h                           |   2 +
 sound/usb/quirks.c                                 |   2 +
 sound/usb/usbaudio.h                               |   4 +
 tools/bpf/bpftool/common.c                         |   1 +
 tools/lib/bpf/bpf.h                                |   7 +
 tools/lib/bpf/btf.c                                |   8 +-
 tools/lib/bpf/btf_dump.c                           |  29 +-
 tools/lib/bpf/libbpf.c                             |  22 +-
 tools/lib/bpf/usdt.c                               |  11 +-
 tools/objtool/check.c                              |  10 +
 tools/perf/Documentation/perf-annotate.txt         |   2 +-
 tools/perf/Documentation/perf-diff.txt             |   2 +-
 tools/perf/Documentation/perf-lock.txt             |   2 +-
 tools/perf/Documentation/perf-probe.txt            |   2 +-
 tools/perf/Documentation/perf-record.txt           |   2 +-
 tools/perf/Documentation/perf-report.txt           |   2 +-
 tools/perf/Documentation/perf-stat.txt             |   4 +-
 tools/perf/bench/numa.c                            |   9 +-
 tools/perf/builtin-annotate.c                      |   2 +-
 tools/perf/builtin-diff.c                          |   2 +-
 tools/perf/builtin-lock.c                          |   2 +-
 tools/perf/builtin-probe.c                         |  22 +-
 tools/perf/builtin-record.c                        |   2 +-
 tools/perf/builtin-report.c                        |   2 +-
 tools/perf/builtin-stat.c                          |  41 +-
 tools/perf/builtin-trace.c                         |  32 +-
 tools/perf/tests/shell/stat_all_pmu.sh             |  13 +-
 tools/perf/ui/util.c                               |   5 +
 tools/perf/util/bpf_off_cpu.c                      |   2 +-
 tools/perf/util/branch.h                           |   3 +-
 tools/perf/util/debug.c                            |   4 +
 tools/perf/util/stat-display.c                     |  33 +-
 tools/perf/util/stat.h                             |   1 -
 tools/perf/util/symbol-elf.c                       |   2 +-
 tools/testing/selftests/bpf/config                 |   1 +
 tools/testing/selftests/bpf/network_helpers.c      |   4 +
 tools/testing/selftests/bpf/prog_tests/bpf_iter.c  |  11 +-
 tools/testing/selftests/bpf/prog_tests/empty_skb.c | 146 +++++
 .../selftests/bpf/prog_tests/kprobe_multi_test.c   |  26 +-
 .../testing/selftests/bpf/prog_tests/lsm_cgroup.c  |  17 +-
 tools/testing/selftests/bpf/prog_tests/map_kptr.c  |   3 +-
 .../selftests/bpf/prog_tests/tcp_hdr_options.c     |   4 +-
 .../selftests/bpf/prog_tests/tracing_struct.c      |   3 +-
 .../selftests/bpf/prog_tests/xdp_adjust_tail.c     |   7 +-
 .../selftests/bpf/prog_tests/xdp_do_redirect.c     |   2 +-
 .../selftests/bpf/prog_tests/xdp_synproxy.c        |   2 +-
 tools/testing/selftests/bpf/progs/bpf_iter_ksym.c  |   6 +-
 tools/testing/selftests/bpf/progs/empty_skb.c      |  37 ++
 tools/testing/selftests/bpf/progs/lsm_cgroup.c     |   8 +
 .../testing/selftests/bpf/test_bpftool_metadata.sh |   7 +-
 tools/testing/selftests/bpf/test_flow_dissector.sh |   6 +-
 tools/testing/selftests/bpf/test_lwt_ip_encap.sh   |  17 +-
 tools/testing/selftests/bpf/test_lwt_seg6local.sh  |   9 +-
 tools/testing/selftests/bpf/test_tc_edt.sh         |   3 +-
 tools/testing/selftests/bpf/test_tc_tunnel.sh      |   5 +-
 tools/testing/selftests/bpf/test_tunnel.sh         |   5 +-
 tools/testing/selftests/bpf/test_xdp_meta.sh       |   9 +-
 tools/testing/selftests/bpf/test_xdp_vlan.sh       |   8 +-
 tools/testing/selftests/bpf/xdp_synproxy.c         |   5 +-
 tools/testing/selftests/cgroup/cgroup_util.c       |   5 +-
 .../selftests/drivers/net/netdevsim/devlink.sh     |   4 +-
 tools/testing/selftests/efivarfs/efivarfs.sh       |   5 +
 .../ftrace/test.d/ftrace/func_event_triggers.tc    |  15 +-
 .../selftests/netfilter/conntrack_icmp_related.sh  |  36 +-
 .../selftests/powerpc/dscr/dscr_sysfs_test.c       |   5 +-
 tools/testing/selftests/proc/proc-uptime-002.c     |   3 +-
 1089 files changed, 12893 insertions(+), 6325 deletions(-)



^ permalink raw reply	[relevance 1%]

* Re: [PATCH 6.0 0000/1066] 6.0.16-rc2 review
@ 2022-12-30 19:23  0% Joel Fernandes
  0 siblings, 0 replies; 77+ results
From: Joel Fernandes @ 2022-12-30 19:23 UTC (permalink / raw)
  To: Greg Kroah-Hartman
  Cc: stable, patches, linux-kernel, torvalds, akpm, linux, shuah,
	patches, lkft-triage, pavel, jonathanh, f.fainelli,
	sudipm.mukherjee, srw, rwarsow, Paul E. McKenney


> On Dec 30, 2022, at 4:50 AM, Greg Kroah-Hartman <gregkh@linuxfoundation.org> wrote:
> 
> This is the start of the stable review cycle for the 6.0.16 release.
> There are 1066 patches in this series, all will be posted as a response
> to this one.  If anyone has any issues with these being applied, please
> let me know.
> 
> Responses should be made by Sun, 01 Jan 2023 09:38:41 +0000.
> Anything received after that time might be too late.
> 
> The whole patch series can be found in one patch at:
>    https://www.kernel.org/pub/linux/kernel/v6.x/stable-review/patch-6.0.16-rc2.gz
> or in the git tree and branch at:
>    git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable-rc.git linux-6.0.y
> and the diffstat can be found below.

All rcutorture scenarios pass, 30 minutes test time each.

Tested-by: Joel Fernandes (Google) <joel@joelfernandes.org>

Thanks,

 - Joel

> 
> thanks,
> 
> greg k-h
> 
> -------------
> Pseudo-Shortlog of commits:
> 
> Greg Kroah-Hartman <gregkh@linuxfoundation.org>
>    Linux 6.0.16-rc2
> 
> Steven Price <steven.price@arm.com>
>    pwm: tegra: Fix 32 bit build
> 
> Christophe JAILLET <christophe.jaillet@wanadoo.fr>
>    mfd: qcom_rpm: Use devm_of_platform_populate() to simplify code
> 
> ChenXiaoSong <chenxiaosong2@huawei.com>
>    cifs: fix use-after-free on the link name
> 
> Paulo Alcantara <pc@cjr.nz>
>    cifs: fix memory leaks in session setup
> 
> Zhang Xiaoxu <zhangxiaoxu5@huawei.com>
>    cifs: Fix xid leak in cifs_get_file_info_unix()
> 
> Paulo Alcantara <pc@cjr.nz>
>    cifs: fix double-fault crash during ntlmssp
> 
> Yassine Oudjana <y.oudjana@protonmail.com>
>    extcon: usbc-tusb320: Call the Type-C IRQ handler only if a port is registered
> 
> Geert Uytterhoeven <geert+renesas@glider.be>
>    clk: renesas: r8a779f0: Fix SD0H clock name
> 
> Martin Leung <Martin.Leung@amd.com>
>    drm/amd/display: revert Disable DRR actions during state commit
> 
> Lin Ma <linma@zju.edu.cn>
>    media: dvbdev: fix refcnt bug
> 
> Lin Ma <linma@zju.edu.cn>
>    media: dvbdev: fix build warning due to comments
> 
> Gaosheng Cui <cuigaosheng1@huawei.com>
>    net: stmmac: fix errno when create_singlethread_workqueue() fails
> 
> Pavel Begunkov <asml.silence@gmail.com>
>    io_uring: remove iopoll spinlock
> 
> Pavel Begunkov <asml.silence@gmail.com>
>    io_uring: protect cq_timeouts with timeout_lock
> 
> Pavel Begunkov <asml.silence@gmail.com>
>    io_uring/net: fix cleanup after recycle
> 
> Pavel Begunkov <asml.silence@gmail.com>
>    io_uring: improve io_double_lock_ctx fail handling
> 
> Pavel Begunkov <asml.silence@gmail.com>
>    io_uring: add completion locking for iopoll
> 
> Arun Easi <aeasi@marvell.com>
>    scsi: qla2xxx: Fix crash when I/O abort times out
> 
> David Hildenbrand <david@redhat.com>
>    mm/gup: disallow FOLL_FORCE|FOLL_WRITE on hugetlb mappings
> 
> Filipe Manana <fdmanana@suse.com>
>    btrfs: do not BUG_ON() on ENOMEM when dropping extent items for a range
> 
> Chen Zhongjin <chenzhongjin@huawei.com>
>    ovl: fix use inode directly in rcu-walk mode
> 
> Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
>    fbdev: fbcon: release buffer when fbcon_do_set_font() failed
> 
> Rickard x Andersson <rickaran@axis.com>
>    gcov: add support for checksum field
> 
> Yuan Can <yuancan@huawei.com>
>    floppy: Fix memory leak in do_floppy_init()
> 
> Johan Hovold <johan+linaro@kernel.org>
>    regulator: core: fix deadlock on regulator enable
> 
> Rasmus Villemoes <linux@rasmusvillemoes.dk>
>    iio: addac: ad74413r: fix integer promotion bug in ad74413_get_input_current_offset()
> 
> Rasmus Villemoes <linux@rasmusvillemoes.dk>
>    iio: adc128s052: add proper .data members in adc128_of_match table
> 
> Nuno Sá <nuno.sa@analog.com>
>    iio: adc: ad_sigma_delta: do not use internal iio_dev lock
> 
> Zeng Heng <zengheng4@huawei.com>
>    iio: fix memory leak in iio_device_register_eventset()
> 
> Roberto Sassu <roberto.sassu@huawei.com>
>    reiserfs: Add missing calls to reiserfs_security_free()
> 
> Nathan Chancellor <nathan@kernel.org>
>    security: Restrict CONFIG_ZERO_CALL_USED_REGS to gcc or clang > 15.0.6
> 
> Schspa Shi <schspa@gmail.com>
>    9p: set req refcount to zero to avoid uninitialized usage
> 
> Isaac J. Manjarres <isaacmanjarres@google.com>
>    loop: Fix the max_loop commandline argument treatment when it is set to 0
> 
> Enrik Berkhan <Enrik.Berkhan@inka.de>
>    HID: mcp2221: don't connect hidraw
> 
> Jason Gerecke <killertofu@gmail.com>
>    HID: wacom: Ensure bootloader PID is usable in hidraw mode
> 
> Mathias Nyman <mathias.nyman@linux.intel.com>
>    xhci: Prevent infinite loop in transaction errors recovery for streams
> 
> Ferry Toth <ftoth@exalondelft.nl>
>    usb: dwc3: core: defer probe on ulpi_read_id timeout
> 
> Sven Peter <sven@svenpeter.dev>
>    usb: dwc3: Fix race between dwc3_set_mode and __dwc3_set_mode
> 
> Li Jun <jun.li@nxp.com>
>    clk: imx: imx8mp: add shared clk gate for usb suspend clk
> 
> Li Jun <jun.li@nxp.com>
>    dt-bindings: clocks: imx8mp: Add ID for usb suspend clock
> 
> Johan Hovold <johan+linaro@kernel.org>
>    arm64: dts: qcom: sm8250: fix USB-DP PHY registers
> 
> Johan Hovold <johan+linaro@kernel.org>
>    arm64: dts: qcom: sm6350: fix USB-DP PHY registers
> 
> Chunfeng Yun <chunfeng.yun@mediatek.com>
>    usb: xhci-mtk: fix leakage of shared hcd when fail to set wakeup irq
> 
> Pawel Laszczak <pawell@cadence.com>
>    usb: cdnsp: fix lack of ZLP for ep0
> 
> Bastien Nocera <hadess@hadess.net>
>    HID: logitech-hidpp: Guard FF init code against non-USB devices
> 
> Jiao Zhou <jiaozhou@google.com>
>    ALSA: hda/hdmi: Add HP Device 0x8711 to force connect list
> 
> Edward Pacman <edward@edward-p.xyz>
>    ALSA: hda/realtek: Add quirk for Lenovo TianYi510Pro-14IOB
> 
> wangdicheng <wangdicheng@kylinos.cn>
>    ALSA: usb-audio: add the quirk for KT0206 device
> 
> Jeff LaBundy <jeff@labundy.com>
>    Input: iqs7222 - add support for IQS7222A v1.13+
> 
> Jeff LaBundy <jeff@labundy.com>
>    Input: iqs7222 - trim force communication command
> 
> Jeff LaBundy <jeff@labundy.com>
>    dt-bindings: input: iqs7222: Add support for IQS7222A v1.13+
> 
> Jeff LaBundy <jeff@labundy.com>
>    dt-bindings: input: iqs7222: Correct minimum slider size
> 
> Jeff LaBundy <jeff@labundy.com>
>    dt-bindings: input: iqs7222: Reduce 'linux,code' to optional
> 
> Jeff LaBundy <jeff@labundy.com>
>    Input: iqs7222 - avoid sending empty SYN_REPORT events
> 
> GUO Zihua <guozihua@huawei.com>
>    ima: Simplify ima_lsm_copy_rule
> 
> John Stultz <jstultz@google.com>
>    pstore: Make sure CONFIG_PSTORE_PMSG selects CONFIG_RT_MUTEXES
> 
> David Howells <dhowells@redhat.com>
>    afs: Fix lost servers_outstanding count
> 
> Michael Petlan <mpetlan@redhat.com>
>    perf test: Fix "all PMU test" to skip parametrized events
> 
> Sergio Paracuellos <sergio.paracuellos@gmail.com>
>    MIPS: ralink: mt7621: avoid to init common ralink reset controller
> 
> Yang Jihong <yangjihong1@huawei.com>
>    perf debug: Set debug_peo_args and redirect_to_stderr variable to correct values in perf_quiet_option()
> 
> Arnd Bergmann <arnd@arndb.de>
>    drm/amd/pm: avoid large variable on kernel stack
> 
> John Stultz <jstultz@google.com>
>    pstore: Switch pmsg_lock to an rt_mutex to avoid priority inversion
> 
> Kristina Martsenko <kristina.martsenko@arm.com>
>    lkdtm: cfi: Make PAC test work with GCC 7 and 8
> 
> Kees Cook <keescook@chromium.org>
>    LoadPin: Ignore the "contents" argument of the LSM hooks
> 
> Khaled Almahallawy <khaled.almahallawy@intel.com>
>    drm/i915/display: Don't disable DDI/Transcoder when setting phy test pattern
> 
> Hans de Goede <hdegoede@redhat.com>
>    ASoC: rt5670: Remove unbalanced pm_runtime_put()
> 
> Wang Jingjin <wangjingjin1@huawei.com>
>    ASoC: rockchip: spdif: Add missing clk_disable_unprepare() in rk_spdif_runtime_resume()
> 
> Marek Szyprowski <m.szyprowski@samsung.com>
>    ASoC: wm8994: Fix potential deadlock
> 
> Kai Vehmanen <kai.vehmanen@linux.intel.com>
>    ALSA: hda/hdmi: fix stream-id config keep-alive for rt suspend
> 
> Jaroslav Kysela <perex@perex.cz>
>    ALSA: hda/hdmi: Use only dynamic PCM device allocation
> 
> Kai Vehmanen <kai.vehmanen@linux.intel.com>
>    ALSA: hda/hdmi: set default audio parameters for KAE silent-stream
> 
> Kai Vehmanen <kai.vehmanen@linux.intel.com>
>    ALSA: hda/hdmi: fix i915 silent stream programming flow
> 
> Wang Yufen <wangyufen@huawei.com>
>    ASoC: mediatek: mt8183: fix refcount leak in mt8183_mt6358_ts3a227_max98357_dev_probe()
> 
> Wang Jingjin <wangjingjin1@huawei.com>
>    ASoC: rockchip: pdm: Add missing clk_disable_unprepare() in rockchip_pdm_runtime_resume()
> 
> Wang Yufen <wangyufen@huawei.com>
>    ASoC: audio-graph-card: fix refcount leak of cpu_ep in __graph_for_each_link()
> 
> Wang Yufen <wangyufen@huawei.com>
>    ASoC: mediatek: mt8173-rt5650-rt5514: fix refcount leak in mt8173_rt5650_rt5514_dev_probe()
> 
> Cezary Rojewski <cezary.rojewski@intel.com>
>    ASoC: Intel: Skylake: Fix driver hang during shutdown
> 
> Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
>    ALSA: hda: add snd_hdac_stop_streams() helper
> 
> Yang Yingliang <yangyingliang@huawei.com>
>    ASoC: sof_es8336: fix possible use-after-free in sof_es8336_remove()
> 
> Yang Yingliang <yangyingliang@huawei.com>
>    hwmon: (jc42) Fix missing unlock on error in jc42_write()
> 
> Wolfram Sang <wsa+renesas@sang-engineering.com>
>    clk: renesas: r8a779f0: Add TMU and parent SASYNC clocks
> 
> Wolfram Sang <wsa+renesas@sang-engineering.com>
>    clk: renesas: r8a779f0: Add SDH0 clock
> 
> Zhang Xiaoxu <zhangxiaoxu5@huawei.com>
>    orangefs: Fix kmemleak in orangefs_{kernel,client}_debug_init()
> 
> Zhang Xiaoxu <zhangxiaoxu5@huawei.com>
>    orangefs: Fix kmemleak in orangefs_sysfs_init()
> 
> Zhang Xiaoxu <zhangxiaoxu5@huawei.com>
>    orangefs: Fix kmemleak in orangefs_prepare_debugfs_help_string()
> 
> Maurizio Lombardi <mlombard@redhat.com>
>    scsi: target: iscsi: Fix a race condition between login_work and the login thread
> 
> Nathan Chancellor <nathan@kernel.org>
>    drm/sti: Fix return type of sti_{dvo,hda,hdmi}_connector_mode_valid()
> 
> Nathan Chancellor <nathan@kernel.org>
>    drm/fsl-dcu: Fix return type of fsl_dcu_drm_connector_mode_valid()
> 
> Kumar Meiyappan <Kumar.Meiyappan@microchip.com>
>    scsi: smartpqi: Correct device removal for multi-actuator devices
> 
> Mike McGowen <mike.mcgowen@microchip.com>
>    scsi: smartpqi: Add new controller PCI IDs
> 
> Hawkins Jiawei <yin31149@gmail.com>
>    hugetlbfs: fix null-ptr-deref in hugetlbfs_parse_param()
> 
> Nathan Chancellor <nathan@kernel.org>
>    scsi: elx: libefc: Fix second parameter type in state callbacks
> 
> Bjorn Helgaas <bhelgaas@google.com>
>    Revert "PCI: Clear PCI_STATUS when setting up device"
> 
> Kai Ye <yekai13@huawei.com>
>    crypto: hisilicon/qm - increase the memory of local variables
> 
> Bart Van Assche <bvanassche@acm.org>
>    scsi: ufs: Reduce the START STOP UNIT timeout
> 
> Justin Tee <justin.tee@broadcom.com>
>    scsi: lpfc: Fix hard lockup when reading the rx_monitor from debugfs
> 
> Zhiqi Song <songzhiqi1@huawei.com>
>    crypto: hisilicon/hpre - fix resource leak in remove process
> 
> ChiYuan Huang <cy_huang@richtek.com>
>    regulator: core: Fix resolve supply lookup issue
> 
> Sven Peter <sven@svenpeter.dev>
>    Bluetooth: Add quirk to disable MWS Transport Configuration
> 
> Sven Peter <sven@svenpeter.dev>
>    Bluetooth: Add quirk to disable extended scanning
> 
> Marek Vasut <marex@denx.de>
>    Bluetooth: hci_bcm: Add CYW4373A0 support
> 
> ChiYuan Huang <cy_huang@richtek.com>
>    regulator: core: Use different devices for resource allocation and DT lookup
> 
> Xiu Jianfeng <xiujianfeng@huawei.com>
>    clk: st: Fix memory leak in st_of_quadfs_setup()
> 
> Shigeru Yoshida <syoshida@redhat.com>
>    media: si470x: Fix use-after-free in si470x_int_in_callback()
> 
> Wolfram Sang <wsa+renesas@sang-engineering.com>
>    mmc: renesas_sdhi: better reset from HS400 mode
> 
> Wolfram Sang <wsa+renesas@sang-engineering.com>
>    mmc: renesas_sdhi: add quirk for broken register layout
> 
> Kunihiko Hayashi <hayashi.kunihiko@socionext.com>
>    mmc: f-sdh30: Add quirks for broken timeout clock capability
> 
> Hawkins Jiawei <yin31149@gmail.com>
>    nfs: fix possible null-ptr-deref when parsing param
> 
> James Hilliard <james.hilliard1@gmail.com>
>    selftests/bpf: Fix conflicts with built-in functions in bpf_iter_ksym
> 
> Denis Pauk <pauk.denis@gmail.com>
>    hwmon: (nct6775) add ASUS CROSSHAIR VIII/TUF/ProArt B550M
> 
> Lorenzo Bianconi <lorenzo@kernel.org>
>    wifi: mt76: do not run mt76u_status_worker if the device is not running
> 
> Rui Zhang <zr.zhang@vivo.com>
>    regulator: core: fix use_count leakage when handling boot-on
> 
> Andrii Nakryiko <andrii@kernel.org>
>    libbpf: Avoid enum forward-declarations in public API in C++ mode
> 
> Artem Lukyanov <dukzcry@ya.ru>
>    ASoC: amd: yc: Add Xiaomi Redmi Book Pro 14 2022 into DMI table
> 
> Alvin Lee <Alvin.Lee2@amd.com>
>    drm/amd/display: Fix DTBCLK disable requests and SRC_SEL programming
> 
> Wesley Chalmers <Wesley.Chalmers@amd.com>
>    drm/amd/display: Use the largest vready_offset in pipe group
> 
> Ye Bin <yebin10@huawei.com>
>    blk-mq: fix possible memleak when register 'hctx' failed
> 
> Yunfei Dong <yunfei.dong@mediatek.com>
>    media: mediatek: vcodec: Can't set dst buffer to done when lat decode error
> 
> Mazin Al Haddad <mazinalhaddad05@gmail.com>
>    media: dvb-usb: fix memory leak in dvb_usb_adapter_init()
> 
> Lin Ma <linma@zju.edu.cn>
>    media: dvbdev: adopts refcnt to avoid UAF
> 
> Yan Lei <yan_lei@dahuatech.com>
>    media: dvb-frontends: fix leak of memory fw
> 
> Maxim Korotkov <korotkov.maxim.s@gmail.com>
>    ethtool: avoiding integer overflow in ethtool_phys_id()
> 
> Stanislav Fomichev <sdf@google.com>
>    bpf: Prevent decl_tag from being referenced in func_proto arg
> 
> Yonghong Song <yhs@fb.com>
>    bpf: Fix a BTF_ID_LIST bug with CONFIG_DEBUG_INFO_BTF not set
> 
> Stanislav Fomichev <sdf@google.com>
>    ppp: associate skb with a device at tx
> 
> Felix Fietkau <nbd@nbd.name>
>    net: ethernet: mtk_eth_soc: drop packets to WDMA if the ring is full
> 
> Schspa Shi <schspa@gmail.com>
>    mrp: introduce active flags to prevent UAF when applicant uninit
> 
> Eric Dumazet <edumazet@google.com>
>    ipv6/sit: use DEV_STATS_INC() to avoid data-races
> 
> Eric Dumazet <edumazet@google.com>
>    net: add atomic_long_t to net_device_stats fields
> 
> Sagi Grimberg <sagi@grimberg.me>
>    nvme-auth: don't override ctrl keys before validation
> 
> Aurabindo Pillai <aurabindo.pillai@amd.com>
>    drm/amd/display: fix array index out of bound error in bios parser
> 
> George Shen <george.shen@amd.com>
>    drm/amd/display: Workaround to increase phantom pipe vactive in pipesplit
> 
> Jiang Li <jiang.li@ugreen.com>
>    md/raid1: stop mdx_raid1 thread when raid1 array run failed
> 
> Xiao Ni <xni@redhat.com>
>    md/raid0, raid10: Don't set discard sectors for request queue
> 
> Li Zhong <floridsleeves@gmail.com>
>    drivers/md/md-bitmap: check the return value of md_bitmap_get_counter()
> 
> Nathan Chancellor <nathan@kernel.org>
>    drm/mediatek: Fix return type of mtk_hdmi_bridge_mode_valid()
> 
> Ville Syrjälä <ville.syrjala@linux.intel.com>
>    drm/sti: Use drm_mode_copy()
> 
> Ville Syrjälä <ville.syrjala@linux.intel.com>
>    drm/rockchip: Use drm_mode_copy()
> 
> Ville Syrjälä <ville.syrjala@linux.intel.com>
>    drm/msm: Use drm_mode_copy()
> 
> Wesley Chalmers <Wesley.Chalmers@amd.com>
>    drm/amd/display: Disable DRR actions during state commit
> 
> Nathan Chancellor <nathan@kernel.org>
>    s390/lcs: Fix return type of lcs_start_xmit()
> 
> Nathan Chancellor <nathan@kernel.org>
>    s390/netiucv: Fix return type of netiucv_tx()
> 
> Nathan Chancellor <nathan@kernel.org>
>    s390/ctcm: Fix return type of ctc{mp,}m_tx()
> 
> Nathan Chancellor <nathan@kernel.org>
>    drm/amdgpu: Fix type of second parameter in odn_edit_dpm_table() callback
> 
> Nathan Chancellor <nathan@kernel.org>
>    drm/amdgpu: Fix type of second parameter in trans_msg() callback
> 
> Kees Cook <keescook@chromium.org>
>    igb: Do not free q_vector unless new one was allocated
> 
> José Expósito <jose.exposito89@gmail.com>
>    HID: input: do not query XP-PEN Deco LW battery
> 
> Minsuk Kang <linuxlovemin@yonsei.ac.kr>
>    wifi: brcmfmac: Fix potential shift-out-of-bounds in brcmf_fw_alloc_request()
> 
> Nathan Chancellor <nathan@kernel.org>
>    hamradio: baycom_epp: Fix return type of baycom_send_packet()
> 
> Nathan Chancellor <nathan@kernel.org>
>    net: ethernet: ti: Fix return type of netcp_ndo_start_xmit()
> 
> Stanislav Fomichev <sdf@google.com>
>    bpf: make sure skb->len != 0 when redirecting to a tunneling device
> 
> Nathan Chancellor <nathan@kernel.org>
>    drm/meson: Fix return type of meson_encoder_cvbs_mode_valid()
> 
> Jiri Slaby (SUSE) <jirislaby@kernel.org>
>    qed (gcc13): use u16 for fid to be big enough
> 
> Rahul Bhattacharjee <quic_rbhattac@quicinc.com>
>    wifi: ath11k: Fix qmi_msg_handler data structure initialization
> 
> Kerem Karabay <kekrby@gmail.com>
>    HID: apple: enable APPLE_ISO_TILDE_QUIRK for the keyboards of Macs with the T2 chip
> 
> Kerem Karabay <kekrby@gmail.com>
>    HID: apple: fix key translations where multiple quirks attempt to translate the same key
> 
> David Jeffery <djeffery@redhat.com>
>    blk-mq: avoid double ->queue_rq() because of early timeout
> 
> Yuan Can <yuancan@huawei.com>
>    drm/rockchip: use pm_runtime_resume_and_get() instead of pm_runtime_get_sync()
> 
> Hamza Mahfooz <hamza.mahfooz@amd.com>
>    Revert "drm/amd/display: Limit max DSC target bpp for specific monitors"
> 
> Hamza Mahfooz <hamza.mahfooz@amd.com>
>    drm/edid: add a quirk for two LG monitors to get them to work on 10bpc
> 
> gehao <gehao@kylinos.cn>
>    drm/amd/display: prevent memory leak
> 
> Youghandhar Chintala <quic_youghand@quicinc.com>
>    wifi: ath10k: Delay the unmapping of the buffer
> 
> Zhang Yuchen <zhangyuchen.lcr@bytedance.com>
>    ipmi: fix memleak when unload ipmi driver
> 
> Amadeusz Sławiński <amadeuszx.slawinski@linux.intel.com>
>    ASoC: Intel: avs: Add quirk for KBL-R RVP platform
> 
> Amadeusz Sławiński <amadeuszx.slawinski@linux.intel.com>
>    ASoC: codecs: rt298: Add quirk for KBL-R RVP platform
> 
> Shigeru Yoshida <syoshida@redhat.com>
>    wifi: ar5523: Fix use-after-free on ar5523_cmd() timed out
> 
> Fedor Pchelkin <pchelkin@ispras.ru>
>    wifi: ath9k: verify the expected usb_endpoints are present
> 
> Wright Feng <wright.feng@cypress.com>
>    brcmfmac: return error when getting invalid max_flowrings from dongle
> 
> Ming Qian <ming.qian@nxp.com>
>    media: imx-jpeg: Disable useless interrupt to avoid kernel panic
> 
> Doug Brown <doug@schmorgal.com>
>    drm/etnaviv: add missing quirks for GC300
> 
> ZhangPeng <zhangpeng362@huawei.com>
>    hfs: fix OOB Read in __hfs_brec_find
> 
> Hans de Goede <hdegoede@redhat.com>
>    ACPI: x86: Add skip i2c clients quirk for Medion Lifetab S10346
> 
> Hans de Goede <hdegoede@redhat.com>
>    ACPI: x86: Add skip i2c clients quirk for Lenovo Yoga Tab 3 Pro (YT3-X90F)
> 
> Mateusz Jończyk <mat.jonczyk@o2.pl>
>    x86/apic: Handle no CONFIG_X86_X2APIC on systems with x2APIC enabled by BIOS
> 
> Zheng Yejian <zhengyejian1@huawei.com>
>    acct: fix potential integer overflow in encode_comp_t()
> 
> Ryusuke Konishi <konishi.ryusuke@gmail.com>
>    nilfs2: fix shift-out-of-bounds due to too large exponent of block size
> 
> Ryusuke Konishi <konishi.ryusuke@gmail.com>
>    nilfs2: fix shift-out-of-bounds/overflow in nilfs_sb2_bad_offset()
> 
> Rafael J. Wysocki <rafael.j.wysocki@intel.com>
>    ACPICA: Fix error code path in acpi_ds_call_control_method()
> 
> Mia Kanashi <chad@redpilled.dev>
>    ACPI: EC: Add quirk for the HP Pavilion Gaming 15-cx0041ur
> 
> Li Zhong <floridsleeves@gmail.com>
>    ACPI: processor: idle: Check acpi_fetch_acpi_dev() return value
> 
> Hoi Pok Wu <wuhoipok@gmail.com>
>    fs: jfs: fix shift-out-of-bounds in dbDiscardAG
> 
> Dr. David Alan Gilbert <linux@treblig.org>
>    jfs: Fix fortify moan in symlink
> 
> Shigeru Yoshida <syoshida@redhat.com>
>    udf: Avoid double brelse() in udf_rename()
> 
> Dongliang Mu <mudongliangabcd@gmail.com>
>    fs: jfs: fix shift-out-of-bounds in dbAllocAG
> 
> Marijn Suijten <marijn.suijten@somainline.org>
>    arm64: dts: qcom: sm6350: Add apps_smmu with streamID to SDHCI 1/2 nodes
> 
> Liu Shixin <liushixin2@huawei.com>
>    binfmt_misc: fix shift-out-of-bounds in check_special_flags
> 
> Gaurav Kohli <gauravkohli@linux.microsoft.com>
>    x86/hyperv: Remove unregister syscore call from Hyper-V cleanup
> 
> Guilherme G. Piccoli <gpiccoli@igalia.com>
>    video: hyperv_fb: Avoid taking busy spinlock on panic path
> 
> Adriana Kobylak <anoo@us.ibm.com>
>    ARM: dts: aspeed: rainier,everest: Move reserved memory regions
> 
> Mark Rutland <mark.rutland@arm.com>
>    arm64: make is_ttbrX_addr() noinstr-safe
> 
> Zqiang <qiang1.zhang@intel.com>
>    rcu: Fix __this_cpu_read() lockdep warning in rcu_force_quiescent_state()
> 
> Jiasheng Jiang <jiasheng@iscas.ac.cn>
>    HID: amd_sfh: Add missing check for dma_alloc_coherent
> 
> Matt Johnston <matt@codeconstruct.com.au>
>    mctp: Remove device type check at unregister
> 
> Jeremy Kerr <jk@codeconstruct.com.au>
>    mctp: serial: Fix starting value for frame check sequence
> 
> Eric Dumazet <edumazet@google.com>
>    net: stream: purge sk_error_queue in sk_stream_kill_queues()
> 
> Christophe JAILLET <christophe.jaillet@wanadoo.fr>
>    myri10ge: Fix an error handling path in myri10ge_probe()
> 
> David Howells <dhowells@redhat.com>
>    rxrpc: Fix missing unlock in rxrpc_do_sendmsg()
> 
> Cong Wang <cong.wang@bytedance.com>
>    net_sched: reject TCF_EM_SIMPLE case for complex ematch module
> 
> Yang Yingliang <yangyingliang@huawei.com>
>    mailbox: zynq-ipi: fix error handling while device_register() fails
> 
> Yang Yingliang <yangyingliang@huawei.com>
>    mailbox: arm_mhuv2: Fix return value check in mhuv2_probe()
> 
> Conor Dooley <conor.dooley@microchip.com>
>    mailbox: mpfs: read the system controller's status
> 
> Subash Abhinov Kasiviswanathan <quic_subashab@quicinc.com>
>    skbuff: Account for tail adjustment during pull operations
> 
> Jakub Kicinski <kuba@kernel.org>
>    devlink: protect devlink dump by the instance lock
> 
> Chen-Yu Tsai <wenst@chromium.org>
>    arm64: dts: mt8183: Fix Mali GPU clock
> 
> Chun-Jie Chen <chun-jie.chen@mediatek.com>
>    soc: mediatek: pm-domains: Fix the power glitch issue
> 
> Eelco Chaudron <echaudro@redhat.com>
>    openvswitch: Fix flow lookup to use unmasked key
> 
> Jakub Kicinski <kuba@kernel.org>
>    selftests: devlink: fix the fd redirect in dummy_reporter_test
> 
> Jakub Kicinski <kuba@kernel.org>
>    devlink: hold region lock when flushing snapshots
> 
> GUO Zihua <guozihua@huawei.com>
>    rtc: mxc_v2: Add missing clk_disable_unprepare()
> 
> Tan Tee Min <tee.min.tan@linux.intel.com>
>    igc: Set Qbv start_time and end_time to end_time if not being configured in GCL
> 
> Tan Tee Min <tee.min.tan@linux.intel.com>
>    igc: recalculate Qbv end_time by considering cycle time
> 
> Tan Tee Min <tee.min.tan@linux.intel.com>
>    igc: allow BaseTime 0 enrollment for Qbv
> 
> Muhammad Husaini Zulkifli <muhammad.husaini.zulkifli@intel.com>
>    igc: Add checking for basetime less than zero
> 
> Vinicius Costa Gomes <vinicius.gomes@intel.com>
>    igc: Use strict cycles for Qbv scheduling
> 
> Vinicius Costa Gomes <vinicius.gomes@intel.com>
>    igc: Enhance Qbv scheduling by using first flag bit
> 
> Vladimir Oltean <vladimir.oltean@nxp.com>
>    net: dsa: mv88e6xxx: avoid reg_lock deadlock in mv88e6xxx_setup_port()
> 
> Li Zetao <lizetao1@huawei.com>
>    r6040: Fix kmemleak in probe and remove
> 
> Kirill Tkhai <tkhai@ya.ru>
>    unix: Fix race in SOCK_SEQPACKET's unix_dgram_sendmsg()
> 
> Minsuk Kang <linuxlovemin@yonsei.ac.kr>
>    nfc: pn533: Clear nfc_target before being used
> 
> Vladimir Oltean <vladimir.oltean@nxp.com>
>    net: enetc: avoid buffer leaks on xdp_do_redirect() failure
> 
> Hans Verkuil <hverkuil-cisco@xs4all.nl>
>    media: v4l2-ctrls-api.c: add back dropped ctrl->is_new = 1
> 
> Milan Landaverde <milan@mdaverde.com>
>    bpf: prevent leak of lsm program after failed attach
> 
> Song Liu <song@kernel.org>
>    selftests/bpf: Select CONFIG_FUNCTION_ERROR_INJECTION
> 
> Yu Kuai <yukuai3@huawei.com>
>    block, bfq: fix possible uaf for 'bfqq->bic'
> 
> Yang Yingliang <yangyingliang@huawei.com>
>    mISDN: hfcmulti: don't call dev_kfree_skb/kfree_skb() under spin_lock_irqsave()
> 
> Yang Yingliang <yangyingliang@huawei.com>
>    mISDN: hfcpci: don't call dev_kfree_skb/kfree_skb() under spin_lock_irqsave()
> 
> Yang Yingliang <yangyingliang@huawei.com>
>    mISDN: hfcsusb: don't call dev_kfree_skb/kfree_skb() under spin_lock_irqsave()
> 
> Hangbin Liu <liuhangbin@gmail.com>
>    bonding: do failover when high prio link up
> 
> Hangbin Liu <liuhangbin@gmail.com>
>    bonding: add missed __rcu annotation for curr_active_slave
> 
> Emeel Hakim <ehakim@nvidia.com>
>    net: macsec: fix net device access prior to holding a lock
> 
> Dan Aloni <dan.aloni@vastdata.com>
>    nfsd: under NFSv4.1, fix double svc_xprt_put on rpc_create failure
> 
> Dan Carpenter <error27@gmail.com>
>    iommu/mediatek: Fix forever loop in error handling
> 
> Alexandre Belloni <alexandre.belloni@bootlin.com>
>    rtc: pcf85063: fix pcf85063_clkout_control
> 
> Gaosheng Cui <cuigaosheng1@huawei.com>
>    rtc: pic32: Move devm_rtc_allocate_device earlier in pic32_rtc_probe()
> 
> Gaosheng Cui <cuigaosheng1@huawei.com>
>    rtc: st-lpc: Add missing clk_disable_unprepare in st_rtc_probe()
> 
> Qingfang DENG <dqfext@gmail.com>
>    netfilter: flowtable: really fix NAT IPv6 offload
> 
> Yang Yingliang <yangyingliang@huawei.com>
>    mfd: pm8008: Fix return value check in pm8008_probe()
> 
> Christophe JAILLET <christophe.jaillet@wanadoo.fr>
>    mfd: qcom_rpm: Fix an error handling path in qcom_rpm_probe()
> 
> Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>
>    mfd: bd957x: Fix Kconfig dependency on REGMAP_IRQ
> 
> Samuel Holland <samuel@sholland.org>
>    mfd: axp20x: Do not sleep in the power off handler
> 
> Bryan O'Donoghue <bryan.odonoghue@linaro.org>
>    dt-bindings: mfd: qcom,spmi-pmic: Drop PWM reg dependency
> 
> Nathan Lynch <nathanl@linux.ibm.com>
>    powerpc/pseries/eeh: use correct API for error log size
> 
> Shang XiaoJing <shangxiaojing@huawei.com>
>    remoteproc: qcom: q6v5: Fix missing clk_disable_unprepare() in q6v5_wcss_qcs404_power_on()
> 
> Yuan Can <yuancan@huawei.com>
>    remoteproc: qcom_q6v5_pas: Fix missing of_node_put() in adsp_alloc_memory_region()
> 
> Luca Weiss <luca.weiss@fairphone.com>
>    remoteproc: qcom_q6v5_pas: detach power domains on remove
> 
> Luca Weiss <luca.weiss@fairphone.com>
>    remoteproc: qcom_q6v5_pas: disable wakeup on probe fail or remove
> 
> Shang XiaoJing <shangxiaojing@huawei.com>
>    remoteproc: qcom: q6v5: Fix potential null-ptr-deref in q6v5_wcss_init_mmio()
> 
> Gaosheng Cui <cuigaosheng1@huawei.com>
>    remoteproc: sysmon: fix memory leak in qcom_add_sysmon_subdev()
> 
> Anup Patel <apatel@ventanamicro.com>
>    RISC-V: KVM: Fix reg_val check in kvm_riscv_vcpu_set_reg_config()
> 
> Daniel Golle <daniel@makrotopia.org>
>    pwm: mediatek: always use bus clock for PWM on MT7622
> 
> xinlei lee <xinlei.lee@mediatek.com>
>    pwm: mtk-disp: Fix the parameters calculated by the enabled flag of disp_pwm
> 
> Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
>    pwm: sifive: Call pwm_sifive_update_clock() while mutex is held
> 
> Jason Gunthorpe <jgg@ziepe.ca>
>    iommu/sun50i: Remove IOMMU_DOMAIN_IDENTITY
> 
> Guenter Roeck <groeck@chromium.org>
>    iommu/mediatek: Validate number of phandles associated with "mediatek,larbs"
> 
> Yong Wu <yong.wu@mediatek.com>
>    iommu/mediatek: Add error path for loop of mm_dts_parse
> 
> Yong Wu <yong.wu@mediatek.com>
>    iommu/mediatek: Use component_match_add
> 
> Yong Wu <yong.wu@mediatek.com>
>    iommu/mediatek: Add platform_device_put for recovering the device refcnt
> 
> Miaoqian Lin <linmq006@gmail.com>
>    selftests/powerpc: Fix resource leaks
> 
> Kajol Jain <kjain@linux.ibm.com>
>    powerpc/hv-gpci: Fix hv_gpci event list
> 
> Yang Yingliang <yangyingliang@huawei.com>
>    powerpc/83xx/mpc832x_rdb: call platform_device_put() in error case in of_fsl_spi_probe()
> 
> Nicholas Piggin <npiggin@gmail.com>
>    powerpc/perf: callchain validate kernel stack pointer bounds
> 
> Pali Rohár <pali@kernel.org>
>    powerpc: dts: turris1x.dts: Add channel labels for temperature sensor
> 
> Li Huafei <lihuafei1@huawei.com>
>    kprobes: Fix check for probe enabled in kill_kprobe()
> 
> Nayna Jain <nayna@linux.ibm.com>
>    powerpc/pseries: fix plpks_read_var() code for different consumers
> 
> Nayna Jain <nayna@linux.ibm.com>
>    powerpc/pseries: Return -EIO instead of -EINTR for H_ABORTED error
> 
> Nayna Jain <nayna@linux.ibm.com>
>    powerpc/pseries: Fix the H_CALL error code in PLPKS driver
> 
> Nayna Jain <nayna@linux.ibm.com>
>    powerpc/pseries: fix the object owners enum value in plpks driver
> 
> Yang Yingliang <yangyingliang@huawei.com>
>    powerpc/xive: add missing iounmap() in error path in xive_spapr_populate_irq_data()
> 
> Gustavo A. R. Silva <gustavoars@kernel.org>
>    powerpc/xmon: Fix -Wswitch-unreachable warning in bpt_cmds
> 
> Miaoqian Lin <linmq006@gmail.com>
>    cxl: Fix refcount leak in cxl_calc_capp_routing
> 
> Christophe JAILLET <christophe.jaillet@wanadoo.fr>
>    powerpc/52xx: Fix a resource leak in an error handling path
> 
> Xie Shaowen <studentxswpy@163.com>
>    macintosh/macio-adb: check the return value of ioremap()
> 
> Yang Yingliang <yangyingliang@huawei.com>
>    macintosh: fix possible memory leak in macio_add_one_device()
> 
> Yuan Can <yuancan@huawei.com>
>    iommu/fsl_pamu: Fix resource leak in fsl_pamu_probe()
> 
> Yang Yingliang <yangyingliang@huawei.com>
>    iommu/amd: Fix pci device refcount leak in ppr_notifier()
> 
> Yang Yingliang <yangyingliang@huawei.com>
>    iommu/mediatek: Check return value after calling platform_get_resource()
> 
> Alexander Stein <alexander.stein@ew.tq-group.com>
>    rtc: pcf85063: Fix reading alarm
> 
> Stefan Eichenberger <stefan.eichenberger@toradex.com>
>    rtc: snvs: Allow a time difference on clock register read
> 
> Rafael J. Wysocki <rafael.j.wysocki@intel.com>
>    rtc: cmos: Disable ACPI RTC event on removal
> 
> Rafael J. Wysocki <rafael.j.wysocki@intel.com>
>    rtc: cmos: Rename ACPI-related functions
> 
> Rafael J. Wysocki <rafael.j.wysocki@intel.com>
>    rtc: cmos: Eliminate forward declarations of some functions
> 
> Rafael J. Wysocki <rafael.j.wysocki@intel.com>
>    rtc: cmos: Call rtc_wake_setup() from cmos_do_probe()
> 
> Rafael J. Wysocki <rafael.j.wysocki@intel.com>
>    rtc: cmos: Call cmos_wake_setup() from cmos_do_probe()
> 
> Shang XiaoJing <shangxiaojing@huawei.com>
>    rtc: class: Fix potential memleak in devm_rtc_allocate_device()
> 
> Yushan Zhou <katrinzhou@tencent.com>
>    rtc: rzn1: Check return value in rzn1_rtc_probe
> 
> Fenghua Yu <fenghua.yu@intel.com>
>    dmaengine: idxd: Fix crc_val field for completion record
> 
> Abdun Nihaal <abdun.nihaal@gmail.com>
>    fs/ntfs3: Fix slab-out-of-bounds read in ntfs_trim_fs
> 
> Manivannan Sadhasivam <mani@kernel.org>
>    phy: qcom-qmp-pcie: Fix sm8450_qmp_gen4x2_pcie_pcs_tbl[] register names
> 
> Jon Hunter <jonathanh@nvidia.com>
>    pwm: tegra: Ensure the clock rate is not less than needed
> 
> Jon Hunter <jonathanh@nvidia.com>
>    pwm: tegra: Improve required rate calculation
> 
> Matt Redfearn <matt.redfearn@mips.com>
>    include/uapi/linux/swab: Fix potentially missing __always_inline
> 
> Justin Chen <justinpopo6@gmail.com>
>    phy: usb: Fix clock imbalance for suspend/resume
> 
> Justin Chen <justinpopo6@gmail.com>
>    phy: usb: Use slow clock for wake enabled suspend
> 
> Al Cooper <alcooperx@gmail.com>
>    phy: usb: s2 WoL wakeup_count not incremented for USB->Eth devices
> 
> Michael Riesch <michael.riesch@wolfvision.net>
>    iommu/rockchip: fix permission bits in page table entries v2
> 
> Jernej Skrabec <jernej.skrabec@gmail.com>
>    iommu/sun50i: Implement .iotlb_sync_map
> 
> Jernej Skrabec <jernej.skrabec@gmail.com>
>    iommu/sun50i: Fix flush size
> 
> Jernej Skrabec <jernej.skrabec@gmail.com>
>    iommu/sun50i: Fix R/W permission check
> 
> Jernej Skrabec <jernej.skrabec@gmail.com>
>    iommu/sun50i: Consider all fault sources for reset
> 
> Jernej Skrabec <jernej.skrabec@gmail.com>
>    iommu/sun50i: Fix reset release
> 
> Niklas Schnelle <schnelle@linux.ibm.com>
>    iommu/s390: Fix duplicate domain attachments
> 
> Johan Hovold <johan+linaro@kernel.org>
>    phy: qcom-qmp-pcie: fix ipq8074-gen3 initialisation
> 
> Martin Povišer <povik+lin@cutebit.org>
>    dmaengine: apple-admac: Allocate cache SRAM to channels
> 
> Martin Povišer <povik+lin@cutebit.org>
>    dmaengine: apple-admac: Do not use devres for IRQs
> 
> Johan Hovold <johan+linaro@kernel.org>
>    phy: qcom-qmp-pcie: drop bogus register update
> 
> Pali Rohár <pali@kernel.org>
>    phy: marvell: phy-mvebu-a3700-comphy: Reset COMPHY registers before USB 3.0 power on
> 
> Dan Carpenter <dan.carpenter@oracle.com>
>    fs/ntfs3: Harden against integer overflows
> 
> Shigeru Yoshida <syoshida@redhat.com>
>    fs/ntfs3: Avoid UBSAN error on true_sectors_per_clst()
> 
> Arnd Bergmann <arnd@arndb.de>
>    RDMA/siw: Fix pointer cast warning
> 
> Namhyung Kim <namhyung@kernel.org>
>    perf stat: Do not delay the workload with --delay
> 
> Ard Biesheuvel <ardb@kernel.org>
>    ftrace: Allow WITH_ARGS flavour of graph tracer with shadow call stack
> 
> Namhyung Kim <namhyung@kernel.org>
>    perf off_cpu: Fix a typo in BTF tracepoint name, it should be 'btf_trace_sched_switch'
> 
> Luca Weiss <luca@z3ntu.xyz>
>    leds: is31fl319x: Fix setting current limit for is31fl319{0,1,3}
> 
> ruanjinjie <ruanjinjie@huawei.com>
>    power: supply: fix null pointer dereferencing in power_supply_get_battery_info
> 
> Hans de Goede <hdegoede@redhat.com>
>    power: supply: bq25890: Ensure pump_express_work is cancelled on remove
> 
> Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
>    power: supply: bq25890: Convert to i2c's .probe_new()
> 
> Marek Vasut <marex@denx.de>
>    power: supply: bq25890: Factor out regulator registration code
> 
> Yuan Can <yuancan@huawei.com>
>    power: supply: ab8500: Fix error handling in ab8500_charger_init()
> 
> Yuan Can <yuancan@huawei.com>
>    HSI: omap_ssi_core: Fix error handling in ssi_init()
> 
> Shang XiaoJing <shangxiaojing@huawei.com>
>    power: supply: cw2015: Fix potential null-ptr-deref in cw_bat_probe()
> 
> Zheyu Ma <zheyuma97@gmail.com>
>    power: supply: cw2015: Use device managed API to simplify the code
> 
> Zhang Qilong <zhangqilong3@huawei.com>
>    power: supply: z2_battery: Fix possible memleak in z2_batt_probe()
> 
> Ajay Kaher <akaher@vmware.com>
>    perf symbol: correction while adjusting symbol
> 
> Leo Yan <leo.yan@linaro.org>
>    perf trace: Handle failure when trace point folder is missed
> 
> Leo Yan <leo.yan@linaro.org>
>    perf trace: Use macro RAW_SYSCALL_ARGS_NUM to replace number
> 
> Leo Yan <leo.yan@linaro.org>
>    perf trace: Return error if a system call doesn't exist
> 
> Mika Westerberg <mika.westerberg@linux.intel.com>
>    watchdog: iTCO_wdt: Set NO_REBOOT if the watchdog is not already running
> 
> Zeng Heng <zengheng4@huawei.com>
>    power: supply: fix residue sysfs file in error handle route of __power_supply_register()
> 
> Yang Yingliang <yangyingliang@huawei.com>
>    HSI: omap_ssi_core: fix possible memory leak in ssi_probe()
> 
> Yang Yingliang <yangyingliang@huawei.com>
>    HSI: omap_ssi_core: fix unbalanced pm_runtime_disable()
> 
> Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
>    led: qcom-lpg: Fix sleeping in atomic
> 
> Christophe JAILLET <christophe.jaillet@wanadoo.fr>
>    fbdev: uvesafb: Fixes an error handling path in uvesafb_probe()
> 
> Randy Dunlap <rdunlap@infradead.org>
>    fbdev: uvesafb: don't build on UML
> 
> Randy Dunlap <rdunlap@infradead.org>
>    fbdev: geode: don't build on UML
> 
> Gaosheng Cui <cuigaosheng1@huawei.com>
>    fbdev: ep93xx-fb: Add missing clk_disable_unprepare in ep93xxfb_probe()
> 
> Xiongfeng Wang <wangxiongfeng2@huawei.com>
>    fbdev: vermilion: decrease reference count in error path
> 
> Shang XiaoJing <shangxiaojing@huawei.com>
>    fbdev: via: Fix error in via_core_init()
> 
> Yang Yingliang <yangyingliang@huawei.com>
>    fbdev: pm2fb: fix missing pci_disable_device()
> 
> Andy Shevchenko <andriy.shevchenko@linux.intel.com>
>    fbdev: ssd1307fb: Drop optional dependency
> 
> Bjorn Andersson <andersson@kernel.org>
>    thermal/drivers/qcom/lmh: Fix irq handler return value
> 
> Luca Weiss <luca.weiss@fairphone.com>
>    thermal/drivers/qcom/temp-alarm: Fix inaccurate warning for gen2
> 
> Keerthy <j-keerthy@ti.com>
>    thermal/drivers/k3_j72xx_bandgap: Fix the debug print message
> 
> Marcus Folkesson <marcus.folkesson@gmail.com>
>    thermal/drivers/imx8mm_thermal: Validate temperature range
> 
> Shang XiaoJing <shangxiaojing@huawei.com>
>    samples: vfio-mdev: Fix missing pci_disable_device() in mdpy_fb_probe()
> 
> Xiu Jianfeng <xiujianfeng@huawei.com>
>    ksmbd: Fix resource leak in ksmbd_session_rpc_open()
> 
> Zheng Yejian <zhengyejian1@huawei.com>
>    tracing/hist: Fix issue of losting command info in error_log
> 
> Yang Yingliang <yangyingliang@huawei.com>
>    usb: typec: wusb3801: fix fwnode refcount leak in wusb3801_probe()
> 
> Jiasheng Jiang <jiasheng@iscas.ac.cn>
>    usb: storage: Add check for kcalloc
> 
> Zheyu Ma <zheyuma97@gmail.com>
>    i2c: ismt: Fix an out-of-bounds bug in ismt_access()
> 
> Yang Yingliang <yangyingliang@huawei.com>
>    i2c: mux: reg: check return value after calling platform_get_resource()
> 
> Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
>    gpiolib: protect the GPIO device against being dropped while in use by user-space
> 
> Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
>    gpiolib: cdev: fix NULL-pointer dereferences
> 
> Chen Zhongjin <chenzhongjin@huawei.com>
>    vme: Fix error not catched in fake_init()
> 
> YueHaibing <yuehaibing@huawei.com>
>    staging: rtl8192e: Fix potential use-after-free in rtllib_rx_Monitor()
> 
> Dan Carpenter <error27@gmail.com>
>    staging: rtl8192u: Fix use after free in ieee80211_rx()
> 
> Hui Tang <tanghui20@huawei.com>
>    i2c: pxa-pci: fix missing pci_disable_device() on error in ce4100_i2c_probe
> 
> Yang Yingliang <yangyingliang@huawei.com>
>    chardev: fix error handling in cdev_device_add()
> 
> Yang Yingliang <yangyingliang@huawei.com>
>    mcb: mcb-parse: fix error handing in chameleon_parse_gdd()
> 
> Zhengchao Shao <shaozhengchao@huawei.com>
>    drivers: mcb: fix resource leak in mcb_probe()
> 
> John Keeping <john@metanate.com>
>    usb: gadget: f_hid: fix refcount leak on error path
> 
> John Keeping <john@metanate.com>
>    usb: gadget: f_hid: fix f_hidg lifetime vs cdev
> 
> Yang Yingliang <yangyingliang@huawei.com>
>    usb: core: hcd: Fix return value check in usb_hcd_setup_local_mem()
> 
> Yang Yingliang <yangyingliang@huawei.com>
>    usb: roles: fix of node refcount leak in usb_role_switch_is_parent()
> 
> Beau Belgrave <beaub@linux.microsoft.com>
>    tracing/user_events: Fix call print_fmt leak
> 
> Yang Shen <shenyang39@huawei.com>
>    coresight: trbe: remove cpuhp instance node before remove cpuhp state
> 
> Fabrice Gasnier <fabrice.gasnier@foss.st.com>
>    counter: stm32-lptimer-cnt: fix the check on arr and cmp registers update
> 
> Ramona Bolboaca <ramona.bolboaca@analog.com>
>    iio: adis: add '__adis_enable_irq()' implementation
> 
> Cosmin Tanislav <cosmin.tanislav@analog.com>
>    iio: temperature: ltc2983: make bulk write buffer DMA-safe
> 
> Yang Yingliang <yangyingliang@huawei.com>
>    cxl: fix possible null-ptr-deref in cxl_pci_init_afu|adapter()
> 
> Yang Yingliang <yangyingliang@huawei.com>
>    cxl: fix possible null-ptr-deref in cxl_guest_init_afu|adapter()
> 
> Yang Yingliang <yangyingliang@huawei.com>
>    firmware: raspberrypi: fix possible memory leak in rpi_firmware_probe()
> 
> Zheng Wang <zyytlz.wz@163.com>
>    misc: sgi-gru: fix use-after-free error in gru_set_context_option, gru_fault and gru_handle_user_call_os
> 
> ruanjinjie <ruanjinjie@huawei.com>
>    misc: tifm: fix possible memory leak in tifm_7xx1_switch_media()
> 
> Yang Yingliang <yangyingliang@huawei.com>
>    ocxl: fix pci device refcount leak when calling get_function_0()
> 
> Yang Yingliang <yangyingliang@huawei.com>
>    misc: ocxl: fix possible name leak in ocxl_file_register_afu()
> 
> Zhengchao Shao <shaozhengchao@huawei.com>
>    test_firmware: fix memory leak in test_firmware_init()
> 
> Yuan Can <yuancan@huawei.com>
>    serial: sunsab: Fix error handling in sunsab_init()
> 
> Gabriel Somlo <gsomlo@gmail.com>
>    serial: altera_uart: fix locking in polling mode
> 
> Jiri Slaby <jirislaby@kernel.org>
>    tty: serial: altera_uart_{r,t}x_chars() need only uart_port
> 
> Jiri Slaby <jirislaby@kernel.org>
>    tty: serial: clean up stop-tx part in altera_uart_tx_chars()
> 
> Xiongfeng Wang <wangxiongfeng2@huawei.com>
>    serial: pch: Fix PCI device refcount leak in pch_request_dma()
> 
> Valentin Caron <valentin.caron@foss.st.com>
>    serial: stm32: move dma_request_chan() before clk_prepare_enable()
> 
> delisun <delisun@pateo.com.cn>
>    serial: pl011: Do not clear RX FIFO & RX interrupt in unthrottle.
> 
> Jiamei Xie <jiamei.xie@arm.com>
>    serial: amba-pl011: avoid SBSA UART accessing DMACR register
> 
> Jiantao Zhang <water.zhangjiantao@huawei.com>
>    USB: gadget: Fix use-after-free during usb config switch
> 
> Marek Vasut <marex@denx.de>
>    extcon: usbc-tusb320: Update state on probe even if no IRQ pending
> 
> Marek Vasut <marex@denx.de>
>    extcon: usbc-tusb320: Add USB TYPE-C support
> 
> Marek Vasut <marex@denx.de>
>    extcon: usbc-tusb320: Factor out extcon into dedicated functions
> 
> Tony Lindgren <tony@atomide.com>
>    usb: musb: omap2430: Fix probe regression for missing resources
> 
> Sven Peter <sven@svenpeter.dev>
>    usb: typec: tipd: Fix typec_unregister_port error paths
> 
> Sven Peter <sven@svenpeter.dev>
>    usb: typec: tipd: Fix spurious fwnode_handle_put in error path
> 
> Sven Peter <sven@svenpeter.dev>
>    usb: typec: tipd: Cleanup resources if devm_tps6598_psy_register fails
> 
> Yang Yingliang <yangyingliang@huawei.com>
>    usb: typec: tcpci: fix of node refcount leak in tcpci_register_port()
> 
> Sven Peter <sven@svenpeter.dev>
>    usb: typec: Check for ops->exit instead of ops->enter in altmode_exit
> 
> Gaosheng Cui <cuigaosheng1@huawei.com>
>    staging: vme_user: Fix possible UAF in tsi148_dma_list_add
> 
> Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
>    interconnect: qcom: sc7180: fix dropped const of qcom_icc_bcm
> 
> Linus Walleij <linus.walleij@linaro.org>
>    usb: fotg210-udc: Fix ages old endianness issues
> 
> Rafael Mendonca <rafaelmendsr@gmail.com>
>    uio: uio_dmem_genirq: Fix deadlock between irq config and handling
> 
> Rafael Mendonca <rafaelmendsr@gmail.com>
>    uio: uio_dmem_genirq: Fix missing unlock in irq configuration
> 
> Rafael Mendonca <rafaelmendsr@gmail.com>
>    vfio: platform: Do not pass return buffer to ACPI _RST method
> 
> Yang Yingliang <yangyingliang@huawei.com>
>    class: fix possible memory leak in __class_register()
> 
> Duoming Zhou <duoming@zju.edu.cn>
>    drivers: staging: r8188eu: Fix sleep-in-atomic-context bug in rtw_join_timeout_handler
> 
> Yuan Can <yuancan@huawei.com>
>    serial: 8250_bcm7271: Fix error handling in brcmuart_init()
> 
> Kartik <kkartik@nvidia.com>
>    serial: tegra: Read DMA status before terminating
> 
> Yang Yingliang <yangyingliang@huawei.com>
>    drivers: dio: fix possible memory leak in dio_init()
> 
> Alexandre Ghiti <alexghiti@rivosinc.com>
>    riscv: Fix P4D_SHIFT definition for 3-level page table mode
> 
> Yangtao Li <frank.li@vivo.com>
>    f2fs: fix iostat parameter for discard
> 
> Palmer Dabbelt <palmer@rivosinc.com>
>    RISC-V: Align the shadow stack
> 
> Dragos Tatulea <dtatulea@nvidia.com>
>    IB/IPoIB: Fix queue count inconsistency for PKEY child interfaces
> 
> Xiongfeng Wang <wangxiongfeng2@huawei.com>
>    hwrng: geode - Fix PCI device refcount leak
> 
> Xiongfeng Wang <wangxiongfeng2@huawei.com>
>    hwrng: amd - Fix PCI device refcount leak
> 
> Gaosheng Cui <cuigaosheng1@huawei.com>
>    crypto: img-hash - Fix variable dereferenced before check 'hdev->req'
> 
> Samuel Holland <samuel@sholland.org>
>    riscv: Fix crash during early errata patching
> 
> Anup Patel <apatel@ventanamicro.com>
>    RISC-V: Fix MEMREMAP_WB for systems with Svpbmt
> 
> Andrew Bresticker <abrestic@rivosinc.com>
>    RISC-V: Fix unannoted hardirqs-on in return to userspace slow-path
> 
> Chengchang Tang <tangchengchang@huawei.com>
>    RDMA/hns: Fix XRC caps on HIP08
> 
> Chengchang Tang <tangchengchang@huawei.com>
>    RDMA/hns: Fix error code of CMD
> 
> Chengchang Tang <tangchengchang@huawei.com>
>    RDMA/hns: Fix page size cap from firmware
> 
> Chengchang Tang <tangchengchang@huawei.com>
>    RDMA/hns: Fix PBL page MTR find
> 
> Chengchang Tang <tangchengchang@huawei.com>
>    RDMA/hns: Fix AH attr queried by query_qp
> 
> Yixing Liu <liuyixing1@huawei.com>
>    RDMA/hns: Fix the gid problem caused by free mr
> 
> Wenpeng Liang <liangwenpeng@huawei.com>
>    RDMA/hns: Remove redundant DFX file and DFX ops structure
> 
> Zhang Xiaoxu <zhangxiaoxu5@huawei.com>
>    orangefs: Fix sysfs not cleanup when dev init failed
> 
> Francisco Munoz <francisco.munoz.ruiz@linux.intel.com>
>    PCI: vmd: Fix secondary bus reset for Intel bridges
> 
> Wang Yufen <wangyufen@huawei.com>
>    RDMA/srp: Fix error return code in srp_parse_options()
> 
> Wang Yufen <wangyufen@huawei.com>
>    RDMA/hfi1: Fix error return code in parse_platform_config()
> 
> Randy Dunlap <rdunlap@infradead.org>
>    RDMA: Disable IB HW for UML
> 
> Tong Tiangen <tongtiangen@huawei.com>
>    riscv/mm: add arch hook arch_clear_hugepage_flags
> 
> Shang XiaoJing <shangxiaojing@huawei.com>
>    crypto: omap-sham - Use pm_runtime_resume_and_get() in omap_sham_probe()
> 
> Christophe JAILLET <christophe.jaillet@wanadoo.fr>
>    crypto: amlogic - Remove kcalloc without check
> 
> Wang Yufen <wangyufen@huawei.com>
>    crypto: qat - fix error return code in adf_probe
> 
> Mark Zhang <markzhang@nvidia.com>
>    RDMA/nldev: Fix failure to send large messages
> 
> Yonggil Song <yonggil.song@samsung.com>
>    f2fs: avoid victim selection from previous victim section
> 
> Sheng Yong <shengyong@oppo.com>
>    f2fs: fix to enable compress for newly created file if extension matches
> 
> Sheng Yong <shengyong@oppo.com>
>    f2fs: set zstd compress level correctly
> 
> Yuan Can <yuancan@huawei.com>
>    RDMA/nldev: Add checks for nla_nest_start() in fill_stat_counter_qps()
> 
> Bart Van Assche <bvanassche@acm.org>
>    scsi: ufs: core: Fix the polling implementation
> 
> Jie Zhan <zhanjie9@hisilicon.com>
>    scsi: hisi_sas: Fix SATA devices missing issue during I_T nexus reset
> 
> Jie Zhan <zhanjie9@hisilicon.com>
>    scsi: libsas: Add smp_ata_check_ready_type()
> 
> Gaosheng Cui <cuigaosheng1@huawei.com>
>    scsi: snic: Fix possible UAF in snic_tgt_create()
> 
> Chen Zhongjin <chenzhongjin@huawei.com>
>    scsi: fcoe: Fix transport not deattached when fcoe_if_init() fails
> 
> Shang XiaoJing <shangxiaojing@huawei.com>
>    scsi: ipr: Fix WARNING in ipr_init()
> 
> Yang Yingliang <yangyingliang@huawei.com>
>    scsi: scsi_debug: Fix possible name leak in sdebug_add_host_helper()
> 
> Yang Yingliang <yangyingliang@huawei.com>
>    scsi: fcoe: Fix possible name leak when device_register() fails
> 
> Harshit Mogalapalli <harshit.m.mogalapalli@oracle.com>
>    scsi: scsi_debug: Fix a warning in resp_report_zones()
> 
> Harshit Mogalapalli <harshit.m.mogalapalli@oracle.com>
>    scsi: scsi_debug: Fix a warning in resp_verify()
> 
> Chen Zhongjin <chenzhongjin@huawei.com>
>    scsi: efct: Fix possible memleak in efct_device_init()
> 
> Yang Yingliang <yangyingliang@huawei.com>
>    scsi: hpsa: Fix possible memory leak in hpsa_add_sas_device()
> 
> Yang Yingliang <yangyingliang@huawei.com>
>    scsi: hpsa: Fix error handling in hpsa_add_sas_host()
> 
> Yang Yingliang <yangyingliang@huawei.com>
>    scsi: mpt3sas: Fix possible resource leaks in mpt3sas_transport_port_add()
> 
> Daniel Jordan <daniel.m.jordan@oracle.com>
>    padata: Fix list iterator in padata_do_serial()
> 
> Daniel Jordan <daniel.m.jordan@oracle.com>
>    padata: Always leave BHs disabled when running ->parallel()
> 
> Zhang Yiqun <zhangyiqun@phytium.com.cn>
>    crypto: tcrypt - Fix multibuffer skcipher speed test mem leak
> 
> Yuan Can <yuancan@huawei.com>
>    scsi: hpsa: Fix possible memory leak in hpsa_init_one()
> 
> Frank Li <frank.li@nxp.com>
>    PCI: endpoint: pci-epf-vntb: Fix call pci_epc_mem_free_addr() in error path
> 
> Serge Semin <Sergey.Semin@baikalelectronics.ru>
>    dt-bindings: visconti-pcie: Fix interrupts array max constraints
> 
> Serge Semin <Sergey.Semin@baikalelectronics.ru>
>    dt-bindings: imx6q-pcie: Fix clock names for imx6sx and imx8mq
> 
> Zhang Xiaoxu <zhangxiaoxu5@huawei.com>
>    RDMA/rxe: Fix NULL-ptr-deref in rxe_qp_do_cleanup() when socket create failed
> 
> Zhengchao Shao <shaozhengchao@huawei.com>
>    RDMA/hns: fix memory leak in hns_roce_alloc_mr()
> 
> Mustafa Ismail <mustafa.ismail@intel.com>
>    RDMA/irdma: Initialize net_type before checking it
> 
> Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
>    crypto: ccree - Make cc_debugfs_global_fini() available for module init function
> 
> Xiongfeng Wang <wangxiongfeng2@huawei.com>
>    RDMA/hfi: Decrease PCI device reference count in error path
> 
> Zeng Heng <zengheng4@huawei.com>
>    PCI: Check for alloc failure in pci_request_irq()
> 
> Luoyouming <luoyouming@huawei.com>
>    RDMA/hns: Fix incorrect sge nums calculation
> 
> Luoyouming <luoyouming@huawei.com>
>    RDMA/hns: Fix ext_sge num error when post send
> 
> Luoyouming <luoyouming@huawei.com>
>    RDMA/hns: Repacing 'dseg_len' by macros in fill_ext_sge_inl_data()
> 
> Li Zhijian <lizhijian@fujitsu.com>
>    RDMA/rxe: Fix mr->map double free
> 
> Xiongfeng Wang <wangxiongfeng2@huawei.com>
>    crypto: hisilicon/qm - add missing pci_dev_put() in q_num_set()
> 
> Herbert Xu <herbert@gondor.apana.org.au>
>    crypto: cryptd - Use request context instead of stack for sub-request
> 
> Gaosheng Cui <cuigaosheng1@huawei.com>
>    crypto: ccree - Remove debugfs when platform_driver_register failed
> 
> Harshit Mogalapalli <harshit.m.mogalapalli@oracle.com>
>    scsi: scsi_debug: Fix a warning in resp_write_scat()
> 
> Mustafa Ismail <mustafa.ismail@intel.com>
>    RDMA/irdma: Do not request 2-level PBLEs for CQ alloc
> 
> Mustafa Ismail <mustafa.ismail@intel.com>
>    RDMA/irdma: Fix RQ completion opcode
> 
> Mustafa Ismail <mustafa.ismail@intel.com>
>    RDMA/irdma: Fix inline for multiple SGE's
> 
> Bernard Metzler <bmt@zurich.ibm.com>
>    RDMA/siw: Set defined status for work completion with undefined status
> 
> Mark Zhang <markzhang@nvidia.com>
>    RDMA/nldev: Return "-EAGAIN" if the cm_id isn't from expected port
> 
> Mark Zhang <markzhang@nvidia.com>
>    RDMA/core: Make sure "ib_port" is valid when access sysfs node
> 
> Mark Zhang <markzhang@nvidia.com>
>    RDMA/restrack: Release MR restrack when delete
> 
> Sascha Hauer <s.hauer@pengutronix.de>
>    PCI: imx6: Initialize PHY before deasserting core reset
> 
> Nirmal Patel <nirmal.patel@linux.intel.com>
>    PCI: vmd: Disable MSI remapping after suspend
> 
> Leonid Ravich <lravich@gmail.com>
>    IB/mad: Don't call to function that might sleep while in atomic context
> 
> Bernard Metzler <bmt@zurich.ibm.com>
>    RDMA/siw: Fix immediate work request flush to completion queue
> 
> Bart Van Assche <bvanassche@acm.org>
>    scsi: qla2xxx: Fix set-but-not-used variable warnings
> 
> Shiraz Saleem <shiraz.saleem@intel.com>
>    RDMA/irdma: Report the correct link speed
> 
> Chao Yu <chao@kernel.org>
>    f2fs: fix to destroy sbi->post_read_wq in error path of f2fs_fill_super()
> 
> Mukesh Ojha <quic_mojha@quicinc.com>
>    f2fs: fix the assign logic of iocb
> 
> Jaegeuk Kim <jaegeuk@kernel.org>
>    f2fs: allow to set compression for inlined file
> 
> Dongdong Zhang <zhangdongdong1@oppo.com>
>    f2fs: fix normal discard process
> 
> Chao Yu <chao@kernel.org>
>    f2fs: fix to invalidate dcc->f2fs_issue_discard in error path
> 
> Kees Cook <keescook@chromium.org>
>    fortify: Do not cast to "unsigned char"
> 
> Kees Cook <keescook@chromium.org>
>    fortify: Use SIZE_MAX instead of (size_t)-1
> 
> Xiu Jianfeng <xiujianfeng@huawei.com>
>    apparmor: Fix memleak in alloc_ns()
> 
> Corentin Labbe <clabbe@baylibre.com>
>    crypto: rockchip - rework by using crypto_engine
> 
> Corentin Labbe <clabbe@baylibre.com>
>    crypto: rockchip - remove non-aligned handling
> 
> Corentin Labbe <clabbe@baylibre.com>
>    crypto: rockchip - better handle cipher key
> 
> Corentin Labbe <clabbe@baylibre.com>
>    crypto: rockchip - add fallback for ahash
> 
> Corentin Labbe <clabbe@baylibre.com>
>    crypto: rockchip - add fallback for cipher
> 
> Corentin Labbe <clabbe@baylibre.com>
>    crypto: rockchip - do not store mode globally
> 
> Corentin Labbe <clabbe@baylibre.com>
>    crypto: rockchip - do not do custom power management
> 
> Zhang Qilong <zhangqilong3@huawei.com>
>    f2fs: Fix the race condition of resize flag between resizefs
> 
> Kunihiko Hayashi <hayashi.kunihiko@socionext.com>
>    PCI: pci-epf-test: Register notifier if only core_init_notifier is enabled
> 
> Leon Romanovsky <leon@kernel.org>
>    RDMA/core: Fix order of nldev_exit call
> 
> Vidya Sagar <vidyas@nvidia.com>
>    PCI: dwc: Fix n_fts[] array overrun
> 
> Xiu Jianfeng <xiujianfeng@huawei.com>
>    apparmor: Use pointer to struct aa_label for lbs_cred
> 
> Bart Van Assche <bvanassche@acm.org>
>    scsi: core: Fix a race between scsi_done() and scsi_timeout()
> 
> Robert Elliott <elliott@hpe.com>
>    crypto: tcrypt - fix return value for multiple subtests
> 
> Natalia Petrova <n.petrova@fintech.ru>
>    crypto: nitrox - avoid double free on error path in nitrox_sriov_init()
> 
> Corentin Labbe <clabbe@baylibre.com>
>    crypto: sun8i-ss - use dma_addr instead u32
> 
> Weili Qian <qianweili@huawei.com>
>    crypto: hisilicon/qm - re-enable communicate interrupt before notifying PF
> 
> Weili Qian <qianweili@huawei.com>
>    crypto: hisilicon/qm - get hardware features from hardware registers
> 
> Weili Qian <qianweili@huawei.com>
>    crypto: hisilicon/qm - fix missing destroy qp_idr
> 
> John Johansen <john.johansen@canonical.com>
>    apparmor: Fix regression in stacking due to label flags
> 
> John Johansen <john.johansen@canonical.com>
>    apparmor: Fix abi check to include v8 abi
> 
> John Johansen <john.johansen@canonical.com>
>    apparmor: fix lockdep warning when removing a namespace
> 
> Gaosheng Cui <cuigaosheng1@huawei.com>
>    apparmor: fix a memleak in multi_transaction_new()
> 
> Vladimir Oltean <vladimir.oltean@nxp.com>
>    net: dsa: tag_8021q: avoid leaking ctx on dsa_tag_8021q_register() error path
> 
> Bartosz Staszewski <bartoszx.staszewski@intel.com>
>    i40e: Fix the inability to attach XDP program on downed interface
> 
> Piergiorgio Beruto <piergiorgio.beruto@gmail.com>
>    stmmac: fix potential division by 0
> 
> Yang Yingliang <yangyingliang@huawei.com>
>    Bluetooth: RFCOMM: don't call kfree_skb() under spin_lock_irqsave()
> 
> Yang Yingliang <yangyingliang@huawei.com>
>    Bluetooth: hci_core: don't call kfree_skb() under spin_lock_irqsave()
> 
> Yang Yingliang <yangyingliang@huawei.com>
>    Bluetooth: hci_bcsp: don't call kfree_skb() under spin_lock_irqsave()
> 
> Yang Yingliang <yangyingliang@huawei.com>
>    Bluetooth: hci_h5: don't call kfree_skb() under spin_lock_irqsave()
> 
> Yang Yingliang <yangyingliang@huawei.com>
>    Bluetooth: hci_ll: don't call kfree_skb() under spin_lock_irqsave()
> 
> Yang Yingliang <yangyingliang@huawei.com>
>    Bluetooth: hci_qca: don't call kfree_skb() under spin_lock_irqsave()
> 
> Yang Yingliang <yangyingliang@huawei.com>
>    Bluetooth: btusb: don't call kfree_skb() under spin_lock_irqsave()
> 
> Wang ShaoBo <bobo.shaobowang@huawei.com>
>    Bluetooth: btintel: Fix missing free skb in btintel_setup_combined()
> 
> Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
>    Bluetooth: hci_conn: Fix crash on hci_create_cis_sync
> 
> Christophe JAILLET <christophe.jaillet@wanadoo.fr>
>    Bluetooth: Fix EALREADY and ELOOP cases in bt_status()
> 
> Inga Stotland <inga.stotland@intel.com>
>    Bluetooth: MGMT: Fix error report for ADD_EXT_ADV_PARAMS
> 
> Yang Yingliang <yangyingliang@huawei.com>
>    Bluetooth: hci_core: fix error handling in hci_register_dev()
> 
> Firo Yang <firo.yang@suse.com>
>    sctp: sysctl: make extra pointers netns aware
> 
> Eric Pilmore <epilmore@gigaio.com>
>    ntb_netdev: Use dev_kfree_skb_any() in interrupt context
> 
> Jerry Ray <jerry.ray@microchip.com>
>    net: lan9303: Fix read error execution path
> 
> Roger Quadros <rogerq@kernel.org>
>    net: ethernet: ti: am65-cpsw: Fix PM runtime leakage in am65_cpsw_nuss_ndo_slave_open()
> 
> Markus Schneider-Pargmann <msp@baylibre.com>
>    can: tcan4x5x: Fix use of register error status mask
> 
> Vivek Yadav <vivek.2311@samsung.com>
>    can: m_can: Call the RAM init directly from m_can_chip_config
> 
> Markus Schneider-Pargmann <msp@baylibre.com>
>    can: tcan4x5x: Remove invalid write in clear_interrupts
> 
> Tom Lendacky <thomas.lendacky@amd.com>
>    net: amd-xgbe: Check only the minimum speed for active/passive cables
> 
> Tom Lendacky <thomas.lendacky@amd.com>
>    net: amd-xgbe: Fix logic around active and passive cables
> 
> Yang Yingliang <yangyingliang@huawei.com>
>    af_unix: call proto_unregister() in the error path in af_unix_init()
> 
> Richard Gobert <richardbgobert@gmail.com>
>    net: setsockopt: fix IPV6_UNICAST_IF option for connected sockets
> 
> Yang Yingliang <yangyingliang@huawei.com>
>    net: amd: lance: don't call dev_kfree_skb() under spin_lock_irqsave()
> 
> Yang Yingliang <yangyingliang@huawei.com>
>    hamradio: don't call dev_kfree_skb() under spin_lock_irqsave()
> 
> Yang Yingliang <yangyingliang@huawei.com>
>    net: ethernet: dnet: don't call dev_kfree_skb() under spin_lock_irqsave()
> 
> Yang Yingliang <yangyingliang@huawei.com>
>    net: emaclite: don't call dev_kfree_skb() under spin_lock_irqsave()
> 
> Yang Yingliang <yangyingliang@huawei.com>
>    net: apple: bmac: don't call dev_kfree_skb() under spin_lock_irqsave()
> 
> Yang Yingliang <yangyingliang@huawei.com>
>    net: apple: mace: don't call dev_kfree_skb() under spin_lock_irqsave()
> 
> Hangbin Liu <liuhangbin@gmail.com>
>    net/tunnel: wait until all sk_user_data reader finish before releasing the sock
> 
> Li Zetao <lizetao1@huawei.com>
>    net: farsync: Fix kmemleak when rmmods farsync
> 
> Yang Yingliang <yangyingliang@huawei.com>
>    ethernet: s2io: don't call dev_kfree_skb() under spin_lock_irqsave()
> 
> ruanjinjie <ruanjinjie@huawei.com>
>    of: overlay: fix null pointer dereferencing in find_dup_cset_node_entry() and find_dup_cset_prop()
> 
> Julian Anastasov <ja@ssi.bg>
>    ipvs: use u64_stats_t for the per-cpu counters
> 
> Thomas Gleixner <tglx@linutronix.de>
>    net: Remove the obsolte u64_stats_fetch_*_irq() users (net).
> 
> Yuan Can <yuancan@huawei.com>
>    drivers: net: qlcnic: Fix potential memory leak in qlcnic_sriov_init()
> 
> Gaosheng Cui <cuigaosheng1@huawei.com>
>    net: stmmac: fix possible memory leak in stmmac_dvr_probe()
> 
> Zhang Changzhong <zhangchangzhong@huawei.com>
>    net: stmmac: selftests: fix potential memleak in stmmac_test_arpoffload()
> 
> Yongqiang Liu <liuyongqiang13@huawei.com>
>    net: defxx: Fix missing err handling in dfx_init()
> 
> Artem Chernyshev <artem.chernyshev@red-soft.ru>
>    net: vmw_vsock: vmci: Check memcpy_from_msg()
> 
> Xiu Jianfeng <xiujianfeng@huawei.com>
>    clk: socfpga: Fix memory leak in socfpga_gate_init()
> 
> Björn Töpel <bjorn@rivosinc.com>
>    bpf: Do not zero-extend kfunc return values
> 
> Yang Jihong <yangjihong1@huawei.com>
>    blktrace: Fix output non-blktrace event when blk_classic option enabled
> 
> Wang Yufen <wangyufen@huawei.com>
>    wifi: brcmfmac: Fix error return code in brcmf_sdio_download_firmware()
> 
> Bitterblue Smith <rtl8821cerfe2@gmail.com>
>    wifi: rtl8xxxu: Fix the channel width reporting
> 
> Bitterblue Smith <rtl8821cerfe2@gmail.com>
>    wifi: rtl8xxxu: Add __packed to struct rtl8723bu_c2h
> 
> Kris Bahnsen <kris@embeddedTS.com>
>    spi: spi-gpio: Don't set MOSI as an input if not 3WIRE mode
> 
> Xiu Jianfeng <xiujianfeng@huawei.com>
>    clk: samsung: Fix memory leak in _samsung_clk_register_pll()
> 
> Geert Uytterhoeven <geert+renesas@glider.be>
>    media: staging: stkwebcam: Restore MEDIA_{USB,CAMERA}_SUPPORT dependencies
> 
> Jiasheng Jiang <jiasheng@iscas.ac.cn>
>    media: coda: Add check for kmalloc
> 
> Jiasheng Jiang <jiasheng@iscas.ac.cn>
>    media: coda: Add check for dcoda_iram_alloc
> 
> Liang He <windhl@126.com>
>    media: c8sectpfe: Add of_node_put() when breaking out of loop
> 
> Yuan Can <yuancan@huawei.com>
>    regulator: qcom-labibb: Fix missing of_node_put() in qcom_labibb_regulator_probe()
> 
> Zhen Lei <thunder.leizhen@huawei.com>
>    mmc: core: Normalize the error handling branch in sd_read_ext_regs()
> 
> Jiasheng Jiang <jiasheng@iscas.ac.cn>
>    memstick/ms_block: Add check for alloc_ordered_workqueue
> 
> Wolfram Sang <wsa+renesas@sang-engineering.com>
>    mmc: renesas_sdhi: alway populate SCC pointer
> 
> Yang Yingliang <yangyingliang@huawei.com>
>    mmc: mmci: fix return value check of mmc_add_host()
> 
> Yang Yingliang <yangyingliang@huawei.com>
>    mmc: wbsd: fix return value check of mmc_add_host()
> 
> Yang Yingliang <yangyingliang@huawei.com>
>    mmc: via-sdmmc: fix return value check of mmc_add_host()
> 
> Yang Yingliang <yangyingliang@huawei.com>
>    mmc: meson-gx: fix return value check of mmc_add_host()
> 
> Yang Yingliang <yangyingliang@huawei.com>
>    mmc: omap_hsmmc: fix return value check of mmc_add_host()
> 
> Yang Yingliang <yangyingliang@huawei.com>
>    mmc: atmel-mci: fix return value check of mmc_add_host()
> 
> Gabriel Somlo <gsomlo@gmail.com>
>    mmc: litex_mmc: ensure `host->irq == 0` if polling
> 
> Yang Yingliang <yangyingliang@huawei.com>
>    mmc: wmt-sdmmc: fix return value check of mmc_add_host()
> 
> Yang Yingliang <yangyingliang@huawei.com>
>    mmc: vub300: fix return value check of mmc_add_host()
> 
> Yang Yingliang <yangyingliang@huawei.com>
>    mmc: toshsd: fix return value check of mmc_add_host()
> 
> Yang Yingliang <yangyingliang@huawei.com>
>    mmc: rtsx_usb_sdmmc: fix return value check of mmc_add_host()
> 
> Yang Yingliang <yangyingliang@huawei.com>
>    mmc: rtsx_pci: fix return value check of mmc_add_host()
> 
> Yang Yingliang <yangyingliang@huawei.com>
>    mmc: pxamci: fix return value check of mmc_add_host()
> 
> Yang Yingliang <yangyingliang@huawei.com>
>    mmc: mxcmmc: fix return value check of mmc_add_host()
> 
> Yang Yingliang <yangyingliang@huawei.com>
>    mmc: moxart: fix return value check of mmc_add_host()
> 
> Yang Yingliang <yangyingliang@huawei.com>
>    mmc: alcor: fix return value check of mmc_add_host()
> 
> Miaoqian Lin <linmq006@gmail.com>
>    bpftool: Fix memory leak in do_build_table_cb
> 
> Pu Lehui <pulehui@huawei.com>
>    riscv, bpf: Emit fixed-length instructions for BPF_PSEUDO_FUNC
> 
> Trond Myklebust <trond.myklebust@hammerspace.com>
>    NFSv4.x: Fail client initialisation if state manager thread can't run
> 
> Anna Schumaker <Anna.Schumaker@Netapp.com>
>    NFS: Allow very small rsize & wsize again
> 
> Anna Schumaker <Anna.Schumaker@Netapp.com>
>    NFSv4.2: Set the correct size scratch buffer for decoding READ_PLUS
> 
> Wang ShaoBo <bobo.shaobowang@huawei.com>
>    SUNRPC: Fix missing release socket in rpc_sockname()
> 
> Zhang Xiaoxu <zhangxiaoxu5@huawei.com>
>    xprtrdma: Fix regbuf data not freed in rpcrdma_req_create()
> 
> Gaosheng Cui <cuigaosheng1@huawei.com>
>    pinctrl: thunderbay: fix possible memory leak in thunderbay_build_functions()
> 
> Gaosheng Cui <cuigaosheng1@huawei.com>
>    ALSA: mts64: fix possible null-ptr-defer in snd_mts64_interrupt
> 
> Guoniu.zhou <guoniu.zhou@nxp.com>
>    media: ov5640: set correct default link frequency
> 
> Liu Shixin <liushixin2@huawei.com>
>    media: saa7164: fix missing pci_disable_device()
> 
> Takashi Iwai <tiwai@suse.de>
>    ALSA: pcm: Set missing stop_operating flag at undoing trigger start
> 
> Eric Dumazet <edumazet@google.com>
>    bpf, sockmap: fix race in sock_map_free()
> 
> Martin Blumenstingl <martin.blumenstingl@googlemail.com>
>    hwmon: (jc42) Restore the min/max/critical temperatures on resume
> 
> Martin Blumenstingl <martin.blumenstingl@googlemail.com>
>    hwmon: (jc42) Convert register access and caching to regmap/regcache
> 
> Yang Yingliang <yangyingliang@huawei.com>
>    regulator: core: fix resource leak in regulator_register()
> 
> Chen Zhongjin <chenzhongjin@huawei.com>
>    configfs: fix possible memory leak in configfs_create_dir()
> 
> Sebastian Andrzej Siewior <bigeasy@linutronix.de>
>    hsr: Synchronize sequence number updates.
> 
> Sebastian Andrzej Siewior <bigeasy@linutronix.de>
>    hsr: Synchronize sending frames to have always incremented outgoing seq nr.
> 
> Sebastian Andrzej Siewior <bigeasy@linutronix.de>
>    hsr: Disable netpoll.
> 
> Sebastian Andrzej Siewior <bigeasy@linutronix.de>
>    hsr: Avoid double remove of a node.
> 
> Sebastian Andrzej Siewior <bigeasy@linutronix.de>
>    hsr: Add a rcu-read lock to hsr_forward_skb().
> 
> Sebastian Andrzej Siewior <bigeasy@linutronix.de>
>    Revert "net: hsr: use hlist_head instead of list_head for mac addresses"
> 
> Christian Marangi <ansuelsmth@gmail.com>
>    clk: qcom: clk-krait: fix wrong div2 functions
> 
> Douglas Anderson <dianders@chromium.org>
>    clk: qcom: lpass-sc7180: Fix pm_runtime usage
> 
> Douglas Anderson <dianders@chromium.org>
>    clk: qcom: lpass-sc7280: Fix pm_runtime usage
> 
> Taniya Das <quic_tdas@quicinc.com>
>    clk: qcom: lpass: Add support for resets & external mclk for SC7280
> 
> Taniya Das <quic_tdas@quicinc.com>
>    clk: qcom: lpass: Handle the regmap overlap of lpasscc and lpass_aon
> 
> Taniya Das <quic_tdas@quicinc.com>
>    dt-bindings: clock: Add support for external MCLKs for LPASS on SC7280
> 
> Taniya Das <quic_tdas@quicinc.com>
>    dt-bindings: clock: Add resets for LPASS audio clock controller for SC7280
> 
> Yang Yingliang <yangyingliang@huawei.com>
>    regulator: core: fix module refcount leak in set_supply()
> 
> Xiongfeng Wang <wangxiongfeng2@huawei.com>
>    mt76: mt7915: Fix PCI device refcount leak in mt7915_pci_init_hif2()
> 
> Deren Wu <deren.wu@mediatek.com>
>    wifi: mt76: fix coverity overrun-call in mt76_get_txpower()
> 
> Nicolas Cavallari <nicolas.cavallari@green-communications.fr>
>    wifi: mt76: mt7915: Fix chainmask calculation on mt7915 DBDC
> 
> Shayne Chen <shayne.chen@mediatek.com>
>    wifi: mt76: mt7915: rework eeprom tx paths and streams init
> 
> Lorenzo Bianconi <lorenzo@kernel.org>
>    wifi: mt76: mt7921: fix reporting of TX AGGR histogram
> 
> Lorenzo Bianconi <lorenzo@kernel.org>
>    wifi: mt76: mt7915: fix reporting of TX AGGR histogram
> 
> Ryder Lee <ryder.lee@mediatek.com>
>    wifi: mt76: mt7915: fix mt7915_mac_set_timing()
> 
> Sean Wang <sean.wang@mediatek.com>
>    wifi: mt76: mt7921: fix antenna signal are way off in monitor mode
> 
> Chen Zhongjin <chenzhongjin@huawei.com>
>    wifi: cfg80211: Fix not unregister reg_pdev when load_builtin_regdb_keys() fails
> 
> Íñigo Huguet <ihuguet@redhat.com>
>    wifi: mac80211: fix maybe-unused warning
> 
> Zhengchao Shao <shaozhengchao@huawei.com>
>    wifi: mac80211: fix memory leak in ieee80211_if_add()
> 
> Yuan Can <yuancan@huawei.com>
>    wifi: nl80211: Add checks for nla_nest_start() in nl80211_send_iface()
> 
> Alexander Sverdlin <alexander.sverdlin@siemens.com>
>    spi: spidev: mask SPI_CS_HIGH in SPI_IOC_RD_MODE
> 
> Dan Carpenter <error27@gmail.com>
>    bonding: uninitialized variable in bond_miimon_inspect()
> 
> Pengcheng Yang <yangpc@wangsu.com>
>    bpf, sockmap: Fix data loss caused by using apply_bytes on ingress redirect
> 
> Pengcheng Yang <yangpc@wangsu.com>
>    bpf, sockmap: Fix missing BPF_F_INGRESS flag when using apply_bytes
> 
> Pengcheng Yang <yangpc@wangsu.com>
>    bpf, sockmap: Fix repeated calls to sock_put() when msg has more_data
> 
> Randy Dunlap <rdunlap@infradead.org>
>    Input: wistron_btns - disable on UML
> 
> Florian Westphal <fw@strlen.de>
>    netfilter: conntrack: set icmpv6 redirects as RELATED
> 
> Xiu Jianfeng <xiujianfeng@huawei.com>
>    clk: visconti: Fix memory leak in visconti_register_pll()
> 
> Zhang Qilong <zhangqilong3@huawei.com>
>    ASoC: pcm512x: Fix PM disable depth imbalance in pcm512x_probe
> 
> Xia Fukun <xiafukun@huawei.com>
>    drm/i915/bios: fix a memory leak in generate_lfp_data_ptrs
> 
> Konstantin Meskhidze <konstantin.meskhidze@huawei.com>
>    drm/amdkfd: Fix memory leakage
> 
> Xiongfeng Wang <wangxiongfeng2@huawei.com>
>    drm/amdgpu: Fix PCI device refcount leak in amdgpu_atrm_get_bios()
> 
> Xiongfeng Wang <wangxiongfeng2@huawei.com>
>    drm/radeon: Fix PCI device refcount leak in radeon_atrm_get_bios()
> 
> Veerabadhran Gopalakrishnan <veerabadhran.gopalakrishnan@amd.com>
>    amdgpu/nv.c: Corrected typo in the video capabilities resolution
> 
> Guchun Chen <guchun.chen@amd.com>
>    drm/amd/pm/smu11: BACO is supported when it's in BACO state
> 
> Daniel Golle <daniel@makrotopia.org>
>    clk: mediatek: fix dependency of MT7986 ADC clocks
> 
> Ricardo Ribalda <ribalda@chromium.org>
>    ASoC: mediatek: mt8173: Enable IRQ when pdata is ready
> 
> zhichao.liu <zhichao.liu@mediatek.com>
>    spi: mt65xx: Add dma max segment size declaration
> 
> Ben Greear <greearb@candelatech.com>
>    wifi: iwlwifi: mvm: fix double free on tx path.
> 
> Bitterblue Smith <rtl8821cerfe2@gmail.com>
>    wifi: rtl8xxxu: Fix use after rcu_read_unlock in rtl8xxxu_bss_info_changed
> 
> Ziyang Xuan <william.xuanziyang@huawei.com>
>    wifi: plfxlc: fix potential memory leak in __lf_x_usb_enable_rx()
> 
> Liu Shixin <liushixin2@huawei.com>
>    ALSA: asihpi: fix missing pci_disable_device()
> 
> Trond Myklebust <trond.myklebust@hammerspace.com>
>    NFS: Fix an Oops in nfs_d_automount()
> 
> Trond Myklebust <trond.myklebust@hammerspace.com>
>    NFSv4: Fix a deadlock between nfs4_open_recover_helper() and delegreturn
> 
> Trond Myklebust <trond.myklebust@hammerspace.com>
>    NFSv4: Fix a credential leak in _nfs4_discover_trunking()
> 
> Trond Myklebust <trond.myklebust@hammerspace.com>
>    NFSv4.2: Fix initialisation of struct nfs4_label
> 
> Trond Myklebust <trond.myklebust@hammerspace.com>
>    NFSv4.2: Fix a memory stomp in decode_attr_security_label
> 
> Trond Myklebust <trond.myklebust@hammerspace.com>
>    NFSv4.2: Always decode the security label
> 
> Trond Myklebust <trond.myklebust@hammerspace.com>
>    NFSv4.2: Clear FATTR4_WORD2_SECURITY_LABEL when done decoding
> 
> Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
>    drm/msm/mdp5: fix reading hw revision on db410c platform
> 
> Jiasheng Jiang <jiasheng@iscas.ac.cn>
>    ASoC: mediatek: mtk-btcvsd: Add checks for write and read of mtk_btcvsd_snd
> 
> Dmitry Torokhov <dmitry.torokhov@gmail.com>
>    ASoC: dt-bindings: wcd9335: fix reset line polarity in example
> 
> Zhang Zekun <zhangzekun11@huawei.com>
>    drm/tegra: Add missing clk_disable_unprepare() in tegra_dc_probe()
> 
> Aakarsh Jain <aakarsh.jain@samsung.com>
>    media: s5p-mfc: Add variant data for MFC v7 hardware for Exynos 3250 SoC
> 
> Yunfei Dong <yunfei.dong@mediatek.com>
>    media: mediatek: vcodec: Core thread depends on core_list
> 
> Yunfei Dong <yunfei.dong@mediatek.com>
>    media: mediatek: vcodec: Setting lat buf to lat_list when lat decode error
> 
> Yunfei Dong <yunfei.dong@mediatek.com>
>    media: mediatek: vcodec: Fix h264 set lat buffer error
> 
> Yunfei Dong <yunfei.dong@mediatek.com>
>    media: mediatek: vcodec: Fix getting NULL pointer for dst buffer
> 
> Ming Qian <ming.qian@nxp.com>
>    media: amphion: lock and check m2m_ctx in event handler
> 
> Ming Qian <ming.qian@nxp.com>
>    media: amphion: cancel vpu before release instance
> 
> Ming Qian <ming.qian@nxp.com>
>    media: amphion: try to wakeup vpu core to avoid failure
> 
> Paul Kocialkowski <paul.kocialkowski@bootlin.com>
>    media: sun8i-a83t-mipi-csi2: Register async subdev with no sensor attached
> 
> Paul Kocialkowski <paul.kocialkowski@bootlin.com>
>    media: sun6i-mipi-csi2: Register async subdev with no sensor attached
> 
> Paul Kocialkowski <paul.kocialkowski@bootlin.com>
>    media: sun8i-a83t-mipi-csi2: Require both pads to be connected for streaming
> 
> Paul Kocialkowski <paul.kocialkowski@bootlin.com>
>    media: sun6i-mipi-csi2: Require both pads to be connected for streaming
> 
> Juergen Gross <jgross@suse.com>
>    x86/boot: Skip realmode init code when running as Xen PV guest
> 
> Baisong Zhong <zhongbaisong@huawei.com>
>    media: dvb-usb: az6027: fix null-ptr-deref in az6027_i2c_xfer()
> 
> Chen Zhongjin <chenzhongjin@huawei.com>
>    media: dvb-core: Fix ignored return value in dvb_register_frontend()
> 
> ZhangPeng <zhangpeng362@huawei.com>
>    pinctrl: pinconf-generic: add missing of_node_put()
> 
> Dario Binacchi <dario.binacchi@amarulasolutions.com>
>    clk: imx8mn: fix imx8mn_enet_phy_sels clocks list
> 
> Dario Binacchi <dario.binacchi@amarulasolutions.com>
>    clk: imx8mn: fix imx8mn_sai2_sels clocks list
> 
> Dario Binacchi <dario.binacchi@amarulasolutions.com>
>    clk: imx: rename video_pll1 to video_pll
> 
> Dario Binacchi <dario.binacchi@amarulasolutions.com>
>    clk: imx: replace osc_hdmi with dummy
> 
> Dario Binacchi <dario.binacchi@amarulasolutions.com>
>    clk: imx8mn: rename vpu_pll to m7_alt_pll
> 
> Marek Vasut <marex@denx.de>
>    media: mt9p031: Drop bogus v4l2_subdev_get_try_crop() call from mt9p031_init_cfg()
> 
> Laurent Pinchart <laurent.pinchart@ideasonboard.com>
>    media: imx: imx7-media-csi: Clear BIT_MIPI_DOUBLE_CMPNT for <16b formats
> 
> Gautam Menghani <gautammenghani201@gmail.com>
>    media: imon: fix a race condition in send_packet()
> 
> Chen Zhongjin <chenzhongjin@huawei.com>
>    media: vimc: Fix wrong function called when vimc_init() fails
> 
> Yuan Can <yuancan@huawei.com>
>    ASoC: qcom: Add checks for devm_kcalloc
> 
> Wang ShaoBo <bobo.shaobowang@huawei.com>
>    drbd: destroy workqueue when drbd device was freed
> 
> Wang ShaoBo <bobo.shaobowang@huawei.com>
>    drbd: remove call to memset before free device/resource/connection
> 
> Zheng Yongjun <zhengyongjun3@huawei.com>
>    mtd: maps: pxa2xx-flash: fix memory leak in probe
> 
> Shang XiaoJing <shangxiaojing@huawei.com>
>    mtd: core: Fix refcount error in del_mtd_device()
> 
> Jonathan Toppins <jtoppins@redhat.com>
>    bonding: fix link recovery in mode 2 when updelay is nonzero
> 
> Stanislav Fomichev <sdf@google.com>
>    selftests/bpf: Mount debugfs in setns_by_fd
> 
> Stanislav Fomichev <sdf@google.com>
>    selftests/bpf: Make sure zero-len skbs aren't redirectable
> 
> Jani Nikula <jani.nikula@intel.com>
>    drm/i915/guc: make default_lists const data
> 
> Yang Yingliang <yangyingliang@huawei.com>
>    drm/amdgpu: fix pci device refcount leak
> 
> Xiu Jianfeng <xiujianfeng@huawei.com>
>    clk: rockchip: Fix memory leak in rockchip_clk_register_pll()
> 
> Wang ShaoBo <bobo.shaobowang@huawei.com>
>    regulator: core: use kfree_const() to free space conditionally
> 
> Baisong Zhong <zhongbaisong@huawei.com>
>    ALSA: seq: fix undefined behavior in bit shift for SNDRV_SEQ_FILTER_USE_EVENT
> 
> Baisong Zhong <zhongbaisong@huawei.com>
>    ALSA: pcm: fix undefined behavior in bit shift for SNDRV_PCM_RATE_KNOT
> 
> Cezary Rojewski <cezary.rojewski@intel.com>
>    ASoC: Intel: avs: Lock substream before snd_pcm_stop()
> 
> Zong-Zhe Yang <kevin_yang@realtek.com>
>    wifi: rtw89: fix physts IE page check
> 
> ZhangPeng <zhangpeng362@huawei.com>
>    pinctrl: k210: call of_node_put()
> 
> Giulio Benetti <giulio.benetti@benettiengineering.com>
>    clk: imx: imxrt1050: fix IMXRT1050_CLK_LCDIF_APB offsets
> 
> Marcus Folkesson <marcus.folkesson@gmail.com>
>    HID: hid-sensor-custom: set fixed size for custom attributes
> 
> Stanislav Fomichev <sdf@google.com>
>    bpf: Move skb->len == 0 checks into __bpf_redirect
> 
> Peng Fan <peng.fan@nxp.com>
>    clk: imx93: correct enet clock
> 
> Peng Fan <peng.fan@nxp.com>
>    clk: imx93: unmap anatop base in error handling path
> 
> Dmitry Torokhov <dmitry.torokhov@gmail.com>
>    HID: i2c: let RMI devices decide what constitutes wakeup event
> 
> Haibo Chen <haibo.chen@nxp.com>
>    clk: imx93: correct the flexspi1 clock setting
> 
> Allen-KH Cheng <allen-kh.cheng@mediatek.com>
>    mtd: spi-nor: Fix the number of bytes for the dummy cycles
> 
> Michael Walle <michael@walle.cc>
>    mtd: spi-nor: hide jedec_id sysfs attribute if not present
> 
> Kuniyuki Iwashima <kuniyu@amazon.com>
>    net: Return errno in sk->sk_prot->get_port().
> 
> Kuniyuki Iwashima <kuniyu@amazon.com>
>    udp: Clean up some functions.
> 
> Lorenzo Bianconi <lorenzo@kernel.org>
>    net: ethernet: mtk_eth_soc: fix RSTCTRL_PPE{0,1} definitions
> 
> Christoph Hellwig <hch@lst.de>
>    media: videobuf-dma-contig: use dma_mmap_coherent
> 
> Yuan Can <yuancan@huawei.com>
>    media: amphion: Fix error handling in vpu_driver_init()
> 
> Yuan Can <yuancan@huawei.com>
>    media: platform: exynos4-is: Fix error handling in fimc_md_init()
> 
> Yang Yingliang <yangyingliang@huawei.com>
>    media: solo6x10: fix possible memory leak in solo_sysfs_init()
> 
> Chen Zhongjin <chenzhongjin@huawei.com>
>    media: vidtv: Fix use-after-free in vidtv_bridge_dvb_init()
> 
> Ming Qian <ming.qian@nxp.com>
>    media: amphion: apply vb2_queue_error instead of setting manually
> 
> Ming Qian <ming.qian@nxp.com>
>    media: amphion: add lock around vdec_g_fmt
> 
> Lorenzo Bianconi <lorenzo@kernel.org>
>    net: ethernet: mtk_eth_soc: do not overwrite mtu configuration running reset routine
> 
> Douglas Anderson <dianders@chromium.org>
>    Input: elants_i2c - properly handle the reset GPIO when power is off
> 
> Hui Tang <tanghui20@huawei.com>
>    mtd: lpddr2_nvm: Fix possible null-ptr-deref
> 
> Rob Clark <robdclark@chromium.org>
>    drm/msm/a6xx: Fix speed-bin detection vs probe-defer
> 
> Xiu Jianfeng <xiujianfeng@huawei.com>
>    wifi: ath10k: Fix return value in ath10k_pci_init()
> 
> Wang Yufen <wangyufen@huawei.com>
>    selftests/bpf: fix memory leak of lsm_cgroup
> 
> Christoph Hellwig <hch@lst.de>
>    dm: track per-add_disk holder relations in DM
> 
> Yu Kuai <yukuai3@huawei.com>
>    dm: make sure create and remove dm device won't race with open and close table
> 
> Christoph Hellwig <hch@lst.de>
>    dm: cleanup close_table_device
> 
> Christoph Hellwig <hch@lst.de>
>    dm: cleanup open_table_device
> 
> Christoph Hellwig <hch@lst.de>
>    block: clear ->slave_dir when dropping the main slave_dir reference
> 
> Xiu Jianfeng <xiujianfeng@huawei.com>
>    ima: Fix misuse of dereference of pointer in template_desc_init_fields()
> 
> GUO Zihua <guozihua@huawei.com>
>    integrity: Fix memory leakage in keyring allocation error path
> 
> Brian Starkey <brian.starkey@arm.com>
>    drm/fourcc: Fix vsub/hsub for Q410 and Q401
> 
> Konrad Dybcio <konrad.dybcio@linaro.org>
>    regulator: qcom-rpmh: Fix PMR735a S3 regulator spec
> 
> Christophe JAILLET <christophe.jaillet@wanadoo.fr>
>    wifi: rtw89: Fix some error handling path in rtw89_core_sta_assoc()
> 
> Joel Granados <j.granados@samsung.com>
>    nvme: return err on nvme_init_non_mdts_limits fail
> 
> Dan Carpenter <error27@gmail.com>
>    amdgpu/pm: prevent array underflow in vega20_odn_edit_dpm_table()
> 
> Yang Yingliang <yangyingliang@huawei.com>
>    regulator: core: fix unbalanced of node refcount in regulator_dev_lookup()
> 
> Christoph Hellwig <hch@lst.de>
>    nvmet: only allocate a single slab for bvecs
> 
> Zeng Heng <zengheng4@huawei.com>
>    ASoC: pxa: fix null-pointer dereference in filter()
> 
> Xinlei Lee <xinlei.lee@mediatek.com>
>    drm/mediatek: Modify dpi power on/off sequence.
> 
> Yang Jihong <yangjihong1@huawei.com>
>    selftests/bpf: Fix xdp_synproxy compilation failure in 32-bit arch
> 
> Randy Dunlap <rdunlap@infradead.org>
>    ASoC: codecs: wsa883x: use correct header file
> 
> Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
>    ASoC: codecs: wsa883x: Use proper shutdown GPIO polarity
> 
> Miaoqian Lin <linmq006@gmail.com>
>    module: Fix NULL vs IS_ERR checking for module_get_next_page
> 
> Johannes Berg <johannes.berg@intel.com>
>    wifi: iwlwifi: mei: fix potential NULL-ptr deref after clone
> 
> Avraham Stern <avraham.stern@intel.com>
>    wifi: iwlwifi: mei: avoid blocking sap messages handling due to rtnl lock
> 
> Emmanuel Grumbach <emmanuel.grumbach@intel.com>
>    wifi: iwlwifi: mei: fix tx DHCP packet for devices with new Tx API
> 
> Emmanuel Grumbach <emmanuel.grumbach@intel.com>
>    wifi: iwlwifi: mei: don't send SAP commands if AMT is disabled
> 
> Avraham Stern <avraham.stern@intel.com>
>    wifi: iwlwifi: mei: make sure ownership confirmed message is sent
> 
> Sam Shih <sam.shih@mediatek.com>
>    pinctrl: mediatek: fix the pinconf register offset of some pins
> 
> Frank Wunderlich <frank-w@public-files.de>
>    dt-bindings: pinctrl: update uart/mmc bindings for MT7986 SoC
> 
> Hanjun Guo <guohanjun@huawei.com>
>    drm/radeon: Add the missed acpi_put_table() to fix memory leak
> 
> Khazhismel Kumykov <khazhy@chromium.org>
>    bfq: fix waker_bfqq inconsistency crash
> 
> Christoph Böhmwalder <christoph.boehmwalder@linbit.com>
>    drbd: use blk_queue_max_discard_sectors helper
> 
> Yassine Oudjana <y.oudjana@protonmail.com>
>    regmap-irq: Use the new num_config_regs property in regmap_add_irq_chip_fwnode
> 
> Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
>    drm: rcar-du: Drop leftovers dependencies from Kconfig
> 
> Ping-Ke Shih <pkshih@realtek.com>
>    wifi: rtw89: use u32_encode_bits() to fill MAC quota value
> 
> Marek Vasut <marex@denx.de>
>    drm: lcdif: Set and enable FIFO Panic threshold
> 
> David Howells <dhowells@redhat.com>
>    rxrpc: Fix ack.bufferSize to be 0 when generating an ack
> 
> David Howells <dhowells@redhat.com>
>    net, proc: Provide PROC_FS=n fallback for proc_create_net_single_write()
> 
> Cole Robinson <crobinso@redhat.com>
>    virt/sev-guest: Add a MODULE_ALIAS
> 
> Wolfram Sang <wsa+renesas@sang-engineering.com>
>    clk: renesas: r8a779f0: Fix SCIF parent clocks
> 
> Wolfram Sang <wsa+renesas@sang-engineering.com>
>    clk: renesas: r8a779f0: Fix HSCIF parent clocks
> 
> Vladimir Zapolskiy <vladimir.zapolskiy@linaro.org>
>    media: camss: Do not attach an already attached power domain on MSM8916 platform
> 
> Vladimir Zapolskiy <vladimir.zapolskiy@linaro.org>
>    media: camss: Clean up received buffers on failed start of streaming
> 
> Marek Vasut <marex@denx.de>
>    wifi: rsi: Fix handling of 802.3 EAPOL frames sent via control port
> 
> Randy Dunlap <rdunlap@infradead.org>
>    Input: joystick - fix Kconfig warning for JOYSTICK_ADC
> 
> Gaosheng Cui <cuigaosheng1@huawei.com>
>    mtd: core: fix possible resource leak in init_mtd()
> 
> Zhang Xiaoxu <zhangxiaoxu5@huawei.com>
>    mtd: Fix device name leak when register device failed in add_mtd_device()
> 
> Manivannan Sadhasivam <mani@kernel.org>
>    clk: qcom: gcc-sm8250: Use retention mode for USB GDSCs
> 
> Konrad Dybcio <konrad.dybcio@somainline.org>
>    clk: qcom: dispcc-sm6350: Add CLK_OPS_PARENT_ENABLE to pixel&byte src
> 
> Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
>    clk: qcom: gcc-ipq806x: use parent_data for the last remaining entry
> 
> Andrii Nakryiko <andrii@kernel.org>
>    bpf: propagate precision across all frames, not just the last one
> 
> Andrii Nakryiko <andrii@kernel.org>
>    bpf: propagate precision in ALU/ALU64 operations
> 
> Yang Yingliang <yangyingliang@huawei.com>
>    media: platform: exynos4-is: fix return value check in fimc_md_probe()
> 
> Liu Shixin <liushixin2@huawei.com>
>    media: vivid: fix compose size exceed boundary
> 
> Andrzej Pietrasiewicz <andrzej.p@collabora.com>
>    media: rkvdec: Add required padding
> 
> Marijn Suijten <marijn.suijten@somainline.org>
>    drm/msm/dsi: Prevent signed BPG offsets from bleeding into adjacent bits
> 
> Marijn Suijten <marijn.suijten@somainline.org>
>    drm/msm/dsi: Disallow 8 BPC DSC configuration for alternative BPC values
> 
> Marijn Suijten <marijn.suijten@somainline.org>
>    drm/msm/dsi: Account for DSC's bits_per_pixel having 4 fractional bits
> 
> Marijn Suijten <marijn.suijten@somainline.org>
>    drm/msm/dsi: Migrate to drm_dsc_compute_rc_parameters()
> 
> Marijn Suijten <marijn.suijten@somainline.org>
>    drm/msm/dsi: Appropriately set dsc->mux_word_size based on bpc
> 
> Marijn Suijten <marijn.suijten@somainline.org>
>    drm/msm/dsi: Reuse earlier computed dsc->slice_chunk_size
> 
> Marijn Suijten <marijn.suijten@somainline.org>
>    drm/msm/dsi: Use DIV_ROUND_UP instead of conditional increment on modulo
> 
> Marijn Suijten <marijn.suijten@somainline.org>
>    drm/msm/dsi: Remove repeated calculation of slice_per_intf
> 
> Marijn Suijten <marijn.suijten@somainline.org>
>    drm/msm/dsi: Remove useless math in DSC calculations
> 
> Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
>    drm/msm/dsi: use drm_dsc_config instead of msm_display_dsc_config
> 
> Marijn Suijten <marijn.suijten@somainline.org>
>    drm/msm/dpu1: Account for DSC's bits_per_pixel having 4 fractional bits
> 
> Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
>    drm/msm/dpu: use drm_dsc_config instead of msm_display_dsc_config
> 
> Kumar Kartikeya Dwivedi <memxor@gmail.com>
>    bpf: Fix slot type check in check_stack_write_var_off
> 
> Kumar Kartikeya Dwivedi <memxor@gmail.com>
>    bpf: Clobber stack slot when writing over spilled PTR_TO_BTF_ID
> 
> Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
>    drm/msm/hdmi: use devres helper for runtime PM management
> 
> GUO Zihua <guozihua@huawei.com>
>    ima: Handle -ESTALE returned by ima_filter_rule_match()
> 
> Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
>    drm/msm/mdp5: stop overriding drvdata
> 
> Gaosheng Cui <cuigaosheng1@huawei.com>
>    drm/ttm: fix undefined behavior in bit shift for TTM_TT_FLAG_PRIV_POPULATED
> 
> Marek Vasut <marex@denx.de>
>    drm/panel/panel-sitronix-st7701: Remove panel on DSI attach failure
> 
> Jonathan Neuschäfer <j.neuschaefer@gmx.net>
>    spi: Update reference to struct spi_controller
> 
> Marco Felsch <m.felsch@pengutronix.de>
>    drm: lcdif: change burst size to 256B
> 
> Marek Vasut <marex@denx.de>
>    clk: renesas: r9a06g032: Repair grave increment error
> 
> Zhang Qilong <zhangqilong3@huawei.com>
>    drm/rockchip: lvds: fix PM usage counter unbalance in poweron
> 
> Haiyi Zhou <Haiyi.Zhou@amd.com>
>    drm/amd/display: wait for vblank during pipe programming
> 
> Sakari Ailus <sakari.ailus@linux.intel.com>
>    dw9768: Enable low-power probe on ACPI
> 
> Alan Previn <alan.previn.teres.alexis@intel.com>
>    drm/i915/guc: Fix GuC error capture sizing estimation and reporting
> 
> Alan Previn <alan.previn.teres.alexis@intel.com>
>    drm/i915/guc: Add error-capture init warnings when needed
> 
> John Harrison <John.C.Harrison@Intel.com>
>    drm/i915/guc: Make GuC log sizes runtime configurable
> 
> John Harrison <John.C.Harrison@Intel.com>
>    drm/i915/guc: Fix capture size warning and bump the size
> 
> Alan Previn <alan.previn.teres.alexis@intel.com>
>    drm/i915/guc: Add a helper for log buffer size
> 
> Nícolas F. R. A. Prado <nfraprado@collabora.com>
>    ASoC: dt-bindings: rt5682: Set sound-dai-cells to 1
> 
> Wolfram Sang <wsa+renesas@sang-engineering.com>
>    clk: renesas: r8a779a0: Fix SD0H clock name
> 
> Jimmy Assarsson <extja@kvaser.com>
>    can: kvaser_usb: Compare requested bittiming parameters with actual parameters in do_set_{,data}_bittiming
> 
> Jimmy Assarsson <extja@kvaser.com>
>    can: kvaser_usb: Add struct kvaser_usb_busparams
> 
> Anssi Hannula <anssi.hannula@bitwise.fi>
>    can: kvaser_usb_leaf: Fix bogus restart events
> 
> Anssi Hannula <anssi.hannula@bitwise.fi>
>    can: kvaser_usb_leaf: Fix wrong CAN state after stopping
> 
> Anssi Hannula <anssi.hannula@bitwise.fi>
>    can: kvaser_usb_leaf: Fix improved state not being reported
> 
> Anssi Hannula <anssi.hannula@bitwise.fi>
>    can: kvaser_usb_leaf: Set Warning state even without bus errors
> 
> Jimmy Assarsson <extja@kvaser.com>
>    can: kvaser_usb: kvaser_usb_leaf: Handle CMD_ERROR_EVENT
> 
> Jimmy Assarsson <extja@kvaser.com>
>    can: kvaser_usb: kvaser_usb_leaf: Rename {leaf,usbcan}_cmd_error_event to {leaf,usbcan}_cmd_can_error_event
> 
> Jimmy Assarsson <extja@kvaser.com>
>    can: kvaser_usb: kvaser_usb_leaf: Get capabilities from device
> 
> Alan Maguire <alan.maguire@oracle.com>
>    libbpf: Btf dedup identical struct test needs check for nested structs/arrays
> 
> Marek Szyprowski <m.szyprowski@samsung.com>
>    media: exynos4-is: don't rely on the v4l2_async_subdev internals
> 
> Rafael Mendonca <rafaelmendsr@gmail.com>
>    media: i2c: ov5648: Free V4L2 fwnode data on unbind
> 
> Kuniyuki Iwashima <kuniyu@amazon.com>
>    soreuseport: Fix socket selection for SO_INCOMING_CPU.
> 
> Tang Bin <tangbin@cmss.chinamobile.com>
>    venus: pm_helpers: Fix error check in vcodec_domains_get()
> 
> Ricardo Ribalda <ribalda@chromium.org>
>    media: i2c: ad5820: Fix error path
> 
> Rafael Mendonca <rafaelmendsr@gmail.com>
>    media: i2c: hi846: Fix memory leak in hi846_parse_dt()
> 
> John Harrison <John.C.Harrison@Intel.com>
>    drm/i915: Fix compute pre-emption w/a to apply to compute engines
> 
> John Harrison <John.C.Harrison@Intel.com>
>    drm/i915/guc: Limit scheduling properties to avoid overflow
> 
> Yunfei Dong <yunfei.dong@mediatek.com>
>    media: mediatek: vcodec: fix h264 cavlc bitstream fail
> 
> Jernej Skrabec <jernej.skrabec@gmail.com>
>    media: cedrus: hevc: Fix offset adjustments
> 
> Jernej Skrabec <jernej.skrabec@gmail.com>
>    media: v4l2-ioctl.c: Unify YCbCr/YUV terms in format descriptions
> 
> Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
>    media: adv748x: afe: Select input port when initializing AFE
> 
> Ming Qian <ming.qian@nxp.com>
>    media: amphion: reset instance if it's aborted before codec header parsed
> 
> Jiasheng Jiang <jiasheng@iscas.ac.cn>
>    media: coda: jpeg: Add check for kmalloc
> 
> Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
>    media: v4l2-ctrls: Fix off-by-one error in integer menu control check
> 
> Jeff LaBundy <jeff@labundy.com>
>    Input: iqs7222 - protect against undefined slider size
> 
> Jeff LaBundy <jeff@labundy.com>
>    Input: iqs7222 - report malformed properties
> 
> Jeff LaBundy <jeff@labundy.com>
>    Input: iqs7222 - drop unused device node references
> 
> Jeff LaBundy <jeff@labundy.com>
>    Input: iqs7222 - set all ULP entry masks by default
> 
> Pin-yen Lin <treapking@chromium.org>
>    drm/bridge: it6505: Initialize AUX channel in it6505_i2c_probe
> 
> Gerhard Engleder <gerhard@engleder-embedded.com>
>    samples/bpf: Fix MAC address swapping in xdp2_kern
> 
> Gerhard Engleder <gerhard@engleder-embedded.com>
>    samples/bpf: Fix map iteration in xdp1_user
> 
> Rafael Mendonca <rafaelmendsr@gmail.com>
>    drm/amdgpu/powerplay/psm: Fix memory leak in power state init
> 
> Andrew Jeffery <andrew@aj.id.au>
>    ipmi: kcs: Poll OBF briefly to reduce OBE latency
> 
> Cezary Rojewski <cezary.rojewski@intel.com>
>    ASoC: Intel: avs: Fix potential RX buffer overflow
> 
> Cezary Rojewski <cezary.rojewski@intel.com>
>    ASoC: Intel: avs: Fix DMA mask assignment
> 
> Yang Yingliang <yangyingliang@huawei.com>
>    pinctrl: ocelot: add missing destroy_workqueue() in error path in ocelot_pinctrl_probe()
> 
> Niklas Cassel <niklas.cassel@wdc.com>
>    ata: libata: fix NCQ autosense logic
> 
> Laurent Pinchart <laurent.pinchart@ideasonboard.com>
>    drm: lcdif: Switch to limited range for RGB to YUV conversion
> 
> Shung-Hsi Yu <shung-hsi.yu@suse.com>
>    libbpf: Fix null-pointer dereference in find_prog_by_sec_insn()
> 
> Shung-Hsi Yu <shung-hsi.yu@suse.com>
>    libbpf: Deal with section with no data gracefully
> 
> Shung-Hsi Yu <shung-hsi.yu@suse.com>
>    libbpf: Use elf_getshdrnum() instead of e_shnum
> 
> Andrii Nakryiko <andrii@kernel.org>
>    libbpf: Reject legacy 'maps' ELF section
> 
> Xu Kuohai <xukuohai@huawei.com>
>    selftest/bpf: Fix error usage of ASSERT_OK in xdp_adjust_tail.c
> 
> Xu Kuohai <xukuohai@huawei.com>
>    selftests/bpf: Fix error failure of case test_xdp_adjust_tail_grow
> 
> Xu Kuohai <xukuohai@huawei.com>
>    selftest/bpf: Fix memory leak in kprobe_multi_test
> 
> Xu Kuohai <xukuohai@huawei.com>
>    selftests/bpf: Fix memory leak caused by not destroying skeleton
> 
> Yonghong Song <yhs@fb.com>
>    selftests/bpf: Add struct argument tests with fentry/fexit programs.
> 
> Xu Kuohai <xukuohai@huawei.com>
>    libbpf: Fix memory leak in parse_usdt_arg()
> 
> Xu Kuohai <xukuohai@huawei.com>
>    libbpf: Fix use-after-free in btf_dump_name_dups
> 
> Abhinav Kumar <quic_abhinavk@quicinc.com>
>    drm/bridge: adv7533: remove dynamic lane switching from adv7533 bridge
> 
> Aditya Kumar Singh <quic_adisi@quicinc.com>
>    wifi: ath11k: fix firmware assert during bandwidth change for peer sta
> 
> Aditya Kumar Singh <quic_adisi@quicinc.com>
>    wifi: ath11k: move firmware stats out of debugfs
> 
> Bitterblue Smith <rtl8821cerfe2@gmail.com>
>    wifi: rtl8xxxu: Fix reading the vendor of combo chips
> 
> Fedor Pchelkin <pchelkin@ispras.ru>
>    wifi: ath9k: hif_usb: Fix use-after-free in ath9k_hif_usb_reg_in_cb()
> 
> Fedor Pchelkin <pchelkin@ispras.ru>
>    wifi: ath9k: hif_usb: fix memory leak of urbs in ath9k_hif_usb_dealloc_tx_urbs()
> 
> Thomas Zimmermann <tzimmermann@suse.de>
>    drm/atomic-helper: Don't allocate new plane state in CRTC check
> 
> Johannes Berg <johannes.berg@intel.com>
>    wifi: mac80211: fix ifdef symbol name
> 
> Johannes Berg <johannes.berg@intel.com>
>    wifi: mac80211: check link ID in auth/assoc continuation
> 
> Johannes Berg <johannes.berg@intel.com>
>    wifi: mac80211: mlme: fix null-ptr deref on failed assoc
> 
> Johannes Berg <johannes.berg@intel.com>
>    wifi: fix multi-link element subelement iteration
> 
> James Hurley <jahurley@nvidia.com>
>    platform/mellanox: mlxbf-pmc: Fix event typo
> 
> Zhengchao Shao <shaozhengchao@huawei.com>
>    ipc: fix memory leak in init_mqueue_fs()
> 
> Cai Xinchen <caixinchen1@huawei.com>
>    rapidio: devices: fix missing put_device in mport_cdev_open
> 
> ZhangPeng <zhangpeng362@huawei.com>
>    hfs: Fix OOB Write in hfs_asc2mac
> 
> Gavrilov Ilia <Ilia.Gavrilov@infotecs.ru>
>    relay: fix type mismatch when allocating memory in relay_create_buf()
> 
> Zhang Qilong <zhangqilong3@huawei.com>
>    eventfd: change int to __u64 in eventfd_signal() ifndef CONFIG_EVENTFD
> 
> Wang Weiyang <wangweiyang2@huawei.com>
>    rapidio: fix possible UAF when kfifo_alloc() fails
> 
> Chen Zhongjin <chenzhongjin@huawei.com>
>    fs: sysv: Fix sysv_nblocks() returns wrong value
> 
> Brian Foster <bfoster@redhat.com>
>    NFSD: pass range end to vfs_fsync_range() instead of count
> 
> Jeff Layton <jlayton@kernel.org>
>    nfsd: return error if nfs4_setacl fails
> 
> Trond Myklebust <trond.myklebust@hammerspace.com>
>    lockd: set other missing fields when unlocking files
> 
> Ladislav Michl <ladis@linux-mips.org>
>    MIPS: OCTEON: warn only once if deprecated link status is being used
> 
> Anastasia Belova <abelova@astralinux.ru>
>    MIPS: BCM63xx: Add check for NULL for clk in clk_enable
> 
> Yang Yingliang <yangyingliang@huawei.com>
>    platform/x86: intel_scu_ipc: fix possible name leak in __intel_scu_ipc_register()
> 
> Yu Liao <liaoyu15@huawei.com>
>    platform/x86: mxm-wmi: fix memleak in mxm_wmi_call_mx[ds|mx]()
> 
> Victor Ding <victording@chromium.org>
>    platform/chrome: cros_ec_typec: zero out stale pointers
> 
> Prashant Malani <pmalani@chromium.org>
>    platform/chrome: cros_ec_typec: Get retimer handle
> 
> Prashant Malani <pmalani@chromium.org>
>    platform/chrome: cros_ec_typec: Cleanup switch handle return paths
> 
> Gao Xiang <xiang@kernel.org>
>    erofs: validate the extent length for uncompressed pclusters
> 
> Yue Hu <huyue2@coolpad.com>
>    erofs: support interlaced uncompressed data for compressed files
> 
> Gao Xiang <xiang@kernel.org>
>    erofs: fix missing unmap if z_erofs_get_extent_compressedlen() fails
> 
> Chen Zhongjin <chenzhongjin@huawei.com>
>    erofs: Fix pcluster memleak when its block address is zero
> 
> Rafael J. Wysocki <rafael.j.wysocki@intel.com>
>    PM: runtime: Do not call __rpm_callback() from rpm_idle()
> 
> Harshit Mogalapalli <harshit.m.mogalapalli@oracle.com>
>    xen/privcmd: Fix a possible warning in privcmd_ioctl_mmap_resource()
> 
> Xiu Jianfeng <xiujianfeng@huawei.com>
>    x86/xen: Fix memory leak in xen_init_lock_cpu()
> 
> Xiu Jianfeng <xiujianfeng@huawei.com>
>    x86/xen: Fix memory leak in xen_smp_intr_init{_pv}()
> 
> Oleg Nesterov <oleg@redhat.com>
>    uprobes/x86: Allow to probe a NOP instruction with 0x66 prefix
> 
> Li Zetao <lizetao1@huawei.com>
>    ACPICA: Fix use-after-free in acpi_ut_copy_ipackage_to_ipackage()
> 
> Yang Yingliang <yangyingliang@huawei.com>
>    clocksource/drivers/timer-ti-dm: Fix missing clk_disable_unprepare in dmtimer_systimer_init_clock()
> 
> Tony Lindgren <tony@atomide.com>
>    clocksource/drivers/timer-ti-dm: Fix warning for omap_timer_match
> 
> Vincent Donnefort <vdonnefort@google.com>
>    cpu/hotplug: Do not bail-out in DYING/STARTING sections
> 
> Phil Auld <pauld@redhat.com>
>    cpu/hotplug: Make target_store() a nop when target == state
> 
> Alexey Izbyshev <izbyshev@ispras.ru>
>    futex: Resend potentially swallowed owner death notification
> 
> John Thomson <git@johnthomson.fastmail.com.au>
>    mips: ralink: mt7621: do not use kzalloc too early
> 
> John Thomson <git@johnthomson.fastmail.com.au>
>    mips: ralink: mt7621: soc queries and tests as functions
> 
> John Thomson <git@johnthomson.fastmail.com.au>
>    mips: ralink: mt7621: define MT7621_SYSC_BASE with __iomem
> 
> Wolfram Sang <wsa+renesas@sang-engineering.com>
>    clocksource/drivers/sh_cmt: Access registers according to spec
> 
> Yang Yingliang <yangyingliang@huawei.com>
>    rapidio: rio: fix possible name leak in rio_register_mport()
> 
> Yang Yingliang <yangyingliang@huawei.com>
>    rapidio: fix possible name leaks when rio_add_device() fails
> 
> Li Zetao <ocfs2-devel@oss.oracle.com>
>    ocfs2: fix memory leak in ocfs2_mount_volume()
> 
> Akinobu Mita <akinobu.mita@gmail.com>
>    debugfs: fix error when writing negative value to atomic_t debugfs file
> 
> Akinobu Mita <akinobu.mita@gmail.com>
>    lib/notifier-error-inject: fix error when writing -errno to debugfs file
> 
> Akinobu Mita <akinobu.mita@gmail.com>
>    libfs: add DEFINE_SIMPLE_ATTRIBUTE_SIGNED for signed value
> 
> Xiongfeng Wang <wangxiongfeng2@huawei.com>
>    cpufreq: amd_freq_sensitivity: Add missing pci_dev_put()
> 
> Yang Yingliang <yangyingliang@huawei.com>
>    genirq/irqdesc: Don't try to remove non-existing sysfs files
> 
> Jeff Layton <jlayton@kernel.org>
>    nfsd: don't call nfsd_file_put from client states seqfile display
> 
> Chuck Lever <chuck.lever@oracle.com>
>    NFSD: Finish converting the NFSv3 GETACL result encoder
> 
> Chuck Lever <chuck.lever@oracle.com>
>    NFSD: Finish converting the NFSv2 GETACL result encoder
> 
> Yang Yingliang <yangyingliang@huawei.com>
>    EDAC/i10nm: fix refcount leak in pci_get_dev_wrapper()
> 
> Liu Peibao <liupeibao@loongson.cn>
>    irqchip/loongson-liointc: Fix improper error handling in liointc_init()
> 
> Wei Yongjun <weiyongjun1@huawei.com>
>    irqchip/wpcm450: Fix memory leak in wpcm450_aic_of_init()
> 
> Shang XiaoJing <shangxiaojing@huawei.com>
>    irqchip: gic-pm: Use pm_runtime_resume_and_get() in gic_probe()
> 
> Jianmin Lv <lvjianmin@loongson.cn>
>    irqchip/loongson-pch-pic: Fix translate callback for DT path
> 
> Yang Yingliang <yangyingliang@huawei.com>
>    thermal: core: fix some possible name leaks in error paths
> 
> Yuan Can <yuancan@huawei.com>
>    platform/chrome: cros_usbpd_notify: Fix error handling in cros_usbpd_notify_init()
> 
> Xiongfeng Wang <wangxiongfeng2@huawei.com>
>    perf/x86/intel/uncore: Fix reference count leak in __uncore_imc_init_box()
> 
> Xiongfeng Wang <wangxiongfeng2@huawei.com>
>    perf/x86/intel/uncore: Fix reference count leak in snr_uncore_mmio_map()
> 
> Xiongfeng Wang <wangxiongfeng2@huawei.com>
>    perf/x86/intel/uncore: Fix reference count leak in hswep_has_limit_sbox()
> 
> Xiongfeng Wang <wangxiongfeng2@huawei.com>
>    perf/x86/intel/uncore: Fix reference count leak in sad_cfg_iio_topology()
> 
> Wang ShaoBo <bobo.shaobowang@huawei.com>
>    ACPI: pfr_update: use ACPI_FREE() to free acpi_object
> 
> Wang ShaoBo <bobo.shaobowang@huawei.com>
>    ACPI: pfr_telemetry: use ACPI_FREE() to free acpi_object
> 
> Huisong Li <lihuisong@huawei.com>
>    mailbox: pcc: Reset pcc_chan_count to zero in case of PCC probe failure
> 
> Yang Yingliang <yangyingliang@huawei.com>
>    PNP: fix name memory leak in pnp_alloc_dev()
> 
> Zhao Gongyi <zhaogongyi@huawei.com>
>    selftests/efivarfs: Add checking of the test return value
> 
> Yang Yingliang <yangyingliang@huawei.com>
>    MIPS: vpe-cmp: fix possible memory leak while module exiting
> 
> Yang Yingliang <yangyingliang@huawei.com>
>    MIPS: vpe-mt: fix possible memory leak while module exiting
> 
> Manivannan Sadhasivam <mani@kernel.org>
>    cpufreq: qcom-hw: Fix the frequency returned by cpufreq_driver->get()
> 
> YueHaibing <yuehaibing@huawei.com>
>    selftests: cgroup: fix unsigned comparison with less than zero
> 
> Shang XiaoJing <shangxiaojing@huawei.com>
>    ocfs2: fix memory leak in ocfs2_stack_glue_init()
> 
> Gaosheng Cui <cuigaosheng1@huawei.com>
>    lib/fonts: fix undefined behavior in bit shift for get_default_font
> 
> Alexey Dobriyan <adobriyan@gmail.com>
>    proc: fixup uptime selftest
> 
> Barnabás Pőcze <pobrn@protonmail.com>
>    timerqueue: Use rb_entry_safe() in timerqueue_getnext()
> 
> Barnabás Pőcze <pobrn@protonmail.com>
>    platform/x86: huawei-wmi: fix return value calculation
> 
> wuchi <wuchi.zero@gmail.com>
>    lib/debugobjects: fix stat count and optimize debug_objects_mem_init
> 
> Chen Zhongjin <chenzhongjin@huawei.com>
>    perf: Fix possible memleak in pmu_dev_alloc()
> 
> Yipeng Zou <zouyipeng@huawei.com>
>    selftests/ftrace: event_triggers: wait longer for test_event_enable
> 
> Xiongfeng Wang <wangxiongfeng2@huawei.com>
>    ACPI: irq: Fix some kernel-doc issues
> 
> Guilherme G. Piccoli <gpiccoli@igalia.com>
>    x86/split_lock: Add sysctl to control the misery mode
> 
> Chen Hui <judy.chenhui@huawei.com>
>    cpufreq: qcom-hw: Fix memory leak in qcom_cpufreq_hw_read_lut()
> 
> Ondrej Mosnacek <omosnace@redhat.com>
>    fs: don't audit the capability check in simple_xattr_list()
> 
> xiongxin <xiongxin@kylinos.cn>
>    PM: hibernate: Fix mistake in kerneldoc comment
> 
> Reinette Chatre <reinette.chatre@intel.com>
>    x86/sgx: Reduce delay and interference of enclave release
> 
> Hao Lee <haolee.swjtu@gmail.com>
>    sched/psi: Fix possible missing or delayed pending event
> 
> Al Viro <viro@zeniv.linux.org.uk>
>    alpha: fix syscall entry in !AUDUT_SYSCALL case
> 
> Al Viro <viro@zeniv.linux.org.uk>
>    alpha: fix TIF_NOTIFY_SIGNAL handling
> 
> Ulf Hansson <ulf.hansson@linaro.org>
>    cpuidle: dt: Return the correct numbers of parsed idle states
> 
> Qais Yousef <qais.yousef@arm.com>
>    sched/uclamp: Cater for uclamp in find_energy_efficient_cpu()'s early exit condition
> 
> Qais Yousef <qais.yousef@arm.com>
>    sched/uclamp: Make cpu_overutilized() use util_fits_cpu()
> 
> Qais Yousef <qais.yousef@arm.com>
>    sched/uclamp: Make asym_fits_capacity() use util_fits_cpu()
> 
> Dietmar Eggemann <dietmar.eggemann@arm.com>
>    sched/core: Introduce sched_asym_cpucap_active()
> 
> Qais Yousef <qais.yousef@arm.com>
>    sched/uclamp: Make select_idle_capacity() use util_fits_cpu()
> 
> Qais Yousef <qais.yousef@arm.com>
>    sched/uclamp: Fix fits_capacity() check in feec()
> 
> Qais Yousef <qais.yousef@arm.com>
>    sched/uclamp: Make task_fits_capacity() use util_fits_cpu()
> 
> Qais Yousef <qais.yousef@arm.com>
>    sched/uclamp: Fix relationship between uclamp and migration margin
> 
> Amir Goldstein <amir73il@gmail.com>
>    ovl: remove privs in ovl_fallocate()
> 
> Amir Goldstein <amir73il@gmail.com>
>    ovl: remove privs in ovl_copyfile()
> 
> Michael Kelley <mikelley@microsoft.com>
>    tpm/tpm_crb: Fix error message in __crb_relinquish_locality()
> 
> Yuan Can <yuancan@huawei.com>
>    tpm/tpm_ftpm_tee: Fix error handling in ftpm_mod_init()
> 
> Eddie James <eajames@linux.ibm.com>
>    tpm: Add flag to use default cancellation policy
> 
> Eddie James <eajames@linux.ibm.com>
>    tpm: tis_i2c: Fix sanity check interrupt enable mask
> 
> Janne Grunau <j@jannau.net>
>    arch: arm64: apple: t8103: Use standard "iommu" node name
> 
> Stephen Boyd <swboyd@chromium.org>
>    pstore: Avoid kcore oops by vmap()ing with VM_IOREMAP
> 
> Doug Brown <doug@schmorgal.com>
>    ARM: mmp: fix timer_read delay
> 
> Wang Yufen <wangyufen@huawei.com>
>    pstore/ram: Fix error return code in ramoops_probe()
> 
> Kuniyuki Iwashima <kuniyu@amazon.com>
>    seccomp: Move copy_seccomp() to no failure path.
> 
> Yicong Yang <yangyicong@hisilicon.com>
>    drivers/perf: hisi: Fix some event id for hisi-pcie-pmu
> 
> Sven Peter <sven@svenpeter.dev>
>    soc: apple: rtkit: Stop casting function pointer signatures
> 
> Sven Peter <sven@svenpeter.dev>
>    soc: apple: sart: Stop casting function pointer signatures
> 
> Pali Rohár <pali@kernel.org>
>    arm64: dts: armada-3720-turris-mox: Add missing interrupt for RTC
> 
> Pali Rohár <pali@kernel.org>
>    ARM: dts: armada-39x: Fix compatible string for gpios
> 
> Pali Rohár <pali@kernel.org>
>    ARM: dts: armada-38x: Fix compatible string for gpios
> 
> Pali Rohár <pali@kernel.org>
>    ARM: dts: turris-omnia: Add switch port 6 node
> 
> Pali Rohár <pali@kernel.org>
>    ARM: dts: turris-omnia: Add ethernet aliases
> 
> Pali Rohár <pali@kernel.org>
>    ARM: dts: armada-39x: Fix assigned-addresses for every PCIe Root Port
> 
> Pali Rohár <pali@kernel.org>
>    ARM: dts: armada-38x: Fix assigned-addresses for every PCIe Root Port
> 
> Pali Rohár <pali@kernel.org>
>    ARM: dts: armada-375: Fix assigned-addresses for every PCIe Root Port
> 
> Pali Rohár <pali@kernel.org>
>    ARM: dts: armada-xp: Fix assigned-addresses for every PCIe Root Port
> 
> Pali Rohár <pali@kernel.org>
>    ARM: dts: armada-370: Fix assigned-addresses for every PCIe Root Port
> 
> Pali Rohár <pali@kernel.org>
>    ARM: dts: dove: Fix assigned-addresses for every PCIe Root Port
> 
> AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
>    arm64: dts: mediatek: mt6797: Fix 26M oscillator unit name
> 
> AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
>    arm64: dts: mediatek: pumpkin-common: Fix devicetree warnings
> 
> AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
>    arm64: dts: mt2712-evb: Fix usb vbus regulators unit names
> 
> AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
>    arm64: dts: mt2712-evb: Fix vproc fixed regulators unit names
> 
> AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
>    arm64: dts: mt2712e: Fix unit address for pinctrl node
> 
> AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
>    arm64: dts: mt2712e: Fix unit_address_vs_reg warning for oscillators
> 
> AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
>    arm64: dts: mt6779: Fix devicetree build warnings
> 
> AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
>    arm64: dts: mt7896a: Fix unit_address_vs_reg warning for oscillator
> 
> AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
>    arm64: dts: mediatek: mt8195: Fix CPUs capacity-dmips-mhz
> 
> Jonathan Neuschäfer <j.neuschaefer@gmx.net>
>    ARM: dts: nuvoton: Remove bogus unit addresses from fixed-partition nodes
> 
> Keerthy <j-keerthy@ti.com>
>    arm64: dts: ti: k3-j721s2: Fix the interrupt ranges property for main & wkup gpio intr
> 
> Jayesh Choudhary <j-choudhary@ti.com>
>    arm64: dts: ti: k3-j721e-main: Drop dma-coherent in crypto node
> 
> Jayesh Choudhary <j-choudhary@ti.com>
>    arm64: dts: ti: k3-am65-main: Drop dma-coherent in crypto node
> 
> Shang XiaoJing <shangxiaojing@huawei.com>
>    perf/smmuv3: Fix hotplug callback leak in arm_smmu_pmu_init()
> 
> Shang XiaoJing <shangxiaojing@huawei.com>
>    perf/arm_dmc620: Fix hotplug callback leak in dmc620_pmu_init()
> 
> Yuan Can <yuancan@huawei.com>
>    drivers: perf: marvell_cn10k: Fix hotplug callback leak in tad_pmu_init()
> 
> Yuan Can <yuancan@huawei.com>
>    perf: arm_dsu: Fix hotplug callback leak in dsu_pmu_init()
> 
> Mark Rutland <mark.rutland@arm.com>
>    arm64: mm: kfence: only handle translation faults
> 
> Zhang Qilong <zhangqilong3@huawei.com>
>    soc: ti: smartreflex: Fix PM disable depth imbalance in omap_sr_probe
> 
> Zhang Qilong <zhangqilong3@huawei.com>
>    soc: ti: knav_qmss_queue: Fix PM disable depth imbalance in knav_queue_probe
> 
> Kory Maincent <kory.maincent@bootlin.com>
>    arm: dts: spear600: Fix clcd interrupt
> 
> Frank Wunderlich <frank-w@public-files.de>
>    arm64: dts: mt7986: fix trng node name
> 
> Conor Dooley <conor.dooley@microchip.com>
>    dt-bindings: pwm: fix microchip corePWM's pwm-cells
> 
> Fabrizio Castro <fabrizio.castro.jz@renesas.com>
>    arm64: dts: renesas: r9a09g011: Fix unit address format error
> 
> Wolfram Sang <wsa+renesas@sang-engineering.com>
>    arm64: dts: renesas: r8a779f0: Fix SCIF "brg_int" clock
> 
> Wolfram Sang <wsa+renesas@sang-engineering.com>
>    arm64: dts: renesas: r8a779f0: Fix HSCIF "brg_int" clock
> 
> Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
>    arm64: dts: qcom: sm6125: fix SDHCI CQE reg names
> 
> Marijn Suijten <marijn.suijten@somainline.org>
>    arm64: dts: qcom: pm6350: Include header for KEY_POWER
> 
> Jiasheng Jiang <jiasheng@iscas.ac.cn>
>    soc: qcom: apr: Add check for idr_alloc and of_property_read_string_index
> 
> Johan Hovold <johan+linaro@kernel.org>
>    arm64: dts: qcom: sm6350: drop bogus DP PHY clock
> 
> Johan Hovold <johan+linaro@kernel.org>
>    arm64: dts: qcom: sm8250: drop bogus DP PHY clock
> 
> Dmitry Torokhov <dmitry.torokhov@gmail.com>
>    arm64: dts: qcom: sm8250-mtp: fix reset line polarity
> 
> Dmitry Torokhov <dmitry.torokhov@gmail.com>
>    arm64: dts: qcom: msm8996: fix sound card reset line polarity
> 
> Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
>    arm64: dts: qcom: use GPIO flags for tlmm
> 
> Johan Hovold <johan+linaro@kernel.org>
>    arm64: dts: qcom: sm8450: fix UFS PHY registers
> 
> Johan Hovold <johan+linaro@kernel.org>
>    arm64: dts: qcom: sm8350: fix UFS PHY registers
> 
> Johan Hovold <johan+linaro@kernel.org>
>    arm64: dts: qcom: sm8250: fix UFS PHY registers
> 
> Johan Hovold <johan+linaro@kernel.org>
>    arm64: dts: qcom: sm8150: fix UFS PHY registers
> 
> Luca Weiss <luca.weiss@fairphone.com>
>    soc: qcom: llcc: make irq truly optional
> 
> Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
>    arm64: dts: qcom: sc7180-trogdor-homestar: fully configure secondary I2S pins
> 
> Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
>    arm64: dts: qcom: sm8250: correct LPASS pin pull down
> 
> Marijn Suijten <marijn.suijten@somainline.org>
>    arm64: dts: qcom: pm660: Use unique ADC5_VCOIN address in node name
> 
> Georgi Vlaev <g-vlaev@ti.com>
>    firmware: ti_sci: Fix polled mode during system suspend
> 
> Chen Jiahao <chenjiahao16@huawei.com>
>    drivers: soc: ti: knav_qmss_queue: Mark knav_acc_firmwares as static
> 
> Marek Vasut <marex@denx.de>
>    ARM: dts: stm32: Fix AV96 WLAN regulator gpio property
> 
> Marek Vasut <marex@denx.de>
>    ARM: dts: stm32: Drop stm32mp15xc.dtsi from Avenger96
> 
> Marco Elver <elver@google.com>
>    objtool, kcsan: Add volatile read/write instrumentation to whitelist
> 
> Cong Dang <cong.dang.xn@renesas.com>
>    memory: renesas-rpc-if: Clear HS bit during hardware initialization
> 
> Padmanabhan Rajanbabu <p.rajanbabu@samsung.com>
>    arm64: dts: fsd: fix drive strength values as per FSD HW UM
> 
> Padmanabhan Rajanbabu <p.rajanbabu@samsung.com>
>    arm64: dts: fsd: fix drive strength macros as per FSD HW UM
> 
> Stephan Gerhold <stephan.gerhold@kernkonzept.com>
>    arm64: dts: qcom: msm8916: Drop MSS fallback compatible
> 
> Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
>    arm64: dts: qcom: sdm845-cheza: fix AP suspend pin bias
> 
> Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
>    arm64: dts: qcom: sdm630: fix UART1 pin bias
> 
> Luca Weiss <luca@z3ntu.xyz>
>    ARM: dts: qcom: apq8064: fix coresight compatible
> 
> Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
>    arm64: dts: qcom: msm8996: fix GPU OPP table
> 
> Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
>    arm64: dts: qcom: msm8996: fix supported-hw in cpufreq OPP tables
> 
> Yassine Oudjana <y.oudjana@protonmail.com>
>    arm64: dts: qcom: msm8996: Add MSM8996 Pro support
> 
> Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
>    arm64: dts: qcom: sdm845-xiaomi-polaris: fix codec pin conf name
> 
> Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
>    arm64: dts: qcom: sm8250-sony-xperia-edo: fix touchscreen bias-disable
> 
> Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
>    arm64: dts: qcom: ipq6018-cp01-c1: use BLSPI1 pins
> 
> Geert Uytterhoeven <geert+renesas@glider.be>
>    arm64: dts: renesas: r8a779g0: Fix HSCIF0 "brg_int" clock
> 
> Paulo Alcantara <pc@cjr.nz>
>    cifs: fix oops during encryption
> 
> Paulo Alcantara <pc@cjr.nz>
>    cifs: improve symlink handling for smb2+
> 
> Enzo Matsumiya <ematsumiya@suse.de>
>    cifs: replace kfree() with kfree_sensitive() for sensitive data
> 
> Ivaylo Dimitrov <ivo.g.dimitrov.75@gmail.com>
>    usb: musb: remove extra check in musb_gadget_vbus_draw
> 
> Martin Kaiser <martin@kaiser.cx>
>    staging: r8188eu: fix led register settings
> 
> Martin Kaiser <martin@kaiser.cx>
>    staging: r8188eu: don't check bSurpriseRemoved in SwLedOff
> 
> Martin Kaiser <martin@kaiser.cx>
>    staging: r8188eu: remove duplicate bSurpriseRemoved check
> 
> 
> -------------
> 
> Diffstat:
> 
> .../ABI/testing/sysfs-bus-spi-devices-spi-nor      |   3 +
> Documentation/admin-guide/sysctl/kernel.rst        |  23 +
> .../bindings/clock/qcom,sc7280-lpasscorecc.yaml    |  19 +-
> .../devicetree/bindings/input/azoteq,iqs7222.yaml  |  25 +-
> .../devicetree/bindings/mfd/qcom,spmi-pmic.yaml    |   8 +-
> .../devicetree/bindings/pci/fsl,imx6q-pcie.yaml    |  46 +-
> .../bindings/pci/toshiba,visconti-pcie.yaml        |   7 +-
> .../bindings/pinctrl/mediatek,mt7986-pinctrl.yaml  |  46 +-
> .../devicetree/bindings/pwm/microchip,corepwm.yaml |   4 +-
> .../devicetree/bindings/sound/qcom,wcd9335.txt     |   2 +-
> Documentation/devicetree/bindings/sound/rt5682.txt |   2 +-
> Documentation/driver-api/spi.rst                   |   4 +-
> Documentation/fault-injection/fault-injection.rst  |  10 +-
> Makefile                                           |   4 +-
> arch/Kconfig                                       |   2 +-
> arch/alpha/include/asm/thread_info.h               |   2 +-
> arch/alpha/kernel/entry.S                          |   4 +-
> arch/arm/boot/dts/armada-370.dtsi                  |   2 +-
> arch/arm/boot/dts/armada-375.dtsi                  |   2 +-
> arch/arm/boot/dts/armada-380.dtsi                  |   4 +-
> arch/arm/boot/dts/armada-385-turris-omnia.dts      |  18 +-
> arch/arm/boot/dts/armada-385.dtsi                  |   6 +-
> arch/arm/boot/dts/armada-38x.dtsi                  |   4 +-
> arch/arm/boot/dts/armada-39x.dtsi                  |  10 +-
> arch/arm/boot/dts/armada-xp-mv78230.dtsi           |   8 +-
> arch/arm/boot/dts/armada-xp-mv78260.dtsi           |  16 +-
> arch/arm/boot/dts/aspeed-bmc-ibm-everest.dts       |  17 +-
> arch/arm/boot/dts/aspeed-bmc-ibm-rainier.dts       |  16 +-
> arch/arm/boot/dts/dove.dtsi                        |   2 +-
> arch/arm/boot/dts/nuvoton-npcm730-gbs.dts          |   2 +-
> arch/arm/boot/dts/nuvoton-npcm730-gsj.dts          |   2 +-
> arch/arm/boot/dts/nuvoton-npcm730-kudo.dts         |   6 +-
> arch/arm/boot/dts/nuvoton-npcm750-evb.dts          |   4 +-
> .../boot/dts/nuvoton-npcm750-runbmc-olympus.dts    |   6 +-
> arch/arm/boot/dts/qcom-apq8064.dtsi                |   2 +-
> arch/arm/boot/dts/spear600.dtsi                    |   2 +-
> arch/arm/boot/dts/stm32mp157a-dhcor-avenger96.dts  |   1 -
> arch/arm/boot/dts/stm32mp15xx-dhcor-avenger96.dtsi |   2 +-
> arch/arm/mach-mmp/time.c                           |  11 +-
> arch/arm64/boot/dts/apple/t8103.dtsi               |   6 +-
> .../boot/dts/marvell/armada-3720-turris-mox.dts    |   3 +
> arch/arm64/boot/dts/mediatek/mt2712-evb.dts        |  12 +-
> arch/arm64/boot/dts/mediatek/mt2712e.dtsi          |  22 +-
> arch/arm64/boot/dts/mediatek/mt6779.dtsi           |   8 +-
> arch/arm64/boot/dts/mediatek/mt6797.dtsi           |   2 +-
> arch/arm64/boot/dts/mediatek/mt7986a.dtsi          |   4 +-
> arch/arm64/boot/dts/mediatek/mt8183.dtsi           |   2 +-
> arch/arm64/boot/dts/mediatek/mt8195.dtsi           |   8 +-
> arch/arm64/boot/dts/mediatek/pumpkin-common.dtsi   |   6 +-
> arch/arm64/boot/dts/qcom/apq8096-ifc6640.dts       |   2 +-
> arch/arm64/boot/dts/qcom/ipq6018-cp01-c1.dts       |   2 +
> arch/arm64/boot/dts/qcom/msm8916.dtsi              |   2 +-
> .../dts/qcom/msm8994-sony-xperia-kitakami.dtsi     |   2 +-
> arch/arm64/boot/dts/qcom/msm8994.dtsi              |   3 +-
> arch/arm64/boot/dts/qcom/msm8996.dtsi              | 115 +++--
> arch/arm64/boot/dts/qcom/msm8996pro.dtsi           | 266 +++++++++++
> arch/arm64/boot/dts/qcom/pm6350.dtsi               |   1 +
> arch/arm64/boot/dts/qcom/pm660.dtsi                |   2 +-
> .../boot/dts/qcom/sc7180-trogdor-homestar.dtsi     |   6 +
> arch/arm64/boot/dts/qcom/sdm630.dtsi               |   2 +-
> arch/arm64/boot/dts/qcom/sdm845-cheza.dtsi         |   4 +-
> arch/arm64/boot/dts/qcom/sdm845-db845c.dts         |   4 +-
> .../boot/dts/qcom/sdm845-xiaomi-beryllium.dts      |   2 +-
> arch/arm64/boot/dts/qcom/sdm845-xiaomi-polaris.dts |   6 +-
> .../boot/dts/qcom/sdm850-lenovo-yoga-c630.dts      |   2 +-
> arch/arm64/boot/dts/qcom/sdm850-samsung-w737.dts   |   2 +-
> arch/arm64/boot/dts/qcom/sm6125.dtsi               |   2 +-
> arch/arm64/boot/dts/qcom/sm6350.dtsi               |  10 +-
> arch/arm64/boot/dts/qcom/sm8150.dtsi               |  10 +-
> arch/arm64/boot/dts/qcom/sm8250-mtp.dts            |   2 +-
> .../boot/dts/qcom/sm8250-sony-xperia-edo.dtsi      |   2 +-
> arch/arm64/boot/dts/qcom/sm8250.dtsi               |  20 +-
> arch/arm64/boot/dts/qcom/sm8350.dtsi               |  10 +-
> arch/arm64/boot/dts/qcom/sm8450.dtsi               |  10 +-
> arch/arm64/boot/dts/renesas/r8a779f0.dtsi          |  16 +-
> arch/arm64/boot/dts/renesas/r8a779g0.dtsi          |   2 +-
> arch/arm64/boot/dts/renesas/r9a09g011.dtsi         |   2 +-
> arch/arm64/boot/dts/tesla/fsd-pinctrl.dtsi         |  34 +-
> arch/arm64/boot/dts/tesla/fsd-pinctrl.h            |   6 +-
> arch/arm64/boot/dts/ti/k3-am65-main.dtsi           |   1 -
> arch/arm64/boot/dts/ti/k3-j721e-main.dtsi          |   1 -
> arch/arm64/boot/dts/ti/k3-j721s2-main.dtsi         |   2 +-
> arch/arm64/boot/dts/ti/k3-j721s2-mcu-wakeup.dtsi   |   2 +-
> arch/arm64/include/asm/processor.h                 |   4 +-
> arch/arm64/mm/fault.c                              |   8 +-
> arch/mips/bcm63xx/clk.c                            |   2 +
> .../cavium-octeon/executive/cvmx-helper-board.c    |   2 +-
> arch/mips/cavium-octeon/executive/cvmx-helper.c    |   2 +-
> arch/mips/include/asm/mach-ralink/mt7621.h         |   4 +-
> arch/mips/kernel/vpe-cmp.c                         |   4 +-
> arch/mips/kernel/vpe-mt.c                          |   4 +-
> arch/mips/ralink/mt7621.c                          |  97 ++--
> arch/mips/ralink/of.c                              |   4 +-
> arch/powerpc/boot/dts/turris1x.dts                 |  14 +
> arch/powerpc/include/asm/hvcall.h                  |   3 +-
> arch/powerpc/perf/callchain.c                      |   1 +
> arch/powerpc/perf/hv-gpci-requests.h               |   4 +
> arch/powerpc/perf/hv-gpci.c                        |  35 +-
> arch/powerpc/perf/hv-gpci.h                        |   1 +
> arch/powerpc/perf/req-gen/perf.h                   |  20 +
> arch/powerpc/platforms/52xx/mpc52xx_lpbfifo.c      |   1 +
> arch/powerpc/platforms/83xx/mpc832x_rdb.c          |   2 +-
> arch/powerpc/platforms/pseries/eeh_pseries.c       |  11 +-
> arch/powerpc/platforms/pseries/plpks.c             |  32 +-
> arch/powerpc/platforms/pseries/plpks.h             |   2 +-
> arch/powerpc/sysdev/xive/spapr.c                   |   1 +
> arch/powerpc/xmon/xmon.c                           |   7 +-
> arch/riscv/include/asm/hugetlb.h                   |   6 +
> arch/riscv/include/asm/io.h                        |   5 +
> arch/riscv/include/asm/pgtable-64.h                |   6 +-
> arch/riscv/kernel/entry.S                          |  18 +-
> arch/riscv/kernel/signal.c                         |  34 +-
> arch/riscv/kernel/traps.c                          |   2 +-
> arch/riscv/kvm/vcpu.c                              |  11 +-
> arch/riscv/mm/physaddr.c                           |   2 +-
> arch/riscv/net/bpf_jit_comp64.c                    |  29 +-
> arch/x86/Kconfig                                   |   4 +-
> arch/x86/events/intel/uncore_snb.c                 |   3 +
> arch/x86/events/intel/uncore_snbep.c               |   5 +
> arch/x86/hyperv/hv_init.c                          |   2 -
> arch/x86/include/asm/apic.h                        |   3 +-
> arch/x86/include/asm/realmode.h                    |   1 +
> arch/x86/include/asm/x86_init.h                    |   4 +
> arch/x86/kernel/apic/apic.c                        |  13 +-
> arch/x86/kernel/cpu/intel.c                        |  63 ++-
> arch/x86/kernel/cpu/sgx/encl.c                     |  23 +-
> arch/x86/kernel/setup.c                            |   2 +-
> arch/x86/kernel/uprobes.c                          |   4 +-
> arch/x86/kernel/x86_init.c                         |   3 +
> arch/x86/realmode/init.c                           |   8 +-
> arch/x86/xen/enlighten_pv.c                        |   2 +
> arch/x86/xen/smp.c                                 |  24 +-
> arch/x86/xen/smp_pv.c                              |  12 +-
> arch/x86/xen/spinlock.c                            |   6 +-
> block/bfq-iosched.c                                |  16 +-
> block/blk-mq-sysfs.c                               |  11 +-
> block/blk-mq.c                                     |  56 ++-
> block/genhd.c                                      |   2 +
> crypto/cryptd.c                                    |  36 +-
> crypto/tcrypt.c                                    | 265 +++++------
> drivers/acpi/acpica/dsmethod.c                     |  10 +-
> drivers/acpi/acpica/utcopy.c                       |   7 -
> drivers/acpi/ec.c                                  |  10 +
> drivers/acpi/irq.c                                 |   5 +-
> drivers/acpi/pfr_telemetry.c                       |   6 +-
> drivers/acpi/pfr_update.c                          |   6 +-
> drivers/acpi/processor_idle.c                      |   3 +
> drivers/acpi/x86/utils.c                           |  24 +-
> drivers/ata/libata-sata.c                          |  11 +-
> drivers/base/class.c                               |   5 +
> drivers/base/power/runtime.c                       |  12 +-
> drivers/base/regmap/regmap-irq.c                   |  15 +-
> drivers/block/drbd/drbd_main.c                     |   9 +-
> drivers/block/drbd/drbd_nl.c                       |  10 +-
> drivers/block/floppy.c                             |   4 +-
> drivers/block/loop.c                               |  28 +-
> drivers/bluetooth/btintel.c                        |   5 +-
> drivers/bluetooth/btusb.c                          |   6 +-
> drivers/bluetooth/hci_bcm.c                        |  13 +-
> drivers/bluetooth/hci_bcsp.c                       |   2 +-
> drivers/bluetooth/hci_h5.c                         |   2 +-
> drivers/bluetooth/hci_ll.c                         |   2 +-
> drivers/bluetooth/hci_qca.c                        |   2 +-
> drivers/char/hw_random/amd-rng.c                   |  18 +-
> drivers/char/hw_random/geode-rng.c                 |  36 +-
> drivers/char/ipmi/ipmi_msghandler.c                |   8 +-
> drivers/char/ipmi/kcs_bmc_aspeed.c                 |  24 +-
> drivers/char/tpm/tpm_crb.c                         |   2 +-
> drivers/char/tpm/tpm_ftpm_tee.c                    |   8 +-
> drivers/char/tpm/tpm_tis_core.c                    |  20 +-
> drivers/char/tpm/tpm_tis_core.h                    |   1 +
> drivers/char/tpm/tpm_tis_i2c.c                     |   3 +-
> drivers/clk/imx/clk-imx8mn.c                       | 116 ++---
> drivers/clk/imx/clk-imx8mp.c                       |   4 +-
> drivers/clk/imx/clk-imx93.c                        |  19 +-
> drivers/clk/imx/clk-imxrt1050.c                    |   2 +-
> drivers/clk/mediatek/clk-mt7986-infracfg.c         |   2 +-
> drivers/clk/qcom/clk-krait.c                       |   2 +
> drivers/clk/qcom/dispcc-sm6350.c                   |   4 +-
> drivers/clk/qcom/gcc-ipq806x.c                     |   4 +-
> drivers/clk/qcom/gcc-sm8250.c                      |   4 +-
> drivers/clk/qcom/lpassaudiocc-sc7280.c             | 117 +++--
> drivers/clk/qcom/lpasscc-sc7280.c                  |  44 --
> drivers/clk/qcom/lpasscorecc-sc7180.c              |  24 +-
> drivers/clk/qcom/lpasscorecc-sc7280.c              |  33 ++
> drivers/clk/renesas/r8a779a0-cpg-mssr.c            |   2 +-
> drivers/clk/renesas/r8a779f0-cpg-mssr.c            |  29 +-
> drivers/clk/renesas/r9a06g032-clocks.c             |   3 +-
> drivers/clk/rockchip/clk-pll.c                     |   1 +
> drivers/clk/samsung/clk-pll.c                      |   1 +
> drivers/clk/socfpga/clk-gate.c                     |   5 +-
> drivers/clk/st/clkgen-fsyn.c                       |   5 +-
> drivers/clk/visconti/pll.c                         |   1 +
> drivers/clocksource/sh_cmt.c                       |  88 ++--
> drivers/clocksource/timer-ti-dm-systimer.c         |   4 +-
> drivers/clocksource/timer-ti-dm.c                  |   2 +-
> drivers/counter/stm32-lptimer-cnt.c                |   2 +-
> drivers/cpufreq/amd_freq_sensitivity.c             |   2 +
> drivers/cpufreq/qcom-cpufreq-hw.c                  |  43 +-
> drivers/cpuidle/dt_idle_states.c                   |   2 +-
> drivers/crypto/Kconfig                             |   5 +
> .../crypto/allwinner/sun8i-ss/sun8i-ss-cipher.c    |   2 +-
> drivers/crypto/amlogic/amlogic-gxl-core.c          |   1 -
> drivers/crypto/amlogic/amlogic-gxl.h               |   2 +-
> drivers/crypto/cavium/nitrox/nitrox_mbx.c          |   1 +
> drivers/crypto/ccree/cc_debugfs.c                  |   2 +-
> drivers/crypto/ccree/cc_driver.c                   |  10 +-
> drivers/crypto/hisilicon/hpre/hpre_main.c          |  14 +-
> drivers/crypto/hisilicon/qm.c                      | 208 ++++++---
> drivers/crypto/hisilicon/sec2/sec_main.c           |   4 +-
> drivers/crypto/hisilicon/zip/zip_main.c            |   4 +-
> drivers/crypto/img-hash.c                          |   8 +-
> drivers/crypto/omap-sham.c                         |   2 +-
> drivers/crypto/qat/qat_4xxx/adf_drv.c              |   1 +
> drivers/crypto/rockchip/rk3288_crypto.c            | 193 +-------
> drivers/crypto/rockchip/rk3288_crypto.h            |  53 +--
> drivers/crypto/rockchip/rk3288_crypto_ahash.c      | 197 ++++----
> drivers/crypto/rockchip/rk3288_crypto_skcipher.c   | 413 +++++++++-------
> drivers/dio/dio.c                                  |   8 +
> drivers/dma/apple-admac.c                          | 129 ++++-
> drivers/edac/i10nm_base.c                          |   3 +-
> drivers/extcon/Kconfig                             |   2 +-
> drivers/extcon/extcon-usbc-tusb320.c               | 247 ++++++++--
> drivers/firmware/raspberrypi.c                     |   1 +
> drivers/firmware/ti_sci.c                          |   5 +-
> drivers/gpio/gpiolib-cdev.c                        | 204 +++++++-
> drivers/gpio/gpiolib.c                             |   4 +
> drivers/gpio/gpiolib.h                             |   5 +
> drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c   |   2 +-
> drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c           |   1 +
> drivers/gpu/drm/amd/amdgpu/amdgpu_device.c         |   4 +
> drivers/gpu/drm/amd/amdgpu/amdgpu_virt.h           |   5 +-
> drivers/gpu/drm/amd/amdgpu/nv.c                    |  28 +-
> drivers/gpu/drm/amd/amdgpu/soc15.c                 |  24 +-
> drivers/gpu/drm/amd/amdgpu/soc21.c                 |   2 +-
> .../drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c  |  35 --
> drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c |  16 +-
> .../amd/display/dc/clk_mgr/dcn32/dcn32_clk_mgr.c |   2 +-
> .../gpu/drm/amd/display/dc/dce60/dce60_resource.c  |   3 +
> .../gpu/drm/amd/display/dc/dce80/dce80_resource.c  |   2 +
> .../drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c  |  30 +-
> drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c |  35 +-
> drivers/gpu/drm/amd/display/dc/dcn32/dcn32_dccg.c  |   6 +-
> .../gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c   |   7 +
> drivers/gpu/drm/amd/include/kgd_pp_interface.h     |   3 +-
> drivers/gpu/drm/amd/pm/powerplay/amd_powerplay.c   |   3 +-
> drivers/gpu/drm/amd/pm/powerplay/hwmgr/pp_psm.c    |   2 +
> .../gpu/drm/amd/pm/powerplay/hwmgr/vega20_hwmgr.c  |   3 +-
> drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c     |   4 +
> .../gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c   |  21 +-
> drivers/gpu/drm/bridge/adv7511/adv7511.h           |   3 +-
> drivers/gpu/drm/bridge/adv7511/adv7511_drv.c       |  18 +-
> drivers/gpu/drm/bridge/adv7511/adv7533.c           |  25 +-
> drivers/gpu/drm/bridge/ite-it6505.c                |   8 +-
> drivers/gpu/drm/drm_atomic_helper.c                |  10 +-
> drivers/gpu/drm/drm_edid.c                         |  12 +
> drivers/gpu/drm/drm_fourcc.c                       |   8 +-
> drivers/gpu/drm/etnaviv/etnaviv_gpu.c              |  11 +-
> drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c          |   5 +-
> drivers/gpu/drm/i915/display/intel_bios.c          |   2 +-
> drivers/gpu/drm/i915/display/intel_dp.c            |  59 ---
> drivers/gpu/drm/i915/gt/intel_engine.h             |   6 +
> drivers/gpu/drm/i915/gt/intel_engine_cs.c          |  91 +++-
> drivers/gpu/drm/i915/gt/sysfs_engines.c            |  25 +-
> drivers/gpu/drm/i915/gt/uc/intel_guc.c             |  53 +--
> drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c     | 147 ++++--
> drivers/gpu/drm/i915/gt/uc/intel_guc_capture.h     |   1 -
> drivers/gpu/drm/i915/gt/uc/intel_guc_fwif.h        |  21 +
> drivers/gpu/drm/i915/gt/uc/intel_guc_log.c         | 227 +++++++--
> drivers/gpu/drm/i915/gt/uc/intel_guc_log.h         |  42 +-
> drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c  |   8 +
> drivers/gpu/drm/i915/i915_params.c                 |  12 +
> drivers/gpu/drm/i915/i915_params.h                 |   3 +
> drivers/gpu/drm/mediatek/mtk_dpi.c                 |  12 +-
> drivers/gpu/drm/mediatek/mtk_hdmi.c                |   7 +-
> drivers/gpu/drm/meson/meson_encoder_cvbs.c         |   7 +-
> drivers/gpu/drm/msm/adreno/a6xx_gpu.c              |  12 +-
> drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c        |  25 +-
> drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h        |   2 +-
> drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.c         |  79 ++--
> drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.h         |   4 +-
> drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c           |  27 +-
> drivers/gpu/drm/msm/dp/dp_display.c                |   2 +-
> drivers/gpu/drm/msm/dsi/dsi.c                      |   2 +-
> drivers/gpu/drm/msm/dsi/dsi.h                      |   2 +-
> drivers/gpu/drm/msm/dsi/dsi_host.c                 | 204 +++-----
> drivers/gpu/drm/msm/hdmi/hdmi.c                    |   2 +-
> drivers/gpu/drm/msm/msm_drv.h                      |   9 +-
> drivers/gpu/drm/mxsfb/lcdif_kms.c                  |  48 +-
> drivers/gpu/drm/mxsfb/lcdif_regs.h                 |   5 +
> drivers/gpu/drm/panel/panel-sitronix-st7701.c      |  10 +-
> drivers/gpu/drm/radeon/radeon_bios.c               |  19 +-
> drivers/gpu/drm/rcar-du/Kconfig                    |   2 -
> drivers/gpu/drm/rockchip/cdn-dp-core.c             |   2 +-
> drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c    |   2 +-
> drivers/gpu/drm/rockchip/inno_hdmi.c               |   2 +-
> drivers/gpu/drm/rockchip/rk3066_hdmi.c             |   2 +-
> drivers/gpu/drm/rockchip/rockchip_drm_vop.c        |   4 +-
> drivers/gpu/drm/rockchip/rockchip_drm_vop2.c       |   2 +-
> drivers/gpu/drm/rockchip/rockchip_lvds.c           |  10 +-
> drivers/gpu/drm/sti/sti_dvo.c                      |   7 +-
> drivers/gpu/drm/sti/sti_hda.c                      |   7 +-
> drivers/gpu/drm/sti/sti_hdmi.c                     |   7 +-
> drivers/gpu/drm/tegra/dc.c                         |   4 +-
> drivers/hid/amd-sfh-hid/amd_sfh_client.c           |   4 +
> drivers/hid/hid-apple.c                            | 118 +++--
> drivers/hid/hid-input.c                            |   6 +
> drivers/hid/hid-logitech-hidpp.c                   |  11 +-
> drivers/hid/hid-mcp2221.c                          |  12 +-
> drivers/hid/hid-rmi.c                              |   2 +
> drivers/hid/hid-sensor-custom.c                    |   2 +-
> drivers/hid/i2c-hid/i2c-hid-core.c                 |   3 +-
> drivers/hid/wacom_sys.c                            |   8 +
> drivers/hid/wacom_wac.c                            |   4 +
> drivers/hid/wacom_wac.h                            |   1 +
> drivers/hsi/controllers/omap_ssi_core.c            |  14 +-
> drivers/hv/ring_buffer.c                           |  13 +
> drivers/hwmon/Kconfig                              |   1 +
> drivers/hwmon/jc42.c                               | 243 ++++++----
> drivers/hwmon/nct6775-platform.c                   |   7 +
> drivers/hwtracing/coresight/coresight-trbe.c       |   1 +
> drivers/i2c/busses/i2c-ismt.c                      |   3 +
> drivers/i2c/busses/i2c-pxa-pci.c                   |  10 +-
> drivers/i2c/muxes/i2c-mux-reg.c                    |   5 +-
> drivers/iio/adc/ad_sigma_delta.c                   |   8 +-
> drivers/iio/adc/ti-adc128s052.c                    |  14 +-
> drivers/iio/addac/ad74413r.c                       |   2 +-
> drivers/iio/imu/adis.c                             |  28 +-
> drivers/iio/industrialio-event.c                   |   4 +-
> drivers/iio/temperature/ltc2983.c                  |  10 +-
> drivers/infiniband/Kconfig                         |   2 +
> drivers/infiniband/core/device.c                   |   2 +-
> drivers/infiniband/core/mad.c                      |   5 -
> drivers/infiniband/core/nldev.c                    |   6 +-
> drivers/infiniband/core/restrack.c                 |   2 -
> drivers/infiniband/core/sysfs.c                    |  17 +-
> drivers/infiniband/hw/hfi1/affinity.c              |   2 +
> drivers/infiniband/hw/hfi1/firmware.c              |   6 +
> drivers/infiniband/hw/hns/Makefile                 |   2 +-
> drivers/infiniband/hw/hns/hns_roce_device.h        |  13 +-
> drivers/infiniband/hw/hns/hns_roce_hw_v2.c         | 257 +++++++---
> drivers/infiniband/hw/hns/hns_roce_hw_v2.h         |  14 +-
> drivers/infiniband/hw/hns/hns_roce_hw_v2_dfx.c     |  34 --
> drivers/infiniband/hw/hns/hns_roce_main.c          |  24 +-
> drivers/infiniband/hw/hns/hns_roce_mr.c            |   4 +-
> drivers/infiniband/hw/hns/hns_roce_qp.c            | 107 ++++-
> drivers/infiniband/hw/hns/hns_roce_restrack.c      |  35 +-
> drivers/infiniband/hw/irdma/uk.c                   | 170 ++++---
> drivers/infiniband/hw/irdma/user.h                 |  20 +-
> drivers/infiniband/hw/irdma/utils.c                |   2 +
> drivers/infiniband/hw/irdma/verbs.c                | 145 ++----
> drivers/infiniband/hw/irdma/verbs.h                |  53 +++
> drivers/infiniband/sw/rxe/rxe_mr.c                 |   9 +-
> drivers/infiniband/sw/rxe/rxe_qp.c                 |   6 +-
> drivers/infiniband/sw/siw/siw_cq.c                 |  24 +-
> drivers/infiniband/sw/siw/siw_qp_tx.c              |   2 +-
> drivers/infiniband/sw/siw/siw_verbs.c              |  40 +-
> drivers/infiniband/ulp/ipoib/ipoib_netlink.c       |   7 +
> drivers/infiniband/ulp/srp/ib_srp.c                |  96 +++-
> drivers/input/joystick/Kconfig                     |   1 +
> drivers/input/misc/Kconfig                         |   2 +-
> drivers/input/misc/iqs7222.c                       | 520 ++++++++++++---------
> drivers/input/touchscreen/elants_i2c.c             |   9 +-
> drivers/interconnect/qcom/sc7180.c                 |   2 +-
> drivers/iommu/amd/iommu_v2.c                       |   1 +
> drivers/iommu/fsl_pamu.c                           |   2 +-
> drivers/iommu/mtk_iommu.c                          |  53 ++-
> drivers/iommu/rockchip-iommu.c                     |  10 +-
> drivers/iommu/s390-iommu.c                         | 106 ++---
> drivers/iommu/sun50i-iommu.c                       |  89 +++-
> drivers/irqchip/irq-gic-pm.c                       |   2 +-
> drivers/irqchip/irq-loongson-liointc.c             |   5 +-
> drivers/irqchip/irq-loongson-pch-pic.c             |   3 +
> drivers/irqchip/irq-wpcm450-aic.c                  |   1 +
> drivers/isdn/hardware/mISDN/hfcmulti.c             |  19 +-
> drivers/isdn/hardware/mISDN/hfcpci.c               |  13 +-
> drivers/isdn/hardware/mISDN/hfcsusb.c              |  12 +-
> drivers/leds/leds-is31fl319x.c                     |   3 +-
> drivers/leds/rgb/leds-qcom-lpg.c                   |  18 +-
> drivers/macintosh/macio-adb.c                      |   4 +
> drivers/macintosh/macio_asic.c                     |   2 +-
> drivers/mailbox/arm_mhuv2.c                        |   4 +-
> drivers/mailbox/mailbox-mpfs.c                     |  31 +-
> drivers/mailbox/pcc.c                              |   1 +
> drivers/mailbox/zynqmp-ipi-mailbox.c               |   4 +-
> drivers/mcb/mcb-core.c                             |   4 +-
> drivers/mcb/mcb-parse.c                            |   2 +-
> drivers/md/dm.c                                    | 123 +++--
> drivers/md/md-bitmap.c                             |  27 +-
> drivers/md/raid0.c                                 |   1 -
> drivers/md/raid1.c                                 |   1 +
> drivers/md/raid10.c                                |   2 -
> drivers/media/dvb-core/dvb_ca_en50221.c            |   2 +-
> drivers/media/dvb-core/dvb_frontend.c              |  10 +-
> drivers/media/dvb-core/dvbdev.c                    |  32 +-
> drivers/media/dvb-frontends/bcm3510.c              |   1 +
> drivers/media/i2c/ad5820.c                         |  10 +-
> drivers/media/i2c/adv748x/adv748x-afe.c            |   4 +
> drivers/media/i2c/dw9768.c                         |  33 +-
> drivers/media/i2c/hi846.c                          |  14 +-
> drivers/media/i2c/mt9p031.c                        |   1 -
> drivers/media/i2c/ov5640.c                         |   3 +-
> drivers/media/i2c/ov5648.c                         |   1 +
> drivers/media/pci/saa7164/saa7164-core.c           |   4 +-
> drivers/media/pci/solo6x10/solo6x10-core.c         |   1 +
> drivers/media/platform/amphion/vdec.c              |  15 +-
> drivers/media/platform/amphion/vpu.h               |   1 +
> drivers/media/platform/amphion/vpu_cmds.c          |  39 +-
> drivers/media/platform/amphion/vpu_drv.c           |   6 +-
> drivers/media/platform/amphion/vpu_malone.c        |   1 +
> drivers/media/platform/amphion/vpu_msgs.c          |   2 +
> drivers/media/platform/amphion/vpu_v4l2.c          |  30 +-
> drivers/media/platform/amphion/vpu_windsor.c       |   1 +
> drivers/media/platform/chips-media/coda-bit.c      |  14 +-
> drivers/media/platform/chips-media/coda-jpeg.c     |  10 +-
> .../mediatek/vcodec/mtk_vcodec_dec_stateless.c     |  13 +-
> .../mediatek/vcodec/vdec/vdec_h264_req_multi_if.c  |  60 ++-
> .../mediatek/vcodec/vdec/vdec_vp9_req_lat_if.c     |  15 +-
> .../platform/mediatek/vcodec/vdec_msg_queue.c      |   2 +-
> drivers/media/platform/nxp/imx-jpeg/mxc-jpeg-hw.c  |   4 +-
> drivers/media/platform/qcom/camss/camss-video.c    |   3 +-
> drivers/media/platform/qcom/camss/camss.c          |  11 +
> drivers/media/platform/qcom/venus/pm_helpers.c     |   4 +-
> .../media/platform/samsung/exynos4-is/fimc-core.c  |   2 +-
> .../media/platform/samsung/exynos4-is/media-dev.c  |  12 +-
> drivers/media/platform/samsung/s5p-mfc/s5p_mfc.c   |  17 +-
> .../platform/st/sti/c8sectpfe/c8sectpfe-core.c     |   1 +
> .../sunxi/sun6i-mipi-csi2/sun6i_mipi_csi2.c        |  23 +-
> .../sun8i-a83t-mipi-csi2/sun8i_a83t_mipi_csi2.c    |  23 +-
> drivers/media/radio/si470x/radio-si470x-usb.c      |   4 +-
> drivers/media/rc/imon.c                            |   6 +-
> drivers/media/test-drivers/vidtv/vidtv_bridge.c    |  22 +-
> drivers/media/test-drivers/vimc/vimc-core.c        |   2 +-
> drivers/media/test-drivers/vivid/vivid-vid-cap.c   |   1 +
> drivers/media/usb/dvb-usb/az6027.c                 |   4 +
> drivers/media/usb/dvb-usb/dvb-usb-init.c           |   4 +-
> drivers/media/v4l2-core/v4l2-ctrls-api.c           |   1 +
> drivers/media/v4l2-core/v4l2-ctrls-core.c          |   2 +-
> drivers/media/v4l2-core/v4l2-ioctl.c               |  34 +-
> drivers/media/v4l2-core/videobuf-dma-contig.c      |  22 +-
> drivers/memory/renesas-rpc-if.c                    |   3 +
> drivers/memstick/core/ms_block.c                   |   9 +-
> drivers/mfd/Kconfig                                |   1 +
> drivers/mfd/axp20x.c                               |   2 +-
> drivers/mfd/qcom-pm8008.c                          |   4 +-
> drivers/mfd/qcom_rpm.c                             |  16 +-
> drivers/misc/cxl/guest.c                           |  24 +-
> drivers/misc/cxl/pci.c                             |  21 +-
> drivers/misc/lkdtm/cfi.c                           |   6 +-
> drivers/misc/ocxl/config.c                         |  20 +-
> drivers/misc/ocxl/file.c                           |   7 +-
> drivers/misc/sgi-gru/grufault.c                    |  13 +-
> drivers/misc/sgi-gru/grumain.c                     |  22 +-
> drivers/misc/sgi-gru/grutables.h                   |   2 +-
> drivers/misc/tifm_7xx1.c                           |   2 +-
> drivers/mmc/core/sd.c                              |  11 +-
> drivers/mmc/host/alcor.c                           |   5 +-
> drivers/mmc/host/atmel-mci.c                       |   9 +-
> drivers/mmc/host/litex_mmc.c                       |   1 +
> drivers/mmc/host/meson-gx-mmc.c                    |   4 +-
> drivers/mmc/host/mmci.c                            |   4 +-
> drivers/mmc/host/moxart-mmc.c                      |   4 +-
> drivers/mmc/host/mxcmmc.c                          |   4 +-
> drivers/mmc/host/omap_hsmmc.c                      |   4 +-
> drivers/mmc/host/pxamci.c                          |   7 +-
> drivers/mmc/host/renesas_sdhi.h                    |   1 +
> drivers/mmc/host/renesas_sdhi_core.c               |  14 +-
> drivers/mmc/host/renesas_sdhi_internal_dmac.c      |   4 +-
> drivers/mmc/host/rtsx_pci_sdmmc.c                  |   9 +-
> drivers/mmc/host/rtsx_usb_sdmmc.c                  |  11 +-
> drivers/mmc/host/sdhci_f_sdh30.c                   |   3 +
> drivers/mmc/host/toshsd.c                          |   6 +-
> drivers/mmc/host/via-sdmmc.c                       |   4 +-
> drivers/mmc/host/vub300.c                          |  11 +-
> drivers/mmc/host/wbsd.c                            |  12 +-
> drivers/mmc/host/wmt-sdmmc.c                       |   6 +-
> drivers/mtd/lpddr/lpddr2_nvm.c                     |   2 +
> drivers/mtd/maps/pxa2xx-flash.c                    |   2 +
> drivers/mtd/mtdcore.c                              |   9 +-
> drivers/mtd/spi-nor/core.c                         |   3 +-
> drivers/mtd/spi-nor/sysfs.c                        |  14 +
> drivers/net/bonding/bond_main.c                    |  37 +-
> drivers/net/can/m_can/m_can.c                      |  32 +-
> drivers/net/can/m_can/m_can_platform.c             |   4 -
> drivers/net/can/m_can/tcan4x5x-core.c              |  18 +-
> drivers/net/can/usb/kvaser_usb/kvaser_usb.h        |  30 +-
> drivers/net/can/usb/kvaser_usb/kvaser_usb_core.c   | 115 ++++-
> drivers/net/can/usb/kvaser_usb/kvaser_usb_hydra.c  | 160 +++++--
> drivers/net/can/usb/kvaser_usb/kvaser_usb_leaf.c   | 437 +++++++++++++++--
> drivers/net/dsa/lan9303-core.c                     |   4 +-
> drivers/net/dsa/mv88e6xxx/chip.c                   |   9 +-
> drivers/net/ethernet/amd/atarilance.c              |   2 +-
> drivers/net/ethernet/amd/lance.c                   |   2 +-
> drivers/net/ethernet/amd/xgbe/xgbe-phy-v2.c        |  23 +-
> drivers/net/ethernet/apple/bmac.c                  |   2 +-
> drivers/net/ethernet/apple/mace.c                  |   2 +-
> drivers/net/ethernet/dnet.c                        |   4 +-
> drivers/net/ethernet/freescale/enetc/enetc.c       |  35 +-
> drivers/net/ethernet/intel/i40e/i40e_main.c        |  36 +-
> drivers/net/ethernet/intel/igb/igb_main.c          |   8 +-
> drivers/net/ethernet/intel/igc/igc.h               |   3 +
> drivers/net/ethernet/intel/igc/igc_defines.h       |   2 +
> drivers/net/ethernet/intel/igc/igc_main.c          | 210 +++++++--
> drivers/net/ethernet/intel/igc/igc_tsn.c           |  13 +-
> drivers/net/ethernet/mediatek/mtk_eth_soc.c        |  71 +--
> drivers/net/ethernet/mediatek/mtk_eth_soc.h        |  11 +-
> drivers/net/ethernet/myricom/myri10ge/myri10ge.c   |   1 +
> drivers/net/ethernet/neterion/s2io.c               |   2 +-
> drivers/net/ethernet/qlogic/qed/qed_debug.c        |   3 +-
> .../ethernet/qlogic/qlcnic/qlcnic_sriov_common.c   |   2 +
> drivers/net/ethernet/rdc/r6040.c                   |   5 +-
> .../net/ethernet/stmicro/stmmac/stmmac_hwtstamp.c  |   3 +-
> drivers/net/ethernet/stmicro/stmmac/stmmac_main.c  |   4 +-
> drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.h   |   2 +-
> .../net/ethernet/stmicro/stmmac/stmmac_selftests.c |   8 +-
> drivers/net/ethernet/ti/am65-cpsw-nuss.c           |  10 +-
> drivers/net/ethernet/ti/netcp_core.c               |   2 +-
> drivers/net/ethernet/xilinx/xilinx_emaclite.c      |   2 +-
> drivers/net/fddi/defxx.c                           |  22 +-
> drivers/net/hamradio/baycom_epp.c                  |   2 +-
> drivers/net/hamradio/scc.c                         |   6 +-
> drivers/net/macsec.c                               |  34 +-
> drivers/net/mctp/mctp-serial.c                     |   6 +-
> drivers/net/ntb_netdev.c                           |   4 +-
> drivers/net/ppp/ppp_generic.c                      |   2 +
> drivers/net/wan/farsync.c                          |   2 +
> drivers/net/wireless/ath/ar5523/ar5523.c           |   6 +
> drivers/net/wireless/ath/ath10k/core.c             |  16 +
> drivers/net/wireless/ath/ath10k/htc.c              |   9 +
> drivers/net/wireless/ath/ath10k/hw.h               |   2 +
> drivers/net/wireless/ath/ath10k/pci.c              |  20 +-
> drivers/net/wireless/ath/ath11k/core.c             |  46 ++
> drivers/net/wireless/ath/ath11k/core.h             |  14 +-
> drivers/net/wireless/ath/ath11k/debugfs.c          | 139 ++----
> drivers/net/wireless/ath/ath11k/debugfs.h          |   6 +-
> drivers/net/wireless/ath/ath11k/mac.c              | 122 +++--
> drivers/net/wireless/ath/ath11k/qmi.c              |   3 +
> drivers/net/wireless/ath/ath11k/wmi.c              |  48 +-
> drivers/net/wireless/ath/ath9k/hif_usb.c           |  46 +-
> .../broadcom/brcm80211/brcmfmac/firmware.c         |   5 +
> .../wireless/broadcom/brcm80211/brcmfmac/pcie.c    |   6 +-
> .../wireless/broadcom/brcm80211/brcmfmac/sdio.c    |   1 +
> drivers/net/wireless/intel/iwlwifi/mei/iwl-mei.h   |   7 +-
> drivers/net/wireless/intel/iwlwifi/mei/main.c      | 172 ++++---
> drivers/net/wireless/intel/iwlwifi/mei/net.c       |  10 +-
> drivers/net/wireless/intel/iwlwifi/mvm/fw.c        |   2 +
> drivers/net/wireless/intel/iwlwifi/mvm/mvm.h       |   4 +-
> drivers/net/wireless/intel/iwlwifi/mvm/ops.c       |   2 +-
> drivers/net/wireless/intel/iwlwifi/mvm/tx.c        |  20 +-
> drivers/net/wireless/mediatek/mt76/mt76.h          |   3 +-
> drivers/net/wireless/mediatek/mt76/mt7915/eeprom.c |  58 +--
> drivers/net/wireless/mediatek/mt76/mt7915/eeprom.h |   5 -
> drivers/net/wireless/mediatek/mt76/mt7915/mac.c    |  23 +-
> drivers/net/wireless/mediatek/mt76/mt7915/pci.c    |  13 +-
> drivers/net/wireless/mediatek/mt76/mt7921/mac.c    |  34 +-
> drivers/net/wireless/mediatek/mt76/usb.c           |  11 +-
> drivers/net/wireless/purelifi/plfxlc/usb.c         |   1 +
> drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h   |   2 +-
> .../net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c  |  28 +-
> drivers/net/wireless/realtek/rtw89/core.c          |   2 +-
> drivers/net/wireless/realtek/rtw89/mac.c           |   6 +-
> drivers/net/wireless/realtek/rtw89/phy.c           |   2 +-
> drivers/net/wireless/rsi/rsi_91x_core.c            |   4 +-
> drivers/net/wireless/rsi/rsi_91x_hal.c             |   6 +-
> drivers/nfc/pn533/pn533.c                          |   4 +
> drivers/nvme/host/core.c                           |  14 +-
> drivers/nvme/target/core.c                         |  22 +-
> drivers/nvme/target/io-cmd-file.c                  |  16 +-
> drivers/nvme/target/nvmet.h                        |   3 +-
> drivers/of/overlay.c                               |   4 +-
> drivers/pci/controller/dwc/pci-imx6.c              |  13 +-
> drivers/pci/controller/dwc/pcie-designware.c       |   2 +-
> drivers/pci/controller/vmd.c                       |  27 +-
> drivers/pci/endpoint/functions/pci-epf-test.c      |   2 +-
> drivers/pci/endpoint/functions/pci-epf-vntb.c      |   2 +-
> drivers/pci/irq.c                                  |   2 +
> drivers/pci/probe.c                                |   3 -
> drivers/perf/arm_dmc620_pmu.c                      |   8 +-
> drivers/perf/arm_dsu_pmu.c                         |   6 +-
> drivers/perf/arm_smmuv3_pmu.c                      |   8 +-
> drivers/perf/hisilicon/hisi_pcie_pmu.c             |   8 +-
> drivers/perf/marvell_cn10k_tad_pmu.c               |   6 +-
> drivers/phy/broadcom/phy-brcm-usb-init-synopsys.c  |   9 +-
> drivers/phy/broadcom/phy-brcm-usb-init.h           |   1 -
> drivers/phy/broadcom/phy-brcm-usb.c                |  14 +-
> drivers/phy/marvell/phy-mvebu-a3700-comphy.c       |   3 +
> drivers/phy/qualcomm/phy-qcom-qmp-pcie.c           |  15 +-
> drivers/phy/qualcomm/phy-qcom-qmp-pcs-v5_20.h      |  14 +
> drivers/phy/qualcomm/phy-qcom-qmp.h                |   1 +
> drivers/pinctrl/mediatek/pinctrl-mt7986.c          |  24 +-
> drivers/pinctrl/pinconf-generic.c                  |   4 +-
> drivers/pinctrl/pinctrl-k210.c                     |   4 +-
> drivers/pinctrl/pinctrl-ocelot.c                   |  20 +-
> drivers/pinctrl/pinctrl-thunderbay.c               |   8 +-
> drivers/platform/chrome/cros_ec_typec.c            |  53 ++-
> drivers/platform/chrome/cros_usbpd_notify.c        |   6 +-
> drivers/platform/mellanox/mlxbf-pmc.c              |   2 +-
> drivers/platform/x86/huawei-wmi.c                  |  20 +-
> .../platform/x86/intel/int3472/clk_and_regulator.c |   3 +-
> drivers/platform/x86/intel_scu_ipc.c               |   2 +-
> drivers/platform/x86/mxm-wmi.c                     |   8 +-
> drivers/pnp/core.c                                 |   4 +-
> drivers/power/supply/ab8500_charger.c              |   9 +-
> drivers/power/supply/bq25890_charger.c             |  71 ++-
> drivers/power/supply/cw2015_battery.c              |  17 +-
> drivers/power/supply/power_supply_core.c           |   7 +-
> drivers/power/supply/z2_battery.c                  |   6 +-
> drivers/pwm/pwm-mediatek.c                         |   2 +-
> drivers/pwm/pwm-mtk-disp.c                         |   5 +-
> drivers/pwm/pwm-sifive.c                           |   5 +-
> drivers/pwm/pwm-tegra.c                            |  15 +-
> drivers/rapidio/devices/rio_mport_cdev.c           |  15 +-
> drivers/rapidio/rio-scan.c                         |   8 +-
> drivers/rapidio/rio.c                              |   9 +-
> drivers/regulator/core.c                           |  25 +-
> drivers/regulator/devres.c                         |   2 +-
> drivers/regulator/of_regulator.c                   |   2 +-
> drivers/regulator/qcom-labibb-regulator.c          |   1 +
> drivers/regulator/qcom-rpmh-regulator.c            |   2 +-
> drivers/regulator/stm32-vrefbuf.c                  |   2 +-
> drivers/remoteproc/qcom_q6v5_pas.c                 |   4 +
> drivers/remoteproc/qcom_q6v5_wcss.c                |   6 +-
> drivers/remoteproc/qcom_sysmon.c                   |   5 +-
> drivers/rtc/class.c                                |   4 +-
> drivers/rtc/rtc-cmos.c                             | 378 +++++++--------
> drivers/rtc/rtc-mxc_v2.c                           |   4 +-
> drivers/rtc/rtc-pcf85063.c                         |  10 +-
> drivers/rtc/rtc-pic32.c                            |   8 +-
> drivers/rtc/rtc-rzn1.c                             |   4 +-
> drivers/rtc/rtc-snvs.c                             |  16 +-
> drivers/rtc/rtc-st-lpc.c                           |   1 +
> drivers/s390/net/ctcm_main.c                       |  11 +-
> drivers/s390/net/lcs.c                             |   8 +-
> drivers/s390/net/netiucv.c                         |   9 +-
> drivers/scsi/elx/efct/efct_driver.c                |   1 +
> drivers/scsi/elx/libefc/efclib.h                   |   6 +-
> drivers/scsi/fcoe/fcoe.c                           |   1 +
> drivers/scsi/fcoe/fcoe_sysfs.c                     |  19 +-
> drivers/scsi/hisi_sas/hisi_sas_main.c              |   8 +-
> drivers/scsi/hpsa.c                                |   9 +-
> drivers/scsi/ipr.c                                 |  10 +-
> drivers/scsi/libsas/sas_ata.c                      |  25 +
> drivers/scsi/libsas/sas_expander.c                 |   4 +-
> drivers/scsi/libsas/sas_internal.h                 |   2 +
> drivers/scsi/lpfc/lpfc_sli.c                       |   6 +-
> drivers/scsi/mpt3sas/mpt3sas_transport.c           |   2 +
> drivers/scsi/qla2xxx/qla_def.h                     |  22 +-
> drivers/scsi/qla2xxx/qla_init.c                    |  20 +-
> drivers/scsi/qla2xxx/qla_inline.h                  |   4 +-
> drivers/scsi/qla2xxx/qla_os.c                      |   4 +-
> drivers/scsi/scsi_debug.c                          |  11 +-
> drivers/scsi/scsi_error.c                          |  14 +-
> drivers/scsi/smartpqi/smartpqi.h                   |   2 +-
> drivers/scsi/smartpqi/smartpqi_init.c              |  77 ++-
> drivers/scsi/snic/snic_disc.c                      |   3 +
> drivers/soc/apple/rtkit.c                          |   7 +-
> drivers/soc/apple/sart.c                           |   7 +-
> drivers/soc/mediatek/mtk-pm-domains.c              |   2 +-
> drivers/soc/qcom/apr.c                             |  15 +-
> drivers/soc/qcom/llcc-qcom.c                       |   2 +-
> drivers/soc/ti/knav_qmss_queue.c                   |   3 +-
> drivers/soc/ti/smartreflex.c                       |   1 +
> drivers/spi/spi-gpio.c                             |  16 +-
> drivers/spi/spi-mt65xx.c                           |   5 +
> drivers/spi/spidev.c                               |  21 +-
> drivers/staging/media/imx/imx7-media-csi.c         |   6 +-
> drivers/staging/media/rkvdec/rkvdec-vp9.c          |   3 +
> drivers/staging/media/stkwebcam/Kconfig            |   2 +-
> drivers/staging/media/sunxi/cedrus/cedrus_h265.c   |  25 +-
> drivers/staging/media/sunxi/cedrus/cedrus_regs.h   |   2 +
> drivers/staging/r8188eu/core/rtw_led.c             |  29 +-
> drivers/staging/r8188eu/core/rtw_pwrctrl.c         |   2 +-
> drivers/staging/rtl8192e/rtllib_rx.c               |   2 +-
> drivers/staging/rtl8192u/ieee80211/ieee80211_rx.c  |   4 +-
> drivers/staging/vme_user/vme_fake.c                |   2 +
> drivers/staging/vme_user/vme_tsi148.c              |   1 +
> drivers/target/iscsi/iscsi_target_nego.c           |  12 +-
> drivers/thermal/imx8mm_thermal.c                   |   8 +-
> drivers/thermal/k3_j72xx_bandgap.c                 |   2 +-
> drivers/thermal/qcom/lmh.c                         |   2 +-
> drivers/thermal/qcom/qcom-spmi-temp-alarm.c        |   3 +-
> drivers/thermal/thermal_core.c                     |  18 +-
> drivers/tty/serial/8250/8250_bcm7271.c             |  10 +-
> drivers/tty/serial/altera_uart.c                   |  21 +-
> drivers/tty/serial/amba-pl011.c                    |  14 +-
> drivers/tty/serial/pch_uart.c                      |   4 +
> drivers/tty/serial/serial-tegra.c                  |   6 +-
> drivers/tty/serial/stm32-usart.c                   |  47 +-
> drivers/tty/serial/sunsab.c                        |   8 +-
> drivers/ufs/core/ufshcd.c                          |  37 +-
> drivers/uio/uio_dmem_genirq.c                      |  13 +-
> drivers/usb/cdns3/cdnsp-ring.c                     |  42 +-
> drivers/usb/core/hcd.c                             |   6 +-
> drivers/usb/dwc3/core.c                            |  23 +-
> drivers/usb/gadget/function/f_hid.c                |  53 ++-
> drivers/usb/gadget/udc/core.c                      |  12 +-
> drivers/usb/gadget/udc/fotg210-udc.c               |  12 +-
> drivers/usb/host/xhci-mtk.c                        |   1 -
> drivers/usb/host/xhci-ring.c                       |  14 +-
> drivers/usb/host/xhci.h                            |   2 +-
> drivers/usb/musb/musb_gadget.c                     |   2 -
> drivers/usb/musb/omap2430.c                        |  54 +++
> drivers/usb/roles/class.c                          |   5 +-
> drivers/usb/storage/alauda.c                       |   2 +
> drivers/usb/typec/bus.c                            |   2 +-
> drivers/usb/typec/tcpm/tcpci.c                     |   5 +-
> drivers/usb/typec/tipd/core.c                      |  11 +-
> drivers/usb/typec/wusb3801.c                       |   2 +-
> drivers/vfio/platform/vfio_platform_common.c       |   3 +-
> drivers/video/fbdev/Kconfig                        |   2 +-
> drivers/video/fbdev/core/fbcon.c                   |   3 +-
> drivers/video/fbdev/ep93xx-fb.c                    |   4 +-
> drivers/video/fbdev/geode/Kconfig                  |   1 +
> drivers/video/fbdev/hyperv_fb.c                    |   8 +-
> drivers/video/fbdev/pm2fb.c                        |   9 +-
> drivers/video/fbdev/uvesafb.c                      |   1 +
> drivers/video/fbdev/vermilion/vermilion.c          |   4 +-
> drivers/video/fbdev/via/via-core.c                 |   9 +-
> drivers/virt/coco/sev-guest/sev-guest.c            |   1 +
> drivers/watchdog/iTCO_wdt.c                        |  21 +-
> drivers/xen/privcmd.c                              |   2 +-
> fs/afs/fs_probe.c                                  |   5 +-
> fs/binfmt_misc.c                                   |   8 +-
> fs/btrfs/file.c                                    |  10 +-
> fs/char_dev.c                                      |   2 +-
> fs/cifs/cifsencrypt.c                              |  12 +-
> fs/cifs/cifsfs.c                                   |  31 +-
> fs/cifs/cifsglob.h                                 | 114 ++++-
> fs/cifs/cifsproto.h                                |  17 +-
> fs/cifs/connect.c                                  |   6 +-
> fs/cifs/dir.c                                      |  30 +-
> fs/cifs/file.c                                     |  41 +-
> fs/cifs/fs_context.c                               |  12 +-
> fs/cifs/inode.c                                    | 167 ++++---
> fs/cifs/link.c                                     | 107 +----
> fs/cifs/misc.c                                     |   6 +-
> fs/cifs/readdir.c                                  |   2 +
> fs/cifs/sess.c                                     |  30 +-
> fs/cifs/smb1ops.c                                  |  56 ++-
> fs/cifs/smb2file.c                                 | 127 ++++-
> fs/cifs/smb2inode.c                                | 169 +++----
> fs/cifs/smb2ops.c                                  | 252 ++++------
> fs/cifs/smb2pdu.c                                  |  20 +-
> fs/cifs/smb2pdu.h                                  |   3 +
> fs/cifs/smb2proto.h                                |  22 +-
> fs/configfs/dir.c                                  |   2 +
> fs/debugfs/file.c                                  |  28 +-
> fs/erofs/decompressor.c                            |  47 +-
> fs/erofs/erofs_fs.h                                |   2 +
> fs/erofs/internal.h                                |   1 +
> fs/erofs/zdata.c                                   |   3 +-
> fs/erofs/zmap.c                                    |  25 +-
> fs/f2fs/compress.c                                 |   2 +-
> fs/f2fs/f2fs.h                                     |   2 +-
> fs/f2fs/file.c                                     |   4 +
> fs/f2fs/gc.c                                       |  10 +-
> fs/f2fs/namei.c                                    | 329 +++++++------
> fs/f2fs/segment.c                                  |   8 +-
> fs/f2fs/super.c                                    |   2 +-
> fs/hfs/inode.c                                     |   2 +
> fs/hfs/trans.c                                     |   2 +-
> fs/hugetlbfs/inode.c                               |   6 +-
> fs/jfs/jfs_dmap.c                                  |  27 +-
> fs/jfs/namei.c                                     |   2 +-
> fs/ksmbd/mgmt/user_session.c                       |   8 +-
> fs/libfs.c                                         |  22 +-
> fs/lockd/svcsubs.c                                 |  17 +-
> fs/nfs/fs_context.c                                |   6 +
> fs/nfs/internal.h                                  |   6 +-
> fs/nfs/namespace.c                                 |   2 +-
> fs/nfs/nfs42xdr.c                                  |   2 +-
> fs/nfs/nfs4proc.c                                  |  38 +-
> fs/nfs/nfs4state.c                                 |   2 +
> fs/nfs/nfs4xdr.c                                   |  22 +-
> fs/nfsd/nfs2acl.c                                  |  10 -
> fs/nfsd/nfs3acl.c                                  |  30 +-
> fs/nfsd/nfs4callback.c                             |   4 +-
> fs/nfsd/nfs4proc.c                                 |   7 +-
> fs/nfsd/nfs4state.c                                |  51 +-
> fs/nilfs2/the_nilfs.c                              |  73 ++-
> fs/ntfs3/bitmap.c                                  |   2 +-
> fs/ntfs3/super.c                                   |   2 +-
> fs/ntfs3/xattr.c                                   |   2 +-
> fs/ocfs2/journal.c                                 |   2 +-
> fs/ocfs2/journal.h                                 |   1 +
> fs/ocfs2/stackglue.c                               |   8 +-
> fs/ocfs2/super.c                                   |   5 +-
> fs/orangefs/orangefs-debugfs.c                     |  29 +-
> fs/orangefs/orangefs-mod.c                         |   8 +-
> fs/orangefs/orangefs-sysfs.c                       |  71 ++-
> fs/overlayfs/file.c                                |  28 +-
> fs/overlayfs/super.c                               |   7 +-
> fs/pstore/Kconfig                                  |   1 +
> fs/pstore/pmsg.c                                   |   7 +-
> fs/pstore/ram.c                                    |   2 +
> fs/pstore/ram_core.c                               |   6 +-
> fs/reiserfs/namei.c                                |   4 +
> fs/reiserfs/xattr_security.c                       |   2 +-
> fs/sysv/itree.c                                    |   2 +-
> fs/udf/namei.c                                     |   8 +-
> fs/xattr.c                                         |   2 +-
> include/drm/drm_connector.h                        |   6 +
> include/drm/ttm/ttm_tt.h                           |   2 +-
> include/dt-bindings/clock/imx8mn-clock.h           |  24 +-
> include/dt-bindings/clock/imx8mp-clock.h           |   3 +-
> .../dt-bindings/clock/qcom,lpassaudiocc-sc7280.h   |   5 +
> .../dt-bindings/clock/qcom,lpasscorecc-sc7280.h    |   2 +
> include/linux/btf_ids.h                            |   2 +-
> include/linux/debugfs.h                            |  19 +-
> include/linux/eventfd.h                            |   2 +-
> include/linux/fortify-string.h                     |  31 +-
> include/linux/fs.h                                 |  12 +-
> include/linux/hisi_acc_qm.h                        |  37 +-
> include/linux/hyperv.h                             |   2 +
> include/linux/ieee80211.h                          |   2 +-
> include/linux/iio/imu/adis.h                       |  13 +-
> include/linux/netdevice.h                          |  58 ++-
> include/linux/proc_fs.h                            |   2 +
> include/linux/regulator/driver.h                   |   3 +-
> include/linux/skmsg.h                              |   1 +
> include/linux/timerqueue.h                         |   2 +-
> include/media/dvbdev.h                             |  32 +-
> include/net/bluetooth/hci.h                        |  20 +
> include/net/bluetooth/hci_core.h                   |   7 +-
> include/net/dst.h                                  |   5 +-
> include/net/ip_vs.h                                |  10 +-
> include/net/mrp.h                                  |   1 +
> include/net/sock_reuseport.h                       |   2 +
> include/net/tcp.h                                  |   4 +-
> include/scsi/sas_ata.h                             |   6 +
> include/sound/hda_codec.h                          |   2 +-
> include/sound/hdaudio.h                            |   1 +
> include/sound/pcm.h                                |  36 +-
> include/trace/events/f2fs.h                        |  34 +-
> include/trace/events/ib_mad.h                      |  13 +-
> include/uapi/linux/idxd.h                          |   2 +-
> include/uapi/linux/swab.h                          |   2 +-
> include/uapi/rdma/hns-abi.h                        |  15 +
> include/uapi/sound/asequencer.h                    |   8 +-
> io_uring/msg_ring.c                                |   2 +
> io_uring/net.c                                     |   2 +-
> io_uring/timeout.c                                 |   4 +-
> ipc/mqueue.c                                       |   6 +-
> kernel/acct.c                                      |   2 +
> kernel/bpf/btf.c                                   |   5 +
> kernel/bpf/syscall.c                               |   6 +-
> kernel/bpf/verifier.c                              | 108 +++--
> kernel/cpu.c                                       |  60 ++-
> kernel/events/core.c                               |   8 +-
> kernel/fork.c                                      |  17 +-
> kernel/futex/core.c                                |  26 +-
> kernel/gcov/gcc_4_7.c                              |   5 +
> kernel/irq/internals.h                             |   2 +
> kernel/irq/irqdesc.c                               |  15 +-
> kernel/kprobes.c                                   |  16 +-
> kernel/module/decompress.c                         |   8 +-
> kernel/padata.c                                    |  15 +-
> kernel/power/snapshot.c                            |   4 +-
> kernel/rcu/tree.c                                  |   2 +-
> kernel/relay.c                                     |   4 +-
> kernel/sched/core.c                                |  10 +-
> kernel/sched/cpudeadline.c                         |   2 +-
> kernel/sched/deadline.c                            |   4 +-
> kernel/sched/fair.c                                | 231 +++++++--
> kernel/sched/psi.c                                 |   8 +-
> kernel/sched/rt.c                                  |   4 +-
> kernel/sched/sched.h                               |  56 ++-
> kernel/trace/blktrace.c                            |   3 +-
> kernel/trace/trace_events_hist.c                   |   2 +-
> kernel/trace/trace_events_user.c                   |   1 +
> lib/debugobjects.c                                 |  10 +
> lib/fonts/fonts.c                                  |   4 +-
> lib/notifier-error-inject.c                        |   2 +-
> lib/test_firmware.c                                |   1 +
> mm/gup.c                                           |   3 +
> net/802/mrp.c                                      |  18 +-
> net/8021q/vlan_dev.c                               |   4 +-
> net/9p/client.c                                    |   5 +
> net/bluetooth/hci_conn.c                           |   2 +-
> net/bluetooth/hci_core.c                           |   4 +-
> net/bluetooth/hci_sync.c                           |   2 +-
> net/bluetooth/lib.c                                |   4 +-
> net/bluetooth/mgmt.c                               |   2 +-
> net/bluetooth/rfcomm/core.c                        |   2 +-
> net/bpf/test_run.c                                 |   3 -
> net/bridge/br_multicast.c                          |   4 +-
> net/bridge/br_vlan.c                               |   4 +-
> net/core/dev.c                                     |  18 +-
> net/core/devlink.c                                 |   9 +-
> net/core/drop_monitor.c                            |   8 +-
> net/core/filter.c                                  |  11 +-
> net/core/gen_stats.c                               |  16 +-
> net/core/skbuff.c                                  |   3 +
> net/core/skmsg.c                                   |   9 +-
> net/core/sock.c                                    |   2 +-
> net/core/sock_map.c                                |   2 +
> net/core/sock_reuseport.c                          |  94 +++-
> net/core/stream.c                                  |   6 +
> net/dsa/slave.c                                    |   4 +-
> net/dsa/tag_8021q.c                                |  11 +-
> net/ethtool/ioctl.c                                |   3 +-
> net/hsr/hsr_debugfs.c                              |  40 +-
> net/hsr/hsr_device.c                               |  32 +-
> net/hsr/hsr_forward.c                              |  14 +-
> net/hsr/hsr_framereg.c                             | 222 ++++-----
> net/hsr/hsr_framereg.h                             |  17 +-
> net/hsr/hsr_main.h                                 |   9 +-
> net/hsr/hsr_netlink.c                              |   4 +-
> net/ipv4/af_inet.c                                 |   8 +-
> net/ipv4/inet_connection_sock.c                    |   5 +-
> net/ipv4/ping.c                                    |   2 +-
> net/ipv4/tcp_bpf.c                                 |  19 +-
> net/ipv4/udp.c                                     |  39 +-
> net/ipv4/udp_tunnel_core.c                         |   1 +
> net/ipv6/af_inet6.c                                |   4 +-
> net/ipv6/datagram.c                                |  15 +-
> net/ipv6/seg6_local.c                              |   4 +-
> net/ipv6/sit.c                                     |  22 +-
> net/ipv6/udp.c                                     |  12 +-
> net/mac80211/cfg.c                                 |   2 +-
> net/mac80211/ieee80211_i.h                         |   1 +
> net/mac80211/iface.c                               |   1 +
> net/mac80211/mlme.c                                |  15 +-
> net/mac80211/sta_info.c                            |   8 +-
> net/mac80211/tx.c                                  |   2 +-
> net/mctp/device.c                                  |  14 +-
> net/mpls/af_mpls.c                                 |   4 +-
> net/netfilter/ipvs/ip_vs_core.c                    |  30 +-
> net/netfilter/ipvs/ip_vs_ctl.c                     |  14 +-
> net/netfilter/ipvs/ip_vs_est.c                     |  20 +-
> net/netfilter/nf_conntrack_proto_icmpv6.c          |  53 +++
> net/netfilter/nf_flow_table_offload.c              |   6 +-
> net/netfilter/nf_tables_api.c                      |   4 +-
> net/openvswitch/datapath.c                         |  29 +-
> net/openvswitch/flow_table.c                       |   9 +-
> net/rxrpc/output.c                                 |   2 +-
> net/rxrpc/sendmsg.c                                |   2 +-
> net/sched/ematch.c                                 |   2 +
> net/sctp/sysctl.c                                  |  73 +--
> net/sunrpc/clnt.c                                  |   2 +-
> net/sunrpc/xprtrdma/verbs.c                        |   2 +-
> net/tls/tls_sw.c                                   |   6 +-
> net/unix/af_unix.c                                 |  12 +-
> net/vmw_vsock/vmci_transport.c                     |   6 +-
> net/wireless/nl80211.c                             |   3 +
> net/wireless/reg.c                                 |   4 +-
> samples/bpf/xdp1_user.c                            |   2 +-
> samples/bpf/xdp2_kern.c                            |   4 +
> samples/vfio-mdev/mdpy-fb.c                        |   8 +-
> security/Kconfig.hardening                         |   3 +
> security/apparmor/apparmorfs.c                     |   4 +-
> security/apparmor/label.c                          |  12 +-
> security/apparmor/lsm.c                            |   4 +-
> security/apparmor/policy.c                         |   2 +-
> security/apparmor/policy_ns.c                      |   2 +-
> security/apparmor/policy_unpack.c                  |   2 +-
> security/integrity/digsig.c                        |   6 +-
> security/integrity/ima/ima_policy.c                |  51 +-
> security/integrity/ima/ima_template.c              |   4 +-
> security/loadpin/loadpin.c                         |  30 +-
> sound/core/pcm_native.c                            |   4 +-
> sound/drivers/mts64.c                              |   3 +
> sound/hda/hdac_stream.c                            |  17 +-
> sound/pci/asihpi/hpioctl.c                         |   2 +-
> sound/pci/hda/hda_codec.c                          |   3 +-
> sound/pci/hda/hda_controller.c                     |   4 +-
> sound/pci/hda/patch_hdmi.c                         | 273 ++++++-----
> sound/pci/hda/patch_realtek.c                      |  27 ++
> sound/soc/amd/yc/acp6x-mach.c                      |   7 +
> sound/soc/codecs/hda.c                             |   3 -
> sound/soc/codecs/hdac_hda.c                        |   3 -
> sound/soc/codecs/pcm512x.c                         |   8 +-
> sound/soc/codecs/rt298.c                           |   7 +
> sound/soc/codecs/rt5670.c                          |   2 -
> sound/soc/codecs/wm8994.c                          |   5 +
> sound/soc/codecs/wsa883x.c                         |   6 +-
> sound/soc/generic/audio-graph-card.c               |   4 +-
> sound/soc/intel/avs/boards/rt298.c                 |  24 +-
> sound/soc/intel/avs/core.c                         |   2 +-
> sound/soc/intel/avs/ipc.c                          |   6 +-
> sound/soc/intel/boards/sof_es8336.c                |   2 +-
> sound/soc/intel/skylake/skl.c                      |   5 +-
> sound/soc/mediatek/common/mtk-btcvsd.c             |   6 +-
> sound/soc/mediatek/mt8173/mt8173-afe-pcm.c         |  20 +-
> sound/soc/mediatek/mt8173/mt8173-rt5650-rt5514.c   |   7 +-
> .../mt8183/mt8183-mt6358-ts3a227-max98357.c        |  14 +-
> sound/soc/pxa/mmp-pcm.c                            |   2 +-
> sound/soc/qcom/lpass-sc7180.c                      |   3 +
> sound/soc/rockchip/rockchip_pdm.c                  |   1 +
> sound/soc/rockchip/rockchip_spdif.c                |   1 +
> sound/usb/quirks-table.h                           |   2 +
> tools/bpf/bpftool/common.c                         |   1 +
> tools/lib/bpf/bpf.h                                |   7 +
> tools/lib/bpf/btf.c                                |   8 +-
> tools/lib/bpf/btf_dump.c                           |  29 +-
> tools/lib/bpf/libbpf.c                             |  30 +-
> tools/lib/bpf/usdt.c                               |  11 +-
> tools/objtool/check.c                              |  10 +
> tools/perf/builtin-stat.c                          |  33 +-
> tools/perf/builtin-trace.c                         |  32 +-
> tools/perf/tests/shell/stat_all_pmu.sh             |  13 +-
> tools/perf/util/bpf_off_cpu.c                      |   2 +-
> tools/perf/util/debug.c                            |   4 +
> tools/perf/util/symbol-elf.c                       |   2 +-
> .../selftests/bpf/bpf_testmod/bpf_testmod.c        |  48 ++
> tools/testing/selftests/bpf/config                 |   1 +
> tools/testing/selftests/bpf/network_helpers.c      |   4 +
> tools/testing/selftests/bpf/prog_tests/empty_skb.c | 146 ++++++
> .../selftests/bpf/prog_tests/kprobe_multi_test.c   |  26 +-
> .../testing/selftests/bpf/prog_tests/lsm_cgroup.c  |  17 +-
> tools/testing/selftests/bpf/prog_tests/map_kptr.c  |   3 +-
> .../selftests/bpf/prog_tests/tracing_struct.c      |  64 +++
> .../selftests/bpf/prog_tests/xdp_adjust_tail.c     |   7 +-
> .../selftests/bpf/prog_tests/xdp_do_redirect.c     |   2 +-
> .../selftests/bpf/prog_tests/xdp_synproxy.c        |   2 +-
> tools/testing/selftests/bpf/progs/bpf_iter_ksym.c  |   6 +-
> tools/testing/selftests/bpf/progs/empty_skb.c      |  37 ++
> tools/testing/selftests/bpf/progs/lsm_cgroup.c     |   8 +
> tools/testing/selftests/bpf/progs/tracing_struct.c | 120 +++++
> tools/testing/selftests/bpf/xdp_synproxy.c         |   5 +-
> tools/testing/selftests/cgroup/cgroup_util.c       |   5 +-
> .../selftests/drivers/net/netdevsim/devlink.sh     |   4 +-
> tools/testing/selftests/efivarfs/efivarfs.sh       |   5 +
> .../ftrace/test.d/ftrace/func_event_triggers.tc    |  15 +-
> .../selftests/netfilter/conntrack_icmp_related.sh  |  36 +-
> .../selftests/powerpc/dscr/dscr_sysfs_test.c       |   5 +-
> tools/testing/selftests/proc/proc-uptime-002.c     |   3 +-
> 1027 files changed, 12883 insertions(+), 6780 deletions(-)
> 
> 

^ permalink raw reply	[relevance 0%]

* Linux 6.0.16
@ 2022-12-31 12:38  1% Greg Kroah-Hartman
  0 siblings, 0 replies; 77+ results
From: Greg Kroah-Hartman @ 2022-12-31 12:38 UTC (permalink / raw)
  To: linux-kernel, akpm, torvalds, stable; +Cc: lwn, jslaby, Greg Kroah-Hartman

I'm announcing the release of the 6.0.16 kernel.

All users of the 6.0 kernel series must upgrade.

The updated 6.0.y git tree can be found at:
	git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable.git linux-6.0.y
and can be browsed at the normal kernel.org git web browser:
	https://git.kernel.org/?p=linux/kernel/git/stable/linux-stable.git;a=summary

thanks,

greg k-h

------------

 Documentation/ABI/testing/sysfs-bus-spi-devices-spi-nor                  |    3 
 Documentation/admin-guide/sysctl/kernel.rst                              |   23 
 Documentation/devicetree/bindings/clock/qcom,sc7280-lpasscorecc.yaml     |   19 
 Documentation/devicetree/bindings/input/azoteq,iqs7222.yaml              |   25 
 Documentation/devicetree/bindings/mfd/qcom,spmi-pmic.yaml                |    8 
 Documentation/devicetree/bindings/pci/fsl,imx6q-pcie.yaml                |   46 
 Documentation/devicetree/bindings/pci/toshiba,visconti-pcie.yaml         |    7 
 Documentation/devicetree/bindings/pinctrl/mediatek,mt7986-pinctrl.yaml   |   46 
 Documentation/devicetree/bindings/pwm/microchip,corepwm.yaml             |    4 
 Documentation/devicetree/bindings/sound/qcom,wcd9335.txt                 |    2 
 Documentation/devicetree/bindings/sound/rt5682.txt                       |    2 
 Documentation/driver-api/spi.rst                                         |    4 
 Documentation/fault-injection/fault-injection.rst                        |   10 
 Makefile                                                                 |    2 
 arch/Kconfig                                                             |    2 
 arch/alpha/include/asm/thread_info.h                                     |    2 
 arch/alpha/kernel/entry.S                                                |    4 
 arch/arm/boot/dts/armada-370.dtsi                                        |    2 
 arch/arm/boot/dts/armada-375.dtsi                                        |    2 
 arch/arm/boot/dts/armada-380.dtsi                                        |    4 
 arch/arm/boot/dts/armada-385-turris-omnia.dts                            |   18 
 arch/arm/boot/dts/armada-385.dtsi                                        |    6 
 arch/arm/boot/dts/armada-39x.dtsi                                        |    6 
 arch/arm/boot/dts/armada-xp-mv78230.dtsi                                 |    8 
 arch/arm/boot/dts/armada-xp-mv78260.dtsi                                 |   16 
 arch/arm/boot/dts/aspeed-bmc-ibm-everest.dts                             |   17 
 arch/arm/boot/dts/aspeed-bmc-ibm-rainier.dts                             |   16 
 arch/arm/boot/dts/dove.dtsi                                              |    2 
 arch/arm/boot/dts/nuvoton-npcm730-gbs.dts                                |    2 
 arch/arm/boot/dts/nuvoton-npcm730-gsj.dts                                |    2 
 arch/arm/boot/dts/nuvoton-npcm730-kudo.dts                               |    6 
 arch/arm/boot/dts/nuvoton-npcm750-evb.dts                                |    4 
 arch/arm/boot/dts/nuvoton-npcm750-runbmc-olympus.dts                     |    6 
 arch/arm/boot/dts/qcom-apq8064.dtsi                                      |    2 
 arch/arm/boot/dts/spear600.dtsi                                          |    2 
 arch/arm/boot/dts/stm32mp157a-dhcor-avenger96.dts                        |    1 
 arch/arm/boot/dts/stm32mp15xx-dhcor-avenger96.dtsi                       |    2 
 arch/arm/mach-mmp/time.c                                                 |   11 
 arch/arm64/boot/dts/apple/t8103.dtsi                                     |    6 
 arch/arm64/boot/dts/marvell/armada-3720-turris-mox.dts                   |    3 
 arch/arm64/boot/dts/mediatek/mt2712-evb.dts                              |   12 
 arch/arm64/boot/dts/mediatek/mt2712e.dtsi                                |   22 
 arch/arm64/boot/dts/mediatek/mt6779.dtsi                                 |    8 
 arch/arm64/boot/dts/mediatek/mt6797.dtsi                                 |    2 
 arch/arm64/boot/dts/mediatek/mt7986a.dtsi                                |    4 
 arch/arm64/boot/dts/mediatek/mt8183.dtsi                                 |    2 
 arch/arm64/boot/dts/mediatek/mt8195.dtsi                                 |    8 
 arch/arm64/boot/dts/mediatek/pumpkin-common.dtsi                         |    6 
 arch/arm64/boot/dts/qcom/apq8096-ifc6640.dts                             |    2 
 arch/arm64/boot/dts/qcom/ipq6018-cp01-c1.dts                             |    2 
 arch/arm64/boot/dts/qcom/msm8916.dtsi                                    |    2 
 arch/arm64/boot/dts/qcom/msm8994-sony-xperia-kitakami.dtsi               |    2 
 arch/arm64/boot/dts/qcom/msm8994.dtsi                                    |    3 
 arch/arm64/boot/dts/qcom/msm8996.dtsi                                    |  115 +-
 arch/arm64/boot/dts/qcom/msm8996pro.dtsi                                 |  266 +++++
 arch/arm64/boot/dts/qcom/pm6350.dtsi                                     |    1 
 arch/arm64/boot/dts/qcom/pm660.dtsi                                      |    2 
 arch/arm64/boot/dts/qcom/sc7180-trogdor-homestar.dtsi                    |    6 
 arch/arm64/boot/dts/qcom/sdm630.dtsi                                     |    2 
 arch/arm64/boot/dts/qcom/sdm845-cheza.dtsi                               |    4 
 arch/arm64/boot/dts/qcom/sdm845-db845c.dts                               |    4 
 arch/arm64/boot/dts/qcom/sdm845-xiaomi-beryllium.dts                     |    2 
 arch/arm64/boot/dts/qcom/sdm845-xiaomi-polaris.dts                       |    6 
 arch/arm64/boot/dts/qcom/sdm850-lenovo-yoga-c630.dts                     |    2 
 arch/arm64/boot/dts/qcom/sdm850-samsung-w737.dts                         |    2 
 arch/arm64/boot/dts/qcom/sm6125.dtsi                                     |    2 
 arch/arm64/boot/dts/qcom/sm6350.dtsi                                     |   10 
 arch/arm64/boot/dts/qcom/sm8150.dtsi                                     |   10 
 arch/arm64/boot/dts/qcom/sm8250-mtp.dts                                  |    2 
 arch/arm64/boot/dts/qcom/sm8250-sony-xperia-edo.dtsi                     |    2 
 arch/arm64/boot/dts/qcom/sm8250.dtsi                                     |   20 
 arch/arm64/boot/dts/qcom/sm8350.dtsi                                     |   10 
 arch/arm64/boot/dts/qcom/sm8450.dtsi                                     |   10 
 arch/arm64/boot/dts/renesas/r8a779f0.dtsi                                |   16 
 arch/arm64/boot/dts/renesas/r8a779g0.dtsi                                |    2 
 arch/arm64/boot/dts/renesas/r9a09g011.dtsi                               |    2 
 arch/arm64/boot/dts/tesla/fsd-pinctrl.dtsi                               |   34 
 arch/arm64/boot/dts/tesla/fsd-pinctrl.h                                  |    6 
 arch/arm64/boot/dts/ti/k3-am65-main.dtsi                                 |    1 
 arch/arm64/boot/dts/ti/k3-j721e-main.dtsi                                |    1 
 arch/arm64/boot/dts/ti/k3-j721s2-main.dtsi                               |    2 
 arch/arm64/boot/dts/ti/k3-j721s2-mcu-wakeup.dtsi                         |    2 
 arch/arm64/include/asm/processor.h                                       |    4 
 arch/arm64/mm/fault.c                                                    |    8 
 arch/mips/bcm63xx/clk.c                                                  |    2 
 arch/mips/cavium-octeon/executive/cvmx-helper-board.c                    |    2 
 arch/mips/cavium-octeon/executive/cvmx-helper.c                          |    2 
 arch/mips/include/asm/mach-ralink/mt7621.h                               |    4 
 arch/mips/kernel/vpe-cmp.c                                               |    4 
 arch/mips/kernel/vpe-mt.c                                                |    4 
 arch/mips/ralink/mt7621.c                                                |   97 +
 arch/mips/ralink/of.c                                                    |    4 
 arch/powerpc/boot/dts/turris1x.dts                                       |   14 
 arch/powerpc/include/asm/hvcall.h                                        |    3 
 arch/powerpc/perf/callchain.c                                            |    1 
 arch/powerpc/perf/hv-gpci-requests.h                                     |    4 
 arch/powerpc/perf/hv-gpci.c                                              |   35 
 arch/powerpc/perf/hv-gpci.h                                              |    1 
 arch/powerpc/perf/req-gen/perf.h                                         |   20 
 arch/powerpc/platforms/52xx/mpc52xx_lpbfifo.c                            |    1 
 arch/powerpc/platforms/83xx/mpc832x_rdb.c                                |    2 
 arch/powerpc/platforms/pseries/eeh_pseries.c                             |   11 
 arch/powerpc/platforms/pseries/plpks.c                                   |   32 
 arch/powerpc/platforms/pseries/plpks.h                                   |    2 
 arch/powerpc/sysdev/xive/spapr.c                                         |    1 
 arch/powerpc/xmon/xmon.c                                                 |    7 
 arch/riscv/include/asm/hugetlb.h                                         |    6 
 arch/riscv/include/asm/io.h                                              |    5 
 arch/riscv/include/asm/pgtable-64.h                                      |    6 
 arch/riscv/kernel/entry.S                                                |   18 
 arch/riscv/kernel/signal.c                                               |   34 
 arch/riscv/kernel/traps.c                                                |    2 
 arch/riscv/kvm/vcpu.c                                                    |   11 
 arch/riscv/mm/physaddr.c                                                 |    2 
 arch/riscv/net/bpf_jit_comp64.c                                          |   29 
 arch/x86/Kconfig                                                         |    4 
 arch/x86/events/intel/uncore_snb.c                                       |    3 
 arch/x86/events/intel/uncore_snbep.c                                     |    5 
 arch/x86/hyperv/hv_init.c                                                |    2 
 arch/x86/include/asm/apic.h                                              |    3 
 arch/x86/include/asm/realmode.h                                          |    1 
 arch/x86/include/asm/x86_init.h                                          |    4 
 arch/x86/kernel/apic/apic.c                                              |   13 
 arch/x86/kernel/cpu/intel.c                                              |   63 +
 arch/x86/kernel/cpu/sgx/encl.c                                           |   23 
 arch/x86/kernel/setup.c                                                  |    2 
 arch/x86/kernel/uprobes.c                                                |    4 
 arch/x86/kernel/x86_init.c                                               |    3 
 arch/x86/realmode/init.c                                                 |    8 
 arch/x86/xen/enlighten_pv.c                                              |    2 
 arch/x86/xen/smp.c                                                       |   24 
 arch/x86/xen/smp_pv.c                                                    |   12 
 arch/x86/xen/spinlock.c                                                  |    6 
 block/bfq-iosched.c                                                      |   16 
 block/blk-mq-sysfs.c                                                     |   11 
 block/blk-mq.c                                                           |   56 -
 block/genhd.c                                                            |    2 
 crypto/cryptd.c                                                          |   36 
 crypto/tcrypt.c                                                          |  265 ++---
 drivers/acpi/acpica/dsmethod.c                                           |   10 
 drivers/acpi/acpica/utcopy.c                                             |    7 
 drivers/acpi/ec.c                                                        |   10 
 drivers/acpi/irq.c                                                       |    5 
 drivers/acpi/pfr_telemetry.c                                             |    6 
 drivers/acpi/pfr_update.c                                                |    6 
 drivers/acpi/processor_idle.c                                            |    3 
 drivers/acpi/x86/utils.c                                                 |   24 
 drivers/ata/libata-sata.c                                                |   11 
 drivers/base/class.c                                                     |    5 
 drivers/base/power/runtime.c                                             |   12 
 drivers/base/regmap/regmap-irq.c                                         |   15 
 drivers/block/drbd/drbd_main.c                                           |    9 
 drivers/block/drbd/drbd_nl.c                                             |   10 
 drivers/block/floppy.c                                                   |    4 
 drivers/block/loop.c                                                     |   28 
 drivers/bluetooth/btintel.c                                              |    5 
 drivers/bluetooth/btusb.c                                                |    6 
 drivers/bluetooth/hci_bcm.c                                              |   13 
 drivers/bluetooth/hci_bcsp.c                                             |    2 
 drivers/bluetooth/hci_h5.c                                               |    2 
 drivers/bluetooth/hci_ll.c                                               |    2 
 drivers/bluetooth/hci_qca.c                                              |    2 
 drivers/char/hw_random/amd-rng.c                                         |   18 
 drivers/char/hw_random/geode-rng.c                                       |   36 
 drivers/char/ipmi/ipmi_msghandler.c                                      |    8 
 drivers/char/ipmi/kcs_bmc_aspeed.c                                       |   24 
 drivers/char/tpm/tpm_crb.c                                               |    2 
 drivers/char/tpm/tpm_ftpm_tee.c                                          |    8 
 drivers/char/tpm/tpm_tis_core.c                                          |   20 
 drivers/char/tpm/tpm_tis_core.h                                          |    1 
 drivers/char/tpm/tpm_tis_i2c.c                                           |    3 
 drivers/clk/imx/clk-imx8mn.c                                             |  116 +-
 drivers/clk/imx/clk-imx8mp.c                                             |    4 
 drivers/clk/imx/clk-imx93.c                                              |   19 
 drivers/clk/imx/clk-imxrt1050.c                                          |    2 
 drivers/clk/mediatek/clk-mt7986-infracfg.c                               |    2 
 drivers/clk/qcom/clk-krait.c                                             |    2 
 drivers/clk/qcom/dispcc-sm6350.c                                         |    4 
 drivers/clk/qcom/gcc-ipq806x.c                                           |    4 
 drivers/clk/qcom/gcc-sm8250.c                                            |    4 
 drivers/clk/qcom/lpassaudiocc-sc7280.c                                   |  117 +-
 drivers/clk/qcom/lpasscc-sc7280.c                                        |   44 
 drivers/clk/qcom/lpasscorecc-sc7180.c                                    |   24 
 drivers/clk/qcom/lpasscorecc-sc7280.c                                    |   33 
 drivers/clk/renesas/r8a779a0-cpg-mssr.c                                  |    2 
 drivers/clk/renesas/r8a779f0-cpg-mssr.c                                  |   29 
 drivers/clk/renesas/r9a06g032-clocks.c                                   |    3 
 drivers/clk/rockchip/clk-pll.c                                           |    1 
 drivers/clk/samsung/clk-pll.c                                            |    1 
 drivers/clk/socfpga/clk-gate.c                                           |    5 
 drivers/clk/st/clkgen-fsyn.c                                             |    5 
 drivers/clk/visconti/pll.c                                               |    1 
 drivers/clocksource/sh_cmt.c                                             |   88 +
 drivers/clocksource/timer-ti-dm-systimer.c                               |    4 
 drivers/clocksource/timer-ti-dm.c                                        |    2 
 drivers/counter/stm32-lptimer-cnt.c                                      |    2 
 drivers/cpufreq/amd_freq_sensitivity.c                                   |    2 
 drivers/cpufreq/qcom-cpufreq-hw.c                                        |   43 
 drivers/cpuidle/dt_idle_states.c                                         |    2 
 drivers/crypto/Kconfig                                                   |    5 
 drivers/crypto/allwinner/sun8i-ss/sun8i-ss-cipher.c                      |    2 
 drivers/crypto/amlogic/amlogic-gxl-core.c                                |    1 
 drivers/crypto/amlogic/amlogic-gxl.h                                     |    2 
 drivers/crypto/cavium/nitrox/nitrox_mbx.c                                |    1 
 drivers/crypto/ccree/cc_debugfs.c                                        |    2 
 drivers/crypto/ccree/cc_driver.c                                         |   10 
 drivers/crypto/hisilicon/hpre/hpre_main.c                                |   14 
 drivers/crypto/hisilicon/qm.c                                            |  208 ++--
 drivers/crypto/hisilicon/sec2/sec_main.c                                 |    4 
 drivers/crypto/hisilicon/zip/zip_main.c                                  |    4 
 drivers/crypto/img-hash.c                                                |    8 
 drivers/crypto/omap-sham.c                                               |    2 
 drivers/crypto/qat/qat_4xxx/adf_drv.c                                    |    1 
 drivers/crypto/rockchip/rk3288_crypto.c                                  |  193 ---
 drivers/crypto/rockchip/rk3288_crypto.h                                  |   53 -
 drivers/crypto/rockchip/rk3288_crypto_ahash.c                            |  197 ++-
 drivers/crypto/rockchip/rk3288_crypto_skcipher.c                         |  413 ++++---
 drivers/dio/dio.c                                                        |    8 
 drivers/dma/apple-admac.c                                                |  129 ++
 drivers/edac/i10nm_base.c                                                |    3 
 drivers/extcon/Kconfig                                                   |    2 
 drivers/extcon/extcon-usbc-tusb320.c                                     |  247 ++++
 drivers/firmware/raspberrypi.c                                           |    1 
 drivers/firmware/ti_sci.c                                                |    5 
 drivers/gpio/gpiolib-cdev.c                                              |  204 +++
 drivers/gpio/gpiolib.c                                                   |    4 
 drivers/gpio/gpiolib.h                                                   |    5 
 drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c                         |    2 
 drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c                                 |    1 
 drivers/gpu/drm/amd/amdgpu/amdgpu_device.c                               |    4 
 drivers/gpu/drm/amd/amdgpu/amdgpu_virt.h                                 |    5 
 drivers/gpu/drm/amd/amdgpu/nv.c                                          |   28 
 drivers/gpu/drm/amd/amdgpu/soc15.c                                       |   24 
 drivers/gpu/drm/amd/amdgpu/soc21.c                                       |    2 
 drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c                |   35 
 drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c                       |   16 
 drivers/gpu/drm/amd/display/dc/clk_mgr/dcn32/dcn32_clk_mgr.c             |    2 
 drivers/gpu/drm/amd/display/dc/dce60/dce60_resource.c                    |    3 
 drivers/gpu/drm/amd/display/dc/dce80/dce80_resource.c                    |    2 
 drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c                |   30 
 drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c                       |   35 
 drivers/gpu/drm/amd/display/dc/dcn32/dcn32_dccg.c                        |    6 
 drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c                     |    7 
 drivers/gpu/drm/amd/include/kgd_pp_interface.h                           |    3 
 drivers/gpu/drm/amd/pm/powerplay/amd_powerplay.c                         |    3 
 drivers/gpu/drm/amd/pm/powerplay/hwmgr/pp_psm.c                          |    2 
 drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega20_hwmgr.c                    |    3 
 drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c                           |    4 
 drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c                     |   21 
 drivers/gpu/drm/bridge/adv7511/adv7511.h                                 |    3 
 drivers/gpu/drm/bridge/adv7511/adv7511_drv.c                             |   18 
 drivers/gpu/drm/bridge/adv7511/adv7533.c                                 |   25 
 drivers/gpu/drm/bridge/ite-it6505.c                                      |    8 
 drivers/gpu/drm/drm_atomic_helper.c                                      |   10 
 drivers/gpu/drm/drm_edid.c                                               |   12 
 drivers/gpu/drm/drm_fourcc.c                                             |    8 
 drivers/gpu/drm/etnaviv/etnaviv_gpu.c                                    |   11 
 drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c                                |    5 
 drivers/gpu/drm/i915/display/intel_bios.c                                |    2 
 drivers/gpu/drm/i915/display/intel_dp.c                                  |   59 -
 drivers/gpu/drm/i915/gt/intel_engine.h                                   |    6 
 drivers/gpu/drm/i915/gt/intel_engine_cs.c                                |   91 +
 drivers/gpu/drm/i915/gt/sysfs_engines.c                                  |   25 
 drivers/gpu/drm/i915/gt/uc/intel_guc.c                                   |   53 -
 drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c                           |  147 ++
 drivers/gpu/drm/i915/gt/uc/intel_guc_capture.h                           |    1 
 drivers/gpu/drm/i915/gt/uc/intel_guc_fwif.h                              |   21 
 drivers/gpu/drm/i915/gt/uc/intel_guc_log.c                               |  227 +++-
 drivers/gpu/drm/i915/gt/uc/intel_guc_log.h                               |   42 
 drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c                        |    8 
 drivers/gpu/drm/i915/i915_params.c                                       |   12 
 drivers/gpu/drm/i915/i915_params.h                                       |    3 
 drivers/gpu/drm/mediatek/mtk_dpi.c                                       |   12 
 drivers/gpu/drm/mediatek/mtk_hdmi.c                                      |    7 
 drivers/gpu/drm/meson/meson_encoder_cvbs.c                               |    7 
 drivers/gpu/drm/msm/adreno/a6xx_gpu.c                                    |   12 
 drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c                              |   25 
 drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h                              |    2 
 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.c                               |   79 -
 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.h                               |    4 
 drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c                                 |   27 
 drivers/gpu/drm/msm/dp/dp_display.c                                      |    2 
 drivers/gpu/drm/msm/dsi/dsi.c                                            |    2 
 drivers/gpu/drm/msm/dsi/dsi.h                                            |    2 
 drivers/gpu/drm/msm/dsi/dsi_host.c                                       |  204 +--
 drivers/gpu/drm/msm/hdmi/hdmi.c                                          |    2 
 drivers/gpu/drm/msm/msm_drv.h                                            |    9 
 drivers/gpu/drm/mxsfb/lcdif_kms.c                                        |   48 
 drivers/gpu/drm/mxsfb/lcdif_regs.h                                       |    5 
 drivers/gpu/drm/panel/panel-sitronix-st7701.c                            |   10 
 drivers/gpu/drm/radeon/radeon_bios.c                                     |   19 
 drivers/gpu/drm/rcar-du/Kconfig                                          |    2 
 drivers/gpu/drm/rockchip/cdn-dp-core.c                                   |    2 
 drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c                          |    2 
 drivers/gpu/drm/rockchip/inno_hdmi.c                                     |    2 
 drivers/gpu/drm/rockchip/rk3066_hdmi.c                                   |    2 
 drivers/gpu/drm/rockchip/rockchip_drm_vop.c                              |    4 
 drivers/gpu/drm/rockchip/rockchip_drm_vop2.c                             |    2 
 drivers/gpu/drm/rockchip/rockchip_lvds.c                                 |   10 
 drivers/gpu/drm/sti/sti_dvo.c                                            |    7 
 drivers/gpu/drm/sti/sti_hda.c                                            |    7 
 drivers/gpu/drm/sti/sti_hdmi.c                                           |    7 
 drivers/gpu/drm/tegra/dc.c                                               |    4 
 drivers/hid/amd-sfh-hid/amd_sfh_client.c                                 |    4 
 drivers/hid/hid-apple.c                                                  |  118 +-
 drivers/hid/hid-input.c                                                  |    6 
 drivers/hid/hid-logitech-hidpp.c                                         |   11 
 drivers/hid/hid-mcp2221.c                                                |   12 
 drivers/hid/hid-rmi.c                                                    |    2 
 drivers/hid/hid-sensor-custom.c                                          |    2 
 drivers/hid/i2c-hid/i2c-hid-core.c                                       |    3 
 drivers/hid/wacom_sys.c                                                  |    8 
 drivers/hid/wacom_wac.c                                                  |    4 
 drivers/hid/wacom_wac.h                                                  |    1 
 drivers/hsi/controllers/omap_ssi_core.c                                  |   14 
 drivers/hv/ring_buffer.c                                                 |   13 
 drivers/hwmon/Kconfig                                                    |    1 
 drivers/hwmon/jc42.c                                                     |  243 ++--
 drivers/hwmon/nct6775-platform.c                                         |    7 
 drivers/hwtracing/coresight/coresight-trbe.c                             |    1 
 drivers/i2c/busses/i2c-ismt.c                                            |    3 
 drivers/i2c/busses/i2c-pxa-pci.c                                         |   10 
 drivers/i2c/muxes/i2c-mux-reg.c                                          |    5 
 drivers/iio/adc/ad_sigma_delta.c                                         |    8 
 drivers/iio/adc/ti-adc128s052.c                                          |   14 
 drivers/iio/addac/ad74413r.c                                             |    2 
 drivers/iio/imu/adis.c                                                   |   28 
 drivers/iio/industrialio-event.c                                         |    4 
 drivers/iio/temperature/ltc2983.c                                        |   10 
 drivers/infiniband/Kconfig                                               |    2 
 drivers/infiniband/core/device.c                                         |    2 
 drivers/infiniband/core/mad.c                                            |    5 
 drivers/infiniband/core/nldev.c                                          |    6 
 drivers/infiniband/core/restrack.c                                       |    2 
 drivers/infiniband/core/sysfs.c                                          |   17 
 drivers/infiniband/hw/hfi1/affinity.c                                    |    2 
 drivers/infiniband/hw/hfi1/firmware.c                                    |    6 
 drivers/infiniband/hw/hns/Makefile                                       |    2 
 drivers/infiniband/hw/hns/hns_roce_device.h                              |   13 
 drivers/infiniband/hw/hns/hns_roce_hw_v2.c                               |  257 +++-
 drivers/infiniband/hw/hns/hns_roce_hw_v2.h                               |   14 
 drivers/infiniband/hw/hns/hns_roce_hw_v2_dfx.c                           |   34 
 drivers/infiniband/hw/hns/hns_roce_main.c                                |   24 
 drivers/infiniband/hw/hns/hns_roce_mr.c                                  |    4 
 drivers/infiniband/hw/hns/hns_roce_qp.c                                  |  107 +-
 drivers/infiniband/hw/hns/hns_roce_restrack.c                            |   35 
 drivers/infiniband/hw/irdma/uk.c                                         |  170 ++-
 drivers/infiniband/hw/irdma/user.h                                       |   20 
 drivers/infiniband/hw/irdma/utils.c                                      |    2 
 drivers/infiniband/hw/irdma/verbs.c                                      |  145 --
 drivers/infiniband/hw/irdma/verbs.h                                      |   53 +
 drivers/infiniband/sw/rxe/rxe_mr.c                                       |    9 
 drivers/infiniband/sw/rxe/rxe_qp.c                                       |    6 
 drivers/infiniband/sw/siw/siw_cq.c                                       |   24 
 drivers/infiniband/sw/siw/siw_qp_tx.c                                    |    2 
 drivers/infiniband/sw/siw/siw_verbs.c                                    |   40 
 drivers/infiniband/ulp/ipoib/ipoib_netlink.c                             |    7 
 drivers/infiniband/ulp/srp/ib_srp.c                                      |   96 +
 drivers/input/joystick/Kconfig                                           |    1 
 drivers/input/misc/Kconfig                                               |    2 
 drivers/input/misc/iqs7222.c                                             |  520 +++++-----
 drivers/input/touchscreen/elants_i2c.c                                   |    9 
 drivers/interconnect/qcom/sc7180.c                                       |    2 
 drivers/iommu/amd/iommu_v2.c                                             |    1 
 drivers/iommu/fsl_pamu.c                                                 |    2 
 drivers/iommu/mtk_iommu.c                                                |   53 -
 drivers/iommu/rockchip-iommu.c                                           |   10 
 drivers/iommu/s390-iommu.c                                               |  106 --
 drivers/iommu/sun50i-iommu.c                                             |   89 +
 drivers/irqchip/irq-gic-pm.c                                             |    2 
 drivers/irqchip/irq-loongson-liointc.c                                   |    5 
 drivers/irqchip/irq-loongson-pch-pic.c                                   |    3 
 drivers/irqchip/irq-wpcm450-aic.c                                        |    1 
 drivers/isdn/hardware/mISDN/hfcmulti.c                                   |   19 
 drivers/isdn/hardware/mISDN/hfcpci.c                                     |   13 
 drivers/isdn/hardware/mISDN/hfcsusb.c                                    |   12 
 drivers/leds/leds-is31fl319x.c                                           |    3 
 drivers/leds/rgb/leds-qcom-lpg.c                                         |   18 
 drivers/macintosh/macio-adb.c                                            |    4 
 drivers/macintosh/macio_asic.c                                           |    2 
 drivers/mailbox/arm_mhuv2.c                                              |    4 
 drivers/mailbox/mailbox-mpfs.c                                           |   31 
 drivers/mailbox/pcc.c                                                    |    1 
 drivers/mailbox/zynqmp-ipi-mailbox.c                                     |    4 
 drivers/mcb/mcb-core.c                                                   |    4 
 drivers/mcb/mcb-parse.c                                                  |    2 
 drivers/md/dm.c                                                          |  123 +-
 drivers/md/md-bitmap.c                                                   |   27 
 drivers/md/raid0.c                                                       |    1 
 drivers/md/raid1.c                                                       |    1 
 drivers/md/raid10.c                                                      |    2 
 drivers/media/dvb-core/dvb_ca_en50221.c                                  |    2 
 drivers/media/dvb-core/dvb_frontend.c                                    |   10 
 drivers/media/dvb-core/dvbdev.c                                          |   32 
 drivers/media/dvb-frontends/bcm3510.c                                    |    1 
 drivers/media/i2c/ad5820.c                                               |   10 
 drivers/media/i2c/adv748x/adv748x-afe.c                                  |    4 
 drivers/media/i2c/dw9768.c                                               |   33 
 drivers/media/i2c/hi846.c                                                |   14 
 drivers/media/i2c/mt9p031.c                                              |    1 
 drivers/media/i2c/ov5640.c                                               |    3 
 drivers/media/i2c/ov5648.c                                               |    1 
 drivers/media/pci/saa7164/saa7164-core.c                                 |    4 
 drivers/media/pci/solo6x10/solo6x10-core.c                               |    1 
 drivers/media/platform/amphion/vdec.c                                    |   15 
 drivers/media/platform/amphion/vpu.h                                     |    1 
 drivers/media/platform/amphion/vpu_cmds.c                                |   39 
 drivers/media/platform/amphion/vpu_drv.c                                 |    6 
 drivers/media/platform/amphion/vpu_malone.c                              |    1 
 drivers/media/platform/amphion/vpu_msgs.c                                |    2 
 drivers/media/platform/amphion/vpu_v4l2.c                                |   30 
 drivers/media/platform/amphion/vpu_windsor.c                             |    1 
 drivers/media/platform/chips-media/coda-bit.c                            |   14 
 drivers/media/platform/chips-media/coda-jpeg.c                           |   10 
 drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_stateless.c        |   13 
 drivers/media/platform/mediatek/vcodec/vdec/vdec_h264_req_multi_if.c     |   60 -
 drivers/media/platform/mediatek/vcodec/vdec/vdec_vp9_req_lat_if.c        |   15 
 drivers/media/platform/mediatek/vcodec/vdec_msg_queue.c                  |    2 
 drivers/media/platform/nxp/imx-jpeg/mxc-jpeg-hw.c                        |    4 
 drivers/media/platform/qcom/camss/camss-video.c                          |    3 
 drivers/media/platform/qcom/camss/camss.c                                |   11 
 drivers/media/platform/qcom/venus/pm_helpers.c                           |    4 
 drivers/media/platform/samsung/exynos4-is/fimc-core.c                    |    2 
 drivers/media/platform/samsung/exynos4-is/media-dev.c                    |   12 
 drivers/media/platform/samsung/s5p-mfc/s5p_mfc.c                         |   17 
 drivers/media/platform/st/sti/c8sectpfe/c8sectpfe-core.c                 |    1 
 drivers/media/platform/sunxi/sun6i-mipi-csi2/sun6i_mipi_csi2.c           |   23 
 drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/sun8i_a83t_mipi_csi2.c |   23 
 drivers/media/radio/si470x/radio-si470x-usb.c                            |    4 
 drivers/media/rc/imon.c                                                  |    6 
 drivers/media/test-drivers/vidtv/vidtv_bridge.c                          |   22 
 drivers/media/test-drivers/vimc/vimc-core.c                              |    2 
 drivers/media/test-drivers/vivid/vivid-vid-cap.c                         |    1 
 drivers/media/usb/dvb-usb/az6027.c                                       |    4 
 drivers/media/usb/dvb-usb/dvb-usb-init.c                                 |    4 
 drivers/media/v4l2-core/v4l2-ctrls-api.c                                 |    1 
 drivers/media/v4l2-core/v4l2-ctrls-core.c                                |    2 
 drivers/media/v4l2-core/v4l2-ioctl.c                                     |   34 
 drivers/media/v4l2-core/videobuf-dma-contig.c                            |   22 
 drivers/memory/renesas-rpc-if.c                                          |    3 
 drivers/memstick/core/ms_block.c                                         |    9 
 drivers/mfd/Kconfig                                                      |    1 
 drivers/mfd/axp20x.c                                                     |    2 
 drivers/mfd/qcom-pm8008.c                                                |    4 
 drivers/mfd/qcom_rpm.c                                                   |   16 
 drivers/misc/cxl/guest.c                                                 |   24 
 drivers/misc/cxl/pci.c                                                   |   21 
 drivers/misc/lkdtm/cfi.c                                                 |    6 
 drivers/misc/ocxl/config.c                                               |   20 
 drivers/misc/ocxl/file.c                                                 |    7 
 drivers/misc/sgi-gru/grufault.c                                          |   13 
 drivers/misc/sgi-gru/grumain.c                                           |   22 
 drivers/misc/sgi-gru/grutables.h                                         |    2 
 drivers/misc/tifm_7xx1.c                                                 |    2 
 drivers/mmc/core/sd.c                                                    |   11 
 drivers/mmc/host/alcor.c                                                 |    5 
 drivers/mmc/host/atmel-mci.c                                             |    9 
 drivers/mmc/host/litex_mmc.c                                             |    1 
 drivers/mmc/host/meson-gx-mmc.c                                          |    4 
 drivers/mmc/host/mmci.c                                                  |    4 
 drivers/mmc/host/moxart-mmc.c                                            |    4 
 drivers/mmc/host/mxcmmc.c                                                |    4 
 drivers/mmc/host/omap_hsmmc.c                                            |    4 
 drivers/mmc/host/pxamci.c                                                |    7 
 drivers/mmc/host/renesas_sdhi.h                                          |    1 
 drivers/mmc/host/renesas_sdhi_core.c                                     |   14 
 drivers/mmc/host/renesas_sdhi_internal_dmac.c                            |    4 
 drivers/mmc/host/rtsx_pci_sdmmc.c                                        |    9 
 drivers/mmc/host/rtsx_usb_sdmmc.c                                        |   11 
 drivers/mmc/host/sdhci_f_sdh30.c                                         |    3 
 drivers/mmc/host/toshsd.c                                                |    6 
 drivers/mmc/host/via-sdmmc.c                                             |    4 
 drivers/mmc/host/vub300.c                                                |   11 
 drivers/mmc/host/wbsd.c                                                  |   12 
 drivers/mmc/host/wmt-sdmmc.c                                             |    6 
 drivers/mtd/lpddr/lpddr2_nvm.c                                           |    2 
 drivers/mtd/maps/pxa2xx-flash.c                                          |    2 
 drivers/mtd/mtdcore.c                                                    |    9 
 drivers/mtd/spi-nor/core.c                                               |    3 
 drivers/mtd/spi-nor/sysfs.c                                              |   14 
 drivers/net/bonding/bond_main.c                                          |   37 
 drivers/net/can/m_can/m_can.c                                            |   32 
 drivers/net/can/m_can/m_can_platform.c                                   |    4 
 drivers/net/can/m_can/tcan4x5x-core.c                                    |   18 
 drivers/net/can/usb/kvaser_usb/kvaser_usb.h                              |   30 
 drivers/net/can/usb/kvaser_usb/kvaser_usb_core.c                         |  115 ++
 drivers/net/can/usb/kvaser_usb/kvaser_usb_hydra.c                        |  160 ++-
 drivers/net/can/usb/kvaser_usb/kvaser_usb_leaf.c                         |  437 +++++++-
 drivers/net/dsa/lan9303-core.c                                           |    4 
 drivers/net/dsa/mv88e6xxx/chip.c                                         |    9 
 drivers/net/ethernet/amd/atarilance.c                                    |    2 
 drivers/net/ethernet/amd/lance.c                                         |    2 
 drivers/net/ethernet/amd/xgbe/xgbe-phy-v2.c                              |   23 
 drivers/net/ethernet/apple/bmac.c                                        |    2 
 drivers/net/ethernet/apple/mace.c                                        |    2 
 drivers/net/ethernet/dnet.c                                              |    4 
 drivers/net/ethernet/freescale/enetc/enetc.c                             |   35 
 drivers/net/ethernet/intel/i40e/i40e_main.c                              |   36 
 drivers/net/ethernet/intel/igb/igb_main.c                                |    8 
 drivers/net/ethernet/intel/igc/igc.h                                     |    3 
 drivers/net/ethernet/intel/igc/igc_defines.h                             |    2 
 drivers/net/ethernet/intel/igc/igc_main.c                                |  210 +++-
 drivers/net/ethernet/intel/igc/igc_tsn.c                                 |   13 
 drivers/net/ethernet/mediatek/mtk_eth_soc.c                              |   71 -
 drivers/net/ethernet/mediatek/mtk_eth_soc.h                              |   11 
 drivers/net/ethernet/myricom/myri10ge/myri10ge.c                         |    1 
 drivers/net/ethernet/neterion/s2io.c                                     |    2 
 drivers/net/ethernet/qlogic/qed/qed_debug.c                              |    3 
 drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c                 |    2 
 drivers/net/ethernet/rdc/r6040.c                                         |    5 
 drivers/net/ethernet/stmicro/stmmac/stmmac_hwtstamp.c                    |    3 
 drivers/net/ethernet/stmicro/stmmac/stmmac_main.c                        |    4 
 drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.h                         |    2 
 drivers/net/ethernet/stmicro/stmmac/stmmac_selftests.c                   |    8 
 drivers/net/ethernet/ti/am65-cpsw-nuss.c                                 |   10 
 drivers/net/ethernet/ti/netcp_core.c                                     |    2 
 drivers/net/ethernet/xilinx/xilinx_emaclite.c                            |    2 
 drivers/net/fddi/defxx.c                                                 |   22 
 drivers/net/hamradio/baycom_epp.c                                        |    2 
 drivers/net/hamradio/scc.c                                               |    6 
 drivers/net/macsec.c                                                     |   34 
 drivers/net/mctp/mctp-serial.c                                           |    6 
 drivers/net/ntb_netdev.c                                                 |    4 
 drivers/net/ppp/ppp_generic.c                                            |    2 
 drivers/net/wan/farsync.c                                                |    2 
 drivers/net/wireless/ath/ar5523/ar5523.c                                 |    6 
 drivers/net/wireless/ath/ath10k/core.c                                   |   16 
 drivers/net/wireless/ath/ath10k/htc.c                                    |    9 
 drivers/net/wireless/ath/ath10k/hw.h                                     |    2 
 drivers/net/wireless/ath/ath10k/pci.c                                    |   20 
 drivers/net/wireless/ath/ath11k/core.c                                   |   46 
 drivers/net/wireless/ath/ath11k/core.h                                   |   14 
 drivers/net/wireless/ath/ath11k/debugfs.c                                |  139 --
 drivers/net/wireless/ath/ath11k/debugfs.h                                |    6 
 drivers/net/wireless/ath/ath11k/mac.c                                    |  122 +-
 drivers/net/wireless/ath/ath11k/qmi.c                                    |    3 
 drivers/net/wireless/ath/ath11k/wmi.c                                    |   48 
 drivers/net/wireless/ath/ath9k/hif_usb.c                                 |   46 
 drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c              |    5 
 drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c                  |    6 
 drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c                  |    1 
 drivers/net/wireless/intel/iwlwifi/mei/iwl-mei.h                         |    7 
 drivers/net/wireless/intel/iwlwifi/mei/main.c                            |  172 +--
 drivers/net/wireless/intel/iwlwifi/mei/net.c                             |   10 
 drivers/net/wireless/intel/iwlwifi/mvm/fw.c                              |    2 
 drivers/net/wireless/intel/iwlwifi/mvm/mvm.h                             |    4 
 drivers/net/wireless/intel/iwlwifi/mvm/ops.c                             |    2 
 drivers/net/wireless/intel/iwlwifi/mvm/tx.c                              |   20 
 drivers/net/wireless/mediatek/mt76/mt76.h                                |    3 
 drivers/net/wireless/mediatek/mt76/mt7915/eeprom.c                       |   58 -
 drivers/net/wireless/mediatek/mt76/mt7915/eeprom.h                       |    5 
 drivers/net/wireless/mediatek/mt76/mt7915/mac.c                          |   23 
 drivers/net/wireless/mediatek/mt76/mt7915/pci.c                          |   13 
 drivers/net/wireless/mediatek/mt76/mt7921/mac.c                          |   34 
 drivers/net/wireless/mediatek/mt76/usb.c                                 |   11 
 drivers/net/wireless/purelifi/plfxlc/usb.c                               |    1 
 drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h                         |    2 
 drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c                    |   28 
 drivers/net/wireless/realtek/rtw89/core.c                                |    2 
 drivers/net/wireless/realtek/rtw89/mac.c                                 |    6 
 drivers/net/wireless/realtek/rtw89/phy.c                                 |    2 
 drivers/net/wireless/rsi/rsi_91x_core.c                                  |    4 
 drivers/net/wireless/rsi/rsi_91x_hal.c                                   |    6 
 drivers/nfc/pn533/pn533.c                                                |    4 
 drivers/nvme/host/core.c                                                 |   14 
 drivers/nvme/target/core.c                                               |   22 
 drivers/nvme/target/io-cmd-file.c                                        |   16 
 drivers/nvme/target/nvmet.h                                              |    3 
 drivers/of/overlay.c                                                     |    4 
 drivers/pci/controller/dwc/pci-imx6.c                                    |   13 
 drivers/pci/controller/dwc/pcie-designware.c                             |    2 
 drivers/pci/controller/vmd.c                                             |   27 
 drivers/pci/endpoint/functions/pci-epf-test.c                            |    2 
 drivers/pci/endpoint/functions/pci-epf-vntb.c                            |    2 
 drivers/pci/irq.c                                                        |    2 
 drivers/pci/probe.c                                                      |    3 
 drivers/perf/arm_dmc620_pmu.c                                            |    8 
 drivers/perf/arm_dsu_pmu.c                                               |    6 
 drivers/perf/arm_smmuv3_pmu.c                                            |    8 
 drivers/perf/hisilicon/hisi_pcie_pmu.c                                   |    8 
 drivers/perf/marvell_cn10k_tad_pmu.c                                     |    6 
 drivers/phy/broadcom/phy-brcm-usb-init-synopsys.c                        |    9 
 drivers/phy/broadcom/phy-brcm-usb-init.h                                 |    1 
 drivers/phy/broadcom/phy-brcm-usb.c                                      |   14 
 drivers/phy/marvell/phy-mvebu-a3700-comphy.c                             |    3 
 drivers/phy/qualcomm/phy-qcom-qmp-pcie.c                                 |   15 
 drivers/phy/qualcomm/phy-qcom-qmp-pcs-v5_20.h                            |   14 
 drivers/phy/qualcomm/phy-qcom-qmp.h                                      |    1 
 drivers/pinctrl/mediatek/pinctrl-mt7986.c                                |   24 
 drivers/pinctrl/pinconf-generic.c                                        |    4 
 drivers/pinctrl/pinctrl-k210.c                                           |    4 
 drivers/pinctrl/pinctrl-ocelot.c                                         |   20 
 drivers/pinctrl/pinctrl-thunderbay.c                                     |    8 
 drivers/platform/chrome/cros_ec_typec.c                                  |   53 -
 drivers/platform/chrome/cros_usbpd_notify.c                              |    6 
 drivers/platform/mellanox/mlxbf-pmc.c                                    |    2 
 drivers/platform/x86/huawei-wmi.c                                        |   20 
 drivers/platform/x86/intel/int3472/clk_and_regulator.c                   |    3 
 drivers/platform/x86/intel_scu_ipc.c                                     |    2 
 drivers/platform/x86/mxm-wmi.c                                           |    8 
 drivers/pnp/core.c                                                       |    4 
 drivers/power/supply/ab8500_charger.c                                    |    9 
 drivers/power/supply/bq25890_charger.c                                   |   71 +
 drivers/power/supply/cw2015_battery.c                                    |   17 
 drivers/power/supply/power_supply_core.c                                 |    7 
 drivers/power/supply/z2_battery.c                                        |    6 
 drivers/pwm/pwm-mediatek.c                                               |    2 
 drivers/pwm/pwm-mtk-disp.c                                               |    5 
 drivers/pwm/pwm-sifive.c                                                 |    5 
 drivers/pwm/pwm-tegra.c                                                  |   15 
 drivers/rapidio/devices/rio_mport_cdev.c                                 |   15 
 drivers/rapidio/rio-scan.c                                               |    8 
 drivers/rapidio/rio.c                                                    |    9 
 drivers/regulator/core.c                                                 |   25 
 drivers/regulator/devres.c                                               |    2 
 drivers/regulator/of_regulator.c                                         |    2 
 drivers/regulator/qcom-labibb-regulator.c                                |    1 
 drivers/regulator/qcom-rpmh-regulator.c                                  |    2 
 drivers/regulator/stm32-vrefbuf.c                                        |    2 
 drivers/remoteproc/qcom_q6v5_pas.c                                       |    4 
 drivers/remoteproc/qcom_q6v5_wcss.c                                      |    6 
 drivers/remoteproc/qcom_sysmon.c                                         |    5 
 drivers/rtc/class.c                                                      |    4 
 drivers/rtc/rtc-cmos.c                                                   |  378 +++----
 drivers/rtc/rtc-mxc_v2.c                                                 |    4 
 drivers/rtc/rtc-pcf85063.c                                               |   10 
 drivers/rtc/rtc-pic32.c                                                  |    8 
 drivers/rtc/rtc-rzn1.c                                                   |    4 
 drivers/rtc/rtc-snvs.c                                                   |   16 
 drivers/rtc/rtc-st-lpc.c                                                 |    1 
 drivers/s390/net/ctcm_main.c                                             |   11 
 drivers/s390/net/lcs.c                                                   |    8 
 drivers/s390/net/netiucv.c                                               |    9 
 drivers/scsi/elx/efct/efct_driver.c                                      |    1 
 drivers/scsi/elx/libefc/efclib.h                                         |    6 
 drivers/scsi/fcoe/fcoe.c                                                 |    1 
 drivers/scsi/fcoe/fcoe_sysfs.c                                           |   19 
 drivers/scsi/hisi_sas/hisi_sas_main.c                                    |    8 
 drivers/scsi/hpsa.c                                                      |    9 
 drivers/scsi/ipr.c                                                       |   10 
 drivers/scsi/libsas/sas_ata.c                                            |   25 
 drivers/scsi/libsas/sas_expander.c                                       |    4 
 drivers/scsi/libsas/sas_internal.h                                       |    2 
 drivers/scsi/lpfc/lpfc_sli.c                                             |    6 
 drivers/scsi/mpt3sas/mpt3sas_transport.c                                 |    2 
 drivers/scsi/qla2xxx/qla_def.h                                           |   22 
 drivers/scsi/qla2xxx/qla_init.c                                          |   20 
 drivers/scsi/qla2xxx/qla_inline.h                                        |    4 
 drivers/scsi/qla2xxx/qla_os.c                                            |    4 
 drivers/scsi/scsi_debug.c                                                |   11 
 drivers/scsi/scsi_error.c                                                |   14 
 drivers/scsi/smartpqi/smartpqi.h                                         |    2 
 drivers/scsi/smartpqi/smartpqi_init.c                                    |   77 +
 drivers/scsi/snic/snic_disc.c                                            |    3 
 drivers/soc/apple/rtkit.c                                                |    7 
 drivers/soc/apple/sart.c                                                 |    7 
 drivers/soc/mediatek/mtk-pm-domains.c                                    |    2 
 drivers/soc/qcom/apr.c                                                   |   15 
 drivers/soc/qcom/llcc-qcom.c                                             |    2 
 drivers/soc/ti/knav_qmss_queue.c                                         |    3 
 drivers/soc/ti/smartreflex.c                                             |    1 
 drivers/spi/spi-gpio.c                                                   |   16 
 drivers/spi/spi-mt65xx.c                                                 |    5 
 drivers/spi/spidev.c                                                     |   21 
 drivers/staging/media/imx/imx7-media-csi.c                               |    6 
 drivers/staging/media/rkvdec/rkvdec-vp9.c                                |    3 
 drivers/staging/media/stkwebcam/Kconfig                                  |    2 
 drivers/staging/media/sunxi/cedrus/cedrus_h265.c                         |   25 
 drivers/staging/media/sunxi/cedrus/cedrus_regs.h                         |    2 
 drivers/staging/r8188eu/core/rtw_led.c                                   |   29 
 drivers/staging/r8188eu/core/rtw_pwrctrl.c                               |    2 
 drivers/staging/rtl8192e/rtllib_rx.c                                     |    2 
 drivers/staging/rtl8192u/ieee80211/ieee80211_rx.c                        |    4 
 drivers/staging/vme_user/vme_fake.c                                      |    2 
 drivers/staging/vme_user/vme_tsi148.c                                    |    1 
 drivers/target/iscsi/iscsi_target_nego.c                                 |   12 
 drivers/thermal/imx8mm_thermal.c                                         |    8 
 drivers/thermal/k3_j72xx_bandgap.c                                       |    2 
 drivers/thermal/qcom/lmh.c                                               |    2 
 drivers/thermal/qcom/qcom-spmi-temp-alarm.c                              |    3 
 drivers/thermal/thermal_core.c                                           |   18 
 drivers/tty/serial/8250/8250_bcm7271.c                                   |   10 
 drivers/tty/serial/altera_uart.c                                         |   21 
 drivers/tty/serial/amba-pl011.c                                          |   14 
 drivers/tty/serial/pch_uart.c                                            |    4 
 drivers/tty/serial/serial-tegra.c                                        |    6 
 drivers/tty/serial/stm32-usart.c                                         |   47 
 drivers/tty/serial/sunsab.c                                              |    8 
 drivers/ufs/core/ufshcd.c                                                |   37 
 drivers/uio/uio_dmem_genirq.c                                            |   13 
 drivers/usb/cdns3/cdnsp-ring.c                                           |   42 
 drivers/usb/core/hcd.c                                                   |    6 
 drivers/usb/dwc3/core.c                                                  |   23 
 drivers/usb/gadget/function/f_hid.c                                      |   53 -
 drivers/usb/gadget/udc/core.c                                            |   12 
 drivers/usb/gadget/udc/fotg210-udc.c                                     |   12 
 drivers/usb/host/xhci-mtk.c                                              |    1 
 drivers/usb/host/xhci-ring.c                                             |   14 
 drivers/usb/host/xhci.h                                                  |    2 
 drivers/usb/musb/musb_gadget.c                                           |    2 
 drivers/usb/musb/omap2430.c                                              |   54 +
 drivers/usb/roles/class.c                                                |    5 
 drivers/usb/storage/alauda.c                                             |    2 
 drivers/usb/typec/bus.c                                                  |    2 
 drivers/usb/typec/tcpm/tcpci.c                                           |    5 
 drivers/usb/typec/tipd/core.c                                            |   11 
 drivers/usb/typec/wusb3801.c                                             |    2 
 drivers/vfio/platform/vfio_platform_common.c                             |    3 
 drivers/video/fbdev/Kconfig                                              |    2 
 drivers/video/fbdev/core/fbcon.c                                         |    3 
 drivers/video/fbdev/ep93xx-fb.c                                          |    4 
 drivers/video/fbdev/geode/Kconfig                                        |    1 
 drivers/video/fbdev/hyperv_fb.c                                          |    8 
 drivers/video/fbdev/pm2fb.c                                              |    9 
 drivers/video/fbdev/uvesafb.c                                            |    1 
 drivers/video/fbdev/vermilion/vermilion.c                                |    4 
 drivers/video/fbdev/via/via-core.c                                       |    9 
 drivers/virt/coco/sev-guest/sev-guest.c                                  |    1 
 drivers/watchdog/iTCO_wdt.c                                              |   21 
 drivers/xen/privcmd.c                                                    |    2 
 fs/afs/fs_probe.c                                                        |    5 
 fs/binfmt_misc.c                                                         |    8 
 fs/btrfs/file.c                                                          |   10 
 fs/char_dev.c                                                            |    2 
 fs/cifs/cifsencrypt.c                                                    |   12 
 fs/cifs/cifsfs.c                                                         |   31 
 fs/cifs/cifsglob.h                                                       |  114 ++
 fs/cifs/cifsproto.h                                                      |   17 
 fs/cifs/connect.c                                                        |    6 
 fs/cifs/dir.c                                                            |   30 
 fs/cifs/file.c                                                           |   41 
 fs/cifs/fs_context.c                                                     |   12 
 fs/cifs/inode.c                                                          |  167 +--
 fs/cifs/link.c                                                           |  107 --
 fs/cifs/misc.c                                                           |    6 
 fs/cifs/readdir.c                                                        |    2 
 fs/cifs/sess.c                                                           |   30 
 fs/cifs/smb1ops.c                                                        |   56 -
 fs/cifs/smb2file.c                                                       |  127 ++
 fs/cifs/smb2inode.c                                                      |  170 +--
 fs/cifs/smb2ops.c                                                        |  252 +---
 fs/cifs/smb2pdu.c                                                        |   20 
 fs/cifs/smb2pdu.h                                                        |    3 
 fs/cifs/smb2proto.h                                                      |   22 
 fs/configfs/dir.c                                                        |    2 
 fs/debugfs/file.c                                                        |   28 
 fs/erofs/decompressor.c                                                  |   47 
 fs/erofs/erofs_fs.h                                                      |    2 
 fs/erofs/internal.h                                                      |    1 
 fs/erofs/zdata.c                                                         |    3 
 fs/erofs/zmap.c                                                          |   25 
 fs/f2fs/compress.c                                                       |    2 
 fs/f2fs/f2fs.h                                                           |    2 
 fs/f2fs/file.c                                                           |    4 
 fs/f2fs/gc.c                                                             |   10 
 fs/f2fs/namei.c                                                          |  329 +++---
 fs/f2fs/segment.c                                                        |    8 
 fs/f2fs/super.c                                                          |    2 
 fs/hfs/inode.c                                                           |    2 
 fs/hfs/trans.c                                                           |    2 
 fs/hugetlbfs/inode.c                                                     |    6 
 fs/jfs/jfs_dmap.c                                                        |   27 
 fs/jfs/namei.c                                                           |    2 
 fs/ksmbd/mgmt/user_session.c                                             |    8 
 fs/libfs.c                                                               |   22 
 fs/lockd/svcsubs.c                                                       |   17 
 fs/nfs/fs_context.c                                                      |    6 
 fs/nfs/internal.h                                                        |    6 
 fs/nfs/namespace.c                                                       |    2 
 fs/nfs/nfs42xdr.c                                                        |    2 
 fs/nfs/nfs4proc.c                                                        |   38 
 fs/nfs/nfs4state.c                                                       |    2 
 fs/nfs/nfs4xdr.c                                                         |   22 
 fs/nfsd/nfs2acl.c                                                        |   10 
 fs/nfsd/nfs3acl.c                                                        |   30 
 fs/nfsd/nfs4callback.c                                                   |    4 
 fs/nfsd/nfs4proc.c                                                       |    7 
 fs/nfsd/nfs4state.c                                                      |   51 
 fs/nilfs2/the_nilfs.c                                                    |   73 +
 fs/ntfs3/bitmap.c                                                        |    2 
 fs/ntfs3/super.c                                                         |    2 
 fs/ntfs3/xattr.c                                                         |    2 
 fs/ocfs2/journal.c                                                       |    2 
 fs/ocfs2/journal.h                                                       |    1 
 fs/ocfs2/stackglue.c                                                     |    8 
 fs/ocfs2/super.c                                                         |    5 
 fs/orangefs/orangefs-debugfs.c                                           |   29 
 fs/orangefs/orangefs-mod.c                                               |    8 
 fs/orangefs/orangefs-sysfs.c                                             |   71 +
 fs/overlayfs/file.c                                                      |   28 
 fs/overlayfs/super.c                                                     |    7 
 fs/pstore/Kconfig                                                        |    1 
 fs/pstore/pmsg.c                                                         |    7 
 fs/pstore/ram.c                                                          |    2 
 fs/pstore/ram_core.c                                                     |    6 
 fs/reiserfs/namei.c                                                      |    4 
 fs/reiserfs/xattr_security.c                                             |    2 
 fs/sysv/itree.c                                                          |    2 
 fs/udf/namei.c                                                           |    8 
 fs/xattr.c                                                               |    2 
 include/drm/drm_connector.h                                              |    6 
 include/drm/ttm/ttm_tt.h                                                 |    2 
 include/dt-bindings/clock/imx8mn-clock.h                                 |   24 
 include/dt-bindings/clock/imx8mp-clock.h                                 |    3 
 include/dt-bindings/clock/qcom,lpassaudiocc-sc7280.h                     |    5 
 include/dt-bindings/clock/qcom,lpasscorecc-sc7280.h                      |    2 
 include/linux/btf_ids.h                                                  |    2 
 include/linux/debugfs.h                                                  |   19 
 include/linux/eventfd.h                                                  |    2 
 include/linux/fortify-string.h                                           |   31 
 include/linux/fs.h                                                       |   12 
 include/linux/hisi_acc_qm.h                                              |   37 
 include/linux/hyperv.h                                                   |    2 
 include/linux/ieee80211.h                                                |    2 
 include/linux/iio/imu/adis.h                                             |   13 
 include/linux/netdevice.h                                                |   58 -
 include/linux/proc_fs.h                                                  |    2 
 include/linux/regulator/driver.h                                         |    3 
 include/linux/skmsg.h                                                    |    1 
 include/linux/timerqueue.h                                               |    2 
 include/media/dvbdev.h                                                   |   32 
 include/net/bluetooth/hci.h                                              |   20 
 include/net/bluetooth/hci_core.h                                         |    7 
 include/net/dst.h                                                        |    5 
 include/net/ip_vs.h                                                      |   10 
 include/net/mrp.h                                                        |    1 
 include/net/sock_reuseport.h                                             |    2 
 include/net/tcp.h                                                        |    4 
 include/scsi/sas_ata.h                                                   |    6 
 include/sound/hda_codec.h                                                |    2 
 include/sound/hdaudio.h                                                  |    1 
 include/sound/pcm.h                                                      |   36 
 include/trace/events/f2fs.h                                              |   34 
 include/trace/events/ib_mad.h                                            |   13 
 include/uapi/linux/idxd.h                                                |    2 
 include/uapi/linux/swab.h                                                |    2 
 include/uapi/rdma/hns-abi.h                                              |   15 
 include/uapi/sound/asequencer.h                                          |    8 
 io_uring/msg_ring.c                                                      |    2 
 io_uring/net.c                                                           |    2 
 io_uring/timeout.c                                                       |    4 
 ipc/mqueue.c                                                             |    6 
 kernel/acct.c                                                            |    2 
 kernel/bpf/btf.c                                                         |    5 
 kernel/bpf/syscall.c                                                     |    6 
 kernel/bpf/verifier.c                                                    |  108 +-
 kernel/cpu.c                                                             |   60 -
 kernel/events/core.c                                                     |    8 
 kernel/fork.c                                                            |   17 
 kernel/futex/core.c                                                      |   26 
 kernel/gcov/gcc_4_7.c                                                    |    5 
 kernel/irq/internals.h                                                   |    2 
 kernel/irq/irqdesc.c                                                     |   15 
 kernel/kprobes.c                                                         |   16 
 kernel/module/decompress.c                                               |    8 
 kernel/padata.c                                                          |   15 
 kernel/power/snapshot.c                                                  |    4 
 kernel/rcu/tree.c                                                        |    2 
 kernel/relay.c                                                           |    4 
 kernel/sched/core.c                                                      |   10 
 kernel/sched/cpudeadline.c                                               |    2 
 kernel/sched/deadline.c                                                  |    4 
 kernel/sched/fair.c                                                      |  231 +++-
 kernel/sched/psi.c                                                       |    8 
 kernel/sched/rt.c                                                        |    4 
 kernel/sched/sched.h                                                     |   56 +
 kernel/trace/blktrace.c                                                  |    3 
 kernel/trace/trace_events_hist.c                                         |    2 
 kernel/trace/trace_events_user.c                                         |    1 
 lib/debugobjects.c                                                       |   10 
 lib/fonts/fonts.c                                                        |    4 
 lib/notifier-error-inject.c                                              |    2 
 lib/test_firmware.c                                                      |    1 
 mm/gup.c                                                                 |    3 
 net/802/mrp.c                                                            |   18 
 net/8021q/vlan_dev.c                                                     |    4 
 net/9p/client.c                                                          |    5 
 net/bluetooth/hci_conn.c                                                 |    2 
 net/bluetooth/hci_core.c                                                 |    4 
 net/bluetooth/hci_sync.c                                                 |    2 
 net/bluetooth/lib.c                                                      |    4 
 net/bluetooth/mgmt.c                                                     |    2 
 net/bluetooth/rfcomm/core.c                                              |    2 
 net/bpf/test_run.c                                                       |    3 
 net/bridge/br_multicast.c                                                |    4 
 net/bridge/br_vlan.c                                                     |    4 
 net/core/dev.c                                                           |   18 
 net/core/devlink.c                                                       |    9 
 net/core/drop_monitor.c                                                  |    8 
 net/core/filter.c                                                        |   11 
 net/core/gen_stats.c                                                     |   16 
 net/core/skbuff.c                                                        |    3 
 net/core/skmsg.c                                                         |    9 
 net/core/sock.c                                                          |    2 
 net/core/sock_map.c                                                      |    2 
 net/core/sock_reuseport.c                                                |   94 +
 net/core/stream.c                                                        |    6 
 net/dsa/slave.c                                                          |    4 
 net/dsa/tag_8021q.c                                                      |   11 
 net/ethtool/ioctl.c                                                      |    3 
 net/hsr/hsr_debugfs.c                                                    |   40 
 net/hsr/hsr_device.c                                                     |   32 
 net/hsr/hsr_forward.c                                                    |   14 
 net/hsr/hsr_framereg.c                                                   |  222 +---
 net/hsr/hsr_framereg.h                                                   |   17 
 net/hsr/hsr_main.h                                                       |    9 
 net/hsr/hsr_netlink.c                                                    |    4 
 net/ipv4/af_inet.c                                                       |    8 
 net/ipv4/inet_connection_sock.c                                          |    5 
 net/ipv4/ping.c                                                          |    2 
 net/ipv4/tcp_bpf.c                                                       |   19 
 net/ipv4/udp.c                                                           |   39 
 net/ipv4/udp_tunnel_core.c                                               |    1 
 net/ipv6/af_inet6.c                                                      |    4 
 net/ipv6/datagram.c                                                      |   15 
 net/ipv6/seg6_local.c                                                    |    4 
 net/ipv6/sit.c                                                           |   22 
 net/ipv6/udp.c                                                           |   12 
 net/mac80211/cfg.c                                                       |    2 
 net/mac80211/ieee80211_i.h                                               |    1 
 net/mac80211/iface.c                                                     |    1 
 net/mac80211/mlme.c                                                      |   15 
 net/mac80211/sta_info.c                                                  |    8 
 net/mac80211/tx.c                                                        |    2 
 net/mctp/device.c                                                        |   14 
 net/mpls/af_mpls.c                                                       |    4 
 net/netfilter/ipvs/ip_vs_core.c                                          |   30 
 net/netfilter/ipvs/ip_vs_ctl.c                                           |   14 
 net/netfilter/ipvs/ip_vs_est.c                                           |   20 
 net/netfilter/nf_conntrack_proto_icmpv6.c                                |   53 +
 net/netfilter/nf_flow_table_offload.c                                    |    6 
 net/netfilter/nf_tables_api.c                                            |    4 
 net/openvswitch/datapath.c                                               |   29 
 net/openvswitch/flow_table.c                                             |    9 
 net/rxrpc/output.c                                                       |    2 
 net/rxrpc/sendmsg.c                                                      |    2 
 net/sched/ematch.c                                                       |    2 
 net/sctp/sysctl.c                                                        |   73 -
 net/sunrpc/clnt.c                                                        |    2 
 net/sunrpc/xprtrdma/verbs.c                                              |    2 
 net/tls/tls_sw.c                                                         |    6 
 net/unix/af_unix.c                                                       |   12 
 net/vmw_vsock/vmci_transport.c                                           |    6 
 net/wireless/nl80211.c                                                   |    3 
 net/wireless/reg.c                                                       |    4 
 samples/bpf/xdp1_user.c                                                  |    2 
 samples/bpf/xdp2_kern.c                                                  |    4 
 samples/vfio-mdev/mdpy-fb.c                                              |    8 
 security/Kconfig.hardening                                               |    3 
 security/apparmor/apparmorfs.c                                           |    4 
 security/apparmor/label.c                                                |   12 
 security/apparmor/lsm.c                                                  |    4 
 security/apparmor/policy.c                                               |    2 
 security/apparmor/policy_ns.c                                            |    2 
 security/apparmor/policy_unpack.c                                        |    2 
 security/integrity/digsig.c                                              |    6 
 security/integrity/ima/ima_policy.c                                      |   51 
 security/integrity/ima/ima_template.c                                    |    4 
 security/loadpin/loadpin.c                                               |   30 
 sound/core/pcm_native.c                                                  |    4 
 sound/drivers/mts64.c                                                    |    3 
 sound/hda/hdac_stream.c                                                  |   17 
 sound/pci/asihpi/hpioctl.c                                               |    2 
 sound/pci/hda/hda_codec.c                                                |    3 
 sound/pci/hda/hda_controller.c                                           |    4 
 sound/pci/hda/patch_hdmi.c                                               |  273 ++---
 sound/pci/hda/patch_realtek.c                                            |   27 
 sound/soc/amd/yc/acp6x-mach.c                                            |    7 
 sound/soc/codecs/hda.c                                                   |    3 
 sound/soc/codecs/hdac_hda.c                                              |    3 
 sound/soc/codecs/pcm512x.c                                               |    8 
 sound/soc/codecs/rt298.c                                                 |    7 
 sound/soc/codecs/rt5670.c                                                |    2 
 sound/soc/codecs/wm8994.c                                                |    5 
 sound/soc/codecs/wsa883x.c                                               |    6 
 sound/soc/generic/audio-graph-card.c                                     |    4 
 sound/soc/intel/avs/boards/rt298.c                                       |   24 
 sound/soc/intel/avs/core.c                                               |    2 
 sound/soc/intel/avs/ipc.c                                                |    6 
 sound/soc/intel/boards/sof_es8336.c                                      |    2 
 sound/soc/intel/skylake/skl.c                                            |    5 
 sound/soc/mediatek/common/mtk-btcvsd.c                                   |    6 
 sound/soc/mediatek/mt8173/mt8173-afe-pcm.c                               |   20 
 sound/soc/mediatek/mt8173/mt8173-rt5650-rt5514.c                         |    7 
 sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c               |   14 
 sound/soc/pxa/mmp-pcm.c                                                  |    2 
 sound/soc/qcom/lpass-sc7180.c                                            |    3 
 sound/soc/rockchip/rockchip_pdm.c                                        |    1 
 sound/soc/rockchip/rockchip_spdif.c                                      |    1 
 sound/usb/quirks-table.h                                                 |    2 
 tools/bpf/bpftool/common.c                                               |    1 
 tools/lib/bpf/bpf.h                                                      |    7 
 tools/lib/bpf/btf.c                                                      |    8 
 tools/lib/bpf/btf_dump.c                                                 |   29 
 tools/lib/bpf/libbpf.c                                                   |   30 
 tools/lib/bpf/usdt.c                                                     |   11 
 tools/objtool/check.c                                                    |   10 
 tools/perf/builtin-stat.c                                                |   33 
 tools/perf/builtin-trace.c                                               |   32 
 tools/perf/tests/shell/stat_all_pmu.sh                                   |   13 
 tools/perf/util/bpf_off_cpu.c                                            |    2 
 tools/perf/util/debug.c                                                  |    4 
 tools/perf/util/symbol-elf.c                                             |    2 
 tools/testing/selftests/bpf/bpf_testmod/bpf_testmod.c                    |   48 
 tools/testing/selftests/bpf/config                                       |    1 
 tools/testing/selftests/bpf/network_helpers.c                            |    4 
 tools/testing/selftests/bpf/prog_tests/empty_skb.c                       |  146 ++
 tools/testing/selftests/bpf/prog_tests/kprobe_multi_test.c               |   26 
 tools/testing/selftests/bpf/prog_tests/lsm_cgroup.c                      |   17 
 tools/testing/selftests/bpf/prog_tests/map_kptr.c                        |    3 
 tools/testing/selftests/bpf/prog_tests/tracing_struct.c                  |   64 +
 tools/testing/selftests/bpf/prog_tests/xdp_adjust_tail.c                 |    7 
 tools/testing/selftests/bpf/prog_tests/xdp_do_redirect.c                 |    2 
 tools/testing/selftests/bpf/prog_tests/xdp_synproxy.c                    |    2 
 tools/testing/selftests/bpf/progs/bpf_iter_ksym.c                        |    6 
 tools/testing/selftests/bpf/progs/empty_skb.c                            |   37 
 tools/testing/selftests/bpf/progs/lsm_cgroup.c                           |    8 
 tools/testing/selftests/bpf/progs/tracing_struct.c                       |  120 ++
 tools/testing/selftests/bpf/xdp_synproxy.c                               |    5 
 tools/testing/selftests/cgroup/cgroup_util.c                             |    5 
 tools/testing/selftests/drivers/net/netdevsim/devlink.sh                 |    4 
 tools/testing/selftests/efivarfs/efivarfs.sh                             |    5 
 tools/testing/selftests/ftrace/test.d/ftrace/func_event_triggers.tc      |   15 
 tools/testing/selftests/netfilter/conntrack_icmp_related.sh              |   36 
 tools/testing/selftests/powerpc/dscr/dscr_sysfs_test.c                   |    5 
 tools/testing/selftests/proc/proc-uptime-002.c                           |    3 
 1026 files changed, 12879 insertions(+), 6775 deletions(-)

Aakarsh Jain (1):
      media: s5p-mfc: Add variant data for MFC v7 hardware for Exynos 3250 SoC

Abdun Nihaal (1):
      fs/ntfs3: Fix slab-out-of-bounds read in ntfs_trim_fs

Abhinav Kumar (1):
      drm/bridge: adv7533: remove dynamic lane switching from adv7533 bridge

Aditya Kumar Singh (2):
      wifi: ath11k: move firmware stats out of debugfs
      wifi: ath11k: fix firmware assert during bandwidth change for peer sta

Adriana Kobylak (1):
      ARM: dts: aspeed: rainier,everest: Move reserved memory regions

Ajay Kaher (1):
      perf symbol: correction while adjusting symbol

Akinobu Mita (3):
      libfs: add DEFINE_SIMPLE_ATTRIBUTE_SIGNED for signed value
      lib/notifier-error-inject: fix error when writing -errno to debugfs file
      debugfs: fix error when writing negative value to atomic_t debugfs file

Al Cooper (1):
      phy: usb: s2 WoL wakeup_count not incremented for USB->Eth devices

Al Viro (2):
      alpha: fix TIF_NOTIFY_SIGNAL handling
      alpha: fix syscall entry in !AUDUT_SYSCALL case

Alan Maguire (1):
      libbpf: Btf dedup identical struct test needs check for nested structs/arrays

Alan Previn (3):
      drm/i915/guc: Add a helper for log buffer size
      drm/i915/guc: Add error-capture init warnings when needed
      drm/i915/guc: Fix GuC error capture sizing estimation and reporting

Alexander Stein (1):
      rtc: pcf85063: Fix reading alarm

Alexander Sverdlin (1):
      spi: spidev: mask SPI_CS_HIGH in SPI_IOC_RD_MODE

Alexandre Belloni (1):
      rtc: pcf85063: fix pcf85063_clkout_control

Alexandre Ghiti (1):
      riscv: Fix P4D_SHIFT definition for 3-level page table mode

Alexey Dobriyan (1):
      proc: fixup uptime selftest

Alexey Izbyshev (1):
      futex: Resend potentially swallowed owner death notification

Allen-KH Cheng (1):
      mtd: spi-nor: Fix the number of bytes for the dummy cycles

Alvin Lee (1):
      drm/amd/display: Fix DTBCLK disable requests and SRC_SEL programming

Amadeusz Sławiński (2):
      ASoC: codecs: rt298: Add quirk for KBL-R RVP platform
      ASoC: Intel: avs: Add quirk for KBL-R RVP platform

Amir Goldstein (2):
      ovl: remove privs in ovl_copyfile()
      ovl: remove privs in ovl_fallocate()

Anastasia Belova (1):
      MIPS: BCM63xx: Add check for NULL for clk in clk_enable

Andrew Bresticker (1):
      RISC-V: Fix unannoted hardirqs-on in return to userspace slow-path

Andrew Jeffery (1):
      ipmi: kcs: Poll OBF briefly to reduce OBE latency

Andrii Nakryiko (4):
      libbpf: Reject legacy 'maps' ELF section
      bpf: propagate precision in ALU/ALU64 operations
      bpf: propagate precision across all frames, not just the last one
      libbpf: Avoid enum forward-declarations in public API in C++ mode

Andrzej Pietrasiewicz (1):
      media: rkvdec: Add required padding

Andy Shevchenko (1):
      fbdev: ssd1307fb: Drop optional dependency

AngeloGioacchino Del Regno (9):
      arm64: dts: mediatek: mt8195: Fix CPUs capacity-dmips-mhz
      arm64: dts: mt7896a: Fix unit_address_vs_reg warning for oscillator
      arm64: dts: mt6779: Fix devicetree build warnings
      arm64: dts: mt2712e: Fix unit_address_vs_reg warning for oscillators
      arm64: dts: mt2712e: Fix unit address for pinctrl node
      arm64: dts: mt2712-evb: Fix vproc fixed regulators unit names
      arm64: dts: mt2712-evb: Fix usb vbus regulators unit names
      arm64: dts: mediatek: pumpkin-common: Fix devicetree warnings
      arm64: dts: mediatek: mt6797: Fix 26M oscillator unit name

Anna Schumaker (2):
      NFSv4.2: Set the correct size scratch buffer for decoding READ_PLUS
      NFS: Allow very small rsize & wsize again

Anssi Hannula (4):
      can: kvaser_usb_leaf: Set Warning state even without bus errors
      can: kvaser_usb_leaf: Fix improved state not being reported
      can: kvaser_usb_leaf: Fix wrong CAN state after stopping
      can: kvaser_usb_leaf: Fix bogus restart events

Anup Patel (2):
      RISC-V: Fix MEMREMAP_WB for systems with Svpbmt
      RISC-V: KVM: Fix reg_val check in kvm_riscv_vcpu_set_reg_config()

Ard Biesheuvel (1):
      ftrace: Allow WITH_ARGS flavour of graph tracer with shadow call stack

Arnd Bergmann (2):
      RDMA/siw: Fix pointer cast warning
      drm/amd/pm: avoid large variable on kernel stack

Artem Chernyshev (1):
      net: vmw_vsock: vmci: Check memcpy_from_msg()

Artem Lukyanov (1):
      ASoC: amd: yc: Add Xiaomi Redmi Book Pro 14 2022 into DMI table

Arun Easi (1):
      scsi: qla2xxx: Fix crash when I/O abort times out

Aurabindo Pillai (1):
      drm/amd/display: fix array index out of bound error in bios parser

Avraham Stern (2):
      wifi: iwlwifi: mei: make sure ownership confirmed message is sent
      wifi: iwlwifi: mei: avoid blocking sap messages handling due to rtnl lock

Baisong Zhong (3):
      ALSA: pcm: fix undefined behavior in bit shift for SNDRV_PCM_RATE_KNOT
      ALSA: seq: fix undefined behavior in bit shift for SNDRV_SEQ_FILTER_USE_EVENT
      media: dvb-usb: az6027: fix null-ptr-deref in az6027_i2c_xfer()

Barnabás Pőcze (2):
      platform/x86: huawei-wmi: fix return value calculation
      timerqueue: Use rb_entry_safe() in timerqueue_getnext()

Bart Van Assche (4):
      scsi: core: Fix a race between scsi_done() and scsi_timeout()
      scsi: qla2xxx: Fix set-but-not-used variable warnings
      scsi: ufs: core: Fix the polling implementation
      scsi: ufs: Reduce the START STOP UNIT timeout

Bartosz Golaszewski (2):
      gpiolib: cdev: fix NULL-pointer dereferences
      gpiolib: protect the GPIO device against being dropped while in use by user-space

Bartosz Staszewski (1):
      i40e: Fix the inability to attach XDP program on downed interface

Bastien Nocera (1):
      HID: logitech-hidpp: Guard FF init code against non-USB devices

Beau Belgrave (1):
      tracing/user_events: Fix call print_fmt leak

Ben Greear (1):
      wifi: iwlwifi: mvm: fix double free on tx path.

Bernard Metzler (2):
      RDMA/siw: Fix immediate work request flush to completion queue
      RDMA/siw: Set defined status for work completion with undefined status

Bitterblue Smith (4):
      wifi: rtl8xxxu: Fix reading the vendor of combo chips
      wifi: rtl8xxxu: Fix use after rcu_read_unlock in rtl8xxxu_bss_info_changed
      wifi: rtl8xxxu: Add __packed to struct rtl8723bu_c2h
      wifi: rtl8xxxu: Fix the channel width reporting

Bjorn Andersson (1):
      thermal/drivers/qcom/lmh: Fix irq handler return value

Bjorn Helgaas (1):
      Revert "PCI: Clear PCI_STATUS when setting up device"

Björn Töpel (1):
      bpf: Do not zero-extend kfunc return values

Brian Foster (1):
      NFSD: pass range end to vfs_fsync_range() instead of count

Brian Starkey (1):
      drm/fourcc: Fix vsub/hsub for Q410 and Q401

Bryan O'Donoghue (1):
      dt-bindings: mfd: qcom,spmi-pmic: Drop PWM reg dependency

Cai Xinchen (1):
      rapidio: devices: fix missing put_device in mport_cdev_open

Cezary Rojewski (4):
      ASoC: Intel: avs: Fix DMA mask assignment
      ASoC: Intel: avs: Fix potential RX buffer overflow
      ASoC: Intel: avs: Lock substream before snd_pcm_stop()
      ASoC: Intel: Skylake: Fix driver hang during shutdown

Chao Yu (2):
      f2fs: fix to invalidate dcc->f2fs_issue_discard in error path
      f2fs: fix to destroy sbi->post_read_wq in error path of f2fs_fill_super()

Chen Hui (1):
      cpufreq: qcom-hw: Fix memory leak in qcom_cpufreq_hw_read_lut()

Chen Jiahao (1):
      drivers: soc: ti: knav_qmss_queue: Mark knav_acc_firmwares as static

Chen Zhongjin (12):
      perf: Fix possible memleak in pmu_dev_alloc()
      erofs: Fix pcluster memleak when its block address is zero
      fs: sysv: Fix sysv_nblocks() returns wrong value
      media: vidtv: Fix use-after-free in vidtv_bridge_dvb_init()
      media: vimc: Fix wrong function called when vimc_init() fails
      media: dvb-core: Fix ignored return value in dvb_register_frontend()
      wifi: cfg80211: Fix not unregister reg_pdev when load_builtin_regdb_keys() fails
      configfs: fix possible memory leak in configfs_create_dir()
      scsi: efct: Fix possible memleak in efct_device_init()
      scsi: fcoe: Fix transport not deattached when fcoe_if_init() fails
      vme: Fix error not catched in fake_init()
      ovl: fix use inode directly in rcu-walk mode

Chen-Yu Tsai (1):
      arm64: dts: mt8183: Fix Mali GPU clock

ChenXiaoSong (1):
      cifs: fix use-after-free on the link name

Chengchang Tang (5):
      RDMA/hns: Fix AH attr queried by query_qp
      RDMA/hns: Fix PBL page MTR find
      RDMA/hns: Fix page size cap from firmware
      RDMA/hns: Fix error code of CMD
      RDMA/hns: Fix XRC caps on HIP08

ChiYuan Huang (2):
      regulator: core: Use different devices for resource allocation and DT lookup
      regulator: core: Fix resolve supply lookup issue

Christian Marangi (1):
      clk: qcom: clk-krait: fix wrong div2 functions

Christoph Böhmwalder (1):
      drbd: use blk_queue_max_discard_sectors helper

Christoph Hellwig (6):
      nvmet: only allocate a single slab for bvecs
      block: clear ->slave_dir when dropping the main slave_dir reference
      dm: cleanup open_table_device
      dm: cleanup close_table_device
      dm: track per-add_disk holder relations in DM
      media: videobuf-dma-contig: use dma_mmap_coherent

Christophe JAILLET (8):
      wifi: rtw89: Fix some error handling path in rtw89_core_sta_assoc()
      Bluetooth: Fix EALREADY and ELOOP cases in bt_status()
      crypto: amlogic - Remove kcalloc without check
      fbdev: uvesafb: Fixes an error handling path in uvesafb_probe()
      powerpc/52xx: Fix a resource leak in an error handling path
      mfd: qcom_rpm: Fix an error handling path in qcom_rpm_probe()
      myri10ge: Fix an error handling path in myri10ge_probe()
      mfd: qcom_rpm: Use devm_of_platform_populate() to simplify code

Chuck Lever (2):
      NFSD: Finish converting the NFSv2 GETACL result encoder
      NFSD: Finish converting the NFSv3 GETACL result encoder

Chun-Jie Chen (1):
      soc: mediatek: pm-domains: Fix the power glitch issue

Chunfeng Yun (1):
      usb: xhci-mtk: fix leakage of shared hcd when fail to set wakeup irq

Cole Robinson (1):
      virt/sev-guest: Add a MODULE_ALIAS

Cong Dang (1):
      memory: renesas-rpc-if: Clear HS bit during hardware initialization

Cong Wang (1):
      net_sched: reject TCF_EM_SIMPLE case for complex ematch module

Conor Dooley (2):
      dt-bindings: pwm: fix microchip corePWM's pwm-cells
      mailbox: mpfs: read the system controller's status

Corentin Labbe (8):
      crypto: sun8i-ss - use dma_addr instead u32
      crypto: rockchip - do not do custom power management
      crypto: rockchip - do not store mode globally
      crypto: rockchip - add fallback for cipher
      crypto: rockchip - add fallback for ahash
      crypto: rockchip - better handle cipher key
      crypto: rockchip - remove non-aligned handling
      crypto: rockchip - rework by using crypto_engine

Cosmin Tanislav (1):
      iio: temperature: ltc2983: make bulk write buffer DMA-safe

Dan Aloni (1):
      nfsd: under NFSv4.1, fix double svc_xprt_put on rpc_create failure

Dan Carpenter (5):
      amdgpu/pm: prevent array underflow in vega20_odn_edit_dpm_table()
      bonding: uninitialized variable in bond_miimon_inspect()
      staging: rtl8192u: Fix use after free in ieee80211_rx()
      fs/ntfs3: Harden against integer overflows
      iommu/mediatek: Fix forever loop in error handling

Daniel Golle (2):
      clk: mediatek: fix dependency of MT7986 ADC clocks
      pwm: mediatek: always use bus clock for PWM on MT7622

Daniel Jordan (2):
      padata: Always leave BHs disabled when running ->parallel()
      padata: Fix list iterator in padata_do_serial()

Dario Binacchi (5):
      clk: imx8mn: rename vpu_pll to m7_alt_pll
      clk: imx: replace osc_hdmi with dummy
      clk: imx: rename video_pll1 to video_pll
      clk: imx8mn: fix imx8mn_sai2_sels clocks list
      clk: imx8mn: fix imx8mn_enet_phy_sels clocks list

David Hildenbrand (1):
      mm/gup: disallow FOLL_FORCE|FOLL_WRITE on hugetlb mappings

David Howells (4):
      net, proc: Provide PROC_FS=n fallback for proc_create_net_single_write()
      rxrpc: Fix ack.bufferSize to be 0 when generating an ack
      rxrpc: Fix missing unlock in rxrpc_do_sendmsg()
      afs: Fix lost servers_outstanding count

David Jeffery (1):
      blk-mq: avoid double ->queue_rq() because of early timeout

Denis Pauk (1):
      hwmon: (nct6775) add ASUS CROSSHAIR VIII/TUF/ProArt B550M

Deren Wu (1):
      wifi: mt76: fix coverity overrun-call in mt76_get_txpower()

Dietmar Eggemann (1):
      sched/core: Introduce sched_asym_cpucap_active()

Dmitry Baryshkov (9):
      arm64: dts: qcom: msm8996: fix supported-hw in cpufreq OPP tables
      arm64: dts: qcom: msm8996: fix GPU OPP table
      drm/msm/mdp5: stop overriding drvdata
      drm/msm/hdmi: use devres helper for runtime PM management
      drm/msm/dpu: use drm_dsc_config instead of msm_display_dsc_config
      drm/msm/dsi: use drm_dsc_config instead of msm_display_dsc_config
      clk: qcom: gcc-ipq806x: use parent_data for the last remaining entry
      drm/msm/mdp5: fix reading hw revision on db410c platform
      led: qcom-lpg: Fix sleeping in atomic

Dmitry Torokhov (4):
      arm64: dts: qcom: msm8996: fix sound card reset line polarity
      arm64: dts: qcom: sm8250-mtp: fix reset line polarity
      HID: i2c: let RMI devices decide what constitutes wakeup event
      ASoC: dt-bindings: wcd9335: fix reset line polarity in example

Dongdong Zhang (1):
      f2fs: fix normal discard process

Dongliang Mu (1):
      fs: jfs: fix shift-out-of-bounds in dbAllocAG

Doug Brown (2):
      ARM: mmp: fix timer_read delay
      drm/etnaviv: add missing quirks for GC300

Douglas Anderson (3):
      Input: elants_i2c - properly handle the reset GPIO when power is off
      clk: qcom: lpass-sc7280: Fix pm_runtime usage
      clk: qcom: lpass-sc7180: Fix pm_runtime usage

Dr. David Alan Gilbert (1):
      jfs: Fix fortify moan in symlink

Dragos Tatulea (1):
      IB/IPoIB: Fix queue count inconsistency for PKEY child interfaces

Duoming Zhou (1):
      drivers: staging: r8188eu: Fix sleep-in-atomic-context bug in rtw_join_timeout_handler

Eddie James (2):
      tpm: tis_i2c: Fix sanity check interrupt enable mask
      tpm: Add flag to use default cancellation policy

Edward Pacman (1):
      ALSA: hda/realtek: Add quirk for Lenovo TianYi510Pro-14IOB

Eelco Chaudron (1):
      openvswitch: Fix flow lookup to use unmasked key

Emeel Hakim (1):
      net: macsec: fix net device access prior to holding a lock

Emmanuel Grumbach (2):
      wifi: iwlwifi: mei: don't send SAP commands if AMT is disabled
      wifi: iwlwifi: mei: fix tx DHCP packet for devices with new Tx API

Enrik Berkhan (1):
      HID: mcp2221: don't connect hidraw

Enzo Matsumiya (1):
      cifs: replace kfree() with kfree_sensitive() for sensitive data

Eric Dumazet (4):
      bpf, sockmap: fix race in sock_map_free()
      net: stream: purge sk_error_queue in sk_stream_kill_queues()
      net: add atomic_long_t to net_device_stats fields
      ipv6/sit: use DEV_STATS_INC() to avoid data-races

Eric Pilmore (1):
      ntb_netdev: Use dev_kfree_skb_any() in interrupt context

Fabrice Gasnier (1):
      counter: stm32-lptimer-cnt: fix the check on arr and cmp registers update

Fabrizio Castro (1):
      arm64: dts: renesas: r9a09g011: Fix unit address format error

Fedor Pchelkin (3):
      wifi: ath9k: hif_usb: fix memory leak of urbs in ath9k_hif_usb_dealloc_tx_urbs()
      wifi: ath9k: hif_usb: Fix use-after-free in ath9k_hif_usb_reg_in_cb()
      wifi: ath9k: verify the expected usb_endpoints are present

Felix Fietkau (1):
      net: ethernet: mtk_eth_soc: drop packets to WDMA if the ring is full

Fenghua Yu (1):
      dmaengine: idxd: Fix crc_val field for completion record

Ferry Toth (1):
      usb: dwc3: core: defer probe on ulpi_read_id timeout

Filipe Manana (1):
      btrfs: do not BUG_ON() on ENOMEM when dropping extent items for a range

Firo Yang (1):
      sctp: sysctl: make extra pointers netns aware

Florian Westphal (1):
      netfilter: conntrack: set icmpv6 redirects as RELATED

Francisco Munoz (1):
      PCI: vmd: Fix secondary bus reset for Intel bridges

Frank Li (1):
      PCI: endpoint: pci-epf-vntb: Fix call pci_epc_mem_free_addr() in error path

Frank Wunderlich (2):
      arm64: dts: mt7986: fix trng node name
      dt-bindings: pinctrl: update uart/mmc bindings for MT7986 SoC

GUO Zihua (4):
      ima: Handle -ESTALE returned by ima_filter_rule_match()
      integrity: Fix memory leakage in keyring allocation error path
      rtc: mxc_v2: Add missing clk_disable_unprepare()
      ima: Simplify ima_lsm_copy_rule

Gabriel Somlo (2):
      mmc: litex_mmc: ensure `host->irq == 0` if polling
      serial: altera_uart: fix locking in polling mode

Gao Xiang (2):
      erofs: fix missing unmap if z_erofs_get_extent_compressedlen() fails
      erofs: validate the extent length for uncompressed pclusters

Gaosheng Cui (16):
      lib/fonts: fix undefined behavior in bit shift for get_default_font
      drm/ttm: fix undefined behavior in bit shift for TTM_TT_FLAG_PRIV_POPULATED
      mtd: core: fix possible resource leak in init_mtd()
      ALSA: mts64: fix possible null-ptr-defer in snd_mts64_interrupt
      pinctrl: thunderbay: fix possible memory leak in thunderbay_build_functions()
      net: stmmac: fix possible memory leak in stmmac_dvr_probe()
      apparmor: fix a memleak in multi_transaction_new()
      crypto: ccree - Remove debugfs when platform_driver_register failed
      scsi: snic: Fix possible UAF in snic_tgt_create()
      crypto: img-hash - Fix variable dereferenced before check 'hdev->req'
      staging: vme_user: Fix possible UAF in tsi148_dma_list_add
      fbdev: ep93xx-fb: Add missing clk_disable_unprepare in ep93xxfb_probe()
      remoteproc: sysmon: fix memory leak in qcom_add_sysmon_subdev()
      rtc: st-lpc: Add missing clk_disable_unprepare in st_rtc_probe()
      rtc: pic32: Move devm_rtc_allocate_device earlier in pic32_rtc_probe()
      net: stmmac: fix errno when create_singlethread_workqueue() fails

Gaurav Kohli (1):
      x86/hyperv: Remove unregister syscore call from Hyper-V cleanup

Gautam Menghani (1):
      media: imon: fix a race condition in send_packet()

Gavrilov Ilia (1):
      relay: fix type mismatch when allocating memory in relay_create_buf()

Geert Uytterhoeven (3):
      arm64: dts: renesas: r8a779g0: Fix HSCIF0 "brg_int" clock
      media: staging: stkwebcam: Restore MEDIA_{USB,CAMERA}_SUPPORT dependencies
      clk: renesas: r8a779f0: Fix SD0H clock name

George Shen (1):
      drm/amd/display: Workaround to increase phantom pipe vactive in pipesplit

Georgi Vlaev (1):
      firmware: ti_sci: Fix polled mode during system suspend

Gerhard Engleder (2):
      samples/bpf: Fix map iteration in xdp1_user
      samples/bpf: Fix MAC address swapping in xdp2_kern

Giulio Benetti (1):
      clk: imx: imxrt1050: fix IMXRT1050_CLK_LCDIF_APB offsets

Greg Kroah-Hartman (1):
      Linux 6.0.16

Guchun Chen (1):
      drm/amd/pm/smu11: BACO is supported when it's in BACO state

Guenter Roeck (1):
      iommu/mediatek: Validate number of phandles associated with "mediatek,larbs"

Guilherme G. Piccoli (2):
      x86/split_lock: Add sysctl to control the misery mode
      video: hyperv_fb: Avoid taking busy spinlock on panic path

Guoniu.zhou (1):
      media: ov5640: set correct default link frequency

Gustavo A. R. Silva (1):
      powerpc/xmon: Fix -Wswitch-unreachable warning in bpt_cmds

Haibo Chen (1):
      clk: imx93: correct the flexspi1 clock setting

Haiyi Zhou (1):
      drm/amd/display: wait for vblank during pipe programming

Hamza Mahfooz (2):
      drm/edid: add a quirk for two LG monitors to get them to work on 10bpc
      Revert "drm/amd/display: Limit max DSC target bpp for specific monitors"

Hangbin Liu (3):
      net/tunnel: wait until all sk_user_data reader finish before releasing the sock
      bonding: add missed __rcu annotation for curr_active_slave
      bonding: do failover when high prio link up

Hanjun Guo (1):
      drm/radeon: Add the missed acpi_put_table() to fix memory leak

Hans Verkuil (1):
      media: v4l2-ctrls-api.c: add back dropped ctrl->is_new = 1

Hans de Goede (4):
      power: supply: bq25890: Ensure pump_express_work is cancelled on remove
      ACPI: x86: Add skip i2c clients quirk for Lenovo Yoga Tab 3 Pro (YT3-X90F)
      ACPI: x86: Add skip i2c clients quirk for Medion Lifetab S10346
      ASoC: rt5670: Remove unbalanced pm_runtime_put()

Hao Lee (1):
      sched/psi: Fix possible missing or delayed pending event

Harshit Mogalapalli (4):
      xen/privcmd: Fix a possible warning in privcmd_ioctl_mmap_resource()
      scsi: scsi_debug: Fix a warning in resp_write_scat()
      scsi: scsi_debug: Fix a warning in resp_verify()
      scsi: scsi_debug: Fix a warning in resp_report_zones()

Hawkins Jiawei (2):
      nfs: fix possible null-ptr-deref when parsing param
      hugetlbfs: fix null-ptr-deref in hugetlbfs_parse_param()

Herbert Xu (1):
      crypto: cryptd - Use request context instead of stack for sub-request

Hoi Pok Wu (1):
      fs: jfs: fix shift-out-of-bounds in dbDiscardAG

Hui Tang (2):
      mtd: lpddr2_nvm: Fix possible null-ptr-deref
      i2c: pxa-pci: fix missing pci_disable_device() on error in ce4100_i2c_probe

Huisong Li (1):
      mailbox: pcc: Reset pcc_chan_count to zero in case of PCC probe failure

Inga Stotland (1):
      Bluetooth: MGMT: Fix error report for ADD_EXT_ADV_PARAMS

Isaac J. Manjarres (1):
      loop: Fix the max_loop commandline argument treatment when it is set to 0

Ivaylo Dimitrov (1):
      usb: musb: remove extra check in musb_gadget_vbus_draw

Jaegeuk Kim (1):
      f2fs: allow to set compression for inlined file

Jakub Kicinski (3):
      devlink: hold region lock when flushing snapshots
      selftests: devlink: fix the fd redirect in dummy_reporter_test
      devlink: protect devlink dump by the instance lock

James Hilliard (1):
      selftests/bpf: Fix conflicts with built-in functions in bpf_iter_ksym

James Hurley (1):
      platform/mellanox: mlxbf-pmc: Fix event typo

Jani Nikula (1):
      drm/i915/guc: make default_lists const data

Janne Grunau (1):
      arch: arm64: apple: t8103: Use standard "iommu" node name

Jaroslav Kysela (1):
      ALSA: hda/hdmi: Use only dynamic PCM device allocation

Jason Gerecke (1):
      HID: wacom: Ensure bootloader PID is usable in hidraw mode

Jason Gunthorpe (1):
      iommu/sun50i: Remove IOMMU_DOMAIN_IDENTITY

Jayesh Choudhary (2):
      arm64: dts: ti: k3-am65-main: Drop dma-coherent in crypto node
      arm64: dts: ti: k3-j721e-main: Drop dma-coherent in crypto node

Jeff LaBundy (10):
      Input: iqs7222 - set all ULP entry masks by default
      Input: iqs7222 - drop unused device node references
      Input: iqs7222 - report malformed properties
      Input: iqs7222 - protect against undefined slider size
      Input: iqs7222 - avoid sending empty SYN_REPORT events
      dt-bindings: input: iqs7222: Reduce 'linux,code' to optional
      dt-bindings: input: iqs7222: Correct minimum slider size
      dt-bindings: input: iqs7222: Add support for IQS7222A v1.13+
      Input: iqs7222 - trim force communication command
      Input: iqs7222 - add support for IQS7222A v1.13+

Jeff Layton (2):
      nfsd: don't call nfsd_file_put from client states seqfile display
      nfsd: return error if nfs4_setacl fails

Jeremy Kerr (1):
      mctp: serial: Fix starting value for frame check sequence

Jernej Skrabec (7):
      media: v4l2-ioctl.c: Unify YCbCr/YUV terms in format descriptions
      media: cedrus: hevc: Fix offset adjustments
      iommu/sun50i: Fix reset release
      iommu/sun50i: Consider all fault sources for reset
      iommu/sun50i: Fix R/W permission check
      iommu/sun50i: Fix flush size
      iommu/sun50i: Implement .iotlb_sync_map

Jerry Ray (1):
      net: lan9303: Fix read error execution path

Jiamei Xie (1):
      serial: amba-pl011: avoid SBSA UART accessing DMACR register

Jiang Li (1):
      md/raid1: stop mdx_raid1 thread when raid1 array run failed

Jianmin Lv (1):
      irqchip/loongson-pch-pic: Fix translate callback for DT path

Jiantao Zhang (1):
      USB: gadget: Fix use-after-free during usb config switch

Jiao Zhou (1):
      ALSA: hda/hdmi: Add HP Device 0x8711 to force connect list

Jiasheng Jiang (8):
      soc: qcom: apr: Add check for idr_alloc and of_property_read_string_index
      media: coda: jpeg: Add check for kmalloc
      ASoC: mediatek: mtk-btcvsd: Add checks for write and read of mtk_btcvsd_snd
      memstick/ms_block: Add check for alloc_ordered_workqueue
      media: coda: Add check for dcoda_iram_alloc
      media: coda: Add check for kmalloc
      usb: storage: Add check for kcalloc
      HID: amd_sfh: Add missing check for dma_alloc_coherent

Jie Zhan (2):
      scsi: libsas: Add smp_ata_check_ready_type()
      scsi: hisi_sas: Fix SATA devices missing issue during I_T nexus reset

Jimmy Assarsson (5):
      can: kvaser_usb: kvaser_usb_leaf: Get capabilities from device
      can: kvaser_usb: kvaser_usb_leaf: Rename {leaf,usbcan}_cmd_error_event to {leaf,usbcan}_cmd_can_error_event
      can: kvaser_usb: kvaser_usb_leaf: Handle CMD_ERROR_EVENT
      can: kvaser_usb: Add struct kvaser_usb_busparams
      can: kvaser_usb: Compare requested bittiming parameters with actual parameters in do_set_{,data}_bittiming

Jiri Slaby (2):
      tty: serial: clean up stop-tx part in altera_uart_tx_chars()
      tty: serial: altera_uart_{r,t}x_chars() need only uart_port

Jiri Slaby (SUSE) (1):
      qed (gcc13): use u16 for fid to be big enough

Joel Granados (1):
      nvme: return err on nvme_init_non_mdts_limits fail

Johan Hovold (11):
      arm64: dts: qcom: sm8150: fix UFS PHY registers
      arm64: dts: qcom: sm8250: fix UFS PHY registers
      arm64: dts: qcom: sm8350: fix UFS PHY registers
      arm64: dts: qcom: sm8450: fix UFS PHY registers
      arm64: dts: qcom: sm8250: drop bogus DP PHY clock
      arm64: dts: qcom: sm6350: drop bogus DP PHY clock
      phy: qcom-qmp-pcie: drop bogus register update
      phy: qcom-qmp-pcie: fix ipq8074-gen3 initialisation
      arm64: dts: qcom: sm6350: fix USB-DP PHY registers
      arm64: dts: qcom: sm8250: fix USB-DP PHY registers
      regulator: core: fix deadlock on regulator enable

Johannes Berg (5):
      wifi: fix multi-link element subelement iteration
      wifi: mac80211: mlme: fix null-ptr deref on failed assoc
      wifi: mac80211: check link ID in auth/assoc continuation
      wifi: mac80211: fix ifdef symbol name
      wifi: iwlwifi: mei: fix potential NULL-ptr deref after clone

John Harrison (4):
      drm/i915/guc: Limit scheduling properties to avoid overflow
      drm/i915: Fix compute pre-emption w/a to apply to compute engines
      drm/i915/guc: Fix capture size warning and bump the size
      drm/i915/guc: Make GuC log sizes runtime configurable

John Johansen (3):
      apparmor: fix lockdep warning when removing a namespace
      apparmor: Fix abi check to include v8 abi
      apparmor: Fix regression in stacking due to label flags

John Keeping (2):
      usb: gadget: f_hid: fix f_hidg lifetime vs cdev
      usb: gadget: f_hid: fix refcount leak on error path

John Stultz (2):
      pstore: Switch pmsg_lock to an rt_mutex to avoid priority inversion
      pstore: Make sure CONFIG_PSTORE_PMSG selects CONFIG_RT_MUTEXES

John Thomson (3):
      mips: ralink: mt7621: define MT7621_SYSC_BASE with __iomem
      mips: ralink: mt7621: soc queries and tests as functions
      mips: ralink: mt7621: do not use kzalloc too early

Jon Hunter (2):
      pwm: tegra: Improve required rate calculation
      pwm: tegra: Ensure the clock rate is not less than needed

Jonathan Neuschäfer (2):
      ARM: dts: nuvoton: Remove bogus unit addresses from fixed-partition nodes
      spi: Update reference to struct spi_controller

Jonathan Toppins (1):
      bonding: fix link recovery in mode 2 when updelay is nonzero

José Expósito (1):
      HID: input: do not query XP-PEN Deco LW battery

Juergen Gross (1):
      x86/boot: Skip realmode init code when running as Xen PV guest

Julian Anastasov (1):
      ipvs: use u64_stats_t for the per-cpu counters

Justin Chen (2):
      phy: usb: Use slow clock for wake enabled suspend
      phy: usb: Fix clock imbalance for suspend/resume

Justin Tee (1):
      scsi: lpfc: Fix hard lockup when reading the rx_monitor from debugfs

Kai Vehmanen (3):
      ALSA: hda/hdmi: fix i915 silent stream programming flow
      ALSA: hda/hdmi: set default audio parameters for KAE silent-stream
      ALSA: hda/hdmi: fix stream-id config keep-alive for rt suspend

Kai Ye (1):
      crypto: hisilicon/qm - increase the memory of local variables

Kajol Jain (1):
      powerpc/hv-gpci: Fix hv_gpci event list

Kartik (1):
      serial: tegra: Read DMA status before terminating

Keerthy (2):
      arm64: dts: ti: k3-j721s2: Fix the interrupt ranges property for main & wkup gpio intr
      thermal/drivers/k3_j72xx_bandgap: Fix the debug print message

Kees Cook (4):
      fortify: Use SIZE_MAX instead of (size_t)-1
      fortify: Do not cast to "unsigned char"
      igb: Do not free q_vector unless new one was allocated
      LoadPin: Ignore the "contents" argument of the LSM hooks

Kerem Karabay (2):
      HID: apple: fix key translations where multiple quirks attempt to translate the same key
      HID: apple: enable APPLE_ISO_TILDE_QUIRK for the keyboards of Macs with the T2 chip

Khaled Almahallawy (1):
      drm/i915/display: Don't disable DDI/Transcoder when setting phy test pattern

Khazhismel Kumykov (1):
      bfq: fix waker_bfqq inconsistency crash

Kirill Tkhai (1):
      unix: Fix race in SOCK_SEQPACKET's unix_dgram_sendmsg()

Konrad Dybcio (2):
      clk: qcom: dispcc-sm6350: Add CLK_OPS_PARENT_ENABLE to pixel&byte src
      regulator: qcom-rpmh: Fix PMR735a S3 regulator spec

Konstantin Meskhidze (1):
      drm/amdkfd: Fix memory leakage

Kory Maincent (1):
      arm: dts: spear600: Fix clcd interrupt

Kris Bahnsen (1):
      spi: spi-gpio: Don't set MOSI as an input if not 3WIRE mode

Kristina Martsenko (1):
      lkdtm: cfi: Make PAC test work with GCC 7 and 8

Krzysztof Kozlowski (11):
      arm64: dts: qcom: ipq6018-cp01-c1: use BLSPI1 pins
      arm64: dts: qcom: sm8250-sony-xperia-edo: fix touchscreen bias-disable
      arm64: dts: qcom: sdm845-xiaomi-polaris: fix codec pin conf name
      arm64: dts: qcom: sdm630: fix UART1 pin bias
      arm64: dts: qcom: sdm845-cheza: fix AP suspend pin bias
      arm64: dts: qcom: sm8250: correct LPASS pin pull down
      arm64: dts: qcom: sc7180-trogdor-homestar: fully configure secondary I2S pins
      arm64: dts: qcom: use GPIO flags for tlmm
      arm64: dts: qcom: sm6125: fix SDHCI CQE reg names
      ASoC: codecs: wsa883x: Use proper shutdown GPIO polarity
      interconnect: qcom: sc7180: fix dropped const of qcom_icc_bcm

Kumar Kartikeya Dwivedi (2):
      bpf: Clobber stack slot when writing over spilled PTR_TO_BTF_ID
      bpf: Fix slot type check in check_stack_write_var_off

Kumar Meiyappan (1):
      scsi: smartpqi: Correct device removal for multi-actuator devices

Kunihiko Hayashi (2):
      PCI: pci-epf-test: Register notifier if only core_init_notifier is enabled
      mmc: f-sdh30: Add quirks for broken timeout clock capability

Kuniyuki Iwashima (4):
      seccomp: Move copy_seccomp() to no failure path.
      soreuseport: Fix socket selection for SO_INCOMING_CPU.
      udp: Clean up some functions.
      net: Return errno in sk->sk_prot->get_port().

Ladislav Michl (1):
      MIPS: OCTEON: warn only once if deprecated link status is being used

Laurent Pinchart (4):
      drm: lcdif: Switch to limited range for RGB to YUV conversion
      media: v4l2-ctrls: Fix off-by-one error in integer menu control check
      drm: rcar-du: Drop leftovers dependencies from Kconfig
      media: imx: imx7-media-csi: Clear BIT_MIPI_DOUBLE_CMPNT for <16b formats

Leo Yan (3):
      perf trace: Return error if a system call doesn't exist
      perf trace: Use macro RAW_SYSCALL_ARGS_NUM to replace number
      perf trace: Handle failure when trace point folder is missed

Leon Romanovsky (1):
      RDMA/core: Fix order of nldev_exit call

Leonid Ravich (1):
      IB/mad: Don't call to function that might sleep while in atomic context

Li Huafei (1):
      kprobes: Fix check for probe enabled in kill_kprobe()

Li Jun (2):
      dt-bindings: clocks: imx8mp: Add ID for usb suspend clock
      clk: imx: imx8mp: add shared clk gate for usb suspend clk

Li Zetao (4):
      ocfs2: fix memory leak in ocfs2_mount_volume()
      ACPICA: Fix use-after-free in acpi_ut_copy_ipackage_to_ipackage()
      net: farsync: Fix kmemleak when rmmods farsync
      r6040: Fix kmemleak in probe and remove

Li Zhijian (1):
      RDMA/rxe: Fix mr->map double free

Li Zhong (2):
      ACPI: processor: idle: Check acpi_fetch_acpi_dev() return value
      drivers/md/md-bitmap: check the return value of md_bitmap_get_counter()

Liang He (1):
      media: c8sectpfe: Add of_node_put() when breaking out of loop

Lin Ma (3):
      media: dvbdev: adopts refcnt to avoid UAF
      media: dvbdev: fix build warning due to comments
      media: dvbdev: fix refcnt bug

Linus Walleij (1):
      usb: fotg210-udc: Fix ages old endianness issues

Liu Peibao (1):
      irqchip/loongson-liointc: Fix improper error handling in liointc_init()

Liu Shixin (4):
      media: vivid: fix compose size exceed boundary
      ALSA: asihpi: fix missing pci_disable_device()
      media: saa7164: fix missing pci_disable_device()
      binfmt_misc: fix shift-out-of-bounds in check_special_flags

Lorenzo Bianconi (5):
      net: ethernet: mtk_eth_soc: do not overwrite mtu configuration running reset routine
      net: ethernet: mtk_eth_soc: fix RSTCTRL_PPE{0,1} definitions
      wifi: mt76: mt7915: fix reporting of TX AGGR histogram
      wifi: mt76: mt7921: fix reporting of TX AGGR histogram
      wifi: mt76: do not run mt76u_status_worker if the device is not running

Luca Weiss (6):
      ARM: dts: qcom: apq8064: fix coresight compatible
      soc: qcom: llcc: make irq truly optional
      thermal/drivers/qcom/temp-alarm: Fix inaccurate warning for gen2
      leds: is31fl319x: Fix setting current limit for is31fl319{0,1,3}
      remoteproc: qcom_q6v5_pas: disable wakeup on probe fail or remove
      remoteproc: qcom_q6v5_pas: detach power domains on remove

Luiz Augusto von Dentz (1):
      Bluetooth: hci_conn: Fix crash on hci_create_cis_sync

Luoyouming (3):
      RDMA/hns: Repacing 'dseg_len' by macros in fill_ext_sge_inl_data()
      RDMA/hns: Fix ext_sge num error when post send
      RDMA/hns: Fix incorrect sge nums calculation

Manivannan Sadhasivam (3):
      cpufreq: qcom-hw: Fix the frequency returned by cpufreq_driver->get()
      clk: qcom: gcc-sm8250: Use retention mode for USB GDSCs
      phy: qcom-qmp-pcie: Fix sm8450_qmp_gen4x2_pcie_pcs_tbl[] register names

Marco Elver (1):
      objtool, kcsan: Add volatile read/write instrumentation to whitelist

Marco Felsch (1):
      drm: lcdif: change burst size to 256B

Marcus Folkesson (2):
      HID: hid-sensor-custom: set fixed size for custom attributes
      thermal/drivers/imx8mm_thermal: Validate temperature range

Marek Szyprowski (2):
      media: exynos4-is: don't rely on the v4l2_async_subdev internals
      ASoC: wm8994: Fix potential deadlock

Marek Vasut (12):
      ARM: dts: stm32: Drop stm32mp15xc.dtsi from Avenger96
      ARM: dts: stm32: Fix AV96 WLAN regulator gpio property
      clk: renesas: r9a06g032: Repair grave increment error
      drm/panel/panel-sitronix-st7701: Remove panel on DSI attach failure
      wifi: rsi: Fix handling of 802.3 EAPOL frames sent via control port
      drm: lcdif: Set and enable FIFO Panic threshold
      media: mt9p031: Drop bogus v4l2_subdev_get_try_crop() call from mt9p031_init_cfg()
      extcon: usbc-tusb320: Factor out extcon into dedicated functions
      extcon: usbc-tusb320: Add USB TYPE-C support
      extcon: usbc-tusb320: Update state on probe even if no IRQ pending
      power: supply: bq25890: Factor out regulator registration code
      Bluetooth: hci_bcm: Add CYW4373A0 support

Marijn Suijten (13):
      arm64: dts: qcom: pm660: Use unique ADC5_VCOIN address in node name
      arm64: dts: qcom: pm6350: Include header for KEY_POWER
      drm/msm/dpu1: Account for DSC's bits_per_pixel having 4 fractional bits
      drm/msm/dsi: Remove useless math in DSC calculations
      drm/msm/dsi: Remove repeated calculation of slice_per_intf
      drm/msm/dsi: Use DIV_ROUND_UP instead of conditional increment on modulo
      drm/msm/dsi: Reuse earlier computed dsc->slice_chunk_size
      drm/msm/dsi: Appropriately set dsc->mux_word_size based on bpc
      drm/msm/dsi: Migrate to drm_dsc_compute_rc_parameters()
      drm/msm/dsi: Account for DSC's bits_per_pixel having 4 fractional bits
      drm/msm/dsi: Disallow 8 BPC DSC configuration for alternative BPC values
      drm/msm/dsi: Prevent signed BPG offsets from bleeding into adjacent bits
      arm64: dts: qcom: sm6350: Add apps_smmu with streamID to SDHCI 1/2 nodes

Mark Rutland (2):
      arm64: mm: kfence: only handle translation faults
      arm64: make is_ttbrX_addr() noinstr-safe

Mark Zhang (4):
      RDMA/restrack: Release MR restrack when delete
      RDMA/core: Make sure "ib_port" is valid when access sysfs node
      RDMA/nldev: Return "-EAGAIN" if the cm_id isn't from expected port
      RDMA/nldev: Fix failure to send large messages

Markus Schneider-Pargmann (2):
      can: tcan4x5x: Remove invalid write in clear_interrupts
      can: tcan4x5x: Fix use of register error status mask

Martin Blumenstingl (2):
      hwmon: (jc42) Convert register access and caching to regmap/regcache
      hwmon: (jc42) Restore the min/max/critical temperatures on resume

Martin Kaiser (3):
      staging: r8188eu: remove duplicate bSurpriseRemoved check
      staging: r8188eu: don't check bSurpriseRemoved in SwLedOff
      staging: r8188eu: fix led register settings

Martin Leung (1):
      drm/amd/display: revert Disable DRR actions during state commit

Martin Povišer (2):
      dmaengine: apple-admac: Do not use devres for IRQs
      dmaengine: apple-admac: Allocate cache SRAM to channels

Mateusz Jończyk (1):
      x86/apic: Handle no CONFIG_X86_X2APIC on systems with x2APIC enabled by BIOS

Mathias Nyman (1):
      xhci: Prevent infinite loop in transaction errors recovery for streams

Matt Johnston (1):
      mctp: Remove device type check at unregister

Matt Redfearn (1):
      include/uapi/linux/swab: Fix potentially missing __always_inline

Matti Vaittinen (1):
      mfd: bd957x: Fix Kconfig dependency on REGMAP_IRQ

Maurizio Lombardi (1):
      scsi: target: iscsi: Fix a race condition between login_work and the login thread

Maxim Korotkov (1):
      ethtool: avoiding integer overflow in ethtool_phys_id()

Mazin Al Haddad (1):
      media: dvb-usb: fix memory leak in dvb_usb_adapter_init()

Mia Kanashi (1):
      ACPI: EC: Add quirk for the HP Pavilion Gaming 15-cx0041ur

Miaoqian Lin (4):
      module: Fix NULL vs IS_ERR checking for module_get_next_page
      bpftool: Fix memory leak in do_build_table_cb
      cxl: Fix refcount leak in cxl_calc_capp_routing
      selftests/powerpc: Fix resource leaks

Michael Kelley (1):
      tpm/tpm_crb: Fix error message in __crb_relinquish_locality()

Michael Petlan (1):
      perf test: Fix "all PMU test" to skip parametrized events

Michael Riesch (1):
      iommu/rockchip: fix permission bits in page table entries v2

Michael Walle (1):
      mtd: spi-nor: hide jedec_id sysfs attribute if not present

Mika Westerberg (1):
      watchdog: iTCO_wdt: Set NO_REBOOT if the watchdog is not already running

Mike McGowen (1):
      scsi: smartpqi: Add new controller PCI IDs

Milan Landaverde (1):
      bpf: prevent leak of lsm program after failed attach

Ming Qian (7):
      media: amphion: reset instance if it's aborted before codec header parsed
      media: amphion: add lock around vdec_g_fmt
      media: amphion: apply vb2_queue_error instead of setting manually
      media: amphion: try to wakeup vpu core to avoid failure
      media: amphion: cancel vpu before release instance
      media: amphion: lock and check m2m_ctx in event handler
      media: imx-jpeg: Disable useless interrupt to avoid kernel panic

Minsuk Kang (2):
      nfc: pn533: Clear nfc_target before being used
      wifi: brcmfmac: Fix potential shift-out-of-bounds in brcmf_fw_alloc_request()

Muhammad Husaini Zulkifli (1):
      igc: Add checking for basetime less than zero

Mukesh Ojha (1):
      f2fs: fix the assign logic of iocb

Mustafa Ismail (4):
      RDMA/irdma: Fix inline for multiple SGE's
      RDMA/irdma: Fix RQ completion opcode
      RDMA/irdma: Do not request 2-level PBLEs for CQ alloc
      RDMA/irdma: Initialize net_type before checking it

Namhyung Kim (2):
      perf off_cpu: Fix a typo in BTF tracepoint name, it should be 'btf_trace_sched_switch'
      perf stat: Do not delay the workload with --delay

Natalia Petrova (1):
      crypto: nitrox - avoid double free on error path in nitrox_sriov_init()

Nathan Chancellor (13):
      drm/meson: Fix return type of meson_encoder_cvbs_mode_valid()
      net: ethernet: ti: Fix return type of netcp_ndo_start_xmit()
      hamradio: baycom_epp: Fix return type of baycom_send_packet()
      drm/amdgpu: Fix type of second parameter in trans_msg() callback
      drm/amdgpu: Fix type of second parameter in odn_edit_dpm_table() callback
      s390/ctcm: Fix return type of ctc{mp,}m_tx()
      s390/netiucv: Fix return type of netiucv_tx()
      s390/lcs: Fix return type of lcs_start_xmit()
      drm/mediatek: Fix return type of mtk_hdmi_bridge_mode_valid()
      scsi: elx: libefc: Fix second parameter type in state callbacks
      drm/fsl-dcu: Fix return type of fsl_dcu_drm_connector_mode_valid()
      drm/sti: Fix return type of sti_{dvo,hda,hdmi}_connector_mode_valid()
      security: Restrict CONFIG_ZERO_CALL_USED_REGS to gcc or clang > 15.0.6

Nathan Lynch (1):
      powerpc/pseries/eeh: use correct API for error log size

Nayna Jain (4):
      powerpc/pseries: fix the object owners enum value in plpks driver
      powerpc/pseries: Fix the H_CALL error code in PLPKS driver
      powerpc/pseries: Return -EIO instead of -EINTR for H_ABORTED error
      powerpc/pseries: fix plpks_read_var() code for different consumers

Nicholas Piggin (1):
      powerpc/perf: callchain validate kernel stack pointer bounds

Nicolas Cavallari (1):
      wifi: mt76: mt7915: Fix chainmask calculation on mt7915 DBDC

Niklas Cassel (1):
      ata: libata: fix NCQ autosense logic

Niklas Schnelle (1):
      iommu/s390: Fix duplicate domain attachments

Niklas Söderlund (1):
      media: adv748x: afe: Select input port when initializing AFE

Nirmal Patel (1):
      PCI: vmd: Disable MSI remapping after suspend

Nuno Sá (1):
      iio: adc: ad_sigma_delta: do not use internal iio_dev lock

Nícolas F. R. A. Prado (1):
      ASoC: dt-bindings: rt5682: Set sound-dai-cells to 1

Oleg Nesterov (1):
      uprobes/x86: Allow to probe a NOP instruction with 0x66 prefix

Ondrej Mosnacek (1):
      fs: don't audit the capability check in simple_xattr_list()

Padmanabhan Rajanbabu (2):
      arm64: dts: fsd: fix drive strength macros as per FSD HW UM
      arm64: dts: fsd: fix drive strength values as per FSD HW UM

Pali Rohár (11):
      ARM: dts: dove: Fix assigned-addresses for every PCIe Root Port
      ARM: dts: armada-370: Fix assigned-addresses for every PCIe Root Port
      ARM: dts: armada-xp: Fix assigned-addresses for every PCIe Root Port
      ARM: dts: armada-375: Fix assigned-addresses for every PCIe Root Port
      ARM: dts: armada-38x: Fix assigned-addresses for every PCIe Root Port
      ARM: dts: armada-39x: Fix assigned-addresses for every PCIe Root Port
      ARM: dts: turris-omnia: Add ethernet aliases
      ARM: dts: turris-omnia: Add switch port 6 node
      arm64: dts: armada-3720-turris-mox: Add missing interrupt for RTC
      phy: marvell: phy-mvebu-a3700-comphy: Reset COMPHY registers before USB 3.0 power on
      powerpc: dts: turris1x.dts: Add channel labels for temperature sensor

Palmer Dabbelt (1):
      RISC-V: Align the shadow stack

Paul Kocialkowski (4):
      media: sun6i-mipi-csi2: Require both pads to be connected for streaming
      media: sun8i-a83t-mipi-csi2: Require both pads to be connected for streaming
      media: sun6i-mipi-csi2: Register async subdev with no sensor attached
      media: sun8i-a83t-mipi-csi2: Register async subdev with no sensor attached

Paulo Alcantara (5):
      cifs: improve symlink handling for smb2+
      cifs: fix oops during encryption
      cifs: fix double-fault crash during ntlmssp
      cifs: fix memory leaks in session setup
      cifs: fix uninitialised var in smb2_compound_op()

Pavel Begunkov (5):
      io_uring: add completion locking for iopoll
      io_uring: improve io_double_lock_ctx fail handling
      io_uring/net: fix cleanup after recycle
      io_uring: protect cq_timeouts with timeout_lock
      io_uring: remove iopoll spinlock

Pawel Laszczak (1):
      usb: cdnsp: fix lack of ZLP for ep0

Peng Fan (2):
      clk: imx93: unmap anatop base in error handling path
      clk: imx93: correct enet clock

Pengcheng Yang (3):
      bpf, sockmap: Fix repeated calls to sock_put() when msg has more_data
      bpf, sockmap: Fix missing BPF_F_INGRESS flag when using apply_bytes
      bpf, sockmap: Fix data loss caused by using apply_bytes on ingress redirect

Phil Auld (1):
      cpu/hotplug: Make target_store() a nop when target == state

Piergiorgio Beruto (1):
      stmmac: fix potential division by 0

Pierre-Louis Bossart (1):
      ALSA: hda: add snd_hdac_stop_streams() helper

Pin-yen Lin (1):
      drm/bridge: it6505: Initialize AUX channel in it6505_i2c_probe

Ping-Ke Shih (1):
      wifi: rtw89: use u32_encode_bits() to fill MAC quota value

Prashant Malani (2):
      platform/chrome: cros_ec_typec: Cleanup switch handle return paths
      platform/chrome: cros_ec_typec: Get retimer handle

Pu Lehui (1):
      riscv, bpf: Emit fixed-length instructions for BPF_PSEUDO_FUNC

Qais Yousef (7):
      sched/uclamp: Fix relationship between uclamp and migration margin
      sched/uclamp: Make task_fits_capacity() use util_fits_cpu()
      sched/uclamp: Fix fits_capacity() check in feec()
      sched/uclamp: Make select_idle_capacity() use util_fits_cpu()
      sched/uclamp: Make asym_fits_capacity() use util_fits_cpu()
      sched/uclamp: Make cpu_overutilized() use util_fits_cpu()
      sched/uclamp: Cater for uclamp in find_energy_efficient_cpu()'s early exit condition

Qingfang DENG (1):
      netfilter: flowtable: really fix NAT IPv6 offload

Rafael J. Wysocki (7):
      PM: runtime: Do not call __rpm_callback() from rpm_idle()
      rtc: cmos: Call cmos_wake_setup() from cmos_do_probe()
      rtc: cmos: Call rtc_wake_setup() from cmos_do_probe()
      rtc: cmos: Eliminate forward declarations of some functions
      rtc: cmos: Rename ACPI-related functions
      rtc: cmos: Disable ACPI RTC event on removal
      ACPICA: Fix error code path in acpi_ds_call_control_method()

Rafael Mendonca (6):
      drm/amdgpu/powerplay/psm: Fix memory leak in power state init
      media: i2c: hi846: Fix memory leak in hi846_parse_dt()
      media: i2c: ov5648: Free V4L2 fwnode data on unbind
      vfio: platform: Do not pass return buffer to ACPI _RST method
      uio: uio_dmem_genirq: Fix missing unlock in irq configuration
      uio: uio_dmem_genirq: Fix deadlock between irq config and handling

Rahul Bhattacharjee (1):
      wifi: ath11k: Fix qmi_msg_handler data structure initialization

Ramona Bolboaca (1):
      iio: adis: add '__adis_enable_irq()' implementation

Randy Dunlap (6):
      Input: joystick - fix Kconfig warning for JOYSTICK_ADC
      ASoC: codecs: wsa883x: use correct header file
      Input: wistron_btns - disable on UML
      RDMA: Disable IB HW for UML
      fbdev: geode: don't build on UML
      fbdev: uvesafb: don't build on UML

Rasmus Villemoes (2):
      iio: adc128s052: add proper .data members in adc128_of_match table
      iio: addac: ad74413r: fix integer promotion bug in ad74413_get_input_current_offset()

Reinette Chatre (1):
      x86/sgx: Reduce delay and interference of enclave release

Ricardo Ribalda (2):
      media: i2c: ad5820: Fix error path
      ASoC: mediatek: mt8173: Enable IRQ when pdata is ready

Richard Gobert (1):
      net: setsockopt: fix IPV6_UNICAST_IF option for connected sockets

Rickard x Andersson (1):
      gcov: add support for checksum field

Rob Clark (1):
      drm/msm/a6xx: Fix speed-bin detection vs probe-defer

Robert Elliott (1):
      crypto: tcrypt - fix return value for multiple subtests

Roberto Sassu (1):
      reiserfs: Add missing calls to reiserfs_security_free()

Roger Quadros (1):
      net: ethernet: ti: am65-cpsw: Fix PM runtime leakage in am65_cpsw_nuss_ndo_slave_open()

Rui Zhang (1):
      regulator: core: fix use_count leakage when handling boot-on

Ryder Lee (1):
      wifi: mt76: mt7915: fix mt7915_mac_set_timing()

Ryusuke Konishi (2):
      nilfs2: fix shift-out-of-bounds/overflow in nilfs_sb2_bad_offset()
      nilfs2: fix shift-out-of-bounds due to too large exponent of block size

Sagi Grimberg (1):
      nvme-auth: don't override ctrl keys before validation

Sakari Ailus (1):
      dw9768: Enable low-power probe on ACPI

Sam Shih (1):
      pinctrl: mediatek: fix the pinconf register offset of some pins

Samuel Holland (2):
      riscv: Fix crash during early errata patching
      mfd: axp20x: Do not sleep in the power off handler

Sascha Hauer (1):
      PCI: imx6: Initialize PHY before deasserting core reset

Schspa Shi (2):
      mrp: introduce active flags to prevent UAF when applicant uninit
      9p: set req refcount to zero to avoid uninitialized usage

Sean Wang (1):
      wifi: mt76: mt7921: fix antenna signal are way off in monitor mode

Sebastian Andrzej Siewior (6):
      Revert "net: hsr: use hlist_head instead of list_head for mac addresses"
      hsr: Add a rcu-read lock to hsr_forward_skb().
      hsr: Avoid double remove of a node.
      hsr: Disable netpoll.
      hsr: Synchronize sending frames to have always incremented outgoing seq nr.
      hsr: Synchronize sequence number updates.

Serge Semin (2):
      dt-bindings: imx6q-pcie: Fix clock names for imx6sx and imx8mq
      dt-bindings: visconti-pcie: Fix interrupts array max constraints

Sergio Paracuellos (1):
      MIPS: ralink: mt7621: avoid to init common ralink reset controller

Shang XiaoJing (13):
      perf/arm_dmc620: Fix hotplug callback leak in dmc620_pmu_init()
      perf/smmuv3: Fix hotplug callback leak in arm_smmu_pmu_init()
      ocfs2: fix memory leak in ocfs2_stack_glue_init()
      irqchip: gic-pm: Use pm_runtime_resume_and_get() in gic_probe()
      mtd: core: Fix refcount error in del_mtd_device()
      scsi: ipr: Fix WARNING in ipr_init()
      crypto: omap-sham - Use pm_runtime_resume_and_get() in omap_sham_probe()
      samples: vfio-mdev: Fix missing pci_disable_device() in mdpy_fb_probe()
      fbdev: via: Fix error in via_core_init()
      power: supply: cw2015: Fix potential null-ptr-deref in cw_bat_probe()
      rtc: class: Fix potential memleak in devm_rtc_allocate_device()
      remoteproc: qcom: q6v5: Fix potential null-ptr-deref in q6v5_wcss_init_mmio()
      remoteproc: qcom: q6v5: Fix missing clk_disable_unprepare() in q6v5_wcss_qcs404_power_on()

Shayne Chen (1):
      wifi: mt76: mt7915: rework eeprom tx paths and streams init

Sheng Yong (2):
      f2fs: set zstd compress level correctly
      f2fs: fix to enable compress for newly created file if extension matches

Shigeru Yoshida (4):
      fs/ntfs3: Avoid UBSAN error on true_sectors_per_clst()
      udf: Avoid double brelse() in udf_rename()
      wifi: ar5523: Fix use-after-free on ar5523_cmd() timed out
      media: si470x: Fix use-after-free in si470x_int_in_callback()

Shiraz Saleem (1):
      RDMA/irdma: Report the correct link speed

Shung-Hsi Yu (3):
      libbpf: Use elf_getshdrnum() instead of e_shnum
      libbpf: Deal with section with no data gracefully
      libbpf: Fix null-pointer dereference in find_prog_by_sec_insn()

Song Liu (1):
      selftests/bpf: Select CONFIG_FUNCTION_ERROR_INJECTION

Stanislav Fomichev (6):
      bpf: Move skb->len == 0 checks into __bpf_redirect
      selftests/bpf: Make sure zero-len skbs aren't redirectable
      selftests/bpf: Mount debugfs in setns_by_fd
      bpf: make sure skb->len != 0 when redirecting to a tunneling device
      ppp: associate skb with a device at tx
      bpf: Prevent decl_tag from being referenced in func_proto arg

Stefan Eichenberger (1):
      rtc: snvs: Allow a time difference on clock register read

Stephan Gerhold (1):
      arm64: dts: qcom: msm8916: Drop MSS fallback compatible

Stephen Boyd (1):
      pstore: Avoid kcore oops by vmap()ing with VM_IOREMAP

Steven Price (1):
      pwm: tegra: Fix 32 bit build

Subash Abhinov Kasiviswanathan (1):
      skbuff: Account for tail adjustment during pull operations

Sven Peter (9):
      soc: apple: sart: Stop casting function pointer signatures
      soc: apple: rtkit: Stop casting function pointer signatures
      usb: typec: Check for ops->exit instead of ops->enter in altmode_exit
      usb: typec: tipd: Cleanup resources if devm_tps6598_psy_register fails
      usb: typec: tipd: Fix spurious fwnode_handle_put in error path
      usb: typec: tipd: Fix typec_unregister_port error paths
      Bluetooth: Add quirk to disable extended scanning
      Bluetooth: Add quirk to disable MWS Transport Configuration
      usb: dwc3: Fix race between dwc3_set_mode and __dwc3_set_mode

Takashi Iwai (1):
      ALSA: pcm: Set missing stop_operating flag at undoing trigger start

Tan Tee Min (3):
      igc: allow BaseTime 0 enrollment for Qbv
      igc: recalculate Qbv end_time by considering cycle time
      igc: Set Qbv start_time and end_time to end_time if not being configured in GCL

Tang Bin (1):
      venus: pm_helpers: Fix error check in vcodec_domains_get()

Taniya Das (4):
      dt-bindings: clock: Add resets for LPASS audio clock controller for SC7280
      dt-bindings: clock: Add support for external MCLKs for LPASS on SC7280
      clk: qcom: lpass: Handle the regmap overlap of lpasscc and lpass_aon
      clk: qcom: lpass: Add support for resets & external mclk for SC7280

Tetsuo Handa (1):
      fbdev: fbcon: release buffer when fbcon_do_set_font() failed

Thomas Gleixner (1):
      net: Remove the obsolte u64_stats_fetch_*_irq() users (net).

Thomas Zimmermann (1):
      drm/atomic-helper: Don't allocate new plane state in CRTC check

Tom Lendacky (2):
      net: amd-xgbe: Fix logic around active and passive cables
      net: amd-xgbe: Check only the minimum speed for active/passive cables

Tong Tiangen (1):
      riscv/mm: add arch hook arch_clear_hugepage_flags

Tony Lindgren (2):
      clocksource/drivers/timer-ti-dm: Fix warning for omap_timer_match
      usb: musb: omap2430: Fix probe regression for missing resources

Trond Myklebust (9):
      lockd: set other missing fields when unlocking files
      NFSv4.2: Clear FATTR4_WORD2_SECURITY_LABEL when done decoding
      NFSv4.2: Always decode the security label
      NFSv4.2: Fix a memory stomp in decode_attr_security_label
      NFSv4.2: Fix initialisation of struct nfs4_label
      NFSv4: Fix a credential leak in _nfs4_discover_trunking()
      NFSv4: Fix a deadlock between nfs4_open_recover_helper() and delegreturn
      NFS: Fix an Oops in nfs_d_automount()
      NFSv4.x: Fail client initialisation if state manager thread can't run

Ulf Hansson (1):
      cpuidle: dt: Return the correct numbers of parsed idle states

Uwe Kleine-König (3):
      crypto: ccree - Make cc_debugfs_global_fini() available for module init function
      power: supply: bq25890: Convert to i2c's .probe_new()
      pwm: sifive: Call pwm_sifive_update_clock() while mutex is held

Valentin Caron (1):
      serial: stm32: move dma_request_chan() before clk_prepare_enable()

Veerabadhran Gopalakrishnan (1):
      amdgpu/nv.c: Corrected typo in the video capabilities resolution

Victor Ding (1):
      platform/chrome: cros_ec_typec: zero out stale pointers

Vidya Sagar (1):
      PCI: dwc: Fix n_fts[] array overrun

Ville Syrjälä (3):
      drm/msm: Use drm_mode_copy()
      drm/rockchip: Use drm_mode_copy()
      drm/sti: Use drm_mode_copy()

Vincent Donnefort (1):
      cpu/hotplug: Do not bail-out in DYING/STARTING sections

Vinicius Costa Gomes (2):
      igc: Enhance Qbv scheduling by using first flag bit
      igc: Use strict cycles for Qbv scheduling

Vivek Yadav (1):
      can: m_can: Call the RAM init directly from m_can_chip_config

Vladimir Oltean (3):
      net: dsa: tag_8021q: avoid leaking ctx on dsa_tag_8021q_register() error path
      net: enetc: avoid buffer leaks on xdp_do_redirect() failure
      net: dsa: mv88e6xxx: avoid reg_lock deadlock in mv88e6xxx_setup_port()

Vladimir Zapolskiy (2):
      media: camss: Clean up received buffers on failed start of streaming
      media: camss: Do not attach an already attached power domain on MSM8916 platform

Wang Jingjin (2):
      ASoC: rockchip: pdm: Add missing clk_disable_unprepare() in rockchip_pdm_runtime_resume()
      ASoC: rockchip: spdif: Add missing clk_disable_unprepare() in rk_spdif_runtime_resume()

Wang ShaoBo (7):
      ACPI: pfr_telemetry: use ACPI_FREE() to free acpi_object
      ACPI: pfr_update: use ACPI_FREE() to free acpi_object
      regulator: core: use kfree_const() to free space conditionally
      drbd: remove call to memset before free device/resource/connection
      drbd: destroy workqueue when drbd device was freed
      SUNRPC: Fix missing release socket in rpc_sockname()
      Bluetooth: btintel: Fix missing free skb in btintel_setup_combined()

Wang Weiyang (1):
      rapidio: fix possible UAF when kfifo_alloc() fails

Wang Yufen (9):
      pstore/ram: Fix error return code in ramoops_probe()
      selftests/bpf: fix memory leak of lsm_cgroup
      wifi: brcmfmac: Fix error return code in brcmf_sdio_download_firmware()
      crypto: qat - fix error return code in adf_probe
      RDMA/hfi1: Fix error return code in parse_platform_config()
      RDMA/srp: Fix error return code in srp_parse_options()
      ASoC: mediatek: mt8173-rt5650-rt5514: fix refcount leak in mt8173_rt5650_rt5514_dev_probe()
      ASoC: audio-graph-card: fix refcount leak of cpu_ep in __graph_for_each_link()
      ASoC: mediatek: mt8183: fix refcount leak in mt8183_mt6358_ts3a227_max98357_dev_probe()

Wei Yongjun (1):
      irqchip/wpcm450: Fix memory leak in wpcm450_aic_of_init()

Weili Qian (3):
      crypto: hisilicon/qm - fix missing destroy qp_idr
      crypto: hisilicon/qm - get hardware features from hardware registers
      crypto: hisilicon/qm - re-enable communicate interrupt before notifying PF

Wenpeng Liang (1):
      RDMA/hns: Remove redundant DFX file and DFX ops structure

Wesley Chalmers (2):
      drm/amd/display: Disable DRR actions during state commit
      drm/amd/display: Use the largest vready_offset in pipe group

Wolfram Sang (11):
      arm64: dts: renesas: r8a779f0: Fix HSCIF "brg_int" clock
      arm64: dts: renesas: r8a779f0: Fix SCIF "brg_int" clock
      clocksource/drivers/sh_cmt: Access registers according to spec
      clk: renesas: r8a779a0: Fix SD0H clock name
      clk: renesas: r8a779f0: Fix HSCIF parent clocks
      clk: renesas: r8a779f0: Fix SCIF parent clocks
      mmc: renesas_sdhi: alway populate SCC pointer
      mmc: renesas_sdhi: add quirk for broken register layout
      mmc: renesas_sdhi: better reset from HS400 mode
      clk: renesas: r8a779f0: Add SDH0 clock
      clk: renesas: r8a779f0: Add TMU and parent SASYNC clocks

Wright Feng (1):
      brcmfmac: return error when getting invalid max_flowrings from dongle

Xia Fukun (1):
      drm/i915/bios: fix a memory leak in generate_lfp_data_ptrs

Xiao Ni (1):
      md/raid0, raid10: Don't set discard sectors for request queue

Xie Shaowen (1):
      macintosh/macio-adb: check the return value of ioremap()

Xinlei Lee (1):
      drm/mediatek: Modify dpi power on/off sequence.

Xiongfeng Wang (15):
      ACPI: irq: Fix some kernel-doc issues
      perf/x86/intel/uncore: Fix reference count leak in sad_cfg_iio_topology()
      perf/x86/intel/uncore: Fix reference count leak in hswep_has_limit_sbox()
      perf/x86/intel/uncore: Fix reference count leak in snr_uncore_mmio_map()
      perf/x86/intel/uncore: Fix reference count leak in __uncore_imc_init_box()
      cpufreq: amd_freq_sensitivity: Add missing pci_dev_put()
      drm/radeon: Fix PCI device refcount leak in radeon_atrm_get_bios()
      drm/amdgpu: Fix PCI device refcount leak in amdgpu_atrm_get_bios()
      mt76: mt7915: Fix PCI device refcount leak in mt7915_pci_init_hif2()
      crypto: hisilicon/qm - add missing pci_dev_put() in q_num_set()
      RDMA/hfi: Decrease PCI device reference count in error path
      hwrng: amd - Fix PCI device refcount leak
      hwrng: geode - Fix PCI device refcount leak
      serial: pch: Fix PCI device refcount leak in pch_request_dma()
      fbdev: vermilion: decrease reference count in error path

Xiu Jianfeng (12):
      x86/xen: Fix memory leak in xen_smp_intr_init{_pv}()
      x86/xen: Fix memory leak in xen_init_lock_cpu()
      ima: Fix misuse of dereference of pointer in template_desc_init_fields()
      wifi: ath10k: Fix return value in ath10k_pci_init()
      clk: rockchip: Fix memory leak in rockchip_clk_register_pll()
      clk: visconti: Fix memory leak in visconti_register_pll()
      clk: samsung: Fix memory leak in _samsung_clk_register_pll()
      clk: socfpga: Fix memory leak in socfpga_gate_init()
      apparmor: Use pointer to struct aa_label for lbs_cred
      apparmor: Fix memleak in alloc_ns()
      ksmbd: Fix resource leak in ksmbd_session_rpc_open()
      clk: st: Fix memory leak in st_of_quadfs_setup()

Xu Kuohai (6):
      libbpf: Fix use-after-free in btf_dump_name_dups
      libbpf: Fix memory leak in parse_usdt_arg()
      selftests/bpf: Fix memory leak caused by not destroying skeleton
      selftest/bpf: Fix memory leak in kprobe_multi_test
      selftests/bpf: Fix error failure of case test_xdp_adjust_tail_grow
      selftest/bpf: Fix error usage of ASSERT_OK in xdp_adjust_tail.c

Yan Lei (1):
      media: dvb-frontends: fix leak of memory fw

Yang Jihong (3):
      selftests/bpf: Fix xdp_synproxy compilation failure in 32-bit arch
      blktrace: Fix output non-blktrace event when blk_classic option enabled
      perf debug: Set debug_peo_args and redirect_to_stderr variable to correct values in perf_quiet_option()

Yang Shen (1):
      coresight: trbe: remove cpuhp instance node before remove cpuhp state

Yang Yingliang (83):
      MIPS: vpe-mt: fix possible memory leak while module exiting
      MIPS: vpe-cmp: fix possible memory leak while module exiting
      PNP: fix name memory leak in pnp_alloc_dev()
      thermal: core: fix some possible name leaks in error paths
      EDAC/i10nm: fix refcount leak in pci_get_dev_wrapper()
      genirq/irqdesc: Don't try to remove non-existing sysfs files
      rapidio: fix possible name leaks when rio_add_device() fails
      rapidio: rio: fix possible name leak in rio_register_mport()
      clocksource/drivers/timer-ti-dm: Fix missing clk_disable_unprepare in dmtimer_systimer_init_clock()
      platform/x86: intel_scu_ipc: fix possible name leak in __intel_scu_ipc_register()
      pinctrl: ocelot: add missing destroy_workqueue() in error path in ocelot_pinctrl_probe()
      media: platform: exynos4-is: fix return value check in fimc_md_probe()
      regulator: core: fix unbalanced of node refcount in regulator_dev_lookup()
      media: solo6x10: fix possible memory leak in solo_sysfs_init()
      drm/amdgpu: fix pci device refcount leak
      regulator: core: fix module refcount leak in set_supply()
      regulator: core: fix resource leak in regulator_register()
      mmc: alcor: fix return value check of mmc_add_host()
      mmc: moxart: fix return value check of mmc_add_host()
      mmc: mxcmmc: fix return value check of mmc_add_host()
      mmc: pxamci: fix return value check of mmc_add_host()
      mmc: rtsx_pci: fix return value check of mmc_add_host()
      mmc: rtsx_usb_sdmmc: fix return value check of mmc_add_host()
      mmc: toshsd: fix return value check of mmc_add_host()
      mmc: vub300: fix return value check of mmc_add_host()
      mmc: wmt-sdmmc: fix return value check of mmc_add_host()
      mmc: atmel-mci: fix return value check of mmc_add_host()
      mmc: omap_hsmmc: fix return value check of mmc_add_host()
      mmc: meson-gx: fix return value check of mmc_add_host()
      mmc: via-sdmmc: fix return value check of mmc_add_host()
      mmc: wbsd: fix return value check of mmc_add_host()
      mmc: mmci: fix return value check of mmc_add_host()
      ethernet: s2io: don't call dev_kfree_skb() under spin_lock_irqsave()
      net: apple: mace: don't call dev_kfree_skb() under spin_lock_irqsave()
      net: apple: bmac: don't call dev_kfree_skb() under spin_lock_irqsave()
      net: emaclite: don't call dev_kfree_skb() under spin_lock_irqsave()
      net: ethernet: dnet: don't call dev_kfree_skb() under spin_lock_irqsave()
      hamradio: don't call dev_kfree_skb() under spin_lock_irqsave()
      net: amd: lance: don't call dev_kfree_skb() under spin_lock_irqsave()
      af_unix: call proto_unregister() in the error path in af_unix_init()
      Bluetooth: hci_core: fix error handling in hci_register_dev()
      Bluetooth: btusb: don't call kfree_skb() under spin_lock_irqsave()
      Bluetooth: hci_qca: don't call kfree_skb() under spin_lock_irqsave()
      Bluetooth: hci_ll: don't call kfree_skb() under spin_lock_irqsave()
      Bluetooth: hci_h5: don't call kfree_skb() under spin_lock_irqsave()
      Bluetooth: hci_bcsp: don't call kfree_skb() under spin_lock_irqsave()
      Bluetooth: hci_core: don't call kfree_skb() under spin_lock_irqsave()
      Bluetooth: RFCOMM: don't call kfree_skb() under spin_lock_irqsave()
      scsi: mpt3sas: Fix possible resource leaks in mpt3sas_transport_port_add()
      scsi: hpsa: Fix error handling in hpsa_add_sas_host()
      scsi: hpsa: Fix possible memory leak in hpsa_add_sas_device()
      scsi: fcoe: Fix possible name leak when device_register() fails
      scsi: scsi_debug: Fix possible name leak in sdebug_add_host_helper()
      drivers: dio: fix possible memory leak in dio_init()
      class: fix possible memory leak in __class_register()
      usb: typec: tcpci: fix of node refcount leak in tcpci_register_port()
      misc: ocxl: fix possible name leak in ocxl_file_register_afu()
      ocxl: fix pci device refcount leak when calling get_function_0()
      firmware: raspberrypi: fix possible memory leak in rpi_firmware_probe()
      cxl: fix possible null-ptr-deref in cxl_guest_init_afu|adapter()
      cxl: fix possible null-ptr-deref in cxl_pci_init_afu|adapter()
      usb: roles: fix of node refcount leak in usb_role_switch_is_parent()
      usb: core: hcd: Fix return value check in usb_hcd_setup_local_mem()
      mcb: mcb-parse: fix error handing in chameleon_parse_gdd()
      chardev: fix error handling in cdev_device_add()
      i2c: mux: reg: check return value after calling platform_get_resource()
      usb: typec: wusb3801: fix fwnode refcount leak in wusb3801_probe()
      fbdev: pm2fb: fix missing pci_disable_device()
      HSI: omap_ssi_core: fix unbalanced pm_runtime_disable()
      HSI: omap_ssi_core: fix possible memory leak in ssi_probe()
      iommu/mediatek: Check return value after calling platform_get_resource()
      iommu/amd: Fix pci device refcount leak in ppr_notifier()
      macintosh: fix possible memory leak in macio_add_one_device()
      powerpc/xive: add missing iounmap() in error path in xive_spapr_populate_irq_data()
      powerpc/83xx/mpc832x_rdb: call platform_device_put() in error case in of_fsl_spi_probe()
      mfd: pm8008: Fix return value check in pm8008_probe()
      mISDN: hfcsusb: don't call dev_kfree_skb/kfree_skb() under spin_lock_irqsave()
      mISDN: hfcpci: don't call dev_kfree_skb/kfree_skb() under spin_lock_irqsave()
      mISDN: hfcmulti: don't call dev_kfree_skb/kfree_skb() under spin_lock_irqsave()
      mailbox: arm_mhuv2: Fix return value check in mhuv2_probe()
      mailbox: zynq-ipi: fix error handling while device_register() fails
      hwmon: (jc42) Fix missing unlock on error in jc42_write()
      ASoC: sof_es8336: fix possible use-after-free in sof_es8336_remove()

Yangtao Li (1):
      f2fs: fix iostat parameter for discard

Yassine Oudjana (3):
      arm64: dts: qcom: msm8996: Add MSM8996 Pro support
      regmap-irq: Use the new num_config_regs property in regmap_add_irq_chip_fwnode
      extcon: usbc-tusb320: Call the Type-C IRQ handler only if a port is registered

Ye Bin (1):
      blk-mq: fix possible memleak when register 'hctx' failed

Yicong Yang (1):
      drivers/perf: hisi: Fix some event id for hisi-pcie-pmu

Yipeng Zou (1):
      selftests/ftrace: event_triggers: wait longer for test_event_enable

Yixing Liu (1):
      RDMA/hns: Fix the gid problem caused by free mr

Yong Wu (3):
      iommu/mediatek: Add platform_device_put for recovering the device refcnt
      iommu/mediatek: Use component_match_add
      iommu/mediatek: Add error path for loop of mm_dts_parse

Yonggil Song (1):
      f2fs: avoid victim selection from previous victim section

Yonghong Song (2):
      selftests/bpf: Add struct argument tests with fentry/fexit programs.
      bpf: Fix a BTF_ID_LIST bug with CONFIG_DEBUG_INFO_BTF not set

Yongqiang Liu (1):
      net: defxx: Fix missing err handling in dfx_init()

Youghandhar Chintala (1):
      wifi: ath10k: Delay the unmapping of the buffer

Yu Kuai (2):
      dm: make sure create and remove dm device won't race with open and close table
      block, bfq: fix possible uaf for 'bfqq->bic'

Yu Liao (1):
      platform/x86: mxm-wmi: fix memleak in mxm_wmi_call_mx[ds|mx]()

Yuan Can (20):
      perf: arm_dsu: Fix hotplug callback leak in dsu_pmu_init()
      drivers: perf: marvell_cn10k: Fix hotplug callback leak in tad_pmu_init()
      tpm/tpm_ftpm_tee: Fix error handling in ftpm_mod_init()
      platform/chrome: cros_usbpd_notify: Fix error handling in cros_usbpd_notify_init()
      media: platform: exynos4-is: Fix error handling in fimc_md_init()
      media: amphion: Fix error handling in vpu_driver_init()
      ASoC: qcom: Add checks for devm_kcalloc
      wifi: nl80211: Add checks for nla_nest_start() in nl80211_send_iface()
      regulator: qcom-labibb: Fix missing of_node_put() in qcom_labibb_regulator_probe()
      drivers: net: qlcnic: Fix potential memory leak in qlcnic_sriov_init()
      scsi: hpsa: Fix possible memory leak in hpsa_init_one()
      RDMA/nldev: Add checks for nla_nest_start() in fill_stat_counter_qps()
      serial: 8250_bcm7271: Fix error handling in brcmuart_init()
      serial: sunsab: Fix error handling in sunsab_init()
      HSI: omap_ssi_core: Fix error handling in ssi_init()
      power: supply: ab8500: Fix error handling in ab8500_charger_init()
      iommu/fsl_pamu: Fix resource leak in fsl_pamu_probe()
      remoteproc: qcom_q6v5_pas: Fix missing of_node_put() in adsp_alloc_memory_region()
      drm/rockchip: use pm_runtime_resume_and_get() instead of pm_runtime_get_sync()
      floppy: Fix memory leak in do_floppy_init()

Yue Hu (1):
      erofs: support interlaced uncompressed data for compressed files

YueHaibing (2):
      selftests: cgroup: fix unsigned comparison with less than zero
      staging: rtl8192e: Fix potential use-after-free in rtllib_rx_Monitor()

Yunfei Dong (6):
      media: mediatek: vcodec: fix h264 cavlc bitstream fail
      media: mediatek: vcodec: Fix getting NULL pointer for dst buffer
      media: mediatek: vcodec: Fix h264 set lat buffer error
      media: mediatek: vcodec: Setting lat buf to lat_list when lat decode error
      media: mediatek: vcodec: Core thread depends on core_list
      media: mediatek: vcodec: Can't set dst buffer to done when lat decode error

Yushan Zhou (1):
      rtc: rzn1: Check return value in rzn1_rtc_probe

Zeng Heng (4):
      ASoC: pxa: fix null-pointer dereference in filter()
      PCI: Check for alloc failure in pci_request_irq()
      power: supply: fix residue sysfs file in error handle route of __power_supply_register()
      iio: fix memory leak in iio_device_register_eventset()

Zhang Changzhong (1):
      net: stmmac: selftests: fix potential memleak in stmmac_test_arpoffload()

Zhang Qilong (7):
      soc: ti: knav_qmss_queue: Fix PM disable depth imbalance in knav_queue_probe
      soc: ti: smartreflex: Fix PM disable depth imbalance in omap_sr_probe
      eventfd: change int to __u64 in eventfd_signal() ifndef CONFIG_EVENTFD
      drm/rockchip: lvds: fix PM usage counter unbalance in poweron
      ASoC: pcm512x: Fix PM disable depth imbalance in pcm512x_probe
      f2fs: Fix the race condition of resize flag between resizefs
      power: supply: z2_battery: Fix possible memleak in z2_batt_probe()

Zhang Xiaoxu (8):
      mtd: Fix device name leak when register device failed in add_mtd_device()
      xprtrdma: Fix regbuf data not freed in rpcrdma_req_create()
      RDMA/rxe: Fix NULL-ptr-deref in rxe_qp_do_cleanup() when socket create failed
      orangefs: Fix sysfs not cleanup when dev init failed
      orangefs: Fix kmemleak in orangefs_prepare_debugfs_help_string()
      orangefs: Fix kmemleak in orangefs_sysfs_init()
      orangefs: Fix kmemleak in orangefs_{kernel,client}_debug_init()
      cifs: Fix xid leak in cifs_get_file_info_unix()

Zhang Yiqun (1):
      crypto: tcrypt - Fix multibuffer skcipher speed test mem leak

Zhang Yuchen (1):
      ipmi: fix memleak when unload ipmi driver

Zhang Zekun (1):
      drm/tegra: Add missing clk_disable_unprepare() in tegra_dc_probe()

ZhangPeng (4):
      hfs: Fix OOB Write in hfs_asc2mac
      pinctrl: k210: call of_node_put()
      pinctrl: pinconf-generic: add missing of_node_put()
      hfs: fix OOB Read in __hfs_brec_find

Zhao Gongyi (1):
      selftests/efivarfs: Add checking of the test return value

Zhen Lei (1):
      mmc: core: Normalize the error handling branch in sd_read_ext_regs()

Zheng Wang (1):
      misc: sgi-gru: fix use-after-free error in gru_set_context_option, gru_fault and gru_handle_user_call_os

Zheng Yejian (2):
      tracing/hist: Fix issue of losting command info in error_log
      acct: fix potential integer overflow in encode_comp_t()

Zheng Yongjun (1):
      mtd: maps: pxa2xx-flash: fix memory leak in probe

Zhengchao Shao (5):
      ipc: fix memory leak in init_mqueue_fs()
      wifi: mac80211: fix memory leak in ieee80211_if_add()
      RDMA/hns: fix memory leak in hns_roce_alloc_mr()
      test_firmware: fix memory leak in test_firmware_init()
      drivers: mcb: fix resource leak in mcb_probe()

Zheyu Ma (2):
      i2c: ismt: Fix an out-of-bounds bug in ismt_access()
      power: supply: cw2015: Use device managed API to simplify the code

Zhiqi Song (1):
      crypto: hisilicon/hpre - fix resource leak in remove process

Ziyang Xuan (1):
      wifi: plfxlc: fix potential memory leak in __lf_x_usb_enable_rx()

Zong-Zhe Yang (1):
      wifi: rtw89: fix physts IE page check

Zqiang (1):
      rcu: Fix __this_cpu_read() lockdep warning in rcu_force_quiescent_state()

delisun (1):
      serial: pl011: Do not clear RX FIFO & RX interrupt in unthrottle.

gehao (1):
      drm/amd/display: prevent memory leak

ruanjinjie (3):
      of: overlay: fix null pointer dereferencing in find_dup_cset_node_entry() and find_dup_cset_prop()
      misc: tifm: fix possible memory leak in tifm_7xx1_switch_media()
      power: supply: fix null pointer dereferencing in power_supply_get_battery_info

wangdicheng (1):
      ALSA: usb-audio: add the quirk for KT0206 device

wuchi (1):
      lib/debugobjects: fix stat count and optimize debug_objects_mem_init

xinlei lee (1):
      pwm: mtk-disp: Fix the parameters calculated by the enabled flag of disp_pwm

xiongxin (1):
      PM: hibernate: Fix mistake in kerneldoc comment

zhichao.liu (1):
      spi: mt65xx: Add dma max segment size declaration

Íñigo Huguet (1):
      wifi: mac80211: fix maybe-unused warning


^ permalink raw reply	[relevance 1%]

* Linux 6.1.2
@ 2022-12-31 12:46  1% Greg Kroah-Hartman
  0 siblings, 0 replies; 77+ results
From: Greg Kroah-Hartman @ 2022-12-31 12:46 UTC (permalink / raw)
  To: linux-kernel, akpm, torvalds, stable; +Cc: lwn, jslaby, Greg Kroah-Hartman

I'm announcing the release of the 6.1.2 kernel.

All users of the 6.1 kernel series must upgrade.

The updated 6.1.y git tree can be found at:
	git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable.git linux-6.1.y
and can be browsed at the normal kernel.org git web browser:
	https://git.kernel.org/?p=linux/kernel/git/stable/linux-stable.git;a=summary

thanks,

greg k-h

------------

 Documentation/ABI/stable/sysfs-driver-dma-idxd                           |   12 
 Documentation/ABI/testing/sysfs-bus-spi-devices-spi-nor                  |    3 
 Documentation/admin-guide/sysctl/kernel.rst                              |   23 
 Documentation/devicetree/bindings/input/azoteq,iqs7222.yaml              |   25 
 Documentation/devicetree/bindings/mfd/qcom,spmi-pmic.yaml                |    8 
 Documentation/devicetree/bindings/pci/fsl,imx6q-pcie.yaml                |   46 
 Documentation/devicetree/bindings/pci/toshiba,visconti-pcie.yaml         |    7 
 Documentation/devicetree/bindings/pinctrl/mediatek,mt7986-pinctrl.yaml   |   46 
 Documentation/devicetree/bindings/pwm/microchip,corepwm.yaml             |    4 
 Documentation/devicetree/bindings/sound/qcom,wcd9335.txt                 |    2 
 Documentation/devicetree/bindings/sound/rt5682.txt                       |    2 
 Documentation/driver-api/spi.rst                                         |    4 
 Documentation/fault-injection/fault-injection.rst                        |   10 
 Makefile                                                                 |    2 
 arch/Kconfig                                                             |    2 
 arch/alpha/include/asm/thread_info.h                                     |    2 
 arch/alpha/kernel/entry.S                                                |    4 
 arch/arm/boot/dts/armada-370.dtsi                                        |    2 
 arch/arm/boot/dts/armada-375.dtsi                                        |    2 
 arch/arm/boot/dts/armada-380.dtsi                                        |    4 
 arch/arm/boot/dts/armada-385-turris-omnia.dts                            |   18 
 arch/arm/boot/dts/armada-385.dtsi                                        |    6 
 arch/arm/boot/dts/armada-39x.dtsi                                        |    6 
 arch/arm/boot/dts/armada-xp-mv78230.dtsi                                 |    8 
 arch/arm/boot/dts/armada-xp-mv78260.dtsi                                 |   16 
 arch/arm/boot/dts/aspeed-bmc-ibm-everest.dts                             |   17 
 arch/arm/boot/dts/aspeed-bmc-ibm-rainier.dts                             |   16 
 arch/arm/boot/dts/dove.dtsi                                              |    2 
 arch/arm/boot/dts/nuvoton-npcm730-gbs.dts                                |    2 
 arch/arm/boot/dts/nuvoton-npcm730-gsj.dts                                |    2 
 arch/arm/boot/dts/nuvoton-npcm730-kudo.dts                               |    6 
 arch/arm/boot/dts/nuvoton-npcm750-evb.dts                                |    4 
 arch/arm/boot/dts/nuvoton-npcm750-runbmc-olympus.dts                     |    6 
 arch/arm/boot/dts/qcom-apq8064.dtsi                                      |    2 
 arch/arm/boot/dts/spear600.dtsi                                          |    2 
 arch/arm/boot/dts/stm32mp157a-dhcor-avenger96.dts                        |    1 
 arch/arm/boot/dts/stm32mp15xx-dhcor-avenger96.dtsi                       |    2 
 arch/arm/mach-mmp/time.c                                                 |   11 
 arch/arm64/boot/dts/apple/t8103.dtsi                                     |    6 
 arch/arm64/boot/dts/marvell/armada-3720-turris-mox.dts                   |    3 
 arch/arm64/boot/dts/mediatek/mt2712-evb.dts                              |   12 
 arch/arm64/boot/dts/mediatek/mt2712e.dtsi                                |   22 
 arch/arm64/boot/dts/mediatek/mt6779.dtsi                                 |    8 
 arch/arm64/boot/dts/mediatek/mt6797.dtsi                                 |    2 
 arch/arm64/boot/dts/mediatek/mt7986a.dtsi                                |   16 
 arch/arm64/boot/dts/mediatek/mt8183.dtsi                                 |    2 
 arch/arm64/boot/dts/mediatek/mt8195.dtsi                                 |    8 
 arch/arm64/boot/dts/mediatek/pumpkin-common.dtsi                         |    6 
 arch/arm64/boot/dts/nvidia/tegra234.dtsi                                 |    8 
 arch/arm64/boot/dts/qcom/ipq6018-cp01-c1.dts                             |    2 
 arch/arm64/boot/dts/qcom/msm8916.dtsi                                    |    2 
 arch/arm64/boot/dts/qcom/msm8996.dtsi                                    |  114 +
 arch/arm64/boot/dts/qcom/msm8996pro.dtsi                                 |  266 ++++
 arch/arm64/boot/dts/qcom/pm6350.dtsi                                     |    1 
 arch/arm64/boot/dts/qcom/pm660.dtsi                                      |    2 
 arch/arm64/boot/dts/qcom/sc7180-trogdor-homestar.dtsi                    |    6 
 arch/arm64/boot/dts/qcom/sc7280-idp.dts                                  |    1 
 arch/arm64/boot/dts/qcom/sc7280-idp.dtsi                                 |    3 
 arch/arm64/boot/dts/qcom/sc7280-qcard.dtsi                               |    2 
 arch/arm64/boot/dts/qcom/sdm630.dtsi                                     |    2 
 arch/arm64/boot/dts/qcom/sdm845-cheza.dtsi                               |    4 
 arch/arm64/boot/dts/qcom/sdm845-xiaomi-polaris.dts                       |    2 
 arch/arm64/boot/dts/qcom/sm6125.dtsi                                     |    2 
 arch/arm64/boot/dts/qcom/sm6350.dtsi                                     |   10 
 arch/arm64/boot/dts/qcom/sm8150.dtsi                                     |   10 
 arch/arm64/boot/dts/qcom/sm8250-mtp.dts                                  |    2 
 arch/arm64/boot/dts/qcom/sm8250-sony-xperia-edo.dtsi                     |    2 
 arch/arm64/boot/dts/qcom/sm8250.dtsi                                     |   20 
 arch/arm64/boot/dts/qcom/sm8350.dtsi                                     |   10 
 arch/arm64/boot/dts/qcom/sm8450-sony-xperia-nagara-pdx223.dts            |    2 
 arch/arm64/boot/dts/qcom/sm8450.dtsi                                     |   13 
 arch/arm64/boot/dts/renesas/r8a779f0.dtsi                                |   16 
 arch/arm64/boot/dts/renesas/r8a779g0.dtsi                                |    2 
 arch/arm64/boot/dts/renesas/r9a09g011.dtsi                               |    6 
 arch/arm64/boot/dts/tesla/fsd-pinctrl.dtsi                               |   34 
 arch/arm64/boot/dts/tesla/fsd-pinctrl.h                                  |    6 
 arch/arm64/boot/dts/ti/k3-am65-main.dtsi                                 |    1 
 arch/arm64/boot/dts/ti/k3-j7200-mcu-wakeup.dtsi                          |    1 
 arch/arm64/boot/dts/ti/k3-j721e-main.dtsi                                |    1 
 arch/arm64/boot/dts/ti/k3-j721s2-main.dtsi                               |    2 
 arch/arm64/boot/dts/ti/k3-j721s2-mcu-wakeup.dtsi                         |    2 
 arch/arm64/crypto/Kconfig                                                |   11 
 arch/arm64/crypto/Makefile                                               |    3 
 arch/arm64/crypto/sm3-neon-core.S                                        |  601 +++++++++
 arch/arm64/crypto/sm3-neon-glue.c                                        |  103 +
 arch/arm64/include/asm/processor.h                                       |    4 
 arch/arm64/mm/fault.c                                                    |    8 
 arch/mips/bcm63xx/clk.c                                                  |    2 
 arch/mips/boot/dts/ingenic/ci20.dts                                      |    2 
 arch/mips/cavium-octeon/executive/cvmx-helper-board.c                    |    2 
 arch/mips/cavium-octeon/executive/cvmx-helper.c                          |    2 
 arch/mips/kernel/vpe-cmp.c                                               |    4 
 arch/mips/kernel/vpe-mt.c                                                |    4 
 arch/mips/ralink/of.c                                                    |    4 
 arch/powerpc/boot/dts/turris1x.dts                                       |   14 
 arch/powerpc/include/asm/hvcall.h                                        |    3 
 arch/powerpc/perf/callchain.c                                            |    1 
 arch/powerpc/perf/hv-gpci-requests.h                                     |    4 
 arch/powerpc/perf/hv-gpci.c                                              |   35 
 arch/powerpc/perf/hv-gpci.h                                              |    1 
 arch/powerpc/perf/req-gen/perf.h                                         |   20 
 arch/powerpc/platforms/52xx/mpc52xx_lpbfifo.c                            |    1 
 arch/powerpc/platforms/83xx/mpc832x_rdb.c                                |    2 
 arch/powerpc/platforms/pseries/eeh_pseries.c                             |   11 
 arch/powerpc/platforms/pseries/plpks.c                                   |   32 
 arch/powerpc/platforms/pseries/plpks.h                                   |    2 
 arch/powerpc/sysdev/xive/spapr.c                                         |    1 
 arch/powerpc/xmon/xmon.c                                                 |    7 
 arch/riscv/boot/dts/microchip/mpfs-icicle-kit-fabric.dtsi                |    2 
 arch/riscv/boot/dts/microchip/mpfs-icicle-kit.dts                        |    2 
 arch/riscv/boot/dts/microchip/mpfs-sev-kit-fabric.dtsi                   |   29 
 arch/riscv/include/asm/hugetlb.h                                         |    6 
 arch/riscv/include/asm/io.h                                              |    5 
 arch/riscv/include/asm/pgtable-64.h                                      |    6 
 arch/riscv/kernel/entry.S                                                |   18 
 arch/riscv/kernel/signal.c                                               |   34 
 arch/riscv/kernel/traps.c                                                |    2 
 arch/riscv/kvm/vcpu.c                                                    |   11 
 arch/riscv/mm/physaddr.c                                                 |    2 
 arch/riscv/net/bpf_jit_comp64.c                                          |   29 
 arch/x86/Kconfig                                                         |    4 
 arch/x86/crypto/aegis128-aesni-asm.S                                     |    9 
 arch/x86/crypto/aria-aesni-avx-asm_64.S                                  |   13 
 arch/x86/crypto/sha1_ni_asm.S                                            |    3 
 arch/x86/crypto/sha1_ssse3_asm.S                                         |    3 
 arch/x86/crypto/sha256-avx-asm.S                                         |    3 
 arch/x86/crypto/sha256-avx2-asm.S                                        |    3 
 arch/x86/crypto/sha256-ssse3-asm.S                                       |    3 
 arch/x86/crypto/sha256_ni_asm.S                                          |    3 
 arch/x86/crypto/sha512-avx-asm.S                                         |    3 
 arch/x86/crypto/sha512-avx2-asm.S                                        |    3 
 arch/x86/crypto/sha512-ssse3-asm.S                                       |    3 
 arch/x86/crypto/sm3-avx-asm_64.S                                         |    3 
 arch/x86/crypto/sm4-aesni-avx-asm_64.S                                   |    7 
 arch/x86/crypto/sm4-aesni-avx2-asm_64.S                                  |    7 
 arch/x86/events/intel/uncore_snb.c                                       |    3 
 arch/x86/events/intel/uncore_snbep.c                                     |    5 
 arch/x86/hyperv/hv_init.c                                                |    2 
 arch/x86/include/asm/apic.h                                              |    3 
 arch/x86/include/asm/realmode.h                                          |    1 
 arch/x86/include/asm/x86_init.h                                          |    4 
 arch/x86/kernel/apic/apic.c                                              |   13 
 arch/x86/kernel/cpu/intel.c                                              |   63 -
 arch/x86/kernel/cpu/sgx/encl.c                                           |   23 
 arch/x86/kernel/setup.c                                                  |    2 
 arch/x86/kernel/uprobes.c                                                |    4 
 arch/x86/kernel/x86_init.c                                               |    3 
 arch/x86/realmode/init.c                                                 |    8 
 arch/x86/xen/enlighten_pv.c                                              |    2 
 arch/x86/xen/smp.c                                                       |   24 
 arch/x86/xen/smp_pv.c                                                    |   12 
 arch/x86/xen/spinlock.c                                                  |    6 
 block/bfq-iosched.c                                                      |   16 
 block/blk-cgroup.c                                                       |    2 
 block/blk-mq-sysfs.c                                                     |   11 
 block/blk-mq.c                                                           |   56 
 block/genhd.c                                                            |    2 
 crypto/cryptd.c                                                          |   36 
 crypto/tcrypt.c                                                          |  265 ++--
 drivers/acpi/acpica/dsmethod.c                                           |   10 
 drivers/acpi/acpica/utcopy.c                                             |    7 
 drivers/acpi/ec.c                                                        |   10 
 drivers/acpi/irq.c                                                       |    5 
 drivers/acpi/pfr_telemetry.c                                             |    6 
 drivers/acpi/pfr_update.c                                                |    6 
 drivers/acpi/processor_idle.c                                            |    3 
 drivers/acpi/video_detect.c                                              |   54 
 drivers/acpi/x86/utils.c                                                 |   24 
 drivers/ata/libata-sata.c                                                |   11 
 drivers/base/class.c                                                     |    5 
 drivers/base/power/runtime.c                                             |   12 
 drivers/base/regmap/regmap-irq.c                                         |   15 
 drivers/block/drbd/drbd_main.c                                           |    9 
 drivers/block/drbd/drbd_nl.c                                             |   10 
 drivers/block/floppy.c                                                   |    4 
 drivers/block/loop.c                                                     |   28 
 drivers/bluetooth/btintel.c                                              |    5 
 drivers/bluetooth/btusb.c                                                |    6 
 drivers/bluetooth/hci_bcm.c                                              |   13 
 drivers/bluetooth/hci_bcsp.c                                             |    2 
 drivers/bluetooth/hci_h5.c                                               |    2 
 drivers/bluetooth/hci_ll.c                                               |    2 
 drivers/bluetooth/hci_qca.c                                              |    2 
 drivers/char/hw_random/amd-rng.c                                         |   18 
 drivers/char/hw_random/geode-rng.c                                       |   36 
 drivers/char/ipmi/ipmi_msghandler.c                                      |    8 
 drivers/char/ipmi/kcs_bmc_aspeed.c                                       |   24 
 drivers/char/tpm/tpm_crb.c                                               |    2 
 drivers/char/tpm/tpm_ftpm_tee.c                                          |    8 
 drivers/char/tpm/tpm_tis_core.c                                          |   20 
 drivers/char/tpm/tpm_tis_core.h                                          |    1 
 drivers/char/tpm/tpm_tis_i2c.c                                           |    3 
 drivers/clk/imx/clk-imx8mn.c                                             |  116 -
 drivers/clk/imx/clk-imx8mp.c                                             |    4 
 drivers/clk/imx/clk-imx93.c                                              |   19 
 drivers/clk/imx/clk-imxrt1050.c                                          |    2 
 drivers/clk/mediatek/clk-mt7986-infracfg.c                               |    2 
 drivers/clk/microchip/clk-mpfs-ccc.c                                     |    6 
 drivers/clk/qcom/clk-krait.c                                             |    2 
 drivers/clk/qcom/dispcc-sm6350.c                                         |    4 
 drivers/clk/qcom/gcc-ipq806x.c                                           |    4 
 drivers/clk/qcom/gcc-sm8250.c                                            |    4 
 drivers/clk/qcom/lpassaudiocc-sc7280.c                                   |   55 
 drivers/clk/qcom/lpasscorecc-sc7180.c                                    |   24 
 drivers/clk/renesas/r8a779a0-cpg-mssr.c                                  |    2 
 drivers/clk/renesas/r8a779f0-cpg-mssr.c                                  |   18 
 drivers/clk/renesas/r9a06g032-clocks.c                                   |    3 
 drivers/clk/rockchip/clk-pll.c                                           |    1 
 drivers/clk/samsung/clk-pll.c                                            |    1 
 drivers/clk/socfpga/clk-gate.c                                           |    5 
 drivers/clk/st/clkgen-fsyn.c                                             |    5 
 drivers/clk/visconti/pll.c                                               |    1 
 drivers/clocksource/sh_cmt.c                                             |   88 -
 drivers/clocksource/timer-ti-dm-systimer.c                               |    4 
 drivers/clocksource/timer-ti-dm.c                                        |    2 
 drivers/counter/stm32-lptimer-cnt.c                                      |    2 
 drivers/cpufreq/amd_freq_sensitivity.c                                   |    2 
 drivers/cpufreq/qcom-cpufreq-hw.c                                        |   43 
 drivers/cpuidle/dt_idle_states.c                                         |    2 
 drivers/crypto/Kconfig                                                   |    5 
 drivers/crypto/allwinner/sun8i-ss/sun8i-ss-cipher.c                      |    2 
 drivers/crypto/amlogic/amlogic-gxl-core.c                                |    1 
 drivers/crypto/amlogic/amlogic-gxl.h                                     |    2 
 drivers/crypto/cavium/nitrox/nitrox_mbx.c                                |    1 
 drivers/crypto/ccree/cc_debugfs.c                                        |    2 
 drivers/crypto/ccree/cc_driver.c                                         |   10 
 drivers/crypto/hisilicon/hpre/hpre_main.c                                |   10 
 drivers/crypto/hisilicon/qm.c                                            |   11 
 drivers/crypto/img-hash.c                                                |    8 
 drivers/crypto/omap-sham.c                                               |    2 
 drivers/crypto/qat/qat_4xxx/adf_drv.c                                    |    1 
 drivers/crypto/rockchip/rk3288_crypto.c                                  |  193 ---
 drivers/crypto/rockchip/rk3288_crypto.h                                  |   53 
 drivers/crypto/rockchip/rk3288_crypto_ahash.c                            |  197 +--
 drivers/crypto/rockchip/rk3288_crypto_skcipher.c                         |  413 +++---
 drivers/dio/dio.c                                                        |    8 
 drivers/dma/apple-admac.c                                                |  102 +
 drivers/dma/idxd/sysfs.c                                                 |   68 +
 drivers/edac/i10nm_base.c                                                |    3 
 drivers/extcon/extcon-usbc-tusb320.c                                     |   17 
 drivers/firmware/raspberrypi.c                                           |    1 
 drivers/firmware/ti_sci.c                                                |    5 
 drivers/gpio/gpiolib-cdev.c                                              |  204 ++-
 drivers/gpio/gpiolib.c                                                   |    4 
 drivers/gpio/gpiolib.h                                                   |    5 
 drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c                         |    2 
 drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c                                 |    1 
 drivers/gpu/drm/amd/amdgpu/amdgpu_device.c                               |    9 
 drivers/gpu/drm/amd/amdgpu/amdgpu_virt.h                                 |    5 
 drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.c                                 |    2 
 drivers/gpu/drm/amd/amdgpu/nv.c                                          |   28 
 drivers/gpu/drm/amd/amdgpu/soc15.c                                       |   24 
 drivers/gpu/drm/amd/amdgpu/soc21.c                                       |    2 
 drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c                |   35 
 drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c                       |   16 
 drivers/gpu/drm/amd/display/dc/clk_mgr/dcn32/dcn32_clk_mgr.c             |    2 
 drivers/gpu/drm/amd/display/dc/core/dc.c                                 |   65 -
 drivers/gpu/drm/amd/display/dc/dce60/dce60_resource.c                    |    3 
 drivers/gpu/drm/amd/display/dc/dce80/dce80_resource.c                    |    2 
 drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c                |   30 
 drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c                       |   35 
 drivers/gpu/drm/amd/display/dc/dcn32/dcn32_dccg.c                        |    6 
 drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.c                    |    2 
 drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c                     |    7 
 drivers/gpu/drm/amd/include/kgd_pp_interface.h                           |    3 
 drivers/gpu/drm/amd/pm/powerplay/amd_powerplay.c                         |    3 
 drivers/gpu/drm/amd/pm/powerplay/hwmgr/pp_psm.c                          |    2 
 drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega10_thermal.c                  |   25 
 drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega20_hwmgr.c                    |    3 
 drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c                           |    4 
 drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c                     |   21 
 drivers/gpu/drm/bridge/adv7511/adv7511.h                                 |    3 
 drivers/gpu/drm/bridge/adv7511/adv7511_drv.c                             |   18 
 drivers/gpu/drm/bridge/adv7511/adv7533.c                                 |   25 
 drivers/gpu/drm/bridge/ite-it6505.c                                      |    8 
 drivers/gpu/drm/drm_atomic_helper.c                                      |   10 
 drivers/gpu/drm/drm_edid.c                                               |   12 
 drivers/gpu/drm/drm_fourcc.c                                             |    8 
 drivers/gpu/drm/etnaviv/etnaviv_gpu.c                                    |   11 
 drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c                                |    5 
 drivers/gpu/drm/i915/display/intel_bios.c                                |    2 
 drivers/gpu/drm/i915/display/intel_dp.c                                  |   59 
 drivers/gpu/drm/i915/gem/i915_gem_mman.c                                 |   21 
 drivers/gpu/drm/i915/gem/i915_gem_pm.c                                   |    2 
 drivers/gpu/drm/i915/gem/i915_gem_ttm.c                                  |   63 -
 drivers/gpu/drm/i915/gem/i915_gem_ttm.h                                  |   18 
 drivers/gpu/drm/i915/gem/i915_gem_ttm_move.c                             |    2 
 drivers/gpu/drm/i915/gt/intel_engine.h                                   |    6 
 drivers/gpu/drm/i915/gt/intel_engine_cs.c                                |   91 +
 drivers/gpu/drm/i915/gt/intel_gt.c                                       |    3 
 drivers/gpu/drm/i915/gt/intel_gt_types.h                                 |   17 
 drivers/gpu/drm/i915/gt/sysfs_engines.c                                  |   25 
 drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c                           |  109 +
 drivers/gpu/drm/i915/gt/uc/intel_guc_fwif.h                              |   21 
 drivers/gpu/drm/i915/gt/uc/intel_guc_log.c                               |    6 
 drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c                        |    8 
 drivers/gpu/drm/i915/i915_driver.c                                       |    3 
 drivers/gpu/drm/i915/i915_gem.c                                          |   45 
 drivers/gpu/drm/i915/intel_runtime_pm.c                                  |    5 
 drivers/gpu/drm/i915/intel_runtime_pm.h                                  |   22 
 drivers/gpu/drm/mediatek/mtk_dpi.c                                       |   12 
 drivers/gpu/drm/mediatek/mtk_hdmi.c                                      |    7 
 drivers/gpu/drm/meson/meson_encoder_cvbs.c                               |    7 
 drivers/gpu/drm/msm/adreno/a6xx_gpu.c                                    |   12 
 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.c                               |   11 
 drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c                                 |   27 
 drivers/gpu/drm/msm/dp/dp_display.c                                      |    2 
 drivers/gpu/drm/msm/dsi/dsi_host.c                                       |  121 -
 drivers/gpu/drm/msm/hdmi/hdmi.c                                          |    2 
 drivers/gpu/drm/mxsfb/lcdif_kms.c                                        |   48 
 drivers/gpu/drm/mxsfb/lcdif_regs.h                                       |    5 
 drivers/gpu/drm/panel/panel-sitronix-st7701.c                            |   12 
 drivers/gpu/drm/radeon/radeon_bios.c                                     |   19 
 drivers/gpu/drm/rcar-du/Kconfig                                          |    2 
 drivers/gpu/drm/rockchip/cdn-dp-core.c                                   |    2 
 drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c                          |    2 
 drivers/gpu/drm/rockchip/inno_hdmi.c                                     |    2 
 drivers/gpu/drm/rockchip/rk3066_hdmi.c                                   |    2 
 drivers/gpu/drm/rockchip/rockchip_drm_vop.c                              |    4 
 drivers/gpu/drm/rockchip/rockchip_drm_vop2.c                             |    2 
 drivers/gpu/drm/rockchip/rockchip_lvds.c                                 |   10 
 drivers/gpu/drm/sti/sti_dvo.c                                            |    7 
 drivers/gpu/drm/sti/sti_hda.c                                            |    7 
 drivers/gpu/drm/sti/sti_hdmi.c                                           |    7 
 drivers/gpu/drm/tegra/dc.c                                               |    4 
 drivers/hid/amd-sfh-hid/amd_sfh_client.c                                 |    4 
 drivers/hid/hid-apple.c                                                  |  118 -
 drivers/hid/hid-input.c                                                  |    6 
 drivers/hid/hid-logitech-hidpp.c                                         |   11 
 drivers/hid/hid-mcp2221.c                                                |   12 
 drivers/hid/hid-rmi.c                                                    |    2 
 drivers/hid/hid-sensor-custom.c                                          |    2 
 drivers/hid/hid-uclogic-params.c                                         |   73 +
 drivers/hid/hid-uclogic-rdesc.c                                          |   34 
 drivers/hid/hid-uclogic-rdesc.h                                          |    7 
 drivers/hid/i2c-hid/i2c-hid-core.c                                       |    3 
 drivers/hid/wacom_sys.c                                                  |    8 
 drivers/hid/wacom_wac.c                                                  |    4 
 drivers/hid/wacom_wac.h                                                  |    1 
 drivers/hsi/controllers/omap_ssi_core.c                                  |   14 
 drivers/hv/ring_buffer.c                                                 |   13 
 drivers/hwmon/Kconfig                                                    |    1 
 drivers/hwmon/emc2305.c                                                  |   44 
 drivers/hwmon/jc42.c                                                     |  243 ++--
 drivers/hwmon/nct6775-platform.c                                         |    7 
 drivers/hwtracing/coresight/coresight-cti-core.c                         |    2 
 drivers/hwtracing/coresight/coresight-trbe.c                             |    1 
 drivers/i2c/busses/i2c-ismt.c                                            |    3 
 drivers/i2c/busses/i2c-pxa-pci.c                                         |   10 
 drivers/i2c/muxes/i2c-mux-reg.c                                          |    5 
 drivers/iio/adc/ad_sigma_delta.c                                         |    8 
 drivers/iio/adc/ti-adc128s052.c                                          |   14 
 drivers/iio/addac/ad74413r.c                                             |    2 
 drivers/iio/imu/adis.c                                                   |   28 
 drivers/iio/industrialio-event.c                                         |    4 
 drivers/iio/temperature/ltc2983.c                                        |   10 
 drivers/infiniband/Kconfig                                               |    2 
 drivers/infiniband/core/device.c                                         |    2 
 drivers/infiniband/core/mad.c                                            |    5 
 drivers/infiniband/core/nldev.c                                          |    6 
 drivers/infiniband/core/restrack.c                                       |    2 
 drivers/infiniband/core/sysfs.c                                          |   17 
 drivers/infiniband/hw/hfi1/affinity.c                                    |    2 
 drivers/infiniband/hw/hfi1/firmware.c                                    |    6 
 drivers/infiniband/hw/hns/hns_roce_device.h                              |    3 
 drivers/infiniband/hw/hns/hns_roce_hw_v2.c                               |  217 ++-
 drivers/infiniband/hw/hns/hns_roce_hw_v2.h                               |   13 
 drivers/infiniband/hw/hns/hns_roce_main.c                                |   18 
 drivers/infiniband/hw/hns/hns_roce_mr.c                                  |    4 
 drivers/infiniband/hw/hns/hns_roce_qp.c                                  |  107 +
 drivers/infiniband/hw/irdma/uk.c                                         |  170 +-
 drivers/infiniband/hw/irdma/user.h                                       |   20 
 drivers/infiniband/hw/irdma/utils.c                                      |    2 
 drivers/infiniband/hw/irdma/verbs.c                                      |  145 --
 drivers/infiniband/hw/irdma/verbs.h                                      |   53 
 drivers/infiniband/sw/rxe/rxe_mr.c                                       |    9 
 drivers/infiniband/sw/rxe/rxe_qp.c                                       |    6 
 drivers/infiniband/sw/siw/siw_cq.c                                       |   24 
 drivers/infiniband/sw/siw/siw_qp_tx.c                                    |    2 
 drivers/infiniband/sw/siw/siw_verbs.c                                    |   40 
 drivers/infiniband/ulp/ipoib/ipoib_netlink.c                             |    7 
 drivers/infiniband/ulp/srp/ib_srp.c                                      |   96 +
 drivers/input/joystick/Kconfig                                           |    1 
 drivers/input/misc/Kconfig                                               |    2 
 drivers/input/misc/iqs7222.c                                             |  504 ++++----
 drivers/input/touchscreen/elants_i2c.c                                   |    9 
 drivers/interconnect/qcom/sc7180.c                                       |    2 
 drivers/iommu/amd/iommu_v2.c                                             |    1 
 drivers/iommu/fsl_pamu.c                                                 |    2 
 drivers/iommu/iommu.c                                                    |   28 
 drivers/iommu/mtk_iommu.c                                                |   53 
 drivers/iommu/rockchip-iommu.c                                           |   10 
 drivers/iommu/s390-iommu.c                                               |  106 -
 drivers/iommu/sun50i-iommu.c                                             |   89 +
 drivers/irqchip/irq-gic-pm.c                                             |    2 
 drivers/irqchip/irq-loongson-liointc.c                                   |    5 
 drivers/irqchip/irq-loongson-pch-pic.c                                   |    3 
 drivers/irqchip/irq-wpcm450-aic.c                                        |    1 
 drivers/isdn/hardware/mISDN/hfcmulti.c                                   |   19 
 drivers/isdn/hardware/mISDN/hfcpci.c                                     |   13 
 drivers/isdn/hardware/mISDN/hfcsusb.c                                    |   12 
 drivers/leds/leds-is31fl319x.c                                           |    3 
 drivers/leds/rgb/leds-qcom-lpg.c                                         |   18 
 drivers/macintosh/macio-adb.c                                            |    4 
 drivers/macintosh/macio_asic.c                                           |    2 
 drivers/mailbox/arm_mhuv2.c                                              |    4 
 drivers/mailbox/mailbox-mpfs.c                                           |   31 
 drivers/mailbox/pcc.c                                                    |    1 
 drivers/mailbox/zynqmp-ipi-mailbox.c                                     |    4 
 drivers/mcb/mcb-core.c                                                   |    4 
 drivers/mcb/mcb-parse.c                                                  |    2 
 drivers/md/dm.c                                                          |  123 +-
 drivers/md/md-bitmap.c                                                   |   27 
 drivers/md/raid0.c                                                       |    1 
 drivers/md/raid1.c                                                       |    1 
 drivers/md/raid10.c                                                      |    2 
 drivers/media/dvb-core/dvb_ca_en50221.c                                  |    2 
 drivers/media/dvb-core/dvb_frontend.c                                    |   10 
 drivers/media/dvb-core/dvbdev.c                                          |   32 
 drivers/media/dvb-frontends/bcm3510.c                                    |    1 
 drivers/media/i2c/ad5820.c                                               |   10 
 drivers/media/i2c/adv748x/adv748x-afe.c                                  |    4 
 drivers/media/i2c/dw9768.c                                               |   33 
 drivers/media/i2c/hi846.c                                                |   14 
 drivers/media/i2c/mt9p031.c                                              |    1 
 drivers/media/i2c/ov5640.c                                               |    3 
 drivers/media/i2c/ov5648.c                                               |    1 
 drivers/media/pci/saa7164/saa7164-core.c                                 |    4 
 drivers/media/pci/solo6x10/solo6x10-core.c                               |    1 
 drivers/media/platform/amphion/vdec.c                                    |   15 
 drivers/media/platform/amphion/vpu.h                                     |    1 
 drivers/media/platform/amphion/vpu_cmds.c                                |   39 
 drivers/media/platform/amphion/vpu_drv.c                                 |    6 
 drivers/media/platform/amphion/vpu_malone.c                              |    1 
 drivers/media/platform/amphion/vpu_msgs.c                                |    2 
 drivers/media/platform/amphion/vpu_v4l2.c                                |   30 
 drivers/media/platform/amphion/vpu_windsor.c                             |    1 
 drivers/media/platform/chips-media/coda-bit.c                            |   14 
 drivers/media/platform/chips-media/coda-jpeg.c                           |   10 
 drivers/media/platform/mediatek/mdp3/mtk-mdp3-cmdq.c                     |   51 
 drivers/media/platform/mediatek/mdp3/mtk-mdp3-comp.c                     |   24 
 drivers/media/platform/mediatek/mdp3/mtk-mdp3-core.c                     |   15 
 drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_stateless.c        |   13 
 drivers/media/platform/mediatek/vcodec/vdec/vdec_h264_req_multi_if.c     |   60 
 drivers/media/platform/mediatek/vcodec/vdec/vdec_vp9_req_lat_if.c        |   15 
 drivers/media/platform/mediatek/vcodec/vdec_msg_queue.c                  |    2 
 drivers/media/platform/nxp/imx-jpeg/mxc-jpeg-hw.c                        |    4 
 drivers/media/platform/qcom/camss/camss-video.c                          |    3 
 drivers/media/platform/qcom/camss/camss.c                                |   11 
 drivers/media/platform/qcom/venus/pm_helpers.c                           |    4 
 drivers/media/platform/samsung/exynos4-is/fimc-core.c                    |    2 
 drivers/media/platform/samsung/exynos4-is/media-dev.c                    |   12 
 drivers/media/platform/samsung/s5p-mfc/s5p_mfc.c                         |   17 
 drivers/media/platform/st/sti/c8sectpfe/c8sectpfe-core.c                 |    1 
 drivers/media/platform/sunxi/sun6i-mipi-csi2/sun6i_mipi_csi2.c           |   23 
 drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/sun8i_a83t_mipi_csi2.c |   23 
 drivers/media/radio/si470x/radio-si470x-usb.c                            |    4 
 drivers/media/rc/imon.c                                                  |    6 
 drivers/media/test-drivers/vidtv/vidtv_bridge.c                          |   22 
 drivers/media/test-drivers/vimc/vimc-core.c                              |    2 
 drivers/media/test-drivers/vivid/vivid-vid-cap.c                         |    1 
 drivers/media/usb/dvb-usb/az6027.c                                       |    4 
 drivers/media/usb/dvb-usb/dvb-usb-init.c                                 |    4 
 drivers/media/v4l2-core/v4l2-ctrls-api.c                                 |    1 
 drivers/media/v4l2-core/v4l2-ctrls-core.c                                |    2 
 drivers/media/v4l2-core/v4l2-ioctl.c                                     |   34 
 drivers/media/v4l2-core/videobuf-dma-contig.c                            |   22 
 drivers/memory/renesas-rpc-if.c                                          |    3 
 drivers/memstick/core/ms_block.c                                         |    9 
 drivers/mfd/Kconfig                                                      |    1 
 drivers/mfd/axp20x.c                                                     |    2 
 drivers/mfd/qcom-pm8008.c                                                |    4 
 drivers/mfd/qcom_rpm.c                                                   |   16 
 drivers/misc/cxl/guest.c                                                 |   24 
 drivers/misc/cxl/pci.c                                                   |   21 
 drivers/misc/habanalabs/common/firmware_if.c                             |    2 
 drivers/misc/lkdtm/cfi.c                                                 |    6 
 drivers/misc/ocxl/config.c                                               |   20 
 drivers/misc/ocxl/file.c                                                 |    7 
 drivers/misc/sgi-gru/grufault.c                                          |   13 
 drivers/misc/sgi-gru/grumain.c                                           |   22 
 drivers/misc/sgi-gru/grutables.h                                         |    2 
 drivers/misc/tifm_7xx1.c                                                 |    2 
 drivers/mmc/core/sd.c                                                    |   11 
 drivers/mmc/host/alcor.c                                                 |    5 
 drivers/mmc/host/atmel-mci.c                                             |    9 
 drivers/mmc/host/litex_mmc.c                                             |    1 
 drivers/mmc/host/meson-gx-mmc.c                                          |    4 
 drivers/mmc/host/mmci.c                                                  |    4 
 drivers/mmc/host/moxart-mmc.c                                            |    4 
 drivers/mmc/host/mxcmmc.c                                                |    4 
 drivers/mmc/host/omap_hsmmc.c                                            |    4 
 drivers/mmc/host/pxamci.c                                                |    7 
 drivers/mmc/host/renesas_sdhi.h                                          |    1 
 drivers/mmc/host/renesas_sdhi_core.c                                     |   14 
 drivers/mmc/host/renesas_sdhi_internal_dmac.c                            |    4 
 drivers/mmc/host/rtsx_pci_sdmmc.c                                        |    9 
 drivers/mmc/host/rtsx_usb_sdmmc.c                                        |   11 
 drivers/mmc/host/sdhci-tegra.c                                           |    3 
 drivers/mmc/host/sdhci.c                                                 |    5 
 drivers/mmc/host/sdhci.h                                                 |    2 
 drivers/mmc/host/sdhci_f_sdh30.c                                         |    3 
 drivers/mmc/host/toshsd.c                                                |    6 
 drivers/mmc/host/via-sdmmc.c                                             |    4 
 drivers/mmc/host/vub300.c                                                |   11 
 drivers/mmc/host/wbsd.c                                                  |   12 
 drivers/mmc/host/wmt-sdmmc.c                                             |    6 
 drivers/mtd/lpddr/lpddr2_nvm.c                                           |    2 
 drivers/mtd/maps/pxa2xx-flash.c                                          |    2 
 drivers/mtd/mtdcore.c                                                    |    9 
 drivers/mtd/spi-nor/core.c                                               |    3 
 drivers/mtd/spi-nor/sysfs.c                                              |   14 
 drivers/net/bonding/bond_main.c                                          |   37 
 drivers/net/can/m_can/m_can.c                                            |   32 
 drivers/net/can/m_can/m_can_platform.c                                   |    4 
 drivers/net/can/m_can/tcan4x5x-core.c                                    |   18 
 drivers/net/can/usb/kvaser_usb/kvaser_usb.h                              |   30 
 drivers/net/can/usb/kvaser_usb/kvaser_usb_core.c                         |  115 +
 drivers/net/can/usb/kvaser_usb/kvaser_usb_hydra.c                        |  160 ++
 drivers/net/can/usb/kvaser_usb/kvaser_usb_leaf.c                         |  437 ++++++-
 drivers/net/dsa/lan9303-core.c                                           |    4 
 drivers/net/dsa/microchip/ksz_common.c                                   |    3 
 drivers/net/dsa/mv88e6xxx/chip.c                                         |    9 
 drivers/net/ethernet/adi/adin1110.c                                      |   37 
 drivers/net/ethernet/amd/atarilance.c                                    |    2 
 drivers/net/ethernet/amd/lance.c                                         |    2 
 drivers/net/ethernet/amd/xgbe/xgbe-phy-v2.c                              |   23 
 drivers/net/ethernet/apple/bmac.c                                        |    2 
 drivers/net/ethernet/apple/mace.c                                        |    2 
 drivers/net/ethernet/broadcom/bnx2.c                                     |    5 
 drivers/net/ethernet/dnet.c                                              |    4 
 drivers/net/ethernet/freescale/enetc/enetc.c                             |   35 
 drivers/net/ethernet/freescale/fec_main.c                                |    8 
 drivers/net/ethernet/intel/i40e/i40e_main.c                              |   36 
 drivers/net/ethernet/intel/ice/ice_ptp.c                                 |   10 
 drivers/net/ethernet/intel/igb/igb_main.c                                |    8 
 drivers/net/ethernet/intel/igc/igc.h                                     |    3 
 drivers/net/ethernet/intel/igc/igc_defines.h                             |    2 
 drivers/net/ethernet/intel/igc/igc_main.c                                |  210 ++-
 drivers/net/ethernet/intel/igc/igc_tsn.c                                 |   13 
 drivers/net/ethernet/marvell/octeontx2/af/mcs.c                          |    6 
 drivers/net/ethernet/mediatek/mtk_eth_soc.c                              |   71 -
 drivers/net/ethernet/mediatek/mtk_eth_soc.h                              |   11 
 drivers/net/ethernet/myricom/myri10ge/myri10ge.c                         |    1 
 drivers/net/ethernet/neterion/s2io.c                                     |    2 
 drivers/net/ethernet/qlogic/qed/qed_debug.c                              |    3 
 drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c                 |    2 
 drivers/net/ethernet/rdc/r6040.c                                         |    5 
 drivers/net/ethernet/stmicro/stmmac/stmmac_hwtstamp.c                    |    3 
 drivers/net/ethernet/stmicro/stmmac/stmmac_main.c                        |    4 
 drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.h                         |    2 
 drivers/net/ethernet/stmicro/stmmac/stmmac_selftests.c                   |    8 
 drivers/net/ethernet/ti/am65-cpsw-nuss.c                                 |   10 
 drivers/net/ethernet/ti/netcp_core.c                                     |    2 
 drivers/net/ethernet/xilinx/xilinx_emaclite.c                            |    2 
 drivers/net/fddi/defxx.c                                                 |   22 
 drivers/net/hamradio/baycom_epp.c                                        |    2 
 drivers/net/hamradio/scc.c                                               |    6 
 drivers/net/macsec.c                                                     |   34 
 drivers/net/mctp/mctp-serial.c                                           |    6 
 drivers/net/ntb_netdev.c                                                 |    4 
 drivers/net/ppp/ppp_generic.c                                            |    2 
 drivers/net/wan/farsync.c                                                |    2 
 drivers/net/wireless/ath/ar5523/ar5523.c                                 |    6 
 drivers/net/wireless/ath/ath10k/core.c                                   |   16 
 drivers/net/wireless/ath/ath10k/htc.c                                    |    9 
 drivers/net/wireless/ath/ath10k/hw.h                                     |    2 
 drivers/net/wireless/ath/ath10k/pci.c                                    |   20 
 drivers/net/wireless/ath/ath11k/core.h                                   |    2 
 drivers/net/wireless/ath/ath11k/mac.c                                    |  122 +-
 drivers/net/wireless/ath/ath11k/qmi.c                                    |    3 
 drivers/net/wireless/ath/ath9k/hif_usb.c                                 |   46 
 drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c                |    8 
 drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c              |    5 
 drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c                  |    6 
 drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c                  |    1 
 drivers/net/wireless/intel/iwlwifi/mei/iwl-mei.h                         |    7 
 drivers/net/wireless/intel/iwlwifi/mei/main.c                            |  172 +-
 drivers/net/wireless/intel/iwlwifi/mei/net.c                             |   10 
 drivers/net/wireless/intel/iwlwifi/mvm/fw.c                              |    2 
 drivers/net/wireless/intel/iwlwifi/mvm/mvm.h                             |    4 
 drivers/net/wireless/intel/iwlwifi/mvm/ops.c                             |    2 
 drivers/net/wireless/intel/iwlwifi/mvm/tx.c                              |   20 
 drivers/net/wireless/mediatek/mt76/mt76.h                                |    3 
 drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c                     |    4 
 drivers/net/wireless/mediatek/mt76/mt7915/eeprom.c                       |   58 
 drivers/net/wireless/mediatek/mt76/mt7915/eeprom.h                       |    5 
 drivers/net/wireless/mediatek/mt76/mt7915/mac.c                          |   23 
 drivers/net/wireless/mediatek/mt76/mt7915/pci.c                          |   13 
 drivers/net/wireless/mediatek/mt76/mt7921/init.c                         |    1 
 drivers/net/wireless/mediatek/mt76/mt7921/mac.c                          |   34 
 drivers/net/wireless/mediatek/mt76/mt7921/main.c                         |    6 
 drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h                       |    4 
 drivers/net/wireless/mediatek/mt76/usb.c                                 |   11 
 drivers/net/wireless/purelifi/plfxlc/usb.c                               |    1 
 drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h                         |    2 
 drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c                    |   28 
 drivers/net/wireless/realtek/rtw89/core.c                                |    2 
 drivers/net/wireless/realtek/rtw89/mac.c                                 |    6 
 drivers/net/wireless/realtek/rtw89/phy.c                                 |    2 
 drivers/net/wireless/rsi/rsi_91x_core.c                                  |    4 
 drivers/net/wireless/rsi/rsi_91x_hal.c                                   |    6 
 drivers/nfc/pn533/pn533.c                                                |    4 
 drivers/nvme/host/core.c                                                 |   19 
 drivers/nvme/host/fc.c                                                   |    2 
 drivers/nvme/host/nvme.h                                                 |    2 
 drivers/nvme/host/rdma.c                                                 |    4 
 drivers/nvme/host/tcp.c                                                  |    1 
 drivers/nvme/target/core.c                                               |   22 
 drivers/nvme/target/io-cmd-file.c                                        |   16 
 drivers/nvme/target/loop.c                                               |    2 
 drivers/nvme/target/nvmet.h                                              |    3 
 drivers/of/overlay.c                                                     |    4 
 drivers/pci/controller/dwc/pci-imx6.c                                    |   13 
 drivers/pci/controller/dwc/pcie-designware.c                             |    2 
 drivers/pci/controller/vmd.c                                             |   27 
 drivers/pci/endpoint/functions/pci-epf-test.c                            |    2 
 drivers/pci/endpoint/functions/pci-epf-vntb.c                            |    2 
 drivers/pci/irq.c                                                        |    2 
 drivers/pci/probe.c                                                      |    3 
 drivers/perf/arm_dmc620_pmu.c                                            |    8 
 drivers/perf/arm_dsu_pmu.c                                               |    6 
 drivers/perf/arm_smmuv3_pmu.c                                            |    8 
 drivers/perf/hisilicon/hisi_pcie_pmu.c                                   |    8 
 drivers/perf/marvell_cn10k_tad_pmu.c                                     |    6 
 drivers/phy/broadcom/phy-brcm-usb-init-synopsys.c                        |    9 
 drivers/phy/broadcom/phy-brcm-usb-init.h                                 |    1 
 drivers/phy/broadcom/phy-brcm-usb.c                                      |   14 
 drivers/phy/marvell/phy-mvebu-a3700-comphy.c                             |    3 
 drivers/phy/qualcomm/phy-qcom-qmp-pcie.c                                 |  607 +++++-----
 drivers/phy/qualcomm/phy-qcom-qmp-pcs-pcie-v5_20.h                       |    2 
 drivers/phy/qualcomm/phy-qcom-qmp-pcs-v5_20.h                            |   14 
 drivers/phy/qualcomm/phy-qcom-qmp-usb.c                                  |  142 --
 drivers/phy/qualcomm/phy-qcom-qmp.h                                      |    1 
 drivers/pinctrl/mediatek/pinctrl-mt7986.c                                |   24 
 drivers/pinctrl/pinconf-generic.c                                        |    4 
 drivers/pinctrl/pinctrl-k210.c                                           |    4 
 drivers/pinctrl/pinctrl-ocelot.c                                         |   20 
 drivers/pinctrl/pinctrl-thunderbay.c                                     |    8 
 drivers/platform/chrome/cros_ec_typec.c                                  |    3 
 drivers/platform/chrome/cros_usbpd_notify.c                              |    6 
 drivers/platform/mellanox/mlxbf-pmc.c                                    |    2 
 drivers/platform/x86/huawei-wmi.c                                        |   20 
 drivers/platform/x86/intel/int3472/clk_and_regulator.c                   |    3 
 drivers/platform/x86/intel_scu_ipc.c                                     |    2 
 drivers/platform/x86/mxm-wmi.c                                           |    8 
 drivers/pnp/core.c                                                       |    4 
 drivers/power/supply/ab8500_charger.c                                    |    9 
 drivers/power/supply/bq25890_charger.c                                   |   71 -
 drivers/power/supply/cw2015_battery.c                                    |    3 
 drivers/power/supply/power_supply_core.c                                 |    7 
 drivers/power/supply/rk817_charger.c                                     |    4 
 drivers/power/supply/z2_battery.c                                        |    6 
 drivers/pwm/pwm-mediatek.c                                               |    2 
 drivers/pwm/pwm-mtk-disp.c                                               |    5 
 drivers/pwm/pwm-sifive.c                                                 |    5 
 drivers/pwm/pwm-tegra.c                                                  |   15 
 drivers/rapidio/devices/rio_mport_cdev.c                                 |   15 
 drivers/rapidio/rio-scan.c                                               |    8 
 drivers/rapidio/rio.c                                                    |    9 
 drivers/regulator/core.c                                                 |   25 
 drivers/regulator/devres.c                                               |    2 
 drivers/regulator/of_regulator.c                                         |    2 
 drivers/regulator/qcom-labibb-regulator.c                                |    1 
 drivers/regulator/qcom-rpmh-regulator.c                                  |    2 
 drivers/regulator/stm32-vrefbuf.c                                        |    2 
 drivers/remoteproc/qcom_q6v5_pas.c                                       |    4 
 drivers/remoteproc/qcom_q6v5_wcss.c                                      |    6 
 drivers/remoteproc/qcom_sysmon.c                                         |    5 
 drivers/remoteproc/remoteproc_core.c                                     |    8 
 drivers/rtc/class.c                                                      |    4 
 drivers/rtc/rtc-cmos.c                                                   |  378 +++---
 drivers/rtc/rtc-mxc_v2.c                                                 |    4 
 drivers/rtc/rtc-pcf2127.c                                                |   22 
 drivers/rtc/rtc-pcf85063.c                                               |   10 
 drivers/rtc/rtc-pic32.c                                                  |    8 
 drivers/rtc/rtc-rzn1.c                                                   |    4 
 drivers/rtc/rtc-snvs.c                                                   |   16 
 drivers/rtc/rtc-st-lpc.c                                                 |    1 
 drivers/s390/net/ctcm_main.c                                             |   11 
 drivers/s390/net/lcs.c                                                   |    8 
 drivers/s390/net/netiucv.c                                               |    9 
 drivers/scsi/elx/efct/efct_driver.c                                      |    1 
 drivers/scsi/elx/libefc/efclib.h                                         |    6 
 drivers/scsi/fcoe/fcoe.c                                                 |    1 
 drivers/scsi/fcoe/fcoe_sysfs.c                                           |   19 
 drivers/scsi/hpsa.c                                                      |    9 
 drivers/scsi/ipr.c                                                       |   10 
 drivers/scsi/lpfc/lpfc_sli.c                                             |    6 
 drivers/scsi/mpt3sas/mpt3sas_transport.c                                 |    2 
 drivers/scsi/qla2xxx/qla_def.h                                           |   22 
 drivers/scsi/qla2xxx/qla_init.c                                          |   20 
 drivers/scsi/qla2xxx/qla_inline.h                                        |    4 
 drivers/scsi/qla2xxx/qla_os.c                                            |    4 
 drivers/scsi/scsi_debug.c                                                |   11 
 drivers/scsi/scsi_error.c                                                |   14 
 drivers/scsi/smartpqi/smartpqi.h                                         |    2 
 drivers/scsi/smartpqi/smartpqi_init.c                                    |   77 +
 drivers/scsi/snic/snic_disc.c                                            |    3 
 drivers/soc/apple/rtkit.c                                                |    7 
 drivers/soc/apple/sart.c                                                 |    7 
 drivers/soc/mediatek/mtk-pm-domains.c                                    |    2 
 drivers/soc/qcom/apr.c                                                   |   15 
 drivers/soc/qcom/llcc-qcom.c                                             |    2 
 drivers/soc/sifive/sifive_ccache.c                                       |   33 
 drivers/soc/tegra/cbb/tegra194-cbb.c                                     |   14 
 drivers/soc/tegra/cbb/tegra234-cbb.c                                     |  170 ++
 drivers/soc/ti/knav_qmss_queue.c                                         |    3 
 drivers/soc/ti/smartreflex.c                                             |    1 
 drivers/spi/spi-fsl-spi.c                                                |   19 
 drivers/spi/spi-gpio.c                                                   |   16 
 drivers/spi/spidev.c                                                     |   21 
 drivers/staging/media/deprecated/stkwebcam/Kconfig                       |    2 
 drivers/staging/media/imx/imx7-media-csi.c                               |    6 
 drivers/staging/media/rkvdec/rkvdec-vp9.c                                |    3 
 drivers/staging/media/sunxi/cedrus/cedrus_h265.c                         |   25 
 drivers/staging/media/sunxi/cedrus/cedrus_regs.h                         |    2 
 drivers/staging/r8188eu/core/rtw_pwrctrl.c                               |    2 
 drivers/staging/rtl8192e/rtllib_rx.c                                     |    2 
 drivers/staging/rtl8192u/ieee80211/ieee80211_rx.c                        |    4 
 drivers/staging/vme_user/vme_fake.c                                      |    2 
 drivers/staging/vme_user/vme_tsi148.c                                    |    1 
 drivers/target/iscsi/iscsi_target_nego.c                                 |   12 
 drivers/thermal/imx8mm_thermal.c                                         |    8 
 drivers/thermal/k3_j72xx_bandgap.c                                       |    2 
 drivers/thermal/qcom/lmh.c                                               |    2 
 drivers/thermal/qcom/qcom-spmi-temp-alarm.c                              |    3 
 drivers/thermal/thermal_core.c                                           |   18 
 drivers/thermal/thermal_helpers.c                                        |    7 
 drivers/thermal/thermal_of.c                                             |    8 
 drivers/tty/serial/8250/8250_bcm7271.c                                   |   10 
 drivers/tty/serial/altera_uart.c                                         |    5 
 drivers/tty/serial/amba-pl011.c                                          |   14 
 drivers/tty/serial/pch_uart.c                                            |    4 
 drivers/tty/serial/serial-tegra.c                                        |    6 
 drivers/tty/serial/stm32-usart.c                                         |   47 
 drivers/tty/serial/sunsab.c                                              |    8 
 drivers/ufs/core/ufshcd.c                                                |   37 
 drivers/uio/uio_dmem_genirq.c                                            |   13 
 drivers/usb/cdns3/cdnsp-ring.c                                           |   42 
 drivers/usb/core/hcd.c                                                   |    6 
 drivers/usb/dwc3/core.c                                                  |   23 
 drivers/usb/dwc3/dwc3-qcom.c                                             |   13 
 drivers/usb/gadget/function/f_hid.c                                      |   53 
 drivers/usb/gadget/udc/core.c                                            |   12 
 drivers/usb/gadget/udc/fotg210-udc.c                                     |   12 
 drivers/usb/host/xhci-mtk.c                                              |    1 
 drivers/usb/host/xhci-ring.c                                             |   14 
 drivers/usb/host/xhci.h                                                  |    2 
 drivers/usb/musb/musb_gadget.c                                           |    2 
 drivers/usb/musb/omap2430.c                                              |   54 
 drivers/usb/roles/class.c                                                |    5 
 drivers/usb/storage/alauda.c                                             |    2 
 drivers/usb/typec/bus.c                                                  |    2 
 drivers/usb/typec/tcpm/tcpci.c                                           |    5 
 drivers/usb/typec/tipd/core.c                                            |   11 
 drivers/usb/typec/wusb3801.c                                             |    2 
 drivers/vfio/iova_bitmap.c                                               |   32 
 drivers/vfio/platform/vfio_platform_common.c                             |    3 
 drivers/video/fbdev/Kconfig                                              |    2 
 drivers/video/fbdev/core/fbcon.c                                         |    3 
 drivers/video/fbdev/ep93xx-fb.c                                          |    4 
 drivers/video/fbdev/geode/Kconfig                                        |    1 
 drivers/video/fbdev/hyperv_fb.c                                          |    8 
 drivers/video/fbdev/pm2fb.c                                              |    9 
 drivers/video/fbdev/uvesafb.c                                            |    1 
 drivers/video/fbdev/vermilion/vermilion.c                                |    4 
 drivers/video/fbdev/via/via-core.c                                       |    9 
 drivers/virt/coco/sev-guest/sev-guest.c                                  |    1 
 drivers/watchdog/iTCO_wdt.c                                              |   21 
 drivers/xen/privcmd.c                                                    |    2 
 fs/afs/fs_probe.c                                                        |    5 
 fs/binfmt_misc.c                                                         |    8 
 fs/btrfs/extent-io-tree.c                                                |   22 
 fs/btrfs/file.c                                                          |   10 
 fs/char_dev.c                                                            |    2 
 fs/cifs/smb2file.c                                                       |    4 
 fs/configfs/dir.c                                                        |    2 
 fs/debugfs/file.c                                                        |   28 
 fs/erofs/fscache.c                                                       |   47 
 fs/erofs/internal.h                                                      |   10 
 fs/erofs/super.c                                                         |    2 
 fs/erofs/zdata.c                                                         |    3 
 fs/erofs/zmap.c                                                          |   11 
 fs/f2fs/compress.c                                                       |    2 
 fs/f2fs/f2fs.h                                                           |    2 
 fs/f2fs/file.c                                                           |    4 
 fs/f2fs/gc.c                                                             |   29 
 fs/f2fs/namei.c                                                          |  329 ++---
 fs/f2fs/segment.c                                                        |    8 
 fs/f2fs/super.c                                                          |    8 
 fs/gfs2/glock.c                                                          |    2 
 fs/hfs/inode.c                                                           |    2 
 fs/hfs/trans.c                                                           |    2 
 fs/hugetlbfs/inode.c                                                     |    6 
 fs/jfs/jfs_dmap.c                                                        |   27 
 fs/jfs/namei.c                                                           |    2 
 fs/ksmbd/mgmt/user_session.c                                             |    8 
 fs/libfs.c                                                               |   22 
 fs/lockd/svcsubs.c                                                       |   17 
 fs/nfs/fs_context.c                                                      |    6 
 fs/nfs/internal.h                                                        |    6 
 fs/nfs/namespace.c                                                       |    2 
 fs/nfs/nfs42xdr.c                                                        |    2 
 fs/nfs/nfs4proc.c                                                        |   38 
 fs/nfs/nfs4state.c                                                       |    2 
 fs/nfs/nfs4xdr.c                                                         |   22 
 fs/nfsd/nfs2acl.c                                                        |   10 
 fs/nfsd/nfs3acl.c                                                        |   30 
 fs/nfsd/nfs4callback.c                                                   |    4 
 fs/nfsd/nfs4proc.c                                                       |    7 
 fs/nfsd/nfs4state.c                                                      |   51 
 fs/nilfs2/the_nilfs.c                                                    |   73 +
 fs/ntfs3/bitmap.c                                                        |    2 
 fs/ntfs3/super.c                                                         |    2 
 fs/ntfs3/xattr.c                                                         |    2 
 fs/ocfs2/journal.c                                                       |    2 
 fs/ocfs2/journal.h                                                       |    1 
 fs/ocfs2/stackglue.c                                                     |    8 
 fs/ocfs2/super.c                                                         |    5 
 fs/orangefs/orangefs-debugfs.c                                           |   29 
 fs/orangefs/orangefs-mod.c                                               |    8 
 fs/orangefs/orangefs-sysfs.c                                             |   71 +
 fs/overlayfs/file.c                                                      |   28 
 fs/overlayfs/super.c                                                     |    7 
 fs/pstore/Kconfig                                                        |    1 
 fs/pstore/pmsg.c                                                         |    7 
 fs/pstore/ram.c                                                          |    2 
 fs/pstore/ram_core.c                                                     |    6 
 fs/reiserfs/namei.c                                                      |    4 
 fs/reiserfs/xattr_security.c                                             |    2 
 fs/sysv/itree.c                                                          |    2 
 fs/udf/namei.c                                                           |    8 
 fs/xattr.c                                                               |    2 
 include/drm/drm_connector.h                                              |    6 
 include/drm/ttm/ttm_tt.h                                                 |    2 
 include/dt-bindings/clock/imx8mn-clock.h                                 |   24 
 include/dt-bindings/clock/imx8mp-clock.h                                 |    3 
 include/linux/btf_ids.h                                                  |    2 
 include/linux/debugfs.h                                                  |   19 
 include/linux/eventfd.h                                                  |    2 
 include/linux/fortify-string.h                                           |    2 
 include/linux/fs.h                                                       |   12 
 include/linux/hisi_acc_qm.h                                              |    6 
 include/linux/hyperv.h                                                   |    2 
 include/linux/ieee80211.h                                                |    2 
 include/linux/iio/imu/adis.h                                             |   13 
 include/linux/netdevice.h                                                |   58 
 include/linux/proc_fs.h                                                  |    2 
 include/linux/regulator/driver.h                                         |    3 
 include/linux/skmsg.h                                                    |    1 
 include/linux/timerqueue.h                                               |    2 
 include/media/dvbdev.h                                                   |   32 
 include/net/bluetooth/hci.h                                              |   20 
 include/net/bluetooth/hci_core.h                                         |    7 
 include/net/dst.h                                                        |    5 
 include/net/ip_vs.h                                                      |   10 
 include/net/mrp.h                                                        |    1 
 include/net/sock_reuseport.h                                             |    2 
 include/net/tcp.h                                                        |    4 
 include/sound/hda_codec.h                                                |    1 
 include/sound/pcm.h                                                      |   36 
 include/trace/events/f2fs.h                                              |   34 
 include/trace/events/ib_mad.h                                            |   13 
 include/uapi/linux/idxd.h                                                |    2 
 include/uapi/linux/io_uring.h                                            |   18 
 include/uapi/linux/swab.h                                                |    2 
 include/uapi/rdma/hns-abi.h                                              |   15 
 include/uapi/sound/asequencer.h                                          |    8 
 io_uring/io_uring.c                                                      |    2 
 io_uring/msg_ring.c                                                      |    6 
 io_uring/net.c                                                           |    9 
 io_uring/notif.c                                                         |   12 
 io_uring/notif.h                                                         |    3 
 io_uring/opdef.c                                                         |    7 
 io_uring/opdef.h                                                         |    2 
 io_uring/timeout.c                                                       |    4 
 ipc/mqueue.c                                                             |    6 
 kernel/Makefile                                                          |    3 
 kernel/acct.c                                                            |    2 
 kernel/bpf/btf.c                                                         |    5 
 kernel/bpf/cgroup_iter.c                                                 |   14 
 kernel/bpf/syscall.c                                                     |    6 
 kernel/bpf/verifier.c                                                    |  120 +
 kernel/cpu.c                                                             |   60 
 kernel/events/core.c                                                     |    8 
 kernel/fork.c                                                            |   17 
 kernel/futex/core.c                                                      |   26 
 kernel/gcov/gcc_4_7.c                                                    |    5 
 kernel/irq/internals.h                                                   |    2 
 kernel/irq/irqdesc.c                                                     |   15 
 kernel/kprobes.c                                                         |   16 
 kernel/module/decompress.c                                               |    8 
 kernel/padata.c                                                          |   15 
 kernel/power/snapshot.c                                                  |    4 
 kernel/rcu/tree.c                                                        |    2 
 kernel/relay.c                                                           |    4 
 kernel/sched/core.c                                                      |   10 
 kernel/sched/fair.c                                                      |  223 +++
 kernel/sched/psi.c                                                       |    8 
 kernel/sched/sched.h                                                     |   51 
 kernel/trace/blktrace.c                                                  |    3 
 kernel/trace/trace_events_hist.c                                         |    2 
 kernel/trace/trace_events_user.c                                         |    1 
 lib/debugobjects.c                                                       |   10 
 lib/fonts/fonts.c                                                        |    4 
 lib/maple_tree.c                                                         |    4 
 lib/notifier-error-inject.c                                              |    2 
 lib/test_firmware.c                                                      |    1 
 lib/test_maple_tree.c                                                    |   23 
 mm/gup.c                                                                 |    3 
 net/802/mrp.c                                                            |   18 
 net/9p/client.c                                                          |    5 
 net/bluetooth/hci_conn.c                                                 |    2 
 net/bluetooth/hci_core.c                                                 |    4 
 net/bluetooth/hci_sync.c                                                 |    2 
 net/bluetooth/lib.c                                                      |    4 
 net/bluetooth/mgmt.c                                                     |    2 
 net/bluetooth/rfcomm/core.c                                              |    2 
 net/bpf/test_run.c                                                       |    3 
 net/core/dev.c                                                           |   14 
 net/core/devlink.c                                                       |    5 
 net/core/filter.c                                                        |   25 
 net/core/skbuff.c                                                        |    3 
 net/core/skmsg.c                                                         |    9 
 net/core/sock.c                                                          |    2 
 net/core/sock_map.c                                                      |    2 
 net/core/sock_reuseport.c                                                |   94 +
 net/core/stream.c                                                        |    6 
 net/dsa/tag_8021q.c                                                      |   11 
 net/ethtool/ioctl.c                                                      |    3 
 net/hsr/hsr_debugfs.c                                                    |   40 
 net/hsr/hsr_device.c                                                     |   32 
 net/hsr/hsr_forward.c                                                    |   14 
 net/hsr/hsr_framereg.c                                                   |  222 +--
 net/hsr/hsr_framereg.h                                                   |   17 
 net/hsr/hsr_main.h                                                       |    9 
 net/hsr/hsr_netlink.c                                                    |    4 
 net/ipv4/af_inet.c                                                       |    4 
 net/ipv4/inet_connection_sock.c                                          |    7 
 net/ipv4/ping.c                                                          |    2 
 net/ipv4/tcp_bpf.c                                                       |   19 
 net/ipv4/udp.c                                                           |   39 
 net/ipv4/udp_tunnel_core.c                                               |    1 
 net/ipv6/af_inet6.c                                                      |    4 
 net/ipv6/datagram.c                                                      |   15 
 net/ipv6/sit.c                                                           |   22 
 net/ipv6/udp.c                                                           |   12 
 net/mac80211/cfg.c                                                       |    2 
 net/mac80211/ieee80211_i.h                                               |    1 
 net/mac80211/iface.c                                                     |    1 
 net/mac80211/mlme.c                                                      |   15 
 net/mac80211/tx.c                                                        |    2 
 net/mctp/device.c                                                        |   14 
 net/netfilter/ipvs/ip_vs_core.c                                          |   30 
 net/netfilter/ipvs/ip_vs_ctl.c                                           |   10 
 net/netfilter/ipvs/ip_vs_est.c                                           |   20 
 net/netfilter/nf_conntrack_proto_icmpv6.c                                |   53 
 net/netfilter/nf_flow_table_offload.c                                    |    6 
 net/openvswitch/datapath.c                                               |   25 
 net/openvswitch/flow_netlink.c                                           |    2 
 net/rxrpc/output.c                                                       |    2 
 net/rxrpc/sendmsg.c                                                      |    2 
 net/sched/ematch.c                                                       |    2 
 net/sctp/sysctl.c                                                        |   73 -
 net/sunrpc/clnt.c                                                        |    2 
 net/sunrpc/xprtrdma/verbs.c                                              |    2 
 net/tls/tls_sw.c                                                         |    6 
 net/unix/af_unix.c                                                       |   12 
 net/vmw_vsock/vmci_transport.c                                           |    6 
 net/wireless/nl80211.c                                                   |    3 
 net/wireless/reg.c                                                       |    4 
 samples/bpf/xdp1_user.c                                                  |    2 
 samples/bpf/xdp2_kern.c                                                  |    4 
 samples/vfio-mdev/mdpy-fb.c                                              |    8 
 security/Kconfig.hardening                                               |    3 
 security/apparmor/apparmorfs.c                                           |    4 
 security/apparmor/label.c                                                |   12 
 security/apparmor/lsm.c                                                  |    4 
 security/apparmor/policy.c                                               |    2 
 security/apparmor/policy_ns.c                                            |    2 
 security/apparmor/policy_unpack.c                                        |    2 
 security/integrity/digsig.c                                              |    6 
 security/integrity/ima/ima_policy.c                                      |   51 
 security/integrity/ima/ima_template.c                                    |    4 
 security/loadpin/loadpin.c                                               |   30 
 sound/core/memalloc.c                                                    |   44 
 sound/core/pcm_native.c                                                  |    4 
 sound/drivers/mts64.c                                                    |    3 
 sound/pci/asihpi/hpioctl.c                                               |    2 
 sound/pci/hda/hda_codec.c                                                |    3 
 sound/pci/hda/patch_hdmi.c                                               |  120 +
 sound/pci/hda/patch_realtek.c                                            |   27 
 sound/soc/amd/acp/acp-platform.c                                         |    8 
 sound/soc/amd/yc/acp6x-mach.c                                            |    7 
 sound/soc/codecs/pcm512x.c                                               |    8 
 sound/soc/codecs/rt298.c                                                 |    7 
 sound/soc/codecs/rt5670.c                                                |    2 
 sound/soc/codecs/wm8994.c                                                |    5 
 sound/soc/codecs/wsa883x.c                                               |    6 
 sound/soc/generic/audio-graph-card.c                                     |    4 
 sound/soc/intel/Kconfig                                                  |    2 
 sound/soc/intel/avs/boards/rt298.c                                       |   24 
 sound/soc/intel/avs/core.c                                               |    2 
 sound/soc/intel/avs/ipc.c                                                |    6 
 sound/soc/intel/boards/sof_es8336.c                                      |    2 
 sound/soc/intel/skylake/skl.c                                            |    5 
 sound/soc/mediatek/common/mtk-btcvsd.c                                   |    6 
 sound/soc/mediatek/mt8173/mt8173-afe-pcm.c                               |   20 
 sound/soc/mediatek/mt8173/mt8173-rt5650-rt5514.c                         |    7 
 sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c               |   14 
 sound/soc/mediatek/mt8186/mt8186-mt6366-da7219-max98357.c                |    2 
 sound/soc/mediatek/mt8186/mt8186-mt6366-rt1019-rt5682s.c                 |    2 
 sound/soc/pxa/mmp-pcm.c                                                  |    2 
 sound/soc/qcom/Kconfig                                                   |   16 
 sound/soc/qcom/common.c                                                  |    2 
 sound/soc/qcom/common.h                                                  |   23 
 sound/soc/qcom/lpass-sc7180.c                                            |    3 
 sound/soc/rockchip/rockchip_pdm.c                                        |    1 
 sound/soc/rockchip/rockchip_spdif.c                                      |    1 
 sound/usb/endpoint.c                                                     |    7 
 sound/usb/pcm.c                                                          |   13 
 sound/usb/quirks-table.h                                                 |    2 
 sound/usb/quirks.c                                                       |    2 
 sound/usb/usbaudio.h                                                     |    4 
 tools/bpf/bpftool/common.c                                               |    1 
 tools/lib/bpf/bpf.h                                                      |    7 
 tools/lib/bpf/btf.c                                                      |    8 
 tools/lib/bpf/btf_dump.c                                                 |   29 
 tools/lib/bpf/libbpf.c                                                   |   22 
 tools/lib/bpf/usdt.c                                                     |   11 
 tools/objtool/check.c                                                    |   10 
 tools/perf/Documentation/perf-annotate.txt                               |    2 
 tools/perf/Documentation/perf-diff.txt                                   |    2 
 tools/perf/Documentation/perf-lock.txt                                   |    2 
 tools/perf/Documentation/perf-probe.txt                                  |    2 
 tools/perf/Documentation/perf-record.txt                                 |    2 
 tools/perf/Documentation/perf-report.txt                                 |    2 
 tools/perf/Documentation/perf-stat.txt                                   |    4 
 tools/perf/bench/numa.c                                                  |    9 
 tools/perf/builtin-annotate.c                                            |    2 
 tools/perf/builtin-diff.c                                                |    2 
 tools/perf/builtin-lock.c                                                |    2 
 tools/perf/builtin-probe.c                                               |   22 
 tools/perf/builtin-record.c                                              |    2 
 tools/perf/builtin-report.c                                              |    2 
 tools/perf/builtin-stat.c                                                |   41 
 tools/perf/builtin-trace.c                                               |   32 
 tools/perf/tests/shell/stat_all_pmu.sh                                   |   13 
 tools/perf/ui/util.c                                                     |    5 
 tools/perf/util/bpf_off_cpu.c                                            |    2 
 tools/perf/util/branch.h                                                 |    3 
 tools/perf/util/debug.c                                                  |    4 
 tools/perf/util/stat-display.c                                           |   33 
 tools/perf/util/stat.h                                                   |    1 
 tools/perf/util/symbol-elf.c                                             |    2 
 tools/testing/selftests/bpf/config                                       |    1 
 tools/testing/selftests/bpf/network_helpers.c                            |    4 
 tools/testing/selftests/bpf/prog_tests/bpf_iter.c                        |   11 
 tools/testing/selftests/bpf/prog_tests/empty_skb.c                       |  146 ++
 tools/testing/selftests/bpf/prog_tests/kprobe_multi_test.c               |   26 
 tools/testing/selftests/bpf/prog_tests/lsm_cgroup.c                      |   17 
 tools/testing/selftests/bpf/prog_tests/map_kptr.c                        |    3 
 tools/testing/selftests/bpf/prog_tests/tcp_hdr_options.c                 |    4 
 tools/testing/selftests/bpf/prog_tests/tracing_struct.c                  |    3 
 tools/testing/selftests/bpf/prog_tests/xdp_adjust_tail.c                 |    7 
 tools/testing/selftests/bpf/prog_tests/xdp_do_redirect.c                 |    2 
 tools/testing/selftests/bpf/prog_tests/xdp_synproxy.c                    |    2 
 tools/testing/selftests/bpf/progs/bpf_iter_ksym.c                        |    6 
 tools/testing/selftests/bpf/progs/empty_skb.c                            |   37 
 tools/testing/selftests/bpf/progs/lsm_cgroup.c                           |    8 
 tools/testing/selftests/bpf/test_bpftool_metadata.sh                     |    7 
 tools/testing/selftests/bpf/test_flow_dissector.sh                       |    6 
 tools/testing/selftests/bpf/test_lwt_ip_encap.sh                         |   17 
 tools/testing/selftests/bpf/test_lwt_seg6local.sh                        |    9 
 tools/testing/selftests/bpf/test_tc_edt.sh                               |    3 
 tools/testing/selftests/bpf/test_tc_tunnel.sh                            |    5 
 tools/testing/selftests/bpf/test_tunnel.sh                               |    5 
 tools/testing/selftests/bpf/test_xdp_meta.sh                             |    9 
 tools/testing/selftests/bpf/test_xdp_vlan.sh                             |    8 
 tools/testing/selftests/bpf/xdp_synproxy.c                               |    5 
 tools/testing/selftests/cgroup/cgroup_util.c                             |    5 
 tools/testing/selftests/drivers/net/netdevsim/devlink.sh                 |    4 
 tools/testing/selftests/efivarfs/efivarfs.sh                             |    5 
 tools/testing/selftests/ftrace/test.d/ftrace/func_event_triggers.tc      |   15 
 tools/testing/selftests/netfilter/conntrack_icmp_related.sh              |   36 
 tools/testing/selftests/powerpc/dscr/dscr_sysfs_test.c                   |    5 
 tools/testing/selftests/proc/proc-uptime-002.c                           |    3 
 1088 files changed, 12888 insertions(+), 6320 deletions(-)

Aakarsh Jain (1):
      media: s5p-mfc: Add variant data for MFC v7 hardware for Exynos 3250 SoC

Abdun Nihaal (1):
      fs/ntfs3: Fix slab-out-of-bounds read in ntfs_trim_fs

Abhinav Kumar (1):
      drm/bridge: adv7533: remove dynamic lane switching from adv7533 bridge

Aditya Kumar Singh (1):
      wifi: ath11k: fix firmware assert during bandwidth change for peer sta

Adriana Kobylak (1):
      ARM: dts: aspeed: rainier,everest: Move reserved memory regions

Ajay Kaher (1):
      perf symbol: correction while adjusting symbol

Akinobu Mita (3):
      libfs: add DEFINE_SIMPLE_ATTRIBUTE_SIGNED for signed value
      lib/notifier-error-inject: fix error when writing -errno to debugfs file
      debugfs: fix error when writing negative value to atomic_t debugfs file

Al Cooper (1):
      phy: usb: s2 WoL wakeup_count not incremented for USB->Eth devices

Al Viro (2):
      alpha: fix TIF_NOTIFY_SIGNAL handling
      alpha: fix syscall entry in !AUDUT_SYSCALL case

Alan Maguire (1):
      libbpf: Btf dedup identical struct test needs check for nested structs/arrays

Alan Previn (2):
      drm/i915/guc: Add error-capture init warnings when needed
      drm/i915/guc: Fix GuC error capture sizing estimation and reporting

Alexander Stein (1):
      rtc: pcf85063: Fix reading alarm

Alexander Sverdlin (1):
      spi: spidev: mask SPI_CS_HIGH in SPI_IOC_RD_MODE

Alexandre Belloni (1):
      rtc: pcf85063: fix pcf85063_clkout_control

Alexandre Ghiti (1):
      riscv: Fix P4D_SHIFT definition for 3-level page table mode

Alexandru Tachici (1):
      net: ethernet: adi: adin1110: Fix SPI transfers

Alexey Dobriyan (1):
      proc: fixup uptime selftest

Alexey Izbyshev (1):
      futex: Resend potentially swallowed owner death notification

Allen-KH Cheng (1):
      mtd: spi-nor: Fix the number of bytes for the dummy cycles

Alvin Lee (2):
      drm/amd/display: Use min transition for SubVP into MPO
      drm/amd/display: Fix DTBCLK disable requests and SRC_SEL programming

Amadeusz Sławiński (2):
      ASoC: codecs: rt298: Add quirk for KBL-R RVP platform
      ASoC: Intel: avs: Add quirk for KBL-R RVP platform

Amir Goldstein (2):
      ovl: remove privs in ovl_copyfile()
      ovl: remove privs in ovl_fallocate()

Anastasia Belova (1):
      MIPS: BCM63xx: Add check for NULL for clk in clk_enable

Andreas Gruenbacher (1):
      gfs2: Partially revert gfs2_inode_lookup change

Andrew Bresticker (1):
      RISC-V: Fix unannoted hardirqs-on in return to userspace slow-path

Andrew Jeffery (1):
      ipmi: kcs: Poll OBF briefly to reduce OBE latency

Andrii Nakryiko (3):
      bpf: propagate precision in ALU/ALU64 operations
      bpf: propagate precision across all frames, not just the last one
      libbpf: Avoid enum forward-declarations in public API in C++ mode

Andrzej Pietrasiewicz (1):
      media: rkvdec: Add required padding

Andy Shevchenko (1):
      fbdev: ssd1307fb: Drop optional dependency

AngeloGioacchino Del Regno (9):
      arm64: dts: mediatek: mt8195: Fix CPUs capacity-dmips-mhz
      arm64: dts: mt7896a: Fix unit_address_vs_reg warning for oscillator
      arm64: dts: mt6779: Fix devicetree build warnings
      arm64: dts: mt2712e: Fix unit_address_vs_reg warning for oscillators
      arm64: dts: mt2712e: Fix unit address for pinctrl node
      arm64: dts: mt2712-evb: Fix vproc fixed regulators unit names
      arm64: dts: mt2712-evb: Fix usb vbus regulators unit names
      arm64: dts: mediatek: pumpkin-common: Fix devicetree warnings
      arm64: dts: mediatek: mt6797: Fix 26M oscillator unit name

Anna Schumaker (2):
      NFSv4.2: Set the correct size scratch buffer for decoding READ_PLUS
      NFS: Allow very small rsize & wsize again

Anshuman Gupta (2):
      drm/i915: Encapsulate lmem rpm stuff in intel_runtime_pm
      drm/i915/dgfx: Grab wakeref at i915_ttm_unmap_virtual

Anssi Hannula (4):
      can: kvaser_usb_leaf: Set Warning state even without bus errors
      can: kvaser_usb_leaf: Fix improved state not being reported
      can: kvaser_usb_leaf: Fix wrong CAN state after stopping
      can: kvaser_usb_leaf: Fix bogus restart events

Anup Patel (2):
      RISC-V: Fix MEMREMAP_WB for systems with Svpbmt
      RISC-V: KVM: Fix reg_val check in kvm_riscv_vcpu_set_reg_config()

Ard Biesheuvel (1):
      ftrace: Allow WITH_ARGS flavour of graph tracer with shadow call stack

Arnd Bergmann (2):
      RDMA/siw: Fix pointer cast warning
      drm/amd/pm: avoid large variable on kernel stack

Artem Chernyshev (1):
      net: vmw_vsock: vmci: Check memcpy_from_msg()

Artem Lukyanov (1):
      ASoC: amd: yc: Add Xiaomi Redmi Book Pro 14 2022 into DMI table

Arun Easi (1):
      scsi: qla2xxx: Fix crash when I/O abort times out

Arun Ramadoss (1):
      net: dsa: microchip: remove IRQF_TRIGGER_FALLING in request_threaded_irq

Asher Song (1):
      drm/amdgpu: Revert "drm/amdgpu: getting fan speed pwm for vega10 properly"

Aurabindo Pillai (1):
      drm/amd/display: fix array index out of bound error in bios parser

Avraham Stern (2):
      wifi: iwlwifi: mei: make sure ownership confirmed message is sent
      wifi: iwlwifi: mei: avoid blocking sap messages handling due to rtnl lock

Baisong Zhong (3):
      ALSA: pcm: fix undefined behavior in bit shift for SNDRV_PCM_RATE_KNOT
      ALSA: seq: fix undefined behavior in bit shift for SNDRV_SEQ_FILTER_USE_EVENT
      media: dvb-usb: az6027: fix null-ptr-deref in az6027_i2c_xfer()

Barnabás Pőcze (2):
      platform/x86: huawei-wmi: fix return value calculation
      timerqueue: Use rb_entry_safe() in timerqueue_getnext()

Bart Van Assche (4):
      scsi: core: Fix a race between scsi_done() and scsi_timeout()
      scsi: qla2xxx: Fix set-but-not-used variable warnings
      scsi: ufs: core: Fix the polling implementation
      scsi: ufs: Reduce the START STOP UNIT timeout

Bartosz Golaszewski (2):
      gpiolib: cdev: fix NULL-pointer dereferences
      gpiolib: protect the GPIO device against being dropped while in use by user-space

Bartosz Staszewski (1):
      i40e: Fix the inability to attach XDP program on downed interface

Bastien Nocera (1):
      HID: logitech-hidpp: Guard FF init code against non-USB devices

Beau Belgrave (1):
      tracing/user_events: Fix call print_fmt leak

Ben Greear (1):
      wifi: iwlwifi: mvm: fix double free on tx path.

Bernard Metzler (2):
      RDMA/siw: Fix immediate work request flush to completion queue
      RDMA/siw: Set defined status for work completion with undefined status

Bitterblue Smith (4):
      wifi: rtl8xxxu: Fix reading the vendor of combo chips
      wifi: rtl8xxxu: Fix use after rcu_read_unlock in rtl8xxxu_bss_info_changed
      wifi: rtl8xxxu: Add __packed to struct rtl8723bu_c2h
      wifi: rtl8xxxu: Fix the channel width reporting

Bjorn Andersson (1):
      thermal/drivers/qcom/lmh: Fix irq handler return value

Bjorn Helgaas (1):
      Revert "PCI: Clear PCI_STATUS when setting up device"

Björn Töpel (1):
      bpf: Do not zero-extend kfunc return values

Brian Foster (1):
      NFSD: pass range end to vfs_fsync_range() instead of count

Brian Starkey (1):
      drm/fourcc: Fix vsub/hsub for Q410 and Q401

Bryan O'Donoghue (1):
      dt-bindings: mfd: qcom,spmi-pmic: Drop PWM reg dependency

Cai Xinchen (1):
      rapidio: devices: fix missing put_device in mport_cdev_open

Cezary Rojewski (4):
      ASoC: Intel: avs: Fix DMA mask assignment
      ASoC: Intel: avs: Fix potential RX buffer overflow
      ASoC: Intel: avs: Lock substream before snd_pcm_stop()
      ASoC: Intel: Skylake: Fix driver hang during shutdown

Chao Yu (3):
      f2fs: fix to invalidate dcc->f2fs_issue_discard in error path
      f2fs: fix to destroy sbi->post_read_wq in error path of f2fs_fill_super()
      f2fs: fix to avoid accessing uninitialized spinlock

Chen Hui (1):
      cpufreq: qcom-hw: Fix memory leak in qcom_cpufreq_hw_read_lut()

Chen Jiahao (1):
      drivers: soc: ti: knav_qmss_queue: Mark knav_acc_firmwares as static

Chen Zhongjin (12):
      perf: Fix possible memleak in pmu_dev_alloc()
      erofs: Fix pcluster memleak when its block address is zero
      fs: sysv: Fix sysv_nblocks() returns wrong value
      media: vidtv: Fix use-after-free in vidtv_bridge_dvb_init()
      media: vimc: Fix wrong function called when vimc_init() fails
      media: dvb-core: Fix ignored return value in dvb_register_frontend()
      wifi: cfg80211: Fix not unregister reg_pdev when load_builtin_regdb_keys() fails
      configfs: fix possible memory leak in configfs_create_dir()
      scsi: efct: Fix possible memleak in efct_device_init()
      scsi: fcoe: Fix transport not deattached when fcoe_if_init() fails
      vme: Fix error not catched in fake_init()
      ovl: fix use inode directly in rcu-walk mode

Chen-Yu Tsai (1):
      arm64: dts: mt8183: Fix Mali GPU clock

Chengchang Tang (5):
      RDMA/hns: Fix AH attr queried by query_qp
      RDMA/hns: Fix PBL page MTR find
      RDMA/hns: Fix page size cap from firmware
      RDMA/hns: Fix error code of CMD
      RDMA/hns: Fix XRC caps on HIP08

ChiYuan Huang (2):
      regulator: core: Use different devices for resource allocation and DT lookup
      regulator: core: Fix resolve supply lookup issue

Christian Marangi (2):
      clk: qcom: clk-krait: fix wrong div2 functions
      phy: qcom-qmp-pcie: split pcs_misc init cfg for ipq8074 pcs table

Christoph Böhmwalder (1):
      drbd: use blk_queue_max_discard_sectors helper

Christoph Hellwig (7):
      nvmet: only allocate a single slab for bvecs
      block: clear ->slave_dir when dropping the main slave_dir reference
      dm: cleanup open_table_device
      dm: cleanup close_table_device
      dm: track per-add_disk holder relations in DM
      media: videobuf-dma-contig: use dma_mmap_coherent
      nvme: pass nr_maps explicitly to nvme_alloc_io_tag_set

Christophe JAILLET (9):
      wifi: rtw89: Fix some error handling path in rtw89_core_sta_assoc()
      Bluetooth: Fix EALREADY and ELOOP cases in bt_status()
      octeontx2-af: cn10k: mcs: Fix a resource leak in the probe and remove functions
      crypto: amlogic - Remove kcalloc without check
      fbdev: uvesafb: Fixes an error handling path in uvesafb_probe()
      powerpc/52xx: Fix a resource leak in an error handling path
      mfd: qcom_rpm: Fix an error handling path in qcom_rpm_probe()
      myri10ge: Fix an error handling path in myri10ge_probe()
      mfd: qcom_rpm: Use devm_of_platform_populate() to simplify code

Christophe Leroy (1):
      spi: fsl_spi: Don't change speed while chipselect is active

Chuck Lever (2):
      NFSD: Finish converting the NFSv2 GETACL result encoder
      NFSD: Finish converting the NFSv3 GETACL result encoder

Chun-Jie Chen (1):
      soc: mediatek: pm-domains: Fix the power glitch issue

Chunfeng Yun (1):
      usb: xhci-mtk: fix leakage of shared hcd when fail to set wakeup irq

Cole Robinson (1):
      virt/sev-guest: Add a MODULE_ALIAS

Cong Dang (1):
      memory: renesas-rpc-if: Clear HS bit during hardware initialization

Cong Wang (1):
      net_sched: reject TCF_EM_SIMPLE case for complex ematch module

Conor Dooley (5):
      riscv: dts: microchip: fix memory node unit address for icicle
      dt-bindings: pwm: fix microchip corePWM's pwm-cells
      riscv: dts: microchip: fix the icicle's #pwm-cells
      riscv: dts: microchip: remove pcie node from the sev kit
      mailbox: mpfs: read the system controller's status

Corentin Labbe (8):
      crypto: sun8i-ss - use dma_addr instead u32
      crypto: rockchip - do not do custom power management
      crypto: rockchip - do not store mode globally
      crypto: rockchip - add fallback for cipher
      crypto: rockchip - add fallback for ahash
      crypto: rockchip - better handle cipher key
      crypto: rockchip - remove non-aligned handling
      crypto: rockchip - rework by using crypto_engine

Cosmin Tanislav (1):
      iio: temperature: ltc2983: make bulk write buffer DMA-safe

Dan Aloni (1):
      nfsd: under NFSv4.1, fix double svc_xprt_put on rpc_create failure

Dan Carpenter (5):
      amdgpu/pm: prevent array underflow in vega20_odn_edit_dpm_table()
      bonding: uninitialized variable in bond_miimon_inspect()
      staging: rtl8192u: Fix use after free in ieee80211_rx()
      fs/ntfs3: Harden against integer overflows
      iommu/mediatek: Fix forever loop in error handling

Daniel Golle (2):
      clk: mediatek: fix dependency of MT7986 ADC clocks
      pwm: mediatek: always use bus clock for PWM on MT7622

Daniel Jordan (2):
      padata: Always leave BHs disabled when running ->parallel()
      padata: Fix list iterator in padata_do_serial()

Dario Binacchi (5):
      clk: imx8mn: rename vpu_pll to m7_alt_pll
      clk: imx: replace osc_hdmi with dummy
      clk: imx: rename video_pll1 to video_pll
      clk: imx8mn: fix imx8mn_sai2_sels clocks list
      clk: imx8mn: fix imx8mn_enet_phy_sels clocks list

David Hildenbrand (1):
      mm/gup: disallow FOLL_FORCE|FOLL_WRITE on hugetlb mappings

David Howells (4):
      net, proc: Provide PROC_FS=n fallback for proc_create_net_single_write()
      rxrpc: Fix ack.bufferSize to be 0 when generating an ack
      rxrpc: Fix missing unlock in rxrpc_do_sendmsg()
      afs: Fix lost servers_outstanding count

David Jeffery (1):
      blk-mq: avoid double ->queue_rq() because of early timeout

Denis Pauk (1):
      hwmon: (nct6775) add ASUS CROSSHAIR VIII/TUF/ProArt B550M

Deren Wu (3):
      wifi: mt76: fix coverity overrun-call in mt76_get_txpower()
      wifi: mt76: mt7921: Add missing __packed annotation of struct mt7921_clc
      wifi: mt76: do not send firmware FW_FEATURE_NON_DL region

Dmitry Baryshkov (11):
      arm64: dts: qcom: msm8996: fix supported-hw in cpufreq OPP tables
      arm64: dts: qcom: msm8996: fix GPU OPP table
      drm/msm/mdp5: stop overriding drvdata
      drm/msm/hdmi: use devres helper for runtime PM management
      clk: qcom: gcc-ipq806x: use parent_data for the last remaining entry
      drm/msm/mdp5: fix reading hw revision on db410c platform
      led: qcom-lpg: Fix sleeping in atomic
      phy: qcom-qmp-usb: correct registers layout for IPQ8074 USB3 PHY
      phy: qcom-qmp-pcie: split register tables into common and extra parts
      phy: qcom-qmp-pcie: support separate tables for EP mode
      phy: qcom-qmp-pcie: Support SM8450 PCIe1 PHY in EP mode

Dmitry Torokhov (7):
      MIPS: DTS: CI20: fix reset line polarity of the ethernet controller
      arm64: dts: qcom: msm8996: fix sound card reset line polarity
      arm64: dts: qcom: sm8250-mtp: fix reset line polarity
      arm64: dts: qcom: sc7280: fix codec reset line polarity for CRD 3.0/3.1
      arm64: dts: qcom: sc7280: fix codec reset line polarity for CRD 1.0/2.0
      HID: i2c: let RMI devices decide what constitutes wakeup event
      ASoC: dt-bindings: wcd9335: fix reset line polarity in example

Dongdong Zhang (1):
      f2fs: fix normal discard process

Dongliang Mu (1):
      fs: jfs: fix shift-out-of-bounds in dbAllocAG

Doug Brown (2):
      ARM: mmp: fix timer_read delay
      drm/etnaviv: add missing quirks for GC300

Douglas Anderson (3):
      Input: elants_i2c - properly handle the reset GPIO when power is off
      clk: qcom: lpass-sc7280: Fix pm_runtime usage
      clk: qcom: lpass-sc7180: Fix pm_runtime usage

Dr. David Alan Gilbert (1):
      jfs: Fix fortify moan in symlink

Dragos Tatulea (1):
      IB/IPoIB: Fix queue count inconsistency for PKEY child interfaces

Duoming Zhou (1):
      drivers: staging: r8188eu: Fix sleep-in-atomic-context bug in rtw_join_timeout_handler

Eddie James (2):
      tpm: tis_i2c: Fix sanity check interrupt enable mask
      tpm: Add flag to use default cancellation policy

Edward Pacman (1):
      ALSA: hda/realtek: Add quirk for Lenovo TianYi510Pro-14IOB

Eelco Chaudron (1):
      openvswitch: Fix flow lookup to use unmasked key

Emeel Hakim (1):
      net: macsec: fix net device access prior to holding a lock

Emmanuel Grumbach (2):
      wifi: iwlwifi: mei: don't send SAP commands if AMT is disabled
      wifi: iwlwifi: mei: fix tx DHCP packet for devices with new Tx API

Enrik Berkhan (1):
      HID: mcp2221: don't connect hidraw

Eric Biggers (8):
      crypto: x86/aegis128 - fix possible crash with CFI enabled
      crypto: x86/aria - fix crash with CFI enabled
      crypto: x86/sha1 - fix possible crash with CFI enabled
      crypto: x86/sha256 - fix possible crash with CFI enabled
      crypto: x86/sha512 - fix possible crash with CFI enabled
      crypto: x86/sm3 - fix possible crash with CFI enabled
      crypto: x86/sm4 - fix crash with CFI enabled
      crypto: arm64/sm3 - fix possible crash with CFI enabled

Eric Dumazet (4):
      bpf, sockmap: fix race in sock_map_free()
      net: stream: purge sk_error_queue in sk_stream_kill_queues()
      net: add atomic_long_t to net_device_stats fields
      ipv6/sit: use DEV_STATS_INC() to avoid data-races

Eric Pilmore (1):
      ntb_netdev: Use dev_kfree_skb_any() in interrupt context

Fabrice Gasnier (1):
      counter: stm32-lptimer-cnt: fix the check on arr and cmp registers update

Fabrizio Castro (2):
      arm64: dts: renesas: r9a09g011: Fix unit address format error
      arm64: dts: renesas: r9a09g011: Fix I2C SoC specific strings

Fedor Pchelkin (3):
      wifi: ath9k: hif_usb: fix memory leak of urbs in ath9k_hif_usb_dealloc_tx_urbs()
      wifi: ath9k: hif_usb: Fix use-after-free in ath9k_hif_usb_reg_in_cb()
      wifi: ath9k: verify the expected usb_endpoints are present

Felix Fietkau (1):
      net: ethernet: mtk_eth_soc: drop packets to WDMA if the ring is full

Fenghua Yu (1):
      dmaengine: idxd: Fix crc_val field for completion record

Ferry Toth (1):
      usb: dwc3: core: defer probe on ulpi_read_id timeout

Filipe Manana (1):
      btrfs: do not BUG_ON() on ENOMEM when dropping extent items for a range

Firo Yang (1):
      sctp: sysctl: make extra pointers netns aware

Florian Westphal (1):
      netfilter: conntrack: set icmpv6 redirects as RELATED

Francisco Munoz (1):
      PCI: vmd: Fix secondary bus reset for Intel bridges

Frank Li (1):
      PCI: endpoint: pci-epf-vntb: Fix call pci_epc_mem_free_addr() in error path

Frank Wunderlich (3):
      arm64: dts: mt7986: fix trng node name
      arm64: dts: mt7986: move wed_pcie node
      dt-bindings: pinctrl: update uart/mmc bindings for MT7986 SoC

GUO Zihua (4):
      ima: Handle -ESTALE returned by ima_filter_rule_match()
      integrity: Fix memory leakage in keyring allocation error path
      rtc: mxc_v2: Add missing clk_disable_unprepare()
      ima: Simplify ima_lsm_copy_rule

Gabriel Somlo (2):
      mmc: litex_mmc: ensure `host->irq == 0` if polling
      serial: altera_uart: fix locking in polling mode

Gao Xiang (2):
      erofs: fix missing unmap if z_erofs_get_extent_compressedlen() fails
      erofs: validate the extent length for uncompressed pclusters

Gaosheng Cui (17):
      lib/fonts: fix undefined behavior in bit shift for get_default_font
      drm/ttm: fix undefined behavior in bit shift for TTM_TT_FLAG_PRIV_POPULATED
      mtd: core: fix possible resource leak in init_mtd()
      ASoC: amd: acp: Fix possible UAF in acp_dma_open
      ALSA: mts64: fix possible null-ptr-defer in snd_mts64_interrupt
      pinctrl: thunderbay: fix possible memory leak in thunderbay_build_functions()
      net: stmmac: fix possible memory leak in stmmac_dvr_probe()
      apparmor: fix a memleak in multi_transaction_new()
      crypto: ccree - Remove debugfs when platform_driver_register failed
      scsi: snic: Fix possible UAF in snic_tgt_create()
      crypto: img-hash - Fix variable dereferenced before check 'hdev->req'
      staging: vme_user: Fix possible UAF in tsi148_dma_list_add
      fbdev: ep93xx-fb: Add missing clk_disable_unprepare in ep93xxfb_probe()
      remoteproc: sysmon: fix memory leak in qcom_add_sysmon_subdev()
      rtc: st-lpc: Add missing clk_disable_unprepare in st_rtc_probe()
      rtc: pic32: Move devm_rtc_allocate_device earlier in pic32_rtc_probe()
      net: stmmac: fix errno when create_singlethread_workqueue() fails

Gaurav Kohli (1):
      x86/hyperv: Remove unregister syscore call from Hyper-V cleanup

Gautam Menghani (1):
      media: imon: fix a race condition in send_packet()

Gavrilov Ilia (1):
      relay: fix type mismatch when allocating memory in relay_create_buf()

Geert Uytterhoeven (3):
      arm64: dts: renesas: r8a779g0: Fix HSCIF0 "brg_int" clock
      clk: renesas: r8a779f0: Fix SD0H clock name
      media: staging: stkwebcam: Restore MEDIA_{USB,CAMERA}_SUPPORT dependencies

George Shen (1):
      drm/amd/display: Workaround to increase phantom pipe vactive in pipesplit

Georgi Vlaev (1):
      firmware: ti_sci: Fix polled mode during system suspend

Gerhard Engleder (2):
      samples/bpf: Fix map iteration in xdp1_user
      samples/bpf: Fix MAC address swapping in xdp2_kern

Giulio Benetti (1):
      clk: imx: imxrt1050: fix IMXRT1050_CLK_LCDIF_APB offsets

Greg Kroah-Hartman (1):
      Linux 6.1.2

Guchun Chen (1):
      drm/amd/pm/smu11: BACO is supported when it's in BACO state

Guenter Roeck (2):
      iommu/mediatek: Validate number of phandles associated with "mediatek,larbs"
      thermal/core: Ensure that thermal device is registered in thermal_zone_get_temp

Guilherme G. Piccoli (2):
      x86/split_lock: Add sysctl to control the misery mode
      video: hyperv_fb: Avoid taking busy spinlock on panic path

Guoniu.zhou (1):
      media: ov5640: set correct default link frequency

Gustavo A. R. Silva (1):
      powerpc/xmon: Fix -Wswitch-unreachable warning in bpt_cmds

Haibo Chen (1):
      clk: imx93: correct the flexspi1 clock setting

Haiyi Zhou (1):
      drm/amd/display: wait for vblank during pipe programming

Hamza Mahfooz (2):
      drm/edid: add a quirk for two LG monitors to get them to work on 10bpc
      Revert "drm/amd/display: Limit max DSC target bpp for specific monitors"

Hangbin Liu (3):
      net/tunnel: wait until all sk_user_data reader finish before releasing the sock
      bonding: add missed __rcu annotation for curr_active_slave
      bonding: do failover when high prio link up

Hanjun Guo (1):
      drm/radeon: Add the missed acpi_put_table() to fix memory leak

Hans Verkuil (1):
      media: v4l2-ctrls-api.c: add back dropped ctrl->is_new = 1

Hans de Goede (8):
      power: supply: bq25890: Ensure pump_express_work is cancelled on remove
      ACPI: video: Change GIGABYTE GB-BXBT-2807 quirk to force_none
      ACPI: video: Change Sony Vaio VPCEH3U1E quirk to force_native
      ACPI: video: Add force_vendor quirk for Sony Vaio PCG-FRV35
      ACPI: video: Add force_native quirk for Sony Vaio VPCY11S1E
      ACPI: x86: Add skip i2c clients quirk for Lenovo Yoga Tab 3 Pro (YT3-X90F)
      ACPI: x86: Add skip i2c clients quirk for Medion Lifetab S10346
      ASoC: rt5670: Remove unbalanced pm_runtime_put()

Hao Lee (1):
      sched/psi: Fix possible missing or delayed pending event

Harshit Mogalapalli (4):
      xen/privcmd: Fix a possible warning in privcmd_ioctl_mmap_resource()
      scsi: scsi_debug: Fix a warning in resp_write_scat()
      scsi: scsi_debug: Fix a warning in resp_verify()
      scsi: scsi_debug: Fix a warning in resp_report_zones()

Hawkins Jiawei (2):
      nfs: fix possible null-ptr-deref when parsing param
      hugetlbfs: fix null-ptr-deref in hugetlbfs_parse_param()

Herbert Xu (1):
      crypto: cryptd - Use request context instead of stack for sub-request

Hoi Pok Wu (1):
      fs: jfs: fix shift-out-of-bounds in dbDiscardAG

Hou Tao (2):
      erofs: check the uniqueness of fsid in shared domain in advance
      bpf: Pin the start cgroup in cgroup_iter_seq_init()

Hui Tang (3):
      mtd: lpddr2_nvm: Fix possible null-ptr-deref
      clk: microchip: check for null return of devm_kzalloc()
      i2c: pxa-pci: fix missing pci_disable_device() on error in ce4100_i2c_probe

Huisong Li (1):
      mailbox: pcc: Reset pcc_chan_count to zero in case of PCC probe failure

Ido Schimmel (1):
      thermal/of: Fix memory leak on thermal_of_zone_register() failure

Ilya Bakoulin (1):
      drm/amd/display: Fix display corruption w/ VSR enable

Inga Stotland (1):
      Bluetooth: MGMT: Fix error report for ADD_EXT_ADV_PARAMS

Isaac J. Manjarres (1):
      loop: Fix the max_loop commandline argument treatment when it is set to 0

Ivaylo Dimitrov (1):
      usb: musb: remove extra check in musb_gadget_vbus_draw

Jacob Keller (1):
      ice: synchronize the misc IRQ when tearing down Tx tracker

Jaegeuk Kim (1):
      f2fs: allow to set compression for inlined file

Jakub Kicinski (3):
      devlink: hold region lock when flushing snapshots
      selftests: devlink: fix the fd redirect in dummy_reporter_test
      devlink: protect devlink dump by the instance lock

James Clark (3):
      perf tools: Fix "kernel lock contention analysis" test by not printing warnings in quiet mode
      perf branch: Fix interpretation of branch records
      perf tools: Make quiet mode consistent between tools

James Hilliard (1):
      selftests/bpf: Fix conflicts with built-in functions in bpf_iter_ksym

James Hurley (1):
      platform/mellanox: mlxbf-pmc: Fix event typo

Jani Nikula (1):
      drm/i915/guc: make default_lists const data

Janne Grunau (1):
      arch: arm64: apple: t8103: Use standard "iommu" node name

Jason Gerecke (1):
      HID: wacom: Ensure bootloader PID is usable in hidraw mode

Jason Gunthorpe (1):
      iommu/sun50i: Remove IOMMU_DOMAIN_IDENTITY

Jayesh Choudhary (3):
      arm64: dts: ti: k3-am65-main: Drop dma-coherent in crypto node
      arm64: dts: ti: k3-j721e-main: Drop dma-coherent in crypto node
      arm64: dts: ti: k3-j7200-mcu-wakeup: Drop dma-coherent in crypto node

Jeff LaBundy (7):
      Input: iqs7222 - protect against undefined slider size
      Input: iqs7222 - drop unused device node references
      Input: iqs7222 - report malformed properties
      Input: iqs7222 - add support for IQS7222A v1.13+
      dt-bindings: input: iqs7222: Reduce 'linux,code' to optional
      dt-bindings: input: iqs7222: Correct minimum slider size
      dt-bindings: input: iqs7222: Add support for IQS7222A v1.13+

Jeff Layton (2):
      nfsd: don't call nfsd_file_put from client states seqfile display
      nfsd: return error if nfs4_setacl fails

Jens Axboe (1):
      io_uring/net: ensure compat import handlers clear free_iov

Jeremy Kerr (1):
      mctp: serial: Fix starting value for frame check sequence

Jernej Skrabec (7):
      media: v4l2-ioctl.c: Unify YCbCr/YUV terms in format descriptions
      media: cedrus: hevc: Fix offset adjustments
      iommu/sun50i: Fix reset release
      iommu/sun50i: Consider all fault sources for reset
      iommu/sun50i: Fix R/W permission check
      iommu/sun50i: Fix flush size
      iommu/sun50i: Implement .iotlb_sync_map

Jerry Ray (1):
      net: lan9303: Fix read error execution path

Jiamei Xie (1):
      serial: amba-pl011: avoid SBSA UART accessing DMACR register

Jiang Li (1):
      md/raid1: stop mdx_raid1 thread when raid1 array run failed

Jianmin Lv (1):
      irqchip/loongson-pch-pic: Fix translate callback for DT path

Jiantao Zhang (1):
      USB: gadget: Fix use-after-free during usb config switch

Jiao Zhou (1):
      ALSA: hda/hdmi: Add HP Device 0x8711 to force connect list

Jiasheng Jiang (8):
      soc: qcom: apr: Add check for idr_alloc and of_property_read_string_index
      media: coda: jpeg: Add check for kmalloc
      ASoC: mediatek: mtk-btcvsd: Add checks for write and read of mtk_btcvsd_snd
      memstick/ms_block: Add check for alloc_ordered_workqueue
      media: coda: Add check for dcoda_iram_alloc
      media: coda: Add check for kmalloc
      usb: storage: Add check for kcalloc
      HID: amd_sfh: Add missing check for dma_alloc_coherent

Jiaxin Yu (1):
      ASoC: mediatek: mt8186: Correct I2S shared clocks

Jimmy Assarsson (5):
      can: kvaser_usb: kvaser_usb_leaf: Get capabilities from device
      can: kvaser_usb: kvaser_usb_leaf: Rename {leaf,usbcan}_cmd_error_event to {leaf,usbcan}_cmd_can_error_event
      can: kvaser_usb: kvaser_usb_leaf: Handle CMD_ERROR_EVENT
      can: kvaser_usb: Add struct kvaser_usb_busparams
      can: kvaser_usb: Compare requested bittiming parameters with actual parameters in do_set_{,data}_bittiming

Jiri Olsa (1):
      selftests/bpf: Add missing bpf_iter_vma_offset__destroy call

Jiri Slaby (SUSE) (1):
      qed (gcc13): use u16 for fid to be big enough

Jisoo Jang (1):
      wifi: brcmfmac: Fix potential NULL pointer dereference in 'brcmf_c_preinit_dcmds()'

Joao Martins (2):
      vfio/iova_bitmap: Fix PAGE_SIZE unaligned bitmaps
      vfio/iova_bitmap: refactor iova_bitmap_set() to better handle page boundaries

Joel Granados (1):
      nvme: return err on nvme_init_non_mdts_limits fail

Johan Hovold (21):
      arm64: dts: qcom: sm8150: fix UFS PHY registers
      arm64: dts: qcom: sm8250: fix UFS PHY registers
      arm64: dts: qcom: sm8350: fix UFS PHY registers
      arm64: dts: qcom: sm8450: fix UFS PHY registers
      arm64: dts: qcom: sm8250: drop bogus DP PHY clock
      arm64: dts: qcom: sm6350: drop bogus DP PHY clock
      phy: qcom-qmp-pcie: drop bogus register update
      phy: qcom-qmp-pcie: drop power-down delay config
      phy: qcom-qmp-pcie: replace power-down delay
      phy: qcom-qmp-pcie: fix sc8180x initialisation
      phy: qcom-qmp-pcie: fix ipq8074-gen3 initialisation
      phy: qcom-qmp-pcie: fix ipq6018 initialisation
      phy: qcom-qmp-usb: clean up power-down handling
      phy: qcom-qmp-usb: drop sc8280xp power-down delay
      phy: qcom-qmp-usb: drop power-down delay config
      phy: qcom-qmp-usb: clean up status polling
      phy: qcom-qmp-usb: drop start and pwrdn-ctrl abstraction
      phy: qcom-qmp-usb: fix sc8280xp PCS_USB offset
      arm64: dts: qcom: sm6350: fix USB-DP PHY registers
      arm64: dts: qcom: sm8250: fix USB-DP PHY registers
      regulator: core: fix deadlock on regulator enable

Johannes Berg (5):
      wifi: fix multi-link element subelement iteration
      wifi: mac80211: mlme: fix null-ptr deref on failed assoc
      wifi: mac80211: check link ID in auth/assoc continuation
      wifi: mac80211: fix ifdef symbol name
      wifi: iwlwifi: mei: fix potential NULL-ptr deref after clone

John Harrison (2):
      drm/i915/guc: Limit scheduling properties to avoid overflow
      drm/i915: Fix compute pre-emption w/a to apply to compute engines

John Johansen (3):
      apparmor: fix lockdep warning when removing a namespace
      apparmor: Fix abi check to include v8 abi
      apparmor: Fix regression in stacking due to label flags

John Keeping (3):
      usb: gadget: f_hid: fix f_hidg lifetime vs cdev
      usb: gadget: f_hid: fix refcount leak on error path
      ALSA: usb-audio: Add quirk for Tascam Model 12

John Stultz (2):
      pstore: Switch pmsg_lock to an rt_mutex to avoid priority inversion
      pstore: Make sure CONFIG_PSTORE_PMSG selects CONFIG_RT_MUTEXES

Jon Hunter (2):
      pwm: tegra: Improve required rate calculation
      pwm: tegra: Ensure the clock rate is not less than needed

Jonathan Neuschäfer (2):
      ARM: dts: nuvoton: Remove bogus unit addresses from fixed-partition nodes
      spi: Update reference to struct spi_controller

Jonathan Toppins (1):
      bonding: fix link recovery in mode 2 when updelay is nonzero

Josef Bacik (1):
      btrfs: do not panic if we can't allocate a prealloc extent state

José Expósito (2):
      HID: input: do not query XP-PEN Deco LW battery
      HID: uclogic: Add support for XP-PEN Deco LW

Juergen Gross (1):
      x86/boot: Skip realmode init code when running as Xen PV guest

Julian Anastasov (1):
      ipvs: use u64_stats_t for the per-cpu counters

Justin Chen (2):
      phy: usb: Use slow clock for wake enabled suspend
      phy: usb: Fix clock imbalance for suspend/resume

Justin Tee (1):
      scsi: lpfc: Fix hard lockup when reading the rx_monitor from debugfs

Kai Vehmanen (3):
      ALSA: hda/hdmi: fix i915 silent stream programming flow
      ALSA: hda/hdmi: set default audio parameters for KAE silent-stream
      ALSA: hda/hdmi: fix stream-id config keep-alive for rt suspend

Kai Ye (1):
      crypto: hisilicon/qm - increase the memory of local variables

Kajol Jain (1):
      powerpc/hv-gpci: Fix hv_gpci event list

Kartik (1):
      serial: tegra: Read DMA status before terminating

Keerthy (2):
      arm64: dts: ti: k3-j721s2: Fix the interrupt ranges property for main & wkup gpio intr
      thermal/drivers/k3_j72xx_bandgap: Fix the debug print message

Kees Cook (6):
      fortify: Do not cast to "unsigned char"
      openvswitch: Use kmalloc_size_roundup() to match ksize() usage
      bnx2: Use kmalloc_size_roundup() to match ksize() usage
      igb: Do not free q_vector unless new one was allocated
      bpf/verifier: Use kmalloc_size_roundup() to match ksize() usage
      LoadPin: Ignore the "contents" argument of the LSM hooks

Kerem Karabay (2):
      HID: apple: fix key translations where multiple quirks attempt to translate the same key
      HID: apple: enable APPLE_ISO_TILDE_QUIRK for the keyboards of Macs with the T2 chip

Khaled Almahallawy (1):
      drm/i915/display: Don't disable DDI/Transcoder when setting phy test pattern

Khazhismel Kumykov (1):
      bfq: fix waker_bfqq inconsistency crash

Kirill Tkhai (1):
      unix: Fix race in SOCK_SEQPACKET's unix_dgram_sendmsg()

Konrad Dybcio (2):
      clk: qcom: dispcc-sm6350: Add CLK_OPS_PARENT_ENABLE to pixel&byte src
      regulator: qcom-rpmh: Fix PMR735a S3 regulator spec

Konstantin Meskhidze (1):
      drm/amdkfd: Fix memory leakage

Kory Maincent (1):
      arm: dts: spear600: Fix clcd interrupt

Kris Bahnsen (1):
      spi: spi-gpio: Don't set MOSI as an input if not 3WIRE mode

Kristina Martsenko (1):
      lkdtm: cfi: Make PAC test work with GCC 7 and 8

Krzysztof Kozlowski (11):
      arm64: dts: qcom: ipq6018-cp01-c1: use BLSPI1 pins
      arm64: dts: qcom: sm8250-sony-xperia-edo: fix touchscreen bias-disable
      arm64: dts: qcom: sdm845-xiaomi-polaris: fix codec pin conf name
      arm64: dts: qcom: sdm630: fix UART1 pin bias
      arm64: dts: qcom: sdm845-cheza: fix AP suspend pin bias
      arm64: dts: qcom: sm8250: correct LPASS pin pull down
      arm64: dts: qcom: sc7180-trogdor-homestar: fully configure secondary I2S pins
      arm64: dts: qcom: sm6125: fix SDHCI CQE reg names
      ASoC: codecs: wsa883x: Use proper shutdown GPIO polarity
      interconnect: qcom: sc7180: fix dropped const of qcom_icc_bcm
      arm64: dts: qcom: sm8450: disable SDHCI SDR104/SDR50 on all boards

Kumar Kartikeya Dwivedi (2):
      bpf: Clobber stack slot when writing over spilled PTR_TO_BTF_ID
      bpf: Fix slot type check in check_stack_write_var_off

Kumar Meiyappan (1):
      scsi: smartpqi: Correct device removal for multi-actuator devices

Kunihiko Hayashi (2):
      PCI: pci-epf-test: Register notifier if only core_init_notifier is enabled
      mmc: f-sdh30: Add quirks for broken timeout clock capability

Kuniyuki Iwashima (4):
      seccomp: Move copy_seccomp() to no failure path.
      soreuseport: Fix socket selection for SO_INCOMING_CPU.
      udp: Clean up some functions.
      net: Return errno in sk->sk_prot->get_port().

Ladislav Michl (1):
      MIPS: OCTEON: warn only once if deprecated link status is being used

Laurent Pinchart (4):
      drm: lcdif: Switch to limited range for RGB to YUV conversion
      media: v4l2-ctrls: Fix off-by-one error in integer menu control check
      drm: rcar-du: Drop leftovers dependencies from Kconfig
      media: imx: imx7-media-csi: Clear BIT_MIPI_DOUBLE_CMPNT for <16b formats

Leo Yan (3):
      perf trace: Return error if a system call doesn't exist
      perf trace: Use macro RAW_SYSCALL_ARGS_NUM to replace number
      perf trace: Handle failure when trace point folder is missed

Leon Romanovsky (1):
      RDMA/core: Fix order of nldev_exit call

Leonid Ravich (1):
      IB/mad: Don't call to function that might sleep while in atomic context

Li Huafei (1):
      kprobes: Fix check for probe enabled in kill_kprobe()

Li Jun (2):
      dt-bindings: clocks: imx8mp: Add ID for usb suspend clock
      clk: imx: imx8mp: add shared clk gate for usb suspend clk

Li Zetao (4):
      ocfs2: fix memory leak in ocfs2_mount_volume()
      ACPICA: Fix use-after-free in acpi_ut_copy_ipackage_to_ipackage()
      net: farsync: Fix kmemleak when rmmods farsync
      r6040: Fix kmemleak in probe and remove

Li Zhijian (1):
      RDMA/rxe: Fix mr->map double free

Li Zhong (2):
      ACPI: processor: idle: Check acpi_fetch_acpi_dev() return value
      drivers/md/md-bitmap: check the return value of md_bitmap_get_counter()

Liam Howlett (2):
      test_maple_tree: add test for mas_spanning_rebalance() on insufficient data
      maple_tree: fix mas_spanning_rebalance() on insufficient data

Liang He (2):
      media: c8sectpfe: Add of_node_put() when breaking out of loop
      drm/amdgpu: Fix potential double free and null pointer dereference

Lili Li (1):
      ASoC: Intel: Skylake: Fix Kconfig dependency

Lin Ma (3):
      media: dvbdev: adopts refcnt to avoid UAF
      media: dvbdev: fix build warning due to comments
      media: dvbdev: fix refcnt bug

Linus Walleij (1):
      usb: fotg210-udc: Fix ages old endianness issues

Liu Peibao (1):
      irqchip/loongson-liointc: Fix improper error handling in liointc_init()

Liu Shixin (4):
      media: vivid: fix compose size exceed boundary
      ALSA: asihpi: fix missing pci_disable_device()
      media: saa7164: fix missing pci_disable_device()
      binfmt_misc: fix shift-out-of-bounds in check_special_flags

Lorenzo Bianconi (5):
      net: ethernet: mtk_eth_soc: do not overwrite mtu configuration running reset routine
      net: ethernet: mtk_eth_soc: fix RSTCTRL_PPE{0,1} definitions
      wifi: mt76: mt7915: fix reporting of TX AGGR histogram
      wifi: mt76: mt7921: fix reporting of TX AGGR histogram
      wifi: mt76: do not run mt76u_status_worker if the device is not running

Luca Weiss (6):
      ARM: dts: qcom: apq8064: fix coresight compatible
      soc: qcom: llcc: make irq truly optional
      thermal/drivers/qcom/temp-alarm: Fix inaccurate warning for gen2
      leds: is31fl319x: Fix setting current limit for is31fl319{0,1,3}
      remoteproc: qcom_q6v5_pas: disable wakeup on probe fail or remove
      remoteproc: qcom_q6v5_pas: detach power domains on remove

Luiz Augusto von Dentz (1):
      Bluetooth: hci_conn: Fix crash on hci_create_cis_sync

Luoyouming (2):
      RDMA/hns: Fix ext_sge num error when post send
      RDMA/hns: Fix incorrect sge nums calculation

Manivannan Sadhasivam (4):
      cpufreq: qcom-hw: Fix the frequency returned by cpufreq_driver->get()
      clk: qcom: gcc-sm8250: Use retention mode for USB GDSCs
      phy: qcom-qmp-pcie: Fix high latency with 4x2 PHY when ASPM is enabled
      phy: qcom-qmp-pcie: Fix sm8450_qmp_gen4x2_pcie_pcs_tbl[] register names

Marco Elver (1):
      objtool, kcsan: Add volatile read/write instrumentation to whitelist

Marco Felsch (1):
      drm: lcdif: change burst size to 256B

Marcus Folkesson (2):
      HID: hid-sensor-custom: set fixed size for custom attributes
      thermal/drivers/imx8mm_thermal: Validate temperature range

Marek Szyprowski (2):
      media: exynos4-is: don't rely on the v4l2_async_subdev internals
      ASoC: wm8994: Fix potential deadlock

Marek Vasut (11):
      ARM: dts: stm32: Drop stm32mp15xc.dtsi from Avenger96
      ARM: dts: stm32: Fix AV96 WLAN regulator gpio property
      clk: renesas: r9a06g032: Repair grave increment error
      drm/panel/panel-sitronix-st7701: Fix RTNI calculation
      drm/panel/panel-sitronix-st7701: Remove panel on DSI attach failure
      wifi: rsi: Fix handling of 802.3 EAPOL frames sent via control port
      drm: lcdif: Set and enable FIFO Panic threshold
      media: mt9p031: Drop bogus v4l2_subdev_get_try_crop() call from mt9p031_init_cfg()
      extcon: usbc-tusb320: Update state on probe even if no IRQ pending
      power: supply: bq25890: Factor out regulator registration code
      Bluetooth: hci_bcm: Add CYW4373A0 support

Marijn Suijten (13):
      arm64: dts: qcom: pm660: Use unique ADC5_VCOIN address in node name
      arm64: dts: qcom: pm6350: Include header for KEY_POWER
      drm/msm/dpu1: Account for DSC's bits_per_pixel having 4 fractional bits
      drm/msm/dsi: Remove useless math in DSC calculations
      drm/msm/dsi: Remove repeated calculation of slice_per_intf
      drm/msm/dsi: Use DIV_ROUND_UP instead of conditional increment on modulo
      drm/msm/dsi: Reuse earlier computed dsc->slice_chunk_size
      drm/msm/dsi: Appropriately set dsc->mux_word_size based on bpc
      drm/msm/dsi: Migrate to drm_dsc_compute_rc_parameters()
      drm/msm/dsi: Account for DSC's bits_per_pixel having 4 fractional bits
      drm/msm/dsi: Disallow 8 BPC DSC configuration for alternative BPC values
      drm/msm/dsi: Prevent signed BPG offsets from bleeding into adjacent bits
      arm64: dts: qcom: sm6350: Add apps_smmu with streamID to SDHCI 1/2 nodes

Mark Rutland (2):
      arm64: mm: kfence: only handle translation faults
      arm64: make is_ttbrX_addr() noinstr-safe

Mark Zhang (4):
      RDMA/restrack: Release MR restrack when delete
      RDMA/core: Make sure "ib_port" is valid when access sysfs node
      RDMA/nldev: Return "-EAGAIN" if the cm_id isn't from expected port
      RDMA/nldev: Fix failure to send large messages

Markus Schneider-Pargmann (2):
      can: tcan4x5x: Remove invalid write in clear_interrupts
      can: tcan4x5x: Fix use of register error status mask

Martin Blumenstingl (2):
      hwmon: (jc42) Convert register access and caching to regmap/regcache
      hwmon: (jc42) Restore the min/max/critical temperatures on resume

Martin KaFai Lau (1):
      selftests/bpf: Fix incorrect ASSERT in the tcp_hdr_options test

Martin Leung (1):
      drm/amd/display: revert Disable DRR actions during state commit

Martin Povišer (1):
      dmaengine: apple-admac: Allocate cache SRAM to channels

Mateusz Jończyk (1):
      x86/apic: Handle no CONFIG_X86_X2APIC on systems with x2APIC enabled by BIOS

Mathias Nyman (1):
      xhci: Prevent infinite loop in transaction errors recovery for streams

Matt Johnston (1):
      mctp: Remove device type check at unregister

Matt Redfearn (1):
      include/uapi/linux/swab: Fix potentially missing __always_inline

Matti Vaittinen (1):
      mfd: bd957x: Fix Kconfig dependency on REGMAP_IRQ

Maurizio Lombardi (1):
      scsi: target: iscsi: Fix a race condition between login_work and the login thread

Maxim Korotkov (1):
      ethtool: avoiding integer overflow in ethtool_phys_id()

Mazin Al Haddad (1):
      media: dvb-usb: fix memory leak in dvb_usb_adapter_init()

Mia Kanashi (1):
      ACPI: EC: Add quirk for the HP Pavilion Gaming 15-cx0041ur

Miaoqian Lin (5):
      module: Fix NULL vs IS_ERR checking for module_get_next_page
      bpftool: Fix memory leak in do_build_table_cb
      cxl: Fix refcount leak in cxl_calc_capp_routing
      selftests/powerpc: Fix resource leaks
      usb: dwc3: qcom: Fix memory leak in dwc3_qcom_interconnect_init

Michael Kelley (1):
      tpm/tpm_crb: Fix error message in __crb_relinquish_locality()

Michael Petlan (1):
      perf test: Fix "all PMU test" to skip parametrized events

Michael Riesch (1):
      iommu/rockchip: fix permission bits in page table entries v2

Michael Walle (1):
      mtd: spi-nor: hide jedec_id sysfs attribute if not present

Mika Westerberg (1):
      watchdog: iTCO_wdt: Set NO_REBOOT if the watchdog is not already running

Mike Leach (1):
      coresight: cti: Fix null pointer error on CTI init before ETM

Mike McGowen (1):
      scsi: smartpqi: Add new controller PCI IDs

Milan Landaverde (1):
      bpf: prevent leak of lsm program after failed attach

Ming Qian (7):
      media: amphion: reset instance if it's aborted before codec header parsed
      media: amphion: add lock around vdec_g_fmt
      media: amphion: apply vb2_queue_error instead of setting manually
      media: amphion: try to wakeup vpu core to avoid failure
      media: amphion: cancel vpu before release instance
      media: amphion: lock and check m2m_ctx in event handler
      media: imx-jpeg: Disable useless interrupt to avoid kernel panic

Minsuk Kang (2):
      nfc: pn533: Clear nfc_target before being used
      wifi: brcmfmac: Fix potential shift-out-of-bounds in brcmf_fw_alloc_request()

Moudy Ho (3):
      media: platform: mtk-mdp3: fix error handling in mdp_cmdq_send()
      media: platform: mtk-mdp3: fix error handling about components clock_on
      media: platform: mtk-mdp3: fix error handling in mdp_probe()

Muhammad Husaini Zulkifli (1):
      igc: Add checking for basetime less than zero

Mukesh Ojha (1):
      f2fs: fix the assign logic of iocb

Mustafa Ismail (4):
      RDMA/irdma: Fix inline for multiple SGE's
      RDMA/irdma: Fix RQ completion opcode
      RDMA/irdma: Do not request 2-level PBLEs for CQ alloc
      RDMA/irdma: Initialize net_type before checking it

Namhyung Kim (4):
      perf stat: Use evsel__is_hybrid() more
      perf stat: Move common code in print_metric_headers()
      perf off_cpu: Fix a typo in BTF tracepoint name, it should be 'btf_trace_sched_switch'
      perf stat: Do not delay the workload with --delay

Natalia Petrova (1):
      crypto: nitrox - avoid double free on error path in nitrox_sriov_init()

Nathan Chancellor (13):
      drm/meson: Fix return type of meson_encoder_cvbs_mode_valid()
      net: ethernet: ti: Fix return type of netcp_ndo_start_xmit()
      hamradio: baycom_epp: Fix return type of baycom_send_packet()
      drm/amdgpu: Fix type of second parameter in trans_msg() callback
      drm/amdgpu: Fix type of second parameter in odn_edit_dpm_table() callback
      s390/ctcm: Fix return type of ctc{mp,}m_tx()
      s390/netiucv: Fix return type of netiucv_tx()
      s390/lcs: Fix return type of lcs_start_xmit()
      drm/mediatek: Fix return type of mtk_hdmi_bridge_mode_valid()
      scsi: elx: libefc: Fix second parameter type in state callbacks
      drm/fsl-dcu: Fix return type of fsl_dcu_drm_connector_mode_valid()
      drm/sti: Fix return type of sti_{dvo,hda,hdmi}_connector_mode_valid()
      security: Restrict CONFIG_ZERO_CALL_USED_REGS to gcc or clang > 15.0.6

Nathan Lynch (1):
      powerpc/pseries/eeh: use correct API for error log size

Nayna Jain (4):
      powerpc/pseries: fix the object owners enum value in plpks driver
      powerpc/pseries: Fix the H_CALL error code in PLPKS driver
      powerpc/pseries: Return -EIO instead of -EINTR for H_ABORTED error
      powerpc/pseries: fix plpks_read_var() code for different consumers

Nicholas Piggin (1):
      powerpc/perf: callchain validate kernel stack pointer bounds

Nicolas Cavallari (1):
      wifi: mt76: mt7915: Fix chainmask calculation on mt7915 DBDC

Niklas Cassel (1):
      ata: libata: fix NCQ autosense logic

Niklas Schnelle (1):
      iommu/s390: Fix duplicate domain attachments

Niklas Söderlund (1):
      media: adv748x: afe: Select input port when initializing AFE

Nirmal Patel (1):
      PCI: vmd: Disable MSI remapping after suspend

Nirmoy Das (1):
      drm/i915: Refactor ttm ghost obj detection

Nuno Sá (1):
      iio: adc: ad_sigma_delta: do not use internal iio_dev lock

Nícolas F. R. A. Prado (1):
      ASoC: dt-bindings: rt5682: Set sound-dai-cells to 1

Oleg Nesterov (1):
      uprobes/x86: Allow to probe a NOP instruction with 0x66 prefix

Ondrej Mosnacek (1):
      fs: don't audit the capability check in simple_xattr_list()

Padmanabhan Rajanbabu (2):
      arm64: dts: fsd: fix drive strength macros as per FSD HW UM
      arm64: dts: fsd: fix drive strength values as per FSD HW UM

Pali Rohár (11):
      ARM: dts: dove: Fix assigned-addresses for every PCIe Root Port
      ARM: dts: armada-370: Fix assigned-addresses for every PCIe Root Port
      ARM: dts: armada-xp: Fix assigned-addresses for every PCIe Root Port
      ARM: dts: armada-375: Fix assigned-addresses for every PCIe Root Port
      ARM: dts: armada-38x: Fix assigned-addresses for every PCIe Root Port
      ARM: dts: armada-39x: Fix assigned-addresses for every PCIe Root Port
      ARM: dts: turris-omnia: Add ethernet aliases
      ARM: dts: turris-omnia: Add switch port 6 node
      arm64: dts: armada-3720-turris-mox: Add missing interrupt for RTC
      phy: marvell: phy-mvebu-a3700-comphy: Reset COMPHY registers before USB 3.0 power on
      powerpc: dts: turris1x.dts: Add channel labels for temperature sensor

Palmer Dabbelt (1):
      RISC-V: Align the shadow stack

Paul Kocialkowski (4):
      media: sun6i-mipi-csi2: Require both pads to be connected for streaming
      media: sun8i-a83t-mipi-csi2: Require both pads to be connected for streaming
      media: sun6i-mipi-csi2: Register async subdev with no sensor attached
      media: sun8i-a83t-mipi-csi2: Register async subdev with no sensor attached

Paulo Alcantara (1):
      cifs: don't leak -ENOMEM in smb2_open_file()

Pavel Begunkov (6):
      io_uring: add completion locking for iopoll
      io_uring: dont remove file from msg_ring reqs
      io_uring: improve io_double_lock_ctx fail handling
      io_uring/net: fix cleanup after recycle
      io_uring: protect cq_timeouts with timeout_lock
      io_uring: remove iopoll spinlock

Pawel Laszczak (1):
      usb: cdnsp: fix lack of ZLP for ep0

Peng Fan (2):
      clk: imx93: unmap anatop base in error handling path
      clk: imx93: correct enet clock

Pengcheng Yang (3):
      bpf, sockmap: Fix repeated calls to sock_put() when msg has more_data
      bpf, sockmap: Fix missing BPF_F_INGRESS flag when using apply_bytes
      bpf, sockmap: Fix data loss caused by using apply_bytes on ingress redirect

Phil Auld (1):
      cpu/hotplug: Make target_store() a nop when target == state

Piergiorgio Beruto (1):
      stmmac: fix potential division by 0

Pin-yen Lin (1):
      drm/bridge: it6505: Initialize AUX channel in it6505_i2c_probe

Ping-Ke Shih (1):
      wifi: rtw89: use u32_encode_bits() to fill MAC quota value

Prathamesh Shete (1):
      mmc: sdhci-tegra: Issue CMD and DAT resets together

Pu Lehui (1):
      riscv, bpf: Emit fixed-length instructions for BPF_PSEUDO_FUNC

Qais Yousef (7):
      sched/uclamp: Fix relationship between uclamp and migration margin
      sched/uclamp: Make task_fits_capacity() use util_fits_cpu()
      sched/uclamp: Fix fits_capacity() check in feec()
      sched/uclamp: Make select_idle_capacity() use util_fits_cpu()
      sched/uclamp: Make asym_fits_capacity() use util_fits_cpu()
      sched/uclamp: Make cpu_overutilized() use util_fits_cpu()
      sched/uclamp: Cater for uclamp in find_energy_efficient_cpu()'s early exit condition

Qiheng Lin (1):
      power: supply: Fix refcount leak in rk817_charger_probe

Qingfang DENG (1):
      netfilter: flowtable: really fix NAT IPv6 offload

Rafael J. Wysocki (7):
      PM: runtime: Do not call __rpm_callback() from rpm_idle()
      rtc: cmos: Call cmos_wake_setup() from cmos_do_probe()
      rtc: cmos: Call rtc_wake_setup() from cmos_do_probe()
      rtc: cmos: Eliminate forward declarations of some functions
      rtc: cmos: Rename ACPI-related functions
      rtc: cmos: Disable ACPI RTC event on removal
      ACPICA: Fix error code path in acpi_ds_call_control_method()

Rafael Mendonca (6):
      drm/amdgpu/powerplay/psm: Fix memory leak in power state init
      media: i2c: hi846: Fix memory leak in hi846_parse_dt()
      media: i2c: ov5648: Free V4L2 fwnode data on unbind
      vfio: platform: Do not pass return buffer to ACPI _RST method
      uio: uio_dmem_genirq: Fix missing unlock in irq configuration
      uio: uio_dmem_genirq: Fix deadlock between irq config and handling

Rahul Bhattacharjee (1):
      wifi: ath11k: Fix qmi_msg_handler data structure initialization

Ramona Bolboaca (1):
      iio: adis: add '__adis_enable_irq()' implementation

Randy Dunlap (6):
      Input: joystick - fix Kconfig warning for JOYSTICK_ADC
      ASoC: codecs: wsa883x: use correct header file
      Input: wistron_btns - disable on UML
      RDMA: Disable IB HW for UML
      fbdev: geode: don't build on UML
      fbdev: uvesafb: don't build on UML

Rasmus Villemoes (2):
      iio: adc128s052: add proper .data members in adc128_of_match table
      iio: addac: ad74413r: fix integer promotion bug in ad74413_get_input_current_offset()

Reinette Chatre (1):
      x86/sgx: Reduce delay and interference of enclave release

Ricardo Ribalda (2):
      media: i2c: ad5820: Fix error path
      ASoC: mediatek: mt8173: Enable IRQ when pdata is ready

Richard Gobert (1):
      net: setsockopt: fix IPV6_UNICAST_IF option for connected sockets

Rickard x Andersson (1):
      gcov: add support for checksum field

Rob Clark (1):
      drm/msm/a6xx: Fix speed-bin detection vs probe-defer

Robert Elliott (1):
      crypto: tcrypt - fix return value for multiple subtests

Roberto Sassu (1):
      reiserfs: Add missing calls to reiserfs_security_free()

Robin Murphy (1):
      iommu: Avoid races around device probe

Roger Quadros (1):
      net: ethernet: ti: am65-cpsw: Fix PM runtime leakage in am65_cpsw_nuss_ndo_slave_open()

Rui Zhang (1):
      regulator: core: fix use_count leakage when handling boot-on

Ryder Lee (1):
      wifi: mt76: mt7915: fix mt7915_mac_set_timing()

Ryusuke Konishi (2):
      nilfs2: fix shift-out-of-bounds/overflow in nilfs_sb2_bad_offset()
      nilfs2: fix shift-out-of-bounds due to too large exponent of block size

Sagi Grimberg (1):
      nvme-auth: don't override ctrl keys before validation

Sakari Ailus (1):
      dw9768: Enable low-power probe on ACPI

Sam Shih (1):
      pinctrl: mediatek: fix the pinconf register offset of some pins

Sami Tolvanen (1):
      cfi: Fix CFI failure with KASAN

Samuel Holland (2):
      riscv: Fix crash during early errata patching
      mfd: axp20x: Do not sleep in the power off handler

Sascha Hauer (1):
      PCI: imx6: Initialize PHY before deasserting core reset

Schspa Shi (2):
      mrp: introduce active flags to prevent UAF when applicant uninit
      9p: set req refcount to zero to avoid uninitialized usage

Sean Wang (1):
      wifi: mt76: mt7921: fix antenna signal are way off in monitor mode

Sebastian Andrzej Siewior (6):
      Revert "net: hsr: use hlist_head instead of list_head for mac addresses"
      hsr: Add a rcu-read lock to hsr_forward_skb().
      hsr: Avoid double remove of a node.
      hsr: Disable netpoll.
      hsr: Synchronize sending frames to have always incremented outgoing seq nr.
      hsr: Synchronize sequence number updates.

Serge Semin (2):
      dt-bindings: imx6q-pcie: Fix clock names for imx6sx and imx8mq
      dt-bindings: visconti-pcie: Fix interrupts array max constraints

Sergio Paracuellos (1):
      MIPS: ralink: mt7621: avoid to init common ralink reset controller

Shang XiaoJing (13):
      perf/arm_dmc620: Fix hotplug callback leak in dmc620_pmu_init()
      perf/smmuv3: Fix hotplug callback leak in arm_smmu_pmu_init()
      ocfs2: fix memory leak in ocfs2_stack_glue_init()
      irqchip: gic-pm: Use pm_runtime_resume_and_get() in gic_probe()
      mtd: core: Fix refcount error in del_mtd_device()
      scsi: ipr: Fix WARNING in ipr_init()
      crypto: omap-sham - Use pm_runtime_resume_and_get() in omap_sham_probe()
      samples: vfio-mdev: Fix missing pci_disable_device() in mdpy_fb_probe()
      fbdev: via: Fix error in via_core_init()
      power: supply: cw2015: Fix potential null-ptr-deref in cw_bat_probe()
      rtc: class: Fix potential memleak in devm_rtc_allocate_device()
      remoteproc: qcom: q6v5: Fix potential null-ptr-deref in q6v5_wcss_init_mmio()
      remoteproc: qcom: q6v5: Fix missing clk_disable_unprepare() in q6v5_wcss_qcs404_power_on()

Shayne Chen (1):
      wifi: mt76: mt7915: rework eeprom tx paths and streams init

Sheng Yong (2):
      f2fs: set zstd compress level correctly
      f2fs: fix to enable compress for newly created file if extension matches

Shengjiu Wang (1):
      remoteproc: core: Auto select rproc-virtio device id

Shigeru Yoshida (4):
      fs/ntfs3: Avoid UBSAN error on true_sectors_per_clst()
      udf: Avoid double brelse() in udf_rename()
      wifi: ar5523: Fix use-after-free on ar5523_cmd() timed out
      media: si470x: Fix use-after-free in si470x_int_in_callback()

Shiraz Saleem (1):
      RDMA/irdma: Report the correct link speed

Shung-Hsi Yu (3):
      libbpf: Use elf_getshdrnum() instead of e_shnum
      libbpf: Deal with section with no data gracefully
      libbpf: Fix null-pointer dereference in find_prog_by_sec_insn()

Sibi Sankar (1):
      arm64: dts: qcom: sc7280: Mark all Qualcomm reference boards as LTE

Song Liu (1):
      selftests/bpf: Select CONFIG_FUNCTION_ERROR_INJECTION

Srinivas Kandagatla (1):
      ASoC: qcom: cleanup and fix dependency of QCOM_COMMON

Stanislav Fomichev (6):
      bpf: Move skb->len == 0 checks into __bpf_redirect
      selftests/bpf: Make sure zero-len skbs aren't redirectable
      selftests/bpf: Mount debugfs in setns_by_fd
      bpf: make sure skb->len != 0 when redirecting to a tunneling device
      ppp: associate skb with a device at tx
      bpf: Prevent decl_tag from being referenced in func_proto arg

Stefan Eichenberger (1):
      rtc: snvs: Allow a time difference on clock register read

Stefan Metzmacher (1):
      io_uring/net: introduce IORING_SEND_ZC_REPORT_USAGE flag

Stephan Gerhold (1):
      arm64: dts: qcom: msm8916: Drop MSS fallback compatible

Stephen Boyd (1):
      pstore: Avoid kcore oops by vmap()ing with VM_IOREMAP

Steven Price (1):
      pwm: tegra: Fix 32 bit build

Subash Abhinov Kasiviswanathan (1):
      skbuff: Account for tail adjustment during pull operations

Sumit Gupta (4):
      soc/tegra: cbb: Use correct master_id mask for CBB NOC in Tegra194
      soc/tegra: cbb: Update slave maps for Tegra234
      soc/tegra: cbb: Add checks for potential out of bound errors
      soc/tegra: cbb: Check firewall before enabling error reporting

Sven Peter (9):
      soc: apple: sart: Stop casting function pointer signatures
      soc: apple: rtkit: Stop casting function pointer signatures
      usb: typec: Check for ops->exit instead of ops->enter in altmode_exit
      usb: typec: tipd: Cleanup resources if devm_tps6598_psy_register fails
      usb: typec: tipd: Fix spurious fwnode_handle_put in error path
      usb: typec: tipd: Fix typec_unregister_port error paths
      Bluetooth: Add quirk to disable extended scanning
      Bluetooth: Add quirk to disable MWS Transport Configuration
      usb: dwc3: Fix race between dwc3_set_mode and __dwc3_set_mode

Takashi Iwai (3):
      ALSA: memalloc: Allocate more contiguous pages for fallback case
      ALSA: pcm: Set missing stop_operating flag at undoing trigger start
      ALSA: usb-audio: Workaround for XRUN at prepare

Tan Tee Min (3):
      igc: allow BaseTime 0 enrollment for Qbv
      igc: recalculate Qbv end_time by considering cycle time
      igc: Set Qbv start_time and end_time to end_time if not being configured in GCL

Tang Bin (1):
      venus: pm_helpers: Fix error check in vcodec_domains_get()

Tejun Heo (1):
      blk-iolatency: Fix memory leak on add_disk() failures

Tetsuo Handa (1):
      fbdev: fbcon: release buffer when fbcon_do_set_font() failed

Thomas Zimmermann (1):
      drm/atomic-helper: Don't allocate new plane state in CRTC check

Tianjia Zhang (1):
      crypto: arm64/sm3 - add NEON assembly implementation

Toke Høiland-Jørgensen (1):
      bpf: Add dummy type reference to nf_conn___init to fix type deduplication

Tom Lendacky (2):
      net: amd-xgbe: Fix logic around active and passive cables
      net: amd-xgbe: Check only the minimum speed for active/passive cables

Tong Tiangen (1):
      riscv/mm: add arch hook arch_clear_hugepage_flags

Tony Lindgren (2):
      clocksource/drivers/timer-ti-dm: Fix warning for omap_timer_match
      usb: musb: omap2430: Fix probe regression for missing resources

Trond Myklebust (9):
      lockd: set other missing fields when unlocking files
      NFSv4.2: Clear FATTR4_WORD2_SECURITY_LABEL when done decoding
      NFSv4.2: Always decode the security label
      NFSv4.2: Fix a memory stomp in decode_attr_security_label
      NFSv4.2: Fix initialisation of struct nfs4_label
      NFSv4: Fix a credential leak in _nfs4_discover_trunking()
      NFSv4: Fix a deadlock between nfs4_open_recover_helper() and delegreturn
      NFS: Fix an Oops in nfs_d_automount()
      NFSv4.x: Fail client initialisation if state manager thread can't run

Tvrtko Ursulin (1):
      drm/i915: Handle all GTs on driver (un)load paths

Ulf Hansson (1):
      cpuidle: dt: Return the correct numbers of parsed idle states

Uwe Kleine-König (4):
      crypto: ccree - Make cc_debugfs_global_fini() available for module init function
      power: supply: bq25890: Convert to i2c's .probe_new()
      rtc: pcf2127: Convert to .probe_new()
      pwm: sifive: Call pwm_sifive_update_clock() while mutex is held

Valentin Caron (1):
      serial: stm32: move dma_request_chan() before clk_prepare_enable()

Veerabadhran Gopalakrishnan (1):
      amdgpu/nv.c: Corrected typo in the video capabilities resolution

Victor Ding (1):
      platform/chrome: cros_ec_typec: zero out stale pointers

Vidya Sagar (3):
      arm64: tegra: Fix Prefetchable aperture ranges of Tegra234 PCIe controllers
      arm64: tegra: Fix non-prefetchable aperture of PCIe C3 controller
      PCI: dwc: Fix n_fts[] array overrun

Ville Syrjälä (3):
      drm/msm: Use drm_mode_copy()
      drm/rockchip: Use drm_mode_copy()
      drm/sti: Use drm_mode_copy()

Vincent Donnefort (1):
      cpu/hotplug: Do not bail-out in DYING/STARTING sections

Vinicius Costa Gomes (2):
      igc: Enhance Qbv scheduling by using first flag bit
      igc: Use strict cycles for Qbv scheduling

Vivek Yadav (1):
      can: m_can: Call the RAM init directly from m_can_chip_config

Vladimir Oltean (3):
      net: dsa: tag_8021q: avoid leaking ctx on dsa_tag_8021q_register() error path
      net: enetc: avoid buffer leaks on xdp_do_redirect() failure
      net: dsa: mv88e6xxx: avoid reg_lock deadlock in mv88e6xxx_setup_port()

Vladimir Zapolskiy (2):
      media: camss: Clean up received buffers on failed start of streaming
      media: camss: Do not attach an already attached power domain on MSM8916 platform

Wang Jingjin (2):
      ASoC: rockchip: pdm: Add missing clk_disable_unprepare() in rockchip_pdm_runtime_resume()
      ASoC: rockchip: spdif: Add missing clk_disable_unprepare() in rk_spdif_runtime_resume()

Wang ShaoBo (7):
      ACPI: pfr_telemetry: use ACPI_FREE() to free acpi_object
      ACPI: pfr_update: use ACPI_FREE() to free acpi_object
      regulator: core: use kfree_const() to free space conditionally
      drbd: remove call to memset before free device/resource/connection
      drbd: destroy workqueue when drbd device was freed
      SUNRPC: Fix missing release socket in rpc_sockname()
      Bluetooth: btintel: Fix missing free skb in btintel_setup_combined()

Wang Weiyang (1):
      rapidio: fix possible UAF when kfifo_alloc() fails

Wang Yufen (10):
      pstore/ram: Fix error return code in ramoops_probe()
      selftests/bpf: fix missing BPF object files
      selftests/bpf: fix memory leak of lsm_cgroup
      wifi: brcmfmac: Fix error return code in brcmf_sdio_download_firmware()
      crypto: qat - fix error return code in adf_probe
      RDMA/hfi1: Fix error return code in parse_platform_config()
      RDMA/srp: Fix error return code in srp_parse_options()
      ASoC: mediatek: mt8173-rt5650-rt5514: fix refcount leak in mt8173_rt5650_rt5514_dev_probe()
      ASoC: audio-graph-card: fix refcount leak of cpu_ep in __graph_for_each_link()
      ASoC: mediatek: mt8183: fix refcount leak in mt8183_mt6358_ts3a227_max98357_dev_probe()

Wei Fang (1):
      net: fec: check the return value of build_skb()

Wei Yongjun (1):
      irqchip/wpcm450: Fix memory leak in wpcm450_aic_of_init()

Weili Qian (3):
      crypto: hisilicon/qm - fix incorrect parameters usage
      crypto: hisilicon/qm - re-enable communicate interrupt before notifying PF
      crypto: hisilicon/qm - fix 'QM_XEQ_DEPTH_CAP' mask value

Wesley Chalmers (2):
      drm/amd/display: Disable DRR actions during state commit
      drm/amd/display: Use the largest vready_offset in pipe group

Wolfram Sang (9):
      arm64: dts: renesas: r8a779f0: Fix HSCIF "brg_int" clock
      arm64: dts: renesas: r8a779f0: Fix SCIF "brg_int" clock
      clocksource/drivers/sh_cmt: Access registers according to spec
      clk: renesas: r8a779a0: Fix SD0H clock name
      clk: renesas: r8a779f0: Fix HSCIF parent clocks
      clk: renesas: r8a779f0: Fix SCIF parent clocks
      mmc: renesas_sdhi: alway populate SCC pointer
      mmc: renesas_sdhi: add quirk for broken register layout
      mmc: renesas_sdhi: better reset from HS400 mode

Wright Feng (1):
      brcmfmac: return error when getting invalid max_flowrings from dongle

Xia Fukun (1):
      drm/i915/bios: fix a memory leak in generate_lfp_data_ptrs

Xiao Ni (1):
      md/raid0, raid10: Don't set discard sectors for request queue

Xiaochen Shen (2):
      dmaengine: idxd: Make max batch size attributes in sysfs invisible for Intel IAA
      dmaengine: idxd: Make read buffer sysfs attributes invisible for Intel IAA

Xie Shaowen (1):
      macintosh/macio-adb: check the return value of ioremap()

Xingjiang Qiao (2):
      hwmon: (emc2305) fix unable to probe emc2301/2/3
      hwmon: (emc2305) fix pwm never being able to set lower

Xinlei Lee (1):
      drm/mediatek: Modify dpi power on/off sequence.

Xiongfeng Wang (15):
      ACPI: irq: Fix some kernel-doc issues
      perf/x86/intel/uncore: Fix reference count leak in sad_cfg_iio_topology()
      perf/x86/intel/uncore: Fix reference count leak in hswep_has_limit_sbox()
      perf/x86/intel/uncore: Fix reference count leak in snr_uncore_mmio_map()
      perf/x86/intel/uncore: Fix reference count leak in __uncore_imc_init_box()
      cpufreq: amd_freq_sensitivity: Add missing pci_dev_put()
      drm/radeon: Fix PCI device refcount leak in radeon_atrm_get_bios()
      drm/amdgpu: Fix PCI device refcount leak in amdgpu_atrm_get_bios()
      mt76: mt7915: Fix PCI device refcount leak in mt7915_pci_init_hif2()
      crypto: hisilicon/qm - add missing pci_dev_put() in q_num_set()
      RDMA/hfi: Decrease PCI device reference count in error path
      hwrng: amd - Fix PCI device refcount leak
      hwrng: geode - Fix PCI device refcount leak
      serial: pch: Fix PCI device refcount leak in pch_request_dma()
      fbdev: vermilion: decrease reference count in error path

Xiu Jianfeng (12):
      x86/xen: Fix memory leak in xen_smp_intr_init{_pv}()
      x86/xen: Fix memory leak in xen_init_lock_cpu()
      ima: Fix misuse of dereference of pointer in template_desc_init_fields()
      wifi: ath10k: Fix return value in ath10k_pci_init()
      clk: rockchip: Fix memory leak in rockchip_clk_register_pll()
      clk: visconti: Fix memory leak in visconti_register_pll()
      clk: samsung: Fix memory leak in _samsung_clk_register_pll()
      clk: socfpga: Fix memory leak in socfpga_gate_init()
      apparmor: Use pointer to struct aa_label for lbs_cred
      apparmor: Fix memleak in alloc_ns()
      ksmbd: Fix resource leak in ksmbd_session_rpc_open()
      clk: st: Fix memory leak in st_of_quadfs_setup()

Xu Kuohai (6):
      libbpf: Fix use-after-free in btf_dump_name_dups
      libbpf: Fix memory leak in parse_usdt_arg()
      selftests/bpf: Fix memory leak caused by not destroying skeleton
      selftest/bpf: Fix memory leak in kprobe_multi_test
      selftests/bpf: Fix error failure of case test_xdp_adjust_tail_grow
      selftest/bpf: Fix error usage of ASSERT_OK in xdp_adjust_tail.c

YN Chen (1):
      wifi: mt76: mt7921: fix wrong power after multiple SAR set

Yan Lei (1):
      media: dvb-frontends: fix leak of memory fw

Yang Jihong (4):
      selftests/bpf: Fix xdp_synproxy compilation failure in 32-bit arch
      blktrace: Fix output non-blktrace event when blk_classic option enabled
      perf debug: Set debug_peo_args and redirect_to_stderr variable to correct values in perf_quiet_option()
      perf probe: Check -v and -q options in the right place

Yang Shen (1):
      coresight: trbe: remove cpuhp instance node before remove cpuhp state

Yang Yingliang (87):
      soc: sifive: ccache: fix missing iounmap() in error path in sifive_ccache_init()
      soc: sifive: ccache: fix missing free_irq() in error path in sifive_ccache_init()
      soc: sifive: ccache: fix missing of_node_put() in sifive_ccache_init()
      MIPS: vpe-mt: fix possible memory leak while module exiting
      MIPS: vpe-cmp: fix possible memory leak while module exiting
      PNP: fix name memory leak in pnp_alloc_dev()
      thermal: core: fix some possible name leaks in error paths
      EDAC/i10nm: fix refcount leak in pci_get_dev_wrapper()
      genirq/irqdesc: Don't try to remove non-existing sysfs files
      rapidio: fix possible name leaks when rio_add_device() fails
      rapidio: rio: fix possible name leak in rio_register_mport()
      clocksource/drivers/timer-ti-dm: Fix missing clk_disable_unprepare in dmtimer_systimer_init_clock()
      platform/x86: intel_scu_ipc: fix possible name leak in __intel_scu_ipc_register()
      pinctrl: ocelot: add missing destroy_workqueue() in error path in ocelot_pinctrl_probe()
      media: platform: exynos4-is: fix return value check in fimc_md_probe()
      regulator: core: fix unbalanced of node refcount in regulator_dev_lookup()
      media: solo6x10: fix possible memory leak in solo_sysfs_init()
      drm/amdgpu: fix pci device refcount leak
      regulator: core: fix module refcount leak in set_supply()
      regulator: core: fix resource leak in regulator_register()
      mmc: alcor: fix return value check of mmc_add_host()
      mmc: moxart: fix return value check of mmc_add_host()
      mmc: mxcmmc: fix return value check of mmc_add_host()
      mmc: pxamci: fix return value check of mmc_add_host()
      mmc: rtsx_pci: fix return value check of mmc_add_host()
      mmc: rtsx_usb_sdmmc: fix return value check of mmc_add_host()
      mmc: toshsd: fix return value check of mmc_add_host()
      mmc: vub300: fix return value check of mmc_add_host()
      mmc: wmt-sdmmc: fix return value check of mmc_add_host()
      mmc: atmel-mci: fix return value check of mmc_add_host()
      mmc: omap_hsmmc: fix return value check of mmc_add_host()
      mmc: meson-gx: fix return value check of mmc_add_host()
      mmc: via-sdmmc: fix return value check of mmc_add_host()
      mmc: wbsd: fix return value check of mmc_add_host()
      mmc: mmci: fix return value check of mmc_add_host()
      ethernet: s2io: don't call dev_kfree_skb() under spin_lock_irqsave()
      net: apple: mace: don't call dev_kfree_skb() under spin_lock_irqsave()
      net: apple: bmac: don't call dev_kfree_skb() under spin_lock_irqsave()
      net: emaclite: don't call dev_kfree_skb() under spin_lock_irqsave()
      net: ethernet: dnet: don't call dev_kfree_skb() under spin_lock_irqsave()
      hamradio: don't call dev_kfree_skb() under spin_lock_irqsave()
      net: amd: lance: don't call dev_kfree_skb() under spin_lock_irqsave()
      af_unix: call proto_unregister() in the error path in af_unix_init()
      Bluetooth: hci_core: fix error handling in hci_register_dev()
      Bluetooth: btusb: don't call kfree_skb() under spin_lock_irqsave()
      Bluetooth: hci_qca: don't call kfree_skb() under spin_lock_irqsave()
      Bluetooth: hci_ll: don't call kfree_skb() under spin_lock_irqsave()
      Bluetooth: hci_h5: don't call kfree_skb() under spin_lock_irqsave()
      Bluetooth: hci_bcsp: don't call kfree_skb() under spin_lock_irqsave()
      Bluetooth: hci_core: don't call kfree_skb() under spin_lock_irqsave()
      Bluetooth: RFCOMM: don't call kfree_skb() under spin_lock_irqsave()
      scsi: mpt3sas: Fix possible resource leaks in mpt3sas_transport_port_add()
      scsi: hpsa: Fix error handling in hpsa_add_sas_host()
      scsi: hpsa: Fix possible memory leak in hpsa_add_sas_device()
      scsi: fcoe: Fix possible name leak when device_register() fails
      scsi: scsi_debug: Fix possible name leak in sdebug_add_host_helper()
      drivers: dio: fix possible memory leak in dio_init()
      class: fix possible memory leak in __class_register()
      usb: typec: tcpci: fix of node refcount leak in tcpci_register_port()
      habanalabs: fix return value check in hl_fw_get_sec_attest_data()
      misc: ocxl: fix possible name leak in ocxl_file_register_afu()
      ocxl: fix pci device refcount leak when calling get_function_0()
      firmware: raspberrypi: fix possible memory leak in rpi_firmware_probe()
      cxl: fix possible null-ptr-deref in cxl_guest_init_afu|adapter()
      cxl: fix possible null-ptr-deref in cxl_pci_init_afu|adapter()
      usb: roles: fix of node refcount leak in usb_role_switch_is_parent()
      usb: core: hcd: Fix return value check in usb_hcd_setup_local_mem()
      mcb: mcb-parse: fix error handing in chameleon_parse_gdd()
      chardev: fix error handling in cdev_device_add()
      i2c: mux: reg: check return value after calling platform_get_resource()
      usb: typec: wusb3801: fix fwnode refcount leak in wusb3801_probe()
      fbdev: pm2fb: fix missing pci_disable_device()
      HSI: omap_ssi_core: fix unbalanced pm_runtime_disable()
      HSI: omap_ssi_core: fix possible memory leak in ssi_probe()
      iommu/mediatek: Check return value after calling platform_get_resource()
      iommu/amd: Fix pci device refcount leak in ppr_notifier()
      macintosh: fix possible memory leak in macio_add_one_device()
      powerpc/xive: add missing iounmap() in error path in xive_spapr_populate_irq_data()
      powerpc/83xx/mpc832x_rdb: call platform_device_put() in error case in of_fsl_spi_probe()
      mfd: pm8008: Fix return value check in pm8008_probe()
      mISDN: hfcsusb: don't call dev_kfree_skb/kfree_skb() under spin_lock_irqsave()
      mISDN: hfcpci: don't call dev_kfree_skb/kfree_skb() under spin_lock_irqsave()
      mISDN: hfcmulti: don't call dev_kfree_skb/kfree_skb() under spin_lock_irqsave()
      mailbox: arm_mhuv2: Fix return value check in mhuv2_probe()
      mailbox: zynq-ipi: fix error handling while device_register() fails
      hwmon: (jc42) Fix missing unlock on error in jc42_write()
      ASoC: sof_es8336: fix possible use-after-free in sof_es8336_remove()

Yangtao Li (2):
      f2fs: fix gc mode when gc_urgent_high_remaining is 1
      f2fs: fix iostat parameter for discard

Yassine Oudjana (2):
      arm64: dts: qcom: msm8996: Add MSM8996 Pro support
      regmap-irq: Use the new num_config_regs property in regmap_add_irq_chip_fwnode

Ye Bin (1):
      blk-mq: fix possible memleak when register 'hctx' failed

Yicong Yang (1):
      drivers/perf: hisi: Fix some event id for hisi-pcie-pmu

Yipeng Zou (1):
      selftests/ftrace: event_triggers: wait longer for test_event_enable

Yixing Liu (1):
      RDMA/hns: Fix the gid problem caused by free mr

Yong Wu (3):
      iommu/mediatek: Add platform_device_put for recovering the device refcnt
      iommu/mediatek: Use component_match_add
      iommu/mediatek: Add error path for loop of mm_dts_parse

Yonggil Song (1):
      f2fs: avoid victim selection from previous victim section

Yonghong Song (1):
      bpf: Fix a BTF_ID_LIST bug with CONFIG_DEBUG_INFO_BTF not set

Yongqiang Liu (1):
      net: defxx: Fix missing err handling in dfx_init()

Youghandhar Chintala (1):
      wifi: ath10k: Delay the unmapping of the buffer

Yu Kuai (2):
      dm: make sure create and remove dm device won't race with open and close table
      block, bfq: fix possible uaf for 'bfqq->bic'

Yu Liao (1):
      platform/x86: mxm-wmi: fix memleak in mxm_wmi_call_mx[ds|mx]()

Yuan Can (20):
      perf: arm_dsu: Fix hotplug callback leak in dsu_pmu_init()
      drivers: perf: marvell_cn10k: Fix hotplug callback leak in tad_pmu_init()
      tpm/tpm_ftpm_tee: Fix error handling in ftpm_mod_init()
      platform/chrome: cros_usbpd_notify: Fix error handling in cros_usbpd_notify_init()
      media: platform: exynos4-is: Fix error handling in fimc_md_init()
      media: amphion: Fix error handling in vpu_driver_init()
      ASoC: qcom: Add checks for devm_kcalloc
      wifi: nl80211: Add checks for nla_nest_start() in nl80211_send_iface()
      regulator: qcom-labibb: Fix missing of_node_put() in qcom_labibb_regulator_probe()
      drivers: net: qlcnic: Fix potential memory leak in qlcnic_sriov_init()
      scsi: hpsa: Fix possible memory leak in hpsa_init_one()
      RDMA/nldev: Add checks for nla_nest_start() in fill_stat_counter_qps()
      serial: 8250_bcm7271: Fix error handling in brcmuart_init()
      serial: sunsab: Fix error handling in sunsab_init()
      HSI: omap_ssi_core: Fix error handling in ssi_init()
      power: supply: ab8500: Fix error handling in ab8500_charger_init()
      iommu/fsl_pamu: Fix resource leak in fsl_pamu_probe()
      remoteproc: qcom_q6v5_pas: Fix missing of_node_put() in adsp_alloc_memory_region()
      drm/rockchip: use pm_runtime_resume_and_get() instead of pm_runtime_get_sync()
      floppy: Fix memory leak in do_floppy_init()

YueHaibing (2):
      selftests: cgroup: fix unsigned comparison with less than zero
      staging: rtl8192e: Fix potential use-after-free in rtllib_rx_Monitor()

Yunfei Dong (6):
      media: mediatek: vcodec: fix h264 cavlc bitstream fail
      media: mediatek: vcodec: Fix getting NULL pointer for dst buffer
      media: mediatek: vcodec: Fix h264 set lat buffer error
      media: mediatek: vcodec: Setting lat buf to lat_list when lat decode error
      media: mediatek: vcodec: Core thread depends on core_list
      media: mediatek: vcodec: Can't set dst buffer to done when lat decode error

Yushan Zhou (1):
      rtc: rzn1: Check return value in rzn1_rtc_probe

Zeng Heng (4):
      ASoC: pxa: fix null-pointer dereference in filter()
      PCI: Check for alloc failure in pci_request_irq()
      power: supply: fix residue sysfs file in error handle route of __power_supply_register()
      iio: fix memory leak in iio_device_register_eventset()

Zhang Changzhong (1):
      net: stmmac: selftests: fix potential memleak in stmmac_test_arpoffload()

Zhang Qilong (7):
      soc: ti: knav_qmss_queue: Fix PM disable depth imbalance in knav_queue_probe
      soc: ti: smartreflex: Fix PM disable depth imbalance in omap_sr_probe
      eventfd: change int to __u64 in eventfd_signal() ifndef CONFIG_EVENTFD
      drm/rockchip: lvds: fix PM usage counter unbalance in poweron
      ASoC: pcm512x: Fix PM disable depth imbalance in pcm512x_probe
      f2fs: Fix the race condition of resize flag between resizefs
      power: supply: z2_battery: Fix possible memleak in z2_batt_probe()

Zhang Xiaoxu (7):
      mtd: Fix device name leak when register device failed in add_mtd_device()
      xprtrdma: Fix regbuf data not freed in rpcrdma_req_create()
      RDMA/rxe: Fix NULL-ptr-deref in rxe_qp_do_cleanup() when socket create failed
      orangefs: Fix sysfs not cleanup when dev init failed
      orangefs: Fix kmemleak in orangefs_prepare_debugfs_help_string()
      orangefs: Fix kmemleak in orangefs_sysfs_init()
      orangefs: Fix kmemleak in orangefs_{kernel,client}_debug_init()

Zhang Yiqun (1):
      crypto: tcrypt - Fix multibuffer skcipher speed test mem leak

Zhang Yuchen (1):
      ipmi: fix memleak when unload ipmi driver

Zhang Zekun (1):
      drm/tegra: Add missing clk_disable_unprepare() in tegra_dc_probe()

ZhangPeng (4):
      hfs: Fix OOB Write in hfs_asc2mac
      pinctrl: k210: call of_node_put()
      pinctrl: pinconf-generic: add missing of_node_put()
      hfs: fix OOB Read in __hfs_brec_find

Zhao Gongyi (1):
      selftests/efivarfs: Add checking of the test return value

Zhen Lei (1):
      mmc: core: Normalize the error handling branch in sd_read_ext_regs()

Zheng Wang (1):
      misc: sgi-gru: fix use-after-free error in gru_set_context_option, gru_fault and gru_handle_user_call_os

Zheng Yejian (2):
      tracing/hist: Fix issue of losting command info in error_log
      acct: fix potential integer overflow in encode_comp_t()

Zheng Yongjun (1):
      mtd: maps: pxa2xx-flash: fix memory leak in probe

Zhengchao Shao (5):
      ipc: fix memory leak in init_mqueue_fs()
      wifi: mac80211: fix memory leak in ieee80211_if_add()
      RDMA/hns: fix memory leak in hns_roce_alloc_mr()
      test_firmware: fix memory leak in test_firmware_init()
      drivers: mcb: fix resource leak in mcb_probe()

Zheyu Ma (1):
      i2c: ismt: Fix an out-of-bounds bug in ismt_access()

Zhiqi Song (1):
      crypto: hisilicon/hpre - fix resource leak in remove process

Ziyang Xuan (1):
      wifi: plfxlc: fix potential memory leak in __lf_x_usb_enable_rx()

Zong-Zhe Yang (1):
      wifi: rtw89: fix physts IE page check

Zqiang (1):
      rcu: Fix __this_cpu_read() lockdep warning in rcu_force_quiescent_state()

delisun (1):
      serial: pl011: Do not clear RX FIFO & RX interrupt in unthrottle.

gehao (1):
      drm/amd/display: prevent memory leak

ruanjinjie (3):
      of: overlay: fix null pointer dereferencing in find_dup_cset_node_entry() and find_dup_cset_prop()
      misc: tifm: fix possible memory leak in tifm_7xx1_switch_media()
      power: supply: fix null pointer dereferencing in power_supply_get_battery_info

wangdicheng (1):
      ALSA: usb-audio: add the quirk for KT0206 device

wuchi (1):
      lib/debugobjects: fix stat count and optimize debug_objects_mem_init

xinlei lee (1):
      pwm: mtk-disp: Fix the parameters calculated by the enabled flag of disp_pwm

xiongxin (1):
      PM: hibernate: Fix mistake in kerneldoc comment

zhikzhai (1):
      drm/amd/display: skip commit minimal transition state

Íñigo Huguet (1):
      wifi: mac80211: fix maybe-unused warning


^ permalink raw reply	[relevance 1%]

Results 1-77 of 77 | reverse | options above
-- pct% links below jump to the message on this page, permalinks otherwise --
2021-12-06 14:02     [PATCH 00/19] Rust support Miguel Ojeda
2021-12-06 14:03  1% ` [PATCH 09/19] rust: add `kernel` crate Miguel Ojeda
2021-12-06 14:03  3% ` [PATCH 16/19] samples: add Rust examples Miguel Ojeda
2022-01-17  5:33     [PATCH v3 00/19] Rust support Miguel Ojeda
2022-01-17  5:33  1% ` [PATCH v3 09/19] rust: add `kernel` crate Miguel Ojeda
2022-01-17  5:33  3% ` [PATCH v3 16/19] samples: add Rust examples Miguel Ojeda
2022-02-12 13:03     [PATCH v4 00/20] Rust support Miguel Ojeda
2022-02-12 13:03  1% ` [PATCH v4 10/20] rust: add `kernel` crate Miguel Ojeda
2022-02-12 13:03  3% ` [PATCH v4 17/20] samples: add Rust examples Miguel Ojeda
2022-03-17 18:09     [PATCH v5 00/20] Rust support Miguel Ojeda
2022-03-17 18:09  1% ` [PATCH v5 10/20] rust: add `kernel` crate Miguel Ojeda
2022-03-17 18:10  3% ` [PATCH v5 17/20] samples: add Rust examples Miguel Ojeda
2022-03-22 14:49 14% [PATCH bpf-next] bpf/bpftool: add unprivileged_bpf_disabled check against value of 2 Milan Landaverde
2022-03-22 15:54  6% ` Quentin Monnet
2022-03-22 17:39  0%   ` KP Singh
2022-03-29 23:49  4% pull-request: bpf 2022-03-29 Alexei Starovoitov
2022-03-31 15:45 13% [PATCH bpf-next 0/3] bpf/bpftool: add program & link type names Milan Landaverde
2022-03-31 15:45 14% ` [PATCH bpf-next 1/3] bpf/bpftool: add syscall prog type Milan Landaverde
2022-04-01 16:04  6%   ` Quentin Monnet
2022-04-01 18:40  0%     ` Andrii Nakryiko
2022-04-01 21:20  0%       ` Quentin Monnet
2022-03-31 15:45 14% ` [PATCH bpf-next 2/3] bpf/bpftool: add missing link types Milan Landaverde
2022-04-01 16:05  6%   ` Quentin Monnet
2022-04-04 21:55  0%     ` Andrii Nakryiko
2022-03-31 15:45 14% ` [PATCH bpf-next 3/3] bpf/bpftool: handle libbpf_probe_prog_type errors Milan Landaverde
2022-04-01 16:05  6%   ` Quentin Monnet
2022-04-01 18:42  0%     ` Andrii Nakryiko
2022-04-01 21:33  0%       ` Quentin Monnet
2022-04-03 23:51  0%         ` Andrii Nakryiko
2022-03-31 17:24  3% [GIT PULL] Networking for 5.18-rc1 Jakub Kicinski
2022-04-02  0:44  3% [linux-linus test] 169100: tolerable FAIL - PUSHED osstest service owner
2022-04-04 14:09  6% [PATCH bpf-next] selftests/bpf: Fix parsing of prog types in UAPI hdr for bpftool sync Quentin Monnet
2022-04-08 23:17  4% pull-request: bpf-next 2022-04-09 Daniel Borkmann
2022-04-28 11:08     [PATCH] bpftool: Use sysfs vmlinux when dumping BTF by ID Larysa Zaremba
2022-05-06  1:32  7% ` Milan Landaverde
2022-05-04 16:13 13% [PATCH bpf-next 0/2] bpftool: fix feature output when helper probes fail Milan Landaverde
2022-05-04 16:13 13% ` [PATCH bpf-next 1/2] bpftool: adjust for error codes from libbpf probes Milan Landaverde
2022-05-04 16:13 13% ` [PATCH bpf-next 2/2] bpftool: output message if no helpers found in feature probing Milan Landaverde
2022-05-05 10:15  6% ` [PATCH bpf-next 0/2] bpftool: fix feature output when helper probes fail Quentin Monnet
2022-05-07  5:23     [PATCH v6 00/23] Rust support Miguel Ojeda
2022-05-07  5:24  1% ` [PATCH v6 12/23] rust: add `kernel` crate Miguel Ojeda
2022-05-07  5:24  3% ` [PATCH v6 20/23] samples: add Rust examples Miguel Ojeda
2022-05-23  2:01     [PATCH v7 00/25] Rust support Miguel Ojeda
2022-05-23  2:01  1% ` [PATCH v7 12/25] rust: add `kernel` crate Miguel Ojeda
2022-05-23  2:01  3% ` [PATCH v7 22/25] samples: add Rust examples Miguel Ojeda
2022-05-23 22:38  2% pull-request: bpf-next 2022-05-23 Daniel Borkmann
2022-05-24 20:31  1% [GIT PULL] Networking for 5.19 Jakub Kicinski
2022-08-02  1:49     [PATCH v8 00/31] Rust support Miguel Ojeda
2022-08-02  1:50  1% ` [PATCH v8 17/31] rust: add `kernel` crate Miguel Ojeda
2022-08-02 13:34  0%   ` Greg Kroah-Hartman
2022-08-02  1:50  3% ` [PATCH v8 28/31] samples: add Rust examples Miguel Ojeda
2022-08-05 15:41     [PATCH v9 00/27] Rust support Miguel Ojeda
2022-08-05 15:41  4% ` [PATCH v9 12/27] rust: add `kernel` crate Miguel Ojeda
2022-08-05 15:42  6% ` [PATCH v9 26/27] samples: add first Rust examples Miguel Ojeda
2022-08-15 17:49  1% [PATCH 5.18 0000/1095] 5.18.18-rc1 review Greg Kroah-Hartman
2022-08-15 17:57  8% ` [PATCH 5.18 0453/1095] bpftool: Add missing link types Greg Kroah-Hartman
2022-08-16 12:59  1% [PATCH 5.18 0000/1094] 5.18.18-rc2 review Greg Kroah-Hartman
2022-08-17 13:24  1% Linux 5.18.18 Greg Kroah-Hartman
2022-09-27 13:14     [PATCH v10 00/27] Rust support Miguel Ojeda
2022-09-27 13:14  4% ` [PATCH v10 12/27] rust: add `kernel` crate Miguel Ojeda
2022-09-27 13:14  6% ` [PATCH v10 26/27] samples: add first Rust examples Miguel Ojeda
2022-09-27 15:25  0%   ` Greg Kroah-Hartman
2022-09-28 14:23  0%   ` Wei Liu
2022-10-01 15:58  3% [GIT PULL] Rust introduction for v6.1-rc1 Kees Cook
2022-10-04  8:06  3% [linux-linus test] 173411: tolerable FAIL - PUSHED osstest service owner
2022-11-10 16:41  4% [PATCH v1 00/28] Rust core additions Miguel Ojeda
2022-11-10 16:41  6% ` [PATCH v1 16/28] rust: str: add `CStr` type Miguel Ojeda
2022-11-10 16:41  8% ` [PATCH v1 18/28] rust: str: add `CStr` unit tests Miguel Ojeda
2022-12-02 16:14  3% [PATCH v2 00/28] Rust core additions ojeda
2022-12-02 16:14  6% ` [PATCH v2 16/28] rust: str: add `CStr` type ojeda
2022-12-02 16:14  8% ` [PATCH v2 18/28] rust: str: add `CStr` unit tests ojeda
2022-12-11  0:56  4% [GIT PULL] Rust for 6.2 ojeda
2022-12-13 17:57 13% [PATCH bpf-next] bpf: prevent leak of lsm program after failed attach Milan Landaverde
2022-12-13 18:43  6% ` Stanislav Fomichev
2022-12-16 17:45  7% pull-request: bpf 2022-12-16 Daniel Borkmann
2022-12-17  9:03  1% vmlinux.o: warning: objtool: _RINvNtCs3yuwAp0waWO_4core3ptr13drop_in_placeINtNtB4_6option6OptionNtCsdVu6umiBwhr_12rust_minimal11RustMinimalEEB14_+0x1b: relocation to !ENDBR: _RNvXsm_NtCsdvv6pRyacSq_5alloc3vecINtB5_3VeclENtNtCs3yuwAp0waWO_4core3fmt5Debug3f kernel test robot
2022-12-20 20:30  3% [PULL] Networking for v6.2-rc1 Jakub Kicinski
2022-12-21 13:27  1% vmlinux.o: warning: objtool: ___ksymtab_gpl+_RNvMs_NtCsfATHBUcknU9_6kernel3strNtB4_4CStr19from_bytes_with_nul+0x0: data relocation to !ENDBR: _RNvMs_NtCsfATHBUcknU9_6kernel3strNtB4_4CStr19from_bytes_with_nul+0x0 kernel test robot
2022-12-28 14:25  1% [PATCH 6.1 0000/1146] 6.1.2-rc1 review Greg Kroah-Hartman
2022-12-28 14:40  8% ` [PATCH 6.1 0896/1146] bpf: prevent leak of lsm program after failed attach Greg Kroah-Hartman
2022-12-28 14:26  1% [PATCH 6.0 0000/1073] 6.0.16-rc1 review Greg Kroah-Hartman
2022-12-28 14:40  8% ` [PATCH 6.0 0846/1073] bpf: prevent leak of lsm program after failed attach Greg Kroah-Hartman
2022-12-30  9:49  1% [PATCH 6.0 0000/1066] 6.0.16-rc2 review Greg Kroah-Hartman
2022-12-30  9:49  1% [PATCH 6.1 0000/1140] 6.1.2-rc2 review Greg Kroah-Hartman
2022-12-30 19:23  0% [PATCH 6.0 0000/1066] 6.0.16-rc2 review Joel Fernandes
2022-12-31 12:38  1% Linux 6.0.16 Greg Kroah-Hartman
2022-12-31 12:46  1% Linux 6.1.2 Greg Kroah-Hartman

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.