| // SPDX-License-Identifier: GPL-2.0 |
| |
| //! Commonly used sizes. |
| //! |
| //! C headers: [`include/linux/sizes.h`](srctree/include/linux/sizes.h). |
| //! |
| //! The top-level `SZ_*` constants are [`usize`]-typed, for use in kernel page |
| //! arithmetic and similar CPU-side work. |
| //! |
| //! The [`SizeConstants`] trait provides the same constants as associated constants |
| //! on [`u32`], [`u64`], and [`usize`], for use in device address spaces where |
| //! the address width depends on the hardware. Device drivers frequently need |
| //! these constants as [`u64`] (or [`u32`]) rather than [`usize`], because |
| //! device address spaces are sized independently of the CPU pointer width. |
| //! |
| //! # Examples |
| //! |
| //! ``` |
| //! use kernel::{ |
| //! page::PAGE_SIZE, |
| //! sizes::{ |
| //! SizeConstants, |
| //! SZ_1M, // |
| //! }, // |
| //! }; |
| //! |
| //! // Module-level constants continue to work without a type qualifier. |
| //! let num_pages_in_1m = SZ_1M / PAGE_SIZE; |
| //! |
| //! // Trait associated constants require a type qualifier. |
| //! let heap_size = 14 * u64::SZ_1M; |
| //! let small = u32::SZ_4K; |
| //! ``` |
| |
| macro_rules! define_sizes { |
| ($($type:ty),* $(,)?) => { |
| define_sizes!(@internal [$($type),*] |
| /// `0x0000_0400`. |
| SZ_1K, |
| /// `0x0000_0800`. |
| SZ_2K, |
| /// `0x0000_1000`. |
| SZ_4K, |
| /// `0x0000_2000`. |
| SZ_8K, |
| /// `0x0000_4000`. |
| SZ_16K, |
| /// `0x0000_8000`. |
| SZ_32K, |
| /// `0x0001_0000`. |
| SZ_64K, |
| /// `0x0002_0000`. |
| SZ_128K, |
| /// `0x0004_0000`. |
| SZ_256K, |
| /// `0x0008_0000`. |
| SZ_512K, |
| /// `0x0010_0000`. |
| SZ_1M, |
| /// `0x0020_0000`. |
| SZ_2M, |
| /// `0x0040_0000`. |
| SZ_4M, |
| /// `0x0080_0000`. |
| SZ_8M, |
| /// `0x0100_0000`. |
| SZ_16M, |
| /// `0x0200_0000`. |
| SZ_32M, |
| /// `0x0400_0000`. |
| SZ_64M, |
| /// `0x0800_0000`. |
| SZ_128M, |
| /// `0x1000_0000`. |
| SZ_256M, |
| /// `0x2000_0000`. |
| SZ_512M, |
| /// `0x4000_0000`. |
| SZ_1G, |
| /// `0x8000_0000`. |
| SZ_2G, |
| ); |
| }; |
| |
| (@internal [$($type:ty),*] $($names_and_metas:tt)*) => { |
| define_sizes!(@consts_and_trait $($names_and_metas)*); |
| define_sizes!(@impls [$($type),*] $($names_and_metas)*); |
| }; |
| |
| (@consts_and_trait $($(#[$meta:meta])* $name:ident,)*) => { |
| $( |
| $(#[$meta])* |
| pub const $name: usize = bindings::$name as usize; |
| )* |
| |
| /// Size constants for device address spaces. |
| /// |
| /// Implemented for [`u32`], [`u64`], and [`usize`] so drivers can |
| /// choose the width that matches their hardware. All `SZ_*` values fit |
| /// in a [`u32`], so all implementations are lossless. |
| /// |
| /// # Examples |
| /// |
| /// ``` |
| /// use kernel::sizes::SizeConstants; |
| /// |
| /// let gpu_heap = 14 * u64::SZ_1M; |
| /// let mmio_window = u32::SZ_16M; |
| /// ``` |
| pub trait SizeConstants { |
| $( |
| $(#[$meta])* |
| const $name: Self; |
| )* |
| } |
| }; |
| |
| (@impls [] $($(#[$meta:meta])* $name:ident,)*) => {}; |
| |
| (@impls [$first:ty $(, $rest:ty)*] $($(#[$meta:meta])* $name:ident,)*) => { |
| impl SizeConstants for $first { |
| $( |
| const $name: Self = { |
| assert!((self::$name as u128) <= (<$first>::MAX as u128)); |
| self::$name as $first |
| }; |
| )* |
| } |
| |
| define_sizes!(@impls [$($rest),*] $($(#[$meta])* $name,)*); |
| }; |
| } |
| |
| define_sizes!(u32, u64, usize); |