diff --git a/rust/bindings/bindings_helper.h b/rust/bindings/bindings_helper.h index ae82e9c941afa1..4aecdc2b312081 100644 --- a/rust/bindings/bindings_helper.h +++ b/rust/bindings/bindings_helper.h @@ -13,10 +13,15 @@ #include #include #include +#include #include #include #include +#include #include +#include +#include +#include #include #include #include diff --git a/rust/helpers/devm.c b/rust/helpers/devm.c new file mode 100644 index 00000000000000..908468d7b89162 --- /dev/null +++ b/rust/helpers/devm.c @@ -0,0 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include + +int rust_helper_devm_add_action(struct device *dev, void (*action)(void *), void *data) +{ + return devm_add_action(dev, action, data); +} diff --git a/rust/helpers/helpers.c b/rust/helpers/helpers.c index 30f40149f3a969..16dc760df29fcd 100644 --- a/rust/helpers/helpers.c +++ b/rust/helpers/helpers.c @@ -11,12 +11,19 @@ #include "bug.c" #include "build_assert.c" #include "build_bug.c" +#include "devm.c" #include "err.c" +#include "i2c.c" +#include "io.c" #include "kunit.c" #include "mutex.c" +#include "of.c" #include "page.c" +#include "platform.c" #include "rbtree.c" +#include "rcu.c" #include "refcount.c" +#include "regmap.c" #include "signal.c" #include "slab.c" #include "spinlock.c" diff --git a/rust/helpers/i2c.c b/rust/helpers/i2c.c new file mode 100644 index 00000000000000..8ffdc454e7597c --- /dev/null +++ b/rust/helpers/i2c.c @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include + +void *rust_helper_i2c_get_clientdata(const struct i2c_client *client) +{ + return i2c_get_clientdata(client); +} + +void rust_helper_i2c_set_clientdata(struct i2c_client *client, void *data) +{ + i2c_set_clientdata(client, data); +} diff --git a/rust/helpers/io.c b/rust/helpers/io.c new file mode 100644 index 00000000000000..f9bb1bbf1fd5da --- /dev/null +++ b/rust/helpers/io.c @@ -0,0 +1,91 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include + +u8 rust_helper_readb(const volatile void __iomem *addr) +{ + return readb(addr); +} + +u16 rust_helper_readw(const volatile void __iomem *addr) +{ + return readw(addr); +} + +u32 rust_helper_readl(const volatile void __iomem *addr) +{ + return readl(addr); +} + +#ifdef CONFIG_64BIT +u64 rust_helper_readq(const volatile void __iomem *addr) +{ + return readq(addr); +} +#endif + +void rust_helper_writeb(u8 value, volatile void __iomem *addr) +{ + writeb(value, addr); +} + +void rust_helper_writew(u16 value, volatile void __iomem *addr) +{ + writew(value, addr); +} + +void rust_helper_writel(u32 value, volatile void __iomem *addr) +{ + writel(value, addr); +} + +#ifdef CONFIG_64BIT +void rust_helper_writeq(u64 value, volatile void __iomem *addr) +{ + writeq(value, addr); +} +#endif + +u8 rust_helper_readb_relaxed(const volatile void __iomem *addr) +{ + return readb_relaxed(addr); +} + +u16 rust_helper_readw_relaxed(const volatile void __iomem *addr) +{ + return readw_relaxed(addr); +} + +u32 rust_helper_readl_relaxed(const volatile void __iomem *addr) +{ + return readl_relaxed(addr); +} + +#ifdef CONFIG_64BIT +u64 rust_helper_readq_relaxed(const volatile void __iomem *addr) +{ + return readq_relaxed(addr); +} +#endif + +void rust_helper_writeb_relaxed(u8 value, volatile void __iomem *addr) +{ + writeb_relaxed(value, addr); +} + +void rust_helper_writew_relaxed(u16 value, volatile void __iomem *addr) +{ + writew_relaxed(value, addr); +} + +void rust_helper_writel_relaxed(u32 value, volatile void __iomem *addr) +{ + writel_relaxed(value, addr); +} + +#ifdef CONFIG_64BIT +void rust_helper_writeq_relaxed(u64 value, volatile void __iomem *addr) +{ + writeq_relaxed(value, addr); +} +#endif diff --git a/rust/helpers/of.c b/rust/helpers/of.c new file mode 100644 index 00000000000000..302c50d86707e8 --- /dev/null +++ b/rust/helpers/of.c @@ -0,0 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include + +const struct of_device_id *rust_helper_of_match_device( + const struct of_device_id *matches, const struct device *dev) +{ + return of_match_device(matches, dev); +} diff --git a/rust/helpers/platform.c b/rust/helpers/platform.c new file mode 100644 index 00000000000000..b68f045ef6054f --- /dev/null +++ b/rust/helpers/platform.c @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include + +void *rust_helper_platform_get_drvdata(const struct platform_device *pdev) +{ + return platform_get_drvdata(pdev); +} + +void rust_helper_platform_set_drvdata(struct platform_device *pdev, void *data) +{ + return platform_set_drvdata(pdev, data); +} diff --git a/rust/helpers/rcu.c b/rust/helpers/rcu.c new file mode 100644 index 00000000000000..f1cec658351349 --- /dev/null +++ b/rust/helpers/rcu.c @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include + +void rust_helper_rcu_read_lock(void) +{ + rcu_read_lock(); +} + +void rust_helper_rcu_read_unlock(void) +{ + rcu_read_unlock(); +} diff --git a/rust/helpers/regmap.c b/rust/helpers/regmap.c new file mode 100644 index 00000000000000..2426e563df339a --- /dev/null +++ b/rust/helpers/regmap.c @@ -0,0 +1,48 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include +#include + +#if IS_BUILTIN(CONFIG_REGMAP_I2C) +struct regmap *rust_helper_regmap_init_i2c(struct i2c_client *i2c, + const struct regmap_config *config) +{ + return regmap_init_i2c(i2c, config); +} +#endif + +int rust_helper_regmap_field_write(struct regmap_field *field, unsigned int val) +{ + return regmap_field_write(field, val); +} + +int rust_helper_regmap_field_force_write(struct regmap_field *field, + unsigned int val) +{ + return regmap_field_force_write(field, val); +} + +int rust_helper_regmap_field_update_bits(struct regmap_field *field, + unsigned int mask, unsigned int val) +{ + return regmap_field_update_bits(field, mask, val); +} + +int rust_helper_regmap_field_set_bits(struct regmap_field *field, + unsigned int bits) +{ + return regmap_field_set_bits(field, bits); +} + +int rust_helper_regmap_field_clear_bits(struct regmap_field *field, + unsigned int bits) +{ + return regmap_field_clear_bits(field, bits); +} + +int rust_helper_regmap_field_force_update_bits(struct regmap_field *field, + unsigned int mask, + unsigned int val) +{ + return regmap_field_force_update_bits(field, mask, val); +} diff --git a/rust/kernel/bits.rs b/rust/kernel/bits.rs new file mode 100644 index 00000000000000..7c111df61d8617 --- /dev/null +++ b/rust/kernel/bits.rs @@ -0,0 +1,12 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! Bit manipulation helpers +//! +//! C header: [`include/linux/bits.h`](srctree/include/linux/bits.h) + +/// Generate a mask where all bits >= `h` and <= `l` are set +/// +/// This is a re-implementation in rust of `GENMASK` +pub const fn genmask(h: u32, l: u32) -> u32 { + ((!0u32) - (1 << l) + 1) & ((!0u32) >> (32 - 1 - h)) +} diff --git a/rust/kernel/device.rs b/rust/kernel/device.rs index 851018eef885e7..36d5e11e8e5ba7 100644 --- a/rust/kernel/device.rs +++ b/rust/kernel/device.rs @@ -8,7 +8,10 @@ use crate::{ bindings, types::{ARef, Opaque}, }; -use core::ptr; +use core::{fmt, ptr}; + +#[cfg(CONFIG_PRINTK)] +use crate::c_str; /// A reference-counted device. /// @@ -82,6 +85,110 @@ impl Device { // SAFETY: Guaranteed by the safety requirements of the function. unsafe { &*ptr.cast() } } + + /// Prints an emergency-level message (level 0) prefixed with device information. + /// + /// More details are available from [`dev_emerg`]. + /// + /// [`dev_emerg`]: crate::dev_emerg + pub 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`]. + /// + /// [`dev_alert`]: crate::dev_alert + pub 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`]. + /// + /// [`dev_crit`]: crate::dev_crit + pub 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`]. + /// + /// [`dev_err`]: crate::dev_err + pub 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`]. + /// + /// [`dev_warn`]: crate::dev_warn + pub 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`]. + /// + /// [`dev_notice`]: crate::dev_notice + pub 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`]. + /// + /// [`dev_info`]: crate::dev_info + pub 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`]. + /// + /// [`dev_dbg`]: crate::dev_dbg + pub 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.as_raw` + // 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.as_raw(), + c_str!("%pA").as_char_ptr(), + &msg as *const _ as *const core::ffi::c_void, + ) + }; + } } // SAFETY: Instances of `Device` are always reference-counted. @@ -103,3 +210,213 @@ unsafe impl Send for Device {} // SAFETY: `Device` can be shared among threads because all immutable methods are protected by the // synchronization in `struct device`. unsafe impl Sync for Device {} + +#[doc(hidden)] +#[macro_export] +macro_rules! dev_printk { + ($method:ident, $dev:expr, $($f:tt)*) => { + { + ($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/device_id.rs b/rust/kernel/device_id.rs new file mode 100644 index 00000000000000..cf1f4476c8a255 --- /dev/null +++ b/rust/kernel/device_id.rs @@ -0,0 +1,386 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! Generic implementation of device IDs. +//! +//! Each bus / subsystem that matches device and driver through a bus / subsystem specific ID is +//! expected to implement [`RawDeviceId`]. + +use core::marker::PhantomData; + +/// 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. +/// +/// Originally, RawDeviceId was implemented as a const trait. However, this unstable feature is +/// broken/gone in 1.73. To work around this, turn IdArray::new() into a macro such that it can use +/// concrete types (which can still have const associated functions) instead of a trait. +/// +/// # Safety +/// +/// Implementers must ensure that: +/// - [`RawDeviceId::ZERO`] is actually a zeroed-out version of the raw device id. +/// - `to_rawid` is implemented and stores `offset` in the context/data field of the raw device +/// id so that buses can recover the pointer to the data. (This should actually be a trait +/// function, however, this requires `const_trait_impl`, and hence has to changed once the +/// feature is stabilized.) +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; +} + +/// A zero-terminated device id array. +#[derive(Copy, Clone)] +#[repr(C)] +pub struct IdArrayIds { + ids: [T::RawType; N], + sentinel: T::RawType, +} + +unsafe impl Sync for IdArrayIds {} + +/// A zero-terminated device id array, followed by context data. +#[repr(C)] +pub struct IdArray { + ids: IdArrayIds, + id_infos: [Option; N], +} + +impl IdArray { + const U_NONE: Option = None; + + /// 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.ids[0], + _p: PhantomData, + } + } + + /// Returns the number of items in the ID table. + pub const fn count(&self) -> usize { + self.ids.ids.len() + } + + /// Returns the inner IdArray array, without the context data. + pub const fn as_ids(&self) -> IdArrayIds + where + T: RawDeviceId + Copy, + { + self.ids + } + + /// Creates a new instance of the array. + /// + /// The contents are derived from the given identifiers and context information. + #[doc(hidden)] + pub const unsafe fn new(raw_ids: [T::RawType; N], infos: [Option; N]) -> Self + where + T: RawDeviceId + Copy, + T::RawType: Copy + Clone, + { + Self { + ids: IdArrayIds { + ids: raw_ids, + sentinel: T::ZERO, + }, + id_infos: infos, + } + } + + #[doc(hidden)] + pub const fn get_offset(idx: usize) -> isize + where + T: RawDeviceId + Copy, + T::RawType: Copy + Clone, + { + // SAFETY: We are only using this dummy value to get offsets. + let array = unsafe { Self::new([T::ZERO; N], [Self::U_NONE; 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 ret = unsafe { + (&array.id_infos[idx] as *const _ as *const u8) + .offset_from(&array.ids.ids[idx] as *const _ as _) + }; + core::mem::forget(array); + ret + } +} + +// Creates a new ID array. This is a macro so it can take the concrete ID type as a parameter in +// order to call to_rawid() on it, and still remain const. This is necessary until a new +// const_trait_impl implementation lands, since the existing implementation was removed in Rust +// 1.73. +#[macro_export] +#[doc(hidden)] +macro_rules! _new_id_array { + (($($args:tt)*), $id_type:ty) => {{ + /// Creates a new instance of the array. + /// + /// The contents are derived from the given identifiers and context information. + const fn new< U, const N: usize>(ids: [$id_type; N], infos: [Option; N]) + -> $crate::device_id::IdArray<$id_type, U, N> + where + $id_type: $crate::device_id::RawDeviceId + Copy, + <$id_type as $crate::device_id::RawDeviceId>::RawType: Copy + Clone, + { + let mut raw_ids = + [<$id_type as $crate::device_id::RawDeviceId>::ZERO; N]; + let mut i = 0usize; + while i < N { + let offset: isize = $crate::device_id::IdArray::<$id_type, U, N>::get_offset(i); + raw_ids[i] = ids[i].to_rawid(offset); + i += 1; + } + + // SAFETY: We are passing valid arguments computed with the correct offsets. + unsafe { + $crate::device_id::IdArray::<$id_type, U, N>::new(raw_ids, infos) + } + } + + new($($args)*) + }} +} + +/// 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`. +pub struct IdTable<'a, T: RawDeviceId, U> { + first: &'a T::RawType, + _p: PhantomData<&'a U>, +} + +impl AsRef 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 +/// +/// ``` +/// # use kernel::{define_id_array, device_id::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 RawDeviceId for Id { +/// type RawType = (u64, isize); +/// const ZERO: Self::RawType = (0, 0); +/// } +/// +/// impl Id { +/// #[allow(clippy::wrong_self_convention)] +/// const fn to_rawid(&self, offset: isize) -> ::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), ]); +/// +/// // Within a bus driver: +/// driver_id_table!(BUS_ID_TABLE, Id, &'static [u8], A1); +/// // At the top level: +/// module_id_table!(MODULE_ID_TABLE, "mybus", Id, A1); +/// ``` +#[macro_export] +macro_rules! define_id_array { + ($table_name:ident, $id_type:ty, $data_type:ty, [ $($t:tt)* ]) => { + const $table_name: $crate::device_id::IdArray<$id_type, + $data_type, { + $crate::count_paren_items!($($t)*) + }> = $crate::_new_id_array!( + ($crate::first_item!($id_type, $($t)*), + $crate::second_item!($($t)*)), + $id_type); + }; +} + +/// Declares an [`IdArray`] as an [`IdTable`] for a bus driver 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 +/// +/// ``` +/// # use kernel::{define_id_table, device_id::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 RawDeviceId for Id { +/// type RawType = (u64, isize); +/// const ZERO: Self::RawType = (0, 0); +/// } +/// +/// impl Id { +/// #[allow(clippy::wrong_self_convention)] +/// const fn to_rawid(&self, offset: isize) -> ::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! driver_id_table { + ($table_name:ident, $id_type:ty, $data_type:ty, $target:expr) => { + const $table_name: Option<$crate::device_id::IdTable<'static, $id_type, $data_type>> = + Some($target.as_table()); + }; +} + +/// Declares an [`IdArray`] as a module-level ID tablewith 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::{driver_id_table}; + +/// driver_id_table!(BUS_ID_TABLE, Id, &'static [u8], MY_ID_ARRAY); +/// ``` +#[macro_export] +macro_rules! module_id_table { + ($item_name:ident, $table_type:literal, $id_type:ty, $table_name:ident) => { + #[export_name = concat!("__mod_", $table_type, "__", stringify!($table_name), "_device_table")] + static $item_name: $crate::device_id::IdArrayIds<$id_type, { $table_name.count() }> = + $table_name.as_ids(); + }; +} diff --git a/rust/kernel/devres.rs b/rust/kernel/devres.rs new file mode 100644 index 00000000000000..ab0a3eb1ea4f94 --- /dev/null +++ b/rust/kernel/devres.rs @@ -0,0 +1,168 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! Devres abstraction +//! +//! [`Devres`] represents an abstraction for the kernel devres (device resource management) +//! implementation. + +use crate::{ + alloc::Flags, + bindings, + device::Device, + error::{Error, Result}, + prelude::*, + revocable::Revocable, + sync::Arc, +}; + +use core::ffi::c_void; +use core::ops::Deref; + +#[pin_data] +struct DevresInner { + #[pin] + data: Revocable, +} + +/// This abstraction is meant to be used by subsystems to containerize [`Device`] bound resources to +/// manage their lifetime. +/// +/// [`Device`] bound resources should be freed when either the resource goes out of scope or the +/// [`Device`] is unbound respectively, depending on what happens first. +/// +/// To achieve that [`Devres`] registers a devres callback on creation, which is called once the +/// [`Device`] is unbound, revoking access to the encapsulated resource (see also [`Revocable`]). +/// +/// After the [`Devres`] has been unbound it is not possible to access the encapsulated resource +/// anymore. +/// +/// [`Devres`] users should make sure to simply free the corresponding backing resource in `T`'s +/// [`Drop`] implementation. +/// +/// # Example +/// +/// ``` +/// # use kernel::{bindings, c_str, device::Device, devres::Devres, io::Io}; +/// # use core::ops::Deref; +/// +/// // See also [`pci::Bar`] for a real example. +/// struct IoMem(Io); +/// +/// impl IoMem { +/// fn new(paddr: usize) -> Result{ +/// +/// // SAFETY: assert safety for this example +/// let addr = unsafe { bindings::ioremap(paddr as _, SIZE.try_into().unwrap()) }; +/// if addr.is_null() { +/// return Err(ENOMEM); +/// } +/// +/// // SAFETY: `addr` is guaranteed to be the start of a valid I/O mapped memory region of +/// // size `SIZE`. +/// let io = unsafe { Io::new(addr as _, SIZE)? }; +/// +/// Ok(IoMem(io)) +/// } +/// } +/// +/// impl Drop for IoMem { +/// fn drop(&mut self) { +/// // SAFETY: Safe as by the invariant of `Io`. +/// unsafe { bindings::iounmap(self.0.base_addr() as _); }; +/// } +/// } +/// +/// impl Deref for IoMem { +/// type Target = Io; +/// +/// fn deref(&self) -> &Self::Target { +/// &self.0 +/// } +/// } +/// +/// # // SAFETY: *NOT* safe, just for the example to get an `ARef` instance +/// # let dev = unsafe { Device::from_raw(core::ptr::null_mut()) }; +/// +/// let iomem = IoMem::<{ core::mem::size_of::() }>::new(0xBAAAAAAD).unwrap(); +/// let devres = Devres::new(&dev, iomem, GFP_KERNEL).unwrap(); +/// +/// let res = devres.try_access().ok_or(ENXIO).unwrap(); +/// res.writel(0x42, 0x0); +/// ``` +/// +pub struct Devres(Arc>); + +impl DevresInner { + fn new(dev: &Device, data: T, flags: Flags) -> Result>> { + let inner = Arc::pin_init( + pin_init!( DevresInner { + data <- Revocable::new(data), + }), + flags, + )?; + + // Convert `Arc` into a raw pointer and make devres own this reference until + // `Self::devres_callback` is called. + let data = inner.clone().into_raw(); + let ret = unsafe { + bindings::devm_add_action(dev.as_raw(), Some(Self::devres_callback), data as _) + }; + + if ret != 0 { + // SAFETY: We just created another reference to `inner` in order to pass it to + // `bindings::devm_add_action`. If `bindings::devm_add_action` fails, we have to drop + // this reference accordingly. + let _ = unsafe { Arc::from_raw(data) }; + return Err(Error::from_errno(ret)); + } + + Ok(inner) + } + + unsafe extern "C" fn devres_callback(ptr: *mut c_void) { + let ptr = ptr as *mut DevresInner; + // Devres owned this memory; now that we received the callback, drop the `Arc` and hence the + // reference. + // SAFETY: Safe, since we leaked an `Arc` reference to devm_add_action() in + // `DevresInner::new`. + let inner = unsafe { Arc::from_raw(ptr) }; + + inner.data.revoke(); + } +} + +impl Devres { + /// Creates a new [`Devres`] instance of the given `data`. The `data` encapsulated within the + /// returned `Devres` instance' `data` will be revoked once the device is detached. + pub fn new(dev: &Device, data: T, flags: Flags) -> Result { + let inner = DevresInner::new(dev, data, flags)?; + + Ok(Devres(inner)) + } + + /// Same as [Devres::new`], but does not return a `Devres` instance. Instead the given `data` + /// is owned by devres and will be revoked / dropped, once the device is detached. + pub fn new_foreign_owned(dev: &Device, data: T, flags: Flags) -> Result { + let _ = DevresInner::new(dev, data, flags)?; + + Ok(()) + } +} + +impl Deref for Devres { + type Target = Revocable; + + fn deref(&self) -> &Self::Target { + &self.0.data + } +} + +impl Drop for Devres { + fn drop(&mut self) { + // Revoke the data, such that it gets dropped already and the actual resource is freed. + // `DevresInner` has to stay alive until the devres callback has been called. This is + // necessary since we don't know when `Devres` is dropped and calling + // `devm_remove_action()` instead could race with `devres_release_all()`. + self.revoke(); + } +} diff --git a/rust/kernel/driver.rs b/rust/kernel/driver.rs new file mode 100644 index 00000000000000..e04406b93b56f0 --- /dev/null +++ b/rust/kernel/driver.rs @@ -0,0 +1,128 @@ +// 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::{Error, Result}; +use crate::{init::PinInit, str::CStr, try_pin_init, types::Opaque, ThisModule}; +use core::pin::Pin; +use macros::{pin_data, pinned_drop}; + +/// The [`DriverOps`] trait serves as generic interface for subsystems (e.g., PCI, Platform, Amba, +/// etc.) to privide the corresponding subsystem specific implementation to register / unregister a +/// driver of the particular type (`RegType`). +/// +/// For instance, the PCI subsystem would set `RegType` to `bindings::pci_driver` and call +/// `bindings::__pci_register_driver` from `DriverOps::register` and +/// `bindings::pci_unregister_driver` from `DriverOps::unregister`. +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`]. + 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`]. + fn unregister(reg: &mut Self::RegType); +} + +/// A [`Registration`] is a generic type that represents the registration of some driver type (e.g. +/// `bindings::pci_driver`). Therefore a [`Registration`] is initialized with some type that +/// implements the [`DriverOps`] trait, such that the generic `T::register` and `T::unregister` +/// calls result in the subsystem specific registration calls. +/// +///Once the `Registration` structure is dropped, the driver is unregistered. +#[pin_data(PinnedDrop)] +pub struct Registration { + #[pin] + reg: Opaque, +} + +// 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 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 instance of the registration object. + pub fn new(name: &'static CStr, module: &'static ThisModule) -> impl PinInit { + try_pin_init!(Self { + reg <- Opaque::try_ffi_init(|ptr: *mut T::RegType| { + // SAFETY: `try_ffi_init` guarantees that `ptr` is valid for write. + unsafe { ptr.write(T::RegType::default()) }; + + // SAFETY: `try_ffi_init` guarantees that `ptr` is valid for write, and it has + // just been initialised above, so it's also valid for read. + let drv = unsafe { &mut *ptr }; + + T::register(drv, name, module) + }), + }) + } +} + +#[pinned_drop] +impl PinnedDrop for Registration { + fn drop(self: Pin<&mut Self>) { + let drv = unsafe { &mut *self.reg.get() }; + + T::unregister(drv); + } +} + +/// 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. +#[pin_data] +pub struct Module { + #[pin] + _driver: Registration, +} + +impl crate::InPlaceModule for Module { + fn init(name: &'static CStr, module: &'static ThisModule) -> impl PinInit { + try_pin_init!(Self { + _driver <- Registration::::new(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>; + $crate::prelude::module! { + type: ModuleType, + $($f)* + } + } +} diff --git a/rust/kernel/error.rs b/rust/kernel/error.rs index 6f1587a2524e8b..3bfaf48125369f 100644 --- a/rust/kernel/error.rs +++ b/rust/kernel/error.rs @@ -77,6 +77,7 @@ pub mod code { declare_err!(EIOCBQUEUED, "iocb queued, will get completion event."); declare_err!(ERECALLCONFLICT, "Conflict with recalled state."); declare_err!(ENOGRACE, "NFS file lock reclaim refused."); + declare_err!(ENOTRECOVERABLE, "State not recoverable."); } /// Generic integer kernel error. diff --git a/rust/kernel/i2c.rs b/rust/kernel/i2c.rs new file mode 100644 index 00000000000000..047f3547d3e322 --- /dev/null +++ b/rust/kernel/i2c.rs @@ -0,0 +1,253 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! I2C devices and drivers. +//! +//! C header: [`include/linux/i2c.h`](../../../../include/linux/i2c.h) + +use crate::{ + bindings, + device::Device, + device_id::{self, RawDeviceId}, + driver, + error::{from_result, to_result, Result}, + of, + str::{BStr, CStr}, + types::ForeignOwnable, + ThisModule, +}; + +/// An I2C device id. +#[derive(Clone, Copy)] +pub struct DeviceId(pub &'static BStr); + +// SAFETY: `ZERO` is all zeroed-out and `to_rawid` stores `offset` in `i2c_device_id::driver_data`. +unsafe impl RawDeviceId for DeviceId { + type RawType = bindings::i2c_device_id; + const ZERO: Self::RawType = bindings::i2c_device_id { + name: [0; 20], + driver_data: 0, + }; +} + +impl DeviceId { + #[doc(hidden)] + pub const fn to_rawid(&self, offset: isize) -> ::RawType { + let mut id = Self::ZERO; + let mut i = 0; + while i < self.0.len() { + id.name[i] = self.0.deref_const()[i] as _; + i += 1; + } + id.name[i] = b'\0' as _; + id.driver_data = offset as _; + id + } +} + +/// Defines a const I2C device id table that also carries per-entry data/context/info. +/// +/// The name of the const is `I2C_DEVICE_ID_TABLE`. +/// +/// # Examples +/// +/// ``` +/// use kernel::i2c; +/// +/// kernel::define_i2c_id_table! {MY_ID_TABLE, u32, [ +/// (i2c::DeviceId(b"test-device1"), Some(0xff)), +/// (i2c::DeviceId(b"test-device2"), None), +/// ]}; +/// ``` +#[macro_export] +macro_rules! define_i2c_id_table { + ($name:ident, $data_type:ty, $($t:tt)*) => { + $crate::define_id_array!($name, $crate::i2c::DeviceId, $data_type, $($t)*); + }; +} +/// +/// Convenience macro to declare which device ID table to use for a bus driver. +#[macro_export] +macro_rules! driver_i2c_id_table { + ($name:expr) => { + $crate::driver_id_table!( + I2C_DEVICE_ID_TABLE, + $crate::i2c::DeviceId, + Self::IdInfo, + $name + ); + }; +} + +/// Declare a device ID table as a module-level table. This creates the necessary module alias +/// entries to enable module autoloading. +#[macro_export] +macro_rules! module_i2c_id_table { + ($item_name:ident, $table_name:ident) => { + $crate::module_id_table!($item_name, "i2c", $crate::i2c::DeviceId, $table_name); + }; +} + +/// An adapter for the registration of i2c drivers. +pub struct Adapter(T); + +impl driver::DriverOps for Adapter { + type RegType = bindings::i2c_driver; + + fn register( + i2cdrv: &mut Self::RegType, + name: &'static CStr, + module: &'static ThisModule, + ) -> Result { + i2cdrv.driver.name = name.as_char_ptr(); + i2cdrv.probe = Some(Self::probe_callback); + i2cdrv.remove = Some(Self::remove_callback); + if let Some(t) = T::I2C_DEVICE_ID_TABLE { + i2cdrv.id_table = t.as_ref(); + } + if let Some(t) = T::OF_DEVICE_ID_TABLE { + i2cdrv.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 [`device_id::IdTable`] type, or null. + to_result(unsafe { bindings::i2c_register_driver(module.0, i2cdrv) }) + } + + fn unregister(i2cdrv: &mut Self::RegType) { + // SAFETY: By the safety requirements of this function (defined in the trait definition), + // `reg` was passed (and updated) by a previous successful call to + // `i2c_register_driver`. + unsafe { bindings::i2c_del_driver(i2cdrv) }; + } +} + +impl Adapter { + extern "C" fn probe_callback(i2c: *mut bindings::i2c_client) -> core::ffi::c_int { + from_result(|| { + let mut client = unsafe { Client::from_ptr(i2c) }; + let data = T::probe(&mut client)?; + + // SAFETY: `i2c` is guaranteed to be a valid, non-null pointer. + unsafe { bindings::i2c_set_clientdata(i2c, data.into_foreign() as _) }; + Ok(0) + }) + } + + extern "C" fn remove_callback(i2c: *mut bindings::i2c_client) { + // SAFETY: `i2c` is guaranteed to be a valid, non-null pointer + let ptr = unsafe { bindings::i2c_get_clientdata(i2c) }; + // 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_foreign(ptr) }; + T::remove(&data); + } +} + +/// A I2C driver. +pub trait Driver { + /// Data stored on device by driver. + /// + /// Corresponds to the data set or retrieved via the kernel's + /// `i2c_{set,get}_clientdata()` functions. + /// + /// Require that `Data` implements `ForeignOwnable`. We guarantee to + /// never move the underlying wrapped data structure. This allows + type Data: ForeignOwnable = (); + + /// The type holding information about each device id supported by the driver. + type IdInfo: 'static = (); + + /// The table of i2c device ids supported by the driver. + const I2C_DEVICE_ID_TABLE: Option> = None; + + /// The table of OF device ids supported by the driver. + const OF_DEVICE_ID_TABLE: Option> = + None; + + /// I2C driver probe. + /// + /// Called when a new i2c client is added or discovered. + /// Implementers should attempt to initialize the client here. + fn probe(client: &mut Client) -> Result; + + /// I2C driver remove. + /// + /// Called when an i2c client is removed. + fn remove(_data: &Self::Data) {} +} + +/// A I2C Client device. +/// +/// # Invariants +/// +/// The field `ptr` is non-null and valid for the lifetime of the object. +pub struct Client { + ptr: *mut bindings::i2c_client, +} + +impl Client { + /// Creates a new client 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::i2c_client) -> Self { + // INVARIANT: The safety requirements of the function ensure the lifetime invariant. + Self { ptr } + } + + /// Returns the raw I2C client structure. + pub fn raw_client(&self) -> *mut bindings::i2c_client { + self.ptr + } +} + +impl AsRef for Client { + fn as_ref(&self) -> &Device { + // SAFETY: By the type invariants, we know that `self.ptr` is non-null and valid. + unsafe { Device::as_ref(&mut (*self.ptr).dev) } + } +} + +/// Declares a kernel module that exposes a single i2c driver. +/// +/// # Examples +/// +/// ```ignore +/// # use kernel::{i2c, define_i2c_id_table, module_i2c_driver}; +/// kernel::module_i2c_id_table!(MOD_TABLE, I2C_CLIENT_I2C_ID_TABLE); +/// kernel::define_i2c_id_table! {I2C_CLIENT_I2C_ID_TABLE, (), [ +/// (i2c::DeviceId(b"fpga"), None), +/// ]} +/// struct MyDriver; +/// impl i2c::Driver for MyDriver { +/// kernel::driver_i2c_id_table!(I2C_CLIENT_I2C_ID_TABLE); +/// // [...] +/// # fn probe(_client: &mut i2c::Client) -> Result { +/// # Ok(()) +/// # } +/// } +/// +/// module_i2c_driver! { +/// type: MyDriver, +/// name: "module_name", +/// author: "Author name", +/// license: "GPL", +/// } +/// ``` +#[macro_export] +macro_rules! module_i2c_driver { + ($($f:tt)*) => { + $crate::module_driver!(, $crate::i2c::Adapter, { $($f)* }); + }; +} diff --git a/rust/kernel/io.rs b/rust/kernel/io.rs new file mode 100644 index 00000000000000..a19a1226181dd7 --- /dev/null +++ b/rust/kernel/io.rs @@ -0,0 +1,219 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! Memory-mapped IO. +//! +//! C header: [`include/asm-generic/io.h`](srctree/include/asm-generic/io.h) + +use crate::error::{code::EINVAL, Result}; +use crate::{bindings, build_assert}; + +/// IO-mapped memory, starting at the base address @addr and spanning @maxlen bytes. +/// +/// The creator (usually a subsystem such as PCI) is responsible for creating the +/// mapping, performing an additional region request etc. +/// +/// # Invariant +/// +/// `addr` is the start and `maxsize` the length of valid I/O remapped memory region. +/// +/// # Examples +/// +/// ``` +/// # use kernel::{bindings, io::Io}; +/// # use core::ops::Deref; +/// +/// // See also [`pci::Bar`] for a real example. +/// struct IoMem(Io); +/// +/// impl IoMem { +/// fn new(paddr: usize) -> Result{ +/// +/// // SAFETY: assert safety for this example +/// let addr = unsafe { bindings::ioremap(paddr as _, SIZE.try_into().unwrap()) }; +/// if addr.is_null() { +/// return Err(ENOMEM); +/// } +/// +/// // SAFETY: `addr` is guaranteed to be the start of a valid I/O mapped memory region of +/// // size `SIZE`. +/// let io = unsafe { Io::new(addr as _, SIZE)? }; +/// +/// Ok(IoMem(io)) +/// } +/// } +/// +/// impl Drop for IoMem { +/// fn drop(&mut self) { +/// // SAFETY: Safe as by the invariant of `Io`. +/// unsafe { bindings::iounmap(self.0.base_addr() as _); }; +/// } +/// } +/// +/// impl Deref for IoMem { +/// type Target = Io; +/// +/// fn deref(&self) -> &Self::Target { +/// &self.0 +/// } +/// } +/// +/// let iomem = IoMem::<{ core::mem::size_of::() }>::new(0xBAAAAAAD).unwrap(); +/// iomem.writel(0x42, 0x0); +/// assert!(iomem.try_writel(0x42, 0x0).is_ok()); +/// assert!(iomem.try_writel(0x42, 0x4).is_err()); +/// ``` +pub struct Io { + addr: usize, + maxsize: usize, +} + +macro_rules! define_read { + ($(#[$attr:meta])* $name:ident, $try_name:ident, $type_name:ty) => { + /// Read IO data from a given offset known at compile time. + /// + /// Bound checks are performed on compile time, hence if the offset is not known at compile + /// time, the build will fail. + $(#[$attr])* + #[inline] + pub fn $name(&self, offset: usize) -> $type_name { + let addr = self.io_addr_assert::<$type_name>(offset); + + unsafe { bindings::$name(addr as _) } + } + + /// Read IO data from a given offset. + /// + /// Bound checks are performed on runtime, it fails if the offset (plus the type size) is + /// out of bounds. + $(#[$attr])* + pub fn $try_name(&self, offset: usize) -> Result<$type_name> { + let addr = self.io_addr::<$type_name>(offset)?; + + Ok(unsafe { bindings::$name(addr as _) }) + } + }; +} + +macro_rules! define_write { + ($(#[$attr:meta])* $name:ident, $try_name:ident, $type_name:ty) => { + /// Write IO data from a given offset known at compile time. + /// + /// Bound checks are performed on compile time, hence if the offset is not known at compile + /// time, the build will fail. + $(#[$attr])* + #[inline] + pub fn $name(&self, value: $type_name, offset: usize) { + let addr = self.io_addr_assert::<$type_name>(offset); + + unsafe { bindings::$name(value, addr as _, ) } + } + + /// Write IO data from a given offset. + /// + /// Bound checks are performed on runtime, it fails if the offset (plus the type size) is + /// out of bounds. + $(#[$attr])* + pub fn $try_name(&self, value: $type_name, offset: usize) -> Result { + let addr = self.io_addr::<$type_name>(offset)?; + + unsafe { bindings::$name(value, addr as _) } + Ok(()) + } + }; +} + +impl Io { + /// + /// + /// # Safety + /// + /// Callers must ensure that `addr` is the start of a valid I/O mapped memory region of size + /// `maxsize`. + pub unsafe fn new(addr: usize, maxsize: usize) -> Result { + if maxsize < SIZE { + return Err(EINVAL); + } + + Ok(Self { addr, maxsize }) + } + + /// Returns the base address of this mapping. + #[inline] + pub fn base_addr(&self) -> usize { + self.addr + } + + /// Returns the size of this mapping. + #[inline] + pub fn maxsize(&self) -> usize { + self.maxsize + } + + #[inline] + const fn offset_valid(offset: usize, size: usize) -> bool { + let type_size = core::mem::size_of::(); + if let Some(end) = offset.checked_add(type_size) { + end <= size && offset % type_size == 0 + } else { + false + } + } + + #[inline] + fn io_addr(&self, offset: usize) -> Result { + if !Self::offset_valid::(offset, self.maxsize()) { + return Err(EINVAL); + } + + // Probably no need to check, since the safety requirements of `Self::new` guarantee that + // this can't overflow. + self.base_addr().checked_add(offset).ok_or(EINVAL) + } + + #[inline] + fn io_addr_assert(&self, offset: usize) -> usize { + build_assert!(Self::offset_valid::(offset, SIZE)); + + self.base_addr() + offset + } + + 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 + ); +} diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs index f10b06a78b9d5c..502c298c18ef36 100644 --- a/rust/kernel/lib.rs +++ b/rust/kernel/lib.rs @@ -12,8 +12,11 @@ //! do so first instead of bypassing this crate. #![no_std] +#![feature(associated_type_defaults)] #![feature(coerce_unsized)] +#![feature(const_refs_to_cell)] #![feature(dispatch_from_dyn)] +#![feature(doc_cfg)] #![feature(new_uninit)] #![feature(receiver_trait)] #![feature(unsize)] @@ -27,13 +30,20 @@ compile_error!("Missing kernel configuration for conditional compilation"); extern crate self as kernel; pub mod alloc; +pub mod bits; #[cfg(CONFIG_BLOCK)] pub mod block; mod build_assert; pub mod device; +pub mod device_id; +pub mod devres; +pub mod driver; pub mod error; #[cfg(CONFIG_RUST_FW_LOADER_ABSTRACTIONS)] pub mod firmware; +#[cfg(any(CONFIG_I2C, doc))] +#[doc(cfg(CONFIG_I2C))] +pub mod i2c; pub mod init; pub mod ioctl; #[cfg(CONFIG_KUNIT)] @@ -41,10 +51,17 @@ pub mod kunit; pub mod list; #[cfg(CONFIG_NET)] pub mod net; +pub mod of; pub mod page; +pub mod platform; pub mod prelude; pub mod print; pub mod rbtree; +#[cfg(CONFIG_REGMAP)] +pub mod regmap; +#[cfg(CONFIG_REGULATOR)] +pub mod regulator; +pub mod revocable; mod static_assert; #[doc(hidden)] pub mod std_vendor; @@ -58,6 +75,7 @@ pub mod workqueue; #[doc(hidden)] pub use bindings; +pub mod io; pub use macros; pub use uapi; @@ -77,7 +95,36 @@ pub trait Module: Sized + Sync + Send { /// should do. /// /// Equivalent to the `module_init` macro in the C API. - fn init(module: &'static ThisModule) -> error::Result; + fn init(name: &'static str::CStr, module: &'static ThisModule) -> error::Result; +} + +/// A module that is pinned and initialised in-place. +pub trait InPlaceModule: Sync + Send { + /// Creates an initialiser for the module. + /// + /// It is called when the module is loaded. + fn init( + name: &'static str::CStr, + module: &'static ThisModule, + ) -> impl init::PinInit; +} + +impl InPlaceModule for T { + fn init( + name: &'static str::CStr, + module: &'static ThisModule, + ) -> impl init::PinInit { + let initer = move |slot: *mut Self| { + let m = ::init(name, module)?; + + // SAFETY: `slot` is valid for write per the contract with `pin_init_from_closure`. + unsafe { slot.write(m) }; + Ok(()) + }; + + // SAFETY: On success, `initer` always fully initialises an instance of `Self`. + unsafe { init::pin_init_from_closure(initer) } + } } /// Equivalent to `THIS_MODULE` in the C API. diff --git a/rust/kernel/net/phy.rs b/rust/kernel/net/phy.rs index fd40b703d2244f..ccb2552dc10723 100644 --- a/rust/kernel/net/phy.rs +++ b/rust/kernel/net/phy.rs @@ -887,7 +887,7 @@ macro_rules! module_phy_driver { [$($crate::net::phy::create_phy_driver::<$driver>()),+]; impl $crate::Module for Module { - fn init(module: &'static ThisModule) -> Result { + fn init(_name: &'static CStr, module: &'static ThisModule) -> Result { // SAFETY: The anonymous constant guarantees that nobody else can access // the `DRIVERS` static. The array is used only in the C side. let drivers = unsafe { &mut DRIVERS }; diff --git a/rust/kernel/of.rs b/rust/kernel/of.rs new file mode 100644 index 00000000000000..3d86d960688398 --- /dev/null +++ b/rust/kernel/of.rs @@ -0,0 +1,90 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! Devicetree and Open Firmware abstractions. +//! +//! C header: [`include/linux/of_*.h`](../../../../include/linux/of_*.h) + +use crate::{bindings, device_id, 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. +/// +/// # Example +/// +/// ``` +/// # use kernel::{define_of_id_table, module_of_id_table, driver_of_id_table}; +/// use kernel::of; +/// +/// define_of_id_table! {MY_ID_TABLE, u32, [ +/// (of::DeviceId::Compatible(b"test-device1,test-device2"), Some(0xff)), +/// (of::DeviceId::Compatible(b"test-device3"), None), +/// ]}; +/// +/// module_of_id_table!(MOD_TABLE, ASAHI_ID_TABLE); +/// +/// // Within the `Driver` implementation: +/// driver_of_id_table!(MY_ID_TABLE); +/// ``` +#[macro_export] +macro_rules! define_of_id_table { + ($name:ident, $data_type:ty, $($t:tt)*) => { + $crate::define_id_array!($name, $crate::of::DeviceId, $data_type, $($t)*); + }; +} + +/// Convenience macro to declare which device ID table to use for a bus driver. +#[macro_export] +macro_rules! driver_of_id_table { + ($name:expr) => { + $crate::driver_id_table!( + OF_DEVICE_ID_TABLE, + $crate::of::DeviceId, + Self::IdInfo, + $name + ); + }; +} + +/// Declare a device ID table as a module-level table. This creates the necessary module alias +/// entries to enable module autoloading. +#[macro_export] +macro_rules! module_of_id_table { + ($item_name:ident, $table_name:ident) => { + $crate::module_id_table!($item_name, "of", $crate::of::DeviceId, $table_name); + }; +} + +// SAFETY: `ZERO` is all zeroed-out and `to_rawid` stores `offset` in `of_device_id::data`. +unsafe impl device_id::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(), + }; +} + +impl DeviceId { + #[doc(hidden)] + pub const fn to_rawid(&self, offset: isize) -> ::RawType { + let DeviceId::Compatible(compatible) = self; + let mut id = ::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.deref_const()[i] as _; + i += 1; + } + id.compatible[i] = b'\0' as _; + id.data = offset as _; + id + } +} diff --git a/rust/kernel/platform.rs b/rust/kernel/platform.rs new file mode 100644 index 00000000000000..b3701f12e55b28 --- /dev/null +++ b/rust/kernel/platform.rs @@ -0,0 +1,212 @@ +// 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, device_id, driver, + error::{from_result, to_result, Result}, + of, + str::CStr, + types::ForeignOwnable, + ThisModule, +}; + +/// A registration of a platform driver. +pub type Registration = driver::Registration>; + +/// An adapter for the registration of platform drivers. +pub struct Adapter(T); + +impl driver::DriverOps for Adapter { + type RegType = bindings::platform_driver; + + fn register( + pdrv: &mut bindings::platform_driver, + name: &'static CStr, + module: &'static ThisModule, + ) -> Result { + pdrv.driver.name = name.as_char_ptr(); + pdrv.probe = Some(Self::probe_callback); + pdrv.__bindgen_anon_1.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 [`device_id::IdTable`] type, or null. + to_result(unsafe { bindings::__platform_driver_register(pdrv, module.0) }) + } + + fn unregister(pdrv: &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(pdrv) }; + } +} + +impl Adapter { + 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.as_ref().as_raw()) }; + 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::() + .offset(offset as _) + .cast::>() + }; + + // SAFETY: The id table has a static lifetime, so `ptr` is guaranteed to be valid for read. + #[allow(clippy::needless_borrow)] + unsafe { + (&*ptr).as_ref() + } + } + + extern "C" fn probe_callback(pdev: *mut bindings::platform_device) -> core::ffi::c_int { + from_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_foreign() as _) }; + Ok(0) + }) + } + + extern "C" fn remove_callback(pdev: *mut bindings::platform_device) { + // 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_foreign`, + // 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_foreign(ptr) }; + T::remove(&data); + } +} + +/// 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 `ForeignOwnable`. We guarantee to + /// never move the underlying wrapped data structure. + type Data: ForeignOwnable = (); + + /// 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> = + 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; + + /// Platform driver remove. + /// + /// Called when a platform device is removed. + /// Implementers should prepare the device for complete removal here. + fn remove(_data: &Self::Data) {} +} + +/// 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 } + } +} + +impl AsRef for Device { + fn as_ref(&self) -> &device::Device { + // SAFETY: By the type invariants, we know that `self.ptr` is non-null and valid. + unsafe { device::Device::as_ref(&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: "module_name", +/// author: "Author name", +/// license: "GPL", +/// } +/// ``` +#[macro_export] +macro_rules! module_platform_driver { + ($($f:tt)*) => { + $crate::module_driver!(, $crate::platform::Adapter, { $($f)* }); + }; +} diff --git a/rust/kernel/prelude.rs b/rust/kernel/prelude.rs index 4571daec0961bb..86cd96608b8e3f 100644 --- a/rust/kernel/prelude.rs +++ b/rust/kernel/prelude.rs @@ -27,6 +27,8 @@ pub use super::build_assert; // `super::std_vendor` is hidden, which makes the macro inline for some reason. #[doc(no_inline)] pub use super::dbg; +pub use super::fmt; +pub use super::{dev_alert, dev_crit, dev_dbg, dev_emerg, dev_err, dev_info, dev_notice, dev_warn}; pub use super::{pr_alert, pr_crit, pr_debug, pr_emerg, pr_err, pr_info, pr_notice, pr_warn}; pub use super::{init, pin_init, try_init, try_pin_init}; diff --git a/rust/kernel/regmap.rs b/rust/kernel/regmap.rs new file mode 100644 index 00000000000000..2074e6c789a6c8 --- /dev/null +++ b/rust/kernel/regmap.rs @@ -0,0 +1,874 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! Register map access API. +//! +//! C header: [`include/linux/regmap.h`](srctree/include/linux/regmap.h) + +#[cfg(CONFIG_REGMAP_I2C = "y")] +use crate::i2c; +use crate::{ + bindings, + error::{code::*, to_result, Error, Result}, + macros::paste, + sync::Arc, +}; +use core::{marker::PhantomData, mem::MaybeUninit}; + +/// Type of caching +#[repr(u32)] +pub enum CacheType { + /// Don't cache anything + None = bindings::regcache_type_REGCACHE_NONE, + /// Use RbTree caching + RbTree = bindings::regcache_type_REGCACHE_RBTREE, + /// Use Flat caching + Flat = bindings::regcache_type_REGCACHE_FLAT, + /// Use Maple caching + Maple = bindings::regcache_type_REGCACHE_MAPLE, +} + +/// Register map +/// +/// # Examples +/// +/// ``` +/// let regmap = Regmap::init_i2c(i2c, &config); +/// ``` +pub struct Regmap(*mut bindings::regmap); + +impl Regmap { + #[cfg(CONFIG_REGMAP_I2C = "y")] + /// Initialize a [`Regmap`] instance for an `i2c` device. + pub fn init_i2c(i2c: &i2c::Client, config: &Config) -> Self { + let regmap = unsafe { bindings::regmap_init_i2c(i2c.raw_client(), &config.raw) }; + + Self(regmap) + } + + /// Allocate regmap [`Fields`] + /// + /// This function allocate regmap fields from the `reg_fields` descriptors + pub fn alloc_fields( + self: &Arc, + descs: &'static FieldDescs, + ) -> Result> { + let mut rm_fields = [core::ptr::null_mut(); N]; + to_result(unsafe { + bindings::regmap_field_bulk_alloc( + self.0, + &mut rm_fields[0], + descs.0.as_ptr(), + descs.0.len() as i32, + ) + })?; + + Ok(Fields { + rm_fields, + _regmap: self.clone(), + }) + } + + /// Return the raw pointer of this regmap + pub fn as_ptr(&self) -> *mut bindings::regmap { + self.0 + } +} + +impl Drop for Regmap { + fn drop(&mut self) { + unsafe { bindings::regmap_exit(self.0) } + } +} + +/// Field Descriptors +/// +/// FieldDescriptors can be created by calling the [`define_regmap_field_descs`] macro. +pub struct FieldDescs([bindings::reg_field; N]); + +impl FieldDescs { + // macro use only + #[doc(hidden)] + pub const fn new(fields: [bindings::reg_field; N]) -> Self { + Self(fields) + } + + /// Number of fields being held by `FieldDescs` + /// + /// This function should be used to retrieve the number of fields that were + /// created when calling [`define_regmap_field_descs`]. + /// + /// # Examples + /// + /// ``` + /// use kernel::regmap::{define_regmap_field_descs, Fields}; + /// + /// define_regmap_field_descs!(DESCS, { + /// {pid, 0x3, kernel::regmap::access::READ, { value => raw([7:0], ro) }}, + /// }); + /// + /// struct Registrations { + /// fields: Fields<{ DESCS.count() }>, + /// } + /// ``` + pub const fn count(&self) -> usize { + N + } +} + +/// Regmap fields +/// +/// # Invariants +/// +/// `rm_fields` is garanteed to contains valid and initialized `regmap_field`s. +/// +pub struct Fields { + rm_fields: [*mut bindings::regmap_field; N], + + // Each regmap_field hold a pointer to the `struct regmap` instance, so we need to keep a copy + // of the wrapper around. + _regmap: Arc, +} +impl Fields { + /// Get field `index` + pub fn index(&mut self, index: usize) -> *mut bindings::regmap_field { + self.rm_fields[index] + } + + // macro use only + #[doc(hidden)] + pub fn read(&mut self, index: usize) -> Result { + let mut val = 0; + + // Make sure we don't panic if the index is out of bound. + if index >= N { + return Err(EINVAL); + } + + // SAFETY: By the type invariants, we are garanteed that all rm_fields entries point + // to valid and initialized values, hence it is safe to make this FFI call. + let ret = unsafe { bindings::regmap_field_read(self.rm_fields[index], &mut val) }; + if ret < 0 { + return Err(Error::from_errno(ret)); + } + + Ok(val) + } +} + +unsafe impl Send for Fields {} + +/// Helper macro for [`Config`] to create methods to set a fields from [`regmap_config`] +/// +/// The following code will create a method named `with_max_register`: +/// ``` +/// config_with!(max_register: u32); +/// ``` +macro_rules! config_with { + ($(#[$meta:meta])* $name:ident: $type:ty) => { + config_with!($(#[$meta])* $name: $type, $name); + }; + + ($(#[$meta:meta])* $name:ident: $type:ty, $e:expr) => { + paste! { + $(#[$meta])* + pub const fn [](mut self, $name: $type) -> Self { + self.raw.$name = $e; + self + } + } + }; +} + +// macro use only +#[doc(hidden)] +pub trait ConfigOps { + fn is_readable_reg(reg: u32) -> bool; + fn is_writeable_reg(reg: u32) -> bool; + fn is_volatile_reg(reg: u32) -> bool; + fn is_precious_reg(reg: u32) -> bool; +} + +/// Regmap Configuration +pub struct Config { + raw: bindings::regmap_config, + _phantom: PhantomData, +} +impl Config { + /// Create a new regmap Config + pub const fn new(reg_bits: i32, val_bits: i32) -> Self { + let cfg = MaybeUninit::::zeroed(); + let mut cfg = unsafe { cfg.assume_init() }; + + cfg.reg_bits = reg_bits; + cfg.val_bits = val_bits; + cfg.writeable_reg = Some(Self::writeable_reg_callback); + cfg.readable_reg = Some(Self::readable_reg_callback); + cfg.volatile_reg = Some(Self::volatile_reg_callback); + cfg.precious_reg = Some(Self::precious_reg_callback); + + Self { + raw: cfg, + _phantom: PhantomData, + } + } + + config_with!( + /// Specifies the maximum valid register address. + max_register: u32 + ); + + config_with!( + /// Type of caching being performed. + cache_type: CacheType, cache_type as _ + ); + + unsafe extern "C" fn writeable_reg_callback(_dev: *mut bindings::device, reg: u32) -> bool { + T::is_writeable_reg(reg) + } + + unsafe extern "C" fn readable_reg_callback(_dev: *mut bindings::device, reg: u32) -> bool { + T::is_readable_reg(reg) + } + + unsafe extern "C" fn volatile_reg_callback(_dev: *mut bindings::device, reg: u32) -> bool { + T::is_volatile_reg(reg) + } + + unsafe extern "C" fn precious_reg_callback(_dev: *mut bindings::device, reg: u32) -> bool { + T::is_precious_reg(reg) + } +} + +/// Definitions describing how registers can be accessed. +pub mod access { + /// Register can be read from. + pub const READ: u32 = 0b000001; + /// Register can be written to. + pub const WRITE: u32 = 0b000010; + /// Register should not be read outside of a call from the driver. + pub const PRECIOUS: u32 = 0b000100; + /// Register value can't be cached. + pub const VOLATILE: u32 = 0b001000; + + /// Register can be read from and written to. + pub const RW: u32 = READ | WRITE; +} + +// macro use only +#[doc(hidden)] +#[macro_export] +macro_rules! regmap_check_access { + ($type:ident, $access:expr, $reg:ident, $addr:literal) => { + if kernel::regmap::access::$type & $access > 0 && $reg == $addr { + return true; + } + }; +} +// macro use only +#[doc(hidden)] +pub use regmap_check_access; + +/// Common operations for all field types +pub trait FieldCommonOps { + /// Get the Mask for the field + fn mask() -> u32; +} + +/// Read operations for fields with `bit` type +pub trait BitFieldReadOps { + /// Returns whether the bit is set + fn is_set(fields: &mut Fields) -> Result; +} + +/// Write operations for fields with `bit` type +pub trait BitFieldWriteOps { + /// Set the bit + fn set(fields: &mut Fields) -> Result; + + /// Force set the bit + fn force_set(fields: &mut Fields) -> Result; + + /// Clear the bit + fn clear(fields: &mut Fields) -> Result; + + /// Force clear the bit + fn force_clear(fields: &mut Fields) -> Result; +} + +/// Read operations for fields with `enum` type +pub trait EnumFieldReadOps { + #[doc(hidden)] + /// Underlying enum type reprensenting the field values + type EnumType; + + /// Read the field + fn read(fields: &mut Fields) -> Result; +} + +/// Write operations for fields with `enum` type +pub trait EnumFieldWriteOps { + #[doc(hidden)] + /// Underlying enum type reprensenting the field values + type EnumType; + + /// Write the field + fn write(fields: &mut Fields, val: Self::EnumType) -> Result; + + /// Force write the field + fn force_write(fields: &mut Fields, val: Self::EnumType) -> Result; +} + +/// Read operations for fields with `raw` type +pub trait RawFieldReadOps { + /// Read the field + fn read(fields: &mut Fields) -> Result; + + /// Test the field bits + fn test_bits(fields: &mut Fields, bits: core::ffi::c_uint) -> Result; +} + +/// Write operations for fields with `raw` type +pub trait RawFieldWriteOps { + /// Write the field + fn write(fields: &mut Fields, val: core::ffi::c_uint) -> Result; + + /// Force write the field + fn force_write(fields: &mut Fields, val: core::ffi::c_uint) -> Result; + + /// Update the field using a mask + fn update_bits( + fields: &mut Fields, + mask: core::ffi::c_uint, + val: core::ffi::c_uint, + ) -> Result; + + /// Force update the field using a mask + fn force_update_bits( + fields: &mut Fields, + mask: core::ffi::c_uint, + val: core::ffi::c_uint, + ) -> Result; + + /// Set field bits + fn set_bits(fields: &mut Fields, bits: core::ffi::c_uint) -> Result; + + /// Clear the field bits + fn clear_bits(fields: &mut Fields, bits: core::ffi::c_uint) -> Result; +} + +// macro use only +#[doc(hidden)] +#[macro_export] +macro_rules! regmap_field_bit { + ($field_name:ident, $access: expr, $reg:literal, $pos:literal, rw) => { + kernel::static_assert!($access & kernel::regmap::access::RW == kernel::regmap::access::RW); + + $crate::regmap_field_bit!($field_name, $reg, $pos, reserved); + $crate::regmap_field_bit!($field_name, _ro); + $crate::regmap_field_bit!($field_name, _wo); + }; + + ($field_name:ident, $access: expr, $reg:literal, $pos:literal, ro) => { + kernel::static_assert!( + $access & kernel::regmap::access::READ == kernel::regmap::access::READ + ); + + $crate::regmap_field_bit!($field_name, $reg, $pos, reserved); + $crate::regmap_field_bit!($field_name, _ro); + }; + + ($field_name:ident, $access: expr, $reg:literal, $pos:literal, wo) => { + kernel::static_assert!( + $access & kernel::regmap::access::WRITE == kernel::regmap::access::WRITE + ); + + $crate::regmap_field_bit!($field_name, $reg, $pos, reserved); + $crate::regmap_field_bit!($field_name, _wo); + }; + + ($field_name:ident, $reg:literal, $pos:literal, reserved) => { + kernel::macros::paste! { + struct [<_Bit $pos >]; + } + + impl $field_name { + pub(crate) const fn reg_field() -> bindings::reg_field { + bindings::reg_field { + reg: $reg, + lsb: $pos, + msb: $pos + 1, + id_offset: 0, + id_size: 0, + } + } + + #[allow(dead_code)] + pub(crate) const fn mask() -> u32 { + kernel::bits::genmask($pos, $pos) + } + } + }; + + ($field_name:ident, _ro) => { + impl super::BitFieldReadOps for $field_name { + fn is_set(fields: &mut regmap::Fields) -> Result { + let field = unsafe { fields.index(Self::id() as usize) }; + let mut val: core::ffi::c_uint = 0; + kernel::error::to_result(unsafe { bindings::regmap_field_read(field, &mut val) })?; + Ok(val == 1) + } + } + }; + + ($field_name:ident, _wo) => { + impl super::BitFieldWriteOps for $field_name { + fn set(fields: &mut regmap::Fields) -> Result { + let field = unsafe { fields.index(Self::id() as usize) }; + kernel::error::to_result(unsafe { bindings::regmap_field_write(field, 1) }) + } + + fn force_set(fields: &mut regmap::Fields) -> Result { + let field = unsafe { fields.index(Self::id() as usize) }; + kernel::error::to_result(unsafe { bindings::regmap_field_force_write(field, 1) }) + } + + fn clear(fields: &mut regmap::Fields) -> Result { + let field = unsafe { fields.index(Self::id() as usize) }; + kernel::error::to_result(unsafe { bindings::regmap_field_write(field, 0) }) + } + + fn force_clear(fields: &mut regmap::Fields) -> Result { + let field = unsafe { fields.index(Self::id() as usize) }; + kernel::error::to_result(unsafe { bindings::regmap_field_force_write(field, 0) }) + } + } + }; +} + +// macro use only +#[doc(hidden)] +#[macro_export] +macro_rules! regmap_field_enum { + ($field_name:ident, $access: expr, $reg:literal, [$msb:literal:$lsb:literal], ro, { + $($k:ident = $v:literal,)+ }) => { + kernel::static_assert!( + $access & kernel::regmap::access::READ == kernel::regmap::access::READ + ); + + $crate::regmap_field_enum!($field_name, $reg, [$msb:$lsb], reserved, { $($k = $v,)+ }); + $crate::regmap_field_enum!($field_name, _ro); + }; + + ($field_name:ident, $access: expr, $reg:literal, [$msb:literal:$lsb:literal], rw, { + $($k:ident = $v:literal,)+ }) => { + kernel::static_assert!($access & kernel::regmap::access::RW == kernel::regmap::access::RW); + + $crate::regmap_field_enum!($field_name, $reg, [$msb:$lsb], reserved, { $($k = $v,)+ }); + $crate::regmap_field_enum!($field_name, _ro); + $crate::regmap_field_enum!($field_name, _wo); + }; + + ($field_name:ident, $access: expr, $reg:literal, [$msb:literal:$lsb:literal], wo, { + $($k:ident = $v:literal,)+ }) => { + kernel::static_assert!( + $access & kernel::regmap::access::WRITE == kernel::regmap::access::WRITE + ); + + $crate::regmap_field_enum!($field_name, $reg, [$msb:$lsb], reserved, { $($k = $v,)+ }); + $crate::regmap_field_enum!($field_name, _wo); + }; + + ($field_name:ident, $reg:literal, [$msb:literal:$lsb:literal], reserved, { + $($k:ident = $v:literal,)+ }) => { + kernel::macros::foreach!(i in $lsb..=$msb { + kernel::macros::paste! { + struct [<_Bit $i>]; + } + }); + + kernel::macros::paste! { + #[repr(u32)] + #[allow(non_camel_case_types)] + pub(crate) enum [<$field_name _enum>] { + $($k = $v,)+ + } + + impl TryFrom for [<$field_name _enum>] { + type Error = kernel::error::Error; + + fn try_from(raw_value: core::ffi::c_uint) -> Result { + match raw_value { + $($v => Ok(Self::$k),)+ + _ => Err(kernel::error::code::EINVAL), + } + } + } + + impl $field_name { + pub(crate) const fn reg_field() -> bindings::reg_field { + bindings::reg_field { + reg: $reg, + lsb: $lsb, + msb: $msb, + id_offset: 0, + id_size: 0, + } + } + + #[allow(dead_code)] + pub(crate) const fn mask() -> u32 { + kernel::bits::genmask($msb, $lsb) + } + } + } + }; + + ($field_name:ident, _ro) => { + impl super::EnumFieldReadOps for $field_name { + type EnumType = kernel::macros::paste! {[<$field_name _enum>]}; + + fn read(fields: &mut regmap::Fields) -> Result { + Self::EnumType::try_from(fields.read(Self::id() as usize)?) + } + } + }; + + ($field_name:ident, _wo) => { + impl super::EnumFieldWriteOps for $field_name { + type EnumType = kernel::macros::paste! {[<$field_name _enum>]}; + + fn write( + fields: &mut regmap::Fields, + val: Self::EnumType + ) -> Result { + let field = unsafe { fields.index(Self::id() as usize) }; + let ret = unsafe { bindings::regmap_field_write(field, val as _) }; + kernel::error::to_result(ret) + } + + fn force_write( + fields: &mut regmap::Fields, + val: Self::EnumType + ) -> Result { + let field = unsafe { fields.index(Self::id() as usize) }; + let ret = unsafe { bindings::regmap_field_force_write(field, val as _) }; + kernel::error::to_result(ret) + } + } + }; +} + +// macro use only +#[doc(hidden)] +#[macro_export] +macro_rules! regmap_field_raw { + ($field_name:ident, $access: expr, $reg:literal, [$msb:literal:$lsb:literal], rw) => { + kernel::static_assert!($access & kernel::regmap::access::RW == kernel::regmap::access::RW); + + $crate::regmap_field_raw!($field_name, $reg, [$msb:$lsb], reserved); + $crate::regmap_field_raw!($field_name, $reg, [$msb:$lsb], _ro); + $crate::regmap_field_raw!($field_name, $reg, [$msb:$lsb], _wo); + }; + + ($field_name:ident, $access: expr, $reg:literal, [$msb:literal:$lsb:literal], ro) => { + kernel::static_assert!( + $access & kernel::regmap::access::READ == kernel::regmap::access::READ + ); + + $crate::regmap_field_raw!($field_name, $reg, [$msb:$lsb], reserved); + $crate::regmap_field_raw!($field_name, $reg, [$msb:$lsb], _ro); + }; + + ($field_name:ident, $access: expr, $reg:literal, [$msb:literal:$lsb:literal], wo) => { + kernel::static_assert!( + $access & kernel::regmap::access::WRITE == kernel::regmap::access::WRITE + ); + + $crate::regmap_field_raw!($field_name, $reg, [$msb:$lsb], reserved); + $crate::regmap_field_raw!($field_name, $reg, [$msb:$lsb], _wo); + }; + + ($field_name:ident, $reg:literal, [$msb:literal:$lsb:literal], reserved) => { + kernel::macros::foreach!(i in $lsb..=$msb { + kernel::macros::paste! { + struct [<_Bit $i>]; + } + }); + + impl $field_name { + pub(crate) const fn reg_field() -> bindings::reg_field { + bindings::reg_field { + reg: $reg, + lsb: $lsb, + msb: $msb, + id_offset: 0, + id_size: 0, + } + } + + #[allow(dead_code)] + pub(crate) const fn mask() -> u32 { + kernel::bits::genmask($msb, $lsb) + } + } + }; + + ($field_name:ident, $reg:literal, [$msb:literal:$lsb:literal], _ro) => { + impl super::RawFieldReadOps for $field_name { + fn read(fields: &mut regmap::Fields) -> Result { + fields.read(Self::id() as usize) + } + + fn test_bits( + fields: &mut regmap::Fields, + bits: core::ffi::c_uint, + ) -> Result { + let field = unsafe { fields.index(Self::id() as usize) }; + kernel::error::to_result(unsafe { bindings::regmap_field_test_bits(field, bits) }) + } + } + }; + + ($field_name:ident, $reg:literal, [$msb:literal:$lsb:literal], _wo) => { + impl super::RawFieldWriteOps for $field_name { + fn write( + fields: &mut regmap::Fields, + val: core::ffi::c_uint, + ) -> Result { + let field = unsafe { fields.index(Self::id() as usize) }; + kernel::error::to_result(unsafe { bindings::regmap_field_write(field, val as _) }) + } + + fn force_write( + fields: &mut regmap::Fields, + val: core::ffi::c_uint, + ) -> Result { + let field = unsafe { fields.index(Self::id() as usize) }; + kernel::error::to_result(unsafe { + bindings::regmap_field_force_write(field, val as _) + }) + } + + fn update_bits( + fields: &mut regmap::Fields, + mask: core::ffi::c_uint, + val: core::ffi::c_uint, + ) -> Result { + let field = unsafe { fields.index(Self::id() as usize) }; + kernel::error::to_result(unsafe { + bindings::regmap_field_update_bits(field, mask, val) + }) + } + + fn force_update_bits( + fields: &mut regmap::Fields, + mask: core::ffi::c_uint, + val: core::ffi::c_uint, + ) -> Result { + let field = unsafe { fields.index(Self::id() as usize) }; + kernel::error::to_result(unsafe { + bindings::regmap_field_force_update_bits(field, mask, val) + }) + } + + fn set_bits( + fields: &mut regmap::Fields, + bits: core::ffi::c_uint, + ) -> Result { + let field = unsafe { fields.index(Self::id() as usize) }; + kernel::error::to_result(unsafe { bindings::regmap_field_set_bits(field, bits) }) + } + + fn clear_bits( + fields: &mut regmap::Fields, + bits: core::ffi::c_uint, + ) -> Result { + let field = unsafe { fields.index(Self::id() as usize) }; + kernel::error::to_result(unsafe { bindings::regmap_field_clear_bits(field, bits) }) + } + } + }; +} + +// macro use only +#[doc(hidden)] +#[macro_export] +macro_rules! regmap_fields { + ($type:ident, $reg:ident, $access:expr, $name:ident, $($t:tt)*) => { + kernel::macros::paste! { + #[allow(non_camel_case_types)] + pub(crate) struct $name; + + impl $name { + #[allow(dead_code)] + pub(crate) const fn id() -> super::Fields { + super::Fields::[<$reg _ $name>] + } + } + + $crate::[]!($name, $access, $($t)*); + } + }; +} + +// macro use only +#[doc(hidden)] +#[macro_export] +macro_rules! regmap_reg_field { + ($reg_name:ident, $field_name:ident) => { + register::$reg_name::$field_name::reg_field() + }; +} + +// macro use only +#[doc(hidden)] +#[macro_export] +macro_rules! regmap_count_fields { + () => { 0usize }; + ($type:ident $($rhs:ident)*) => { 1 + $crate::regmap_count_fields!($($rhs)*) }; +} + +/// Define regmap field descriptors +/// +/// # Syntax +/// +/// ```ignore +/// define_regmap_field_desc!(VAR_NAME, { , [, ...] }); +/// +/// : +/// (name, address, access_permission, { , [, ...] }) +/// +/// : +/// field_name => (...), +/// +/// : +/// * raw(, ) +/// * bit(, ) +/// * enum(, , { +/// EnumKind = , [EnumKind2 = , ...] +/// }) +/// +/// : +/// * ro: read-only +/// * rw: read-write +/// * wo: write-only +/// ``` +/// +/// # Examples +/// +/// ```ignore +/// regmap::define_regmap_field_descs!(FIELD_DESCS, { +/// (pid, 0x3, READ, { value => raw([7:0], ro) }), +/// (limconf, 0x16, RW, { +/// rearm => bit(0, rw), +/// rststatus => bit(1, rw), +/// tpwth => enum([5:4], rw, { +/// Temp83C = 0x0, +/// Temp94C = 0x1, +/// Temp105C = 0x2, +/// Temp116C = 0x3, +/// }), +/// }) +/// }); +/// +/// fn probe(client: &mut i2c::Client) -> Result { +/// # let config = regmap::Config::::new(8, 8) +/// # .with_max_register(0x16) +/// # .with_cache_type(regmap::CacheType::RbTree); +/// # let regmap = Arc::try_new(regmap::Regmap::init_i2c(client, &config))?; +/// # let mut fields = regmap.alloc_fields(&FIELD_DESCS)?; +/// // ... +/// dev_info!(client, "PID: {:#x}", pid::value::read(&mut fields)?); +/// // ... +/// } +/// ``` +#[macro_export] +macro_rules! define_regmap_field_descs { + ($name:ident, { + $(( + $reg_name:ident, $reg_addr:literal, $access:expr, { + $($field_name:ident => $type:ident($($x:tt),*)),* $(,)? + } + )),+ + }) => { + mod register { + use kernel::regmap::{ + access::*, + BitFieldReadOps, BitFieldWriteOps, + ConfigOps, + EnumFieldReadOps, EnumFieldWriteOps, + RawFieldReadOps, RawFieldWriteOps + }; + + kernel::macros::paste! { + $( + pub(crate) mod $reg_name { + use kernel::{bindings, error::{Result}, regmap::{self, access::*}}; + $( + $crate::regmap_fields!($type, $reg_name, $access, $field_name, + $reg_addr, $($x),*); + )* + + #[allow(dead_code)] + pub(crate) const fn addr() -> u32 { + $reg_addr + } + } + )+ + + #[repr(u32)] + #[allow(non_camel_case_types)] + pub(crate) enum Fields { + $($( + [<$reg_name _ $field_name>], + )*)+ + } + + pub(crate) struct AccessOps; + impl ConfigOps for AccessOps { + fn is_readable_reg(reg: u32) -> bool { + $( + kernel::regmap::regmap_check_access!(READ, $access, reg, $reg_addr); + )+ + + false + } + + fn is_writeable_reg(reg: u32) -> bool { + $( + kernel::regmap::regmap_check_access!(WRITE, $access, reg, $reg_addr); + )+ + + false + } + + fn is_volatile_reg(reg: u32) -> bool { + $( + kernel::regmap::regmap_check_access!(VOLATILE, $access, reg, $reg_addr); + )+ + + false + } + + fn is_precious_reg(reg: u32) -> bool { + $( + kernel::regmap::regmap_check_access!(PRECIOUS, $access, reg, $reg_addr); + )+ + + false + } + } + } + } + + const $name: regmap::FieldDescs<{$crate::regmap_count_fields!($($($type)*)+)}> = + regmap::FieldDescs::new([ + $( + $( + $crate::regmap_reg_field!($reg_name, $field_name) + ),* + ),+ + ]); + }; +} +pub use define_regmap_field_descs; diff --git a/rust/kernel/regulator.rs b/rust/kernel/regulator.rs new file mode 100644 index 00000000000000..c932794030e45f --- /dev/null +++ b/rust/kernel/regulator.rs @@ -0,0 +1,45 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! SoC Regulators + +pub mod consumer; +pub mod driver; + +use crate::{ + bindings, + error::{code::*, Error, Result}, +}; + +/// [`consumer::Regulator`] and [`driver::Regulator`] operating modes +#[derive(Copy, Clone)] +#[repr(u32)] +pub enum Mode { + /// Invalid mode + Invalid = bindings::REGULATOR_MODE_INVALID, + /// Regulator can handle fast changes in it's load + Fast = bindings::REGULATOR_MODE_FAST, + /// Normal regulator power supply mode + Normal = bindings::REGULATOR_MODE_NORMAL, + /// Regulator runs in a more efficient mode for light loads + Idle = bindings::REGULATOR_MODE_IDLE, + /// Regulator runs in the most efficient mode for very light loads + Standby = bindings::REGULATOR_MODE_STANDBY, +} + +impl TryFrom for Mode { + type Error = Error; + + /// Convert a mode represented as an unsigned integer into its Rust enum equivalent + /// + /// If the integer does not match any of the [`Mode`], then [`EINVAL`] is returned + fn try_from(mode: core::ffi::c_uint) -> Result { + match mode { + bindings::REGULATOR_MODE_FAST => Ok(Self::Fast), + bindings::REGULATOR_MODE_NORMAL => Ok(Self::Normal), + bindings::REGULATOR_MODE_IDLE => Ok(Self::Idle), + bindings::REGULATOR_MODE_STANDBY => Ok(Self::Standby), + bindings::REGULATOR_MODE_INVALID => Ok(Self::Invalid), + _ => Err(EINVAL), + } + } +} diff --git a/rust/kernel/regulator/consumer.rs b/rust/kernel/regulator/consumer.rs new file mode 100644 index 00000000000000..ea85aa30a49a2a --- /dev/null +++ b/rust/kernel/regulator/consumer.rs @@ -0,0 +1,393 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! SoC Regulator consumer abstractions. +//! +//! C header: [`include/linux/regulator/consumer.h`](srctree/include/linux/regulator/consumer.h) +//! +//! Reference: + +use crate::{ + bindings, + device::Device, + error::{code::*, from_err_ptr, to_result, Error, Result}, + regulator::Mode, + str::CStr, +}; +use core::{ + cmp::min, + ffi::{c_int, c_uint}, + mem::ManuallyDrop, + time::Duration, +}; + +/// [`Regulator`] in its default state (disabled) +/// +/// # Invariants +/// - [`self.0`] is valid and non-null +pub struct Regulator(*mut bindings::regulator); + +impl Regulator { + /// Lookup and obtain an instance of a regulator + /// + /// If the supply does not exists a dummy one will be + /// created + pub fn get>(dev: T, id: &'static CStr) -> Result { + // SAFETY: `dev.as_raw() is valid and non-null by the type invariant and + // id has a static lifetime so it lives indefinitely + let reg = from_err_ptr(unsafe { + bindings::regulator_get(dev.as_ref().as_raw(), id.as_char_ptr()) + })?; + + // This should not happen: in case of error `regulator_get` returns an + // error encoded into the pointer. And in case the device does not + // exists, a dummy regulator is returned + if reg.is_null() { + return Err(ENODEV); + } + + Ok(Self(reg)) + } + + /// Same as `get`, but if the regulator does not exists + /// an error will be returned instead of a dummy regulator + pub fn get_optional>(dev: T, id: &'static CStr) -> Result { + // SAFETY: `dev.as_raw() is valid and non-null by the type invariant and + // id has a static lifetime so it lives indefinitely + let reg = from_err_ptr(unsafe { + bindings::regulator_get_optional(dev.as_ref().as_raw(), id.as_char_ptr()) + })?; + + // does not exists `regulator_get_optional` returns an + // error encoded into the pointer. + if reg.is_null() { + return Err(ENODEV); + } + + Ok(Self(reg)) + } + + /// Same as `get` but ensure that we have exclusive access to the regulator + pub fn get_exclusive>(dev: T, id: &'static CStr) -> Result { + // SAFETY: `dev.as_raw() is valid and non-null by the type invariant and + // id has a static lifetime so it lives indefinitely + let reg = from_err_ptr(unsafe { + bindings::regulator_get_exclusive(dev.as_ref().as_raw(), id.as_char_ptr()) + })?; + + // This should not happen: in case of error `regulator_get` returns an + // error encoded into the pointer. And in case the device does not + // exists, a dummy regulator is returned + if reg.is_null() { + return Err(ENODEV); + } + + Ok(Self(reg)) + } + + /// Enable the regulator + pub fn enable(self) -> Result { + // SAFETY: The pointer is valid and non-null by the type invariant + to_result(unsafe { bindings::regulator_enable(self.0) })?; + Ok(EnabledRegulator(self)) + } + + /// Force disable the regulator. Even if other consumer + /// have enabled it, the regulator will be forcibly disabled. + pub fn force_disable(&mut self) -> Result { + // SAFETY: The pointer is valid and non-null by the type invariant + to_result(unsafe { bindings::regulator_force_disable(self.0) }) + } + + /// Check if the voltage range can be supported + pub fn is_supported_voltage(&self, min_uv: c_int, max_uv: c_int) -> Result { + // SAFETY: The pointer is valid and non-null by the type invariant + let ret = unsafe { bindings::regulator_is_supported_voltage(self.0, min_uv, max_uv) }; + if ret < 0 { + return Err(Error::from_errno(ret)); + } + + Ok(ret > 0) + } + + /// Returns the number of selectors supported by the regulator + pub fn count_voltages(&self) -> Result { + // SAFETY: The pointer is valid and non-null by the type invariant + let ret = unsafe { bindings::regulator_count_voltages(self.0) }; + if ret < 0 { + return Err(Error::from_errno(ret)); + } + + Ok(ret as _) + } + + /// Returns the voltage corresponding to the `selector` + pub fn list_voltage(&self, selector: c_uint) -> Result> { + // SAFETY: The pointer is valid and non-null by the type invariant + let ret = unsafe { bindings::regulator_list_voltage(self.0, selector) }; + if ret < 0 { + return Err(Error::from_errno(ret)); + } + + Ok(if ret == 0 { None } else { Some(ret) }) + } + + /// Returns the voltage step size between VSEL values + pub fn get_linear_step(&self) -> Option { + // SAFETY: The pointer is valid and non-null by the type invariant + let ret = unsafe { bindings::regulator_get_linear_step(self.0) }; + if ret == 0 { + None + } else { + Some(ret) + } + } + + /// Returns the regulator output voltage + pub fn get_voltage(&self) -> Result { + // SAFETY: The pointer is valid and non-null by the type invariant + let ret = unsafe { bindings::regulator_get_voltage(self.0) }; + if ret < 0 { + return Err(Error::from_errno(ret)); + } + + Ok(ret) + } + + /// Set the regulator output voltage + pub fn set_voltage(&mut self, min_uv: c_int, max_uv: c_int) -> Result { + // SAFETY: The pointer is valid and non-null by the type invariant + to_result(unsafe { bindings::regulator_set_voltage(self.0, min_uv, max_uv) }) + } + + /// Get the raise/fall time required for switching voltage + pub fn set_voltage_time(&mut self, old_uv: c_int, new_uv: c_int) -> Result { + // SAFETY: The pointer is valid and non-null by the type invariant + let ret = unsafe { bindings::regulator_set_voltage_time(self.0, old_uv, new_uv) }; + if ret < 0 { + return Err(Error::from_errno(ret)); + } + + Ok(ret) + } + + /// Re-apply last regulator output voltage + pub fn sync_voltage(&mut self) -> Result { + // SAFETY: The pointer is valid and non-null by the type invariant + to_result(unsafe { bindings::regulator_sync_voltage(self.0) }) + } + + /// Get regulator output current + pub fn get_current_limit(&self) -> Result { + // SAFETY: The pointer is valid and non-null by the type invariant + let ret = unsafe { bindings::regulator_get_current_limit(self.0) }; + if ret < 0 { + return Err(Error::from_errno(ret)); + } + + Ok(ret) + } + + /// Set regulator output current limit + pub fn set_current_limit(&mut self, min_ua: c_int, max_ua: c_int) -> Result { + // SAFETY: The pointer is valid and non-null by the type invariant + let ret = unsafe { bindings::regulator_set_current_limit(self.0, min_ua, max_ua) }; + if ret < 0 { + return Err(Error::from_errno(ret)); + } + + Ok(ret) + } + + /// Set regulator load + pub fn set_load(&mut self, load_ua: c_int) -> Result { + // SAFETY: The pointer is valid and non-null by the type invariant + to_result(unsafe { bindings::regulator_set_load(self.0, load_ua) }) + } + + /// Allow the regulator to go into bypass mode + pub fn allow_bypass(&mut self, allow: bool) -> Result { + // SAFETY: The pointer is valid and non-null by the type invariant + to_result(unsafe { bindings::regulator_allow_bypass(self.0, allow) }) + } + + /// Set the mode of the regulator + pub fn set_mode(&mut self, mode: Mode) -> Result { + // SAFETY: The pointer is valid and non-null by the type invariant + to_result(unsafe { bindings::regulator_set_mode(self.0, mode as _) }) + } + + /// Get the current mode of the regulator + pub fn get_mode(&mut self) -> Result { + // SAFETY: The pointer is valid and non-null by the type invariant + Mode::try_from(unsafe { bindings::regulator_get_mode(self.0) }) + } +} + +impl Drop for Regulator { + fn drop(&mut self) { + // SAFETY: The pointer is valid and non-null by the type invariant + unsafe { bindings::regulator_put(self.0) } + } +} + +// SAFETY: `Regulator` is not restricted to a single thread so it is safe +// to move it between threads +unsafe impl Send for Regulator {} + +/// [`Regulator`] that has been enabled +pub struct EnabledRegulator(Regulator); + +impl EnabledRegulator { + /// Disable the regulator + pub fn disable(self) -> Result { + // SAFETY: The pointer is valid and non-null by the type invariant + let ret = unsafe { bindings::regulator_disable(self.0 .0) }; + if ret < 0 { + let mut reg = ManuallyDrop::new(self); + Ok(core::mem::replace( + &mut reg.0, + Regulator(core::ptr::null_mut()), + )) + } else { + Err(Error::from_errno(ret)) + } + } + + /// Disable the regulator with a specified delay + /// + /// Every non-zero delay < 1ms will be rounded up to 1ms, and any delay + /// longer than [`core::ffi::c_int`] will become [`core::ffi::c_int::MAX`] + pub fn disable_deferred(self, duration: Duration) -> Result { + let ms = min(duration.as_millis(), c_int::MAX as u128) as c_int; + // SAFETY: The pointer is valid and non-null by the type invariant + let ret = unsafe { bindings::regulator_disable_deferred(self.0 .0, ms) }; + if ret < 0 { + let mut reg = core::mem::ManuallyDrop::new(self); + Ok(core::mem::replace( + &mut reg.0, + Regulator(core::ptr::null_mut()), + )) + } else { + Err(Error::from_errno(ret)) + } + } + + /* Shared functions */ + + /// See [`Regulator::force_disable`] + pub fn force_disable(self) -> Result { + // SAFETY: The pointer is valid and non-null by the type invariant + let ret = unsafe { bindings::regulator_force_disable(self.0 .0) }; + if ret < 0 { + let mut reg = core::mem::ManuallyDrop::new(self); + Ok(core::mem::replace( + &mut reg.0, + Regulator(core::ptr::null_mut()), + )) + } else { + Err(Error::from_errno(ret)) + } + } + + /// See [`Regulator::is_supported_voltage`] + pub fn is_supported_voltage(&self, min_uv: c_int, max_uv: c_int) -> Result { + self.0.is_supported_voltage(min_uv, max_uv) + } + + /// See [`Regulator::count_voltages`] + pub fn count_voltages(&self) -> Result { + self.0.count_voltages() + } + + /// See [`Regulator::list_voltage`] + pub fn list_voltage(&self, selector: c_uint) -> Result> { + self.0.list_voltage(selector) + } + + /// See [`Regulator::get_linear_step`] + pub fn get_linear_step(&self) -> Option { + self.0.get_linear_step() + } + + /// See [`Regulator::get_voltage`] + pub fn get_voltage(&self) -> Result { + self.0.get_voltage() + } + + /// See [`Regulator::set_voltage`] + pub fn set_voltage(&mut self, min_uv: c_int, max_uv: c_int) -> Result { + self.0.set_voltage(min_uv, max_uv) + } + + /// See [`Regulator::set_voltage_time`] + pub fn set_voltage_time(&mut self, old_uv: c_int, new_uv: c_int) -> Result { + self.0.set_voltage_time(old_uv, new_uv) + } + + /// See [`Regulator::sync_voltage`] + pub fn sync_voltage(&mut self) -> Result { + self.0.sync_voltage() + } + + /// See [`Regulator::get_current_limit`] + pub fn get_current_limit(&self) -> Result { + self.0.get_current_limit() + } + + /// See [`Regulator::set_current_limit`] + pub fn set_current_limit(&mut self, min_ua: c_int, max_ua: c_int) -> Result { + self.0.set_current_limit(min_ua, max_ua) + } + + /// See [`Regulator::set_load`] + pub fn set_load(&mut self, load_ua: c_int) -> Result { + self.0.set_load(load_ua) + } + + /// See [`Regulator::allow_bypass`] + pub fn allow_bypass(&mut self, allow: bool) -> Result { + self.0.allow_bypass(allow) + } + + /// See [`Regulator::set_mode`] + pub fn set_mode(&mut self, mode: Mode) -> Result { + self.0.set_mode(mode) + } + + /// See [`Regulator::get_mode`] + pub fn get_mode(&mut self) -> Result { + self.0.get_mode() + } +} + +impl Drop for EnabledRegulator { + fn drop(&mut self) { + // SAFETY: The pointer is valid and non-null by the type invariant + let _ = unsafe { bindings::regulator_disable(self.0 .0) }; + } +} + +impl PartialEq for Regulator { + fn eq(&self, other: &Regulator) -> bool { + // SAFETY: The pointers are valid and non-null by the type invariant + unsafe { bindings::regulator_is_equal(self.0, other.0) } + } +} + +impl PartialEq for Regulator { + fn eq(&self, other: &EnabledRegulator) -> bool { + self.eq(&other.0) + } +} + +impl PartialEq for EnabledRegulator { + fn eq(&self, other: &EnabledRegulator) -> bool { + self.0.eq(&other.0) + } +} + +impl PartialEq for EnabledRegulator { + fn eq(&self, other: &Regulator) -> bool { + self.0.eq(other) + } +} diff --git a/rust/kernel/regulator/driver.rs b/rust/kernel/regulator/driver.rs new file mode 100644 index 00000000000000..ccd3f9a465653b --- /dev/null +++ b/rust/kernel/regulator/driver.rs @@ -0,0 +1,957 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! SoC Regulator Driver Interface +//! +//! C header: [`include/linux/regulator/driver.h`](srctree/include/linux/regulator/driver.h) +//! +//! # Examples +//! +//! ```ignore +//! use kernel::regulator::driver::{Config, Desc, Driver, Registration, Type}; +//! # use kernel::{c_str, device::Device, module_platform_driver, of, platform, prelude::*}; +//! # +//! # module_platform_driver! { +//! # type: MyRegulatorDriver, +//! # name: "my_regulator_driver", +//! # license: "GPL", +//! # } +//! # +//! # kernel::module_of_id_table!(OF_MOD_TABLE, MY_REG_DRIVER_OF_ID_TABLE); +//! # kernel::define_of_id_table! {MY_REG_DRIVER_OF_ID_TABLE, (), [ +//! # (of::DeviceId::Compatible(b"my-regulator-driver"), None), +//! # ]} +//! +//! static DESC: Desc = +//! Desc::new::(c_str!("my-regulator-driver"), Type::Voltage) +//! .with_owner(&THIS_MODULE); +//! +//! struct MyRegulatorDriver; +//! +//! impl platform::Driver for MyRegulatorDriver { +//! # kernel::driver_of_id_table!(MY_REG_DRIVER_OF_ID_TABLE); +//! # +//! fn probe(pdev: &mut platform::Device, _id_info: Option<&Self::IdInfo>) -> Result { +//! let reg = Registration::register(pdev, &DESC, Config::::new(pdev))?; +//! Ok(()) +//! } +//! } +//! +//! #[vtable] +//! impl Driver for MyRegulatorDriver { +//! // Implement supported `Driver`'s operations here. +//! } +//! ``` + +use crate::{ + device::Device, + error::{code::*, from_err_ptr, from_result, Error, Result}, + macros::vtable, + regulator::Mode, + str::CStr, + sync::Arc, + types::ForeignOwnable, + ThisModule, +}; +#[cfg(CONFIG_REGMAP)] +use crate::{error::to_result, regmap::Regmap}; +use core::{ + marker::PhantomData, + mem::{ManuallyDrop, MaybeUninit}, +}; + +#[cfg(not(CONFIG_REGMAP))] +struct Regmap; + +#[cfg(not(CONFIG_REGMAP))] +impl Regmap { + fn as_ptr(&self) -> *mut bindings::regmap { + core::ptr::null_mut() + } +} + +/// [`Regulator`]'s status +/// +/// Corresponds to the kernel's [`enum regulator_status`]. +/// +/// [`enum regulator_status`]: srctree/include/linux/regulator/driver.h +#[derive(Eq, PartialEq)] +pub enum Status { + /// Regulator is off + Off, + /// Regulator is on + On, + /// Regulator is in an error state + Error, + /// Regulator is on and in Fast mode + Fast, + /// Regulator is on and in Normal mode + Normal, + /// Regulator is on and in Idle mode + Idle, + /// Regulator is on and in Standby mode + Standby, + /// Regulator is enabled but not regulating + Bypass, + /// Regulator is any other status + Undefined, +} + +impl TryFrom for Status { + type Error = Error; + + fn try_from(status: core::ffi::c_uint) -> Result { + match status { + bindings::regulator_status_REGULATOR_STATUS_OFF => Ok(Self::Off), + bindings::regulator_status_REGULATOR_STATUS_ON => Ok(Self::On), + bindings::regulator_status_REGULATOR_STATUS_ERROR => Ok(Self::Error), + bindings::regulator_status_REGULATOR_STATUS_FAST => Ok(Self::Fast), + bindings::regulator_status_REGULATOR_STATUS_NORMAL => Ok(Self::Normal), + bindings::regulator_status_REGULATOR_STATUS_IDLE => Ok(Self::Idle), + bindings::regulator_status_REGULATOR_STATUS_STANDBY => Ok(Self::Standby), + bindings::regulator_status_REGULATOR_STATUS_BYPASS => Ok(Self::Bypass), + bindings::regulator_status_REGULATOR_STATUS_UNDEFINED => Ok(Self::Undefined), + _ => Err(EINVAL), + } + } +} + +impl From for Status { + fn from(mode: Mode) -> Self { + // SAFETY: `regulator_mode_to_status` is a pure function that is only doing integer + // to integer conversion, hence this function call is safe. + let status = unsafe { bindings::regulator_mode_to_status(mode as _) }; + + if status < 0 { + Self::Undefined + } else { + Self::try_from(status as core::ffi::c_uint).unwrap_or(Self::Undefined) + } + } +} + +/// Regulator's operations +#[vtable] +pub trait Driver { + /// User data that will be accessible to all operations + type Data: ForeignOwnable + Send + Sync = (); + + /// Return one of the supported voltages, in microvolt; zero if the selector indicates a + /// voltage that is unusable by the system; or negative errno. Selectors range from zero to one + /// less than the number of voltages supported by the system. + fn list_voltage(_rdev: &Regulator, _selector: u32) -> Result { + Err(ENOTSUPP) + } + + /// Set the voltage for the regulator within the range specified. The driver should select the + /// voltage closest to `min_uv`. + fn set_voltage(_rdev: &Regulator, _min_uv: i32, _max_uv: i32) -> Result { + Err(ENOTSUPP) + } + + /// Set the voltage for the regulator using the specified selector. + fn set_voltage_sel(_rdev: &Regulator, _selector: u32) -> Result { + Err(ENOTSUPP) + } + + /// Convert a voltage into a selector. + fn map_voltage(_rdev: &Regulator, _min_uv: i32, _max_uv: i32) -> Result { + Err(ENOTSUPP) + } + + /// Get the currently configured voltage for the regulator; Returns + /// [`ENOTRECOVERABLE`] if the regulator can't be read at bootup and hasn't been + /// set yet. + fn get_voltage(_rdev: &Regulator) -> Result { + Err(ENOTSUPP) + } + + /// Get the currently configured voltage selector for the regulator; Returns + /// [`ENOTRECOVERABLE`] if the regulator can't be read at bootup and hasn't been + /// set yet. + fn get_voltage_sel(_rdev: &Regulator) -> Result { + Err(ENOTSUPP) + } + + /// Configure a limit for a current-limited regulator. + /// + /// The driver should select the current closest to `max_ua`. + fn set_current_limit(_rdev: &Regulator, _min_ua: i32, _max_ua: i32) -> Result { + Err(ENOTSUPP) + } + + /// Get the configured limit for a current-limited regulator. + fn get_current_limit(_rdev: &Regulator) -> Result { + Err(ENOTSUPP) + } + + /// Enable or disable the active discharge of the regulator. + fn set_active_discharge(_rdev: &Regulator, _enable: bool) -> Result { + Err(ENOTSUPP) + } + + /// Configure the regulator as enabled. + fn enable(_rdev: &Regulator) -> Result { + Err(ENOTSUPP) + } + + /// Configure the regulator as disabled. + fn disable(_rdev: &Regulator) -> Result { + Err(ENOTSUPP) + } + + /// Returns enablement state of the regulator. + fn is_enabled(_rdev: &Regulator) -> Result { + Err(ENOTSUPP) + } + + /// Set the configured operating [`Mode`] for the regulator. + fn set_mode(_rdev: &Regulator, _mode: Mode) -> Result { + Err(ENOTSUPP) + } + + /// Get the configured operating [`Mode`] for the regulator + fn get_mode(_rdev: &Regulator) -> Mode { + Mode::Invalid + } + + /// Report the regulator [`Status`]. + fn get_status(_rdev: &Regulator) -> Result { + Err(ENOTSUPP) + } + + /// Set the voltage for the regaultor when the system is suspended. + fn set_suspend_voltage(_rdev: &Regulator, _uv: i32) -> Result { + Err(ENOTSUPP) + } + + /// Mark the regulator as enabled when the system is suspended. + fn set_suspend_enable(_rdev: &Regulator) -> Result { + Err(ENOTSUPP) + } + + /// Mark the regulator as disabled when the system is suspended. + fn set_suspend_disable(_rdev: &Regulator) -> Result { + Err(ENOTSUPP) + } + + /// Set the operating mode for the regulator when the system is suspended. + fn set_suspend_mode(_rdev: &Regulator, _mode: Mode) -> Result { + Err(ENOTSUPP) + } +} + +/// [`Regulator`]'s descriptor +/// +/// # Invariants +/// +/// `self.0` has always valid data. +pub struct Desc(bindings::regulator_desc); +impl Desc { + /// Create a new [`Regulator`] descriptor + pub const fn new(name: &'static CStr, reg_type: Type) -> Self { + // SAFETY: `desc` is a C structure holding data that has been initialized with 0s, + // hence it is safe to use as-is. + let mut desc = unsafe { MaybeUninit::::zeroed().assume_init() }; + desc.name = name.as_char_ptr(); + desc.type_ = match reg_type { + Type::Voltage => bindings::regulator_type_REGULATOR_VOLTAGE, + Type::Current => bindings::regulator_type_REGULATOR_CURRENT, + }; + desc.ops = Adapter::::build(); + Self(desc) + } + + /// Setup the register address, mask, and {en,dis}able values + pub const fn with_enable(mut self, reg: u32, mask: u32, en_val: u32, dis_val: u32) -> Self { + self.0.enable_reg = reg; + self.0.enable_mask = mask; + self.0.enable_val = en_val; + self.0.disable_val = dis_val; + self + } + + /// Setup the register address, mask, and {en,dis}able values. {En,Dis}able values are + /// inverted, i.e. `dis_val` will be use to enable the regulator while `en_val` will be used + /// to disable the regulator. + pub const fn with_inverted_enable( + mut self, + reg: u32, + mask: u32, + en_val: u32, + dis_val: u32, + ) -> Self { + self.0.enable_is_inverted = true; + self.with_enable(reg, mask, en_val, dis_val) + } + + /// Setup the active discharge regiter address, mask, on/off values. + pub const fn with_active_discharge(mut self, reg: u32, mask: u32, on: u32, off: u32) -> Self { + self.0.active_discharge_on = on; + self.0.active_discharge_off = off; + self.0.active_discharge_reg = reg; + self.0.active_discharge_mask = mask; + self + } + + /// Setup the current selection register address, mask, and current table + pub const fn with_csel(mut self, reg: u32, mask: u32, table: &'static [u32]) -> Self { + self.0.csel_reg = reg; + self.0.csel_mask = mask; + self.0.curr_table = table.as_ptr(); + self + } + + /// Voltages are a linear mapping + pub const fn with_linear_mapping( + mut self, + reg: u32, + mask: u32, + min_uv: u32, + uv_step: u32, + n_voltages: u32, + linear_min_sel: u32, + ) -> Self { + self.0.vsel_reg = reg; + self.0.vsel_mask = mask; + self.0.n_voltages = n_voltages; + self.0.min_uV = min_uv; + self.0.uV_step = uv_step; + self.0.linear_min_sel = linear_min_sel; + self + } + + /// Set the regulator owner + pub const fn with_owner(mut self, owner: &'static ThisModule) -> Self { + self.0.owner = owner.as_ptr(); + self + } +} + +// SAFETY: `Desc` cannot be modified after its declaration, hence it is safe to share references +// between threads. +unsafe impl Sync for Desc {} + +/// [`Regulator`]'s Config +/// +/// # Examples +/// +/// ``` +/// use kernel::regulator::driver::Config; +/// # use kernel::regulator::driver::{Desc, Registration}; +/// # use kernel::{device::Device, sync::Arc}; +/// +/// struct DriverData(u32); +/// +/// # fn probe(dev: &Device, desc: &'static Desc) -> Result { +/// let config = Config::>::new(&dev, Arc::try_new(DriverData(128))?); +/// let reg = Registration::register(dev, desc, config)?; +/// # Ok(()) +/// # } +/// ``` +/// +/// # Invariants +/// +/// `self.cfg` always hold valid data. +pub struct Config { + cfg: bindings::regulator_config, + data: T, + regmap: Option>, +} + +impl Config { + /// Create a [`Regulator`] config. + pub fn new>(dev: U, data: T) -> Self { + Self { + cfg: bindings::regulator_config { + dev: dev.as_ref().as_raw(), + ..Default::default() + }, + data, + regmap: None, + } + } + + /// Assign a regmap device to the config + #[cfg(CONFIG_REGMAP)] + pub fn with_regmap(mut self, regmap: Arc) -> Self { + self.regmap = Some(regmap); + self + } +} + +/// Registration structure for Regulator drivers. +pub struct Registration(#[allow(dead_code)] Regulator); + +impl Registration { + /// register a Regulator driver + pub fn register>( + dev: U, + desc: &'static Desc, + cfg: Config, + ) -> Result { + Ok(Self(Regulator::register(dev, desc, cfg)?)) + } +} + +/// Regulator device +/// +/// Wraps the C structure `regulator_dev`. +/// +/// # Invariants +/// +/// * `self.rdev` is valid and non-null. +/// * [`Self`] has ownership of `self.rdev` memory allocation. +pub struct Regulator { + rdev: *mut bindings::regulator_dev, + _regmap: Option>, +} + +impl Regulator { + /// register a Regulator driver + fn register>( + dev: U, + desc: &'static Desc, + mut config: Config, + ) -> Result { + config.cfg.driver_data = config.data.into_foreign() as _; + + let regmap = config.regmap.take(); + if let Some(regmap) = ®map { + config.cfg.regmap = regmap.as_ptr(); + }; + + // SAFETY: By the type invariants, we know that `dev.as_ref().as_raw()` is always + // valid and non-null, and the descriptor and config are guaranteed to be valid values, + // hence it is safe to perform the FFI call. + let rdev = from_err_ptr(unsafe { + bindings::regulator_register(dev.as_ref().as_raw(), &desc.0, &config.cfg) + })?; + + if rdev.is_null() { + Err(EINVAL) + } else { + Ok(Self { + rdev, + _regmap: regmap, + }) + } + } + + /// List voltages when the regulator is using linear mapping + pub fn list_voltage_linear(&self, selector: u32) -> Result { + // SAFETY: By the type invariants, we know that `self.rdev` is always valid and non-null. + // The C function is safe to call with any selector values. + let ret = unsafe { bindings::regulator_list_voltage_linear(self.rdev, selector) }; + if ret < 0 { + return Err(Error::from_errno(ret)); + } + Ok(ret) + } + + /// Get regulator's name + pub fn get_name(&self) -> &'static CStr { + // SAFETY: By the type invariants, we know that `self.rdev` is always valid and non-null. + // The C function is guaranteed to return a valid string. + unsafe { CStr::from_char_ptr(bindings::rdev_get_name(self.rdev)) } + } + + /// Get regulator's ID + pub fn get_id(&self) -> i32 { + // SAFETY: By the type invariants, we know that `self.rdev` is always valid and non-null. + unsafe { bindings::rdev_get_id(self.rdev) } + } + + /// Retrieve driver data associated to `self` + pub fn data(&self) -> T::Borrowed<'_> { + // SAFETY: By the type invariants, we know that `self.rdev` is always valid and non-null. + unsafe { T::borrow(bindings::rdev_get_drvdata(self.rdev)) } + } +} + +impl Drop for Regulator { + fn drop(&mut self) { + // SAFETY: The type invariants guarantee that `self.rdev` is valid and non-null, + // so it is safe to perform the FFI call. + let regmap = unsafe { bindings::rdev_get_regmap(self.rdev) }; + + // SAFETY: The type invariants guarantee that `self.rdev` is valid and non-null, + // so it is safe to perform the FFI call. + unsafe { bindings::regulator_unregister(self.rdev) } + + if !regmap.is_null() { + drop(unsafe { Arc::from_raw(regmap) }); + } + } +} + +// SAFETY: `Regulator` has sole ownership of `self.rdev` and is never read outside of the C +// implementation. It is safe to use it from any thread. +unsafe impl Send for Regulator {} + +mod sealed { + pub trait Sealed {} +} + +impl sealed::Sealed for Regulator {} + +/// Helper functions to implement some of the [`Driver`] trait methods using [`Regmap`]. +/// +/// This trait is implemented by [`Regulator`] and is Sealed to prevent +/// to be implemented by anyone else. +#[cfg(CONFIG_REGMAP)] +pub trait RegmapHelpers: sealed::Sealed { + /// Implementation of [`Driver::get_voltage_sel`] using [`Regmap`]. + fn get_voltage_sel_regmap(&self) -> Result; + /// Implementation of [`Driver::set_voltage_sel`] using [`Regmap`]. + fn set_voltage_sel_regmap(&self, sel: u32) -> Result; + + /// Implementation of [`Driver::is_enabled`] using [`Regmap`]. + /// + /// [`Desc::with_enable`] or [`Desc::with_inverted_enable`] must have been called + /// to setup the fields required by regmap. + fn is_enabled_regmap(&self) -> Result; + + /// Implementation of [`Driver::enable`] using [`Regmap`]. + /// + /// [`Desc::with_enable`] or [`Desc::with_inverted_enable`] must have been called + /// to setup the fields required by regmap. + fn enable_regmap(&self) -> Result; + + /// Implementation of [`Driver::disable`] using [`Regmap`]. + /// + /// [`Desc::with_enable`] or [`Desc::with_inverted_enable`] must have been called + /// to setup the fields required by regmap. + fn disable_regmap(&self) -> Result; + + /// Implementation of [`Driver::set_active_discharge`] using [`Regmap`]. + /// + /// [`Desc::with_active_discharge`] must have been called to setup the fields required + /// by regmap. + fn set_active_discharge_regmap(&self, enable: bool) -> Result; + /// Implementation of [`Driver::set_current_limit`] using [`Regmap`]. + fn set_current_limit_regmap(&self, min_ua: i32, max_ua: i32) -> Result; + /// Implementation of [`Driver::get_current_limit`] using [`Regmap`]. + fn get_current_limit_regmap(&self) -> Result; +} + +#[cfg(CONFIG_REGMAP)] +impl RegmapHelpers for Regulator { + fn get_voltage_sel_regmap(&self) -> Result { + // SAFETY: The type invariants guarantee that `self.rdev` is valid and non-null, + // so it is safe to perform the FFI call. + let ret = unsafe { bindings::regulator_get_voltage_sel_regmap(self.rdev) }; + if ret < 0 { + return Err(Error::from_errno(ret)); + } + Ok(ret) + } + + fn set_voltage_sel_regmap(&self, sel: u32) -> Result { + // SAFETY: The type invariants guarantee that `self.rdev` is valid and non-null, + // so it is safe to perform the FFI call. + to_result(unsafe { bindings::regulator_set_voltage_sel_regmap(self.rdev, sel) }) + } + + fn is_enabled_regmap(&self) -> Result { + // SAFETY: The type invariants guarantee that `self.rdev` is valid and non-null, + // so it is safe to perform the FFI call. + let ret = unsafe { bindings::regulator_is_enabled_regmap(self.rdev) }; + if ret < 0 { + return Err(Error::from_errno(ret)); + } + Ok(ret > 0) + } + + fn enable_regmap(&self) -> Result { + // SAFETY: The type invariants guarantee that `self.rdev` is valid and non-null, + // so it is safe to perform the FFI call. + to_result(unsafe { bindings::regulator_enable_regmap(self.rdev) }) + } + + fn disable_regmap(&self) -> Result { + // SAFETY: The type invariants guarantee that `self.rdev` is valid and non-null, + // so it is safe to perform the FFI call. + to_result(unsafe { bindings::regulator_disable_regmap(self.rdev) }) + } + + fn set_active_discharge_regmap(&self, enable: bool) -> Result { + // SAFETY: The type invariants guarantee that `self.rdev` is valid and non-null, + // so it is safe to perform the FFI call. + to_result(unsafe { bindings::regulator_set_active_discharge_regmap(self.rdev, enable) }) + } + + fn set_current_limit_regmap(&self, min_ua: i32, max_ua: i32) -> Result { + // SAFETY: The type invariants guarantee that `self.rdev` is valid and non-null, + // so it is safe to perform the FFI call. + to_result(unsafe { + bindings::regulator_set_current_limit_regmap(self.rdev, min_ua, max_ua) + }) + } + + fn get_current_limit_regmap(&self) -> Result { + // SAFETY: The type invariants guarantee that `self.rdev` is valid and non-null, + // so it is safe to perform the FFI call. + let ret = unsafe { bindings::regulator_get_current_limit_regmap(self.rdev) }; + if ret < 0 { + return Err(Error::from_errno(ret)); + } + Ok(ret) + } +} + +/// [`Regulator`] type +pub enum Type { + /// Voltage regulator + Voltage, + /// Current regulator + Current, +} + +pub(crate) struct Adapter(PhantomData); + +impl Adapter { + unsafe extern "C" fn list_voltage_callback( + rdev: *mut bindings::regulator_dev, + selector: core::ffi::c_uint, + ) -> core::ffi::c_int { + let rdev = ManuallyDrop::new(Regulator { + rdev, + _regmap: None, + }); + from_result(|| T::list_voltage(&rdev, selector)) + } + + unsafe extern "C" fn set_voltage_callback( + rdev: *mut bindings::regulator_dev, + min_uv: core::ffi::c_int, + max_uv: core::ffi::c_int, + selector: *mut core::ffi::c_uint, + ) -> core::ffi::c_int { + let rdev = ManuallyDrop::new(Regulator { + rdev, + _regmap: None, + }); + match T::set_voltage(&rdev, min_uv, max_uv) { + Ok(v) => { + unsafe { *selector = v as _ }; + 0 + } + Err(e) => e.to_errno(), + } + } + + unsafe extern "C" fn map_voltage_callback( + rdev: *mut bindings::regulator_dev, + min_uv: core::ffi::c_int, + max_uv: core::ffi::c_int, + ) -> core::ffi::c_int { + let rdev = ManuallyDrop::new(Regulator { + rdev, + _regmap: None, + }); + from_result(|| T::map_voltage(&rdev, min_uv, max_uv)) + } + + unsafe extern "C" fn set_voltage_sel_callback( + rdev: *mut bindings::regulator_dev, + selector: core::ffi::c_uint, + ) -> core::ffi::c_int { + let rdev = ManuallyDrop::new(Regulator { + rdev, + _regmap: None, + }); + from_result(|| { + T::set_voltage_sel(&rdev, selector)?; + Ok(0) + }) + } + + unsafe extern "C" fn get_voltage_callback( + rdev: *mut bindings::regulator_dev, + ) -> core::ffi::c_int { + let rdev = ManuallyDrop::new(Regulator { + rdev, + _regmap: None, + }); + from_result(|| T::get_voltage(&rdev)) + } + + unsafe extern "C" fn get_voltage_sel_callback( + rdev: *mut bindings::regulator_dev, + ) -> core::ffi::c_int { + let rdev = ManuallyDrop::new(Regulator { + rdev, + _regmap: None, + }); + from_result(|| T::get_voltage_sel(&rdev)) + } + + unsafe extern "C" fn set_current_limit_callback( + rdev: *mut bindings::regulator_dev, + min_ua: core::ffi::c_int, + max_ua: core::ffi::c_int, + ) -> core::ffi::c_int { + let rdev = ManuallyDrop::new(Regulator { + rdev, + _regmap: None, + }); + from_result(|| { + T::set_current_limit(&rdev, min_ua, max_ua)?; + Ok(0) + }) + } + + unsafe extern "C" fn get_current_limit_callback( + rdev: *mut bindings::regulator_dev, + ) -> core::ffi::c_int { + let rdev = ManuallyDrop::new(Regulator { + rdev, + _regmap: None, + }); + from_result(|| T::get_current_limit(&rdev)) + } + + unsafe extern "C" fn set_active_discharge_callback( + rdev: *mut bindings::regulator_dev, + enable: bool, + ) -> core::ffi::c_int { + let rdev = ManuallyDrop::new(Regulator { + rdev, + _regmap: None, + }); + from_result(|| { + T::set_active_discharge(&rdev, enable)?; + Ok(0) + }) + } + + unsafe extern "C" fn enable_callback(rdev: *mut bindings::regulator_dev) -> core::ffi::c_int { + let rdev = ManuallyDrop::new(Regulator { + rdev, + _regmap: None, + }); + from_result(|| { + T::enable(&rdev)?; + Ok(0) + }) + } + + unsafe extern "C" fn disable_callback(rdev: *mut bindings::regulator_dev) -> core::ffi::c_int { + let rdev = ManuallyDrop::new(Regulator { + rdev, + _regmap: None, + }); + from_result(|| { + T::disable(&rdev)?; + Ok(0) + }) + } + + unsafe extern "C" fn is_enabled_callback( + rdev: *mut bindings::regulator_dev, + ) -> core::ffi::c_int { + let rdev = ManuallyDrop::new(Regulator { + rdev, + _regmap: None, + }); + from_result(|| { + T::is_enabled(&rdev)?; + Ok(0) + }) + } + + unsafe extern "C" fn set_mode_callback( + rdev: *mut bindings::regulator_dev, + mode: core::ffi::c_uint, + ) -> core::ffi::c_int { + let rdev = ManuallyDrop::new(Regulator { + rdev, + _regmap: None, + }); + from_result(|| { + let mode = Mode::try_from(mode).unwrap_or(Mode::Invalid); + T::set_mode(&rdev, mode)?; + Ok(0) + }) + } + + unsafe extern "C" fn get_mode_callback( + rdev: *mut bindings::regulator_dev, + ) -> core::ffi::c_uint { + let rdev = ManuallyDrop::new(Regulator { + rdev, + _regmap: None, + }); + T::get_mode(&rdev) as _ + } + + unsafe extern "C" fn get_status_callback( + rdev: *mut bindings::regulator_dev, + ) -> core::ffi::c_int { + let rdev = ManuallyDrop::new(Regulator { + rdev, + _regmap: None, + }); + from_result(|| Ok(T::get_status(&rdev)? as _)) + } + + unsafe extern "C" fn set_suspend_voltage_callback( + rdev: *mut bindings::regulator_dev, + uv: core::ffi::c_int, + ) -> core::ffi::c_int { + let rdev = ManuallyDrop::new(Regulator { + rdev, + _regmap: None, + }); + from_result(|| { + T::set_suspend_voltage(&rdev, uv)?; + Ok(0) + }) + } + + unsafe extern "C" fn set_suspend_enable_callback( + rdev: *mut bindings::regulator_dev, + ) -> core::ffi::c_int { + let rdev = ManuallyDrop::new(Regulator { + rdev, + _regmap: None, + }); + from_result(|| { + T::set_suspend_enable(&rdev)?; + Ok(0) + }) + } + + unsafe extern "C" fn set_suspend_disable_callback( + rdev: *mut bindings::regulator_dev, + ) -> core::ffi::c_int { + let rdev = ManuallyDrop::new(Regulator { + rdev, + _regmap: None, + }); + from_result(|| { + T::set_suspend_disable(&rdev)?; + Ok(0) + }) + } + + unsafe extern "C" fn set_suspend_mode_callback( + rdev: *mut bindings::regulator_dev, + mode: core::ffi::c_uint, + ) -> core::ffi::c_int { + let rdev = ManuallyDrop::new(Regulator { + rdev, + _regmap: None, + }); + from_result(|| { + let mode = Mode::try_from(mode).unwrap_or(Mode::Invalid); + T::set_suspend_mode(&rdev, mode)?; + Ok(0) + }) + } + + const VTABLE: bindings::regulator_ops = bindings::regulator_ops { + list_voltage: if T::HAS_LIST_VOLTAGE { + Some(Adapter::::list_voltage_callback) + } else { + None + }, + set_voltage: if T::HAS_SET_VOLTAGE { + Some(Adapter::::set_voltage_callback) + } else { + None + }, + map_voltage: if T::HAS_MAP_VOLTAGE { + Some(Adapter::::map_voltage_callback) + } else { + None + }, + set_voltage_sel: if T::HAS_SET_VOLTAGE_SEL { + Some(Adapter::::set_voltage_sel_callback) + } else { + None + }, + get_voltage: if T::HAS_GET_VOLTAGE { + Some(Adapter::::get_voltage_callback) + } else { + None + }, + get_voltage_sel: if T::HAS_GET_VOLTAGE_SEL { + Some(Adapter::::get_voltage_sel_callback) + } else { + None + }, + set_current_limit: if T::HAS_SET_CURRENT_LIMIT { + Some(Adapter::::set_current_limit_callback) + } else { + None + }, + get_current_limit: if T::HAS_GET_CURRENT_LIMIT { + Some(Adapter::::get_current_limit_callback) + } else { + None + }, + set_active_discharge: if T::HAS_SET_ACTIVE_DISCHARGE { + Some(Adapter::::set_active_discharge_callback) + } else { + None + }, + enable: if T::HAS_ENABLE { + Some(Adapter::::enable_callback) + } else { + None + }, + disable: if T::HAS_DISABLE { + Some(Adapter::::disable_callback) + } else { + None + }, + is_enabled: if T::HAS_IS_ENABLED { + Some(Adapter::::is_enabled_callback) + } else { + None + }, + set_mode: if T::HAS_SET_MODE { + Some(Adapter::::set_mode_callback) + } else { + None + }, + get_mode: if T::HAS_GET_MODE { + Some(Adapter::::get_mode_callback) + } else { + None + }, + get_status: if T::HAS_GET_STATUS { + Some(Adapter::::get_status_callback) + } else { + None + }, + set_suspend_voltage: if T::HAS_SET_SUSPEND_VOLTAGE { + Some(Adapter::::set_suspend_voltage_callback) + } else { + None + }, + set_suspend_enable: if T::HAS_SET_SUSPEND_ENABLE { + Some(Adapter::::set_suspend_enable_callback) + } else { + None + }, + set_suspend_disable: if T::HAS_SET_SUSPEND_DISABLE { + Some(Adapter::::set_suspend_disable_callback) + } else { + None + }, + set_suspend_mode: if T::HAS_SET_SUSPEND_MODE { + Some(Adapter::::set_suspend_mode_callback) + } else { + None + }, + // SAFETY: The rest is zeroed out to initialize `struct regulator_ops`, + // sets `Option<&F>` to be `None`. + ..unsafe { core::mem::MaybeUninit::::zeroed().assume_init() } + }; + + const fn build() -> &'static bindings::regulator_ops { + &Self::VTABLE + } +} diff --git a/rust/kernel/revocable.rs b/rust/kernel/revocable.rs new file mode 100644 index 00000000000000..3d13e7b2f2e82e --- /dev/null +++ b/rust/kernel/revocable.rs @@ -0,0 +1,209 @@ +// 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, + init::{self}, + prelude::*, + sync::rcu, +}; +use core::{ + cell::UnsafeCell, + marker::PhantomData, + mem::MaybeUninit, + 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) -> Option { +/// let guard = v.try_access()?; +/// Some(guard.a + guard.b) +/// } +/// +/// let v = Box::pin_init(Revocable::new(Example { a: 10, b: 20 }), GFP_KERNEL).unwrap(); +/// 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) -> Option { +/// let guard = rcu::read_lock(); +/// let e = v.try_access_with_guard(&guard)?; +/// Some(e.a + e.b) +/// } +/// +/// let v = Box::pin_init(Revocable::new(Example { a: 10, b: 20 }), GFP_KERNEL).unwrap(); +/// assert_eq!(add_two(&v), Some(30)); +/// v.revoke(); +/// assert_eq!(add_two(&v), None); +/// ``` +#[pin_data(PinnedDrop)] +pub struct Revocable { + is_available: AtomicBool, + #[pin] + data: MaybeUninit>, +} + +// 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 Send for Revocable {} + +// 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 Sync for Revocable {} + +impl Revocable { + /// Creates a new revocable instance of the given data. + pub fn new(data: impl PinInit) -> impl PinInit { + pin_init!(Self { + is_available: AtomicBool::new(true), + data <- unsafe { + init::pin_init_from_closure(move |slot: *mut MaybeUninit>| { + init::PinInit::::__pinned_init(data, + slot as *mut T)?; + Ok::<(), core::convert::Infallible>(()) + }) + }, + }) + } + + /// 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> { + 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()) }; + } + } +} + +#[pinned_drop] +impl PinnedDrop for Revocable { + fn drop(self: Pin<&mut Self>) { + // Drop only if the data hasn't been revoked yet (in which case it has already been + // dropped). + // SAFETY: We are not moving out of `p`, only dropping in place + let p = unsafe { self.get_unchecked_mut() }; + if *p.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(p.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 RevocableGuard<'_, T> { + fn new(data_ref: *const T, rcu_guard: rcu::Guard) -> Self { + Self { + data_ref, + _rcu_guard: rcu_guard, + _p: PhantomData, + } + } +} + +impl 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/str.rs b/rust/kernel/str.rs index bb8d4f41475b59..0c5b472065dce7 100644 --- a/rust/kernel/str.rs +++ b/rust/kernel/str.rs @@ -32,6 +32,12 @@ impl BStr { // SAFETY: `BStr` is transparent to `[u8]`. unsafe { &*(bytes as *const [u8] as *const BStr) } } + + /// Returns a reference to the inner [u8]. + #[inline] + pub const fn deref_const(&self) -> &[u8] { + &self.0 + } } impl fmt::Display for BStr { @@ -103,7 +109,7 @@ impl Deref for BStr { #[inline] fn deref(&self) -> &Self::Target { - &self.0 + self.deref_const() } } diff --git a/rust/kernel/sync.rs b/rust/kernel/sync.rs index 0ab20975a3b5db..1806767359fec2 100644 --- a/rust/kernel/sync.rs +++ b/rust/kernel/sync.rs @@ -11,6 +11,7 @@ mod arc; mod condvar; pub mod lock; mod locked_by; +pub mod rcu; pub use arc::{Arc, ArcBorrow, UniqueArc}; pub use condvar::{new_condvar, CondVar, CondVarTimeoutResult}; diff --git a/rust/kernel/sync/rcu.rs b/rust/kernel/sync/rcu.rs new file mode 100644 index 00000000000000..5a35495f69a46b --- /dev/null +++ b/rust/kernel/sync/rcu.rs @@ -0,0 +1,52 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! RCU support. +//! +//! C header: [`include/linux/rcupdate.h`](srctree/include/linux/rcupdate.h) + +use crate::bindings; +use core::marker::PhantomData; + +/// Evidence that the RCU read side lock is held on the current thread/CPU. +/// +/// The type is explicitly not `Send` because this property is per-thread/CPU. +/// +/// # Invariants +/// +/// The RCU read side lock is actually held while instances of this guard exist. +pub struct Guard { + _not_send: PhantomData<*mut ()>, +} + +impl Guard { + /// Acquires the RCU read side lock and returns a guard. + pub fn new() -> Self { + // SAFETY: An FFI call with no additional requirements. + unsafe { bindings::rcu_read_lock() }; + // INVARIANT: The RCU read side lock was just acquired above. + Self { + _not_send: PhantomData, + } + } + + /// Explicitly releases the RCU read side lock. + pub fn unlock(self) {} +} + +impl Default for Guard { + fn default() -> Self { + Self::new() + } +} + +impl Drop for Guard { + fn drop(&mut self) { + // SAFETY: By the type invariants, the rcu read side is locked, so it is ok to unlock it. + unsafe { bindings::rcu_read_unlock() }; + } +} + +/// Acquires the RCU read side lock. +pub fn read_lock() -> Guard { + Guard::new() +} diff --git a/rust/kernel/types.rs b/rust/kernel/types.rs index 9e7ca066355cd5..55b3f1a2851fc9 100644 --- a/rust/kernel/types.rs +++ b/rust/kernel/types.rs @@ -289,14 +289,22 @@ impl Opaque { /// uninitialized. Additionally, access to the inner `T` requires `unsafe`, so the caller needs /// to verify at that point that the inner value is valid. pub fn ffi_init(init_func: impl FnOnce(*mut T)) -> impl PinInit { + Self::try_ffi_init(move |slot| { + init_func(slot); + Ok(()) + }) + } + + /// Similar to [`Self::ffi_init`], except that the closure can fail. + /// + /// To avoid leaks on failure, the closure must drop any fields it has initialised before the + /// failure. + pub fn try_ffi_init( + init_func: impl FnOnce(*mut T) -> Result<(), E>, + ) -> impl PinInit { // SAFETY: We contain a `MaybeUninit`, so it is OK for the `init_func` to not fully // initialize the `T`. - unsafe { - init::pin_init_from_closure::<_, ::core::convert::Infallible>(move |slot| { - init_func(Self::raw_get(slot)); - Ok(()) - }) - } + unsafe { init::pin_init_from_closure(|slot| init_func(Self::raw_get(slot))) } } /// Returns a raw pointer to the opaque data. diff --git a/rust/macros/foreach.rs b/rust/macros/foreach.rs new file mode 100644 index 00000000000000..a92280f229d1de --- /dev/null +++ b/rust/macros/foreach.rs @@ -0,0 +1,137 @@ +// SPDX-License-Identifier: GPL-2.0 + +use proc_macro::{ + Delimiter, TokenStream, + TokenTree::{self, Group, Ident, Literal}, +}; +use std::ops::Range; + +fn process_group(var: &str, i: isize, tokens: impl Iterator) -> Vec { + let mut tt = Vec::::new(); + let mut tokens = tokens.peekable(); + + while let Some(token) = tokens.next() { + match token { + Group(ref group) => { + let group_tokens = process_group(var, i, group.stream().into_iter()); + let stream = FromIterator::from_iter(group_tokens.into_iter()); + let new_group = proc_macro::Group::new(group.delimiter(), stream); + tt.push(TokenTree::Group(new_group)); + } + TokenTree::Punct(ref punct) => { + if punct.to_string() == "$" { + if let Some(TokenTree::Ident(ident)) = tokens.peek() { + if ident.to_string() == var { + tt.push(TokenTree::Literal(proc_macro::Literal::isize_unsuffixed(i))); + tokens.next(); + continue; + } + } + } + + tt.push(token); + } + _ => tt.push(token), + } + } + + tt +} + +pub(crate) fn expand(input: TokenStream) -> TokenStream { + let mut tokens = input.into_iter().peekable(); + + let var = if let Some(Ident(i)) = tokens.next() { + i.to_string() + } else { + panic!("foreach! first token should be an identifier"); + }; + + let token = tokens.next().expect("missing token, expecting ident 'in'"); + assert!(matches!(token, TokenTree::Ident(x) if x.to_string() == "in")); + + let token = tokens + .next() + .expect("foreach!: missing token, expecting range"); + let token = if let Group(group) = token { + group + .stream() + .into_iter() + .next() + .expect("foreach: missing token, expecting integer") + } else { + token + }; + + let start = if let Literal(lit) = token { + lit.to_string() + .parse::() + .expect("Failed to convert literal to isize") + } else { + panic!("foreach!: unexpected token '{token}'"); + }; + + let token = tokens + .next() + .expect("foreach!: missing token, expecting '.'"); + assert!(matches!(token, TokenTree::Punct(x) if x == '.')); + let token = tokens + .next() + .expect("foreach!: missing token, expecting '.'"); + assert!(matches!(token, TokenTree::Punct(x) if x == '.')); + + let is_inclusive_range = if let Some(TokenTree::Punct(p)) = tokens.peek() { + if p.as_char() == '=' { + tokens.next(); + true + } else { + false + } + } else { + false + }; + + let token = tokens + .next() + .expect("foreach!: missing token, expecting integer"); + let token = if let Group(group) = token { + group + .stream() + .into_iter() + .next() + .expect("foreach: missing token, expecting integer") + } else { + token + }; + + let end = if let Literal(lit) = token { + lit.to_string() + .parse::() + .expect("Failed to convert literal to isize") + } else { + panic!("foreach!: unexpected token '{token}'"); + }; + let range = Range { + start, + end: end + if is_inclusive_range { 1 } else { 0 }, + }; + + let tokens = if let Some(Group(group)) = tokens.next() { + if group.delimiter() != Delimiter::Brace { + panic!("foreach! expected brace"); + } + + group.stream().into_iter() + } else { + panic!("foreach! missing opening brace"); + }; + + let tokens: Vec = tokens.collect(); + let mut tt = Vec::::new(); + + for i in range { + tt.extend_from_slice(&process_group(&var, i, tokens.clone().into_iter())); + } + + FromIterator::from_iter(tt) +} diff --git a/rust/macros/lib.rs b/rust/macros/lib.rs index 5be0cb9db3ee49..480ee61d16400c 100644 --- a/rust/macros/lib.rs +++ b/rust/macros/lib.rs @@ -5,6 +5,7 @@ #[macro_use] mod quote; mod concat_idents; +mod foreach; mod helpers; mod module; mod paste; @@ -408,6 +409,30 @@ pub fn paste(input: TokenStream) -> TokenStream { tokens.into_iter().collect() } +/// Repeat a fragment of code and provide a numerical index for the current repetition +/// +/// # Examples +/// +/// ```rust,ignore +/// foreach!(i in 0..10) { +/// paste! { +/// fn []() { +/// } +/// } +/// } +/// +/// foreach!(i in 8..=15) { +/// paste! { +/// struct []() { +/// } +/// } +/// } +/// ``` +#[proc_macro] +pub fn foreach(input: TokenStream) -> TokenStream { + foreach::expand(input) +} + /// Derives the [`Zeroable`] trait for the given struct. /// /// This can only be used for structs where every field implements the [`Zeroable`] trait. diff --git a/rust/macros/module.rs b/rust/macros/module.rs index 571ffa2e189ca6..d2bde78cf0502b 100644 --- a/rust/macros/module.rs +++ b/rust/macros/module.rs @@ -228,6 +228,7 @@ pub(crate) fn module(ts: TokenStream) -> TokenStream { mod __module_init {{ mod __module_init {{ use super::super::{type_}; + use kernel::init::PinInit; /// The \"Rust loadable module\" mark. // @@ -238,7 +239,7 @@ pub(crate) fn module(ts: TokenStream) -> TokenStream { #[used] static __IS_RUST_MODULE: () = (); - static mut __MOD: Option<{type_}> = None; + static mut __MOD: core::mem::MaybeUninit<{type_}> = core::mem::MaybeUninit::uninit(); // Loadable modules need to export the `{{init,cleanup}}_module` identifiers. /// # Safety @@ -327,20 +328,14 @@ pub(crate) fn module(ts: TokenStream) -> TokenStream { /// /// This function must only be called once. unsafe fn __init() -> core::ffi::c_int {{ - match <{type_} as kernel::Module>::init(&super::super::THIS_MODULE) {{ - Ok(m) => {{ - // SAFETY: No data race, since `__MOD` can only be accessed by this - // module and there only `__init` and `__exit` access it. These - // functions are only called once and `__exit` cannot be called - // before or during `__init`. - unsafe {{ - __MOD = Some(m); - }} - return 0; - }} - Err(e) => {{ - return e.to_errno(); - }} + let initer = <{type_} as kernel::InPlaceModule>::init(kernel::c_str!(\"{name}\"), + &super::super::THIS_MODULE); + // SAFETY: No data race, since `__MOD` can only be accessed by this module + // and there only `__init` and `__exit` access it. These functions are only + // called once and `__exit` cannot be called before or during `__init`. + match unsafe {{ initer.__pinned_init(__MOD.as_mut_ptr()) }} {{ + Ok(m) => 0, + Err(e) => e.to_errno(), }} }} @@ -355,7 +350,7 @@ pub(crate) fn module(ts: TokenStream) -> TokenStream { // called once and `__init` was already called. unsafe {{ // Invokes `drop()` on `__MOD`, which should be used for cleanup. - __MOD = None; + __MOD.assume_init_drop(); }} }} diff --git a/rust/macros/paste.rs b/rust/macros/paste.rs index f40d42b35b5869..409f5bb7dfb4be 100644 --- a/rust/macros/paste.rs +++ b/rust/macros/paste.rs @@ -2,7 +2,7 @@ use proc_macro::{Delimiter, Group, Ident, Spacing, Span, TokenTree}; -fn concat(tokens: &[TokenTree], group_span: Span) -> TokenTree { +fn process_tokens_into_segments(tokens: &[TokenTree]) -> (Vec<(String, Span)>, Option) { let mut tokens = tokens.iter(); let mut segments = Vec::new(); let mut span = None; @@ -46,10 +46,29 @@ fn concat(tokens: &[TokenTree], group_span: Span) -> TokenTree { }; segments.push((value, sp)); } + Some(TokenTree::Group(group)) if group.delimiter() == Delimiter::None => { + let group_tokens: Vec<_> = group.stream().into_iter().collect(); + let (group_segments, group_span) = process_tokens_into_segments(&group_tokens); + segments.extend(group_segments); + + assert!( + !(span.is_some() && group_span.is_some()), + "span modifier should only appear at most once" + ); + + if group_span.is_some() { + span = group_span; + } + } _ => panic!("unexpected token in paste segments"), }; } + (segments, span) +} + +fn concat(tokens: &[TokenTree], group_span: Span) -> TokenTree { + let (segments, span) = process_tokens_into_segments(tokens); let pasted: String = segments.into_iter().map(|x| x.0).collect(); TokenTree::Ident(Ident::new(&pasted, span.unwrap_or(group_span))) } diff --git a/samples/rust/rust_minimal.rs b/samples/rust/rust_minimal.rs index 2a9eaab62d1ca7..3b918ff5eebbeb 100644 --- a/samples/rust/rust_minimal.rs +++ b/samples/rust/rust_minimal.rs @@ -17,7 +17,7 @@ struct RustMinimal { } impl kernel::Module for RustMinimal { - fn init(_module: &'static ThisModule) -> Result { + fn init(_name: &'static CStr, _module: &'static ThisModule) -> Result { pr_info!("Rust minimal sample (init)\n"); pr_info!("Am I built-in? {}\n", !cfg!(MODULE)); diff --git a/samples/rust/rust_print.rs b/samples/rust/rust_print.rs index 6eabb0d79ea3a7..722275a735f1d9 100644 --- a/samples/rust/rust_print.rs +++ b/samples/rust/rust_print.rs @@ -40,7 +40,7 @@ fn arc_print() -> Result { } impl kernel::Module for RustPrint { - fn init(_module: &'static ThisModule) -> Result { + fn init(_name: &'static CStr, _module: &'static ThisModule) -> Result { pr_info!("Rust printing macros sample (init)\n"); pr_emerg!("Emergency message (level 0) without args\n");