From nobody Fri Apr 3 01:40:58 2026 Received: from DM5PR21CU001.outbound.protection.outlook.com (mail-centralusazon11011003.outbound.protection.outlook.com [52.101.62.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 8506F2F7ADE; Mon, 16 Feb 2026 08:05:14 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=52.101.62.3 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1771229115; cv=fail; b=RGIG+v/CfrenvApTzYsL0/RwcEzgoVWV8NHXJjzwRQHv85/IXOXxKbE1SAhhmUN9e4+4IN1gh7TyhBTmDW8L4VPN1HxNthQ3SBmCXT5ySXMqosg8MKRb8Zpmb4Fio4CnYrX0D7vVdMA3iZo7t7wfiBSMA1uLbe0yrceMJ8QWCtI= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1771229115; c=relaxed/simple; bh=qwEvQuP4jrCxLMF9mIv/YjA72kw8j5dPHfvQ/k2BoyI=; h=From:Date:Subject:Content-Type:Message-Id:References:In-Reply-To: To:Cc:MIME-Version; b=Iyn9E2UcLrLl7Htrknp1AWftI5gem54239txT2zN2OCDQJGXgk0fc3+o5h6EH/vWF6Gi+N6RaAZUz5jwt1zFfKV1OS5BQlB+Znixa3fKOOAG44Pj9wZuRQbPRbTQ6fO9LEPRNdEY+cigNwjlOzt/IYuDmCW/H+ZrzvmMkVh2e68= 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=auWXnBbc; arc=fail smtp.client-ip=52.101.62.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="auWXnBbc" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=dMu7y4RFoWEQ9uCcWStDpwWVcR7ZSCNOTa2MwrKjkHh8QEzdmgVa2ui3yoSDEb8jLuQGHbfGE3bkCTR+7Gbuu91fpQVQ7nN1ROonPGVqC1dAE3RTkLNtBOPcsjWaZ/NyrJgcFCs5EHtO9t025ggsP3SVG44SAd+cXV46dEz79uvEq45kUVA56btukjOHdUULj6mQ8NdKpXw0nS0mQN4hpJfhjVDg2ujxgJUwrrN93pXEQU2Xk8cahcFJooMx185CYDMdRBshVidLbsdVMMs85mV2zMEmfu8IBSJX6OTpU+vhuvFoZz2sZpJqTxbiBkfon0/tUEGIm94vCBgaGGHlRg== 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=yjeKUiNcT3bJhJNj1kIMm0mzjeHTIShzUnykFpJNBac=; b=rZenN74HmcazJJ/3a/L3wgp+624thc6uo9Bm417uJCzd6mGHOMaaHLN0JpZceqm7yfwten1uiDAQr8vXaYRJflORpQ2kUx6CS0xVcTDcIELo5QA5g5smCk6eQ7sXvfWz2AVEVjUISsfmdh9AAkQTmWWHWwFS4035Q044xwFSlGMzAA+x+3BmanCGQ8JVL2C50EyfWYVWO/66M3K9HRb0fkPqrewZMVmddypCuYCu6qqrN8fNPKkBMi3lkDqehGRaRqdl+0VXh9BLGywUPLx5r9MU6VD23DR1HVP2z3+24shi/5zDNX9CRb5W8oQ+WkXHAjr+ky82kXQg6EvNhjgpJw== 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=yjeKUiNcT3bJhJNj1kIMm0mzjeHTIShzUnykFpJNBac=; b=auWXnBbc5/5sTF9mTaHGUuCEu0tF/pe1Hctb7olmPfjisRFGN+4zoBCBC7SzQ9buGL7MDzD4TUedUxJv0f4SiynIPa7CZiBROSYIm83Mi5ciI9RP+LfTQuPWCD6DSq0HXsknoEQfLaUGFJAUTFwARsJWOg4QoVAJ4uJdCAhjbAXCkJ7/N18BNDlX3QWerGL5pg8K+cpbWzy5ToVL8CSVeBuOE1WF1uitmIS6+OAN6V1KO93dAdj8CRuH2SnVSZNIXGLP0tZF4Z4TEVlq+SWCyEQ2qbKUF/zepRP6uVys3TeMBj7KY2GsSvvgDeA1HsCfMwYqqh6SZ+tUGoIpCmYK0w== 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 SJ0PR12MB6832.namprd12.prod.outlook.com (2603:10b6:a03:47e::12) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.9611.10; Mon, 16 Feb 2026 08:05:12 +0000 Received: from CH2PR12MB3990.namprd12.prod.outlook.com ([fe80::7de1:4fe5:8ead:5989]) by CH2PR12MB3990.namprd12.prod.outlook.com ([fe80::7de1:4fe5:8ead:5989%3]) with mapi id 15.20.9611.013; Mon, 16 Feb 2026 08:05:12 +0000 From: Alexandre Courbot Date: Mon, 16 Feb 2026 17:04:37 +0900 Subject: [PATCH v6 1/9] rust: enable the `generic_arg_infer` feature Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260216-register-v6-1-eec9a4de9e9e@nvidia.com> References: <20260216-register-v6-0-eec9a4de9e9e@nvidia.com> In-Reply-To: <20260216-register-v6-0-eec9a4de9e9e@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: TYWPR01CA0040.jpnprd01.prod.outlook.com (2603:1096:400:17f::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_|SJ0PR12MB6832:EE_ X-MS-Office365-Filtering-Correlation-Id: 321a646d-c990-4bdd-7c21-08de6d321bf9 X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|1800799024|7416014|376014|10070799003|366016|921020; X-Microsoft-Antispam-Message-Info: =?utf-8?B?ekUyN1NzN0xVVnUxakFqR0kyZVJlenJxNEJyNG83SVJMT0QxRnhQMXFxK09H?= =?utf-8?B?c0RLWnJDOWo2SDlqUXJMdHJyVDdiNFRCRUtrQjFTZ2JlVFZJdUFMN0VSMnNz?= =?utf-8?B?SWlEN0gwdzlmdE9QN3U4SnR4QmhjNitGU2tSU0lMN1ZtdjNQZDlSWGpkeG45?= =?utf-8?B?cGg5QmFJVlpYQmg5OUNXeXN4SUQ3cFp4ekNsNUFNMUJmMWVrTFRYTXhHLzF6?= =?utf-8?B?YnQxUVdJLy9vbEpHaFhUakYyMlFoNENlQWJrZFdxWWdRd1lVWmRoTlhQMGdG?= =?utf-8?B?ME5zays0SFM2M1h2bWQvRmwzSWUyZmM1OThlRGNSaHprRmJMV0FTSWJ6dHNN?= =?utf-8?B?cTNickcyV3dhTFRkUVdIN3VhelpPVGc3Z2JRWUM4MlpLbjNVRVA3NkVXMkVE?= =?utf-8?B?bzV5ZUJZS3lpdnJYMENvSXZVdlNZbHVMem95QkJmY2tJOWhPVytGaFVWZDlV?= =?utf-8?B?Nk5SYUgxWHJVSUZKYTY2K20vNWNudHlWRFd1OTljMXVjVlRFeGJ0MmYycVRo?= =?utf-8?B?QlBRekl0VVBsSXFzVW12S3dsdFR4aXhpZ042eVAvaUExbnk3RitIcEtIWFNL?= =?utf-8?B?bXhncE9PcEVPTm94eGFuVGVpQXV0Yko3b3dNUFVqT3ZReTMxNlN0ZisvSzlv?= =?utf-8?B?dW1KV0hMNEpyWEJFZG15VmVyMWlGMXgzdWtNc1duUXJvN1Y5c0JLQXM3Q0d3?= =?utf-8?B?OU1CYVEyUTF1SHlkRFRodzNVSEhuLzB1OWI0dGJzTFBSaE9MVjAxYmhqSUVs?= =?utf-8?B?Z1hDUUhwamRSQUI4Tk53eE9vT3hrUjY4bFJFT3RZdW1Ya2ZPdXRVMVdDMmtD?= =?utf-8?B?NUxnN1BTVHJiY3hoSWh1RmhUUi9vUmlEMkM2bm5sZ1h4bnNLb3N0dHBMdXNt?= =?utf-8?B?MzhQZmJrbS9jU212dE1SQXl2TllZeWVrczB2Ti9uVGthYTFrbXlMMFF6VHNN?= =?utf-8?B?a1ZaSHVoSWIzTUF1QTRaKzVJUklRTEVuVTFvMU02Ymk5QVljOWY5bnk0bTNF?= =?utf-8?B?S3RHWlVFaHNVYmd2VVAzVm5wVzdaWkU2bUY3S0dxclNrajd1bjdEb1RlWDh5?= =?utf-8?B?dmp2eER5ZUw2Z2RPVG9nU2JPQVNLcnR5L04valJGVXF4T1dXemJDRzRTbkhX?= =?utf-8?B?dVNPb3dUVFZ2c3hPSzIvTzd2VE1NTjUzVWRLUDhoUGtGZi9FWlY1QlhKWGJa?= =?utf-8?B?cXYyM0VKdTQwN0lkYU9lVFFiaUp2amZOVTJ0WGR3ZGdKMFZUWEExbEtDZGhU?= =?utf-8?B?b3V0NWJtdzAwUVJsS0ljSzlQYmFaMHVTVkVNTFIwQlpidEU4eFppTjZvR3NW?= =?utf-8?B?TlE4eVROYWJ5VnFyWVVXbkRKK2pIZ3YzcEx1MzJwYW1IbXEyRFhJWG5DcFlr?= =?utf-8?B?SVkwV0IyT2UxRXdyMVlCQUtWZno5eXFZTnJCZGJEYTY5UVc1aW1vSW5QaHcw?= =?utf-8?B?MUwwU0hxM0JveXVmSFU0cnlUSjlmNVFpT2FaMjQ2NHJpSlVnekY5VHpUTHR2?= =?utf-8?B?ZkN6eDN2bVpEaldBVUxJUHhqQjQrOUZKVE9SVDZmbzRRWm5uMldtd3Z1QWth?= =?utf-8?B?Rk9KbytKTDFGQWtuRjBNUUU4emRBN1Y5S1dVN2RLVys4d3NpTlkrTndXcEpm?= =?utf-8?B?L1IrVTJ2OGdpanp1SmFBMVVONkMwbDMzc0g2QmtkSnBVbDVtQ2QvZlpjMDVs?= =?utf-8?B?QVdFT0RMRjRWclg2WHREcTk0VDVmZG96MlhtMEc3eXJMRXliRVJoUnFoMm9r?= =?utf-8?B?c1NBa2JWOEpWaS9HUnlUS3Vmdy8rektiUGhtNWVqN2tQOUtBcjBFUTRidVY1?= =?utf-8?B?QUNvc3pKeXVPSHR0ejBVbjFKOFgzOCsrMnQwSXFGM2swUnFqQktRa3JjTk95?= =?utf-8?B?Rmt1ZGJ4NkYxSWRpQmdPeG9lMnl4T1BCSXFIU3ppTUVYWk9reTNKVHJVa3B6?= =?utf-8?B?SkFrT09FN2t6c0JqZmFncFk1NGRRS1FiUkZxSnluMHV6QzVTckNyS2FXcDgy?= =?utf-8?B?ZGdsSkhSVE1PbUFNaGxYNG9QQ3ZodEdleXFNN2hBYXNna0NkOGhXQTlTWmtW?= =?utf-8?B?UUZXckYydnFFTERvdHlTWHQ3Y2VmS280Zk5PYWhRTDRNYlBPTTRkNDBiLzBK?= =?utf-8?B?NU9DZVFoeHNORUt2NWFSNFVqNEhuWFM1NDI3U3RuZEZqVDZIR1RYZEJlU2tx?= =?utf-8?B?Q3c9PQ==?= X-Forefront-Antispam-Report: CIP:255.255.255.255;CTRY:;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:CH2PR12MB3990.namprd12.prod.outlook.com;PTR:;CAT:NONE;SFS:(13230040)(1800799024)(7416014)(376014)(10070799003)(366016)(921020);DIR:OUT;SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 2 X-MS-Exchange-AntiSpam-MessageData-0: =?utf-8?B?Rk9zRGVDeFpvTDllcXNzQ3cwdEhDZ3JmQVhYVk5XYklKVHliTW53bnArcVdM?= =?utf-8?B?ZE1tWTdReWF5aklPMnhlNE1iTEh0L1djWHZtb1kyWnZET0pBSGh2cTREbGtt?= =?utf-8?B?RzFkOVBQNGZTekFZWDh1V09vdk1yNVpiMlBYTGQ1YWREOFgxRGwvV1F6MW5t?= =?utf-8?B?Y0FsRGV6Tm9ENExENnUvelVWODZYdk1ibXE4dnJiRjZtbFgvK3dUWTd5amky?= =?utf-8?B?ZFFHRk9sN3lqZE1wdUZHRHY1ZzFPUWRpR0lDRWl4cXhFQjJqRmJWaGJmUDhj?= =?utf-8?B?Y0NjRTVKdlIrdXJxbTlOWTZ1Mncrc1FwZ1l0NTd4UmcvQkxGUm1UZklqM0J4?= =?utf-8?B?clpHbkJpNHdOV1lsZTRGOEdZUytSdWdmM0k2RlZsRm9oTGdmeml6YWphNGpD?= =?utf-8?B?YnFKcWQwdjVmem94cjlPR2d0VllUb05Xdkh0L3hwTUZ5ckN3ZDJuVktEYzVC?= =?utf-8?B?RlZURkVkVHh3RE1vaThsdWpJNFpLZ1l6U3QyVVBGTGpXRnFaZ1hoNEVjK2xo?= =?utf-8?B?aVdKclFyb0l5aTF0Nys2UVo3aEY5WUdxdmQ5T2JNc2JRMnpVZnZzYnY2T0Js?= =?utf-8?B?T0VrVTRLWlNucGROWElEYXpLbC9UZHpsRTBUZCtTYzI1UFFGVVJRVzRsV3FF?= =?utf-8?B?b0UyaE9JYnB1TTQ1YktEOUFId3VtZjFEakdQUmxXWXo3N25xd1dYZG5OUTdx?= =?utf-8?B?QmV1V1pIMkNBcDNScXVxK0E3RmhLNzgyMUxHK3g1eUdqK2pISWZuc0JXMkhO?= =?utf-8?B?cWV3RXM1dldreVRKYlY4OHdtbDR1N1pkRXo2MVpyNUJPby92ZitsN2FFUDBr?= =?utf-8?B?cHZmOWNJamt1UXliSEVRL3VFZHlTVm5LQk1iSnFkL0tyYU03c25MenNpNHdB?= =?utf-8?B?U3h3dExJUkZPTzF0YWE1VFpHYmJNdjJFUXZSQ2c4M3U5WnJlTUREYnVSbHNB?= =?utf-8?B?RnE3NkNOaEcwOSsxVUVxd0R6SFVzN09peVFEUmIxaGNaUnVFNWdGMHAvY1I2?= =?utf-8?B?VWlBT2tSRkZnMEtUV0FGbUZGR1o0SWhxV0FFenh4YUdFRlFxRlhTU0lVemt5?= =?utf-8?B?cTcvNTM2eEFxYWR2OFZNU2dnalFNNjZXSXpoU1hqUVVBUk9QTDk1elI1Ukkv?= =?utf-8?B?QjY0ZS9EVndyUloxZHdiU1cweXBjNk0rbHJEYy9ISUFTbFNPWnNEb2NZSmRW?= =?utf-8?B?eVdDeUEzMkxCaHhRVlMySnlxVDV6UzBockZBK0hIUDQrdlBjUURWRi9aMEFw?= =?utf-8?B?UUNsbE5FM1UzTzlPYnlWdDhjWWhMQjRDS25NR05RT1k0aGZrQllrM0w2K1Zj?= =?utf-8?B?K2pEQzVrL3o4Z2J6bEMybUh0Mk12NHJWcVo5eDV2K1A5MkpyVEpJUUMveHB4?= =?utf-8?B?L2h0b3pJdEtkeTVsOUxaaWVQQlgwcEM4WXZIQlZTcTZDWU5xQklVcWlyM21R?= =?utf-8?B?K3dENHRhT2VlaG9UNGkyWFFoWXlMVEJFakErcDAxSW5lOXNRaXlrS2pYZ1Fa?= =?utf-8?B?QlF1UDM1MzNYekp0ZXhyTDR1dWhReHovU1VPV2w4RW1MVmR4dzQwc2traXJJ?= =?utf-8?B?eGkvcjJlSUp1UFYwcUd6UFVqbEJMaXRHMVpDZFhaVFVLTGRMUGVtN0N2MFRp?= =?utf-8?B?OHNMOXgyTk1BUVhHYVFLT2ZvMHZJYTZNOTl5OUYxNHF2aUpyaktyQXRQTzR5?= =?utf-8?B?RHNWTi9OZG52RC9zTVg3YmgxNmppdkJkVXhLSzdsam1lTjV6eGdhbUhTTkZs?= =?utf-8?B?Q0ZpSG5jMkpJR05IazlHTS9mV0luQ1Qxdm5CQTFLRjZYMEFUNEZEREQrbk95?= =?utf-8?B?eTZlc0tHOTV0V2x5TE10ZDJhMkNIRUhvK0l0bjVucFpnV09kTlRJc2Z1cnJ1?= =?utf-8?B?QlQ5dTI5bkFSTERCVFZJV2tRR2JXclRlNVNoNzJhcHllMytPQVdtSDhMUmpz?= =?utf-8?B?VWdseDBseWJrbTJuWUFldDdUa1pjT3V3M3N3L2krbW5kaTFMbWxmTGpncGlB?= =?utf-8?B?a2hPeHdRWDZNTEFrbmwybVRRV2FOejdicEhtcStCT1hPd05hR3U5czJIbFRn?= =?utf-8?B?aTBUYnAvbkZORWE0RGVzNVM2K1R5Y2R5S1Z3VFpZSUVNV0dQRkZ3cnU3bGh6?= =?utf-8?B?YXM3MXhGMVlQc1hDYndIb2hGbjZQRVhaVEhYVTEycGlwWmIvREhYTnJGMHcr?= =?utf-8?B?K3FoWGV3T0RtVlZPUXA4RWZBYXlGQS9aNkV3Z3N1MVBoaHNTWEtseVB1VU0y?= =?utf-8?B?U09lalQxZm9BWHBhdFVOdXU5RGNTWllyamI0REZCM1dZdGZrdXU3Y0E4KzBq?= =?utf-8?B?ckdub2JVUmNvZEU1R1ZFRmZvd3REdW9Qb3JsNTN1Z0FPektoNjFlbUNidDBB?= =?utf-8?Q?79DDgzse7N3jW82b6f30Yc3Df1mcpCRpUxkq25YqVweZY?= X-MS-Exchange-AntiSpam-MessageData-1: pHe9LELjzZfT6A== X-OriginatorOrg: Nvidia.com X-MS-Exchange-CrossTenant-Network-Message-Id: 321a646d-c990-4bdd-7c21-08de6d321bf9 X-MS-Exchange-CrossTenant-AuthSource: CH2PR12MB3990.namprd12.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 16 Feb 2026 08:05:11.9772 (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: iwwc4P2gCyHFgh/cWIg9yOvuA+HE7N9AqZyKYWwsUfwLhnOg7qqvTzfPsZie2hI6cwLS1CCLgfJMb3ipQ2oyvQ== X-MS-Exchange-Transport-CrossTenantHeadersStamped: SJ0PR12MB6832 This feature is stable since 1.89, and used in subsequent patches. Tested-by: Dirk Behme Reviewed-by: Gary Guo 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 Fri Apr 3 01:40:58 2026 Received: from CO1PR03CU002.outbound.protection.outlook.com (mail-westus2azon11010057.outbound.protection.outlook.com [52.101.46.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 E39D52EE617; Mon, 16 Feb 2026 08:05:18 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=52.101.46.57 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1771229120; cv=fail; b=I5CEcCdlo1yDotABCR7NRIJV+WfR3AgkiWXlmuqXiFTtDoELUDLgBVfAZK2S4m7rauHY26uFKqp/BPRXLAcgWHvf1cdR9XvLO53SuzHi63WSs3FKq0Jm+Zm2U3c0vNnYe46j91DkbJ9tcZhnEmrP38ZR5/PQLBVIDpBggT1ugjo= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1771229120; c=relaxed/simple; bh=aopK2/+di1M+EzJJlJKolIXD1RgY+H2U/JzAe/r+Zh0=; h=From:Date:Subject:Content-Type:Message-Id:References:In-Reply-To: To:Cc:MIME-Version; b=E2q/ddqM3Eco5AL4Bof0eGjKs3KAfSsi+RbRV4Y7nkf94qq7rKf383FaTnLWtfTRElslhE5xz3k0qZGYoxwxhsA9Oo3kzfHpt7uQkDGcX7DvSglRfo38ua9VitywGpRl0dPSutCTZvTAwqwcfpFoyoDqnGJEkm5GgWdCm+BcVBY= 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=r1yPSGeN; arc=fail smtp.client-ip=52.101.46.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="r1yPSGeN" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=mp34mUlzSA6k4gAfzzqETt78A36QWZJbJyk4ddH23XY10oHSrrceXJlH2CMfzQeZE44W3SZGvLUY5z56Ln+xoyFw/bNHrOEXxS+R0cXC+Ynq0TdNYchmRANOuwhS2gYeP7nCS1fTbFmvL2mNEAn9QeMItdCX+pA9SZ5ilyaJ19Uey97mTzb2xMwCPpCChDX8yFLky2PY7nZPgGvCSf8q7cqhaWgxui3k9Sb1sCMDTz+rADpI/uGkBkVcHYyywHuT3vIcnc7vFxUU4LpWjp9JZlXsKDrSaGBpYehjI2GYO/AEjcSSkcwEaWaAAo55cLRUgupNMxt109WLFL74wnA7sA== 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=WQynea4T8ZzxQKtSBqmBf/KGVqj9AZi9FNl5cCnTU38=; b=WZuxRdSgIFCRIMelj4zvFjcXLMRVim5HxgojZyi5ukfs8Y88Y7wO8aBpBw6DlCg/R9w2O8A9NrjikjmLNQdule8jPCC+qn60hZ70Qph+i5EhFzUxDZe1FgQhrKxjwYVQFDVt2Be4uIXq8AINYkfHjiJm0W2H1zCjNIQo9k++wsFzPsPVHXOBpVFxH4cKSN4XlCFVFdQAU69Z2qaPZA+CH0m+80Vd6qZTv/i6X2+fa8K/cHBwm558slN6UOj4TXenQNB0LXfVtJKC8D5UWFTqxaKgOpkAJJnX6Ef+c2uUoqXzzPpVE3T+d5+xqZlpSJzzPu35Cje5TPrMAPrj89LYWg== 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=WQynea4T8ZzxQKtSBqmBf/KGVqj9AZi9FNl5cCnTU38=; b=r1yPSGeNXQJif4LbFw8uO6d6sBdbHZlfPtLd8PP+kalYIH0pNpOhA0ZyThg/O8joRUTY+dU0nB7VoqJYMJhwR/rSdGqixootW078RLzEWvsTG+ST1YrWURwwRCzSRVvlTJIa15sA171dO3bqUlnp+ZcGGwAFPRrQyiG9YD18+sSucK9zTgHDXlZRPqJtrtaGk0+4P5lQYtOzVVqb6TP87KRxgQ3TVDL1xx59+vXMkpoiDKh1xTz/D0MvNqzAuJTI04Ff48pks5DGDpj8WJo3FOoBOSSNvM/W4/ZoyvmMnwwH19g9J13QBNqQbJUU2qJKl5pcpLDrGxk2kXabbVx6jQ== 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 SJ0PR12MB6832.namprd12.prod.outlook.com (2603:10b6:a03:47e::12) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.9611.10; Mon, 16 Feb 2026 08:05:15 +0000 Received: from CH2PR12MB3990.namprd12.prod.outlook.com ([fe80::7de1:4fe5:8ead:5989]) by CH2PR12MB3990.namprd12.prod.outlook.com ([fe80::7de1:4fe5:8ead:5989%3]) with mapi id 15.20.9611.013; Mon, 16 Feb 2026 08:05:15 +0000 From: Alexandre Courbot Date: Mon, 16 Feb 2026 17:04:38 +0900 Subject: [PATCH v6 2/9] rust: num: add `shr` and `shl` methods to `Bounded` Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260216-register-v6-2-eec9a4de9e9e@nvidia.com> References: <20260216-register-v6-0-eec9a4de9e9e@nvidia.com> In-Reply-To: <20260216-register-v6-0-eec9a4de9e9e@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: TYCP286CA0301.JPNP286.PROD.OUTLOOK.COM (2603:1096:400:38b::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_|SJ0PR12MB6832:EE_ X-MS-Office365-Filtering-Correlation-Id: 2913dc60-c812-4f0c-1284-08de6d321e19 X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|1800799024|7416014|376014|10070799003|366016|921020; X-Microsoft-Antispam-Message-Info: =?utf-8?B?YUszU1NRZFRxd1ZtTjBOcmp5VmRVUWxsSUU0a2JPenhjR1JHUlRSUk9wY2Iv?= =?utf-8?B?UWFHdzVjSWFzKzdCMXJER0lHV05LSnlkZE4wZnp4bklVSDJNNzlZOEZBNjYz?= =?utf-8?B?SkllSzQrVmM3eVZLU3ZLWDFDTmtwbmFaQ3NPSVpuZkxjUWw3b1VQelBXWTNw?= =?utf-8?B?RXhkWWg0endBenFkOFNOV242b1dkeFpwWWY1cjBiZVI5d3duQ2FtTUhkT2Ra?= =?utf-8?B?RmxXNFJxUGVIa2RFT2dTT2J1NXFnOXNNbGh0RWtXNjBRcENLcmRKd2hJU0JV?= =?utf-8?B?QnNOZUh4dHJQK05PRERpdnVJckliOXpuNThLTkw1K1dXb1F0TDlWRW1IUzhJ?= =?utf-8?B?dy9rMURFYUpDWCtrcmFySnNqTWxUYTUxb2FYNHNINUNteE9kdzZlVDhHT3Vz?= =?utf-8?B?RGdobUJKZlBGR3ZsRVl1bG5HeFRucGdOV0FCRHgrR1NhWTVlV2pPbTV1V081?= =?utf-8?B?dlY5MXBBOFp2cmRnNTVlYVVIOTZyY2I0TE1BV0RBSUdNYXpEWWxFdzFPNnVi?= =?utf-8?B?b2pNdlorOUJDbENFV2hEVWd4WVZvNkhZdXVGQzdBbXgyVXM0ZmJVK2xhdnNP?= =?utf-8?B?OXNDeGRid0NjeWRyZUR6Qms4YkFtMjdIeE9QRzU0R3NURDV5VFVCcVIwaGts?= =?utf-8?B?VXJUYUtvMkduWFVTYUExN1lxVGM3YzUyTUp4dnZWMXRxb2s4K2xVbVdNTWxJ?= =?utf-8?B?dVlUbmMxeXFQMzQ1eFgreXlURjJ3VHV5VWVCQXJSdE9CUDJLazMxcTd1QTJJ?= =?utf-8?B?eEJvWkNaZThFR2ttZ3dGRUIyUUN4TUFIWDE1OVF3VkJkYWU4U255QTdsR0tU?= =?utf-8?B?M1ZoNHFJeWdiZHpKTlVpSXQ5VE5MZlZMOFBDNUxVSFBzQ1k5M0wwYzIyRCtN?= =?utf-8?B?WDZRaHRTWkI5ZEJxUHhPYWZIZE9TYzF4RTNsTjY3a3gzMWtpVlRjZGY1a3Zw?= =?utf-8?B?eFlLNGp4YzNNRERucHk1cUhYd2NNSEh1UWl1aU5sS1JmbVVrVVVIYlJhZzhh?= =?utf-8?B?RTc3Ynp1MU44UnlzZjJpRy8ybUR5SUl2SmE3SFh6TzdFTm5Gb21RdE5ycDd4?= =?utf-8?B?WmN2VWdhbkdJQTFiVldDWFZxL1RYMmZCMUJiWGgxYzNxTDB3UytrSzN1RWRV?= =?utf-8?B?ZURZeUk4RVAzQjhNemNXT0ExMUoybGYwV0NycVd6UmRMWkt2Q3BZWFJyVmhr?= =?utf-8?B?eC9scEJ2QXhSR3lFMitxYU9wUWl0Z0laNmZXTXNCblgxZ29ybzJVSmtBeVJv?= =?utf-8?B?YnFXS1l3bTFmQnBsUmdVSDQzaVVLZWY1emJManBHTjJ3NGZOblUzTzZpWU5r?= =?utf-8?B?MFlwbTJGaUFyeHJMK3ZjdkFjU20xY0NERkdlWWpXd1lVSkd6a1BYcU5lNXYz?= =?utf-8?B?cjNKcEhpc0NUUjZZUHpBdGlBKzNSNzNEWUozZFdCNUxkakI2SmwyWVFIU3c5?= =?utf-8?B?ZEFSOVQ3TmRzWVhFaGN4QlNEWVJXNWgxSVowNVM5ZmVyRmJTQjM2NzdNWHRO?= =?utf-8?B?elljZk1nTTR5bXNudFVmWWgzd3pJRGdhMTRaMnU2azVDR3NiRFVIWXo4UTJv?= =?utf-8?B?R2oyUktaaWpac3lFQlU5U21WdTVEWHdSVnEzam84cy81SzlKaGMvTGhhQlVp?= =?utf-8?B?NkpkQlMyWmt4UG5mY0RTeTlwRTF1T0hYVVR0RlZpNXZ2L29Cejk5V0dBZ3pY?= =?utf-8?B?WGhURy80eUdWdkRaT2E4RFIreHNLSjNRSEhTeDY3cVJRS3Z2N1dKRVBpQ0dt?= =?utf-8?B?eHNhRzR4OFJOQUlpZ0xzaGwwWmxSZUdiSlJjTVJlWm5LVnI2dXZJWlg5V25M?= =?utf-8?B?SWY3d2grZ1JDTHp0MjRKQlBiT2dNdVRmdEhRa3dESW4reDNHZC93dDhoNzhH?= =?utf-8?B?ZUVmYlUxalpCNnZtYjNCVDdCNUVXT0NTbE9aY29nSXdOczZLbGlhTG5tTndp?= =?utf-8?B?QS9ZN05PRFhKQUJxeHpmQy9RWG5jcVd5bVk4MWVKRk4zd0RWZk5YSElXWTRr?= =?utf-8?B?VzF2bS8rN2RHNnFPaGxGQ1BVSE9pdExYMnNwTjBCNGRqcWdXakcrUnBHcS83?= =?utf-8?B?dk5ubzUyZDIxRXZHVEltS1l0VzRNZkFWeDU5R09Xd0ppaDRNRVBnN2FQNUU4?= =?utf-8?B?cWdGQ3JJeHREdGpiM0tqQmpWaml6eWk5OEhvcXBJV1M1ZzhWbmJpT0tCL1Bo?= =?utf-8?B?ZEE9PQ==?= X-Forefront-Antispam-Report: CIP:255.255.255.255;CTRY:;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:CH2PR12MB3990.namprd12.prod.outlook.com;PTR:;CAT:NONE;SFS:(13230040)(1800799024)(7416014)(376014)(10070799003)(366016)(921020);DIR:OUT;SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 2 X-MS-Exchange-AntiSpam-MessageData-0: =?utf-8?B?U3NnZHhSbzlXZHlQUDhoSzh4MlE3Qm9WeFdrSmp3b2RDYXdNNk9DMTZ4QWtm?= =?utf-8?B?YXdKZjF4dnNycmVjYTl1bnNlN0cxTjc0RHEwMmI2UUg4UXFrNGg0NDR3alI0?= =?utf-8?B?WTlPbUd6S0xMdTJ1Qy80aDZQSE1WT2ttdVFVbHBCbDZCVFo4NFhBUlF1b1JW?= =?utf-8?B?SlgzL1VQMVE2RVVFV0JOTUVaWGNTc2w1T2ZGWjhMNHplMjA5UDR6TjE1elBr?= =?utf-8?B?Rm0vM0F3ZTQ2TDFrcXpYOU5zN0hpOVRiMVlnbkFvQUorWDJhMVI3b0JuMW5v?= =?utf-8?B?YnFGTFF4eEc3WGc2ODZXWCtqNVpsb0FPcS9MNTVka3kzcjYvN3BxZmpydXZq?= =?utf-8?B?aXNlZXlWYXhYUVRJTGdoRnFqcVI4cS94WlQ4dUpGN0tHZ3ZaWkQ2Mmt0V2hG?= =?utf-8?B?b3dmdzRaZnpncHlIRGxGZm0wNURYNUJSU1dYelhJYi9Wc3NXckdvaXVCVEc1?= =?utf-8?B?b1pnbW5FSzd3Z1NNKyswcG5MZ3UxZ05abSs3STZJZjMrcS8wQzhHOEw1UEQ5?= =?utf-8?B?em9QTjBqSEdwN2JETzNwYlc1NjZFQnpKQldoNXFVUU81QjdiZnpkMXpSWVdx?= =?utf-8?B?dG43SHVEQUtTazJoZmxaTkZsa3ZYdkQ4Tlp5N3RpT3l1Q0IrQUxnbDh2YUdK?= =?utf-8?B?SUY1UUY2NTdCODV3a0ljdWtWUXNLbTF6UU04cHdzTVJQYUV1dldaRVJhT2RO?= =?utf-8?B?WUJPMk9jWFdzYklRV2taUXZLbGdncWJDRk82SW9jRDUySFFKSzVKb3QrVk5N?= =?utf-8?B?VkJ5K1JDcFhQc2VmM2VxMm1uUW5mT0JJVXZjTzhBcDluNUZXMlVCcXAzeTlU?= =?utf-8?B?T1R1TDdhK3NVT3h3bnBqZWhlRUdZdTFIc2U5QzRET0FzSTdtWlhReUpFSytm?= =?utf-8?B?a2pSSUl3bHpPcjRWVGQwZG9xUDBKRG9hOFRhOVIrZmhnU29EVmQwWW5sUXR3?= =?utf-8?B?VU41S29VV0M5UFBjTERieEhnYStnVEVQdk4vV3ZYYVEvU3RNK0hFOUZqd1ZX?= =?utf-8?B?QlRYdWhGWG5NSURLa1RONHkwZ3hqcFVFZzYzc3VQU1R1VzJHWFVZb2NBNVBO?= =?utf-8?B?QStZdGk5UWVvZ0RVOGRleXB5N2p1enZFRmVZdmovUXdJZytPVnFCM3kyYlpo?= =?utf-8?B?RXJrRjZmODM5YklJVWVLNEdLSVBRZVZqSnRWZWNiOHY0VGllM2tSZUlIQmp5?= =?utf-8?B?dWVMUzlENWZ5RmlWYU1GWHl3dm1MRk5lenNuUE1SM2NKUUZjZjh1eDcwUlhr?= =?utf-8?B?L3dWYjJoNFNCZnFnVHZDbWx2M25zY2xqR2xiUGpXb2VJSTh0K1ZwU0d0amRM?= =?utf-8?B?bDJWUGZZOUlQUVFlZmM4aGRxamRNSXFheTMzRGNqZUVWZHIyUEFGQmFMVkdu?= =?utf-8?B?NDl2Y1ZlNk40VGxsSlpXU3pwSFYzKzBHL21wdkw1eVRpTUJ2bGZJZ2I0NWg3?= =?utf-8?B?RTNNSnBRRWdtVU81MG1MWnIvYlVnMG41THl3Uk1DaGxaUEQyOEJmU3liejcw?= =?utf-8?B?RlJWZkFVc3Vpc3pkRHVYS2JYTWRRSDY5OEhpQ3hnUFljYkN5anBKTHFmRWI3?= =?utf-8?B?dkVLTU51Rk5xMHM3aXE1WGhWZEdQNXg0WUlqejNQaEV2K1dqUjlqUjJlYm5a?= =?utf-8?B?T0NiL2lPVzBRMlh6OWVrUkQ5eGlQY3N3N0lkeUZpa0dCNVdXWGpkSWhXV3Jp?= =?utf-8?B?SmxJVlN3bXZKV0JLcDJLRFF5SVJWQ0lxZXprRytLRDAwRkE2UGlBMjNhS29G?= =?utf-8?B?bzQvd3E2WS9pSWsxT3V2bHBKQU1WOW9wTGNTTU0yZFpJdFZnSXRINlIrdkNL?= =?utf-8?B?dTRBQWE5UFV2d0dUZk9Cb2VoMzRkQ0lua3BtUS9YSWwyZnNyN1JXNHVwaU5t?= =?utf-8?B?QUt4eFVMbjBkVkFlNWpUdjZIUnkzQ2tSL0R3UmNBNERaU0dCWDhMcGs4VHZR?= =?utf-8?B?bGkxTUgybnkvUm1lMWVsWGdQRWMwTmtDNlVtd1hJZ1ZpcWNaSUFETEN3V1hp?= =?utf-8?B?TUZoalJTLzV3d3NSakxWejNqcjZrWUlTbUd1L0JYTTNxT08vNUh6Q01KZnUv?= =?utf-8?B?ak1GdnJpQ1g2RUFTVE5SMVFvbnZlcnNrNkMrckJvejFQK1d2aEhPYUQxTWhV?= =?utf-8?B?YllSMzNsUUxEUUsvU1orZkovblhIbE9scTk5dGlTMTY2a3lZbFNDYzVkY25T?= =?utf-8?B?RnVuSytucVI4V2l1N2FTTnpBVldhek1GdTJKOWpUY1NaUEJtSVYwOEl4dHZR?= =?utf-8?B?dFhUR1VMa0NtVGZwZ3dQYlVOckowTlpOdFBkNHl0ZXFyQUdyaWhDK09yZzFG?= =?utf-8?B?R2U2UnRDd3pqUElvaUxHc0tJSkxqSGdUdWw3T3RLWWN4YTVSd015QmJtSGx2?= =?utf-8?Q?803Q45Glr5Os+zM0rNqNpBH7J5QHurFOt7wm3w2ZWj1Li?= X-MS-Exchange-AntiSpam-MessageData-1: wlLgTbZ2Q24jvw== X-OriginatorOrg: Nvidia.com X-MS-Exchange-CrossTenant-Network-Message-Id: 2913dc60-c812-4f0c-1284-08de6d321e19 X-MS-Exchange-CrossTenant-AuthSource: CH2PR12MB3990.namprd12.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 16 Feb 2026 08:05:15.5077 (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: kfcvfFyfOLGlQ+3+1QJDNyuwDimu/Nz2G3WYMTvHwoOlk3YI9maV8nMoBR0fJNbWTkG9SqtKVIID8vnQwbvUaQ== X-MS-Exchange-Transport-CrossTenantHeadersStamped: SJ0PR12MB6832 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 --- 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..7014b5be66db 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 >=3D N - SHIFT) } + + // 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 Fri Apr 3 01:40:58 2026 Received: from CH1PR05CU001.outbound.protection.outlook.com (mail-northcentralusazon11010036.outbound.protection.outlook.com [52.101.193.36]) (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 EC4E72F7ADE; Mon, 16 Feb 2026 08:05:23 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=52.101.193.36 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1771229125; cv=fail; b=MO6w4YsvSJRIWyF782HnBQKefIYJkg+EVQoqIXgyaDQqU8GZgrkXZ6+TXz9gDEfTvvm6g+RBs2MWlbEV8NUjkHyw5JuzKr3mANleein6OYMNh7dfspq2On180qaRAnY7avTCAVa5X9m4NCL3pgi+FnFE2ut5bXUXysp9DMyGyi0= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1771229125; c=relaxed/simple; bh=hv97a2fqzXjikua63NuXqoBix+iReqw8YTH8WK+k1Dk=; h=From:Date:Subject:Content-Type:Message-Id:References:In-Reply-To: To:Cc:MIME-Version; b=T9FJVa25hKhGNg8p3kwbE6i32STiyvncEmejd1c41GTjDARKSMlzG5vukNKqzyjLe8/XbzPlfPXM2j1E8C2sUUHrZVMgsRNJ2QXE+GwPM3AJsmR6sLKlF2X6fUKms0MLTSTUUjSee9S5cSXKw1IdM5YNVMt6KHcF90JG1mJkKfQ= 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=sz0DOJG5; arc=fail smtp.client-ip=52.101.193.36 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="sz0DOJG5" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=XRXv/D+x0Bkh7PQxVDUFLZDtzOJetT3gfiWzfiUobvZpKhHEDcHaxrqQnnsJs7xGCUVV5cGuVQrwrowlIN21PI9huiNs1tJx9aOZ5T8cObAHvdcvKvJNNAG8KoQg/hR4N9fDVsEL0Wg+VVgA0dtbxrodKiOPrAViJdoBH8FgSfwSB8LU/Zmc1fYyQfNn2mJrVwRf9S1QGf1A9hng+46q08dFlZPgdVq3DvEJ1A65X4EyFmQFahuQafnDxdXqWOBWXvl8iBPNI3KDFQ8EPBoogg+Fs8Ewt2ovtDrIF8G7B18tSCvtWdhLfy80+3EFxQae2v3+ApNqbiLOHz1N1i1Aew== 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=cv5JKYnqpvrnuUFVg1sieZamDmuXJk2Qfart1UP3suc=; b=K246QZLMjjwoPGD5Zb1PuAQtpn3ZFxWGFzTK6WaFnG/ImyRDDnbBnw05fCowyfGrFvovASvdyYvyg5Gcv7sumAVr8yRVLEof8IKbkJDZefQZ9WmugUgjZ7RipFAlaH3K3aCWzEqgnHM8A7St+gKwI2ubPCJpltqEWLSi10kIi2nuBP9O7oAaFs8C5gg4fJeTEF2dKX9JSjuqRMtSCXHVTlJPRPNdn0cIJhgiiAMFg6QykrW7HizIfX4jONPTwAr+O8mjK5TEoS4b1v3Lmm5gWlZDvZHJVF9fRKjhatZ94j8vtdTBrp0cuB1DYlizRwnTHkY7frxmcpYUHzTBo52Glw== 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=cv5JKYnqpvrnuUFVg1sieZamDmuXJk2Qfart1UP3suc=; b=sz0DOJG5yJCkqRL4LfNIjMR++5uJ87phkIMtGGWo4hN46lvvQ7kiHnTuyLRzXdGSpSyQ58hljsM8S9iJYud/bsRAwunvwBjQY2/TIAk7lk9RRf5+m47lETlstpnfvTHnNqJvhl8IpC15pS/IOUHV8kg8+K2sL8Y5HPOoPuaMnRMojB7o/THtKnkDrSnQPcrx0k6E0BZN8N1D+BaiRsD45QOyA0ZLSxZyoHHRUQ1O6ad79aHzhXCOisHaUg9GoK23qFf3xp4jM0Qw9YmKO1FQDKVCK5laCPnnbT8oeH3TbC4sk9Z3Md2YxZ8Aj44J2g9rTQemyTI7vuQKNjO/jQ02jQ== 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 SJ0PR12MB6832.namprd12.prod.outlook.com (2603:10b6:a03:47e::12) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.9611.10; Mon, 16 Feb 2026 08:05:19 +0000 Received: from CH2PR12MB3990.namprd12.prod.outlook.com ([fe80::7de1:4fe5:8ead:5989]) by CH2PR12MB3990.namprd12.prod.outlook.com ([fe80::7de1:4fe5:8ead:5989%3]) with mapi id 15.20.9611.013; Mon, 16 Feb 2026 08:05:19 +0000 From: Alexandre Courbot Date: Mon, 16 Feb 2026 17:04:39 +0900 Subject: [PATCH v6 3/9] rust: num: add `into_bool` method to `Bounded` Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260216-register-v6-3-eec9a4de9e9e@nvidia.com> References: <20260216-register-v6-0-eec9a4de9e9e@nvidia.com> In-Reply-To: <20260216-register-v6-0-eec9a4de9e9e@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: TYCP286CA0136.JPNP286.PROD.OUTLOOK.COM (2603:1096:400:31b::20) 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_|SJ0PR12MB6832:EE_ X-MS-Office365-Filtering-Correlation-Id: 1d90c98f-77b1-4df2-5729-08de6d322045 X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|1800799024|7416014|376014|10070799003|366016|921020; X-Microsoft-Antispam-Message-Info: =?utf-8?B?NkJnTHBLZXBRQkdNRW9RS3JyUXpjcXJzbDV5SnFTV3JnSHNJRUtUbm1zTXJn?= =?utf-8?B?QWxNak0vcFZzdEFsTTFHdXplMzU2WXViWDRhb0ppd20yUzVieG5xSENWZk5F?= =?utf-8?B?TXFQUExBdCtobHZXUXJFaUNteVgyY0wrNFhDTjZXdTdmVlZBMFlPTFozc3VX?= =?utf-8?B?QnY0dDFHaDdSWTIyb0p1SE5BM25halhZNEdLS2FrOEM0cDYza25jU29leE1q?= =?utf-8?B?SHljVDc0aEdJdjEySEpQU25IWHJHYmFDT1FlZzdtU2RwejRHUmJWRVpwK2Y3?= =?utf-8?B?VVJXZHhVdEdqMTBtaXV3UmtCdU1kQkhjMTRqT1dUWm5nbGcydWtRWUxLSEF0?= =?utf-8?B?YzQzL242a2JvZlhyVkExbEVpYzE3eWNGMUJKclM3N3pGbFc2c1pqcGNCQ2VK?= =?utf-8?B?dWFQNVhZT0V1WVdvbGEyeUlvRkV5REROYlQxVnlPSjcwZHB3TWNRL25hSlM4?= =?utf-8?B?bFRQdTVnYmxKU0MzWXVIK2FrVUJDcFB1ZDVFTDdOUUtrSWZTOGdkNlU1cVJj?= =?utf-8?B?azNhcDRhbjhENnZ1Y0lIaUV5OGpZRFZHWWQ5cmJyMVNScFV5WXJHclZkVGJD?= =?utf-8?B?SnlFaStFUzJFNTVaMW5Kdk9JOEY1NGpBSkVWMUtsWkpZSVdSeTYyQW1HRHdu?= =?utf-8?B?ZmViK2pPbUM1Vk42Z2d1bDFkSlgyb2R0cFdPMFpvN21aNFc0WUxDUzRJKytm?= =?utf-8?B?T3ZndlhwakVad0ZhYkNOVTY3cDljaGRaV2FxV1VoUTVpSnZySi9oYmJBSDJj?= =?utf-8?B?Y3JreWN4dWVEc0F3K25jdXpTZkd3bSttV2RKK2pMQ05pWlNQcklkK0RFK0NT?= =?utf-8?B?MDRCM2hmK05kOTRYV1IyVE5qbXBROSszQzNIM0VzaGdWS2xKOVlvb21TRWJq?= =?utf-8?B?RVkxK3FsTzJmNjJHUzBLNWNpc2tGemV4Y1NIdEtVRHJISms0c0YrNmVwZG93?= =?utf-8?B?RzhYc01PdmMzOVJQZTVnVnNUMjhhYy8rU2IxVzdYT3k2cFRBV2ovclJDajV6?= =?utf-8?B?V0RkOVAySUJZQlljcUVHdXdyTnZIcTRpd0lua3dzMHdvK1NrSjZxa1BXYkRu?= =?utf-8?B?Qm4rK04vcktaWWpiMW9lWE9MbzRtcWE4UHp5SDFGUk1GdUkwVWZMRGNQdW80?= =?utf-8?B?UW8rd09wRjBHTm5wdjh2eUtzVDVCZXdUN0FkVVI2VlJBUkRJTDZjSWhMalNN?= =?utf-8?B?bWNoUGllMDJQRVo0RkI2cXcvTmpsckZNMm1KZzl4VkpOdndFeEU5UFZieng2?= =?utf-8?B?c05UVllDZkwzekwvL2VteElSQWRFamViRVdybTgvOFhweHdWWWp0WmR3a1pS?= =?utf-8?B?U0Rvb3psaWIxSG41MUU0Smt6emozb3RQYjB2cjZ0NzdEVUppb3RmV1YwaGR4?= =?utf-8?B?SGN0UzNOYkh5WkRXVUtTa213Q1dPazFpNjQ1bU5pbU9tUWZtS0FiWG9SaWVH?= =?utf-8?B?VVppZk5SV2hRaklQMUhhMktwOHkvc09RMnhHcnVuK1dVMFhrYXY3cWlNblFm?= =?utf-8?B?VDVpbnMxUkVyWWtqSzdYM1lKWjB0Y2NCY2pldmt3dGY2VHJUZGZCZ3ZhalA3?= =?utf-8?B?VWNjbzRsZHF5dlFuRDVOSGJ2bTVIRG9RWFVlc3dUVGM2WGVhTUszQ01IcENC?= =?utf-8?B?Q0g5bjVqOWJyb3FWc294L1JpUHJMSTRHTWJwektabDhzdEsrd0gxWXVDYUFP?= =?utf-8?B?NkJuWmhoaWV1dlZPcDQ3UHFGejlWNXRVOGFOaWVrYWY2djN2dzd3MVgwbTFW?= =?utf-8?B?MHZLM3NOUkg5cEFxdUdUZXgvakdjb2liYkEvdllIMHAxRm1rUEJBUmZiNXds?= =?utf-8?B?dlZBMXova202Q2dsVG5yY2FmYTAwR0duOHllR25qWXZ0MmlMRVplZ1krRlAz?= =?utf-8?B?ZjBLb25mYWxWS0lyd0gyTjNBSStCaUNPVGlDRW5SeU0rVlcrTDBueVJhbktt?= =?utf-8?B?YjRacnBYWVp0QVR2VGV4c0p1RWZPT0pNRHpkanViWjBtS3Y1cWVrWVdhdWxJ?= =?utf-8?B?cWNFRjhWZUNnNGtYdkxMeWFMRzlBT0I0RWljdTh1d0QyRUtERWg0REh4czhQ?= =?utf-8?B?Umc3dCtMTWtPb0dEWWJ1RloyVTVkY1ZGZ3lDMHFsQlFtL1Q5UUw5ekd3Zndz?= =?utf-8?B?QWQ2endTYTZPR21uRkp2Y3lyS0tCZDh5aEVsVVZwRE1ta0loUnM3aks2Zkk4?= =?utf-8?B?RWc9PQ==?= X-Forefront-Antispam-Report: CIP:255.255.255.255;CTRY:;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:CH2PR12MB3990.namprd12.prod.outlook.com;PTR:;CAT:NONE;SFS:(13230040)(1800799024)(7416014)(376014)(10070799003)(366016)(921020);DIR:OUT;SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 2 X-MS-Exchange-AntiSpam-MessageData-0: =?utf-8?B?NE1KMjZrVlB2MllXZElYcXNPZ3owY09XZ09GQ1NtQzhwc2tRUWdoRHc2RjM2?= =?utf-8?B?TnUvRGRUL3lSSlp5SDBNNTk1STZISWNvazBIalh1ZXRRbFFGdmU3S2c0eEhm?= =?utf-8?B?Q0lUZXg0U0NqaEgwOUtXZm5OTUR6K0g2Rkh3bVNuSmY0dGViREdFUVBTMTdQ?= =?utf-8?B?TkRsMzU5OHN2MktrT0ZqeVh3TUtvaGtwdWdGV3Jtam1DSC95UEs4SWhMeFFZ?= =?utf-8?B?NEM2bk0vR2pUd2dCOExpaldrdmpFdytGU3NLYllTTmwwNDZPMHR1cVoyV0FX?= =?utf-8?B?WFpTSlVXTTNDcENrcmNkRjU1b2ZNd0wwbzZkUVRtQThQRi9lUm5Nc3N0dlJ2?= =?utf-8?B?Y3c3S3czVSs1Lzd4ODVyRGlEQ1NFR2NQeFZudElJcmNLOFhKZVJvazkzb0t0?= =?utf-8?B?dEtPMDVJRUJPcXByYmNuUXZzQUJRSFU4QVdaV2RmYS8rM29aZGhNWkkzWDNi?= =?utf-8?B?ZVFwaksyWUZCYlNxT2hBSEFQU3dlb0lZdzhSK05QVW5NWjIrYWxsMS9rWHBP?= =?utf-8?B?T21JUTArOHFQSC8zdGtVR3dhNUt1L3lodnJ6UmR0M3dtVmUzT2FtQVZuelZu?= =?utf-8?B?elZPQ1cwWXdBb1JnejZCSUVxM2lJOEw3MXM0SmtuZ2hnMDljLzdoU2w4ci9n?= =?utf-8?B?bjJUYzVsSlBFSmJkRWlRbFgyZmhhSkFiT0lHNU8xd2RwRE02bkRDSDAzNHc2?= =?utf-8?B?b1Y2YmZrU2RTK0Y2V21ENHNQRWNkelpibnFiWWovdUJBYWxkaXJVRnBRQldp?= =?utf-8?B?VTlyVGZ4aXBZbkVLTHlNQVVYRGlBT2Y1akQrS2RtUXR6eElEaUtGZFZWdTM2?= =?utf-8?B?bVhqd05wa3BqeWJmb3diVDhmcGhpQmFGWDB1Q1gwcVVDenVDZG44YXBpU1k2?= =?utf-8?B?akFIK0p4TmlFakE4UTFTbVdHK3ZXRTM0eE5Sdjd2WWpSS05nRHV0UTgxUHYy?= =?utf-8?B?b0dibjlIZCt0QTVRRUY1WC9xMGZVNlRUNytoQ3hOdWZjY0orOXJXaVBXdXM4?= =?utf-8?B?R0g3alkrQjFycUIrWW1nN09yY1FDcEhmWVh0SWgrTFJ3cDdDRE5QeG1ybmxx?= =?utf-8?B?cVljSmZ3MU9iRlJqZ0wwQ24vYUlqQ01zK3hJNkhmZ0JibzhXanpFc1JZZ3NV?= =?utf-8?B?UGJQcW5qU2t1aWE4ZFRmNVFGc1RjbWhKSVdFL2MybFdkdHBHWVNFVjdTS0E2?= =?utf-8?B?VUZ0aHlpSDBZc0krZkJzNDlBSy9pM3o0S1VPUVhUSDExWUo3bWtNR1gyYml5?= =?utf-8?B?VDFiTmlKU1RwYzVlL0ZiY2pKREdEMndDUHUydnBEWW9BUzJCRVhkemJrSkdL?= =?utf-8?B?NU9hdkFTN0RHZTJWdWtMSG93SnRtb1pqSFhBeVZEWWRxeHZSVVlWM25hdkpu?= =?utf-8?B?WFpyZ1c4UnY0VTdjMERKd3BvYmRZaE92M3UyajMzNjlDMGJvbnlIN28yYUdZ?= =?utf-8?B?Mi9rMTcvRGJsVjgyRjRFdzVKb0NEcGMrUU11M2FKaXhhZXg1akhMcDN2L0o1?= =?utf-8?B?RUVHYUZNY1ltL29zWmRPZ3lEamY5L1ZFT0VubTEyRkdsTWg1R3VFbFVpdXF6?= =?utf-8?B?UTFJSDNBbktWOE5pNTZNOCtLak44cnZHUUlpZFp1YTlRRmExL0RPUC9iYVFM?= =?utf-8?B?dGZ5UWN5dGsvcHVBTnZIemh0bUgwdkZpbCsxZ1pKVDVodkx3T1c5aFJ4QTd2?= =?utf-8?B?RWVXbHNIS2RqeG43K3hoU0ErTllwZHMyM3FvYU94RHByWkxrYStOVVVGTkt4?= =?utf-8?B?Ukdod21vdTl3Q2Y0U29uN3V0TzhEVTVobUljWEdIdkNySVZ6c1pCUlhxU290?= =?utf-8?B?emwrZlFVQTkxUi9wU3pDVzFaMGpxbStvSFIrNW5SY0VFQ2p3T2xLUE5VYlFZ?= =?utf-8?B?L3ZxNkNoVktaekEwRnJsaEJxQjlod1BkSWtwSHZlS1NVQ3l0a2d0SGlrQ2ha?= =?utf-8?B?a1drNXpuM051SmxwdzYva0FHc2NpN2s0Ym5MQWtvWXdQWEZ6N0VVT1BYN3N6?= =?utf-8?B?am9wZXFVcjc4N3hMYWhQRXgvR3FDdU92SU8wSDZERmxMWEdNMkNob1duS1Yz?= =?utf-8?B?ZVpUZE9mV3NEQ3ZmdVd5Vi9yTDRJZ1k5QWNzaHV3UHZOSHU2Wk5EZjcwRjN3?= =?utf-8?B?Sm9obEJHRnF5UnlzcWQ3b0lnZlhqeWFiTWtEaWp0eHROWHZpeUl4NkpTT3l5?= =?utf-8?B?NjlBeGFPRjBGSkhjeW1RYnVUWU54Q0V4cW8zbm9GTERSL3hkbDBvWDhjbnRR?= =?utf-8?B?OTZnbndMM0l0RWJkTGZJdUwvUE40Q3pTV29oRmV5cGhibWVMNWxiZjZqMXlp?= =?utf-8?B?YWhOeFpWWlBkdWloVEp5TWhPOVgyS2krQ1VES1NJazhxbUtkTGZSTFJCZ3Jq?= =?utf-8?Q?OtPvxG7qxJfuiFkMQ38fDs5oATjUrymMsXkZsx6xF3BF3?= X-MS-Exchange-AntiSpam-MessageData-1: e2L2q6UGqh7o3w== X-OriginatorOrg: Nvidia.com X-MS-Exchange-CrossTenant-Network-Message-Id: 1d90c98f-77b1-4df2-5729-08de6d322045 X-MS-Exchange-CrossTenant-AuthSource: CH2PR12MB3990.namprd12.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 16 Feb 2026 08:05:19.3188 (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: 4hv/MRG1dm0Qw9L0cLu48NcwwrWisFkQF9hET7n55d7qTCHyr1thdeD6i9ddFRseDgt2ctPty2JSYc+snOgd4A== X-MS-Exchange-Transport-CrossTenantHeadersStamped: SJ0PR12MB6832 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 --- 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 7014b5be66db..8e4c08924d96 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 Fri Apr 3 01:40:58 2026 Received: from CH1PR05CU001.outbound.protection.outlook.com (mail-northcentralusazon11010036.outbound.protection.outlook.com [52.101.193.36]) (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 68D762FE076; Mon, 16 Feb 2026 08:05:25 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=52.101.193.36 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1771229126; cv=fail; b=SdLML0ElFvuXLWIVMdauP6VT37lK5WF1wgjeMMcRrsTDNYsG1G5KFRcfj/10eWqmVsW1wPwQUBloZJtwW1eebgH/wY35YXqOhT4qa4q4jF9nawPfiE8bhNcC4STfOQ4ncFuj9TnY81eFVcW5u/czCkh3N+lcjhMIj2T3lRvvHX4= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1771229126; c=relaxed/simple; bh=y926/UJ/g1xEjLjydSv1FG7S1eNqGr0qB0ThTWHQDfg=; h=From:Date:Subject:Content-Type:Message-Id:References:In-Reply-To: To:Cc:MIME-Version; b=cG16GSeRbL7W+b8afExr0aJJ1uIKmDFP0bdJ7vO0ou/438Q3Nmu+YzZgStIuOS2/A+LqeVby6qa2KGez+6Ub4a8LWANdfNMIrS/hy1Rkjhf6hxhi7D0I7NyQbKctvCT6yHsekDRjj1Klb2LfsOPL+fDFjCbhRIwIyK9T6arXIjU= 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=Ee/dCrsH; arc=fail smtp.client-ip=52.101.193.36 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="Ee/dCrsH" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=KC2hUssJur9zxSGAP2qBQV1934i8ar1w5BTed0yYon7BH4Uruu5WWXMAKEOUFP2SdDJIuCMwBmtNfGT0fZ0yhHFOCwcWDy7FzCZhUVqvhpEyfcM9mCGvp+gZOtDtkn9IqJhS1hwimNBJcycjYS9dngP7xbnG8P1XprzzGudCRljtURMQJhqoZwFkA86nvbnryYfzmszOFj9tuCwA5h7Z+Fcvl7EgA+jDdNaUKgMsxCi0KQSBIFls2Y0+FOEgOaqsqyg3dLZO7aJmOt0RF5xayC78RmD2bC8EAofq0318Te3zf1hxnbJFZJF4geR4t/98Ereakh9remCUkW9cUlcQ3Q== 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=W69XAM9t97CiywdjiMzuKhyGgwirjvm1zvnEl+j5k9g=; b=bnGMNUUYKzyiuVOjIBN91UUOE/Cndp97euadnefg5ZTSWqRMylZx4IdgACV2wDJf2ZKRzVZbrX+UXxCAf5c3bQCu1F+VKqSc89OhoHEo6q7+fd86rcfmYMGpSNHwoflf1WHlVwLvsIce1CnLsQvxFea+QCFQU3DpN18fHwvi/bnT6sp+WtJ3eTjvSnGCh3gT1OKY6FBphmcoPf2BNCku5NiFw4FkWkLuyvus6aNzQLVRm1/qQLnXfx9NXxpFNB+tQhnp7tVuQ26zjtC4hhvbqGI3PAaRvB5KhXnpbxkVH7pZT4dkLJMgzdWKr1Bzyks/vIiLjcvmlNLm+nTpjOP21w== 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=W69XAM9t97CiywdjiMzuKhyGgwirjvm1zvnEl+j5k9g=; b=Ee/dCrsH4PLnhi0NtXcJ/6AIOCdNMba4ngh1ySzJ7NCe/qdyeKfZLM0zwBIUE+4wcWgMKmPon57TcR34eBPUBCN7BvGzZ7JFyv2aH87uVseT1btAj2+U41E7ZQ6mSawTl8xDPDaTlon/SbGIzDgHjIs4oDi2pHFb+r41QaBkBV0YJDB3Dsqr0kOpWMSJ9YLHxJi3D6XmadrZw1krTcpwSNLJJZj8qDr8Z/oxVfG/0wHUEpgy5mQgpQLndwID3N0Orykh6qidCkah+sxNtzCBdba9v3iFRfIqQ1vuGIs/Pm5XQcHiq6u6Tn2SXOFwsUptX1sXU15CdgKfnT7y+P1SoQ== 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 SJ0PR12MB6832.namprd12.prod.outlook.com (2603:10b6:a03:47e::12) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.9611.10; Mon, 16 Feb 2026 08:05: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%3]) with mapi id 15.20.9611.013; Mon, 16 Feb 2026 08:05:23 +0000 From: Alexandre Courbot Date: Mon, 16 Feb 2026 17:04:40 +0900 Subject: [PATCH v6 4/9] rust: num: make Bounded::get const Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260216-register-v6-4-eec9a4de9e9e@nvidia.com> References: <20260216-register-v6-0-eec9a4de9e9e@nvidia.com> In-Reply-To: <20260216-register-v6-0-eec9a4de9e9e@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: TYCPR01CA0173.jpnprd01.prod.outlook.com (2603:1096:400:2b2::11) 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_|SJ0PR12MB6832:EE_ X-MS-Office365-Filtering-Correlation-Id: 7cfa3b06-d514-4066-adfa-08de6d322283 X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|1800799024|7416014|376014|10070799003|366016|921020; X-Microsoft-Antispam-Message-Info: =?utf-8?B?K2Rob2dqRkxUamUwNE4wcUZTRkRFZkphVmJhdmpUemlRSXVsYjNOeG4xN1dy?= =?utf-8?B?Y09xVTUzWjNVcHRNWXQ0MnlwQmdpdGllUXg4aGIybll6aHhpOWpWNkFwRjRG?= =?utf-8?B?Q2VGekdxU3NwY3ZEVmpPRyszY0RHQ2RoZFprNDZUdmxvY0FUWFlqVmFJYVha?= =?utf-8?B?NWY5SGdYWHBPdEJWQ1hmT0JmSVlDQ1ZRc1J3aGtMVjZMMVlGSHFlR0N3YlI5?= =?utf-8?B?ZWhTWmovVmlLWVJMRmExVVVFQzlWNUdianEzclZrVCsrWWdXK2ViQWEraEVT?= =?utf-8?B?RHIyakJhV3JwbDRGblVsenNPaVJpWmpHdWQrbHdxd25TWGp1R1A4M1JKc3ZE?= =?utf-8?B?S1RyU3ZUWnIrVTQ4L0RqczM3cWROSjF3cms0R3FZaFdncnhkUnVuWmhHdTFP?= =?utf-8?B?d3hMUy9pbVNhaDlhbDhFQWJwazNvcVZZV0w3eUdOT0drTlVKYmZTckYwcGRS?= =?utf-8?B?QWpjNWdXSTVhWGpWWnNVdEFqTEVSY0xOMEJybHIwVERuT2tpWS9Tc1NiVnhZ?= =?utf-8?B?eHhiMWd6QStocll4UEtVV0N6MDg2UGpmVlo2SGMzYWphVWNrRHpTQlV0azJy?= =?utf-8?B?R25TMEp1ZlJIb0FtTk9MYUxMNTA3aXlmTUU1WWFSOSt0Y1BkdmtBSFM4R0do?= =?utf-8?B?Z1Q2dS80SzZ2Y3FkME95bkhjaTNqZTgzMXNudm8wbGpjV2xHQ3ZqSTg5V2d3?= =?utf-8?B?WERHSFhra2pzSytsN0xvb0t3SUg4WEJzNjNkcC9Ra0dwNzR3SWw5aDZib1RQ?= =?utf-8?B?WDhlSDREYUpUSUoxaFI3NzZzRXBpRllpM0VWTzJCUlQ0OHZGWVZId0FLdFVn?= =?utf-8?B?V2pYZnZaRCtvdEs2Y2F0U2laYTFaVi9VdXloNDA3UnR3aU5LdlRXWTc0WG1s?= =?utf-8?B?TjZBUlA0MW1jejI5OUE0NTFpelVPUWZ1SGh6L1RGNlhCanhLaitFWjhuVm9F?= =?utf-8?B?WkJNbWZRQXRkbXFZU0lLRTNSQzRxZkJMNElCMloxMjRUbHFBc2k3NWE4Kzly?= =?utf-8?B?SE9CajlVbkZFK001aUloZjRVMlEzUTd5VTMwQnlHd1k4RWd2YmhpT2ZqVkE3?= =?utf-8?B?QkhkSXRSaDJxRzlKc3JUWjJaUzFJbGRKblQxaTQ0VFg5MVM2ZWxOSit3bW5C?= =?utf-8?B?Ny9qLytyQkJZakRIV0tKOHRUZmljYm8zN3Vub0JXS2Fjd3BvRFEzZEFTeWJy?= =?utf-8?B?R3hUbzF4Y3Z2RkM4N1pTTmlRTGZaRWVvWVRRWHV3eEpRMjNFaWRVb244M25T?= =?utf-8?B?Y01xRVovTlQwR1o3a2VGMkRldkxkZ0R2NDdNL1d2U2s3VXJyaE5Oc1pQR2k5?= =?utf-8?B?bzhGdVVERVdwcFZydXNEdlBBa241MlNkRnlXczUreHA4V212RTl1OWp2NEVM?= =?utf-8?B?ZUE3VlBPZ0lYeEVBYm5ING9tc2ZIVmlrWnd4TFJjYWZLWGFUUFBNWFhPWTJW?= =?utf-8?B?UWQ1U081REh4RDJ6V01PY0paWk5sL1pxTXpwRUZHVkRXeVhuRGgzamNIWGZD?= =?utf-8?B?ZXZRMHRqRVV1QnNDN0FWSW1OY240U2pETDRIWDdwbmJwdkRiaStWV3FXY1N2?= =?utf-8?B?R3dzRDQ3angraEdqNkRkSElIdU95MWMwT09aZHZWQTVoYjNhNitqaUJvZzVo?= =?utf-8?B?YUlDVHNPVmtvdVpYSk95TkZoQks5VENKL0hZckpOT0xsWTdJN3UxcVlSTXho?= =?utf-8?B?RllCL0UxdmdEemxER0NGaExPV0VSMVk0YW1zR1pIRE1ZM29pZzVJcDJ5WXVH?= =?utf-8?B?aGVVRXQ4NVN6d2hoakdOeTVIbHhXTVJKNjl5RjFlbWYrR1RSeFlqVEp1V3o0?= =?utf-8?B?Slg4eEFDWm9MdkpYd1FKbFk5Wkt2eXg5b0gyMG5mOGMxZG5XTzFRbThqVVg1?= =?utf-8?B?d2NUNDBqWlhIZlpDOVdsNE91ZjlVblphQUprbVhwVHVFMlptWFZuM1pzUGVs?= =?utf-8?B?RTREbk5BejNVRDQydk9oN1QzMTlVT3o1K0FXWUwrS1IxQUM3ZityOHFjalFY?= =?utf-8?B?SVJiTXhhSzgvaGJ6MW11V092dXRIZ0RqdWFucldOdUdVbWh2d0lmeUNoMUpp?= =?utf-8?B?VFk0R0hxY1ZLMmxHOG8yZTZBd3BIYnhreXNjT21KK1docXFHNjRNSmFwdVgz?= =?utf-8?B?Q1VYNWVsZGp5TjlTVFhPcDNsRUdkL0VmR0Uvb1hteGtxZm50QnVEOERMYyt3?= =?utf-8?B?Z1E9PQ==?= X-Forefront-Antispam-Report: CIP:255.255.255.255;CTRY:;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:CH2PR12MB3990.namprd12.prod.outlook.com;PTR:;CAT:NONE;SFS:(13230040)(1800799024)(7416014)(376014)(10070799003)(366016)(921020);DIR:OUT;SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 2 X-MS-Exchange-AntiSpam-MessageData-0: =?utf-8?B?SXNvMHVrVjhSVnczc2RIYUptRXQ2UHoxUlh1Q2pYTk9TSUtDaGNZZjMwOFZx?= =?utf-8?B?WFVFZG1VUk5xcHlGdWNsOWErR3RHWG1yY05tQTlVVWhNMUNqaDBRSDJYVUdt?= =?utf-8?B?eWxWbEdPMUw5VHVVQUl1THR4ZUtXQW95dFdZcm5VVkNRL29NOHZidW5qS3pL?= =?utf-8?B?NXNzMWluQ2p5ajluQzVHeFN4dHYzYjFjUVRQVGgxZWc0YTRXczdyQ3FQbHRR?= =?utf-8?B?R1dQbFhoKzgrTnkxZUpNNjVzc3Q0UjgxdnpxWGhJOXJreGEvNFYzMkhDVCtY?= =?utf-8?B?aDRSWWRrZlJTWk12ekhKZisxWDIxREZHSGZtNmRacFRSWThFUlZUT2tVdHFs?= =?utf-8?B?N0hVMzliT1hTdDVwMllvc0dRdHVUUlR6Ry9acXh4MHdpazREa2V5V0F6RzVI?= =?utf-8?B?TnlkNE9HVnRIK0JHRWZLR0s1c3poc2ZwdDkzT01QcitMU3VEWWRRd3ZhUE0x?= =?utf-8?B?YXVqcHQ3dzkxcFkvbXJJYTBEZUM2WUtLekp2aWh3cXhwelcxbzkrcXNEcnpm?= =?utf-8?B?eU9GZjYrQU5tL3R4VndzZWJKTlhNSlFlWUFOOXV6akdzVVUrdWMzNWVVV3B2?= =?utf-8?B?c0pUWUNsQU9CQVMvTEM4c2ZCcS9pV3MyZDJqbFFrREFLZHlKbEpEQTdwOUY4?= =?utf-8?B?OW9ndDRSR0RPb2pHSS9STEJLMWFNVlhTMHVaSnN6M0MxUVlQYWxhQkxuV1Fn?= =?utf-8?B?aEtvVDhuOHRPTVUrYXBndGF1WW5ZRzlLOGEwcG5JVGIraWxhNVhmVVpRMDNz?= =?utf-8?B?VkNxV2gzbU1nTWFTQnBwVmVtRkNwaGRuSysxSnc1V2tWQXFkb0EwZW1WRHh3?= =?utf-8?B?S1oxTUdaOFJVbFF5YmREbWZBSnBzcGI3cFRyNjBGWlBTdHdsdktPWTFUTWw2?= =?utf-8?B?amtCUU1sOTI2Z2trQk9wM1lKY21sZjFjaWkzUUpndHZrS0x5eXNxbnIxRjNX?= =?utf-8?B?VkF2TGNENGhBWWIyclE1ZWtSd2p4MHVvaHZvYkRUeUJuWmRobzZPY2pKRTdj?= =?utf-8?B?Z2c0M1NxNE5nUkNlYWJJczRVRzIyaUhkNnZpdHY5SGEyRG90OFFEc1ZJc3hU?= =?utf-8?B?K25ZTHV1YWZmR1dVWXZSdnk2bVJzb2dJM1NBcTYyWm5jdkphVVlvSnlPY0px?= =?utf-8?B?VkZkdzY3NGVqUFlUSUoybXBxc0tsYjVvazRYbllnS2p1bGJYaXNLbnhkRXh3?= =?utf-8?B?anZ3WGdlVnBua1I3UGtsQmlVbTZUN1JJL3NDcnlqUWhRM3d1aVRLc3lVb3Zx?= =?utf-8?B?Y2FSRDRZcmN0eTlsRVl4VW9VSk1WZWVOdGlzMGl0OU5zNDN6UXZFcm1mWFJ5?= =?utf-8?B?WFpldW4vdlZmbEdETlRQSnJIeWluMXFMcTJPSlA5RU9nYXV4YUdqcURLWFhQ?= =?utf-8?B?eEo5emdnK2VoNUhEWTRzakNlYlVkTlBRQ0Uwam1KTC9ydTB0ZUQvYXkvYm5x?= =?utf-8?B?eEhlNlpVd3VscmZhbUhsRjFaMGNWQjBGS1FlU0lJMEg5UmpaV1U0WnplYXd0?= =?utf-8?B?THRLZUs3STBCM1BFU2ZrR2tTT3ZCVGpPTmdFcTI2SVg0MDdaREJLOTdCdzdM?= =?utf-8?B?ZTBsTW1LSHZsWlVFSVQvVUh3QU5wcDR0T2xzOVVHeTVEdUprTTRNNVhBcHVZ?= =?utf-8?B?M0tGSWVqcmlOUy9Ob2lDcUdVdWNWczk3RjdYeDBKRnVhczlCeEZvcDY1VnVi?= =?utf-8?B?T0dSZGxuR091S0tTbjFhS3U1UXFPTE8zWUZpbGZrcHU3WWRQMkJCR2hURmZ6?= =?utf-8?B?ekZ0dEY5TUI0ekFGcllTVWM3dmZqZlFyUDAxKy9Na3hCU2lMd3ZpRVQ1ZDJ3?= =?utf-8?B?SC8yVGo2aTNLdm5ib0grRC8xQWJhK0ZPcitJZFYzRkZseHNsUEU2TDNYY0dW?= =?utf-8?B?eFlLQS8ycnJZSVFWQXV5QVhnblBoancwek41T3A4elM2RDc2Yjk1VlljQlQ5?= =?utf-8?B?V0pKcFkyVFIwdmpnczhsYlkxTkhKcXUrSWtDV0Z0S0Exc0lxczd1d0V0UDhj?= =?utf-8?B?SjRWRG10ZG55UXF3Wm1vT3JQUTVZWjdHNDl0K1RRSjhZQ2ZWc1cyZUtvb1d3?= =?utf-8?B?Y0hnWS8wOHMzUWFJUzA1anZWdmliQnFsRkhjUGxSUDlIbk5FMVBUckU3dFY0?= =?utf-8?B?eWZlZ1gzcFA3STFEOTY1UEFrRGhzZEU5MEVjWHkxKzR3OHovQUdqTUFOZDYx?= =?utf-8?B?aVoxc1BZU2JReTBmNzJ2OEh3U1JNWGhnSm1xSDJ3Wk5oSWVXcGk3YTRDb3Jq?= =?utf-8?B?NVROckpyZ1JmYVlWMHBQL0JHSUpScTl4R01iSjBDU1F6dW9yTm0rdEJjUGQ0?= =?utf-8?B?VWNlNVY3RTZXRG1BS3lFNVd6SnBoY2I2VEZxN3dpMlZjWUpLbHZ2dXpsSlRR?= =?utf-8?Q?1iuJGJ8uTUlOzCx/pMVz2esOTiALP1QLa8/2cTyZG789s?= X-MS-Exchange-AntiSpam-MessageData-1: /qppJsdIcwFe/A== X-OriginatorOrg: Nvidia.com X-MS-Exchange-CrossTenant-Network-Message-Id: 7cfa3b06-d514-4066-adfa-08de6d322283 X-MS-Exchange-CrossTenant-AuthSource: CH2PR12MB3990.namprd12.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 16 Feb 2026 08:05:22.9363 (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: QcsOmdhivrDeyenJBUs9jLPyfETt9Rc7rb9BdI8pK3FdZpsejNpKDj9P1qzedFkhVMT9742btAf5LcWFQCbDEQ== X-MS-Exchange-Transport-CrossTenantHeadersStamped: SJ0PR12MB6832 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. 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 8e4c08924d96..b09b93cd0c5c 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 Fri Apr 3 01:40:58 2026 Received: from SA9PR02CU001.outbound.protection.outlook.com (mail-southcentralusazon11013055.outbound.protection.outlook.com [40.93.196.55]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 919172F4A05; Mon, 16 Feb 2026 08:05:30 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=40.93.196.55 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1771229132; cv=fail; b=tPfbHl1GbDZayTdswRzYsNPE5PccRQNtwI0v9B3/i6u70gWk42bB5tDFXNByWfpgEx4wX6g5ursgzTmalA3o0N0jyXTcF0lrm2Tu10j/n7IGTRfOouJb9OzJc4nMMKuJ2QOCA4qFmiPfFBpRCrhtw49yLJbtdYapmF9jkwvjmBI= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1771229132; c=relaxed/simple; bh=obXefh6S8juI2ujNf4KX3cCM1Nm7Y/39+LAkZm9KBKg=; h=From:Date:Subject:Content-Type:Message-Id:References:In-Reply-To: To:Cc:MIME-Version; b=f70P3yPpeb40iHMD05NxYGuOoNo/aHLWOR8z821kfsssCpT2/hkTK4mQ0+taICynYSLQ7SRdm3sfusE1Op/Ncg9OTj+lGd0gRNB9pnzDmNdZbiIcRJhPXwfW89lJXhE+bSu3Ax3VqE9ANNLQcS+CfwykxRez4i4LA4Vk6mssyHU= 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=fDmNzCr7; arc=fail smtp.client-ip=40.93.196.55 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=nvidia.com Authentication-Results: smtp.subspace.kernel.org; spf=fail smtp.mailfrom=nvidia.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=Nvidia.com header.i=@Nvidia.com header.b="fDmNzCr7" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=bB/45waVMXB+yl2oUhmlIHuyfCNCnbGFGZLn1HacVtQq7ODEfV5YwnJL1wqqOUGoFiZyvP5CvLOTskTtoadcziOFueF0Pb9ENKeYAevoB088UeCaVpcEtevtQHgzImRLEV30M2uzDLtiiuBR1vpx2+IC5xJkqy5CwSIzJpAozgxH5YcwuiEZYygqDQyqcbWHP7Oe/gKNEKgwLtZW6+FAE8eSj1dyTDtElF922gpC8zy2Uc7hAcXZDD61kCt75ZWWEGTLgI+m2wENiiwFGQfkaXBtKiXK0vFQDkP8ZupHVySYItjmk5mKONWvwM0y5L8yctDbt4XUMCRqQl5sEhtPSw== 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=L5BikZhNTr9M9wJaW/ROMdXaTgtMIyNNRLZkGsl9z7Y=; b=pXEh+XRP5n41Oi5Wxjfym89rhhmBYVXsm9nHyfbQqjKBmleeRsk/CGOafSSx6RwvTnspfPHk/gZ+iSx3hy5wu6APUSOwac7gZFwPZyIA2lWv4OmfLMLukVHnQ3CiS1AGqXCMBX2D0wml+X0xhHJd4Q8Dbp0rPEb3vruORLGNmQuGPy6lUWKUqtFYdIjg/M1x+mYL6nmPsX8AtOtVRHdWKjQ4jh+bxBVkr/XlaLHJxtYPi761OgK9KwFYyDI1v/mGTGapPmNNvAWF1BlTFEPj2dKWN/KtheoIgG6otPPMyF5exR9EOMF9R0uW+g1LAeJ+/GlXeSztLcd2tExywOPNzA== 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=L5BikZhNTr9M9wJaW/ROMdXaTgtMIyNNRLZkGsl9z7Y=; b=fDmNzCr7kizyuF7AeK4r5SDRniuKVyOitt5eeIB9IrDnhnolY1ebjs7NoO/4F5Idrv3nWmIsnjtlP1M9rk0wPKwD/IULs1du/B7qtCQnBG444o69uf42OGH8DFD8MRD9g2bO373KB02/JJ2vZFewXt+lrgduKLnCVik0P/jYzS/PQkTvlBOevIbmtmr+8hda+Uzv/TJee/YEGtw5kdxtUuG0F/O2YGtG3hwkomlyxvXh4ran9ni+EpeqsUz6XdUHygvmmDLK3nK3x1cw5WTPO8dL2BFZi8Avjgxvp8cxXZcMEgVLzieh3NwXhn6KAoXHiv3YsueGMZ4WMRz6jGnxZg== 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 SJ0PR12MB6832.namprd12.prod.outlook.com (2603:10b6:a03:47e::12) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.9611.10; Mon, 16 Feb 2026 08:05: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%3]) with mapi id 15.20.9611.013; Mon, 16 Feb 2026 08:05:26 +0000 From: Alexandre Courbot Date: Mon, 16 Feb 2026 17:04:41 +0900 Subject: [PATCH v6 5/9] rust: io: add IoRef and IoWrite types Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260216-register-v6-5-eec9a4de9e9e@nvidia.com> References: <20260216-register-v6-0-eec9a4de9e9e@nvidia.com> In-Reply-To: <20260216-register-v6-0-eec9a4de9e9e@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: TYCP286CA0040.JPNP286.PROD.OUTLOOK.COM (2603:1096:400:29d::15) 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_|SJ0PR12MB6832:EE_ X-MS-Office365-Filtering-Correlation-Id: 52edd071-a3c4-40b6-4986-08de6d3224c0 X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|1800799024|7416014|376014|10070799003|366016|921020; X-Microsoft-Antispam-Message-Info: =?utf-8?B?bDZiN2F1bUVST3Jyd3JnQnNDWFZGUGV3NHA4OUMva3QxQXFQYWtVdkNpQU1N?= =?utf-8?B?aFlGMGRTT1ZpK3Q1ZmdJa0dTbG5hQUJ6WUFIRlE1TEt6T2hKclpwZ3AzbUhB?= =?utf-8?B?YnQ0emdNa2tYblNGTy9peVBFcXRma2IwNndiOEplMVJRblN4Ylg1ZzJ5RHJT?= =?utf-8?B?Vkx3VysxcDdkR2g3SVBRTWdpWEJxQnNWYWZ2SmFCaXdiZkRLaWVlR2hPbmhy?= =?utf-8?B?Y1d1eVloSHRYSEczc0FyZ29UV29FTVBFNFc5Q1lzblNNRDNrVlZ1SVRyc0pv?= =?utf-8?B?Y0Y5NmkwSmkyNHhMRUtIM1JsZkZsMzFSKzVoV0t4OUhYTEIrNXR5Nm96R2dz?= =?utf-8?B?Ly82MkFjRk9RZXlmNG9mTTlTRDZBVk1NT291UFJFUVlVV1hFaGdGNFJJd0M4?= =?utf-8?B?dkI4aHNJZmdGOFE5TVhSdjVCZzVNZ0ZEV2JLUXI1alk0SVJ5SmsrRDJvSnEr?= =?utf-8?B?ZWpHUDRDcCswb0IzQ2FwOXQ2ZHprTUdHS0pDMDBhQk9OeEV2Nmx3S2kwK1Nv?= =?utf-8?B?dldobjhOb1M5OWhnRmpzNmhVeFVFTml5TEVrTVZLWXhiZy9wK1R4YW9wRXhw?= =?utf-8?B?U2preWhlSzZzVitZY0tXK2x5TVhnK0N1VHBZNGI1Z0hudFN0U2I4MVJ2Ykw1?= =?utf-8?B?bmtIdXZWSmlUK1cxcHJiYWMrUnpZV1NxK0UrR0dqS242RGk0c0FTd01XUTd3?= =?utf-8?B?alFmZlBDekMvMTF2VXhhSnJxSkVQNjR2UjdEc0NJMzhMWXBubm5qY1JkWW5j?= =?utf-8?B?THpod3J3b0FVR1FGUWFINVg2WlhRS2VyRjBmaVc3bnl2M3dTMFZMcGxHM29t?= =?utf-8?B?RjJsaXNuTW1meTFXbzJoQjY1NUYwUkNxZlE4OTZqRTcvYkg3MjUzL0MvUlVa?= =?utf-8?B?OW1zK1RIN2VWcWFvMm55cHBKZVlRZWpGUlZwMnJjd21uTTdvSUo3SDlxTUht?= =?utf-8?B?Wiszb1VMOUFVL29EMjlyeW93amM5aTVWMEpobCttS2lrelVXQ0gvVHNFWHZY?= =?utf-8?B?ZEVic0xFMUd2VXFGL0JmaUNUSkxXSU8rMlJ4TURXTGwzeXR0cXYrMk1kWVMw?= =?utf-8?B?Zk9jSWs2Zk1OWGI4UHVabWFBOU1WU1NoaFBUYTFncmFkcTdhaUZnbXg2UHNC?= =?utf-8?B?cXdqSGtDdGxpVWt5QVVpODUreWxKSmtIUlVKRjY3bitielppWTFzaloxWjh2?= =?utf-8?B?RlNveE5jY3AvMVdQNmdnMk9UVU9scVcrby8wNmlXOTNmRHVmWjhmSDNhbFFR?= =?utf-8?B?MUhWQktzb09aOFl2Z2RCY0xicHA2c2ZTZEdNUzFKUW5lMEhLSUIxZDliSW90?= =?utf-8?B?ekpwWGpqWDdvcm16YTdocW9Ja0Y2a3NGZWRKZ2s1NHgxaHBUcnNBd1JwUllX?= =?utf-8?B?QlZGZmp5YVdndXRteFRYdHJmZUNXRGRmOE1WbkNyenVDc1NBRTZYSkwveWRi?= =?utf-8?B?cEdVZW9GUmpZanNSVG8rUnpLVTExcnI5Nm1URHliWXR1VFNSZUVRYzBvREJu?= =?utf-8?B?WVZrZU0rcGRTNTl4TlBjWnh0eTl4RGdDeVVPVjRDcXlWb3lLdEZWWlovVG1j?= =?utf-8?B?eDI4R2RXOEV6UXhiekkvVEJzUkpHenZ6RlR6T1U0SFZQRkJJL0dlOVpDb214?= =?utf-8?B?K0F5dEc3bUhLNmxOWEpxb2FrWXBqYmRlTko0RUtEa1d4Q3p0NURRc3g5NEpz?= =?utf-8?B?VDZ3VnRES2MrU2RmMGJGNGlLU0FoWk9QSHZmNEFWL3F1WHo1TityUEtMN2g1?= =?utf-8?B?MXpZTWdiNFJ1c0ZKRitvYjBrRzc2TFg3VTJrSnhCVEJ6VUJTZncvSkYwdmgr?= =?utf-8?B?WVFVMHk5blU2ZW1DclVSK0F4WWJxMzRIUU13VDdXa001RG0vYXNBTlE1NVdS?= =?utf-8?B?OE1SWnFVbGJZSUhlMExYckQvd200bEg5eml5Z0Yyd01KUStRb3JjU0hxeURL?= =?utf-8?B?RDJldW1jYVNVMFBCQm53cmVvczJ2SXBOY0FWd0kxWlZOc25xUThnQit5Y2dr?= =?utf-8?B?RTUrRjErbUVwamVZUzNsVS9rL0RsZWJXN2lqd2VlRjRYc1NpUzlFYmozcGl2?= =?utf-8?B?cSt0cThsL0g1ZXBVOTAvQXB0NDZHdTRIVW1GZXNSMWNCdC9rU0FEY0V6SlBj?= =?utf-8?B?dFBBUzVMWndDS082QXpnVEJMZ3I4M3hKNlRsRi9kNVM4QzJXcGpib0RjUjJp?= =?utf-8?B?UEE9PQ==?= X-Forefront-Antispam-Report: CIP:255.255.255.255;CTRY:;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:CH2PR12MB3990.namprd12.prod.outlook.com;PTR:;CAT:NONE;SFS:(13230040)(1800799024)(7416014)(376014)(10070799003)(366016)(921020);DIR:OUT;SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 2 X-MS-Exchange-AntiSpam-MessageData-0: =?utf-8?B?a0JkdzcxYWduMWVYdDVNbVRtd1RBOVBKYWxDRzhjdWZRbDkzVHlmSURuSGhB?= =?utf-8?B?b3lKVER4M0Y0cjJiNGhESUV3TTRPekxlYjhsS1lKZVU5b2NBSHRVeFVjUzZq?= =?utf-8?B?QWFWdnQ1M3k4Ky9iRjdOZ25RUlVyZDh5Qkh2SjZXcUxCdWlsL09lSW5VMndT?= =?utf-8?B?TGxzK24vQUs4Q2NhMWQyVjNKdHhkVlQzdENrekpXN1FOaGVSUFBHWEovbjJC?= =?utf-8?B?Ni80VGlVK3plNktCYW1qTlg5T09LdmhvNVhQdk1Ta1VoRVhYOFZ4V1FCOHVF?= =?utf-8?B?UzdVVmhRUnZQazhQZnFZbGVJOHdoalZ3eFVVTXVETXFkOVJjMHlrcUhKTkdk?= =?utf-8?B?UHJWZWVYT21VSHpsMzFwL2ZKa2NuZGpNbmFvSzJDc0Z1RXF6SGZxaVNwcDNz?= =?utf-8?B?SmFGNzg0MFZ3VVNobDdwUlR2YlIrc3ZIck1BdEk4MUc4RkpPREVpbjhpOWhq?= =?utf-8?B?ZGZvbERWMHNybzBKK0oyK3poRllFY2J4ZTM1Mmh3M2NQYi9ubEVOUHd4RCtJ?= =?utf-8?B?Vjc3K0lGNlY1WnNQLzZDRS9TSGU3NzFpQkhCWmxtUW8ydHJYM1RFR25sY3BY?= =?utf-8?B?NnUvb3pqanNxeVB1T1E0blFYRjlXUTh2bzNIT2doQVVZZlU4MHRobTUwU2xK?= =?utf-8?B?bGtvTW5IYnVoUWZBWkpKSTE2aWdyM1Q5djhsM0ZPOUtZM2hYdnFIenlyTy9y?= =?utf-8?B?SWxuRDdZckcyZTY0b1B1KzliOFlSTnhJSCtqSTZzQzVGTzFnc1JXWkZzWW1S?= =?utf-8?B?UlJjQ1FTeHlFdE1ianRVcStURHI1dlpOeC9rc1VjY3JmMkxaQnQ5KzFqT1dG?= =?utf-8?B?VFZ6OGYzUFFIQzYwY3hwa2JkWHJpWlVpSHZUK0VxVkRpc2RYcVFRMHJOYlBx?= =?utf-8?B?cXZhWWJRMDFCZEhZYkhtaURxN05nLzNwME81d3VwbDBpUHBpNGdHOXJ3ZlZz?= =?utf-8?B?ODgzUng5RFM2bmd2ODRsbkxvTmhzVnEwMjhNYy9KZCsyNURqc0lqN2Zlbm5V?= =?utf-8?B?WmNaMFdKWTNJcjNjN3c4RHJHWjJITjB3NGZiVVN3ZTVGSkg4M2Y0UGxrTDBF?= =?utf-8?B?cEZPOEtzNWhrcHNkTVdKS2lHZ3FMS29zMGs5Tk45T1huZmR1QzBiUGpOR21o?= =?utf-8?B?K2hVWklKSFlJczEwK1VvajhMeEVHNTRNQ3lwRm50UW1ZTXIvVzhVbStoNnpO?= =?utf-8?B?S3RRbHdQdUFBcjFYZUdZMEJzZmh6Znh1YmE2ZEtjUEVzM0ZBaVg2THloY0Q2?= =?utf-8?B?VHJBUVhIRXRJZGVVZm0xaG9JN3hyd1lZdjNLeENPWFlEamd2dDNBakZLY015?= =?utf-8?B?MFFOK2pObjlud1dRTEtxQzlwM2d5UmIrYnEvdXB2QWVjV1RKT3BoSFI0djZI?= =?utf-8?B?YVZlcTdaU0h1ZTAwMHBKWWVWOW0xSlBZSUU5UnFpWTVaR25tNHRNY2JOZ1o1?= =?utf-8?B?ekJDVi9wbXFJWnZjQXBzQWt4dC80V253SVNCTmloT2FBY0hqcituU0ZUOXZF?= =?utf-8?B?T0ViRm13b3dRdzVwaXQxYjFRUDZBSzk1RHhtd1FtNUF3SmI0VGdBR3JjZnRt?= =?utf-8?B?TVUwZnAyd2s4S3AyMXBCQWNIa292TjlYS0E1RGdDVHBPK0VZYm1URGlHSGZu?= =?utf-8?B?dE14WHZhcmRBZGZ1UUxybFBoWVRMcnc3aCt5UXNTcUVhd3hrdFVZdzhWRnhP?= =?utf-8?B?b2dNbHdoYlIwR29BWkFpcXhCQkpRT0VIUU5BR29CdVQzc3dJdnVzOVVxWERr?= =?utf-8?B?ZGJTMnE4VHpMQlBTZmhldmZIMFpOYS9JalloNm4yTFU3akRacVh5cm01SGkv?= =?utf-8?B?allZVHJvcGxOd1VMekZxalBJRlZnK1BsZkE4aVY4aGpsVXg2eGdGczdreEJz?= =?utf-8?B?NVJCMituaHpqOURYU3daVGlwYVVRNWd2VWk4M2NyeGI4T0hkZmk0TmVSTVdK?= =?utf-8?B?aXdwWTZoVGIyKzFNaGNsbzQ3WlFOZzZ2V0dmMUUxWFB1TGJyUnVWNEd4V2Fw?= =?utf-8?B?Yy9ydEZ2K0tNb0UxZVRsMFVZK245UVhoWldicTdvb3oxWTM5d05YWkUvYzd6?= =?utf-8?B?MktXY1dvVGRkeU94VEVQVVRBZXpmaHJHTW00aFUwRHhhY29tZXp4TGRxMS80?= =?utf-8?B?SU12TVF5UnY5aWRuMU5HQ3cvMGdjclZkdFdlOTZYaDNyZlM4N3lLUVhpYzgx?= =?utf-8?B?T2hMaTFJb1FDV1ErQmNmNGc1SThJNW9XejVwdVRrWVg1RWFDcUxBUENLVFcw?= =?utf-8?B?TENZSnpySThkWVBvMVMxalJKalptM05WUnlMeHp6aGVVWGRBUFh5bHk1azJO?= =?utf-8?B?ZzY5aXN2WS9IVUlGYXlyaXprZ2xFSXZPaVBnQkplZE9qajJ4YTVrNUhPR0p1?= =?utf-8?Q?R8kTVljP/lJKMiO4p/z+1igxzU5X0kMOp/Vc0ma3i0KGZ?= X-MS-Exchange-AntiSpam-MessageData-1: lXVacPY0RSZHPw== X-OriginatorOrg: Nvidia.com X-MS-Exchange-CrossTenant-Network-Message-Id: 52edd071-a3c4-40b6-4986-08de6d3224c0 X-MS-Exchange-CrossTenant-AuthSource: CH2PR12MB3990.namprd12.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 16 Feb 2026 08:05:26.7503 (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: 5CoSgHOSS39eEKX9HN+oMyKotrdk1BH/vphCRbVlzpi+3+11ybkg5UfBvxgDYny+C5GVmX/6y21YkL7k6NYjdg== X-MS-Exchange-Transport-CrossTenantHeadersStamped: SJ0PR12MB6832 I/O accesses are defined by the following properties: - For reads, a start address, a width, and a type to interpret the read value as, - For writes, the same as above, and a value to write. Introduce the `IoRef` trait, which allows implementing types to specify the address a type expects to be accessed at, as well as the width of the access, and the user-facing type used to perform the access. This allows read operations to be made generic with the `read` method over an `IoRef` argument. Write operations need a value to write on top of the `IoRef`: fulfill that purpose with the `IoWrite`, which is the combination of an `IoRef` and a value of the type it expects. This allows write operations to be made generic with the `write` method over a single `IoWrite` argument. The main purpose of these new entities is to allow register types to be written using these generic `read` and `write` methods of `Io`. Co-developed-by: Gary Guo Signed-off-by: Gary Guo Signed-off-by: Alexandre Courbot --- rust/kernel/io.rs | 243 ++++++++++++++++++++++++++++++++++++++++++++++++++= ++++ 1 file changed, 243 insertions(+) diff --git a/rust/kernel/io.rs b/rust/kernel/io.rs index b150743ffa4f..6da8593f7858 100644 --- a/rust/kernel/io.rs +++ b/rust/kernel/io.rs @@ -173,6 +173,160 @@ pub trait IoCapable { unsafe fn io_write(&self, value: T, address: usize); } =20 +/// Reference to an I/O location, describing the offset, width, and return= type of an access. +/// +/// This trait is the key abstraction allowing [`Io::read`], [`Io::write`]= , and [`Io::update`] +/// to work uniformly with both raw `usize` offsets (for primitive types l= ike `u32`) and typed +/// references. +/// +/// An `IoRef` carries three pieces of information: +/// +/// - The offset to access (returned by [`IoRef::offset`]), +/// - The width of the access (determined by [`IoRef::IoType`]), +/// - The type `T` in which data is returned or provided. +/// +/// `T` and `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`), wi= th `From`/`Into` +/// conversions between them. +/// +/// An `IoRef` can be passed directly to [`Io::read`] or [`Io::try_read`] = to obtain a value, or +/// turned into an [`IoWrite`] via [`IoRef::set`] to be passed to [`Io::wr= ite`] or +/// [`Io::try_write`]. +pub trait IoRef: Copy +where + T: From + Into, +{ + /// Size (`u8`, `u16`, etc) of the I/O performed on this reference. + type IoType; + + /// Returns the offset of this reference. + fn offset(self) -> usize; + + /// Turns this reference into an [`IoWrite`] with the initial `value`. + fn set(self, value: T) -> IoWrite { + IoWrite { + value, + reference: self, + } + } + + /// Turns this reference into an [`IoWrite`] with the initial value `0= `. + fn zeroed(self) -> IoWrite + where + T: Zeroable, + { + self.set(pin_init::zeroed()) + } + + /// Turns this reference into an [`IoWrite`] with the initial [`Defaul= t`] value of `T`. + fn default(self) -> IoWrite + where + T: Default, + { + self.set(Default::default()) + } + + /// Turns this reference into an [`IoWrite`] initialized from `0` and = transformed by `f`. + /// + /// This is a shortcut for `self.zeroed().update(f)`. + fn init(self, f: F) -> IoWrite + where + T: Zeroable, + F: FnOnce(T) -> T, + { + self.zeroed().update(f) + } + + /// Turns this reference into an [`IoWrite`] initialized from `0` and = transformed by `f`. + /// + /// `f` is expected to return a [`Result`]. + /// + /// This is a shortcut for `self.zeroed().try_update(f)`. + fn try_init(self, f: F) -> Result, E> + where + T: Zeroable, + F: FnOnce(T) -> Result, + { + self.zeroed().try_update(f) + } + + /// Turns this reference into an [`IoWrite`] initialized from [`Defaul= t`] and transformed + /// by `f`. + /// + /// This is a shortcut for `self.default().update(f)`. + fn init_default(self, f: F) -> IoWrite + where + T: Default, + F: FnOnce(T) -> T, + { + self.default().update(f) + } + + /// Turns this reference into an [`IoWrite`] initialized from [`Defaul= t`] and transformed by + /// `f`. + /// + /// `f` is expected to return a [`Result`]. + /// + /// This is a shortcut for `self.default().try_update(f)`. + fn try_init_default(self, f: F) -> Result, E> + where + T: Default, + F: FnOnce(T) -> Result, + { + self.default().try_update(f) + } +} + +/// A pending I/O write operation, bundling a value with the [`IoRef`] it = should be written to. +/// +/// Created by [`IoRef::set`], [`IoRef::zeroed`], [`IoRef::default`], [`Io= Ref::init`], or +/// [`IoRef::init_default`], and consumed by [`Io::write`] or [`Io::try_wr= ite`] to perform the +/// actual write. +/// +/// The value can be modified before writing using [`IoWrite::update`] or = [`IoWrite::try_update`], +/// enabling a builder pattern: +/// +/// ```ignore +/// io.write(REGISTER.init(|v| v.with_field(x))); +/// ``` +pub struct IoWrite +where + R: IoRef, + T: From + Into, +{ + value: T, + reference: R, +} + +impl IoWrite +where + R: IoRef, + T: From + Into, +{ + /// Transforms the value to be written by applying `f`, returning the = modified [`IoWrite`]. + #[inline(always)] + pub fn update(mut self, f: F) -> Self + where + F: FnOnce(T) -> T, + { + self.value =3D f(self.value); + + self + } + + /// Transforms the value to be written by applying `f`, returning the = modified [`IoWrite`] on + /// success. + #[inline(always)] + pub fn try_update(mut self, f: F) -> Result + where + F: FnOnce(T) -> Result, + { + self.value =3D f(self.value)?; + + Ok(self) + } +} + /// Types implementing this trait (e.g. MMIO BARs or PCI config regions) /// can perform I/O operations on regions of memory. /// @@ -406,6 +560,95 @@ 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, r: R) -> Result + where + T: From + Into, + R: IoRef, + Self: IoCapable, + { + let address =3D self.io_addr::(r.offset())?; + + // SAFETY: `address` has been validated by `io_addr`. + Ok(T::from(unsafe { self.io_read(address) })) + } + + /// Generic fallible write with runtime bounds check. + #[inline(always)] + fn try_write(&self, access: IoWrite) -> Result + where + T: From + Into, + R: IoRef, + Self: IoCapable, + { + let address =3D self.io_addr::(access.reference.offset(= ))?; + + // SAFETY: `address` has been validated by `io_addr`. + unsafe { self.io_write(access.value.into(), 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, r: R, f: F) -> Result + where + T: From + Into, + R: IoRef, + Self: IoCapable, + F: FnOnce(T) -> T, + { + let v =3D self.try_read(r)?; + self.try_write(r.set(f(v))) + } + + /// Generic infallible read with compile-time bounds check. + #[inline(always)] + fn read(&self, r: R) -> T + where + T: From + Into, + R: IoRef, + Self: IoKnownSize + IoCapable, + { + let address =3D self.io_addr_assert::(r.offset()); + + // SAFETY: `address` has been validated by `io_addr_assert`. + T::from(unsafe { self.io_read(address) }) + } + + /// Generic infallible write with compile-time bounds check. + #[inline(always)] + fn write(&self, access: IoWrite) + where + R: IoRef, + T: From + Into, + Self: IoKnownSize + IoCapable, + { + let address =3D self.io_addr_assert::(access.reference.= offset()); + + // SAFETY: `address` has been validated by `io_addr_assert`. + unsafe { self.io_write(access.value.into(), 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, r: R, f: F) + where + T: From + Into, + R: IoRef, + Self: IoKnownSize + IoCapable + Sized, + F: FnOnce(T) -> T, + { + let v =3D self.read(r); + self.write(r.set(f(v))); + } } =20 /// Trait for types with a known size at compile time. --=20 2.53.0 From nobody Fri Apr 3 01:40:58 2026 Received: from SA9PR02CU001.outbound.protection.outlook.com (mail-southcentralusazon11013032.outbound.protection.outlook.com [40.93.196.32]) (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 655452F261C; Mon, 16 Feb 2026 08:05:33 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=40.93.196.32 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1771229134; cv=fail; b=WgdkTufkIccQ3a+jr1wiid/H0xYtTP2GFDdqN4c1Hu/iOUFz3Tw+fZSXhjUKBDlIO5jo3B/U6PzPnmzZwB2ZCJYGB7VPinMquHjbKbBPEfo4AdZFuZ2Tz/i64vCWGkOsnWwlQLs5DhtzKYVI7MWiYWG3WKQNPIITqv3ZDPXfwDg= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1771229134; c=relaxed/simple; bh=lLWas88/A/iu9acYrmzLJyj0BwnBaDQirTDZ1J5zWkY=; h=From:Date:Subject:Content-Type:Message-Id:References:In-Reply-To: To:Cc:MIME-Version; b=tzGFQvu2XTJdrI0iufRuGh9Xfhz3ZQPaNCgKq0dADsvzUhqp4peGvvIdN3wbMZFtWFX2oy6KkX+3xOjag3LN4uC/gKdNkEMWY01/BbbxLil+MsJplnHy6GapgEtW78KcVa2lu/hwIaixa2WXWizlvu9uzs3p0rCN7Z0v/QJcsNo= 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=YYadRSzX; arc=fail smtp.client-ip=40.93.196.32 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="YYadRSzX" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=ROdOUQxjIo4Cw+ZKp0KfwMIE+gkEOvd2d8QG8dE9WM7v6F6XeJIiGG9lcIj9q1F7lCZLLYe6YvwvtxCUEMnzIhTkGGXkZ4OGrsD6x082wNYh9CZyz9x3BWn+Q5WrwHaMMlPFj5dWQXMsC7CeozkZ9T8I46XDAtS+KoEUcuNufPaVwomnA5q1lqV129/mCPSrSOlFHf2O/v9mhDyEjHQHevCTKOw/GuQwvaWl3x9FXXG1TC/nLklRColU/DY+03rqq5zSKfmVTOx0GUwgknyGtiq+QpeRZV/Vful7oU9aH0dxSfFaMbVwu8lDWPgdkcel5mmGS1kzjgv9Ix7p+thtVA== 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=vqMHwel5aejcZ/h7F+fWey3srDVEK77hUijpg5WX8XE=; b=xodYS8zZ6xgghw0CLWV2eXSZGSjV1zEbjm2lnBf4P/DbpMYXy3hpDcMm6hqcwy0IxtF+H1r7m8poJFD6u7Q4XPK8tcGqxX/iSZj0j0tWxNk1RBV2EajAyj+WnT8VFlryM51TxsZIdz5fbHOjsyar04u1aKfhYfmmMzSWni4457B3hHW9jjtyGkTnG02UkeA5fpCFu2ILeKk1QzLgipvu8kC+VEq0jpEqJz56AOluNska4t7n2EZqesds61LUGIzGpQQshlykWZ2tQ8q9vXaIKrj9O3pK+IFEsaJ9U2b8pn7KDaj54fot92rVinROdmyYAS1YngiTZJmy4T3XB7wUdw== 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=vqMHwel5aejcZ/h7F+fWey3srDVEK77hUijpg5WX8XE=; b=YYadRSzXO+vOmIiA/XOR9vAMfgP/l72Yc3DH6A0V9572kI8PTR6k3vwTIzOUGLrm/+eX5HVpzxu3EyxOyGKYim/rxfmaXQxyv4QasklpPBNDprbXoeUPmek4+tCEo/y95P8JuFt3/c4YvBr02L69fdeFQIhi9X3uTKLTmjVx0NOKn0cx7HjRZxJpFYaDUar+2hLRyesdUVCuRzry/jF/PSZ9dDnpvWAgD9zes3A1y+Ttn+4510L6UfPyx0p/BOL8saRGyIfLBFZ2LxPUYULBcZ3cF+0UTyu8l2Rh/RYEOJn5tIyh1BGN8a4wrk3OLXYITL8AQhiwO1TehIQhm11Afw== 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 SJ0PR12MB6832.namprd12.prod.outlook.com (2603:10b6:a03:47e::12) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.9611.10; Mon, 16 Feb 2026 08:05:30 +0000 Received: from CH2PR12MB3990.namprd12.prod.outlook.com ([fe80::7de1:4fe5:8ead:5989]) by CH2PR12MB3990.namprd12.prod.outlook.com ([fe80::7de1:4fe5:8ead:5989%3]) with mapi id 15.20.9611.013; Mon, 16 Feb 2026 08:05:30 +0000 From: Alexandre Courbot Date: Mon, 16 Feb 2026 17:04:42 +0900 Subject: [PATCH v6 6/9] rust: io: use generic read/write accessors for primitive accesses Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260216-register-v6-6-eec9a4de9e9e@nvidia.com> References: <20260216-register-v6-0-eec9a4de9e9e@nvidia.com> In-Reply-To: <20260216-register-v6-0-eec9a4de9e9e@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: TYCPR01CA0187.jpnprd01.prod.outlook.com (2603:1096:400:2b0::8) 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_|SJ0PR12MB6832:EE_ X-MS-Office365-Filtering-Correlation-Id: 394b3683-d522-4f2c-20eb-08de6d3226a6 X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|1800799024|7416014|376014|10070799003|366016|921020; X-Microsoft-Antispam-Message-Info: =?utf-8?B?eEdmMEw5NVFCOW9kb1FFenpTejhEMUNmTmZSVXdaekhoeGFBU1daZExQbGhC?= =?utf-8?B?eFVvLy81Z0JFMStXcFY0ZkUxbyt0UUhVeVREZlI1bzF6NXRtMGtnSXc4N2Ju?= =?utf-8?B?YzdmS0lHZHZFR1g3YUFEUE05UnFYT3RMSUFwcmhiU3pPZkpyQU96SzJNR3hB?= =?utf-8?B?NFkvY2dnN3VCQUZiNGp6L0RyNENkdDVwMlJ3c1NUTjFtbGtqeHVkTDY5aFV1?= =?utf-8?B?ZllOelRNTTFBb0RvRmphVzJPQmkraERNMUdNcHJ0TStwQUltSmdpNXF1MTVW?= =?utf-8?B?R3Z6a1RDT1BNTmhGVGhiSld3NkdQdlRNcUMrVFZTUXR3RkU3akRoWXpKRlJS?= =?utf-8?B?MFc5c01ROWVXTmI5RFFhYUhrU1B6UmNSZXdZMkVIZnRodkhjRG1wcUhJTUNM?= =?utf-8?B?TjFIcDcrNFU5cWNLOGdGbE1ONlhBeUpGZ3dLWTlqTURvaTRWY0toM3I5clpL?= =?utf-8?B?TThDby95NVFwb1p3TGNZZlhWUzA2UlNmU3lFLzNUWmNDTHBsd1lERVd2UG5k?= =?utf-8?B?RDBSY05XOG9wbnB4S2FwM3NuU0xtNzh4MGUzcXY1MFQzYXZMejZsUm1mMndS?= =?utf-8?B?ekZVQW1iZHNlbHFlT1ViTm5YTDN0bGVPWm9rWXFaOWhBVVl3N0Q4a2RHRU9q?= =?utf-8?B?RERnQ3RFaHN3WEpxdEVlQmY3b3FMK1VlU1oyN3hMWkRZeFlBK29pdlNHM2Vv?= =?utf-8?B?eHR2NU92TE9yNE9TYWowV1pHMzBYWVhZOGkzSkpWSnhQb2NBTU05K3hqMmxJ?= =?utf-8?B?MEoyeGNzVk03bU5ucUE5YktIOEFTSVJHcHExUUdXM3B1eEVkQmdPa3lQUzZp?= =?utf-8?B?YTFhanI4dld5bjJjOGdCdmtzbHQwYVNGQWxOK0E0TDJFTHZCbVBBVlptWWFS?= =?utf-8?B?S2ZvbGtBekt1aGNjMStyZ1dWS0hka1FSU2V4U3JydHFGaUxxSS9wSFVQQW5p?= =?utf-8?B?azNlb0lhZ0JEaFhjUjZJeFdCVVRMKzNKalBhOTZpLzBxQ3lUbmd0eTFqQlpm?= =?utf-8?B?VGhXTitUeGlUZkZaUnFTcitONXZDNTBReXN6VWp0YmUrNVo3d1A1aWJQeHdm?= =?utf-8?B?MEdLUk1FYTNUN0tLY1YrZ05OOXl0cXhjUXQwWW9MV3MxNmJ1MlppcnZuaGl0?= =?utf-8?B?bE5LWGFmRndiMFFGcUpYUVljOG9wWWF5ZFY2R1JsVEI5KzFieWRUc3dYZzZM?= =?utf-8?B?WVdxZnlwYnVENFhWSFIxMTB5OENkZkNUV3AzMkRRQ3R0S2pkaXVlQ0YwdXlQ?= =?utf-8?B?djFraTB5TWJsUnYzYXBnaE9TcEt4SXlaSmZHT2t6TG81VmZHc0lDQnVld1R4?= =?utf-8?B?aDUwVUY1TnAzRUxITWtaZGJzTFlnaENONjkxVGo3L3RnNmtXYmlTaU1qZmUr?= =?utf-8?B?REdtcGo5dUN1cGhKdVZOWFBBS1VDbG85d3pUS01EbmtvNXZ5QUZrUFdkSUQr?= =?utf-8?B?dEVRZTlNcXVjWDJOdkJvT0I2ZzVPOXhHK0hHR3Z0ZXdMRXI3Rm5wTE9hTnJ2?= =?utf-8?B?d0VlTy96YmNRM1Y0alV1NG1IUm5hVC9NRHhlbEpCU2Vtd2d5TnJxUnlJTUdW?= =?utf-8?B?Kzh1L2xOZFRjQXVlbkdXWS9CT1p3WGRxWGpqd0YrNm5DL2J4N0J3enJFWGVr?= =?utf-8?B?czE3UXMrNnBYT0JhZEFlaEVIY0J0WlJSQk1vWFBJc0FBZFh1ZHU5RkpVOW9J?= =?utf-8?B?Y1RJZVBKSmw2dWtHSlk2ZHlIMCttbjVCczNjWkRBMTBaeTRGVStZOHhlL0Nn?= =?utf-8?B?MEZvT2xrUDFlK3IrQnhuTDZKWko5WXlIWUhFQUlMYXNWUkZweEJsL1FzbkZN?= =?utf-8?B?Zzg4ZjhzZ1JjZEpnVkRxeTZGU1BZTHRCYkhFcklyNlFkUGRGKzhyUmN3M3l0?= =?utf-8?B?Qml2Q284SldQZ1YyR2s0NHkvTUF1dCtmOTFidzZHVDdmMFN1L0ZrNUM1WFA3?= =?utf-8?B?RWlCSWV3clZXeDdBWGVsNkJmMVM1eEtEMENkWmNQRjI5VFFVbGpLenI5SnJB?= =?utf-8?B?UmJ5WTF6NXBXY0NqYWYvUVNFSk1wRUxTdUQybmYvcU5XUXlRVE1nK2tRN1VL?= =?utf-8?B?WUwwRFkyR0wxTDVLN2Z5RFpWR1JWZ1p1MnlPM3ZvakhGRTFtWFJ2c3c1cHAr?= =?utf-8?B?UHQwQ21FbXBPUGtPQ0FyeHJGSEVmS1hDSWM0d1hpbTl2SXlNZnp4YUJnbTI4?= =?utf-8?B?S2c9PQ==?= X-Forefront-Antispam-Report: CIP:255.255.255.255;CTRY:;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:CH2PR12MB3990.namprd12.prod.outlook.com;PTR:;CAT:NONE;SFS:(13230040)(1800799024)(7416014)(376014)(10070799003)(366016)(921020);DIR:OUT;SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 2 X-MS-Exchange-AntiSpam-MessageData-0: =?utf-8?B?UDdVUmpMZjFoQ0VZM3M3MHhHelFRT3c0cmhnVkpPelNVUWk5b2E5OTNWMXkz?= =?utf-8?B?TmRFdk4rUHhpN1l6NVJZYUowdE1RdW5pQUVBd1Jpd2QwR2xKc3dmRjZQeGx2?= =?utf-8?B?Z1NZbERheWduQWR0bEhDbDdJZEdHaXQvMTV6MEFRM3p4K3lPa2xSN09wd2NC?= =?utf-8?B?ZEF0VEE2MWExRmxCaXJjOC9GYXBXMnJFWHhYdDNoM2t4SWp2V3o5OU5yZllw?= =?utf-8?B?NkpyMlRMTVRLazRGK0lNK0JEMmlNT3lBL0FOZ3NkaHZjQS9WTUswMGJ4ZDUy?= =?utf-8?B?b21wL2t3elJqQjNIZWhQMnlDai94eFZDU3hmQyswOGttNVNLR3pBeHlkMk5G?= =?utf-8?B?T1RYcUJmME5FRjRJdXpRc3JYdW4zN0Y3a3RYcm4vN3Q5RTZoNFE2RjZQMEh1?= =?utf-8?B?NWZDdU9ucFFtS1NVYzAvMmg5Z3UyZi9PMWVzSTJtSkI2cWhaUmREbTBSckJK?= =?utf-8?B?TlQ0Ynd4NG42dUZqQnJxb2ZuTGdkK3U4WFlkUTlCQlpJQVhNU2lRdXQyRnh2?= =?utf-8?B?Yjg5WWZtWFp6T2Y0cTB1TnZtQUpIdzV1WVBZRFp2VlYvbWtyWGxZaThhNnlk?= =?utf-8?B?L0taTVdMZUtwNnA4Zmw5VmNjSDlWdGtUaUwySmNuZWx0WHdKaDJNQkRvZERV?= =?utf-8?B?UEtEcmh3L0EvS2s5cXcwazkxelZ3b0ViN2tkRnE1WDJFa2RsaWVlRkU5TytE?= =?utf-8?B?S0tlZG9tS2k5dXFGdSttSzNqV3M3RWdTTi94bXl5ZVBqbmhIMjRCNlVVa0Rl?= =?utf-8?B?OHhVbVlIQVlhTHRrR1dTdnh1QVVOYnhMcGZoZ2pwQjdJTkpRaTZmdlA2bDNW?= =?utf-8?B?aTVBdXJBc3FmL08xaXRqdFlEbzlXcW9XSVlIUWY1azVPNmQyeHdBR080SmRB?= =?utf-8?B?V1BzMU02b0JTOWtYV0pDRXcvZWZIZ3pjdllzekVRYks5M2l2TkdCaXhHU0hl?= =?utf-8?B?VzUvRDhrSFJMZmMvRVVzTlRBczFxdUdtUWlpaDFKcTIwZ2RWdWM5c3JBRGZH?= =?utf-8?B?Sm15YmlVL3hJNXpwdVVGeFNmanpKMW1TZVI1TGpLM3g0d2RtYWYxU2hRTmZZ?= =?utf-8?B?M2IvTGdKTW9sa0tBa3dIVW5GY3hEd2dwNWovUm5PQWlyVXprZ0xVV1NzVSsw?= =?utf-8?B?dEdHRGZnVm91TnJUR2RrUC83WUlQQ2VSMDgrbWJaVEQ3WGlPZlRXczh1b2Z2?= =?utf-8?B?bGhDVFJHcEsrM0lieVdpQ3VVWXNBcENuNFk5eGsxcFZhN0Y2a0FNS0JWb0NU?= =?utf-8?B?c0M3dWxDYkJCYnMyL09hL3lKQkxoL3RrOW9TS0NJMStBQjFYeEUxeTNKUGh1?= =?utf-8?B?aW5OSWl4TkQ5U0cySnFPMnhsVG9VSnBXOUVFYzRrM29yQy9mcUsyNkhKb2VI?= =?utf-8?B?YmJicS9EcnVla1lIK2MwZk9MaCtoTDZFMVdKODRyVVBCd0FNZmppTkdmVXp0?= =?utf-8?B?T1FVRUVESlQzL2V3RDQ4S1o1c0RmYmthaDJiSDF1Wi9sZEg5anlpdnFoWEhw?= =?utf-8?B?SmFIWUtZR0ZlQS9FKzBMSU9WZC9YbU5MaXE5b1dhcHppLzd3YXhUWUxLU1pX?= =?utf-8?B?TlZpNWVldm5iY245SzRzZm1CV0o5cTR4VXA2QlUwVGNMc3ZpRktjVlZuNTJ4?= =?utf-8?B?ZStHeFYwWjZ5ZEw1ci9zYWQzbWw0cDJQNFpxdTIxU3VUa2haamxQeDBHUTll?= =?utf-8?B?c1BUTkRtMjc0Q1JEUWVGNFoyM0E0N0VnbnBZOEJtM3ArWXJ6RzNwVnRaOVpF?= =?utf-8?B?TzBOTGFmNHRBaWRBcmhRK09BNlVrZmk1OXNPb09JQnU3RnlvTkY3ZkszV0p2?= =?utf-8?B?YkhJOGNqSUJPSnhtSU5UZG1wd2JDc0paenhPbVpRbjVWSGpwOXlrQ1BtT2h2?= =?utf-8?B?NVBVYjEwSXNPaUJtTitITm9aNHZVd1BvRmlDZDVUUzRPODBuWWQyenpTZXFx?= =?utf-8?B?RXpFLzFQRGNBSWxNcFJmWml1N093Rm95UXdydjVxZ2lNYU9LODVjNk9SVXVk?= =?utf-8?B?eWFCUDVBaUVMbzBDWmQyWitveUw2T01LU3Y3Q2ZuSVlHSlA1bm8xd01nYUl2?= =?utf-8?B?WFgvUkFEZHlqVm1ickRQTkNCNDYrd2hzOEZ6VHl6SUdsY0s3UnN0NG53a3Vk?= =?utf-8?B?K1lhdXZta3o2cDRxbkxwa2tkNW04UWpKT1I5a1JwdWpGekgyUjd1cER0bFdH?= =?utf-8?B?c1N5bTFYSllOZ04zRThoVjlpNzAwQnRRaW5nSmdwVUszNDdvaUF6aEY5V3V1?= =?utf-8?B?VU5NVzlTOGlITFNVenhlOVhYajk4cFN0MmhXRitseGR3NDRxVDdKWTZIMEZo?= =?utf-8?B?dmNjWFhDSXl4WFNqdW1qZFFDZ1BZQVpvemFVMHN5Z1oxQmdRK21Gc2lQV0k0?= =?utf-8?Q?yRBSnHARrwn7kMs8zplsw57hdE6ILlQAcfu+pTDh1+dSA?= X-MS-Exchange-AntiSpam-MessageData-1: 7rh4fCqTgNI+lA== X-OriginatorOrg: Nvidia.com X-MS-Exchange-CrossTenant-Network-Message-Id: 394b3683-d522-4f2c-20eb-08de6d3226a6 X-MS-Exchange-CrossTenant-AuthSource: CH2PR12MB3990.namprd12.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 16 Feb 2026 08:05:30.0030 (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: 0jBrYUmWp6t3hrN63MENEDowmBDSMnwDJPUNU1z67YV19dEhgz7BSYF3+uw1XaSUcbODXFAgpYsCz1Crl01+Kw== X-MS-Exchange-Transport-CrossTenantHeadersStamped: SJ0PR12MB6832 By providing the required `IoRef` implementation on `usize`, we can leverage the generic accessors and reduce the number of unsafe blocks in the module. Signed-off-by: Alexandre Courbot --- rust/kernel/io.rs | 103 +++++++++++++++++++-------------------------------= ---- 1 file changed, 35 insertions(+), 68 deletions(-) diff --git a/rust/kernel/io.rs b/rust/kernel/io.rs index 6da8593f7858..053c6385842a 100644 --- a/rust/kernel/io.rs +++ b/rust/kernel/io.rs @@ -277,6 +277,25 @@ fn try_init_default(self, f: F) -> Result, E> } } =20 +/// Implements [`IoRef<$primitive>`] for [`usize`], allowing to use `usize= ` as a parameter of +/// [`Io::read`] and [`Io::write`]. +macro_rules! impl_usize_ioref { + ($($ty:ty),*) =3D> { + $( + impl IoRef<$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_ioref!(u8, u16, u32, u64); + /// A pending I/O write operation, bundling a value with the [`IoRef`] it = should be written to. /// /// Created by [`IoRef::set`], [`IoRef::zeroed`], [`IoRef::default`], [`Io= Ref::init`], or @@ -371,10 +390,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. @@ -383,10 +399,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. @@ -395,10 +408,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. @@ -407,10 +417,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. @@ -419,11 +426,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.set(value)) } =20 /// Fallible 16-bit write with runtime bounds check. @@ -432,11 +435,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.set(value)) } =20 /// Fallible 32-bit write with runtime bounds check. @@ -445,11 +444,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.set(value)) } =20 /// Fallible 64-bit write with runtime bounds check. @@ -458,11 +453,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.set(value)) } =20 /// Infallible 8-bit read with compile-time bounds check. @@ -471,10 +462,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. @@ -483,10 +471,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. @@ -495,10 +480,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. @@ -507,10 +489,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. @@ -519,10 +498,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.set(value)) } =20 /// Infallible 16-bit write with compile-time bounds check. @@ -531,10 +507,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.set(value)) } =20 /// Infallible 32-bit write with compile-time bounds check. @@ -543,10 +516,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.set(value)) } =20 /// Infallible 64-bit write with compile-time bounds check. @@ -555,10 +525,7 @@ 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.set(value)) } =20 /// Generic fallible read with runtime bounds check. --=20 2.53.0 From nobody Fri Apr 3 01:40:58 2026 Received: from SN4PR0501CU005.outbound.protection.outlook.com (mail-southcentralusazon11011024.outbound.protection.outlook.com [40.93.194.24]) (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 42FAC2F7ADE; Mon, 16 Feb 2026 08:05:43 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=40.93.194.24 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1771229145; cv=fail; b=qiewr5/eqssfgOOqJBLccyGgNT4tUrHeOUsgQRgIt6DLs2uZofb1aq9Fy3ozqhcCIea1v5/aIEilLBdz9oA/aBrZceHI5OiBTtbNlmqOG2mIViag+ppQoxVrcJij9kyIF/acYsb13Mtn1gSj+qxPqhnKCorSMnJ9agDM62QEOLw= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1771229145; c=relaxed/simple; bh=Utqkn8HskMsJrEyLPk0TkjF2fSrSAt/2uaHltKz3bf4=; h=From:Date:Subject:Content-Type:Message-Id:References:In-Reply-To: To:Cc:MIME-Version; b=u/r8syRJXmBGZ7FyZTfmfB3H/+R/XA/fHqrwD3NwvvY20oN22zy592+Lx35GbHc0+nJdGIlWG+Zt+wyadvxr7Wkd6xpEosu6NUtK8rOGWKGnTS1Rj3H0AmIojFGHbOBm2k2CGSV0GmxQuhD5bQhgMG5DJyR7l1FGxxyP5oeS+3A= 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=GqS6uiNt; arc=fail smtp.client-ip=40.93.194.24 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="GqS6uiNt" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=RHv+7XZ7qUG6XMtHddQXReg8sd2zLI/AcJH4OstXCP+wSrPO0Jx1Q8n1Psnv/Njgn2J5xsVxR0XzlOvXk3SORTF0K3385mcI8DWPLGuGMzHZcstZH2Rj0xggOF/oDDsCC9hHmB0l2XW/j4/+OGCJ4+u2Am0qXwOKEtr0ViAKxbcUvWmEhJ/pKYzQm/h3q/nLVlMffnqQFYf1icQfuKfn6F+UJeJRZLRPamzbi4PaSb8Zzvn5rrPBHU7dcGbjZ9Ln2jfnppUQEcHVWckkZNon6AmawnHG4lBjvySmQkHthNqsqvl/NA9WDt8WHaF0PfUumWR8m1rzMr1ItvzsSIxT+A== 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=hcA3+hByhYSpmXFbIf1Asdo8Shgud85eieBIgiJ3WOQ=; b=xd6hejQ/yM3T4VHLVygGTP90JkjHP0pJb18Er2YKknrYwES1IpdFeSt8G99c05LvY2R+ZNfQUrvQ2uMJTuuz7Qw3GVZ4tFUMMuW5apl1WrFqguXXgx9gzMInD5fLhGQuVT8em9fH7aAOo1TYeTV73G2JH3FcVpLgX8IC22OasoefYoyOv5FxDVm2ORFBRaDRFdPCq5z/BCNfs06BVJQSNhjpzoUn5+Y77kzcJou9Xk17dlmYAdJ+24qgf6n5ST488NN6xFPXDReIsTQRiNSe/3enoyO9Jxll+wqNoT3/ucYbmSHaNKDgKHZs+iKZRodQ5GZc/HzaDkpPyTOk7ScQ6g== 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=hcA3+hByhYSpmXFbIf1Asdo8Shgud85eieBIgiJ3WOQ=; b=GqS6uiNtv1MhmgWGvn+CpzF8nPjr0qGLuZ5lROiESX7bV/r0lzjIYT22Ey33ySiRZyiBq5yBXI9hpchPMtzSA979PMfbZUyaW8l/AW/UODNCZvgQHup2jRiE2o5pKloUx5RvE0oyZjT9wQ681p7b2o6GER4EORfERS6ssPCmf0BJ17+sdCuXLqAtqLODWmLoKoqXEGBKyC32L6JSMDY8SVlgt8BXca5a0Y7TsWGUaLwjJNYvQR8LVXYyu+jpY6UOMy1srTUuy0F5ulQHMeSa1YK+U+i8sNcDF7m5gscFCvY5BdmxN/RcXSmWovsipoNP9f+xNjLZuVHVRsyrnOSYJQ== 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 BL1PR12MB5732.namprd12.prod.outlook.com (2603:10b6:208:387::17) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.9611.13; Mon, 16 Feb 2026 08:05: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%3]) with mapi id 15.20.9611.013; Mon, 16 Feb 2026 08:05:33 +0000 From: Alexandre Courbot Date: Mon, 16 Feb 2026 17:04:43 +0900 Subject: [PATCH v6 7/9] rust: io: add `register!` macro Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260216-register-v6-7-eec9a4de9e9e@nvidia.com> References: <20260216-register-v6-0-eec9a4de9e9e@nvidia.com> In-Reply-To: <20260216-register-v6-0-eec9a4de9e9e@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: TYCP286CA0035.JPNP286.PROD.OUTLOOK.COM (2603:1096:400:29d::8) 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_|BL1PR12MB5732:EE_ X-MS-Office365-Filtering-Correlation-Id: 0ac1aeee-43d1-4abd-b30d-08de6d3228c1 X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|1800799024|10070799003|366016|7416014|376014|921020; X-Microsoft-Antispam-Message-Info: =?utf-8?B?QS9FdTRIZ0NEdXY0UUs5ZFlnMlcvRlhWQ3Z5ZUJ2N3VLVmlUaEhndjdmSW1y?= =?utf-8?B?Y2RIS0lmSG03RkxQMXp2NERwb3hCMXlMRkVUVmlPbjVFSFJpd1pBbEdnZXJS?= =?utf-8?B?K0tBNWdYRWpXZUFXZ2k4cnNXWXRrcjlQNEtkUG1iUnFSMU5WblBLeXZqQlFC?= =?utf-8?B?UGhLLzB3ZVcxdXZ3ZjNnQytJQlNzTFlROCtCVXNlMUduNThURmwyNnpEaG9v?= =?utf-8?B?dlEwelY3NUQzR01GTENjSE1FdXFLUnNxbzdhakZGaWpWTzdTMitCVU9OVCth?= =?utf-8?B?QnltdVZYcjFhOWRwOXU2LzYwQmd4M0JINEFqU3hWMFdiZnVWTTZvYjN0bndj?= =?utf-8?B?YkhTamE0UndvRCsxcnVyTWF4czdOQlY2TGl2NHIzQzFyRnVUN1ZmNUlaakVt?= =?utf-8?B?cEdOb0paRkRQdDdLNC9La29MM3hkRDhkSjlqWlJuOXJFQU80bktPN28rQUY2?= =?utf-8?B?blgycER3eW5iYmxnaUI3SVUxazBZaUtVNUt5OHhOMVI5ZWMvcDJaelFFdVF0?= =?utf-8?B?MU8vK2Y3WWZnOFZYMXZ6d29DUmRHNE55NVNSakJqMHBudVhJK0oxTmxlUWxV?= =?utf-8?B?aWxlRkllVTR4NU02TEZxM1MyTjdCWkRNNFhBRG9rTzhEcnVqeXhYRitqMGlO?= =?utf-8?B?MUMrTGFVMm1YN1lTRWU2RVdFY1ovdzlHT3YzR0NkRU8zNzVULzd6WTlWTmVS?= =?utf-8?B?c2ZHdmkva0M2S1FhWlJPMTVvekd1bitudlBjdzRNT0g3eGdobVlwK0ZFOWJo?= =?utf-8?B?TWUzTGswK0Roek11cXlIcDBBbmxkS0dRRWZYTlNKMDFiaWZEbEpSalhoK2tX?= =?utf-8?B?R2YvcFRIQXkrNjJNOUd3VkxBbFRqQnU2ZjNNTzhYQXp0TGRrVDdkamxRYnJT?= =?utf-8?B?b1NwcDFtZTVhY3phQnYwTGVnanQ2SzIzNnZwMjA2R0pXb0Vta2pTZHlod3Y3?= =?utf-8?B?ZUxNRHhsUndwMitBN0tmNXM1L2pTb0c5a3Y3MTVDdWU1YXU3ZGM2WG9NTjVI?= =?utf-8?B?RnNxSzN5blptOXdoenlyRm9EaW1FQUlpK3poaGx1bGlZT3pkYzdBUjhWTXJr?= =?utf-8?B?OUhIRlFJSHMxMklJUHNDajZMWGxDTEZyazF1cUNxY1dhY0pQdkU5dUpxQkxQ?= =?utf-8?B?eDdJZDlINFUyNlBWRGVXcERUL1FhbXpSOTJJVktUZUdkdG9sL2s3SjNiNFJ3?= =?utf-8?B?VDhmK01qbFd0amhIQUpFREt2aXNtNjZVZlRpWGtvUDhrQkl5MWpDeUx0S1J3?= =?utf-8?B?eE9qdkpYNTVrVUppKzhIU1VzczhVWERNNnc5cFBHMm53RXY4WmFKbFdmekZS?= =?utf-8?B?N25YUHUzNjlNUHlmUlVzL3YvV1A0aEo4RGdtV2ZyUzd0a2FPNW05UitDNWdv?= =?utf-8?B?aVJML290WUI3TW5UVTBSdkJFMTBqYlBrU1VqbkVMS21IeVMrNTBEOGoveEtq?= =?utf-8?B?OWliQ0R4S25MTXIxaHhsV1R6VFBDTUE1UkpCdjRlMmNXK1JkcGJtNUx5ZUFv?= =?utf-8?B?cVlPNWwwUDlyRzFpNHdzUVcrcG9JSGJNRktxQ0hId212cHVMRnNhT1RTbVJo?= =?utf-8?B?d011TVZ3TC93UzYxOUt5bU1rMnk0U3NWeGErejZyVy9Ta1VYbWNWUktaRUQ1?= =?utf-8?B?VHBoTzZHTDZqblVvZFJvbzZOQlR6QnQxRDFRcjdLWlBMcjBaQU85RysrNXdJ?= =?utf-8?B?Z0VmajJqQ0UrYUZZMGFYSjlCd05GVGI3Y3h6Z1YxVllXT3FFaG11aE8yeDJ3?= =?utf-8?B?NVZQR2kxSUh1Q3VVa3FHeHpEM2xoK2hUSUZnN2xjVVIvdm1OQ3dpZDVjTWxD?= =?utf-8?B?cDVzT0Z0RTFjZUNvLzg1QzFxMDUzbHBvdW43ejRiZHBrcHhDbk5PaVlRZFpz?= =?utf-8?B?V3o2VTArRFBCenJUQUlwMmdiR2Njd25SZnJoNzczM244ZGNZK3RtSUdIcTU2?= =?utf-8?B?cjBXTk91NCtmNDM2Q3VWL2ZhU2ZNeDRHNkMvZUI4OFgzQnJwS3E3QmVxQXZL?= =?utf-8?B?dmVOdG9JWG1yTzBqOXRSVmRKcWV6ZVNOZGFkZkp6K054UlNrYVF0L0lnZnRt?= =?utf-8?B?MnFGczV3alF2Q3JocmZlNFZoamtSY2dOeXlBNGRPZWFOVnhQSzZBR3NZeElv?= =?utf-8?B?bG16NHpmOHpGNG1UTi82M0V6R0lpT2tZdmMvajVETm9lWFQxb01zKzhCcUcx?= =?utf-8?Q?RcSOvOXOAWzcqyaZn19OHP8=3D?= X-Forefront-Antispam-Report: CIP:255.255.255.255;CTRY:;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:CH2PR12MB3990.namprd12.prod.outlook.com;PTR:;CAT:NONE;SFS:(13230040)(1800799024)(10070799003)(366016)(7416014)(376014)(921020);DIR:OUT;SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 2 X-MS-Exchange-AntiSpam-MessageData-0: =?utf-8?B?NDA2V0J4d084VjVFWDliVEc4eHoweVNrSnJwS0lIc2RkSXc1K093MVFCZ25K?= =?utf-8?B?ZTZKNEo4MkVKVVNLUE9mQVBnNElEK0w5TmZOaTFaVFV6b2RWRUF4bzl2VHcv?= =?utf-8?B?dUVBc1hJTk5vRUd3RUlaWUlub0FnMU0vdDhXeXhodjJEQWxpaUN6UExVQ05s?= =?utf-8?B?eGREQmNLd3VKTEdYcWRvaHZ5V0o3a1NSK0Iwd0w4Y0lJdnV2eVA0NjV3Y0JC?= =?utf-8?B?Rmcvc0hlMU1rcFZ0eUVrcGg3NnBDTFJSak9zUkZUMkxxK2I2RU84TUVETndL?= =?utf-8?B?cVFXSHNMUEZXTElhc2ZVSmttWUR6N1FKVEE0Z0xFU1ZkbERRQ3RuWmRFQytI?= =?utf-8?B?dnowYkh1cXkxeGQycGFRa1dSTnNEWGsvYUpVOEtjQmp4Rnc3emU5NUp5OXpn?= =?utf-8?B?b2ZWVjJjKzkyeDBOM0diczFqNTlJU0lneXM1OGxLWmdCRkFlNGlkS05Ja0o0?= =?utf-8?B?eEZYVFMrNGJHa05iMWYrNjY0dm1TZDZJaGwwcE5VVDhRQURTNm9PdjdrQnlz?= =?utf-8?B?RWNKaDMxM2p4anZmc0xwK2JSS3FCMEZYRUwxSEVzeHdHR0Z6WDI2ei9Ra0Jn?= =?utf-8?B?ak5PZ0w5MkRLN3RSeDJNakx4Y2tYNVVWbDYxbVE3TzY4VjNsZlFHWW5aR2tj?= =?utf-8?B?a1UzSG5qVGU1WFdRekVLeUUvQ21LY1F1WEw1ekV3bEN4UnBreFN3bzdaUHVj?= =?utf-8?B?QTRIZk9BL1F5RzRKdXBUWTlmc1NsaFZlQVZGNHZWRmVyVXRGeVcxUHFJNHNW?= =?utf-8?B?bjRoSW9wclZXa1JJQ2ovYVA3K05wRUpTVytrbEFDUm00NUsvdDZyMDN1MGtl?= =?utf-8?B?cE5MdEF2amplQjg3VDBPeGtFamltQ3loeURHYkd2WXdCMWdic240VUd5bDFI?= =?utf-8?B?YjMrcFlFdENZY1hTdnB3djhKTmltRUVHSmo0RUVzYmNZVEl1Q01QRXN1MlVR?= =?utf-8?B?U082c24yWFF2NDlIVDRCSmRNaHhERFg0SHJieWljREZReGNuSnVVaXVVbzV1?= =?utf-8?B?Mkw4dXBGZDU5aE8zb3dPT3pqa0RseG12NldHZ3hDS2FveWkwdVFZSDV0V0F2?= =?utf-8?B?NEFQeUx5SjNscFZBc0N5QXh0NHRyWjg2TG1yMzBERWlCckF6MDgyYzQrWTh0?= =?utf-8?B?ZjU1Z3IrQmZVd1p5cEM5K0FITnhNKzNwVDJYMVNabjBjUjZyN1dMMTZqbGhI?= =?utf-8?B?MmUyTHJBL0lNdlFMTGo4WGhFREZhQ3ZOa0FvNkVZQVFzOVU4ak5kZGlEaVdj?= =?utf-8?B?Z1hGSmFJSCtaWHpMOFVqS0plbzFDNzBaOU9ieUd0YjBVN0h5TjZXdTMvQU9C?= =?utf-8?B?Q0tKYjdoZlU2d01vc2Uva3QvSFJqNGdlQW9ZcXhxSHMwcVFQQkk3N0cyb1dB?= =?utf-8?B?endxRDgzR05jZG54cUdPTnpPQ3UxV3ZKM2xieFRxT25wK2Q4elJDL01EY0V2?= =?utf-8?B?UXprRkpMdkpjekozRUs0cm5kY3pCSFJUSHJia29JbCsySGR6akVQc2dLNXI1?= =?utf-8?B?ZmJXcVJFQ0Q5ZVM0SUtSby9SOXE3ckNpelBTNmNsa1NMRGQ0VCtZSGZIRm4x?= =?utf-8?B?VHRvWkk4V2NFSHBBQTUyVWUvRjRtMU5NOXJ6MTBKaG4rLzlHWStxYjU3dmZl?= =?utf-8?B?cUZDeVVaK1VIeGJ3N1JkV0xQOE12VmMrWldHYlVjOE9aNnJzY01QT0pQSDlC?= =?utf-8?B?MGp5TkdSazNHVm9uWW0vbUhwdndOZ3ZHNXBOeXpCS2Z2dTJianlOY1lFWHo0?= =?utf-8?B?QVdVWmFHOTVXb0w2Ym16aHpMQlo1V2pFdVJVK29vS0VQMzBJMUdzUDNQNVZT?= =?utf-8?B?dkdVQ1VQY3kvVnRhZ3JrZHAvTk5lRFhHa3hxeGJSSlZKbDVIcFRqTG9GbENV?= =?utf-8?B?dUZWUTlwOHRyU1pQYlVwWElhaUc4QTEvaUpWVGJBUFRuTUJVaVc5dzVOdTJM?= =?utf-8?B?L0xDeG16ZnE3Z05rZkowcXNyYnpRUERia2FIaUh2Z3M2SG5VL2V6cTBIUUJW?= =?utf-8?B?OTFDVFB5eG9aL3ZqaFhnaXA3dUpkOEFMcTF5MDJZZEM5U2EzbTgvNERWc2F6?= =?utf-8?B?L0VKTzJSdzZPTVo1QnlyUTBWRFBhWitHM2dxQ2tQRWdiSDhNNlUrK1BCVG5a?= =?utf-8?B?VjVFaStqaFhIQ1VpdVZ6MzNXZFVTbVJoS1pqekFMQ2VUenZhQ1NqN2RLVmlW?= =?utf-8?B?dzUyakE2bk41aldOYm1wMGZaQXV4b2xTVjdMTmRjdFlmQzlpZ0l5VlArMkZB?= =?utf-8?B?VUhoeVdMTU5vNlFraDBqRW9LVmpRTjBzaW0yeURGU1lobzNOa1Y0R2IxT2ha?= =?utf-8?B?Q2g5QjV1bHhJVHYvNktXZmRuMjhSVkZLNzB2azZDeVdhdm05QUNnZGdqMGJQ?= =?utf-8?Q?Rft9BggIqTiqO8ZIpQjk4fTsJ4TsRlI36MLKusiLJ4+Wq?= X-MS-Exchange-AntiSpam-MessageData-1: KWTrIQwU2Ca1AQ== X-OriginatorOrg: Nvidia.com X-MS-Exchange-CrossTenant-Network-Message-Id: 0ac1aeee-43d1-4abd-b30d-08de6d3228c1 X-MS-Exchange-CrossTenant-AuthSource: CH2PR12MB3990.namprd12.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 16 Feb 2026 08:05:33.5564 (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: h6o62No+Y0a0Bq7uGCZmOy8jwqEr7gmbNvqXCCfgcmejcphccymLkKB02hNLuVKIB4yReuHbJzGdM4ozK1YoDQ== X-MS-Exchange-Transport-CrossTenantHeadersStamped: BL1PR12MB5732 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 | 5 +- rust/kernel/io/register.rs | 1125 ++++++++++++++++++++++++++++++++++++++++= ++++ 2 files changed, 1129 insertions(+), 1 deletion(-) diff --git a/rust/kernel/io.rs b/rust/kernel/io.rs index 053c6385842a..c2dddf5b9dfd 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; @@ -177,7 +178,7 @@ pub trait IoCapable { /// /// This trait is the key abstraction allowing [`Io::read`], [`Io::write`]= , and [`Io::update`] /// to work uniformly with both raw `usize` offsets (for primitive types l= ike `u32`) and typed -/// references. +/// references (like those generated by the [`register!`] macro). /// /// An `IoRef` carries three pieces of information: /// @@ -192,6 +193,8 @@ pub trait IoCapable { /// An `IoRef` can be passed directly to [`Io::read`] or [`Io::try_read`] = to obtain a value, or /// turned into an [`IoWrite`] via [`IoRef::set`] to be passed to [`Io::wr= ite`] or /// [`Io::try_write`]. +/// +/// [`register!`]: kernel::register! pub trait IoRef: Copy where T: From + Into, diff --git a/rust/kernel/io/register.rs b/rust/kernel/io/register.rs new file mode 100644 index 000000000000..ebafe15d56a2 --- /dev/null +++ b/rust/kernel/io/register.rs @@ -0,0 +1,1125 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! A 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 reada= ble 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. +//! +//! [`register!`]: kernel::register! + +use core::marker::PhantomData; + +use crate::io::IoRef; + +/// 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. +pub trait Register: Copy { + /// Backing primitive type of the register. + type Storage; +} + +/// Trait implemented by registers with a fixed offset. +pub trait FixedRegister: Register { + /// Offset of the register. + const OFFSET: usize; +} + +/// Reference to a fixed register. +#[derive(Clone, Copy)] +pub struct FixedRegisterRef(PhantomData); + +impl FixedRegisterRef { + /// Creates a reference to `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 IoRef for FixedRegisterRef +where + T: FixedRegister + From + Into, +{ + type IoType =3D T::Storage; + + fn offset(self) -> usize { + T::OFFSET + } +} + +/// Trait implemented by relative registers. +pub trait RelativeRegister: Register { + /// Family of bases applicable to this register. + type BaseFamily; + + /// Offset of the register relative to its base. + const OFFSET: usize; +} + +/// Reference to a relative register. +/// +/// This can either be an immediately accessible regular [`RelativeRegiste= r`], or a +/// [`RelativeRegisterArray`] that needs one additional resolution through +/// [`RelativeRegisterRef::at`]. +pub struct RelativeRegisterRef(PhantomData, PhantomData); + +// `Clone` and `Copy` unfortunately cannot be derived without requiring `B= ` to also implement them. +impl Clone for RelativeRegisterRef +where + B: ?Sized, +{ + fn clone(&self) -> Self { + *self + } +} + +impl Copy for RelativeRegisterRef where B: ?Sized {} + +impl RelativeRegisterRef +where + B: ?Sized, +{ + /// Creates a new reference to 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) + } +} + +impl IoRef for RelativeRegisterRef +where + T: RelativeRegister + From + Into, + B: RegisterBase + ?Sized, +{ + type IoType =3D T::Storage; + + fn offset(self) -> usize { + B::BASE + T::OFFSET + } +} + +/// Trait implemented by arrays of registers. +pub trait RegisterArray: Register { + /// Start offset of the registers array. + const OFFSET: usize; + /// 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; +} + +/// Reference to an array register. +#[derive(Clone, Copy)] +pub struct RegisterArrayRef(usize, PhantomData); + +impl RegisterArrayRef { + /// Creates a reference to register `T` at index `idx`, with build-tim= e validation. + #[inline(always)] + pub fn new(idx: usize) -> Self { + ::kernel::build_assert!(idx < T::SIZE); + + Self(idx, PhantomData) + } + + /// Attempts to create a reference to register `T` at index `idx`, wit= h runtime validation. + #[inline(always)] + pub fn try_new(idx: usize) -> Option { + if idx < T::SIZE { + Some(Self(idx, PhantomData)) + } else { + None + } + } +} + +impl IoRef for RegisterArrayRef +where + T: RegisterArray + From + Into, +{ + type IoType =3D T::Storage; + + fn offset(self) -> usize { + T::OFFSET + self.0 * T::STRIDE + } +} + +/// Trait implemented by arrays of relative registers. +pub trait RelativeRegisterArray: Register { + /// Family of bases applicable to this register array. + type BaseFamily; + + /// Offset of the registers array relative to its base. + const OFFSET: usize; + /// Number of elements in the registers array. + const SIZE: usize; + /// Number of bytes between each element in the registers array. + const STRIDE: usize; +} + +/// Reference to a relative array register. +pub struct RelativeRegisterArrayRef< + T: RelativeRegisterArray, + B: RegisterBase + ?Sized, +>(usize, PhantomData, PhantomData); + +// `Clone` and `Copy` unfortunately cannot be derived without requiring `B= ` to also implement them. +impl Clone for RelativeRegisterArrayRef +where + T: RelativeRegisterArray, + B: RegisterBase + ?Sized, +{ + fn clone(&self) -> Self { + *self + } +} + +impl Copy for RelativeRegisterArrayRef +where + T: RelativeRegisterArray, + B: RegisterBase + ?Sized, +{ +} + +impl RelativeRegisterArrayRef +where + T: RelativeRegisterArray, + B: RegisterBase + ?Sized, +{ + /// Creates a reference to register `T` from the base `B` at index `id= x`, with build-time + /// validation. + #[inline(always)] + pub fn new(idx: usize) -> Self { + ::kernel::build_assert!(idx < T::SIZE); + + Self(idx, PhantomData, PhantomData) + } + + /// Attempts to create a reference to register `T` from the base `B` a= t index `idx`, with + /// runtime validation. + #[inline(always)] + pub fn try_new(idx: usize) -> Option { + if idx < T::SIZE { + Some(Self(idx, PhantomData, PhantomData)) + } else { + None + } + } +} + +/// Methods exclusive to [`RelativeRegisterRef`]s created with a [`Relativ= eRegisterArray`]. +impl RelativeRegisterRef +where + T: RelativeRegisterArray, + B: RegisterBase + ?Sized, +{ + /// Returns a reference to the register at index `idx`, with build-tim= e validation. + #[inline(always)] + pub fn at(self, idx: usize) -> RelativeRegisterArrayRef { + RelativeRegisterArrayRef::new(idx) + } + + /// Attempts to return a reference to the register at index `idx`, wit= h runtime validation. + #[inline(always)] + pub fn try_at(self, idx: usize) -> Option> { + RelativeRegisterArrayRef::try_new(idx) + } +} + +impl IoRef for RelativeRegisterArrayRef +where + T: RelativeRegisterArray + From + Into, + B: RegisterBase + ?Sized, +{ + type IoType =3D T::Storage; + + fn offset(self) -> usize { + B::BASE + T::OFFSET + self.0 * 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. +/// +/// # Example +/// +/// ``` +/// 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 fields. For instance, `minor_revision`= 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. +/// +/// ```no_run +/// use kernel::register; +/// use kernel::io::IoRef; +/// 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. +/// bar.write(BOOT_0.set(boot0 +/// // Constant values. +/// .with_const_major_revision::<3>() +/// .with_const_minor_revision::<10>() +/// // Run-time value. +/// .with_vendor_id(obtain_vendor_id()), +/// )); +/// +/// // Or, build a new value from zero and write it: +/// bar.write(BOOT_0.init(|r| r +/// .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>(); +/// # } +/// ``` +/// +/// 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. +/// +/// ``` +/// use kernel::register; +/// +/// register! { +/// pub BOOT_0(u8) @ 0x00000100 { +/// 7:4 major_revision; +/// 3:0 minor_revision; +/// } +/// +/// pub BOOT_1(u8) @ 0x00000101 { +/// 7:5 num_threads; +/// 4:0 num_cores; +/// } +/// }; +/// ``` +/// +/// 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: +/// +/// ``` +/// use kernel::register; +/// +/// register! { +/// /// Scratch register. +/// pub SCRATCH(u32) @ 0x00000200 { +/// /// Raw value. +/// 31:0 value; +/// } +/// +/// /// Boot status of the firmware. +/// pub SCRATCH_BOOT_STATUS(u32) =3D> SCRATCH { +/// /// Whether the firmware has completed booting. +/// 0:0 completed; +/// } +/// } +/// ``` +/// +/// In this example, `SCRATCH_BOOT_STATUS` uses the same I/O address as `S= CRATCH`, 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 = register'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 +/// use kernel::register; +/// use kernel::io::register::RegisterBase; +/// +/// // Type used to identify the base. +/// pub 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; +/// +/// # fn test>(bar= : T) { +/// // This makes `CPU_CTL` accessible from all implementors of `RegisterB= ase`. +/// register! { +/// /// CPU core control. +/// pub CPU_CTL(u32) @ CpuCtlBase + 0x10 { +/// /// Start the CPU core. +/// 0:0 start; +/// } +/// } +/// +/// // Start `Cpu0`. +/// bar.update(CPU_CTL::of::(), |r| r.with_start(true)); +/// +/// // Start `Cpu1`. +/// bar.update(CPU_CTL::of::(), |r| r.with_start(true)); +/// +/// // 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; +/// } +/// } +/// +/// // Start the aliased `CPU0`. +/// bar.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. Simply specify their size insi= de `[` and `]` brackets, +/// and use the `at` method to obtain the correct reference: +/// +/// ```no_run +/// use kernel::register; +/// +/// # fn test>(bar= : T) +/// # -> Result<(), Error>{ +/// # 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; +/// } +/// } +/// +/// // Read scratch register 0, i.e. I/O address `0x80`. +/// let scratch_0 =3D bar.read(SCRATCH::at(0)).value(); +/// // Read scratch register 15, i.e. I/O address `0x80 + (15 * 4)`. +/// let scratch_15 =3D bar.read(SCRATCH::at(15)).value(); +/// +/// // 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 bar.read(SCRATCH::try_at(idx).ok_or(EINVAL)?).val= ue(); +/// +/// // Alias to a particular 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 bar.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: +/// +/// ```no_run +/// use kernel::register; +/// use kernel::io::register::RegisterBase; +/// +/// # fn test>(bar= : T) +/// # -> Result<(), Error>{ +/// # 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; +/// } +/// // 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 a contiguous array. +/// register! { +/// /// Per-CPU scratch registers. +/// pub CPU_SCRATCH(u32)[64] @ CpuCtlBase + 0x00000080 { +/// 31:0 value; +/// } +/// } +/// +/// // Read scratch register 0 of CPU0. +/// let cpu0_scratch_0 =3D bar.read(CPU_SCRATCH::of::().at(0)).value= (); +/// // Read scratch register 15 of CPU1. +/// let cpu1_scratch_15 =3D bar.read(CPU_SCRATCH::of::().at(15)).val= ue(); +/// +/// // 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 bar.read( +/// CPU_SCRATCH::of::().try_at(scratch_idx).ok_or(EINVAL)? +/// ).value(); +/// +/// // `SCRATCH[8]` is 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; +/// } +/// } +/// +/// let cpu0_status =3D bar.read(CPU_FIRMWARE_STATUS::of::()).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 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; +/// } +/// } +/// # 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($storage) { $($fields= )* } + ); + $crate::register!(@io_fixed $(#[$attr])* $vis $name($storage) @ $o= ffset); + }; + + // 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($storage) { $($fields= )* } + ); + $crate::register!( + @io_fixed $(#[$attr])* $vis $name($storage) @ + <$alias as $crate::io::register::FixedRegister>::OFFSET + ); + }; + + // 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($storage) { $($fields= )* } + ); + $crate::register!(@io_relative $vis $name($storage) @ $base + $off= set ); + }; + + // 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($storage) { $($fields= )* } + ); + $crate::register!( + @io_relative $vis $name($storage) @ + $base + <$alias as $crate::io::register::RelativeRegister>::OF= FSET + ); + }; + + // 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($storage) { $($fields= )* } + ); + $crate::register!(@io_array $vis $name($storage) [ $size, stride = =3D $stride ] @ $offset); + }; + + // 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($storage) { $($fields= )* } + ); + $crate::register!(@io_fixed $(#[$attr])* $vis $name($storage) + @ <$alias as $crate::io::register::RegisterArray>::OFFSET + + $idx * <$alias as $crate::io::register::RegisterArray>::= STRIDE + ); + }; + + // 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($storage) { $($fields= )* } + ); + $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::RelativeReg= isterArray>::SIZE); + + $crate::register!( + @bitfield $(#[$attr])* $vis struct $name($storage) { $($fields= )* } + ); + $crate::register!( + @io_relative $vis $name($storage) @ $base + + <$alias as $crate::io::register::RelativeRegisterArray>:= :OFFSET + + $idx * <$alias as $crate::io::register::RelativeRegister= Array>::STRIDE + ); + }; + + // 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= )* }); + + impl $crate::io::register::Register for $name { + type Storage =3D $storage; + } + }; + + // Implementations of fixed registers. + (@io_fixed $(#[$attr:meta])* $vis:vis $name:ident ($storage:ty) @ $off= set:expr) =3D> { + impl $crate::io::register::FixedRegister for $name { + const OFFSET: usize =3D $offset; + } + + $(#[$attr])* + $vis const $name: $crate::io::register::FixedRegisterRef<$name> = =3D + $crate::io::register::FixedRegisterRef::<$name>::new(); + }; + + // Implementations of relative registers. + (@io_relative $vis:vis $name:ident ($storage:ty) @ $base:ident + $offs= et:expr ) =3D> { + impl $crate::io::register::RelativeRegister for $name + { + type BaseFamily =3D $base; + const OFFSET: usize =3D $offset; + } + + #[allow(dead_code)] + impl $name { + /// Returns a reference to the register with the base `B`. + #[inline(always)] + $vis const fn of>= () + -> $crate::io::register::RelativeRegisterRef<$name, B> { + $crate::io::register::RelativeRegisterRef::new() + } + } + }; + + // Implementations of array registers. + (@io_array $vis:vis $name:ident ($storage:ty) [ $size:expr, stride =3D= $stride:expr ] + @ $offset:literal) =3D> { + impl $crate::io::register::RegisterArray for $name { + const OFFSET: usize =3D $offset; + const SIZE: usize =3D $size; + const STRIDE: usize =3D $stride; + } + + #[allow(dead_code)] + impl $name { + /// Returns a reference to the register at index `idx`, with b= uild-time validation. + #[inline(always)] + $vis fn at(idx: usize) -> $crate::io::register::RegisterArrayR= ef<$name> { + $crate::io::register::RegisterArrayRef::new(idx) + } + + /// Attempts to return a reference to the register at index `i= dx`, with runtime + /// validation. + #[inline(always)] + $vis fn try_at(idx: usize) -> Option<$crate::io::register::Reg= isterArrayRef<$name>> { + $crate::io::register::RegisterArrayRef::try_new(idx) + } + } + }; + + // 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::RelativeRegisterArray for $name { + type BaseFamily =3D $base; + const OFFSET: usize =3D $offset; + const SIZE: usize =3D $size; + const STRIDE: usize =3D $stride; + } + + #[allow(dead_code)] + impl $name { + /// Returns a reference to the register array with the base `B= `. + /// + /// An individual register from the array still needs to be ad= dressed using + /// [`RelativeRegisterRef::at`] or [`RelativeRegisterRef::try_= at`]. + #[inline(always)] + $vis const fn of>= () + -> $crate::io::register::RelativeRegisterRef<$name, B> { + $crate::io::register::RelativeRegisterRef::new() + } + } + }; + + // 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 Fri Apr 3 01:40:58 2026 Received: from SN4PR0501CU005.outbound.protection.outlook.com (mail-southcentralusazon11011024.outbound.protection.outlook.com [40.93.194.24]) (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 C28AF291C10; Mon, 16 Feb 2026 08:05:41 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=40.93.194.24 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1771229143; cv=fail; b=rHH4HVXQMVWX11OvuEUlZj+WnKSuWnHwVMF7hYbTcQC8+j1vTIEG5ouZDh9SLWznx+7x3NOjc/l3Pd1yJxS05docd0kBiRRSqXgs85WEZzF2lpWVvNDpe8Q7wsZDVRNG02mF3/xXZnlyVe4qAQVsWQzqyUP5fx9QG63KjM6cN/E= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1771229143; c=relaxed/simple; bh=cEyTgDQ9cKGeztWc5GELvbUozwxNkpOYOjBhAdc8DUY=; h=From:Date:Subject:Content-Type:Message-Id:References:In-Reply-To: To:Cc:MIME-Version; b=Z98DfRQrasGMPBsBssJ2IG69gU0xKQkdsYCg+P4NK2KLmVWgipSL7j8XoU8y+d6ttsRpaoBjM2lGBvKEdTDHU6i/0G2XA2cCKivLsDqRxvm8jZoWRSIfT19UNa6Pm/t+v1oMzSt1YZslTr8dYVA9QZZEDk/PubZF6EUCX+8OZeE= 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=JHytUbSt; arc=fail smtp.client-ip=40.93.194.24 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="JHytUbSt" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=ihb/5bsXAlfZvOwxOEQ9GlJwccpwUIHo1DzbQeCcv18Kn3WiqC1pI9z4Sq8MsKtDKzUmj5Y11brSZ8cvhs7CGDqogvS+BJnH9Zu4pLmctcq6Dh9be2gdMxhPiGceIgRzdNfesReqwlxsV1lgW1ngTy/auPd274FTmNDooOU0r6+ug3CnfEMifr/tEuZqswxBUzZdn6bYKB6xeSc7Qo+8Xvl5b6M7r+I3Hl8XIlVwnZoHxjOOwwvzt3OEqYm8vBVoRnN63/xDQTQGrnRR+d19cjBOF8oFGeWHgQE70r6lAevVRW3nhE229RjcNTpJaabxaQQAMTMwYX/Y5bpBQ3gBww== 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=/9KkZBfK3rEd1RCcnNGR61Dg/xiq8tuLJdgoWvCbNg0=; b=Mnyr3BZXVCOdiI4E1U0/YRZzkZu2EWb8kc+Ck9qk3dTohggJHfNMSoO3szz8yyDcTJHWlkVZ5xq1/aFCdazZTCilz2a/4SihXv56+eRr+7WrB8c8ECV75upBcQmbXzwzt4mN0Fm/6p8NctafKKt9BMY5NU8BYwXZUvofeiuQ3df4l5dBOA/Fs7sd0gPFHjXH6d3HnT25x6m6JZASbN5DTg/PrO0FTMVY6HBNLT6p1oy5Ujv0NAV3NfJ5D8N/0ELVZrS1ioXP+Z38aYuPQ0pc9I8Utk+6boCq6ocBL1Z9BT7y8I1ORxD/ZgCLcBn2rgwQYoC1agkg1yDvhN7HpSDAdA== 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=/9KkZBfK3rEd1RCcnNGR61Dg/xiq8tuLJdgoWvCbNg0=; b=JHytUbStHdzvuZ/jLFfVao9nuIywU4gOhoHSnAGLRUI0hNAuKyXdwPxyjAqD9sCihUrlhebOoba91/twzSNU9L6raSvHSkuFgYlVtvVgkCA+AgehZUbo0PHza8H2GnXHr1ThuQNac0U9MQEDkwzfoNRGQEaUCraUUtTRpO3Hn7tiUrPffRz1P50oUl2RsmR1frx6Ggo61PzYiMCHol1ipcER4SxlO6pG27/FKCwZfyHACe1ccqmT1FPtssXylNnzQRXbIxYTJ38lDBG3HzAeoA/dLNuhse1uIoe6sp3EP+gxmTPrKoYeqdhWXvrQz7VTGxxWL+L4afabBkrxPUku0w== 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 BL1PR12MB5732.namprd12.prod.outlook.com (2603:10b6:208:387::17) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.9611.13; Mon, 16 Feb 2026 08:05: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%3]) with mapi id 15.20.9611.013; Mon, 16 Feb 2026 08:05:37 +0000 From: Alexandre Courbot Date: Mon, 16 Feb 2026 17:04:44 +0900 Subject: [PATCH v6 8/9] sample: rust: pci: use `register!` macro Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260216-register-v6-8-eec9a4de9e9e@nvidia.com> References: <20260216-register-v6-0-eec9a4de9e9e@nvidia.com> In-Reply-To: <20260216-register-v6-0-eec9a4de9e9e@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: TYCP301CA0013.JPNP301.PROD.OUTLOOK.COM (2603:1096:400:386::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_|BL1PR12MB5732:EE_ X-MS-Office365-Filtering-Correlation-Id: 2da74bda-7376-4d18-7a01-08de6d322aff X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|1800799024|10070799003|366016|7416014|376014|921020; X-Microsoft-Antispam-Message-Info: =?utf-8?B?MXM2MGh2eXR1RGdITG8ra2E5Ri9mSm1vUzRRV2xKUU5TVitmWXN3eG9oMEMz?= =?utf-8?B?NEdUOGhyaSs3N2RiT21sQ1pabGI4c1pWZkoxWk5HTDNJajhoRDkxRElRZXpT?= =?utf-8?B?dUNVUDBES1RDYXZ0d0JFeklsK0VYNDZiblV3WEtkMlo0dHRTdWpVNks2REZw?= =?utf-8?B?RjhzTmNwZG9yaWVNSy9NbzdZbHlrdExZZGZIMk52Uk50ZFoxUUVwSzhNMFlM?= =?utf-8?B?OXVjWWtOVVR6eUIzMDc4dSttZG96T0h3UW5kWHF2K2lSMVlSU0g2RTZFRTNr?= =?utf-8?B?am9yUCtYQzhveXV2c0ljSHFmU2VkMVVJcXpoSkN4anczSHlsd1B6TUVLYVlS?= =?utf-8?B?L3k0aEp0SzFOc3BGeGFhTmJsVFhkSm9jSmNLQ29TUzY3ZFlKcDRaN05YUEdD?= =?utf-8?B?MlI3a2xQV24vVEtCWDZzZDRSNCtDMWowMkRoZ2tleGNycDFBWmVoUDZKV0Fp?= =?utf-8?B?OHlBOHBKMHY5TTBQVFpFa1Z3NTV4R205MlR0RU96MEw1NXhQTS9uWXAvanVH?= =?utf-8?B?NjFYUkxCc0tzbHZFV3YwT295SG9TNG1qY1dyeUNrZ0llTERzbWp5d3o3OVl4?= =?utf-8?B?bzJObGtmOUxVN0x2RlFhT1JXZG5Yek5xRGQyZ212Y3NFVGxxNWdwWS9pNTB5?= =?utf-8?B?QVlTazd5a2ZjSlMvVGEwRTV6SnBocXJseXpaZVZWSHk2aFFZTUdIcDZDM0lY?= =?utf-8?B?S3ovaUpXcWFmSnFiMnQzcWtsb203dXFleCs3VUpnM0p4K3RMakhTSWZCcmxM?= =?utf-8?B?TzQ5SC9NblhMZ3FkajIzbTRKNlorOFNYaFNKNjZ4UmJsdWNYVnRuYnB5bnpY?= =?utf-8?B?QWNXWU8xTFVUVTNJc2pOWG5KQ2RjUURNbmZyOTJmUlE5dUtoSm81WFowT1NN?= =?utf-8?B?TUxtMXNqOERnRFJPZUszc2k1ekhEb3paOHZlZG53UnVGK0RmZ1ZaTkJIYXIx?= =?utf-8?B?eUs2dEdPSUlQU0xqdEtLNGdMSlphNi9lcEV1azBTZ0FBaGcyZHJHc2JVQXkr?= =?utf-8?B?R05EcFlZMFFjMTY5Q2lHY1IzYWd2V3NGL0J3WDN4Z3M4Z1kxTXlabDN5NE04?= =?utf-8?B?S0sraTVwY1NEOWp6dWNWNDNGNDFEaTR4cXJDUGxBcUxYa0lucUU5RGt2aVBu?= =?utf-8?B?WWxvZ05PNGlrSnNtaFJFUk4yZVhpdHFMc2t0cHNoZmxvWUhEdUc3MjNJZnVn?= =?utf-8?B?NDNsRVhLWmRtMnVjc2FzOEVRaVZZOXN2R2c5K2hXUGFxcWxqVDNrT1JCR1B4?= =?utf-8?B?aEt4cWc1YnFURWFvcjVOVW1GTWtKbnNOQnpjaHhrTm1IVDdidVBKMnVVdFo4?= =?utf-8?B?dDFsSDl3NHpyRDgwNHQ1NzU0dEpENXRaS0RrUlpvSStRcjhVT0JtQmlrTTRq?= =?utf-8?B?TE5VektFSWdEN21JOHhZUGJBcFVTWTE2LzNlR3VVVndXdXJlRHQ5bVNMU3Vp?= =?utf-8?B?MlpYaFZqUWZDM3ZNY3hVRVVuZ1hRa0xOUXRsNThFZ01mQlRYYTd5RkRrNzE3?= =?utf-8?B?cm0vcVF5OXU2aVUvSFVMeU9ac25kU2J4dXlBeG9WdFhuYmk1clJWeC92UDBY?= =?utf-8?B?N1kreFM3QkR1MWw1ZTNaM1RMMXF3RUNvY1BLM0RNLzdHTDVEcThuaG5VbmZ4?= =?utf-8?B?cXljdEdxTlUyaHY3bi82ajl2UThzaXR2M1M2aFJtUWVLVlpoaUNQRUpCaUFG?= =?utf-8?B?N1lTa3RIL1l3UVFxLzliZVBVOG5lZHBoOFd3ZDc0cjkwTnZycDlWOUNwUWVj?= =?utf-8?B?dmdZNGxGSGZoWnRyZmt3dFY2RkplTGxyalRvdGVXYUNwMy9iQ3J1amhlV1d0?= =?utf-8?B?cEtuUTA5L3kvZzhFWGM3ZmNkbERMajIxWHpaM1hJQStqWHFlTDFUQnJ4eTRo?= =?utf-8?B?TlBCZ2lRZmhRbENqNlVvU2R4MCtDZW1qajNQWEZvZThrcEM1VDVjT0dpT3Rn?= =?utf-8?B?Zk9HR2gwOGZCSlFuWnE1ZGROTlBaSDk0a3BGZWR5YmY3dGpzTkd4VGhjaDd6?= =?utf-8?B?UlBvVDcrT1AxaVdGeVRlMkhwYmdPYjRWNkdMMzVQRGFiRzhkNWxZV2RBbTVu?= =?utf-8?B?ZmJlcjYyU0daMmV2b2p3c3c1MCtYcVpWSERIYVpsZDB5dTUyb3IydXh3L28r?= =?utf-8?B?NFBkMGVzRkhuMzEvTTlnZ3orZGpTOE44UUcyK1QrRUV6VExnM2NmTFNLaUVQ?= =?utf-8?B?OGc9PQ==?= X-Forefront-Antispam-Report: CIP:255.255.255.255;CTRY:;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:CH2PR12MB3990.namprd12.prod.outlook.com;PTR:;CAT:NONE;SFS:(13230040)(1800799024)(10070799003)(366016)(7416014)(376014)(921020);DIR:OUT;SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 2 X-MS-Exchange-AntiSpam-MessageData-0: =?utf-8?B?MzNHMjhRNnRvR2JmK21JVWpMd3ZoTEQrWUFySE9uZTNsRUxTZ2VheHpBY0Fk?= =?utf-8?B?LzVvaFNNSDNUUWN3LzR6enBlS1lNMmVZTTQyNysxWlBScGlOZXdBL1NJeU03?= =?utf-8?B?SGx4eGk5V0t0T0xuSUxBeTlMQlF1ZXAxczh3dnZ3SXM3cG0rZjZ5Y254T043?= =?utf-8?B?ZlBlVldFR2Y5RUl6M2Y4Z3RldVFFWlo1cjZBL3FBR0hBSW5lYzJPOFg3Zktm?= =?utf-8?B?V2JuZklmS3FxWTNCdkp1K0kza1cydW5QaXRqZTR4QjhROWovUUMwb2NkT0k0?= =?utf-8?B?RG5iV0c4TWpHOFNMb0dSdy9Wb2IrdXc3K2NuQzNsZmx0R3ArSU1RUzRNT0M4?= =?utf-8?B?bmdObHYwQ0dFRmFKT3RCbnl1aHJnekIvN0pHVWt4WXQ3ZTRvOHk3T2s3UXBV?= =?utf-8?B?UDRxSDFXaW4zL2J6WWVvUGVXUllJd3dSRE9DSkRsY2FPcmlZcTBLY0kxQ1Fq?= =?utf-8?B?QWYzZENCTWRsMUc5dWJ6dlo3OEZNWEJreXRJZndSTkxjYVhoYVFrMWNvUWtW?= =?utf-8?B?WGFtMjg1ZDlrUDVvRVpZQXN2cEh0dkhSbjRyT2lOWTJBcGNDWEJ2SmdTMnJ0?= =?utf-8?B?VFN5WnUxYTJTcGFlZ3lrL3MrM2NYcnhWNnNoTDRGaml2NXdNclJGSVRTbEZa?= =?utf-8?B?eTF6dUp0MWZyeU9lRDVxZUJzN3lWaXJETEVsR2VmQjljeFlZUW5TTFQxcmQr?= =?utf-8?B?UG9KcnNiTWNaYjFDbjBZMEluZ3A2am5SclZjNmVROEdFR2R0SGp5NCtvWklv?= =?utf-8?B?bHQwL1BFeVpQQ3RXakNuWm55ckxOdGdNRXkwL25iVzkycU5YL2FKTGtYN0Fm?= =?utf-8?B?Vk5lckRMSzJIc3JPaS8zTmxCRnVyNzlxRWxSU2xWOG4zVnVraWcvYmgwcnAy?= =?utf-8?B?V1M3ajVuSm9nZHFpTHN0TWVBME10RWV4QUd1aUJsejkxSkFldDZPYmVCeHNk?= =?utf-8?B?NEkvZlViRmFPTXVnazRpZUtPMXhyYWdaemx1N0FYeGFjRDRwSG1lNzdqcm80?= =?utf-8?B?d2UvRmh6amJhTVd5YXRJZXVRbSt5RFdUSW9IQTJieTFZa0NFTXpjZ05NaGIz?= =?utf-8?B?Y084R0hGNjdwbVYzdVVwekJkYTNzZDYrbEVZSjNHQTRZbkdZbU9yM3lDMWxU?= =?utf-8?B?SFNtV09PTVhqZEpHS25YWlExY1dOM2d2VEtmUDU0Z3hLUml1em9MVzZnSHZS?= =?utf-8?B?dkdPaUljMTI5c0RCMVVHYkFIVWVnOFVnT0E1WDRpVFEweEFXa0lKUDVZVDQw?= =?utf-8?B?Y1V0bE5aRkptMzBzUEdWSzBQajhDN1pWTkFXdTRkZWIzV3dmbUVsbDc1dHp3?= =?utf-8?B?VmVmaE40blYwOWFIUEZSOHY0eWVac1RWbmNNQlJmZ0o4OFBybUlsK290dEgz?= =?utf-8?B?N0hWZ0FsazRMczdyaTJOY2YzT0p3ZVVWelpGWXg0ODlPYzNTU0Q1TkdmVUtB?= =?utf-8?B?SmYzS3o1b21QUjVYbzdJUHFmMXNsd3ZwTllTT0ZNMlFrTTFPSy9naEx3eHB3?= =?utf-8?B?SXA3YTA5c3VPUmhxdU1na0JFQlNvbVRCQTJqZVRHTGJweE9xTUJXVjNVQ2Jm?= =?utf-8?B?WlJsZWphWHpTYnpXVmp4c2xUbG1vUjRjaXBnbXRSRTBEOHcrK2tkdklkb09D?= =?utf-8?B?YkNwTVBtZFRwU3pZc0JjMUlKblpGQngzdFViZWhGMW53UVZReHlRRXp6SWw1?= =?utf-8?B?V3RLNk1LVGZyOTV6N0RzK3ZyTEV6RUg5eWZTVlJwWDZBY05lWmU2cWQ4b0Uy?= =?utf-8?B?c1c1VDdEMlBUVHhYVTd3YVY3dkpoSWVQK1FNemxyckt1YkhESjBTYWkzdGVB?= =?utf-8?B?QkdRUHdycE9vNGhLb1owYzlJUjdJZXNtSjJmWVl6ekNtdW1VcEVYTW9ueFBI?= =?utf-8?B?ZW9ZSkxPRWNWaDc2SU1md3ltamRqckVKdVlMZ1g1RXBPd21kQi9YSHJCK2pC?= =?utf-8?B?bmI1Ujk4elg5K0lJUEdSVnFpelNhUjMza01uYjNPaVFkNWJEdXZ3dWlpVWRX?= =?utf-8?B?WkVXVTVjVVZGa2s4VGRXRXJUSVl6ZkVRSktQZnFDeFBLOUlMSHp4aHBEYVhh?= =?utf-8?B?WmhvNlhGeEV0M2ZSbjNnSmVjZGNnV3ZsaDR2c2xVZk9Sa2tHSGwyemFJaUww?= =?utf-8?B?ZkkxcHlTczlhVXRteXdSeXhrSm1nclJtV21yQlZWRnRWbWZQTUdwbUdReWxr?= =?utf-8?B?UjBvNUg3ZS9kWW9wQ1lSSTgwQllaT1pwZVlqanJHSHMrNnpqYUJmRk5EZjln?= =?utf-8?B?RjAvS0k5aUhqMUVwMmNFNndMNFdBL256eHZKTUNXR3ZZZlVSd2NQM2tzOHk4?= =?utf-8?B?NHZPQ0FKc0NRVzJHR2FCVU5yYmFtdDlvcm5mM0pJZFRTOGhGSjRSQ1BjQVEw?= =?utf-8?Q?KoHxClnJWajT0U6dIr/YegNVJg0g6O1BQxc9cwp3WHlQZ?= X-MS-Exchange-AntiSpam-MessageData-1: MlX6R05zM7ySow== X-OriginatorOrg: Nvidia.com X-MS-Exchange-CrossTenant-Network-Message-Id: 2da74bda-7376-4d18-7a01-08de6d322aff X-MS-Exchange-CrossTenant-AuthSource: CH2PR12MB3990.namprd12.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 16 Feb 2026 08:05:37.2052 (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: mLzwLK6TvR7vaKHAYi/qe6nxeEsoJkkt0FrGMvrTNEOFwcUE5iBHxq9GpHLVWESAYCuZAssnUCtlaRR2SkXEIg== X-MS-Exchange-Transport-CrossTenantHeadersStamped: BL1PR12MB5732 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..f2e1904507f1 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::{ + Io, + IoRef, // + }, + 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(regs::TEST.init(|r| r.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(regs::TEST.init(|r| r.with_index(this.index))); } } } --=20 2.53.0 From nobody Fri Apr 3 01:40:58 2026 Received: from SN4PR2101CU001.outbound.protection.outlook.com (mail-southcentralusazon11012017.outbound.protection.outlook.com [40.93.195.17]) (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 4AB1D2EE617; Mon, 16 Feb 2026 08:05:55 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=40.93.195.17 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1771229160; cv=fail; b=Amody46iXb3rmghohqeMn9iicTOwu6zZkUqqFQV3vb4B935SP4jQyC9JeTNSbWZW37Fw3mVMB7MdnB/GsPCLPeJGJVL8FPIKeCvk8NiHfWqdT6j16hnuZw62hcFzFuUd2Bz4JLpLjkmT+OzDRXYcIQ+3mxXdrVhETIWi9oEM++U= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1771229160; c=relaxed/simple; bh=FV+51e9iYc2xrJcEjK2on6n19ycaSuBPBpOmqNhcq2g=; h=From:Date:Subject:Content-Type:Message-Id:References:In-Reply-To: To:Cc:MIME-Version; b=lHl5PQjXF+7wgtC3PuaU9nKSw1ZGjcsjRUc9UbQ1CyQwBajpi7MKy7n6hw7lainUYaJELQt2EoosqXvUJcn/EFKiU/IyorZb6qF+xL2XcYb+407Jhsnj0klGwGMyLDCrKrkDGjVHuJW1oDsL/cqqB7TlB03dFnPl/HSSP/PVYFs= 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=hFoRr7b4; arc=fail smtp.client-ip=40.93.195.17 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="hFoRr7b4" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=T6eU2+ff/CnwzoBVJ4R74HJ6h02GSEOptNd1AWkT/24vxeqldYp9XbI7F5UaMDDbEy8wzbiPCEIA0j1g+i1dTe7M30vz+uxtYwtfGqhtk5e43jUeSbfpMINOf5lRdoRFVUVagaeu+S3ley/NzkfarzWQrOTaCPmxnfnLYJ4Brrajzc8AoIY+KsoMQGgPET7mnUR4iuTxdJ/Ppy/nRJXuY5jd3MtbfZsYhsZZ9r21SV4gLG7V6stExh/OyfjJb/twlSBfCxpja2dO4o3iBA/GxZP6NP61ze9cWlRv2K/M3At7EOdfrbgGe+IDAlIH7I9I432XipHfkeY6yOVe+sG39g== 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=urroqqKTYxT/UxVao2Le2seml19syv3eilGToqEZXeU=; b=N40k12WMk3oRJhkZC3l+/utFlHzW7UfYmAB3g5vReh8RyltRJyiZimxfjQMSutqa8CEOWiRtr0+VMfLCoz7Ifk9nbT+5yewDPFsYtfz/GeHLZOhPP/DMIIebYDxF/oRa1+C2aJyWmNgNdorqVOM2tTSYZt8H9ixBH/w5x2tUmg6YmYqyKOaWxZcfgq9aE/Pm7FGUzPToxp/ej7qwbiDWB3qYXmTAx2i9Lzy6G50aYm4MWYQ7FtXIWiOFQpv6FVl8haI4z8ZnNPZThdAEttTygbAx7VAPTvw4MtNB1d5NRtw0S77uBrmduVAivVb1wlQxy7xT3oPxaANt9lyqF6hJWg== 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=urroqqKTYxT/UxVao2Le2seml19syv3eilGToqEZXeU=; b=hFoRr7b4E6qjEfW+AQ3CX7TTXc5sABNOv+YzvJReQVKLfXJ/udQJw6I01mWfW9hTvy4ZV3LfzifPVx0jNnxN4hgUpICAfjCuXbhogIV+8+lKhdoM/4wdlf41ZveaD3hK4nHR/2LEU8QH0/kRWEZriLY0hD9pGXbRXO8zfGBvcJ7AscD7Xn2xvAn3m+Bj+0V1cT9lpw/0DH9oFV5f+XnrzPssOvnIZBvrIHWBt4kfs0yQcDe624UJXapyysPYDc6g6ngIW/rL8lHvnoZq7m/ip02z5fSlHKmMQ1UmWDSzKjaPBPUMMPa2+40RUzejRBlNYXC4hhxIyVQ2Exp//7oiDA== 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 BL1PR12MB5732.namprd12.prod.outlook.com (2603:10b6:208:387::17) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.9611.13; Mon, 16 Feb 2026 08:05:41 +0000 Received: from CH2PR12MB3990.namprd12.prod.outlook.com ([fe80::7de1:4fe5:8ead:5989]) by CH2PR12MB3990.namprd12.prod.outlook.com ([fe80::7de1:4fe5:8ead:5989%3]) with mapi id 15.20.9611.013; Mon, 16 Feb 2026 08:05:41 +0000 From: Alexandre Courbot Date: Mon, 16 Feb 2026 17:04:45 +0900 Subject: [PATCH FOR REFERENCE v6 9/9] gpu: nova-core: use the kernel `register!` macro Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260216-register-v6-9-eec9a4de9e9e@nvidia.com> References: <20260216-register-v6-0-eec9a4de9e9e@nvidia.com> In-Reply-To: <20260216-register-v6-0-eec9a4de9e9e@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: TYWPR01CA0013.jpnprd01.prod.outlook.com (2603:1096:400:a9::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_|BL1PR12MB5732:EE_ X-MS-Office365-Filtering-Correlation-Id: 56297488-a338-430b-ba66-08de6d322d35 X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|1800799024|10070799003|366016|7416014|376014|921020; X-Microsoft-Antispam-Message-Info: =?utf-8?B?TWkrQlFzUTQ4ZFJBRWNTeDBJM0xwZ2FEV29rdURQbXdOdjlLRkpiNURaODBz?= =?utf-8?B?QUhEeEg0WkxZcU92V0wyc2lPT09VdlZTWmpnQm1Dek5seE1lTEVpekZNK05w?= =?utf-8?B?aHFQU0k1TWxnS05sOS9MNmF5bjY0WEVhVWg0MlFlZHZCYW9qNXNpSXBhcmhv?= =?utf-8?B?TS9Ma2dhRWRtVlFudDFXcGdteU5yRDNGcTk4eE05OU8wdkVlemdvWW50dU5a?= =?utf-8?B?TE8ybHQ1RzF1QUpoYWdIOUdkZFN4QXJmeHFUbG5xdEVQMzFTdHFodEhWenFS?= =?utf-8?B?czZpWDltMEg3L2NEWVRmTVRvQzAzZk1PakJJakY3M0pFMEQyazVZamZhcVl6?= =?utf-8?B?UkJmSGV0YktURHJPQ0llVjVUeWFXZExYSXdKRHNFdEpjSFBQY0U3QmdPbDJW?= =?utf-8?B?R2Zod2FTQ1FSa0NIeDNXQmtqQmc4YSs3NnpxOGUvTnlVZXNnMStFOFZReW8x?= =?utf-8?B?SzM2MHdZRHBpMEJQRnJ3N2Fzc1lyZWxyL2c2L0xKaG5qWVM4OXMvNzFMT05G?= =?utf-8?B?VmNvMG5ocVcwTE9xN2N0TmFWbndjNVo1UDl1V1pJdnNnZDU0OC9CMnl6M3p0?= =?utf-8?B?OTdRaEJvcEdXN0s5ZHJOazJzWCtlaDJBL2tEYXhpdXlGeFlWNmt5Uk45V0Fn?= =?utf-8?B?ekkwNko3MzhSMnVtTXlYUTQ2aUJmdWNETTVZcUJTVGlCOFZuekxsZisxRFY1?= =?utf-8?B?amtYMldnaFFLNEZNVFRabTM4YTA5N1NtMEdzOHRUaEFFa1ZXSElmSWJSYzNL?= =?utf-8?B?ZmlyVVZFWW14Q1hndGpqK2o0VmlFTEErcmxYeUk5OThpNkpUaWpGdkh6Ulkz?= =?utf-8?B?L29YVk1EaUZGY0ZseGpVL3NyYXhPditybWViT3JHbEZ3ekZiMWFDT3Y2dS9S?= =?utf-8?B?b21lNnc0MDNCWnpGUHU0MEg5dS9HeElnOUlTN1JwcVBlWTdVRWZxQVFneFJC?= =?utf-8?B?dG9XazlTVVduUGU4TmJaUlZNM3RRSmM3SVZCc2ZGMGFPRWR4QlVsSnFkNzd0?= =?utf-8?B?YXFpVFdZanlTek5GMzNWRSs3Q1I3b3UvQmpjejB2UnVBRXJKeFBGQ2VRQUpV?= =?utf-8?B?YlM4dldiTVFEY0FBRWxsSHVDN2ZSdWRoOGNZdUEzWE9SQXhaeWdmN21WUHha?= =?utf-8?B?RmJXS0FUSXJWTkhPanhCQS9aaXBXemdQSkJmZUxFTXhRSFg4cDRkdmtObXVC?= =?utf-8?B?NjJ5MzF5dFB1dVZqNlVrN1JwZVhFT1AyMzRvQzZoNkdZTFovbzQvN0JpaERi?= =?utf-8?B?RE1RZEYvdnBKMjMwSVd1NG5LeDk0bG1BVVM1Z3NaQ2UrRnQwZHJDYW9BZ0lM?= =?utf-8?B?TFZSUXI2MVRMY2J4cllXbnpUUWdzRTdENUgyUmNLUmxPLzNtL2xlNzFxcWhP?= =?utf-8?B?RjU0QVd2UFNTbWdKUWx4endZc0RTR1dta1VKWGQ0cHdYKzlEcithb2tTOFFQ?= =?utf-8?B?WjRKc0N2MEFRMlZpOWhKUGVjWXJ3eTlZV0FTdm16VVZsNnhlbnVEai9yL2wv?= =?utf-8?B?OG5jenVEK0s5Q0VkSk9Cam9WZmh3U2xoZm1YK1pjTmVvOWV0Z1VWRUhQS3FC?= =?utf-8?B?b1ZxV2VCWmtleHFjSmpLSWt2RnkzUTJ5cmlZanl5cTJnd0RRTnhOcjR5eFV2?= =?utf-8?B?cHdIbi9tMm4ybzVZRUdvSFZUanowYUoyVmphNUlVWURjT2t2b3VJajkrZXhy?= =?utf-8?B?V1JhZy9sM2dPRmNtMTZ0cmtBdGlNblFiWlZRaFhyMUxUbWQ5Y3R1ZTZoRWNJ?= =?utf-8?B?RTlzVlFFbVJzRmc1RGJKczlyWVk5S1dvU0h6NDhWeFVvZkFPTmNSbHE1SXR3?= =?utf-8?B?ZUVMdkQ0TkpBdnVhNG1idEN1YkJPSEVreUtTTTUrVU9EaTc1M28vRlZtOW0r?= =?utf-8?B?VEQrbHpQNW1SYmN4ZG9UOUp6V0pMdGxWNUZDbjdQd3ZjUVA5R1ZUS2s1ZWpw?= =?utf-8?B?K1VVRTBtWFdnZ25aNUlvWXdBUm02Kyt6bk9RemRrbXNwOFhzL1NrQ0tqNUE2?= =?utf-8?B?SE1yUE92b2RMa3VqeVgrM3ZJZWxVQmlNeHZ3OE9yRWxTSjEyQ2FUNmNEYkww?= =?utf-8?B?VjE4aUVISThKMndHbTUzRXJYOXl4T0tiNTl4SlJhdnZPQTBkc3Q0K1VJZnVF?= =?utf-8?B?QThrMS9XOGJNMzR3Um5CSXQvL0hEV1VPVEthZWNLSDgxR0NmYVdxTnJsMkxn?= =?utf-8?B?RkE9PQ==?= X-Forefront-Antispam-Report: CIP:255.255.255.255;CTRY:;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:CH2PR12MB3990.namprd12.prod.outlook.com;PTR:;CAT:NONE;SFS:(13230040)(1800799024)(10070799003)(366016)(7416014)(376014)(921020);DIR:OUT;SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 2 X-MS-Exchange-AntiSpam-MessageData-0: =?utf-8?B?ZThHY21QRHFvWGFSMmRDaUFHbzJKOEJSbmk5Z3pQMDN1MStMNnY3clRuR1JE?= =?utf-8?B?VG82ZVVjSU9ZbGpOdVpkV0hGZmwzRFR4dVJ3TmIxNEFWam5JY0FQVlFSd2ln?= =?utf-8?B?c3czRUE3SnZhWU0yUGc1ZlFYcmxBaGJmSmJCVlI4cFdmSDFPZUtOU0NLSTVo?= =?utf-8?B?cE5XNXlYSU9VMDlqYnRKbUlsdjBWZ1czRHRuTW1nL3hWQ0E0N3BDT2tXSzl2?= =?utf-8?B?N2s1WEdDem9OUDBXcHFSdTBtVXlZZ1dUTVluYzZtSlZyc21zUVZDNHFydHJt?= =?utf-8?B?L3ZzRWdwT1FxczZKZ3ZlL2dYSkUycW9QR0Fma0h3ZXdKQ0QxM1RWTFh4UlBq?= =?utf-8?B?VTdmRG5TZ0hWanRKaTJWU0NQQWtJdXdHdGlRSzRSdVhYM0lLejU2U2cxT0sx?= =?utf-8?B?SFlDUVZKTzMwK1ZicmJGdHBUemVmTlFoKzgwN0J3SG1kbEZmSHVseFUwbjBp?= =?utf-8?B?R09EYWtQNWRrU2VJZUNmeTFydTNMckdYdmlXOUtGOWp1THppMnV1dS9ZdDla?= =?utf-8?B?cW1DNDBBTlhFYUs1L2pRUXh3REhXL1RQYWIraE9OYlUxQzlJRWZUM2pKU2lH?= =?utf-8?B?RkhoWjhRbHJGN2hSd21jcFN6WTJld2J3M0hrWFZteTVnYXV0c0QzZVA2aTE2?= =?utf-8?B?S3Qrekp3bVJBUlRPNkxpNFg3WFB2NUkyVTYwbEcyNUt4Z2lRYjdxd1M5dkpu?= =?utf-8?B?UnN6TGxlVGNvUGlzSENBdE1HbDJ0NE1ZV1BmU2Q4WmdsTXNyYlBnWWdMQkls?= =?utf-8?B?d0xURnJacnY0VzMzcHFMMjh3Q2NzVXEzTWVyTnNOTmkvYkVRRll0Q3p2ME9S?= =?utf-8?B?YTgxK2cvbjBoQ2hibTE1am13cjRzYnNiRExRY3ZjS1h6VENvUWVFdWhrME5t?= =?utf-8?B?SkJ4dlpRdHQ1c0VVM2pVN3FBNnZTUEtkcjJ4dy9JNmwyRUYzVlZuS21uS1E1?= =?utf-8?B?OE5DYXlDYVgyNkY3amJhRFdLOE9KVHNSblVwdjcwTjdMY0pDYzJ6WVZZVytm?= =?utf-8?B?emtoMWxFM0ZqaFpIQ2JRbW5nQkFXSjdwK3FublNKMjZHK2EzT2VCZWh0TVRS?= =?utf-8?B?b0lOc2RYcTNRKytXaWdRZVZrMVVtK1RWMHk4Tno5SmlCaU5IbklHUkMxNm9t?= =?utf-8?B?am15TlNuaUI4OUhucFI1RGwvam5lMC9tZXR4TU8zUUtJc0R4N3hFRFE2S2J6?= =?utf-8?B?eW1rUkU0T1V5ekp0d1ZuanlhVzZIV3lPcVVYZGIxVHBaQWR6V01ybVZLMERz?= =?utf-8?B?MkhuLzBMVnV5QlQ3VkNoMzh5OUdsZmVrajFlTzZwaktsMXdUcm1iaDViQ1Mv?= =?utf-8?B?QUhBenVpdnpIakt6ZTRCaW11WWE2OWhWcnVTYzBNL2wrTHNhcjBCSzEzL2gr?= =?utf-8?B?cjlIakpobGtQbmRWV21lMGdkRWJpeWJRaVBBZnpmdHd0SHdkOGRjeTBrTXJT?= =?utf-8?B?U0dIUUphckg5cEZaaFlTekVETWtZOFdHRzBaVEZwSmJUcGt1dGc0bFFmZnRZ?= =?utf-8?B?VUNzczVPdTZrR2NmNDhxRExYSkxveDFRbjQza2N1cGN6TFgrbjJxbkp5a0h4?= =?utf-8?B?WWFnTHN5dG9wWk5EUGZmWVRza2NRRVdUNGRlcFppcXVFdFRLWTl4d1JJZlFn?= =?utf-8?B?RExMNk5CclFaWmJuWk5PN3o5MTVwZ015NXpMMnd2MG85TjJKOTZOZ285Z1ll?= =?utf-8?B?S0xUV20yQ2thVFk5U0tGSHBDTTRMczNUQ0FvaFd1VjE1RXFzNFg4dTU2OU54?= =?utf-8?B?MXJjeDBJT0o4QWh0b0d3VEVOSEJxM0pyMkY0UXRBakZaZUtwdktNcmRJQWlI?= =?utf-8?B?ZHBWbjk1b2E0anluK3hJT1YrL2p2alg4WUE5bGxGTFhJb2h6K0RVRWlXVDNI?= =?utf-8?B?ZmhUS3MyV3V1OThnOTlUNkh2a2VIczdkcVJsSk1RYlkyZ1ZobkNzaVh2dWM0?= =?utf-8?B?N0tLUEw2OFhqVjdQYUhXQnJQaXVHdGR6cUhEVllJMHJ6bXptM2VOOTFjUC9j?= =?utf-8?B?c1dOb2IyRWVJZGJ6QisvQzJIaXA5YXEwek5FRjRxSFpuK2hEQWhqODVCbk5X?= =?utf-8?B?SWlRZHNGWDBLRmlacnF4c1VpQkFDcWpMWHdYVG8zd21UV2N3dUN1R0hoSUJP?= =?utf-8?B?ZENMNXdicXpqK0Q3RnN6TDBBcE5FaGhTYVN0TTZyWjJpcTBpWFFzdDNGd0g1?= =?utf-8?B?Nm02THVFZXFEUzNZajl2MmJOZ2w4dGdRM2dBWWRFUlZLMVdnY3BRTDlDck85?= =?utf-8?B?UlFtZkdBZGRIRWc2bEpZVTBhL0JPVmtuL0ZJcnJoYmJ0M3YzTC9ocXhqcG1w?= =?utf-8?B?bTlpVko3Z1FBYkFZWS9qdzV2b1FjeVFXUVVzREZUN3RkMUFHYXdFQ25DQ0wr?= =?utf-8?Q?zhBhpT1o3JxRh3jJFa0NFtrnmpT7V1JFXHhr/bONPLFWq?= X-MS-Exchange-AntiSpam-MessageData-1: dvEy+MxLhXhJNQ== X-OriginatorOrg: Nvidia.com X-MS-Exchange-CrossTenant-Network-Message-Id: 56297488-a338-430b-ba66-08de6d322d35 X-MS-Exchange-CrossTenant-AuthSource: CH2PR12MB3990.namprd12.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 16 Feb 2026 08:05:41.1951 (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: Tn2o3R9RX3SoCa6VeaeWc2DmQMx+u6g1AspASLpfDNKW0a+SifuK6pk4Xj17jYRZSc2AGDI4pybsWyQ/2RrMbA== X-MS-Exchange-Transport-CrossTenantHeadersStamped: BL1PR12MB5732 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 | 249 +++++----- drivers/gpu/nova-core/falcon/gsp.rs | 23 +- drivers/gpu/nova-core/falcon/hal/ga102.rs | 65 +-- drivers/gpu/nova-core/falcon/hal/tu102.rs | 11 +- drivers/gpu/nova-core/falcon/sec2.rs | 17 +- drivers/gpu/nova-core/fb.rs | 6 +- drivers/gpu/nova-core/fb/hal/ga100.rs | 40 +- drivers/gpu/nova-core/fb/hal/ga102.rs | 7 +- drivers/gpu/nova-core/fb/hal/tu102.rs | 22 +- 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 | 10 +- drivers/gpu/nova-core/regs.rs | 544 ++++++++++++---------- drivers/gpu/nova-core/regs/macros.rs | 739 --------------------------= ---- 15 files changed, 565 insertions(+), 1226 deletions(-) diff --git a/drivers/gpu/nova-core/falcon.rs b/drivers/gpu/nova-core/falcon= .rs index 37bfee1d0949..bd3154a140ac 100644 --- a/drivers/gpu/nova-core/falcon.rs +++ b/drivers/gpu/nova-core/falcon.rs @@ -12,7 +12,13 @@ DmaAddress, DmaMask, // }, - io::poll::read_poll_timeout, + io::{ + poll::read_poll_timeout, + register::RegisterBase, + Io, + IoRef, // + }, + num::Bounded, prelude::*, sync::aref::ARef, time::{ @@ -30,7 +36,6 @@ IntoSafeCast, // }, regs, - regs::macros::RegisterBase, // }; =20 pub(crate) mod gsp; @@ -38,11 +43,11 @@ pub(crate) mod sec2; =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) } } }; @@ -50,10 +55,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, @@ -62,16 +65,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, @@ -88,46 +91,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 @@ -141,16 +136,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, @@ -163,24 +158,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), } @@ -188,21 +181,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), } @@ -210,33 +201,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 { @@ -252,10 +234,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). @@ -263,14 +243,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, @@ -282,34 +262,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 @@ -318,13 +289,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). @@ -394,8 +362,10 @@ 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(regs::NV_PFALCON_FALCON_DMACTL::of::().zeroed()); } =20 /// Reset the controller, select the falcon core, and wait for memory = scrubbing to complete. @@ -404,9 +374,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( + regs::NV_PFALCON_FALCON_RM::of::() + .init(|r| r.with_value(bar.read(regs::NV_PMC_BOOT_0).into_= raw())), + ); =20 Ok(()) } @@ -475,36 +446,37 @@ 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(regs::NV_PFALCON_FALCON_DMATRFBASE::of::().init(|r| + // CAST: `as u32` is used on purpose since we do want = to strip the upper bits, + // which will be written to `NV_PFALCON_FALCON_DMATRFB= ASE1`. + r.with_base((dma_start >> 8) as u32))); + bar.write( + regs::NV_PFALCON_FALCON_DMATRFBASE1::of::() + .try_init(|r| r.try_with_base(dma_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( + regs::NV_PFALCON_FALCON_DMATRFMOFFS::of::() + .try_init(|r| r.try_with_offs(load_offsets.dst_start += pos))?, + ); + bar.write( + regs::NV_PFALCON_FALCON_DMATRFFBOFFS::of::() + .init(|r| r.with_offs(src_start + pos)), + ); + + bar.write(regs::NV_PFALCON_FALCON_DMATRFCMD::of::().set(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), @@ -524,9 +496,9 @@ fn dma_load>(&self, bar= : &Bar0, fw: &F) -> Result } =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(bar, fw, FalconMem::ImemSecure, fw.imem_sec_load_param= s())?; @@ -535,9 +507,9 @@ fn dma_load>(&self, bar= : &Bar0, fw: &F) -> Result 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( + regs::NV_PFALCON_FALCON_BOOTVEC::of::().init(|r| r.with_val= ue(fw.boot_addr())), + ); =20 Ok(()) } @@ -546,7 +518,7 @@ fn dma_load>(&self, bar= : &Bar0, fw: &F) -> Result 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), @@ -557,13 +529,16 @@ 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( + regs::NV_PFALCON_FALCON_CPUCTL_ALIAS::of::().init(|r| r= .with_startcpu(true)), + ), + false =3D> { + bar.write(regs::NV_PFALCON_FALCON_CPUCTL::of::().init(|= r| r.with_startcpu(true))) + } } =20 Ok(()) @@ -572,26 +547,24 @@ 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(regs::NV_PFALCON_FALCON_MAILBOX0::of::().init(|r|= r.with_value(mbox0))); } =20 if let Some(mbox1) =3D mbox1 { - regs::NV_PFALCON_FALCON_MAILBOX1::default() - .set_value(mbox1) - .write(bar, &E::ID); + bar.write(regs::NV_PFALCON_FALCON_MAILBOX1::of::().init(|r|= r.with_value(mbox1))); } } =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. @@ -650,8 +623,6 @@ pub(crate) fn load>(&se= lf, bar: &Bar0, fw: &F) -> =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(regs::NV_PFALCON_FALCON_OS::of::().init(|r| r.with_va= lue(app_version))); } } diff --git a/drivers/gpu/nova-core/falcon/gsp.rs b/drivers/gpu/nova-core/fa= lcon/gsp.rs index 67edef3636c1..2031c6e760b4 100644 --- a/drivers/gpu/nova-core/falcon/gsp.rs +++ b/drivers/gpu/nova-core/falcon/gsp.rs @@ -1,7 +1,12 @@ // SPDX-License-Identifier: GPL-2.0 =20 use kernel::{ - io::poll::read_poll_timeout, + io::{ + poll::read_poll_timeout, + register::RegisterBase, + Io, + IoRef, // + }, prelude::*, time::Delta, // }; @@ -14,13 +19,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 +32,19 @@ 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(regs::NV_PFALCON_FALCON_IRQSCLR::of::().init(|r| r.= 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..acc34f2a8e66 100644 --- a/drivers/gpu/nova-core/falcon/hal/ga102.rs +++ b/drivers/gpu/nova-core/falcon/hal/ga102.rs @@ -5,6 +5,8 @@ use kernel::{ device, io::poll::read_poll_timeout, + io::Io, + io::IoRef, prelude::*, time::Delta, // }; @@ -25,15 +27,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( + regs::NV_PRISCV_RISCV_BCR_CTRL::of::() + .init(|r| r.with_core_select(PeregrineCoreSelect::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 +63,42 @@ 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( + regs::NV_PFALCON2_FALCON_BROM_PARAADDR::of::() + .at(0) + .init(|r| r.with_value(params.pkc_data_offset)), + ); + bar.write( + regs::NV_PFALCON2_FALCON_BROM_ENGIDMASK::of::() + .init(|r| r.with_value(u32::from(params.engine_id_mask))), + ); + bar.write( + regs::NV_PFALCON2_FALCON_BROM_CURR_UCODE_ID::of::() + .init(|r| r.with_ucode_id(params.ucode_id)), + ); + bar.write( + regs::NV_PFALCON2_FALCON_MOD_SEL::of::().init(|r| r.with_algo(F= alconModSelAlgo::Rsa3k)), + ); =20 Ok(()) } @@ -120,14 +131,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 +147,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..cd4ac53e32af 100644 --- a/drivers/gpu/nova-core/falcon/hal/tu102.rs +++ b/drivers/gpu/nova-core/falcon/hal/tu102.rs @@ -3,7 +3,10 @@ use core::marker::PhantomData; =20 use kernel::{ - io::poll::read_poll_timeout, + io::{ + poll::read_poll_timeout, + Io, // + }, prelude::*, time::Delta, // }; @@ -49,14 +52,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..9c95733f1a48 100644 --- a/drivers/gpu/nova-core/fb/hal/ga100.rs +++ b/drivers/gpu/nova-core/fb/hal/ga100.rs @@ -1,6 +1,13 @@ // SPDX-License-Identifier: GPL-2.0 =20 -use kernel::prelude::*; +use kernel::{ + io::{ + Io, + IoRef, // + }, + num::Bounded, + prelude::*, // +}; =20 use crate::{ driver::Bar0, @@ -13,26 +20,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(regs::NV_PFB_NISO_FLUSH_SYSMEM_ADDR_HI.init(|r| { + r.with_adr_63_40( + Bounded::::from(addr) + .shr::() + .cast(), + ) + })); + + bar.write( + regs::NV_PFB_NISO_FLUSH_SYSMEM_ADDR + // 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`. + .init(|r| r.with_adr_39_08((addr >> FLUSH_SYSMEM_ADDR_SHIFT) a= s 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..58894fb870f7 100644 --- a/drivers/gpu/nova-core/fb/hal/tu102.rs +++ b/drivers/gpu/nova-core/fb/hal/tu102.rs @@ -1,6 +1,12 @@ // SPDX-License-Identifier: GPL-2.0 =20 -use kernel::prelude::*; +use kernel::{ + io::{ + Io, + IoRef, // + }, + prelude::*, // +}; =20 use crate::{ driver::Bar0, @@ -13,26 +19,24 @@ 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 { // Check that the address doesn't overflow the receiving 32-bit regist= er. 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) - }) + .map(|addr| bar.write(regs::NV_PFB_NISO_FLUSH_SYSMEM_ADDR.init(|r|= r.with_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/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 9b042ef1a308..ca2c153cf87f 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, // @@ -122,24 +124,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), @@ -148,23 +145,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(), } } } @@ -201,13 +201,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 be427fe26a58..154a2bc4655e 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, // @@ -55,7 +56,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" @@ -78,7 +79,9 @@ fn run_fwsec_frts( fwsec_frts.run(dev, falcon, bar)?; =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, @@ -91,8 +94,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 46819a82a51a..0b01515c39f6 100644 --- a/drivers/gpu/nova-core/gsp/cmdq.rs +++ b/drivers/gpu/nova-core/gsp/cmdq.rs @@ -16,7 +16,11 @@ DmaAddress, // }, dma_write, - io::poll::read_poll_timeout, + io::{ + poll::read_poll_timeout, + Io, + IoRef, // + }, prelude::*, sync::aref::ARef, time::Delta, @@ -475,9 +479,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(regs::NV_PGSP_QUEUE_HEAD.init(|r| r.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 ea0d32f5396c..63d448e90406 100644 --- a/drivers/gpu/nova-core/regs.rs +++ b/drivers/gpu/nova-core/regs.rs @@ -1,13 +1,7 @@ // 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::Io, prelude::*, time, // }; @@ -35,20 +29,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: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)?= ])? + $(@ $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 +94,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 +107,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 +117,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 +126,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 +186,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 +193,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 +211,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 +243,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 +264,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 +288,127 @@ 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; + } + + /// 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,117 +417,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; -}); - -// 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. @@ -437,15 +499,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