From nobody Mon Jun 8 06:36:40 2026 Received: from SA9PR02CU001.outbound.protection.outlook.com (mail-southcentralusazon11013025.outbound.protection.outlook.com [40.93.196.25]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 85D443ADB92; Sat, 6 Jun 2026 12:43:25 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=40.93.196.25 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780749807; cv=fail; b=jakxjXr6HR2XSutOmWBnAVpUwyRSZMOOVzvv11SuHnJjcaNWgJkkBe9awBPVD+8xU2LpE0Z0IC16k4hegprq9m0K34IwtGvwVQQ7agE7AdcfKcfDkBhW11d7/U2quhlILN6xv1Tip+/kYd7pFhaBVeJb3295wII8rTCOR9MO1AE= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780749807; c=relaxed/simple; bh=c6CySw4phJ8kviRpnCviFmghEDJjplf6ZlzBtm0+txU=; h=From:Date:Subject:Content-Type:Message-Id:References:In-Reply-To: To:Cc:MIME-Version; b=TTvCsXV0LKgawo9mONGLfbxpJJnnHnRA4AaYjXuPQmvX3cdK3631R0zl2bD/NfiEN6tBf75XRTesLTtvesy0lPVcYmdYrz5xQ+cRLEhoaPZVVPe1GvuOdD8OhBihqix/qlqqkElnyjlw62/05UrqCdYxerkxCJxdx3k7piQVOpY= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=nvidia.com; spf=fail smtp.mailfrom=nvidia.com; dkim=pass (2048-bit key) header.d=Nvidia.com header.i=@Nvidia.com header.b=tU0pVJw2; arc=fail smtp.client-ip=40.93.196.25 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=nvidia.com Authentication-Results: smtp.subspace.kernel.org; spf=fail smtp.mailfrom=nvidia.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=Nvidia.com header.i=@Nvidia.com header.b="tU0pVJw2" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=txnTvJlVhXmJ3BXT+107zNofbsN85MRx8UaofwZrMBrzH8orBJchvyeAU4DlVUkSp2PRaSB+7fTerQOcwU+bNMa36ce4zNK6f6tRxYDTDN2HSEqPjWCyBitpCo3KOe9Pt6uBwXIZAmyyROvx6pxoPeh+BgHYjAR854TP3oe5vgsWJvLv5t2dMBzibI0KPP8vTeGnbN7T426OEhNM2B0EyLErcZJywZOwrWxJ59G3wT+nlp0S9QHA3oFcSY6LrhP3N7qlbVafcmvwUG2W4dR4Y0rncYpaKxUOeOBtuK0ZrDMAj65742+LR8SzKOHPJCBKk3MQW3SJByHbjcVtbnpkqw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector10001; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=HPoMPigwcVH4Gn1SRjHmXpIIDDoxHPSnXRma1NHqt3c=; b=fHNjvDR4i7ypLfud7U3IWYtZnNZJEFSwSfwbVgEhniOuSM4zdCFLvApiMHm7McFOT2VXo9TIwLGzRfsEn4GRDHqHX1bhh/SmluwhEqCiONjIof6ho3I2gj5x7OegdomUH8qfTtM9khWCH5U1fSMt0Zoss5QFYRS4V6q23UcePeKgnyWy7tMXOIv/Vb9VxMjgx2dkSUql0HbvtDe1VqLPOiwELb8Mujdp5QgJlSwez3/rVVMnpe4gJ5K9W+Qgp/l2Q7tEhpELgHUBnpY9OP4FR7oBTCsYmUxosZEnKYKQRuD2v8Dvd47HvBPxh0YWIjHDQjY1uZ2d8+Scq5Lz5zZO4A== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=nvidia.com; dmarc=pass action=none header.from=nvidia.com; dkim=pass header.d=nvidia.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=Nvidia.com; s=selector2; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=HPoMPigwcVH4Gn1SRjHmXpIIDDoxHPSnXRma1NHqt3c=; b=tU0pVJw2h3LXHWIAGimmpUxAMLCPaFM/P3qMhK9Y27ue0p84524GthsgTvP+tVY6Z9NJ5rX17x3DsEJ27gi76lLsnRmHu9mTUXySvyhpYJ94fyJhDfxLna6ob/Jj41ulT/GqRjtz9VhaSfQoTOzxqY2F4rU/zUnt39kOfc4X+uYu9tR7pA8iUIRpMtUOBjczcHWYPcZouTMcukFzpSXCYX97pvvYMW7UvHCsPTDIRjfymygjvIYz43Ldfo5TWSgHqdo3Xw0oPm1SVrftTFG4asqjCLvLJwoUDAgGRl3ZEiZKeBUt40Mu7CnwH3jt/svwA5VFsx+ghx4yVqyZ6fdfZA== Authentication-Results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=nvidia.com; Received: from CH2PR12MB3990.namprd12.prod.outlook.com (2603:10b6:610:28::18) by BL1PR12MB5730.namprd12.prod.outlook.com (2603:10b6:208:385::9) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.21.92.11; Sat, 6 Jun 2026 12:43:20 +0000 Received: from CH2PR12MB3990.namprd12.prod.outlook.com ([fe80::7de1:4fe5:8ead:5989]) by CH2PR12MB3990.namprd12.prod.outlook.com ([fe80::7de1:4fe5:8ead:5989%4]) with mapi id 15.21.0092.007; Sat, 6 Jun 2026 12:43:19 +0000 From: Alexandre Courbot Date: Sat, 06 Jun 2026 21:43:04 +0900 Subject: [PATCH v5 1/3] rust: extract `bitfield!` macro from `register!` Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260606-bitfield-v5-1-b92188820914@nvidia.com> References: <20260606-bitfield-v5-0-b92188820914@nvidia.com> In-Reply-To: <20260606-bitfield-v5-0-b92188820914@nvidia.com> To: Yury Norov , Miguel Ojeda , Boqun Feng , Gary Guo , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Andreas Hindborg , Alice Ryhl , Trevor Gross , Danilo Krummrich , Daniel Almeida , David Airlie , Simona Vetter Cc: John Hubbard , Alistair Popple , Timur Tabi , Zhi Wang , Eliot Courtney , linux-kernel@vger.kernel.org, rust-for-linux@vger.kernel.org, nova-gpu@lists.linux.dev, driver-core@lists.linux.dev, Alexandre Courbot , Yury Norov X-Mailer: b4 0.15.2 X-ClientProxiedBy: TY4PR01CA0121.jpnprd01.prod.outlook.com (2603:1096:405:379::19) To CH2PR12MB3990.namprd12.prod.outlook.com (2603:10b6:610:28::18) Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: CH2PR12MB3990:EE_|BL1PR12MB5730:EE_ X-MS-Office365-Filtering-Correlation-Id: dea625ea-8a57-45d8-aaf2-08dec3c92fd4 X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|1800799024|10070799003|366016|7416014|376014|22082099003|18002099003|6133799003|921020|5023799004|11063799006|56012099006|3023799007; X-Microsoft-Antispam-Message-Info: ii2/0uRJ8NkV1tdxnGSTZKXwCp+r8yhSwk+FgwfQ0ou3iOrZ3B93BEkf7rJO93Xg/em0fyOzM/HNPVgtQFGaplfWWjK5ZT4lfbt4xLmr+0rkOi4hPwuYdZ/aou88FBmPaqhk7pELnDf9vqLkyiYPFXwGKNU4XgQHXdMSjA0eYsCCQu5MydYs1zjvM0MF5gb9jh+tkzc8iiap8ulrYAzZ1U3p382dRWgbA/2xqHMCNdaq7wBrYlGQbZ2OrL8DNRqK7ZZ6rdm/yOO8gDW4fGUpTLnHKdY/4waRAo9XMvcknw0tbamdOo5pXolsFTIYB5pEKMgyJIqerwAdoyZ7Co3S6MlqG5iREQJQgWnbq22jWbAxPUd03A7KqyTzWFkOTxrNO7TtsVYw2FUUPyWMngk160tO+UgwBg465gs8w0l/OnY1VUo1n5JqkBFeTWACu80WwLdDTXOoCeyGq7soqShsSuRKSLdWno8TUbPcLJl8DLtPmo1zsl0S0a2AHlNLBGrTLz32OG6Y1YFmRWYaXWMEk1jJIOIsPNmb6KxlAehd2nDgRfVgbR5SYQN57uusE+ohsgsQJbEizJYFJuBiiJB0YRHGdV7BVtvw9rBy9wCGdpExgEV1UUDCVFptVBRN93JIUP1uEzS5Fgiu+WSwPxnFNpdVeBb72+2NrcjvY6BGB5KURytfyWqRBJiiSRU299zeK8Cvhs0DVZB1/v/r7dv2cmoRNNLky30fVcqrHUtNbtA0BMD9C8KZcPnJmfCABJ+S X-Forefront-Antispam-Report: CIP:255.255.255.255;CTRY:;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:CH2PR12MB3990.namprd12.prod.outlook.com;PTR:;CAT:NONE;SFS:(13230040)(1800799024)(10070799003)(366016)(7416014)(376014)(22082099003)(18002099003)(6133799003)(921020)(5023799004)(11063799006)(56012099006)(3023799007);DIR:OUT;SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 2 X-MS-Exchange-AntiSpam-MessageData-0: =?utf-8?B?ME5NYzBkKzFuaUxNS1lrU09IaS9NTXl1MWp5NnFTRkhzUFNWUFFhc2xBWWY3?= =?utf-8?B?cGJWU3RaZUJTOThPQ0VWdzFtUVBSZSsxQkdiZStSb3FqQVZGMHZCRnFTaEIy?= =?utf-8?B?WHB0SEhhV01xZmcxc0Vma1ZaTnFGSG4vYlFMUk1kNmRKSmRtUjc4bERoWW9z?= =?utf-8?B?QUJwNmh4QzlCVW16N2oyTGMrY1VkdVlXSWZCSEU0UXFhUjBTK3Z0ZFhvVStP?= =?utf-8?B?eDRsdzlqSjVzSTBYb3dsQWM2eEZvVzFURHJqQWo0cHBTY2RZYzNGcFpHbkVR?= =?utf-8?B?NzlDbnBBTTlFSnM4cXN3bnR2WThpckt6MzRBQU9MeXh3ckg5UFFiTkxTbEY2?= =?utf-8?B?MW1DTXhUQzdVUGJyS1p4SXJGV1hCUjhYYzJPaEpPTXRHNnM5ZnpHdEx6Q0RY?= =?utf-8?B?eDkxSnkyZzNISFRFOXlFTHkyakZpeWRST1R1RTRXVjhzRkR5QWRBcnUrcDNi?= =?utf-8?B?U2JxSWxhUmt0cWt0QUc2NkxTSnk4ZnJmSWRVK0F1RHoweHlObWxqblZiYlBZ?= =?utf-8?B?Z09uZVNON1p2d04zN2dZUlpXcm8yWVQ1WnA3Vkx0dE9hS29VR3k0TnMyMUg5?= =?utf-8?B?UE9vdDMxNGVieHFNOGM5MmlvbUtTTDBVZ0hLM29EWTdsSS9FdkJKMnUzUTl4?= =?utf-8?B?cjV5SDYzZFdvR21jVnE0YXlZcWg1RFlCMkFGQzlCeGoyU2xEKzVuNUFLNjc0?= =?utf-8?B?RldnUVVwbEx1U25EZVpxQjhqVW1SbFhvdHhOTkxRTzZnSjIxdmFuQ3BzTmJw?= =?utf-8?B?U3dvcGRESjlTYVJxbWw0a0lWQy9ER2JvODd4MTFTcDJWa0duMXh5L3Mrdm4v?= =?utf-8?B?M3lrOEQxTnhLbXZrdTF2U0V6emlKeFl4SzdSNWM3L0xkVDhJMzl6ZTAwV1hj?= =?utf-8?B?NmdhY09YNzJFVFdZYlZYUkE5NFBTNVRNYjBwMFczdmIwUzR2ZlhRYzNIdklw?= =?utf-8?B?a0tXcGt4eU5PWEZqTE1oKzY3RitNN1YxcFQ5VFZCaXU0ZkZpTURBLzJYeitC?= =?utf-8?B?blpkV3pKUWRtVU5BdDNVc0hDUVFyRWljNFRwT1gzRlBZa2F0MkxYYVUzeEU5?= =?utf-8?B?WmhKekFEYW1qakdaYU5kVWgvMHNLME5FZTk1WTFKK2wrdEE2V3liN0grL0hR?= =?utf-8?B?L3VOZUZyRUErK0tXR0p1ZjNUMno1SlhueFdLMm9BOTBrWVp3TGlUWjZyZERU?= =?utf-8?B?WTdzbWxDQTh1alQyRWJ1VFFyeVZGTTdmUE11U20zMFZneWFKUy9LVEkvcFNo?= =?utf-8?B?Z2NwTUZpVGFmbnphUjNISmdObnQva1hPVjExYW83MjZaT0xIcmJoQWxIWENt?= =?utf-8?B?aUpiV0xLd0tVd2RjVzVyd2pxVVI3K3hWcnRyeXJob00rR1B5S09ZTlgrem1R?= =?utf-8?B?OE5LV3IydHp1L3JaL0hMNTZTVnhZWEVzQjVpSnRPNUhyczdCMTUxbHZLdjZU?= =?utf-8?B?RTF5Z1RGYi9Da0cyTGg4WnA3UUkxckJYcHlGVy9HdTNvcDFUOXlnZSttOElE?= =?utf-8?B?U3ZiL1dpdU0zTStzTlU4Q2JyV0JmS0Rpc005L2MrSWhzUzdreHBUWE5WazNi?= =?utf-8?B?LzMra1ZMeXZ6bS8yay9MR2RKYXFGRG9wZndlMDZsWlNPQWNuY0tsWEwyY3FY?= =?utf-8?B?QWN2UGFQZ0VQOW1RWktHSmkyYUN1ZzdlbUl4MElWZEFjODUvV0lYcWU4bmJz?= =?utf-8?B?ZytPNlk4WmVlMWpzS0Vodld0T1VFZUtkV3NXUFEycW94cXNWdldxbHZnOHJC?= =?utf-8?B?U0ZJMGg0bVVmYm9TWnJUZjgvMjJhY3pBYWZiVTZ1b3pUQytBbTJnQVlZcVc2?= =?utf-8?B?ZERwM0pFUTg5My9ocHpLNTl2Qi9heTBwZi9Xazkxby9ra3lJd0IvajNQM0ds?= =?utf-8?B?UC8rSDg4cytROTdvSklrbXB1VGphb21EUFV5WW1hYnhDTEhjWnFZbnhQeXlC?= =?utf-8?B?VEhhbml3aWswSTRBNEMvMFNGZ1pXbjNXT2dLOG91WENGb0p4Ynpobld3bmlE?= =?utf-8?B?MzREdU9CYkdLR2RMcEJvS3pyM2dRNFVHQnphajJIODlkdXNsSXM0VnpHWjV1?= =?utf-8?B?VjlvSkx6SDdzclllbFAyZlN5aHYvZVJLZ3Bwb0JmRFg5K1ZFNjd6dGRPRmIz?= =?utf-8?B?MUVuNXM3dGh1ajcxMGlpcHhRdEdPb21kc3dWdmp2OTM1WW13a3ZlYmF1RGFV?= =?utf-8?B?S2M2K0lSR1lNcUN3K09yNmxmY2hYZ3FkTE9Hc2EvL3JNY0F3cCtYZUlIbGg1?= =?utf-8?B?akYybWk1RHBpZ21qMG5LZXdXdUpZRFpVNWxxNnE5TXE5bmRoQzNhc2tqV1dM?= =?utf-8?B?c3FQS0lMektycGJWVFEyYTA1d1ZuWnF0S1VLaWUxSTZCVE9UdmlJSDdBZEdv?= =?utf-8?Q?mt4eeNFEZjU8S//J9DarIAvb8fmQrjx1eYvRtojH7c4Cl?= X-MS-Exchange-AntiSpam-MessageData-1: jtkBwVQDQqci1g== X-OriginatorOrg: Nvidia.com X-MS-Exchange-CrossTenant-Network-Message-Id: dea625ea-8a57-45d8-aaf2-08dec3c92fd4 X-MS-Exchange-CrossTenant-AuthSource: CH2PR12MB3990.namprd12.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 06 Jun 2026 12:43:19.8468 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: 43083d15-7273-40c1-b7db-39efd9ccc17a X-MS-Exchange-CrossTenant-MailboxType: HOSTED X-MS-Exchange-CrossTenant-UserPrincipalName: V/EiHMWD8ZvFQRLihmoUp4qqS5HsGqnMEwLG6jndLEZIyQtfV3P+PHjUfEVz17cuTlh0lr5ParpXK0WJQSFsOw== X-MS-Exchange-Transport-CrossTenantHeadersStamped: BL1PR12MB5730 Extract the bitfield-defining part of the `register!` macro into an independent macro used to define bitfield types with bounds-checked accessors. Each field is represented as a `Bounded` of the appropriate bit width, ensuring field values are never silently truncated. Fields can optionally be converted to/from custom types, either fallibly or infallibly. Appropriate documentation is also added, and a MAINTAINERS entry created for the new module. Two minor fixups are also applied: the private accessors are inlined, and a couple of missing fully qualified types in the macro are fixed. Acked-by: Yury Norov Acked-by: Danilo Krummrich Signed-off-by: Alexandre Courbot --- MAINTAINERS | 7 + rust/kernel/bitfield.rs | 548 ++++++++++++++++++++++++++++++++++++++++++++= ++++ rust/kernel/lib.rs | 1 + 3 files changed, 556 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index c2c6d79275c6..d40e0c606893 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -23422,6 +23422,13 @@ T: git https://github.com/Rust-for-Linux/linux.git= alloc-next F: rust/kernel/alloc.rs F: rust/kernel/alloc/ =20 +RUST [BITFIELD] +M: Alexandre Courbot +R: Yury Norov +L: rust-for-linux@vger.kernel.org +S: Maintained +F: rust/kernel/bitfield.rs + RUST [INTEROP] M: Joel Fernandes M: Alexandre Courbot diff --git a/rust/kernel/bitfield.rs b/rust/kernel/bitfield.rs new file mode 100644 index 000000000000..2498107979dc --- /dev/null +++ b/rust/kernel/bitfield.rs @@ -0,0 +1,548 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! Support for defining bitfields as Rust structures. +//! +//! The [`bitfield!`](kernel::bitfield!) macro declares integer types that= are split into distinct +//! bit fields of arbitrary length. Each field is typed using [`Bounded`](= kernel::num::Bounded) to +//! ensure values are properly validated and to avoid implicit data loss. +//! +//! # Example +//! +//! ```rust +//! use kernel::bitfield; +//! use kernel::num::Bounded; +//! +//! bitfield! { +//! pub struct Rgb(u16) { +//! 15:11 blue; +//! 10:5 green; +//! 4:0 red; +//! } +//! } +//! +//! // Valid value for the `blue` field. +//! let blue =3D Bounded::::new::<0x18>(); +//! +//! // Setters can be chained. Values ranges are checked at compile-time. +//! let color =3D Rgb::zeroed() +//! // Compile-time bounds check of constant value. +//! .with_const_red::<0x10>() +//! .with_const_green::<0x1f>() +//! // A `Bounded` can also be passed. +//! .with_blue(blue); +//! +//! assert_eq!(color.red(), 0x10); +//! assert_eq!(color.green(), 0x1f); +//! assert_eq!(color.blue(), 0x18); +//! assert_eq!( +//! color.into_raw(), +//! (0x18 << Rgb::BLUE_SHIFT) + (0x1f << Rgb::GREEN_SHIFT) + 0x10, +//! ); +//! +//! // Convert to/from the backing storage type. +//! let raw: u16 =3D color.into(); +//! assert_eq!(Rgb::from(raw), color); +//! ``` +//! +//! # Syntax +//! +//! ```text +//! bitfield! { +//! #[attributes] +//! // Documentation for `Name`. +//! pub struct Name(storage_type) { +//! // `field_1` documentation. +//! hi:lo field_1; +//! // `field_2` documentation. +//! hi:lo field_2 =3D> ConvertedType; +//! // `field_3` documentation. +//! hi:lo field_3 ?=3D> ConvertedType; +//! ... +//! } +//! } +//! ``` +//! +//! - `storage_type`: The underlying unsigned integer type (`u8`, `u16`, `= u32`, `u64`). +//! Signed integer storage types are not supported. +//! - `hi:lo`: Bit range (inclusive), where `hi >=3D lo`. +//! - `=3D> Type`: Optional infallible conversion (see [below](#infallible= -conversion-)). +//! - `?=3D> Type`: Optional fallible conversion (see [below](#fallible-co= nversion-)). +//! - Documentation strings and attributes are optional. +//! +//! # Generated code +//! +//! Each field is internally represented as a [`Bounded`] parameterized by= its bit width. Field +//! values can either be set/retrieved directly, or converted from/to anot= her type. +//! +//! The use of `Bounded` for each field enforces bounds-checking (at build= time or runtime) of every +//! value assigned to a field. This ensures that data is never accidentall= y truncated. +//! +//! The macro generates the bitfield type, [`From`] and [`Into`] implement= ations for its storage +//! type, as well as [`Debug`] and [`Zeroable`](pin_init::Zeroable) implem= entations. +//! +//! For each field, it also generates: +//! +//! - `field()`: Getter method for the field value. +//! - `with_field(value)`: Infallible setter; the argument type must fit w= ithin the field's width. +//! - `with_const_field::()`: `const` setter; the value is validate= d at compile time. +//! Usually shorter to use than `with_field` for constant values as it d= oesn't require +//! constructing a [`Bounded`]. +//! - `try_with_field(value)`: Fallible setter. Returns an error if the va= lue is out of range. +//! - `FIELD_MASK`, `FIELD_SHIFT`, `FIELD_RANGE`: Constants for manual bit= manipulation. +//! +//! # Reserved names for field identifiers +//! +//! Field identifiers are used to generate methods and associated constant= s on the bitfield type. +//! For a field named `field`, the macro may generate methods named `field= `, `with_field`, +//! `with_const_field`, `try_with_field`, `__field` and `__with_field`, as= well as constants named +//! `FIELD_MASK`, `FIELD_SHIFT` and `FIELD_RANGE`. +//! +//! Therefore, field identifiers must not use names that would collide wit= h generated items for +//! any field in the same bitfield. The following prefixes are thus reserv= ed for field identifiers: +//! +//! - `with_` +//! - `const_` +//! - `try_with_` +//! - `__` +//! +//! The field identifiers `from_raw`, `into_raw`, and `into` are also rese= rved. +//! +//! In addition, field identifiers should follow Rust `snake_case` convent= ions, since the associated +//! constants are generated by uppercasing the field name. +//! +//! # Implicit conversions +//! +//! Types that fit entirely within a field's bit width can be used directl= y with setters. For +//! example, `bool` works with single-bit fields, and `u8` works with 8-bi= t fields: +//! +//! ```rust +//! use kernel::bitfield; +//! +//! bitfield! { +//! pub struct Flags(u32) { +//! 15:8 byte_field; +//! 0:0 flag; +//! } +//! } +//! +//! let flags =3D Flags::zeroed() +//! .with_byte_field(0x42_u8) +//! .with_flag(true); +//! +//! assert_eq!(flags.into_raw(), (0x42 << Flags::BYTE_FIELD_SHIFT) | 1); +//! ``` +//! +//! # Runtime bounds checking +//! +//! When a value is not known at compile time, use `try_with_field()` to c= heck bounds at runtime: +//! +//! ```rust +//! use kernel::bitfield; +//! +//! bitfield! { +//! pub struct Config(u8) { +//! 3:0 nibble; +//! } +//! } +//! +//! fn set_nibble(config: Config, value: u8) -> Result { +//! // Returns `EOVERFLOW` if `value > 0xf`. +//! config.try_with_nibble(value) +//! } +//! # Ok::<(), Error>(()) +//! ``` +//! +//! # Type conversion +//! +//! Fields can be automatically converted to/from a custom type using `=3D= >` (infallible) or `?=3D>` +//! (fallible). The custom type must implement the appropriate `From` or `= TryFrom` traits with +//! `Bounded`. +//! +//! ## Infallible conversion (`=3D>`) +//! +//! Use this when all possible bit patterns of a field map to valid values: +//! +//! ```rust +//! use kernel::bitfield; +//! use kernel::num::Bounded; +//! +//! #[derive(Debug, Clone, Copy, PartialEq)] +//! enum Power { +//! Off, +//! On, +//! } +//! +//! impl From> for Power { +//! fn from(v: Bounded) -> Self { +//! match *v { +//! 0 =3D> Power::Off, +//! _ =3D> Power::On, +//! } +//! } +//! } +//! +//! impl From for Bounded { +//! fn from(p: Power) -> Self { +//! (p as u32 !=3D 0).into() +//! } +//! } +//! +//! bitfield! { +//! pub struct Control(u32) { +//! 0:0 power =3D> Power; +//! } +//! } +//! +//! let ctrl =3D Control::zeroed().with_power(Power::On); +//! assert_eq!(ctrl.power(), Power::On); +//! ``` +//! +//! ## Fallible conversion (`?=3D>`) +//! +//! Use this when some bit patterns of a field are invalid. The getter ret= urns a [`Result`]: +//! +//! ```rust +//! use kernel::bitfield; +//! use kernel::num::Bounded; +//! +//! #[derive(Debug, Clone, Copy, PartialEq)] +//! enum Mode { +//! Low =3D 0, +//! High =3D 1, +//! Auto =3D 2, +//! // 3 is invalid +//! } +//! +//! impl TryFrom> for Mode { +//! type Error =3D u32; +//! +//! fn try_from(v: Bounded) -> Result { +//! match *v { +//! 0 =3D> Ok(Mode::Low), +//! 1 =3D> Ok(Mode::High), +//! 2 =3D> Ok(Mode::Auto), +//! n =3D> Err(n), +//! } +//! } +//! } +//! +//! impl From for Bounded { +//! fn from(m: Mode) -> Self { +//! match m { +//! Mode::Low =3D> Bounded::::new::<0>(), +//! Mode::High =3D> Bounded::::new::<1>(), +//! Mode::Auto =3D> Bounded::::new::<2>(), +//! } +//! } +//! } +//! +//! bitfield! { +//! pub struct Config(u32) { +//! 1:0 mode ?=3D> Mode; +//! } +//! } +//! +//! let cfg =3D Config::zeroed().with_mode(Mode::Auto); +//! assert_eq!(cfg.mode(), Ok(Mode::Auto)); +//! +//! // Invalid bit pattern returns an error. +//! assert_eq!(Config::from(0b11).mode(), Err(3)); +//! ``` +//! +//! # Bits outside of declared fields +//! +//! Bits of the storage type that are not part of any declared field are p= reserved by the setter +//! methods, and can only be modified through `from_raw` or the [`From`] i= mplementation from the +//! storage type. +//! +//! ```rust +//! use kernel::bitfield; +//! +//! bitfield! { +//! pub struct Sparse(u8) { +//! 7:6 high; +//! // Bits 5:1 are not covered by any field. +//! 0:0 low; +//! } +//! } +//! +//! // Set the gap bits via `from_raw`, then mutate the declared fields. +//! let val =3D Sparse::from_raw(0b0010_1010) +//! .with_const_high::<0b11>() +//! .with_low(true); +//! +//! // Bits 5:1 are unchanged. +//! assert_eq!(val.into_raw(), 0b1110_1011); +//! ``` +//! +//! # Signed field values +//! +//! Bitfield storage types are unsigned. Since field getter methods return= a [`Bounded`] of the +//! storage type, fields are also unsigned by default. +//! +//! If a field needs to encode a signed value, use a custom conversion typ= e with `=3D>` or `?=3D>` to +//! perform the sign interpretation explicitly. +//! +//! [`Bounded`]: kernel::num::Bounded + +/// Defines a bitfield struct with bounds-checked accessors for individual= bit ranges. +/// +/// See the [`mod@kernel::bitfield`] module for full documentation and exa= mples. +#[macro_export] +macro_rules! bitfield { + // Entry point defining the bitfield struct, its implementations and i= ts field accessors. + ( + $(#[$attr:meta])* $vis:vis struct $name:ident($storage:ty) { $($fi= elds:tt)* } + ) =3D> { + $crate::bitfield!(@core + #[allow(non_camel_case_types)] + $(#[$attr])* $vis $name $storage + ); + $crate::bitfield!(@fields $vis $name $storage { $($fields)* }); + }; + + // All rules below are helpers. + + // Defines the wrapper `$name` type and its conversions from/to the st= orage type. + (@core $(#[$attr:meta])* $vis:vis $name:ident $storage:ty) =3D> { + $(#[$attr])* + #[repr(transparent)] + #[derive(Clone, Copy, PartialEq, Eq)] + $vis struct $name { + inner: $storage, + } + + #[allow(dead_code)] + impl $name { + /// Creates a bitfield from a raw value. + #[inline(always)] + $vis const fn from_raw(value: $storage) -> Self { + Self{ inner: value } + } + + /// Turns this bitfield into its raw value. + /// + /// This is similar to the [`From`] implementation, but is sho= rter to invoke in + /// most cases. + #[inline(always)] + $vis const fn into_raw(self) -> $storage { + self.inner + } + } + + // SAFETY: `$storage` is `Zeroable` and `$name` is transparent. + unsafe impl ::pin_init::Zeroable for $name {} + + impl ::core::convert::From<$name> for $storage { + #[inline(always)] + fn from(val: $name) -> $storage { + val.into_raw() + } + } + + impl ::core::convert::From<$storage> for $name { + #[inline(always)] + fn from(val: $storage) -> $name { + Self::from_raw(val) + } + } + }; + + // Definitions requiring knowledge of individual fields: private and p= ublic field accessors, + // and `Debug` implementation. + (@fields $vis:vis $name:ident $storage:ty { + $($(#[doc =3D $doc:expr])* $hi:literal:$lo:literal $field:ident + $(?=3D> $try_into_type:ty)? + $(=3D> $into_type:ty)? + ; + )* + } + ) =3D> { + #[allow(dead_code)] + impl $name { + $( + $crate::bitfield!(@private_field_accessors $vis $name $storage : $= hi:$lo $field); + $crate::bitfield!( + @public_field_accessors $(#[doc =3D $doc])* $vis $name $storag= e : $hi:$lo $field + $(?=3D> $try_into_type)? + $(=3D> $into_type)? + ); + )* + } + + $crate::bitfield!(@debug $name { $($field;)* }); + }; + + // Private field accessors working with the exact `Bounded` type for t= he field. + ( + @private_field_accessors $vis:vis $name:ident $storage:ty : $hi:tt= :$lo:tt $field:ident + ) =3D> { + ::kernel::macros::paste!( + $vis const [<$field:upper _RANGE>]: ::core::ops::RangeInclusive =3D $lo..=3D$hi; + $vis const [<$field:upper _MASK>]: $storage =3D + ((((1 << $hi) - 1) << 1) + 1) - ((1 << $lo) - 1); + $vis const [<$field:upper _SHIFT>]: u32 =3D $lo; + ); + + ::kernel::macros::paste!( + #[inline(always)] + fn [<__ $field>](self) -> + ::kernel::num::Bounded<$storage, { $hi + 1 - $lo }> { + // Left shift to align the field's MSB with the storage MSB. + const ALIGN_TOP: u32 =3D $storage::BITS - ($hi + 1); + // Right shift to move the top-aligned field to bit 0 of the s= torage. + const ALIGN_BOTTOM: u32 =3D ALIGN_TOP + $lo; + + // Extract the field using two shifts. `Bounded::shr` produces= the correctly-sized + // output type. + let val =3D ::kernel::num::Bounded::<$storage, { $storage::BIT= S }>::from( + self.inner << ALIGN_TOP + ); + val.shr::() + } + + #[inline(always)] + const fn [<__with_ $field>]( + mut self, + value: ::kernel::num::Bounded<$storage, { $hi + 1 - $lo }>, + ) -> Self + { + const MASK: $storage =3D <$name>::[<$field:upper _MASK>]; + const SHIFT: u32 =3D <$name>::[<$field:upper _SHIFT>]; + + let value =3D value.get() << SHIFT; + self.inner =3D (self.inner & !MASK) | value; + + self + } + ); + }; + + // Public accessors for fields infallibly (`=3D>`) converted to a type. + ( + @public_field_accessors $(#[doc =3D $doc:expr])* $vis:vis $name:id= ent $storage:ty : + $hi:literal:$lo:literal $field:ident =3D> $into_type:ty + ) =3D> { + ::kernel::macros::paste!( + + $(#[doc =3D $doc])* + #[doc =3D "Returns the value of this field."] + #[inline(always)] + $vis fn $field(self) -> $into_type + { + self.[<__ $field>]().into() + } + + $(#[doc =3D $doc])* + #[doc =3D "Sets this field to the given `value`."] + #[inline(always)] + $vis fn [](self, value: $into_type) -> Self + { + self.[<__with_ $field>](value.into()) + } + + ); + }; + + // Public accessors for fields fallibly (`?=3D>`) converted to a type. + ( + @public_field_accessors $(#[doc =3D $doc:expr])* $vis:vis $name:id= ent $storage:ty : + $hi:tt:$lo:tt $field:ident ?=3D> $try_into_type:ty + ) =3D> { + ::kernel::macros::paste!( + + $(#[doc =3D $doc])* + #[doc =3D "Returns the value of this field."] + #[inline(always)] + $vis fn $field(self) -> + ::core::result::Result< + $try_into_type, + <$try_into_type as ::core::convert::TryFrom< + ::kernel::num::Bounded<$storage, { $hi + 1 - $lo }> + >>::Error + > + { + self.[<__ $field>]().try_into() + } + + $(#[doc =3D $doc])* + #[doc =3D "Sets this field to the given `value`."] + #[inline(always)] + $vis fn [](self, value: $try_into_type) -> Self + { + self.[<__with_ $field>](value.into()) + } + + ); + }; + + // Public accessors for fields not converted to a type. + ( + @public_field_accessors $(#[doc =3D $doc:expr])* $vis:vis $name:id= ent $storage:ty : + $hi:tt:$lo:tt $field:ident + ) =3D> { + ::kernel::macros::paste!( + + $(#[doc =3D $doc])* + #[doc =3D "Returns the value of this field."] + #[inline(always)] + $vis fn $field(self) -> + ::kernel::num::Bounded<$storage, { $hi + 1 - $lo }> + { + self.[<__ $field>]() + } + + $(#[doc =3D $doc])* + #[doc =3D "Sets this field to the compile-time constant `VALUE`."] + #[inline(always)] + $vis const fn [](self) = -> Self { + self.[<__with_ $field>]( + ::kernel::num::Bounded::<$storage, { $hi + 1 - $lo }>::new= ::() + ) + } + + $(#[doc =3D $doc])* + #[doc =3D "Sets this field to the given `value`."] + #[inline(always)] + $vis fn []( + self, + value: T, + ) -> Self + where T: ::core::convert::Into<::kernel::num::Bounded<$storage= , { $hi + 1 - $lo }>>, + { + self.[<__with_ $field>](value.into()) + } + + $(#[doc =3D $doc])* + #[doc =3D "Tries to set this field to `value`, returning an error = if it is out of range."] + #[inline(always)] + $vis fn []( + self, + value: T, + ) -> ::kernel::error::Result + where T: ::kernel::num::TryIntoBounded<$storage, { $hi + 1 - $= lo }>, + { + Ok( + self.[<__with_ $field>]( + value.try_into_bounded().ok_or(::kernel::error::code::= EOVERFLOW)? + ) + ) + } + + ); + }; + + // `Debug` implementation. + (@debug $name:ident { $($field:ident;)* }) =3D> { + impl ::kernel::fmt::Debug for $name { + fn fmt(&self, f: &mut ::kernel::fmt::Formatter<'_>) -> ::kerne= l::fmt::Result { + f.debug_struct(stringify!($name)) + .field("", &::kernel::prelude::fmt!("{:#x}", self= .inner)) + $( + .field(stringify!($field), &self.$field()) + )* + .finish() + } + } + }; +} diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs index b72b2fbe046d..9512af7156df 100644 --- a/rust/kernel/lib.rs +++ b/rust/kernel/lib.rs @@ -44,6 +44,7 @@ pub mod alloc; #[cfg(CONFIG_AUXILIARY_BUS)] pub mod auxiliary; +pub mod bitfield; pub mod bitmap; pub mod bits; #[cfg(CONFIG_BLOCK)] --=20 2.54.0 From nobody Mon Jun 8 06:36:40 2026 Received: from SN4PR2101CU001.outbound.protection.outlook.com (mail-southcentralusazon11012006.outbound.protection.outlook.com [40.93.195.6]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 54353378D9F; Sat, 6 Jun 2026 12:43:30 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=40.93.195.6 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780749811; cv=fail; b=uPGORhiFf270LrmyY8qZpUDwLffIzqrV27Mnlzaa3f3q4ae4RKQ74ss0+Cn/ZncjlDBBoPPwQetQPID8wq5pdXUkbYtcv89qnUPDsVEIj1xvyJ7G93pbTC5sRwYfs0kC3FJf03yutp5sv/IooVbWCGif3IatFZF1Yu+sF0lIa2M= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780749811; c=relaxed/simple; bh=/B5dPsLNsNBDyYI9rPH2hWACa18Y1eQRhIzpZ/K+E4Y=; h=From:Date:Subject:Content-Type:Message-Id:References:In-Reply-To: To:Cc:MIME-Version; b=CtAZedov5+N2ffx7vu2CC3s44a/vZYV302MEYZbx4B9Y2S/cR8Vid2gQLf8jU0ndYYiQ6pmD88YZhZN5u5G6TWRnYsj5Pl3GL0idCAxLpSrt6Bnnwz5MAnpxO7YR0fGIMnTP8RCx1EJUS0vgpv/woXYakyfxCfaSVTjRkCpqMgg= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=nvidia.com; spf=fail smtp.mailfrom=nvidia.com; dkim=pass (2048-bit key) header.d=Nvidia.com header.i=@Nvidia.com header.b=rc54VWbM; arc=fail smtp.client-ip=40.93.195.6 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=nvidia.com Authentication-Results: smtp.subspace.kernel.org; spf=fail smtp.mailfrom=nvidia.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=Nvidia.com header.i=@Nvidia.com header.b="rc54VWbM" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=qMGIlO4vgwOBqY0F16DNpzl5nWukMX7INVY2SCPLQAlxDjhnBEJ54Vgk2sM9GXdc840yQ9VXaxdqaqu+XaeufSAQ+ZZb/s97VirJrw+AS5S2BhPU62U8M6797RV4fTNN0BHCIOxx/ysIXyKrYiIw+eg349vb9b5irCMBbog+qaPcm8fCTArtGplwnTSNvtAWmubfTwYD9zEKb66YX1eWTwgYxMQqgJbJO3iSVhYNggwyV7ib8+mkzgrMzOIu92KcMiNeg0xrw5YUmzWyPLs9k13/xQqjw2b7ZBHfstgax9GCUqCEiXyVGjrYvVF3ix3/pnlby6OMZnX04asERwIdRQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector10001; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=xsGpwbjo0lscqhknCCCN37hsjfVFAXBIc8Qii3NckEM=; b=DMRWP24/LrGReEQ86QaruDEI8Ux+aFWNaZ908PCdgDmjaQsEZUpK5mNDPlas34dZYZxZ5MX3DDq9trR8BbYfIW+OJ7C48UqANXu1NBcF/2rKtHaCAd2WcPLTHCYRMBoi0+14bORBmLOvxxoCNUqmhZA20JbFedYt7varA6O459/8fvRy45fJkh6nNNI8ZVkax2wwWM+YWrxDoF8nOU5h0juxaITeURSoTxW0++M6y1v0Sj6tI2U1jkKJoZNZAMxB4tEStdCcD8f51lJc/JrdyZax8Aiz11gZrrcgJLHwZoYqY0qnOab/5kJzbCx2dlZoQ8K5uu5cjn3vcW8T/ic/fw== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=nvidia.com; dmarc=pass action=none header.from=nvidia.com; dkim=pass header.d=nvidia.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=Nvidia.com; s=selector2; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=xsGpwbjo0lscqhknCCCN37hsjfVFAXBIc8Qii3NckEM=; b=rc54VWbMrtJ5k+5LTyhzlsagsd6EYI9nrF+f8NNN5BiLhsGP6AT6XuKoGR0YKcFcUU1yzjSAp53fJDyCkFXlV+dP6h2305PNUxnn6tUp75qvf4/MQ/jKpeYiRpL1G2Cl0zSw3XA3jj4vkxkYqleYweIkVg02KuMjnKuEdvNfuCoUtutEZ7GCKBbtrjW28DNmjUVblnvwSlN4crxRe8fFoScxWiPQny2OSDdUssj/3Mbv7yGC2G3pyfMNXKlr27X2x0aY0qne165gdggV6X6+WVGq6Rtb4O1+RcP5ATvMkx7us5mtajkG+WTnw0F3JamHZWdcOdcrurjbL5RLCjoMCA== Authentication-Results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=nvidia.com; Received: from CH2PR12MB3990.namprd12.prod.outlook.com (2603:10b6:610:28::18) by BL1PR12MB5730.namprd12.prod.outlook.com (2603:10b6:208:385::9) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.21.92.11; Sat, 6 Jun 2026 12:43:25 +0000 Received: from CH2PR12MB3990.namprd12.prod.outlook.com ([fe80::7de1:4fe5:8ead:5989]) by CH2PR12MB3990.namprd12.prod.outlook.com ([fe80::7de1:4fe5:8ead:5989%4]) with mapi id 15.21.0092.007; Sat, 6 Jun 2026 12:43:25 +0000 From: Alexandre Courbot Date: Sat, 06 Jun 2026 21:43:05 +0900 Subject: [PATCH v5 2/3] rust: bitfield: Add KUnit tests for bitfield Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260606-bitfield-v5-2-b92188820914@nvidia.com> References: <20260606-bitfield-v5-0-b92188820914@nvidia.com> In-Reply-To: <20260606-bitfield-v5-0-b92188820914@nvidia.com> To: Yury Norov , Miguel Ojeda , Boqun Feng , Gary Guo , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Andreas Hindborg , Alice Ryhl , Trevor Gross , Danilo Krummrich , Daniel Almeida , David Airlie , Simona Vetter Cc: John Hubbard , Alistair Popple , Timur Tabi , Zhi Wang , Eliot Courtney , linux-kernel@vger.kernel.org, rust-for-linux@vger.kernel.org, nova-gpu@lists.linux.dev, driver-core@lists.linux.dev, Alexandre Courbot , Joel Fernandes X-Mailer: b4 0.15.2 X-ClientProxiedBy: TYCP286CA0268.JPNP286.PROD.OUTLOOK.COM (2603:1096:400:455::13) To CH2PR12MB3990.namprd12.prod.outlook.com (2603:10b6:610:28::18) Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: CH2PR12MB3990:EE_|BL1PR12MB5730:EE_ X-MS-Office365-Filtering-Correlation-Id: 894cefe9-9677-4d98-2e6e-08dec3c93385 X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|1800799024|10070799003|366016|7416014|376014|22082099003|18002099003|921020|11063799006|56012099006; X-Microsoft-Antispam-Message-Info: BnPMw8cmlh+e65Q0W55ZEHvyGohRf+c2vmSBH53vLA7VA9nSbPbbgSehzmBN3Eo9I0+8Gt7jJL3sDWZXg4iw1zXSLtK93QQUBYWQ+TgNOdeGaklsSzIDIUS/PKY6/qUDvx3JYCj7BoSPWy++YaNJFdJXcr9x1dn3F7Y4GGTYGwmtLSskDPPSQzgWAmz4PNhvf0hgUPT23lvNZun5MFGDX/Zli8FAjPYT2K9t4C8dAGECZkIz4GKPPmJC3CEgwHF8HwYs4LGpogjIBwZaXnmRBMthbihqMMu0od5dky7i6MZ0ojwSmdrXlRRD5jUsi214g0PZxDURTM6n59RAKsLNw474xUs5W5SfsZvtfEMlsscTwgImgGdvrsOY6/IqhJr/M8DwHAneD1tYe/y2JSysdVVyzfeyb1UevRxe3qbAtxHNCSsBcV+ciFdbWVaFxjOvLmUD9IoQ5hFhY1es7MgpF4i4YsnF4ZXiBJ5gF52cgAo7WkEyMbKUiBkaRqHcHkI4NQbVsqNw1muzcTGcZdigUFbuN/tWTXFuHVHDz1FTb15zyjTo49eLovsFnDLR7KPoRYsuWCq67mYXXmCIy/CCGeAFwfD3K/jlcInGDOMXBhDOJC2Mt61USnY/ek1pSiWjTSu0IkUQZG8wXr23v/q613u4CE1LkafHRfUFJFn70dxJKx3gYdQwovQnsgG2HJ0Q6t+XgHRKHNdp0Uj/6wzfOr9iAsdrIU7lqzqF/mnBwIk= X-Forefront-Antispam-Report: CIP:255.255.255.255;CTRY:;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:CH2PR12MB3990.namprd12.prod.outlook.com;PTR:;CAT:NONE;SFS:(13230040)(1800799024)(10070799003)(366016)(7416014)(376014)(22082099003)(18002099003)(921020)(11063799006)(56012099006);DIR:OUT;SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 2 X-MS-Exchange-AntiSpam-MessageData-0: =?utf-8?B?cytmM1NXb25xTzNwRWN6MHVEbVFqRXhzbFY4Y21RUzQzVGFudUtCTFBUZG9H?= =?utf-8?B?MFQ0Q25KOE83RUtkNlRPWGJ4RUplYXBudnkyZjlDdkQrZGVQbmZFd2Voc1VF?= =?utf-8?B?VnBCTWZIM0t1cG9iUzF1RjhsZXlwWS9EVkt6Ym9pYytzRkJxbXREc2VOVzlP?= =?utf-8?B?d2gvRGJhSUEydlZYbzBQK0l5M2JSeGE3TXFkQzZySjd0QWFXa3RJQlR5Vnp2?= =?utf-8?B?ayt2NHR2TVRFRXVjV3p6Uk04OFphSXU5U1o4R3FnT1V4VzhOQ29rZVNBQ2FG?= =?utf-8?B?NllrRVlXZ2luZmIvRUtrVDArU1ltYjl5THpmV3RZVWhDeUZnQUsrdWlPTEpT?= =?utf-8?B?RHZQWkRTY1dGS3RqNlJMZjBsY0lVY0FkdkY0R0dmOTR2WEVkNGUwVFhZOWM2?= =?utf-8?B?WlZsL2lGWDFQWTd0WWx1enN2YkF6Tk5Zckd5TnFvUlJyeWs5Sk1acnQzbmVt?= =?utf-8?B?UnpDakRhc0VRL0FWaE1vdlRJRGcvY2xkbE5pbWE5YkxWaWQzWWMzRndja1Qv?= =?utf-8?B?SVIvcnJIQ0xuMUpjTzBsaFRwRHZER2ZrTDJQSk95QTJmdmdXQ2hrSURzS1Zo?= =?utf-8?B?V3h3QmluK2dOZDdzZHlKNmhIVkxmL3RHNjVtQjhydmJrL1lEQ3ZQZ3ZoRGhT?= =?utf-8?B?RTJpN0pFc1JVNWhEbmp1dWFYajB1WXJwM3k2cWJVcWJkY0k2dUQ3bG9IVEgz?= =?utf-8?B?bnJuSlhLWGxxSi9mdzdrMzNnRFkxWnl0bk5tQXVVUnlGVk9aczVtcmhOTzVq?= =?utf-8?B?Zm1VRmpiOEE0TjdEWE5SOGVKMC9oU3NqTWMyVlpWTG5rMmRnOUxXWTBoMC9q?= =?utf-8?B?RFovNGxQYkNpaVl3YlVFMllmcnFxc2FTVENUTmFzTTNjWlRiU0g4M1pEWnZa?= =?utf-8?B?ejNIaEFlUkdFa0c1eXhKMENPdnhTMFU5aDEvaDZCSm0rZHl5YUFsNUwzeWdR?= =?utf-8?B?OXZjSkMyNFN6WXZMTHRGQmFySnJ5clFhdlJzbDUxeDZDcHlwdVlLUEliWmQy?= =?utf-8?B?aDdnT1hKdUN5SmFLQkg4SlFVakZTSnBCUVlyNkg4bVZSTjZpR0pobENPVHhT?= =?utf-8?B?ZTgwQ3QzN3dQSjZhMUZIekllTGprZGxqNEdhT3g4NDFSRWRQbi9kZ2dIL0VV?= =?utf-8?B?ZUt0Mmh6S2t4ZGVFOG5hVGRPL0dUTWZoS2pKUHM5MVhKVGtlUE1mMERYOSs1?= =?utf-8?B?eno2eVdEaG1BTjh3VEdsTXZsSUVEdXRLaXZjZTB0MWFlbnQyTmdQcVVKWTVw?= =?utf-8?B?dXhvQnVOQWhtYkZDYWlhKzV1SFF5OE83UjdNUVJCaFVsMk85TjA0YXNDVVBB?= =?utf-8?B?ZXVJeEFlT2x3MEtPLzZnaGU0SVBHVEovWU9sdVNZY09HTnBjcXpxQ3lVcEha?= =?utf-8?B?aVBmUkMyZzV0VHhWcFZjQUVPSDNDRkQ3aFhOVXppMWtDQTR1S3ZJakVHOTlr?= =?utf-8?B?d3JZMW5hdnNzdlZRZm5tTEh1SVBRbS9YMHRyVjNwV1lVL0gvdlhtQmVWR21z?= =?utf-8?B?a01zbVJnK0VmYkZUc1hJTGYxWkcyd2I2VGhDOGxXd2JjdHFGQmE5L29BaXpy?= =?utf-8?B?b0JPNE9UTzgxeW5DK1RBQ1FqY2ZaUVpJV3pIZjRBZW9GenUyTWVqdmFja1FM?= =?utf-8?B?aEZodS9GdFR2TGhHWmcrNVIzWUxBNFNsbFBqVHBaKzgrQ1NMNVI1cG5ia1lm?= =?utf-8?B?VVNTNGs0YW5FY2o0WmM0UGZwODQ3YWxFM1dsVXFicU9ZZk5WeHdFME1JbUpv?= =?utf-8?B?TE10TWJNSzRPK00wYjdBMUhXbGFXd2VKYUtKQS8yR0IvQXIwejlRb2t2bzhw?= =?utf-8?B?Ti9BamZlc0svYkJKNjF0c1ptU1Zua2c5UjVnb2RnRUtZSHdxc0gwYUg3TmUx?= =?utf-8?B?bmhjMVhodGdtNDBpS1lBNlk4NXFxT1A2ay92dmpJUElaUURSZTN1U0RZdVZx?= =?utf-8?B?MGN1ZEtyOWNqQlprNTFJczA3Vm1OcjcrT3VQUncrZ1labGFZZlBDTXVjUUl0?= =?utf-8?B?bldjU3ZvVzcwcTlhajFhY0doWlZvOTVSUWRxMVp2Z0FiZFJjVmpNRDIvbHhS?= =?utf-8?B?TUhBTXVIaHp3V1l0V0RqRGNJdmcvTi9lQ3JPNnpMUnJjUXhlS0FPU0dVcThy?= =?utf-8?B?dHFScXgwUEk5V0lKOFFORXBld1gwWEh0am5KZmViNGtHWWFTcS8xRkRxdnVP?= =?utf-8?B?WWIyMFUyVUVkWW1oMFh3Q0NqTGMzUGRrYjhSbHU2MVFVb2ViN2h3RmlCcjhX?= =?utf-8?B?Qkw0bXVubktVNzRFK2dYUHNidXo5VFdzamxyUFY1WFIram43Y0ZEdzRGNDMx?= =?utf-8?B?azdTaExxZ3lmKzduMVMyendEeWVqNWl1czZnV01iZ3N0SjVZMGdMT3BpaTVw?= =?utf-8?Q?VdKjWwMfCS12OF96eryh1dHWC4VS1JM+9+a5b3sn0Qk6E?= X-MS-Exchange-AntiSpam-MessageData-1: mxebSRkx5iVDTA== X-OriginatorOrg: Nvidia.com X-MS-Exchange-CrossTenant-Network-Message-Id: 894cefe9-9677-4d98-2e6e-08dec3c93385 X-MS-Exchange-CrossTenant-AuthSource: CH2PR12MB3990.namprd12.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 06 Jun 2026 12:43:25.7699 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: 43083d15-7273-40c1-b7db-39efd9ccc17a X-MS-Exchange-CrossTenant-MailboxType: HOSTED X-MS-Exchange-CrossTenant-UserPrincipalName: rBPcfGPe0oFsv80j4051BlZEXcCCvwqe7dBXf3vDYGf73MbWtzJ9PjUlkda595Cxc3mpBLs82MFlxZIsBpuPZw== X-MS-Exchange-Transport-CrossTenantHeadersStamped: BL1PR12MB5730 From: Joel Fernandes Add KUnit tests to make sure the macro is working correctly. The unit tests are put behind the new `RUST_BITFIELD_KUNIT_TEST` Kconfig option. Acked-by: Danilo Krummrich Reviewed-by: Eliot Courtney Signed-off-by: Joel Fernandes [acourbot: - Use a consistent test axis where each test focuses on a single thing. - Rename members to generic name including range for readability. - Add test exercising `try_with`. - Add test checking that unallocated bits are left untouched. ] Co-developed-by: Alexandre Courbot Signed-off-by: Alexandre Courbot --- rust/kernel/Kconfig.test | 10 ++ rust/kernel/bitfield.rs | 314 +++++++++++++++++++++++++++++++++++++++++++= ++++ 2 files changed, 324 insertions(+) diff --git a/rust/kernel/Kconfig.test b/rust/kernel/Kconfig.test index fc47614e6ec9..4fc6dc978101 100644 --- a/rust/kernel/Kconfig.test +++ b/rust/kernel/Kconfig.test @@ -73,4 +73,14 @@ config RUST_ATOMICS_KUNIT_TEST =20 If unsure, say N. =20 +config RUST_BITFIELD_KUNIT_TEST + bool "KUnit tests for the Rust `bitfield!` macro" if !KUNIT_ALL_TESTS + default KUNIT_ALL_TESTS + help + This option enables KUnit tests for the Rust `bitfield!` macro. + These are only for development and testing, not for regular + kernel use cases. + + If unsure, say N. + endif diff --git a/rust/kernel/bitfield.rs b/rust/kernel/bitfield.rs index 2498107979dc..0e2f805c19ba 100644 --- a/rust/kernel/bitfield.rs +++ b/rust/kernel/bitfield.rs @@ -546,3 +546,317 @@ fn fmt(&self, f: &mut ::kernel::fmt::Formatter<'_>) -= > ::kernel::fmt::Result { } }; } + +#[cfg(CONFIG_RUST_BITFIELD_KUNIT_TEST)] +#[::kernel::macros::kunit_tests(kernel_bitfield)] +mod tests { + use core::convert::TryFrom; + + use pin_init::Zeroable; + + use kernel::num::Bounded; + + // Enum types for testing =3D> and ?=3D> conversions + + #[derive(Debug, Clone, Copy, PartialEq)] + enum MemoryType { + Unmapped =3D 0, + Normal =3D 1, + Device =3D 2, + Reserved =3D 3, + } + + impl TryFrom> for MemoryType { + type Error =3D u64; + fn try_from(value: Bounded) -> Result { + match value.get() { + 0 =3D> Ok(MemoryType::Unmapped), + 1 =3D> Ok(MemoryType::Normal), + 2 =3D> Ok(MemoryType::Device), + 3 =3D> Ok(MemoryType::Reserved), + _ =3D> Err(value.get()), + } + } + } + + impl From for Bounded { + fn from(mt: MemoryType) -> Bounded { + Bounded::from_expr(mt as u64) + } + } + + #[derive(Debug, Clone, Copy, PartialEq)] + enum Priority { + Low =3D 0, + Medium =3D 1, + High =3D 2, + Critical =3D 3, + } + + impl From> for Priority { + fn from(value: Bounded) -> Self { + match value & 0x3 { + 0 =3D> Priority::Low, + 1 =3D> Priority::Medium, + 2 =3D> Priority::High, + _ =3D> Priority::Critical, + } + } + } + + impl From for Bounded { + fn from(p: Priority) -> Bounded { + Bounded::from_expr(p as u16) + } + } + + bitfield! { + struct TestU64(u64) { + 63:63 field_63; + 61:52 field_61_52; + 51:16 field_51_16; + 15:12 field_15_12 ?=3D> MemoryType; + 11:9 field_11_9; + 1:1 field_1; + 0:0 field_0; + } + } + + bitfield! { + struct TestU16(u16) { + 15:8 field_15_8; + 7:4 field_7_4; // Partial overlap with `field_5_4`. + 5:4 field_5_4 =3D> Priority; + 3:1 field_3_1; + 0:0 field_0; + } + } + + bitfield! { + struct TestU8(u8) { + 7:0 field_7_0; // Full byte overlap. + 7:4 field_7_4; + 3:2 field_3_2; + 1:1 field_1; + 0:0 field_0; + } + } + + // Single and multi-bit fields basic access. + #[test] + fn test_basic_access() { + // TestU64 + let mut val =3D TestU64::zeroed(); + assert_eq!(val.into_raw(), 0x0); + + val =3D val.with_field_0(true); + assert!(val.field_0().into_bool()); + assert_eq!(val.into_raw(), 0x1); + + val =3D val.with_field_1(true); + assert!(val.field_1().into_bool()); + val =3D val.with_field_1(false); + assert!(!val.field_1().into_bool()); + assert_eq!(val.into_raw(), 0x1); + + val =3D val.with_const_field_11_9::<0x5>(); + assert_eq!(val.field_11_9(), 0x5); + assert_eq!(val.into_raw(), 0xA01); + + val =3D val.with_const_field_51_16::<0x123456>(); + assert_eq!(val.field_51_16(), 0x123456); + assert_eq!(val.into_raw(), 0x0012_3456_0A01); + + const MAX_FIELD_51_16: u64 =3D ::kernel::bits::genmask_u64(0..=3D3= 5); + val =3D val.with_const_field_51_16::<{ MAX_FIELD_51_16 }>(); + assert_eq!(val.field_51_16(), MAX_FIELD_51_16); + + val =3D val.with_const_field_61_52::<0x3FF>(); + assert_eq!(val.field_61_52(), 0x3FF); + + val =3D val.with_field_63(true); + assert!(val.field_63().into_bool()); + + // TestU16 + let mut val =3D TestU16::zeroed(); + assert_eq!(val.into_raw(), 0x0); + + val =3D val.with_field_0(true); + assert!(val.field_0().into_bool()); + assert_eq!(val.into_raw(), 0x1); + + val =3D val.with_const_field_3_1::<0x5>(); + assert_eq!(val.field_3_1(), 0x5); + assert_eq!(val.into_raw(), 0xB); + + val =3D val.with_const_field_7_4::<0xA>(); + assert_eq!(val.field_7_4(), 0xA); + assert_eq!(val.into_raw(), 0xAB); + + val =3D val.with_const_field_15_8::<0x42>(); + assert_eq!(val.field_15_8(), 0x42); + assert_eq!(val.into_raw(), 0x42AB); + + // TestU8 + let mut val =3D TestU8::zeroed(); + assert_eq!(val.into_raw(), 0x0); + + val =3D val.with_field_0(true); + assert!(val.field_0().into_bool()); + assert_eq!(val.into_raw(), 0x1); + + val =3D val.with_field_1(true); + assert!(val.field_1().into_bool()); + assert_eq!(val.into_raw(), 0x3); + + val =3D val.with_const_field_3_2::<0x3>(); + assert_eq!(val.field_3_2(), 0x3); + assert_eq!(val.into_raw(), 0xF); + + val =3D val.with_const_field_7_4::<0xA>(); + assert_eq!(val.field_7_4(), 0xA); + assert_eq!(val.into_raw(), 0xAF); + } + + // =3D> infallible conversion. + #[test] + fn test_infallible_conversion() { + let mut val =3D TestU16::zeroed(); + + val =3D val.with_field_5_4(Priority::Low); + assert_eq!(val.field_5_4(), Priority::Low); + assert_eq!(val.into_raw() & 0x30, 0x00); + + val =3D val.with_field_5_4(Priority::Medium); + assert_eq!(val.field_5_4(), Priority::Medium); + assert_eq!(val.into_raw() & 0x30, 0x10); + + val =3D val.with_field_5_4(Priority::High); + assert_eq!(val.field_5_4(), Priority::High); + assert_eq!(val.into_raw() & 0x30, 0x20); + + val =3D val.with_field_5_4(Priority::Critical); + assert_eq!(val.field_5_4(), Priority::Critical); + assert_eq!(val.into_raw() & 0x30, 0x30); + } + + // ?=3D> fallible conversion. + #[test] + fn test_fallible_conversion() { + let mut val =3D TestU64::zeroed(); + + val =3D val.with_field_15_12(MemoryType::Unmapped); + assert_eq!(val.field_15_12(), Ok(MemoryType::Unmapped)); + val =3D val.with_field_15_12(MemoryType::Normal); + assert_eq!(val.field_15_12(), Ok(MemoryType::Normal)); + val =3D val.with_field_15_12(MemoryType::Device); + assert_eq!(val.field_15_12(), Ok(MemoryType::Device)); + val =3D val.with_field_15_12(MemoryType::Reserved); + assert_eq!(val.field_15_12(), Ok(MemoryType::Reserved)); + + // `field_15_12` is 4 bits wide (0-15); `MemoryType` only covers 0= -3, so 4-15 return Err. + let raw =3D (val.into_raw() & !::kernel::bits::genmask_u64(12..=3D= 15)) | (0x7 << 12); + assert_eq!(TestU64::from_raw(raw).field_15_12(), Err(0x7)); + } + + // Test that setting an overlapping field affects the overlapped one a= s expected. + #[test] + fn test_overlapping_fields() { + let mut val =3D TestU16::zeroed(); + + val =3D val.with_field_5_4(Priority::High); // High =3D=3D 2 =3D= =3D 0b10. + assert_eq!(val.field_5_4(), Priority::High); + assert_eq!(val.field_7_4(), 0x2); // bits 7:6 =3D=3D 0, bits 5:4 = =3D=3D 0b10 + + val =3D val.with_const_field_7_4::<0xF>(); + assert_eq!(val.field_7_4(), 0xF); + assert_eq!(val.field_5_4(), Priority::Critical); // bits 5:4 =3D= =3D 0b11 + + // `field_7_0` should encompass all other fields. + let mut val =3D TestU8::zeroed() + .with_field_0(true) + .with_field_1(true) + .with_const_field_3_2::<0x3>() + .with_const_field_7_4::<0xA>(); + assert_eq!(val.into_raw(), 0xAF); + + val =3D val.with_field_7_0(0x55); + assert_eq!(val.field_7_0(), 0x55); + assert!(val.field_0().into_bool()); + assert!(!val.field_1().into_bool()); + assert_eq!(val.field_3_2(), 0x1); + assert_eq!(val.field_7_4(), 0x5); + } + + // Checks that bits not mapped to any field are left untouched. + #[test] + fn test_unallocated_bits() { + let gap_bits =3D (1u64 << 62) | 0x1FC; + + let set_all_fields =3D |val: TestU64| { + val.with_field_63(true) + .with_const_field_61_52::<0x155>() + .with_const_field_51_16::<0x123456>() + .with_field_15_12(MemoryType::Device) + .with_const_field_11_9::<0x5>() + .with_field_1(true) + .with_field_0(true) + }; + + // Gap bits to 0. + let val =3D set_all_fields(TestU64::from_raw(0)); + assert_eq!(val.into_raw() & gap_bits, 0); + + // Gap bits to 1. + let val =3D set_all_fields(TestU64::from_raw(gap_bits)); + assert_eq!(val.into_raw() & gap_bits, gap_bits); + } + + #[test] + fn test_try_with() { + let val =3D TestU64::zeroed().try_with_field_51_16(0x123456).unwra= p(); + assert_eq!(val.field_51_16(), 0x123456); + + let err =3D TestU64::zeroed().try_with_field_51_16(u64::MAX); + assert_eq!(err, Err(::kernel::error::code::EOVERFLOW)); + + let val =3D TestU64::zeroed() + .try_with_field_51_16(0xABCDEF) + .and_then(|p| p.try_with_field_0(1)) + .unwrap(); + assert_eq!(val.field_51_16(), 0xABCDEF); + assert!(val.field_0().into_bool()); + } + + // `from_raw`/`into_raw` and `From`/`Into` round-trips. + #[test] + fn test_raw() { + let raw: u64 =3D 0xBFF0_0000_3123_3E03; + let val =3D TestU64::from_raw(raw); + assert_eq!(u64::from(val), raw); + assert!(val.field_0().into_bool()); + assert!(val.field_1().into_bool()); + assert_eq!(val.field_11_9(), 0x7); + assert_eq!(val.field_51_16(), 0x3123); + assert_eq!(val.field_15_12(), Ok(MemoryType::Reserved)); + assert_eq!(val.field_61_52(), 0x3FF); + assert!(val.field_63().into_bool()); + + let raw: u16 =3D 0x42AB; + let val =3D TestU16::from_raw(raw); + assert_eq!(u16::from(val), raw); + assert!(val.field_0().into_bool()); + assert_eq!(val.field_3_1(), 0x5); + assert_eq!(val.field_7_4(), 0xA); + assert_eq!(val.field_15_8(), 0x42); + + let raw: u8 =3D 0xAF; + let val =3D TestU8::from_raw(raw); + assert_eq!(u8::from(val), raw); + assert!(val.field_0().into_bool()); + assert!(val.field_1().into_bool()); + assert_eq!(val.field_3_2(), 0x3); + assert_eq!(val.field_7_4(), 0xA); + assert_eq!(val.field_7_0(), 0xAF); + } +} --=20 2.54.0 From nobody Mon Jun 8 06:36:40 2026 Received: from DM5PR21CU001.outbound.protection.outlook.com (mail-centralusazon11011055.outbound.protection.outlook.com [52.101.62.55]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id CF08F3AE1BC; Sat, 6 Jun 2026 12:43:34 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=52.101.62.55 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780749817; cv=fail; b=U3Ej4AKHHMwJ5LsvQI5nW1oTF8zDNVKviVmn1vRxoyMhSUJXs5B1TW0SiRb0ySlkQy+C2cVcHTitT05T0kzK6MY4iGaKub0av2j7RiJRJ0SbnqLuY23+tiFuJe8/iVkIAIqAm48kFvYaDAfHH2FIwrV8nhFqxigFFswGn4qDL5M= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780749817; c=relaxed/simple; bh=+N7MwY8L8OeAcDzWRXVEtu4vzkFzWQhVfBq67eJfWC4=; h=From:Date:Subject:Content-Type:Message-Id:References:In-Reply-To: To:Cc:MIME-Version; b=Q+RJZrzrhVdqlZJENayECv4zaGHFWqi4VTnwMvXCYZVTAj+4+uW3NUr/aotgDX75EskgBlRfrK1/Z9k8f2qS2YEPkiyu4z6K5zemTBla+M8tyooHbOgePAmysghCko+YVsxi0u3zfm5wqy6T66BGlNQ9QL++Zb+EOIfhrXceIsU= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=nvidia.com; spf=fail smtp.mailfrom=nvidia.com; dkim=pass (2048-bit key) header.d=Nvidia.com header.i=@Nvidia.com header.b=UYy86QQf; arc=fail smtp.client-ip=52.101.62.55 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=nvidia.com Authentication-Results: smtp.subspace.kernel.org; spf=fail smtp.mailfrom=nvidia.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=Nvidia.com header.i=@Nvidia.com header.b="UYy86QQf" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=uavby9VccOLhv4M2AN/M0v8iozm6YLQiuN9rPNznO866rdxyhoWCtiIAqOi0N2cvAeX3jt0ug3xzjeu1YoJiEK8ABldk4Hi+7ORa3DDD5h1l57mXTLKPwoxOZqQ0MJ28xlDka89ChG2UJd7Ejf4ImetDiOUv0jZrHq6Yzx0e2g67j8gXwLWnLX5r2d6BTPRLSBqAV/luaH+MzU4BMla37YtSK7naDJbG5j+xYtBKb6/YpWUouO6mx6NC8uHhuMpvWRgN4Q0IzpGbWHtmSNjLkjMzmm8JQn9OkNzq12Je0npo+HmlFbAChq9lJgYVT6dEF0bpLZCgmy483X7HD00k9Q== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector10001; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=a3MZzwtoGJMQd0XhMtqUl4I/37/qDHLRJC6TFKgxmr4=; b=um4QPujw9Nd4roEJ9zPYB7RI/IXvxaY0DI1n/RH5LW4Z58HLzKpNKgUVqEHEnACH3JEt/dtLsbqgiypN30hVDT5LfzlGzo1tNyTvRMdRcgSBZKEubYaQfJJWuA32aDQQfpN+tq2NBZukXwvqXUltz6iGMIDwGM2T5VaSoo60bWUhtD6npr+1Jm8wo2f1YCJ4Tp/sfvWf2axBYLMbu5eiPkKWUIyOCuT8fk56hPZlyJZdruXvXDpjNEkfp6mehecEiHPG0yARTCOaysBZmb717FwJNf2qiwstvXo7Q8uXEEnb5LlP53hzOKAvFsFrp8uwChyyBViSP0JosZXm6L4kcQ== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=nvidia.com; dmarc=pass action=none header.from=nvidia.com; dkim=pass header.d=nvidia.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=Nvidia.com; s=selector2; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=a3MZzwtoGJMQd0XhMtqUl4I/37/qDHLRJC6TFKgxmr4=; b=UYy86QQfxxvlK6FXipHpUK66CHndzk8Z/OTCEUPyjSxHM8A2R53czCQX/DDzGCHLYneR8OKATasFHchxxibKuu6eRLmZ9bnU08if68MWbWzpIF/umBsZ+AEAC9XZHgrWT23Q0qXrjg/tA9VIkqI5xpVeCtSrCuf4rOHHnJf4ERv4UQGFMQm616savVH4+JVvbAiYhrajyHqccX4NR3n9KlinyG2KwIBt97cUk3n2LOexWd9KpY5dqCFARdL9IKOTjB5ovxkGYwO3ZEp2+GPIoAQi1Yx2ii/PqKX/hm3km+1AQdqRG3NWqwVVBrGvf73TH7olwsQ8JVM+k95Vt3skkg== Authentication-Results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=nvidia.com; Received: from CH2PR12MB3990.namprd12.prod.outlook.com (2603:10b6:610:28::18) by BL1PR12MB5730.namprd12.prod.outlook.com (2603:10b6:208:385::9) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.21.92.11; Sat, 6 Jun 2026 12:43:31 +0000 Received: from CH2PR12MB3990.namprd12.prod.outlook.com ([fe80::7de1:4fe5:8ead:5989]) by CH2PR12MB3990.namprd12.prod.outlook.com ([fe80::7de1:4fe5:8ead:5989%4]) with mapi id 15.21.0092.007; Sat, 6 Jun 2026 12:43:31 +0000 From: Alexandre Courbot Date: Sat, 06 Jun 2026 21:43:06 +0900 Subject: [PATCH v5 3/3] rust: io: use the `bitfield!` macro in `register!` Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260606-bitfield-v5-3-b92188820914@nvidia.com> References: <20260606-bitfield-v5-0-b92188820914@nvidia.com> In-Reply-To: <20260606-bitfield-v5-0-b92188820914@nvidia.com> To: Yury Norov , Miguel Ojeda , Boqun Feng , Gary Guo , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Andreas Hindborg , Alice Ryhl , Trevor Gross , Danilo Krummrich , Daniel Almeida , David Airlie , Simona Vetter Cc: John Hubbard , Alistair Popple , Timur Tabi , Zhi Wang , Eliot Courtney , linux-kernel@vger.kernel.org, rust-for-linux@vger.kernel.org, nova-gpu@lists.linux.dev, driver-core@lists.linux.dev, Alexandre Courbot X-Mailer: b4 0.15.2 X-ClientProxiedBy: TY4PR01CA0018.jpnprd01.prod.outlook.com (2603:1096:405:2bf::7) To CH2PR12MB3990.namprd12.prod.outlook.com (2603:10b6:610:28::18) Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: CH2PR12MB3990:EE_|BL1PR12MB5730:EE_ X-MS-Office365-Filtering-Correlation-Id: 41c61df8-4a84-4a1f-4c36-08dec3c9365a X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|1800799024|10070799003|366016|7416014|376014|22082099003|18002099003|6133799003|921020|5023799004|11063799006|56012099006|3023799007; X-Microsoft-Antispam-Message-Info: WIubFTEq1c/HyzCnruFr7aMnogE0m+JHPP/0Q2jt+a20pU5xvy1UUICkvpyPnvMUZDN3NdMSWynXN71rLlCMWvgI/8Ld+9Nc17w4pDZIVqMOsNq1Yf8NEbEBI7Gtr57pVm1/oVmrSyQDIJIiVvKnzAyUxPCz8UT25Xs38sLcZ9yg7j7fTKMwTly7NBl44rA00vtjWZLfzcUlbC3NdW2g6SDSu0pXntPbQXDeGIhgGqShNoxr6vzR5k6Xkz9NysCLgZC45PvE2RhWIJ8D0n+spWNNNvb7v8gTc3rJ/v1VOZPGsoVYPc5WGHldRpXZVaFyIanOt3YaLSQmzK7wBYOhPzlvV5PHSuzheGfvFlVafLwijEGqiF/VMVdoeJCoKGpFAwS6gJQ0YIrMwcN5gzNnwBoQRgyI8WkLgBTXxqTPX2y0SpZaOSdnEUT1fNwmtUcEtrqZ9AnJVtVN00/lIZOsH0FyTsndLT0yoClRKOSKhvzf+vycOIBzlVSuul+OhCRi7c1vqa2Si8VzlQhBNY+6Lzxg1EA3MtqpGAjjNMEqHngLfY3WgotTMlcE6qbZPs9zrpV5Q7mKgH6ytjcMNrq4Kr63tjxYLkUFMAxH0fS/8ZsheFQ+o91W9duqACn1OMOdBZUP3Vp/tlBrmR1HG4ksd5t/V7nKIL7i1kysoOJvylb2d47lLU9h5qVaPFzjpXN+Jm/S8aEcrlVFpMZVlKNMGsHH2236MpBPoOXqCaK+I98= X-Forefront-Antispam-Report: CIP:255.255.255.255;CTRY:;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:CH2PR12MB3990.namprd12.prod.outlook.com;PTR:;CAT:NONE;SFS:(13230040)(1800799024)(10070799003)(366016)(7416014)(376014)(22082099003)(18002099003)(6133799003)(921020)(5023799004)(11063799006)(56012099006)(3023799007);DIR:OUT;SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 2 X-MS-Exchange-AntiSpam-MessageData-0: =?utf-8?B?VVZjaHdUbDV1VnI4QkVOTERsakRlVlRPZy9JSHcyNkJIM1EvNXg4MU9KVGJD?= =?utf-8?B?dXZWdjNFU0N0a1lEbHhRT0hyMG5NeTFreEZHQ1pZTFptVFhVNG9JYVBkUStR?= =?utf-8?B?NzRKbDZuMGd6cTljRlAzSzhBT3ZnaGRGTjUxcHl4dThtRFNiRmd0eG1qd3lD?= =?utf-8?B?eEw3WElqV0hnTnhiK0xVNUR2UWpLci9qS29YTEJHekRoK2c3RThsSkJpRjBn?= =?utf-8?B?T01oSjlCYUd6VTFBZTJEeGRYNkFPOTFNUGZkOFJLeldUaFN3UlBWZ2lXTkZ2?= =?utf-8?B?SDVDSVdicU0vcEo1NnQ0MWhMR3k4c3FMbmVTR25XVG8wSXh6UXZLV0hhYm1m?= =?utf-8?B?bEFpdXE0SGl5eTIxVFh3RHNUN2RJbzE1Wm1WL2xLVlo3S1VET3hFcFFxZTdX?= =?utf-8?B?RXpQSXlwTjdEZ3JwNTB4dUFjdUdmWStzY2w5Q21kTWNPL0F4OFdKYU1Gd2wy?= =?utf-8?B?eTJCMGZTc0VvWkZnMUJFek5zOUsxSmVkTGx3NUFVMUc3VFVsR0piT3E0RDJI?= =?utf-8?B?ZzFtSDh4U1EwREowMis2TmY1WHpXVUg4OTBpeDN6cDVHdkxpMFcrRUdjWG1r?= =?utf-8?B?KzIwL1kzT1orUG4wYkxRajhKRmtBMmh2eEVaMDlJZFV5eFBCekRXSDc5RlIy?= =?utf-8?B?UVhqakRZeUxCZ1ZnZ0ZsQlJBcGJ6dmJxWFpUUEdIdmFHTkdLQjBkS09EeURn?= =?utf-8?B?d1cwNnE2bGIrQ2hqSUNRMHpiM1NTKzI5eWZweGFJU2RlYUlaYm42SjArNkRL?= =?utf-8?B?NWxZNC9aK21PSE1iL2M2cEdQUWlTd09GM3hWU2ttbXFwU3Via0oxQjJ5WGVU?= =?utf-8?B?NThEMzJoVnNwWk82MVFZZ1BYbXVGZkpxelNhREowR1pEOGc5d3NWaVptVlJW?= =?utf-8?B?SUNtN2tyWFlWUG9JNlJqa0NiR01jRFVVTXNoWk12VStEREJKZ3JMcEF2TTRF?= =?utf-8?B?Y2VyWjBBU3p6bkVjOUlOVEJqZkgvRlFxb28zTGtMQVZ1N25wOUlzOEZrZnpM?= =?utf-8?B?NEwwTmp1RGlVcGZGOEFVa2NEUmhyd1V2bkZFcEJ0YzduNDhXekZONTFTYWl4?= =?utf-8?B?T0JxZ2czbnlCTWxmTFNwUDVsU012OUlEeHdlcVNLR2MvTWJNU0ZwTWptYTQw?= =?utf-8?B?QkMvbEl4TjVaZFdXVmFiRk9DbzFRMEQ2VUFhU2lsRUJuY0M2Q1JnTGNGcjda?= =?utf-8?B?bktuaFArZGlQRWMrbXNSR3dneGFFTU5oc0NTd2tUSVN4bFFaeW5RWjVmZXJL?= =?utf-8?B?NEdrck9MbmJMclJFMmNOZzdvWGRLNUxZWTdqbWwxMGlQbVE3UWd4M0ZEKzFu?= =?utf-8?B?VFhXVTVEWTZXOVpKcDNyTzdER092VXV3bis1bjFRcXhrV1FRTXptVUZZaG5z?= =?utf-8?B?N0x6VzlELzZ3VEowWEpzUE5ObmdoWEQxZUxIclpSelZ6Q0lZVFBQYUxSOFlp?= =?utf-8?B?WDZWeTFLcVplMU9paTFjQ1dpZG9RcmtGNjVyNVhsNmd2anFDcCt5THpZc25H?= =?utf-8?B?S1RtRHlPL1kwSW4zclk3UUpVdDlSd0xYcEZYTGVmSXc4K3ViUi91OWNEU0xT?= =?utf-8?B?eCt2bHlGOUZwcm1lVzkxYlBPdEhYY2dhS2d1SUxxWTJvNGd1bHJpZm5lemZ1?= =?utf-8?B?MkJBN0VhOVlDY0lkQUY5WURwTG1zbkNySFI2RFlENWFSYk1ybEozQWpRT1VG?= =?utf-8?B?ekg4a1U5L3A4dUtWdWdhU2VnQ21RZktxb1NweW04NWxzRlhROC9iTFRTY2hB?= =?utf-8?B?VkVReWZkbVdXbFhEWkx1K3dpc2dXaHlBWEowZndPNGVPL09hWUU5bmQ3OGha?= =?utf-8?B?V0xrd0FOaU4wSFR3MWpUSUJ6azl5QkNpMHozYjhkVHIrYXZwcXBuanh6dWNz?= =?utf-8?B?K2p6a1BhdWEzR2FpanYwZ25lcFgra3NwYlgxRmRPdTh1MlRUY21zdFlqWmVS?= =?utf-8?B?a3RLbmVENlNYcFVmYmx0c3k2OE1Ec09vczU0QVJHT1VNUS80TU92aGlzWGhx?= =?utf-8?B?RjlBWjUvakV0NjJGT04yVFhYSWZrUVJ6OGR1V1ZzZm1iL1FkRUt1TlRHRzBu?= =?utf-8?B?UmcvTDRwVnczVW1vSmcyUVg5YnlhZm5oT1dyd2RVWk1pUGwxVXUxbHdvNjNZ?= =?utf-8?B?MlU2NXVHN1RJQ25sd1ZTNWlhSE1aUFJaU1dCb09VTE1NK1pWYXVkQm1vdWF4?= =?utf-8?B?K0dnNGlLbWlFNUoybzNaUWNsSXRQT2YxMVJIZVNKeGpWcUdIVnhCajg5Vkk5?= =?utf-8?B?WXc0cXIxMW9nNm5BcmtpUVNxY1BCOGtJWFRZWndnbjJEallENWFHVHVXTXE5?= =?utf-8?B?ZkJIdTQ4STc1RWZiR1dRTkxBSytqUVRFeE5YdnNSczhBKzVBcUJreGkrU2k3?= =?utf-8?Q?OljuJ4E06bQo2oR5Xz8UzqlfBEkNaQ9JujZIplbP3SaLq?= X-MS-Exchange-AntiSpam-MessageData-1: MvWLOBOFhYeHAw== X-OriginatorOrg: Nvidia.com X-MS-Exchange-CrossTenant-Network-Message-Id: 41c61df8-4a84-4a1f-4c36-08dec3c9365a X-MS-Exchange-CrossTenant-AuthSource: CH2PR12MB3990.namprd12.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 06 Jun 2026 12:43:30.8961 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: 43083d15-7273-40c1-b7db-39efd9ccc17a X-MS-Exchange-CrossTenant-MailboxType: HOSTED X-MS-Exchange-CrossTenant-UserPrincipalName: 15XiS2yzmXL4ay82c2WdQhlTliTtEvjMpKbTKqNXDDJTa8SwTmqewSvAurZ3FepdbZ2Cwt6kXja0F0a9CiljOA== X-MS-Exchange-Transport-CrossTenantHeadersStamped: BL1PR12MB5730 Replace the local bitfield rules by the equivalent invocation of the `bitfield!` macro. No functional change should be introduced as the `bitfield!` macro has been extracted from the rules of `register!`. Acked-by: Yury Norov Acked-by: Danilo Krummrich Signed-off-by: Alexandre Courbot --- rust/kernel/io/register.rs | 246 +----------------------------------------= ---- 1 file changed, 2 insertions(+), 244 deletions(-) diff --git a/rust/kernel/io/register.rs b/rust/kernel/io/register.rs index abc49926abfe..388647f28292 100644 --- a/rust/kernel/io/register.rs +++ b/rust/kernel/io/register.rs @@ -956,11 +956,10 @@ macro_rules! register { ( @bitfield $(#[$attr:meta])* $vis:vis struct $name:ident($storage:t= y) { $($fields:tt)* } ) =3D> { - $crate::register!(@bitfield_core + $crate::bitfield!( #[allow(non_camel_case_types)] - $(#[$attr])* $vis $name $storage + $(#[$attr])* $vis struct $name($storage) { $($fields)* } ); - $crate::register!(@bitfield_fields $vis $name $storage { $($fields= )* }); }; =20 // Implementations shared by all registers types. @@ -1016,245 +1015,4 @@ impl $crate::io::register::RegisterArray for $name { =20 impl $crate::io::register::RelativeRegisterArray for $name {} }; - - // Defines the wrapper `$name` type and its conversions from/to the st= orage type. - (@bitfield_core $(#[$attr:meta])* $vis:vis $name:ident $storage:ty) = =3D> { - $(#[$attr])* - #[repr(transparent)] - #[derive(Clone, Copy, PartialEq, Eq)] - $vis struct $name { - inner: $storage, - } - - #[allow(dead_code)] - impl $name { - /// Creates a bitfield from a raw value. - #[inline(always)] - $vis const fn from_raw(value: $storage) -> Self { - Self{ inner: value } - } - - /// Turns this bitfield into its raw value. - /// - /// This is similar to the [`From`] implementation, but is sho= rter to invoke in - /// most cases. - #[inline(always)] - $vis const fn into_raw(self) -> $storage { - self.inner - } - } - - // SAFETY: `$storage` is `Zeroable` and `$name` is transparent. - unsafe impl ::pin_init::Zeroable for $name {} - - impl ::core::convert::From<$name> for $storage { - #[inline(always)] - fn from(val: $name) -> $storage { - val.into_raw() - } - } - - impl ::core::convert::From<$storage> for $name { - #[inline(always)] - fn from(val: $storage) -> $name { - Self::from_raw(val) - } - } - }; - - // Definitions requiring knowledge of individual fields: private and p= ublic field accessors, - // and `Debug` implementation. - (@bitfield_fields $vis:vis $name:ident $storage:ty { - $($(#[doc =3D $doc:expr])* $hi:literal:$lo:literal $field:ident - $(?=3D> $try_into_type:ty)? - $(=3D> $into_type:ty)? - ; - )* - } - ) =3D> { - #[allow(dead_code)] - impl $name { - $( - $crate::register!(@private_field_accessors $vis $name $storage : $= hi:$lo $field); - $crate::register!( - @public_field_accessors $(#[doc =3D $doc])* $vis $name $storag= e : $hi:$lo $field - $(?=3D> $try_into_type)? - $(=3D> $into_type)? - ); - )* - } - - $crate::register!(@debug $name { $($field;)* }); - }; - - // Private field accessors working with the exact `Bounded` type for t= he field. - ( - @private_field_accessors $vis:vis $name:ident $storage:ty : $hi:tt= :$lo:tt $field:ident - ) =3D> { - ::kernel::macros::paste!( - $vis const [<$field:upper _RANGE>]: ::core::ops::RangeInclusive =3D $lo..=3D$hi; - $vis const [<$field:upper _MASK>]: $storage =3D - ((((1 << $hi) - 1) << 1) + 1) - ((1 << $lo) - 1); - $vis const [<$field:upper _SHIFT>]: u32 =3D $lo; - ); - - ::kernel::macros::paste!( - fn [<__ $field>](self) -> - ::kernel::num::Bounded<$storage, { $hi + 1 - $lo }> { - // Left shift to align the field's MSB with the storage MSB. - const ALIGN_TOP: u32 =3D $storage::BITS - ($hi + 1); - // Right shift to move the top-aligned field to bit 0 of the s= torage. - const ALIGN_BOTTOM: u32 =3D ALIGN_TOP + $lo; - - // Extract the field using two shifts. `Bounded::shr` produces= the correctly-sized - // output type. - let val =3D ::kernel::num::Bounded::<$storage, { $storage::BIT= S }>::from( - self.inner << ALIGN_TOP - ); - val.shr::() - } - - const fn [<__with_ $field>]( - mut self, - value: ::kernel::num::Bounded<$storage, { $hi + 1 - $lo }>, - ) -> Self - { - const MASK: $storage =3D <$name>::[<$field:upper _MASK>]; - const SHIFT: u32 =3D <$name>::[<$field:upper _SHIFT>]; - - let value =3D value.get() << SHIFT; - self.inner =3D (self.inner & !MASK) | value; - - self - } - ); - }; - - // Public accessors for fields infallibly (`=3D>`) converted to a type. - ( - @public_field_accessors $(#[doc =3D $doc:expr])* $vis:vis $name:id= ent $storage:ty : - $hi:literal:$lo:literal $field:ident =3D> $into_type:ty - ) =3D> { - ::kernel::macros::paste!( - - $(#[doc =3D $doc])* - #[doc =3D "Returns the value of this field."] - #[inline(always)] - $vis fn $field(self) -> $into_type - { - self.[<__ $field>]().into() - } - - $(#[doc =3D $doc])* - #[doc =3D "Sets this field to the given `value`."] - #[inline(always)] - $vis fn [](self, value: $into_type) -> Self - { - self.[<__with_ $field>](value.into()) - } - - ); - }; - - // Public accessors for fields fallibly (`?=3D>`) converted to a type. - ( - @public_field_accessors $(#[doc =3D $doc:expr])* $vis:vis $name:id= ent $storage:ty : - $hi:tt:$lo:tt $field:ident ?=3D> $try_into_type:ty - ) =3D> { - ::kernel::macros::paste!( - - $(#[doc =3D $doc])* - #[doc =3D "Returns the value of this field."] - #[inline(always)] - $vis fn $field(self) -> - Result< - $try_into_type, - <$try_into_type as ::core::convert::TryFrom< - ::kernel::num::Bounded<$storage, { $hi + 1 - $lo }> - >>::Error - > - { - self.[<__ $field>]().try_into() - } - - $(#[doc =3D $doc])* - #[doc =3D "Sets this field to the given `value`."] - #[inline(always)] - $vis fn [](self, value: $try_into_type) -> Self - { - self.[<__with_ $field>](value.into()) - } - - ); - }; - - // Public accessors for fields not converted to a type. - ( - @public_field_accessors $(#[doc =3D $doc:expr])* $vis:vis $name:id= ent $storage:ty : - $hi:tt:$lo:tt $field:ident - ) =3D> { - ::kernel::macros::paste!( - - $(#[doc =3D $doc])* - #[doc =3D "Returns the value of this field."] - #[inline(always)] - $vis fn $field(self) -> - ::kernel::num::Bounded<$storage, { $hi + 1 - $lo }> - { - self.[<__ $field>]() - } - - $(#[doc =3D $doc])* - #[doc =3D "Sets this field to the compile-time constant `VALUE`."] - #[inline(always)] - $vis const fn [](self) = -> Self { - self.[<__with_ $field>]( - ::kernel::num::Bounded::<$storage, { $hi + 1 - $lo }>::new= ::() - ) - } - - $(#[doc =3D $doc])* - #[doc =3D "Sets this field to the given `value`."] - #[inline(always)] - $vis fn []( - self, - value: T, - ) -> Self - where T: Into<::kernel::num::Bounded<$storage, { $hi + 1 - $lo= }>>, - { - self.[<__with_ $field>](value.into()) - } - - $(#[doc =3D $doc])* - #[doc =3D "Tries to set this field to `value`, returning an error = if it is out of range."] - #[inline(always)] - $vis fn []( - self, - value: T, - ) -> ::kernel::error::Result - where T: ::kernel::num::TryIntoBounded<$storage, { $hi + 1 - $= lo }>, - { - Ok( - self.[<__with_ $field>]( - value.try_into_bounded().ok_or(::kernel::error::code::= EOVERFLOW)? - ) - ) - } - - ); - }; - - // `Debug` implementation. - (@debug $name:ident { $($field:ident;)* }) =3D> { - impl ::kernel::fmt::Debug for $name { - fn fmt(&self, f: &mut ::kernel::fmt::Formatter<'_>) -> ::kerne= l::fmt::Result { - f.debug_struct(stringify!($name)) - .field("", &::kernel::prelude::fmt!("{:#x}", self= .inner)) - $( - .field(stringify!($field), &self.$field()) - )* - .finish() - } - } - }; } --=20 2.54.0