From nobody Sat Feb 7 12:40:41 2026 Received: from MW6PR02CU001.outbound.protection.outlook.com (mail-westus2azon11012053.outbound.protection.outlook.com [52.101.48.53]) (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 8A81333970C; Mon, 26 Jan 2026 13:29:04 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=52.101.48.53 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1769434145; cv=fail; b=n9v6RxVjP02JT2XzcZyx68ZO03Q6iOqMY73KYOdmXLij3QbV9mMFF68bU+J58e1HMAKruid10ty/v7oYcsPqCTCcFIWgrayFzJF3C1ZghL3wHwbaKT3+Bg4FoY8zg2HJp0lMnFHqwNI9UDes+qibOnDZ30coSdPTvIsKUWex+6g= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1769434145; c=relaxed/simple; bh=3K6nvH074Kvv6TOL3YT7lDASKr/Cw1XfaZ8pwnEV6iM=; h=From:Date:Subject:Content-Type:Message-Id:References:In-Reply-To: To:Cc:MIME-Version; b=IM8F4sbGoElf4tuGWI9IVwCmN56ZEVSPrv+5IUdvrvOgia9aii1ETg1J/JOjnsm4unWU9WTphuAkfzxrW6NX0lLm0Y/Q68pb0pqFaTQEVqRTMZt+ryVVW3zOtSlbaSCx3qEKJsjh0fNNR/M6KT+X0HcrYeoe7+7BXxgmSd+Ti1A= 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=uMAkhBNA; arc=fail smtp.client-ip=52.101.48.53 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="uMAkhBNA" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=uz4TCrDwd/R1rr4B/Jel+f2rOIFOyMJjKk+DF7kkLTdPgwuyK8y2qKaFXelHsIxil5CygYh9N4M6CuHpkZkUdUrN8PFtan1Ly7TlmLlR9WwU/zBAmoBPZQGyAk2FPNlUfISQh1aAPku0f/p24gPFy+LRr05aUIeeZhfOXXJS77v88G94+/BLXdzQDLPaPc7y5kzu17+vuFFAWftbG0yhyVYEKYUTWBHZoDOIZT/SG2yEqG6FgN8/AqXHu0IyQ+7iIV50P9hKWh0iiTl0UbxQAgxqH5bqgMJmzaShZlhecr3q5gTQD/fXY8kjdK4cYcHov4X7xEYCOjECfCdI9z9NLA== 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=MDeQpmkBsRJSKmuaBQCG2Kg68X0sFstTnl5x21LvRNQ=; b=RAPlt0BcaCUy0YAQPLjOZXGgebtKClXvV/ITnBE38zD81t5X7Jn86CvOXcmC76bQDejb+UfStruxURVRRrPahQJAGZpmiqzf6nnvYDC5DhXS98hFC8dg695GPf3NtmMe7hrzqaZokFf0RVlAtAZB/XL0mYMCCTnPtyW1H7I0rIzRvr23o9H7qTm7hexpWd0Ho5BdtGlcLpr5k+JNyrjW2s+yHjk6YnS2T0b0LthXb2HWPCC2lYvhvGMS23nMyV+C6Qtno0WBTkriGzC5H9LXnI5sE8ixFX+0i/AhRQIarnLawqGYWD4RNwn4ZwHfRLCPax7yVHVsRG04o0yXVvE6Wg== 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=MDeQpmkBsRJSKmuaBQCG2Kg68X0sFstTnl5x21LvRNQ=; b=uMAkhBNAGYh9gNyl6BYdDu7nFWw4qmsTLHzIAqx1HmfX5KH0Q7y4+IO6uCFDu5cVQkeNbRaEDsR4tskYICknX0AjsG3VvV2o2zZMFd1AeE8TNt4u8NIxb+PMAIgvXP60kzxi3T6fpngzVqkbhHvFHGYIDjCMZIKthmelJ7VTFzPLiPHxlSPI/utZ6saaaByI9yDRKkfucbUMXulDjIHFRculX5NXRi5fYOXu1pttzLTh2NJ8GKkX3Pa3z2vZrRuVQBjn02DPunlNUZTXDFX1SanXGJJLNtiKTudJEr1Zq1Qw6Evtq3ugL+44HFAX0at4n2H4WvpJg6qLJPoIU6ayng== 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 LV2PR12MB5942.namprd12.prod.outlook.com (2603:10b6:408:171::19) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.9542.15; Mon, 26 Jan 2026 13:28:58 +0000 Received: from CH2PR12MB3990.namprd12.prod.outlook.com ([fe80::7de1:4fe5:8ead:5989]) by CH2PR12MB3990.namprd12.prod.outlook.com ([fe80::7de1:4fe5:8ead:5989%6]) with mapi id 15.20.9542.010; Mon, 26 Jan 2026 13:28:58 +0000 From: Alexandre Courbot Date: Mon, 26 Jan 2026 22:28:40 +0900 Subject: [PATCH v3 1/6] rust: enable the `generic_arg_infer` feature Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260126-register-v3-1-2328a59d7312@nvidia.com> References: <20260126-register-v3-0-2328a59d7312@nvidia.com> In-Reply-To: <20260126-register-v3-0-2328a59d7312@nvidia.com> To: Danilo Krummrich , Alice Ryhl , Daniel Almeida , Miguel Ojeda , Boqun Feng , Gary Guo , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Andreas Hindborg , Trevor Gross 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: TYCP286CA0164.JPNP286.PROD.OUTLOOK.COM (2603:1096:400:383::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_|LV2PR12MB5942:EE_ X-MS-Office365-Filtering-Correlation-Id: 5f5c58a0-7138-4b34-630f-08de5cdedc91 X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|366016|10070799003|7416014|376014|1800799024|7053199007|921020; X-Microsoft-Antispam-Message-Info: =?utf-8?B?SmtPTWxGdkR6dzJ3elkzOFUrU2JpZHhHNyt5Um1ySStKd0JvN1p4WWs2TUdq?= =?utf-8?B?M1JRNEVtTDQxenZpeDAzU2VMN1lKYWYzTjZHeHNtNFo5cURaSTVrblNzMWdw?= =?utf-8?B?L1BoSlk4SzZrbVdyQ04vWStwWHYyU29USzNrYjZCTlBxU0lwbVpwR09xczJJ?= =?utf-8?B?YThIc3lsaTVodTlLYk5NOFJtSTFWbXRVRitJaWtwQkNhbWNKbm5XeEs1eVhh?= =?utf-8?B?c1JTeHM0bEtnQWovRHdWalVjcXFPUG5kejJtZFN3bXJLTno5MVNUY3VaM2JC?= =?utf-8?B?MVBtS3kwUEVwUHVKNlBwZWNWODNzbVQxVG1mNzRPWjhUSkF4azc0ZnQzT1Ft?= =?utf-8?B?bkZXQ1kzWVF4NXA3dFd2cS9kbzRVSFdTYUR5MHNGRUVrL2EvaVlPSG5vU1gz?= =?utf-8?B?TVR1bDRpSWJZLzl0YkpIeUxWUGJnUHpWbWRCK1pqby9rdU15SGx2bXRNT2d1?= =?utf-8?B?dk1GbUozelZ5ODJKN05TQ0kzckVydUpkV0RBSElHbkY0VklIT3FJaVp2OVVR?= =?utf-8?B?eFovczN5UktMZmRHUC9pc2F6S05RejRhTGhJVGRXVi9BbXEyU2c0WllrUmkz?= =?utf-8?B?amh5K3FhakR6MFQ0RnNSWkVxMUdGcG1la3B5VmZhMGw4TzRnNlA5UXdsQnFt?= =?utf-8?B?Nmg0dWV5N1JFSmRkY3E2dTcvd24wYjEyQUdkVjUyN1RpZ0lTNUZybUU4TDkr?= =?utf-8?B?bkxkbnQyNzlHWkp6ZVVlUEd6bDVlZUpGb2I4NytPZE5FRER2U2ptZTBZNTZQ?= =?utf-8?B?Y0NpQU1XWmNUWVJlM01yM29MbW0xQjR5OFA2MnR3cnpjNmNHaDRSNXZsUUhO?= =?utf-8?B?K2c5VlRyNTJlTEM0N0M2VzlMWWFnbUNzYTVVVWVsak5CcUdjYXZyOG92QllK?= =?utf-8?B?M0l0MXVwTGN5bU5STit2RHM3NldGMXdBLzBDMEQ2WDRUY1I4RFRIcjI1MnNH?= =?utf-8?B?QjdnY3dSRDhuT1NZT2Q3OWhFNmY1aGpKWDBxa3lDcVVRYnM1ZkdhTzljQWVR?= =?utf-8?B?dTZKZ21weXRlKy80ai91Z1BEWXl3L1VTT0YvR1hNektDOFdLazY1SU5OQjZL?= =?utf-8?B?QXpSRTlJZU8xdXIyanI2V3JoN3NPbFpVU0ZaSXJtYVVKRUxkR0ZEenM5TTNX?= =?utf-8?B?SlZsY0MzNHpCNlRZcVBPaHIyaVRDWTQxeTRYK0ZsN0JaL0pEZUwxWkRLYXlZ?= =?utf-8?B?RTVmM2RteEN2N3VJczM4VkJaNFpKallGb2FyaEQrYW1TY3M4SnlLSkJzczgr?= =?utf-8?B?aEtvMjVOWVZiNkFZNFBCY2NWNGVQVlUyNXpZc3dha2ZwZmdTc1JkZGY3MjJv?= =?utf-8?B?bEdiOFVOWjF0NnZZWnk2K2VJenJvSzdacDRBVGR0UXZqZWZRNmgyS3RZUm9I?= =?utf-8?B?ekJEaXN4YXVWanAwaXVsVFZmbUJZRHpkOE9FVEpDdFdBdlFsVFRKZ0FUQmda?= =?utf-8?B?Q2pjcFdRUFFCcUVmZ3AwYkdHeUdwVjNTcHhGNjROM01GYWZOcE01WDlZWlIw?= =?utf-8?B?bWdXc3V2R3pScjJHb05rcHptQmQ1YXZQWTV1c2FweUt4aEZSZXQrWFltWWhE?= =?utf-8?B?dHY1NHI5Ti9HNlRPQlVsTFhaWDE2c0hvMlV0K1lVbllhRjZTUEVwdjhZZzcx?= =?utf-8?B?QVN6NVBScGVzVHVTRWFUemxFaURjV0ZEcnVlN2VzeWRxTzU2RmNUYUhuc01y?= =?utf-8?B?U08xY01MMTF6TnNyelhia0swM05lT05OeWx1Vmw4NWluNDdZaGFKSnFTaDJE?= =?utf-8?B?ZXZJU016VHdBR0dUQitKZXhrTW5zT3Npa1FyMjBpenNvSFAxMlBZczF1dUxW?= =?utf-8?B?UERBQmsweTBLdzQ1ZUQrNHNwM0tvQzZLbHBsUSsrcm1vOVRibUE5dzFod1ls?= =?utf-8?B?TVB1TnNPMFEvVXo4dzJKeXNCYjAyK1UvWit5M0JKSVBXbUtPN0pvdVBPZTFJ?= =?utf-8?B?UC9CNzNIR1hLbm5xQy92UXhTZ1RVSmZWcUNJaldmTHROYWNLUi81YWQ4UjVP?= =?utf-8?B?Um5wRWJtbTB6ZUdLdW94eFB5NHdKcDgxOVVJSnBYVXFVOFI3RCt1Yy9iNUlo?= =?utf-8?B?VkxEdnNWbGFlSUdQRElnQ1VvSnZmSkNNREhvMXFONXJNblphUFlYZ2RqVWgw?= =?utf-8?B?Tjd3L1U0cTZ3UW1QQ0VWR0FjOTFXbHA5OWFXV1pjd3NoZUd5TXo2R3MweC93?= =?utf-8?B?UVE9PQ==?= 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)(366016)(10070799003)(7416014)(376014)(1800799024)(7053199007)(921020);DIR:OUT;SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 2 X-MS-Exchange-AntiSpam-MessageData-0: =?utf-8?B?M1FvRjByWHplWnlZY25PQlU5bzlhbWFhODBmK3BQZ2d1QW8yT1BKSXlnSTQ0?= =?utf-8?B?WnA0RnUwaW80YWJiMnd6dFJoUUtEc3Q0anp0VjRrZTZCTzhSQVlkOW9HbVdD?= =?utf-8?B?YVlFTXlqNnNBMkRxZFphNlEvbnVCTkVkL0xNZ2R3T3NGUDN1N0FXMHU1Y1JJ?= =?utf-8?B?OU13VkI5YWxIVWR5WHZRaG1nWjVlV3dnRjMreGhkWFgzTVppK1kxU3hwZlRs?= =?utf-8?B?emY3b0xrbkk2L1kwQ21USUZ0TEEyR2VjV2M0UWNNSXJYVXJ5ZXV1clhYQWhY?= =?utf-8?B?K3VXM2MyZ3pqazhWemZvUmwxNitlaXQ1eXE5MjFtbFhWTjJ2YU5udmw2SHdC?= =?utf-8?B?Njc2TERFVjVsS3BiNWt1NUlkVVF5Sjk3akpXL0gxamEyaHpXeGVraFRDeVB2?= =?utf-8?B?dnYvQkl4M1VHR3JMQ0FFbVltcHpES1kzeURUYkJGRC9YQ0o0NERGVjJKNHRo?= =?utf-8?B?bUpTNFdSamtxYTdDb1V5Qmc1VXFlU0RlQkY2aUNSZDdiTTlCZmpoYXQ0aENL?= =?utf-8?B?QWRRUkdiSFIyVmxtV2dGWXdCVGZDM1lsdit3T1NIY1NRMmhnandlWUg5Z3Vi?= =?utf-8?B?ME5Hd1RKMVJJbkxGcTBRZm1QNkM3d2tRait4TzI0S1BxaVNNSE1HcW92Tyts?= =?utf-8?B?MEVjU1FVZ1Q4bURMZnpZcG9IR3ZSWmZ0Tm5SMUcrYzh5ZXU2QVc3KzlnSEdY?= =?utf-8?B?K3dNYzhMV2tQYWZKOEY5a0RCaExaSHVyY1hFUmV2bzcrazRSck15RXhxMzZX?= =?utf-8?B?enRtUEdZLzhQTGdaaW9OZzJ5WE9Ta1ZlZFQxQUdleHhzeEZSVTJBZjdzc3dW?= =?utf-8?B?bU9FYm91M1FrTE4zMUZmcTkzVDJxa254Vmd3WHRNUHY3YzFKU0FGakNKay9F?= =?utf-8?B?VnpPTVNCbE9obC9rYi9ZcW5adTZyaGtMYzBORVBRYlU0cm1mTW1qbXIrOExK?= =?utf-8?B?anYyNEpEY29PK2Z6SjZaOGlodEhlSHZuekQvRm9vMFNPTHNsZVJSam04TUhl?= =?utf-8?B?eGJkNVN3RGZkeTRFT3VXeTNTZnJTQnFzRVl2Yjg2bTlOOU9Wbit0TGVKRWZx?= =?utf-8?B?UklzM1RybS90VTZEdXZKNjNvT2hVSjBvQjI5ZGFGbkdMZ0ZLdnF3Y1VmQXJ5?= =?utf-8?B?MmtPYURzQlo1bVQ1cFF2cytta1JpcmtjLytsYTdpbzVmOTUzaWhGcGZ2MnNi?= =?utf-8?B?U1JqTHM2czVSdHIyMVppSzI5N1k4Mmk3THJ6eXE2VGFBbSt3NzRHVDR1MTFC?= =?utf-8?B?OTByZVB5bGVudFZZRDRYR3pvYVRtNFhTZUY0Zko0b2w1elV0YVhTYis3UDVo?= =?utf-8?B?VEJEdjlSMzQvZ3dYb1pxUDFJSUF1NThibHk0Sy9xdjF3eS9VZHMwbld5NFJN?= =?utf-8?B?NzZaNmw2ZzhzbEdna250LzJMMUx2ckVrQzlYTjk0YzVGK1pqZk95N1ZkSG1n?= =?utf-8?B?aEVJckxreHNUczh0OVduTUZkQkEwM0UwUW1LR3dzZWxCdU1tRTNlcnRqbURW?= =?utf-8?B?UFpQSUNvV3FWTVBnOXcvRDJDNE8zSGlwN0kzODlSSlkrUFBqeTBjQ3h3cXpL?= =?utf-8?B?c1h0YmFHL281MytveUw0QWpxeVBWNXhjTkxncVdTMTV4emNsSUx3dlA1bjlV?= =?utf-8?B?dEs5aWRqc29OaUNNZXFCRTh4cFN6VnduTG9SYW5vejJ0M0dMcEIwS3pZOXdC?= =?utf-8?B?U09oM3VVU2VleENjWWljb0cxc3M1U2Y1NUIrRkhQQmFwck52a1cvU1UrTFBp?= =?utf-8?B?UDJnRTc5b2VCWjlZaXRpaGJEanZWdlpDb3VnRkIvSlgybVJkTkhZRjNwYzJr?= =?utf-8?B?WEVQV2pGbHhSOXVkVmhXWEtaQnVsc2kxaENkWU1XQUx0c0EwOFQ5OHRROFJa?= =?utf-8?B?QTluem1xUnVsa2lEdkVCQkZyeFN4VHR1R3NWMGtmTlNwSmhDSjZTQkk2L052?= =?utf-8?B?OUxETlV0dGNiL2RxRU9NMVRkV3Y3V0NKUlc1a1JRNkNISUMvSWwrOUI5WUJm?= =?utf-8?B?cnBUSVNaTWxXaFhQeXQ2RFZHZWsxQjl0UHd0TERSdTV1aXNGV1M3NnpmNWdX?= =?utf-8?B?Ly8rUFFnVmRheUlwTS9Pd2JrRFRZNzRDeFBuNmpqZlBzTHFIdUoybXpjVjJT?= =?utf-8?B?SVBILzlWK3ZkNmRUcGllS2RhWVVOdWpwNnJQVlo4ckhubnhzdWxUV29Ub3RZ?= =?utf-8?B?ZHVZZ1VyNklXNU9WdER4Mk8wNm1GdU56V1BTeXQwdlpaaW84UjA5VnlXNVNO?= =?utf-8?B?Y1NjQy9xUVFXdGk1VWRDdjdVckxCTUYvKzMrd0ErZjhhSHpZY3BDNWo3aVM3?= =?utf-8?B?VHJLdkdVT1pRcVF1RVpZNEYzODl1YWU4YXE5ZXBUVmxQRTJ5dk9GaUpobWM3?= =?utf-8?Q?AjEmCumDOIWUN1bEpVWXEaDExKtiUBNWH0cK7TNIbfD3u?= X-MS-Exchange-AntiSpam-MessageData-1: n5SCvdYN6w7Kcw== X-OriginatorOrg: Nvidia.com X-MS-Exchange-CrossTenant-Network-Message-Id: 5f5c58a0-7138-4b34-630f-08de5cdedc91 X-MS-Exchange-CrossTenant-AuthSource: CH2PR12MB3990.namprd12.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 26 Jan 2026 13:28:58.8314 (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: jNii5TvKizJsfxgAh5SpmsWFELlMk99sPr6GeH05vgwgUU0YlsHIEI9LIq1oFNUAoBbVhwNhWrOCWERe2g3ukg== X-MS-Exchange-Transport-CrossTenantHeadersStamped: LV2PR12MB5942 This feature is stable since 1.89, and used in subsequent patches. Tested-by: Dirk Behme Signed-off-by: Alexandre Courbot Acked-by: Miguel Ojeda Reviewed-by: Gary Guo --- 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 6d637e2fed1b..122ad64880cd 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 5037f4715d74..4637aa11e870 100644 --- a/scripts/Makefile.build +++ b/scripts/Makefile.build @@ -312,12 +312,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.52.0 From nobody Sat Feb 7 12:40:41 2026 Received: from MW6PR02CU001.outbound.protection.outlook.com (mail-westus2azon11012053.outbound.protection.outlook.com [52.101.48.53]) (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 205FD33987A; Mon, 26 Jan 2026 13:29:06 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=52.101.48.53 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1769434147; cv=fail; b=YWmk/bGT5yeN5YJdflY3L85L+drkATxu8L52Xb85kR65X9UXmdijoUs3GpQpmOnoIF2SExeaXnmWgrpUP4oiBkuBBA1ZeS+MWDK8k6XwYcK55DUXmRqUTDnOFe3yyyvKGQgeSS66764070e+TMkk6f03hdVi3zpC3LBCPrpMul8= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1769434147; c=relaxed/simple; bh=94a0GfIIcpNG4qFW/FtzPoI4PHKALm6qq5o403n47EI=; h=From:Date:Subject:Content-Type:Message-Id:References:In-Reply-To: To:Cc:MIME-Version; b=YBQ+/yKwOfsO5MP9OQydNqDHFN3qu4t6id4G/bNcEh/idTcsDCBdC9mRLSNmz7KPqCzJGOwfPTab7QqYrFnpz7fRsmk8AoXlXFjLcT8vBjBLwAh6MW8DJYugMUFhthT5acc+6SHMdYur52WbkBb0M/hZukKdaxuX3lFC77EJSiA= 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=d2GSHRlN; arc=fail smtp.client-ip=52.101.48.53 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="d2GSHRlN" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=ju5IFLwBjWTyfa5dKMhaSBPe9VYaP0cUrJJQQ0lAXNF4AyXqFYJK5GxclI+5BCWhA4/2O6263CC/8/qqbnxIeKRfga/U9T4bpu47yJpQO4G2X1NQLvxL/QR9ZX06EF4LItEf5jhn9VNjJtorfhwvyKKuEuuGwhkhIbRLMf9oY6KFAHQRM+XGLbFn8M1Ai1/12GL1XEd0GM1HUH9t06ldwNciobefbMjeVgbcCqyTZlH4aTJAReq5WlZnRCJG1jtu+2QjXuNPAgZzUBunUq7kn6gpeZHkDhiwPbxyRUdYjk2FoCZf6fAxzSpUrTOx9EevhRQGgWvl3CvwExScn+GHbA== 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=idq7gFyxrdFRzym8TMUz1tq5ZeWxC+YNOQmdhq/3BVk=; b=L465GJ59CAi8Ixaer0cyAfUZO5OSlxQBXsbVkgVlVFxa7nBdOOZ5tYOSOO0bYM86lGlvNHfMplNlnx25PNBTymYDKAP4sghDHifOP9GRRC2J8NaDGxseRmqNZLSWaEcBZeW8fDFIRdaqQeGZIVmciynNn9aVpHCJtTqHp5tcs5KbX/NQQp3icqauQ0CKsxK9cUqsdjGhaBLQQM0Ku3YveXMqRbURSKHUrFdXbBikxz+IthywC8maA6H5lEx8NZV02+3QDGHVmOtIFhJn7JOUod56ZFqP0Z+gHjr2rzv+sRVbQ6wsxgQy4GhXRUfdm04PWwTDQw5BEYzFklPwjyjRcg== 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=idq7gFyxrdFRzym8TMUz1tq5ZeWxC+YNOQmdhq/3BVk=; b=d2GSHRlNMiryRj0Fks2azcn7mh7hunDPoxjrKnUajZleTnwjyybIpsSIAXhqkA8kJi/hRyBaUPKFSksCy3nFVsxsvk4qt4u9T6lgoRGJmT56eMZc2QWzgmV2+79P1lkw113p2ODClSiCQ9CPxP2iJ///Q2tjGCHmb94orQE5RMlrSeIDo/lSitQG3l4jmmR+cXXFNcjv+wAv6dToJUsCpCX1PHV8E/KnSwvTo7qrZrKEu42g9u3SY3aKvv9FmE1i5TKfHhabLenqCMR2rPvsYnebo5+tyTGsd0OoLtS1U5c7kJseBwT4W750ricjRyLj23RaRRqLFhmBmywpw7HzpA== 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 LV2PR12MB5942.namprd12.prod.outlook.com (2603:10b6:408:171::19) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.9542.15; Mon, 26 Jan 2026 13:29:02 +0000 Received: from CH2PR12MB3990.namprd12.prod.outlook.com ([fe80::7de1:4fe5:8ead:5989]) by CH2PR12MB3990.namprd12.prod.outlook.com ([fe80::7de1:4fe5:8ead:5989%6]) with mapi id 15.20.9542.010; Mon, 26 Jan 2026 13:29:02 +0000 From: Alexandre Courbot Date: Mon, 26 Jan 2026 22:28:41 +0900 Subject: [PATCH v3 2/6] rust: num: add `shr` and `shl` methods to `Bounded` Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260126-register-v3-2-2328a59d7312@nvidia.com> References: <20260126-register-v3-0-2328a59d7312@nvidia.com> In-Reply-To: <20260126-register-v3-0-2328a59d7312@nvidia.com> To: Danilo Krummrich , Alice Ryhl , Daniel Almeida , Miguel Ojeda , Boqun Feng , Gary Guo , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Andreas Hindborg , Trevor Gross 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: TYCPR01CA0152.jpnprd01.prod.outlook.com (2603:1096:400:2b1::6) 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_|LV2PR12MB5942:EE_ X-MS-Office365-Filtering-Correlation-Id: 3913a41c-6958-4f18-6d2e-08de5cdededb X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|366016|10070799003|7416014|376014|1800799024|7053199007|921020; X-Microsoft-Antispam-Message-Info: =?utf-8?B?elpTS3djL0JvTjVrNXFNcWN2LzFZb2dNenZhSG1wK0xDUlpHQlA1V1cvRThh?= =?utf-8?B?QU54amZ4Z043cWtVaTM4Y20reFBCMnRKd3AwLyt2dWpJRXB2bHRHY1A3UDhl?= =?utf-8?B?ZVV0K1daYi9mK3QvSFhWZUVWbzcvSkdsZFJQK1dLWnovRGpLMyt0QnZBdE5Y?= =?utf-8?B?ZngwekV4amhyUWUwNWhkS1ExL2hYbGRLUlIzRHQ0NElmRzdKNmlBVzE2WHhm?= =?utf-8?B?MTY0RHRZUXl3dFphT1hUeVk5d0lmaER0TnhQVTgrYkFseXlEMTh6VGdZSE5F?= =?utf-8?B?Z2JCVUN3bmRUY25YV2k5NlgwdmhDdXpCVmJsU1RoSFlTTUVaak8vSWVjbUth?= =?utf-8?B?cUpOa3lCa0dWdnd3U29DRUpXUDFxdjhRWlN2OS96c3dCUU9BUitPSG03MzFL?= =?utf-8?B?ckJkOVZ5MVQ1dnhidndZb0hLY2V5T0VsR1dNenpvbmRNc0o0ZE9xN3NwdVNS?= =?utf-8?B?U1lkc2swdDAxYS9YQ0ovNHcrR3pZSEhYeFhlL3MrUk56VDZDZEQwUW9BUmxt?= =?utf-8?B?ejJjLzl4QUtmVjBaQnFpMTJsY1lmODY4SU5TdDdidnFvQkZ0WTU5WDdIdVBr?= =?utf-8?B?TVpGUjBSK0Z6TTF6aGxTTXhDZGh6TzZENTdQZDFNY0gwaHA0NkdXZDZPQWRl?= =?utf-8?B?OVVaSzFKdDFtTnZBeHVwRjNHUmt6SnVBMXEvbkFDTGlDaTVqaEhkeXo0VTdm?= =?utf-8?B?TUlUekFiT1p6bzJlN3gwVHZ3Y1l0S3pPcGJjMXZteUFMRWVBQTR0NndhYkVT?= =?utf-8?B?c0h0dlFJTENUQm94YWZWdnY5M0ZhSmQyalRteTZKRnlnLzhZN2hJTFRIUktQ?= =?utf-8?B?MXI0clZtTGNibmtML2JqY2RYUC9OTjgxMHlEWFBIZ1hVUWdLT2piQVFoSUVW?= =?utf-8?B?azFGVUlrSCtvTXpGV0ZaSE9Hb2VrbXRDNFY5eUJPT2Z4QjVEVnJYVXFFTUVq?= =?utf-8?B?TVVSZ3huSGtpUnlaN25ud3lsT2s1SmluQ1dkQ0d4eXZLTFR6Z1NxUnhoMnJq?= =?utf-8?B?UVkxb1V1MUhKblhjcFFZRUFnUktuMkRnTFBoRFcwQUVJQm5QbVgySmc5V2pM?= =?utf-8?B?czVyYTN2V3doZGJZaDJGMU9scFJxaG5iQ0o2TmNJWnJPTHlxZGV2UTVjUlBN?= =?utf-8?B?SzR4cFJ0VVlOVG8vQng1VVJ4WXBYcWNyTFRFS1VOTDRaL05sNVJzdERlNm0v?= =?utf-8?B?NjBnZU11aDcycm40bVhFRUkzUXFRTlFNbzA5Z2hhbnBjZTBhQ2U4Ym9acnpX?= =?utf-8?B?aDQyeXpVSHhETi9BblhXTy9BYS9oZkNBUGNkU0lNc1k1V3Y3Z3FQcGsycGlG?= =?utf-8?B?ZGpRaFdnRUI1cVEzOGJiemsxaE5VOW9tMzFnNUpDNmI4QTRaMGFNejdmZjBh?= =?utf-8?B?M2YwSnZmTnlwcVYySnM4YTlKSi9CVDFLL3czU2gxYy9acnhiOGNoRWhqbTFz?= =?utf-8?B?b2YxM1JqM1hzSzNyUVJndWxhaUNPTEExdjJqWkc0OHpaZ2U1Y20veHBOZ0c1?= =?utf-8?B?TGxJVzhRU0JqeTB3T1JyQk5yNG16ak5iNFAxUWttVUFaQk5RYThiYlpWZEVu?= =?utf-8?B?eHQ3YktQWWZwQVlQK0N6aG5kWXoyNUg2MWhTRk9kTXdQeWFiTys5SUh4WDFV?= =?utf-8?B?dk9DTE9RRCtHV1M5NHl2dENXWHJ1MzdGU1hGMzlyc1lqZVVLSmtvbTdGcytl?= =?utf-8?B?NWY5U2tJcTZUSkMxTFlYNkNQNDNaV3ViV3k4VS90MGVGd3NwbSt1WG1Rc05t?= =?utf-8?B?WnhuSnVNeE9rMDF1dW0vNE9EQXJrdEthTWl5eXdjZUpwVWtKcm1xTzdpQVRp?= =?utf-8?B?RzlMTVRwUDQ1bUFKRDJwa2V5R2xYNVpQMkdkNHFxdVM0eU1HdkswZVphMnRp?= =?utf-8?B?SE1ySWFLdEk2cGNhNmRSNVlnT2RuVk5tR2dqVnZncVJ1QUdiSGRCQUZNaU5D?= =?utf-8?B?aDFYS3hPNUlPODBISWNUcTdSaWZONTNjYXdSR3F4WjVlZjF4Q2RUNmNPS2cx?= =?utf-8?B?NEc2b2J4NTdpZTE0aFc1Zm9OVVZVREhOU1FjY2hEbnJ2ZzVtU0NRZ21pNUM1?= =?utf-8?B?WTF4YmREd1I1MVkzZEpvMHpzd1puSFhiL3JMZnZtR3pzMmNjU20rVlE0dTA2?= =?utf-8?B?b09NZDJERHhhVXNldndTbko4K2EwTlhjQmdra1hxR1dObnc5S3VwenJ4MDRK?= =?utf-8?B?UUE9PQ==?= 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)(366016)(10070799003)(7416014)(376014)(1800799024)(7053199007)(921020);DIR:OUT;SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 2 X-MS-Exchange-AntiSpam-MessageData-0: =?utf-8?B?ZHdQTDVkNnY4MGNhUWYwQ2tmTFg4ZzBmTzhtRmF3RUE0TzM0ZUxkS0RZazg4?= =?utf-8?B?eUF3Q01JdjZlTzVyTkVVdjBXM29Ld3BEYVkvV3cwSHFhQzJxQm9vR2QycFl2?= =?utf-8?B?anU5M25rZW1ocW5ESHZPVHlyajJyUzlIamUzNVRweTh0MW5IbFRQRXMzaFM0?= =?utf-8?B?MlNUQ1ZCMXkyT2twVHBTMm1wZjVkMjZYRVhhTFBibXlGcSt6Q2hpLzNkRjVq?= =?utf-8?B?Q2dYekRSNUZkQXRPWjBxcDJBbkhib2RSalpNNWdRY0UrMVBXNmJvSi8wV2FX?= =?utf-8?B?WFdqWC9PaHBYZU52UkRkcGpONjBqNHZvczdxZnRoWnd3R2pXNU9iWm5lc1ZE?= =?utf-8?B?Z1Zyc0t0b2dMTzJHYy96YzcxTktQVi9iendDeTZmMEt6RWwxWWh2dk9KU25S?= =?utf-8?B?K0RKTU4vM3RJc0ZWWUJidFd5NGV5M0NsejE3c2FLdFBjbEFlbFZkWXhnTTAw?= =?utf-8?B?cG54YXo1QzU4UU1KYzREb29YbzBiZm1qdWdMVWx1QmhVVUEyWFkvUUFkbGYy?= =?utf-8?B?dDdRcXh3cVd1elN6b2c2SXl3OVg0VHFPaE1FSCt5UVU2NUc5QWRTQ1JQRWJX?= =?utf-8?B?MW93ekIzSjdSYnh4OEo5ZFV0dFl0dXAwM1Y4Wkw0VDNkSnJOeG5IaGdxTDBI?= =?utf-8?B?cWlyanpDQ090K1RCSU81RUlpQS9ndmpQdE1CclQ4YW1NZTRVSnhOVCtTa0pI?= =?utf-8?B?bS9zTk9mYVNKbURpcnk2eGpnWXBaUFpBK01tem1Dc0JKVGxjQlhNWUt0S2ww?= =?utf-8?B?c3BpbW10dHpVczYyL1pEYjl4Vk5VMDhEdkFNa0F3c1Y4RCttQVlrS3lZM0l5?= =?utf-8?B?Q2U4UTJTWVd4TG1kZUxrRDlaVVBqM3NmNklObmFTUzRlaXdPRTlGb1FydVN4?= =?utf-8?B?Z2FPRWFLTUVSOGYwRk5PamdaMVA4OUF0L0tiRUJjdTQwczE3UWFSYm40R3hk?= =?utf-8?B?ZTlUU09rcUZtbmVyckJJckVQMGpUOGhvZUI3V2VZZExqUnpsM1hIOHhGTDJi?= =?utf-8?B?endGUjBoTjVqN01lZDJKRkRNc3d6UWhjWEpSY1MrMGNHbVhoOW4yQWlSN3ZN?= =?utf-8?B?K1VBbE0yUWF1MTVNb1hTS2loZ2MzZ2h3djRoQnc5a1FQTXdXTHF1UkNuT3Yx?= =?utf-8?B?TnhhZ3VVclp6VWpRRjlxNGQ5RUxxZmE2OVZTV1ZOV2hLb2doaUlsa3BZYWNl?= =?utf-8?B?d2VxOEJSSkY5Q00zaFZPUnorblhUS0FNUXRKTHFhTXdTMUlYek5ad0M4RXZ0?= =?utf-8?B?OGxKUmFKOGVrYUNQZk5SbGUyYU9selRDbE9MRTgrSnFqSGUxN3E5UnBkemk1?= =?utf-8?B?RGVNVS9DMk1QUXJJb1ZLUERzdERoWlJERHQ4ZVlvQnovbVZLYnFkbTdrUVhs?= =?utf-8?B?NkZrY3dsNzlIK0RHSnhacEViMGlIZCtIcFljK25uWWVMKzg3UFdkU3VNZVlD?= =?utf-8?B?TnBRL2kxaUJOM0VCdDVWQ1UxeWhyMXNkQjVIa2dtVU5rSEQvQlljd1NaTWIz?= =?utf-8?B?SVNLUUg5dysxTHhLd3o4VlExdGVheERLRjd5dnZqOGlncGd3N3B0bnZYc1Ba?= =?utf-8?B?OTBVNXk1OVMwT2JPKzhEaitMRElyY1IzcTNoY0pZeER4SUlWU1NaOElGbHZ4?= =?utf-8?B?K1RNcGhXRVlybkhKNk9SWnR5Y2lGMUpkQjJNSkEzV1NwU0lLVmQ1bWFsclJy?= =?utf-8?B?Z0I3NWlLM3N5SFl3UnZyV21razRORFZuMUpQSU5Va2k2UFJIWTY1L2dmd3RD?= =?utf-8?B?aTFqOXVZR3ZZcTl4ZGJxWHpMWTMxUko0UmNTRlJlNTNwTUs4OExmaEV4a3lU?= =?utf-8?B?QTJEVGc0dUFRamdCR1RlclExMThaTUlBRWp1Q3V0VjY3cnlIYXBOak9kY0Z0?= =?utf-8?B?WDZEWkptQ0tKTS9uRkpnVk11SmN3L3JRY2pFNDlGd2tFbndxdFlhV0Zwdmhq?= =?utf-8?B?Y2xhUElOTTRmZkRvUnlwMG5RbVdUZmlIbkU0OUU1OWs4U0JFaGJwN0RIWnp5?= =?utf-8?B?WmJUeDhGNXNabDAreFRLWnFUaExTTmJPMnRZOVBUeEpUMTFOTnZrRnU2cHlt?= =?utf-8?B?K1JGUVhaZ0VBczFQa3dQRWVubE5MYWwxV0xwSTBsUHhsbWdUUDBvYmtoZUZY?= =?utf-8?B?VXdGN0tTcDM4eUpPc05YNitiZ0dVbHcrOE83MldkbHRudXJLWHdkQ2laY01U?= =?utf-8?B?OFplcncyQ2FySEZIQlFCMW94b2hEazlKNEpYbXhadVRZUWpuTldSZUJhQTBC?= =?utf-8?B?SUV0aDlwdm8yZWg1T0crcURtUGFGQXlkSkVENzdwQTNyV1Q1Y255ZXhSWmlQ?= =?utf-8?B?SXhqL3FmbHk1d09XTWRIbkVJTm1hcnpla1F4ZWtRNDRZaWJlMHFncDlMdTRI?= =?utf-8?Q?qpMUUtWGVdm8xAX2zxUvLo5KyccrIHc1l2HKIctsN9n1x?= X-MS-Exchange-AntiSpam-MessageData-1: pXhGICpeB83QJg== X-OriginatorOrg: Nvidia.com X-MS-Exchange-CrossTenant-Network-Message-Id: 3913a41c-6958-4f18-6d2e-08de5cdededb X-MS-Exchange-CrossTenant-AuthSource: CH2PR12MB3990.namprd12.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 26 Jan 2026 13:29:02.6137 (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: 2BjJkNybzwo52b9XP6YoLF2R/g2vkLTwB7P6Tg2Zsoe/E9klcrxRmE8nAe3ELwKlrU4qXLIp7qOjuzfoes+hoA== X-MS-Exchange-Transport-CrossTenantHeadersStamped: LV2PR12MB5942 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 Tested-by: Dirk Behme Signed-off-by: Alexandre Courbot Acked-by: Miguel Ojeda --- 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 f870080af8ac..69e718153137 100644 --- a/rust/kernel/num/bounded.rs +++ b/rust/kernel/num/bounded.rs @@ -470,6 +470,48 @@ pub fn cast(self) -> Bounded // `N` bits, and with the same signedness. 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=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=3D N + SHIFT`. + unsafe { Bounded::__new(self.0 << SHIFT) } + } } =20 impl Deref for Bounded --=20 2.52.0 From nobody Sat Feb 7 12:40:41 2026 Received: from MW6PR02CU001.outbound.protection.outlook.com (mail-westus2azon11012070.outbound.protection.outlook.com [52.101.48.70]) (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 1261333984E; Mon, 26 Jan 2026 13:29:08 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=52.101.48.70 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1769434158; cv=fail; b=p3cOsBTSl1BmIizgIT2AU2/bK2FVCrzzriP/OPqGqPF2jrrmMEy4rXFvZsEAoLk3efG2TcDi9j8uu+XqexbSRKmo1Q273kTS8y9/wXb/OOj3Jvj+QyE4UaOEh4RaDbxRyMMkqEA7cDpecw9qp6QeNU5oZQxU54cwhbvFd0Arc64= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1769434158; c=relaxed/simple; bh=jnflilpLiKX+TVKHkAg6Qql87jCk4oerEonJC4HJtXc=; h=From:Date:Subject:Content-Type:Message-Id:References:In-Reply-To: To:Cc:MIME-Version; b=emSJPC6PUk1FnXbSok9m2Hqk4uO9s2gIOttrz6gift5ncxvEKVuFHaIwTUWNio7ipI1ASN+gpePo++I4TYFic9RdPMY22kdiT5J+6ZoDaiK/QGZV1ZenRBGMAfrAWLmpvm1E74BhFIRMZs7AAcY3/rQTfPtSz9eUHySxPuKeJ6g= 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=YBOCguCw; arc=fail smtp.client-ip=52.101.48.70 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="YBOCguCw" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=MkG1QNGU6Bg4XPOl1qCY1TO2lEVC6wS1ade+lftyoVfKpsWnG8VJTAUTvEtSZYDB3zfCapY0iy3E1x4m1kTQq/Mrc66enO/YE6nz7gaT+RdV3kylFLaR6gvJIWiSQLqgRQVA73MOxEPYhnnhDyePBBMhWFD9wux7E/0XfEg435/bEeDkPmePOUOllAT03eMeC7BpIZ3N80v1fzNfljL5431H8HPodbCS3CWJE8mhlVRdSOjn8VbiJ1E56tnQBntWn3S+YASKMZTChDD2Jm0I98yqI6RfIkkk+0nzfohYPEX7W5UlxasUJTPvXgWu1E3zwX+y8ThHuliMx/Bptadg0A== 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=otgn6OT1DxDnwPoMIHj1l4EFVJY4Y9u9pszrXUdtBIk=; b=Hmz1Kz01F92DF1Zqbv5r9Rb2Jib+6cYxASTuG4y9h+fuQwi/elh3bDGVKgY9AKfjHZwgCI9310MLF9NbI2PXruOcV1tCK/8TgC7ial1cc9zJZf5aZNGms8Ut16UZu0acusz8VCx0t0TRWGhTOOpQ8qgi9xIrdR6MsV2J8H4cy8FHrrQ/fZsK+sUb1xpo8EzDa61AyD2CML6nGZRfEpGl8QpK439bZvNj/oXLiofrFfDz/HOdYhgtiw7v2M6bhdiC2okOLa568NvYPCLjeSPpbqYbRUBmL9ttsbqLKRYnQrJg/ABy6QyP8MDK2tok7NsVZxqBGs/NFKzu+xIRAfKcvQ== 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=otgn6OT1DxDnwPoMIHj1l4EFVJY4Y9u9pszrXUdtBIk=; b=YBOCguCwrzco3nv3uWDQiJCl0FVI8n5j4oAif4Znej4Pw+SvpCziJDdRXCAJ/UAKy2biJ/O4ZRWdzWHYzH5f8+KIG/QkbGZnPtDFXCCCg7bijvLUUqRDhUMk48N/Pt2eAFtaNuyOXFq7u/KcNvZ6XpQF2xJWELWgpxgxDxTRH59DeLrgdBwxzPdiyt3MyRceU6WfJ4SVIbBcP8FK8ThaAxKvzsk2s1huh1yv/9pgZKCAE9nlQnkNN2DQ+ldNvvSZXLN9Yson3GCcCSv7b1qNL4WgkGIqEX68P7n+fn/R1Ky6M+bujdK3UN6lab4f6IqwU4qUoDZ/ThYs02jUSAkIWg== 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 LV2PR12MB5942.namprd12.prod.outlook.com (2603:10b6:408:171::19) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.9542.15; Mon, 26 Jan 2026 13:29:07 +0000 Received: from CH2PR12MB3990.namprd12.prod.outlook.com ([fe80::7de1:4fe5:8ead:5989]) by CH2PR12MB3990.namprd12.prod.outlook.com ([fe80::7de1:4fe5:8ead:5989%6]) with mapi id 15.20.9542.010; Mon, 26 Jan 2026 13:29:06 +0000 From: Alexandre Courbot Date: Mon, 26 Jan 2026 22:28:42 +0900 Subject: [PATCH v3 3/6] rust: num: add `as_bool` method to `Bounded<_, 1>` Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260126-register-v3-3-2328a59d7312@nvidia.com> References: <20260126-register-v3-0-2328a59d7312@nvidia.com> In-Reply-To: <20260126-register-v3-0-2328a59d7312@nvidia.com> To: Danilo Krummrich , Alice Ryhl , Daniel Almeida , Miguel Ojeda , Boqun Feng , Gary Guo , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Andreas Hindborg , Trevor Gross 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: TYCP286CA0109.JPNP286.PROD.OUTLOOK.COM (2603:1096:400:29c::6) 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_|LV2PR12MB5942:EE_ X-MS-Office365-Filtering-Correlation-Id: b080a44e-67f8-40b7-75bd-08de5cdee12d X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|366016|10070799003|7416014|376014|1800799024|7053199007|921020; X-Microsoft-Antispam-Message-Info: =?utf-8?B?MEJzYXVDMU94Y3NoK0plcUM5M3FRWGM4KzA0L09Pak8yaDMyT1N5a2dYRGo2?= =?utf-8?B?OU01SFFpR3FjT2JHZGtiTWhtTVVmMGJXdUlXZ1JLRVNsWnA1QzM5dDRWMG1V?= =?utf-8?B?SDhhNDUzY21PeEZZd1ZUL1pESDcrKy9zSTBHNEJNZ3ArSUlZaFV5czUzdUY1?= =?utf-8?B?ek5MdWZPbmkyYlptK05USi9tdFpocUQ5K3lidE1rVXUvN1lCS0lTY2Z2RGhx?= =?utf-8?B?bTJ0ZmZPL0lwM0pVdEpvWmhvdGNkRWRYWmVNZHgwdFBFa2hPaGx2SW9uWElU?= =?utf-8?B?S2prbDMzWUpWWVNiWm5Ya2toK3IyajRXWU90N0ZTOHVUbEN6aXd4Tkk0Rkpx?= =?utf-8?B?UXNpR2xnSm1XZC9oK1RJZHNtUE5SbmdvTmYrZEhsQVllQk81TjBRRldHb3U5?= =?utf-8?B?aFlTRCtxTnVhaTRUMUVsbzlyakJUdzQ1V29seXM2REVUSkExNFFqRk5qMDJE?= =?utf-8?B?R3lyNW56RmlEQTk4cUxsTStLaEl4ckVneHFQWnErUVdrb0VjdS9jRytBdkx4?= =?utf-8?B?bWF1T2g4Z0NqUkxxcHBNZERSUWs2Q0Nkd0huYytjVVdkOWtneVQ5N3pLVXBU?= =?utf-8?B?WDFmTmVkRG84YXpzTkx4c1ZEM3g0SUpZd2t5UGF1QXp0VU9COXc2eVQ3Z2pm?= =?utf-8?B?M1ZBWUczUWdZdEFXeEsvMGNIVDZmWSswemliSkRrWi9FNFJVTitLRlBSUTdH?= =?utf-8?B?L0Q5bVJXeVRqQlNuOW51Qld0TlM0TGt5czJML1Y4d2s3dkx4d05Uay9VZlNt?= =?utf-8?B?ZkJYRzZnSmFPVGlYck1YajRlZDI0Qkh1VGt0R3JmVHdWVmxQT0kwbUV4RGZu?= =?utf-8?B?QXpMYUdFQ2U1OElwZTlpNmhibHZlQStiYnJkdVhVM3ZTTXZ1TjZqKzY1RGVV?= =?utf-8?B?T0s5QjBHWFJSNzM0bjFSUytrNnE4VkdOdk50RUFvdW5LSkdWaXJXVlZseHVE?= =?utf-8?B?ZGNreDZQZncyRG1wejVLNDcwbzVMYXRrL3hCRXduVEYvWk9qd1VYblFZWGlF?= =?utf-8?B?Nkk0YUZsOWt6Yjk0MHp5R2dsMUpqM3hmV3Q0WTRIVEQya2k2aWJ2MzFiVXNp?= =?utf-8?B?RVg5MUVuWGJMbGJuajBVZE9yekFuWHhlZFJ0L1BaZE1CWFhMTExPdGpzc01F?= =?utf-8?B?S0haWEFRaGtBSmF5ODJiU1l3OXJSdHVqcU90VzdSMHliWnlyay9DT1JxUnNl?= =?utf-8?B?dzBacDRwbHkyR2JzSDRGNWg0UG9vcmF3eXFoL1ErNVd6SlJoR045WHh0REZC?= =?utf-8?B?aU1YeWNQTmhGNmc3YXFsK2dhUEdEUU4zSEhTS0gwTG11S2RobjVxeElLV01B?= =?utf-8?B?a05WcFRNajNrczdkMml2SHh2UlBrWXBrZS96Qko2bUhyOWFyRDNKOEU1UlYz?= =?utf-8?B?ektCbEV1Ymg2dDd1MnRaZ0N3SmhHc21DcWlHMW4zcTdFNW9HajB1aW81aVJY?= =?utf-8?B?L0cvdGtOSXNINzVHTEZSR095VXJlYkc5aUJrbys2WXcyTGhFcDh0SkxhMXVP?= =?utf-8?B?UXNsaE9GQmxUaEs5MUZLUEJERG50c0drWjJIaVpuRE5KT3ZLNTdsb3dYRFJt?= =?utf-8?B?WjJXR1ZDZEsvWlA3czBWd2pOaDk1d2gwdG5YVmZpSjQvVlpwVHRUd0dBZzBX?= =?utf-8?B?NmpSY3JhdkJFREcxU3JTaWFiem9XdHVJTGxmNitydlR5ZTV5ZWZFSTdrVFBO?= =?utf-8?B?WmlMcW83MVNCQWRiSU5KN1hXZzFxcWxUbEtWd2MvbE5ySkFNMHU2dXFlbkZt?= =?utf-8?B?czR1ZGZBZlVydDBsZ1Y0Zm84OGNLTEpWV01DUVRodFVwM25RZ3c4VllxK2Vu?= =?utf-8?B?TVNHTjJyaTZsdENvazB6RGs5WTBZMklidmRkWFptN0VnSHhGQzAwUFVEMk9K?= =?utf-8?B?djRMWU9JaTFMS0JKUjN5cmFEVUIvYzYxUjhzTDNBRy80aFMyeUdCZjh2NWcy?= =?utf-8?B?aHV1b2xSTGUwcjhNeWdPRFdTRmlWWklHcFJpclhyMzl3SFg5ZUtaamFSZTN3?= =?utf-8?B?SWNPbjF6cXFnMmRDWUpqbEtBYzZ0cFd2bjRVN0llMWpwK3lLWEpTTDUvbnJS?= =?utf-8?B?YVFCeW5CaHFUMzdnV0hBS3ZNUUJ0S1pRY09YYURpVmhWVjFtWnBNVHRTa1pa?= =?utf-8?B?Y28yUSt2SlE4VENRT1NuVHAvbktQdTVjWm5MU0Uzc3ppVElrVGw4UDQ3Q2JZ?= =?utf-8?B?aXc9PQ==?= 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)(366016)(10070799003)(7416014)(376014)(1800799024)(7053199007)(921020);DIR:OUT;SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 2 X-MS-Exchange-AntiSpam-MessageData-0: =?utf-8?B?c1RoM1ZHY0pJaG9zWWNiaEE2T0NXRktKM3kwd2hNR3k0ZWtnRzgvTnRkczcy?= =?utf-8?B?L3RiSWcrZTNLTm56N1hvVjZMM1RhSy9qbG0zeHZBb2ZtbVdoQlRhQk5PSXNj?= =?utf-8?B?QnNoVlNHbmphS1BOREFqVklDSWtLRGFXVzhNWXZhb3gxbmRsbjdDUy9wRitW?= =?utf-8?B?UzJRYTE3Y0dLN0EwaGMyWXNvSURKVk90Snp4UWFOQ2FYa2RTOVcxOCtQcmJI?= =?utf-8?B?WGJHTXFHRFA1bGlkSkVPTzBnTWxYL0VhemRpV0hTRWpZT3pYQytOVXFEVWNP?= =?utf-8?B?Y3ZpelVtbzQ5bjRvcGVZY3c2MmtDbjFxUlpGMllMUDBqVk1PUEdtaGs5R2Jy?= =?utf-8?B?TkhyMHlsZEZCUTVjVTI4MjJSMFBKM2R6YW5pV0xvTldJRGt5T0N4MmsxWTJv?= =?utf-8?B?MzdwWHY4b0pYTjVhYklPMkF5MU82WVJqRFczS2Vnd0JlS1IyMnFQa0hid3A2?= =?utf-8?B?cUFYeUpDS2J2MFRXYU01UXludWFZYWdYNWRjdnVvNlJUNVlqNk5ZbGZMZ3BS?= =?utf-8?B?eGcvUHdtNlArYnlmRlV3YUYwSG5UZWo4TFRFdHdqNDNndi9FNmZUbG5EU1Qv?= =?utf-8?B?dmtEV2ZsZzRuRlNodWNQa05OVlVPVlI0MnZkVGlVZGZXRmNkbXI5eDdLMi9L?= =?utf-8?B?WVcxSW1xYXBMUVpCWXNScS91NDlBa2JFY3JSNEhVMTFQeGZoVnhRd2pDR2VC?= =?utf-8?B?amhDcXFjZHhKWUlXNUNyUUpwdjlCSEVCNDlSbXl1WnZTRnoyZXMzLys2RmIy?= =?utf-8?B?L1o2YktUSXpNYUFIeGR0QnZ4NDl6cmZheUpTUUJJQmhNaVloOStZekh6aHJI?= =?utf-8?B?ekRyN0ZUSlJRc0JOWk1Xbk1PVzZHUExQMitrNEVuVUhyOUdjVHZpV1U1Rkhs?= =?utf-8?B?Vmg3dFZBbUQ2S2UreWl5MGtuSGpqSDhuSVBJTGp2LzhEQUFSZWRQaHRVdVhu?= =?utf-8?B?VEtjWnptWWt1NEE0M2JuR29sSmc1UFIrWjlrL0dIUVVHYjZKaGZ0VXM3NzI3?= =?utf-8?B?Q0IvUkhoaGRYam1laHphU1BZZm5OcEdkNkFZcG92dzA5bUZIL1NSUjN5SGNT?= =?utf-8?B?UVg4R25aeXdQUlNEOUl2RHdjdTZ1QUFyMTNRL242MXhydkl0QnhJQ1pDdkI0?= =?utf-8?B?cTFYRDVGTGl5dWZtRVd4RU5VNFV0ZUs5R2c0bXJCZEdBeWtyVzFJTC94YTh2?= =?utf-8?B?MXRVQ0FQaVVucklpTFBLbkhwSGlLSXdOZEE5Y2lPamlFbmhjQ0U5NWlrSk5t?= =?utf-8?B?dEV4YWJ2Qm54bnp0KzJuSzV4eGVDVW84akFCYWIzV0NTQVdHOWs0YkU4bnBE?= =?utf-8?B?ME54REJ6SGFSM1VUSktpRGlCRW9GNTlUY3Q5bU4xclIzenJWUFcxczh6OHRH?= =?utf-8?B?VTU0QTJpaWlQT2xFcDNLdG5EMEpKdWNMZ2pKWlAwa2FiS3h5N2dEOWhNSkVP?= =?utf-8?B?L0ZZcThZY0YvTkNoeFVYMmJ4SWZhWndqVENCNVgzTGpzdFRYbnRaT0I2Qmg4?= =?utf-8?B?QXc1RCszQXB1dmVQc3Nhc1M0NFNvV1JVMUlpT2pPbS8rNFBndVcyUG5LVGpN?= =?utf-8?B?MGRCc1BmaTlSRjBjY0tyWTQ3QnlYL24yWjhTS3dubzNKTk9rcmdCdlRVdWow?= =?utf-8?B?TEk1aUw0VUp6QVQ4bElyNkJqRHh3TXVxcGlPQk9ObjhiYlA4cENUTUwyc1U1?= =?utf-8?B?a085L2pGSWlQV1ZDYWpRVWZNUzlZaHVxNzNnQVdNT1gyWUdYaVRxUVNFTko3?= =?utf-8?B?NDFySWRpbCtwSmJqcno3bVdhc0hGUjZtQ2NnOVozaWtBU1Q1eHU5VjVHTmIz?= =?utf-8?B?bXpxVlhjS2IvcEYwa3FGcHRveW1LTlFPV1JubnJjN2s4eDNTdEpLaVYybDIw?= =?utf-8?B?SWlXQ0ZHdVVka2o2dG5iendkc3FFeGk2Y0haZzNQWS93aTZRVnZhUFlpREdO?= =?utf-8?B?TDEvVUZSSzR3emszUTVoN2dzOFRtaXRYUkNCMWVRUC9jajRneWgwaFlkeHBp?= =?utf-8?B?TWlTZEtzWEFxRHc3MEEya1dwYnNraVozMkpmS0YzOXRmZElYZ1pEVHBONEto?= =?utf-8?B?NFczQWJOcHZobWZkUnhicjRLVFlBTG1RakNQWFF5ZlBDVXYvUXk5b1NDbGM2?= =?utf-8?B?dzQ5bGdyVmhSeWpJWU05NmJFWDEvYVYyZFgxWFo0WG52ZE9Icmt5TVFmNXhI?= =?utf-8?B?b3ZtTkxWRnRBMWFnVTBIbDBmaVAyTW9BSldzTUw5aUtweVFRcnpZK1ZtS2Jq?= =?utf-8?B?STN6NzBrNnhuZ0Q3V3pKUXNsd29vejlSNC9uOTZVajFIUFNQdmR1ZEVuNnhK?= =?utf-8?B?SFdxOERxZTdReUdjZ1Jjd29XdzU0SWdrdHlEUitEOXhvZDl3Q3BwZmtYTUFj?= =?utf-8?Q?y5IK19cAHbyQeOCCSQjbPqQ+ARy5/3iaCerHC3X619CIx?= X-MS-Exchange-AntiSpam-MessageData-1: 3hwJ8pi4EjZzMg== X-OriginatorOrg: Nvidia.com X-MS-Exchange-CrossTenant-Network-Message-Id: b080a44e-67f8-40b7-75bd-08de5cdee12d X-MS-Exchange-CrossTenant-AuthSource: CH2PR12MB3990.namprd12.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 26 Jan 2026 13:29:06.8284 (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: WVbruLhqytWmIF6DR5abmXtnef7y58IlZzpfU7UME3h2VTx1FMTEniAes8I2ndK7xntLrimgxsoF5NS2CZkUTw== X-MS-Exchange-Transport-CrossTenantHeadersStamped: LV2PR12MB5942 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 `as_bool` method as a simpler shortcut. Reviewed-by: Alice Ryhl Reviewed-by: Gary Guo Tested-by: Dirk Behme Signed-off-by: Alexandre Courbot Acked-by: Miguel Ojeda --- 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 69e718153137..a629931915c1 100644 --- a/rust/kernel/num/bounded.rs +++ b/rust/kernel/num/bounded.rs @@ -1098,3 +1098,24 @@ fn from(value: bool) -> Self { Self::__new(T::from(value)) } } + +impl Bounded +where + T: Integer + Zeroable, +{ + /// Returns the value of this `Bounded` as a `bool`. + /// + /// This is a shorter way of writing `bool::from(self)`. + /// + /// # Examples + /// + /// ``` + /// use kernel::num::Bounded; + /// + /// assert_eq!(Bounded::::new::<0>().as_bool(), false); + /// assert_eq!(Bounded::::new::<1>().as_bool(), true); + /// ``` + pub fn as_bool(self) -> bool { + self.into() + } +} --=20 2.52.0 From nobody Sat Feb 7 12:40:41 2026 Received: from MW6PR02CU001.outbound.protection.outlook.com (mail-westus2azon11012070.outbound.protection.outlook.com [52.101.48.70]) (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 BA93C339B30; Mon, 26 Jan 2026 13:29:19 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=52.101.48.70 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1769434164; cv=fail; b=DamNBR8jbzHmxsij/G60vpHDwJJ1PGb+3qrSW58efyVIwcLqo+tsuaZri1Dpa7HEoXdiJnEP+1oVNtcRUbyJ7ng9A0VqoUU8wXOVBFjoJaStz6YbZq2+kpej/BS1fs0PX9K4d6z6PzUdlbBL9386Ahxzw4Vvc8xT01xs93+bXpI= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1769434164; c=relaxed/simple; bh=LpJOqQQv80rpbScdYBAXQbdPnefJG7cxJf/W5fqnWX8=; h=From:Date:Subject:Content-Type:Message-Id:References:In-Reply-To: To:Cc:MIME-Version; b=sXa9r4CKRrsMyUHLCuRCuhrYS2rANSnOxEHgO29KKSPzp6oQqIGgQMQusRRxBvCOaF+jko6SKQ/Ou4t3aR8M0OVGXAdRu0RyOQamqMuy6mzO7vGvkmKWs7imZsW5M6KGREVlELar6OmEpWRXDMI2oF4nU52KGcBLwzLbAVgdnm0= 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=rXpUA/mb; arc=fail smtp.client-ip=52.101.48.70 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="rXpUA/mb" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=IMxhBFqUG3bnUDLBIgKDbJfnvBcZRcd4PZgyIevGTJeeb/DbZNR5KpYmB/4tAA8r/hhJ7OXhlquL70rDxfkYXkYHo0q2fr+MZHMQk4+8VL15bkCsluj7jDqRqiB2WYv6pLiE18kTLuDdxmgti2/VXnpbiw/yVN8gSDqh7sP+Y6K31N/F7/xROWIIhv7eSAIK7ujOiBDgbQ0gBu1Ie2/4wql6p89D9NqwEH/nPcCCkEcBrBE6iBAA90/hixMSMS3OxZJDfV6HJBAQ4TfZoxs8TWfnKV+o/rn2b1TWxRNG5mjW4S2RVu50jpKkGIdLSeAH28JyQ0+9HMTtsyoRFGQfYA== 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=qXYJUYs/2ceh+S/G1BVv7h6Qwx4QbVKGZvxc1F1Euh4=; b=Ud/jr3Z1GicUu/m1uw0I9mV5giYEyiC/ZmeU9uBzwUDhpzto9iHkkEJF48GnruFkfIkPWQBqixhjqUDIT7w+/XJwXTZhNHxDgXKreUd4jpaLyGsFc7fa9uPRtklqh1dmzOfyI0zdzTJ0kAYf5ohEHcr3xpwiCPAqaTvUavAWt7y25F1VaxZs+panH8m+5yNGr8RQGKp32z5TijexV2nTaYGhiNloX6CmseN5DZI43RSgkyFc+H46fhcgdfKQs+zAmUezqrGS1w0dmM5LjsoB3OAbWpey6xEF4QVPADU75vLurINpUdLPCa2v9i7hgKXAesRBRR+mD/krqRc8qp4Udg== 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=qXYJUYs/2ceh+S/G1BVv7h6Qwx4QbVKGZvxc1F1Euh4=; b=rXpUA/mbumnP/rR2dM+LVLeHi80k0jTn8CoAS0phEbOwuVDJcqmGa9VypCrAn15ynyVYq9ZK9PhTokvEyPnb5Wo5DO3lXk/fOQ6jlZaacNEyykkEs5RjhmoHnEVmwhICFLd9rR1iECtj/4dalyOpzmdyU3pxSjRcdrKJ95N5HFNZIwZjEZ2lhoqjBfqeHmrLu1K+6CFJsIbAAmlu9xfJpSvVutlVWDDBJaxFqhYwQQ/qHj4L3d0L+UUIACK24NBs/v9u+0viPgCS2bwtZPbirG/MLmer4OdGhfzlczDeJ1OVEctaMYovtRZrDAO3Qj3ulFViI1xQUvzy4ddlIoBVvQ== 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 LV2PR12MB5942.namprd12.prod.outlook.com (2603:10b6:408:171::19) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.9542.15; Mon, 26 Jan 2026 13:29:11 +0000 Received: from CH2PR12MB3990.namprd12.prod.outlook.com ([fe80::7de1:4fe5:8ead:5989]) by CH2PR12MB3990.namprd12.prod.outlook.com ([fe80::7de1:4fe5:8ead:5989%6]) with mapi id 15.20.9542.010; Mon, 26 Jan 2026 13:29:11 +0000 From: Alexandre Courbot Date: Mon, 26 Jan 2026 22:28:43 +0900 Subject: [PATCH v3 4/6] rust: io: add `register!` macro Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260126-register-v3-4-2328a59d7312@nvidia.com> References: <20260126-register-v3-0-2328a59d7312@nvidia.com> In-Reply-To: <20260126-register-v3-0-2328a59d7312@nvidia.com> To: Danilo Krummrich , Alice Ryhl , Daniel Almeida , Miguel Ojeda , Boqun Feng , Gary Guo , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Andreas Hindborg , Trevor Gross 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: TYCP286CA0042.JPNP286.PROD.OUTLOOK.COM (2603:1096:400:29d::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_|LV2PR12MB5942:EE_ X-MS-Office365-Filtering-Correlation-Id: 263763b8-b76e-4533-fd57-08de5cdee3f6 X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|366016|10070799003|7416014|376014|1800799024|7053199007|921020; X-Microsoft-Antispam-Message-Info: =?utf-8?B?ODFYYkZ2eFpVOTVETTFOY0FnQXNrVTI0Tk5WOW5oWVUvZmRTZ09yV29BSWdB?= =?utf-8?B?RXhMMVZKNkp2cVpoS3Uxc0k3OUFyY2hQWWprQzNOeE0zTXJYUVlzVFpOQTJl?= =?utf-8?B?NVo3WVQ1S0ZHYWFvNlIvZmZ5b3lGRmpMeG1EWStKbzBvTi9nZ051V1F5MzZS?= =?utf-8?B?bE4xRTU2SXZwTWhPVWFmT21rUy9nYVZHbzU4bHRDT2xDSm9zVGwrUEcyYnhH?= =?utf-8?B?Y0tvQ2RscFdpVm8xNWZ2K1N4eGplSGZ4THBqNXAzbkZVYjY3aDRFU2tSd2VK?= =?utf-8?B?V0dWalJCV2szK1FRWGtQYTg1Um5TV0dlU08xK09oVEtkRUVPVVZ0cWxxVXg5?= =?utf-8?B?M1J2dUNrSUtzc0Z6WkhDaHMwa3NMU1dPcytQdzE3ZTlkN3VIdExGTGFHczI5?= =?utf-8?B?c3NNQ0ZaN0tZV0dHS1FsK1Vuc2RaT2cvOVdmS0praVppN0pQQ3N3YTRxV1JS?= =?utf-8?B?MUdDRFE4TTVmck5KL2MwQWZ4NDJJTE5nWTFDNWV6SnF4U1BqQ1JMMC9qZ3BL?= =?utf-8?B?VjJybjBhZlFXakMzdS95d2NTZ2VCVTN4TmFvQWYxdlZmeHlZMmpWc1dNWm1q?= =?utf-8?B?NU1IaXcvOUM3SzRudDE1dXBWSjJhWVNaeTFJMi9mbTVTNXVSR2RqUEp0bG90?= =?utf-8?B?eG15SFpoN0xTb3pPald3YnFOdm91UzAwdHEzN2dJRkpyaEJBNzFNemJQbU9L?= =?utf-8?B?aFJhTWgza1FKbFVsU296eXdLVDN1WjFPdTdFc2l6YnlzQkcweFZKVjhLU29P?= =?utf-8?B?TXpwQmlEd2EzUUdKWE9JdldRUUd3ZkZuWHA1d0tqMmxUWFZaK0lEWTN4VXdy?= =?utf-8?B?cm52OThSZzROZHhmbHhVclBlVFV1Y2tKSktsY0FnUlFidE8wNXphVnZEcFU5?= =?utf-8?B?RmtDQnlMT2lrdTRXWEI2RUw1RW9NS0VXcHhGaEJqTlVkT21ERnFQdjFSaUFP?= =?utf-8?B?WGw4Mm5BSEZhcUlLdWVlVHF6VXlTQ0pCdG4wenBueDlLZ29oZFFUTkJUdk9E?= =?utf-8?B?Wk5FRmNycTQyM2JIekJhcG44aFdwMXI5Y0JSOGRwZ0RyWmp1bE9qOGpoNFM5?= =?utf-8?B?ak9ZZ2dsbmNNYkNDMFZhK3MrWDNROUlIT240eGQyOEwvTlVoU0hPdkJGQWJL?= =?utf-8?B?bE5nS1pvYm82SzY2NzlEVUxpSWcrWHBrTkE2MHZ6REVnWkIwejFacEN6bG1E?= =?utf-8?B?dmE1ZFliWG5MMVhZenNhWmNiVTV5ZEVzWGhZV3plZEdtR2xjZzQ4K21QR2Uw?= =?utf-8?B?NmFYUEttQ2szSjVGQjNtU00wSTJCa1pVZE9PVkZCazJSQ3Q2YnVTY0xFV2hm?= =?utf-8?B?cTVKZEJLbCtheWZETlhyNHB1K0tRbGhBVEt1YTVMMWVlVW1WeXk2VUxlSzBv?= =?utf-8?B?MUxzY1VIVkpZVnRtRE5sL0ZMZ1JzNHpXUjlYQkhHZGZ4dlRLVkNTKzhLUkp6?= =?utf-8?B?Njh1S2RuRHU0MVpQd2s4Tk9SblJibE9mRDRNdU9NakJaUVNwTW5CVEdBTHVj?= =?utf-8?B?NmRLOHJFUmZIVmRGRkdvWUxjQmtCbjVSdmgwV1JuWDl4WUlRdGR5SzN4Tm8x?= =?utf-8?B?UHpHaFVWR0tTbHgwb0paWTVGZjVNYUhQenpTa0VWRm5SWVZFenA2cUN5bG1I?= =?utf-8?B?dFp2Y0lvU01BOXNWRDFha2dTQzBpRmtwZ2ZXMVczcUJ2RG5MckZsMVIycndm?= =?utf-8?B?Sk1HQnFCYUtybFEwSk9sUEhGMDFKYlNPajlqQmNCT1hJUXdUaWM0ZURDTjlG?= =?utf-8?B?czg2RFVjVUo1d2dqN3kxVnFQcXpqRGkwdktWMmkzbzdxWC83amlpakdrYVFR?= =?utf-8?B?K0V5TWVBd2hzOGxxYStteXhTeWlvWC9LMStLUnJQR1JJRzdxdkZxYiszckFB?= =?utf-8?B?WXl1MnlTUVBPUHpnTFdoOEs5SjJ5VHM5cHVWR3VRa3o2by93bzNCUHROT3ZV?= =?utf-8?B?ZUQ4MGthbkI0SUlETkpWVXNzTklWRjlybktEell6RTVhUUxZRGJUalhJZ3lL?= =?utf-8?B?K3JxR0pWMkhKK2ZKWjJ5bVBSN2NnSWgwUUtpcUtreE91THUzNWw2cHQ0RWE3?= =?utf-8?B?djR6VW5CSkpIVE9kYWM3UkJQV056UWJvM0NwbTVpUkN0ajM0VkFHYVhpb1Ro?= =?utf-8?B?elVQMmUyZ1RDanBaRUFhdUNTNjhNNWhkY0pSVnUwc21kMTlPZy94aHVORlM4?= =?utf-8?B?MEE9PQ==?= 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)(366016)(10070799003)(7416014)(376014)(1800799024)(7053199007)(921020);DIR:OUT;SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 2 X-MS-Exchange-AntiSpam-MessageData-0: =?utf-8?B?NEwweUVSNEZaNllaM28rVXU1WUs1dkpIVzUyWnpXdUVQUDdTZlBqTVIxbnps?= =?utf-8?B?QjlnS2RDRWdDc3ZVZ2hmbXRTNUllOHpKSkJBOWpDOU0za0xvOWhaSDRYei9D?= =?utf-8?B?azgvcHhSc2RjL1BrdWcyaXVWaDlCMlliaWh3SGZLdzJraDRSUnRLSWE5emFo?= =?utf-8?B?QllVWXBIems5RHdlNWVkaEZKVHBRaVozaHBneUV2K3czZXRpYldwZHpkeWc4?= =?utf-8?B?cldxT3E2eXVQZDJuZDV3VHBGeEE4cnVrV1NzeVRSQTMyNTlYekUzNFdZRXhJ?= =?utf-8?B?REZnd2xXNDY0K1hJTVAxVi9zc0lLUVBuS2J6azBGSWwyTEIwNWZtQ2RPTE5l?= =?utf-8?B?eW5pRnBNNkcwT3NsUGxWbDhLV1Z3Z3BaZ05BZHB6YzFtektmbjd2UldWcXRO?= =?utf-8?B?YmlCaUFZVnlZYkVxVno5U05CcVpYN25YTVI3aGoyNFlZWEhhR3V0R1duSmxO?= =?utf-8?B?R3hXVUp5amxZSTNYQzhRWVRhcE0rSFhRbTVCUlFwdUs4bnJkeVZRRDdvR3U3?= =?utf-8?B?S1pwWStlWm9sUXl2aERicFFEMEdrWE1lVkdZRHovYWRyV1UwVi9qTnVFTlll?= =?utf-8?B?ZHhscXJuN0djend2bWxCcW42L1JJWWUvRUw5WkFiTWlrUmx5Mk9QN2xIOENl?= =?utf-8?B?VUliUW9EeXlxRDRsbk5RRUtBVitzYTZrN0NLZzRXN0tqUTV1TUFyaUs2T3Ix?= =?utf-8?B?dnh1aERCRmMyRVNNM3pLT0dRVXl6aXFqNkFiMSs5WkUveXMvQTZJc3pYV3dQ?= =?utf-8?B?M0RjWk0zTTE4YlhUWlVKbVFSeTRYQjYvL255WXJhRURRWDdqeUd3QlcrR1lx?= =?utf-8?B?MFhWTzhuZFZlK0c4b1NMK1hpRWRrOUxNUC9BMHRrY21vQ2xyajVLMlpZVlR0?= =?utf-8?B?NGNYdWg2L0MxenVUQVVLWEVyMFJ3RU16cHpOd2xXWjRYbTFNdEZTUThZZGxJ?= =?utf-8?B?M0NDcmJYdzd3VkpKbXZaWTdkZ1MzZkxxM05iSXNjMnBqS3VnT243RG9oeFdt?= =?utf-8?B?WGJkWm00ZnUyd1hLelBRazVxeTB6Qi8zZ3Y4d0wyMG54Ym11NE1kaXFwUzFQ?= =?utf-8?B?TnQzMHh6YXRncGdMRmgrOEpSS3NDR3dFQ2tYSjJpUURHY1BSbHd5T25OSkZp?= =?utf-8?B?YmQ0RnpkS0NITHZHQXNDaldWVFlBRkdpRVNDYVVIZE5PdDJDVWRpcjRjSUw0?= =?utf-8?B?R3lUK1VTaXUyTlNLNzBmU296SmxtdjZFSlpkK0hKd2t2a1RQZlh3QnVSSXU0?= =?utf-8?B?TVVHSmQ0VU8wK3Q2V25HRXdIU09qKzBVK2UxV0xZY2RITERCeDBKV1RPTnZ3?= =?utf-8?B?eGU0M3lYblh5RGlndnkxc2VpMEZQdFBlV25jM0J5Zm42aERqajlEMHduNFI1?= =?utf-8?B?aGJVR0J2YnphOEdnclVXdFVrOGgvUlR6SGd1Z2xuOGdlRytwaVdsbFB0RStx?= =?utf-8?B?NzV3K1dNUkdRYi9vQ3EyNjIxOTNYSXMwSklIMHJ5ZWRuTUpKVG8raE5oUHA4?= =?utf-8?B?TWNtR1Y3TURMdnhtRExyY1FJWE1sZk1KWklIOW9LQitWZXo5NDJZcWxWMG5D?= =?utf-8?B?aEJuTU83VG91MEJlY3lCaWUvbXQrRXU5aUgvbk1OUTFwWnBEc3Jtem9FL2hB?= =?utf-8?B?WXozd0hYNjJ5SHRwWDJpK0hKcExTMTNRclN0QWxPenVtRHlhZ0hBQnRDNmxC?= =?utf-8?B?KzVpVDRuWkcyYUxuR0FiWFpUWmVyWHVkazRMcERVZEFwYW1BS2hpV1JEMi9R?= =?utf-8?B?RXdvQWliUERsQlowdm9MS1hGMWFTQ0FvK2tpejdicU41NzRwYWdFWnFTbXFs?= =?utf-8?B?bjNjVmVVY0FTS21OQzgyTHd5d0tPYWhUR3RYdE1wR0hTNDcvMjU4bUliaXpU?= =?utf-8?B?S2FSQ0I1NDN6WnZQK2JzQ2pqcStSRU5RY3RSdDlKWTh4ZUNHdkE1WThnV3Vl?= =?utf-8?B?dUtUclFuMm1EUU5WSnRaSkI4RmZjVHpkdUp2TDhtdTdCRnRpdWFtZE5udHhy?= =?utf-8?B?eWpRSzJRV2M2WWRRQnAwUTVMVm8raks5bHRudG5IQ2YxU2JTLzF5N085MGpU?= =?utf-8?B?bjI3K2ViVUwwdVowdXdWZjd4eVpDN2Vlb0R6b0xXeEhJdlB1M25zWnJ0ZUVi?= =?utf-8?B?eDZITFJhVGFUZDZRZHI0aC9rbHg5VHhUa2V5eXdqRHNTcFV6Nzdla1AyQnAz?= =?utf-8?B?L0FrTGJSb3RRN1JhZTYzaDl1bCsrWEhkUnF6aTlCWXAzNFUyeTk5c01kWURz?= =?utf-8?B?L3dEU0ZkemkwZU1nR1p2WUoxeXlhT3ZxSWRtMHYrVUZaRWlINHdVMFZQOGh2?= =?utf-8?B?aWJhVVM2eURGZkhkUVBvYy80OTBQTytMYXVRSm5JcHBxN1VPcGoxY3hacWJM?= =?utf-8?Q?iBfhKF+IPIHD00tusL/ouSEeV3O8PGmqN9cmg9ew9fRrh?= X-MS-Exchange-AntiSpam-MessageData-1: HIUCBkwPP/MkXA== X-OriginatorOrg: Nvidia.com X-MS-Exchange-CrossTenant-Network-Message-Id: 263763b8-b76e-4533-fd57-08de5cdee3f6 X-MS-Exchange-CrossTenant-AuthSource: CH2PR12MB3990.namprd12.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 26 Jan 2026 13:29:11.3562 (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: gHDN51sYHLmO9g6cAuoFjWb3J/p9fjeRrDL85T/weWIkZS7njUo/V88XzkzFb2kpk+aLI245eDEWim9+g6TwTw== X-MS-Exchange-Transport-CrossTenantHeadersStamped: LV2PR12MB5942 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. Tested-by: Dirk Behme Signed-off-by: Alexandre Courbot --- rust/kernel/io.rs | 1 + rust/kernel/io/register.rs | 1234 ++++++++++++++++++++++++++++++++++++++++= ++++ 2 files changed, 1235 insertions(+) diff --git a/rust/kernel/io.rs b/rust/kernel/io.rs index fcd1b156a14a..26d091df4991 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; diff --git a/rust/kernel/io/register.rs b/rust/kernel/io/register.rs new file mode 100644 index 000000000000..3745763aa034 --- /dev/null +++ b/rust/kernel/io/register.rs @@ -0,0 +1,1234 @@ +// 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::ops::Deref; + +use crate::io::{ + IoCapable, + IoKnownSize, // +}; + +/// 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 providing I/O read/write operations for register storage types. +/// +/// This trait is implemented for all integer types on which I/O can be pe= rformed, allowing the +/// `register!` macro to generate appropriate I/O accessor methods based o= n the register's storage +/// type. +pub trait RegisterIo: Sized { + /// Read a value from the given offset in the I/O region. + fn read(io: &T, offset: usize) -> Self + where + T: Deref, + I: IoKnownSize + IoCapable; + + /// Write a value to the given offset in the I/O region. + fn write(self, io: &T, offset: usize) + where + T: Deref, + I: IoKnownSize + IoCapable; +} + +impl RegisterIo for u8 { + #[inline(always)] + fn read(io: &T, offset: usize) -> Self + where + T: Deref, + I: IoKnownSize + IoCapable, + { + io.read8(offset) + } + + #[inline(always)] + fn write(self, io: &T, offset: usize) + where + T: Deref, + I: IoKnownSize + IoCapable, + { + io.write8(self, offset) + } +} + +impl RegisterIo for u16 { + #[inline(always)] + fn read(io: &T, offset: usize) -> Self + where + T: Deref, + I: IoKnownSize + IoCapable, + { + io.read16(offset) + } + + #[inline(always)] + fn write(self, io: &T, offset: usize) + where + T: Deref, + I: IoKnownSize + IoCapable, + { + io.write16(self, offset) + } +} + +impl RegisterIo for u32 { + #[inline(always)] + fn read(io: &T, offset: usize) -> Self + where + T: Deref, + I: IoKnownSize + IoCapable, + { + io.read32(offset) + } + + #[inline(always)] + fn write(self, io: &T, offset: usize) + where + T: Deref, + I: IoKnownSize + IoCapable, + { + io.write32(self, offset) + } +} + +#[cfg(CONFIG_64BIT)] +impl RegisterIo for u64 { + #[inline(always)] + fn read(io: &T, offset: usize) -> Self + where + T: Deref, + I: IoKnownSize + IoCapable, + { + io.read64(offset) + } + + #[inline(always)] + fn write(self, io: &T, offset: usize) + where + T: Deref, + I: IoKnownSize + IoCapable, + { + io.write64(self, offset) + } +} + +/// 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`] region. +/// +/// Example: +/// +/// ``` +/// use kernel::register; +/// +/// register! { +/// /// Basic revision information about the chip. +/// pub BOOT_0(u32) @ 0x00000100 { +/// /// Major revision of the chip. +/// 7:4 major_revision; +/// /// Minor revision of the chip. +/// 3:0 minor_revision; +/// } +/// } +/// ``` +/// +/// This defines a `BOOT_0` type which can be read or written from offset = `0x100` of an `Io` +/// region. For instance, `minor_revision` is made of the 4 least signific= ant bits of the +/// register. Each field can be accessed and modified using accessor +/// methods: +/// +/// ```no_run +/// use kernel::register; +/// use kernel::num::Bounded; +/// +/// # register! { +/// # pub BOOT_0(u32) @ 0x00000100 { +/// # 7:4 major_revision; +/// # 3:0 minor_revision; +/// # } +/// # } +/// # fn test>(bar= : &T) { +/// // Read from the register's defined offset (0x100). +/// let boot0 =3D BOOT_0::read(&bar); +/// pr_info!("chip revision: {}.{}", boot0.major_revision().get(), boot0.m= inor_revision().get()); +/// +/// // Update some fields and write the value back. +/// boot0 +/// .set_major_revision(Bounded::::new::<3>()) +/// .set_minor_revision(Bounded::::new::<10>()) +/// .write(&bar); +/// +/// // Or, just read and update the register in a single step: +/// BOOT_0::update(&bar, |r| r +/// .set_major_revision(Bounded::::new::<3>()) +/// .set_minor_revision(Bounded::::new::<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. +/// +/// Attributes can be applied to the generated struct. The `#[allow(non_ca= mel_case_types)]` +/// attribute is automatically added since register names typically use SC= REAMING_CASE. +/// +/// 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 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 +/// 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; +/// } +/// } +/// +/// // 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! { +/// /// 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`. +/// 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 +/// 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 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 exit status code. +/// pub FIRMWARE_STATUS(u32) =3D> SCRATCH[8] { +/// 7:0 status; +/// } +/// } +/// 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 registers bank 0. +/// pub SCRATCH_INTERLEAVED_0(u32)[16 ; 8] @ 0x000000c0 { +/// 31:0 value; +/// } +/// +/// /// Scratch registers bank 1. +/// pub SCRATCH_INTERLEAVED_1(u32)[16 ; 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; +/// } +/// } +/// +/// 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_i= dx)?.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 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! { +/// /// Scratch registers bank 0. +/// pub CPU_SCRATCH_INTERLEAVED_0(u32)[16 ; 8] @ CpuCtlBase + 0x00000d= 00 { +/// 31:0 value; +/// } +/// +/// /// Scratch registers bank 1. +/// pub CPU_SCRATCH_INTERLEAVED_1(u32)[16 ; 8] @ CpuCtlBase + 0x00000d= 04 { +/// 31:0 value; +/// } +/// } +/// # Ok(()) +/// # } +/// ``` +/// [`Io`]: kernel::io::Io +#[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:expr)? ])? $(@ $offset:literal)? + $(@ $base:ident + $base_offset:literal)? + $(=3D> $alias:ident $(+ $alias_offset:ident)? $([$alias_id= x:expr])? )? + { $($fields:tt)* } + )* + ) =3D> { + $( + ::kernel::register!( + @reg $(#[$attr])* $vis $name ($storage) $([$size $(; $stride)?= ])? + $(@ $offset)? + $(@ $base + $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> { + ::kernel::register!( + @bitfield $(#[$attr])* $vis struct $name($storage) { $($fields= )* } + ); + ::kernel::register!(@io_fixed $name($storage) @ $offset); + }; + + // 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> { + ::kernel::register!( + @bitfield $(#[$attr])* $vis struct $name($storage) { $($fields= )* } + ); + ::kernel::register!(@io_fixed $name($storage) @ $alias::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> { + ::kernel::register!( + @bitfield $(#[$attr])* $vis struct $name($storage) { $($fields= )* } + ); + ::kernel::register!(@io_relative $name($storage) @ $base + $offset= ); + }; + + // 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> { + ::kernel::register!( + @bitfield $(#[$attr])* $vis struct $name($storage) { $($fields= )* } + ); + ::kernel::register!(@io_relative $name($storage) @ $base + $alias:= :OFFSET ); + }; + + // 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:expr ] @ $offset:literal { $($fields:tt= )* } + ) =3D> { + static_assert!(::core::mem::size_of::<$storage>() <=3D $stride); + + ::kernel::register!( + @bitfield $(#[$attr])* $vis struct $name($storage) { $($fields= )* } + ); + ::kernel::register!(@io_array $name($storage) [ $size ; $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> { + ::kernel::register!( + $(#[$attr])* $vis $name($storage) [ $size ; ::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::SIZE); + + ::kernel::register!( + @bitfield $(#[$attr])* $vis struct $name($storage) { $($fields= )* } + ); + ::kernel::register!(@io_fixed $name($storage) @ $alias::OFFSET + $= idx * $alias::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:expr ] + @ $base:ident + $offset:literal { $($fields:tt)* } + ) =3D> { + static_assert!(::core::mem::size_of::<$storage>() <=3D $stride); + + ::kernel::register!( + @bitfield $(#[$attr])* $vis struct $name($storage) { $($fields= )* } + ); + ::kernel::register!( + @io_relative_array $name($storage) [ $size ; $stride ] @ $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> { + ::kernel::register!( + $(#[$attr])* $vis $name($storage) [ $size ; ::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::SIZE); + + ::kernel::register!( + @bitfield $(#[$attr])* $vis struct $name($storage) { $($fields= )* } + ); + ::kernel::register!( + @io_relative $name($storage) @ $base + $alias::OFFSET + $idx *= $alias::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> { + ::kernel::register!(@bitfield_core + #[allow(non_camel_case_types)] + $(#[$attr])* $vis $name $storage + ); + ::kernel::register!(@bitfield_fields $vis $name $storage { $($fiel= ds)* }); + }; + + // Generates the IO accessors for a fixed offset register. + (@io_fixed $name:ident ($storage:ty) @ $offset:expr) =3D> { + #[allow(dead_code)] + impl $name { + pub const OFFSET: usize =3D $offset; + + /// Read the register from its address in `io`. + #[inline(always)] + pub fn read(io: &T) -> Self where + T: ::core::ops::Deref, + I: ::kernel::io::IoKnownSize + ::kernel::io::IoCapable<$st= orage>, + { + Self(<$storage as $crate::io::register::RegisterIo>::read(= io, $offset)) + } + + /// Write the value contained in `self` to the register addres= s in `io`. + #[inline(always)] + pub fn write(self, io: &T) where + T: ::core::ops::Deref, + I: ::kernel::io::IoKnownSize + ::kernel::io::IoCapable<$st= orage>, + { + <$storage as $crate::io::register::RegisterIo>::write(self= .0, io, $offset) + } + + /// Read the register from its address in `io` and run `f` on = its value to obtain a new + /// value to write back. + /// + /// Note that this operation is not atomic. In concurrent cont= exts, external + /// synchronization may be required to prevent race conditions. + #[inline(always)] + pub fn update( + io: &T, + f: F, + ) where + T: ::core::ops::Deref, + I: ::kernel::io::IoKnownSize + ::kernel::io::IoCapable<$st= orage>, + 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 ($storage:ty) @ $base:ident + $offset:expr )= =3D> { + #[allow(dead_code)] + impl $name { + pub 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 fn read( + io: &T, + #[allow(unused_variables)] + base: &B, + ) -> Self where + T: ::core::ops::Deref, + I: ::kernel::io::IoKnownSize + ::kernel::io::IoCapable<$st= orage>, + B: $crate::io::register::RegisterBase<$base>, + { + let offset =3D >::BASE + $name::OFFSET; + + Self(<$storage as $crate::io::register::RegisterIo>::read(= io, offset)) + } + + /// 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 fn write( + self, + io: &T, + #[allow(unused_variables)] + base: &B, + ) where + T: ::core::ops::Deref, + I: ::kernel::io::IoKnownSize + ::kernel::io::IoCapable<$st= orage>, + B: $crate::io::register::RegisterBase<$base>, + { + let offset =3D >::BASE + $name::OFFSET; + + <$storage as $crate::io::register::RegisterIo>::write(self= .0, io, 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. + /// + /// Note that this operation is not atomic. In concurrent cont= exts, external + /// synchronization may be required to prevent race conditions. + #[inline(always)] + pub fn update( + io: &T, + base: &B, + f: F, + ) where + T: ::core::ops::Deref, + I: ::kernel::io::IoKnownSize + ::kernel::io::IoCapable<$st= orage>, + B: $crate::io::register::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 ($storage:ty) [ $size:expr ; $stride:expr ] @ $= offset:literal) =3D> { + #[allow(dead_code)] + impl $name { + pub const OFFSET: usize =3D $offset; + pub const SIZE: usize =3D $size; + pub const STRIDE: usize =3D $stride; + + /// Read the array register at index `idx` from its address in= `io`. + #[inline(always)] + pub fn read( + io: &T, + idx: usize, + ) -> Self where + T: ::core::ops::Deref, + I: ::kernel::io::IoKnownSize + ::kernel::io::IoCapable<$st= orage>, + { + build_assert!(idx < Self::SIZE); + + let offset =3D Self::OFFSET + (idx * Self::STRIDE); + + Self(<$storage as $crate::io::register::RegisterIo>::read(= io, offset)) + } + + /// Write the value contained in `self` to the array register = with index `idx` in `io`. + #[inline(always)] + pub fn write( + self, + io: &T, + idx: usize + ) where + T: ::core::ops::Deref, + I: ::kernel::io::IoKnownSize + ::kernel::io::IoCapable<$st= orage>, + { + build_assert!(idx < Self::SIZE); + + let offset =3D Self::OFFSET + (idx * Self::STRIDE); + + <$storage as $crate::io::register::RegisterIo>::write(self= .0, io, offset) + } + + /// Read the array register at index `idx` in `io` and run `f`= on its value to obtain a + /// new value to write back. + /// + /// Note that this operation is not atomic. In concurrent cont= exts, external + /// synchronization may be required to prevent race conditions. + #[inline(always)] + pub fn update( + io: &T, + idx: usize, + f: F, + ) where + T: ::core::ops::Deref, + I: ::kernel::io::IoKnownSize + ::kernel::io::IoCapable<$st= orage>, + 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 if the + /// access was out-of-bounds. + #[inline(always)] + pub fn try_read( + io: &T, + idx: usize, + ) -> ::kernel::error::Result where + T: ::core::ops::Deref, + I: ::kernel::io::IoKnownSize + ::kernel::io::IoCapable<$st= orage>, + { + if idx < Self::SIZE { + Ok(Self::read(io, idx)) + } else { + Err(::kernel::error::code::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 if the + /// access was out-of-bounds. + #[inline(always)] + pub fn try_write( + self, + io: &T, + idx: usize, + ) -> ::kernel::error::Result where + T: ::core::ops::Deref, + I: ::kernel::io::IoKnownSize + ::kernel::io::IoCapable<$st= orage>, + { + if idx < Self::SIZE { + Ok(self.write(io, idx)) + } else { + Err(::kernel::error::code::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 if the + /// access was out-of-bounds. + /// + /// Note that this operation is not atomic. In concurrent cont= exts, external + /// synchronization may be required to prevent race conditions. + #[inline(always)] + pub fn try_update( + io: &T, + idx: usize, + f: F, + ) -> ::kernel::error::Result where + T: ::core::ops::Deref, + I: ::kernel::io::IoKnownSize + ::kernel::io::IoCapable<$st= orage>, + F: ::core::ops::FnOnce(Self) -> Self, + { + if idx < Self::SIZE { + Ok(Self::update(io, idx, f)) + } else { + Err(::kernel::error::code::EINVAL) + } + } + } + }; + + // Generates the IO accessors for an array of relative registers. + ( + @io_relative_array $name:ident ($storage:ty) [ $size:expr ; $strid= e:expr ] + @ $base:ident + $offset:literal + ) =3D> { + #[allow(dead_code)] + impl $name { + pub const OFFSET: usize =3D $offset; + pub const SIZE: usize =3D $size; + pub 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 fn read( + io: &T, + #[allow(unused_variables)] + base: &B, + idx: usize, + ) -> Self where + T: ::core::ops::Deref, + I: ::kernel::io::IoKnownSize + ::kernel::io::IoCapable<$st= orage>, + B: $crate::io::register::RegisterBase<$base>, + { + build_assert!(idx < Self::SIZE); + + let offset =3D >::BASE + + Self::OFFSET + (idx * Self::STRIDE); + + Self(<$storage as $crate::io::register::RegisterIo>::read(= io, offset)) + } + + /// 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 fn write( + self, + io: &T, + #[allow(unused_variables)] + base: &B, + idx: usize + ) where + T: ::core::ops::Deref, + I: ::kernel::io::IoKnownSize + ::kernel::io::IoCapable<$st= orage>, + B: $crate::io::register::RegisterBase<$base>, + { + build_assert!(idx < Self::SIZE); + + let offset =3D >::BASE + + Self::OFFSET + (idx * Self::STRIDE); + + <$storage as $crate::io::register::RegisterIo>::write(self= .0, io, 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. + /// + /// Note that this operation is not atomic. In concurrent cont= exts, external + /// synchronization may be required to prevent race conditions. + #[inline(always)] + pub fn update( + io: &T, + base: &B, + idx: usize, + f: F, + ) where + T: ::core::ops::Deref, + I: ::kernel::io::IoKnownSize + ::kernel::io::IoCapable<$st= orage>, + B: $crate::io::register::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 if the + /// access was out-of-bounds. + #[inline(always)] + pub fn try_read( + io: &T, + base: &B, + idx: usize, + ) -> ::kernel::error::Result where + T: ::core::ops::Deref, + I: ::kernel::io::IoKnownSize + ::kernel::io::IoCapable<$st= orage>, + B: $crate::io::register::RegisterBase<$base>, + { + if idx < Self::SIZE { + Ok(Self::read(io, base, idx)) + } else { + Err(::kernel::error::code::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 if the + /// access was out-of-bounds. + #[inline(always)] + pub 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<$st= orage>, + B: $crate::io::register::RegisterBase<$base>, + { + if idx < Self::SIZE { + Ok(self.write(io, base, idx)) + } else { + Err(::kernel::error::code::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 if the + /// access was out-of-bounds. + /// + /// Note that this operation is not atomic. In concurrent cont= exts, external + /// synchronization may be required to prevent race conditions. + #[inline(always)] + pub 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<$st= orage>, + B: $crate::io::register::RegisterBase<$base>, + F: ::core::ops::FnOnce(Self) -> Self, + { + if idx < Self::SIZE { + Ok(Self::update(io, base, idx, f)) + } else { + Err(::kernel::error::code::EINVAL) + } + } + } + }; + + // 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($storage); + + // SAFETY: `$storage` is `Zeroable` and `$name` is transparent. + unsafe impl ::pin_init::Zeroable for $name {} + + #[allow(dead_code)] + impl $name { + /// Returns the raw value of this bitfield. + /// + /// This is similar to the [`From`] implementation, but is sho= rter to invoke in + /// most cases. + $vis fn as_raw(self) -> $storage { + self.0 + } + } + + impl ::core::convert::From<$name> for $storage { + fn from(val: $name) -> $storage { + val.0 + } + } + + impl ::core::convert::From<$storage> for $name { + fn from(val: $storage) -> $name { + Self(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 { + $( + ::kernel::register!(@private_field_accessors $vis $name $storage := $hi:$lo $field); + ::kernel::register!( + @public_field_accessors $(#[doc =3D $doc])* $vis $name $storag= e : $hi:$lo $field + $(?=3D> $try_into_type)? + $(=3D> $into_type)? + ); + )* + } + + ::kernel::register!(@debug $name { $($field;)* }); + }; + + // Private field accessors working with the correct `Bounded` type for= the 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.0 << ALIGN_TOP + ); + val.shr::() + } + + fn [<__set_ $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.0 =3D (self.0 & !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])* + #[inline(always)] + $vis fn $field(self) -> $into_type + { + self.[<__ $field>]().into() + } + + $(#[doc =3D $doc])* + #[inline(always)] + $vis fn [](self, value: $into_type) -> Self + { + self.[<__set_ $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])* + #[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])* + #[inline(always)] + $vis fn [](self, value: $try_into_type) -> Self + { + self.[<__set_ $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])* + #[inline(always)] + $vis fn $field(self) -> + ::kernel::num::Bounded<$storage, { $hi + 1 - $lo }> + { + self.[<__ $field>]() + } + + $(#[doc =3D $doc])* + #[inline(always)] + $vis fn []( + self, + value: T, + ) -> Self + where T: Into<::kernel::num::Bounded<$storage, { $hi + 1 - $lo= }>>, + { + self.[<__set_ $field>](value.into()) + } + + $(#[doc =3D $doc])* + #[inline(always)] + $vis fn []( + self, + value: T, + ) -> ::kernel::error::Result + where T: ::kernel::num::TryIntoBounded<$storage, { $hi + 1 - $= lo }>, + { + Ok( + self.[<__set_ $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= .0)) + $( + .field(stringify!($field), &self.$field()) + )* + .finish() + } + } + }; +} --=20 2.52.0 From nobody Sat Feb 7 12:40:41 2026 Received: from MW6PR02CU001.outbound.protection.outlook.com (mail-westus2azon11012070.outbound.protection.outlook.com [52.101.48.70]) (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 478B0339846; Mon, 26 Jan 2026 13:29:18 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=52.101.48.70 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1769434159; cv=fail; b=RupaBRAB1tZcJMwUUct/z0RaImaxZaOn9xiV1yUc9+7kIal57x4pKYsUMV252CPNgRJji/IakfOgpjjvrol6Ize1BhsMsEAIysDxevJCdWD6a+3k1kA7Ztx/2pT3jNeGvPmkBtkFsbs4Wqvyu1qpm7BBQT0I/azg4qomWErxqKk= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1769434159; c=relaxed/simple; bh=NcOB0KTjmSMVqkxjEDxbyVk3/qDkhNMKwnwLpeYFN3g=; h=From:Date:Subject:Content-Type:Message-Id:References:In-Reply-To: To:Cc:MIME-Version; b=Np/cYFAWBVZVf77ePHRAjxmqYKeTiHh4jmfsb8zhVoTJCJ3XLOMMImJ8V7RGf6ABpF19rhwo6TzR20Y2hB0pklo3rldlF5RTfHdnxX4mu+nm3aj2OJY0OMaS/73u2kFDTA24s7OejB6kVq1MrLHdBGyNhtEWf3QGQC8biHxyUUQ= 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=c1OFLbtB; arc=fail smtp.client-ip=52.101.48.70 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="c1OFLbtB" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=azOpm1/YJ92TeWKqsub0l+SbFxRwpYH0p91d6Op0l/oOGTtc7qqHMN+mu3TupS4OYE1LveNkr/eWlasL66T60thtHF2XzcGjv1lKpM78+ijcH6gOIu1umDyaqzciVQKZgRklapmGP2fhXZa8h2vwjEkNA44uGysH0ReoEOXOFU/LbqpbTCY/qo6Ovm0ex21j7rUcJgMx71OzAowDrO3SCgj5C6w28jI4GQryRrZFelJiiSIsFn9woyVLOsaR4aQmdyyB2Kw1KSF0aixebzZ3sLPX81JhS0MPrvJDmrsVfngWd3wRZjq9otWVA5WwJCxtEANCM6kV/41EJPtgJ3X3cA== 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=6jBdQu6GetQOFtmsL631n5vo03qTOEBIJojMceXek6I=; b=aZ/17OSIP3Rh7z87H8MDhVzFPr2wHq/v9ZH0iWRKKdGo8fLlL4p2CRHrlpL04rx67h0dNDO5Hoz4kKrhTjRYkxkvpBYBVLahySVr4IeoPcukOSXox1cWxfs0QYCLaoI47DwUllfj5pYAeeMmnSX+SOaKvF7uHkWjRaWPDQdN4paNAuvIpzM2A/gUUXAEmE/pMjiaLVzqwPB+ZMsU8mPo75C4eZgFl6vXwuTwKNS90Pp3Bf296oTJEz11DDZ2C9zLDA/0ZZX4ywAWSJL4I3DK+hKMUW67cAtSlR5TWk2U2h8osY4Qm6DBXZoCalunawkesDS1XtxPxTUqgGAVqpVm0Q== 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=6jBdQu6GetQOFtmsL631n5vo03qTOEBIJojMceXek6I=; b=c1OFLbtBE06GhNLobcOn2U59iNGvYBRt39ecSF+M/E0jzMFSk4CANa30p9meyNYzfhKiCS+ZNeDBkpGaZ5S0kZpNJzRDgB8+BLbrHS7aE141pMUELy0oVSDTzWhO2mntiTqFj0qAluBVvX+8UAmwDaLKZ6BRuxdfTuN6KKiIefr4Qk+WkpsUauiVtIKv0B8Z2Q1/qGm0ZmMZCF+9UF1kZDAdZiZNGSw5jGLEK103gIF1J5/CuVYtFoIi3crU1QHbrvIToR81XqNFSpglEw4vDNgbSOotl7Ccb14zYWtwuXh/upT4Iazr14LJwvRWVrO6VcSzRUHBSchoov+TzOl/kA== 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 LV2PR12MB5942.namprd12.prod.outlook.com (2603:10b6:408:171::19) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.9542.15; Mon, 26 Jan 2026 13:29: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%6]) with mapi id 15.20.9542.010; Mon, 26 Jan 2026 13:29:15 +0000 From: Alexandre Courbot Date: Mon, 26 Jan 2026 22:28:44 +0900 Subject: [PATCH v3 5/6] sample: rust: pci: use `register!` macro Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260126-register-v3-5-2328a59d7312@nvidia.com> References: <20260126-register-v3-0-2328a59d7312@nvidia.com> In-Reply-To: <20260126-register-v3-0-2328a59d7312@nvidia.com> To: Danilo Krummrich , Alice Ryhl , Daniel Almeida , Miguel Ojeda , Boqun Feng , Gary Guo , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Andreas Hindborg , Trevor Gross 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: TYCPR01CA0208.jpnprd01.prod.outlook.com (2603:1096:405:7a::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_|LV2PR12MB5942:EE_ X-MS-Office365-Filtering-Correlation-Id: 3a8e5ad6-d712-41ab-028a-08de5cdee660 X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|366016|10070799003|7416014|376014|1800799024|921020; X-Microsoft-Antispam-Message-Info: =?utf-8?B?eGx0MXk0UUpVWEVaenhESDlqMldSWHpQYzZEQjF5bVhDbkdrOXcyTDIzZDZt?= =?utf-8?B?d1gwRXl4WG5lVEw5NFFBanJ1Sm5TNkxpeDduMC95NlJTaURYM2ZCOGZlakpj?= =?utf-8?B?ZEpXUlhEaHN6TGlHeGlYdnNmN1hUSGRSZ2VrU2xKNktxWGpSTWpSVUdlVzJ0?= =?utf-8?B?S1lOTi9aMTV3KzJmdm1haWlpYUZuU0J1alkzSmZoMjkweWY1TkVpZGRiZ3JX?= =?utf-8?B?SE9aVWhybnRnbWlmSFRMTDYySWJuYnBEQkJBQklob013V21iRVBEamZtRDdn?= =?utf-8?B?azBncXZJYjRDL0x2dWEyanFVQjhFSjIzZ3JOSWZtTHdtbWNweC9VZ2xCSmFK?= =?utf-8?B?S1ZSczQ4TkRJVlhPb2hyaFRQSHlOaHFaNy95TmxVMEw2ckFMWWljOXBjOGpB?= =?utf-8?B?WFpiQzByeFVEbXFmR3NNY1k4SW05cDdIaEF4WklMRHhFTTJhVXAwczJodWxS?= =?utf-8?B?ZEpNZW11OG9sajQyVERNdjlUd2tJZzcvVnpaL0xPVGIySXl5TlcxS1FkMUwz?= =?utf-8?B?QllQODJQOWMrczFnVGxBTHFUeW45RmJ4b2ZkLzF0Z3NhSlk3MFl4WTJ5TmFx?= =?utf-8?B?Vk1BaTh3TFZZRlhJdlo2SnRucEc0TFl0VEgvc2w2M1J3UHcxSkUwNmgyZXdi?= =?utf-8?B?UzNOR1lRajZYbGtnQXJaejhqYUMzR3pCNEN1NEF4SmpjNStCaUNwK0hobW1u?= =?utf-8?B?eTZ0Q3NlcURhR3dpczdhbjBYdjQ1cDFHeGloUm5ONXZqbFVLeGpWeU9IdVZ3?= =?utf-8?B?L1o4dkgwZDY2NnNTenRTT1U2b2dEd0RaKzJTdm9FK3VHZ1Z0QTZ3QzdwYUdZ?= =?utf-8?B?V3hyZUtYeTJ0SWtZSTBtWEdJTUpUc0FwVnVBaUMvRGdaSFIxR0wyS3IyNmtO?= =?utf-8?B?ZHdleUhoRVR1aXdvVTZoRTkrZGhHMVg3NVJzcXZuQUNhL1Z6MGN3S21tdlJq?= =?utf-8?B?NmMyQUtYaCtHaWF5L01qWnUxemJoQUg2WmMrRm9wOXdxZkE3dE1lcVBERkhW?= =?utf-8?B?V2tLYXZqa2IzSmdSNnhkMmtOZjBIc0VIcDNPbklkUzdSSVlXYjRjd0NZODd2?= =?utf-8?B?d2x0azhES1BSQms3Q2hsdFN4UmZWNEJncnJOL1pTZkxTcEU2RU5TcE51YWkx?= =?utf-8?B?VEE3VHRpM3RZN0FYYmVYKytxRklCRkNUMEQ2UHBMYldMUGtCWGdWVlBZTDhD?= =?utf-8?B?NjMwckljVElsV1Y3Y3ZTVVhMVXVtMUJXVzhYOEZBKzcxMmllL1NJamZDNS9p?= =?utf-8?B?azlUQUtSZXN1ejFpckcwWTBJSGdBKzRlazI2aUFCYTlwTm9YeENhRERBVkt4?= =?utf-8?B?emhkY3dMRU9JSjQxMG1BUzM0M0t3Szcwb3E3Z2Y1dUk3cW9NdGUvVHM1U004?= =?utf-8?B?ZkhjdW9VcndIWWRxWmV5M241WHh5UTFNUEVSdUY0OHdETjJndEhwVnFrRjhE?= =?utf-8?B?NUVUWkpiYkMzMmd4OFhuRTZrREZ5Uk5yRHI2VVR5Y2JOdDJrbHZaQmlwVlUv?= =?utf-8?B?SmE2dUJ2T1d5Y2l5OWNoTytuekNmVUxQQnlVWFdod0kyR3h2d2JjeUtoSTd3?= =?utf-8?B?dU1CSFFQb01lTDF4NDhzbWtZanI5Y3NreXdDSjlwaGFUazlzWWRMWWRYSEpI?= =?utf-8?B?WWFHRVYrT1ZCdUxoSGQ0WDFURE9TWXRyNE1id3pyNUQyOHdEM2hTMXpNazBx?= =?utf-8?B?WWtyY3JuZ0J2eE5WTjJVNk40NFhlcDF1UVdtSDNOQ0lvOHBFWFJSRFJkZ2Jr?= =?utf-8?B?YmF4WEdDTWRxenhTUUlRalhNOXRXUFd5NWFjeXVneXNFN3hUNnFyakYwOFNW?= =?utf-8?B?dDdsRll2b2NyRk1zQnFNV1RvZXUvMkJneE9oRngxTXpyendZdUY4WGtHS0FR?= =?utf-8?B?cTRmemR6eWVvQkRCb0JFNnA0VG1DbzJ2UVRhb3NpaTdDQ3FkQ3ZHTUN5b2w0?= =?utf-8?B?K0lUVUU0VksrQW9NZ0VsZ0ZTd2lueFBOZEpPaXoyZmpvbGtlVzJtYmVKZUQ3?= =?utf-8?B?ampKb3JsKzFHczNNWlRkaDAxQjdNcU11cEFRQytpWjJtV2h2QVpHejhDdzVS?= =?utf-8?B?NTdaOEVCUFFxbjZRVktVcDdtQWYvdkI5TEkya0pHQVBXRS9aUEhQMXpTditQ?= =?utf-8?B?UTNGWXd4bjFFQXl6VGMyNGZiZzhVLzZSQ2dKUVkrSWxnN1hEN0FoeG5hT01Y?= =?utf-8?B?SlE9PQ==?= 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)(366016)(10070799003)(7416014)(376014)(1800799024)(921020);DIR:OUT;SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 2 X-MS-Exchange-AntiSpam-MessageData-0: =?utf-8?B?czJ3ZFRYcmppVE1DUm5SWUhwU3ZEbWV2L1BNVTBCL21wMkNmcFNVWU0zTVlQ?= =?utf-8?B?NkJHanZkT0ZOUmo4V0NYKzU4NDhwd3J3M05IZmFYTGtBcGRYRU5mb0ZnN21V?= =?utf-8?B?TENiTU1pd3hJZHlkYmRMY1hHMnkxZVltcWdtRmxYRWU0bXFuOEVNU1Y4elF3?= =?utf-8?B?L1NMQTdoaHRETFliRkptOFZkSmU4VCt1QzFiT0ZPVkNTNUJxaXJDTnc3c0tG?= =?utf-8?B?TjNFN0J3WHQwL0lWU0I0ODd4SDJ1eGFMTksvVUQ3eXlnMzMzT1c5YWdqZmhZ?= =?utf-8?B?bWR0a3czVnlOd0YyN21kb1Z1bXcyWWZHaXd5VmprMlFBQnphMngyRWFOYXJ0?= =?utf-8?B?TWx1bXdxMWdCdmZKZEY4NmRnQm9wTHBpdW5aZXozVlk0Q0xxNHlxWmt5dEFk?= =?utf-8?B?b0RLeFlCTm43a2tJOWZKWUsvOENiNzlNSk5zeVFOWXBTNnF4Ri9sOFYrTTc0?= =?utf-8?B?U0hKZUpQeUNTVkhOclUyU0h2aFZzdkFka256YlBmVjdMWVBCalRaV25hTndm?= =?utf-8?B?RnF1MEx0TWdaSCt0aHB2bFhLWk5mVHhOSnlHQzhjK2ZSYmgxU3J0ZURmOC9h?= =?utf-8?B?eDN0dHB0OURKRzdtcDh3bm4xTEtHelMyZ3RCUnRWT1E0QTVncHFpcEswQm5l?= =?utf-8?B?UkVLak1STEsyeXpLUHJlSEwxUFFURTFaQ2hRNmcrK1FYNDNXS2JCWDhYRld2?= =?utf-8?B?VUdJUlhvZjZ0VDY0Qk1aRk1GajRTYUpjcHkyS041Y3BNTnZVazVYaFFxSjR4?= =?utf-8?B?K1hFMmQ5NTFCaGVTZUNZb1lWci9EbWJKMTd1UlIxb0I5Zk5mQnNxWWhTL0ND?= =?utf-8?B?YUZOVGp0VlZqVGZjeVpkN1FlUEZCR09oUUhvOXJtVEpHMzlOOUQ5NEpTQWpE?= =?utf-8?B?MjU0VHFQcXhETEVBY0c3WEtOTCtvZTdRL1FlbFJOV0p2S0ErMWduVXI0T0ow?= =?utf-8?B?NCtiUGIxTjdXY21HRmRRSEhiY2VDTGhPdmR4VUtQV1ltNGJQYXFLYksrdURV?= =?utf-8?B?OFFjdXZBYlhhblRYdXUrS1J5eDBmRTBsWEkwWnEvdDB4Ymk0WndqbTJsYVhG?= =?utf-8?B?SUxzS2Z5RVE2d0N0TGZsY1RidmFUNGo0UlNYL2M4SzByRTFCWFNtL1BaOFhs?= =?utf-8?B?Uk1Gck5ZYVBZTGxncXdpdm8xVHptNGduZHFlVWdEM3RsMUdTY1lvNDVES3FG?= =?utf-8?B?QldEcHp6alR3N3lDZ2F3WGM2T0xOckhmcFVmL0Fpdk1OZmpuSURIQlEvZlc3?= =?utf-8?B?eE02Z0o3b0ErUjJoaUpzNWhJTW5HdWZNR3JCZkpIVWFmNnJZSkxYQnVabGdN?= =?utf-8?B?NWxIb3c3K2k2L2d4bjNhS1gxc3FUWk1RN3JyZ1ZtT2RLbFdtSjFOUGZkZ002?= =?utf-8?B?QWowcFJaVm1WRitPUlhXbUJwcEVrR1FGc0JEbFZOcGVBVit5WUV0czFhNFZv?= =?utf-8?B?bWxMQWFBMDlEYzR4NUVIOGk3cmJGQmlLci84ZGUzWG9Sb0I1bGVFaUhkbm5m?= =?utf-8?B?VWFIeTQwL0ZXV29iQVRyN3F5S25qNEs5NXZFdi9ZL1F5RE9CVE51SE9xbW9k?= =?utf-8?B?cWVEajZHT0drTmFXck4yVTFKQ1crTHlWbjN1MEROaURyaG5WU3B0aXo2NU9J?= =?utf-8?B?WlE1QnlLQWJZeldXT1hFVGNna0tZT2ZYbldXbGR5ZkQwdElLL05XWitDbGFI?= =?utf-8?B?N2tRUXZQbjF0eHJHNmk5ZWFydm1CQlJYdWlKT3c4a2RNcjE0VW5ZOTExTHd3?= =?utf-8?B?dXNuZzdsZktJM2VVS3RSbXh0N2E0L3VkSnFPSk9YTXhGNDBCQTlnOFdMSFpS?= =?utf-8?B?aFlyU29IRi9heTcyT1MxbS9DbXgzOFJUSEE2N0V0dzVuWTBadXdHR3RPbkpt?= =?utf-8?B?TXBLdkQ5ekg1UlFlWWdjRU9TOVlXVmp0ek1xVjRWSXBMeFBETTVGLyt4Tkht?= =?utf-8?B?QTdUSC8vRVB5RVYyNDJtUFpUemZ2RlN5MnBrMVU0YWpxQ0VUYjNvZzd3L1VK?= =?utf-8?B?aFJ1eVFUcWdTdTdmdGNwa1JzUmpBbWVlUE4wbW91c2YzQlhBTXZxYkdMaXh5?= =?utf-8?B?RzRJLzZvQnVPa3QxbVRqR1V0T1Z2OFVLWHZMRkRhQm9Dbi96TlRKaDB0Q0pv?= =?utf-8?B?OGtReVdtVEg0c0lkQjRPc2tUWWhWc3g3R3BwT3hYOE9ta3Bnekc4MTQyVE0w?= =?utf-8?B?OEg1cUViejhVZzVYZ3VMVUFuaW9sQkRIckU4aXdCVFpxczZYck4yemRtb2RW?= =?utf-8?B?S3haMURaOXlUcTJ1VTB0UTBBdGlIOVFUdTFxNlVoZFI4RGJyWTNQY0RCdlRO?= =?utf-8?B?TUttclNYOE9lbVduaFdmN29VMTQ0Z2cxcUJUaXkwMmdtOVQwRW96TjNyY3c1?= =?utf-8?Q?u/ZDxbtZABHCMuFV+p//gszYZL4vYMIboS4Uu0hh+rjM6?= X-MS-Exchange-AntiSpam-MessageData-1: 5XNKH4HcHkqgSg== X-OriginatorOrg: Nvidia.com X-MS-Exchange-CrossTenant-Network-Message-Id: 3a8e5ad6-d712-41ab-028a-08de5cdee660 X-MS-Exchange-CrossTenant-AuthSource: CH2PR12MB3990.namprd12.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 26 Jan 2026 13:29:15.4102 (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: 8cNM1WKhduR8E1AvvY64/khegBKJxVvCcZICoF6PNs4q4w9WLOZh0154KvC4XxphIJKbrpbPeqHO3rH6XzY/uA== X-MS-Exchange-Transport-CrossTenantHeadersStamped: LV2PR12MB5942 Convert the direct IO accesses to properly defined registers. Signed-off-by: Alexandre Courbot --- samples/rust/rust_driver_pci.rs | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/samples/rust/rust_driver_pci.rs b/samples/rust/rust_driver_pci= .rs index 4dfb8a6a4707..df2232d6b71f 100644 --- a/samples/rust/rust_driver_pci.rs +++ b/samples/rust/rust_driver_pci.rs @@ -70,24 +70,37 @@ fn testdev(index: &TestIndex, bar: &Bar0) -> Result { 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. + ::kernel::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.as_ref(), "pci-testdev config space read8 rev ID: {:x}\n", - config.read8(0x8) + REVISION_ID::read(&&config).revision_id() ); =20 dev_info!( pdev.as_ref(), "pci-testdev config space read16 vendor ID: {:x}\n", - config.read16(0) + VENDOR_ID::read(&&config).vendor_id() ); =20 dev_info!( pdev.as_ref(), "pci-testdev config space read32 BAR 0: {:x}\n", - config.read32(0x10) + BAR::read(&&config, 0).value() ); } } --=20 2.52.0 From nobody Sat Feb 7 12:40:41 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 138C033985B; Mon, 26 Jan 2026 13:29:31 +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=1769434175; cv=fail; b=k9MUxjKQoryWAv2YKsIBWlk+lH6N/t/rNYU/kVznaHrhfjzqMnGW3mEf9QJtS3GkORhxRHMJNM7Ij59AGy/UnjCGgC3jYJGPoHpkTAWZHK8U5wy4SSljxT7dR4GnVhafR2CjvYvYCWCnAPobll2AfVL9ZpPisLye7Cb2SVQSTGY= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1769434175; c=relaxed/simple; bh=8Mvhf0RR0/OPR6qbUu/Jc3S5kw70b/9kiIAQyhUMhNc=; h=From:Date:Subject:Content-Type:Message-Id:References:In-Reply-To: To:Cc:MIME-Version; b=l6OEK9Xs5HIXHkFayiRNfB8RZ7c1ybGSWSXiuB8bQBJiF9oLC+EM31tE5LFQPIC+TdYQUqImnUq4Q0wot30DJBcexTeV6LJNCYm55aw1XQmxEhIKs6b+pa4ERysvQpgeDJB6SEqAiNgvQIJp2WGArJfogkAYRRtx4/EqnYOjEJQ= 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=U1k3IFQL; 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="U1k3IFQL" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=vV1d3hBEQHCgZxhoPvDC8xR7mdUNJkmqWQHOXjFG57PlrWxcc5Q700G+syxwtmj1940/Xc4Rsnk5U4/deP5SjTxIsPtewvuAg9TxgDbMtwdWPqAAbZOfrN4pKJatxYWmiypHUbKYsZOOWaVxrFP+NNkR9ZlnXKxifp629hP5TkQnUpHrVQ9mDKbaTBkGNwdVkZ/5YCR04OZQ41K8fRvuY7M1z6fULUYZvRQEP0PIfV3/Y22d/4GqRY/XpE/eTS5AHRUZ0j+31ZeDr2GRkP+xoBMfoA1EO2ahUp4mpqH5WErC+nZ0x4aSK8ChlKZJ3ltsYnCPt39duZiF/ykimfwFGQ== 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=bTQ1OPrF+a5lvR0Wgto4j/ovHEjFIEY+jqjDUeBezYo=; b=H30X1juYn6Mtj0tr9x8jqH+sjBTyV38ZbflmbURxkN8olGZJneuZ+GrGFi/+XM+WO0bC2dTWP0ipluq0gYpE5Dsal38wVw/mRjnMR8ZsEsLSzsLmZX0vBkgBL6rX5VKGSdVdi897JWZZKQvd1o+vqvBYPwACWFeCL09Bmr2iJ8RMlH4hWz8EMJ5Sa1FjpeKXg/Whz9N1HBmhDtBrgOOhjRNdu7YAMR1UvnmTIIcqMxr5MlL+p4O/GNokgAj2epGV+CJtUxX6BXniYlrhanxx/EY7p6xcXyn5wky1hT7NxpW+iRRUfvbJAUEg/eZwTKkZ4u6cIpuQ70MyOBUF69R8Jg== 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=bTQ1OPrF+a5lvR0Wgto4j/ovHEjFIEY+jqjDUeBezYo=; b=U1k3IFQLro+UJZUJm5nrq/gjjZRHKmMqx9GHqZiDYRdO7fRuiWk+PdSBeWHWbaZGyWVS04vjZ7SWRijVW/liylrbvXUdhRb37W5y1uQQkf3AxzD6PWgy79NS1IicGQPM11aUzhN9Eymard+zfJy6vGxARsgNA399o+QxVk5Uhb6NMP7mMjHhHcIdejqPsNTHAizlvcrL7tcvf7pPUTqnTisr4wHWsQvbnH2FjbGQRV8MYv3YAlxshCKcwwFU+11aEhPOVUNzklOTN3XkZxXuMqI1YLIYWY+MyzTwj4pv3w1qX7DIOg49uppnerl9Pl4p0dLujvgYKYueF/us01/ydQ== 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 LV2PR12MB5942.namprd12.prod.outlook.com (2603:10b6:408:171::19) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.9542.15; Mon, 26 Jan 2026 13:29:21 +0000 Received: from CH2PR12MB3990.namprd12.prod.outlook.com ([fe80::7de1:4fe5:8ead:5989]) by CH2PR12MB3990.namprd12.prod.outlook.com ([fe80::7de1:4fe5:8ead:5989%6]) with mapi id 15.20.9542.010; Mon, 26 Jan 2026 13:29:20 +0000 From: Alexandre Courbot Date: Mon, 26 Jan 2026 22:28:45 +0900 Subject: [PATCH FOR REFERENCE v3 6/6] gpu: nova-core: use the kernel `register!` macro Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260126-register-v3-6-2328a59d7312@nvidia.com> References: <20260126-register-v3-0-2328a59d7312@nvidia.com> In-Reply-To: <20260126-register-v3-0-2328a59d7312@nvidia.com> To: Danilo Krummrich , Alice Ryhl , Daniel Almeida , Miguel Ojeda , Boqun Feng , Gary Guo , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Andreas Hindborg , Trevor Gross 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: TYCP286CA0306.JPNP286.PROD.OUTLOOK.COM (2603:1096:400:38b::13) To CH2PR12MB3990.namprd12.prod.outlook.com (2603:10b6:610:28::18) Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: CH2PR12MB3990:EE_|LV2PR12MB5942:EE_ X-MS-Office365-Filtering-Correlation-Id: 95ca6d35-a1e6-4123-f692-08de5cdee92d X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|366016|10070799003|7416014|376014|1800799024|7053199007|921020; X-Microsoft-Antispam-Message-Info: =?utf-8?B?RXc0b2RXR3NOWFNmdHhOR0ZqVm90WXZPcWhVcGpGSWpVUnI2REZ3VnMxV1RK?= =?utf-8?B?UmoxMDRVTHdjWW11ZVVKeEVKOGhRM1gvbTlUYmV4L0J4RTQ1YUFzd0Zpb3Ix?= =?utf-8?B?a2tueHpsL0l3ai9pLzU2MjJDMS8zWnU4M2FsbFV5WWpOQ3d0bnErQ1FuQlFr?= =?utf-8?B?bTl0Qk5JS1N4anhBM2o5dGlObUFmUmIxZ2Z6SG5RL2pGUkg1a3VDS2RTcEJ6?= =?utf-8?B?RVJZNVlZb1RnWkloaXVyOXB5dnFFKzh3bS84eTJaTzNQZjlqL1c1N1FlYUlk?= =?utf-8?B?a2x1U3VLOFQzVW1JQktsV1B1MXFUdlVMRnYzUmtBRkZEZXJJa1E3dExKUktN?= =?utf-8?B?NWdyOFpHNmN6M2wrdmw2WWl4TkFuK1d0U1lEQWl3Uit1WVNLVXNqM05YTzd2?= =?utf-8?B?cGZRSVZaT3ZQRzE1WUZsd21tRU5wQnUwSDdVMkRyZ3FESzF3cnpDMDVGcnhI?= =?utf-8?B?c3VIb1NOWG56UmdmelFqS2pZWm93eUxxVFlvZkZFUFJtWXBzak0xcEtxcUVC?= =?utf-8?B?bUhCTHRXQjE4V2tKSzk3K25oN3dQbHY5TERuR1hTUUZJdWxubm85ekgrOGRV?= =?utf-8?B?YnFZZERadllWdGs3MWt6dDl4QlgyNmJSdnIzZktHV0tSNlpiSmRwc3phRlRY?= =?utf-8?B?aUxqdkM5Q0Z1QlR3ZWZleUpqQjdBNVhDTkFJRVBsdjRlL05iMm5Lc3Q5VS9x?= =?utf-8?B?ZXdNQWxNSmxCSFRpMHB2SlRmTjE1YmtRMUtjMkx5UklTYkw0SUl5ZmlIU3d6?= =?utf-8?B?VjQ3cVdFdlZHck9ya0NXL1VyK0pRNUx0eDFtSUNjZVc1bFI0bjJyVXFwNEk2?= =?utf-8?B?ZEVpdW9TS1plcU4vUnE4REV6ZGo3blovd2JiKzEyTUZvWXVuSndNYUVlV3dD?= =?utf-8?B?d1oxb2dML25JU3dxVWF3YkRBMllYVkVoTFgyVU94VzhkQkVndXlDRzZNenBa?= =?utf-8?B?b21IWTl3cm1XYUd3dnMydWZwc2tZSWNidmdVdmx6UklYRW9ldlg0UkNlU2N1?= =?utf-8?B?ZzEvUzVDU2hpSzVSbTE0Qk1MVGNMUkdXQ3JaMEFMb2RmdXU0SmJmS2VUQ3lN?= =?utf-8?B?MzYyWVlleGI3bVE5em1yUmlqenRHYm95ZzA3QThVdk1vcFVxdGpFS01qU1Zp?= =?utf-8?B?ODU1RTZaa015bUZUUCtCVVBYQ1NrK2d6SHpzc09lNEhmaTFDUTJNS3BIc3Vr?= =?utf-8?B?S2Yxc3pyOVViRjhRRSswS3ZmM0ZNNGhOYVp6ekVjZ2llVWc1UFNuR1dNSDJP?= =?utf-8?B?S2VzcHdmT0FIWDdSei8vT3djaEQ2Ym5wNmh6Ujg5VXphRTQ1MEQxTHpoVUpE?= =?utf-8?B?RDFuTU5jdC9JV2pMRVl0Y3g4RDdCajlxbHpGanR6YzVQWXdIN3daM0ZmL2M3?= =?utf-8?B?aHBPaDFNZFFBRTlCY0Z0cDErZGlpVmVHeGNwMXQzRW8zMyt3QUhaRTNkK0xm?= =?utf-8?B?V2kvaTNoZXE1Y3FrLy9QYlFPM2ExUkhwY21zUmMvZnRvWUF4OWNkQjJmTXEv?= =?utf-8?B?OEhVYlVvSkIxQitPQXk5SlYxOHhrZTFEQ2cwRHovUXhkVlhpQU01a2ZOclJD?= =?utf-8?B?cmQycTBMalNFUzNLNCthZUx2Rzl4aXV2YVNZa1p0QjVZV1BTMENraDl0b2hT?= =?utf-8?B?dy84Yy9VV2VUSWNYaDhhc2pZMkdadERodUJiMWdwbTAwZWFKOHB4UWdtQ2Z2?= =?utf-8?B?RG9lblladHJFU214Vld1K0JIcFlFekxKUW1MUkJlU3BvMHFGRzNVcmlBdjR4?= =?utf-8?B?cXRlL2Q1L3NLNHhmWEhURkluSWdQNHpkRHVSTmFnOVkxYTBlV004b3M4RTNj?= =?utf-8?B?dUVNWmpLNDBEeXhYK0tvRnhSUjBISkVLQ1E1STI0aVBkL1pWWlAxb3BjN0Q1?= =?utf-8?B?Vnl0UEk5QjhzK2hVQUtmVGxjNkZ3Y3lVMmpMZ3VQTlhDMHRxMG9qSEppemtE?= =?utf-8?B?UkwrSmRIT3J2WTQ3WTRMNEUwdlluelp5ZUNBc0UxRDZwY0NUMVVpS1FqSXJD?= =?utf-8?B?NVRWdlNGdVE2SjJkbmUzQWhCb21lSFhCeHFmc0pHVmJOcVZvbFR4T3VuWE1x?= =?utf-8?B?MHhibzZoM0Fpb3dqRkpBMkVHR1VCeUpoRU1NYlVqN0o3NHNoTmt4TjU2bGlu?= =?utf-8?B?MWNpNnhUMjlKeUY5Q29TRU9qbG03cFRzdzVDNlNUSW1rNkIyd0x3M3Vvem9a?= =?utf-8?Q?Xx47vDfmC+W2oBX8Ki4ooF0=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)(366016)(10070799003)(7416014)(376014)(1800799024)(7053199007)(921020);DIR:OUT;SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 2 X-MS-Exchange-AntiSpam-MessageData-0: =?utf-8?B?VE5BK201Q2VMb1lUUkJuM0I0V2tnSzF0SE5ZSDhPRk5WYmhmTWxjS1A0TlJO?= =?utf-8?B?bE51YytnQTAwTy9vNElhZ0xJZ2JtU1NYUVJQZXFHUWlmTEhRWldUeDlmSHVM?= =?utf-8?B?WWtsQlZBQU13RlE3L3drTVduOVVsaGNqcnZ1MVgydmZlajlIVVhiTllJbnJ6?= =?utf-8?B?U3hGRmZaKzh4V0l5ZW56QjBZUFRhd3JQRTdEU01zMkRpeWkrTHlEZVhnTnlK?= =?utf-8?B?MzJPM2tXazhPTXEyRzkxN1VBQXNzSmZOaCtJc2pHNnFNM3cvNGN2SGkvd0Fn?= =?utf-8?B?YjRwcTQwcHEvdTZ2RUdBdlJCZHJwTWtyeXZWb2dIandhTFJ6S05pQnBCeUkv?= =?utf-8?B?d245bXA5ci8rLzIxeHpNMCt4bXFldThXWlppN0VvZ1M1TmZTczZ3ek13Rys1?= =?utf-8?B?am9IWnF2RWdRcTdBbS81bEdxOFo2Zkh2dXFRZlFpVUwxMFdzbHhSMFVXbGd6?= =?utf-8?B?TGVUVmRzekhOcWxzRU92alMrTHNtRTcyb0E1dS9HY1NZMFB3SUpjbDBPeEcx?= =?utf-8?B?Ti9IVm1rSDJEN0dEWVRuZnY4R1RqNVorZFY5UEZnc1BzQm5ZVTRMNTkvQWlh?= =?utf-8?B?N25idDRvcEZ4eFRROUIyQnRWUUc4WWloYWQwY3kwZkdVc28yR2xDbVo4OE5L?= =?utf-8?B?QUJLdFJyYmlzN3ZyNXNOcm1vcEx3TWtQSlg5M1l2ZC84Qzh3NHkzeSsyaW1C?= =?utf-8?B?OXdSUlVPVlplZ216djNUejBRSitrY2FsVm5BTS9VU09vZ3krYkY5RDhuTjgx?= =?utf-8?B?RFZQckozTExGdnI3UTBGeGpMbUI5VTNiMDhZTlFrT0E4S25NcWJWV1k2Vm1Q?= =?utf-8?B?UkQxTEZFaUhzS3RJMHhpR1IvelVlM3dRV0JEUGk0Tys5SXE4bDI5Mk5iRDRn?= =?utf-8?B?a1VQNTdEWkU2MG9XdXNKdGtoTWpBWFcwQm1xRW9uS1NRKytnV2hPb1JUdXNP?= =?utf-8?B?SDZGdWw3azhlcStTZWN0bmhhOXQ1VElHQlY5andpOUNaL3dYemk0VG5BdGpa?= =?utf-8?B?ZGZ3SkVURGpGRmM3ZktKU3VReTNsaWFYUGc0ampNVDJPSUhQTCtRa2REUzNX?= =?utf-8?B?eEJnWWkrNFhYbVJlNFAweEFXOWxwZDNEcE5ROGU3UHR3eXYzRXE2NWd4bE9s?= =?utf-8?B?Vjhxdnc0RDB3ZUVTR0I1dVIvSGxxc2dMLzljMC83dVM5K3BESnpJUVJFZGZk?= =?utf-8?B?Q1hRUG1PYXV0NTVrSXRPSXhKTjc0QTQ4cEFZWWk1azNwSWNxNGN4dTlrbmFF?= =?utf-8?B?UkdkanJhczVEbGNJbm9Db0w1dUhUVS9NK0hOY01uekFQZzN6YmNpeGh4S1o4?= =?utf-8?B?ejJscG1pdGYzMmdPb1NxaE1zWTJ5N2tKSVA2aDFDemlmMG5QbFBDaGhTMUhi?= =?utf-8?B?NVNUQnVZeVpENit0YTk1NlBCczFQVk5vNFNBV1NCaHkzaGlFTms1ckVUR09z?= =?utf-8?B?WllKUDhMVkdVVTBFcmdMcUlzZS9pY2xaSllCdTJLVCt0c1ZBNk51WmZBY2lK?= =?utf-8?B?WllMR1BOTEwwcGtUNExldjFlMGxaWnAyaWVVbkVoRXlOQ045eVdIUHhiUEl1?= =?utf-8?B?SzVBTDQwK0Jxd2VJMUxwQ29mL2tYNXJ0bjIrT0twc1BTbkxlNzFOSnNHN2hh?= =?utf-8?B?aDd1d0lodEF5R0o0Mml1ZkJyRlRvc0dDWDdKWXRmaWk4S2UzWWVkTUxBd0tM?= =?utf-8?B?SWxKZkZLODFFaTZLWjdobExTUWFXcXJKRTBpQ3Fxd29USnhFaysrUjU2aVN2?= =?utf-8?B?aExqclZabFZ5bHp4d1R1N0VrNXRGQmVNZkpCaWlUbHErdFI0cEtkN0x1cDVO?= =?utf-8?B?clBndEJ5d2dVTWQwaTY1VUdkQlcrbDFlbFMxWGdWb3E0ODE1eldEcHV5dXZ4?= =?utf-8?B?cGFEYnpzR3VJMXBxTFBMUUNKVFZGdFFVRnBxVFR1bW1HQTNjS0hYRzdDL056?= =?utf-8?B?WkFyYVRxaXFqOWRGZlhYZ3lTb3ZVRTRNYVE1dXhiYkw1dHN6UjhPOEZGdmNi?= =?utf-8?B?ZklZRGRUc0gxMTVXMUhtZkJHTjNTK1N6ZmJab0NkY2hDaFlLdGkzbU56V2NR?= =?utf-8?B?NmlyRW16VlN6MTN4WW1neGhXMTB6cDJzcnQ3Yjh3T2tSYkVYQ3FOUThMM2JT?= =?utf-8?B?ekkwQ3d1bFZGcmM2YWtwdjJuTGtEaTRLOVhxQ1lZMUpsUGRaUHFHbThlTUFU?= =?utf-8?B?L2RyMlRqOEdBclFkSWcyMHkzM0hpTDRwcEFaVk1NaElJd2xMRDNKNWpteWRJ?= =?utf-8?B?NUEwcW1YekQwRGZTQjFXRXFPaWpiYS9adGZscTRCenhRZ3VlaUtjVDBFT1pn?= =?utf-8?B?NG5LaU1BU0JYLzh4S2QyMG55RnNtVEtvZERLbE95OS9ieU15R3Y3RTV2VU4x?= =?utf-8?Q?Le0ksfmmrRL5iYfNXdGaBj9jy17IoSMYnUvoTZDd6O9rG?= X-MS-Exchange-AntiSpam-MessageData-1: HMdTTK7y+TUg1A== X-OriginatorOrg: Nvidia.com X-MS-Exchange-CrossTenant-Network-Message-Id: 95ca6d35-a1e6-4123-f692-08de5cdee92d X-MS-Exchange-CrossTenant-AuthSource: CH2PR12MB3990.namprd12.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 26 Jan 2026 13:29:20.2805 (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: 16S/vr1c42o3EdqIen5zb0TMgzFZPLiIf4caWlTvzCbs9Jb+OAK59xZAlTbr3kbw6iJ3ipaCHCWoEIoxkrSwcA== X-MS-Exchange-Transport-CrossTenantHeadersStamped: LV2PR12MB5942 Replace the nova-core internal `register!` macro by the one defined in the `kernel` crate and remove our own private implementations. Tested-by: Dirk Behme Signed-off-by: Alexandre Courbot --- drivers/gpu/nova-core/falcon.rs | 175 +++---- drivers/gpu/nova-core/falcon/gsp.rs | 12 +- drivers/gpu/nova-core/falcon/hal/ga102.rs | 15 +- drivers/gpu/nova-core/falcon/sec2.rs | 13 +- drivers/gpu/nova-core/fb/hal/ga100.rs | 13 +- drivers/gpu/nova-core/fb/hal/tu102.rs | 2 +- drivers/gpu/nova-core/gpu.rs | 31 +- drivers/gpu/nova-core/gsp/cmdq.rs | 4 +- drivers/gpu/nova-core/regs.rs | 494 +++++++++++--------- drivers/gpu/nova-core/regs/macros.rs | 739 --------------------------= ---- 10 files changed, 393 insertions(+), 1105 deletions(-) diff --git a/drivers/gpu/nova-core/falcon.rs b/drivers/gpu/nova-core/falcon= .rs index 82c661aef594..1b9283018c13 100644 --- a/drivers/gpu/nova-core/falcon.rs +++ b/drivers/gpu/nova-core/falcon.rs @@ -9,7 +9,11 @@ use kernel::{ device, dma::DmaAddress, - io::poll::read_poll_timeout, + io::{ + poll::read_poll_timeout, + register::RegisterBase, // + }, + num::Bounded, prelude::*, sync::aref::ARef, time::{ @@ -27,7 +31,6 @@ IntoSafeCast, // }, regs, - regs::macros::RegisterBase, // }; =20 pub(crate) mod gsp; @@ -35,11 +38,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) } } }; @@ -47,10 +50,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, @@ -59,16 +60,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, @@ -85,46 +86,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 @@ -138,16 +131,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, @@ -160,24 +153,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), } @@ -185,21 +176,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), } @@ -207,33 +196,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 { @@ -246,10 +226,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). @@ -257,14 +235,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, @@ -276,34 +254,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 @@ -385,7 +354,7 @@ pub(crate) fn new(dev: &device::Device, chipset: Chipse= t) -> Result { /// 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); + regs::NV_PFALCON_FALCON_DMACTL::zeroed().write(bar, &E::ID); } =20 /// Wait for memory scrubbing to complete. @@ -431,8 +400,8 @@ pub(crate) fn reset(&self, bar: &Bar0) -> Result { self.hal.select_core(self, bar)?; self.reset_wait_mem_scrubbing(bar)?; =20 - regs::NV_PFALCON_FALCON_RM::default() - .set_value(regs::NV_PMC_BOOT_0::read(bar).into()) + regs::NV_PFALCON_FALCON_RM::zeroed() + .set_value(regs::NV_PMC_BOOT_0::read(bar).as_raw()) .write(bar, &E::ID); =20 Ok(()) @@ -495,28 +464,26 @@ fn dma_wr>( =20 // Set up the base source DMA address. =20 - regs::NV_PFALCON_FALCON_DMATRFBASE::default() + regs::NV_PFALCON_FALCON_DMATRFBASE::zeroed() // 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) + regs::NV_PFALCON_FALCON_DMATRFBASE1::zeroed() + .try_set_base(dma_start >> 40)? .write(bar, &E::ID); =20 - let cmd =3D regs::NV_PFALCON_FALCON_DMATRFCMD::default() + let cmd =3D regs::NV_PFALCON_FALCON_DMATRFCMD::zeroed() .set_size(DmaTrfCmdSize::Size256B) .set_imem(target_mem =3D=3D FalconMem::Imem) - .set_sec(if sec { 1 } else { 0 }); + .set_sec(sec); =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) + regs::NV_PFALCON_FALCON_DMATRFMOFFS::zeroed() + .try_set_offs(load_offsets.dst_start + pos)? .write(bar, &E::ID); - regs::NV_PFALCON_FALCON_DMATRFFBOFFS::default() + regs::NV_PFALCON_FALCON_DMATRFFBOFFS::zeroed() .set_offs(src_start + pos) .write(bar, &E::ID); cmd.write(bar, &E::ID); @@ -549,7 +516,7 @@ pub(crate) fn dma_load>= (&self, bar: &Bar0, fw: &F) self.hal.program_brom(self, bar, &fw.brom_params())?; =20 // Set `BootVec` to start of non-secure code. - regs::NV_PFALCON_FALCON_BOOTVEC::default() + regs::NV_PFALCON_FALCON_BOOTVEC::zeroed() .set_value(fw.boot_addr()) .write(bar, &E::ID); =20 @@ -572,10 +539,10 @@ pub(crate) fn wait_till_halted(&self, bar: &Bar0) -> = Result<()> { /// 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() + true =3D> regs::NV_PFALCON_FALCON_CPUCTL_ALIAS::zeroed() .set_startcpu(true) .write(bar, &E::ID), - false =3D> regs::NV_PFALCON_FALCON_CPUCTL::default() + false =3D> regs::NV_PFALCON_FALCON_CPUCTL::zeroed() .set_startcpu(true) .write(bar, &E::ID), } @@ -586,13 +553,13 @@ 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() + regs::NV_PFALCON_FALCON_MAILBOX0::zeroed() .set_value(mbox0) .write(bar, &E::ID); } =20 if let Some(mbox1) =3D mbox1 { - regs::NV_PFALCON_FALCON_MAILBOX1::default() + regs::NV_PFALCON_FALCON_MAILBOX1::zeroed() .set_value(mbox1) .write(bar, &E::ID); } @@ -657,7 +624,7 @@ pub(crate) fn is_riscv_active(&self, bar: &Bar0) -> boo= l { =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() + regs::NV_PFALCON_FALCON_OS::zeroed() .set_value(app_version) .write(bar, &E::ID); } diff --git a/drivers/gpu/nova-core/falcon/gsp.rs b/drivers/gpu/nova-core/fa= lcon/gsp.rs index 67edef3636c1..32b28e22c741 100644 --- a/drivers/gpu/nova-core/falcon/gsp.rs +++ b/drivers/gpu/nova-core/falcon/gsp.rs @@ -1,7 +1,10 @@ // SPDX-License-Identifier: GPL-2.0 =20 use kernel::{ - io::poll::read_poll_timeout, + io::{ + poll::read_poll_timeout, + register::RegisterBase, // + }, prelude::*, time::Delta, // }; @@ -14,10 +17,7 @@ PFalcon2Base, PFalconBase, // }, - regs::{ - self, - macros::RegisterBase, // - }, + regs, }; =20 /// Type specifying the `Gsp` falcon engine. Cannot be instantiated. @@ -39,7 +39,7 @@ 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() + regs::NV_PFALCON_FALCON_IRQSCLR::zeroed() .set_swgen0(true) .write(bar, &Gsp::ID); } diff --git a/drivers/gpu/nova-core/falcon/hal/ga102.rs b/drivers/gpu/nova-c= ore/falcon/hal/ga102.rs index 69a7a95cac16..c567d7d81f2a 100644 --- a/drivers/gpu/nova-core/falcon/hal/ga102.rs +++ b/drivers/gpu/nova-core/falcon/hal/ga102.rs @@ -26,7 +26,7 @@ fn select_core_ga102(bar: &Bar0) -> Result { let bcr_ctrl =3D regs::NV_PRISCV_RISCV_BCR_CTRL::read(bar, &E::ID); if bcr_ctrl.core_select() !=3D PeregrineCoreSelect::Falcon { - regs::NV_PRISCV_RISCV_BCR_CTRL::default() + regs::NV_PRISCV_RISCV_BCR_CTRL::zeroed() .set_core_select(PeregrineCoreSelect::Falcon) .write(bar, &E::ID); =20 @@ -59,7 +59,7 @@ 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 { + let reg_fuse_version: u16 =3D if engine_id_mask & 0x0001 !=3D 0 { regs::NV_FUSE_OPT_FPF_SEC2_UCODE1_VERSION::read(bar, ucode_idx).da= ta() } else if engine_id_mask & 0x0004 !=3D 0 { regs::NV_FUSE_OPT_FPF_NVDEC_UCODE1_VERSION::read(bar, ucode_idx).d= ata() @@ -68,23 +68,24 @@ fn signature_reg_fuse_version_ga102( } else { dev_err!(dev, "unexpected engine_id_mask {:#x}", 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() + regs::NV_PFALCON2_FALCON_BROM_PARAADDR::zeroed() .set_value(params.pkc_data_offset) .write(bar, &E::ID, 0); - regs::NV_PFALCON2_FALCON_BROM_ENGIDMASK::default() + regs::NV_PFALCON2_FALCON_BROM_ENGIDMASK::zeroed() .set_value(u32::from(params.engine_id_mask)) .write(bar, &E::ID); - regs::NV_PFALCON2_FALCON_BROM_CURR_UCODE_ID::default() + regs::NV_PFALCON2_FALCON_BROM_CURR_UCODE_ID::zeroed() .set_ucode_id(params.ucode_id) .write(bar, &E::ID); - regs::NV_PFALCON2_FALCON_MOD_SEL::default() + regs::NV_PFALCON2_FALCON_MOD_SEL::zeroed() .set_algo(FalconModSelAlgo::Rsa3k) .write(bar, &E::ID); =20 diff --git a/drivers/gpu/nova-core/falcon/sec2.rs b/drivers/gpu/nova-core/f= alcon/sec2.rs index b57d362e576a..5d836e2d17dd 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. diff --git a/drivers/gpu/nova-core/fb/hal/ga100.rs b/drivers/gpu/nova-core/= fb/hal/ga100.rs index e0acc41aa7cd..655eac3a1dfd 100644 --- a/drivers/gpu/nova-core/fb/hal/ga100.rs +++ b/drivers/gpu/nova-core/fb/hal/ga100.rs @@ -1,6 +1,9 @@ // SPDX-License-Identifier: GPL-2.0 =20 -use kernel::prelude::*; +use kernel::{ + num::Bounded, + prelude::*, // +}; =20 use crate::{ driver::Bar0, @@ -19,12 +22,10 @@ pub(super) fn read_sysmem_flush_page_ga100(bar: &Bar0) = -> u64 { } =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) + regs::NV_PFB_NISO_FLUSH_SYSMEM_ADDR_HI::zeroed() + .set_adr_63_40(Bounded::from_expr(addr >> FLUSH_SYSMEM_ADDR_SHIFT_= HI).cast()) .write(bar); - regs::NV_PFB_NISO_FLUSH_SYSMEM_ADDR::default() + regs::NV_PFB_NISO_FLUSH_SYSMEM_ADDR::zeroed() // 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) diff --git a/drivers/gpu/nova-core/fb/hal/tu102.rs b/drivers/gpu/nova-core/= fb/hal/tu102.rs index eec984f4e816..37da571e9962 100644 --- a/drivers/gpu/nova-core/fb/hal/tu102.rs +++ b/drivers/gpu/nova-core/fb/hal/tu102.rs @@ -21,7 +21,7 @@ pub(super) fn write_sysmem_flush_page_gm107(bar: &Bar0, a= ddr: u64) -> Result { u32::try_from(addr >> FLUSH_SYSMEM_ADDR_SHIFT) .map_err(|_| EINVAL) .map(|addr| { - regs::NV_PFB_NISO_FLUSH_SYSMEM_ADDR::default() + regs::NV_PFB_NISO_FLUSH_SYSMEM_ADDR::zeroed() .set_adr_39_08(addr) .write(bar) }) diff --git a/drivers/gpu/nova-core/gpu.rs b/drivers/gpu/nova-core/gpu.rs index 629c9d2dc994..e42b1aec95b4 100644 --- a/drivers/gpu/nova-core/gpu.rs +++ b/drivers/gpu/nova-core/gpu.rs @@ -4,6 +4,7 @@ device, devres::Devres, fmt, + num::Bounded, pci, prelude::*, sync::Arc, // @@ -122,24 +123,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 +144,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(), } } } diff --git a/drivers/gpu/nova-core/gsp/cmdq.rs b/drivers/gpu/nova-core/gsp/= cmdq.rs index 3991ccc0c10f..0a7b00fc399e 100644 --- a/drivers/gpu/nova-core/gsp/cmdq.rs +++ b/drivers/gpu/nova-core/gsp/cmdq.rs @@ -475,8 +475,8 @@ 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) + regs::NV_PGSP_QUEUE_HEAD::zeroed() + .set_address(0u32) .write(bar); } =20 diff --git a/drivers/gpu/nova-core/regs.rs b/drivers/gpu/nova-core/regs.rs index 82cc6c0790e5..dbc6fa121ef9 100644 --- a/drivers/gpu/nova-core/regs.rs +++ b/drivers/gpu/nova-core/regs.rs @@ -1,12 +1,5 @@ // 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::prelude::*; =20 use crate::{ @@ -29,20 +22,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". @@ -50,13 +87,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 { @@ -89,35 +119,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. @@ -134,10 +179,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 { @@ -145,10 +186,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. /// @@ -167,29 +204,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. @@ -198,16 +236,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. @@ -218,10 +257,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. @@ -238,48 +281,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; -}); + NV_FUSE_OPT_FPF_GSP_UCODE1_VERSION[NV_FUSE_OPT_FPF_SIZE] @ 0x008241c0 { + 15:0 data; + } +} =20 // PFALCON =20 -register!(NV_PFALCON_FALCON_IRQSCLR @ PFalconBase[0x00000004] { - 4:4 halt as bool; - 6:6 swgen0 as bool; -}); +nv_reg! { + NV_PFALCON_FALCON_IRQSCLR @ PFalconBase + 0x00000004 { + 4:4 halt =3D> bool; + 6:6 swgen0 =3D> bool; + } =20 -register!(NV_PFALCON_FALCON_MAILBOX0 @ PFalconBase[0x00000040] { - 31:0 value as u32; -}); + NV_PFALCON_FALCON_MAILBOX0 @ PFalconBase + 0x00000040 { + 31:0 value =3D> u32; + } =20 -register!(NV_PFALCON_FALCON_MAILBOX1 @ PFalconBase[0x00000044] { - 31:0 value as u32; -}); + NV_PFALCON_FALCON_MAILBOX1 @ PFalconBase + 0x00000044 { + 31:0 value =3D> u32; + } =20 -// 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; -}); + /// Used to store version information about the firmware running + /// on the Falcon processor. + NV_PFALCON_FALCON_OS @ PFalconBase + 0x00000080 { + 31:0 value =3D> u32; + } =20 -register!(NV_PFALCON_FALCON_RM @ PFalconBase[0x00000084] { - 31:0 value as u32; -}); + NV_PFALCON_FALCON_RM @ PFalconBase + 0x00000084 { + 31:0 value =3D> u32; + } =20 -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+)"; -}); + 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_HWCFG2 { /// Returns `true` if memory scrubbing is completed. @@ -288,108 +410,42 @@ pub(crate) fn mem_scrubbing_done(self) -> bool { } } =20 -register!(NV_PFALCON_FALCON_CPUCTL @ PFalconBase[0x00000100] { - 1:1 startcpu as bool; - 4:4 halted as bool; - 6:6 alias_en as bool; -}); - -register!(NV_PFALCON_FALCON_BOOTVEC @ PFalconBase[0x00000104] { - 31:0 value as u32; -}); - -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; -}); - -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; -}); - -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; -}); - -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; -}); - /* 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 -register!(NV_PRISCV_RISCV_CPUCTL @ PFalcon2Base[0x00000388] { - 0:0 halted as bool; - 7:7 active_stat as bool; -}); +nv_reg! { + NV_PRISCV_RISCV_CPUCTL @ PFalcon2Base + 0x00000388 { + 0:0 halted =3D> bool; + 7:7 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_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. @@ -397,15 +453,19 @@ pub(crate) fn mem_scrubbing_done(self) -> bool { 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.52.0