From nobody Sat Feb 7 19:41:42 2026 Received: from SN4PR2101CU001.outbound.protection.outlook.com (mail-southcentralusazon11012038.outbound.protection.outlook.com [40.93.195.38]) (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 C4CC03AEF2D; Wed, 21 Jan 2026 07:24:22 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=40.93.195.38 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1768980264; cv=fail; b=s947gEoc88wg2nfa7RBZe9rLTIVVR34fsVga2/yMA14NbVovpODU1aViWu8XpuHk3E2k6VGCwnEHazWt1MGfsWYBkjtzI2YwOMbghY1BVNrYgazMmrluZIsmm5EZFmnYH21dJiegIW0HMRaK8V1vLAITT6aREYWXetNjHLGHvno= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1768980264; c=relaxed/simple; bh=u6vranoC1vQuUDy/FpehRH8OoU9Zd8p1WGFA0bKnHFM=; h=From:Date:Subject:Content-Type:Message-Id:References:In-Reply-To: To:Cc:MIME-Version; b=Fq0bSGYiu/vFhQgYy9CCSlffIDRgvQamQS+cfgaW1x36PCiKXWYWCjfwQPNvO3+3nTS8fFFlQf2bGWtbw3NZRH/bY1s88YSXA0ieWH4RUl6kmunOecwxIPtfJsdjxX2up/Z4BkTejbZiK4MSg0bsi6tTrrPKoE/SBmIqV5p4Ppk= 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=WtNE16qv; arc=fail smtp.client-ip=40.93.195.38 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="WtNE16qv" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=bHAlJHI51sO8ZB45W5qhSFmgLR24mzeVCypYXWxBvm3aZvQ4eK5Ftr2NuThcgT9LckCAyIxRAI5B9M1Yic6nK4lEPCdY8xDiWZ+VJNaRCOwR7PL4keEwwZwkwV8guUu2+ry/5+8A12Im9W87qLGHSzYG9QhT78qJF1BBjNdYZj+0oE4HkIcdK1g1MhBT5H3RAI1Ofy4FiiZtYTjtSUoWr6EUZnMIUbOgBmYmT7zqFzdjgqikqjdPE9GebfFm97slyqRS2e7mwEHsS2d7wlOLqqfliYPM0n0SXY2B88TRxaXsVzn4h5bVF9zBid8f9tOYhvy2IOaI+6qZM3GGZrrc9w== 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=PcbbOxSZWOgbb//TER3P6xUcbw1rNq1B103CxYv3CkM=; b=nW4/59sUjJpBHjsAXLLWQ8Rt74w82oi1dj49RvHmXHZjLzFUsLgLNoN8GpCM151ynOQNdpXVqEZmO2ReUjddnziJ9vxNGSW/kzGtN1X+mW6ZSKAkZXD8ZnfnP79yZEADAStJo6MeAktyg3K0z7QOuQ9HPrxSkT6lQ6FB4Az3OFdV/MBHvNxy/1wDs9DMQ96qYdpQ7J8oZ0rFDi+wf4GpF+zfLnDjo+us2wN5QQgrWvA/9FhSant8sZ3SxqY4oZFe3HDAWsUDKRlM+y5f+DjxgZv5/teDtBDlb7ZSkgb9C/+sgmblHIo/DGi/A82LVD6kukFc5eSNsMO/dxQHMxbzcA== 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=PcbbOxSZWOgbb//TER3P6xUcbw1rNq1B103CxYv3CkM=; b=WtNE16qvjT8M5VSz7B1jojXYFHX+WDS2eoy8QfK1s1Z8gXJz5ChJ3mOFSnPeulcJDbTcbKsNCcfVddLs22V3cXyJYAsUw25JDq8ERoNGIyF30rtwpvrN+880vBEXlRJZw9rNB0ks/SQF4RoeEuA1ZqJY7fx18K/KLHaMz21mj2I7SQexPXFBA3/AylOXOMbhxNCm+12jlFMvUeyQOJKY5J9PPxjgyHVW5G4BWlcsmfjMARjwWIDsUWGBlF/T4B4/5cgyEIjq7tjSYTV877KD3yfs2VtVhKt8EruRQHg71GG2F701IXn3xIff2bjMtVNrreEKi6hmLFXiY634OnVVoA== 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 DS0PR12MB8272.namprd12.prod.outlook.com (2603:10b6:8:fc::7) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.9542.9; Wed, 21 Jan 2026 07:24:18 +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.008; Wed, 21 Jan 2026 07:24:18 +0000 From: Alexandre Courbot Date: Wed, 21 Jan 2026 16:23:53 +0900 Subject: [PATCH v2 1/5] rust: enable the `generic_arg_infer` feature Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260121-register-v2-1-79d9b8d5e36a@nvidia.com> References: <20260121-register-v2-0-79d9b8d5e36a@nvidia.com> In-Reply-To: <20260121-register-v2-0-79d9b8d5e36a@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: TYCP286CA0105.JPNP286.PROD.OUTLOOK.COM (2603:1096:400:2b4::15) To CH2PR12MB3990.namprd12.prod.outlook.com (2603:10b6:610:28::18) Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: CH2PR12MB3990:EE_|DS0PR12MB8272:EE_ X-MS-Office365-Filtering-Correlation-Id: 84f833eb-6b64-4c89-e283-08de58be16d6 X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|366016|376014|7416014|1800799024|10070799003|921020; X-Microsoft-Antispam-Message-Info: =?utf-8?B?U3hNZmhmclFsRm1FeFAvSS9laVZrZkp0R294NEpvZmxpRStOWjZUUExrOGdK?= =?utf-8?B?K0ZtbG8vNklyaVRHc2FUSHVVeGhHQzlhV3VmdGZ4SjJtUUFab2FQK2VNcFNi?= =?utf-8?B?VS8yWGdKN3hrRk13NE0yQi9pa0Y3Wkk1WGFHdGJycjRGUW8xOXhkWGw2cGs0?= =?utf-8?B?TWxQNFZKZHZPSENpOGtSQzRFU1hPM3dqTVJ6dDNKd2gvWHp1SEJBaUIyQS9I?= =?utf-8?B?Vy9vOUZVN2k5S1Y4UWpUajlZUWtiYVN4WHljMUtMUTJRd2o5bitqUEVVRVdK?= =?utf-8?B?QlR1SjV1a2FIanlDNHNLUmFZY1NzVmdPYmM2bEtnVFlSWENZVkYrL0FCaWRF?= =?utf-8?B?Rmg1enQ2a2plRjUwMHQ0R2c3bGtRK0FGdWl5SGlSREdPanRqdWFWZ09sZkw1?= =?utf-8?B?d1NvaENXMWJDMm8zWjR1U0wwRkk4Y0RVYXJIb3U3a3NNZ05IazlwL1AyVndF?= =?utf-8?B?R1FBQms3dTZIeUJaRFRlQU5wOVZGc29HcE8xT0F3K0cwSXhNbVMzbVIxdVk3?= =?utf-8?B?WThTZFRnbHp6RjQ3akZvM3AyRjdyei8zdUU5TWIwaFR5dkthMVBlLzZmOTlG?= =?utf-8?B?eTArbm9VUHJOMXRNYmUra0doaUpOWUxWRG04NHNRZmdpZFNIZmg2T0Y2OXdo?= =?utf-8?B?YkY0UUZMWkJDQU5sVkI0bnJJa3o3YkRWc1JvTUhvZ1pNcDZWY0E5SjdzRVl6?= =?utf-8?B?SU0zVlZFMnh5TmJ6RHZsQUUrYXBiUUJRQmU0UFFNT0lka0NoWUlTa0hsQ3Ix?= =?utf-8?B?cjBLdG9YeUk1OUJhc2Q4UWg4L1dDZXB3TjRBdktKVnFZQnpxb2FNVlFpTUww?= =?utf-8?B?V2RTQmEvck5VejF4MkdoQVFqM041Mmw3anlXc0NkY09tSERobEdneDhXTjN3?= =?utf-8?B?SGpaZldoZWhNU0dVZVl0UHdLK1FpVWZ6NkxKMDZJZjFTc1JZemlETzQxZDc3?= =?utf-8?B?NDBpaTJWQjFMZEZ5U2hhdXA1Tlc5V3JSZmIrcnFFdXFCK09CSUZlMnRBWS9L?= =?utf-8?B?MU8zbXNDaHArOEYzTzRzandyUTc5N1BPUTE2a21SbWhvcmJEUWwrRXdSMXY2?= =?utf-8?B?UlcwSGp0amJYMERjN0x5UDBlZGdobGhodEtSa0ZhSU5RakJEMWNQNytiRWVa?= =?utf-8?B?anYzK1JFWG9KamlpNk85a2paZjRQR2EyV0dsdWRISGlUUU50d0Vwa2taMXFT?= =?utf-8?B?WjdRaEZnTmpmckZtRHV2Q2dXZnBJZ1JmVDA0V3lSOVBseFVlS3NIWm1zTUpU?= =?utf-8?B?NFBHOHptV1dwQkFaRC9OQk5jVjlMSzFIcExnUlBjZHVWYm8wS3N6RFJvNS9O?= =?utf-8?B?OFNnYkwvMlZUdVNpUUZ2RW1SU24vcXJjTHZxWS9pcHZuNFphUlNEZkZFZjBx?= =?utf-8?B?WHNsVHc1UjU1Z1RkOE5XRVFLUHJYK3FHM04xWE5ZTFl5TkFqYVdmY3d0cnFS?= =?utf-8?B?emJlWHBsdVVkbXNQN0ZabzBjMGxxSmxlaGd5ZG11d1NOc24wdTY4cnJiSEpx?= =?utf-8?B?VHJsRFJEeDNUM0wxVDdjN1g2Q21qM29oNG5Id0RhZGhmbFhrQldOVkJOV3l3?= =?utf-8?B?bzZwQ3FVUHpUSk1ZekZKdnR6MkxzVElWWnZMMWNoNFRWSUlWTGRjckRJOXhE?= =?utf-8?B?eEY3Qll3YVF3S25rcTg1VVZ0WnlrV0UvbUVLWjRBaTY3dmE3blRldDBvRFhM?= =?utf-8?B?UGd0U1JRWXFYUU11aEtMM3MyZGdKMnc2dlI4SFJqbGUvNFd2OXNFakI1UVNh?= =?utf-8?B?Z2ZacGhyS01samFrOHBsd0htWGprYWdXMEdpQWthd1pRNnhSYlpGZ3N1WW11?= =?utf-8?B?Mmt0QzZ3cGZEZ3hzWG1JeGlsb0N2MFRSbWt6blh4MjlxNUJWNlJxNHZiaWJj?= =?utf-8?B?WmUzM1ZHVzMwUU5VYm1JMUFrTFQyNjRYNnFGQTUrYWVNUDk0QzVDdFdNQ2Zy?= =?utf-8?B?eXVqUGFBQnhhTGhVQjZJQ212WjJSRlBDblk3R2NYazdDZkRzVnZrQUFSZlBn?= =?utf-8?B?VHprZW9XMzE2V1VrVU01VmJPeDFYdUh6ZzRqc3hQQWlpY2ZKYnpVWFYyVVcr?= =?utf-8?B?ZHl2RFhMM1owUCt6aVNZSkFvTUxZV1lyQi9mc0RyN0VrN2dVUkFpOW51ZWRM?= =?utf-8?B?by91S2ZFWDFyYmVQWGtpQ1pObkZmN0xaYnJlSkJvQ2F5bk1ROHNUa2laeC9h?= =?utf-8?B?S3c9PQ==?= 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)(376014)(7416014)(1800799024)(10070799003)(921020);DIR:OUT;SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 2 X-MS-Exchange-AntiSpam-MessageData-0: =?utf-8?B?UGpuQXhwYTNNZG53Y2EzbzFCN3JsQ0pYQ2IxSFYxNFN1d2FWTzNIcTMrREZm?= =?utf-8?B?NUdoaDJ5SWViZ0UxUUFNQXJJS2JUaXVNZTdXS1c4aEtxTEYvbkIvSGVUdTI1?= =?utf-8?B?VlNra0FYK0drUmh2aTk5Tk9LeXJCYTRRd2VrTjQ4ZmJCZFR6a0UyN1ZUT2h6?= =?utf-8?B?c2gySDF3dWZWVHVGd2RERnFjVEJRSGhqMG5UVFdZTlgvSVJZSnhOVDJkR2Q5?= =?utf-8?B?cS9LeHhIZ25Cd0t3Ri83Y1hDbEZHODEwQXJFNEhEQVdPY2NYWEZscXduWlJk?= =?utf-8?B?cTNzUTczeE9zUWVxcGo0bEZ3KzQzdmU5L0dyYUNUTjI1Y2NpbXhvQXJtZitt?= =?utf-8?B?Q3Z2R3Fjc0RiK0szR3I2T2NCYkZVTmhrSEZGZndVOFdzZ2VUR1F1UnFXVlF1?= =?utf-8?B?aWlHRDQ2NmNMay9aRlVtaW05dXRqekFXM1psL3BudFlTbkxSTEhSRXRsbHlx?= =?utf-8?B?bko1dGhtdHd1Zm5SM05UMXZ4RFZCUE5pZ1J6TE5pOFBjTVlFd3l0bEVkeG1X?= =?utf-8?B?M09rTnQ1SUcrdDhvbFhLZXhDWXBUQWJaclFXYnNaS3FXSmtPQzR5VHVVWEdZ?= =?utf-8?B?L1JVRHJuSTkvMGZGYVJMbXE0ZDllV0VEOU9DdmZMZmNLK24vK2haaHhMRXNt?= =?utf-8?B?UjVSYTNxcm9BSURyZ2xqQUpodGpGY0VCQnA4UFZoNDh5aG9OUXk0Ly9sRVlS?= =?utf-8?B?eiswbUN1TjZOcjNNY2hmSVRucVBrdUY2WVNSQnhRSmVhZ1Z3bXNNcnYrVkkx?= =?utf-8?B?WjFuY2d6VWxwNmtoNVVBZUEyNFV6Wk1iNkhxNWc3MjFlcnhvSkE0WE0vREhz?= =?utf-8?B?b2ZPQzZTWE10ZURKK29QVnJFNFJuTVhFLzdicU9yN2M4Ny9uNlQ0MGRVNXlv?= =?utf-8?B?Znh4WW5VNlhxR2hPQWVndm9TRmRsNmFycWdpZitpNC9IcWNZTmx1ckZrRFJ1?= =?utf-8?B?OEtXSkd6V3Nod0ljQWlrUmhTWjlrSjhQRXQyN3o5bmE5eTBCRW5RbkljZDc0?= =?utf-8?B?cEtzUllkMlIwNEpnRHpMZk9ka2RLNXhXWkdUYm1ldVNqWHFwb1E5RjFyYlVT?= =?utf-8?B?UUxRT3doT3RmOVdsenA1ejhiL0g3YjgweUwvdUJTVGpxbmx5S3hkUG1IWE9H?= =?utf-8?B?ZkdEMzJjcXV6bVdjR0lVcmsyR0huMkFFM1UzbEIrU0ppQmV5OGRyWXY5bFVK?= =?utf-8?B?WHd3UXdzLy9wdEltakFMaExYaGwva1MrNnc1Q0FRS1lVNThzd0tjcWZjblpu?= =?utf-8?B?amxpVDI3VU1ESERIWFhMbjBwdFNwK1JETkpRS0lSUHBueU1OZHROcGJ5WjE1?= =?utf-8?B?a3dyUnNmRmlIamtjbEY3VnRuenlsenozQThLQTFjTkpxYTU4TXJBT1RjcFA5?= =?utf-8?B?MEhHWTFwekZkeTNnL1d0M3dPRkloK1JyUU1oUldhK0J6Z3hETU9NUlpWdXRC?= =?utf-8?B?d0Nnb1JncDFOTmZmd2lnNHB6cXJzYUFkRG42UmYrM2QwSVNxZk80TlY5aHhY?= =?utf-8?B?Vm0vRHhjRzJnNzhRK1ljajU2Y2tTY2dObDlRd1o2cDVTdlU0K3AyYTZKVUlN?= =?utf-8?B?d0tTSlVFVE1jQjBpcEF5RDl3Z0VZV2R3TDZIdy93WU9pbG9iR0lhTDVjbitY?= =?utf-8?B?aHhST2tNb0VMSVdyY1I1TWdJR0R3T2t3Rmp5SnpSOXlaaTNLSkkzZUZQMTJE?= =?utf-8?B?UmpSeW4zM0cxUGF3ZFMvWWExamY4Tk9iYzBvTGV1ZzI2TWovWFYxYW1sZVdB?= =?utf-8?B?ckkyNUVYWS9nbWh1V1lWSmVZR2JJSC84bExwL3BDRk9kNXIwWjVNeEdyNVFN?= =?utf-8?B?OGxkaTZLT2F3Y1B2ZkV2RHdiUjFLcmVDcjI2NzJNRlBCVllUZTRNQk56aWRx?= =?utf-8?B?Y2dyem9Zc1FaQi9VK09qL1BTakRndHdwTENQSktELy85UUhsMkFtY1NnQXhU?= =?utf-8?B?aVpkM0lkU2FlM2xaaVViVGw0aUZsWkFmVVl1bEJwUm92S2RNc0lxSHN0Tkg5?= =?utf-8?B?Z2pURjN5dmI4czZNSGtwNEFxK3dkbVVFemNRU1Y0MmJIT0JVZ25UOGZQbVcr?= =?utf-8?B?aTYxL3BTT3NZZG1BbGg5Um52YVlhdU1kNGtpd0xJVk5zL0NYTGhyVktOSW9u?= =?utf-8?B?UXFvV2c5QStHUXRCaHJQTHpNVnZIdEZZdThMcmdML05QeURHYzJwRDdCdm1Q?= =?utf-8?B?aW9XU3B1QjhsVU5xODc1ZjU3YjFjRjEwTzQrN2UzQnBXTjFKNXZjK2ZBVXFj?= =?utf-8?B?YmpNSXIreXAxbk1FQ3lpQTBoR01jR2ExMys3ZElpdUNIamQzYmR3ZldRa0dB?= =?utf-8?B?TkZQQVpNSlBjRDcvQ3pldnNUZkdjN3R0WGxrcmkySVUzeVFwN2lXMzFDcFRG?= =?utf-8?Q?+7/wKZLMED+kXHNOoTfQ/wO9tsZ0XAzYIiKAOmwpJDRy3?= X-MS-Exchange-AntiSpam-MessageData-1: Brll8v6rbHHIiA== X-OriginatorOrg: Nvidia.com X-MS-Exchange-CrossTenant-Network-Message-Id: 84f833eb-6b64-4c89-e283-08de58be16d6 X-MS-Exchange-CrossTenant-AuthSource: CH2PR12MB3990.namprd12.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 21 Jan 2026 07:24:18.5211 (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: G5/uhey6qJGjc2eTOid1e/BEKorzcE99J+BSSIRwCnxqN7mqf/0mrc4DHvF/FqX3RMqm8wzehr44Tgnx427UIw== X-MS-Exchange-Transport-CrossTenantHeadersStamped: DS0PR12MB8272 This feature is stable since 1.89, and used in subsequent patches. Signed-off-by: Alexandre Courbot Tested-by: Dirk Behme --- 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..8fd0e7096bd1 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,lint_re= asons,offset_of_nested,raw_ref_op,used_with_arg,generic_arg_infer =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 19:41:42 2026 Received: from SN4PR2101CU001.outbound.protection.outlook.com (mail-southcentralusazon11012038.outbound.protection.outlook.com [40.93.195.38]) (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 BB3C045107A; Wed, 21 Jan 2026 07:24:24 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=40.93.195.38 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1768980266; cv=fail; b=jIKCQrjTaZ8I5WkYdIAMhA5JCtRONtc+2wmVlRgl4ltM5ihW/slGrkSoRmOLZezW6geGOqz6mrDR1YSjsSeCy274HbH0fDE3v4DWmSuHSyG5vV6wG7XPZxqPfo78x1h8Nq/6JCcPLbk6RIzWYCFn3keQsd3zcm7Lp2nfRS1Tr9c= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1768980266; c=relaxed/simple; bh=IMzatzCrIxi4T8hAsll0CxNINWx0UeaVNDNS2ebepQg=; h=From:Date:Subject:Content-Type:Message-Id:References:In-Reply-To: To:Cc:MIME-Version; b=lxzb/d520E5yhCZzXRvCM33nCl2+RLTdPpn/h8WE9OC68OPldAPuNV/5RLUGmZWeUg3A7BmIug896CXYvsxYUrGNNKmy8+3s01yAe9k1vydTF9S40hZaRTG5tJyNQWVhc5quFo+yDdvBv10oLDjjGUX054TlOOHuSudO0kOqgFg= 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=cxeRXbzf; arc=fail smtp.client-ip=40.93.195.38 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="cxeRXbzf" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=BBcMz9uj/GYHE0C8w2tCSdiGyNPBGOfUwPw4v3C/Tgg2Xm2+Izb28NSeMedzENYk0k7Fk3OYNhrDRjAx/IPI1+cxpWLuiRBDomNmET3VhAuHs2laAqKeM6iPyC7fCJqiq4XO8x1R+vo6DXzK1BiMe6ZhLn+A5DGMT/j32/gvFfJO5mBkS6x41iUTzLLo69+P6uxLvmiGCHRgXzSVgbmvmKqGw7J+QtfnCLedvwhosnjBXjkRhUBIZzJ0z+VrR35bvikub6N2ZbE2KRal32EMcYBczQeFjQmJZuRC+xBQ0DK3YJhSh564GMBdDVXXmtwY9PECkC4u353yNFqLy3cdvg== 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=NexVWWkDQlA5zImf0jfw62MXBphUWgkzhw+aGf4B+Dg=; b=c04wdzctcjRnySu+MnwqKmP6g6qiN75UVh8ns1RUHYrmHd2cZ311NuH5tOC5mawd//VqcIq0LCe/oTNmvSVd1vLuX3HaclhVS/138402pejwzsmkO8MM9Y0slfyfmMHr1+WVPKPo9jq7C/nTLHvAsSkExpDKfx+E7oEvZw3Ttf0X75zAzH1GvDhvR76QKCDV9xu8nuKpRLwmkxa/RG6tLCT0KXz8p+1egs1OJ4bFFjGOYfkXngoRiBRBGRNEnW9j2FxGbt+/gRSozrlLFZbkBpvrmR4hWwcv9KaHWDY9Rf5yonV+UYlmqeMYQ0y+XYuITJbg3/noUoMNTk4wESUCJg== 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=NexVWWkDQlA5zImf0jfw62MXBphUWgkzhw+aGf4B+Dg=; b=cxeRXbzf6ImRpf/exGpCkAe/edK8gOHbkYRoz63dNwUWaOVSwVfsfW/EyOE7Av2rOX9U+0WQzKKK4sOzv7UHkzROZam63wb9magfQpFCZILLei4BHqRwkqgocybwubc+MQPLqow808onm5O4fktWN5ASG279GkQLdVtLSYShY017gMSM8R0rKVrMKcnrcnqbpCJK5P7Jhoc7AFPx9C18Y0O81J78R8sUF0EU+IS5tS0YGVaIvQk+dTaXXLDNz5OnfCDSDP+q0M5W3WCsRiNDNGBBMO+eDvvUu5hEwiW5kxO/4KxqXotcu+U8OaT9evGb56o2NrGiD7l11BXDnnZ0/Q== 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 DS0PR12MB8272.namprd12.prod.outlook.com (2603:10b6:8:fc::7) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.9542.9; Wed, 21 Jan 2026 07:24:22 +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.008; Wed, 21 Jan 2026 07:24:22 +0000 From: Alexandre Courbot Date: Wed, 21 Jan 2026 16:23:54 +0900 Subject: [PATCH v2 2/5] rust: num: add `shr` and `shl` methods to `Bounded` Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260121-register-v2-2-79d9b8d5e36a@nvidia.com> References: <20260121-register-v2-0-79d9b8d5e36a@nvidia.com> In-Reply-To: <20260121-register-v2-0-79d9b8d5e36a@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: TY4P286CA0103.JPNP286.PROD.OUTLOOK.COM (2603:1096:405:380::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_|DS0PR12MB8272:EE_ X-MS-Office365-Filtering-Correlation-Id: 52cea01d-f486-4e9c-f6fe-08de58be1923 X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|366016|376014|7416014|1800799024|10070799003|921020; X-Microsoft-Antispam-Message-Info: =?utf-8?B?RUFiOTQ1alVwRy9vTDZOMm5UQnJDTHMwZC9SUGZhbkhpOEI0K2FxaWY2SllN?= =?utf-8?B?STd6ZDVYWllrVkVHMWZVc0NyTlZkT1JYb0gwbytJb2NDbWhWZUJmcUZXbWxo?= =?utf-8?B?cGdOV2IwTkdHVHZaQi9IalJsZUVmUHIrTDVGMUU0anlXR2xrUytGYTZJTVVw?= =?utf-8?B?M0VSV2VQMjJ1Y2tTSGswdUdhOE1IT2N1dUVKZTYwVkZyNndyalFraDJHSTM1?= =?utf-8?B?eUZKRkowREFDcmpMYmh6ZlJoQVdtdjE5M2QzcU5NdjRvVGxTcGRvSG5rT2VX?= =?utf-8?B?eWlkR3hxQjdPNEpCT0dDazNqRDBLTG02bU4zaklHa2ZSNEhwOUllM0ZtYUQv?= =?utf-8?B?d3FUR0M1WTM5U0FoNXRLcTNYcnpPT1RlNmFtSmQ0Z3BLMTUxc01rNjNrdFdD?= =?utf-8?B?S1RCOWRXR3BkcUxURWl6T05JcksyUzUzNklMTE50VjlzUmtoVjlCbS95SFhH?= =?utf-8?B?YWE5di9nUGw0U1BoeWZNRmd0SnhlWFdkbnJUVTIzYjZWVWxPRUZyaXFSdHBO?= =?utf-8?B?NWZDdTI5UmhDdjhtenlUZ2Jzd3pFMzB6T2Ezdlh0dDBQQnArQnVZeEtYY1po?= =?utf-8?B?UWpWUnhtVkdIMTVlRzRCRTFVc0ovZDRLaFpDOXk1WndBN3JsYklYRzJUekNm?= =?utf-8?B?VUwxTEdtWGFFdWJTN05Jbi8zT0YvMG5XYlVNN3lkcFlTM1J4T0VuUDlHVGJ1?= =?utf-8?B?UXE0dG50enhrdUYyUk5ocHVUZkxibk1TZEdaWTQ5ZmhXblFCZU5iTDQwYkxM?= =?utf-8?B?S1hWeGFRS1ZLNG9jdjZ1cUFseDlUWm0yWGJXeDQyekJRMnIxdWNtVFdxSHlL?= =?utf-8?B?SjJ1M3dqVUJNcDB3ZDdMYmMwWm5GQ1ZGYzFCVmpFeU5qelZYRTFVcnQzOGZX?= =?utf-8?B?R2VFQ08vbnFrNGpFUTE1dFExcVJCMlArVjYrNXBQQ1BZRENZMndvVW44WnRR?= =?utf-8?B?N3VXbXRtM3Vna3pBZXd4UjhUMlZyUVpQdjc2R0VUT0xVdU4rSHIzVXNWN3g5?= =?utf-8?B?L1REWVNnMmttU1czSjRVckdRbldncEJKMmNObVg0Z3JJL1lJODh2WnM2WEJT?= =?utf-8?B?eisvbXRFamZpREg5WUxnZ0Ntby9QWDhEM3Q5ejRzY2kxODlFK3RwdVNJMEd4?= =?utf-8?B?TGxENStySnI1Unp5enl1b2hZMUJqUXRmUFp3SGEvcWxTMHg4RmhNZFo4dnhv?= =?utf-8?B?ekdQUE9VTVlqT1BpcGFCemdzNGNwMWJaZ01YaHFUbGdtblE0ZXNQMjArUmhW?= =?utf-8?B?NVZydDdCNlgySm1QK3piWjBvSUg3WlNwVUgxTzQrRTVSMG5rNmY4cjBwZzNB?= =?utf-8?B?R3RiSVBENVdDK2R3RVR4Uis1S2RVNTdsbUxFZEhmR0JmaTFIZlVTTFhic3Ay?= =?utf-8?B?bVl2N3ZmWEdRU09ZUHJnRm9iRGlDWG93Z2FIOTkvK0dZN3E2MWwwMDl0T2hu?= =?utf-8?B?VnZjejN6ZnpKVlB5VWRWQ2ZrNmdrOS9kMmtMS1JxQVNEUUZrcUkxWmJ2ajFV?= =?utf-8?B?bVJSd0lpblIxNzRVRGg1WXhsMTBqa1RyTHJVY0tiWFNLRlNsUnlxSEIrOTQw?= =?utf-8?B?T0N2T0JhL1dIcGMySUdvQStDaXRGWGVCUEJFNnpMdng1cDNBZ05TRllYV1FC?= =?utf-8?B?R3pMYVVmUldmbjd1OUtyS3dHbTdtcWpZSW8zSDZRQ0Y1VFpjZlBGMzVRdkZZ?= =?utf-8?B?SDdSRm9kNWtZb3pTYmJ6QVZHWkMvWmo3VXFYbG5RZ1FwUHhuVGdUdHVDOUlo?= =?utf-8?B?MWJPQmtrUllYKzFKQ1RzYnNDakp4NjVjRzUxNTBpNmlWMlh1WGpQVyt5bTNt?= =?utf-8?B?UHB5T09XTVAyZWlZVzdraTRlVS83eGsra3F5YW5HYzlENFh2R2FCWHBsaTVs?= =?utf-8?B?UzR4dGN1cjllb0ZkMzFnUXlhOXFLd1NnWm52czJwUmVDazhwZGs5czVQbFlJ?= =?utf-8?B?OHdlZmo0b3hyWjFKeTMzS0VWWWxoSWx0elRKQ0VIUVNRd2gyYnRXOU5CMVBZ?= =?utf-8?B?WU54RVBUV0p2Qlk0SVVXQ0tqTnVhWWIzYkVVcXBJQUlIclBRR2tQQnVkc3pD?= =?utf-8?B?U0JSc2JTNTNxeEJxR2hnZ2VxRWUydUxjYUJIY2xXUEl6R3FYNnFWSDdvUHZ6?= =?utf-8?B?MG1ZaURDb1ZFVUE4bVNlZDd6MUNpL1NGTHBpd2FIMWE3SDB3QlZhZWZQUUlm?= =?utf-8?B?TVE9PQ==?= 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)(376014)(7416014)(1800799024)(10070799003)(921020);DIR:OUT;SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 2 X-MS-Exchange-AntiSpam-MessageData-0: =?utf-8?B?czcxWDRZUjlDYmFxb3BQR01iSTR5dDFmdUIrNFZkSTFNbHRiT1ZleUY0aUhp?= =?utf-8?B?M2pmV1BINkIxbyt0bk5sREFKd2F0ci9Pa1l6eHZaclhBcVlBYkxRNlJPaFdI?= =?utf-8?B?QnozTEhUWVFYd3MwTGFINEN2MXNjY1pmYUFPakg0U3E0WlpRSmJvMzhTR2Ja?= =?utf-8?B?Rnd6MjUzbTRZdGY4S0dlUTRFZmJNSDJYaUZHeFdQNnBkQ09XTk0xREExMTNh?= =?utf-8?B?U3lHVnl1MnIzOGwvd3VCTVNMNVU5ZjR1UHJBMXNVdWdKMldvWjgvd0JoTWZS?= =?utf-8?B?S0l5T3VneTFhZDRET2RXSnRPZkd0SkJWeXVVeXZQSk8vRSszMkxjVXluaFdx?= =?utf-8?B?MUJCQk9wdE1Kd2I2QkdVNHRvWHQ5ODdrMGJWclRCeWlYN3N2aWhvU04wbDJi?= =?utf-8?B?d1MzMDJxenRsRXRSdUgrd0JLYWJGU0haMzZZOE9vcGJVeFhaMHltaDlPNWhW?= =?utf-8?B?dVBLbjF2cHRMNmNHcG1kd1REMWdCVUdSS1ZPbUw2UThaU2FLZWRFQUNDTFpw?= =?utf-8?B?Nm5vTlBsekswanJIaEpIb2FQeFpkdGpOb2tPMUtVVFFBelQ5RUwzQ05qR1c2?= =?utf-8?B?aVlGK1lDME5xREtKQUlCTDRDMncvdThqZmh1eVNVT2JzK1dLQ3JNc2crK2dt?= =?utf-8?B?bzlySjc5cUh2aXRsNG1rTXdlK2RHL2NoUHZVSzlFc0lkVktYRzc5SXpOalNV?= =?utf-8?B?WEMrTlU4eWVpTWNiYWhCQjBsU2FrQXE4d0hjNGdGeWZ4K1dqZkp0UTg2WlRm?= =?utf-8?B?Z3cxWE5rWkdCd0Y1SFBuWjNZSDBVcWVFZTRpalBibG5tTTg3TGRFYnBlUUZm?= =?utf-8?B?SDRMTlovZUt0RHRPOC9ycVlNbG4wRm1GazE1cll2dVVSYVo5L0FNeGV4eU52?= =?utf-8?B?LzZyQ1Y2ZFJOVGticTgvOFRPWjd4TGpSWUlhWXRRaWU4R3lFVmorY0Y5cndF?= =?utf-8?B?QmtEdEpzNzNXVWNpdHhqdklMNFRXTFZrdUpSU0tHZUpyWkJ5Q0c2NEpYVTFL?= =?utf-8?B?bnhVT24rSVZGMUt1dk5FQVRpK1BwSytOaExnakw4L2dPSXJFbDlLNm8wWHMv?= =?utf-8?B?ZHg0Zk50K3JYNUFGVEZXNWJUTHBQYitJNmd5QUI4aVdRbmVjVVdCbXJ3TzlL?= =?utf-8?B?a2hMVlZVZVI0aDF2QmU1R21KK0ZLdmJOTmVmSGtJZDJScnlzRktCd0FpZmpm?= =?utf-8?B?SjRtdVF3T01OVVVneGZLc2xRMFlpK0J3UHFhUzJxZDNIeitNdDZKaHpna2Vp?= =?utf-8?B?WkEzb1BmT2J1UW4zdVhBM0xkVzArcXY1REF5czAwWnJkYmxZZ3R0cmN2Zklu?= =?utf-8?B?S29CQ05Rd1VKNXRuejZucitFVU9kZUJNeXpmRUhPYjQ2OGxycENoL3dWeFdU?= =?utf-8?B?Z2VzTDhKUnd5eTZ6dWEyT0pWMHZaaFJHTHVkdTBZSTVOaWlpUjZUR0Q3b1Zn?= =?utf-8?B?SFl2UnRNaHlSVi9XTndqZlpDRC8rS2trWm5Oa2VibjVSMkZKcG9GRHIwR01v?= =?utf-8?B?bDZzZEtXek9ZWGlHaDB3clJ3bzJsRTB5RXZkZ3pvMnRYYkcreVYxd25ydm42?= =?utf-8?B?QkxWTGZxbzUrSVZ1dEJRbjBNOXBhYTBWeXZzTXhibll5Z1E4TlpWdkxZMGJu?= =?utf-8?B?S2VaNUU5b0dVblJxMVdMNTRkNXZoOXV6RjF6aUZXTUpJVzVFaHB3SU0zMU0x?= =?utf-8?B?N2d4d0NjSEJBc1FiYkl2M3NVYytRSUpmcUlHbmZzZUF1WmZnQThTanBTZU9s?= =?utf-8?B?ZllmWGltL3NRWTI3S2djNGhIRTFWc2FDWmRVRWYrV3V1Q1BvK2taSE1iL2Q2?= =?utf-8?B?cHIwek5XbWo2clYyK25xOTNMUUpXOFlPQ3V6d3h4b2RmeXhuRG0rQm9CSkpR?= =?utf-8?B?RkE3N1hGWHdVSmFxanNCVWlyakhWZFBEdURwN0RxYk8rWVhyYjcvajkzZk1M?= =?utf-8?B?cXNJSnEveG5pOWtuSmtFWGpJK1d0VGJGMlZuZ3Fkd2tPNFNuVFVEN2FZRkdI?= =?utf-8?B?MWM4YkJ2NzhROUd3OGp4eTZkS0pYNi8zc1F1OEhPb0VKL0wzTXZJZFBUSk1H?= =?utf-8?B?KzVjQVBCam1BaDJMSDV1dDk1Qk0wMGFwZjRWVlhQVG4rUmpobFBCYnhxUUtx?= =?utf-8?B?QVQ2K2hxeWN4MjlXdGFoOGZmbzNsZ0k3WG5vVFZCS2lvZXFpR2pxT1ZGd25L?= =?utf-8?B?aGNTcE11Y0prZjUwTHVaNFprR0Z6MDNYM09YV3dSSE5paTFla280dXBJWGRS?= =?utf-8?B?Y0pkODBxSWdOSStINEVBUjNLMXVxeWxUSGV0ZmM5akFrSkUyaHJyNzlnSDZC?= =?utf-8?B?Z25XcEdDS0Y1RXpPUlg2a05JTktXaVRTWnZSNC9jWTh3RXhVOFdLdkVvT0E5?= =?utf-8?Q?TMi6PeeB3X0+RuQpl6cSczNo7+J0BKB1qMVLYB0Vbu34d?= X-MS-Exchange-AntiSpam-MessageData-1: lHedLs+nUed6lA== X-OriginatorOrg: Nvidia.com X-MS-Exchange-CrossTenant-Network-Message-Id: 52cea01d-f486-4e9c-f6fe-08de58be1923 X-MS-Exchange-CrossTenant-AuthSource: CH2PR12MB3990.namprd12.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 21 Jan 2026 07:24:22.3145 (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: xwdKQB91xKHg8Y2t21QUSXriVb6287y7R/0MmcMjL/8kFAaBRq4GMrjEGEUw0PhPskbsSuxpxr5fZY/JJTCHCQ== X-MS-Exchange-Transport-CrossTenantHeadersStamped: DS0PR12MB8272 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 Signed-off-by: Alexandre Courbot Tested-by: Dirk Behme --- rust/kernel/num/bounded.rs | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/rust/kernel/num/bounded.rs b/rust/kernel/num/bounded.rs index f870080af8ac..8782535770f1 100644 --- a/rust/kernel/num/bounded.rs +++ b/rust/kernel/num/bounded.rs @@ -470,6 +470,46 @@ 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<_, { 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= <_, { 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 19:41:42 2026 Received: from CH4PR04CU002.outbound.protection.outlook.com (mail-northcentralusazon11013024.outbound.protection.outlook.com [40.107.201.24]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id A25DF45BD66; Wed, 21 Jan 2026 07:24:28 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=40.107.201.24 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1768980270; cv=fail; b=Ai3H+eFrz+k2noqpBxFg8mKrtee+Zelh/TeU1rVIEGOk9X6yj4GZ2HWzdmS6H0zbAHUrVz9LGsnYzifBAewDegOyC9y9fu+E2VbL9UeJb4cxeU8WjG9Wr9QfD9ZSUKo/6mBfBwxnJNGhQQAjYSIlRKg8KozHi0FLt1oksFKDhuU= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1768980270; c=relaxed/simple; bh=w1cn8kq/BrGoinnMSbJko0juqVpYOQHJtsllBiFWSFg=; h=From:Date:Subject:Content-Type:Message-Id:References:In-Reply-To: To:Cc:MIME-Version; b=UPayUgS7tE1QbmdK9APx5DOEcHONAAzgXyRJHQcB+qF5xbbQNkamvZAFlIJkfWGBrv5Lau/keHFRlFII753UApNfSJ3+aLVn1D6M9IYJlq6lxlolkNZ/8l9rB5nknPLWFH89To6mm6l3QeEswxgF9V/orwE3TOcu4NnOhswfNzU= 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=Jxp6KMXH; arc=fail smtp.client-ip=40.107.201.24 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=nvidia.com Authentication-Results: smtp.subspace.kernel.org; spf=fail smtp.mailfrom=nvidia.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=Nvidia.com header.i=@Nvidia.com header.b="Jxp6KMXH" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=NVGbYQpVyA+OVeCd+lx8BkdmrIDCuHQBSAYKlm1IGY2T2sT82VxZ5ijg/LkpE9m4wxzbFeaNRn3jxp91CpX7djBlLOMtxnt1SY7hFsWl8dzE7eJgry/dJx/MjeOuo/2t4yQzfjqm+FmdGFTfe7VzvvprrHWW388jBAS9hj5TzltZbeNQNcENOHXuuZk6DprZI492WTtla11xBOEOMrMpg8TOPXaTzfnHXj9ycYHd1FyJ6ssKwU81CgHWp9HUYJYxysYUCqccfRtCSHZPW6H8j+3eml/FsXbwJGfGBboUBpec/fpK6OUySBOO94sftFkTvrWU1jPvivojGInKG0DCRQ== 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=cQ6GPSb2xvEbZTbYjfsUpd4o1OXGcJfKeVrmQqld0+8=; b=hQQVd6mEjOxegYOhp1QX6sV85oLNFqpcSxC15wjr4mP+TB115kAE6W2N1Bpx4N4IkrpMIKWNrxtqTOz1eCTXjktG2X4+NyZ0e+BK2a3P7xLq/rewfCq7E2jM3l6pQFtpzwlnCIAUerrbG8lRd6QOL5dDFxcMwxfwdqK9/r07x5IqHKGjjS5DqhcO3+7wF47hpWYc3GWVeCKcz6rGNJKp6LdiAicVC2tHd0hGxInZ3fe/8GYJDPIPVXE+G90ZfuZOsYSFAsKdyYGSwQlIjX8xOyao9qILLmZ7TdKsTzR8nSk/IA/N/Vtsury7uxryXH8m8sb5WBjbTGefDdXfo4G48Q== 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=cQ6GPSb2xvEbZTbYjfsUpd4o1OXGcJfKeVrmQqld0+8=; b=Jxp6KMXHoO8oY6VWG4/d4fA0a7SRu5ZRtc7vSb/MawQeOKJpVdrIxQO8yFWAHMYQarvYBptDQzN/12ZN+UWgkHL2EHKmbtoPWct+McfdvZpR6P9f+L/38Uftw2wAgwjLhl+G75CkEVBMxQQnAlIZaPc9pJ6D/3vPH7XUSBmvf9FvmvieCUuaYUa9CzsSEZFXfFdDLRcyAAqmiwW3dnjeqM+m518X7ZqRraBtU6ntiSLAvLU+loOpwRzDc4RPkeqoj2i11fxf8WPGBvXIq0sEppQLCnOKt2L06MKSYiFmyTtzDr65k9p8nr3+DG5v+tXHzGYjsbtUDgmUSClMMjsKtQ== 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 DS0PR12MB8272.namprd12.prod.outlook.com (2603:10b6:8:fc::7) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.9542.9; Wed, 21 Jan 2026 07:24:25 +0000 Received: from CH2PR12MB3990.namprd12.prod.outlook.com ([fe80::7de1:4fe5:8ead:5989]) by CH2PR12MB3990.namprd12.prod.outlook.com ([fe80::7de1:4fe5:8ead:5989%6]) with mapi id 15.20.9542.008; Wed, 21 Jan 2026 07:24:25 +0000 From: Alexandre Courbot Date: Wed, 21 Jan 2026 16:23:55 +0900 Subject: [PATCH v2 3/5] rust: num: add `as_bool` method to `Bounded<_, 1>` Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260121-register-v2-3-79d9b8d5e36a@nvidia.com> References: <20260121-register-v2-0-79d9b8d5e36a@nvidia.com> In-Reply-To: <20260121-register-v2-0-79d9b8d5e36a@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: TYCP301CA0057.JPNP301.PROD.OUTLOOK.COM (2603:1096:400:384::8) To CH2PR12MB3990.namprd12.prod.outlook.com (2603:10b6:610:28::18) Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: CH2PR12MB3990:EE_|DS0PR12MB8272:EE_ X-MS-Office365-Filtering-Correlation-Id: 7d5c686a-1241-4831-ea01-08de58be1b3a X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|366016|376014|7416014|1800799024|10070799003|921020; X-Microsoft-Antispam-Message-Info: =?utf-8?B?b1Nldno4RzFrL28wSVFFRmtxUWxFaEhHZHUrbHRmR1Q1RmtqcVBoQWhaRmRj?= =?utf-8?B?djlhK09UQ0RtVnlER2k4Z2h1bGNlL09MOUpSKzVzci95c25RR0l4ZnZaYy9n?= =?utf-8?B?M0UyQlZlSE5rQXhpUURac1ZHWE5VSWNXMmd4c2pCYmc3UW1CL2lheENTTHp4?= =?utf-8?B?RG1zQ09pY2xyR2w5QklLNmtja2VrU1d2Z0NUUlAzdk5ySjZDczQwZURJQlpR?= =?utf-8?B?UkZqMWs4eWl3VDlQclFLNWptSFRIMTdweGhIUW5lZnFLbkpvUmtJRVFVbDFM?= =?utf-8?B?akYxdlgvTHN1d0JyS0JHT3RXS2ZpT3ZJTGEwWVNMMFF1b1YxYjlNSkdXdXZH?= =?utf-8?B?djhkQTZsSUF5UnJHclpqVFQ3bUV2dnNXMkV5cUY5VHd3bEFjeld3VTlkbmx5?= =?utf-8?B?ZGVOTFlDeTlFZ1htTkRrSjBKR0tYbXdCb0VUMGYwR1NjY1JpRThUa21oZlNM?= =?utf-8?B?RHBPRXVIUmFZaGNmQ1BtcWVqRXRaMFZCdU91NlhQemFYKzd1SEFnWERDRHE4?= =?utf-8?B?Yk53dWUwaktvL3hCaFJSWVN2VUNGYy9FRHhEc0RIVmsxaVRKNlc0c0kzekcr?= =?utf-8?B?TEUyVWN5N2JCOUN4TjBkUngrMXhUQndwYnFZcWl2RS80UVMrRWVFYTZqTUNw?= =?utf-8?B?RUk2VmlVVTNETmV0Z0FwdDVmY3ZEeXhJZEdNMHB0WEJRR2ZrU1FMRWsvTFJ5?= =?utf-8?B?MUhlT3dUdGRsQ3MvQkp2SWVJekZ5akEwYjNneTE2dGVROWJBb2ZCUERzUDBk?= =?utf-8?B?TGx4RDJ4KzJrQVA3YzlNUDFJMlNncHErZlE4WVpucDdiZndjRVNwNk1EMjhT?= =?utf-8?B?c1VnbWVwa3VFWkpRbDlVMnNoS3FncnZkeTM4STZJMUpFOVcvYkYzcXZEK2Vs?= =?utf-8?B?Qk8rQWxrWkdWbmRsakdMalFSUko5ZllhaXorUHFRNG5oNUZYck1kTGk3bnJl?= =?utf-8?B?RzZNRmg1UXdTQUF5RkhmSmxKZm5uNy8rcHB1UVNLSUdlNE1Db0FjWXJtdzZp?= =?utf-8?B?eUR1bHc0endXRWNiSlZRUVRCUkRoSW93SmxqSW5wMEVnSG1vYmFUZEVkc1la?= =?utf-8?B?T3paNlRBRnR4elJDaG9VSnFCNnpkNHJ0Mnpvb0d1djJadk5JNHNjTzBwYmsy?= =?utf-8?B?cDNZNnRUNDhPM2ppamx6bDRlelR4bjA4a3pTd2hRb3cxR25lTzZPWUc4SW5W?= =?utf-8?B?RUJGVzJBZlBsbkFGRzJLN2grMkVRaG9rdE1PRlZIS1ByS0I2TFA1dVJCZi9D?= =?utf-8?B?NXZJYnl1ZnYwTUN3aUdNZXBRZ0ZxeHEwMFB1VjhWTUZpV3BLd3pRV3ZaQUhp?= =?utf-8?B?clBmcm5NdzhqK2NxV1ZNaFNydnIyUVFkYit4cVo1bzI1aXpVNmN2RERKQVZ3?= =?utf-8?B?dSsvWlVCSnNBc0dGdHJZMDA3aDBOdWh0RlN4dXgvQTVEbGh2WWVybEs3ZmFk?= =?utf-8?B?NTJwdmFXajR1WXkybVhwcEVManhuZkxySGh1cEk2ZDZjZXN3WnR3cmFKTjhH?= =?utf-8?B?UlZEdkQ3bEwwdEF3WVlmR0FjU0dkWWhzMVRkRTVValBkODZYY3BMbGhGbVUw?= =?utf-8?B?cGlzMjZnUTNQQ1VMZCtYSE1qenp0ODlJRXpGRU1TRHBjZWxMejhURjJ6N0g2?= =?utf-8?B?Qi9zSHgvYW9GT0QzNTRnU0JzdzlTMm9OSU81QXBFK0VyOWgrVFVpRThHdzhz?= =?utf-8?B?VCtNdVNXVnpRQ3lodnJKY1NaUFdGc1hFUWFrbHB1TEFVN1Z4TnF5bWFETVhE?= =?utf-8?B?VVIyK0d3bExBZ1V5T2ovOUdVNjF6a01JMGNLRTNTend5em5SU3F6Vi9IR0w1?= =?utf-8?B?QTBTTkNwRUYwdGJUSEMxaGY2WnFieWtRbmZlVUxQM3NzY0dGRHVOWGhtZkRJ?= =?utf-8?B?UEVwUER5dnd2OUluQzhsZ0ROMHR0MEptcGxFNHVUWFNQY0tqR2p6dnVtYmUx?= =?utf-8?B?K2YvZzdjbnV5L1V2SkF0YnRhbWRlNHp4SGNUVjRCM2tUd1ZqL3k4aDVEamU1?= =?utf-8?B?bCtQMmVXODN2OUNKQ1FqeDEwRmw3YlFXMXNvaWl2QlpvWUVmdkI1Witwa3oy?= =?utf-8?B?TEJYbE1qbkVacDB5OWwvbDFKaC81NnVlWVNwRUw3NGsrTkovNTZzSUNGT0xU?= =?utf-8?B?UzRJRS9JK0d2cVVFMGJaNE82YngwR1ZocTlnWGErZ1BRZExOTytGU1IxWXBQ?= =?utf-8?B?eVE9PQ==?= 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)(376014)(7416014)(1800799024)(10070799003)(921020);DIR:OUT;SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 2 X-MS-Exchange-AntiSpam-MessageData-0: =?utf-8?B?ZDFWM0FlWmdWeFJuaGV5YUNYYUpWM2NWWVhnOVg0U0hxWm5yQUNjWDhNTnBy?= =?utf-8?B?Vi9tM1grWHBSSFkvZ2paN29aWHR4eEQ5R1owMGoza1JzOGZENDZiTXdoSWV6?= =?utf-8?B?RE14cHdsVDgvTWtkYzJ5dUdvVno2a0lIeVNuZmx3eDdCRzJKS2RDWDlYWTFp?= =?utf-8?B?QkNjdHNiWUpXcEFDQnIwcFZiM21tejZUMDNjM3ZKVGFBUnIzV3ptMTRWaDd0?= =?utf-8?B?U1hYOHN1SFc0ZVVwK1RidGUyMC9VVUhuZnRZWFVON3p6amJVTHZTaEY1dmpP?= =?utf-8?B?LzZtT204UHFhYVN3dGhlTUdZTktiQzNmdGwxRW96SXFncTVQTTRmeFBTZmlU?= =?utf-8?B?MVRDWlJ4NjB4bGQxRnFWWUVpN1c1RGM2WENQc2QzZDQwTXRZdm82MHhzUmFs?= =?utf-8?B?cCtKUFZxdWJLM0dJUDJNV2gyZHhyVjBjY0JhNWY3ZFJsVWZTNlJ6S0w0cEdX?= =?utf-8?B?U0JJS3pwU29ZR3YrUncrTS9rNHh2cXM3UXduTjdNU05aZnFVOFp0TzZPZm9m?= =?utf-8?B?NFcwTnNFanBKdEZ1bWR6dkc4YVNCUTFSOVdEdjJGNlM1VE9VVzV4emZPSy9B?= =?utf-8?B?OWsvWHpNY3BtajJRalNLVzlIMCtqUkk2ak8rS3lyVmlkUGpWaGZMVjhMTHVK?= =?utf-8?B?SmgxT2k0RDAvS1Erc1VlblFVL0o3QzV5aGRCc2lNTjREU2t2WDExdjVMM2d6?= =?utf-8?B?N1RrWXphS01zMnBNWGJJYjJ1RjZtajcvZ3RoVGdBZUxJUjI3c0V2QTdtSE14?= =?utf-8?B?bUFaZFloakcyZ2VUd3oyZXc4K1QrNy83emppemhONXFQMnVNV1kwOGR3bVdj?= =?utf-8?B?U3FvRENaa1pxSVlnZ0RMaGRJcFVURmJkVTFjVjJScEtqaWNvYkFzWi9UQUU3?= =?utf-8?B?ekhzM3gzSmF1K2JiR25mLzNzMUwrc2wrckFjREduOGVwU3VKUXdEaDlKczFx?= =?utf-8?B?OEtzT1gvWVBRMUVsVUh1L2F4UlFrNEQyU2hzVHQ5bjMwVkd1UFRYTm90ekQz?= =?utf-8?B?MW9YUno3U2wzdlNuS2lTZkg4MkFRSnc0U2o4c0o4dkNvN05qU0NVQWFjdWti?= =?utf-8?B?ZzVjYlMvNWRlWU9LbHY0YVZYU3JyK1F3MVhwK3hSTVRsZVJpY2c3dmV4VUlF?= =?utf-8?B?bDYvdUxiYnVMYnFIOTlmek1LOVJXV2plQmZrYWR6K3JmakRaU0h6OGJMRGRw?= =?utf-8?B?WWVILy8rSXp4cU9YN0xpbzFMQm05THR6dUErcWZ3QkpqZ3RXRk1tdnFhcno2?= =?utf-8?B?YjFXKzJqL0Z6Yjd3TXJ4WW9TczNkTmVMYm5xdEhQczJPQWN6VHppY3N1dmhT?= =?utf-8?B?akhxV2lnK3I2RjFIbXNncXFyZ3JWWkJ1SFMrejZoZnFlSFFuSE9pQXkzL2dF?= =?utf-8?B?UUpBZjlOWVhyWHEwbEZuNkVaQktBTHMrb1lCR0VDUHh5U1lPYXk2aCtXT3Iv?= =?utf-8?B?ZnJacVhBS2trZ20xTllqY3p6VkkwbzJhcGFZbS9NVXFQVXIrRjFrOU5PWTdv?= =?utf-8?B?V1I0MGRIOWd5MXZmcGhGVVR6UElsRDkwMkY5M2tpOGwrdWZscEVkTXd5bjE1?= =?utf-8?B?TFg2MUJ6anFYTmZheUN5MFRXVkVoVUhqWGdzLzNaN3NwQVFaL3ByNXBheDFK?= =?utf-8?B?cEpKMTFpZTBxdHNKT0JOT3pNcU5vZDF3UU4wUUFKNFpsZWtobHAybU5GVmV0?= =?utf-8?B?TThDc3dtanNrTllIWGl3MzNLT3EwU0RjY3JvQWFzRWM5MFBOV0ZjRzhzMzZu?= =?utf-8?B?aXBHdUFGaytIbGJVY1hPU1MxNEV5eFBMb2ZoZzg1aEF5cjlJSTlTRVNHR3do?= =?utf-8?B?VUVUTk5IeUhDMXByRlJNYm1zYzhqNjQ5ZzRKRDlLdVl5MUVadVpwQ3R5TkNy?= =?utf-8?B?TnhhcC9HVWRxd0xKOVl6R1dwOEd2ZFl5aTB3RlZLU1dmTHBmSWxPWUN2SDBO?= =?utf-8?B?WmlCRTJtcm9QVjB5WGJKeStVNVQzd2ZaVUhMVTRidXJLV1RONnZLTGJzK08x?= =?utf-8?B?azB0b0FSY0JlQU9EK2VIR21qV1hrUXh1RDA2WjJ4aVA0SExPTkQycHZ4dlV1?= =?utf-8?B?TzlRWTdiOWxvaGQ5YTFJbGhDem92dko3bTI3dE4zL2xMSGNFeTljdmwyYnNC?= =?utf-8?B?TGNJcVZmRmN4M1V4RyttK09DNkFxWFdrN25YOUFaNGhUdC83ZUdXRXkwUUFh?= =?utf-8?B?S3dZdzR4MU52dGU1K2tYTGRrcUJGM1BXQ2tpdHZsOFpYc1dNUWdJUmZGdHNV?= =?utf-8?B?dTRKTXowcnJIS1JQeTRtRTI1bitJcmdJUDVtbHpKazRVUnY5bi8zVFI5Njdq?= =?utf-8?B?eCtZNGVncGJVS1QvenF6RjlVNExYYi9zSXozODRTd0lLRkl1dzdiSFBEQmlq?= =?utf-8?Q?OmyZlykJzRb1y91I4qs8dB1y0zcVg0OMXMtuiw8/vq+XM?= X-MS-Exchange-AntiSpam-MessageData-1: aqnPcP/poccShQ== X-OriginatorOrg: Nvidia.com X-MS-Exchange-CrossTenant-Network-Message-Id: 7d5c686a-1241-4831-ea01-08de58be1b3a X-MS-Exchange-CrossTenant-AuthSource: CH2PR12MB3990.namprd12.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 21 Jan 2026 07:24:25.8201 (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: mDiqQCb1ilX1VqFX+HRAttGmfjmZ4Sx9HogPomRTXdsccaoiBR7TCFCACpXSUaHJXJeH7DZmXKLErLbkVAksmA== X-MS-Exchange-Transport-CrossTenantHeadersStamped: DS0PR12MB8272 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 Signed-off-by: Alexandre Courbot Reviewed-by: Gary Guo Tested-by: Dirk Behme --- 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 8782535770f1..8407606f2fa7 100644 --- a/rust/kernel/num/bounded.rs +++ b/rust/kernel/num/bounded.rs @@ -1096,3 +1096,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 19:41:42 2026 Received: from BN1PR04CU002.outbound.protection.outlook.com (mail-eastus2azon11010011.outbound.protection.outlook.com [52.101.56.11]) (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 3F00B45091F; Wed, 21 Jan 2026 07:24:38 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=52.101.56.11 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1768980282; cv=fail; b=aU6muGAWfH1Iq2YhKX41/BaA/Au1o7Yrb3PIFb4ZtUIlsl6cdO+klrms3rCGl2ZZ6mxxY5qwotK4H7L0OBmF5sZm5kgl1yowJqwW0az72x4WzybBo4iiggcN0f0ghbCwfFZ3AwnixX7GPQLlbZqWDK82i0gicPw4iTyXjm5xhpY= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1768980282; c=relaxed/simple; bh=jwDNtk9OsX29eCQwgUtAYZE0XkL1rAyEt8OT3AFDots=; h=From:Date:Subject:Content-Type:Message-Id:References:In-Reply-To: To:Cc:MIME-Version; b=QbnOpgg4UjJiHZhG78JDAg/bR2tYkzqFwJHetug3eegezuDXr26tsjRTlXRUQPjIFhMqInRiwffJ5gagEXKFCwxj5FtQnzq/RsxQAlSiVs0xVx/+Ycd+ZnrzgtTK7246ujpsBtEPwiGDqaDkPO7xM2tPkawpMP5xPdcDD7g9Brg= 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=bQScDoCt; arc=fail smtp.client-ip=52.101.56.11 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="bQScDoCt" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=u7locDCG4wqTgi6/T7AslthqFPN40lCRBBA4JupF5hygNDSZs2FLRzi2DxrHFJJ3dhc/65Aq0XRgQsDN5LKDidtzMd6+yuG62QOFWfSZUkRWU1UKqKgsqmrVJgtWMEE/m7n8S1iYHwiM/EL4X6S7mwY1NjhDYkyvFrDup4EovHQh7VMmcQJeDB1jYBHwSnr7vNQ2yi71pD06tan/X6KKCS0VUSK8T6w3k8HV4ZtLTiPW3mJMZn2F8NafSsvs0OazNgzodvh63WXo8VxOA2kzg3GYHSg2SG44N9tEexJ9wH1JlOsXVyl/XQoI5N/O6hNmvM/OynylopyRBu7RFAxbXA== 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=qgPdXLNesZw3etccU1i7jLaVS0pP2U3FeEQU3aJq4pw=; b=pJh0ujyxOCYvqp0WwMhvzBJohmsiXHAG2BC/hG5t9sWXORXsFqcWuAvpCGUTOV+EZTe3pEQ4olRxXWUeBoIAiz3+X1sR5AcZO1OKuA5oh47Kou2FyJ8dVBYVrcWs0rkH7bu6ppJumqKTGZFdBmGyFLq+AwhGN6aJS6VcuuvpplDTqQjsaHfzeWkSLscuq7MmTaETyXkGv8KCNLdpOo9/IMKPQVZCEp925DyruD9Ux3rHC0dGudeEYVpN8zS5Qnlxsr4BAjB6mrhPR9XWQ6rzwIwQkXHrxiCHe8EzaKrTWImwmG2Jdchm8penEVpuru/m4slUuoUr6Azj7uLSoqaUig== 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=qgPdXLNesZw3etccU1i7jLaVS0pP2U3FeEQU3aJq4pw=; b=bQScDoCtQ8edWJIW+NjTApU7xp+rBQhNTT03tyPMwC1UlSdBEbh1LHTahjDyASavWKXosSBkg3+WUkjG/fICSJBEbzgbkqpX3kl9L2juUV7x7maR0A7spMBVQ17c1eoa/HDCIT0ra/XEvtGTn+pmTbgmbbMXJlns0bEmWv4KcRTFJe1oes0THMi2XXNYe58iDQWVPTQ8ltOZjaYGmEqbtF/Eh9GVasYivoRXC66r8u+E/0WFfRnK3u0QJX3uh44bAn3Bnn2qPr31LScCyVGOCtcjuIkq+be6lWSblom4obw82ZGzGlcKzDd5mlyTQvlYjl8Uomo3nOih9XTLroLADg== 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 DS0PR12MB8272.namprd12.prod.outlook.com (2603:10b6:8:fc::7) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.9542.9; Wed, 21 Jan 2026 07:24:29 +0000 Received: from CH2PR12MB3990.namprd12.prod.outlook.com ([fe80::7de1:4fe5:8ead:5989]) by CH2PR12MB3990.namprd12.prod.outlook.com ([fe80::7de1:4fe5:8ead:5989%6]) with mapi id 15.20.9542.008; Wed, 21 Jan 2026 07:24:29 +0000 From: Alexandre Courbot Date: Wed, 21 Jan 2026 16:23:56 +0900 Subject: [PATCH v2 4/5] rust: io: add `register!` macro Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260121-register-v2-4-79d9b8d5e36a@nvidia.com> References: <20260121-register-v2-0-79d9b8d5e36a@nvidia.com> In-Reply-To: <20260121-register-v2-0-79d9b8d5e36a@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: TYCP286CA0108.JPNP286.PROD.OUTLOOK.COM (2603:1096:400:29c::14) To CH2PR12MB3990.namprd12.prod.outlook.com (2603:10b6:610:28::18) Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: CH2PR12MB3990:EE_|DS0PR12MB8272:EE_ X-MS-Office365-Filtering-Correlation-Id: 07cb4f18-b2a9-4b1e-98bb-08de58be1d23 X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|366016|376014|7416014|1800799024|10070799003|7142099003|921020; X-Microsoft-Antispam-Message-Info: =?utf-8?B?Y2hGM2F0ZjRRVGNLcUs1Y0R4TnI4N1FuUWt5VXY5ZVkzNnUyYmFDRnRlbWpr?= =?utf-8?B?SDk4WUtjb2tMV0I4MmNhK3ZsVnpBK0t0N3pnNkJGL0M2WU5yRHRiSXk4SFZ0?= =?utf-8?B?cC9yVEg1SjRWWGROb3FaVDg0d3VlQWtEY0t6TEtjcDZrMVFManlBRW5BSGdI?= =?utf-8?B?TUl2cGROdUJ1Zm9Wcm1iclZtVk9yM3dCRUQzbm03VE1jcnRzMEdSaUxwY0Ex?= =?utf-8?B?NUIzYjVPNXpLU2dGbCs2Um9FQmI3QUJOelNPMmJXN3djYUJ6UzN1NXowZ0Jv?= =?utf-8?B?Q1FzZ3lTNlkrLzNZdy84YlZwTDA3OUJXTzYweU1LSGY4eURmbVpLSUNHQmtr?= =?utf-8?B?bWRXazlzMUhwdWRqTXkxQnFBRWhWbXNKdVBGWDVBTzZhekRDb1ZhOUcxcXdh?= =?utf-8?B?VTdJYTZsZXhpZ1lzaGQzUG1GNGNLNjhETHhXMmhWYkN5eHltZk9LSVN0bzNt?= =?utf-8?B?N09oTFZmU09BTjZyRjVaUW9OeWZqUWdQRzhKYUFaME9pYVZiYjBVMVl3OHRt?= =?utf-8?B?QWtERkpMc3lRdEZJVyszcG1FTzVxanJyeXNWZFg1QnJhVmxkOGR3WVJaRkhE?= =?utf-8?B?T2ZJUXpHY245SFVCV0Z2TFNqMnFoVDZQZWtTaGhQT21TRlpaWGxqeVBEWExV?= =?utf-8?B?aGJab2dscHRKMm8ySzcxT0Z0TXJQZG1LZ0ZRWjMzN05YMnRiRFVHL0JhQ3dl?= =?utf-8?B?bCs5dlNlbHFncjFLYUNhLzNzYTJIeDRnNndUcFEwM3R3SHp0SFVGTW9mTUJB?= =?utf-8?B?WGg2QnMzemJFTlAzc1lEME55UGI0S05peGVIY1ZZMmNvY0xTRkR1UzhrRmJK?= =?utf-8?B?YkJ2N0MwbWUzdWJDck1sZStsTUJ6S1diY01OZTZodkRzbmNtUXNKWHBRREN1?= =?utf-8?B?c2tjYWtHZWllQ1VrcWZoRStXWWVwQ3E4RnhXTmdFVnVYZzlkZDBNQ01FL1Jk?= =?utf-8?B?elVrK1RkOFEwSHdVZXg0MStQdlNOSjZJS0pvcVo2T3hFRGU1RUY0VWdLVU90?= =?utf-8?B?WklNTng3alBuV1pqdjJFV3N1b3VIbmNkU1dPbXkycnJPN0FzbXpJN1pHb0pZ?= =?utf-8?B?ZlVFNEF5RnhMSS9UbXhNZFg4OStySGFyRlJLRVkvMWNCVUgzZTU3QkEvTFcr?= =?utf-8?B?aldDYjFsVlc4YzBWL1hQOUZVZVcrcW5HZjh1NDE1TGFMWFIvb2pNV3RCZElm?= =?utf-8?B?b0U5Ly9KK283ZDBVQ0pkd1FFRFpoUHlsdXRMbkhmalg1QkFiN3oxMGlnODZ1?= =?utf-8?B?UjR5RDNLZjYzQjlWVC93ZWtzVEdhVFlZY3BPSTFmWXA5RUV6QUVBNmozUFow?= =?utf-8?B?djJVK3RrcjJPd3BJQlpWUlpWTWVRMHRHQVptUk5KaXVZa3cxdHd3RnFTTEdQ?= =?utf-8?B?bFRuODFSb0l4clEyU1hOc2NyTXorSmdBdmwxS0Z0bHVIdUpWaGYzYzM5bEhL?= =?utf-8?B?emZpUlFOMlVmUkxUWDNJOWNjZ2ZkRThkakwvZ29hVnpvd0xiNGxxa1owMFRG?= =?utf-8?B?QndKUnFuQzR2QXFtVmFwbFNUOGlWM3B0Rm1rZnlsc05qT3VBdUdvcll1SWVa?= =?utf-8?B?c1JCaUZ5NnIwY2d6N3pDWkw3N1FHRXpsNXg0bVpnbzNVUmdxWmE2SjNFVStn?= =?utf-8?B?eHNKSEtVNnZ5NlQ4RHZORzZVYjZHMWxnS3JvQko3TmlzbHpiWERCaFFENlg3?= =?utf-8?B?Qk9wOW04QmFaT2p6S0ROOVpCQ1JaRDFuM2tsMTRNL3oxWmg2YkxIanBiVXZ2?= =?utf-8?B?NG5pdTZNMFNoMzZibG9mZzkyQkhsRHY1SkNTd0pIOGJURjJBNURqYnFFdDdM?= =?utf-8?B?djFGTWowckg3Wk5rODdEblZGRG5ESUloVGcyNTd2OEl3V1Y0NldQTURGT2lI?= =?utf-8?B?eXVYeUVXVm5TRVFtcHc2N2xvRW9uTUdtUmFoUzdtbVNSQkhuZEd2LzhmendN?= =?utf-8?B?c2duZGNnV2ExL25mSjRvTlIvZHRYalhHUDBwUk4wVjZjVnM2cFhEU01JRHBV?= =?utf-8?B?QXI1NG52cEphU3ladHFXYkZheFk2RkR2SFBpM01CVmtsOHZEQXhaMUhiS29m?= =?utf-8?B?TTF2NmxkeEdCSnpZazdPbERPVXhmdG83SGo0NnBIMjdBWWpNd2QwQ2haR0d0?= =?utf-8?B?eWRtWDhmN0hXNEtsbmJFMFEzekwxNWVIekFDTVBENkJYRlAxajdGWlN1RFZq?= =?utf-8?B?Umc9PQ==?= 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)(376014)(7416014)(1800799024)(10070799003)(7142099003)(921020);DIR:OUT;SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 2 X-MS-Exchange-AntiSpam-MessageData-0: =?utf-8?B?L2c0M3BJV1FOZHpHS0hXekJ1aFJIZEk3Y3hldTRwZnI2T1BadFpldkk3TjI4?= =?utf-8?B?blBETjJzLzhaM0NLMDJkOTA0TkdKSHlXQ2xKVWoxQWtGOEZ3UUZIOTJ3dktD?= =?utf-8?B?TGZmZnVHQS85RXpMalF5ZUFmQnhwSUNZWCtiQytLajZ1VDUvS2Z3ZGpTalY3?= =?utf-8?B?MHhzWlBYTHV6TFV0WEZleU0xWGNjTEZBMXBTVzZTSkZaSnpFVFVDWER3elFQ?= =?utf-8?B?VWxESkF0UlFEVDQxajlueE16S2VMSjVVdUIyRWMrZGF3SC9mK3BCbzVXQytn?= =?utf-8?B?RmFTWkduYlAwWXNlRHY2UjA3dzI4Vm1mNWNLZkFWVXQwSWpOZzA1aGZJa0ZF?= =?utf-8?B?azRXM1NMR1ZSTCtDaUpzU2dWRjhLYlEvUWVNRCs4SmsyeC83STlmcTNMZ3do?= =?utf-8?B?Wk11QXlzSjhoaldjblZITml0c0xRWnVzMHNLbEtwR3VXbnp1T1AzRmZ2aXpS?= =?utf-8?B?Z0cyOGQ3ZWtYL2NGL29idEFaakE1bnV4NHJtNnFsTmEvMW05ZjJaRHVhalUz?= =?utf-8?B?dC9FNDRFOUZYbUg0UkQxVzFHM21IbGdrUVBDZFpoTk5iYzA3T3hEVStSLzN0?= =?utf-8?B?Mnd3N29ZTVcwSncxWTJlZEQ5WjFjVWZLS0FsZ2VTRUM2cmVUckZEcE4vT3ZB?= =?utf-8?B?RXJ6cWNPNkcyajdJbFhQKzVtWnNEa2trM0JNcXFLZ0FTcmQ2TW9oVW5rMk5S?= =?utf-8?B?eGVDZCswOEs4aDhPMGpQQi9DbUtmMkRYMmhUNm9qekpYc1hoQkRHcGVzSXUy?= =?utf-8?B?M0lhT3dCR2VtMzN2dnhWZnRtaTFtem0wYkp2a2hoRnlOY3lWcVlRcGZMOTlG?= =?utf-8?B?TmhIeFpmWjNrU2NmellKSDdUald1eUkxY040QnBaWHJtZUFIeS9mcmxOeWpC?= =?utf-8?B?bFE3M3I2ZGYyclZ4SWwwUzR2SGdOKzVvZmNwNEttSjZONUYvOVZRQnM1VUhT?= =?utf-8?B?WXhSNHp2U3o5N2tVOHJnY2JVR1k5VlNaRWozbE8vYi9HK0FjL040MlFyVkRI?= =?utf-8?B?bVJYN2xLbm1OWDlrSnVkRTVLMERSbkhtUWdQYnZFNWtGa0V6M3hlUkRWRXlp?= =?utf-8?B?SG1JSlZOTjM5SEF4U1VDNVJKZWZ5Y1kzV2FWcHVZa3d3Vjd3TEZuM0NtSXBj?= =?utf-8?B?VGNUMG80MS9OT1QxcjNTMVUrUmFGS2llZWNxanptblR4aWUxbjJkZER5L25O?= =?utf-8?B?bWhyeU84dXhoTmZjdFNUUGlSVnFvN3RPTXlnYXo0bmN1SDFnU2gwT2xVNTJJ?= =?utf-8?B?NFFNWWxiZkQzVE5vTnhzVFNWWi9KQUVNa1dXZnVsSWtMR3FONmd4VVcxQmJB?= =?utf-8?B?TVUycndtVEZNT24ySzA3UXVDV1ZnVGVBYnZIcWNLaU1GY3cwM0Y1Q3dkaFht?= =?utf-8?B?WnQyczdsbmZ1WkNsRFk0cFE1MlBmMGRnakVEL0xaV3ZiU3NHQ2Z5VXFVdUtE?= =?utf-8?B?UW5haGFGZW55QmNLNEZzMTAvT1ZxcHlsU3R2REhRZHhOQkdJb012ZnNxRWho?= =?utf-8?B?eG5IS2FwQ1NFVkRtOVZiSG1URzRXNjNBcDVBUkFiMVV3Smg0eldtOHg5YllK?= =?utf-8?B?Ykhwc1UzTFhBdFVLKzJrZmFvWjljQ3g2SVJnUTR2RHdpaWlvRCszYUhpbkRE?= =?utf-8?B?Z3NnMlppdXlOWjVKQ25nS1VJSnkzWTQwSlFXZ29QcE96TVI3dUJCaDJIQTVS?= =?utf-8?B?Y0RMWWpTQ25kWDNlNFJaZU9IOEhwMkN3R2JhbUttWHUya0dVZllTckdYVXZJ?= =?utf-8?B?V2xkdHFWdjRBOWJEYmpESmI4NlQvYXJvNkRoL25VdE8vV2gzQXdHN1RYNVVs?= =?utf-8?B?bmRNWENQOHBYd2QvUWxuWGQxSEJaRTE2WE03aHdIcTJ2MXNDWWRMQWtBakdH?= =?utf-8?B?NkZJVW9qS0RxQkh1RU8xa3BHaDJZZjloRWtQV3prUERCdTR1dWhnS3lITi9y?= =?utf-8?B?N3psNUtzUEN2QnVubTQ3N2xsdkM3V3Q4Mzc5TFhiRCs4SUZ1d2JhY3VIT2R5?= =?utf-8?B?UjA0T1NQRStkKzZJY2FZa3pvWlhrTVdlUDRDcTNqSExCam1QNFNFTXl4U0Uw?= =?utf-8?B?Z1JCRmkraWNDUXhESGhaTFkydDRJTWpXVjN5bm1UaElHNHViUUNNSERWbmx1?= =?utf-8?B?K3YvTTBuVjJRdWk1dlZVeEI5Wmswb0lSZWVmcGh3NW52YS8reVN0QTdNYnVq?= =?utf-8?B?YWZlbHF5WG42enVSbnJZOXFwQlNpelZsUHhDU2dLVDR2eFlWb0FBMUx2d0Vw?= =?utf-8?B?WENaMUJQd0Y2d0RmdmFkUkR1MVBwb0VnM0RKdkZQZklyRkd3UEF4Sk54eHBJ?= =?utf-8?B?NXNBekVEWFkwbVlkL0U3V1ZjV2dZYlorZG43elE1Nkw4OGVXOE1Fc0FxYnBo?= =?utf-8?Q?wKONIAiC6fJJuYO12DiSLT2o2Y4v99hcOO58P/sCypvL1?= X-MS-Exchange-AntiSpam-MessageData-1: GlOYnZz+QFB3Ww== X-OriginatorOrg: Nvidia.com X-MS-Exchange-CrossTenant-Network-Message-Id: 07cb4f18-b2a9-4b1e-98bb-08de58be1d23 X-MS-Exchange-CrossTenant-AuthSource: CH2PR12MB3990.namprd12.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 21 Jan 2026 07:24:29.1982 (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: MVefm7FLOXCKqBsPuWWEhRa36bTYkJ5xznZ261ggKN/bk0Kw0lEWONxvO+mvAp6IFC0vK0GyfhvsBngPl2r6eQ== X-MS-Exchange-Transport-CrossTenantHeadersStamped: DS0PR12MB8272 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. Signed-off-by: Alexandre Courbot Tested-by: Dirk Behme --- rust/kernel/io.rs | 1 + rust/kernel/io/register.rs | 1198 ++++++++++++++++++++++++++++++++++++++++= ++++ 2 files changed, 1199 insertions(+) diff --git a/rust/kernel/io.rs b/rust/kernel/io.rs index a97eb44a9a87..eccaa176b6b9 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..e414aebe4c86 --- /dev/null +++ b/rust/kernel/io/register.rs @@ -0,0 +1,1198 @@ +// 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. Please look at the [`bi= tfield!`] macro for the +//! complete syntax of fields definitions. +//! +//! [`register!`]: kernel::register! +//! [`bitfield!`]: crate::bitfield! + +/// 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: core::ops::Deref>; + + /// Write a value to the given offset in the I/O region. + fn write(self, io: &T, offset: usize) + where + T: core::ops::Deref>; +} + +impl RegisterIo for u8 { + #[inline(always)] + fn read(io: &T, offset: usize) -> Self + where + T: core::ops::Deref>, + { + io.read8(offset) + } + + #[inline(always)] + fn write(self, io: &T, offset: usize) + where + T: core::ops::Deref>, + { + io.write8(self, offset) + } +} + +impl RegisterIo for u16 { + #[inline(always)] + fn read(io: &T, offset: usize) -> Self + where + T: core::ops::Deref>, + { + io.read16(offset) + } + + #[inline(always)] + fn write(self, io: &T, offset: usize) + where + T: core::ops::Deref>, + { + io.write16(self, offset) + } +} + +impl RegisterIo for u32 { + #[inline(always)] + fn read(io: &T, offset: usize) -> Self + where + T: core::ops::Deref>, + { + io.read32(offset) + } + + #[inline(always)] + fn write(self, io: &T, offset: usize) + where + T: core::ops::Deref>, + { + io.write32(self, offset) + } +} + +#[cfg(CONFIG_64BIT)] +impl RegisterIo for u64 { + #[inline(always)] + fn read(io: &T, offset: usize) -> Self + where + T: core::ops::Deref>, + { + io.read64(offset) + } + + #[inline(always)] + fn write(self, io: &T, offset: usize) + where + T: core::ops::Deref>, + { + io.write64(self, offset) + } +} + +/// 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. +/// +/// A register is essentially a [`bitfield!`] with I/O capabilities. The s= yntax of the `register!` +/// macro reflects that fact, being essentially identical to that of [`bit= field!`] with the +/// addition of addressing information after the `@` token. +/// +/// Example: +/// +/// ``` +/// use kernel::register; +/// +/// register!(pub BOOT_0(u32) @ 0x00000100, "Basic revision information ab= out the chip" { +/// 7:4 major_revision, "Major revision of the chip"; +/// 3:0 minor_revision, "Minor revision of the chip"; +/// }); +/// ``` +/// +/// 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, "Basic revision information = about the chip" { +/// # 7:4 major_revision, "Major revision of the chip"; +/// # 3:0 minor_revision, "Minor revision of the chip"; +/// # }); +/// # fn test(bar: &kernel::io::Io) { +/// // 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: +/// +/// ``` +/// use kernel::register; +/// +/// register! { +/// pub STATUS(u32) @ 0x00000000, "Status register" { +/// 0:0 ready, "Device ready flag"; +/// } +/// } +/// ``` +/// +/// It is also possible to create an alias register by using the `=3D> ALI= AS` syntax. This is useful +/// for cases where a register's interpretation depends on the context: +/// +/// ``` +/// use kernel::register; +/// +/// register!(pub SCRATCH(u32) @ 0x00000200, "Scratch register" { +/// 31:0 value, "Raw value"; +/// }); +/// +/// register!(pub SCRATCH_BOOT_STATUS(u32) =3D> SCRATCH, "Boot status of t= he firmware" { +/// 0:0 completed, "Whether the firmware has completed booting"; +/// }); +/// ``` +/// +/// 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: &kernel::io::Io) { +/// // This makes `CPU_CTL` accessible from all implementors of `RegisterB= ase`. +/// register!(pub CPU_CTL(u32) @ CpuCtlBase[0x10], "CPU core control" { +/// 0:0 start, "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!(pub CPU_CTL_ALIAS(u32) =3D> CpuCtlBase[CPU_CTL], "Alias to C= PU core control" { +/// 1:1 alias_start, "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 +/// use kernel::register; +/// +/// # fn no_run(bar: &kernel::io::Io) -> Result<(), Error> { +/// # fn get_scratch_idx() -> usize { +/// # 0x15 +/// # } +/// // Array of 64 consecutive registers with the same layout starting at = offset `0x80`. +/// register!(pub SCRATCH(u32) @ 0x00000080[64], "Scratch registers" { +/// 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!(pub FIRMWARE_STATUS(u32) =3D> SCRATCH[8], "Firmware exit sta= tus code" { +/// 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!(pub SCRATCH_INTERLEAVED_0(u32) @ 0x000000c0[16 ; 8], "Scratc= h registers bank 0" { +/// 31:0 value; +/// }); +/// register!(pub SCRATCH_INTERLEAVED_1(u32) @ 0x000000c4[16 ; 8], "Scratc= h registers bank 1" { +/// 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 no_run(bar: &kernel::io::Io) -> 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!(pub CPU_SCRATCH(u32) @ CpuCtlBase[0x00000080[64]], "Per-CPU = scratch registers" { +/// 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!(pub CPU_FIRMWARE_STATUS(u32) =3D> CpuCtlBase[CPU_SCRATCH[8]], +/// "Per-CPU firmware exit status code" { +/// 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!(pub CPU_SCRATCH_INTERLEAVED_0(u32) @ CpuCtlBase[0x00000d00[1= 6 ; 8]], +/// "Scratch registers bank 0" { +/// 31:0 value; +/// }); +/// register!(pub CPU_SCRATCH_INTERLEAVED_1(u32) @ CpuCtlBase[0x00000d04[1= 6 ; 8]], +/// "Scratch registers bank 1" { +/// 31:0 value; +/// }); +/// # Ok(()) +/// # } +/// ``` +/// [`bitfield!`]: crate::bitfield! +#[macro_export] +macro_rules! register { + // Creates a register at a fixed offset of the MMIO space. + ( + $(#[$attr:meta])* $vis:vis $name:ident ($storage:ty) @ $offset:lit= eral + $(, $comment:literal)? { $($fields:tt)* } + ) =3D> { + ::kernel::register!( + @bitfield $(#[$attr])* $vis struct $name($storage) $(, $commen= t)? { $($fields)* } + ); + ::kernel::register!(@io_fixed $name($storage) @ $offset); + }; + + // Creates an alias register of fixed offset register `alias` with its= own fields. + ( + $(#[$attr:meta])* $vis:vis $name:ident ($storage:ty) =3D> $alias:i= dent + $(, $comment:literal)? { $($fields:tt)* } + ) =3D> { + ::kernel::register!( + @bitfield $(#[$attr])* $vis struct $name($storage) $(, $commen= t)? { $($fields)* } + ); + ::kernel::register!(@io_fixed $name($storage) @ $alias::OFFSET); + }; + + // Creates a register at a relative offset from a base address provide= r. + ( + $(#[$attr:meta])* $vis:vis $name:ident ($storage:ty) @ $base:ty [ = $offset:literal ] + $(, $comment:literal)? { $($fields:tt)* } + ) =3D> { + ::kernel::register!( + @bitfield $(#[$attr])* $vis struct $name($storage) $(, $commen= t)? { $($fields)* } + ); + ::kernel::register!(@io_relative $name($storage) @ $base [ $offset= ]); + }; + + // Creates an alias register of relative offset register `alias` with = its own fields. + ( + $(#[$attr:meta])* $vis:vis $name:ident ($storage:ty) =3D> $base:ty= [ $alias:ident ] + $(, $comment:literal)? { $($fields:tt)* } + ) =3D> { + ::kernel::register!( + @bitfield $(#[$attr])* $vis struct $name($storage) $(, $commen= t)? { $($fields)* } + ); + ::kernel::register!(@io_relative $name($storage) @ $base [ $alias:= :OFFSET ]); + }; + + // Creates an array of registers at a fixed offset of the MMIO space. + ( + $(#[$attr:meta])* $vis:vis $name:ident ($storage:ty) + @ $offset:literal [ $size:expr ; $stride:expr ] + $(, $comment:literal)? { $($fields:tt)* } + ) =3D> { + static_assert!(::core::mem::size_of::<$storage>() <=3D $stride); + + ::kernel::register!( + @bitfield $(#[$attr])* $vis struct $name($storage) $(, $commen= t)? { $($fields)* } + ); + ::kernel::register!(@io_array $name($storage) @ $offset [ $size ; = $stride ]); + }; + + // Shortcut for contiguous array of registers (stride =3D=3D size of e= lement). + ( + $(#[$attr:meta])* $vis:vis $name:ident ($storage:ty) @ $offset:lit= eral [ $size:expr ] + $(, $comment:literal)? { $($fields:tt)* } + ) =3D> { + ::kernel::register!( + $(#[$attr])* $vis $name($storage) + @ $offset [ $size ; ::core::mem::size_of::<$storage>() ] + $(, $comment)? { $($fields)* } + ); + }; + + // Creates an array of registers at a relative offset from a base addr= ess provider. + ( + $(#[$attr:meta])* $vis:vis $name:ident ($storage:ty) + @ $base:ty [ $offset:literal [ $size:expr ; $stride:expr ] ] + $(, $comment:literal)? { $($fields:tt)* } + ) =3D> { + static_assert!(::core::mem::size_of::<$storage>() <=3D $stride); + + ::kernel::register!( + @bitfield $(#[$attr])* $vis struct $name($storage) $(, $commen= t)? { $($fields)* } + ); + ::kernel::register!( + @io_relative_array $name($storage) @ $base [ $offset [ $size ;= $stride ] ] + ); + }; + + // Shortcut for contiguous array of relative registers (stride =3D=3D = size of element). + ( + $(#[$attr:meta])* $vis:vis $name:ident ($storage:ty) + @ $base:ty [ $offset:literal [ $size:expr ] ] + $(, $comment:literal)? { $($fields:tt)* } + ) =3D> { + ::kernel::register!( + $(#[$attr])* $vis $name($storage) + @ $base [ $offset [ $size ; ::core::mem::size_of::<$storag= e>() ] ] + $(, $comment)? { $($fields)* } + ); + }; + + // Creates an alias of register `idx` of relative array of registers `= alias` with its own + // fields. + ( + $(#[$attr:meta])* $vis:vis $name:ident ($storage:ty) + =3D> $base:ty [ $alias:ident [ $idx:expr ] ] + $(, $comment:literal)? { $($fields:tt)* } + ) =3D> { + static_assert!($idx < $alias::SIZE); + + ::kernel::register!( + @bitfield $(#[$attr])* $vis struct $name($storage) $(, $commen= t)? { $($fields)* } + ); + ::kernel::register!( + @io_relative $name($storage) @ $base [ $alias::OFFSET + $idx *= $alias::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. + ( + $(#[$attr:meta])* $vis:vis $name:ident ($storage:ty) =3D> $alias:i= dent [ $idx:expr ] + $(, $comment:literal)? { $($fields:tt)* } + ) =3D> { + static_assert!($idx < $alias::SIZE); + + ::kernel::register!( + @bitfield $(#[$attr])* $vis struct $name($storage) $(, $commen= t)? { $($fields)* } + ); + ::kernel::register!(@io_fixed $name($storage) @ $alias::OFFSET + $= idx * $alias::STRIDE); + }; + + // All rules below are helpers. + + // 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) + $(, $comment:literal)? { $($fields:tt)* } + ) =3D> { + ::kernel::register!(@bitfield_core + #[allow(non_camel_case_types)] + $(#[$attr])* $vis $name $storage $(, $comment)? + ); + ::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>, + { + 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>, + { + <$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>, + 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:ty [ $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>, + 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>, + 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>, + 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) @ $offset:literal [ $size:expr ; = $stride:expr ]) =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>, + { + 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>, + { + 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>, + 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>, + { + 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>, + { + 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>, + 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) @ $base:ty + [ $offset:literal [ $size:expr ; $stride:expr ] ] + ) =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>, + 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>, + 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>, + 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>, + 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>, + 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>, + 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 $(,= $comment:literal)?) =3D> { + $( + #[doc=3D$comment] + )? + $(#[$attr])* + #[repr(transparent)] + #[derive(Clone, Copy, PartialEq, Eq)] + $vis struct $name($storage); + + #[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` and `Default` implementations. + (@bitfield_fields $vis:vis $name:ident $storage:ty { + $($hi:tt:$lo:tt $field:ident + $(?=3D> $try_into_type:ty)? + $(=3D> $into_type:ty)? + $(, $comment:literal)? + ; + )* + } + ) =3D> { + #[allow(dead_code)] + impl $name { + $( + ::kernel::register!(@private_field_accessors $vis $name $storage := $hi:$lo $field); + ::kernel::register!(@public_field_accessors $vis $name $storage : = $hi:$lo $field + $(?=3D> $try_into_type)? + $(=3D> $into_type)? + $(, $comment)? + ); + )* + } + + ::kernel::register!(@debug $name { $($field;)* }); + ::kernel::register!(@default $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 $vis:vis $name:ident $storage:ty : $hi:tt:= $lo:tt $field:ident + =3D> $into_type:ty $(, $comment:literal)? + ) =3D> { + ::kernel::macros::paste!( + + $( + #[doc=3D"Returns the value of this field:"] + #[doc=3D$comment] + )? + #[inline(always)] + $vis fn $field(self) -> $into_type + { + self.[<__ $field>]().into() + } + + $( + #[doc=3D"Sets the value of this field:"] + #[doc=3D$comment] + )? + #[inline(always)] + $vis fn [](self, value: $into_type) -> Self + { + self.[<__set_ $field>](value.into()) + } + + /// Private method, for use in the [`Default`] implementation. + fn [<$field _default>]() -> $into_type { + Default::default() + } + + ); + }; + + // Public accessors for fields fallibly (`?=3D>`) converted to a type. + ( + @public_field_accessors $vis:vis $name:ident $storage:ty : $hi:tt:= $lo:tt $field:ident + ?=3D> $try_into_type:ty $(, $comment:literal)? + ) =3D> { + ::kernel::macros::paste!( + + $( + #[doc=3D"Returns the value of this field:"] + #[doc=3D$comment] + )? + #[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"Sets the value of this field:"] + #[doc=3D$comment] + )? + #[inline(always)] + $vis fn [](self, value: $try_into_type) -> Self + { + self.[<__set_ $field>](value.into()) + } + + /// Private method, for use in the [`Default`] implementation. + fn [<$field _default>]() -> $try_into_type { + Default::default() + } + + ); + }; + + // Public accessors for fields not converted to a type. + ( + @public_field_accessors $vis:vis $name:ident $storage:ty : $hi:tt:= $lo:tt $field:ident + $(, $comment:literal)? + ) =3D> { + ::kernel::macros::paste!( + + $( + #[doc=3D"Returns the value of this field:"] + #[doc=3D$comment] + )? + #[inline(always)] + $vis fn $field(self) -> + ::kernel::num::Bounded<$storage, { $hi + 1 - $lo }> + { + self.[<__ $field>]() + } + + $( + #[doc=3D"Sets the value of this field:"] + #[doc=3D$comment] + )? + #[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"Attempts to set the value of this field:"] + #[doc=3D$comment] + )? + #[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)? + ) + ) + } + + /// Private method, for use in the [`Default`] implementation. + fn [<$field _default>]() -> ::kernel::num::Bounded<$storage, { $hi= + 1 - $lo }> { + Default::default() + } + + ); + }; + + // `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() + } + } + }; + + // `Default` implementation. + (@default $name:ident { $($field:ident;)* }) =3D> { + /// Returns a value for the bitfield where all fields are set to t= heir default value. + impl ::core::default::Default for $name { + fn default() -> Self { + #[allow(unused_mut)] + let mut value =3D Self(Default::default()); + + ::kernel::macros::paste!( + $( + value =3D value.[](Self::[<$field _default>](= )); + )* + ); + + value + } + } + }; +} --=20 2.52.0 From nobody Sat Feb 7 19:41:42 2026 Received: from BN1PR04CU002.outbound.protection.outlook.com (mail-eastus2azon11010011.outbound.protection.outlook.com [52.101.56.11]) (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 A0B7644DB90; Wed, 21 Jan 2026 07:24:42 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=52.101.56.11 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1768980286; cv=fail; b=jUzcqafqGQXayMIt/+QnTWDExxvyDOAcv5NQFioRQyE+VLLy3E5cKyscRVy9RspLBSYmlIDUYL3Dvi2KLxOR/d05Qiot+hiR6RdG9xkLsZOJ+HTXIObmfeXjfzxbuHaMi12TJppsf0P+cgHLR5jvjzp4oOEl6Q2ToLt0b3/FQbQ= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1768980286; c=relaxed/simple; bh=OZSnsue5KumOrYn7Pc0Dhn4Tsp9VEniSIyfvaFUVmws=; h=From:Date:Subject:Content-Type:Message-Id:References:In-Reply-To: To:Cc:MIME-Version; b=KH3NX8gBXhDpiqVfWM7dcU/3l8e+HnPE+wm48psHe1/3oUfHqowJz46sZuQsWzHXeYQC2CO3O9r5GQUTq18d7SR9Ix91MnDJhzV5w03OhKIAF4eF0QllaTw5FpmNkTPg2FWjniK9B/FUcjWJtGxzIb3+t6cwQk6Z/7X+f57+zvw= 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=KFr1qbuJ; arc=fail smtp.client-ip=52.101.56.11 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="KFr1qbuJ" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=agEuxRiyAT3X0YxBwtr/MZ6usV52/nd0sJAu7BOCh5bcvJgEqYV1FSW/y0tN9sVAUJ6eDGbdqUxZLKaXRQ/GT15QQ05Nzhk/TYmJPpuRB6IDGakqo2cMe+GTb/igfMusYx3Jwy+SSufu8qOYbkjOa4exAyRZKRl36ZzyM8lvhY1Nzjoz5s3N5E0y2R4boKLP9TexDYj0feMcnEwPRLqK33xVjaPHc3XH6BDvs4ipIzEvysiH/jb3BwNrVgqxcesAKfSWajVHIt87moCYqSKDYaJVm/5h42n7NjPZX6RYssf4OFVTQP7Qc1o+UME7GXjQfIm9d6djzxylOHsu/4gnlg== 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=jnB3HZNg0ZspWQ1GRTdMW8Go0AZBwJJpS4CdH11xN4g=; b=ZZqyCgjvUEaBQPidAJs3wuJcYgwRHClE5XK+/LiaqdVkCfWo39qn/UoBClNdClEuPttBsOYB3/zwPKfomcGWP0N5uBjQXEkyI8NYFUg+zmzSdhE7Jn7TVoyZ/yb4CUTtmodPBH1gpPU/YCfMpA1ptnCw9ZpuYUKVxEfI9yKuFksYbTazaNORc31UfhjtSMd8piktt+Lhl0FVcUiM1iP04OI2wE10EhPpWwOE1F4eoSVAA6eFuyoiwZ0PKrtrzW1t7XgTxmko3ySMRlXDrZfRxkxrAmUwsvtOe3mqz6COSHBZG6H02XM1GlYHYCJgzY82rwhj7EuTbRbxi46CjDddCQ== 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=jnB3HZNg0ZspWQ1GRTdMW8Go0AZBwJJpS4CdH11xN4g=; b=KFr1qbuJkknPQVCwkcbBr9Lw4e9Sl7KBufyhfsfOuzecks1nU4j0y7POoKfdh8mUiYX879ox5pji2hsdnuVAtNlpuuqql9CGUr8Gcmqyjdadf3tYec9B8nz5+oO+s6BRnloKUNmkxWVNih3zgwRqgxxBYHwfhT0QUaE9/BDe04BTmMMVsKBjfC9bGkP0nSHUgfY5uOhZ/OCI1rL0jvF4dkVRFpvRAth2LcEzy12Hwp8LdrAoZj4b9PiJf/fo+H/TZvq8JQIXSHo01LB7BFEavzGygoYcweVgDCKlttDDkmRDNsUJiSP/4U1Kqo/6w8ffmX9xwMSdtlpl3ySDvq09Yg== 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 DS0PR12MB8272.namprd12.prod.outlook.com (2603:10b6:8:fc::7) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.9542.9; Wed, 21 Jan 2026 07:24:32 +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.008; Wed, 21 Jan 2026 07:24:32 +0000 From: Alexandre Courbot Date: Wed, 21 Jan 2026 16:23:57 +0900 Subject: [PATCH FOR REFERENCE v2 5/5] gpu: nova-core: use the kernel `register!` macro Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260121-register-v2-5-79d9b8d5e36a@nvidia.com> References: <20260121-register-v2-0-79d9b8d5e36a@nvidia.com> In-Reply-To: <20260121-register-v2-0-79d9b8d5e36a@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: TYCP301CA0060.JPNP301.PROD.OUTLOOK.COM (2603:1096:400:384::9) To CH2PR12MB3990.namprd12.prod.outlook.com (2603:10b6:610:28::18) Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: CH2PR12MB3990:EE_|DS0PR12MB8272:EE_ X-MS-Office365-Filtering-Correlation-Id: 664b5bbc-66db-46dc-d319-08de58be1f3b X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|366016|376014|7416014|1800799024|10070799003|921020; X-Microsoft-Antispam-Message-Info: =?utf-8?B?QnlUY0FhS1pDcEJ6NWdYV0JRdDFvaXhGRXRKVlk2NEhud1ArT09DelorTStP?= =?utf-8?B?eC9KcFh5TU5Na3lMbUs0MWFHTTZtbkVnQ0Q3UmdMLzlrenNpdURRbW13bFor?= =?utf-8?B?cTIxQlRNZjM5dGU5akpvSmRtZnpNWUVlQytRbVhGbkZTbkhyTUJUa3JnYTZH?= =?utf-8?B?a1huQ3VNQkZza1p4ZXF1bHRmcXY3VlBJSjhZSUxTUVNpVXBralFWclV4dWkx?= =?utf-8?B?RGRacm5MbTZMVkxOS0ZDbExPeWY0N0VhaFJVYkt0VUl2RTJTLzlER3RRNDQ2?= =?utf-8?B?NXFIcWN2NGNIVlZXTnBEQitzVVV0RnY4clBmbHQ0aDJ4MllNY1kyazdjTng2?= =?utf-8?B?R3lYZVVMVHpIcDZZS2xvUkh4L3BXa0tzV1F0dFB3dXhWVmtNR252UHVBazlw?= =?utf-8?B?cExDc2lHdDdSdTZYVFBQUDI4OWxxdE1Pa1BFc1ltRkkvaDI3ZWRES2VGSTZl?= =?utf-8?B?SmV2WU5jR2NNa2wvYXROL2RjNXpUWW9jSTZwWjU1NldCV1Uxd3FlZnVwb2ZO?= =?utf-8?B?ZVo2UE9PdXNUTUdROTRicE9jc3ErOVRsYXl3ZlF2QVhiSFVsSmFKK2J1Yi9X?= =?utf-8?B?VnlSVWtPVmdUMUpNZ0dRTTc3ZEE0Z2t5MFl2amcyL3BSaFU1eG1wLzV3VDJP?= =?utf-8?B?Tko4VmxySFZ3N09jeklKdko3a2tMazRrZUpMWHNDczVDNitrLzVzSHNsajNY?= =?utf-8?B?ejRhL1BiVnNIbmpYeHRtVWloQU01Q3RjUmpFUnNqRVRocS9MbDF5Q2d4QkZP?= =?utf-8?B?MUVWT2o4SG1kanY4dCtkK3g2T0Z1RXpOYWs3Y1djTnVrdGhsRmZKNUgxK1JS?= =?utf-8?B?eWl6R0d0UU1ORFNLQysrYUxiQytKZU91ZTNKZ2Y3NWtiQ3doZUtIc2ViUm1R?= =?utf-8?B?UWN5dTFWa2JuVXhGV0JoL1ZXNjhQOGpBRXo5VzJDV3FnQURaT0l2eVA5U1NW?= =?utf-8?B?M1BmQ3JnTTIvSFZQZkxPSWhwTHJZcmhTYXdWdXlnbWR1Y083RWk0cmE2VUxh?= =?utf-8?B?a1VENng2aXRiQnBDRmRJUHkxQ0tnbVVhTHVtc0xDK3g3d2dyU3IvZE9NVDBs?= =?utf-8?B?QkQ4dnYrVzBPQVRoZnlmcGFpRitFdThZdlRaTnY2NC9yQkI3cmszamlPSzZl?= =?utf-8?B?bnpmRFltak1oTlpSaDFKdHFFZWdseUZBSzBoczREK3JpWnBZK2x0cTcvWkxF?= =?utf-8?B?VnJuQ0tkb1c3ZmY3ZkNVMlh2MDdyVWFPVU1aSDNrbmx3MDJRblF2Q0lBS2pY?= =?utf-8?B?cm92ZFFrS0xoODRwNzh4QWZVUVJaSlhvVzBRYTltS2NmU0NOR1dYcEZhVkdO?= =?utf-8?B?SzJnWXNJU1pNczFqVUVUNlAxUGhUZDZBVi9CY3p1N1dnZEwwQ2QwZmdOMk0w?= =?utf-8?B?YlFCUVcvMUViTHpkaS9HNkpzbUR4RWFIWUUyK1BpMEVlTndRVGNmbVp5Z0pN?= =?utf-8?B?aFIxR0wxRWVZdlI0WHgvdytXTFlZdVRwN0RrZVozK3hlc1diS0g4aWErdm4v?= =?utf-8?B?eW9FUHVXTzFwdHRaZHI0S2RRWndQSk1LOTNIM2EzRlBRQXJYV0FYSFNhN2VW?= =?utf-8?B?RmtzRTRhT2JVVm9vdkhUMTFQL0xtekZycnBGa2V4YXQ0OHdjNytRQUowbmdu?= =?utf-8?B?RmNaaVg1R1NEVU85MGZPTUpsNXRyYzRybklEQThCNUxHODN4Y0Y4am9KQnJU?= =?utf-8?B?Wm0zVEFNcmg3RHVFOTZFWE1PYzIyS1lhSCttcUxaVnp3eE1lQ090V09DTU9p?= =?utf-8?B?N3NPMG9RK0p1MTVVKzJhTlM0dEZqalNZYWZmTVhJUFI4K3ptazJ0bFdIbG9p?= =?utf-8?B?QmxUaUx6ZDVoTTJxaHpRRkxqNVpQcElRalRHYVVOWWo1V3N1Y3RqdExuQmZS?= =?utf-8?B?Uko1ZkE5Tk5qYTFheG5rK2hnbG9DTzRvc2hBRkJCRnRjZ2dWVHVaNHkyR0kv?= =?utf-8?B?Smt2NUgvYTB6QzhabHN5OThtM0h4R3pGcEtYalF5ZFhDcWZmTE5vTXdDOGla?= =?utf-8?B?L2FRR2hpMG1jZ0NQdFZEMmpVMDU2NE5OalJsLzFpTFFJeXNQL1l1aHlRTGxv?= =?utf-8?B?MHRDMTBCci9Qb0UrK0p3ZzRVeXROSndtZWlGVTJZUUxua2x6WmtoNTNESG1p?= =?utf-8?B?OXAyYXM5UG5UQkJNOHJqV3BzU2ZEWkllYmo3NS9LRVNQclNyc200c1dCMDgz?= =?utf-8?Q?mGEzWiLIahs8osYtH/uZT7M=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)(376014)(7416014)(1800799024)(10070799003)(921020);DIR:OUT;SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 2 X-MS-Exchange-AntiSpam-MessageData-0: =?utf-8?B?VU5yaHFDZTVVdEVRakQwUDBzMmJDekVyOGZxSmhlVjVkYnZkVE1NZlVoOU5a?= =?utf-8?B?dDhKOG14bWVxLzVhTEVzdnJOWTVORjdPR3FkZHpnWE5lVmVZWXRsU1JVbTJt?= =?utf-8?B?QWxIREI3TTJWYW9qNyt6R2JPNEg2WFFsL0pxWlV6bmVyQk5sQUlLc0RtN0dp?= =?utf-8?B?UDY3V1dueFpOVmhCeUg5d2tBZ1hENnVwN0kzdDQ5MEVIRHdCSzFPU1hKRk1B?= =?utf-8?B?R0QwQTg0RUtQS3M4M0V3RHA3UDlhUXVIR1Erb0N1U0FFamkrczNWU0pvNk1Z?= =?utf-8?B?Y0NoQjR2bkNqUllLSW5FTVhtcytKN1pYS3c5Qnd0TzQzcVB1NEF6OHJOb2Vk?= =?utf-8?B?cWZxb0NFS3YrSTE5MVEza2hnOWxWRjVTMlg1aXRoVXYzUExlU2dPelNJSHQw?= =?utf-8?B?d2pndlFLZ0pOZUY3UkRyNTBHWkxtdU0yNTdUa0xnWTM4U1IvMWJ5NGVYUUpO?= =?utf-8?B?UW5pNXRJRTNLMVpHWExKbnBGcU92QzkyQkhJbVp1eThrUUFKSDFlM1R5VUQr?= =?utf-8?B?YkdRMCtpVDdBbUFtaW84cmZTTTVEQjRHWWYvZHdBcmhlK3pUWkVDOTRnTml6?= =?utf-8?B?ZHdCeFhGU05jajFPRWxVa3UwRlhaRVk2c2orZmdPVDBOK083eVVoQmVYR0VG?= =?utf-8?B?UTFXUDMvY20zVTFqNDI2WVRWL0I2U1hnRkt1Ymx1b3NWWE44ckFkbW9pemJn?= =?utf-8?B?bGgvT1pOQkdlVmxHYzI5Mncrd3p2UWdHU25qZUluVVFMdW9DQ0lTalYvMDFz?= =?utf-8?B?QVR3WXpIQU1hTlM5UHRnd256ditUS3l4cG1wV1JFa1djVkU0SmE4b2M2OEVB?= =?utf-8?B?YVRzcm5ER3VQTUMxWkxLVUxVWHAySGgyeWh6ZHdiVDdtZWtLY3JmanhEeUhy?= =?utf-8?B?YWNMZ2tZTE9aK2ZRK2wzNGhlRmVIL1FiVmpLNS8rQU01dTBZaHk0OG1oUzY5?= =?utf-8?B?RHZHakVzZ2tTVzA5elp4YzBISlMrQ1ZQVUt2Z0gxUTZXOG1aOWdnbkg2TWwy?= =?utf-8?B?dWt0d3FSWkFZeGloRFQ3a2FoM055MXFqSTJ5NFk5M2pYOG8yakRCSFprZXFL?= =?utf-8?B?MzJJZEJ3NzluamZHdkZzOVowVFhvdmNkUjUvU2VKYWJ5VUlZbDlmb2paSGdx?= =?utf-8?B?UEtmS3pNekNJV0R6VTZkdUxOQWx4U09YOHB2RmtFQlRXWVdsNm9YOHQ4ZjdJ?= =?utf-8?B?THJZdW5JL3M3N2RSRXRtMUdIUnJYZjlvMkEzYnVST0Vtb2xEN1YyakczVVJm?= =?utf-8?B?U1BMRXNoNzB5TEdJbGoyeTBzTmtXUlpybGNBaEsxUzEvNTdhRDkyaHBRZjRx?= =?utf-8?B?VU92MUM2ODRCbXRLeWM0Y1VjWHdlRWlrMmpjQjBaMWlYQ1kxLzZFWjFDTG1E?= =?utf-8?B?aVNOS0g3KzhFblBYeTVsRWNiNzNROXJZc05UUUNZUlVrTTFMWUt4WW5qT1Ns?= =?utf-8?B?dVMwQnN5aFhwNW9wSWI1c2JVMDZaNFpIWi9XZGFTZVRGdXoxMXFFc0JzVHNz?= =?utf-8?B?V2IzRVpJM2J4b0xQbHFmQ2lyZVlJWWZzVHgzV01OK2ViZzlFUWVyeFU1Ui9U?= =?utf-8?B?UHRzOGw3am9qMUpEQzZXN0I4b0VnNXJ4dXhRcXQ2RkNvZll3NlpWV0VoeU5G?= =?utf-8?B?KzhpU1NkQ3hIZTBIUlRTUkFuendpYUZaL2kyeFBVUDRTd0ZQb0k1elhsL1N5?= =?utf-8?B?blVoUjBQajZGT1l1dGxhYnFWdlY2cWkxaFEzL01TU0ltSnpFb2lWQ2trdWQx?= =?utf-8?B?YjdkTDdjeXNUeFR3SlZRTUJqWnNacU5OVHVVdG04K1hoQmtiWnZKbDdHNlF2?= =?utf-8?B?NXlmWHpNUFp2MEsyblc0RXRqSGYwNDJXSGY2MGRRaGdRS1dDV0tJVnZtMkZH?= =?utf-8?B?L0xEeFdtaW1ETWJsUWNDNWk3NWQ5UWhZL1RXRnhBUTFac2pyZXFGaWpnSzUz?= =?utf-8?B?K29YYWxGY05tZnROd0VRV2ptdzByUG1xbFZONUZoeEtjZ2gxTTd0cXFvR0tx?= =?utf-8?B?TE1xQU1LRW5KK3Y2bmNGOWVqa0krcW9RT0FEYjVLQkNqdm0vK2hrTExyWFNz?= =?utf-8?B?Z2xhTEF2OXFkdGgrR3ZHMzlKdzlucm5uNWNibDFra1ZYeVZVWUNuOTFXOGE5?= =?utf-8?B?YTl2L0RLaWpuTUNWOFcxaHpzTE9XekRiMkh6WDcrQlB4VHhSWU10R1cxdXJM?= =?utf-8?B?blhXRGxySTBtK2plbnpLMENnUUtqWHBQUUlDSWV4M0crYUxEZy9RR2paVlZ6?= =?utf-8?B?OWJOaFJvZWlBcGl3V2tFdDVrZVREQ2hyTkZjdDZGd3NwMzFPODVhZ3U0Y283?= =?utf-8?B?S2E5NUh6TU15bkJ6eFlJSzRIMEE0Y0VTZ3orKzVCQk9lQUtuNmVpWVRQcXZB?= =?utf-8?Q?e2fhWdPLqlyZ6k/0tauCAtasR9efF3T/vPoMKEsh65r15?= X-MS-Exchange-AntiSpam-MessageData-1: eY4IZHtLvuEbCQ== X-OriginatorOrg: Nvidia.com X-MS-Exchange-CrossTenant-Network-Message-Id: 664b5bbc-66db-46dc-d319-08de58be1f3b X-MS-Exchange-CrossTenant-AuthSource: CH2PR12MB3990.namprd12.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 21 Jan 2026 07:24:32.6950 (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: CWrIq48WgHFc8A09ehX285jiWxsN5AAZownjaACJhPcUFIcwoQJCE6uMBcW0Ejlc9T29vDDS6GIblkNB8LTH2g== X-MS-Exchange-Transport-CrossTenantHeadersStamped: DS0PR12MB8272 Replace the nova-core internal `register!` macro by the one defined in the `kernel` crate and remove our own private implementations. Signed-off-by: Alexandre Courbot Tested-by: Dirk Behme --- drivers/gpu/nova-core/falcon.rs | 127 +++--- drivers/gpu/nova-core/falcon/gsp.rs | 10 +- drivers/gpu/nova-core/falcon/hal/ga102.rs | 5 +- drivers/gpu/nova-core/falcon/sec2.rs | 13 +- drivers/gpu/nova-core/fb/hal/ga100.rs | 9 +- drivers/gpu/nova-core/gpu.rs | 24 +- drivers/gpu/nova-core/gsp/cmdq.rs | 2 +- drivers/gpu/nova-core/regs.rs | 265 +++++------ drivers/gpu/nova-core/regs/macros.rs | 721 --------------------------= ---- 9 files changed, 220 insertions(+), 956 deletions(-) diff --git a/drivers/gpu/nova-core/falcon.rs b/drivers/gpu/nova-core/falcon= .rs index 82c661aef594..2d0c4cbd9e67 100644 --- a/drivers/gpu/nova-core/falcon.rs +++ b/drivers/gpu/nova-core/falcon.rs @@ -9,12 +9,16 @@ use kernel::{ device, dma::DmaAddress, - io::poll::read_poll_timeout, + io::{ + poll::read_poll_timeout, + register::RegisterBase, // + }, + num::Bounded, prelude::*, sync::aref::ARef, time::{ - delay::fsleep, - Delta, // + delay::fsleep, // + Delta, }, }; =20 @@ -27,7 +31,6 @@ IntoSafeCast, // }, regs, - regs::macros::RegisterBase, // }; =20 pub(crate) mod gsp; @@ -35,11 +38,12 @@ 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 { +// TODO: macro that defines the struct and impls, like for Chipset. +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,7 +51,6 @@ 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)] pub(crate) enum FalconCoreRev { #[default] @@ -59,16 +62,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,7 +88,6 @@ 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)] pub(crate) enum FalconCoreRevSubversion { #[default] @@ -94,30 +96,27 @@ pub(crate) enum FalconCoreRevSubversion { 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. /// @@ -138,16 +137,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 +159,23 @@ 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)] 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 +183,20 @@ 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)] 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), } @@ -215,25 +212,17 @@ pub(crate) enum PeregrineCoreSelect { /// 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 { @@ -257,14 +246,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, @@ -284,26 +273,18 @@ pub(crate) enum FalconFbifMemType { /// 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 @@ -432,7 +413,7 @@ pub(crate) fn reset(&self, bar: &Bar0) -> Result { self.reset_wait_mem_scrubbing(bar)?; =20 regs::NV_PFALCON_FALCON_RM::default() - .set_value(regs::NV_PMC_BOOT_0::read(bar).into()) + .set_value(regs::NV_PMC_BOOT_0::read(bar).as_raw()) .write(bar, &E::ID); =20 Ok(()) @@ -501,20 +482,18 @@ fn dma_wr>( .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) + .try_set_base(dma_start >> 40)? .write(bar, &E::ID); =20 let cmd =3D regs::NV_PFALCON_FALCON_DMATRFCMD::default() .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) + .try_set_offs(load_offsets.dst_start + pos)? .write(bar, &E::ID); regs::NV_PFALCON_FALCON_DMATRFFBOFFS::default() .set_offs(src_start + pos) diff --git a/drivers/gpu/nova-core/falcon/gsp.rs b/drivers/gpu/nova-core/fa= lcon/gsp.rs index 67edef3636c1..dcdf3962ab0d 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. diff --git a/drivers/gpu/nova-core/falcon/hal/ga102.rs b/drivers/gpu/nova-c= ore/falcon/hal/ga102.rs index 69a7a95cac16..72afbd9101cf 100644 --- a/drivers/gpu/nova-core/falcon/hal/ga102.rs +++ b/drivers/gpu/nova-core/falcon/hal/ga102.rs @@ -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,7 +68,8 @@ 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()) 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..acf46ad0dba1 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, @@ -20,9 +23,7 @@ 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) + .set_adr_63_40(Bounded::from_expr(addr >> FLUSH_SYSMEM_ADDR_SHIFT_= HI).cast()) .write(bar); regs::NV_PFB_NISO_FLUSH_SYSMEM_ADDR::default() // CAST: `as u32` is used on purpose since we want to strip the up= per bits that have been diff --git a/drivers/gpu/nova-core/gpu.rs b/drivers/gpu/nova-core/gpu.rs index 629c9d2dc994..556b2454b5a6 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, // @@ -135,11 +136,11 @@ pub(crate) enum Architecture { 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 +149,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..60a1b0fecf62 100644 --- a/drivers/gpu/nova-core/gsp/cmdq.rs +++ b/drivers/gpu/nova-core/gsp/cmdq.rs @@ -476,7 +476,7 @@ fn calculate_checksum>(it: T) = -> u32 { /// 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) + .set_address(0u32) .write(bar); } =20 diff --git a/drivers/gpu/nova-core/regs.rs b/drivers/gpu/nova-core/regs.rs index 82cc6c0790e5..794401122f06 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,28 @@ 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 $($tail:tt)*) =3D> { + ::kernel::register!($(#[$attr])* pub(crate) $name(u32) $($tail)*); + }; +} + // 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!(NV_PMC_BOOT_0 @ 0x00000000, "Basic revision information about the = GPU" { + 3:0 minor_revision, "Minor revision of the chip"; + 7:4 major_revision, "Major revision of the chip"; + 8:8 architecture_1, "MSB of the architecture"; + 23:20 implementation, "Implementation version of the architecture"; + 28:24 architecture_0, "Lower bits of the 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,11 +51,11 @@ 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"; +nv_reg!(NV_PMC_BOOT_42 @ 0x00000a00, "Extended architecture information" { + 15:12 minor_revision, "Minor revision of the chip"; + 19:16 major_revision, "Major revision of the chip"; + 23:20 implementation, "Implementation version of the architecture"; + 29:24 architecture ?=3D> Architecture, "Architecture value"; }); =20 impl NV_PMC_BOOT_42 { @@ -89,11 +90,11 @@ fn fmt(&self, f: &mut kernel::fmt::Formatter<'_>) -> ke= rnel::fmt::Result { =20 // PBUS =20 -register!(NV_PBUS_SW_SCRATCH @ 0x00001400[64] {}); +nv_reg!(NV_PBUS_SW_SCRATCH @ 0x00001400[64] {}); =20 -register!(NV_PBUS_SW_SCRATCH_0E_FRTS_ERR =3D> NV_PBUS_SW_SCRATCH[0xe], +nv_reg!(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; + 31:16 frts_err_code; }); =20 // PFB @@ -101,22 +102,22 @@ fn fmt(&self, f: &mut kernel::fmt::Formatter<'_>) -> = kernel::fmt::Result { // 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`). =20 -register!(NV_PFB_NISO_FLUSH_SYSMEM_ADDR @ 0x00100c10 { - 31:0 adr_39_08 as u32; +nv_reg!(NV_PFB_NISO_FLUSH_SYSMEM_ADDR @ 0x00100c10 { + 31:0 adr_39_08; }); =20 -register!(NV_PFB_NISO_FLUSH_SYSMEM_ADDR_HI @ 0x00100c40 { - 23:0 adr_63_40 as u32; +nv_reg!(NV_PFB_NISO_FLUSH_SYSMEM_ADDR_HI @ 0x00100c40 { + 23:0 adr_63_40; }); =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_reg!(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_PGSP_QUEUE_HEAD @ 0x00110c00 { - 31:0 address as u32; +nv_reg!(NV_PGSP_QUEUE_HEAD @ 0x00110c00 { + 31:0 address; }); =20 impl NV_PFB_PRI_MMU_LOCAL_MEMORY_RANGE { @@ -134,8 +135,8 @@ 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"; +nv_reg!(NV_PFB_PRI_MMU_WPR2_ADDR_LO@0x001fa824 { + 31:4 lo_val, "Bits 12..40 of the lower (inclusive) bound of the WPR= 2 region"; }); =20 impl NV_PFB_PRI_MMU_WPR2_ADDR_LO { @@ -145,8 +146,8 @@ 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"; +nv_reg!(NV_PFB_PRI_MMU_WPR2_ADDR_HI@0x001fa828 { + 31:4 hi_val, "Bits 12..40 of the higher (exclusive) bound of the WP= R2 region"; }); =20 impl NV_PFB_PRI_MMU_WPR2_ADDR_HI { @@ -169,25 +170,25 @@ pub(crate) fn higher_bound(self) -> u64 { =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; +nv_reg!(NV_PGC6_BSI_SECURE_SCRATCH_14 @ 0x001180f8 { + 26:26 boot_stage_3_handoff =3D> bool; }); =20 // 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, +nv_reg!(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"; + 0:0 read_protection_level0 =3D> bool, "Set after FWSEC lowers its = protection level"; }); =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_PGC6_AON_SECURE_SCRATCH_GROUP_05 @ 0x00118234[1] {}); +nv_reg!(NV_PGC6_AON_SECURE_SCRATCH_GROUP_05 @ 0x00118234[1] {}); =20 -register!( +nv_reg!( 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= )"; + 7:0 progress, "Progress of GFW boot (0xff means completed)"; } ); =20 @@ -198,14 +199,14 @@ pub(crate) fn completed(self) -> bool { } } =20 -register!(NV_PGC6_AON_SECURE_SCRATCH_GROUP_42 @ 0x001183a4 { - 31:0 value as u32; +nv_reg!(NV_PGC6_AON_SECURE_SCRATCH_GROUP_42 @ 0x001183a4 { + 31:0 value; }); =20 -register!( +nv_reg!( 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"; + 31:0 value, "Usable framebuffer size, in megabytes"; } ); =20 @@ -218,9 +219,9 @@ 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 { + 3:3 status_valid =3D> bool, "Set if the `addr` field is valid"; + 31:8 addr, "VGA workspace base address divided by 0x10000"; }); =20 impl NV_PDISP_VGA_WORKSPACE_BASE { @@ -238,47 +239,47 @@ 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 @ 0x00824100[NV_FUSE_OPT_FPF_= SIZE] { + 15:0 data; }); =20 -register!(NV_FUSE_OPT_FPF_SEC2_UCODE1_VERSION @ 0x00824140[NV_FUSE_OPT_FPF= _SIZE] { - 15:0 data as u16; +nv_reg!(NV_FUSE_OPT_FPF_SEC2_UCODE1_VERSION @ 0x00824140[NV_FUSE_OPT_FPF_S= IZE] { + 15:0 data; }); =20 -register!(NV_FUSE_OPT_FPF_GSP_UCODE1_VERSION @ 0x008241c0[NV_FUSE_OPT_FPF_= SIZE] { - 15:0 data as u16; +nv_reg!(NV_FUSE_OPT_FPF_GSP_UCODE1_VERSION @ 0x008241c0[NV_FUSE_OPT_FPF_SI= ZE] { + 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_reg!(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_reg!(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; +nv_reg!(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_reg!(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_reg!(NV_PFALCON_FALCON_HWCFG2 @ PFalconBase[0x000000f4] { + 10:10 riscv =3D> bool; + 12:12 mem_scrubbing =3D> bool, "Set to 0 after memory scrubbing is c= ompleted"; + 31:31 reset_ready =3D> bool, "Signal indicating that reset is comple= ted (GA102+)"; }); =20 impl NV_PFALCON_FALCON_HWCFG2 { @@ -288,107 +289,107 @@ 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; +nv_reg!(NV_PFALCON_FALCON_CPUCTL @ PFalconBase[0x00000100] { + 1:1 startcpu =3D> bool; + 4:4 halted =3D> bool; + 6:6 alias_en =3D> bool; }); =20 -register!(NV_PFALCON_FALCON_BOOTVEC @ PFalconBase[0x00000104] { - 31:0 value as u32; +nv_reg!(NV_PFALCON_FALCON_BOOTVEC @ PFalconBase[0x00000104] { + 31:0 value =3D> u32; }); =20 -register!(NV_PFALCON_FALCON_DMACTL @ PFalconBase[0x0000010c] { - 0:0 require_ctx as bool; - 1:1 dmem_scrubbing as bool; - 2:2 imem_scrubbing as bool; - 6:3 dmaq_num as u8; - 7:7 secure_stat as bool; +nv_reg!(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; }); =20 -register!(NV_PFALCON_FALCON_DMATRFBASE @ PFalconBase[0x00000110] { - 31:0 base as u32; +nv_reg!(NV_PFALCON_FALCON_DMATRFBASE @ PFalconBase[0x00000110] { + 31:0 base =3D> u32; }); =20 -register!(NV_PFALCON_FALCON_DMATRFMOFFS @ PFalconBase[0x00000114] { - 23:0 offs as u32; +nv_reg!(NV_PFALCON_FALCON_DMATRFMOFFS @ PFalconBase[0x00000114] { + 23:0 offs; }); =20 -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; +nv_reg!(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; }); =20 -register!(NV_PFALCON_FALCON_DMATRFFBOFFS @ PFalconBase[0x0000011c] { - 31:0 offs as u32; +nv_reg!(NV_PFALCON_FALCON_DMATRFFBOFFS @ PFalconBase[0x0000011c] { + 31:0 offs =3D> u32; }); =20 -register!(NV_PFALCON_FALCON_DMATRFBASE1 @ PFalconBase[0x00000128] { - 8:0 base as u16; +nv_reg!(NV_PFALCON_FALCON_DMATRFBASE1 @ PFalconBase[0x00000128] { + 8:0 base; }); =20 -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"; +nv_reg!(NV_PFALCON_FALCON_HWCFG1 @ PFalconBase[0x0000012c] { + 3:0 core_rev ?=3D> FalconCoreRev, "Core revision"; + 5:4 security_model ?=3D> FalconSecurityModel, "Security model"; + 7:6 core_rev_subversion =3D> FalconCoreRevSubversion, "Core revisi= on subversion"; }); =20 -register!(NV_PFALCON_FALCON_CPUCTL_ALIAS @ PFalconBase[0x00000130] { - 1:1 startcpu as bool; +nv_reg!(NV_PFALCON_FALCON_CPUCTL_ALIAS @ PFalconBase[0x00000130] { + 1:1 startcpu =3D> bool; }); =20 // 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; +nv_reg!(NV_PFALCON_FALCON_ENGINE @ PFalconBase[0x000003c0] { + 0:0 reset =3D> bool; }); =20 -register!(NV_PFALCON_FBIF_TRANSCFG @ PFalconBase[0x00000600[8]] { - 1:0 target as u8 ?=3D> FalconFbifTarget; - 2:2 mem_type as bool =3D> FalconFbifMemType; +nv_reg!(NV_PFALCON_FBIF_TRANSCFG @ PFalconBase[0x00000600[8]] { + 1:0 target ?=3D> FalconFbifTarget; + 2:2 mem_type =3D> FalconFbifMemType; }); =20 -register!(NV_PFALCON_FBIF_CTL @ PFalconBase[0x00000624] { - 7:7 allow_phys_no_ctx as bool; +nv_reg!(NV_PFALCON_FBIF_CTL @ PFalconBase[0x00000624] { + 7:7 allow_phys_no_ctx =3D> bool; }); =20 /* PFALCON2 */ =20 -register!(NV_PFALCON2_FALCON_MOD_SEL @ PFalcon2Base[0x00000180] { - 7:0 algo as u8 ?=3D> FalconModSelAlgo; +nv_reg!(NV_PFALCON2_FALCON_MOD_SEL @ PFalcon2Base[0x00000180] { + 7:0 algo ?=3D> FalconModSelAlgo; }); =20 -register!(NV_PFALCON2_FALCON_BROM_CURR_UCODE_ID @ PFalcon2Base[0x00000198]= { - 7:0 ucode_id as u8; +nv_reg!(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_reg!(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; +nv_reg!(NV_PFALCON2_FALCON_BROM_PARAADDR @ PFalcon2Base[0x00000210[1]] { + 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_reg!(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 @@ -397,15 +398,15 @@ 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 fd1a815fa57d..000000000000 --- a/drivers/gpu/nova-core/regs/macros.rs +++ /dev/null @@ -1,721 +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>, - { - 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>, - { - 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>, - 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>, - 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>, - 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>, - 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>, - { - 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>, - { - 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>, - 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>, - { - 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>, - { - 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>, - 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>, - 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>, - 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>, - 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>, - 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>, - 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>, - 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