From nobody Thu Apr 9 10:29:43 2026 Received: from BL2PR02CU003.outbound.protection.outlook.com (mail-eastusazon11011064.outbound.protection.outlook.com [52.101.52.64]) (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 F29B83D4100; Mon, 9 Mar 2026 15:14:26 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=52.101.52.64 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773069268; cv=fail; b=SFWIcmmYd3R791ro8zfyHVahPqjCHsEbWMPRRcPA8s/j547sQa9nJxNvQ0VXWOU1EGLI1RBWiaTHWJKyxwn7feE6VU6WzJn2htTq4vI5Y0b/yYckHv/klOw0DW2JcjdbIQW8uLooIXhJLKFzynCF8A2b5UQ57Pqy/ZIad2akbWw= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773069268; c=relaxed/simple; bh=0FP89CQyif/oPbzDEF0KNnDxci3xeSqE0b59wHIER0w=; h=From:Date:Subject:Content-Type:Message-Id:References:In-Reply-To: To:Cc:MIME-Version; b=U01ta5sMIIc5TYYVi4YQ7q3OTd8T9YsdcJDIMtgmYqmmxUoLyiq7iao+Ecwy/WM8Y0TEbDT082yNta+6cq/y6NT9zKSUcHjhdrQ7JeNvnzCxA2MDnL13Xk7kRzWr+Nx6Xl6UbLIrrPKGGKRoRSgiPy0w7LDElkTlo46r+kBLkzk= 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=cyO1fPVa; arc=fail smtp.client-ip=52.101.52.64 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="cyO1fPVa" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=n2biOCraBkyLffZUj+1BUGKtzQ8xRcl6jaoz+es0xDU/pvakbMNfclTs2zGgAIK52iJks9EDtn2ed4FUxmppPY85+7Bt2x79lC+6isi09yW1014C+o5JzPdXojMQO5YjJ/NsHu9A5LPV3P73RZyEeD1EKnMP09h2KADS6b9Fgjj0bZppgrxdTq0gl8ARDgYGbn4LoNbBjE3Bvg/udJvcCtwOpnPXbStgoyc2Ccs1qjwqPBvtVRkHazkMGvLbxxwKKv62JBCccR6lvJqA+YzEDlm99+1m6CegyY82f8jQP1iZ9CjGqFnzXEqx2L9GpoxfHKJbI/fcqaLkhAWpq8U/4A== 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=ae4UeDgfUfzoEEPMB/DfNXHA5UjZCs21uT8+xeI1MT8=; b=nLwoN9rtb0LLA9taC+SvVFjcVt3CvRBKERJgWnlaZpF0YGR1YKtSYq8ztJEHty82qn1UHOfFye9j84o2bWOSMQt34Tur6ElZ82SpHde+pPxc+CScbg6ynZDMfxugYfAY2SEYDqHnuiMU//xXZm2MjHgmxu1Vpwwn2AGij3Q9Cha+iNxVVqFs9vCbN8CRrFMKpRAVY5lcndIZVU91xFleYNCQDjCF/tVcEw0E0z3yWqR12wO8jxXRp64JbfR2MYNa7ERuzQxIV7zBB3/UtLP/UQuAXYQIRKG3gSRtdsJ93ZVgNG8YyI6aS7ZAvjebTFAUZ8TDsle4hH4HFQ8/dYk6PQ== 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=ae4UeDgfUfzoEEPMB/DfNXHA5UjZCs21uT8+xeI1MT8=; b=cyO1fPVacs9xDyy4bdsb9MCLn8UbX5qb7L2TCuYrsrtLmba5/w68HfVWYXyH6RLRB7eC4HC8TMGL12O9zkImkA0+EDW1wb1B2BWq95ONR28cA9/35k1etE8WGIWZMbyjqavhN6YFq8tuxKUF2K5Cp4RAc3g8IGxCBIMtWy9L1C0d9mVNUIlO6muwyuYSIqevYY7R2SypiDTEFtdzpG74PCVDYHyGEY661TBoKJcGgFHqXTESLvrQRk8mckidwK4gQQifjMG/r8XADK8Q9smqWjDCdXlydaxGY2VmWVHUwhYMYns9wye3txra327x6UdaXv8Y4tkApxamiQIuHwFiPg== 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 CY5PR12MB6131.namprd12.prod.outlook.com (2603:10b6:930:25::10) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.9700.11; Mon, 9 Mar 2026 15:14: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%6]) with mapi id 15.20.9700.009; Mon, 9 Mar 2026 15:14:18 +0000 From: Alexandre Courbot Date: Tue, 10 Mar 2026 00:13:58 +0900 Subject: [PATCH v8 01/10] rust: enable the `generic_arg_infer` feature Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260310-register-v8-1-424f80dd43bc@nvidia.com> References: <20260310-register-v8-0-424f80dd43bc@nvidia.com> In-Reply-To: <20260310-register-v8-0-424f80dd43bc@nvidia.com> To: Danilo Krummrich , Alice Ryhl , Daniel Almeida , Miguel Ojeda , Gary Guo , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Andreas Hindborg , Trevor Gross , Boqun Feng Cc: Yury Norov , John Hubbard , Alistair Popple , Joel Fernandes , Timur Tabi , Edwin Peer , Eliot Courtney , Dirk Behme , Steven Price , rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, Alexandre Courbot X-Mailer: b4 0.14.3 X-ClientProxiedBy: TYWP286CA0003.JPNP286.PROD.OUTLOOK.COM (2603:1096:400:178::22) 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_|CY5PR12MB6131:EE_ X-MS-Office365-Filtering-Correlation-Id: fcf54a75-069b-49e5-33ba-08de7dee886d X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|10070799003|376014|7416014|1800799024|366016|921020; X-Microsoft-Antispam-Message-Info: kOLEwebWbh4K1QckuaEjjgLMgthhVC1q4eEpCl1fvNVememHe2qMZ5fWcio4KN7XP1AkPabGbS86oZ8B4vYnPOtW6zJ66jhQzaItclYXtIcJCMRtGoEhz0ghQFExXL7yzl/RtUMjnUjJKlulzKmxfyvH3O1hew5NOAaHbyoRc0TpyMuG/7CVHP24Lc+uOGZ1tlwurcH00LZPAtYsEWU+jhEmlBDTxNisGYt0Hvgabe5NIwgVn9ktNCtMmqbt59CkUUvApc+hhBe8P6vJggYM6vt5pGsbyaiyVh8nhw5PwEs6Ct3bS/LTioVDvQiuITTnoH8w/rixoVZkPgi+3alB/adc1rYXXCKP5vdZl5EDc3GZm4yUbk38qpMpRLfiPhJTtb+oEVpgv4puem+NjoNl1YDq36aTrrMKRt2Hgp+ScyzwI2HlVH++iOOb+mZxIFlFYac0xpGADVZlwJGe2pIVdIndxzPY0N+Ntg+69CoH+lmSB/7INbiu7WZwRIknii0Yj0REsiZPPW+JFW2tQRyVX4oHORfrJTkZsFtSzXpBfqlAaeCbqI0Szb78VirzYVD/vOw+r99Ar2eADvERnrrd3AbL/Z2GLV6bAZ6TjQKVRAxzG+W4AUN8at4BHabMNKc9o10v+SHOyFPlgNfoN3n7vL00aoyaHfzD10whEu4YsczjU5fTG9E1hPcRt6yJV9LhE/lgZ+KdbdjckdEq5cWD2k5dEdrCoFUhF4kiWGhgUshKDA3H66Onvk9g9oDGynQnhDg6Y7ECP9CooJjk6KORog== 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)(10070799003)(376014)(7416014)(1800799024)(366016)(921020);DIR:OUT;SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 2 X-MS-Exchange-AntiSpam-MessageData-0: =?utf-8?B?eFgxdzVoUDZOV0EzSlVpcVNic2dmR3ZRcWZQOEs5WHp3VGJybTMwK01wcXdY?= =?utf-8?B?Ynllb3duQ3VDVEF3Wm42ZDVUbDJGWEhSZXNTZFZndGE4Wi9VT1ptZEtwWXNN?= =?utf-8?B?QklHZTFRSkU5a3R0RFlTMEl1citoK0pIN0phdEpuQlQzd2VJNll6QnJ2VUlD?= =?utf-8?B?SW1nYWd1NXB3TFFSRjA1ZjRPZDZzR3hrd1UrSmxWYTNmWjQwL0pTNjlQNDkz?= =?utf-8?B?b1lDWGc0bE5YUHlVVFNPam1xc0VSNlBmTWczK3lZRmVGbU5lQkk0L0Jmd050?= =?utf-8?B?WXN3bFpSVy8zd3Q0eXVQTXk0djN5Z0NWa1FGYnRINWtYZ01RRVFMU3VHM0h4?= =?utf-8?B?NlgvN29oMVZRVXRTVGc4cm5MTFJ6a3k2Tm5LcmFpajlsVFJwYks1Qk9hL3JP?= =?utf-8?B?YUNSOE5OZFdDZkJ2QTVLVnFZL3I2Y1c5OVVaQ1dKQmk4ZmpvSzhtTDRaOU9v?= =?utf-8?B?Z1EvUmpHK1JwbWFGSE1WQ2hLTndDQTJDMHF6b292RTBWZHdEOEk3c3hBUEtj?= =?utf-8?B?Z0ErclQrV2VhUGxPUnp0TTFTZzM2ZzArUy9GckhJWmg1MTVpRjVQQ05xbzA3?= =?utf-8?B?WXplT1F2UVVrWkYvRHBjSk02TW1Xai9pbGZYejZ0R0VTU1plNjVjMWZYUnVy?= =?utf-8?B?QWVzSk9LQVBENUFRMy9icmxOZWhsZ3dZdE9CZ3FCMlZBZU1wYk41d05mT0dn?= =?utf-8?B?R2FmYWJRUVJsVm00dzlvNTlFT2R0aGNnT2h2S1R3ZFZyZXZ6YTJBM3ZIMWVy?= =?utf-8?B?cllWUFhDOWhaSDhlUUY3UG1IZVFHU3g0MU81SVhSVVBkWWtCQWZGZ015TmxY?= =?utf-8?B?TjNscXZEazN6N0krWTBuV0h1eXowbldwRFl6aFVnQXFTYm1pSHJQbU1ETUJJ?= =?utf-8?B?dExubmsrNHVKaUx3czE2enpraldMNTc3VGVqa29Udk1tNlFYU24vV3R4dXFp?= =?utf-8?B?SDYxSjZuVXg3L1VUc3lwMWRZN3pNKzhkTWxYd1haTHF5dXR2elZ2K0s4T2tD?= =?utf-8?B?RHB0MTZVU2JqTXVFRXhDYlFzNm95YTZTN1orYWZ4azg0TFdIM3N5c3RQV0JG?= =?utf-8?B?K1FFTTFMc3ZMYWh2M1N4Nm1pZEhTZjRMMjNJSTFGNGRncjA1NTFHWmw1NWN0?= =?utf-8?B?bmNjUXlrUDIxVWM4ZzI5QkRPUnFiUGlBSy9TOTdVYXlFT0pGdG9sMHE0UDUw?= =?utf-8?B?Y1hFeGVEWDB5SG5RdlI4WmprWlM4bTJMY1B1S0Urb3FUZVZSdTFBZ2RRSi9J?= =?utf-8?B?U2FNdXI4V3NIdGlyd1EvdFhzNjliRVpxd0RwN1JQSEUwVm9ybUdVRERpTWxv?= =?utf-8?B?YXR2NGFpTysyUHFZL3pxZGNGM2xNTlNVZGtsamZpSi9oVGFKRUYvQVA5cFZW?= =?utf-8?B?bm82UE1lTXZxN0M4aE52V2tJM25RcHB2VmlUZFhWTW53dlB2QjMyeWxsdmww?= =?utf-8?B?TlBZS0lyRUdSR2FhbzZOWE1LU2hSMUVpUnlkTSsxejRqTmwzNlJOZGRsVUVz?= =?utf-8?B?WWIvNWFtV2hpWjdsWDc3d1k0RUkvZDA0SWVvQU5mcnFjeVBIRkN6N2lvSzBG?= =?utf-8?B?WlJWTGJ1MmFEUHpiam1VdFFGejVQcHNNNHRYM09mcWhDUXljd0tqMjB4bHo1?= =?utf-8?B?VTVJaStqN2hYRXFJdlgxenVhSENWdFNscHMzSkRML2lTb2RtVi9UOG15cnAz?= =?utf-8?B?V3pjbm1FUThIZFBVZjEwTEtaUjNwbzhtWFV6aFhad0R2RzBxM2M4dFk5RHZy?= =?utf-8?B?TWpzOUF2Z2lCZ1BRYWlWczVheGcyZXBmRWVkOFd1aDQvWTM4aVBaNjc1NlFk?= =?utf-8?B?eHlCNUpPK0k0RUowQVJKYXpRMEtqUzd6NDkvd0FEWVhFNi9kclFrZ3VoWlVu?= =?utf-8?B?d2daRHk1Vy93YWVISGMyUklCdHpCSDFsZ3Bic1JiWkpwa2ZOTng0M05sbWJt?= =?utf-8?B?cGgzM1NJMnJBY2JsMkM2K2F4TkJjTlhrOG1xTWhMRUZ5S1E2cEVJK0k0ZWRI?= =?utf-8?B?MmtOb1RvSktqRDVYaEVLNm10UGg5dXNaYjM1cUZxWTRZa0xXQXpPajZadG1B?= =?utf-8?B?NUNKU3h2OEVsWXBockpMbCtQWExRQWZXQjN2SG5MRkY1cStUaVhOekFFY1BT?= =?utf-8?B?RStqK1BXY3kxd0tpSmVNZ0MzU1pqdGlzd0tyK2s2c1FBMUQ3Tm5MR2RQc3hn?= =?utf-8?B?ZDYwUzB3T3ZEU0VtbVNIaHppY3ZoY3ZpUTVjNWxySk9YTUJpTDJ6Mmhkamt2?= =?utf-8?B?K29PbzNTT0hqMGdwdmFPYUJjdndtRkZNMFZiOTBXMy8zNmhpVDJJSEJJRk83?= =?utf-8?B?NVlueFNmbDVDblV1UEpnclVpNlRaa0JvYngxM21mQjRBNkdPZzlCT3B2am1V?= =?utf-8?Q?842z5BiN+76LWpn45gg9d+zJ2mTXxLc4R2YVNLqOkglNo?= X-MS-Exchange-AntiSpam-MessageData-1: 7Eqq81tvwokAUQ== X-OriginatorOrg: Nvidia.com X-MS-Exchange-CrossTenant-Network-Message-Id: fcf54a75-069b-49e5-33ba-08de7dee886d X-MS-Exchange-CrossTenant-AuthSource: CH2PR12MB3990.namprd12.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 09 Mar 2026 15:14:17.9366 (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: fchXAjNJd9+plibijh1Or0pnsQy95zpz0sjwN6N+xWG4ZHJiLDtmyE37hUce9C5TAIRpW7hPRvnc5gkDvjdHBw== X-MS-Exchange-Transport-CrossTenantHeadersStamped: CY5PR12MB6131 This feature is stable since 1.89, and used in subsequent patches. Reviewed-by: Gary Guo Tested-by: Dirk Behme Acked-by: Miguel Ojeda Signed-off-by: Alexandre Courbot --- rust/kernel/lib.rs | 3 +++ scripts/Makefile.build | 3 ++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs index 3da92f18f4ee..cddeae8b6cb2 100644 --- a/rust/kernel/lib.rs +++ b/rust/kernel/lib.rs @@ -37,6 +37,9 @@ #![feature(const_ptr_write)] #![feature(const_refs_to_cell)] // +// Stable since Rust 1.89.0. +#![feature(generic_arg_infer)] +// // Expected to become stable. #![feature(arbitrary_self_types)] // diff --git a/scripts/Makefile.build b/scripts/Makefile.build index 32e209bc7985..923886735299 100644 --- a/scripts/Makefile.build +++ b/scripts/Makefile.build @@ -314,12 +314,13 @@ $(obj)/%.lst: $(obj)/%.c FORCE # - Stable since Rust 1.82.0: `feature(asm_const)`, # `feature(offset_of_nested)`, `feature(raw_ref_op)`. # - Stable since Rust 1.87.0: `feature(asm_goto)`. +# - Stable since Rust 1.89.0: `feature(generic_arg_infer)`. # - Expected to become stable: `feature(arbitrary_self_types)`. # - To be determined: `feature(used_with_arg)`. # # Please see https://github.com/Rust-for-Linux/linux/issues/2 for details = on # the unstable features in use. -rust_allowed_features :=3D asm_const,asm_goto,arbitrary_self_types,lint_re= asons,offset_of_nested,raw_ref_op,used_with_arg +rust_allowed_features :=3D asm_const,asm_goto,arbitrary_self_types,generic= _arg_infer,lint_reasons,offset_of_nested,raw_ref_op,used_with_arg =20 # `--out-dir` is required to avoid temporaries being created by `rustc` in= the # current working directory, which may be not accessible in the out-of-tree --=20 2.53.0 From nobody Thu Apr 9 10:29:43 2026 Received: from BL2PR02CU003.outbound.protection.outlook.com (mail-eastusazon11011064.outbound.protection.outlook.com [52.101.52.64]) (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 B7B2A3A6EE9; Mon, 9 Mar 2026 15:14:28 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=52.101.52.64 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773069270; cv=fail; b=XaAapnVtdV01nbPH9vhQPgJKdUG3EGqF12xqpxVxwTAIEsZPStaTit+PmNTpS6rRVBN3zCJV0MPC4kytgkETP9XwnhGZWw4hRui/Ejt7xs2kHMVliwVjKw7aRv1GNTn+BVFrVm9qCK2F5lxhhxdpu81ABDM027b6bpWJNhOJa1Q= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773069270; c=relaxed/simple; bh=TcC/0HgSiNIqEHyMERhzbunfuxnhABk0R6879fRIrvE=; h=From:Date:Subject:Content-Type:Message-Id:References:In-Reply-To: To:Cc:MIME-Version; b=sjvErJ/NXU/T9fQqgZrHQg/gZlod0ccVGzPOqZ82h4yPGjUgbn2yEEow61444ybwlaTeuGYthJze9xcIU5uPHVYhAVzGEOVjamfWR080I6cTChYVdMLwqJOLeTXgxV/JeVAB4MtbWR8VEPlDk+Y4zahUziq3sloMUBG+MVff0i4= 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=rAixXmQ/; arc=fail smtp.client-ip=52.101.52.64 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="rAixXmQ/" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=izUgcWWa/7aL5IE33bHVk5h42+RhZYOK4F3eQzcqzAZfe7KCyf3MOVVpXYFbj7kEgDEmTftGs2LAvrTHgmtIRtI+l2vfs8QuaQqLVcM1pk0lYfuL/cspmj3z1nOhCzp45a0kA7Sk7UOsWEAc1/1uEQcxO6RDdsn1Nk/od9ccgRfC6tKTPILeqbUjU5SXdekyFIUaJ63dtorvbeZaEhQr3CMxbrwjJLbE97ilQ0jk7qJcDzs8m5wZ6t6bo0VMw7fAHriEphHINzZMBfPm/66Ku7Vc0yDW9Y9ey0uLO82YbbhybWEqRA++2f2PSsRShjmiciLpBfigzRhmJKKtvMVcbg== 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=CSznYsY1ajD8r+TxMVK8h1CuRPjgUYV87ErETI4erGs=; b=l3nY4Nqw0t07BBojx2OsyZzKFG+Bgwr+sCwXJjzGaWc1o3jtofJ2Evc7syzTdtN6GlXlEUDQ2v1EmR6lm4nNkSAadQsz0NJmo1i6rOshFkEzWAMCDqQp/pBTTLxzWnZ/E0ta62K+D143p+rmLBouh5ENxECqhx3cc836NKol5W7uTG8Hrdk9UPhjGCnCSTpkppkKDE60WvWKp2Bnt3qeZguXj4IEiy2qB/LH0zky69G1eywtBeDgMJe7CKJ6kqRY8B0cmNvlMGn0tKT34w6oc2+iYYdvEQuheczDlw7faoe6srkumj/LdBbRCZNUtBnV+5ERSJruanVEeSQ5RVGAxw== 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=CSznYsY1ajD8r+TxMVK8h1CuRPjgUYV87ErETI4erGs=; b=rAixXmQ/gDq5a+RM9I1a36vStOVi9WB5msP7z4f+NW7mqbRH4wYHfr4mRmO9MF4fdAYHwtRSgodNJkqmfbMQTSudji8gGXM6osYLwZR3PC5VPFf1YR231fYndQEdboqhG/PaNthllgZYJ2wy/jMX4mMR0bkYyp80a/D9J0OZgTugtVaQBZQ6zIRenSOv54FrCFatPFnSxPHjhOLbNY5I1/BWsYuCJxlZrTsN/RLnV/GEIprxLqc+EgKW7UEDUqznBi05f8tvIqJ79s72bDibIIoMlJbQeJhjpRk0XvLvngx3UzI0RL7dck2bQUlAh/LEGOXevHrAXQqfsfolMDmA4A== 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 CY5PR12MB6131.namprd12.prod.outlook.com (2603:10b6:930:25::10) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.9700.11; Mon, 9 Mar 2026 15:14:23 +0000 Received: from CH2PR12MB3990.namprd12.prod.outlook.com ([fe80::7de1:4fe5:8ead:5989]) by CH2PR12MB3990.namprd12.prod.outlook.com ([fe80::7de1:4fe5:8ead:5989%6]) with mapi id 15.20.9700.009; Mon, 9 Mar 2026 15:14:23 +0000 From: Alexandre Courbot Date: Tue, 10 Mar 2026 00:13:59 +0900 Subject: [PATCH v8 02/10] rust: num: add `shr` and `shl` methods to `Bounded` Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260310-register-v8-2-424f80dd43bc@nvidia.com> References: <20260310-register-v8-0-424f80dd43bc@nvidia.com> In-Reply-To: <20260310-register-v8-0-424f80dd43bc@nvidia.com> To: Danilo Krummrich , Alice Ryhl , Daniel Almeida , Miguel Ojeda , Gary Guo , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Andreas Hindborg , Trevor Gross , Boqun Feng Cc: Yury Norov , John Hubbard , Alistair Popple , Joel Fernandes , Timur Tabi , Edwin Peer , Eliot Courtney , Dirk Behme , Steven Price , rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, Alexandre Courbot X-Mailer: b4 0.14.3 X-ClientProxiedBy: TY4P301CA0119.JPNP301.PROD.OUTLOOK.COM (2603:1096:405:37e::9) 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_|CY5PR12MB6131:EE_ X-MS-Office365-Filtering-Correlation-Id: 146433e4-ed97-474f-1841-08de7dee8b1f X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|10070799003|376014|7416014|1800799024|366016|921020; X-Microsoft-Antispam-Message-Info: J09Cz2YYTkxH/MkeP9WQV1YFV03b2Sj8iaVA1ovW0+/38gouCJYZ9BdRaTz4c9eI/NMHzki/8+XObBw7s+qxgmjS3ZRjI0JdwUwmfCxVSQqUb04uwSHQNh7nGm1/t6aIXxSZzZW0oUogsoRTEIXjsAXzT2jr89qjzu8APKtXE13ocsN/RQRHvqOY+tDFeNcg3JR9TuCPU6+/IsJ5C3Uxc3QWva2qURMbXOCecPEepdROXLY/YvsJH9SgHvIguOmIx1r4h2oV0/ZXUwHzhO2SZ9TibffWpfQvoKOl2LfPKKLFWEvoQmHJD619/mSRI0xjv7QaR5OlR8p1lfxQOnyB3gTPVKp91ivy0aEeH5ggglqe5pzM34h0x4vjfP0O+CqmMfkbq7O9V/WCz1TdPAl7hU3xVzMXgzfH8MKQwe7Y+VJQE3MJ/ZtLApJijtYWXAPB/RgB/toKwtbQ+h4pQ0mDUMwye1Uienrxwh8jzqmBvPZKLHm2Crzhr8Gm8TdByRX8K8nhiwbLlGlrH2AGDdqimk7jmZ95pfyeG6FJdhX49H5vu/frRpq3JgrQF4k8YMVvdad0jI58j+J+YhSZ9AGOMkVWgiAqLPrSCupX0lcbzPbOJOT5MUzh9q1Cj5Hxa8SkCGjL0RY1xtz4XfdBWd0albIY6ehtZm42s4jlM4GXO8JjgemolnNFqAwRZZAFh6TwSLRp9GM/SRdpaFpR9kEF4NFLqGjJODYf/5pLFlJqW82tJoGIM2QrTnAeXiYZHYORInqUqzDQ4/FgEx7wr9N/MA== 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)(10070799003)(376014)(7416014)(1800799024)(366016)(921020);DIR:OUT;SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 2 X-MS-Exchange-AntiSpam-MessageData-0: =?utf-8?B?bFdUdlVseXliMnJDVis3WjNVZ0RJQVhBRHJVTS9UM2RidEo0Tkt6c1BibDJZ?= =?utf-8?B?N0F4SjRDbThkT0tVRzNZNCtzcHVoZGpPT2IyQ1lPZzZRQ1BTMHMyeUkvZ2dv?= =?utf-8?B?S3cwYlFQSFlNT0RaSURZNGIwSnNwMUhieWVPeWUzaWxDcGJpallrcXI0Qmp1?= =?utf-8?B?WkpKOVM1ejMzVDhpNE5lQlJNbjk4REdxUWlWbzFTWjZxMFdab2dpSDhhT2l1?= =?utf-8?B?TEVNbllzY3htcGtQWVU2UGxLMkJBbzlnam1JZHU2NUZiODRwdEVCUHNTbmFG?= =?utf-8?B?RW9teHQrSVNnRWdQK1Bpc2h3Q2pTRHdOdUFKUzRwVkY0cm9lTkF1T0hzR1Jr?= =?utf-8?B?UVdkUDlJRlhrSmR2QXZwS29tbS9TMWVIZFlERFpveWFyOUxGKzFkUG85WVRD?= =?utf-8?B?cXZiUm9JUmh5cVRSbThaUXRTTWJjakRxQ3VQN2hvbEpSVzJqWkNLREVMdUZU?= =?utf-8?B?MVFaVDFUenpHcFRWMzAwMUZ6VmtxcDNEZml4R2ZzQnVpRTdLUnIvb3hWcnkv?= =?utf-8?B?ZExJWmN5THo3QnpEZ0FIMUhsaFZiZjhTd2I0c3BwdzBUQkphR3hvSDNZVmVT?= =?utf-8?B?a3YxVXRIMm1yWmx0MEhnTHNiYVQ3T1RYL00xUXY1QitLZ3E5L010RjRYdEJB?= =?utf-8?B?TkljUHl2ajlJcHJDamhiaU55K28xaTczN1dFM0JCU2h1VlBqOGtqNG1aV1JF?= =?utf-8?B?bDU4ZjI4dytFZXB1Q08xdFhIREhJbzU0UkNBckpQWU42dThBTFJ3eE5YejZ5?= =?utf-8?B?MkNlM0pSZkMwT0dIOTlINVcycnMxSVEzR3FlM0JpSVV5WHdqS3NsRS94Ynha?= =?utf-8?B?djJjalBMTFlKOS9UN2NtQmhXZldhNmRnWGV4c09uT2JWTWpuRnI5MTUwV3dB?= =?utf-8?B?ZU1BcjVMSjFNL251UTFrSWhKV2RoR01LbCtMZGJ6R284Tk5LVEp1OEVIcCts?= =?utf-8?B?ckFqOXlWM1NIL2xzNkVEaE5hZ09OMjZrODcvQzhPNmthSGhqVHhtWTlDWDdL?= =?utf-8?B?d3k1b0J3VWdEYkRUbVdHc3Y1Ymt1SGVXblRqMFBEQ2FNSHl4MHdkZWg2SGFY?= =?utf-8?B?SklBaVhuUFJaVSs0NHJNeCtvSDlXNzZoUU9GeWx4UTUzSHN6ZFlsa1I4M1NC?= =?utf-8?B?NmlFNkpnbE1SNEltMEc4bWp1cGZWMFVKMjVsQ01uOGRENVhBWjlDYXdOY3VT?= =?utf-8?B?Mnc3ak5ST3NKQUt6cFdzQXAvelN2TTdaWWFSeDRxZVViVWhYVEQyZzlyTGI1?= =?utf-8?B?SVFNckVmRWFKMWd1QjlIcmdQZWFBUkRJMHZVUXQ2ZDgyMlZVZDh2bXFJK2Rz?= =?utf-8?B?RUlQdFRxVUVzMlFMUkIxTGdsN1EzbkNrSCsyTXRGY21obFNrMUhCSnVDb09K?= =?utf-8?B?L1B3MkNmVzBtcEVKb3N0dzBnUzVMNlVHRnNjdE5VQXJ6RGt3cDAzNVNtenRK?= =?utf-8?B?N0FHUDFXVDZJcE1EVjNIT0F6bnhDQjl6cU9HUXdHS0tCR0s2K0ZtZG9Qem5U?= =?utf-8?B?dVQ2ZGZHTVZvOG5XcEkxWW9KZFYvVXo3RG9aVUMxaXk5WUlBTEtmbktFT1Jz?= =?utf-8?B?eFBJNEpKOTYvSVpzYjl5YmpGckVROG42NnhpUGR1Nitwem9qY2lhY0tMS1lJ?= =?utf-8?B?ZXU2TGlXTElGZFlYOGlLM2l0SFh0TS9yWU9UVldlSlQwT1BRalpYUmo0SmUx?= =?utf-8?B?R28zZDN4bXlCWmcvQU9SRkkySjBFTkVRcm5uaFNwdm45ZXRuZ054eFV5bGd6?= =?utf-8?B?K1hKWXBCaUdIdUZaRXZ6UytaSjl4Tm1KU3oxZ2ZiQ1EwRGdEVFQ2L3JoQ2xS?= =?utf-8?B?ZWlxTkE0amNoU2pWOUk2NitEWS9JV1hEYXRXMWJiZk83eE1oSTVCMm1URW1Y?= =?utf-8?B?eVpER2xHdmE5cXRib2d0bkhOWTRwNDU2OXV5LzNwTTVJcmpZLzgzRjN1UHUy?= =?utf-8?B?QWkzclkzK2llRktlRDY0WE1qL3lkcEUyV1d1NXl3SlhXRmswRGtsamxFMmQy?= =?utf-8?B?YXlyVUJUUEpSSVM2cG90ck5mVFNmVFh6MnhTWk1oYndES3dwVW5uRC9vQUhS?= =?utf-8?B?YkZLMVl5QU1yNmF2aFFpNkdDZHZmMi92Ny9HN21UdWNvVWVJbDRacGpkMHph?= =?utf-8?B?M2dmKzBTY2JzVTBMUjAranVqaGt3dW5TZks2eUVaaWIxNlQ0THR0eTRkVVdi?= =?utf-8?B?b3NCSkgwa0FnWDNMYm5LY3JHTStaOVFGb3o4TUtXZ3RTQWJTRThTSWVZRGx3?= =?utf-8?B?WEFxajR0ZndjOGlzYzViYUVvWXZhKzdKU1F0bXlhbHFucGx4TUg1eWcrd1RD?= =?utf-8?B?WjY1bzE4NkgwZHpFdGNuQWxsMUQzTjZHcTZSL3VXNERMd3NlVmUvbEJwYzcw?= =?utf-8?Q?RqlkThu7MG6HbbLYtuWopfexecgO5oi+0oAIqJCKQmZND?= X-MS-Exchange-AntiSpam-MessageData-1: I42rsHBwPgYYbQ== X-OriginatorOrg: Nvidia.com X-MS-Exchange-CrossTenant-Network-Message-Id: 146433e4-ed97-474f-1841-08de7dee8b1f X-MS-Exchange-CrossTenant-AuthSource: CH2PR12MB3990.namprd12.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 09 Mar 2026 15:14:22.5225 (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: NUQDKhUGaV2UTxJ9sAE+zK/xYJU4oIrjAv2EpVvslFN8QGEFWGGUAC1Ft9ZOKqYKuSBE8znTH8tIcUELqzqHHQ== X-MS-Exchange-Transport-CrossTenantHeadersStamped: CY5PR12MB6131 Shifting a `Bounded` left or right changes the number of bits required to represent the value. Add methods that perform the shift and return a `Bounded` with the appropriately adjusted bit width. These methods are particularly useful for bitfield extraction. Suggested-by: Alice Ryhl Reviewed-by: Alice Ryhl Reviewed-by: Gary Guo Reviewed-by: Daniel Almeida Tested-by: Dirk Behme Acked-by: Miguel Ojeda Signed-off-by: Alexandre Courbot Acked-by: Yury Norov --- rust/kernel/num/bounded.rs | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/rust/kernel/num/bounded.rs b/rust/kernel/num/bounded.rs index fa81acbdc8c2..2f5f13ecd3d6 100644 --- a/rust/kernel/num/bounded.rs +++ b/rust/kernel/num/bounded.rs @@ -473,6 +473,48 @@ pub fn cast(self) -> Bounded // `N` bits, and with the same signedness. unsafe { Bounded::__new(value) } } + + /// Right-shifts `self` by `SHIFT` and returns the result as a `Bounde= d<_, RES>`, where `RES >=3D + /// N - SHIFT`. + /// + /// # Examples + /// + /// ``` + /// use kernel::num::Bounded; + /// + /// let v =3D Bounded::::new::<0xff00>(); + /// let v_shifted: Bounded:: =3D v.shr::<8, _>(); + /// + /// assert_eq!(v_shifted.get(), 0xff); + /// ``` + pub fn shr(self) -> Bounded { + const { assert!(RES + SHIFT >=3D N) } + + // SAFETY: We shift the value right by `SHIFT`, reducing the numbe= r of bits needed to + // represent the shifted value by as much, and just asserted that = `RES >=3D N - SHIFT`. + unsafe { Bounded::__new(self.0 >> SHIFT) } + } + + /// Left-shifts `self` by `SHIFT` and returns the result as a `Bounded= <_, RES>`, where `RES >=3D + /// N + SHIFT`. + /// + /// # Examples + /// + /// ``` + /// use kernel::num::Bounded; + /// + /// let v =3D Bounded::::new::<0xff>(); + /// let v_shifted: Bounded:: =3D v.shl::<8, _>(); + /// + /// assert_eq!(v_shifted.get(), 0xff00); + /// ``` + pub fn shl(self) -> Bounded { + const { assert!(RES >=3D N + SHIFT) } + + // SAFETY: We shift the value left by `SHIFT`, augmenting the numb= er of bits needed to + // represent the shifted value by as much, and just asserted that = `RES >=3D N + SHIFT`. + unsafe { Bounded::__new(self.0 << SHIFT) } + } } =20 impl Deref for Bounded --=20 2.53.0 From nobody Thu Apr 9 10:29:43 2026 Received: from BL2PR02CU003.outbound.protection.outlook.com (mail-eastusazon11011064.outbound.protection.outlook.com [52.101.52.64]) (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 4A2653D7D97; Mon, 9 Mar 2026 15:14:30 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=52.101.52.64 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773069271; cv=fail; b=cNY1qYQ5NzTp8nXkbVKIaE/u17j4fS5XlvbTqnFZvmtj2Rr/OV3uy1reSIjRTjR0oFKvRelmIekylecHMaUcwc0xreoBPekAyNohYWkvg/09q3gqH6vuuy8cy0qtkvxKThkatHobVhWvcW9Xrs1y0A4j4vRiSRD5mKC7byUw8ak= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773069271; c=relaxed/simple; bh=g6pxC7YDKxn8dWDn1GgkniFa+rnZSH2UAw9aQPrd5WE=; h=From:Date:Subject:Content-Type:Message-Id:References:In-Reply-To: To:Cc:MIME-Version; b=A4GS/SabxVxKK7aE88pE0nnKdzF6tXJKkIsS8oNvc6kBoeH+Nzu6OHHWBSDSFoBeKdX5dTpgfOdzvO4vH1ptEaA5yHA24BRvRh+vcMj4U4yXtOuzfYPtJvcHoxUSYSPz/MIQaF/kDaUSd5OwV6PF5f9cdOzYfQtnJ+qgURPM2X0= 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=YXVrZ4es; arc=fail smtp.client-ip=52.101.52.64 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="YXVrZ4es" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=SxXRDIGgZK5YjwSdelaVozb7kXWIFPsqePabEIRZO8aLKsq/3oaBDeJ9OEvaPrDOnBmd1y0n7tORjAkjaw8L53pBmMykwP0XGpROqb5cPNg3ZGJdX8bmd+9B5wpcquMZpEXSnOoELmqivCaKcm/3Kgq3ADJNaLmdfdlGhXNmqTjCWnqNtvEd21RA+2ogWuCfsCm96eeK0c/xxJxMOZvlMIVXk3FAN/JHDwMu6jHHNUvmMSCkRJkrtZaTXn1+dXtLQ7IdAW2dTfE9fwUTTUAoIwz9JYFuYAQWpoiRMSTLYFGFD+oD3OkPpo0wzZkB6JxqArhBjxtHOMfAvWRh9esuXg== 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=4dnFWA9MUzwJOAGqB5UIX9vY/f4AMIt2w8I5b+B/Cx4=; b=e5dgqf9lQFchuCEaJE10eueMQzyiroGzGGzvgJw/nLlheOPKvaMAyDQrfdKOIbU5gfxp54lSTKQ9o3D1i8QM52fah9MdbcgL/y2RJQGndwQ1Py4yDffDhzZjWnrKPYrVxYBw72nDYE3IwlDwmPfqb/JwN+NbMdbOk1NLnjxIsalpXVwU3jcpaUflaggOnpD+xKdywMHHaQ7BIaXI7Nkb0M3agqDMICz1nCOuJPAjm79C+iJmOS9BdxS1TMMNRhqgi8Y7JeYhMfDhhkQG0Pq103kdAMg7Wq/OZXDp3UHLndqJx+QkKGlGcwKgIWUpxUz+jRnrR7zFCB4s+xoKaHwrKg== 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=4dnFWA9MUzwJOAGqB5UIX9vY/f4AMIt2w8I5b+B/Cx4=; b=YXVrZ4esmBc76fngLZYAcdFHbRs1Sjtuw0YWnyn0PmP4UM75Ol/pftVz3N2n80e9OuTpVAwYpy9BFxoyJJ9GMITeqhqwlXXzpKRCrP2vrgQmlQagunK4BrgQu0FvGglKj3kO6DQjniBEVLsN5VRkmI6X0xSINvfJG9/1Rombdnwf3pizjCVNrFEQfvFUJBKyo6pTH73iURAMUyxTUh6TCzC9wE+9+bxjAiM3a1QaGgg23yqzMLhcSREopYfJOajRMIq/GWdqvhGKE5cE4mzl7B4IHwQFgHXioiiyOixkY9fRdyqDOPrC9xHIExEzgiF8cdv99FhoDpAciDdWK42hCw== 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 CY5PR12MB6131.namprd12.prod.outlook.com (2603:10b6:930:25::10) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.9700.11; Mon, 9 Mar 2026 15:14:26 +0000 Received: from CH2PR12MB3990.namprd12.prod.outlook.com ([fe80::7de1:4fe5:8ead:5989]) by CH2PR12MB3990.namprd12.prod.outlook.com ([fe80::7de1:4fe5:8ead:5989%6]) with mapi id 15.20.9700.009; Mon, 9 Mar 2026 15:14:26 +0000 From: Alexandre Courbot Date: Tue, 10 Mar 2026 00:14:00 +0900 Subject: [PATCH v8 03/10] rust: num: add `into_bool` method to `Bounded` Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260310-register-v8-3-424f80dd43bc@nvidia.com> References: <20260310-register-v8-0-424f80dd43bc@nvidia.com> In-Reply-To: <20260310-register-v8-0-424f80dd43bc@nvidia.com> To: Danilo Krummrich , Alice Ryhl , Daniel Almeida , Miguel Ojeda , Gary Guo , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Andreas Hindborg , Trevor Gross , Boqun Feng Cc: Yury Norov , John Hubbard , Alistair Popple , Joel Fernandes , Timur Tabi , Edwin Peer , Eliot Courtney , Dirk Behme , Steven Price , rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, Alexandre Courbot X-Mailer: b4 0.14.3 X-ClientProxiedBy: TY4P301CA0018.JPNP301.PROD.OUTLOOK.COM (2603:1096:405:2b1::16) 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_|CY5PR12MB6131:EE_ X-MS-Office365-Filtering-Correlation-Id: d148d91a-c6b4-4933-48ef-08de7dee8d5e X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|10070799003|376014|7416014|1800799024|366016|921020; X-Microsoft-Antispam-Message-Info: ROMfP3uWz3IdmsVeHxBUVURas64YrLqBw/nE9TE+F208rIpNyhK9y9d0TOtku9Y+bFpiL6eNNoL/Gysi5IgpoLZBFzwFAk5cFHwFcjNJqdU97h9qbGrW4lqgv7fswfmxIzq3OqaFGldnTe3gu44vymA5QrDmRUjeM34To+IoMDOfGu43tOmcLHWUXsbaxbvUAUOfbXzeSf9kdedcm9oBpQcUxY4sktz8ue8UsBkMQOoZ1SlfzybGSilXQtlKblcrnmOG18Ae6PROVVR6uRUy8Y83Mjhd+DV3ZwMAgwRNA725v3o+9wqCnuAqFMrJbJaQ5unT5Sflzxxg+mpR+PNp43egoYYTDVpQ0zujs2U+3b89XN0S0VKq88goyR9EhVcTVDF98yoaJ2Q5Y7knBv68CDVCpkdXFcUEHAlZJiThsTuW3uKq36uQPmUC/X2k00WqJNJs2k4SA9Sa2WG84RqS3gfy0vpuQxVKS3m6+ufCae/bC1d+LWTalQ32ybEliQbnDD+j070FZ5z5jrPU97qKHtPcTntvfGIEVR7sFE3ESm7nI01hRPSzcmtr1EuSPKHSqubtFYP9qtAHkz52cA7C33vr+Hv1lse38lvSZ9prxc2wNX+B+ZlLeozZ5RVMsqLQEiyUwvPnNxnV6gZc8NaWA44oW//LVx5XHLQQnxQCc505pQ7f/jS1//iC70KK/2H1rlGTi1ksKig2wcDfEggf+aBn4iv5TUVQPo1I2GZ7LV3bpJgCHpEyRiqsw01USu2NKWrANXml1fY147uea5lFZw== 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)(10070799003)(376014)(7416014)(1800799024)(366016)(921020);DIR:OUT;SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 2 X-MS-Exchange-AntiSpam-MessageData-0: =?utf-8?B?OWxBV2xrZ3hWNGNsakpMQ2NEUTh2V3J6QW1hM2pQaWFMUmp6L205MDU3M1Bv?= =?utf-8?B?aGlMWStrcU5nUzBWS3JuN2R3RDZ2ZGtmb1g1cjdLZGpHNVBkZWVPM0ZiRFRR?= =?utf-8?B?MEhoT3l2Y1llR0Z0YzJqaDM4a3YvaS9hdGRDcnNRSU1XRVloVVFWQlpTK2dm?= =?utf-8?B?WnY1NUZJSDArbnNKMVRrZmNxMzJ5QU81SGxPRWQ2eElla3N3MDNCRVMzZHp5?= =?utf-8?B?TitrQ3NMM0tSVlp1UGIvaXZvaE9ZUDNRNTF0TzZVTkF3T0craHZkd0xxVWN1?= =?utf-8?B?SDdRMFpFa2xnTjFQVEp5V2xUV0dmbFl4Q0hSN0VVKzl4dXFhSzBFeWU2RFdS?= =?utf-8?B?dVJYWkRxbFliOUdQVHlBdjRzQWhLMEZheVRRdFhzOUpvamFWYk5YZWFUQUpx?= =?utf-8?B?UG9DalE3aytvTDd4Z1g4VmxvK09ObURObENONWMyTFhRek9UZHJwWko1K1d1?= =?utf-8?B?THcwQW93RHdsbGJQcmpnTjNMd3V3ZEIzaEUzMnZ5UmN0aXVnOXJzbXVDam02?= =?utf-8?B?UWtzbVFWa1NIUTNsVnp3dEJ4ZDY5aEd5TXFCWkwwb3diV0RJMU4yc2NJdjl5?= =?utf-8?B?MFRzMDhzSHd5YVh0eXJXd0FkR240MDdiYnBBQm54TkNJcmM5aFQ1TDZqYlBE?= =?utf-8?B?RGR0TzdXNnFyOTRPeTdNMUV2NTZCVXhmTm1QSzB2SXB4WVVoVS9TK1JYWVFY?= =?utf-8?B?SWNvOGd6bEZSNXdYSkRmVkpYOU5wTm1uNmIwZUZMbWYyQTFFZnRkaEJEWHBR?= =?utf-8?B?TVlOZFVsSkNMdDg2QkZjUHdDdXBTc3FIOWJwM0huYmxQSVMvcjdDaHpLUUdE?= =?utf-8?B?WHZxZUpkY1lGMTZTOTVGVnhDQXpEcTk3Y2tPNGN2KzFzcU9sNFYzcG9pT1JM?= =?utf-8?B?LzNkNEJwOG13SmpiWThhS3VUMkdjczNuWVJQeDRaa3FORkQ4UEprL0k1bVIz?= =?utf-8?B?Mk5ERjRVT1hscUtWTjFKZlMvY3cvRnZCN0hlWFlpUldnWWJZS25tZGErWUFI?= =?utf-8?B?QTF1Q0NuVEVzZ1MvRlFIdTZPRVlJcUFWQm45QXh4d3BmT0VDVnRnNGFIRVRa?= =?utf-8?B?cTVrR1NoL1FMdG5OU0ZjU3JoNW1VTEJGTUpZaFdCb3FNWTVnRUFQZkZrYXA4?= =?utf-8?B?dlR2TlRRYUwrdEl1N0RSaUhJWndDSURLUkxaZUdRc3dlRXprTTFxd3lGNDlu?= =?utf-8?B?OTdJeUNvZmYyb2tnVHhOTzFDcGFwV2FudSs5MjY4aGVMd0d1NFZaRWcvLzlr?= =?utf-8?B?d1hqYmRWQWs4ODhxUGFtMmxBMHVOY3NjK05uM3ZHeDh3L2ZTMnB5TTl0UjJv?= =?utf-8?B?ZEpTZGhYcXFFd0ZGOXpSNHA2cFJJQXh3cmZRMS9RM0xiVU5vQmlMaThjaGFJ?= =?utf-8?B?YTJoNWNwK0xKTGFzMURhUExPeUQ0bWlHUkZodWVscWJyVTlCSENzSXVkWXQ4?= =?utf-8?B?R2hqZHN5MFZhV1RlKzhwYjZCNVRLQlI5K01zR2l5ZG43SVc5ZG5DMU1uMWZx?= =?utf-8?B?RGlWM3BZQmlGMVlkR2Nad0VtTFJOZDdpR3lKTHlqV0JFWU45Z3Q5RktuYjN1?= =?utf-8?B?RE5SeU1ncnBLUGdrQXJmUnVEek1EMW1Tb0hYRlBtWlBKTFlzUTVaYUw0WldH?= =?utf-8?B?K0FSb01vUjZLMVdlWE9aYzBMMXRqWnNDS1d2YzZRWjZrRzFieVJMYkZXVGRW?= =?utf-8?B?ejNzaVhsbGxSRzRVZGN3UzFKNmRFMUQ0KzNDSkFOeG1PYkp1UEt2bElCeE41?= =?utf-8?B?OGVxTjlJTk41SVFPWFAzTVBPOGpRMXIzN1hNcEsyU2NIdlE5T0htZVdtL25S?= =?utf-8?B?RDBQbnVwbDExc0hZdjFRTXNKcGJpb1lFSkg0YzZvTFUvZ2VoVFh3VkNFUE1n?= =?utf-8?B?amlKeEpxcmc0R0JhZkhVOUxvYTJpVkNKay9IV2JWVG81SzJSN2hQbnVjWmxi?= =?utf-8?B?N09tSUZIaysybDMyQzV5a2lhR1JKQkhQVy90MlhtZGt3dUJnTTFwUkYyc3F2?= =?utf-8?B?RXNwVHljMVBIaWM2SkNFMVZIVEV2OStsc3RLdnhaRnc4TjFGSS9UbVAvbmht?= =?utf-8?B?cGNjZ1AyUHpFdks1RForU3BsZDY3STNyRGxaMjNKWDVlTTk4LzI0aEFOMmdp?= =?utf-8?B?RmlaSmZKQlMxTlFpK2wyeEw1eDJyNUh1SUdiZzhiNzh2QjBMaTVNektjYTNJ?= =?utf-8?B?VERRQm5qK2o1SkttSG9JRXFPRlN3b3dzN3J4RDBGR1h1WHF6bFdHVnFvc1l2?= =?utf-8?B?bXo4cDd1Q0pHYnRFYkZ3dFE3elNkL1BmcFUwZUJydXlSeE5PU25MbU9qTmlH?= =?utf-8?B?MXdNNi9PYlpKTzM4dXQ5QUpZeEhYZHpCbTBudU1pZ2RNYWxlMHhRcXgvVy9k?= =?utf-8?Q?ue4r/6Vovsev9Iy61TAhA1ZLN8T2ikLqez19zYxCDc+gv?= X-MS-Exchange-AntiSpam-MessageData-1: ZSWDqxAx7y/wBQ== X-OriginatorOrg: Nvidia.com X-MS-Exchange-CrossTenant-Network-Message-Id: d148d91a-c6b4-4933-48ef-08de7dee8d5e X-MS-Exchange-CrossTenant-AuthSource: CH2PR12MB3990.namprd12.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 09 Mar 2026 15:14:26.2094 (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: 1muEXyELbAtALjMXNlHMSFjMuNbpwwq3pu6MeHxUfuoFs45wbCsBKnQg4oEaTArYsfII6ZAkZhat/5GRZQ+NRg== X-MS-Exchange-Transport-CrossTenantHeadersStamped: CY5PR12MB6131 Single-bit numbers are typically treated as booleans. There is an `Into` implementation for those, but invoking it from contexts that lack type expectations is not always convenient. Add an `into_bool` method as a simpler shortcut. Reviewed-by: Alice Ryhl Reviewed-by: Gary Guo Reviewed-by: Daniel Almeida Tested-by: Dirk Behme Acked-by: Miguel Ojeda Signed-off-by: Alexandre Courbot Reviewed-by: Yury Norov --- rust/kernel/num/bounded.rs | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/rust/kernel/num/bounded.rs b/rust/kernel/num/bounded.rs index 2f5f13ecd3d6..d28d118abd8e 100644 --- a/rust/kernel/num/bounded.rs +++ b/rust/kernel/num/bounded.rs @@ -1101,3 +1101,24 @@ fn from(value: bool) -> Self { unsafe { Self::__new(T::from(value)) } } } + +impl Bounded +where + T: Integer + Zeroable, +{ + /// Converts this [`Bounded`] into a [`bool`]. + /// + /// This is a shorter way of writing `bool::from(self)`. + /// + /// # Examples + /// + /// ``` + /// use kernel::num::Bounded; + /// + /// assert_eq!(Bounded::::new::<0>().into_bool(), false); + /// assert_eq!(Bounded::::new::<1>().into_bool(), true); + /// ``` + pub fn into_bool(self) -> bool { + self.into() + } +} --=20 2.53.0 From nobody Thu Apr 9 10:29:43 2026 Received: from CY3PR05CU001.outbound.protection.outlook.com (mail-westcentralusazon11013046.outbound.protection.outlook.com [40.93.201.46]) (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 419293DA5B4; Mon, 9 Mar 2026 15:14:35 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=40.93.201.46 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773069276; cv=fail; b=M+h9nkYLa5T8o+93aV5XQ6VYXiCUXSC1+d8qVToQFpkRgPRiOhIzM5ssGslm6puc9VBZFWv8vVWnlFlGbKy5Q3ep5ipH7+U/tFVyZKAVmyoDMdSnAycb6v/3X/VZjWNEZK1RejmvoVIsszwNnLZVLPw/uAY7WPO4eeevr0IOmAA= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773069276; c=relaxed/simple; bh=s1ZY5UjravxF6orXaQnV2BPeU9346o1GOVyeBfDj2+Y=; h=From:Date:Subject:Content-Type:Message-Id:References:In-Reply-To: To:Cc:MIME-Version; b=JBMPm4zsYvvv8vHlj17Kg8j+3dDTi4Jcjz3uI+SKIZaQhtD3QaM16EnYFuuBGATtNyr0petJ3zzcqZU35Bh+mpniXYt1yqyjlOhcSQOhfwsns/+y2ABTA09MIfRqB7urNuitbaHYdNEcFaPuHKDFp/2F8YQ4aZ86oirZ+2lYj9k= 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=rRG1469m; arc=fail smtp.client-ip=40.93.201.46 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="rRG1469m" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=H4Mfz17BOMz2qrtB9hZfiSbB73Y+Fx12rz4cR2KB/lp10KFCJun5tXUlHy4GQvivF+EO2jhDFm8Bq7FNe9FVs8QVNijcVpooLCFgEIw5uDi5TXDEku5UbfaWzCQrlcOsiqBqTWjwlCtg3REXhUP6lMWO/9Sv04DzqtYYA7wQ8GgyZiLeGW7UqSxiRuPaGXzXhw0dGuvHPkh7Fpme1bPPV5NyMz/XdyCoFPQjn+qZlnp2ost2LzYP0KpepPQ82oXP1xHyQeRrPH27SwHw0+rZ0fbCFdHFWzaiYFS3sejx7qcGmLR5svnBkSptJs1ETh5z3vVD/rInhGXOsM628/VR0A== 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=zDdXjlcBiC5X5uW1KKVSvdZBRIiMUXuzKu+k7F5RJ5E=; b=gQaOW+ci1IZl1WSywtJ0h+qj73uzrs/Z/LxDWF2XCvbB/ja8ilALIwvUfoDb3dpUhs+CAt7LVQSQ7H+WKFpYW820NIslTDLBgjkXMfDACPs+ewGnEB2PdIo4sPK6jUxc/yNfrDFsLRGGxvh/qeEaAjZQR+M85tWWxoQoN59Gyzt61iyIgtRobqUF2dd2j+t80lBWtJckjAf8qULWCM68P0auxZkxjjJnglmUQEQ+t6+OC3m5J+JSrWpw4Q9mjDzsGLHeBpy91OhMqpy+2henrRypPioH5lUA6m2wavg48cqkpi+l7D4h8UqLVflRNxsD3cUFxOed3kL6H3AzjPX8XA== 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=zDdXjlcBiC5X5uW1KKVSvdZBRIiMUXuzKu+k7F5RJ5E=; b=rRG1469m+Au5YYEb3EfFQ2FQzz6QSHiHaIEM8SFT6cZVWJn2GbK4IkdVBVSmBsq4CrftOZOjzu23/J7gBhiOMmVQKAmCz4GbkkNx49a/5JCALKbiWnxTsYpblbInXf5zJ1FmGjW4WEJWgFKOufD8pfcDe/1YgfBINj+tQz80b/v0q53BTb7XVc7aLZAvPj5Em+L8RdalH3/SiBYxRKgobvWTQOP6hPWjiCxA/SafBYmXgP/f6PJHDZOeDx2MXxzeEKPug5iLpOLWD0yGcBc15G7kggjAoAVJ0UsB44WltcqJv8o741HEJYTOU67mKRFSNjInuhGEbvx5h5z6ewk3jg== 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 CY5PR12MB6131.namprd12.prod.outlook.com (2603:10b6:930:25::10) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.9700.11; Mon, 9 Mar 2026 15:14:29 +0000 Received: from CH2PR12MB3990.namprd12.prod.outlook.com ([fe80::7de1:4fe5:8ead:5989]) by CH2PR12MB3990.namprd12.prod.outlook.com ([fe80::7de1:4fe5:8ead:5989%6]) with mapi id 15.20.9700.009; Mon, 9 Mar 2026 15:14:29 +0000 From: Alexandre Courbot Date: Tue, 10 Mar 2026 00:14:01 +0900 Subject: [PATCH v8 04/10] rust: num: make Bounded::get const Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260310-register-v8-4-424f80dd43bc@nvidia.com> References: <20260310-register-v8-0-424f80dd43bc@nvidia.com> In-Reply-To: <20260310-register-v8-0-424f80dd43bc@nvidia.com> To: Danilo Krummrich , Alice Ryhl , Daniel Almeida , Miguel Ojeda , Gary Guo , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Andreas Hindborg , Trevor Gross , Boqun Feng Cc: Yury Norov , John Hubbard , Alistair Popple , Joel Fernandes , Timur Tabi , Edwin Peer , Eliot Courtney , Dirk Behme , Steven Price , rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, Alexandre Courbot X-Mailer: b4 0.14.3 X-ClientProxiedBy: TYWPR01CA0031.jpnprd01.prod.outlook.com (2603:1096:400:aa::18) 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_|CY5PR12MB6131:EE_ X-MS-Office365-Filtering-Correlation-Id: 406a54e6-c51a-4695-4b7e-08de7dee8f8a X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|10070799003|376014|7416014|1800799024|366016|921020; X-Microsoft-Antispam-Message-Info: 7di6NDODcpezvxz8SH6s4Nc86YPbHJt9Jnj+Ocb8IvWv54plNlDoe7r2/kH0kSihc2r/T0XDNuaChRGv58AN76jWx6S/Th/xLb2lIsiu0M+Nj1AR6fhQJsbMYJWQd6cq8z67N8Gbu9cxZ3oSK4JHr/m4FQnicf5VEDwy0VkzgRhpUvnWTxs6kqLfFslXunqv/td3GWYrDL6ERtzSue58nh+FWIIS1GFFbwY8FFe3LXPAkaARHtht1HDpavDlkSvZF1+Td43OXGp7kZ3BK+1FbCB6wQplNrs7G2dLFh9kgdwmJQwMAcg06HDUVkOCmQLFHs/uI8X7F9IL4ZqJRhXJW3O8t1emxAlHXQbprvCbX9RYKY9rCC94v0vJ2j0KKtfftEX/J3+P//iAi7/fhOk1gdqhZcJfM0Am3tt352BvcFd3t3fV620vWl4FN3mnOxv8Xniws3YvgAFxZ5ieMxc2S4IWl6KQxwwC87oIwuonuvLNbhMTDdamUUtZl/bhr8ag6AoWy+nKIGwAu8yYCMz3ENxuXPRIYy9NRrK8Lev+TPjVNxXSUQJzcz3plSpwYzKBUyUT/yoVXVgU4RbxcRGPIVIDGaTZHMrq7VJ7BmueopSKmfGD3W1Ikde3wZsXzeCy+mjB1nNhx8twPIO5oHj59s2FciXTfN519B6y5hFRiBCi96Dk3FGF7pz8n70omEY7BJEY2TlHuptaliWNW9XAnXmvuKtb6aJ4qE9ltU0hFSRpgLCKPJCmvFQo9auxkprbfhEnOBkMsrZeNFJQlqYBCQ== 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)(10070799003)(376014)(7416014)(1800799024)(366016)(921020);DIR:OUT;SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 2 X-MS-Exchange-AntiSpam-MessageData-0: =?utf-8?B?andybkxCY1p0MXZYemhCMWdlL01adHA5dCtkR05sNExsQlUxNG0zSWIxV3dt?= =?utf-8?B?NU9FbkRSak80cmJHWjFwV0JuQVNBaFJOK0srbEp6QWN1YmxGMFp6U1pYTEZo?= =?utf-8?B?d3pJSldFblVuMDd1R0RseGZ3d3d2MmZWMDBrN0lCSFRjV1RiZWthQUpoazZE?= =?utf-8?B?K3RzQ0RUeUpQSFpTcTcwUlVxbjhqSloyNEhnTVdYOWJPTmFUdVBPaEFqM0dI?= =?utf-8?B?ZjhXWTVOUlpiOTB2SjdabXF1d0VnTGpFbXBPVzY1amowQXQ5d2VuUUZacUJx?= =?utf-8?B?QlpWOHJVSlFNQ2h4MU1oemlnZURLMlZvNE1neElKR3ZOM2EvUHdXVmliUGFl?= =?utf-8?B?czNMaFEwc1pGdXNMbG94K29FS3BiTGxLU2tLYUc4cjBjUzRHK0lLbE1YK05l?= =?utf-8?B?Sm9IMVh0bGJsQWc2azMzdnJ3VVJGb1d5SVIxcnVKL1Vmb0dZRGtDWHFvTE1s?= =?utf-8?B?VlZtanRRakg5ZFRpY2FWS0NxNHF6L2JOTVAyekdlT1RYNVIwTjJSL0t4ZWtK?= =?utf-8?B?cmxtL1E5ZkhYTitZRmNoWnV1RXZJVUY1ZS9yZmVNL1FoZXdWc2c5WHVuWmJP?= =?utf-8?B?NXNUREd0VHd3M3dNd2NTeW5HbEk0cnEwcDFVb3hVaGoxcWxBUUFSV3pFdTY1?= =?utf-8?B?UEhpeTZjMk1KSHRJdFJINEJFeVhMWVlaL3FZRWRXbm1LZy8xTllmNWNURnlQ?= =?utf-8?B?bHZ2eXRGYXBneEFOWmhLbnEvOENiSzAyK25USDMybWFqN0xXT3pWSzUzZUE3?= =?utf-8?B?MkppaWFQMnFldFkrN2JHTE01TFBGc3dpdEVDOEVraC9FNmFBb3ZDYXVZbGVY?= =?utf-8?B?TnVvK2ppOXozT21Pam14UWpyWitLZ2tzcjYxakNTRHR0UDFzYmc1WGpVL2ZD?= =?utf-8?B?Q3BJMlA4d0JNSTNaSTBUOFBKaGlkdDNPV3BLcVpLUmJrREtkNGUxSlFCSTRs?= =?utf-8?B?RTBHSkpmL3FrVDFROUdHdmc5SWpNSm1od1g5VEh3cm1SRXBYaG9wNXJsUEFj?= =?utf-8?B?ZVJ4UVZ4SUk2VGl0cG5QTnVLSXJZZTJ1Mjh5TFNydUtJWWptMUJJbWI2ejhQ?= =?utf-8?B?TXJVdkxpVVFEWHFJSWF4dWIvOU4wTTVMZXJFWTJhVktDR3Erb2pPdVZ3WTlJ?= =?utf-8?B?TlZGUE9TUmQ5aCtKTmd2WkxyMXk3djQ0M05FdFlhSEJMOUNYZDN5Y1BCaVdG?= =?utf-8?B?K3B2eUZhY1piM01SNjh6cUI2K1V2ZGlsSHNhb2pvTXpIL24zbVRIdzNkdE1Z?= =?utf-8?B?dDFLYVNVUE1YeXlMRVAxbnJqa2g0bjhCQTZJTmVkT2VodU9TMFgxNWM1MWtO?= =?utf-8?B?NllOb0NBd1l4VVNXK0tjOWZkSGtRUm9yTnpsMEtsS2oybkpKdkgyVG1JQWlO?= =?utf-8?B?ZS9zY0R2YjVhWEM2OVhxRkRlaGh2eUlEMXpKeitwSXZPQWNXcm9vU0I5c29t?= =?utf-8?B?aUxONU9WcmlxVW0wL0xjU0pxSUkwYXQyZmRhRXV2c3E1WXJSVXA5QUI5bDdC?= =?utf-8?B?ankreGNHWDBrWU9jL0NPcytrbzZEbG5JNCtwZkdlOUcxYnhEMytUcW1iblpa?= =?utf-8?B?eUNkM3I1YUhFYjdHaSt5RmF5aC9ybkFRVG91UVpUbVhvdmN3UEN0NmFUcGVJ?= =?utf-8?B?ZzNsa004TFZheHpROGFCZWVFN3lwS0d3OUh4MUFnTUtqRHVUMFRUekZKYnR2?= =?utf-8?B?dWRpT3VrUUJGNlF4eTRYR0dzc1ozQkY0Ty9UckJYV2wvYjBWQThwbkY1WW45?= =?utf-8?B?dnh2aGEwSDJjZ05aY2FveldleDZCdlNzbVlUYkZKYzF1Rk4wdUZKY1FmQzZh?= =?utf-8?B?ZFRySmRTOHZmS0pLU1k3cmZJRXRkN3RFMUdyK2N4eVpaT3Q5dmdBNEpzTFd2?= =?utf-8?B?aHRrYy9UMFdKODVNdXVQNkFTa3hXZGhiYUc5VU5lMC9VUXNnSnQxeitPbWJR?= =?utf-8?B?c3JWMUFONWtBRjhwMjAweS91bW9uMnVveVJCUWErc2w4TG85dG9hcTh1eExj?= =?utf-8?B?eEtvNU5ZaXRCTE85Mmt5RDdndkdTSkF2bHpkMzdjUkwzUHBRZEpsckRuM0Zx?= =?utf-8?B?ZFBtV21XWUpQdFRJWkhLQXhsOFdEQm1mdkhyekxUNE9mOTVzOERtZlR0WnJq?= =?utf-8?B?aHo4a09iRFU3M2h4TkZ1eUIvWlFSRVpHV1RwelFXa1ZwWHdhZ2dsLzgyTTlq?= =?utf-8?B?N2ZlSzAzVHhCQVdvMmh5blNMSitZd0ZBWUp2NnZMcm5RUHBLcEtySXBTeWtY?= =?utf-8?B?bWYzeFg1WWJTMWdyUVB6bTY2U3RBd1BiOVVJOWNCaDJ3WTU2eGlPMjZ5a2pR?= =?utf-8?B?T1hpbHNhaXJxalNWak5zNUFIRnNoU2xzYjhvbVVKcnhtTlVrMUJFNUJpMHFP?= =?utf-8?Q?8dv+0E748ndxIkdpSM0CsYVaX4qyzQ+I/Ocpan9rFyqpP?= X-MS-Exchange-AntiSpam-MessageData-1: I//Efem81yvrqA== X-OriginatorOrg: Nvidia.com X-MS-Exchange-CrossTenant-Network-Message-Id: 406a54e6-c51a-4695-4b7e-08de7dee8f8a X-MS-Exchange-CrossTenant-AuthSource: CH2PR12MB3990.namprd12.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 09 Mar 2026 15:14:29.8454 (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: WzHClBPYtjuZW6UXcKl7LxTGFeZB0jhNlvb4DqyaOsz63uPfV1mo83czElSuVO7WOE0kcqbDfi5wYGC00kxQ7Q== X-MS-Exchange-Transport-CrossTenantHeadersStamped: CY5PR12MB6131 There is a need to access the inner value of a `Bounded` in const context, notably for bitfields and registers. Remove the invariant check of `Bounded::get`, which allows us to make it const. Reviewed-by: Gary Guo Signed-off-by: Alexandre Courbot --- rust/kernel/num/bounded.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/rust/kernel/num/bounded.rs b/rust/kernel/num/bounded.rs index d28d118abd8e..bbab6bbcb315 100644 --- a/rust/kernel/num/bounded.rs +++ b/rust/kernel/num/bounded.rs @@ -379,6 +379,9 @@ pub fn from_expr(expr: T) -> Self { =20 /// Returns the wrapped value as the backing type. /// + /// This is similar to the [`Deref`] implementation, but doesn't enfor= ce the size invariant of + /// the [`Bounded`], which might produce slightly less optimal code. + /// /// # Examples /// /// ``` @@ -387,8 +390,8 @@ pub fn from_expr(expr: T) -> Self { /// let v =3D Bounded::::new::<7>(); /// assert_eq!(v.get(), 7u32); /// ``` - pub fn get(self) -> T { - *self.deref() + pub const fn get(self) -> T { + self.0 } =20 /// Increases the number of bits usable for `self`. --=20 2.53.0 From nobody Thu Apr 9 10:29:43 2026 Received: from DM1PR04CU001.outbound.protection.outlook.com (mail-centralusazon11010003.outbound.protection.outlook.com [52.101.61.3]) (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 628E63DA5BB; Mon, 9 Mar 2026 15:14:37 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=52.101.61.3 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773069278; cv=fail; b=e4m7vy+LO51Kh6Ji4RpFpfT3yqhMj6+KbyiJE4YunS/Scpc2Z3G1hJ9MCyx2XlAl5P5atEpxzezF388x/NZuoAGVr343rw+PsJmhcW4Mivvs3CS2FaDm/UD+Vb//WtynYxc0CGKOrqIACLbmDTROLvFMGzp7FIxb36BUIYxBEIw= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773069278; c=relaxed/simple; bh=wUSIjD2YXoq+vf7Xi891tLazl7bTq6+pUjGSDbz+j34=; h=From:Date:Subject:Content-Type:Message-Id:References:In-Reply-To: To:Cc:MIME-Version; b=bmQDKMIkU0Xuqu0/ttGCCWJZXuyvF3wom+sO+a6xO+x/SCNYPL2VOzP1bZnNVcbPUQkLib0RiJKsjQ+mLso/V9uckPxjYWEI8DBuN/RNmrj1l5C7ON0iIxVonwo2OuEEPggeDtNvsCdbQ8jARXYgheeh48FbiEpWSM2GqgC8LVU= 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=N0DOYlKL; arc=fail smtp.client-ip=52.101.61.3 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="N0DOYlKL" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=jfcCRKOU7ZTMmNkVXeMEZgn9D2opwXh7eS+VFNBBwIDkdhQHnUbRws6h9m2Ecoip8b/6UMA3HX89DDqNS93GU+wosyG976C2NYbRCc14TUb6Z/HMpm/UsnbsimI3GTpdf8M0zmT/pnsRcJOnh5yo19euAS5ZDTMtldvpBcMF5QgQJJoPZ8VV+CVjSaU7iScfBwxa+zvLJXv4JEsJ/8t46VWgM9R7xDmrhbXUURYSnK+o1R3FdhS1Rx/JOlfiztX5BCA3HKbj3Prpsx+iBNrSUhOA81IaT+nBX0CXtqQXgv+JKbL5WZRYBMgeeD6rCgpkJ/Y3om9x15isQSuCh+XtAg== 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=cbvmRtvWm1CcO9vTzzaaiMMG7wVAMWq+MUfU42tONIM=; b=KtTZnCQbMegk40u2VGm0IV9P2/1LtPVECtYDe6QTU2iZTmqrqOEiL8jhKs8hScULpoiLJYWhq0IHqyTJa3jMQyAtmjxI7WVzRket1D1OSrdJtUlyh3f+lH9cduPSFMTnwZD7nVTwC4b3xMw5a+8MrdAhrOXxWWUa9jxR+Q9a1McptxoyGL+BAn2NgoEgaGzrRXYZpOozTiSvFcFmhzPOf7gmkMWCEur0J/wDENyZv3AiCw4XhcVYId2qwWT/vuqhSn9CGekgm26RY1CsRHSUdKhgJNZertfQctJaq3h58bmripZNz5fLaHp1+5u6BZ5RTlCD0Li1HKcOrv+KyAhC7Q== 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=cbvmRtvWm1CcO9vTzzaaiMMG7wVAMWq+MUfU42tONIM=; b=N0DOYlKLmiAUPxLFO2kxFMPuaISRS0jsrNyUQTEEnW/t00rrOmXSx63hIYda1OKF/i3mWuGkdgG8aSb8o94DQMSZaM6tkd9wXk+CmFCaPKnEnQQ+N94rYY/LWHEBRSRSQZbGap2u+MRaaLXVQSXsqwUnlJ7GDKnp42q6R+puG35AFBRXNgeLlN0sgUXNFPlYJNGb4x2v1jrY9nBZx5qC2mfPrXX0atFJZUFPpsvegr+3UQQiWtHsrV+t7VpOUdB3swm2eEbspRXbvDm/SeZRMicTwlN4ii4Uy8RmnJOItjeqUev//i9EDCiLwP9La0VqqvCRbu/LCilzNP2pJloqeg== 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 CY5PR12MB6131.namprd12.prod.outlook.com (2603:10b6:930:25::10) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.9700.11; Mon, 9 Mar 2026 15:14:33 +0000 Received: from CH2PR12MB3990.namprd12.prod.outlook.com ([fe80::7de1:4fe5:8ead:5989]) by CH2PR12MB3990.namprd12.prod.outlook.com ([fe80::7de1:4fe5:8ead:5989%6]) with mapi id 15.20.9700.009; Mon, 9 Mar 2026 15:14:33 +0000 From: Alexandre Courbot Date: Tue, 10 Mar 2026 00:14:02 +0900 Subject: [PATCH v8 05/10] rust: io: add IoLoc type and generic I/O accessors Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260310-register-v8-5-424f80dd43bc@nvidia.com> References: <20260310-register-v8-0-424f80dd43bc@nvidia.com> In-Reply-To: <20260310-register-v8-0-424f80dd43bc@nvidia.com> To: Danilo Krummrich , Alice Ryhl , Daniel Almeida , Miguel Ojeda , Gary Guo , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Andreas Hindborg , Trevor Gross , Boqun Feng Cc: Yury Norov , John Hubbard , Alistair Popple , Joel Fernandes , Timur Tabi , Edwin Peer , Eliot Courtney , Dirk Behme , Steven Price , rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, Alexandre Courbot X-Mailer: b4 0.14.3 X-ClientProxiedBy: TY4P286CA0055.JPNP286.PROD.OUTLOOK.COM (2603:1096:405:36e::14) 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_|CY5PR12MB6131:EE_ X-MS-Office365-Filtering-Correlation-Id: 727d041c-891c-4596-0cfe-08de7dee919b X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|10070799003|376014|7416014|1800799024|366016|921020; X-Microsoft-Antispam-Message-Info: frXi9zNASCUtXRH6vL1KzgEdvbJJ2p+bW14qYHT9DedqnhkEG6Nd9v7eptJ3bMisNMF70qr/BbhJdBSKZUcBY0x1mQ0QDUHeG1u7Tp7EiwEE8dMmKbA7WcpWwz9RzDaKCsaB0S/UJUDbceJ0Z/gxl/Cd60wW2I3Yj/lMO0cZIucz8E2SyiDjVbeCvkjDla1xfrAmvDukNcEiCmxZcvaDvivoEqNkhJRtmW1RMeiEjEwUt4VKQntoL3d+TKbSwN7jYbUog2NeuRa0jprfh8Kn1bekW/gjIHJyWxGjfPXv465xXjzq0eFXT4L2DmPBIrkpGtpMGlOkAs+aeVnzcSQDEr0mU5ZeBXAtpjnmNMiGCYqKA1ZWFNHVixNja5MnBc+6QEDAQPbYckP/AOxmqaGekoIjobb2yeRgTntLBsYRoppjLQM6ofvsV83FleaFnDEpJRHBMyH5mIFKLdKUJtceHMMWUltqCLU8Shv/7/uarNzjlyJf/vL11GuQjH784CSZ+5KBwDBM6bFP33QP69XA+hbaS6ovFRAfNByyoFqai74g+OOHqIwXw7YW1m+204LJZsHI3PXyYA2rZyz3M6JYPm4uVGhFT/osw/g41xXsO1wxHGR4GIzh6gjoW5GXyKhGykXmmQztRw8uO1ZvE7Bq95F+/5jh8R00TgN4dZKUyl+n1DVByO95y4i5uwXx27X2eY/REHR0w198y6r/3I53Hf0jYNs5/IiWejL68DPfcf5Gj58uHPLzj+rIxj9cjmq33ix+H1eexRSGb5YC0N6k2A== 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)(10070799003)(376014)(7416014)(1800799024)(366016)(921020);DIR:OUT;SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 2 X-MS-Exchange-AntiSpam-MessageData-0: =?utf-8?B?S2N0bW1jNWhGUFlQUGZIZzYvVkZuaXZTMjB4azgveTFVUHR4RHdRYjI4TU12?= =?utf-8?B?QTNSOEJlTFAxRGl0MkxQUTNubVpGZWdyb0ZHZkhjK1hxWSsraEtWalUrRDEv?= =?utf-8?B?UldSa2c4NUZuWk5JdzdoZEZia0Nwa1ovQUhvbStneWpDNFRiU205VHZQbHA4?= =?utf-8?B?YTNtbnJJVFZ0RTNMdHd2c3U4WjBIMDhvVXRKMUFCamJZS0pxU0NVdTJ5cisz?= =?utf-8?B?YnlPUXdqbUlNcncxblRVVnUxUlhPNmFQUk45VU5FUWFzYkRycWN3VWI1bWNZ?= =?utf-8?B?UHV2eWswZE5uNzdmMUhHcHp1TFZVN3B3aXBiSFVXanB0QUFvSVprNXVWaThP?= =?utf-8?B?ZExUZkdFOG1YK1N6cmhTUFFFUEpOK0dKZnVmcUE5Tm1BWW5NM2NaZmdFVFZB?= =?utf-8?B?ejlSM1F1SENnNmVvM0pGTjFVN2Z6ZTVMQ2Z1SkNlQ1B1bS9ZbTBYWERIQ0FN?= =?utf-8?B?RmdCNWs5RGFFTEpCR09telNucXJxTTEvSmkrL3FuSW9DWU1aRjNudVZhUDRw?= =?utf-8?B?blhCRWVadFZNTGpuYzhTc3B3VDBuejhMa0YvUzJBazE0OGNUeFVkR0h0YnhT?= =?utf-8?B?MHNEOEZDR29lNGNvdFo5MVh4eWwyT095Z2FNL0JMMjVYdHBDYStYZEZCNHlB?= =?utf-8?B?RHV4dHhBOENjMmcvREQzYnc2ZmF0NUF3ZTNhSHd1UVRobFIxd1c4UmtZV1d2?= =?utf-8?B?SnhZbUF3UDc4NVF5TG52RE9yelVET2ZVeG1KRGZneExXSDk5ME1CK21uWDBo?= =?utf-8?B?NjRiNDd2N1pzTDlNdXhDWFpuSzYxY3ZMTjFQSytRYktMaUtMQ2hhUXFXd09v?= =?utf-8?B?cUNGakhsWmQxTHlwK2VOM3hXcy93Nys4emhBK2tDSWUwR3pnV0RFT29RSDht?= =?utf-8?B?b2E0TnJoMTlUeTNJeVZWQkRoRE9ZQWJvazMxNnFKU2doZEVGQjV2ekVkaDQ3?= =?utf-8?B?MXpUVm0vSGZrTG5sWGJJcXZsM2JkTmtXRktYeWdEM0NYL2NpZ1owTGJ6MU51?= =?utf-8?B?NlR2anhjdVdsd1N3eE13S3NObGdzYThpYkFoTnR5TklrMjM4b2xubW5FQzUz?= =?utf-8?B?WFFJNUxIN3RoMmt3MkdtQXMxN3paekdhSVB2QTUzckMxTUNSaWVZbytMbkM0?= =?utf-8?B?QVczMzl3M28rM2pkZWx1bFVyNHk5SXdJSmhJSUVWY1hRTHQxNHcyMVlBRmRo?= =?utf-8?B?cDlERzI4VnBSUmRRaEwrMjZmTDE2ZlpxUGQvYXpOK2JmUHBYMjBpRE91VnVq?= =?utf-8?B?RTZiY09pK0QyVEFWQmFtK082SkkydVdPd0ZVbGhKYnBGN0tTSTAwWUx5S3Zs?= =?utf-8?B?ZGpMSENSWk0wNTUwcGdCNHU1QjFkNWtkTGYrNWdQMEJsbjQzbHg3TlFXU3p0?= =?utf-8?B?Z1FvN1FUTmZadmRTcFlLakNVdW8vSEhBUm9CNlJ2Z1lMVUkxNGVLRW1KNnZG?= =?utf-8?B?d0Q2WkJUT21nSThoWThHUVg1MEtKWnVUSmxDa3dpV3AvYkhDcm9ZNGtsOTZz?= =?utf-8?B?TmovMjE4THFrSVc1Y0VIY0pUTjVmdk5pbmhhenViV3k1NjVobk9wUG1wNSty?= =?utf-8?B?ZHRLMnN5Y1JGTXhrNDNxd01XelRSdEhCMm94YUdnOGw4TVhpV204MGtzbmpo?= =?utf-8?B?NDVWVWRSMHUvaVduVG5LdVFtbldUeHh1dm4zYktpaVEvUXh2eDAwY253SlRO?= =?utf-8?B?eC9vSnRkTE1aSnFqdnRyWUVNRkJ1Z1FxSGhQRDlIMXJjSlJTRmMveU00cHdJ?= =?utf-8?B?N0xiSnNlVFl4Qmc2RkhGSDNOa2gvWDdIc0RnRWRIbHBtakFWbDluNC9jb3VQ?= =?utf-8?B?eVNPVkQ4TGZIa2lVa0pvY2lrdW8zUUhzZi9CT1BMZERCTUhqQkkxYndTcGY5?= =?utf-8?B?YzBqbTY3ZVp2QTAxRGhPcVF1M1E4QUFWOEl2OGtXa29hczV1dU5oTzg4VVp1?= =?utf-8?B?T3RlM3hGaXUzb0M3MFZGOTNhcjlTT2daVjAvZDB1WXh4dGM1bFpHZm02aEJB?= =?utf-8?B?Q21ieW9hejdZQ1BUT3RVUVB4Zy81YUJIdE5FbEJtck51bGJpdVZtTVVkd1A2?= =?utf-8?B?dVFKOW9lTUo2VkVQMVRheEhlZ0dJZzJ0VnFRaHIrWndqaDBxZmZBM0hGNytK?= =?utf-8?B?NkJGYXVhT2VvRXlYaEh1eGNZaU13cmdZaWQweEJZM2hCZkJvRUp0Z3ZDYlhx?= =?utf-8?B?cmo0WWRtUzhtaDd3bjJsL1B3MlpTS09yb0tIUG9HcDhJbTlkSW9aeXYzV3dC?= =?utf-8?B?aE02OXQxV0JxRGpMY1l1c1hFQ2NIdzVBM0lmRnlhNGwwbE43cDhqaEdGQVl0?= =?utf-8?B?aldSV3VwOEVQdWVBTzFLQ09VK2taMXZCWXFWQUsrVFljRnBwME03bHFhSWgz?= =?utf-8?Q?rVwyqcYxfK31U3gdpAN0Y/IT4V5WS4tUp9n4Iy8Gz1h4+?= X-MS-Exchange-AntiSpam-MessageData-1: cym3+rEyweGHHA== X-OriginatorOrg: Nvidia.com X-MS-Exchange-CrossTenant-Network-Message-Id: 727d041c-891c-4596-0cfe-08de7dee919b X-MS-Exchange-CrossTenant-AuthSource: CH2PR12MB3990.namprd12.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 09 Mar 2026 15:14:33.3306 (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: YwLu56m2snQQa8zoOLfi6TwBrWefoWn/GSTEAnF+IhZj8ese9jusG/t69xZQ3GXhAS4wemBk4kkII3t2nsI0Wg== X-MS-Exchange-Transport-CrossTenantHeadersStamped: CY5PR12MB6131 I/O accesses are defined by the following properties: - An I/O location, which consists of a start address, a width, and a type to interpret the read value as, - A value, which is returned for reads or provided for writes. Introduce the `IoLoc` trait, which allows implementing types to fully specify an I/O location. This allows I/O operations to be made generic through the new `read` and `write` methods. This design will allow us to factorize the I/O code working with primitives, and to introduce ways to perform I/O with a higher degree of control through register types. Co-developed-by: Gary Guo Signed-off-by: Gary Guo Signed-off-by: Alexandre Courbot --- rust/kernel/io.rs | 124 ++++++++++++++++++++++++++++++++++++++++++++++++++= ++++ 1 file changed, 124 insertions(+) diff --git a/rust/kernel/io.rs b/rust/kernel/io.rs index b150743ffa4f..1db6572f4a42 100644 --- a/rust/kernel/io.rs +++ b/rust/kernel/io.rs @@ -173,6 +173,30 @@ pub trait IoCapable { unsafe fn io_write(&self, value: T, address: usize); } =20 +/// Describes a given I/O location: its offset, width, and type to convert= the raw value from and +/// into. +/// +/// This trait is the key abstraction allowing [`Io::read`], [`Io::write`]= , and [`Io::update`] (and +/// their fallible [`try_read`](Io::try_read), [`try_write`](Io::try_write= ) and +/// [`try_update`](Io::try_update) counterparts) to work uniformly with bo= th raw [`usize`] offsets +/// (for primitive types like [`u32`]) and typed ones. +/// +/// An `IoLoc` carries three pieces of information: +/// +/// - The offset to access (returned by [`IoLoc::offset`]), +/// - The width of the access (determined by [`IoLoc::IoType`]), +/// - The type `T` in which the raw data is returned or provided. +/// +/// `T` and `IoLoc::IoType` may differ: for instance, a typed register has= `T` =3D the register type +/// with its bitfields, and `IoType` =3D its backing primitive (e.g. `u32`= ). +pub trait IoLoc { + /// Size ([`u8`], [`u16`], etc) of the I/O performed on the returned [= `offset`](IoLoc::offset). + type IoType: Into + From; + + /// Returns the offset of this location. + fn offset(&self) -> usize; +} + /// Types implementing this trait (e.g. MMIO BARs or PCI config regions) /// can perform I/O operations on regions of memory. /// @@ -406,6 +430,106 @@ fn write64(&self, value: u64, offset: usize) // SAFETY: `address` has been validated by `io_addr_assert`. unsafe { self.io_write(value, address) } } + + /// Generic fallible read with runtime bounds check. + #[inline(always)] + fn try_read(&self, location: L) -> Result + where + L: IoLoc, + Self: IoCapable, + { + let address =3D self.io_addr::(location.offset())?; + + // SAFETY: `address` has been validated by `io_addr`. + Ok(unsafe { self.io_read(address) }.into()) + } + + /// Generic fallible write with runtime bounds check. + #[inline(always)] + fn try_write(&self, location: L, value: T) -> Result + where + L: IoLoc, + Self: IoCapable, + { + let address =3D self.io_addr::(location.offset())?; + let io_value =3D value.into(); + + // SAFETY: `address` has been validated by `io_addr`. + unsafe { self.io_write(io_value, address) } + + Ok(()) + } + + /// Generic fallible update with runtime bounds check. + /// + /// Caution: this does not perform any synchronization. Race condition= s can occur in case of + /// concurrent access. + #[inline(always)] + fn try_update(&self, location: L, f: F) -> Result + where + L: IoLoc, + Self: IoCapable, + F: FnOnce(T) -> T, + { + let address =3D self.io_addr::(location.offset())?; + + // SAFETY: `address` has been validated by `io_addr`. + let value: T =3D unsafe { self.io_read(address) }.into(); + let io_value =3D f(value).into(); + + // SAFETY: `address` has been validated by `io_addr_assert`. + unsafe { self.io_write(io_value, address) } + + Ok(()) + } + + /// Generic infallible read with compile-time bounds check. + #[inline(always)] + fn read(&self, location: L) -> T + where + L: IoLoc, + Self: IoKnownSize + IoCapable, + { + let address =3D self.io_addr_assert::(location.offset()= ); + + // SAFETY: `address` has been validated by `io_addr_assert`. + unsafe { self.io_read(address) }.into() + } + + /// Generic infallible write with compile-time bounds check. + #[inline(always)] + fn write(&self, location: L, value: T) + where + L: IoLoc, + Self: IoKnownSize + IoCapable, + { + let address =3D self.io_addr_assert::(location.offset()= ); + let io_value =3D value.into(); + + // SAFETY: `address` has been validated by `io_addr_assert`. + unsafe { self.io_write(io_value, address) } + } + + /// Generic infallible update with compile-time bounds check. + /// + /// Caution: this does not perform any synchronization. Race condition= s can occur in case of + /// concurrent access. + #[inline(always)] + fn update(&self, location: L, f: F) + where + L: IoLoc, + Self: IoKnownSize + IoCapable + Sized, + F: FnOnce(T) -> T, + { + let address =3D self.io_addr_assert::(location.offset()= ); + + // SAFETY: `address` has been validated by `io_addr_assert`. + let value: T =3D unsafe { self.io_read(address) }.into(); + let io_value =3D f(value).into(); + + // SAFETY: `address` has been validated by `io_addr_assert`. + unsafe { self.io_write(io_value, address) } + } } =20 /// Trait for types with a known size at compile time. --=20 2.53.0 From nobody Thu Apr 9 10:29:43 2026 Received: from CY7PR03CU001.outbound.protection.outlook.com (mail-westcentralusazon11010061.outbound.protection.outlook.com [40.93.198.61]) (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 24FA53DA7C3; Mon, 9 Mar 2026 15:14:42 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=40.93.198.61 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773069284; cv=fail; b=r8c8QTt1NhL8ezM/IOvLi3pfjA/18dDyJ9MFLcSvvzTKapRuuDkrx5z7JeKhOMxtNz4TI6gPoAiOfBkCyxRc08xmdvUAjTjJzLXzO+DyKeDwTOkhIwMu+HkvHldqwcec3Ypa12FrLq52/dF21jFpAx4LvhLusCNAVCMLjGjnvro= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773069284; c=relaxed/simple; bh=pPQS9lbrS7Dj4lAMmB+EItnkWUlmtHHvnIxH8l+aNF8=; h=From:Date:Subject:Content-Type:Message-Id:References:In-Reply-To: To:Cc:MIME-Version; b=jVfwNmrRMpIdPOwLJPgCP75KdlyRK5VSyIuwoK/dQ8UJBXbA0acOHCDYWs7MwUEhFd0+LgweVxbbAscKGtpO6lDXy1yT0mqpb4kafSs7KAZRYhrSHXuiA172AWfc6wxBwPoWn4LwdV7XYX2kCR+rf9381VX7tk1etYh39voYjv8= 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=jS4aqwXw; arc=fail smtp.client-ip=40.93.198.61 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="jS4aqwXw" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=PBOu+1vD6nNJ/SUV3g1y4hO/KNorfx+dREbw79rbBLrI5X4LJBNgNbE5ZbRsQIbkD14MYU5WemDZHTxNgFKD3hcb4oYpJVWw4l5dOSRaNp2uWuGZORuiHrVYhgHPfaesz7+4I5XrGrH0VdS39lYb7y/iGGf1CQNbm4tiAa6bkr5ac+4lY12GP3cJccJ7v+1WlkqtHQDLvEshhF7WKb5ckfC1hx1uQQi2/qN2U4AHH9g5QEAUJ/1teSI9Xsvz9js9oNPBbVzhTAf5ZkLlQg5JPtOi6pLpY3v1POiIzDonxeJm5/dPhxZNBN7Kg6Bwzw41O9fguESnl6YumCGathHqfw== 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=VoU6ThMforKVvi7iA3cbMKe8D4UDyjRSMXaBpWS+SAA=; b=dlMtz2lwvDTc+QT3hy6PXz/61ytPQ9z15n/n47vn5r88O1I461i3DaO6wO4ILw9c+ygXP7wBDdSg5DEMfiJvlZzkdf0f+dhwjJYkEJ+JL4jpvHluDqUf+JR4jBSaCou1AzidVIfaHREdwiWTYYiZcz30cdP9BuBSzmtaI2zZV6KfDouRy5EonpS5XkU9MW/Airpc2ia1/E98YHX9AnfXRYgPpZQUuT9fBvz8/UCGl/TTYeZ7coB4PXIBbSIHEsQBE9V3pkFIOxitc2nTqkqv/EZB9NmMi1nLi0J5Pj6o6Ft72jJxTj2GxrKXb3smRQdi+LE2YPgtdnsiEjfYSNAuDQ== 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=VoU6ThMforKVvi7iA3cbMKe8D4UDyjRSMXaBpWS+SAA=; b=jS4aqwXw5FwsUQ/f7YkaiA+3D7NKqve5dsFL6cFGdnJ0htEg3MQHVk7YXYPEQ9a3+3Y1YSlgVzpJUbW+L+tzkH1BiksBpZY+Y5iXX/XZeWr/w4QiAbazc1AK3q8xXIFM98FW2pUQBeh4UCo+LdlLNArhKJz6P7Iud+aqUyRQtO+zMBPrDR1Me/qvY6n92hN9Cfx7asftKC4pQiNKLCCHYFdMPOgsWvLZ0zuQwTkFQSKrI7u1cJWDMoZBSxfzBuT5H67wzPqYjqc2bXd84iiR0IMTx0gG7bLEIPEug/w5f9v7mpaecbD1T/wVWN2FT2TFuYHMV0lXiRO2uZhmSOvgzA== 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 CY5PR12MB6131.namprd12.prod.outlook.com (2603:10b6:930:25::10) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.9700.11; Mon, 9 Mar 2026 15:14:37 +0000 Received: from CH2PR12MB3990.namprd12.prod.outlook.com ([fe80::7de1:4fe5:8ead:5989]) by CH2PR12MB3990.namprd12.prod.outlook.com ([fe80::7de1:4fe5:8ead:5989%6]) with mapi id 15.20.9700.009; Mon, 9 Mar 2026 15:14:37 +0000 From: Alexandre Courbot Date: Tue, 10 Mar 2026 00:14:03 +0900 Subject: [PATCH v8 06/10] rust: io: use generic read/write accessors for primitive accesses Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260310-register-v8-6-424f80dd43bc@nvidia.com> References: <20260310-register-v8-0-424f80dd43bc@nvidia.com> In-Reply-To: <20260310-register-v8-0-424f80dd43bc@nvidia.com> To: Danilo Krummrich , Alice Ryhl , Daniel Almeida , Miguel Ojeda , Gary Guo , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Andreas Hindborg , Trevor Gross , Boqun Feng Cc: Yury Norov , John Hubbard , Alistair Popple , Joel Fernandes , Timur Tabi , Edwin Peer , Eliot Courtney , Dirk Behme , Steven Price , rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, Alexandre Courbot X-Mailer: b4 0.14.3 X-ClientProxiedBy: TYCP286CA0367.JPNP286.PROD.OUTLOOK.COM (2603:1096:405:79::14) 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_|CY5PR12MB6131:EE_ X-MS-Office365-Filtering-Correlation-Id: 3c3be781-cf02-4e81-132a-08de7dee93c9 X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|10070799003|376014|7416014|1800799024|366016|921020; X-Microsoft-Antispam-Message-Info: Bt7Ds2ZNNvioTNWpzcrua0+VBJgjsYGChM/+dr9jmOMJRy7c03XDK0xDuqDhZvr06917mkvpPvplQgpcctW+9m+f77Vb/mQnSDYnnxQFUXqBZ1WEnmD1Wv0FuaJibel9EpLPdJIdstt1QoMi9As9ieRoVn/+XTGOdCXgoheT+QGOCUc4ZGBYmf9wt8ozmMAEapwNj8tc1+AmAlGI9Xy+Z05uUj7v6vo44QTM6yFQ1xCJrk5tTbRsnXt6E09RmVb3Qc9l3whaIZylniKAT0U2kMcGYYAVGPxojW16g4hqmh4cMHxfMoh6sWo44ESoBHoemONbk69oymtUAkocGvhO19FK2nzI06dMdFfk4bljHQGU3ouUDKnW62DZRD6sCpZee8oc1idvtV4Euo2G+vngIi8ALNVATqY8d4UM1KUUvUbQnzYpgWDFCFOU/cu6uLRvYVOmcLhlUXKa08oNvUbrSo738Zd85RkkAVzWKI+h2dqiGpBEfu84bCZ8qLTAsmEPxTpimbDEg/XXh4aJ6ddTwfueAxJt0pc+OtGyhgzreG2vMkuUGrdlRomzqudawroNtSk4Er9/b/+RVfsACx2hNgY4TwF4sjO8pm50Rvmpe3PRcXaOV6H2yCJSlAbrlkpIR64zQhgT6GKkIvURg1J4LcDpJ9vpAo9QZ/eJ5saP2Maw6atJ/7FdvTMmh2fCWOBh5c+6E4FgCt/AhOlf3AOusaOzYR3p4YLKpX/615mmgwaImFvosFaweEBTQZrwAmssG5Z/rr75URl77t4YkCX65w== 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)(10070799003)(376014)(7416014)(1800799024)(366016)(921020);DIR:OUT;SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 2 X-MS-Exchange-AntiSpam-MessageData-0: =?utf-8?B?SDluaTh3MU5idlE2b0hKVHdsd1V1VUdJdCt0Lzk5b04yODFyUGtpZUl2YjRR?= =?utf-8?B?dnlOck90a3h5SGV2eitnei9NSWtBbGhRMEFPQytoeDZWdnlEeEdJcmwzNXhO?= =?utf-8?B?UEc3WUZvdmdtV0swREd6L3AzSG8xWTFjSThPc3JvQ0xNRXdtWFdXdXE1L09y?= =?utf-8?B?dWlOUXB5ajNHSkt4MVg4ek9adUN4VWg4SVJ1NWlFSHNKUGxndGpobzBoSUpN?= =?utf-8?B?dWJWY1VCMlRMMVpiWHJweWlOcmZoc3Z6ZmpEQlllaHpWNGVSSHB6UWU3Njgr?= =?utf-8?B?Mms5aUJsRDZVSzUyeUUxMVZHQVB4R3pLb1RqNkwrTExJcmE2R0dXUFhmZHdm?= =?utf-8?B?aUZMY2RTampEaG56Q2FoVUl0aUNEcFVFRTJ1bENERzBKdTk2NVAvclBlSmlY?= =?utf-8?B?dThmVmFIYnU1dVlncnU1V2Y3eG5XTVBMYjU2bEpZcFFoV3ZJNFhPaWFGQjhy?= =?utf-8?B?VGpkZURUcHdEdU4wQTg3aFpkTVhQK0VuejBzdHg5d25nRFRNYjRKa2t4NWwx?= =?utf-8?B?aW9GYlNGdTVHeE1QSkF6bm9NNnZqMHU4SFdUeEQzaDg3RWdaRGwrUXlkamZ4?= =?utf-8?B?MjhWZHRnRnh2bUtZY1VBR0ZkOGhCZDlxb0lJWHc2TE9rUlRsZjdaeURGc0hN?= =?utf-8?B?MHEwUzM4WlNZSHJlc0Q4Z1dBV0dkMWg1YzYwVlRGeWlPNTZjNkk4Z21yNk1L?= =?utf-8?B?dVVFZVB2RkphNVRuTzFwemVsQmttaDNNWGdmdVhDend1ZHkxT0J0Y1JUazNu?= =?utf-8?B?cHE1WW5pRDhJZHE1SHJiSVJ5V2JjU0NXWXp6SFBEZXVMUkNsWUNsWklVU0xG?= =?utf-8?B?YWFOcW5GOGYwYjZRbWNYWW91UmVjMm5FSktrWDVJbUlPdFBqUFVlcTZoVWxB?= =?utf-8?B?cEp6SjhpRVNIMXFBUHdreGE5RDdmN2krMWxhalNkWGx3MGNJN2hzTWtiMWRE?= =?utf-8?B?R2lwUjRPUytTMUZYakhqSFhXSENSZFJselhpLy9oL3c5cTBqbmlSWitGaVZm?= =?utf-8?B?OEZJeDkzcVg3aE5iUnN2QUdYeWZLMnZjOXYzZCt1YndIeUdOZFpSdUZlYXQw?= =?utf-8?B?WlMvN1JsWW82eWM0V0RpUlVkYThYc0tTQnhhNUZYS1Z6VGZTQlhWUWdNdUlU?= =?utf-8?B?cVM4dXRVM3p0bDA0eFZub3dJcStXeGxVUDYrR3E1S2J2ZjNETjM2UXRwWGJT?= =?utf-8?B?YWZmcW9OaUpUbFBqSlZkRVRMRG1QbnZFRmdRT09rekxVdU00RXRlYlVHTFNW?= =?utf-8?B?aHgyTlZQQTFRRmtOa2lNRzJ2Ymt4OURnZW9HclpLWDJTMU50ZU5POWs0SUtu?= =?utf-8?B?REhETjZQNmVwQm5PVnZFOHBidTVXZmxieGZ1UXVlOTYyQnYxTEZFaENpTWx6?= =?utf-8?B?UEk3M1hraGxmNVc3U2pULzJGQWNRaDk5VHNac1F0cFVWSFdBbzc4TFhJdjVr?= =?utf-8?B?QzFzazdNUDNFVitiV3c0Z3ZFOVFaeGRkS1R6QXBwSEJ5dGtrQjBxL0prbmV6?= =?utf-8?B?VHVKM0NETHZLckpiSjliaEM5U0lNNmljbmhYS3FQUUlPT2NObmVWZi83RkZ0?= =?utf-8?B?U2paV3p2Rmt0ZitUQ003Z2RVc0RLM1E1OWFSQmh5dFVrQ0VFRFdZRWhmam1D?= =?utf-8?B?RE9GajhZNGNhaVhDbjdkK2xJSGRjWVAvVWRVRE9WMDlMY0FpSktUSnZub2RQ?= =?utf-8?B?RkpLV1BrSnFEWlZyR2EwL1A1UjUwR3lGbm9URzdGTU9HRDlxZkN6cDJxb0cx?= =?utf-8?B?TkdoZkNRS2thazZtd1RmZURaL2JGSjlNNm5TMnJGbmNPOGVZQURYQWJQYmVi?= =?utf-8?B?ODFFRVNnciticXp2Z2FWa0NHeUZsUmxNVitMYmR6KzhDNDl4L1N1QU44OUdG?= =?utf-8?B?RzBlS293bG5QMlJ3N1RCczlWZ1IwSVI4WElmZVJwL2ZGcmd2N2hsSmlTbFJI?= =?utf-8?B?aXVaUHgxcngzemtVN0ZiMU9ZT0pFMUgxZDdlZ1pkR04rUzlYQWx5cXlQTk43?= =?utf-8?B?S2o0aVRIa1lXVlBHV2dCakNxMkFTSU9OZGIvS2Q2cGg5RVdEZmV5VkMvYWFv?= =?utf-8?B?Y3kwMlZKSXJTdXIrRUN2bzJvT0UzM0dLTmxCaThYVmlGQ2x6NmY5eEZFUkVZ?= =?utf-8?B?TkdpWnlyLzV0QW80bHBibGVNeElDSDZ4UktGK3lOcnkvVFB2TFZWTjN4NXpw?= =?utf-8?B?ZUl6RTRhV0pHZDk5empnNUFOSFVVYWxFU1VjbStrUVE5Vko0OU1hZ1V0WmJP?= =?utf-8?B?N1kzS1A2L2VSdlU5NEZ0QmlMZVk4RWVIUGxTbkRXdmZJL1d1d1kwRHh4bW9N?= =?utf-8?B?WlFLdEx6OUNzT0dhcHNSOEZJbE11TXNTdFAyeWZNOWFXbUE1RFliMUN0d3VC?= =?utf-8?Q?FdhOEFtib/eZCprEg0bTW5ADncqDVr9StPoGrbUVkEAEM?= X-MS-Exchange-AntiSpam-MessageData-1: FxzW+n3Fpqjwnw== X-OriginatorOrg: Nvidia.com X-MS-Exchange-CrossTenant-Network-Message-Id: 3c3be781-cf02-4e81-132a-08de7dee93c9 X-MS-Exchange-CrossTenant-AuthSource: CH2PR12MB3990.namprd12.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 09 Mar 2026 15:14:36.9642 (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: M7ILU+iJjGYiuUUJgeWR6vfyiQ6tLHNsE6hpxtrbCFpdcePNHBI3Z9JRxO2ZxeRi7nNJaE5hTq87Fx2jBDlr8A== X-MS-Exchange-Transport-CrossTenantHeadersStamped: CY5PR12MB6131 By providing the required `IoLoc` implementations on `usize`, we can leverage the generic accessors and reduce the number of unsafe blocks in the module. This also allows us to directly call the generic `read/write/update` methods with primitive types, so add examples illustrating this. Signed-off-by: Alexandre Courbot --- rust/kernel/io.rs | 199 +++++++++++++++++++++++++++++++++++---------------= ---- 1 file changed, 131 insertions(+), 68 deletions(-) diff --git a/rust/kernel/io.rs b/rust/kernel/io.rs index 1db6572f4a42..ed6fab001a39 100644 --- a/rust/kernel/io.rs +++ b/rust/kernel/io.rs @@ -197,6 +197,25 @@ pub trait IoLoc { fn offset(&self) -> usize; } =20 +/// Implements [`IoLoc<$ty>`] for [`usize`], allowing to use `usize` as a = parameter of +/// [`Io::read`] and [`Io::write`]. +macro_rules! impl_usize_ioloc { + ($($ty:ty),*) =3D> { + $( + impl IoLoc<$ty> for usize { + type IoType =3D $ty; + + fn offset(&self) -> usize { + *self + } + } + )* + } +} + +// Provide the ability to read any primitive type from a [`usize`]. +impl_usize_ioloc!(u8, u16, u32, u64); + /// Types implementing this trait (e.g. MMIO BARs or PCI config regions) /// can perform I/O operations on regions of memory. /// @@ -241,10 +260,7 @@ fn try_read8(&self, offset: usize) -> Result where Self: IoCapable, { - let address =3D self.io_addr::(offset)?; - - // SAFETY: `address` has been validated by `io_addr`. - Ok(unsafe { self.io_read(address) }) + self.try_read(offset) } =20 /// Fallible 16-bit read with runtime bounds check. @@ -253,10 +269,7 @@ fn try_read16(&self, offset: usize) -> Result where Self: IoCapable, { - let address =3D self.io_addr::(offset)?; - - // SAFETY: `address` has been validated by `io_addr`. - Ok(unsafe { self.io_read(address) }) + self.try_read(offset) } =20 /// Fallible 32-bit read with runtime bounds check. @@ -265,10 +278,7 @@ fn try_read32(&self, offset: usize) -> Result where Self: IoCapable, { - let address =3D self.io_addr::(offset)?; - - // SAFETY: `address` has been validated by `io_addr`. - Ok(unsafe { self.io_read(address) }) + self.try_read(offset) } =20 /// Fallible 64-bit read with runtime bounds check. @@ -277,10 +287,7 @@ fn try_read64(&self, offset: usize) -> Result where Self: IoCapable, { - let address =3D self.io_addr::(offset)?; - - // SAFETY: `address` has been validated by `io_addr`. - Ok(unsafe { self.io_read(address) }) + self.try_read(offset) } =20 /// Fallible 8-bit write with runtime bounds check. @@ -289,11 +296,7 @@ fn try_write8(&self, value: u8, offset: usize) -> Resu= lt where Self: IoCapable, { - let address =3D self.io_addr::(offset)?; - - // SAFETY: `address` has been validated by `io_addr`. - unsafe { self.io_write(value, address) }; - Ok(()) + self.try_write(offset, value) } =20 /// Fallible 16-bit write with runtime bounds check. @@ -302,11 +305,7 @@ fn try_write16(&self, value: u16, offset: usize) -> Re= sult where Self: IoCapable, { - let address =3D self.io_addr::(offset)?; - - // SAFETY: `address` has been validated by `io_addr`. - unsafe { self.io_write(value, address) }; - Ok(()) + self.try_write(offset, value) } =20 /// Fallible 32-bit write with runtime bounds check. @@ -315,11 +314,7 @@ fn try_write32(&self, value: u32, offset: usize) -> Re= sult where Self: IoCapable, { - let address =3D self.io_addr::(offset)?; - - // SAFETY: `address` has been validated by `io_addr`. - unsafe { self.io_write(value, address) }; - Ok(()) + self.try_write(offset, value) } =20 /// Fallible 64-bit write with runtime bounds check. @@ -328,11 +323,7 @@ fn try_write64(&self, value: u64, offset: usize) -> Re= sult where Self: IoCapable, { - let address =3D self.io_addr::(offset)?; - - // SAFETY: `address` has been validated by `io_addr`. - unsafe { self.io_write(value, address) }; - Ok(()) + self.try_write(offset, value) } =20 /// Infallible 8-bit read with compile-time bounds check. @@ -341,10 +332,7 @@ fn read8(&self, offset: usize) -> u8 where Self: IoKnownSize + IoCapable, { - let address =3D self.io_addr_assert::(offset); - - // SAFETY: `address` has been validated by `io_addr_assert`. - unsafe { self.io_read(address) } + self.read(offset) } =20 /// Infallible 16-bit read with compile-time bounds check. @@ -353,10 +341,7 @@ fn read16(&self, offset: usize) -> u16 where Self: IoKnownSize + IoCapable, { - let address =3D self.io_addr_assert::(offset); - - // SAFETY: `address` has been validated by `io_addr_assert`. - unsafe { self.io_read(address) } + self.read(offset) } =20 /// Infallible 32-bit read with compile-time bounds check. @@ -365,10 +350,7 @@ fn read32(&self, offset: usize) -> u32 where Self: IoKnownSize + IoCapable, { - let address =3D self.io_addr_assert::(offset); - - // SAFETY: `address` has been validated by `io_addr_assert`. - unsafe { self.io_read(address) } + self.read(offset) } =20 /// Infallible 64-bit read with compile-time bounds check. @@ -377,10 +359,7 @@ fn read64(&self, offset: usize) -> u64 where Self: IoKnownSize + IoCapable, { - let address =3D self.io_addr_assert::(offset); - - // SAFETY: `address` has been validated by `io_addr_assert`. - unsafe { self.io_read(address) } + self.read(offset) } =20 /// Infallible 8-bit write with compile-time bounds check. @@ -389,10 +368,7 @@ fn write8(&self, value: u8, offset: usize) where Self: IoKnownSize + IoCapable, { - let address =3D self.io_addr_assert::(offset); - - // SAFETY: `address` has been validated by `io_addr_assert`. - unsafe { self.io_write(value, address) } + self.write(offset, value) } =20 /// Infallible 16-bit write with compile-time bounds check. @@ -401,10 +377,7 @@ fn write16(&self, value: u16, offset: usize) where Self: IoKnownSize + IoCapable, { - let address =3D self.io_addr_assert::(offset); - - // SAFETY: `address` has been validated by `io_addr_assert`. - unsafe { self.io_write(value, address) } + self.write(offset, value) } =20 /// Infallible 32-bit write with compile-time bounds check. @@ -413,10 +386,7 @@ fn write32(&self, value: u32, offset: usize) where Self: IoKnownSize + IoCapable, { - let address =3D self.io_addr_assert::(offset); - - // SAFETY: `address` has been validated by `io_addr_assert`. - unsafe { self.io_write(value, address) } + self.write(offset, value) } =20 /// Infallible 64-bit write with compile-time bounds check. @@ -425,13 +395,28 @@ fn write64(&self, value: u64, offset: usize) where Self: IoKnownSize + IoCapable, { - let address =3D self.io_addr_assert::(offset); - - // SAFETY: `address` has been validated by `io_addr_assert`. - unsafe { self.io_write(value, address) } + self.write(offset, value) } =20 /// Generic fallible read with runtime bounds check. + /// + /// # Examples + /// + /// Read a primitive type from an I/O address: + /// + /// ```no_run + /// use kernel::io::{Io, Mmio}; + /// + /// fn do_reads(io: &Mmio) -> Result { + /// // 32-bit read from address `0x10`. + /// let v: u32 =3D io.try_read(0x10)?; + /// + /// // 8-bit read from address `0xfff`. + /// let v: u8 =3D io.try_read(0xfff)?; + /// + /// Ok(()) + /// } + /// ``` #[inline(always)] fn try_read(&self, location: L) -> Result where @@ -445,6 +430,24 @@ fn try_read(&self, location: L) -> Result } =20 /// Generic fallible write with runtime bounds check. + /// + /// # Examples + /// + /// Write a primitive type to an I/O address: + /// + /// ```no_run + /// use kernel::io::{Io, Mmio}; + /// + /// fn do_writes(io: &Mmio) -> Result { + /// // 32-bit write of value `1` at address `0x10`. + /// io.try_write(0x10, 1u32)?; + /// + /// // 8-bit write of value `0xff` at address `0xfff`. + /// io.try_write(0xfff, 0xffu8)?; + /// + /// Ok(()) + /// } + /// ``` #[inline(always)] fn try_write(&self, location: L, value: T) -> Result where @@ -464,6 +467,20 @@ fn try_write(&self, location: L, value: T) -> Re= sult /// /// Caution: this does not perform any synchronization. Race condition= s can occur in case of /// concurrent access. + /// + /// # Examples + /// + /// Read the u32 value at address `0x10`, increment it, and store the = updated value back: + /// + /// ```no_run + /// use kernel::io::{Io, Mmio}; + /// + /// fn do_update(io: &Mmio<0x1000>) -> Result { + /// io.try_update(0x10, |v: u32| { + /// v + 1 + /// }) + /// } + /// ``` #[inline(always)] fn try_update(&self, location: L, f: F) -> Result where @@ -484,6 +501,22 @@ fn try_update(&self, location: L, f: F) -> Re= sult } =20 /// Generic infallible read with compile-time bounds check. + /// + /// # Examples + /// + /// Read a primitive type from an I/O address: + /// + /// ```no_run + /// use kernel::io::{Io, Mmio}; + /// + /// fn do_reads(io: &Mmio<0x1000>) { + /// // 32-bit read from address `0x10`. + /// let v: u32 =3D io.read(0x10); + /// + /// // 8-bit read from the top of the I/O space. + /// let v: u8 =3D io.read(0xfff); + /// } + /// ``` #[inline(always)] fn read(&self, location: L) -> T where @@ -497,6 +530,22 @@ fn read(&self, location: L) -> T } =20 /// Generic infallible write with compile-time bounds check. + /// + /// # Examples + /// + /// Write a primitive type to an I/O address: + /// + /// ```no_run + /// use kernel::io::{Io, Mmio}; + /// + /// fn do_writes(io: &Mmio<0x1000>) { + /// // 32-bit write of value `1` at address `0x10`. + /// io.write(0x10, 1u32); + /// + /// // 8-bit write of value `0xff` at the top of the I/O space. + /// io.write(0xfff, 0xffu8); + /// } + /// ``` #[inline(always)] fn write(&self, location: L, value: T) where @@ -514,6 +563,20 @@ fn write(&self, location: L, value: T) /// /// Caution: this does not perform any synchronization. Race condition= s can occur in case of /// concurrent access. + /// + /// # Examples + /// + /// Read the u32 value at address `0x10`, increment it, and store the = updated value back: + /// + /// ```no_run + /// use kernel::io::{Io, Mmio}; + /// + /// fn do_update(io: &Mmio<0x1000>) { + /// io.update(0x10, |v: u32| { + /// v + 1 + /// }) + /// } + /// ``` #[inline(always)] fn update(&self, location: L, f: F) where --=20 2.53.0 From nobody Thu Apr 9 10:29:43 2026 Received: from CY7PR03CU001.outbound.protection.outlook.com (mail-westcentralusazon11010061.outbound.protection.outlook.com [40.93.198.61]) (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 CDFE83DA7D2; Mon, 9 Mar 2026 15:14:44 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=40.93.198.61 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773069286; cv=fail; b=PnXx7lTsP6sIBF60Vjn5ZJNWYRntscasu4yR2nppgEPyfxyNka0ncq3UzYWW6G6d0zB+ZKRkXg/nZJiRCANVF7OGZLrwNaQQ32pdELiDWKzld/xxRgIZl8ztMYMy0DTtTaZTdWNKJVAYPeHqc1BrD5yP7HcjiVYQWQyf6BczGXI= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773069286; c=relaxed/simple; bh=0BjgrF6bkB+OVqzBIQhnrAvYjKQpkCmh4w4YvmD2gto=; h=From:Date:Subject:Content-Type:Message-Id:References:In-Reply-To: To:Cc:MIME-Version; b=gu6dD877Lkkw9pjWgdY84qqRAXLMoJSTz9xC+OmlE2s2pIfq/r7M091Tp0uWyMMTPwIE03jXndrOt6bu4sd1JapdUWsumRBEiJqlmCF+9RdwG9mYSSxkvMDh+ih5CXHPxIoEzmo9D7yWF5TSZWpqw0VhT86IcaWveIzFv1Ve1aI= 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=TeFC4zYx; arc=fail smtp.client-ip=40.93.198.61 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="TeFC4zYx" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=u27M0QclgNeVS9+bWHo/VPLnRpPeNxtrhGZ1rDlbLU6Isl8MN4CcDdkEWN0NWdztV8S4uIkqL1JWJuQk+MKPVGd79XejNhJYvjW2QBZe9dLiTTzzT36sksGncMEMJZ/+nP9OFh5SQBW+9eNnex+iR/InMCR4BaeMOKL6jJl0aK+JAahhWiXQ5HLhIjyWwovwQO2U74297qfy4nlIIfdVMraTV+aeogZ6A/qMyJGV1sRq+g4iJG4xjWKau4oyw5xqxTUdddFVtdW3V43Su2quTbtw7wnn6UILtKt4vkdjPE3ZsjPHgjqPboErc8en3jlO1HKZaZXDa0jBPMH5F/F0ow== 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=5M9UYNc3SrS+Pmr8CpCBE2BqFPQDxrsmj77dU3U8lMc=; b=C1+7dn70+oojPxcdSzgWf5yZdZQE57xNx742k2eBLxnIZ83G2n1pDK9KEnK/BUofFu+aGL8tk/kPG6RoG/mK1eufAqP2hRj4d6hy3UoDzL0J5pEqHcHNDeegLw6FNxcPc/k+hh1UyjIQMiFIO//aYpmkh38Uz7/7lozPcS2oLtZnIOgXrarRSMiBPGvtiUjxKIp9eBJbgGaTqKv3IWla1jJn2VUHiRxRVvYUEwNdv5oUHBwjUGVk3ewaYfTGi6oWzXGsp/BHQVugDhp8il0lkqn5M+aEVMEihwQ5X0LoktSJo/Hgdp+QCwQE0azjUS/6bDcPmfvsN4vxKOqiWEHrjA== 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=5M9UYNc3SrS+Pmr8CpCBE2BqFPQDxrsmj77dU3U8lMc=; b=TeFC4zYxZlvqt3PE5c+8bBEeRigIt96GqXQskO++QNIOmRR3U+JkOYr9X8idE55zzWXVOn/n5QnvNNH+9ECa+FP65pBbwhr9RB0Na49ZXjVVqtK+xP2Q2itAAnM4bpXJM6b1IgAXAbbO6w9ux1Qew+miVxVmmt35nUrct7foAdmPachwVWLOniZSQ2QBfttub/IRNmBrL0xJUwUBBDGfXPEH74Ind7Ms4gEtxLYAiEhYfMqD6C94Zj8pEyrBnr+M81QX4tas7tvVh3BIKdZhbO1ikBxpW3fch4Jp+PYIeV1EZcespf1345C4k8Dx2QThJ9CLgoyAHsdhlyDK3mMq0g== 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 CY5PR12MB6131.namprd12.prod.outlook.com (2603:10b6:930:25::10) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.9700.11; Mon, 9 Mar 2026 15:14:40 +0000 Received: from CH2PR12MB3990.namprd12.prod.outlook.com ([fe80::7de1:4fe5:8ead:5989]) by CH2PR12MB3990.namprd12.prod.outlook.com ([fe80::7de1:4fe5:8ead:5989%6]) with mapi id 15.20.9700.009; Mon, 9 Mar 2026 15:14:40 +0000 From: Alexandre Courbot Date: Tue, 10 Mar 2026 00:14:04 +0900 Subject: [PATCH v8 07/10] rust: io: introduce `IntoIoVal` trait and single-argument `write_val` Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260310-register-v8-7-424f80dd43bc@nvidia.com> References: <20260310-register-v8-0-424f80dd43bc@nvidia.com> In-Reply-To: <20260310-register-v8-0-424f80dd43bc@nvidia.com> To: Danilo Krummrich , Alice Ryhl , Daniel Almeida , Miguel Ojeda , Gary Guo , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Andreas Hindborg , Trevor Gross , Boqun Feng Cc: Yury Norov , John Hubbard , Alistair Popple , Joel Fernandes , Timur Tabi , Edwin Peer , Eliot Courtney , Dirk Behme , Steven Price , rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, Alexandre Courbot X-Mailer: b4 0.14.3 X-ClientProxiedBy: TY4P301CA0029.JPNP301.PROD.OUTLOOK.COM (2603:1096:405:2be::12) 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_|CY5PR12MB6131:EE_ X-MS-Office365-Filtering-Correlation-Id: 431a1447-6698-4e29-62f8-08de7dee95ef X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|10070799003|376014|7416014|1800799024|366016|921020; X-Microsoft-Antispam-Message-Info: cXNuAX9AU+6aIfuscLNp0C7FRHxA0tab5gn2eJuwb/0ptiyndqtuMRi/DWuEGAOS8OlDH/sojhD8SOxBkcs9k5qhNABBhV5ayk2M3+NXC/Sbb0LuSmPcbH/xDg4QM6HmaU8JsN7bjBid04oz3HnRAi/U01oU2CtZeOCrTO7JM884FketmLoCz1+OxiVapMVe+DrkklSagGbl8fz/klYj0KRAI30Vs0kPWW8utPTO+TAcQgmDIsnrrVeq9SOjRlSKWiIAU5iNXdr18oMyrTzKD9XZz5LO2oEmjI8YxBEbepI572MxqXdf+FDnrqt5HTJFY2FxtQGabJwXdqw1ImjB32e5d4yyjK9ZgjwL4Adrhi63VLz6AtU70uU29H/lo88YeNqocziMVg5tYmtAztPzLyKxv1TWbhRfm6L7GamkLea35jbsOTcG5Fp7P+EHM3Kmpd/dHrAxoPVogjOsudNqi6aj4yS0zza2qZ0oenGi/HbeuePUY9W2casOi4QxpCJiBU6Tuj0qQouESCxEI1gn+E+fQqnVQtEyNYlSi4V05jJV3DQZJa61LnY1w+EZkURB0R94M/zNiCIBSLXXC6yAk5fICPYpzrkAVU15DsPta++lyP2RF3foa4RC5fu/34J1p9WcO4tXEn7JvNWWZFICTNpX5BWwl7mZ0kw7aezK8jLMh/Rfd+ISKt5pCv/XfoJhaeVTJ8ufXIVoFyGYJyKNLKZeKRFfuhk6p7z9uswUWPj8aNFe50Kq3470foHkkPGJDsvNQFD6aI04AyIgiNpqXQ== 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)(10070799003)(376014)(7416014)(1800799024)(366016)(921020);DIR:OUT;SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 2 X-MS-Exchange-AntiSpam-MessageData-0: =?utf-8?B?WWJBN2NvelhVV0R4ZUlrRS9vcEVhaVpMZ0VRK2dhQUJaZ29ST2JYekRNTWpM?= =?utf-8?B?U3NBdTE4ZjNHUm83MEZCZUR3NEtUcEFqOFV2cmxub2c2Q1NZcnJvTmJmSlFn?= =?utf-8?B?NnFHWjN0UnRvOXdtdzRBbGZyNlFKOHc5NVNxc3JOTVRISWpVRm04ejUzalRn?= =?utf-8?B?WTVURER6Z2ZmWkcwcXd0enU0K2JLVWlIU292UHJQVTNwb0hraDgweVFtUmpQ?= =?utf-8?B?bVZ1N0ZpZmh5dHZtdU1WR3dlOXBjYk5nY1JTMkpiR25uRVNxbVNhNjlLSCto?= =?utf-8?B?QmhSZDZoMUNidjFZQlRpNVJXcmJNNS9tUTFheHk3ZkhEWGRPNmFFS2p2K0xV?= =?utf-8?B?amY5NU9xTDBWSlhkMUI4blFLTFFoLzBPdVRJaVRpenRIWTYwUXBkQVFYT3N5?= =?utf-8?B?bmdsVHFVdHZQbmlOY0pJNnZOaDRTZWtMZ1VwMVU3UHNKOSswSE5YejI1VkY2?= =?utf-8?B?eUowVk04MDNycUV2SFFnZHlSamNORnRudjE0QjJvMkplcHN5QmRjNER2bVh4?= =?utf-8?B?R0NRSFJVU2pFNm9MV2FQRXRnclFnVHhUeDhTdWlZS2N4KzdRVVQ1NFZISGU2?= =?utf-8?B?Zk91Tnc2OWZOa0l6Wm5HcUMvMm1OM3NRMnBNVUpqSUliYk80Qkp6cXdmRGZQ?= =?utf-8?B?UjVCeTl6TWplTVQzYmtJeFVGcHlsbTlXWVgvYlE0cEhRVFo1eEJHQ3N2Wmdu?= =?utf-8?B?a0tWSTkxeldwOHhKOXJrNHRxOXpYQjc1RWxUVmNsOHBNRG1OL2ROUC8vSyt5?= =?utf-8?B?VFNsSjRKSXdiOTVWR1lNSjhTakRNUC94KzVuR0daRERoZ29IdVlwa0xvSzQ4?= =?utf-8?B?NmdRZVpwcFFSUUpPaFc0UkdmREpESXQ2c3pYOXh6YU9DNHBOUGltZjJhZTFK?= =?utf-8?B?aGNNN1NIcklPRzZqd3I5aU02YVp2cEdDYlhaZG1MVWJZRkRTMTdHWXdHNFJO?= =?utf-8?B?Q254Y3RKeG1xcTB6MHd5SEp5T1QxazdWb2h0ejcyOVlKL3hqRHNvbndNQnV3?= =?utf-8?B?a2RnSTZWNnQ5Ym4rV3ExbURvUGY5UGo4YlRsL1B0YTY4cXkwWjlKczdwdUlh?= =?utf-8?B?aTlsRlFBck42WGROTUlMUDg5aCs0ZkNpcElHOXNSQ1lkeHNERDI2UE83T1NO?= =?utf-8?B?YkNlMkJYYytiaG5PVko3YWI0Z0pDeDlEL3BNL0hlNmtKcStTYUNxL2E0SkxO?= =?utf-8?B?bloxOWVnWlREcUNkUU15bnhtUTh4OG5Kd3c1TU93RGQ5cXlaSWN4Wjk0Z3pI?= =?utf-8?B?cFI0U25HTys1OFBWaG1DQjJqWmRJSStmYk1CSGVBYUNnUWNXZGNBY3VMamZM?= =?utf-8?B?MXpkVGYwblBVVDZETG5FV3JGVTlQWjM0N3hkUkwySks2RmpnRGJsNS9HRyth?= =?utf-8?B?TjZHOFJZT2R5RXRvUVhyVWlqL2R2ejJnVjZqV01YNFZFVzV4c0tqRGtEVU5I?= =?utf-8?B?d3MvbndlMkFib2ROTG42Vzh1TGZSZFBtd3Ztb3YycTVJcnlXRUo2OVRtUUdV?= =?utf-8?B?R0QrSjF5WjR0aFFEZDdqQm9sWHJRTVRybnBIRzF2UGhmd2VCUElRRndkMmhz?= =?utf-8?B?RnllV3FuS211N2syNC9lSFY3MlR2bmZsQzM2eXkwU1V5Y3JFUUx2aDJON2RT?= =?utf-8?B?OWlTZmVqOE1VMGNWRGxKWEdtYUcxZXIyMDRXdXh1Ylp2TldWb2Q1Qmlmc25l?= =?utf-8?B?SmZ2V29OTjVvT09jZnpPY25KTERvSVgxdWZTMmxHOU0xNFB1eW5XQzJaZUI0?= =?utf-8?B?a25PNlVaN1A1aSs1Q2FjL2V0eDl4K0FtbkNyRUlYR3FXYlR4NVJoZyswNVFP?= =?utf-8?B?YjE4dXdEMW1zSWJyNGplaWczNnVJUklHRmdqRGdHenhVZm5xRndOQnkwVVUy?= =?utf-8?B?ZDNUM1pvbFVvaGlTcGZDOUhIcUd0aFlkUjVqTkZ6MWJuUUJHS0lWQ1ppOEt3?= =?utf-8?B?dUM2R0xVY0ZRVDBCMGdOQkVXNWg1aGhYSy9adkZaRzBGTlVVK0F5TmNXTjF3?= =?utf-8?B?dldwQkgwazZaaldzNmFESHo4M0xyTWRUVXpmK2d1dEM1SGtqR3BVdjEzaG1j?= =?utf-8?B?eUhCVnhpb0ZrejFsbnB3cWJDRTFFRGkwZWFUSFRFWWI3OE9QREhKVjgycHZu?= =?utf-8?B?ZHp1dnJjRFVYdTQ2V1N1VkM2Q3MxcTc4KzFXanVEQXNqd29WQ1N1ekp3ZU84?= =?utf-8?B?bzgrMHo0Y3FFYzN5L0VnL2d1d0JqMExwYkoycEYyeWNRSlhEeXJwZCswenoz?= =?utf-8?B?endnaHV2bG9XTUZhckZRUjJLYjJnNkJKZUg3R1o0Qk9MbkF2ZGdlUis4QVRM?= =?utf-8?B?OExTWit0YjdVMUQzQU9neFVZd3Y2QkExdEZFbEczUlE2bEhUcDdKaklOcjMy?= =?utf-8?Q?awA/I5Wv3+F/eG4nf2c6oFPOb1HFXpN1dt4BmDykBe6nj?= X-MS-Exchange-AntiSpam-MessageData-1: c6sbDidJSylFMA== X-OriginatorOrg: Nvidia.com X-MS-Exchange-CrossTenant-Network-Message-Id: 431a1447-6698-4e29-62f8-08de7dee95ef X-MS-Exchange-CrossTenant-AuthSource: CH2PR12MB3990.namprd12.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 09 Mar 2026 15:14:40.7378 (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: 10eTFVK3Q+2h+eHELaYczCArKrqZC8OU7jOjDxIcTkKJCtcf/+oqZahlgm+UxjhG77SRBKBRgXGGe7rif8sulw== X-MS-Exchange-Transport-CrossTenantHeadersStamped: CY5PR12MB6131 Some I/O types, like fixed address registers, carry their location alongside their values. For these types, the regular `Io::write` method can lead into repeating the location information twice: once to provide the location itself, another time to build the value. Add a new `Io::write_val` convenience method that takes a single argument implementing `IntoIoVal`, a trait that decomposes implementors into a `(location, value)` tuple. This allows write operations on fixed offset registers to be done while specifying their name only once. Signed-off-by: Alexandre Courbot --- rust/kernel/io.rs | 68 +++++++++++++++++++++++++++++++++++++++++++++++++++= ++++ 1 file changed, 68 insertions(+) diff --git a/rust/kernel/io.rs b/rust/kernel/io.rs index ed6fab001a39..09a0fe06f201 100644 --- a/rust/kernel/io.rs +++ b/rust/kernel/io.rs @@ -216,6 +216,22 @@ fn offset(&self) -> usize { // Provide the ability to read any primitive type from a [`usize`]. impl_usize_ioloc!(u8, u16, u32, u64); =20 +/// Trait implemented by items that contain both an I/O location and a val= ue to assign to it. +/// +/// Implementors can be used with [`Io::write_val`]. +pub trait IntoIoVal> { + /// Consumes `self` and returns a `(location, value)` tuple describing= a valid I/O write + /// operation. + fn into_io_val(self) -> (L, T); +} + +/// `(location, value)` tuples can be used as [`IntoIoVal`]s. +impl> IntoIoVal for (L, T) { + fn into_io_val(self) -> (L, T) { + self + } +} + /// Types implementing this trait (e.g. MMIO BARs or PCI config regions) /// can perform I/O operations on regions of memory. /// @@ -463,6 +479,32 @@ fn try_write(&self, location: L, value: T) -> Re= sult Ok(()) } =20 + /// Generic fallible write of value bearing its location, with runtime= bounds check. + /// + /// # Examples + /// + /// Tuples carrying a location and a value can be used with this metho= d: + /// + /// ```no_run + /// use kernel::io::{Io, Mmio}; + /// + /// fn do_writes(io: &Mmio) -> Result { + /// // 32-bit write of value `1` at address `0x10`. + /// io.try_write_val((0x10, 1u32)) + /// } + /// ``` + #[inline(always)] + fn try_write_val(&self, value: V) -> Result + where + L: IoLoc, + V: IntoIoVal, + Self: IoCapable, + { + let (location, value) =3D value.into_io_val(); + + self.try_write(location, value) + } + /// Generic fallible update with runtime bounds check. /// /// Caution: this does not perform any synchronization. Race condition= s can occur in case of @@ -559,6 +601,32 @@ fn write(&self, location: L, value: T) unsafe { self.io_write(io_value, address) } } =20 + /// Generic infallible write of value bearing its location, with compi= le-time bounds check. + /// + /// # Examples + /// + /// Tuples carrying a location and a value can be used with this metho= d: + /// + /// ```no_run + /// use kernel::io::{Io, Mmio}; + /// + /// fn do_writes(io: &Mmio) { + /// // 32-bit write of value `1` at address `0x10`. + /// io.write_val((0x10, 1u32)); + /// } + /// ``` + #[inline(always)] + fn write_val(&self, value: V) + where + L: IoLoc, + V: IntoIoVal, + Self: IoKnownSize + IoCapable, + { + let (location, value) =3D value.into_io_val(); + + self.write(location, value) + } + /// Generic infallible update with compile-time bounds check. /// /// Caution: this does not perform any synchronization. Race condition= s can occur in case of --=20 2.53.0 From nobody Thu Apr 9 10:29:43 2026 Received: from CY3PR05CU001.outbound.protection.outlook.com (mail-westcentralusazon11013042.outbound.protection.outlook.com [40.93.201.42]) (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 292883DA7FD; Mon, 9 Mar 2026 15:14:55 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=40.93.201.42 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773069298; cv=fail; b=PLc8pML2I5OBTPrB53cp6WFIrW9hHkz56zC+yL2FctaHRoi959o/2hruSrTc043YPpVikfexD4aBmn01Jkaa3diJJs9vNWQ1F4xXRMSCwu1eeUZ9uQqI6b5LROw0O3OaTC5iL3KxYcM2qOsFRcv8FHBpb8fKYXwxkpkjbdkIxJk= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773069298; c=relaxed/simple; bh=BodgAetG2B4y2LnJF1XiWNiNI2FxUYECNF4QSH2lppQ=; h=From:Date:Subject:Content-Type:Message-Id:References:In-Reply-To: To:Cc:MIME-Version; b=d8V7iWQ9O0i445pbFJRrkY+0G7uAiNYvjIRyitCdL2OmoCAHwE00vsEeeIfFtJucdTkUKeTgmDkXuQqDhqE7Ama3J7fgUPNWDCaFoqq9135ifaTpFshK9zAedq8aA3ityCpqRr9x0Q7CiZGoG4PyBvTeqIkbG6us/3hs9coUcNA= 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=a1At++0s; arc=fail smtp.client-ip=40.93.201.42 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="a1At++0s" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=pT/mQ9czf5lwNHPgNLfroYaQy0NKF+fv7O3+cKj+OOkCQocXRuYspisUq2iHIxZEaZw9I14KXyQHa2UeO5MclCyL5nLHyRRl2WjR8LfAuzoHxTWICgE7eoXL9LbK3B7EiCGSiT3h4q4QeC1YJtBN0kedwepCqGyclCQv0OR9KH3zgKkbkyeoLrtYID0nKsP1k4z6veBgx1hayS6NwE5z1ErfSMT2f9ST3A3Vyp0SU/YmyA/ETHvYDL4YBVw0VN0E82lEa46YcFIAvTjASH65FAveL4c9SFPPWkLwjg2ThOnkMF/3gRXYAO/7/7bVkQoGNu7aB9HkPEKkxAkONP3grA== 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=X8v00QVw5WJhho2Bvj5kSnMzvY6qfkp2uvC929FuqLI=; b=Ad5slekDSd1krOiwe4qJrK7NupJwAc9prU6BjvxzW7VDwi9Eyn7va+3KXnWrFCg9Ma68OOOgKgfuXyIxVP56/W8cecJmIH5mwmfDLWjVFPuyedIc373tMfhDnmHYSGnMwpy0SAk1Exn+C2DXLcJ/lRXjnWcNbbxf07uXs2mvmk2BCqEeNr/OpUhF6DUCBxgrVsZCedej36hVsNvmM/ozIHIrsGgnE5LtosYNLWA2QrVPeBz98igfLTwpXUHw6zZ1J2Q7/V/BIfjwpUAz7z9HYGj/GqZOs7WKhDB3onPrtu9XYuo7XGrEe5RUPGpf0t4JSlQpgYppZ31IMG+FEHJGqQ== 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=X8v00QVw5WJhho2Bvj5kSnMzvY6qfkp2uvC929FuqLI=; b=a1At++0sFIws48ZPWfZ8DQSGfhiQ9wAUnn+zIyRhTq2LkJQxcfB3fyj19Rd8aZ9860XjpFDXUBLuqJ4GyjLLrqqRPGtlDSeD2l86oWPebZbpXMergpE8kAdb+qMhq0QnWvEJM8FmDPCYQGzbx0xzrxqCxW5ZNN0aIOxAV6wtYjLlh/qGiT1wA1Z4NX9R1OF8ZmIxjHF5VtSmBVFkZNF+9Fxeg1kMOnb5lckHVZ2x6I69GpdhYaxIBmqHwcL+Pzn2mtgG4vgKsphmvgFoPjPrvHqZKIOQWodv7zO4VEEE4Bn9+iUmIuaD77OsalQDcuh1sAdlOxDM90caw0++qufwaQ== 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 CY5PR12MB6131.namprd12.prod.outlook.com (2603:10b6:930:25::10) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.9700.11; Mon, 9 Mar 2026 15:14:47 +0000 Received: from CH2PR12MB3990.namprd12.prod.outlook.com ([fe80::7de1:4fe5:8ead:5989]) by CH2PR12MB3990.namprd12.prod.outlook.com ([fe80::7de1:4fe5:8ead:5989%6]) with mapi id 15.20.9700.009; Mon, 9 Mar 2026 15:14:44 +0000 From: Alexandre Courbot Date: Tue, 10 Mar 2026 00:14:05 +0900 Subject: [PATCH v8 08/10] rust: io: add `register!` macro Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260310-register-v8-8-424f80dd43bc@nvidia.com> References: <20260310-register-v8-0-424f80dd43bc@nvidia.com> In-Reply-To: <20260310-register-v8-0-424f80dd43bc@nvidia.com> To: Danilo Krummrich , Alice Ryhl , Daniel Almeida , Miguel Ojeda , Gary Guo , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Andreas Hindborg , Trevor Gross , Boqun Feng Cc: Yury Norov , John Hubbard , Alistair Popple , Joel Fernandes , Timur Tabi , Edwin Peer , Eliot Courtney , Dirk Behme , Steven Price , rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, Alexandre Courbot X-Mailer: b4 0.14.3 X-ClientProxiedBy: TYCP301CA0003.JPNP301.PROD.OUTLOOK.COM (2603:1096:400:386::9) 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_|CY5PR12MB6131:EE_ X-MS-Office365-Filtering-Correlation-Id: 65b4d3fa-0fb3-4f63-a188-08de7dee9851 X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|10070799003|376014|7416014|1800799024|366016|921020; X-Microsoft-Antispam-Message-Info: jZjbOwpPU3KXCV+3Gwo7xwLyHtDwwX9EaPi9Y8B856pIBDs7nm12eCUby+aWpu9dEqqovDnFu1BB4Ax2Fbl8f99VhDXO6hwVidafRZqIQqhN6oFaaG5Kytxo63Ju6bqpD8ArwaM3X5mGYrwXslciXPZ3bdBcfvVHEWAjClZL9C1GCsCNlvfic7oIjpz/01hv4+KS4Elw1gZ49HVy0rxHW+8YXiFxold5IfPAKtVuu1TKZF8LmoDLNTLbQgbXeOApGTliLx7J9/Pch85E+a/WTDVBM1oOtenMXK5ziCDk3n6MjgbpGsuGHSGeB5B64XTmwzSYgMl4oyKuWMCuq6hK88OA3fUwy6Nrsfqcz5nbTKv921g02j0E10FpP2kdB99a4yqEhBCm3GBFCUshOU4rBYYKx/cCvZHo0REXevD3leKaRQjt7XbyqJoJcnz8EcZSadyEOTyX8rg2ZDbGoW2j7CawWbKTtPJhoVHX+20R3rkgxkGEwY31hFQA55aNPcrxf2VcNlWttTaK7uwuhkaRX9NyJ+vEr3pcygT0FikFL9kc2wPh64c6IHO5s7PXBVXz11QPyGIqAoUSIAh/ElQ5rwPd2SBIcTx0Yy4roxjfGHmZGH8bWwYmTcxUz+EGdh7l+C41iu7lXAtOCWvMdcp9lZixgxZGbsIhTmJRI6T9Fd69poQIFjJtshKT4ag6/SEY0tBWlyK3v1spYxFAkWSU2yDs4yvSV56FgAGeFKs/rApNk3qTsnRNrbK5Ao5D4KPlUhLcILURxSTtEO6LMcd1ZLO9eLP/s8EaVIhmG44IvgM= 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)(10070799003)(376014)(7416014)(1800799024)(366016)(921020);DIR:OUT;SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 2 X-MS-Exchange-AntiSpam-MessageData-0: =?utf-8?B?aDhNclhzUVlWQm4rbGVyR1JKSmFnUmpMczNLRGdMRG0yRHF3dEwzc0QwWVN4?= =?utf-8?B?SVVPU01kdjdNSWl5cUI2em9EeERaWUV2Q28xcGZZSFZlTlNWTlh6R0xOUm85?= =?utf-8?B?MUh6RCtyM3RvZ3JoRGFSSk9OTGF1aHJFRHJOMUZ0QTZoekE4M3JidGlVc3Jt?= =?utf-8?B?c1NPQXNZT1VLZVhEbm5CdEJNQmQzdDh0Kzh3YkdLa2ZDQVpLT1hGQzUvM0xK?= =?utf-8?B?ODRnSXZVdEgvblc2azc1Tk52NGJpSWY5UkRjNWV6S1pPTUx1UkE4aUxPSG1s?= =?utf-8?B?K0NnSzZUN2I2Q2U3aTNkYW5oaExYcTFCSjRxeFBaSUd0Q0hYR2tVUm1oNlpJ?= =?utf-8?B?SDlkK0JOYXZyZ21iK01tN2N4Tm1yNjlzUWtsUDFCMk1veG1QMEZWSVZJMTdH?= =?utf-8?B?WldlZUk5d2VCbHlxUmZuV1lsVGtLUURLT2NRb0xZUHBjaUQ2c1JIaFdQN0Ns?= =?utf-8?B?TnBMYWlhbVpqRW5PMmlKbklESFFCV3liVERidHlCUEtyTzRXYll6dlIvVGUv?= =?utf-8?B?OXBqcXlKSXQ3TVFSdlo5WmpVd0E2dWlwNTZ4Q01abXBKbGdxSXJya0g4R2RK?= =?utf-8?B?cXBXQm1tcG01aWF5VWptU2Z2MXRaZVl3MW9JOUd3L3VRUkFBR01PbC9KaThv?= =?utf-8?B?VWZaYnM1Nnp5WHI0TlVDdXBTQ25kdzBKM1VtNHhaWi92NitrNjJURDhlK1VC?= =?utf-8?B?cUJRRVRYZUZRRVNoc0ZDUnRvTmFRRkJZMkNqR1owQWZZR0NlNGtubU9QR0ZU?= =?utf-8?B?L0NqcHNxNU9hTURFRHN2WkVhUFBkMDQvc01TeVpGUDBFZ1V3VFJnbjFJT2Fo?= =?utf-8?B?MHJVRVFHNjhFMWcwNzhMMEp2L0pqUzJOeWRUS0JYOUFoUXhKQVg1UUFhWThD?= =?utf-8?B?UnlMak80SWNaZmdhMUpMdkR4ajZPL3VsejlhUlUydmdwcy9UQ3gzQmtCQjFa?= =?utf-8?B?SUZOdHhtZjlhTGk5a1dPcGNBd3J0Z2VrR0dzcW53YzdWY1RZN3ZacnlXbzhW?= =?utf-8?B?aEtOdmo1NFJBTlA5bkt2ajlsbUN2Z0R1QmlhWmtPZDVxUE9oZWtyUHd2QmY5?= =?utf-8?B?M2FSQVRGWExGTHBEcSsweUhvNVdZSHFMRVVxRGlhQmdMUkVDZE9GcFNrWHA4?= =?utf-8?B?d09aWmlrRUs5QU1paXNTNVA2MmdZYWJqNDFORW04RUNxM0M3N2pUdEJ0T0Zp?= =?utf-8?B?T1JDQ3BqK2tvTXhrY1hoRGZPT04vcWdsNlAyV0tzdnNacXFyOTVCaSttR3dB?= =?utf-8?B?SEp4dXdxMXZGR2o4Z0U4T1JmTnVMdm94djhHcDZPREFaTi9jOXpKb2xhUzZQ?= =?utf-8?B?TUJnNldGYjdzZFpYcC8wbFNQRHpzZ1lWZzl3YUhqalRaTnQvVXAydE5abGxN?= =?utf-8?B?UFZ6djNtK2VrYTVhU2g1b1hsbTY0Ylh4L1dkWFZLc2JsMGpENkdnbHJRRFdn?= =?utf-8?B?T3FENzd2QUZCeCtud21wbWtKUk1OZGIySnVxVkZBcWJ6SlZ1V3EwKzQyM1RQ?= =?utf-8?B?NVM0OVNXYTlmTFBPYno5Rkt4N096d3ZyZDZ4UkpFWUFtNHZwVHZvMzV5bnBQ?= =?utf-8?B?Ry9teGY2U3orQTRrQi85Mnc5VS9QTFFkRGxoMTh4anVKM2FYTjhhNVROc21N?= =?utf-8?B?RHhQUUdVM2tuVU55eU1HalB1N3FuUk5nOUo5a1VYNHJBRkNUZy85Ujd1OTg4?= =?utf-8?B?b09qem1pVit3NGpXYWlVb3M1YXhlclJycGtpTThOTjJ1Mmw5YjcrQS9JaENF?= =?utf-8?B?eTRFT3RQYnpjSXk3Z1hScGQ4ZDlabElJSHdkK1pQSXlrbUZJZzBCN3pEd1Yy?= =?utf-8?B?WXRsb1FGVGJjVlVMNktIRkl0QlJYNjdhRjNXOWpEdmpMWmZOaWZzWnVhUnVk?= =?utf-8?B?U1ZsUldGcjFSVzBHcXh6UU5rNTVHd051a0JuQkRkREVZejdNSWhuNWVDNktz?= =?utf-8?B?M2ZXcTZ3bkJlZVJwWGF2SXBaRTh3STMwMXZOTjREVmdtWWNKZjN0TWd2Qlcv?= =?utf-8?B?N1huUlN3UjVBRWRnVHd3V29nM2FZLzVHMkVUMWdZa1gyUVpzWGlVd2c5YVN3?= =?utf-8?B?S281TzZpTk9mYmJNemFQdUJnNzhPbFBtTGt2dUF2UFVsTks2ZHJFbFJJb1F2?= =?utf-8?B?WHlSamtXNlgxY2JHbjVMblloejBQOXZXbkhheUZ3SHlKUkJTWkdGY0VDMTJ1?= =?utf-8?B?dlpWNmpPVWVKMWVqUVJtWWh3YW9ObUpKQloydFF3WHVGUFJXeUxveW16MWJv?= =?utf-8?B?b0RLd3F4NzBsNkpSRlphQ3hyc09Hb0gzUVREaEJ4WE5lRUg4OWgxcjZuTXli?= =?utf-8?B?RURQWlQxL1liWEwyK1daZDRyRUtvM3JWdkdJeklTSkpnMjZLWXk0MUZUd2E2?= =?utf-8?Q?JA7caIEyvxIog7xxdPAcw9JIjE8eSW4+bF3jlrzGK4wDA?= X-MS-Exchange-AntiSpam-MessageData-1: suPbuziyglOtBw== X-OriginatorOrg: Nvidia.com X-MS-Exchange-CrossTenant-Network-Message-Id: 65b4d3fa-0fb3-4f63-a188-08de7dee9851 X-MS-Exchange-CrossTenant-AuthSource: CH2PR12MB3990.namprd12.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 09 Mar 2026 15:14:44.7258 (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: /PwSgfG31XqQcDMcONianik+OQxJ1KaWcDmpqQh4/NRgGV931OipKIIM52C+g7WEVPycnLt6NjQIh7cfRzWXyg== X-MS-Exchange-Transport-CrossTenantHeadersStamped: CY5PR12MB6131 Add a macro for defining hardware register types with I/O accessors. Each register 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. The address of registers can be direct, relative, or indexed, supporting most of the patterns in which registers are arranged. Suggested-by: Danilo Krummrich Link: https://lore.kernel.org/all/20250306222336.23482-6-dakr@kernel.org/ Co-developed-by: Gary Guo Signed-off-by: Gary Guo Signed-off-by: Alexandre Courbot --- rust/kernel/io.rs | 6 +- rust/kernel/io/register.rs | 1190 ++++++++++++++++++++++++++++++++++++++++= ++++ 2 files changed, 1195 insertions(+), 1 deletion(-) diff --git a/rust/kernel/io.rs b/rust/kernel/io.rs index 09a0fe06f201..bb58a77fd055 100644 --- a/rust/kernel/io.rs +++ b/rust/kernel/io.rs @@ -11,6 +11,7 @@ =20 pub mod mem; pub mod poll; +pub mod register; pub mod resource; =20 pub use resource::Resource; @@ -179,7 +180,8 @@ pub trait IoCapable { /// This trait is the key abstraction allowing [`Io::read`], [`Io::write`]= , and [`Io::update`] (and /// their fallible [`try_read`](Io::try_read), [`try_write`](Io::try_write= ) and /// [`try_update`](Io::try_update) counterparts) to work uniformly with bo= th raw [`usize`] offsets -/// (for primitive types like [`u32`]) and typed ones. +/// (for primitive types like [`u32`]) and typed ones (like those generate= d by the [`register!`] +/// macro). /// /// An `IoLoc` carries three pieces of information: /// @@ -189,6 +191,8 @@ pub trait IoCapable { /// /// `T` and `IoLoc::IoType` may differ: for instance, a typed register has= `T` =3D the register type /// with its bitfields, and `IoType` =3D its backing primitive (e.g. `u32`= ). +/// +/// [`register!`]: kernel::register! pub trait IoLoc { /// Size ([`u8`], [`u16`], etc) of the I/O performed on the returned [= `offset`](IoLoc::offset). type IoType: Into + From; diff --git a/rust/kernel/io/register.rs b/rust/kernel/io/register.rs new file mode 100644 index 000000000000..153ea779b244 --- /dev/null +++ b/rust/kernel/io/register.rs @@ -0,0 +1,1190 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! Macro to define register layout and accessors. +//! +//! The [`register!`](kernel::register) macro in this module provides an i= ntuitive and readable +//! syntax for defining a dedicated type for each register and accessing i= t using +//! [`Io`](super::Io). Each such type comes with its own field accessors t= hat can return an error +//! if a field's value is invalid. +//! +//! Most of the items in this module are public so they can be referenced = by the macro, but most +//! are not to be used directly by users. Outside of the `register!` macro= itself, the only items +//! you might want to import from this module are [`WithBase`] and [`Array= `]. + +use core::marker::PhantomData; + +use crate::io::{ + IntoIoVal, + IoLoc, // +}; + +/// Trait implemented by all registers. +pub trait Register: Sized { + /// Backing primitive type of the register. + type Storage: Into + From; + + /// Start offset of the register. + /// + /// The interpretation of this offset depends on the type of the regis= ter. + const OFFSET: usize; +} + +/// Trait implemented by registers with a fixed offset. +pub trait FixedRegister: Register {} + +/// Allows `()` to be used as the `location` parameter of [`Io::write`](su= per::Io::write) when +/// passing a [`FixedRegister`] value. +impl IoLoc for () +where + T: FixedRegister, +{ + type IoType =3D T::Storage; + + fn offset(&self) -> usize { + T::OFFSET + } +} + +/// A [`FixedRegister`] carries its location in its type. Thus `FixedRegis= ter` values can be used +/// as an [`IoLoc`]. +impl IoLoc for T +where + T: FixedRegister, +{ + type IoType =3D T::Storage; + + fn offset(&self) -> usize { + T::OFFSET + } +} + +impl IntoIoVal> for T +where + T: FixedRegister, +{ + fn into_io_val(self) -> (FixedRegisterLoc, T) { + (FixedRegisterLoc::new(), self) + } +} + +/// Location of a fixed register. +pub struct FixedRegisterLoc(PhantomData); + +impl FixedRegisterLoc { + /// Returns the location of `T`. + #[inline(always)] + // We do not implement `Default` so we can be const. + #[allow(clippy::new_without_default)] + pub const fn new() -> Self { + Self(PhantomData) + } +} + +impl IoLoc for FixedRegisterLoc +where + T: FixedRegister, +{ + type IoType =3D T::Storage; + + fn offset(&self) -> usize { + T::OFFSET + } +} + +/// Trait providing a base address to be added to the offset of a relative= register to obtain +/// its actual offset. +/// +/// The `T` generic argument is used to distinguish which base to use, in = case a type provides +/// several bases. It is given to the `register!` macro to restrict the us= e of the register to +/// implementors of this particular variant. +pub trait RegisterBase { + /// Base address to which register offsets are added. + const BASE: usize; +} + +/// Trait implemented by all registers that are relative to a base. +pub trait WithBase { + /// Family of bases applicable to this register. + type BaseFamily; + + /// Returns the absolute location of this type when using `B` as its b= ase. + fn of>() -> RelativeRegisterLoc + where + Self: Register, + { + RelativeRegisterLoc::new() + } +} + +/// Trait implemented by relative registers. +pub trait RelativeRegister: Register + WithBase {} + +/// Location of a relative register. +/// +/// This can either be an immediately accessible regular [`RelativeRegiste= r`], or a +/// [`RelativeRegisterArray`] that needs one additional resolution through +/// [`RelativeRegisterLoc::at`]. +pub struct RelativeRegisterLoc(PhantomData, Pha= ntomData); + +impl RelativeRegisterLoc +where + T: Register + WithBase, + B: RegisterBase + ?Sized, +{ + /// Returns the location of a relative register or register array. + #[inline(always)] + // We do not implement `Default` so we can be const. + #[allow(clippy::new_without_default)] + pub const fn new() -> Self { + Self(PhantomData, PhantomData) + } + + // Returns the absolute offset of the relative register using base `B`. + // + // This is implemented as a private const method so it can be reused b= y the [`IoLoc`] + // implementations of both [`RelativeRegisterLoc`] and [`RelativeRegis= terArrayLoc`]. + const fn offset(&self) -> usize { + B::BASE + T::OFFSET + } +} + +impl IoLoc for RelativeRegisterLoc +where + T: RelativeRegister, + B: RegisterBase + ?Sized, +{ + type IoType =3D T::Storage; + + fn offset(&self) -> usize { + self.offset() + } +} + +/// Trait implemented by arrays of registers. +pub trait RegisterArray: Register { + /// Number of elements in the registers array. + const SIZE: usize; + /// Number of bytes between the start of elements in the registers arr= ay. + const STRIDE: usize; +} + +/// Location of an array register. +pub struct RegisterArrayLoc(usize, PhantomData); + +impl RegisterArrayLoc { + /// Returns the location of register `T` at position `idx`, with build= -time validation. + #[inline(always)] + pub fn new(idx: usize) -> Self { + ::kernel::build_assert!(idx < T::SIZE); + + Self(idx, PhantomData) + } + + /// Attempts to return the location of register `T` at position `idx`,= with runtime validation. + #[inline(always)] + pub fn try_new(idx: usize) -> Option { + if idx < T::SIZE { + Some(Self(idx, PhantomData)) + } else { + None + } + } +} + +impl IoLoc for RegisterArrayLoc +where + T: RegisterArray, +{ + type IoType =3D T::Storage; + + fn offset(&self) -> usize { + T::OFFSET + self.0 * T::STRIDE + } +} + +/// Trait providing location builders for [`RegisterArray`]s. +pub trait Array { + /// Returns the location of the register at position `idx`, with build= -time validation. + fn at(idx: usize) -> RegisterArrayLoc + where + Self: RegisterArray, + { + RegisterArrayLoc::new(idx) + } + + /// Returns the location of the register at position `idx`, with runti= me validation. + fn try_at(idx: usize) -> Option> + where + Self: RegisterArray, + { + RegisterArrayLoc::try_new(idx) + } +} + +/// Trait implemented by arrays of relative registers. +pub trait RelativeRegisterArray: RegisterArray + WithBase {} + +/// Location to a relative array register. +pub struct RelativeRegisterArrayLoc< + T: RelativeRegisterArray, + B: RegisterBase + ?Sized, +>(RelativeRegisterLoc, usize); + +impl RelativeRegisterArrayLoc +where + T: RelativeRegisterArray, + B: RegisterBase + ?Sized, +{ + /// Returns the location of register `T` from the base `B` at index `i= dx`, with build-time + /// validation. + #[inline(always)] + pub fn new(idx: usize) -> Self { + ::kernel::build_assert!(idx < T::SIZE); + + Self(RelativeRegisterLoc::new(), idx) + } + + /// Attempts to return the location of register `T` from the base `B` = at index `idx`, with + /// runtime validation. + #[inline(always)] + pub fn try_new(idx: usize) -> Option { + if idx < T::SIZE { + Some(Self(RelativeRegisterLoc::new(), idx)) + } else { + None + } + } +} + +/// Methods exclusive to [`RelativeRegisterLoc`]s created with a [`Relativ= eRegisterArray`]. +impl RelativeRegisterLoc +where + T: RelativeRegisterArray, + B: RegisterBase + ?Sized, +{ + /// Returns the location of the register at position `idx`, with build= -time validation. + #[inline(always)] + pub fn at(self, idx: usize) -> RelativeRegisterArrayLoc { + RelativeRegisterArrayLoc::new(idx) + } + + /// Returns the location of the register at position `idx`, with runti= me validation. + #[inline(always)] + pub fn try_at(self, idx: usize) -> Option> { + RelativeRegisterArrayLoc::try_new(idx) + } +} + +impl IoLoc for RelativeRegisterArrayLoc +where + T: RelativeRegisterArray, + B: RegisterBase + ?Sized, +{ + type IoType =3D T::Storage; + + fn offset(&self) -> usize { + self.0.offset() + self.1 * T::STRIDE + } +} + +/// Defines a dedicated type for a register, including getter and setter m= ethods for its fields and +/// methods to read and write it from an [`Io`](kernel::io::Io) region. +/// +/// # Simple example +/// +/// ```no_run +/// use kernel::register; +/// +/// register! { +/// /// Basic information about the chip. +/// pub BOOT_0(u32) @ 0x00000100 { +/// /// Vendor ID. +/// 15:8 vendor_id; +/// /// Major revision of the chip. +/// 7:4 major_revision; +/// /// Minor revision of the chip. +/// 3:0 minor_revision; +/// } +/// } +/// ``` +/// +/// This defines a 32-bit `BOOT_0` type which can be read from or written = to offset `0x100` of an +/// `Io` region, with the described bitfields. For instance, `minor_revisi= on` consists of the 4 +/// least significant bits of the type. +/// +/// Fields are instances of [`Bounded`](kernel::num::Bounded) and can be r= ead by calling their +/// getter method, which is named after them. They also have setter method= s prefixed with `with_` +/// for runtime values and `with_const_` for constant values. All setters = return the updated +/// register value. +/// +/// Fields can also be transparently converted from/to an arbitrary type b= y using the `=3D>` and +/// `?=3D>` syntaxes. +/// +/// If present, doc comments above register or fields definitions are adde= d to the relevant item +/// they document (the register type itself, or the field's setter and get= ter methods). +/// +/// Note that multiple registers can be defined in a single `register!` in= vocation. This can be +/// useful to group related registers together. +/// +/// ```no_run +/// use kernel::register; +/// use kernel::io::IoLoc; +/// use kernel::num::Bounded; +/// +/// # register! { +/// # pub BOOT_0(u32) @ 0x00000100 { +/// # 15:8 vendor_id; +/// # 7:4 major_revision; +/// # 3:0 minor_revision; +/// # } +/// # } +/// # fn test>(bar= : T) { +/// # fn obtain_vendor_id() -> u8 { 0xff } +/// // Read from the register's defined offset (0x100). +/// let boot0 =3D bar.read(BOOT_0); +/// pr_info!("chip revision: {}.{}", boot0.major_revision().get(), boot0.m= inor_revision().get()); +/// +/// // Update some fields and write the new value back. +/// let new_boot0 =3D boot0 +/// // Constant values. +/// .with_const_major_revision::<3>() +/// .with_const_minor_revision::<10>() +/// // Run-time value. +/// .with_vendor_id(obtain_vendor_id()); +/// bar.write_val(new_boot0); +/// +/// // Or, build a new value from zero and write it: +/// bar.write_val(BOOT_0::zeroed() +/// .with_const_major_revision::<3>() +/// .with_const_minor_revision::<10>() +/// .with_vendor_id(obtain_vendor_id()) +/// ); +/// +/// // Or, read and update the register in a single step. +/// bar.update(BOOT_0, |r| r +/// .with_const_major_revision::<3>() +/// .with_const_minor_revision::<10>() +/// .with_vendor_id(obtain_vendor_id()) +/// ); +/// +/// // Constant values can also be built using the const setters. +/// const V: BOOT_0 =3D pin_init::zeroed::() +/// .with_const_major_revision::<3>() +/// .with_const_minor_revision::<10>(); +/// # } +/// ``` +/// +/// There are 4 possible kinds of registers: fixed offset registers, relat= ive registers, arrays of +/// registers, and relative arrays of registers. +/// +/// ## Fixed offset registers +/// +/// These are the simplest kind of registers. Their location is simply an = offset inside the I/O +/// region. For instance: +/// +/// ```ignore +/// register! { +/// pub FIXED_REG(u16) @ 0x80 { +/// ... +/// } +/// } +/// ``` +/// +/// This creates a 16-bit register named `FIXED_REG` located at offset `0x= 80` of an I/O region. +/// +/// These registers' location can be built for access by just referencing = their name: +/// +/// ```no_run +/// use kernel::io::Io; +/// use kernel::register; +/// # use kernel::io::Mmio; +/// +/// register! { +/// FIXED_REG(u32) @ 0x100 { +/// 16:8 high_byte; +/// 7:0 low_byte; +/// } +/// } +/// +/// # fn test(io: &Mmio<0x1000>) { +/// let val =3D io.read(FIXED_REG); +/// +/// // Write from an already-existing value. +/// io.write(FIXED_REG, val.with_low_byte(0xff)); +/// +/// // Write a value created from scratch. +/// io.write_val(FIXED_REG::zeroed().with_high_byte(0x80)); +/// # } +/// +/// ``` +/// +/// It is possible to create an alias of an existing register with new fie= ld definitions by using +/// the `=3D> ALIAS` syntax. This is useful for cases where a register's i= nterpretation depends on +/// the context: +/// +/// ```no_run +/// use kernel::register; +/// +/// register! { +/// /// Scratch register. +/// pub SCRATCH(u32) @ 0x00000200 { +/// 31:0 value; +/// } +/// +/// /// Boot status of the firmware. +/// pub SCRATCH_BOOT_STATUS(u32) =3D> SCRATCH { +/// 0:0 completed; +/// } +/// } +/// ``` +/// +/// In this example, `SCRATCH_BOOT_STATUS` uses the same I/O address as `S= CRATCH`, while providing +/// its own `completed` field. +/// +/// ## Relative registers +/// +/// Relative registers can be instantiated several times at a relative off= set of a group of bases. +/// For instance, imagine the following I/O space: +/// +/// ```text +/// +-----------------------------+ +/// | ... | +/// | | +/// 0x100--->+------------CPU0-------------+ +/// | | +/// 0x110--->+-----------------------------+ +/// | CPU_CTL | +/// +-----------------------------+ +/// | ... | +/// | | +/// | | +/// 0x200--->+------------CPU1-------------+ +/// | | +/// 0x210--->+-----------------------------+ +/// | CPU_CTL | +/// +-----------------------------+ +/// | ... | +/// +-----------------------------+ +/// ``` +/// +/// `CPU0` and `CPU1` both have a `CPU_CTL` register that starts at offset= `0x10` of their I/O +/// space segment. Since both instances of `CPU_CTL` share the same layout= , we don't want to define +/// them twice and would prefer a way to select which one to use from a si= ngle definition. +/// +/// This can be done using the `Base + Offset` syntax when specifying the = register's address: +/// +/// ```ignore +/// register! { +/// pub RELATIVE_REG(u32) @ Base + 0x80 { +/// ... +/// } +/// } +/// ``` +/// +/// This creates a register with an offset of `0x80` from a given base. +/// +/// `Base` is an arbitrary type (typically a ZST) to be used as a generic = parameter of the +/// [`RegisterBase`] trait to provide the base as a constant, i.e. each ty= pe providing a base for +/// this register needs to implement `RegisterBase`. +/// +/// The location of relative registers can be built using the [`WithBase::= of`] method to specify +/// its base. All relative registers implement [`WithBase`]. +/// +/// Here is the above layout translated into code: +/// +/// ```no_run +/// use kernel::io::Io; +/// use kernel::io::register::{RegisterBase, WithBase}; +/// use kernel::register; +/// # use kernel::io::Mmio; +/// +/// // Type used to identify the base. +/// pub struct CpuCtlBase; +/// +/// // ZST describing `CPU0`. +/// struct Cpu0; +/// impl RegisterBase for Cpu0 { +/// const BASE: usize =3D 0x100; +/// } +/// +/// // ZST describing `CPU1`. +/// struct Cpu1; +/// impl RegisterBase for Cpu1 { +/// const BASE: usize =3D 0x200; +/// } +/// +/// // This makes `CPU_CTL` accessible from all implementors of `RegisterB= ase`. +/// register! { +/// /// CPU core control. +/// pub CPU_CTL(u32) @ CpuCtlBase + 0x10 { +/// 0:0 start; +/// } +/// } +/// +/// # fn test(io: Mmio<0x1000>) { +/// // Read the status of `Cpu0`. +/// let cpu0_started =3D io.read(CPU_CTL::of::()); +/// +/// // Stop `Cpu0`. +/// io.write(WithBase::of::(), CPU_CTL::zeroed()); +/// # } +/// +/// // Aliases can also be defined for relative register. +/// register! { +/// /// Alias to CPU core control. +/// pub CPU_CTL_ALIAS(u32) =3D> CpuCtlBase + CPU_CTL { +/// /// Start the aliased CPU core. +/// 1:1 alias_start; +/// } +/// } +/// +/// # fn test2(io: Mmio<0x1000>) { +/// // Start the aliased `CPU0`, leaving its other fields untouched. +/// io.update(CPU_CTL_ALIAS::of::(), |r| r.with_alias_start(true)); +/// # } +/// ``` +/// +/// ## Arrays of registers +/// +/// Some I/O areas contain consecutive registers that share the same field= layout. These areas can +/// be defined as an array of identical registers, allowing them to be acc= essed by index with +/// compile-time or runtime bound checking: +/// +/// +/// ```ignore +/// register! { +/// pub REGISTER_ARRAY(u8)[10, stride =3D 4] @ 0x100 { +/// ... +/// } +/// } +/// ``` +/// +/// This defines `REGISER_ARRAY`, an array of 10 byte registers starting a= t offset `0x100`. Each +/// register is separated from its neighbor by 4 bytes. +/// +/// The `stride` parameter is optional; if unspecified, the registers are = placed consecutively from +/// each other. +/// +/// A location for a register in a register array is built using the [`Arr= ay::at`] trait method. +/// All arrays of registers implement [`Array`]. +/// +/// ```no_run +/// use kernel::register; +/// use kernel::io::Io; +/// use kernel::io::register::Array; +/// # use kernel::io::Mmio; +/// # fn get_scratch_idx() -> usize { +/// # 0x15 +/// # } +/// +/// // Array of 64 consecutive registers with the same layout starting at = offset `0x80`. +/// register! { +/// /// Scratch registers. +/// pub SCRATCH(u32)[64] @ 0x00000080 { +/// 31:0 value; +/// } +/// } +/// +/// # fn test(io: &Mmio<0x1000>) +/// # -> Result<(), Error>{ +/// // Read scratch register 0, i.e. I/O address `0x80`. +/// let scratch_0 =3D io.read(SCRATCH::at(0)).value(); +/// +/// // Write scratch register 15, i.e. I/O address `0x80 + (15 * 4)`. +/// io.write(Array::at(15), SCRATCH::from(0xffeeaabb)); +/// +/// // This is out of bounds and won't build. +/// // let scratch_128 =3D bar.read(SCRATCH::at(128)).value(); +/// +/// // Runtime-obtained array index. +/// let idx =3D get_scratch_idx(); +/// // Access on a runtime index returns an error if it is out-of-bounds. +/// let some_scratch =3D io.read(SCRATCH::try_at(idx).ok_or(EINVAL)?).valu= e(); +/// +/// // Alias to a specific register in an array. +/// // Here `SCRATCH[8]` is used to convey the firmware exit code. +/// register! { +/// /// Firmware exit status code. +/// pub FIRMWARE_STATUS(u32) =3D> SCRATCH[8] { +/// 7:0 status; +/// } +/// } +/// +/// let status =3D io.read(FIRMWARE_STATUS).status(); +/// +/// // Non-contiguous register arrays can be defined by adding a stride pa= rameter. +/// // Here, each of the 16 registers of the array are separated by 8 byte= s, meaning that the +/// // registers of the two declarations below are interleaved. +/// register! { +/// /// Scratch registers bank 0. +/// pub SCRATCH_INTERLEAVED_0(u32)[16, stride =3D 8] @ 0x000000c0 { +/// 31:0 value; +/// } +/// +/// /// Scratch registers bank 1. +/// pub SCRATCH_INTERLEAVED_1(u32)[16, stride =3D 8] @ 0x000000c4 { +/// 31:0 value; +/// } +/// } +/// # Ok(()) +/// # } +/// ``` +/// +/// ## Relative arrays of registers +/// +/// Combining the two features described in the sections above, arrays of = registers accessible from +/// a base can also be defined: +/// +/// ```ignore +/// register! { +/// pub RELATIVE_REGISTER_ARRAY(u8)[10, stride =3D 4] @ Base + 0x100 { +/// ... +/// } +/// } +/// ``` +/// +/// Like relative registers, they implement the [`WithBase`] trait. Howeve= r the return value of +/// [`WithBase::of`] cannot be used directly as a location and must be fur= ther specified using the +/// [`at`](RelativeRegisterLoc::at) method. +/// +/// ```no_run +/// use kernel::io::Io; +/// use kernel::io::register::{RegisterBase, WithBase}; +/// use kernel::register; +/// # use kernel::io::Mmio; +/// # fn get_scratch_idx() -> usize { +/// # 0x15 +/// # } +/// +/// // Type used as parameter of `RegisterBase` to specify the base. +/// pub struct CpuCtlBase; +/// +/// // ZST describing `CPU0`. +/// struct Cpu0; +/// impl RegisterBase for Cpu0 { +/// const BASE: usize =3D 0x100; +/// } +/// +/// // ZST describing `CPU1`. +/// struct Cpu1; +/// impl RegisterBase for Cpu1 { +/// const BASE: usize =3D 0x200; +/// } +/// +/// // 64 per-cpu scratch registers, arranged as a contiguous array. +/// register! { +/// /// Per-CPU scratch registers. +/// pub CPU_SCRATCH(u32)[64] @ CpuCtlBase + 0x00000080 { +/// 31:0 value; +/// } +/// } +/// +/// # fn test(io: &Mmio<0x1000>) -> Result<(), Error> { +/// // Read scratch register 0 of CPU0. +/// let scratch =3D io.read(CPU_SCRATCH::of::().at(0)); +/// +/// // Write the retrieved value into scratch register 15 of CPU1. +/// io.write(WithBase::of::().at(15), scratch); +/// +/// // This won't build. +/// // let cpu0_scratch_128 =3D bar.read(CPU_SCRATCH::of::().at(128)= ).value(); +/// +/// // Runtime-obtained array index. +/// let scratch_idx =3D get_scratch_idx(); +/// // Access on a runtime index returns an error if it is out-of-bounds. +/// let cpu0_scratch =3D io.read( +/// CPU_SCRATCH::of::().try_at(scratch_idx).ok_or(EINVAL)? +/// ).value(); +/// # Ok(()) +/// # } +/// +/// // Alias to `SCRATCH[8]` used to convey the firmware exit code. +/// register! { +/// /// Per-CPU firmware exit status code. +/// pub CPU_FIRMWARE_STATUS(u32) =3D> CpuCtlBase + CPU_SCRATCH[8] { +/// 7:0 status; +/// } +/// } +/// +/// // Non-contiguous relative register arrays can be defined by adding a = stride parameter. +/// // Here, each of the 16 registers of the array are separated by 8 byte= s, meaning that the +/// // registers of the two declarations below are interleaved. +/// register! { +/// /// Scratch registers bank 0. +/// pub CPU_SCRATCH_INTERLEAVED_0(u32)[16, stride =3D 8] @ CpuCtlBase = + 0x00000d00 { +/// 31:0 value; +/// } +/// +/// /// Scratch registers bank 1. +/// pub CPU_SCRATCH_INTERLEAVED_1(u32)[16, stride =3D 8] @ CpuCtlBase = + 0x00000d04 { +/// 31:0 value; +/// } +/// } +/// +/// # fn test2(io: &Mmio<0x1000>) -> Result<(), Error> { +/// let cpu0_status =3D io.read(CPU_FIRMWARE_STATUS::of::()).status(= ); +/// # Ok(()) +/// # } +/// ``` +#[macro_export] +macro_rules! register { + // Entry point for the macro, allowing multiple registers to be define= d in one call. + // It matches all possible register declaration patterns to dispatch t= hem to corresponding + // `@reg` rule that defines a single register. + ( + $( + $(#[$attr:meta])* $vis:vis $name:ident ($storage:ty) + $([ $size:expr $(, stride =3D $stride:expr)? ])? + $(@ $($base:ident +)? $offset:literal)? + $(=3D> $alias:ident $(+ $alias_offset:ident)? $([$alias_id= x:expr])? )? + { $($fields:tt)* } + )* + ) =3D> { + $( + $crate::register!( + @reg $(#[$attr])* $vis $name ($storage) $([$size $(, stride = =3D $stride)?])? + $(@ $($base +)? $offset)? + $(=3D> $alias $(+ $alias_offset)? $([$alias_idx])? )? + { $($fields)* } + ); + )* + }; + + // All the rules below are private helpers. + + // Creates a register at a fixed offset of the MMIO space. + ( + @reg $(#[$attr:meta])* $vis:vis $name:ident ($storage:ty) @ $offse= t:literal + { $($fields:tt)* } + ) =3D> { + $crate::register!(@bitfield $(#[$attr])* $vis struct $name($storag= e) { $($fields)* }); + $crate::register!(@io_base $name($storage) @ $offset); + $crate::register!(@io_fixed $(#[$attr])* $vis $name($storage)); + }; + + // Creates an alias register of fixed offset register `alias` with its= own fields. + ( + @reg $(#[$attr:meta])* $vis:vis $name:ident ($storage:ty) =3D> $al= ias:ident + { $($fields:tt)* } + ) =3D> { + $crate::register!(@bitfield $(#[$attr])* $vis struct $name($storag= e) { $($fields)* }); + $crate::register!( + @io_base $name($storage) @ + <$alias as $crate::io::register::Register>::OFFSET + ); + $crate::register!(@io_fixed $(#[$attr])* $vis $name($storage)); + }; + + // Creates a register at a relative offset from a base address provide= r. + ( + @reg $(#[$attr:meta])* $vis:vis $name:ident ($storage:ty) @ $base:= ident + $offset:literal + { $($fields:tt)* } + ) =3D> { + $crate::register!(@bitfield $(#[$attr])* $vis struct $name($storag= e) { $($fields)* }); + $crate::register!(@io_base $name($storage) @ $offset); + $crate::register!(@io_relative $vis $name($storage) @ $base); + }; + + // Creates an alias register of relative offset register `alias` with = its own fields. + ( + @reg $(#[$attr:meta])* $vis:vis $name:ident ($storage:ty) =3D> $ba= se:ident + $alias:ident + { $($fields:tt)* } + ) =3D> { + $crate::register!(@bitfield $(#[$attr])* $vis struct $name($storag= e) { $($fields)* }); + $crate::register!( + @io_base $name($storage) @ <$alias as $crate::io::register::Re= gister>::OFFSET + ); + $crate::register!(@io_relative $vis $name($storage) @ $base); + }; + + // Creates an array of registers at a fixed offset of the MMIO space. + ( + @reg $(#[$attr:meta])* $vis:vis $name:ident ($storage:ty) + [ $size:expr, stride =3D $stride:expr ] @ $offset:literal { $(= $fields:tt)* } + ) =3D> { + static_assert!(::core::mem::size_of::<$storage>() <=3D $stride); + + $crate::register!(@bitfield $(#[$attr])* $vis struct $name($storag= e) { $($fields)* }); + $crate::register!(@io_base $name($storage) @ $offset); + $crate::register!(@io_array $vis $name($storage) [ $size, stride = =3D $stride ]); + }; + + // Shortcut for contiguous array of registers (stride =3D=3D size of e= lement). + ( + @reg $(#[$attr:meta])* $vis:vis $name:ident ($storage:ty) [ $size:= expr ] @ $offset:literal + { $($fields:tt)* } + ) =3D> { + $crate::register!( + $(#[$attr])* $vis $name($storage) [ $size, stride =3D ::core::= mem::size_of::<$storage>() ] + @ $offset { $($fields)* } + ); + }; + + // Creates an alias of register `idx` of array of registers `alias` wi= th its own fields. + ( + @reg $(#[$attr:meta])* $vis:vis $name:ident ($storage:ty) =3D> $al= ias:ident [ $idx:expr ] + { $($fields:tt)* } + ) =3D> { + static_assert!($idx < <$alias as $crate::io::register::RegisterArr= ay>::SIZE); + + $crate::register!(@bitfield $(#[$attr])* $vis struct $name($storag= e) { $($fields)* }); + $crate::register!( + @io_base $name($storage) @ + <$alias as $crate::io::register::Register>::OFFSET + + $idx * <$alias as $crate::io::register::RegisterArray>::= STRIDE + ); + $crate::register!(@io_fixed $(#[$attr])* $vis $name($storage)); + }; + + // Creates an array of registers at a relative offset from a base addr= ess provider. + ( + @reg $(#[$attr:meta])* $vis:vis $name:ident ($storage:ty) + [ $size:expr, stride =3D $stride:expr ] + @ $base:ident + $offset:literal { $($fields:tt)* } + ) =3D> { + static_assert!(::core::mem::size_of::<$storage>() <=3D $stride); + + $crate::register!(@bitfield $(#[$attr])* $vis struct $name($storag= e) { $($fields)* }); + $crate::register!(@io_base $name($storage) @ $offset); + $crate::register!( + @io_relative_array $vis $name($storage) [ $size, stride =3D $s= tride ] @ $base + $offset + ); + }; + + // Shortcut for contiguous array of relative registers (stride =3D=3D = size of element). + ( + @reg $(#[$attr:meta])* $vis:vis $name:ident ($storage:ty) [ $size:= expr ] + @ $base:ident + $offset:literal { $($fields:tt)* } + ) =3D> { + $crate::register!( + $(#[$attr])* $vis $name($storage) [ $size, stride =3D ::core::= mem::size_of::<$storage>() ] + @ $base + $offset { $($fields)* } + ); + }; + + // Creates an alias of register `idx` of relative array of registers `= alias` with its own + // fields. + ( + @reg $(#[$attr:meta])* $vis:vis $name:ident ($storage:ty) + =3D> $base:ident + $alias:ident [ $idx:expr ] { $($fields:tt)*= } + ) =3D> { + static_assert!($idx < <$alias as $crate::io::register::RegisterArr= ay>::SIZE); + + $crate::register!(@bitfield $(#[$attr])* $vis struct $name($storag= e) { $($fields)* }); + $crate::register!( + @io_base $name($storage) @ + <$alias as $crate::io::register::Register>::OFFSET + + $idx * <$alias as $crate::io::register::RegisterArray>::ST= RIDE + ); + $crate::register!(@io_relative $vis $name($storage) @ $base); + }; + + // Generates the bitfield for the register. + // + // `#[allow(non_camel_case_types)]` is added since register names typi= cally use + // `SCREAMING_CASE`. + ( + @bitfield $(#[$attr:meta])* $vis:vis struct $name:ident($storage:t= y) { $($fields:tt)* } + ) =3D> { + $crate::register!(@bitfield_core + #[allow(non_camel_case_types)] + $(#[$attr])* $vis $name $storage + ); + $crate::register!(@bitfield_fields $vis $name $storage { $($fields= )* }); + }; + + // Implementations shared by all registers types. + (@io_base $name:ident($storage:ty) @ $offset:expr) =3D> { + impl $crate::io::register::Register for $name { + type Storage =3D $storage; + + const OFFSET: usize =3D $offset; + } + }; + + // Implementations of fixed registers. + (@io_fixed $(#[$attr:meta])* $vis:vis $name:ident ($storage:ty)) =3D> { + impl $crate::io::register::FixedRegister for $name {} + + $(#[$attr])* + $vis const $name: $crate::io::register::FixedRegisterLoc<$name> = =3D + $crate::io::register::FixedRegisterLoc::<$name>::new(); + }; + + // Implementations of relative registers. + (@io_relative $vis:vis $name:ident ($storage:ty) @ $base:ident) =3D> { + impl $crate::io::register::WithBase for $name { + type BaseFamily =3D $base; + } + + impl $crate::io::register::RelativeRegister for $name {} + }; + + // Implementations of register arrays. + (@io_array $vis:vis $name:ident ($storage:ty) [ $size:expr, stride =3D= $stride:expr ]) =3D> { + impl $crate::io::register::Array for $name {} + + impl $crate::io::register::RegisterArray for $name { + const SIZE: usize =3D $size; + const STRIDE: usize =3D $stride; + } + }; + + // Implementations of relative array registers. + ( + @io_relative_array $vis:vis $name:ident ($storage:ty) [ $size:expr= , stride =3D $stride:expr ] + @ $base:ident + $offset:literal + ) =3D> { + impl $crate::io::register::WithBase for $name { + type BaseFamily =3D $base; + } + + impl $crate::io::register::RegisterArray for $name { + const SIZE: usize =3D $size; + const STRIDE: usize =3D $stride; + } + + 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.53.0 From nobody Thu Apr 9 10:29:43 2026 Received: from CY7PR03CU001.outbound.protection.outlook.com (mail-westcentralusazon11010057.outbound.protection.outlook.com [40.93.198.57]) (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 02CEB3D903A; Mon, 9 Mar 2026 15:14:51 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=40.93.198.57 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773069293; cv=fail; b=NzAXFrdHAwJVpMaI+wmHp0hJJaEX2cg18Zzm0t0VdXGBGXdIoorz8ImQXTzpvaVmCxBb5cL0E43SxBrjH6dzjnbzjJBKQeyvzouN6cyaBOjiWCOFiQELRP5WpbRRZKGLcy91Cdno27nju8XZhdPcPUp6Lp2ff4JdKaV6MvzRcfg= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773069293; c=relaxed/simple; bh=ij6iTnY48ItDw7a0bv0zSXVP2mQR/tx18HYSM0Jy+UY=; h=From:Date:Subject:Content-Type:Message-Id:References:In-Reply-To: To:Cc:MIME-Version; b=EAPvL570LMy/+n9Sh2ZVhrb4io5NdTVd1ghbWCKzcZrrbPfmoBANB3zPWE4hJxAf3w5KjtUTCzjhfAxNvlS8uxWcKYQThdPs1s/rKH2Lrx4I98c1LDFNjussJV7bgPQXG9OcQAunNQrpMCPGWS/oISsKhVhz98bfP54L1+AiONY= 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=o4JSBxKE; arc=fail smtp.client-ip=40.93.198.57 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="o4JSBxKE" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=HZed/sPE9/KsYQOc7e4s0zEAcAFJXiUnN6+Bq/ubYmN7TsWb+Y87Ru0PgP0rDo2VbeQ5OVjOwi9qz0svMgacMvTGRRQD1xlPPf3VSgHRHlcHVJP4GFxTRsGcFYo8FNLUEIQBVrXf8gjawadzfQcIQeo6X+BHrzizJ/qxf6kvl+aXZGJ5TVuYcayOwMHl2Yhpa2fry9vMuTEP2EBgKoXlrpFkhaRumPHx8k+fhZUGZ3Yeuzgm0/5NY56/9A7gaSo2IbnCCClZZXK8xtaInrfFYMTaMJrFj0dvGHRjqkjWRsmoih1+xO1JkuBjdRyZj/Zf4aoVFopJ5dipMMg3wsS5rQ== 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=P5SZoiRY//guABI5KuykvsFaXf+/TSR5RkT1/mJc1sA=; b=efD7B4Hfgf1iMjgoIHLwGDoJDtX36WOOsZT4p67s9f2VHDNMC0oUgKODObKm03mKBEa1pZ2PPas3/l5FAG/7a648kAoCKqOChjnPbhlKvdsXwoxoKSuMUVdnkaEOmepD3+BUGTuwj2Rl/t2EmYNtDhDWYQt1aW2Jp8X+luap3I8ZiOoydqC6YLcWTdYAn2bs4Kv4onYEklJe13l2rjKZZh7Z4NMjPDO3OQGMZ0XLhyL8giLvbdrNAQp09sfROmA9beZZRTVGxo2k/jIG8DU6J4cYl8py+lRR/CJuGfrzSr+toO/ivIOX1O9hpR4OocvH5K9evo47ygfh6vQEZrP8vg== 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=P5SZoiRY//guABI5KuykvsFaXf+/TSR5RkT1/mJc1sA=; b=o4JSBxKEIHJy/+JLiYmAhXD727cCzfbdNoLZGqlTB9gQY251GHaDTk7TW4O5akDxBEJIWT09mFTHxlMxFtpJ4qmN3DmC9+IwM6VDw3LX0duUb3hSQPk5qeJbUfLUIb8zieNyJnDFajDD2FdnKrP0k6rD8//e7EYnjDNP25B71k0l+n5OqnTwNTk4zxYwJsZeqNzuHW9TPe5Tcq+lbsy+rfYjRtoH1IKuxMnOwFsHj96sM5sAnajBzLF+ecPE1davEb1H+dyAWMCnHL7oQgGiy/d/ZSRqsilyrdBzuzRy3TFO6zZhg2eerBS56yuO9KLPqXW3cRBiJ1lMMWJabRhF2A== 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 CY5PR12MB6131.namprd12.prod.outlook.com (2603:10b6:930:25::10) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.9700.11; Mon, 9 Mar 2026 15:14:48 +0000 Received: from CH2PR12MB3990.namprd12.prod.outlook.com ([fe80::7de1:4fe5:8ead:5989]) by CH2PR12MB3990.namprd12.prod.outlook.com ([fe80::7de1:4fe5:8ead:5989%6]) with mapi id 15.20.9700.009; Mon, 9 Mar 2026 15:14:48 +0000 From: Alexandre Courbot Date: Tue, 10 Mar 2026 00:14:06 +0900 Subject: [PATCH v8 09/10] sample: rust: pci: use `register!` macro Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260310-register-v8-9-424f80dd43bc@nvidia.com> References: <20260310-register-v8-0-424f80dd43bc@nvidia.com> In-Reply-To: <20260310-register-v8-0-424f80dd43bc@nvidia.com> To: Danilo Krummrich , Alice Ryhl , Daniel Almeida , Miguel Ojeda , Gary Guo , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Andreas Hindborg , Trevor Gross , Boqun Feng Cc: Yury Norov , John Hubbard , Alistair Popple , Joel Fernandes , Timur Tabi , Edwin Peer , Eliot Courtney , Dirk Behme , Steven Price , rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, Alexandre Courbot X-Mailer: b4 0.14.3 X-ClientProxiedBy: TY4P301CA0031.JPNP301.PROD.OUTLOOK.COM (2603:1096:405:2be::17) 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_|CY5PR12MB6131:EE_ X-MS-Office365-Filtering-Correlation-Id: da80f268-6798-46b2-364d-08de7dee9a5f X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|10070799003|376014|7416014|1800799024|366016|921020; X-Microsoft-Antispam-Message-Info: XyICoVlrFxNK4AStRLtOseDOgFAqbb4OKMv2CKmRSxn41LxNwjnhOwMr0t++N3P2+IgoFIsOzZzjMpl8YnMllVxsqA/YCXjR0s/ehSnb6fA00lz2TO7XWCEqQmAenk38oolkEClJpTvKG05eg9qjLUsrKgy8IqBPz/shu8rfzeq8aEyRSdcQf/dSdXgMzWTs72oNY9VLyDBmhXKtTQkPXP9IRzoZY7dwuZxaQnKvFjinrxC6IDhEeQVyG9rJ08Akbh/GHdiWTdL9aqHpLDGNPapYIYQQnwQb6HiEftD5esZlvHvMDU3MntOJzhISWpmjBjjergnfw2o+3zTy6ebh5mPcFjN3L4W+DBk37emhBJH6GZaClNGwl6zowyaTs543BqU2BatveQ/nBq1Fx4heVY0qgvNdYm2SIQpiY96l3SGrDqd6i/CYYtNfjdM/ptUXYDQt02NhLCaYDxrCTzTdQRyOBWgQEpDcFkZ+WESozOVVpMqXKIkO8glhUwFN0oY5lkqijR/F36Z50Fmn+juBx8Fbbu9QsCMTTHJ8sF4mkGTVIElPOSqd8Q3wI4SkkB2mwaAZmjfbrBUH5+e8o+YeR8QVfYrr8AneGK3S4Xo2VBc4Cx/kYVD1rgIZF1IMnqbPNAP20Xf3vE03cpY9IKelQs6g3Z1GCrAlTxaV1TsN142n1hJb59/vTe+htTphZwJEGNEVzS8PLSzz+0ULVdjjxsoOYHIaNQEHnxpPma6EkxOad6bVw/WBxW4GOT4sRAfGWv6RmHXUlJNIof8c2m65Xg== 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)(10070799003)(376014)(7416014)(1800799024)(366016)(921020);DIR:OUT;SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 2 X-MS-Exchange-AntiSpam-MessageData-0: =?utf-8?B?UEZWVzNNYkc2Zlh6d0N2MEZaTkN0U1V5elRRUFFBM2ExZnZIWkp3cFdBbnZQ?= =?utf-8?B?WTdUSFhwVmwxb0pHc1pYVTNHbG40YnlzaExITGNOWXFkMmYxOGZlbm94QlJC?= =?utf-8?B?NnYrRzBRQVNxRi9kQklBWnB2WnNJUXVNWVg2VXhkNjM4ZFhUSmxOQkphc0ZF?= =?utf-8?B?WUNDV3h3VTdmZjBkS2hCMExLeEZ4bGVYa0UxZ2FpeXdsbEZmK3Zjcm1RVEdn?= =?utf-8?B?dHlHaGhGejhybG1WcmwzRWNlcUdVRUU4b0syUHVUcEpScGFkYW8wYklGOFg2?= =?utf-8?B?YlpyVlRxeFhNYm1RcnVuNFluUkpNTUNZVjVIVlVvcVZkYjQ3TkIzVHkyMmgx?= =?utf-8?B?dDdDcjZwYUcxRytzbmlHNi9iSkpSN1lDNmlpS1lFc2o4RWhDZE8xU0hTMUdH?= =?utf-8?B?N2ZMT1lDSitzbFg4RERhQ2tzWmoyQkh3dEVjdWNrN0J3TlQ5Q0tKRWNSNTNB?= =?utf-8?B?QkZDdnViNmQ5T2R0cHBCT1V3SDQxME05TkhPejR5OHdMbDZvWFFpSklGRVhY?= =?utf-8?B?bHRQOHl1dXBvd0NDVnN1VUdMcTZhK1c4cVRRelcrc0luMjRJZ1BZaEU2b1VQ?= =?utf-8?B?S2N3dExpUnhDUjBsR25LUUp1c0hOcEV6ZUIvNlpUSmVuMHVqTVBVOEo1RnZD?= =?utf-8?B?WDRiN01iYloyZ2FpdGpVUDBhMUdrSEl0THlPTmZ5cnlaS2YwNm9uVjEvV2p4?= =?utf-8?B?UjYrY204dlFKT1FkcVFXZlU3SUl3N0VKYVFKdHVUd3lvRUx0RFpmbTluNVIr?= =?utf-8?B?RVNKcHBXZThBVEl0cUMxQVpZUTNLdVVpUVQ2NjN1ZVlXQ0dMT3hKL3hUcEYv?= =?utf-8?B?SHR6RTVGL1EzTjFxTlJ0NXBobEdVZDdGa0k0a2IvNVJ1VGFmb2V3OVJxZkJt?= =?utf-8?B?aEJNOE1qSEU4aml6NkRzQ1B4SFh3SVlidXpPd2JNc1NCMG9nb2JrZ2FHdFpW?= =?utf-8?B?U0d1SDlJSTN0MVhqa0pHTjQ3dGtqSTgyeVFHN3AxOG5QMlBudWdFSSs3SGhL?= =?utf-8?B?REoyclJseEtiaDRuRDI4TllXbitJSkcwUDZ3bjJCZDBITWtuVFFHZ29QWG1F?= =?utf-8?B?a3UyVU8wTWIrZjArS0hsN3BxQzZLNEUzMjIrYlVTeDh0d3ZtbGlVUEQ0c1BW?= =?utf-8?B?VmlKbUREdkZnamUxLzFVVEtxUEFTbHZZTVlHMnJWMUJLUDA2eVJEV3Y5cytB?= =?utf-8?B?TXJOWHhpMVhkVys0Nm01aklHRVh2TWJsM0FPZE0xOVlhb25PRldWUzFSMk5R?= =?utf-8?B?aWhHQ2ZHMEp5UDROaTQxSVNXaGVqeDBuU1B5MDQ5ZDNSYXU3Wm5lekdWQ2ls?= =?utf-8?B?alBlRmtpc3RmNmIvYjFidXpwT0g0aU9tcGxsTVdkS2lST3dvR0dYOWpNZ2hn?= =?utf-8?B?cFNWOHBEY242RHU2b3Q2Y0ozU2J2Mnc1UzBnZkZkLzdoK2FSc0hJd2o2U2RH?= =?utf-8?B?Q1RHakNHRTBxcGpLV3pMckR1N2dLWGdhdVdtQmlOOVdkTTNvQndqVG9NRXFl?= =?utf-8?B?OXdMYTlydUk3K0Z4OUg1VFl0T1VDa3c1c2l2akRZcW9kZzM5ck0wYnViVjRo?= =?utf-8?B?TjBPNkZkejd2OE9md2FFejJQK2IzYzVvaW9rT3I2eEFoQUFuVUlOdXA5bDUr?= =?utf-8?B?ejRlQ2RpL013UUNBZm1YdENCSW13OWdyTHVYSTJmUy9iYlQ4RC93WmNhT2hS?= =?utf-8?B?bW1IQ3hXWE8rR0crTnZTVHVKRm5zd29zdHRoT1RHczI0NTlKZzNWTU1LWFpC?= =?utf-8?B?a3NKYy9IL2o4c2tobXFpdWgwcFJ0ZldhejlVRDNiQXMzRDc3TUwvajVnM1Yr?= =?utf-8?B?YkwxbmlzcWsrV1l0SFR2TkxqSUlRODNKMXU0WFd4bGRoRzl0M1VhcHgvbDdF?= =?utf-8?B?Y2ZzL1czR3FNVkpGKzdQbHAzK2g0KysrK0Y2NzhlMlhLMDZzUXd5VURXdnlN?= =?utf-8?B?ZFFnam84TGVhL21jMzlOazE1bVp5NDBwamk0Y1lBdWs4NXlOSVJXd2F5TkZn?= =?utf-8?B?YzlHcks4WndwZ2t3cWt2Vnc5V0JYeXBQNGNCeld0UVVtU1NacC9jbjNVdXY4?= =?utf-8?B?Vi90cUh1Y3U3Z1ZtRVVCZW9mN1VROEUwVFo1ZlBZMkxUckR5ZDdHU2kxNFlo?= =?utf-8?B?RTNBaWgyMmVmeUhZWVRoakNqSlNQdzgrc2krcUI4b1NHYnUrRHdLcUhyRm04?= =?utf-8?B?c2pPNTZORWVIN2xyL0ZWYy8xeXRIbTdEaURBUEE5QzU3ZUxTSW1Ca3oxUVZO?= =?utf-8?B?bVFwKzlvMUdKNzM2RUl3Mm4yS0JPNnIybElJTkFVZG53SnJ4WUVZOU9neEVW?= =?utf-8?B?dUlJcW1YSThDZ2dNcExYYzIyalZ3K1lUNkw2RzhzaFZuY2xrYnJrY0VscktS?= =?utf-8?Q?Ljywbu0R5WsR55PvVXfAxZicH6EEjHELWuLbFryiwrIu7?= X-MS-Exchange-AntiSpam-MessageData-1: qrDfbH8qZr1g1g== X-OriginatorOrg: Nvidia.com X-MS-Exchange-CrossTenant-Network-Message-Id: da80f268-6798-46b2-364d-08de7dee9a5f X-MS-Exchange-CrossTenant-AuthSource: CH2PR12MB3990.namprd12.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 09 Mar 2026 15:14:48.0251 (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: UlB6lCqPJQQPndfIEhp+mqpgf19izU1z6dM0jywFsNzKc9AyKGcpV0jYEMdmbfQ5ruz2B4+F45I9XoZBlAm2uQ== X-MS-Exchange-Transport-CrossTenantHeadersStamped: CY5PR12MB6131 Convert the direct IO accesses to properly defined registers. Signed-off-by: Alexandre Courbot --- samples/rust/rust_driver_pci.rs | 84 +++++++++++++++++++++++++++++++------= ---- 1 file changed, 64 insertions(+), 20 deletions(-) diff --git a/samples/rust/rust_driver_pci.rs b/samples/rust/rust_driver_pci= .rs index d3d4a7931deb..3f52cfcb7f4b 100644 --- a/samples/rust/rust_driver_pci.rs +++ b/samples/rust/rust_driver_pci.rs @@ -8,27 +8,58 @@ device::Bound, device::Core, devres::Devres, - io::Io, + io::{ + register::Array, + Io, // + }, + num::Bounded, pci, prelude::*, + register, sync::aref::ARef, // }; =20 -struct Regs; +mod regs { + use super::*; =20 -impl Regs { - const TEST: usize =3D 0x0; - const OFFSET: usize =3D 0x4; - const DATA: usize =3D 0x8; - const COUNT: usize =3D 0xC; - const END: usize =3D 0x10; + register! { + pub(super) TEST(u8) @ 0x0 { + 7:0 index =3D> TestIndex; + } + + pub(super) OFFSET(u32) @ 0x4 { + 31:0 offset; + } + + pub(super) DATA(u8) @ 0x8 { + 7:0 data; + } + + pub(super) COUNT(u32) @ 0xC { + 31:0 count; + } + } + + pub(super) const END: usize =3D 0x10; } =20 -type Bar0 =3D pci::Bar<{ Regs::END }>; +type Bar0 =3D pci::Bar<{ regs::END }>; =20 #[derive(Copy, Clone, Debug)] struct TestIndex(u8); =20 +impl From> for TestIndex { + fn from(value: Bounded) -> Self { + Self(value.into()) + } +} + +impl From for Bounded { + fn from(value: TestIndex) -> Self { + value.0.into() + } +} + impl TestIndex { const NO_EVENTFD: Self =3D Self(0); } @@ -54,40 +85,53 @@ struct SampleDriver { impl SampleDriver { fn testdev(index: &TestIndex, bar: &Bar0) -> Result { // Select the test. - bar.write8(index.0, Regs::TEST); + bar.write_val(regs::TEST::zeroed().with_index(*index)); =20 - let offset =3D bar.read32(Regs::OFFSET) as usize; - let data =3D bar.read8(Regs::DATA); + let offset =3D bar.read(regs::OFFSET).into_raw() as usize; + let data =3D bar.read(regs::DATA).into(); =20 // Write `data` to `offset` to increase `count` by one. // // Note that we need `try_write8`, since `offset` can't be checked= at compile-time. bar.try_write8(data, offset)?; =20 - Ok(bar.read32(Regs::COUNT)) + Ok(bar.read(regs::COUNT).into()) } =20 fn config_space(pdev: &pci::Device) { let config =3D pdev.config_space(); =20 - // TODO: use the register!() macro for defining PCI configuration = space registers once it - // has been move out of nova-core. + // Some PCI configuration space registers. + register! { + VENDOR_ID(u16) @ 0x0 { + 15:0 vendor_id; + } + + REVISION_ID(u8) @ 0x8 { + 7:0 revision_id; + } + + BAR(u32)[6] @ 0x10 { + 31:0 value; + } + } + dev_info!( pdev, "pci-testdev config space read8 rev ID: {:x}\n", - config.read8(0x8) + config.read(REVISION_ID).revision_id() ); =20 dev_info!( pdev, "pci-testdev config space read16 vendor ID: {:x}\n", - config.read16(0) + config.read(VENDOR_ID).vendor_id() ); =20 dev_info!( pdev, "pci-testdev config space read32 BAR 0: {:x}\n", - config.read32(0x10) + config.read(BAR::at(0)).value() ); } } @@ -111,7 +155,7 @@ fn probe(pdev: &pci::Device, info: &Self::IdInfo)= -> impl PinInit(0, c"rust_= driver_pci"), + bar <- pdev.iomap_region_sized::<{ regs::END }>(0, c"rust_= driver_pci"), index: *info, _: { let bar =3D bar.access(pdev.as_ref())?; @@ -131,7 +175,7 @@ fn probe(pdev: &pci::Device, info: &Self::IdInfo)= -> impl PinInit, this: Pin<&Self>) { if let Ok(bar) =3D this.bar.access(pdev.as_ref()) { // Reset pci-testdev by writing a new test index. - bar.write8(this.index.0, Regs::TEST); + bar.write_val(regs::TEST::zeroed().with_index(this.index)); } } } --=20 2.53.0 From nobody Thu Apr 9 10:29:43 2026 Received: from CH1PR05CU001.outbound.protection.outlook.com (mail-northcentralusazon11010071.outbound.protection.outlook.com [52.101.193.71]) (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 5C1EC2222A9; Mon, 9 Mar 2026 15:15:19 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=52.101.193.71 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773069323; cv=fail; b=nPyK5y1fn322MbBnf/HIg03l6UCYBy33vT/tf/5IW6JF1CcdSRtnTOaP7qHM3DMcSVH0p1Eo8zO2TpkFp2OD/NAPRtEpUdzHSK1+NSrk/TozQguymdrZJqy3MGVlwNbz4+xXBogAQQc7gxcAQJhBlxoHFYQhY6QSs/UYkqG1S5E= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773069323; c=relaxed/simple; bh=A61V0lsXM+uiAnGrbhhGLHp0A9dQW3nU4C0TphGkDl0=; h=From:Date:Subject:Content-Type:Message-Id:References:In-Reply-To: To:Cc:MIME-Version; b=n7vJi2XQHnPMzW5O2fte4bEJvTbTIpCSQCtqZWYVtIulBCoLyx///3k9bCN8KlTJb/mmTWTb1ua4uE03gjxJP3tP1jmIZWGnTFgw1y8nDOigq5vgcFF64qhVNdWZ2YIgDEz9G2fUChwYFwfL/TFKiKRTfHZ5IuXtqaydad7dpgs= 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=XdR0O3Ti; arc=fail smtp.client-ip=52.101.193.71 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="XdR0O3Ti" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=UyrdJHU5R0lKJzxkT/2rKjbjdlQfy/6UWdeDDF+tBdylQqtXvtTB2+3xGqZ52G4BBXH+7YqtoowTSbBQhNbL/mUomKESY8SlMqtX6s4q+o9ZNQSYecTw55mzES9JY8AWfX6DyNm4cNq2rnzs3FxjFOPQS6ST554w3GnstaBkBEkxtShgViOqyGZX/QkESGXxTe5r2OxebovG3svw3QY9cIMnEpzeWonrn0whUO8mLkWtsfyBEzZ5T6iUAclfEGqcZrCnwDqSnSOphjzrEf7FGpDBCAg5vjlgEDsJC9Aqj6iU+kiIfPKYqCnSrXJ6zC47lLSwBW/iy/0fSVec0nR3lQ== 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=tEyfE33GgAb/DWOedJV9vfu5UiTC9l8epQsicraRsrc=; b=BkM2ymut+oz7dq43cdPw9uNaQmUwlaykjCWLLrPeelsCrn+NCZTskF+CWVLFfHAh5A9J17KAit67uxC2AFXxu0Xx7gY4RNL1qt2sDtB9lOVxxpfybuGEOS1mOTSnek+3aP/PhBCkXKOBVbH67AUAtFSoM8m589qDh6dCWO767wTc+nn6tNl+fqUMZoLeQ4HDzaq7owvsGp0ZRvz3ACE8lk68QUV21++kbdiZ9dRLOfWaSZdkBt3WJeOIEfIHeQSa7G5wXnF1JBxlxa5sxjKM6iUHCUFsUtiRFYhIgyxH7GnD1yduSOLNcGdEt1mHjtqWoksc5HbmUPpdsPYfpOL1UQ== 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=tEyfE33GgAb/DWOedJV9vfu5UiTC9l8epQsicraRsrc=; b=XdR0O3TizGZuEEtAak5ZRDFk6swWq6BuICauKRVxHTRChLQ8fE8m7Bm7TbnI0UvIY+Wp641+DAUB6tKVh3IBc1Cgi8qvBuQ8z3GtyiV18j6NcBctIjPQa+DZxBXp4offMmJYHeru/W7LHvLrpLsOczgUiwhYL48JcG7+O37W6T7PdZrjTLKNHfc3nn76Wng4QkuWNYkySqFmTOTJDnwxnJuXMRdLXt66mPIQcTmxSy03doA529GKt6ofIhyjke1UoEwEFIfx9DM1oznPw0vJoxdyySEPXLE88YpDZY4lcgpEPI8yHKAAu7BPqWL4r7w7oRIVxXsj3CIqdim2sC4SLg== 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 CY5PR12MB6131.namprd12.prod.outlook.com (2603:10b6:930:25::10) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.9700.11; Mon, 9 Mar 2026 15:14:52 +0000 Received: from CH2PR12MB3990.namprd12.prod.outlook.com ([fe80::7de1:4fe5:8ead:5989]) by CH2PR12MB3990.namprd12.prod.outlook.com ([fe80::7de1:4fe5:8ead:5989%6]) with mapi id 15.20.9700.009; Mon, 9 Mar 2026 15:14:52 +0000 From: Alexandre Courbot Date: Tue, 10 Mar 2026 00:14:07 +0900 Subject: [PATCH FOR REFERENCE v8 10/10] gpu: nova-core: use the kernel `register!` macro Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260310-register-v8-10-424f80dd43bc@nvidia.com> References: <20260310-register-v8-0-424f80dd43bc@nvidia.com> In-Reply-To: <20260310-register-v8-0-424f80dd43bc@nvidia.com> To: Danilo Krummrich , Alice Ryhl , Daniel Almeida , Miguel Ojeda , Gary Guo , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Andreas Hindborg , Trevor Gross , Boqun Feng Cc: Yury Norov , John Hubbard , Alistair Popple , Joel Fernandes , Timur Tabi , Edwin Peer , Eliot Courtney , Dirk Behme , Steven Price , rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, Alexandre Courbot X-Mailer: b4 0.14.3 X-ClientProxiedBy: TYCP286CA0233.JPNP286.PROD.OUTLOOK.COM (2603:1096:400:3c7::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_|CY5PR12MB6131:EE_ X-MS-Office365-Filtering-Correlation-Id: 273211b9-3816-4cbc-e312-08de7dee9c83 X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|10070799003|376014|7416014|1800799024|366016|921020; X-Microsoft-Antispam-Message-Info: 8CZTOLoH66AyCYDaqyo/K7coMNltTYSftKfMa5TloZPwWhei3CwBkL25WZO0VYaYIHn1zDpjNtO41yrBO+5GeiAT+UavbxnpmHqbQAjDi2PWKyN8pc7cYIG88czE1v9OTVckf2o7Lh7CgIeQtp1LR+GoTP/l/pghhGoBZ96bJnHh8Dfj35M80El/jsOVdBmVhuUxy9iKk1aYnn2BnioAj2inaf/wt/YL4VDQu8L5GbOtceRF81X2MKe6Gc/DCyeYa8W0Xhu6USEOKN6Hw3n5m5/EyIXHztW3U+s+xj6+2OAtf8U9vjDsQKzjm7EK2IIXLtW5xAA5KKe1fUy5rRtb4VaX4iT4FpyNPmb42YaWuHHpzMugc8CzpW0KIDNiVmNK366wW5PjsSLKt8fQ+ViqQwF7dzF5Ig0IMP+xMNyDwUF9hp1gKfCwfHeOW81O7LzYD4MMwv1FNlHw0kt+/P8ky7rEju+tCFqA7StrqE34UiTXioL4Oo1NXBtQ1nu6dhvDmotYk8RuMnTga9hOu4FSjfWLyf5OEdvfJfl5M0wjo9nbIad/jZfiiNfTQEvFDFlKjRCoxdfO6JatFgkgoW6mwde1ZYIW+xGfTLLXNO74v0O0YcI/vswJm9+Dspj2KURQC2GAHwlCzEDvhz4fR8sveGyOGavcXPIbhTXAR7nh+gLqcl4XSGG72uukZhs0Gfmx+fbb4AUHwAITDWfac9kn3vqE+6Q+ZliXjB+Yzs8VVJpiW3gLa2iSNvNyLtzCa2cbvgZjwyuEhsNmpo68PzxUZwVkNlZriDwgQ5ZXNgg0bGc= 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)(10070799003)(376014)(7416014)(1800799024)(366016)(921020);DIR:OUT;SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 2 X-MS-Exchange-AntiSpam-MessageData-0: =?utf-8?B?U0srWW1adUJuckVSWWRQUFpLbEttQzJna3JvRVg3em1pWFRqL3JmOXYzZENY?= =?utf-8?B?OXBadW5VWkcxWU8vaGtqVno2aE5mYVFhdjZtSStURDZraVJtcmVCVkVERDUx?= =?utf-8?B?bm00QVBCYWpqRlNMblg0cTFzWGw5U25jWjhtckRhVUZjOTZCVjcycjFKNTJl?= =?utf-8?B?ZVRxMnhHdmhjdkdENGNlSHpSeE4ybVVpV2JtYjdGWWN0eVN3bXI0Tk10eDNv?= =?utf-8?B?UnNrU0pXTnJTa3JmSTNDSVVjRkI1Z1RmRjkxQndubk80S0FoQUVBdFhNSWFV?= =?utf-8?B?NGZUZUhzSHZmRE0zZmpUK3lwQm5WT0FLdFBTWUljbW45TElwSWprOFQ5YUdv?= =?utf-8?B?MGZkb3ZzSldCc21maWdRZWFPamc2aUxXUC9ZWFpxYThPbDY0SmdLYjg0RnZy?= =?utf-8?B?eURJVHRWR1BjeG5tNFVRU2R4STdTNFQxNHVqTENvNWtnSzhsT2t4MEpFVFVI?= =?utf-8?B?YzFnNmdIMVE5SHBPekNDWWlNTFhxK092QjZyNlBqUFNQSFBUUUR2YWdzQlAx?= =?utf-8?B?T0xyb24yMkdIRlNocVJMV2gvMkZaR0swKzRGaTRFaEhTRlZ1ZjFRQXN2RmVa?= =?utf-8?B?TjBLVHI3eGd4bGhvSjFRRGFBdDdHQmM4bjFoSThBbFNnb1RRVnlUaVBBVk80?= =?utf-8?B?QnFqM2ptSTgxOUtNWUtWZUROdnU0dXpOQWVEd0FpVUQvRWFTcUx1TFpSWC9Z?= =?utf-8?B?eE9yNGx4UVREUXJHM1NNRmI5ZGtMYS9CNVFYMWZKVisvMC9PNCt2TDI4cjZK?= =?utf-8?B?NnJ2TEtnUUxUWFZKMWVFNG9vMnBLVUIwOTlzK09NeDFEa3k5L0FBQ3JVcEZK?= =?utf-8?B?Mm42a21xM2VOM0V5ZUNqcmtBOXZaZUhSVHo3Zmc0YnBQNEQ3RzZkQklWNHQ4?= =?utf-8?B?MnZXK0xBazJUQVNKd1M1QW1jZHcySEhDa0pOVzRJMVlYN2l1aGE3cVR0RUt6?= =?utf-8?B?cEV2S2l6NnZyaXZaMnRBd0QzQmlBZ2h2MndzTzVDeS9abGF2cFZneWtsbm0z?= =?utf-8?B?bm5kcjlsN1JhS0hmNGNjK0dNUnl2Q0ZIendsOFVVSzg1RTRPMU45dEtFeHFo?= =?utf-8?B?VjI0SVVMQVNRVENLTFRPMWsxV1JRT3RsdW54ZG95akRpM1h2RVl3c21XbXEv?= =?utf-8?B?c29vYU9vb214NWQ1dlovNzBDemdKNjcrMHYxR1E1VG96MU1saXRGT2ExbEhS?= =?utf-8?B?b0hTVTlqZHZoWHVmUlMwRGhZaUtSMGZEcUtGcmFOUFVrUVZqcFZpOHg5NDA0?= =?utf-8?B?ZnlIQ2JqYW9TOUR3Mys4K3h2ekxrckx6VjVRUG5BRGdEYmdQN2hyUEl6b1RM?= =?utf-8?B?RTFIRE1yYnVwelFvMmlBRVBmU0tiNTlrSVRucFNKcEZxVXhrRXF6NXQ0QWUv?= =?utf-8?B?R0N5V00wa3gyR2pFMStwV1hhWVZOYTh4a2FNSjhsU25GZ0VKbGhnd2pwS0V4?= =?utf-8?B?dHczL3duaFdFVGl6T25Pcndhd3hKTWxMY0Z5MjZXVmEzSGxQWnhtVCtHYUZO?= =?utf-8?B?b1g5LzVYRmNIQzFkSzV5Y2RjdURVbDNUb0pMUlNJc2FNSGNTNk4wUnppaGpv?= =?utf-8?B?cm9zRWRxbGNMODhQdlhidGRSQllnaHNCdjJsNFBEZVZzSGNkb0sycjBsVE10?= =?utf-8?B?RHF5MjdUTmp6aDVkc1BESDY5VG41ME1rMFZlZm1hSTFMVjBhS2RVZ0NobGRu?= =?utf-8?B?QlJ3S0hleDl0bWRLamhGbDYwSHFvNEM1R2xKR2F6ekMvbjBqMnB0NGFpM2hN?= =?utf-8?B?THR5S2xGZTRJVTAvTGtmenI2N09NZXdwU3MxVjVoczNiaUJ2cGlqVGdDUjE2?= =?utf-8?B?VDB5emdiNEFESWJ0Um9Wb2NlaDlsbU4zWjFOSTFsZEtCQ3I5MWtDOU9mWGE3?= =?utf-8?B?U1lXQU9WRm1tUzZ6SGwvaThwODV4RC9jREdZcGhHQ2NoM1NsUUQ3L0J0amRX?= =?utf-8?B?UEdDL1hMTnRKRzNnUkRhdzhITUc5RytMUkFUc05PM0wzVm1QeFl1SUs3L2pD?= =?utf-8?B?ZytScGNYZTdsa2lvZFlJQStGWmt3ZTJUbE1CQXhIa2Z6VURIbGlDY280NTZi?= =?utf-8?B?b2hLYzI1THpXOEFuREN3NlpJaE9pV3RLM2V6ZVpsOHJaaTNCdlpjRXNuZmhD?= =?utf-8?B?a2dnaTI2dXRDMzFJbklBZDVIZ2NRck81OVNCVEtQWVdNK3A4L29aQThFVERk?= =?utf-8?B?WTZ2Rk4xd0ordlhxWnExRmlwUGF3WGluM2I1aXA2MkJKcjJoMU9BL3NkR1Bz?= =?utf-8?B?U09SZzJIR2RIaDR0SWREQzFwQ1k4M0EyeU9uelc3NTg5MzI2TGlUWGNIblZ3?= =?utf-8?B?eWUxelIxSUw1MlpUUHE4d3YrNDEzSTV5RG42Tm1UTnJwNnJ2cUQ4cFNGTGw4?= =?utf-8?Q?89b5DlRPmT8I89oEdpBE2ifKC0/uMolrfTLU/H+/nEQDI?= X-MS-Exchange-AntiSpam-MessageData-1: 044uGQG76mIdmw== X-OriginatorOrg: Nvidia.com X-MS-Exchange-CrossTenant-Network-Message-Id: 273211b9-3816-4cbc-e312-08de7dee9c83 X-MS-Exchange-CrossTenant-AuthSource: CH2PR12MB3990.namprd12.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 09 Mar 2026 15:14:51.9629 (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: FfwpNWtiZaJtfu4A2eF2u/jwpGab/ORacP75JJAfsvpLVSRlNQ77spbHJApA95rZS9ybTr7C94o9ZioiaHdYBw== X-MS-Exchange-Transport-CrossTenantHeadersStamped: CY5PR12MB6131 Replace the nova-core internal `register!` macro by the one defined in the `kernel` crate and remove our own private implementations. Signed-off-by: Alexandre Courbot --- drivers/gpu/nova-core/falcon.rs | 330 ++++----- drivers/gpu/nova-core/falcon/gsp.rs | 25 +- drivers/gpu/nova-core/falcon/hal/ga102.rs | 70 +- drivers/gpu/nova-core/falcon/hal/tu102.rs | 12 +- drivers/gpu/nova-core/falcon/sec2.rs | 17 +- drivers/gpu/nova-core/fb.rs | 6 +- drivers/gpu/nova-core/fb/hal/ga100.rs | 37 +- drivers/gpu/nova-core/fb/hal/ga102.rs | 7 +- drivers/gpu/nova-core/fb/hal/tu102.rs | 17 +- drivers/gpu/nova-core/firmware/fwsec/bootloader.rs | 16 +- drivers/gpu/nova-core/gfw.rs | 11 +- drivers/gpu/nova-core/gpu.rs | 36 +- drivers/gpu/nova-core/gsp/boot.rs | 11 +- drivers/gpu/nova-core/gsp/cmdq.rs | 9 +- drivers/gpu/nova-core/regs.rs | 612 +++++++++-------- drivers/gpu/nova-core/regs/macros.rs | 739 -----------------= ---- 16 files changed, 667 insertions(+), 1288 deletions(-) diff --git a/drivers/gpu/nova-core/falcon.rs b/drivers/gpu/nova-core/falcon= .rs index 7097a206ec3c..a2611e6bba90 100644 --- a/drivers/gpu/nova-core/falcon.rs +++ b/drivers/gpu/nova-core/falcon.rs @@ -13,7 +13,12 @@ DmaAddress, DmaMask, // }, - io::poll::read_poll_timeout, + io::{ + poll::read_poll_timeout, + register::{RegisterBase, WithBase}, + Io, + }, + num::Bounded, prelude::*, sync::aref::ARef, time::Delta, @@ -30,7 +35,6 @@ IntoSafeCast, // }, regs, - regs::macros::RegisterBase, // }; =20 pub(crate) mod gsp; @@ -41,11 +45,11 @@ pub(crate) const MEM_BLOCK_ALIGNMENT: usize =3D 256; =20 // TODO[FPRI]: Replace with `ToPrimitive`. -macro_rules! impl_from_enum_to_u8 { - ($enum_type:ty) =3D> { - impl From<$enum_type> for u8 { +macro_rules! impl_from_enum_to_bounded { + ($enum_type:ty, $length:literal) =3D> { + impl From<$enum_type> for Bounded { fn from(value: $enum_type) -> Self { - value as u8 + Bounded::from_expr(value as u32) } } }; @@ -53,10 +57,8 @@ fn from(value: $enum_type) -> Self { =20 /// Revision number of a falcon core, used in the [`crate::regs::NV_PFALCO= N_FALCON_HWCFG1`] /// register. -#[repr(u8)] -#[derive(Debug, Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] +#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] pub(crate) enum FalconCoreRev { - #[default] Rev1 =3D 1, Rev2 =3D 2, Rev3 =3D 3, @@ -65,16 +67,16 @@ pub(crate) enum FalconCoreRev { Rev6 =3D 6, Rev7 =3D 7, } -impl_from_enum_to_u8!(FalconCoreRev); +impl_from_enum_to_bounded!(FalconCoreRev, 4); =20 // TODO[FPRI]: replace with `FromPrimitive`. -impl TryFrom for FalconCoreRev { +impl TryFrom> for FalconCoreRev { type Error =3D Error; =20 - fn try_from(value: u8) -> Result { + fn try_from(value: Bounded) -> Result { use FalconCoreRev::*; =20 - let rev =3D match value { + let rev =3D match value.get() { 1 =3D> Rev1, 2 =3D> Rev2, 3 =3D> Rev3, @@ -91,46 +93,38 @@ fn try_from(value: u8) -> Result { =20 /// Revision subversion number of a falcon core, used in the /// [`crate::regs::NV_PFALCON_FALCON_HWCFG1`] register. -#[repr(u8)] -#[derive(Debug, Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] +#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] pub(crate) enum FalconCoreRevSubversion { - #[default] Subversion0 =3D 0, Subversion1 =3D 1, Subversion2 =3D 2, Subversion3 =3D 3, } -impl_from_enum_to_u8!(FalconCoreRevSubversion); +impl_from_enum_to_bounded!(FalconCoreRevSubversion, 2); =20 // TODO[FPRI]: replace with `FromPrimitive`. -impl TryFrom for FalconCoreRevSubversion { - type Error =3D Error; - - fn try_from(value: u8) -> Result { +impl From> for FalconCoreRevSubversion { + fn from(value: Bounded) -> Self { use FalconCoreRevSubversion::*; =20 - let sub_version =3D match value & 0b11 { + match value.get() { 0 =3D> Subversion0, 1 =3D> Subversion1, 2 =3D> Subversion2, 3 =3D> Subversion3, - _ =3D> return Err(EINVAL), - }; - - Ok(sub_version) + // SAFETY: `value` comes from a 2-bit `Bounded`, and we just c= hecked all possible + // values. + _ =3D> unsafe { core::hint::unreachable_unchecked() }, + } } } =20 -/// Security model of a falcon core, used in the [`crate::regs::NV_PFALCON= _FALCON_HWCFG1`] -/// register. -#[repr(u8)] -#[derive(Debug, Default, Copy, Clone)] /// Security mode of the Falcon microprocessor. /// /// See `falcon.rst` for more details. +#[derive(Debug, Copy, Clone)] pub(crate) enum FalconSecurityModel { /// Non-Secure: runs unsigned code without privileges. - #[default] None =3D 0, /// Light-Secured (LS): Runs signed code with some privileges. /// Entry into this mode is only possible from 'Heavy-secure' mode, wh= ich verifies the code's @@ -144,16 +138,16 @@ pub(crate) enum FalconSecurityModel { /// Also known as High-Secure, Privilege Level 3 or PL3. Heavy =3D 3, } -impl_from_enum_to_u8!(FalconSecurityModel); +impl_from_enum_to_bounded!(FalconSecurityModel, 2); =20 // TODO[FPRI]: replace with `FromPrimitive`. -impl TryFrom for FalconSecurityModel { +impl TryFrom> for FalconSecurityModel { type Error =3D Error; =20 - fn try_from(value: u8) -> Result { + fn try_from(value: Bounded) -> Result { use FalconSecurityModel::*; =20 - let sec_model =3D match value { + let sec_model =3D match value.get() { 0 =3D> None, 2 =3D> Light, 3 =3D> Heavy, @@ -166,24 +160,22 @@ fn try_from(value: u8) -> Result { =20 /// Signing algorithm for a given firmware, used in the [`crate::regs::NV_= PFALCON2_FALCON_MOD_SEL`] /// register. It is passed to the Falcon Boot ROM (BROM) as a parameter. -#[repr(u8)] -#[derive(Debug, Default, Copy, Clone, PartialEq, Eq)] +#[derive(Debug, Copy, Clone, PartialEq, Eq)] pub(crate) enum FalconModSelAlgo { /// AES. - #[expect(dead_code)] Aes =3D 0, /// RSA3K. - #[default] Rsa3k =3D 1, } -impl_from_enum_to_u8!(FalconModSelAlgo); +impl_from_enum_to_bounded!(FalconModSelAlgo, 8); =20 // TODO[FPRI]: replace with `FromPrimitive`. -impl TryFrom for FalconModSelAlgo { +impl TryFrom> for FalconModSelAlgo { type Error =3D Error; =20 - fn try_from(value: u8) -> Result { - match value { + fn try_from(value: Bounded) -> Result { + match value.get() { + 0 =3D> Ok(FalconModSelAlgo::Aes), 1 =3D> Ok(FalconModSelAlgo::Rsa3k), _ =3D> Err(EINVAL), } @@ -191,21 +183,19 @@ fn try_from(value: u8) -> Result { } =20 /// Valid values for the `size` field of the [`crate::regs::NV_PFALCON_FAL= CON_DMATRFCMD`] register. -#[repr(u8)] -#[derive(Debug, Default, Copy, Clone, PartialEq, Eq)] +#[derive(Debug, Copy, Clone, PartialEq, Eq)] pub(crate) enum DmaTrfCmdSize { /// 256 bytes transfer. - #[default] Size256B =3D 0x6, } -impl_from_enum_to_u8!(DmaTrfCmdSize); +impl_from_enum_to_bounded!(DmaTrfCmdSize, 3); =20 // TODO[FPRI]: replace with `FromPrimitive`. -impl TryFrom for DmaTrfCmdSize { +impl TryFrom> for DmaTrfCmdSize { type Error =3D Error; =20 - fn try_from(value: u8) -> Result { - match value { + fn try_from(value: Bounded) -> Result { + match value.get() { 0x6 =3D> Ok(Self::Size256B), _ =3D> Err(EINVAL), } @@ -213,33 +203,24 @@ fn try_from(value: u8) -> Result { } =20 /// Currently active core on a dual falcon/riscv (Peregrine) controller. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] pub(crate) enum PeregrineCoreSelect { /// Falcon core is active. - #[default] Falcon =3D 0, /// RISC-V core is active. Riscv =3D 1, } +impl_from_enum_to_bounded!(PeregrineCoreSelect, 1); =20 -impl From for PeregrineCoreSelect { - fn from(value: bool) -> Self { - match value { +impl From> for PeregrineCoreSelect { + fn from(value: Bounded) -> Self { + match bool::from(value) { false =3D> PeregrineCoreSelect::Falcon, true =3D> PeregrineCoreSelect::Riscv, } } } =20 -impl From for bool { - fn from(value: PeregrineCoreSelect) -> Self { - match value { - PeregrineCoreSelect::Falcon =3D> false, - PeregrineCoreSelect::Riscv =3D> true, - } - } -} - /// Different types of memory present in a falcon core. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub(crate) enum FalconMem { @@ -255,10 +236,8 @@ pub(crate) enum FalconMem { /// Defines the Framebuffer Interface (FBIF) aperture type. /// This determines the memory type for external memory access during a DM= A transfer, which is /// performed by the Falcon's Framebuffer DMA (FBDMA) engine. See falcon.r= st for more details. -#[derive(Debug, Clone, Default)] +#[derive(Debug, Clone)] pub(crate) enum FalconFbifTarget { - /// VRAM. - #[default] /// Local Framebuffer (GPU's VRAM memory). LocalFb =3D 0, /// Coherent system memory (System DRAM). @@ -266,14 +245,14 @@ pub(crate) enum FalconFbifTarget { /// Non-coherent system memory (System DRAM). NoncoherentSysmem =3D 2, } -impl_from_enum_to_u8!(FalconFbifTarget); +impl_from_enum_to_bounded!(FalconFbifTarget, 2); =20 // TODO[FPRI]: replace with `FromPrimitive`. -impl TryFrom for FalconFbifTarget { +impl TryFrom> for FalconFbifTarget { type Error =3D Error; =20 - fn try_from(value: u8) -> Result { - let res =3D match value { + fn try_from(value: Bounded) -> Result { + let res =3D match value.get() { 0 =3D> Self::LocalFb, 1 =3D> Self::CoherentSysmem, 2 =3D> Self::NoncoherentSysmem, @@ -285,34 +264,25 @@ fn try_from(value: u8) -> Result { } =20 /// Type of memory addresses to use. -#[derive(Debug, Clone, Default)] +#[derive(Debug, Clone)] pub(crate) enum FalconFbifMemType { /// Virtual memory addresses. - #[default] Virtual =3D 0, /// Physical memory addresses. Physical =3D 1, } +impl_from_enum_to_bounded!(FalconFbifMemType, 1); =20 /// Conversion from a single-bit register field. -impl From for FalconFbifMemType { - fn from(value: bool) -> Self { - match value { +impl From> for FalconFbifMemType { + fn from(value: Bounded) -> Self { + match bool::from(value) { false =3D> Self::Virtual, true =3D> Self::Physical, } } } =20 -impl From for bool { - fn from(value: FalconFbifMemType) -> Self { - match value { - FalconFbifMemType::Virtual =3D> false, - FalconFbifMemType::Physical =3D> true, - } - } -} - /// Type used to represent the `PFALCON` registers address base for a give= n falcon engine. pub(crate) struct PFalconBase(()); =20 @@ -321,13 +291,10 @@ fn from(value: FalconFbifMemType) -> Self { =20 /// Trait defining the parameters of a given Falcon engine. /// -/// Each engine provides one base for `PFALCON` and `PFALCON2` registers. = The `ID` constant is used -/// to identify a given Falcon instance with register I/O methods. +/// Each engine provides one base for `PFALCON` and `PFALCON2` registers. pub(crate) trait FalconEngine: Send + Sync + RegisterBase + RegisterBase += Sized { - /// Singleton of the engine, used to identify it with register I/O met= hods. - const ID: Self; } =20 /// Represents a portion of the firmware to be loaded into a particular me= mory (e.g. IMEM or DMEM) @@ -521,8 +488,14 @@ pub(crate) fn new(dev: &device::Device, chipset: Chips= et) -> Result { =20 /// Resets DMA-related registers. pub(crate) fn dma_reset(&self, bar: &Bar0) { - regs::NV_PFALCON_FBIF_CTL::update(bar, &E::ID, |v| v.set_allow_phy= s_no_ctx(true)); - regs::NV_PFALCON_FALCON_DMACTL::default().write(bar, &E::ID); + bar.update(regs::NV_PFALCON_FBIF_CTL::of::(), |v| { + v.with_allow_phys_no_ctx(true) + }); + + bar.write( + WithBase::of::(), + regs::NV_PFALCON_FALCON_DMACTL::zeroed(), + ); } =20 /// Reset the controller, select the falcon core, and wait for memory = scrubbing to complete. @@ -531,9 +504,10 @@ pub(crate) fn reset(&self, bar: &Bar0) -> Result { self.hal.select_core(self, bar)?; self.hal.reset_wait_mem_scrubbing(bar)?; =20 - regs::NV_PFALCON_FALCON_RM::default() - .set_value(regs::NV_PMC_BOOT_0::read(bar).into()) - .write(bar, &E::ID); + bar.write( + WithBase::of::(), + regs::NV_PFALCON_FALCON_RM::from(bar.read(regs::NV_PMC_BOOT_0)= .into_raw()), + ); =20 Ok(()) } @@ -551,25 +525,27 @@ fn pio_wr_imem_slice(&self, bar: &Bar0, load_offsets:= FalconPioImemLoadTarget<'_ return Err(EINVAL); } =20 - regs::NV_PFALCON_FALCON_IMEMC::default() - .set_secure(load_offsets.secure) - .set_aincw(true) - .set_offs(load_offsets.dst_start) - .write(bar, &E::ID, Self::PIO_PORT); + bar.write( + WithBase::of::().at(Self::PIO_PORT), + regs::NV_PFALCON_FALCON_IMEMC::zeroed() + .with_secure(load_offsets.secure) + .with_aincw(true) + .with_offs(load_offsets.dst_start), + ); =20 for (n, block) in load_offsets.data.chunks(MEM_BLOCK_ALIGNMENT).en= umerate() { let n =3D u16::try_from(n)?; let tag: u16 =3D load_offsets.start_tag.checked_add(n).ok_or(E= RANGE)?; - regs::NV_PFALCON_FALCON_IMEMT::default().set_tag(tag).write( - bar, - &E::ID, - Self::PIO_PORT, + bar.write( + WithBase::of::().at(Self::PIO_PORT), + regs::NV_PFALCON_FALCON_IMEMT::zeroed().with_tag(tag), ); for word in block.chunks_exact(4) { let w =3D [word[0], word[1], word[2], word[3]]; - regs::NV_PFALCON_FALCON_IMEMD::default() - .set_data(u32::from_le_bytes(w)) - .write(bar, &E::ID, Self::PIO_PORT); + bar.write( + WithBase::of::().at(Self::PIO_PORT), + regs::NV_PFALCON_FALCON_IMEMD::zeroed().with_data(u32:= :from_le_bytes(w)), + ); } } =20 @@ -586,16 +562,19 @@ fn pio_wr_dmem_slice(&self, bar: &Bar0, load_offsets:= FalconPioDmemLoadTarget<'_ return Err(EINVAL); } =20 - regs::NV_PFALCON_FALCON_DMEMC::default() - .set_aincw(true) - .set_offs(load_offsets.dst_start) - .write(bar, &E::ID, Self::PIO_PORT); + bar.write( + WithBase::of::().at(Self::PIO_PORT), + regs::NV_PFALCON_FALCON_DMEMC::zeroed() + .with_aincw(true) + .with_offs(load_offsets.dst_start), + ); =20 for word in load_offsets.data.chunks_exact(4) { let w =3D [word[0], word[1], word[2], word[3]]; - regs::NV_PFALCON_FALCON_DMEMD::default() - .set_data(u32::from_le_bytes(w)) - .write(bar, &E::ID, Self::PIO_PORT); + bar.write( + WithBase::of::().at(Self::PIO_PORT), + regs::NV_PFALCON_FALCON_DMEMD::zeroed().with_data(u32::fro= m_le_bytes(w)), + ); } =20 Ok(()) @@ -607,11 +586,14 @@ pub(crate) fn pio_load + FalconPioLoadable>( bar: &Bar0, fw: &F, ) -> Result { - regs::NV_PFALCON_FBIF_CTL::read(bar, &E::ID) - .set_allow_phys_no_ctx(true) - .write(bar, &E::ID); + bar.update(regs::NV_PFALCON_FBIF_CTL::of::(), |v| { + v.with_allow_phys_no_ctx(true) + }); =20 - regs::NV_PFALCON_FALCON_DMACTL::default().write(bar, &E::ID); + bar.write( + WithBase::of::(), + regs::NV_PFALCON_FALCON_DMACTL::zeroed(), + ); =20 if let Some(imem_ns) =3D fw.imem_ns_load_params() { self.pio_wr_imem_slice(bar, imem_ns)?; @@ -623,9 +605,10 @@ pub(crate) fn pio_load= + FalconPioLoadable>( =20 self.hal.program_brom(self, bar, &fw.brom_params())?; =20 - regs::NV_PFALCON_FALCON_BOOTVEC::default() - .set_value(fw.boot_addr()) - .write(bar, &E::ID); + bar.write( + WithBase::of::(), + regs::NV_PFALCON_FALCON_BOOTVEC::zeroed().with_value(fw.boot_a= ddr()), + ); =20 Ok(()) } @@ -694,36 +677,42 @@ fn dma_wr( =20 // Set up the base source DMA address. =20 - regs::NV_PFALCON_FALCON_DMATRFBASE::default() - // CAST: `as u32` is used on purpose since we do want to strip= the upper bits, which - // will be written to `NV_PFALCON_FALCON_DMATRFBASE1`. - .set_base((dma_start >> 8) as u32) - .write(bar, &E::ID); - regs::NV_PFALCON_FALCON_DMATRFBASE1::default() - // CAST: `as u16` is used on purpose since the remaining bits = are guaranteed to fit - // within a `u16`. - .set_base((dma_start >> 40) as u16) - .write(bar, &E::ID); + bar.write( + WithBase::of::(), + regs::NV_PFALCON_FALCON_DMATRFBASE::zeroed().with_base( + // CAST: `as u32` is used on purpose since we do want to s= trip the upper bits, + // which will be written to `NV_PFALCON_FALCON_DMATRFBASE1= `. + (dma_start >> 8) as u32, + ), + ); + bar.write( + WithBase::of::(), + regs::NV_PFALCON_FALCON_DMATRFBASE1::zeroed().try_with_base(dm= a_start >> 40)?, + ); =20 - let cmd =3D regs::NV_PFALCON_FALCON_DMATRFCMD::default() - .set_size(DmaTrfCmdSize::Size256B) + let cmd =3D regs::NV_PFALCON_FALCON_DMATRFCMD::zeroed() + .with_size(DmaTrfCmdSize::Size256B) .with_falcon_mem(target_mem); =20 for pos in (0..num_transfers).map(|i| i * DMA_LEN) { // Perform a transfer of size `DMA_LEN`. - regs::NV_PFALCON_FALCON_DMATRFMOFFS::default() - .set_offs(load_offsets.dst_start + pos) - .write(bar, &E::ID); - regs::NV_PFALCON_FALCON_DMATRFFBOFFS::default() - .set_offs(src_start + pos) - .write(bar, &E::ID); - cmd.write(bar, &E::ID); + bar.write( + WithBase::of::(), + regs::NV_PFALCON_FALCON_DMATRFMOFFS::zeroed() + .try_with_offs(load_offsets.dst_start + pos)?, + ); + bar.write( + WithBase::of::(), + regs::NV_PFALCON_FALCON_DMATRFFBOFFS::zeroed().with_offs(s= rc_start + pos), + ); + + bar.write(WithBase::of::(), cmd); =20 // Wait for the transfer to complete. // TIMEOUT: arbitrarily large value, no DMA transfer to the fa= lcon's small memories // should ever take that long. read_poll_timeout( - || Ok(regs::NV_PFALCON_FALCON_DMATRFCMD::read(bar, &E::ID)= ), + || Ok(bar.read(regs::NV_PFALCON_FALCON_DMATRFCMD::of::(= ))), |r| r.idle(), Delta::ZERO, Delta::from_secs(2), @@ -744,9 +733,9 @@ fn dma_load + FalconDma= Loadable>( let dma_obj =3D DmaObject::from_data(dev, fw.as_slice())?; =20 self.dma_reset(bar); - regs::NV_PFALCON_FBIF_TRANSCFG::update(bar, &E::ID, 0, |v| { - v.set_target(FalconFbifTarget::CoherentSysmem) - .set_mem_type(FalconFbifMemType::Physical) + bar.update(regs::NV_PFALCON_FBIF_TRANSCFG::of::().at(0), |v| { + v.with_target(FalconFbifTarget::CoherentSysmem) + .with_mem_type(FalconFbifMemType::Physical) }); =20 self.dma_wr( @@ -760,9 +749,10 @@ fn dma_load + FalconDm= aLoadable>( self.hal.program_brom(self, bar, &fw.brom_params())?; =20 // Set `BootVec` to start of non-secure code. - regs::NV_PFALCON_FALCON_BOOTVEC::default() - .set_value(fw.boot_addr()) - .write(bar, &E::ID); + bar.write( + WithBase::of::(), + regs::NV_PFALCON_FALCON_BOOTVEC::zeroed().with_value(fw.boot_a= ddr()), + ); =20 Ok(()) } @@ -771,7 +761,7 @@ fn dma_load + FalconDma= Loadable>( pub(crate) fn wait_till_halted(&self, bar: &Bar0) -> Result<()> { // TIMEOUT: arbitrarily large value, firmwares should complete in = less than 2 seconds. read_poll_timeout( - || Ok(regs::NV_PFALCON_FALCON_CPUCTL::read(bar, &E::ID)), + || Ok(bar.read(regs::NV_PFALCON_FALCON_CPUCTL::of::())), |r| r.halted(), Delta::ZERO, Delta::from_secs(2), @@ -782,13 +772,18 @@ pub(crate) fn wait_till_halted(&self, bar: &Bar0) -> = Result<()> { =20 /// Start the falcon CPU. pub(crate) fn start(&self, bar: &Bar0) -> Result<()> { - match regs::NV_PFALCON_FALCON_CPUCTL::read(bar, &E::ID).alias_en()= { - true =3D> regs::NV_PFALCON_FALCON_CPUCTL_ALIAS::default() - .set_startcpu(true) - .write(bar, &E::ID), - false =3D> regs::NV_PFALCON_FALCON_CPUCTL::default() - .set_startcpu(true) - .write(bar, &E::ID), + match bar + .read(regs::NV_PFALCON_FALCON_CPUCTL::of::()) + .alias_en() + { + true =3D> bar.write( + WithBase::of::(), + regs::NV_PFALCON_FALCON_CPUCTL_ALIAS::zeroed().with_startc= pu(true), + ), + false =3D> bar.write( + WithBase::of::(), + regs::NV_PFALCON_FALCON_CPUCTL::zeroed().with_startcpu(tru= e), + ), } =20 Ok(()) @@ -797,26 +792,30 @@ pub(crate) fn start(&self, bar: &Bar0) -> Result<()> { /// Writes values to the mailbox registers if provided. pub(crate) fn write_mailboxes(&self, bar: &Bar0, mbox0: Option, m= box1: Option) { if let Some(mbox0) =3D mbox0 { - regs::NV_PFALCON_FALCON_MAILBOX0::default() - .set_value(mbox0) - .write(bar, &E::ID); + bar.write( + WithBase::of::(), + regs::NV_PFALCON_FALCON_MAILBOX0::zeroed().with_value(mbox= 0), + ); } =20 if let Some(mbox1) =3D mbox1 { - regs::NV_PFALCON_FALCON_MAILBOX1::default() - .set_value(mbox1) - .write(bar, &E::ID); + bar.write( + WithBase::of::(), + regs::NV_PFALCON_FALCON_MAILBOX1::zeroed().with_value(mbox= 1), + ); } } =20 /// Reads the value from `mbox0` register. pub(crate) fn read_mailbox0(&self, bar: &Bar0) -> u32 { - regs::NV_PFALCON_FALCON_MAILBOX0::read(bar, &E::ID).value() + bar.read(regs::NV_PFALCON_FALCON_MAILBOX0::of::()) + .value() } =20 /// Reads the value from `mbox1` register. pub(crate) fn read_mailbox1(&self, bar: &Bar0) -> u32 { - regs::NV_PFALCON_FALCON_MAILBOX1::read(bar, &E::ID).value() + bar.read(regs::NV_PFALCON_FALCON_MAILBOX1::of::()) + .value() } =20 /// Reads values from both mailbox registers. @@ -881,8 +880,9 @@ pub(crate) fn load + Fa= lconDmaLoadable>( =20 /// Write the application version to the OS register. pub(crate) fn write_os_version(&self, bar: &Bar0, app_version: u32) { - regs::NV_PFALCON_FALCON_OS::default() - .set_value(app_version) - .write(bar, &E::ID); + bar.write( + WithBase::of::(), + regs::NV_PFALCON_FALCON_OS::zeroed().with_value(app_version), + ); } } diff --git a/drivers/gpu/nova-core/falcon/gsp.rs b/drivers/gpu/nova-core/fa= lcon/gsp.rs index 67edef3636c1..41b9fa49414c 100644 --- a/drivers/gpu/nova-core/falcon/gsp.rs +++ b/drivers/gpu/nova-core/falcon/gsp.rs @@ -1,7 +1,11 @@ // SPDX-License-Identifier: GPL-2.0 =20 use kernel::{ - io::poll::read_poll_timeout, + io::{ + poll::read_poll_timeout, + register::{RegisterBase, WithBase}, + Io, + }, prelude::*, time::Delta, // }; @@ -14,13 +18,9 @@ PFalcon2Base, PFalconBase, // }, - regs::{ - self, - macros::RegisterBase, // - }, + regs, }; =20 -/// Type specifying the `Gsp` falcon engine. Cannot be instantiated. pub(crate) struct Gsp(()); =20 impl RegisterBase for Gsp { @@ -31,23 +31,22 @@ impl RegisterBase for Gsp { const BASE: usize =3D 0x00111000; } =20 -impl FalconEngine for Gsp { - const ID: Self =3D Gsp(()); -} +impl FalconEngine for Gsp {} =20 impl Falcon { /// Clears the SWGEN0 bit in the Falcon's IRQ status clear register to /// allow GSP to signal CPU for processing new messages in message que= ue. pub(crate) fn clear_swgen0_intr(&self, bar: &Bar0) { - regs::NV_PFALCON_FALCON_IRQSCLR::default() - .set_swgen0(true) - .write(bar, &Gsp::ID); + bar.write( + WithBase::of::(), + regs::NV_PFALCON_FALCON_IRQSCLR::zeroed().with_swgen0(true), + ); } =20 /// Checks if GSP reload/resume has completed during the boot process. pub(crate) fn check_reload_completed(&self, bar: &Bar0, timeout: Delta= ) -> Result { read_poll_timeout( - || Ok(regs::NV_PGC6_BSI_SECURE_SCRATCH_14::read(bar)), + || Ok(bar.read(regs::NV_PGC6_BSI_SECURE_SCRATCH_14)), |val| val.boot_stage_3_handoff(), Delta::ZERO, timeout, diff --git a/drivers/gpu/nova-core/falcon/hal/ga102.rs b/drivers/gpu/nova-c= ore/falcon/hal/ga102.rs index 8f62df10da0a..e8c8414c90f2 100644 --- a/drivers/gpu/nova-core/falcon/hal/ga102.rs +++ b/drivers/gpu/nova-core/falcon/hal/ga102.rs @@ -4,7 +4,11 @@ =20 use kernel::{ device, - io::poll::read_poll_timeout, + io::{ + poll::read_poll_timeout, + register::{Array, WithBase}, + Io, + }, prelude::*, time::Delta, // }; @@ -25,15 +29,16 @@ use super::FalconHal; =20 fn select_core_ga102(bar: &Bar0) -> Result { - let bcr_ctrl =3D regs::NV_PRISCV_RISCV_BCR_CTRL::read(bar, &E::ID); + let bcr_ctrl =3D bar.read(regs::NV_PRISCV_RISCV_BCR_CTRL::of::()); if bcr_ctrl.core_select() !=3D PeregrineCoreSelect::Falcon { - regs::NV_PRISCV_RISCV_BCR_CTRL::default() - .set_core_select(PeregrineCoreSelect::Falcon) - .write(bar, &E::ID); + bar.write( + WithBase::of::(), + regs::NV_PRISCV_RISCV_BCR_CTRL::zeroed().with_core_select(Pere= grineCoreSelect::Falcon), + ); =20 // TIMEOUT: falcon core should take less than 10ms to report being= enabled. read_poll_timeout( - || Ok(regs::NV_PRISCV_RISCV_BCR_CTRL::read(bar, &E::ID)), + || Ok(bar.read(regs::NV_PRISCV_RISCV_BCR_CTRL::of::())), |r| r.valid(), Delta::ZERO, Delta::from_millis(10), @@ -60,34 +65,43 @@ fn signature_reg_fuse_version_ga102( =20 // `ucode_idx` is guaranteed to be in the range [0..15], making the `r= ead` calls provable valid // at build-time. - let reg_fuse_version =3D if engine_id_mask & 0x0001 !=3D 0 { - regs::NV_FUSE_OPT_FPF_SEC2_UCODE1_VERSION::read(bar, ucode_idx).da= ta() + let reg_fuse_version: u16 =3D if engine_id_mask & 0x0001 !=3D 0 { + bar.read(regs::NV_FUSE_OPT_FPF_SEC2_UCODE1_VERSION::at(ucode_idx)) + .data() } else if engine_id_mask & 0x0004 !=3D 0 { - regs::NV_FUSE_OPT_FPF_NVDEC_UCODE1_VERSION::read(bar, ucode_idx).d= ata() + bar.read(regs::NV_FUSE_OPT_FPF_NVDEC_UCODE1_VERSION::at(ucode_idx)) + .data() } else if engine_id_mask & 0x0400 !=3D 0 { - regs::NV_FUSE_OPT_FPF_GSP_UCODE1_VERSION::read(bar, ucode_idx).dat= a() + bar.read(regs::NV_FUSE_OPT_FPF_GSP_UCODE1_VERSION::at(ucode_idx)) + .data() } else { dev_err!(dev, "unexpected engine_id_mask {:#x}\n", engine_id_mask); return Err(EINVAL); - }; + } + .into(); =20 // TODO[NUMM]: replace with `last_set_bit` once it lands. Ok(u16::BITS - reg_fuse_version.leading_zeros()) } =20 fn program_brom_ga102(bar: &Bar0, params: &FalconBromPara= ms) -> Result { - regs::NV_PFALCON2_FALCON_BROM_PARAADDR::default() - .set_value(params.pkc_data_offset) - .write(bar, &E::ID, 0); - regs::NV_PFALCON2_FALCON_BROM_ENGIDMASK::default() - .set_value(u32::from(params.engine_id_mask)) - .write(bar, &E::ID); - regs::NV_PFALCON2_FALCON_BROM_CURR_UCODE_ID::default() - .set_ucode_id(params.ucode_id) - .write(bar, &E::ID); - regs::NV_PFALCON2_FALCON_MOD_SEL::default() - .set_algo(FalconModSelAlgo::Rsa3k) - .write(bar, &E::ID); + bar.write( + WithBase::of::().at(0), + regs::NV_PFALCON2_FALCON_BROM_PARAADDR::zeroed().with_value(params= .pkc_data_offset), + ); + bar.write( + WithBase::of::(), + regs::NV_PFALCON2_FALCON_BROM_ENGIDMASK::zeroed() + .with_value(u32::from(params.engine_id_mask)), + ); + bar.write( + WithBase::of::(), + regs::NV_PFALCON2_FALCON_BROM_CURR_UCODE_ID::zeroed().with_ucode_i= d(params.ucode_id), + ); + bar.write( + WithBase::of::(), + regs::NV_PFALCON2_FALCON_MOD_SEL::zeroed().with_algo(FalconModSelA= lgo::Rsa3k), + ); =20 Ok(()) } @@ -120,14 +134,14 @@ fn program_brom(&self, _falcon: &Falcon, bar: &Bar= 0, params: &FalconBromParam } =20 fn is_riscv_active(&self, bar: &Bar0) -> bool { - let cpuctl =3D regs::NV_PRISCV_RISCV_CPUCTL::read(bar, &E::ID); - cpuctl.active_stat() + bar.read(regs::NV_PRISCV_RISCV_CPUCTL::of::()) + .active_stat() } =20 fn reset_wait_mem_scrubbing(&self, bar: &Bar0) -> Result { // TIMEOUT: memory scrubbing should complete in less than 20ms. read_poll_timeout( - || Ok(regs::NV_PFALCON_FALCON_HWCFG2::read(bar, &E::ID)), + || Ok(bar.read(regs::NV_PFALCON_FALCON_HWCFG2::of::())), |r| r.mem_scrubbing_done(), Delta::ZERO, Delta::from_millis(20), @@ -136,12 +150,12 @@ fn reset_wait_mem_scrubbing(&self, bar: &Bar0) -> Res= ult { } =20 fn reset_eng(&self, bar: &Bar0) -> Result { - let _ =3D regs::NV_PFALCON_FALCON_HWCFG2::read(bar, &E::ID); + let _ =3D bar.read(regs::NV_PFALCON_FALCON_HWCFG2::of::()); =20 // According to OpenRM's `kflcnPreResetWait_GA102` documentation, = HW sometimes does not set // RESET_READY so a non-failing timeout is used. let _ =3D read_poll_timeout( - || Ok(regs::NV_PFALCON_FALCON_HWCFG2::read(bar, &E::ID)), + || Ok(bar.read(regs::NV_PFALCON_FALCON_HWCFG2::of::())), |r| r.reset_ready(), Delta::ZERO, Delta::from_micros(150), diff --git a/drivers/gpu/nova-core/falcon/hal/tu102.rs b/drivers/gpu/nova-c= ore/falcon/hal/tu102.rs index 7de6f24cc0a0..c7a90266cb44 100644 --- a/drivers/gpu/nova-core/falcon/hal/tu102.rs +++ b/drivers/gpu/nova-core/falcon/hal/tu102.rs @@ -3,7 +3,11 @@ use core::marker::PhantomData; =20 use kernel::{ - io::poll::read_poll_timeout, + io::{ + poll::read_poll_timeout, + register::WithBase, + Io, // + }, prelude::*, time::Delta, // }; @@ -49,14 +53,14 @@ fn program_brom(&self, _falcon: &Falcon, _bar: &Bar0= , _params: &FalconBromPar } =20 fn is_riscv_active(&self, bar: &Bar0) -> bool { - let cpuctl =3D regs::NV_PRISCV_RISCV_CORE_SWITCH_RISCV_STATUS::rea= d(bar, &E::ID); - cpuctl.active_stat() + bar.read(regs::NV_PRISCV_RISCV_CORE_SWITCH_RISCV_STATUS::of::()) + .active_stat() } =20 fn reset_wait_mem_scrubbing(&self, bar: &Bar0) -> Result { // TIMEOUT: memory scrubbing should complete in less than 10ms. read_poll_timeout( - || Ok(regs::NV_PFALCON_FALCON_DMACTL::read(bar, &E::ID)), + || Ok(bar.read(regs::NV_PFALCON_FALCON_DMACTL::of::())), |r| r.mem_scrubbing_done(), Delta::ZERO, Delta::from_millis(10), diff --git a/drivers/gpu/nova-core/falcon/sec2.rs b/drivers/gpu/nova-core/f= alcon/sec2.rs index b57d362e576a..91ec7d49c1f5 100644 --- a/drivers/gpu/nova-core/falcon/sec2.rs +++ b/drivers/gpu/nova-core/falcon/sec2.rs @@ -1,12 +1,11 @@ // SPDX-License-Identifier: GPL-2.0 =20 -use crate::{ - falcon::{ - FalconEngine, - PFalcon2Base, - PFalconBase, // - }, - regs::macros::RegisterBase, +use kernel::io::register::RegisterBase; + +use crate::falcon::{ + FalconEngine, + PFalcon2Base, + PFalconBase, // }; =20 /// Type specifying the `Sec2` falcon engine. Cannot be instantiated. @@ -20,6 +19,4 @@ impl RegisterBase for Sec2 { const BASE: usize =3D 0x00841000; } =20 -impl FalconEngine for Sec2 { - const ID: Self =3D Sec2(()); -} +impl FalconEngine for Sec2 {} diff --git a/drivers/gpu/nova-core/fb.rs b/drivers/gpu/nova-core/fb.rs index c62abcaed547..6b392588f766 100644 --- a/drivers/gpu/nova-core/fb.rs +++ b/drivers/gpu/nova-core/fb.rs @@ -4,6 +4,7 @@ =20 use kernel::{ device, + io::Io, prelude::*, ptr::{ Alignable, @@ -134,7 +135,10 @@ pub(crate) fn new(chipset: Chipset, bar: &Bar0, gsp_fw= : &GspFirmware) -> Result< let base =3D fb.end - NV_PRAMIN_SIZE; =20 if hal.supports_display(bar) { - match regs::NV_PDISP_VGA_WORKSPACE_BASE::read(bar).vga= _workspace_addr() { + match bar + .read(regs::NV_PDISP_VGA_WORKSPACE_BASE) + .vga_workspace_addr() + { Some(addr) =3D> { if addr < base { const VBIOS_WORKSPACE_SIZE: u64 =3D usize_= as_u64(SZ_128K); diff --git a/drivers/gpu/nova-core/fb/hal/ga100.rs b/drivers/gpu/nova-core/= fb/hal/ga100.rs index e0acc41aa7cd..bda343e73399 100644 --- a/drivers/gpu/nova-core/fb/hal/ga100.rs +++ b/drivers/gpu/nova-core/fb/hal/ga100.rs @@ -1,6 +1,10 @@ // SPDX-License-Identifier: GPL-2.0 =20 -use kernel::prelude::*; +use kernel::{ + io::Io, + num::Bounded, + prelude::*, // +}; =20 use crate::{ driver::Bar0, @@ -13,26 +17,31 @@ struct Ga100; =20 pub(super) fn read_sysmem_flush_page_ga100(bar: &Bar0) -> u64 { - u64::from(regs::NV_PFB_NISO_FLUSH_SYSMEM_ADDR::read(bar).adr_39_08()) = << FLUSH_SYSMEM_ADDR_SHIFT - | u64::from(regs::NV_PFB_NISO_FLUSH_SYSMEM_ADDR_HI::read(bar).adr_= 63_40()) + u64::from(bar.read(regs::NV_PFB_NISO_FLUSH_SYSMEM_ADDR).adr_39_08()) <= < FLUSH_SYSMEM_ADDR_SHIFT + | u64::from(bar.read(regs::NV_PFB_NISO_FLUSH_SYSMEM_ADDR_HI).adr_6= 3_40()) << FLUSH_SYSMEM_ADDR_SHIFT_HI } =20 pub(super) fn write_sysmem_flush_page_ga100(bar: &Bar0, addr: u64) { - regs::NV_PFB_NISO_FLUSH_SYSMEM_ADDR_HI::default() - // CAST: `as u32` is used on purpose since the remaining bits are = guaranteed to fit within - // a `u32`. - .set_adr_63_40((addr >> FLUSH_SYSMEM_ADDR_SHIFT_HI) as u32) - .write(bar); - regs::NV_PFB_NISO_FLUSH_SYSMEM_ADDR::default() - // CAST: `as u32` is used on purpose since we want to strip the up= per bits that have been - // written to `NV_PFB_NISO_FLUSH_SYSMEM_ADDR_HI`. - .set_adr_39_08((addr >> FLUSH_SYSMEM_ADDR_SHIFT) as u32) - .write(bar); + bar.write_val( + regs::NV_PFB_NISO_FLUSH_SYSMEM_ADDR_HI::zeroed().with_adr_63_40( + Bounded::::from(addr) + .shr::() + .cast(), + ), + ); + + bar.write_val( + regs::NV_PFB_NISO_FLUSH_SYSMEM_ADDR::zeroed() + // CAST: `as u32` is used on purpose since we want to strip th= e upper bits that have + // been written to `NV_PFB_NISO_FLUSH_SYSMEM_ADDR_HI`. + .with_adr_39_08((addr >> FLUSH_SYSMEM_ADDR_SHIFT) as u32), + ); } =20 pub(super) fn display_enabled_ga100(bar: &Bar0) -> bool { - !regs::ga100::NV_FUSE_STATUS_OPT_DISPLAY::read(bar).display_disabled() + !bar.read(regs::ga100::NV_FUSE_STATUS_OPT_DISPLAY) + .display_disabled() } =20 /// Shift applied to the sysmem address before it is written into diff --git a/drivers/gpu/nova-core/fb/hal/ga102.rs b/drivers/gpu/nova-core/= fb/hal/ga102.rs index 734605905031..4b9f0f74d0e7 100644 --- a/drivers/gpu/nova-core/fb/hal/ga102.rs +++ b/drivers/gpu/nova-core/fb/hal/ga102.rs @@ -1,6 +1,9 @@ // SPDX-License-Identifier: GPL-2.0 =20 -use kernel::prelude::*; +use kernel::{ + io::Io, + prelude::*, // +}; =20 use crate::{ driver::Bar0, @@ -9,7 +12,7 @@ }; =20 fn vidmem_size_ga102(bar: &Bar0) -> u64 { - regs::NV_USABLE_FB_SIZE_IN_MB::read(bar).usable_fb_size() + bar.read(regs::NV_USABLE_FB_SIZE_IN_MB).usable_fb_size() } =20 struct Ga102; diff --git a/drivers/gpu/nova-core/fb/hal/tu102.rs b/drivers/gpu/nova-core/= fb/hal/tu102.rs index eec984f4e816..2833c1c57ac9 100644 --- a/drivers/gpu/nova-core/fb/hal/tu102.rs +++ b/drivers/gpu/nova-core/fb/hal/tu102.rs @@ -1,6 +1,9 @@ // SPDX-License-Identifier: GPL-2.0 =20 -use kernel::prelude::*; +use kernel::{ + io::Io, + prelude::*, // +}; =20 use crate::{ driver::Bar0, @@ -13,7 +16,7 @@ pub(super) const FLUSH_SYSMEM_ADDR_SHIFT: u32 =3D 8; =20 pub(super) fn read_sysmem_flush_page_gm107(bar: &Bar0) -> u64 { - u64::from(regs::NV_PFB_NISO_FLUSH_SYSMEM_ADDR::read(bar).adr_39_08()) = << FLUSH_SYSMEM_ADDR_SHIFT + u64::from(bar.read(regs::NV_PFB_NISO_FLUSH_SYSMEM_ADDR).adr_39_08()) <= < FLUSH_SYSMEM_ADDR_SHIFT } =20 pub(super) fn write_sysmem_flush_page_gm107(bar: &Bar0, addr: u64) -> Resu= lt { @@ -21,18 +24,18 @@ pub(super) fn write_sysmem_flush_page_gm107(bar: &Bar0,= addr: u64) -> Result { u32::try_from(addr >> FLUSH_SYSMEM_ADDR_SHIFT) .map_err(|_| EINVAL) .map(|addr| { - regs::NV_PFB_NISO_FLUSH_SYSMEM_ADDR::default() - .set_adr_39_08(addr) - .write(bar) + bar.write_val(regs::NV_PFB_NISO_FLUSH_SYSMEM_ADDR::zeroed().wi= th_adr_39_08(addr)) }) } =20 pub(super) fn display_enabled_gm107(bar: &Bar0) -> bool { - !regs::gm107::NV_FUSE_STATUS_OPT_DISPLAY::read(bar).display_disabled() + !bar.read(regs::gm107::NV_FUSE_STATUS_OPT_DISPLAY) + .display_disabled() } =20 pub(super) fn vidmem_size_gp102(bar: &Bar0) -> u64 { - regs::NV_PFB_PRI_MMU_LOCAL_MEMORY_RANGE::read(bar).usable_fb_size() + bar.read(regs::NV_PFB_PRI_MMU_LOCAL_MEMORY_RANGE) + .usable_fb_size() } =20 struct Tu102; diff --git a/drivers/gpu/nova-core/firmware/fwsec/bootloader.rs b/drivers/g= pu/nova-core/firmware/fwsec/bootloader.rs index 342dba59b2f9..9a16d328685b 100644 --- a/drivers/gpu/nova-core/firmware/fwsec/bootloader.rs +++ b/drivers/gpu/nova-core/firmware/fwsec/bootloader.rs @@ -12,6 +12,10 @@ self, Device, // }, + io::{ + register::WithBase, // + Io, + }, prelude::*, ptr::{ Alignable, @@ -33,7 +37,6 @@ Falcon, FalconBromParams, FalconDmaLoadable, - FalconEngine, FalconFbifMemType, FalconFbifTarget, FalconFirmware, @@ -288,13 +291,12 @@ pub(crate) fn run( .inspect_err(|e| dev_err!(dev, "Failed to load FWSEC firmware:= {:?}\n", e))?; =20 // Configure DMA index for the bootloader to fetch the FWSEC firmw= are from system memory. - regs::NV_PFALCON_FBIF_TRANSCFG::try_update( - bar, - &Gsp::ID, - usize::from_safe_cast(self.dmem_desc.ctx_dma), + bar.try_update( + regs::NV_PFALCON_FBIF_TRANSCFG::of::() + .at(usize::from_safe_cast(self.dmem_desc.ctx_dma)), |v| { - v.set_target(FalconFbifTarget::CoherentSysmem) - .set_mem_type(FalconFbifMemType::Physical) + v.with_target(FalconFbifTarget::CoherentSysmem) + .with_mem_type(FalconFbifMemType::Physical) }, )?; =20 diff --git a/drivers/gpu/nova-core/gfw.rs b/drivers/gpu/nova-core/gfw.rs index 9121f400046d..fb75dd10a172 100644 --- a/drivers/gpu/nova-core/gfw.rs +++ b/drivers/gpu/nova-core/gfw.rs @@ -19,7 +19,10 @@ //! Note that the devinit sequence also needs to run during suspend/resume. =20 use kernel::{ - io::poll::read_poll_timeout, + io::{ + poll::read_poll_timeout, + Io, // + }, prelude::*, time::Delta, // }; @@ -58,9 +61,11 @@ pub(crate) fn wait_gfw_boot_completion(bar: &Bar0) -> Re= sult { Ok( // Check that FWSEC has lowered its protection level befor= e reading the GFW_BOOT // status. - regs::NV_PGC6_AON_SECURE_SCRATCH_GROUP_05_PRIV_LEVEL_MASK:= :read(bar) + bar.read(regs::NV_PGC6_AON_SECURE_SCRATCH_GROUP_05_PRIV_LE= VEL_MASK) .read_protection_level0() - && regs::NV_PGC6_AON_SECURE_SCRATCH_GROUP_05_0_GFW_BOO= T::read(bar).completed(), + && bar + .read(regs::NV_PGC6_AON_SECURE_SCRATCH_GROUP_05_0_= GFW_BOOT) + .completed(), ) }, |&gfw_booted| gfw_booted, diff --git a/drivers/gpu/nova-core/gpu.rs b/drivers/gpu/nova-core/gpu.rs index 8579d632e717..bb1c6bf88657 100644 --- a/drivers/gpu/nova-core/gpu.rs +++ b/drivers/gpu/nova-core/gpu.rs @@ -4,6 +4,8 @@ device, devres::Devres, fmt, + io::Io, + num::Bounded, pci, prelude::*, sync::Arc, // @@ -129,24 +131,19 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Res= ult { } =20 /// Enum representation of the GPU generation. -/// -/// TODO: remove the `Default` trait implementation, and the `#[default]` -/// attribute, once the register!() macro (which creates Architecture item= s) no -/// longer requires it for read-only fields. -#[derive(fmt::Debug, Default, Copy, Clone)] +#[derive(fmt::Debug, Copy, Clone)] #[repr(u8)] pub(crate) enum Architecture { - #[default] Turing =3D 0x16, Ampere =3D 0x17, Ada =3D 0x19, } =20 -impl TryFrom for Architecture { +impl TryFrom> for Architecture { type Error =3D Error; =20 - fn try_from(value: u8) -> Result { - match value { + fn try_from(value: Bounded) -> Result { + match u8::from(value) { 0x16 =3D> Ok(Self::Turing), 0x17 =3D> Ok(Self::Ampere), 0x19 =3D> Ok(Self::Ada), @@ -155,23 +152,26 @@ fn try_from(value: u8) -> Result { } } =20 -impl From for u8 { +impl From for Bounded { fn from(value: Architecture) -> Self { - // CAST: `Architecture` is `repr(u8)`, so this cast is always loss= less. - value as u8 + match value { + Architecture::Turing =3D> Bounded::::new::<0x16>().cast= (), + Architecture::Ampere =3D> Bounded::::new::<0x17>().cast= (), + Architecture::Ada =3D> Bounded::::new::<0x19>().cast(), + } } } =20 pub(crate) struct Revision { - major: u8, - minor: u8, + major: Bounded, + minor: Bounded, } =20 impl From for Revision { fn from(boot0: regs::NV_PMC_BOOT_42) -> Self { Self { - major: boot0.major_revision(), - minor: boot0.minor_revision(), + major: boot0.major_revision().cast(), + minor: boot0.minor_revision().cast(), } } } @@ -208,13 +208,13 @@ fn new(dev: &device::Device, bar: &Bar0) -> Result { // from an earlier (pre-Fermi) era, and then using boot42 to p= recisely identify the GPU. // Somewhere in the Rubin timeframe, boot0 will no longer have= space to add new GPU IDs. =20 - let boot0 =3D regs::NV_PMC_BOOT_0::read(bar); + let boot0 =3D bar.read(regs::NV_PMC_BOOT_0); =20 if boot0.is_older_than_fermi() { return Err(ENODEV); } =20 - let boot42 =3D regs::NV_PMC_BOOT_42::read(bar); + let boot42 =3D bar.read(regs::NV_PMC_BOOT_42); Spec::try_from(boot42).inspect_err(|_| { dev_err!(dev, "Unsupported chipset: {}\n", boot42); }) diff --git a/drivers/gpu/nova-core/gsp/boot.rs b/drivers/gpu/nova-core/gsp/= boot.rs index 9a00ddb922ac..d9d999519183 100644 --- a/drivers/gpu/nova-core/gsp/boot.rs +++ b/drivers/gpu/nova-core/gsp/boot.rs @@ -5,6 +5,7 @@ dma::CoherentAllocation, dma_write, io::poll::read_poll_timeout, + io::Io, pci, prelude::*, time::Delta, // @@ -57,7 +58,7 @@ fn run_fwsec_frts( ) -> Result<()> { // Check that the WPR2 region does not already exists - if it does= , we cannot run // FWSEC-FRTS until the GPU is reset. - if regs::NV_PFB_PRI_MMU_WPR2_ADDR_HI::read(bar).higher_bound() != =3D 0 { + if bar.read(regs::NV_PFB_PRI_MMU_WPR2_ADDR_HI).higher_bound() !=3D= 0 { dev_err!( dev, "WPR2 region already exists - GPU needs to be reset to pro= ceed\n" @@ -87,7 +88,9 @@ fn run_fwsec_frts( } =20 // SCRATCH_E contains the error code for FWSEC-FRTS. - let frts_status =3D regs::NV_PBUS_SW_SCRATCH_0E_FRTS_ERR::read(bar= ).frts_err_code(); + let frts_status =3D bar + .read(regs::NV_PBUS_SW_SCRATCH_0E_FRTS_ERR) + .frts_err_code(); if frts_status !=3D 0 { dev_err!( dev, @@ -100,8 +103,8 @@ fn run_fwsec_frts( =20 // Check that the WPR2 region has been created as we requested. let (wpr2_lo, wpr2_hi) =3D ( - regs::NV_PFB_PRI_MMU_WPR2_ADDR_LO::read(bar).lower_bound(), - regs::NV_PFB_PRI_MMU_WPR2_ADDR_HI::read(bar).higher_bound(), + bar.read(regs::NV_PFB_PRI_MMU_WPR2_ADDR_LO).lower_bound(), + bar.read(regs::NV_PFB_PRI_MMU_WPR2_ADDR_HI).higher_bound(), ); =20 match (wpr2_lo, wpr2_hi) { diff --git a/drivers/gpu/nova-core/gsp/cmdq.rs b/drivers/gpu/nova-core/gsp/= cmdq.rs index 87dbbd6d1be9..04a3ba4b9e05 100644 --- a/drivers/gpu/nova-core/gsp/cmdq.rs +++ b/drivers/gpu/nova-core/gsp/cmdq.rs @@ -15,7 +15,10 @@ DmaAddress, // }, dma_write, - io::poll::read_poll_timeout, + io::{ + poll::read_poll_timeout, + Io, // + }, prelude::*, sync::aref::ARef, time::Delta, @@ -488,9 +491,7 @@ fn calculate_checksum>(it: T) = -> u32 { =20 /// Notifies the GSP that we have updated the command queue pointers. fn notify_gsp(bar: &Bar0) { - regs::NV_PGSP_QUEUE_HEAD::default() - .set_address(0) - .write(bar); + bar.write_val(regs::NV_PGSP_QUEUE_HEAD::zeroed().with_address(0u32= )); } =20 /// Sends `command` to the GSP. diff --git a/drivers/gpu/nova-core/regs.rs b/drivers/gpu/nova-core/regs.rs index 53f412f0ca32..d65a7ceffd1b 100644 --- a/drivers/gpu/nova-core/regs.rs +++ b/drivers/gpu/nova-core/regs.rs @@ -1,13 +1,10 @@ // SPDX-License-Identifier: GPL-2.0 =20 -// Required to retain the original register names used by OpenRM, which ar= e all capital snake case -// but are mapped to types. -#![allow(non_camel_case_types)] - -#[macro_use] -pub(crate) mod macros; - use kernel::{ + io::{ + register::WithBase, + Io, // + }, prelude::*, time, // }; @@ -35,20 +32,64 @@ num::FromSafeCast, }; =20 +// All nova-core registers are 32-bit and `pub(crate)`. Wrap the `register= !` macro to avoid +// repeating this information for every register. +macro_rules! nv_reg { + ( + $( + $(#[$attr:meta])* $name:ident $([ $size:expr $(, stride =3D $s= tride:expr)? ])? + $(@ $offset:literal)? + $(@ $base:ident + $base_offset:literal)? + $(=3D> $alias:ident $(+ $alias_offset:ident)? $([$alias_id= x:expr])? )? + $(, $comment:literal)? { $($fields:tt)* } + )* + )=3D> { + $( + ::kernel::register!( + @reg $(#[$attr])* pub(crate) $name(u32) $([$size $(, stride = =3D $stride)?])? + $(@ $offset)? + $(@ $base + $base_offset)? + $(=3D> $alias $(+ $alias_offset)? $([$alias_idx])? )? + $(, $comment)? { $($fields)* } + ); + )* + }; +} + // PMC =20 -register!(NV_PMC_BOOT_0 @ 0x00000000, "Basic revision information about th= e GPU" { - 3:0 minor_revision as u8, "Minor revision of the chip"; - 7:4 major_revision as u8, "Major revision of the chip"; - 8:8 architecture_1 as u8, "MSB of the architecture"; - 23:20 implementation as u8, "Implementation version of the architect= ure"; - 28:24 architecture_0 as u8, "Lower bits of the architecture"; -}); +nv_reg! { + /// Basic revision information about the GPU. + NV_PMC_BOOT_0 @ 0x00000000 { + /// Minor revision of the chip. + 3:0 minor_revision; + /// Major revision of the chip. + 7:4 major_revision; + /// Meta-variable `newbase` repeats 0 times, but `offset` repeats = 1 time. + 8:8 architecture_1; + /// Implementation version of the architecture. + 23:20 implementation; + /// Lower bits of the architecture. + 28:24 architecture_0; + } + + /// Extended architecture information. + NV_PMC_BOOT_42 @ 0x00000a00 { + /// Minor revision of the chip. + 15:12 minor_revision; + /// Major revision of the chip. + 19:16 major_revision; + /// Implementation version of the architecture. + 23:20 implementation; + /// Architecture value. + 29:24 architecture ?=3D> Architecture; + } +} =20 impl NV_PMC_BOOT_0 { pub(crate) fn is_older_than_fermi(self) -> bool { // From https://github.com/NVIDIA/open-gpu-doc/tree/master/manuals= : - const NV_PMC_BOOT_0_ARCHITECTURE_GF100: u8 =3D 0xc; + const NV_PMC_BOOT_0_ARCHITECTURE_GF100: u32 =3D 0xc; =20 // Older chips left arch1 zeroed out. That, combined with an arch0= value that is less than // GF100, means "older than Fermi". @@ -56,13 +97,6 @@ pub(crate) fn is_older_than_fermi(self) -> bool { } } =20 -register!(NV_PMC_BOOT_42 @ 0x00000a00, "Extended architecture information"= { - 15:12 minor_revision as u8, "Minor revision of the chip"; - 19:16 major_revision as u8, "Major revision of the chip"; - 23:20 implementation as u8, "Implementation version of the architect= ure"; - 29:24 architecture as u8 ?=3D> Architecture, "Architecture value"; -}); - impl NV_PMC_BOOT_42 { /// Combines `architecture` and `implementation` to obtain a code uniq= ue to the chipset. pub(crate) fn chipset(self) -> Result { @@ -76,8 +110,8 @@ pub(crate) fn chipset(self) -> Result { =20 /// Returns the raw architecture value from the register. fn architecture_raw(self) -> u8 { - ((self.0 >> Self::ARCHITECTURE_RANGE.start()) & ((1 << Self::ARCHI= TECTURE_RANGE.len()) - 1)) - as u8 + ((self.inner >> Self::ARCHITECTURE_RANGE.start()) + & ((1 << Self::ARCHITECTURE_RANGE.len()) - 1)) as u8 } } =20 @@ -86,7 +120,7 @@ fn fmt(&self, f: &mut kernel::fmt::Formatter<'_>) -> ker= nel::fmt::Result { write!( f, "boot42 =3D 0x{:08x} (architecture 0x{:x}, implementation 0x{:= x})", - self.0, + self.inner, self.architecture_raw(), self.implementation() ) @@ -95,35 +129,50 @@ fn fmt(&self, f: &mut kernel::fmt::Formatter<'_>) -> k= ernel::fmt::Result { =20 // PBUS =20 -register!(NV_PBUS_SW_SCRATCH @ 0x00001400[64] {}); +nv_reg! { + NV_PBUS_SW_SCRATCH[64] @ 0x00001400 {} =20 -register!(NV_PBUS_SW_SCRATCH_0E_FRTS_ERR =3D> NV_PBUS_SW_SCRATCH[0xe], - "scratch register 0xe used as FRTS firmware error code" { - 31:16 frts_err_code as u16; -}); + /// Scratch register 0xe used as FRTS firmware error code. + NV_PBUS_SW_SCRATCH_0E_FRTS_ERR =3D> NV_PBUS_SW_SCRATCH[0xe] { + 31:16 frts_err_code; + } +} =20 // PFB =20 -// The following two registers together hold the physical system memory ad= dress that is used by the -// GPU to perform sysmembar operations (see `fb::SysmemFlush`). +nv_reg! { + /// Low bits of the physical system memory address used by the GPU to = perform sysmembar + /// operations (see [`crate::fb::SysmemFlush`]). + NV_PFB_NISO_FLUSH_SYSMEM_ADDR @ 0x00100c10 { + 31:0 adr_39_08; + } =20 -register!(NV_PFB_NISO_FLUSH_SYSMEM_ADDR @ 0x00100c10 { - 31:0 adr_39_08 as u32; -}); + /// High bits of the physical system memory address used by the GPU to= perform sysmembar + /// operations (see [`crate::fb::SysmemFlush`]). + NV_PFB_NISO_FLUSH_SYSMEM_ADDR_HI @ 0x00100c40 { + 23:0 adr_63_40; + } =20 -register!(NV_PFB_NISO_FLUSH_SYSMEM_ADDR_HI @ 0x00100c40 { - 23:0 adr_63_40 as u32; -}); + NV_PFB_PRI_MMU_LOCAL_MEMORY_RANGE @ 0x00100ce0 { + 3:0 lower_scale; + 9:4 lower_mag; + 30:30 ecc_mode_enabled =3D> bool; + } =20 -register!(NV_PFB_PRI_MMU_LOCAL_MEMORY_RANGE @ 0x00100ce0 { - 3:0 lower_scale as u8; - 9:4 lower_mag as u8; - 30:30 ecc_mode_enabled as bool; -}); + NV_PGSP_QUEUE_HEAD @ 0x00110c00 { + 31:0 address; + } =20 -register!(NV_PGSP_QUEUE_HEAD @ 0x00110c00 { - 31:0 address as u32; -}); + NV_PFB_PRI_MMU_WPR2_ADDR_LO @ 0x001fa824 { + /// Bits 12..40 of the lower (inclusive) bound of the WPR2 region. + 31:4 lo_val; + } + + NV_PFB_PRI_MMU_WPR2_ADDR_HI @ 0x001fa828 { + /// Bits 12..40 of the higher (exclusive) bound of the WPR2 region. + 31:4 hi_val; + } +} =20 impl NV_PFB_PRI_MMU_LOCAL_MEMORY_RANGE { /// Returns the usable framebuffer size, in bytes. @@ -140,10 +189,6 @@ pub(crate) fn usable_fb_size(self) -> u64 { } } =20 -register!(NV_PFB_PRI_MMU_WPR2_ADDR_LO@0x001fa824 { - 31:4 lo_val as u32, "Bits 12..40 of the lower (inclusive) bound of = the WPR2 region"; -}); - impl NV_PFB_PRI_MMU_WPR2_ADDR_LO { /// Returns the lower (inclusive) bound of the WPR2 region. pub(crate) fn lower_bound(self) -> u64 { @@ -151,10 +196,6 @@ pub(crate) fn lower_bound(self) -> u64 { } } =20 -register!(NV_PFB_PRI_MMU_WPR2_ADDR_HI@0x001fa828 { - 31:4 hi_val as u32, "Bits 12..40 of the higher (exclusive) bound of= the WPR2 region"; -}); - impl NV_PFB_PRI_MMU_WPR2_ADDR_HI { /// Returns the higher (exclusive) bound of the WPR2 region. /// @@ -173,29 +214,30 @@ pub(crate) fn higher_bound(self) -> u64 { // These scratch registers remain powered on even in a low-power state and= have a designated group // number. =20 -// Boot Sequence Interface (BSI) register used to determine -// if GSP reload/resume has completed during the boot process. -register!(NV_PGC6_BSI_SECURE_SCRATCH_14 @ 0x001180f8 { - 26:26 boot_stage_3_handoff as bool; -}); - -// Privilege level mask register. It dictates whether the host CPU has pri= vilege to access the -// `PGC6_AON_SECURE_SCRATCH_GROUP_05` register (which it needs to read GFW= _BOOT). -register!(NV_PGC6_AON_SECURE_SCRATCH_GROUP_05_PRIV_LEVEL_MASK @ 0x00118128, - "Privilege level mask register" { - 0:0 read_protection_level0 as bool, "Set after FWSEC lowers its pr= otection level"; -}); - -// OpenRM defines this as a register array, but doesn't specify its size a= nd only uses its first -// element. Be conservative until we know the actual size or need to use m= ore registers. -register!(NV_PGC6_AON_SECURE_SCRATCH_GROUP_05 @ 0x00118234[1] {}); - -register!( - NV_PGC6_AON_SECURE_SCRATCH_GROUP_05_0_GFW_BOOT =3D> NV_PGC6_AON_SECURE= _SCRATCH_GROUP_05[0], - "Scratch group 05 register 0 used as GFW boot progress indicator" { - 7:0 progress as u8, "Progress of GFW boot (0xff means completed= )"; +nv_reg! { + /// Boot Sequence Interface (BSI) register used to determine + /// if GSP reload/resume has completed during the boot process. + NV_PGC6_BSI_SECURE_SCRATCH_14 @ 0x001180f8 { + 26:26 boot_stage_3_handoff =3D> bool; } -); + + /// Privilege level mask register. It dictates whether the host CPU ha= s privilege to access the + /// `PGC6_AON_SECURE_SCRATCH_GROUP_05` register (which it needs to rea= d GFW_BOOT). + NV_PGC6_AON_SECURE_SCRATCH_GROUP_05_PRIV_LEVEL_MASK @ 0x00118128 { + /// Set after FWSEC lowers its protection level. + 0:0 read_protection_level0 =3D> bool; + } + + /// OpenRM defines this as a register array, but doesn't specify its s= ize and only uses its + /// first element. Be conservative until we know the actual size or ne= ed to use more registers. + NV_PGC6_AON_SECURE_SCRATCH_GROUP_05[1] @ 0x00118234 {} + + /// Scratch group 05 register 0 used as GFW boot progress indicator. + NV_PGC6_AON_SECURE_SCRATCH_GROUP_05_0_GFW_BOOT =3D> NV_PGC6_AON_SECURE= _SCRATCH_GROUP_05[0] { + /// Progress of GFW boot (0xff means completed). + 7:0 progress; + } +} =20 impl NV_PGC6_AON_SECURE_SCRATCH_GROUP_05_0_GFW_BOOT { /// Returns `true` if GFW boot is completed. @@ -204,16 +246,17 @@ pub(crate) fn completed(self) -> bool { } } =20 -register!(NV_PGC6_AON_SECURE_SCRATCH_GROUP_42 @ 0x001183a4 { - 31:0 value as u32; -}); - -register!( - NV_USABLE_FB_SIZE_IN_MB =3D> NV_PGC6_AON_SECURE_SCRATCH_GROUP_42, - "Scratch group 42 register used as framebuffer size" { - 31:0 value as u32, "Usable framebuffer size, in megabytes"; +nv_reg! { + NV_PGC6_AON_SECURE_SCRATCH_GROUP_42 @ 0x001183a4 { + 31:0 value; } -); + + /// Scratch group 42 register used as framebuffer size. + NV_USABLE_FB_SIZE_IN_MB =3D> NV_PGC6_AON_SECURE_SCRATCH_GROUP_42 { + /// Usable framebuffer size, in megabytes. + 31:0 value; + } +} =20 impl NV_USABLE_FB_SIZE_IN_MB { /// Returns the usable framebuffer size, in bytes. @@ -224,10 +267,14 @@ pub(crate) fn usable_fb_size(self) -> u64 { =20 // PDISP =20 -register!(NV_PDISP_VGA_WORKSPACE_BASE @ 0x00625f04 { - 3:3 status_valid as bool, "Set if the `addr` field is valid"; - 31:8 addr as u32, "VGA workspace base address divided by 0x10000"; -}); +nv_reg! { + NV_PDISP_VGA_WORKSPACE_BASE @ 0x00625f04 { + /// Set if the `addr` field is valid. + 3:3 status_valid =3D> bool; + /// VGA workspace base address divided by 0x10000. + 31:8 addr; + } +} =20 impl NV_PDISP_VGA_WORKSPACE_BASE { /// Returns the base address of the VGA workspace, or `None` if none e= xists. @@ -244,73 +291,162 @@ pub(crate) fn vga_workspace_addr(self) -> Option { =20 pub(crate) const NV_FUSE_OPT_FPF_SIZE: usize =3D 16; =20 -register!(NV_FUSE_OPT_FPF_NVDEC_UCODE1_VERSION @ 0x00824100[NV_FUSE_OPT_FP= F_SIZE] { - 15:0 data as u16; -}); +nv_reg! { + NV_FUSE_OPT_FPF_NVDEC_UCODE1_VERSION[NV_FUSE_OPT_FPF_SIZE] @ 0x0082410= 0 { + 15:0 data; + } =20 -register!(NV_FUSE_OPT_FPF_SEC2_UCODE1_VERSION @ 0x00824140[NV_FUSE_OPT_FPF= _SIZE] { - 15:0 data as u16; -}); + NV_FUSE_OPT_FPF_SEC2_UCODE1_VERSION[NV_FUSE_OPT_FPF_SIZE] @ 0x00824140= { + 15:0 data; + } =20 -register!(NV_FUSE_OPT_FPF_GSP_UCODE1_VERSION @ 0x008241c0[NV_FUSE_OPT_FPF_= SIZE] { - 15:0 data as u16; -}); - -// PFALCON - -register!(NV_PFALCON_FALCON_IRQSCLR @ PFalconBase[0x00000004] { - 4:4 halt as bool; - 6:6 swgen0 as bool; -}); - -register!(NV_PFALCON_FALCON_MAILBOX0 @ PFalconBase[0x00000040] { - 31:0 value as u32; -}); - -register!(NV_PFALCON_FALCON_MAILBOX1 @ PFalconBase[0x00000044] { - 31:0 value as u32; -}); - -// Used to store version information about the firmware running -// on the Falcon processor. -register!(NV_PFALCON_FALCON_OS @ PFalconBase[0x00000080] { - 31:0 value as u32; -}); - -register!(NV_PFALCON_FALCON_RM @ PFalconBase[0x00000084] { - 31:0 value as u32; -}); - -register!(NV_PFALCON_FALCON_HWCFG2 @ PFalconBase[0x000000f4] { - 10:10 riscv as bool; - 12:12 mem_scrubbing as bool, "Set to 0 after memory scrubbing is com= pleted"; - 31:31 reset_ready as bool, "Signal indicating that reset is complete= d (GA102+)"; -}); - -impl NV_PFALCON_FALCON_HWCFG2 { - /// Returns `true` if memory scrubbing is completed. - pub(crate) fn mem_scrubbing_done(self) -> bool { - !self.mem_scrubbing() + NV_FUSE_OPT_FPF_GSP_UCODE1_VERSION[NV_FUSE_OPT_FPF_SIZE] @ 0x008241c0 { + 15:0 data; } } =20 -register!(NV_PFALCON_FALCON_CPUCTL @ PFalconBase[0x00000100] { - 1:1 startcpu as bool; - 4:4 halted as bool; - 6:6 alias_en as bool; -}); +// PFALCON =20 -register!(NV_PFALCON_FALCON_BOOTVEC @ PFalconBase[0x00000104] { - 31:0 value as u32; -}); +nv_reg! { + NV_PFALCON_FALCON_IRQSCLR @ PFalconBase + 0x00000004 { + 4:4 halt =3D> bool; + 6:6 swgen0 =3D> bool; + } =20 -register!(NV_PFALCON_FALCON_DMACTL @ PFalconBase[0x0000010c] { - 0:0 require_ctx as bool; - 1:1 dmem_scrubbing as bool; - 2:2 imem_scrubbing as bool; - 6:3 dmaq_num as u8; - 7:7 secure_stat as bool; -}); + NV_PFALCON_FALCON_MAILBOX0 @ PFalconBase + 0x00000040 { + 31:0 value =3D> u32; + } + + NV_PFALCON_FALCON_MAILBOX1 @ PFalconBase + 0x00000044 { + 31:0 value =3D> u32; + } + + /// Used to store version information about the firmware running + /// on the Falcon processor. + NV_PFALCON_FALCON_OS @ PFalconBase + 0x00000080 { + 31:0 value =3D> u32; + } + + NV_PFALCON_FALCON_RM @ PFalconBase + 0x00000084 { + 31:0 value =3D> u32; + } + + NV_PFALCON_FALCON_HWCFG2 @ PFalconBase + 0x000000f4 { + 10:10 riscv =3D> bool; + /// Set to 0 after memory scrubbing is completed. + 12:12 mem_scrubbing =3D> bool; + /// Signal indicating that reset is completed (GA102+). + 31:31 reset_ready =3D> bool; + } + + NV_PFALCON_FALCON_CPUCTL @ PFalconBase + 0x00000100 { + 1:1 startcpu =3D> bool; + 4:4 halted =3D> bool; + 6:6 alias_en =3D> bool; + } + + NV_PFALCON_FALCON_BOOTVEC @ PFalconBase + 0x00000104 { + 31:0 value =3D> u32; + } + + NV_PFALCON_FALCON_DMACTL @ PFalconBase + 0x0000010c { + 0:0 require_ctx =3D> bool; + 1:1 dmem_scrubbing =3D> bool; + 2:2 imem_scrubbing =3D> bool; + 6:3 dmaq_num; + 7:7 secure_stat =3D> bool; + } + + NV_PFALCON_FALCON_DMATRFBASE @ PFalconBase + 0x00000110 { + 31:0 base =3D> u32; + } + + NV_PFALCON_FALCON_DMATRFMOFFS @ PFalconBase + 0x00000114 { + 23:0 offs; + } + + NV_PFALCON_FALCON_DMATRFCMD @ PFalconBase + 0x00000118 { + 0:0 full =3D> bool; + 1:1 idle =3D> bool; + 3:2 sec; + 4:4 imem =3D> bool; + 5:5 is_write =3D> bool; + 10:8 size ?=3D> DmaTrfCmdSize; + 14:12 ctxdma; + 16:16 set_dmtag; + } + + NV_PFALCON_FALCON_DMATRFFBOFFS @ PFalconBase + 0x0000011c { + 31:0 offs =3D> u32; + } + + NV_PFALCON_FALCON_DMATRFBASE1 @ PFalconBase + 0x00000128 { + 8:0 base; + } + + NV_PFALCON_FALCON_HWCFG1 @ PFalconBase + 0x0000012c { + /// Core revision. + 3:0 core_rev ?=3D> FalconCoreRev; + /// Security model. + 5:4 security_model ?=3D> FalconSecurityModel; + /// Core revision subversion. + 7:6 core_rev_subversion =3D> FalconCoreRevSubversion; + } + + NV_PFALCON_FALCON_CPUCTL_ALIAS @ PFalconBase + 0x00000130 { + 1:1 startcpu =3D> bool; + } + + /// IMEM access control register. Up to 4 ports are available for IMEM= access. + NV_PFALCON_FALCON_IMEMC[4, stride =3D 16] @ PFalconBase + 0x00000180 { + /// IMEM block and word offset. + 15:0 offs; + /// Auto-increment on write. + 24:24 aincw =3D> bool; + /// Access secure IMEM. + 28:28 secure =3D> bool; + } + + /// IMEM data register. Reading/writing this register accesses IMEM at= the address + /// specified by the corresponding IMEMC register. + NV_PFALCON_FALCON_IMEMD[4, stride =3D 16] @ PFalconBase + 0x00000184 { + 31:0 data; + } + + /// IMEM tag register. Used to set the tag for the current IMEM block. + NV_PFALCON_FALCON_IMEMT[4, stride =3D 16] @ PFalconBase + 0x00000188 { + 15:0 tag; + } + + /// DMEM access control register. Up to 8 ports are available for DMEM= access. + NV_PFALCON_FALCON_DMEMC[8, stride =3D 8] @ PFalconBase + 0x000001c0 { + /// DMEM block and word offset. + 15:0 offs; + /// Auto-increment on write. + 24:24 aincw =3D> bool; + } + + /// DMEM data register. Reading/writing this register accesses DMEM at= the address + /// specified by the corresponding DMEMC register. + NV_PFALCON_FALCON_DMEMD[8, stride =3D 8] @ PFalconBase + 0x000001c4 { + 31:0 data; + } + + /// Actually known as `NV_PSEC_FALCON_ENGINE` and `NV_PGSP_FALCON_ENGI= NE` depending on the + /// falcon instance. + NV_PFALCON_FALCON_ENGINE @ PFalconBase + 0x000003c0 { + 0:0 reset =3D> bool; + } + + NV_PFALCON_FBIF_TRANSCFG[8] @ PFalconBase + 0x00000600 { + 1:0 target ?=3D> FalconFbifTarget; + 2:2 mem_type =3D> FalconFbifMemType; + } + + NV_PFALCON_FBIF_CTL @ PFalconBase + 0x00000624 { + 7:7 allow_phys_no_ctx =3D> bool; + } +} =20 impl NV_PFALCON_FALCON_DMACTL { /// Returns `true` if memory scrubbing is completed. @@ -319,147 +455,81 @@ pub(crate) fn mem_scrubbing_done(self) -> bool { } } =20 -register!(NV_PFALCON_FALCON_DMATRFBASE @ PFalconBase[0x00000110] { - 31:0 base as u32; -}); - -register!(NV_PFALCON_FALCON_DMATRFMOFFS @ PFalconBase[0x00000114] { - 23:0 offs as u32; -}); - -register!(NV_PFALCON_FALCON_DMATRFCMD @ PFalconBase[0x00000118] { - 0:0 full as bool; - 1:1 idle as bool; - 3:2 sec as u8; - 4:4 imem as bool; - 5:5 is_write as bool; - 10:8 size as u8 ?=3D> DmaTrfCmdSize; - 14:12 ctxdma as u8; - 16:16 set_dmtag as u8; -}); - impl NV_PFALCON_FALCON_DMATRFCMD { /// Programs the `imem` and `sec` fields for the given FalconMem pub(crate) fn with_falcon_mem(self, mem: FalconMem) -> Self { - self.set_imem(mem !=3D FalconMem::Dmem) - .set_sec(if mem =3D=3D FalconMem::ImemSecure { 1 } else { 0 }) + let this =3D self.with_imem(mem !=3D FalconMem::Dmem); + + match mem { + FalconMem::ImemSecure =3D> this.with_const_sec::<1>(), + _ =3D> this.with_const_sec::<0>(), + } } } =20 -register!(NV_PFALCON_FALCON_DMATRFFBOFFS @ PFalconBase[0x0000011c] { - 31:0 offs as u32; -}); - -register!(NV_PFALCON_FALCON_DMATRFBASE1 @ PFalconBase[0x00000128] { - 8:0 base as u16; -}); - -register!(NV_PFALCON_FALCON_HWCFG1 @ PFalconBase[0x0000012c] { - 3:0 core_rev as u8 ?=3D> FalconCoreRev, "Core revision"; - 5:4 security_model as u8 ?=3D> FalconSecurityModel, "Security mode= l"; - 7:6 core_rev_subversion as u8 ?=3D> FalconCoreRevSubversion, "Core= revision subversion"; -}); - -register!(NV_PFALCON_FALCON_CPUCTL_ALIAS @ PFalconBase[0x00000130] { - 1:1 startcpu as bool; -}); - -// IMEM access control register. Up to 4 ports are available for IMEM acce= ss. -register!(NV_PFALCON_FALCON_IMEMC @ PFalconBase[0x00000180[4; 16]] { - 15:0 offs as u16, "IMEM block and word offset"; - 24:24 aincw as bool, "Auto-increment on write"; - 28:28 secure as bool, "Access secure IMEM"; -}); - -// IMEM data register. Reading/writing this register accesses IMEM at the = address -// specified by the corresponding IMEMC register. -register!(NV_PFALCON_FALCON_IMEMD @ PFalconBase[0x00000184[4; 16]] { - 31:0 data as u32; -}); - -// IMEM tag register. Used to set the tag for the current IMEM block. -register!(NV_PFALCON_FALCON_IMEMT @ PFalconBase[0x00000188[4; 16]] { - 15:0 tag as u16; -}); - -// DMEM access control register. Up to 8 ports are available for DMEM acce= ss. -register!(NV_PFALCON_FALCON_DMEMC @ PFalconBase[0x000001c0[8; 8]] { - 15:0 offs as u16, "DMEM block and word offset"; - 24:24 aincw as bool, "Auto-increment on write"; -}); - -// DMEM data register. Reading/writing this register accesses DMEM at the = address -// specified by the corresponding DMEMC register. -register!(NV_PFALCON_FALCON_DMEMD @ PFalconBase[0x000001c4[8; 8]] { - 31:0 data as u32; -}); - -// Actually known as `NV_PSEC_FALCON_ENGINE` and `NV_PGSP_FALCON_ENGINE` d= epending on the falcon -// instance. -register!(NV_PFALCON_FALCON_ENGINE @ PFalconBase[0x000003c0] { - 0:0 reset as bool; -}); - impl NV_PFALCON_FALCON_ENGINE { /// Resets the falcon pub(crate) fn reset_engine(bar: &Bar0) { - Self::read(bar, &E::ID).set_reset(true).write(bar, &E::ID); + bar.update(Self::of::(), |r| r.with_reset(true)); =20 // TIMEOUT: falcon engine should not take more than 10us to reset. time::delay::fsleep(time::Delta::from_micros(10)); =20 - Self::read(bar, &E::ID).set_reset(false).write(bar, &E::ID); + bar.update(Self::of::(), |r| r.with_reset(false)); } } =20 -register!(NV_PFALCON_FBIF_TRANSCFG @ PFalconBase[0x00000600[8]] { - 1:0 target as u8 ?=3D> FalconFbifTarget; - 2:2 mem_type as bool =3D> FalconFbifMemType; -}); - -register!(NV_PFALCON_FBIF_CTL @ PFalconBase[0x00000624] { - 7:7 allow_phys_no_ctx as bool; -}); +impl NV_PFALCON_FALCON_HWCFG2 { + /// Returns `true` if memory scrubbing is completed. + pub(crate) fn mem_scrubbing_done(self) -> bool { + !self.mem_scrubbing() + } +} =20 /* PFALCON2 */ =20 -register!(NV_PFALCON2_FALCON_MOD_SEL @ PFalcon2Base[0x00000180] { - 7:0 algo as u8 ?=3D> FalconModSelAlgo; -}); +nv_reg! { + NV_PFALCON2_FALCON_MOD_SEL @ PFalcon2Base + 0x00000180 { + 7:0 algo ?=3D> FalconModSelAlgo; + } =20 -register!(NV_PFALCON2_FALCON_BROM_CURR_UCODE_ID @ PFalcon2Base[0x00000198]= { - 7:0 ucode_id as u8; -}); + NV_PFALCON2_FALCON_BROM_CURR_UCODE_ID @ PFalcon2Base + 0x00000198 { + 7:0 ucode_id =3D> u8; + } =20 -register!(NV_PFALCON2_FALCON_BROM_ENGIDMASK @ PFalcon2Base[0x0000019c] { - 31:0 value as u32; -}); + NV_PFALCON2_FALCON_BROM_ENGIDMASK @ PFalcon2Base + 0x0000019c { + 31:0 value =3D> u32; + } =20 -// OpenRM defines this as a register array, but doesn't specify its size a= nd only uses its first -// element. Be conservative until we know the actual size or need to use m= ore registers. -register!(NV_PFALCON2_FALCON_BROM_PARAADDR @ PFalcon2Base[0x00000210[1]] { - 31:0 value as u32; -}); + /// OpenRM defines this as a register array, but doesn't specify its s= ize and only uses its + /// first element. Be conservative until we know the actual size or ne= ed to use more registers. + NV_PFALCON2_FALCON_BROM_PARAADDR[1] @ PFalcon2Base + 0x00000210 { + 31:0 value =3D> u32; + } +} =20 // PRISCV =20 -// RISC-V status register for debug (Turing and GA100 only). -// Reflects current RISC-V core status. -register!(NV_PRISCV_RISCV_CORE_SWITCH_RISCV_STATUS @ PFalcon2Base[0x000002= 40] { - 0:0 active_stat as bool, "RISC-V core active/inactive status"; -}); - // GA102 and later -register!(NV_PRISCV_RISCV_CPUCTL @ PFalcon2Base[0x00000388] { - 0:0 halted as bool; - 7:7 active_stat as bool; -}); +nv_reg! { + // RISC-V status register for debug (Turing and GA100 only). + // Reflects current RISC-V core status. + NV_PRISCV_RISCV_CORE_SWITCH_RISCV_STATUS @ PFalcon2Base + 0x00000240 { + // RISC-V core active/inactive status. + 0:0 active_stat =3D> bool; + } =20 -register!(NV_PRISCV_RISCV_BCR_CTRL @ PFalcon2Base[0x00000668] { - 0:0 valid as bool; - 4:4 core_select as bool =3D> PeregrineCoreSelect; - 8:8 br_fetch as bool; -}); + NV_PRISCV_RISCV_CPUCTL @ PFalcon2Base + 0x00000388 { + 0:0 halted =3D> bool; + 7:7 active_stat =3D> bool; + } + + NV_PRISCV_RISCV_BCR_CTRL @ PFalconBase + 0x00001668 { + 0:0 valid =3D> bool; + 4:4 core_select =3D> PeregrineCoreSelect; + 8:8 br_fetch =3D> bool; + } +} =20 // The modules below provide registers that are not identical on all suppo= rted chips. They should // only be used in HAL modules. @@ -467,15 +537,19 @@ pub(crate) fn reset_engine(bar: &Bar= 0) { pub(crate) mod gm107 { // FUSE =20 - register!(NV_FUSE_STATUS_OPT_DISPLAY @ 0x00021c04 { - 0:0 display_disabled as bool; - }); + nv_reg! { + NV_FUSE_STATUS_OPT_DISPLAY @ 0x00021c04 { + 0:0 display_disabled =3D> bool; + } + } } =20 pub(crate) mod ga100 { // FUSE =20 - register!(NV_FUSE_STATUS_OPT_DISPLAY @ 0x00820c04 { - 0:0 display_disabled as bool; - }); + nv_reg! { + NV_FUSE_STATUS_OPT_DISPLAY @ 0x00820c04 { + 0:0 display_disabled =3D> bool; + } + } } diff --git a/drivers/gpu/nova-core/regs/macros.rs b/drivers/gpu/nova-core/r= egs/macros.rs deleted file mode 100644 index ed624be1f39b..000000000000 --- a/drivers/gpu/nova-core/regs/macros.rs +++ /dev/null @@ -1,739 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 - -//! `register!` macro to define register layout and accessors. -//! -//! A single register typically includes several fields, which are accesse= d through a combination -//! of bit-shift and mask operations that introduce a class of potential m= istakes, notably because -//! not all possible field values are necessarily valid. -//! -//! The `register!` macro in this module provides an intuitive and readabl= e syntax for defining a -//! dedicated type for each register. Each such type comes with its own fi= eld accessors that can -//! return an error if a field's value is invalid. Please look at the [`bi= tfield`] macro for the -//! complete syntax of fields definitions. - -/// Trait providing a base address to be added to the offset of a relative= register to obtain -/// its actual offset. -/// -/// The `T` generic argument is used to distinguish which base to use, in = case a type provides -/// several bases. It is given to the `register!` macro to restrict the us= e of the register to -/// implementors of this particular variant. -pub(crate) trait RegisterBase { - const BASE: usize; -} - -/// Defines a dedicated type for a register with an absolute offset, inclu= ding getter and setter -/// methods for its fields and methods to read and write it from an `Io` r= egion. -/// -/// Example: -/// -/// ```no_run -/// register!(BOOT_0 @ 0x00000100, "Basic revision information about the G= PU" { -/// 3:0 minor_revision as u8, "Minor revision of the chip"; -/// 7:4 major_revision as u8, "Major revision of the chip"; -/// 28:20 chipset as u32 ?=3D> Chipset, "Chipset model"; -/// }); -/// ``` -/// -/// This defines a `BOOT_0` type which can be read or written from offset = `0x100` of an `Io` -/// region. It is composed of 3 fields, for instance `minor_revision` is m= ade of the 4 least -/// significant bits of the register. Each field can be accessed and modif= ied using accessor -/// methods: -/// -/// ```no_run -/// // Read from the register's defined offset (0x100). -/// let boot0 =3D BOOT_0::read(&bar); -/// pr_info!("chip revision: {}.{}", boot0.major_revision(), boot0.minor_r= evision()); -/// -/// // `Chipset::try_from` is called with the value of the `chipset` field= and returns an -/// // error if it is invalid. -/// let chipset =3D boot0.chipset()?; -/// -/// // Update some fields and write the value back. -/// boot0.set_major_revision(3).set_minor_revision(10).write(&bar); -/// -/// // Or, just read and update the register in a single step: -/// BOOT_0::update(&bar, |r| r.set_major_revision(3).set_minor_revision(10= )); -/// ``` -/// -/// The documentation strings are optional. If present, they will be added= to the type's -/// definition, or the field getter and setter methods they are attached t= o. -/// -/// It is also possible to create a alias register by using the `=3D> ALIA= S` syntax. This is useful -/// for cases where a register's interpretation depends on the context: -/// -/// ```no_run -/// register!(SCRATCH @ 0x00000200, "Scratch register" { -/// 31:0 value as u32, "Raw value"; -/// }); -/// -/// register!(SCRATCH_BOOT_STATUS =3D> SCRATCH, "Boot status of the firmwa= re" { -/// 0:0 completed as bool, "Whether the firmware has completed boo= ting"; -/// }); -/// ``` -/// -/// In this example, `SCRATCH_0_BOOT_STATUS` uses the same I/O address as = `SCRATCH`, while also -/// providing its own `completed` field. -/// -/// ## Relative registers -/// -/// A register can be defined as being accessible from a fixed offset of a= provided base. For -/// instance, imagine the following I/O space: -/// -/// ```text -/// +-----------------------------+ -/// | ... | -/// | | -/// 0x100--->+------------CPU0-------------+ -/// | | -/// 0x110--->+-----------------------------+ -/// | CPU_CTL | -/// +-----------------------------+ -/// | ... | -/// | | -/// | | -/// 0x200--->+------------CPU1-------------+ -/// | | -/// 0x210--->+-----------------------------+ -/// | CPU_CTL | -/// +-----------------------------+ -/// | ... | -/// +-----------------------------+ -/// ``` -/// -/// `CPU0` and `CPU1` both have a `CPU_CTL` register that starts at offset= `0x10` of their I/O -/// space segment. Since both instances of `CPU_CTL` share the same layout= , we don't want to define -/// them twice and would prefer a way to select which one to use from a si= ngle definition -/// -/// This can be done using the `Base[Offset]` syntax when specifying the r= egister's address. -/// -/// `Base` is an arbitrary type (typically a ZST) to be used as a generic = parameter of the -/// [`RegisterBase`] trait to provide the base as a constant, i.e. each ty= pe providing a base for -/// this register needs to implement `RegisterBase`. Here is the abo= ve example translated -/// into code: -/// -/// ```no_run -/// // Type used to identify the base. -/// pub(crate) struct CpuCtlBase; -/// -/// // ZST describing `CPU0`. -/// struct Cpu0; -/// impl RegisterBase for Cpu0 { -/// const BASE: usize =3D 0x100; -/// } -/// // Singleton of `CPU0` used to identify it. -/// const CPU0: Cpu0 =3D Cpu0; -/// -/// // ZST describing `CPU1`. -/// struct Cpu1; -/// impl RegisterBase for Cpu1 { -/// const BASE: usize =3D 0x200; -/// } -/// // Singleton of `CPU1` used to identify it. -/// const CPU1: Cpu1 =3D Cpu1; -/// -/// // This makes `CPU_CTL` accessible from all implementors of `RegisterB= ase`. -/// register!(CPU_CTL @ CpuCtlBase[0x10], "CPU core control" { -/// 0:0 start as bool, "Start the CPU core"; -/// }); -/// -/// // The `read`, `write` and `update` methods of relative registers take= an extra `base` argument -/// // that is used to resolve its final address by adding its `BASE` to t= he offset of the -/// // register. -/// -/// // Start `CPU0`. -/// CPU_CTL::update(bar, &CPU0, |r| r.set_start(true)); -/// -/// // Start `CPU1`. -/// CPU_CTL::update(bar, &CPU1, |r| r.set_start(true)); -/// -/// // Aliases can also be defined for relative register. -/// register!(CPU_CTL_ALIAS =3D> CpuCtlBase[CPU_CTL], "Alias to CPU core c= ontrol" { -/// 1:1 alias_start as bool, "Start the aliased CPU core"; -/// }); -/// -/// // Start the aliased `CPU0`. -/// CPU_CTL_ALIAS::update(bar, &CPU0, |r| r.set_alias_start(true)); -/// ``` -/// -/// ## Arrays of registers -/// -/// Some I/O areas contain consecutive values that can be interpreted in t= he same way. These areas -/// can be defined as an array of identical registers, allowing them to be= accessed by index with -/// compile-time or runtime bound checking. Simply define their address as= `Address[Size]`, and add -/// an `idx` parameter to their `read`, `write` and `update` methods: -/// -/// ```no_run -/// # fn no_run() -> Result<(), Error> { -/// # fn get_scratch_idx() -> usize { -/// # 0x15 -/// # } -/// // Array of 64 consecutive registers with the same layout starting at = offset `0x80`. -/// register!(SCRATCH @ 0x00000080[64], "Scratch registers" { -/// 31:0 value as u32; -/// }); -/// -/// // Read scratch register 0, i.e. I/O address `0x80`. -/// let scratch_0 =3D SCRATCH::read(bar, 0).value(); -/// // Read scratch register 15, i.e. I/O address `0x80 + (15 * 4)`. -/// let scratch_15 =3D SCRATCH::read(bar, 15).value(); -/// -/// // This is out of bounds and won't build. -/// // let scratch_128 =3D SCRATCH::read(bar, 128).value(); -/// -/// // Runtime-obtained array index. -/// let scratch_idx =3D get_scratch_idx(); -/// // Access on a runtime index returns an error if it is out-of-bounds. -/// let some_scratch =3D SCRATCH::try_read(bar, scratch_idx)?.value(); -/// -/// // Alias to a particular register in an array. -/// // Here `SCRATCH[8]` is used to convey the firmware exit code. -/// register!(FIRMWARE_STATUS =3D> SCRATCH[8], "Firmware exit status code"= { -/// 7:0 status as u8; -/// }); -/// -/// let status =3D FIRMWARE_STATUS::read(bar).status(); -/// -/// // Non-contiguous register arrays can be defined by adding a stride pa= rameter. -/// // Here, each of the 16 registers of the array are separated by 8 byte= s, meaning that the -/// // registers of the two declarations below are interleaved. -/// register!(SCRATCH_INTERLEAVED_0 @ 0x000000c0[16 ; 8], "Scratch registe= rs bank 0" { -/// 31:0 value as u32; -/// }); -/// register!(SCRATCH_INTERLEAVED_1 @ 0x000000c4[16 ; 8], "Scratch registe= rs bank 1" { -/// 31:0 value as u32; -/// }); -/// # Ok(()) -/// # } -/// ``` -/// -/// ## Relative arrays of registers -/// -/// Combining the two features described in the sections above, arrays of = registers accessible from -/// a base can also be defined: -/// -/// ```no_run -/// # fn no_run() -> Result<(), Error> { -/// # fn get_scratch_idx() -> usize { -/// # 0x15 -/// # } -/// // Type used as parameter of `RegisterBase` to specify the base. -/// pub(crate) struct CpuCtlBase; -/// -/// // ZST describing `CPU0`. -/// struct Cpu0; -/// impl RegisterBase for Cpu0 { -/// const BASE: usize =3D 0x100; -/// } -/// // Singleton of `CPU0` used to identify it. -/// const CPU0: Cpu0 =3D Cpu0; -/// -/// // ZST describing `CPU1`. -/// struct Cpu1; -/// impl RegisterBase for Cpu1 { -/// const BASE: usize =3D 0x200; -/// } -/// // Singleton of `CPU1` used to identify it. -/// const CPU1: Cpu1 =3D Cpu1; -/// -/// // 64 per-cpu scratch registers, arranged as an contiguous array. -/// register!(CPU_SCRATCH @ CpuCtlBase[0x00000080[64]], "Per-CPU scratch r= egisters" { -/// 31:0 value as u32; -/// }); -/// -/// let cpu0_scratch_0 =3D CPU_SCRATCH::read(bar, &Cpu0, 0).value(); -/// let cpu1_scratch_15 =3D CPU_SCRATCH::read(bar, &Cpu1, 15).value(); -/// -/// // This won't build. -/// // let cpu0_scratch_128 =3D CPU_SCRATCH::read(bar, &Cpu0, 128).value(); -/// -/// // Runtime-obtained array index. -/// let scratch_idx =3D get_scratch_idx(); -/// // Access on a runtime value returns an error if it is out-of-bounds. -/// let cpu0_some_scratch =3D CPU_SCRATCH::try_read(bar, &Cpu0, scratch_id= x)?.value(); -/// -/// // `SCRATCH[8]` is used to convey the firmware exit code. -/// register!(CPU_FIRMWARE_STATUS =3D> CpuCtlBase[CPU_SCRATCH[8]], -/// "Per-CPU firmware exit status code" { -/// 7:0 status as u8; -/// }); -/// -/// let cpu0_status =3D CPU_FIRMWARE_STATUS::read(bar, &Cpu0).status(); -/// -/// // Non-contiguous register arrays can be defined by adding a stride pa= rameter. -/// // Here, each of the 16 registers of the array are separated by 8 byte= s, meaning that the -/// // registers of the two declarations below are interleaved. -/// register!(CPU_SCRATCH_INTERLEAVED_0 @ CpuCtlBase[0x00000d00[16 ; 8]], -/// "Scratch registers bank 0" { -/// 31:0 value as u32; -/// }); -/// register!(CPU_SCRATCH_INTERLEAVED_1 @ CpuCtlBase[0x00000d04[16 ; 8]], -/// "Scratch registers bank 1" { -/// 31:0 value as u32; -/// }); -/// # Ok(()) -/// # } -/// ``` -macro_rules! register { - // Creates a register at a fixed offset of the MMIO space. - ($name:ident @ $offset:literal $(, $comment:literal)? { $($fields:tt)*= } ) =3D> { - bitfield!(pub(crate) struct $name(u32) $(, $comment)? { $($fields)= * } ); - register!(@io_fixed $name @ $offset); - }; - - // Creates an alias register of fixed offset register `alias` with its= own fields. - ($name:ident =3D> $alias:ident $(, $comment:literal)? { $($fields:tt)*= } ) =3D> { - bitfield!(pub(crate) struct $name(u32) $(, $comment)? { $($fields)= * } ); - register!(@io_fixed $name @ $alias::OFFSET); - }; - - // Creates a register at a relative offset from a base address provide= r. - ($name:ident @ $base:ty [ $offset:literal ] $(, $comment:literal)? { $= ($fields:tt)* } ) =3D> { - bitfield!(pub(crate) struct $name(u32) $(, $comment)? { $($fields)= * } ); - register!(@io_relative $name @ $base [ $offset ]); - }; - - // Creates an alias register of relative offset register `alias` with = its own fields. - ($name:ident =3D> $base:ty [ $alias:ident ] $(, $comment:literal)? { $= ($fields:tt)* }) =3D> { - bitfield!(pub(crate) struct $name(u32) $(, $comment)? { $($fields)= * } ); - register!(@io_relative $name @ $base [ $alias::OFFSET ]); - }; - - // Creates an array of registers at a fixed offset of the MMIO space. - ( - $name:ident @ $offset:literal [ $size:expr ; $stride:expr ] $(, $c= omment:literal)? { - $($fields:tt)* - } - ) =3D> { - static_assert!(::core::mem::size_of::() <=3D $stride); - bitfield!(pub(crate) struct $name(u32) $(, $comment)? { $($fields)= * } ); - register!(@io_array $name @ $offset [ $size ; $stride ]); - }; - - // Shortcut for contiguous array of registers (stride =3D=3D size of e= lement). - ( - $name:ident @ $offset:literal [ $size:expr ] $(, $comment:literal)= ? { - $($fields:tt)* - } - ) =3D> { - register!($name @ $offset [ $size ; ::core::mem::size_of::() = ] $(, $comment)? { - $($fields)* - } ); - }; - - // Creates an array of registers at a relative offset from a base addr= ess provider. - ( - $name:ident @ $base:ty [ $offset:literal [ $size:expr ; $stride:ex= pr ] ] - $(, $comment:literal)? { $($fields:tt)* } - ) =3D> { - static_assert!(::core::mem::size_of::() <=3D $stride); - bitfield!(pub(crate) struct $name(u32) $(, $comment)? { $($fields)= * } ); - register!(@io_relative_array $name @ $base [ $offset [ $size ; $st= ride ] ]); - }; - - // Shortcut for contiguous array of relative registers (stride =3D=3D = size of element). - ( - $name:ident @ $base:ty [ $offset:literal [ $size:expr ] ] $(, $com= ment:literal)? { - $($fields:tt)* - } - ) =3D> { - register!($name @ $base [ $offset [ $size ; ::core::mem::size_of::= () ] ] - $(, $comment)? { $($fields)* } ); - }; - - // Creates an alias of register `idx` of relative array of registers `= alias` with its own - // fields. - ( - $name:ident =3D> $base:ty [ $alias:ident [ $idx:expr ] ] $(, $comm= ent:literal)? { - $($fields:tt)* - } - ) =3D> { - static_assert!($idx < $alias::SIZE); - bitfield!(pub(crate) struct $name(u32) $(, $comment)? { $($fields)= * } ); - register!(@io_relative $name @ $base [ $alias::OFFSET + $idx * $al= ias::STRIDE ] ); - }; - - // Creates an alias of register `idx` of array of registers `alias` wi= th its own fields. - // This rule belongs to the (non-relative) register arrays set, but ne= eds to be put last - // to avoid it being interpreted in place of the relative register arr= ay alias rule. - ($name:ident =3D> $alias:ident [ $idx:expr ] $(, $comment:literal)? { = $($fields:tt)* }) =3D> { - static_assert!($idx < $alias::SIZE); - bitfield!(pub(crate) struct $name(u32) $(, $comment)? { $($fields)= * } ); - register!(@io_fixed $name @ $alias::OFFSET + $idx * $alias::STRIDE= ); - }; - - // Generates the IO accessors for a fixed offset register. - (@io_fixed $name:ident @ $offset:expr) =3D> { - #[allow(dead_code)] - impl $name { - pub(crate) const OFFSET: usize =3D $offset; - - /// Read the register from its address in `io`. - #[inline(always)] - pub(crate) fn read(io: &T) -> Self where - T: ::core::ops::Deref, - I: ::kernel::io::IoKnownSize + ::kernel::io::IoCapable, - { - Self(io.read32($offset)) - } - - /// Write the value contained in `self` to the register addres= s in `io`. - #[inline(always)] - pub(crate) fn write(self, io: &T) where - T: ::core::ops::Deref, - I: ::kernel::io::IoKnownSize + ::kernel::io::IoCapable, - { - io.write32(self.0, $offset) - } - - /// Read the register from its address in `io` and run `f` on = its value to obtain a new - /// value to write back. - #[inline(always)] - pub(crate) fn update( - io: &T, - f: F, - ) where - T: ::core::ops::Deref, - I: ::kernel::io::IoKnownSize + ::kernel::io::IoCapable, - F: ::core::ops::FnOnce(Self) -> Self, - { - let reg =3D f(Self::read(io)); - reg.write(io); - } - } - }; - - // Generates the IO accessors for a relative offset register. - (@io_relative $name:ident @ $base:ty [ $offset:expr ]) =3D> { - #[allow(dead_code)] - impl $name { - pub(crate) const OFFSET: usize =3D $offset; - - /// Read the register from `io`, using the base address provid= ed by `base` and adding - /// the register's offset to it. - #[inline(always)] - pub(crate) fn read( - io: &T, - #[allow(unused_variables)] - base: &B, - ) -> Self where - T: ::core::ops::Deref, - I: ::kernel::io::IoKnownSize + ::kernel::io::IoCapable, - B: crate::regs::macros::RegisterBase<$base>, - { - const OFFSET: usize =3D $name::OFFSET; - - let value =3D io.read32( - >::BASE = + OFFSET - ); - - Self(value) - } - - /// Write the value contained in `self` to `io`, using the bas= e address provided by - /// `base` and adding the register's offset to it. - #[inline(always)] - pub(crate) fn write( - self, - io: &T, - #[allow(unused_variables)] - base: &B, - ) where - T: ::core::ops::Deref, - I: ::kernel::io::IoKnownSize + ::kernel::io::IoCapable, - B: crate::regs::macros::RegisterBase<$base>, - { - const OFFSET: usize =3D $name::OFFSET; - - io.write32( - self.0, - >::BASE = + OFFSET - ); - } - - /// Read the register from `io`, using the base address provid= ed by `base` and adding - /// the register's offset to it, then run `f` on its value to = obtain a new value to - /// write back. - #[inline(always)] - pub(crate) fn update( - io: &T, - base: &B, - f: F, - ) where - T: ::core::ops::Deref, - I: ::kernel::io::IoKnownSize + ::kernel::io::IoCapable, - B: crate::regs::macros::RegisterBase<$base>, - F: ::core::ops::FnOnce(Self) -> Self, - { - let reg =3D f(Self::read(io, base)); - reg.write(io, base); - } - } - }; - - // Generates the IO accessors for an array of registers. - (@io_array $name:ident @ $offset:literal [ $size:expr ; $stride:expr ]= ) =3D> { - #[allow(dead_code)] - impl $name { - pub(crate) const OFFSET: usize =3D $offset; - pub(crate) const SIZE: usize =3D $size; - pub(crate) const STRIDE: usize =3D $stride; - - /// Read the array register at index `idx` from its address in= `io`. - #[inline(always)] - pub(crate) fn read( - io: &T, - idx: usize, - ) -> Self where - T: ::core::ops::Deref, - I: ::kernel::io::IoKnownSize + ::kernel::io::IoCapable, - { - build_assert!(idx < Self::SIZE); - - let offset =3D Self::OFFSET + (idx * Self::STRIDE); - let value =3D io.read32(offset); - - Self(value) - } - - /// Write the value contained in `self` to the array register = with index `idx` in `io`. - #[inline(always)] - pub(crate) fn write( - self, - io: &T, - idx: usize - ) where - T: ::core::ops::Deref, - I: ::kernel::io::IoKnownSize + ::kernel::io::IoCapable, - { - build_assert!(idx < Self::SIZE); - - let offset =3D Self::OFFSET + (idx * Self::STRIDE); - - io.write32(self.0, offset); - } - - /// Read the array register at index `idx` in `io` and run `f`= on its value to obtain a - /// new value to write back. - #[inline(always)] - pub(crate) fn update( - io: &T, - idx: usize, - f: F, - ) where - T: ::core::ops::Deref, - I: ::kernel::io::IoKnownSize + ::kernel::io::IoCapable, - F: ::core::ops::FnOnce(Self) -> Self, - { - let reg =3D f(Self::read(io, idx)); - reg.write(io, idx); - } - - /// Read the array register at index `idx` from its address in= `io`. - /// - /// The validity of `idx` is checked at run-time, and `EINVAL`= is returned is the - /// access was out-of-bounds. - #[inline(always)] - pub(crate) fn try_read( - io: &T, - idx: usize, - ) -> ::kernel::error::Result where - T: ::core::ops::Deref, - I: ::kernel::io::IoKnownSize + ::kernel::io::IoCapable, - { - if idx < Self::SIZE { - Ok(Self::read(io, idx)) - } else { - Err(EINVAL) - } - } - - /// Write the value contained in `self` to the array register = with index `idx` in `io`. - /// - /// The validity of `idx` is checked at run-time, and `EINVAL`= is returned is the - /// access was out-of-bounds. - #[inline(always)] - pub(crate) fn try_write( - self, - io: &T, - idx: usize, - ) -> ::kernel::error::Result where - T: ::core::ops::Deref, - I: ::kernel::io::IoKnownSize + ::kernel::io::IoCapable, - { - if idx < Self::SIZE { - Ok(self.write(io, idx)) - } else { - Err(EINVAL) - } - } - - /// Read the array register at index `idx` in `io` and run `f`= on its value to obtain a - /// new value to write back. - /// - /// The validity of `idx` is checked at run-time, and `EINVAL`= is returned is the - /// access was out-of-bounds. - #[inline(always)] - pub(crate) fn try_update( - io: &T, - idx: usize, - f: F, - ) -> ::kernel::error::Result where - T: ::core::ops::Deref, - I: ::kernel::io::IoKnownSize + ::kernel::io::IoCapable, - F: ::core::ops::FnOnce(Self) -> Self, - { - if idx < Self::SIZE { - Ok(Self::update(io, idx, f)) - } else { - Err(EINVAL) - } - } - } - }; - - // Generates the IO accessors for an array of relative registers. - ( - @io_relative_array $name:ident @ $base:ty - [ $offset:literal [ $size:expr ; $stride:expr ] ] - ) =3D> { - #[allow(dead_code)] - impl $name { - pub(crate) const OFFSET: usize =3D $offset; - pub(crate) const SIZE: usize =3D $size; - pub(crate) const STRIDE: usize =3D $stride; - - /// Read the array register at index `idx` from `io`, using th= e base address provided - /// by `base` and adding the register's offset to it. - #[inline(always)] - pub(crate) fn read( - io: &T, - #[allow(unused_variables)] - base: &B, - idx: usize, - ) -> Self where - T: ::core::ops::Deref, - I: ::kernel::io::IoKnownSize + ::kernel::io::IoCapable, - B: crate::regs::macros::RegisterBase<$base>, - { - build_assert!(idx < Self::SIZE); - - let offset =3D >::BASE + - Self::OFFSET + (idx * Self::STRIDE); - let value =3D io.read32(offset); - - Self(value) - } - - /// Write the value contained in `self` to `io`, using the bas= e address provided by - /// `base` and adding the offset of array register `idx` to it. - #[inline(always)] - pub(crate) fn write( - self, - io: &T, - #[allow(unused_variables)] - base: &B, - idx: usize - ) where - T: ::core::ops::Deref, - I: ::kernel::io::IoKnownSize + ::kernel::io::IoCapable, - B: crate::regs::macros::RegisterBase<$base>, - { - build_assert!(idx < Self::SIZE); - - let offset =3D >::BASE + - Self::OFFSET + (idx * Self::STRIDE); - - io.write32(self.0, offset); - } - - /// Read the array register at index `idx` from `io`, using th= e base address provided - /// by `base` and adding the register's offset to it, then run= `f` on its value to - /// obtain a new value to write back. - #[inline(always)] - pub(crate) fn update( - io: &T, - base: &B, - idx: usize, - f: F, - ) where - T: ::core::ops::Deref, - I: ::kernel::io::IoKnownSize + ::kernel::io::IoCapable, - B: crate::regs::macros::RegisterBase<$base>, - F: ::core::ops::FnOnce(Self) -> Self, - { - let reg =3D f(Self::read(io, base, idx)); - reg.write(io, base, idx); - } - - /// Read the array register at index `idx` from `io`, using th= e base address provided - /// by `base` and adding the register's offset to it. - /// - /// The validity of `idx` is checked at run-time, and `EINVAL`= is returned is the - /// access was out-of-bounds. - #[inline(always)] - pub(crate) fn try_read( - io: &T, - base: &B, - idx: usize, - ) -> ::kernel::error::Result where - T: ::core::ops::Deref, - I: ::kernel::io::IoKnownSize + ::kernel::io::IoCapable, - B: crate::regs::macros::RegisterBase<$base>, - { - if idx < Self::SIZE { - Ok(Self::read(io, base, idx)) - } else { - Err(EINVAL) - } - } - - /// Write the value contained in `self` to `io`, using the bas= e address provided by - /// `base` and adding the offset of array register `idx` to it. - /// - /// The validity of `idx` is checked at run-time, and `EINVAL`= is returned is the - /// access was out-of-bounds. - #[inline(always)] - pub(crate) fn try_write( - self, - io: &T, - base: &B, - idx: usize, - ) -> ::kernel::error::Result where - T: ::core::ops::Deref, - I: ::kernel::io::IoKnownSize + ::kernel::io::IoCapable, - B: crate::regs::macros::RegisterBase<$base>, - { - if idx < Self::SIZE { - Ok(self.write(io, base, idx)) - } else { - Err(EINVAL) - } - } - - /// Read the array register at index `idx` from `io`, using th= e base address provided - /// by `base` and adding the register's offset to it, then run= `f` on its value to - /// obtain a new value to write back. - /// - /// The validity of `idx` is checked at run-time, and `EINVAL`= is returned is the - /// access was out-of-bounds. - #[inline(always)] - pub(crate) fn try_update( - io: &T, - base: &B, - idx: usize, - f: F, - ) -> ::kernel::error::Result where - T: ::core::ops::Deref, - I: ::kernel::io::IoKnownSize + ::kernel::io::IoCapable, - B: crate::regs::macros::RegisterBase<$base>, - F: ::core::ops::FnOnce(Self) -> Self, - { - if idx < Self::SIZE { - Ok(Self::update(io, base, idx, f)) - } else { - Err(EINVAL) - } - } - } - }; -} --=20 2.53.0