From nobody Sat Oct 3 03:53:58 2026 Received: from PH0PR06CU001.outbound.protection.outlook.com (mail-westus3azon11011065.outbound.protection.outlook.com [40.107.208.65]) (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 A3C0E3BB9E1; Thu, 6 Aug 2026 07:36:38 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=40.107.208.65 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786001800; cv=fail; b=DjRLkeVe0wGCKjzoOPbYIZ7LKsRpYKjoYW/6MRRd93z/RizII+IypgspGgorMjdhOwlIX/i39cx2Bvmzegm1pezJhK9kkxl5YRie72xNCljqA5FjmbGJ6rpHtYbjwbHXNpSbCQsv6Xd8Ckzbk8VwmJo3X3VJaqFPQrsjcinCYz0= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786001800; c=relaxed/simple; bh=uXQqdD5fxgQflsgVMNEfqTIkPGY5wmUo2XnYmjRbESA=; h=From:Date:Subject:Content-Type:Message-Id:References:In-Reply-To: To:Cc:MIME-Version; b=MmBhUxeJ8rG2WtXFnsGgTXJJV3XWl9fFtTrIopCT2c7fLWsDXphceIAUImnTe6WgeD3zXZexuX3qun/nosT0bR995lwjpEXHFjrYAKdHsUus4WZ/jevQucgp8dgjZT7EolDi1DX+2Vc/4ominAgvd6tisy5qERCzdE7lyWqnjSc= 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=RV2nYT9n; arc=fail smtp.client-ip=40.107.208.65 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="RV2nYT9n" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=nMzF4k3LFGAmNF3sfYV78VaHFDW2e7+AHKRG6tgXk9iVclj+DFUsETYcEqjbk09IIii1XC6yxoPVotdHhoC0uaq8jlQjl0L9D7bOfcLFwob3iqAVZOcs3fhR5p9fBAf2z99IWAEhTwJj9xK+xKNdm073FhdfmfNJ+nzGJK5Il2W2loU++rPaSyGkI/fs5bmKi5trPLEfE1qIsdiKjpieHqqDeEmPGmFngfnVjuH9Cl37YpIs1F+imMq+x7AfNs9dkOBK83WyCaBT1NnLzdsXqkxmOD7hYdhhuYNBpcDUV6kV4CQIU3Z/gUdaSF8IaijHc0qCUqfxkjpCAst6z6K/Nw== 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=dAYpAy8/2R8bDfnL6Bdl/75karKxdg5K3s6wbTei5Qs=; b=wQld0cqOloBhlMN8r1n4d9kI29JgdaBIj4cv5x7++3jWuy6Sqs979joOvmS0gS5mNYizvlGjuD5RmF9++DH2KwR3k6HKXdj40sV65KmKiG8u0jm4zwyGEMDA8uHnqaoIBe96XC6GSHKJ8IU02J9OCFy2/6x69QfwnDOIFYHiPxCiyfA9PlAqPUt+jdrPo4BPRZpB3IUxMpMs9fDl7hoJ8za4SPR4BoKjPwshfL2YEKEMVQN8JfZT1VeF+1EeVp5XuuV5Da1q4ajywl+rasAn8fe1quDYbpAOib7ZWIxOwNyXK3A8HRwb1bXNw77UYwoXiYUKbpc5ijqqHd12VXp4fQ== 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=dAYpAy8/2R8bDfnL6Bdl/75karKxdg5K3s6wbTei5Qs=; b=RV2nYT9nO4Q7K5KN2SbzDYvPIYWxUS/w+X3F5l9udHp3hGSQre9OnZ1Z84VyySTK8VA0Xm1SxXO2H4krxVZ93YTLCeeJb8AsoVB4lA70vxyyisV/5kNROAkzE0QWhKOk4Ki06fMKtxWwjb9Kq7OcNuqyxljRJfv9SiVwrEtCiJkWlRujfnoQTBiwIs0eVcyPWL1P0yJyOAH7cqB3QmDDzoOaw+Rbbft+Rm8EIW/hJTwWnBMs7TH3IS9VgeuwBPQx+n089g6HpmTMMv1UdxWBP5MrJbzjsEN7P9J8Icy9q4BSVMYqMoyixa8qXqLfTKONzFaVmWHXuUeTY2SwENUNjw== 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 CH3PR12MB8878.namprd12.prod.outlook.com (2603:10b6:610:17e::21) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.21.292.19; Thu, 6 Aug 2026 07:36:31 +0000 Received: from CH2PR12MB3990.namprd12.prod.outlook.com ([fe80::7de1:4fe5:8ead:5989]) by CH2PR12MB3990.namprd12.prod.outlook.com ([fe80::7de1:4fe5:8ead:5989%4]) with mapi id 15.21.0292.018; Thu, 6 Aug 2026 07:36:31 +0000 From: Alexandre Courbot Date: Thu, 06 Aug 2026 16:35:53 +0900 Subject: [PATCH v2 1/2] rust: add functions and traits for lossless integer conversions Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260806-as_casts-v2-1-cb76a4d3a6ef@nvidia.com> References: <20260806-as_casts-v2-0-cb76a4d3a6ef@nvidia.com> In-Reply-To: <20260806-as_casts-v2-0-cb76a4d3a6ef@nvidia.com> To: Alexandre Courbot , Yury Norov , Miguel Ojeda , Boqun Feng , Gary Guo , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Andreas Hindborg , Alice Ryhl , Trevor Gross , Danilo Krummrich , Daniel Almeida , Tamir Duberstein , =?utf-8?q?Onur_=C3=96zkan?= , David Airlie , Simona Vetter Cc: John Hubbard , Alistair Popple , Timur Tabi , Eliot Courtney , Zhi Wang , linux-kernel@vger.kernel.org, rust-for-linux@vger.kernel.org, nova-gpu@lists.linux.dev, dri-devel@lists.freedesktop.org X-Mailer: b4 0.15.2 X-ClientProxiedBy: TYCP286CA0147.JPNP286.PROD.OUTLOOK.COM (2603:1096:400:31b::10) 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_|CH3PR12MB8878:EE_ X-MS-Office365-Filtering-Correlation-Id: 731de16a-452d-4087-dc70-08def38d6ee1 X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|376014|7416014|23010399003|10070799003|366016|1800799024|921020|6133799003|10067099003|11063799006|56012099006|18002099003|22082099003; X-Microsoft-Antispam-Message-Info: f2aa50bOpe6ZlTCWm2Vvs84sBkbhnDIOu5Y2N1qWPzPRCSlRdhv5+M8jE4T4zEoVMzGLE5fa0DImePXr9liGOwExRXDq4v31xDWmY7yNhz9cS+qtz1CqbdM/tcCamaM6XCTXcNCAcUEdnW9Ry722rzweoTFGO/PumPgXpJ+m0fhOjRqfVkY7JWoCAL3tMxbh0wXByuvRbael9H57NrHBSRyyp0oGvHbdlwzvDJSAwPzN2yrF5VHapPQUiFThrZF3aMxy9a1H7Pta1JrBu8bxbLPJN3i9xvKkcgaay5khKlOmxwwIv4MGIzssuWji49hS9lKcN3O/W2zudZcUWLrilyR+UjJ8uRZtlkT6GdCWnp+GP25y5/wHeMbnsHcDd8QHyBTjLbhRm3k0kP3pF7gb/HhqWBON2UhHwmP+7jw3cauNQS50JTmWXPmcQbD1+mpKfzx+cMHbVlybwHtg1g0uDJ5sUOXnCmkykNz03JpHVwlYce8pmWdo4mTVjvdwfWgvX32wzWl1uCjXquLpqCuWnxLHHP4ZtEA7eMmflvuWu7YIYJkYPByJpEPfRHXzUd9d25ADMYTvJQqR+1J+/dKQp01fQWGhmd3fD8I05kWrQ4Z9NZhko8Fi5ZVcGUKQ0mdGEAkk9Ahpzkku4O+0urxSs2PkiUSaqdAaBxFwDq1sMwgyypalGOpA0PPu9FUXuUrS/r8PBpY8+yvcwwKcnV949A== 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)(376014)(7416014)(23010399003)(10070799003)(366016)(1800799024)(921020)(6133799003)(10067099003)(11063799006)(56012099006)(18002099003)(22082099003);DIR:OUT;SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 2 X-MS-Exchange-AntiSpam-MessageData-0: =?utf-8?B?TVEzdSthZUQ0djY2QW41ei9rSW5RMk51ZXRkVnd6ODJHVWM0T3pQOHRxOEJ4?= =?utf-8?B?bjFTaW41ZkNVcm94dlFqbzE3VmxNdjYvZnhNWGRyOEw0bDUzS2p4Nm9aSG8y?= =?utf-8?B?VHRDTHR6ajRHaGVXdFlyQjlJZnl6ODA3bVB0Q1NJanZTQnNNcDN6UGFDb0Ry?= =?utf-8?B?T0c0VVhuVFAvR3BTTGQ5ZmkwT2ZvdTExb1lDS0hETEl0KzBBSnhUd3UzUStO?= =?utf-8?B?eWFKeUNEa2VubEViRDBuTGFWZDN3WnJtUE5CWG9xLzJnQmVqaktuREJuL3Yz?= =?utf-8?B?OEVMMEI1OU1yNWhrOEtMdVpEb2FGcnEyUTJ4U01HOUs1ZVdHcHFaS2RZZmJ2?= =?utf-8?B?Vk5OK2d0VXBOZ2dRSXhnVEVieVFBZkx3RnNMdVRUa3BnSHo4aW1qSllpdlNU?= =?utf-8?B?WGs5QmlzMDlhdXpTN3JBYm1ZUmdRSXhrbkhORHRteXFFc3Z4ZnJINHVhQUhF?= =?utf-8?B?STRKR0ttM3JJVncwRjdMNHdmL2h1RS9LbS84TXQ2UEZYbU91M25PeFJZTWJu?= =?utf-8?B?V2tNL2d5TFBXaGVWU3h4WDBOZlFvZTRSdXRuZFhEc2k3NzNNMVU3dUxBRmZH?= =?utf-8?B?Q1ZyZm5teXQybDRrZ0wzY3lFNExxVU9GUzdLK2Y3d2JhS3lJeXZrOHJJeGZo?= =?utf-8?B?UDhEQkdCVnkwalR5ZW1vQVNkSStKUm5QUjVQSFg4SkdrbzZ6c2dLT1gycTEy?= =?utf-8?B?d1R2Z0h0T2lsWVdKN2oyN3RPUkZVb285WWQ5Q1VrTDVlN1NGaWFDMWkwMDZo?= =?utf-8?B?TlhzQmtyVWpUb0Y3U2VnSDB3bG9wdEc5dWhiWExuZm1XZkpxSS9Mckp3a256?= =?utf-8?B?WlQxbWVHQjJtcUJWVlJvenQ2N1hQcHVFdGxnaEFCOGcwNDdoVTJzdHduSkJE?= =?utf-8?B?T3ZMVjRMWGM3UlN0VVp4UWdCMlFkc2I4WFl2VDIvdVZEMEZLRVJqUFN6Z1k1?= =?utf-8?B?dTgrQzlpKzhyNW10Z21kMkNnSWdLMVZSR3R2MjY1RGRRSlRmRXRoNG0vbXRq?= =?utf-8?B?aUtHRUYrdnBSVXo5VzZDMzVxcCthOXQrMzBta0luVDRUdG9UNGZKYjhFcExl?= =?utf-8?B?L3o5blF1MGZjU3dhRWxXZjhrUFFlRnR2aFpKbGt5dUtDbzVaQis2VjBVRm5I?= =?utf-8?B?Wk1WSjJjR00zcXhlckEzTGdJUXdUOHZxRkozMVRlQksyemNsOFlmSDFFWTEx?= =?utf-8?B?RFQ4SGYwNnZWT0R6RkwwelFMeEExWmw3cFVmMktQUUNzUk0vUVRzLzEvVGtW?= =?utf-8?B?QW1taExJc3hEWDBsZjhmeWk0Q0dZaCtCZnZVaDI0TldHRnU5YzdtQ0RxK2lU?= =?utf-8?B?cGNUU1FEc0QrODYrZ0tmK3VtMWpLZ09WR0hIVFR5VVBFS3VmKzJIeHB2QmlX?= =?utf-8?B?dkJ2U2ZTV3JPY2V5VDJxQ3duVU1LblNhZkVjeWpobWFFeVdjMkRZbWo3ZGVL?= =?utf-8?B?b3ZtYmpabHZLcnBuVlJ5TlZDb29hZGpabzZUSGZaNk5YWEdqUWtETVN4NldT?= =?utf-8?B?WDc2NFNBK1BHYjlrendaTGJoMXYrSFdzakRLUUpSemdUNkxZSTB5SlF2Q1pS?= =?utf-8?B?RzVRSjhveUJRZ2gvejRzOUJLK2hpSExLcEt5OU1jU01iTHVPYURIUHcycVJx?= =?utf-8?B?UFFjc045RnE3azkrems4Y1dPY01OVndRRm40Rmd3Y2RmcmZWbkNnR3Z5dWxp?= =?utf-8?B?enFWUDhQNDVuWC9wZkRhUkFnUFE1RjhFV0VhQlJqN1pjWFlJTTN4YXZXdHdo?= =?utf-8?B?bWZ3YjRmVnNMcnFwT0dsU3VOZ3JUeXVVSWJKM2t5ZzNHR2ZyQ1dmL0VJcVFC?= =?utf-8?B?YUxHRTJjUHZtZzhkUGtmMXROcUxpU2svQ2VKQm5QZzVRQUF5akNMZ0t1cW52?= =?utf-8?B?ZzFZSys0cUpQTytCQytDaUlET1JzYmlYV2FnVFlHYWNXSzJ5bTc2TXcvMEN3?= =?utf-8?B?RDVOWi9Tajg3Z2lITDlvU3B2SzN3RC91cGM2SXBPU3h2YWxoYzNMbnhTZzhu?= =?utf-8?B?VlhGb0FoOUxGZWZvK3pGVGxzbFY3eDJMUUFyQkFwYjhnREdKaXJnNHgyN2Vr?= =?utf-8?B?UVB6cHBwWkhLRVpYN25CTHY2RDNhOUlHOVRNUHlKQXVpRWFWWm9qbkQrbWpv?= =?utf-8?B?bkZENXBBTjZGNlFra1NOQzNhRkNRK2Y4ZWlSM0FxOHdlTXM1RmVRd2gwVUs3?= =?utf-8?B?dnlTekhZNm5zcmRkOFJzOTlNQys2a2dadm1EeHlpOUp0L2NJT2srSzRSK1I0?= =?utf-8?B?OGhhaG9xS0M5RG5Fd3BPMnBFOUFuMzdMWnh5SEF3UFg5UURXcUJlUEwxY0ZF?= =?utf-8?B?Y215NXA4WUxlZHVEczIwcWRBdElkRitzMG12ZzdQVlVwYmp0T3VCYTFiOFp4?= =?utf-8?Q?PWbc01fSQZZOn/25heb+ajAuth+ymkIIhXz1Tf94aYsBQ?= X-MS-Exchange-AntiSpam-MessageData-1: 2W9PwPqU3Je0Jg== X-OriginatorOrg: Nvidia.com X-MS-Exchange-CrossTenant-Network-Message-Id: 731de16a-452d-4087-dc70-08def38d6ee1 X-MS-Exchange-CrossTenant-AuthSource: CH2PR12MB3990.namprd12.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 06 Aug 2026 07:36:31.1075 (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: LQkGmWiyuoN3BIAVUa+V78pVh9CPEHz092REHVhJCzcVBMYlPCjAy+2umhhG0YHxTIi5ZfcbnJAMIrA7GFSHJQ== X-MS-Exchange-Transport-CrossTenantHeadersStamped: CH3PR12MB8878 The core library's `From` implementations do not cover conversions that are not portable or future-proof. For instance, even though it is safe today, `From` is not implemented for `u64` because of the possibility of supporting larger-than-64bit architectures in the future. However, the kernel supports a narrower set of architectures, with a considerable amount of code that is architecture-specific. This makes it helpful and desirable to provide more infallible conversions, lest we rely on the `as` keyword and carry the risk of silently losing data. Thus, introduce a new module `num::casts` that provides safe const functions performing more conversions allowed by the build target, as well as `FromSafeCast` and `IntoSafeCast` traits that are just extensions of `From` and `Into` to conversions that are known to be lossless. Some conversions are architecture-specific: for instance, converting a `u64` to a `usize` is only lossless on 64-bit platforms. These conversions are made available via a dedicated `arch` sub-module. Suggested-by: Danilo Krummrich Link: https://lore.kernel.org/rust-for-linux/DDK4KADWJHMG.1FUPL3SDR26XF@ker= nel.org/ Signed-off-by: Alexandre Courbot Reviewed-by: Danilo Krummrich --- rust/kernel/num.rs | 2 + rust/kernel/num/casts.rs | 298 +++++++++++++++++++++++++++++++++++++++++++= ++++ 2 files changed, 300 insertions(+) diff --git a/rust/kernel/num.rs b/rust/kernel/num.rs index 8532b511384c..dbe848e30efe 100644 --- a/rust/kernel/num.rs +++ b/rust/kernel/num.rs @@ -5,6 +5,8 @@ use core::ops; =20 pub mod bounded; +pub mod casts; + pub use bounded::*; =20 /// Designates unsigned primitive types. diff --git a/rust/kernel/num/casts.rs b/rust/kernel/num/casts.rs new file mode 100644 index 000000000000..a44397541cfe --- /dev/null +++ b/rust/kernel/num/casts.rs @@ -0,0 +1,298 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! Helpers for performing lossless integer casts. +//! +//! The `as` keyword can be used to perform casts between integer types, b= ut it unfortunately makes +//! no distinction between casts that are lossless, and casts from a large= r type into a smaller one +//! that might silently strip data away. Thus, its use in the kernel is di= scouraged in favor of +//! [`From`] implementations. +//! +//! Conversely, there are casts that are lossless depending on the build a= rchitecture (such as +//! casting [`usize`] to [`u64`] on 32 or 64 bit archs), but not supported= by [`From`] +//! implementations in the standard library because they are not portable.= It does however make +//! sense for the kernel to support these, if only for code that is archit= ecture-specific. +//! +//! This module provides ways to perform such conversions safely: +//! +//! - A series of const functions (e.g. [`usize_as_u64`]) supporting safe = conversions in const +//! context. Conversions supported by [`From`] implementations in the st= andard library are also +//! covered as the [`From`] trait cannot be used in const context. +//! - Two extension traits, [`FromSafeCast`] and [`IntoSafeCast`], providi= ng conversion methods +//! similar to [`From`] and [`Into`] for conversions that are safe to pe= rform in the kernel, but +//! not supported by the standard library. +//! - Another series of const functions (e.g. [`u64_into_u8`]) supporting = the conversion of a const +//! value from a larger type into a smaller one, provided the value fits= into the destination +//! type. This is useful if a constant is defined as a larger type, but = needs to be used as a +//! smaller one. +//! - An [`arch`] sub-module, defining more conversion functions that are = only guaranteed to be +//! lossless for a given pointer size. These can only be used in code th= at is specific to a +//! given pointer size. +//! +//! # Examples +//! +//! ``` +//! use kernel::num::casts::{self, FromSafeCast, IntoSafeCast}; +//! +//! // Conversion from const context. +//! const USIZED_CONST: usize =3D casts::u8_as_usize(255u8); +//! +//! // Non-const conversions. +//! let a =3D u64::from_safe_cast(4096usize); +//! let b: u64 =3D 4096usize.into_safe_cast(); +//! ``` + +use crate::prelude::*; + +/// Implements safe `as` conversion functions from a given type into a ser= ies of target types. +/// +/// These functions can be used in place of `as`, with the guarantee that = they will be lossless. +macro_rules! impl_safe_as { + ($from:ty as { $($into:ty),* }) =3D> { + $( + $crate::macros::paste! { + #[doc =3D ::core::concat!( + "Losslessly converts a [`", + ::core::stringify!($from), + "`] into a [`", + ::core::stringify!($into), + "`].")] + /// + /// This conversion is allowed as it is always lossless. Prefe= r this over the `as` + /// keyword to ensure no lossy casts are performed. + /// + /// This is for use from a `const` context. For non `const` us= e, prefer the + /// [`FromSafeCast`] and [`IntoSafeCast`] traits. + /// + /// # Examples + /// + /// ``` + /// use kernel::num::casts; + /// + #[doc =3D ::core::concat!( + "assert_eq!(casts::", + ::core::stringify!($from), + "_as_", + ::core::stringify!($into), + "(1", + ::core::stringify!($from), + "), 1", + ::core::stringify!($into), + ");")] + /// ``` + #[inline] + pub const fn [<$from _as_ $into>](value: $from) -> $into { + $crate::static_assert!(size_of::<$into>() >=3D size_of::<$= from>()); + + value as $into + } + } + )* + }; +} + +// Valid `Into` transformations. +impl_safe_as!(u8 as { u16, u32, u64, usize }); +impl_safe_as!(u16 as { u32, u64, usize }); +impl_safe_as!(u32 as { u64 }); +// A `usize` fits into a `u64` on all supported platforms. +impl_safe_as!(usize as { u64 }); +// A `u32` fits into a `usize` on all supported platforms. +impl_safe_as!(u32 as { usize }); + +/// Extension trait providing guaranteed lossless cast to `Self` from `T`. +/// +/// The standard library's `From` implementations do not cover conversions= that are not portable or +/// future-proof. For instance, even though it is safe today, `From= ` is not implemented for +/// [`u64`] because of the possibility of needing to support larger-than-6= 4bit architectures in the +/// future. +/// +/// The workaround is to either deal with the error handling of [`TryFrom`= ] for an operation that +/// technically cannot fail, or to use the `as` keyword, which can silentl= y strip data if the +/// destination type is smaller than the source. +/// +/// Both options are hardly acceptable for the kernel. It is also a much m= ore architecture +/// dependent environment, supporting only 32 and 64 bit architectures, wi= th some modules +/// explicitly depending on a specific bus width that could greatly benefi= t from infallible +/// conversion operations. +/// +/// Thus this extension trait that provides, for all architectures support= ed by the kernel, +/// conversion methods between types for which such a cast is lossless. +/// +/// In other words, this trait is implemented if, for all supported target= s and with `t: T`, the +/// `t as Self` operation is completely lossless. +/// +/// Prefer this over the `as` keyword to guarantee that no lossy casts are= performed. +/// +/// If you need to perform a conversion in `const` context, use [`u32_as_u= size`], [`usize_as_u64`], +/// etc. +/// +/// # Examples +/// +/// ``` +/// use kernel::num::casts::FromSafeCast; +/// +/// assert_eq!(usize::from_safe_cast(0xf00u32), 0xf00usize); +/// ``` +pub trait FromSafeCast { + /// Create a `Self` from `value`. This operation is guaranteed to be l= ossless. + fn from_safe_cast(value: T) -> Self; +} + +// A `usize` fits into a `u64` on all supported platforms. +impl FromSafeCast for u64 { + #[inline] + fn from_safe_cast(value: usize) -> Self { + usize_as_u64(value) + } +} + +// A `u32` fits into a `usize` on all supported platforms. +impl FromSafeCast for usize { + #[inline] + fn from_safe_cast(value: u32) -> Self { + u32_as_usize(value) + } +} + +/// Counterpart to the [`FromSafeCast`] trait, i.e. this trait is to [`Fro= mSafeCast`] what [`Into`] +/// is to [`From`]. +/// +/// See the documentation of [`FromSafeCast`] for the motivation. +/// +/// # Examples +/// +/// ``` +/// use kernel::num::casts::IntoSafeCast; +/// +/// assert_eq!(0xf00usize, 0xf00u32.into_safe_cast()); +/// ``` +pub trait IntoSafeCast { + /// Convert `self` into a `T`. This operation is guaranteed to be loss= less. + fn into_safe_cast(self) -> T; +} + +/// Reverse operation for types implementing [`FromSafeCast`]. +impl IntoSafeCast for S +where + T: FromSafeCast, +{ + #[inline] + fn into_safe_cast(self) -> T { + T::from_safe_cast(self) + } +} + +/// Implements lossless conversion of a constant from a larger type into a= smaller one. +macro_rules! impl_const_into { + ($from:ty =3D> { $($into:ty),* }) =3D> { + $( + $crate::macros::paste! { + #[doc =3D ::core::concat!( + "Performs a build-time safe conversion of a [`", + ::core::stringify!($from), + "`] constant value into a [`", + ::core::stringify!($into), + "`].")] + /// + /// This checks at compile-time that the conversion is lossles= s, and triggers a build + /// error if it isn't. + /// + /// # Examples + /// + /// ``` + /// use kernel::num::casts; + /// + /// // Succeeds because the value of the source fits into the = destination's type. + #[doc =3D ::core::concat!( + "assert_eq!(casts::", + ::core::stringify!($from), + "_into_", + ::core::stringify!($into), + "::<1", + ::core::stringify!($from), + ">(), 1", + ::core::stringify!($into), + ");")] + /// ``` + #[inline] + pub const fn [<$from _into_ $into>]() -> $into= { + // Make sure that the target type is smaller than the sour= ce one. + $crate::static_assert!($from::BITS >=3D $into::BITS); + // CAST: we statically enforced above that `$from` is larg= er than `$into`, so the + // `as` conversion will be lossless. + $crate::const_assert!(N >=3D $into::MIN as $from && N <=3D= $into::MAX as $from); + + N as $into + } + } + )* + }; +} + +impl_const_into!(usize =3D> { u8, u16, u32 }); +impl_const_into!(u64 =3D> { u8, u16, u32 }); +impl_const_into!(u32 =3D> { u8, u16 }); +impl_const_into!(u16 =3D> { u8 }); + +/// Conversions that are only lossless for the current architecture. +/// +/// # Portability +/// +/// Callers of this module become dependent on the setting of `CONFIG_64BI= T`. Use with caution, and +/// never in code that is portable across pointer sizes. +pub mod arch { + /// Trait identical to [`FromSafeCast`](super::FromSafeCast), but for = conversions that are not + /// available on all architectures. + pub trait FromSafeCastArch { + /// Create a `Self` from `value`. This operation is guaranteed to = be lossless. + fn from_safe_cast_arch(value: T) -> Self; + } + + /// Trait identical to [`IntoSafeCast`](super::IntoSafeCast), but for = conversions that are not + /// available on all architectures. + pub trait IntoSafeCastArch { + /// Convert `self` into a `T`. This operation is guaranteed to be = lossless. + fn into_safe_cast_arch(self) -> T; + } + + /// Reverse operation for types implementing [`FromSafeCastArch`]. + impl IntoSafeCastArch for S + where + T: FromSafeCastArch, + { + #[inline] + fn into_safe_cast_arch(self) -> T { + T::from_safe_cast_arch(self) + } + } + + /// A `u64` fits into a `usize` on 64-bit platforms. + #[cfg(CONFIG_64BIT)] + #[inline] + pub const fn u64_as_usize(value: u64) -> usize { + value as usize + } + + #[cfg(CONFIG_64BIT)] + impl FromSafeCastArch for usize { + #[inline] + fn from_safe_cast_arch(value: u64) -> Self { + u64_as_usize(value) + } + } + + /// A `usize` fits into a `u32` on 32-bit platforms. + #[cfg(not(CONFIG_64BIT))] + #[inline] + pub const fn usize_as_u32(value: usize) -> u32 { + value as u32 + } + + #[cfg(not(CONFIG_64BIT))] + impl FromSafeCastArch for u32 { + #[inline] + fn from_safe_cast_arch(value: usize) -> Self { + usize_as_u32(value) + } + } +} --=20 2.55.0 From nobody Sat Oct 3 03:53:58 2026 Received: from CO1PR03CU002.outbound.protection.outlook.com (mail-westus2azon11010056.outbound.protection.outlook.com [52.101.46.56]) (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 415BA3BB9E1; Thu, 6 Aug 2026 07:36:46 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=52.101.46.56 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786001811; cv=fail; b=AI1wS69b/FT8icISyke7JpR6JudCvfUfLBgISCkq9FjSfLkWwLKXISZ8DsdlDSO0srKGI1dTKjofpp16l2c+T1wX1gD7jrAznlJSixqQFjBL7+FO5wPcSlGaYGxBtTSaQyQYHeavAZIZRk9LC3niMhH87morWl6x0xAcwpRx/Og= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786001811; c=relaxed/simple; bh=7z3sf+XOHz4sV6Cn8X1V9/2miOqHsLzGgPmKKz9y348=; h=From:Date:Subject:Content-Type:Message-Id:References:In-Reply-To: To:Cc:MIME-Version; b=oeLxhC/VNMGw2Wd4luht9RI0lQYq29MHgJNxE/OrdLxv4yC6ORQ2+zygJzA+YYuQpxkwAOkdwLK+3EK4ImxwQO0TP8KPRjgmqcR6VmNeeQZwOBnheqnqQ6+WLI9HUmqs+4GjfjGqBAQWgXSSLs+TVAUFQfwgkPaZMgxA9IvPOTk= 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=QWX0Zn4A; arc=fail smtp.client-ip=52.101.46.56 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="QWX0Zn4A" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=OGDuLAM8NAaUdr4p6uEljN5CoRRNPjlvCDOM1CxaVkHwSm8iNs9eKTRDCCXsl67f1mLq1Ewz5UulxcnwTIllRcsEY3y4QZGWQDSGNnZOi8wRZWioui7lCvi41eNSImZF02ueomEqFfOPO61UnsNBNOvcbn/lj+GVgQodZajcegQura8WKUpqHjBzxmwjW9TxJiMGlaICORv1i6H4dCaBeYWuABS7lIHGMbAIUu/GQbsqouqs7g6hjfYL2OSkkF0OAvuBH95Yl+F8Jbjysm0yfiP4Pcp6Kyq9ewk91+f3i3/9Ut+JmA9yroRfcBhHC8KD0ynUlXm/PcKVXXxq386zjw== 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=2x0K2C+2AUoj+aDSk33iAFJm31vdhGpz60oxtJcjmAg=; b=rQCZk4qGZ3ffaHoa3T249DSZxHsWvYLI6OZ4BTz/EUsqGAWsmSXdDLIPxKwc75QMF2X33f/39RExVmHg9AMWek+SkgirggXBniRFkr/3eHHq2L8kF8Jmf19YdbnUXae4GKHAIfe5906Kw1+SyFefazp0knODybAS7o1gTgckU+DrxrKKVCqGXM4H7rMRoUmtenCSpjonFUMFl8resU9j6Zb0P1Lh7J+cAeoVOIwbJbkTukrXPp2khzO5spXnseIwP+mNyFvVVdOpqIDsJU5Rew/g9g9XMmixRb4Q+O89Rw25v2D3v+sHT75AbMqCf3FzM6obz442QW66foRN7/PS5g== 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=2x0K2C+2AUoj+aDSk33iAFJm31vdhGpz60oxtJcjmAg=; b=QWX0Zn4A1hNYBxPcBETV+CvdvTuWovks8FJsi3z6/ryv/0OPT3Xm4/LdGR3+9Qao/GShjBckKtJr0hAVYr3NvqtwIJ9htvWcV+SRv7LyVnfq92Vg4rJdl5YVN9ZFzYhK1SAAWW173O2ASvDekpYP1/NIcGsCr6B1jAPkA7qvv1/6CCALPcVsu/zS18bhaYgfu9DmicyaONOx3boLp5aijFplRdFr7GPy63+4zJcWeXNfUmyK3zBdGFeYAktnozG1QnwDtTfUv4zXcI0Bg5bH54gBJVB5JYVnNOFwEyfFBiOQzKDmVrlBSrCIb3VDgFZ2Aev54hb9uv9JOAx2GzMlLw== 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 CH3PR12MB8878.namprd12.prod.outlook.com (2603:10b6:610:17e::21) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.21.292.19; Thu, 6 Aug 2026 07:36:35 +0000 Received: from CH2PR12MB3990.namprd12.prod.outlook.com ([fe80::7de1:4fe5:8ead:5989]) by CH2PR12MB3990.namprd12.prod.outlook.com ([fe80::7de1:4fe5:8ead:5989%4]) with mapi id 15.21.0292.018; Thu, 6 Aug 2026 07:36:35 +0000 From: Alexandre Courbot Date: Thu, 06 Aug 2026 16:35:54 +0900 Subject: [PATCH v2 2/2] gpu: nova-core: use kernel lossless integer conversion module Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260806-as_casts-v2-2-cb76a4d3a6ef@nvidia.com> References: <20260806-as_casts-v2-0-cb76a4d3a6ef@nvidia.com> In-Reply-To: <20260806-as_casts-v2-0-cb76a4d3a6ef@nvidia.com> To: Alexandre Courbot , Yury Norov , Miguel Ojeda , Boqun Feng , Gary Guo , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Andreas Hindborg , Alice Ryhl , Trevor Gross , Danilo Krummrich , Daniel Almeida , Tamir Duberstein , =?utf-8?q?Onur_=C3=96zkan?= , David Airlie , Simona Vetter Cc: John Hubbard , Alistair Popple , Timur Tabi , Eliot Courtney , Zhi Wang , linux-kernel@vger.kernel.org, rust-for-linux@vger.kernel.org, nova-gpu@lists.linux.dev, dri-devel@lists.freedesktop.org X-Mailer: b4 0.15.2 X-ClientProxiedBy: TY4PR01CA0080.jpnprd01.prod.outlook.com (2603:1096:405:36c::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_|CH3PR12MB8878:EE_ X-MS-Office365-Filtering-Correlation-Id: 35035d9b-7b83-4086-d00e-08def38d7114 X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|376014|7416014|23010399003|10070799003|366016|1800799024|921020|6133799003|10067099003|11063799006|56012099006|18002099003|22082099003|3023799007; X-Microsoft-Antispam-Message-Info: hpMsi8MbXu55oYlR/VoHFu1Q5ce0i0EhGJS9NIi6vZxgaYyzslA1HTfI8NAD73UZAb8BBLyTQGYUuHI6dQDpI+N6yz1nRVIfVbC6jbDXgOydU4Bk3JM6eVzWqA5mcfiRavoFw//VUe8DGhrh9k50ypjm3n5yVRJJdsZo+hiK71+zq1p9aesaXB4S5NUZ1yxjJMSo+pZKuVnvN7Fvz+m0dHiRynw6bezRZwo7NFF4wmOf6bSRspM1TreYpWGCu0IataNnfDVcHOIGn1VzE2nooWjytNBqSQDmqbT0CWooy20/B7DPWYjkrNs6beRl5wVq/TA0bvvRJcGFcifFD64wwN4heY1nwgWopvV2hoQs0crMlFqyp6YpSxpX3pae31Sj/hOYQ+OuelbAw7nYUzdKxeoLuspNNuWSzMts3K4pUsMi+j62NdPNQR/mFNTm8S5MF64oH5nZ64CCOOHpsmkSLmnTDudqbXhFkjUnRBArLKXbuGoS8nOnhpwXfdegNvYzIhduMLzPV9/xPujdwsH1vv3vkWX9y9Z1jONjx6LENIg9fq0puGtAcXa1rSKRchqtV8aK94CDQo9KnQFJbGQNr4FlvYGqIZntjNSHTLPDPNzgEHPUlVIW7KwjBNltd/3LxvipPClpzoksRvhD8APv2eyGvc9EKnw0+NrnQ8pXterzU8pivDrwNuySJTXhcF4869yRAbeSk41iIxkHfIKQyw== 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)(376014)(7416014)(23010399003)(10070799003)(366016)(1800799024)(921020)(6133799003)(10067099003)(11063799006)(56012099006)(18002099003)(22082099003)(3023799007);DIR:OUT;SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 2 X-MS-Exchange-AntiSpam-MessageData-0: =?utf-8?B?UkJTQU1WaW1JS1BqcUlZeXU5OTJjS3gwWFFPUXNia2hVMHNXSDMzeE5aRnI2?= =?utf-8?B?bjJLeTVGMkxrSFp6cW9BcXhtNmZhTDVHTDMwRVFKSGxCQ3RxUmR5Z1RVdkRE?= =?utf-8?B?L0c4UnJTM1hIOUpZRnpZU1ZZTFBlYWR0SzZTeisrV0Y5aWRQVnl5TnRheTAv?= =?utf-8?B?SlVRNUZKNXQ3ODlJR0dyMWFXYXQ5WERDR3h2UEx6QWFZS1NFVFdCd1l2d0Vx?= =?utf-8?B?c1M5WjZ5M1BETWZMSDdFckhCNlkwK0thYytDbVBKVit4WFBHQnA4cFR0ZmNt?= =?utf-8?B?djRqV2xMc2ZyYTFpUGlVMWYyM01QeWVXWlNjeVRxUzBkRGtaRVFRVlhRMUc3?= =?utf-8?B?L2xlYlRCZzVyQzFLQmxJMWd6WkxRZDRPK1czVUo2d0pNbnVJRk45b1NNc04w?= =?utf-8?B?NFA2QzhhSGdOOU02ZzZONmlwTlorZUZ0NUtUM3QrZVo1YnJDOVlYM3RCTG1u?= =?utf-8?B?V1ZyVlB6em9OUGxwRms2TFg0b0hTWTFjM2pRaGw0YkYyUmxTT09EZjRLY1M0?= =?utf-8?B?UUhwdGlzR3JpWSsvUGY0dlM4U0RVT3JKQ0NvQTVVOFcwelI2dDRLSG1RSXVu?= =?utf-8?B?TVJHSlArWWdQRVBucFhQUVRySS9RaW5JSFVtdldld2pOM1Q5cGRUTUVmc3Fk?= =?utf-8?B?ejJjazRkemtrTXpsSWRsZlM4Uk5tU0p1ZW1veENUY0xyeUp0ZHFQQ3ZNRFA3?= =?utf-8?B?Y2Fhc1ZLR3RhbFN0SGFMYzZpK21laVYxbUs5UkV0U3ZXTmg2QU9yZitnczJ2?= =?utf-8?B?NGxJQ05GMWFrYlEwYnVnQmxDbGg4RUZsT3NwSGRkTW9hMTBaNmxQeEtJb1Bj?= =?utf-8?B?NXVIYVI4SVNsYXE3MENLS3gxNkhKam5IZ3k2Z2F1cjNyLzJUekE4NUdQUTBh?= =?utf-8?B?YnAyZk11d055SXA3bXVvMWs1OHViNk1mcDQ5U081RUxYdkQrRGZ1dzFWanJP?= =?utf-8?B?a21FQTc5NjRORk5mN2paMVI5ZmFBWjBKU1ZKUUVNbW1ycDd5aXFmZlB5QWhs?= =?utf-8?B?VnJiOUtqYlMxUGFUZk1FSHlyemhJOTNFNTlBdm80Q3FId0tZbUtIR1lZKzdx?= =?utf-8?B?QThqS2k5Q3RsMGdadDMxUjNoNm5JaFFoeWVxMFdjckNSbGZEMEd0bDROYUhO?= =?utf-8?B?UTJzQzE1MU1rNjNieHlqYlpjNG5TSi9wejcweEFFWXUrNFljZ1cxWVFQdndy?= =?utf-8?B?OURhdGh6UExXMGdGVS9XSzllelB6em5KRWd6SzRBQ0hwVnBYbk9ZUk1YeTVX?= =?utf-8?B?ZUROWjArWDdKejc3SnFXa0ltRUdoSXlmb1UydExYbTJiRURIRWUxSUpIYk5u?= =?utf-8?B?dU5mczk2R3FXeE9raWhpenhCSmpTV3JjKzFQcmVTUVNvcWE3a3J3azFXY08y?= =?utf-8?B?Z3Z1cFF4V3d1Q2hJalRBZ0U3dUg5TEJZWWlqdHVGVysxZjhpZjlRbnFMSVJ2?= =?utf-8?B?UDEvMno3dGdETmc1OE91OTR4aFhLQk0wdnlUcE1kdkRhbnphL1cySnpwZXN2?= =?utf-8?B?dzZ4YThSMmpSYzBRaFY0YTRhc3BFUVgvZytKR01mVEpyc0pWa095VHNURjdw?= =?utf-8?B?WXY1S0hUbTdWeGNpYzBaZU90THBZdWJBOUY5YzNnSkNwTlpWYW1zMFhrUTdD?= =?utf-8?B?bndnRTJyY0J5SmtQVzZPcjdRWTdoNDVrR1dEbTRBTDVpOVhmaVgvWmdLUERx?= =?utf-8?B?VnBEM0lKYkVPRmt3OUV3QlNMalZhaHIyamo4Sm5vcGFyU0VNUTEvbnZiYWhV?= =?utf-8?B?UmZ0dHR3NGhJREs3V0VRZ2RveUEwejFlZGJ6RjdhbHNHOTB0TWJaQkN2OUpD?= =?utf-8?B?eUZSNlFUUjNVbzlLbm0yb3BaTmorV05qNGlWK1BVRy9xLzk4OE9ScXkwWmdv?= =?utf-8?B?V0YrQ3FiMlBQSzRKV0kyUlFjclV1ZmlGZTNEemNVRm90VHp5NzVoMU12bDNZ?= =?utf-8?B?UWV0ZTRXZkgvMS9VbEloK3ZkcUJ1d1hVVXZSclZJSENwNnR6aEkrYlJETXFK?= =?utf-8?B?S2oxMDNBa2QvT29LcVUrNmR4cmlVZ05WQ0ZMYzQ1U2JlOHFWc1pLbFVOdlNP?= =?utf-8?B?SVJWSWF2OEh6b1Q0a0tPd2Jkd01vUExXSkZENWpGRFJ0bkptc3o2MUMzQXdi?= =?utf-8?B?ZDN0MVJzVUFWSFRPMFdETU5iV2tLdWk0UnRiWFUwRW9veEgrUCs3ZzFRUFdr?= =?utf-8?B?SnM0bndqYnYvb0JoZWJNZmlCWGZuVjdSRnBPdzE1SExWZGlHZ2tnTmpvbHdQ?= =?utf-8?B?bHoybngvRmNlREVoVUxLelpFaVoyd0FPRVExTzRBSGhZWkYvNERISnVDWVhZ?= =?utf-8?B?K1lZb2ZIMCttSlF4bDgxS1lUc05HNVM2Z2NJS0ZSekpNVnNHN2F0ejhjN2hO?= =?utf-8?Q?d5iwpEs0w9mk7Z9wDsc+834IHSqkE8VvqnmvNxjdkVJ0D?= X-MS-Exchange-AntiSpam-MessageData-1: 2OP5AGS3G14Yjg== X-OriginatorOrg: Nvidia.com X-MS-Exchange-CrossTenant-Network-Message-Id: 35035d9b-7b83-4086-d00e-08def38d7114 X-MS-Exchange-CrossTenant-AuthSource: CH2PR12MB3990.namprd12.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 06 Aug 2026 07:36:34.9571 (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: AEbmWCA/GngFSgvg+/2pbtJt/Qb90FN24gkIYxDXKe+463LykokKXlbusESLjgTZpsrYtt3VoqGRJ/FvgYkfTQ== X-MS-Exchange-Transport-CrossTenantHeadersStamped: CH3PR12MB8878 The `kernel` crate now features a copy of our lossless integer conversion routines. Switch to the kernel version and remove our own. Signed-off-by: Alexandre Courbot Reviewed-by: Danilo Krummrich --- drivers/gpu/nova-core/falcon.rs | 12 +- drivers/gpu/nova-core/falcon/fsp.rs | 4 +- drivers/gpu/nova-core/fb.rs | 2 +- drivers/gpu/nova-core/fb/hal/gb100.rs | 11 +- drivers/gpu/nova-core/firmware.rs | 8 +- drivers/gpu/nova-core/firmware/booter.rs | 10 +- drivers/gpu/nova-core/firmware/fwsec.rs | 2 +- drivers/gpu/nova-core/firmware/fwsec/bootloader.rs | 2 +- drivers/gpu/nova-core/firmware/gsp.rs | 7 +- drivers/gpu/nova-core/firmware/riscv.rs | 6 +- drivers/gpu/nova-core/fsp.rs | 4 +- drivers/gpu/nova-core/gsp.rs | 4 +- drivers/gpu/nova-core/gsp/cmdq.rs | 24 +-- drivers/gpu/nova-core/gsp/fw.rs | 42 ++-- drivers/gpu/nova-core/gsp/sequencer.rs | 2 +- drivers/gpu/nova-core/num.rs | 211 -----------------= ---- drivers/gpu/nova-core/vbios.rs | 2 +- 17 files changed, 73 insertions(+), 280 deletions(-) diff --git a/drivers/gpu/nova-core/falcon.rs b/drivers/gpu/nova-core/falcon= .rs index 94c7696a6493..e352b300f763 100644 --- a/drivers/gpu/nova-core/falcon.rs +++ b/drivers/gpu/nova-core/falcon.rs @@ -23,6 +23,10 @@ }, Io, }, + num::casts::{ + self, + FromSafeCast, // + }, prelude::*, sync::aref::ARef, time::Delta, @@ -33,11 +37,7 @@ driver::Bar0, falcon::hal::LoadMethod, gpu::Chipset, - num::{ - self, - FromSafeCast, // - }, - regs, + regs, // }; =20 pub(crate) mod fsp; @@ -518,7 +518,7 @@ fn dma_wr( target_mem: FalconMem, load_offsets: FalconDmaLoadTarget, ) -> Result { - const DMA_LEN: u32 =3D num::usize_into_u32::<{ MEM_BLOCK_ALIGNMENT= }>(); + const DMA_LEN: u32 =3D casts::usize_into_u32::<{ MEM_BLOCK_ALIGNME= NT }>(); =20 // For IMEM, we want to use the start offset as a virtual address = tag for each page, since // code addresses in the firmware (and the boot vector) are virtua= l. diff --git a/drivers/gpu/nova-core/falcon/fsp.rs b/drivers/gpu/nova-core/fa= lcon/fsp.rs index 52cdb84ef0e8..00bfd56c52a5 100644 --- a/drivers/gpu/nova-core/falcon/fsp.rs +++ b/drivers/gpu/nova-core/falcon/fsp.rs @@ -16,6 +16,7 @@ }, Io, // }, + num::casts, prelude::*, time::Delta, }; @@ -28,7 +29,6 @@ PFalcon2Base, PFalconBase, // }, - num, regs, // }; =20 @@ -155,7 +155,7 @@ pub(crate) fn recv_msg(&mut self, bar: Bar0<'_>) -> Res= ult> { Delta::from_millis(10), Delta::from_millis(FSP_MSG_TIMEOUT_MS), ) - .map(num::u32_as_usize)?; + .map(casts::u32_as_usize)?; =20 let mut buffer =3D KVec::::new(); buffer.resize(msg_size, 0, GFP_KERNEL)?; diff --git a/drivers/gpu/nova-core/fb.rs b/drivers/gpu/nova-core/fb.rs index 725e428154cf..6301ea3ddfb0 100644 --- a/drivers/gpu/nova-core/fb.rs +++ b/drivers/gpu/nova-core/fb.rs @@ -10,6 +10,7 @@ dma::CoherentHandle, fmt, io::Io, + num::casts::FromSafeCast, prelude::*, ptr::{ Alignable, @@ -23,7 +24,6 @@ firmware::gsp::GspFirmware, gpu::Chipset, gsp, - num::FromSafeCast, regs, // }; =20 diff --git a/drivers/gpu/nova-core/fb/hal/gb100.rs b/drivers/gpu/nova-core/= fb/hal/gb100.rs index 6e0eba101ca1..49b85968e919 100644 --- a/drivers/gpu/nova-core/fb/hal/gb100.rs +++ b/drivers/gpu/nova-core/fb/hal/gb100.rs @@ -11,7 +11,10 @@ }, Io, // }, - num::Bounded, + num::{ + casts, + Bounded, // + }, prelude::*, ptr::{ const_align_up, @@ -23,7 +26,6 @@ use crate::{ driver::Bar0, fb::hal::FbHal, - num::usize_into_u32, regs, // }; =20 @@ -79,8 +81,9 @@ fn write_sysmem_flush_page_gb100(bar: Bar0<'_>, addr: Bou= nded) { } =20 pub(super) const fn pmu_reserved_size_gb100() -> u32 { - usize_into_u32::<{ const_align_up(SZ_8M + SZ_16M + SZ_4K, Alignment::n= ew::()).unwrap() }>( - ) + casts::usize_into_u32::< + { const_align_up(SZ_8M + SZ_16M + SZ_4K, Alignment::new::= ()).unwrap() }, + >() } =20 impl FbHal for Gb100 { diff --git a/drivers/gpu/nova-core/firmware.rs b/drivers/gpu/nova-core/firm= ware.rs index 1e89390209f5..454d08ad8542 100644 --- a/drivers/gpu/nova-core/firmware.rs +++ b/drivers/gpu/nova-core/firmware.rs @@ -10,6 +10,10 @@ use kernel::{ device, firmware, + num::casts::{ + FromSafeCast, + IntoSafeCast, // + }, prelude::*, str::CString, transmute::FromBytes, // @@ -21,10 +25,6 @@ FalconFirmware, // }, gpu, - num::{ - FromSafeCast, - IntoSafeCast, // - }, }; =20 pub(crate) mod booter; diff --git a/drivers/gpu/nova-core/firmware/booter.rs b/drivers/gpu/nova-co= re/firmware/booter.rs index d9313ac361af..46fec211a4c2 100644 --- a/drivers/gpu/nova-core/firmware/booter.rs +++ b/drivers/gpu/nova-core/firmware/booter.rs @@ -10,6 +10,10 @@ use kernel::{ device, dma::Coherent, + num::casts::{ + FromSafeCast, + IntoSafeCast, // + }, prelude::*, transmute::FromBytes, // }; @@ -31,11 +35,7 @@ Signed, Unsigned, // }, - gpu::Chipset, - num::{ - FromSafeCast, - IntoSafeCast, // - }, + gpu::Chipset, // }; =20 /// Local convenience function to return a copy of `S` by reinterpreting t= he bytes starting at diff --git a/drivers/gpu/nova-core/firmware/fwsec.rs b/drivers/gpu/nova-cor= e/firmware/fwsec.rs index 199ae2adb664..fca127d96e55 100644 --- a/drivers/gpu/nova-core/firmware/fwsec.rs +++ b/drivers/gpu/nova-core/firmware/fwsec.rs @@ -19,6 +19,7 @@ self, Device, // }, + num::casts::FromSafeCast, prelude::*, transmute::{ AsBytes, @@ -43,7 +44,6 @@ Signed, Unsigned, // }, - num::FromSafeCast, vbios::Vbios, }; =20 diff --git a/drivers/gpu/nova-core/firmware/fwsec/bootloader.rs b/drivers/g= pu/nova-core/firmware/fwsec/bootloader.rs index 039920dc340b..0fbc7971477b 100644 --- a/drivers/gpu/nova-core/firmware/fwsec/bootloader.rs +++ b/drivers/gpu/nova-core/firmware/fwsec/bootloader.rs @@ -17,6 +17,7 @@ register::WithBase, // Io, }, + num::casts::FromSafeCast, prelude::*, ptr::{ Alignable, @@ -51,7 +52,6 @@ FIRMWARE_VERSION, // }, gpu::Chipset, - num::FromSafeCast, regs, }; =20 diff --git a/drivers/gpu/nova-core/firmware/gsp.rs b/drivers/gpu/nova-core/= firmware/gsp.rs index 99a302bae567..39f50c927b72 100644 --- a/drivers/gpu/nova-core/firmware/gsp.rs +++ b/drivers/gpu/nova-core/firmware/gsp.rs @@ -8,6 +8,10 @@ DataDirection, DmaAddress, // }, + num::casts::{ + arch::FromSafeCastArch, + FromSafeCast, // + }, prelude::*, scatterlist::{ Owned, @@ -25,7 +29,6 @@ Chipset, // }, gsp::GSP_PAGE_SIZE, - num::FromSafeCast, }; =20 /// GSP firmware with 3-level radix page tables for the GSP bootloader. @@ -175,7 +178,7 @@ pub(crate) fn radix3_dma_handle(&self) -> DmaAddress { fn map_into_lvl(sg_table: &SGTable>>, mut dst: VVec) ->= Result> { for sg_entry in sg_table.iter() { // Number of pages we need to map. - let num_pages =3D usize::from_safe_cast(sg_entry.dma_len()).div_ce= il(GSP_PAGE_SIZE); + let num_pages =3D usize::from_safe_cast_arch(sg_entry.dma_len()).d= iv_ceil(GSP_PAGE_SIZE); =20 for i in 0..num_pages { let entry =3D sg_entry.dma_address() diff --git a/drivers/gpu/nova-core/firmware/riscv.rs b/drivers/gpu/nova-cor= e/firmware/riscv.rs index 2afa7f36404e..43015ea5c831 100644 --- a/drivers/gpu/nova-core/firmware/riscv.rs +++ b/drivers/gpu/nova-core/firmware/riscv.rs @@ -7,14 +7,12 @@ device, dma::Coherent, firmware::Firmware, + num::casts::FromSafeCast, prelude::*, transmute::FromBytes, // }; =20 -use crate::{ - firmware::BinFirmware, - num::FromSafeCast, // -}; +use crate::firmware::BinFirmware; =20 /// Descriptor for microcode running on a RISC-V core. #[repr(C)] diff --git a/drivers/gpu/nova-core/fsp.rs b/drivers/gpu/nova-core/fsp.rs index 8fc243c66e35..581ed301d37a 100644 --- a/drivers/gpu/nova-core/fsp.rs +++ b/drivers/gpu/nova-core/fsp.rs @@ -11,6 +11,7 @@ device, dma::Coherent, io::poll::read_poll_timeout, + num::casts, prelude::*, ptr::{ Alignable, @@ -42,7 +43,6 @@ NvdmHeader, NvdmType, // }, - num, regs, // }; =20 @@ -128,7 +128,7 @@ fn new<'a>( }; =20 let version =3D hal::fsp_hal(args.chipset).ok_or(ENOTSUPP)?.cot_ve= rsion(); - let size =3D num::usize_into_u16::<{ core::mem::size_of::() }>(); + let size =3D casts::usize_into_u16::<{ core::mem::size_of::() }>(); =20 Ok(init!(Self { mctp_header: MctpHeader::single_packet(), diff --git a/drivers/gpu/nova-core/gsp.rs b/drivers/gpu/nova-core/gsp.rs index 69175ca3315c..5fafd6716ba3 100644 --- a/drivers/gpu/nova-core/gsp.rs +++ b/drivers/gpu/nova-core/gsp.rs @@ -11,6 +11,7 @@ CoherentBox, DmaAddress, // }, + num::casts, pci, prelude::*, transmute::{ @@ -36,7 +37,6 @@ GspArgumentsPadded, LibosMemoryRegionInitArgument, // }, - num, }; =20 pub(crate) const GSP_PAGE_SHIFT: usize =3D 12; @@ -61,7 +61,7 @@ impl PteArray { // TODO: Replace with `IoView` projection once available. fn entry(start: DmaAddress, index: usize) -> Result { start - .checked_add(num::usize_as_u64(index) << GSP_PAGE_SHIFT) + .checked_add(casts::usize_as_u64(index) << GSP_PAGE_SHIFT) .ok_or(EOVERFLOW) } } diff --git a/drivers/gpu/nova-core/gsp/cmdq.rs b/drivers/gpu/nova-core/gsp/= cmdq.rs index 070de0731e95..39326e3007bd 100644 --- a/drivers/gpu/nova-core/gsp/cmdq.rs +++ b/drivers/gpu/nova-core/gsp/cmdq.rs @@ -16,6 +16,7 @@ Io, // }, new_mutex, + num::casts, prelude::*, ptr, sync::{ @@ -26,7 +27,7 @@ transmute::{ AsBytes, FromBytes, // - }, + }, // }; =20 use continuation::{ @@ -50,7 +51,6 @@ GSP_PAGE_SHIFT, GSP_PAGE_SIZE, // }, - num, regs, sbuffer::SBufferIter, // }; @@ -154,7 +154,7 @@ fn read( #[repr(C, align(0x1000))] #[derive(Debug)] struct MsgqData { - data: [[u8; GSP_PAGE_SIZE]; num::u32_as_usize(MSGQ_NUM_PAGES)], + data: [[u8; GSP_PAGE_SIZE]; casts::u32_as_usize(MSGQ_NUM_PAGES)], } =20 // Annoyingly we are forced to use a literal to specify the alignment of @@ -229,8 +229,8 @@ unsafe impl FromBytes for GspMem {} impl DmaGspMem { /// Allocate a new instance and map it for `dev`. fn new(dev: &device::Device) -> Result { - const MSGQ_SIZE: u32 =3D num::usize_into_u32::<{ size_of::()= }>(); - const RX_HDR_OFF: u32 =3D num::usize_into_u32::<{ mem::offset_of!(= Msgq, rx) }>(); + const MSGQ_SIZE: u32 =3D casts::usize_into_u32::<{ size_of::= () }>(); + const RX_HDR_OFF: u32 =3D casts::usize_into_u32::<{ mem::offset_of= !(Msgq, rx) }>(); =20 let gsp_mem =3D Coherent::::zeroed(dev, GFP_KERNEL)?; =20 @@ -291,10 +291,10 @@ fn new(dev: &device::Device) -> Result= { unsafe { ( core::slice::from_raw_parts_mut( - data.add(num::u32_as_usize(tx)), - num::u32_as_usize(tail_end - tx), + data.add(casts::u32_as_usize(tx)), + casts::u32_as_usize(tail_end - tx), ), - core::slice::from_raw_parts_mut(data, num::u32_as_usize(wr= ap_end)), + core::slice::from_raw_parts_mut(data, casts::u32_as_usize(= wrap_end)), ) } } @@ -309,7 +309,7 @@ fn driver_write_area_size(&self) -> usize { // `cpu_write_ptr`. The minimum value case is where `rx =3D=3D 0` = and `tx =3D=3D MSGQ_NUM_PAGES - // 1`, which gives `0 + MSGQ_NUM_PAGES - (MSGQ_NUM_PAGES - 1) - 1 = =3D=3D 0`. let slots =3D (rx + MSGQ_NUM_PAGES - tx - 1) % MSGQ_NUM_PAGES; - num::u32_as_usize(slots) * GSP_PAGE_SIZE + casts::u32_as_usize(slots) * GSP_PAGE_SIZE } =20 /// Returns the region of the GSP message queue that the driver is cur= rently allowed to read @@ -345,10 +345,10 @@ fn driver_write_area_size(&self) -> usize { unsafe { ( core::slice::from_raw_parts( - data.add(num::u32_as_usize(rx)), - num::u32_as_usize(tail_end - rx), + data.add(casts::u32_as_usize(rx)), + casts::u32_as_usize(tail_end - rx), ), - core::slice::from_raw_parts(data, num::u32_as_usize(wrap_e= nd)), + core::slice::from_raw_parts(data, casts::u32_as_usize(wrap= _end)), ) } } diff --git a/drivers/gpu/nova-core/gsp/fw.rs b/drivers/gpu/nova-core/gsp/fw= .rs index 4db0cfa4dc4d..ad659293aae1 100644 --- a/drivers/gpu/nova-core/gsp/fw.rs +++ b/drivers/gpu/nova-core/gsp/fw.rs @@ -11,6 +11,10 @@ =20 use kernel::{ dma::Coherent, + num::casts::{ + self, + FromSafeCast, // + }, prelude::*, ptr::{ Alignable, @@ -38,10 +42,6 @@ cmdq::Cmdq, // GSP_PAGE_SIZE, }, - num::{ - self, - FromSafeCast, // - }, }; =20 // TODO: Replace with `IoView` projections once available. @@ -99,7 +99,7 @@ pub(in crate::gsp) fn advance_cpu_write_ptr(qs: &Coherent= , count: u32) { =20 /// Maximum size of a single GSP message queue element in bytes. pub(crate) const GSP_MSG_QUEUE_ELEMENT_SIZE_MAX: usize =3D - num::u32_as_usize(bindings::GSP_MSG_QUEUE_ELEMENT_SIZE_MAX); + casts::u32_as_usize(bindings::GSP_MSG_QUEUE_ELEMENT_SIZE_MAX); =20 /// Empty type to group methods related to heap parameters for running the= GSP firmware. enum GspFwHeapParams {} @@ -152,19 +152,19 @@ pub(crate) struct LibosParams { impl LibosParams { /// Version 2 of the GSP LIBOS (Turing and GA100) const LIBOS2: LibosParams =3D LibosParams { - carveout_size: num::u32_as_u64(bindings::GSP_FW_HEAP_PARAM_OS_SIZE= _LIBOS2), - allowed_heap_size: num::u32_as_u64(bindings::GSP_FW_HEAP_SIZE_OVER= RIDE_LIBOS2_MIN_MB) + carveout_size: casts::u32_as_u64(bindings::GSP_FW_HEAP_PARAM_OS_SI= ZE_LIBOS2), + allowed_heap_size: casts::u32_as_u64(bindings::GSP_FW_HEAP_SIZE_OV= ERRIDE_LIBOS2_MIN_MB) * u64::SZ_1M - ..num::u32_as_u64(bindings::GSP_FW_HEAP_SIZE_OVERRIDE_LIBOS2_M= AX_MB) * u64::SZ_1M, + ..casts::u32_as_u64(bindings::GSP_FW_HEAP_SIZE_OVERRIDE_LIBOS2= _MAX_MB) * u64::SZ_1M, }; =20 /// Version 3 of the GSP LIBOS (GA102+) const LIBOS3: LibosParams =3D LibosParams { - carveout_size: num::u32_as_u64(bindings::GSP_FW_HEAP_PARAM_OS_SIZE= _LIBOS3_BAREMETAL), - allowed_heap_size: num::u32_as_u64( + carveout_size: casts::u32_as_u64(bindings::GSP_FW_HEAP_PARAM_OS_SI= ZE_LIBOS3_BAREMETAL), + allowed_heap_size: casts::u32_as_u64( bindings::GSP_FW_HEAP_SIZE_OVERRIDE_LIBOS3_BAREMETAL_MIN_MB, ) * u64::SZ_1M - ..num::u32_as_u64(bindings::GSP_FW_HEAP_SIZE_OVERRIDE_LIBOS3_B= AREMETAL_MAX_MB) + ..casts::u32_as_u64(bindings::GSP_FW_HEAP_SIZE_OVERRIDE_LIBOS3= _BAREMETAL_MAX_MB) * u64::SZ_1M, }; =20 @@ -678,11 +678,11 @@ fn id8(name: &str) -> u64 { let init_inner =3D init!(bindings::LibosMemoryRegionInitArgument { id8: id8(name), pa: obj.dma_handle(), - size: num::usize_as_u64(obj.size()), - kind: num::u32_into_u8::< + size: casts::usize_as_u64(obj.size()), + kind: casts::u32_into_u8::< { bindings::LibosMemoryRegionKind_LIBOS_MEMORY_REGION_CONT= IGUOUS }, >(), - loc: num::u32_into_u8::< + loc: casts::u32_into_u8::< { bindings::LibosMemoryRegionLoc_LIBOS_MEMORY_REGION_LOC_S= YSMEM }, >(), ..Zeroable::init_zeroed() @@ -712,12 +712,12 @@ pub(crate) fn new(msgq_size: u32, rx_hdr_offset: u32,= msg_count: u32) -> Self { Self(bindings::msgqTxHeader { version: 0, size: msgq_size, - msgSize: num::usize_into_u32::(), + msgSize: casts::usize_into_u32::(), msgCount: msg_count, writePtr: 0, flags: 1, rxHdrOff: rx_hdr_offset, - entryOff: num::usize_into_u32::(), + entryOff: casts::usize_into_u32::(), }) } } @@ -829,7 +829,7 @@ pub(crate) fn set_checksum(&mut self, checksum: u32) { /// Returns the length of the message's payload. pub(crate) fn payload_length(&self) -> usize { // `rpc.length` includes the length of the RPC message header. - num::u32_as_usize(self.inner.rpc.length) + casts::u32_as_usize(self.inner.rpc.length) .saturating_sub(size_of::()) } =20 @@ -927,9 +927,9 @@ impl MessageQueueInitArguments { fn new(cmdq: &Cmdq) -> impl Init + '_ { init!(MessageQueueInitArguments { sharedMemPhysAddr: cmdq.dma_handle, - pageTableEntryCount: num::usize_into_u32::<{ Cmdq::NUM_PTES }>= (), - cmdQueueOffset: num::usize_as_u64(Cmdq::CMDQ_OFFSET), - statQueueOffset: num::usize_as_u64(Cmdq::STATQ_OFFSET), + pageTableEntryCount: casts::usize_into_u32::<{ Cmdq::NUM_PTES = }>(), + cmdQueueOffset: casts::usize_as_u64(Cmdq::CMDQ_OFFSET), + statQueueOffset: casts::usize_as_u64(Cmdq::STATQ_OFFSET), ..Zeroable::init_zeroed() }) } @@ -950,7 +950,7 @@ fn new(target: GspDmaTarget, wpr_meta_addr: u64) -> imp= l Init { #[allow(non_snake_case)] let params =3D init!(Self { target: target as u32, - gspRmDescSize: num::usize_into_u32::<{ size_of::= () }>(), + gspRmDescSize: casts::usize_into_u32::<{ size_of::() }>(), gspRmDescOffset: wpr_meta_addr, bIsGspRmBoot: 1, wprCarveoutOffset: 0, diff --git a/drivers/gpu/nova-core/gsp/sequencer.rs b/drivers/gpu/nova-core= /gsp/sequencer.rs index e0850d21adca..3944b396f67c 100644 --- a/drivers/gpu/nova-core/gsp/sequencer.rs +++ b/drivers/gpu/nova-core/gsp/sequencer.rs @@ -10,6 +10,7 @@ poll::read_poll_timeout, Io, // }, + num::casts::FromSafeCast, prelude::*, time::{ delay::fsleep, @@ -32,7 +33,6 @@ }, fw, }, - num::FromSafeCast, sbuffer::SBufferIter, }; =20 diff --git a/drivers/gpu/nova-core/num.rs b/drivers/gpu/nova-core/num.rs index 6eb174d136ab..3921ef6f238e 100644 --- a/drivers/gpu/nova-core/num.rs +++ b/drivers/gpu/nova-core/num.rs @@ -5,217 +5,6 @@ //! This is essentially a staging module for code to mature until it can b= e moved to the `kernel` //! crate. =20 -use kernel::{ - macros::paste, - prelude::*, // -}; - -/// Implements safe `as` conversion functions from a given type into a ser= ies of target types. -/// -/// These functions can be used in place of `as`, with the guarantee that = they will be lossless. -macro_rules! impl_safe_as { - ($from:ty as { $($into:ty),* }) =3D> { - $( - paste! { - #[doc =3D ::core::concat!( - "Losslessly converts a [`", - ::core::stringify!($from), - "`] into a [`", - ::core::stringify!($into), - "`].")] - /// - /// This conversion is allowed as it is always lossless. Prefe= r this over the `as` - /// keyword to ensure no lossy casts are performed. - /// - /// This is for use from a `const` context. For non `const` us= e, prefer the - /// [`FromSafeCast`] and [`IntoSafeCast`] traits. - /// - /// # Examples - /// - /// ``` - /// use crate::num; - /// - #[doc =3D ::core::concat!( - "assert_eq!(num::", - ::core::stringify!($from), - "_as_", - ::core::stringify!($into), - "(1", - ::core::stringify!($from), - "), 1", - ::core::stringify!($into), - ");")] - /// ``` - #[allow(unused)] - #[inline(always)] - pub(crate) const fn [<$from _as_ $into>](value: $from) -> $int= o { - ::kernel::build_assert::static_assert!(size_of::<$into>() = >=3D size_of::<$from>()); - - value as $into - } - } - )* - }; -} - -impl_safe_as!(u8 as { u16, u32, u64, usize }); -impl_safe_as!(u16 as { u32, u64, usize }); -impl_safe_as!(u32 as { u64, usize } ); -// `u64` and `usize` have the same size on 64-bit platforms. -#[cfg(CONFIG_64BIT)] -impl_safe_as!(u64 as { usize } ); - -// A `usize` fits into a `u64` on 32 and 64-bit platforms. -#[cfg(any(CONFIG_32BIT, CONFIG_64BIT))] -impl_safe_as!(usize as { u64 }); - -// A `usize` fits into a `u32` on 32-bit platforms. -#[cfg(CONFIG_32BIT)] -impl_safe_as!(usize as { u32 }); - -/// Extension trait providing guaranteed lossless cast to `Self` from `T`. -/// -/// The standard library's `From` implementations do not cover conversions= that are not portable or -/// future-proof. For instance, even though it is safe today, `From= ` is not implemented for -/// [`u64`] because of the possibility to support larger-than-64bit archit= ectures in the future. -/// -/// The workaround is to either deal with the error handling of [`TryFrom`= ] for an operation that -/// technically cannot fail, or to use the `as` keyword, which can silentl= y strip data if the -/// destination type is smaller than the source. -/// -/// Both options are hardly acceptable for the kernel. It is also a much m= ore architecture -/// dependent environment, supporting only 32 and 64 bit architectures, wi= th some modules -/// explicitly depending on a specific bus width that could greatly benefi= t from infallible -/// conversion operations. -/// -/// Thus this extension trait that provides, for the architecture the kern= el is built for, safe -/// conversion between types for which such cast is lossless. -/// -/// In other words, this trait is implemented if, for the current build ta= rget and with `t: T`, the -/// `t as Self` operation is completely lossless. -/// -/// Prefer this over the `as` keyword to ensure no lossy casts are perform= ed. -/// -/// If you need to perform a conversion in `const` context, use [`u64_as_u= size`], [`u32_as_usize`], -/// [`usize_as_u64`], etc. -/// -/// # Examples -/// -/// ``` -/// use crate::num::FromSafeCast; -/// -/// assert_eq!(usize::from_safe_cast(0xf00u32), 0xf00u32 as usize); -/// ``` -pub(crate) trait FromSafeCast { - /// Create a `Self` from `value`. This operation is guaranteed to be l= ossless. - fn from_safe_cast(value: T) -> Self; -} - -impl FromSafeCast for u64 { - fn from_safe_cast(value: usize) -> Self { - usize_as_u64(value) - } -} - -#[cfg(CONFIG_32BIT)] -impl FromSafeCast for u32 { - fn from_safe_cast(value: usize) -> Self { - usize_as_u32(value) - } -} - -impl FromSafeCast for usize { - fn from_safe_cast(value: u32) -> Self { - u32_as_usize(value) - } -} - -#[cfg(CONFIG_64BIT)] -impl FromSafeCast for usize { - fn from_safe_cast(value: u64) -> Self { - u64_as_usize(value) - } -} - -/// Counterpart to the [`FromSafeCast`] trait, i.e. this trait is to [`Fro= mSafeCast`] what [`Into`] -/// is to [`From`]. -/// -/// See the documentation of [`FromSafeCast`] for the motivation. -/// -/// # Examples -/// -/// ``` -/// use crate::num::IntoSafeCast; -/// -/// assert_eq!(0xf00u32.into_safe_cast(), 0xf00u32 as usize); -/// ``` -pub(crate) trait IntoSafeCast { - /// Convert `self` into a `T`. This operation is guaranteed to be loss= less. - fn into_safe_cast(self) -> T; -} - -/// Reverse operation for types implementing [`FromSafeCast`]. -impl IntoSafeCast for S -where - T: FromSafeCast, -{ - fn into_safe_cast(self) -> T { - T::from_safe_cast(self) - } -} - -/// Implements lossless conversion of a constant from a larger type into a= smaller one. -macro_rules! impl_const_into { - ($from:ty =3D> { $($into:ty),* }) =3D> { - $( - paste! { - #[doc =3D ::core::concat!( - "Performs a build-time safe conversion of a [`", - ::core::stringify!($from), - "`] constant value into a [`", - ::core::stringify!($into), - "`].")] - /// - /// This checks at compile-time that the conversion is lossles= s, and triggers a build - /// error if it isn't. - /// - /// # Examples - /// - /// ``` - /// use crate::num; - /// - /// // Succeeds because the value of the source fits into the = destination's type. - #[doc =3D ::core::concat!( - "assert_eq!(num::", - ::core::stringify!($from), - "_into_", - ::core::stringify!($into), - "::<1", - ::core::stringify!($from), - ">(), 1", - ::core::stringify!($into), - ");")] - /// ``` - #[allow(unused)] - pub(crate) const fn [<$from _into_ $into>]() -= > $into { - // Make sure that the target type is smaller than the sour= ce one. - static_assert!($from::BITS >=3D $into::BITS); - // CAST: we statically enforced above that `$from` is larg= er than `$into`, so the - // `as` conversion will be lossless. - build_assert!(N >=3D $into::MIN as $from && N <=3D $into::= MAX as $from); - - N as $into - } - } - )* - }; -} - -impl_const_into!(usize =3D> { u8, u16, u32 }); -impl_const_into!(u64 =3D> { u8, u16, u32 }); -impl_const_into!(u32 =3D> { u8, u16 }); -impl_const_into!(u16 =3D> { u8 }); - /// Creates an enum type associated to a [`Bounded`](kernel::num::Bounded)= , with a [`From`] /// conversion to the associated `Bounded` and either a [`TryFrom`] or `Fr= om` conversion from the /// associated `Bounded`. diff --git a/drivers/gpu/nova-core/vbios.rs b/drivers/gpu/nova-core/vbios.rs index c6e6bfcd6a1f..e67a82fcc8c0 100644 --- a/drivers/gpu/nova-core/vbios.rs +++ b/drivers/gpu/nova-core/vbios.rs @@ -5,6 +5,7 @@ use kernel::{ device, io::Io, + num::casts::FromSafeCast, prelude::*, ptr::{ Alignable, @@ -26,7 +27,6 @@ FalconUCodeDescV2, FalconUCodeDescV3, // }, - num::FromSafeCast, }; =20 /// BIOS Image Type from PCI Data Structure code_type field. --=20 2.55.0