From nobody Tue Dec 16 21:28:44 2025 Received: from NAM10-BN7-obe.outbound.protection.outlook.com (mail-bn7nam10on2048.outbound.protection.outlook.com [40.107.92.48]) (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 491F91C68F for ; Tue, 9 Sep 2025 21:21:04 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=40.107.92.48 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1757452866; cv=fail; b=Dvk97p2Z1gY7BcUF3QAKar+gQ+YirlpKHejAKxn7pqE+5hMPySO4J0PlO3ntt8U4UDg/OlroRapaMVvrWC8rGJePQxd3rRPscsdK1RPOMxlsFz61lRTHu/pflE9Atf7wG3BIV/DkJVw8EfHjSND7HHBCL8HdVzhea0NiqiQJabw= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1757452866; c=relaxed/simple; bh=dVUk4QCTbkw3Snja51paJWN5i+gW7//OjbJW0G7TX3Q=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: Content-Type:MIME-Version; b=l+2IT7o1UtYQayqUEwFFyOZyJXMUA9F070uFp52naX0kPVoNpLoAsmfTzgHS+w4BMuHqwCpfKHm/iaKaK98yR44pZsklrchOZU8WZGHbH0rZ6hKaQQHlJHOuDq5xXE0//09ZSoZAlPl/2aY0poVGAH3HMXY0F+dVvPMCasHRVsM= 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=V+Glw4xP; arc=fail smtp.client-ip=40.107.92.48 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="V+Glw4xP" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=rK7C2axKKJ43gbR4gesGU8di3YlmU+uBNPOcUvtaRX8oyYls1s59JXWBQjmE3lq0Ky37/S//SpZfpQONIxJMv72AosTH1yRi1FODapVL5rVfM1ILu9Ti6GT94qp9N/1D4b6LbvrayZ4XqB+NuEbN0GLaCuQn7vkkseIl/Ss9g6OmZAEjRMwDQ4ZkZnJkz6cgmrtZdOZbNNsYVc+rYTy0V/EkfY7bUJPXj9slpYYBdtFkQx4+O1v09ksx+iVg8XAXCUSZYJQnlDUAAUCQs0Q58fxH/Fu9Z/MkOXbPN7Ya1bhsjvbrlSIpf5cCEujihVIbvK8TlFZ5GspAZqjOQ/SeQw== 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=ejeKvgKxM5rW202LkEZMVywTo6wVO1dyxBQgYkGtaHQ=; b=G0ydYUQrNg/RY50KVrpz2i4lzjuHN38g36oupJUbqCOPirP2kuvLdXSggy+UFQpJZS+LhXrDMef1vXYimApKwPL8sS6sVxCwMVNOsD/4yqnDcDnL6418a8vzmuhK5ZVBOmsFFvQZFykgKI+XtkfExzGO7WB+erb0qL45cG7zMxVHNuuFIJ04CB+rihplB20YatGRSpyghP/28prqSfxw3NyXxhh/lryzCkmdGJb0/Pwv2gGYR+iEFK+pwYiI96zaV0KkBxUPw8FJeEeuiDvFWtTMjlsmMGeNREcmqqRFzgN5UDZdeQ+LRlO0RcDFJ9C52r/zhQBHtYBJw3fDg3x1Bw== 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=ejeKvgKxM5rW202LkEZMVywTo6wVO1dyxBQgYkGtaHQ=; b=V+Glw4xPZ7PbwU97bkBYxCY8BudyEq0zJu82SQPOXnP89frN+PPDmtLGAkiqH1h553TIRdI7ZL3pyRUY81jhv+5pPcNHMjCHcCr4tjuqbm5lnPb9Tizah5XhE9NSbP4QHE5MREarzkF88lQ9uabBvKU3Ce6AnSCM0EP9hV5bjpnVzQNR+cxt1fht4jQJ2GXPwc4FfqCAIYRvEU6CR35kcvY/WGR+1qbmI4MdQfrBUlcMyIb2XYGZIo3HEk2uOLjdvCVxOcdbCrXeV+KvyMWHJ66U8jwhrAhWv6YIJ/Twj7gwosuxpl2vibuFlazTnhmZVVZYR5tjlYM4a/rrMu6O9Q== Authentication-Results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=nvidia.com; Received: from DS0PR12MB8044.namprd12.prod.outlook.com (2603:10b6:8:148::14) by MN0PR12MB6031.namprd12.prod.outlook.com (2603:10b6:208:3cd::7) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.9094.22; Tue, 9 Sep 2025 21:20:51 +0000 Received: from DS0PR12MB8044.namprd12.prod.outlook.com ([fe80::49af:9ef0:2373:1515]) by DS0PR12MB8044.namprd12.prod.outlook.com ([fe80::49af:9ef0:2373:1515%6]) with mapi id 15.20.9094.021; Tue, 9 Sep 2025 21:20:51 +0000 From: Joel Fernandes To: linux-kernel@vger.kernel.org, dri-devel@lists.freedesktop.org, dakr@kernel.org, acourbot@nvidia.com Cc: Alistair Popple , Miguel Ojeda , Alex Gaynor , Boqun Feng , Gary Guo , bjorn3_gh@protonmail.com, Benno Lossin , Andreas Hindborg , Alice Ryhl , Trevor Gross , David Airlie , Simona Vetter , Maarten Lankhorst , Maxime Ripard , Thomas Zimmermann , John Hubbard , Joel Fernandes , Timur Tabi , joel@joelfernandes.org, Elle Rhumsaa , Yury Norov , Daniel Almeida , nouveau@lists.freedesktop.org Subject: [PATCH v3 1/5] nova-core: bitfield: Move bitfield-specific code from register! into new macro Date: Tue, 9 Sep 2025 17:20:35 -0400 Message-Id: <20250909212039.227221-2-joelagnelf@nvidia.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20250909212039.227221-1-joelagnelf@nvidia.com> References: <20250909212039.227221-1-joelagnelf@nvidia.com> Content-Transfer-Encoding: quoted-printable X-ClientProxiedBy: BN1PR10CA0024.namprd10.prod.outlook.com (2603:10b6:408:e0::29) To DS0PR12MB8044.namprd12.prod.outlook.com (2603:10b6:8:148::14) 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: DS0PR12MB8044:EE_|MN0PR12MB6031:EE_ X-MS-Office365-Filtering-Correlation-Id: 3c1a8fb1-3d5c-48ec-61d2-08ddefe6c0be X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|1800799024|366016|376014|7416014; X-Microsoft-Antispam-Message-Info: =?us-ascii?Q?JWeH/bbxxW4B+fR0yG4yTn0lp5I3HZaXKTTa6yJ9nuje8D1Kd7SQPohvwNnJ?= =?us-ascii?Q?vIWcXiONr7j+aFsatYGgnNdJvGF/aM/irLW6breSTXODf9/L9ES690keMUt4?= =?us-ascii?Q?8KBRbapiaBl85T7jwR76WnrRmCLeTAZmfo5xx9xDJ938kLRXHgMTS9TEWj/g?= =?us-ascii?Q?RbVslj5+KpY68UInyAkk6x5MXNjm/3EsrqsU0J76F5DZV1d9uK3aSGye+r9w?= =?us-ascii?Q?mPqU9aipj8kEpKMqi+gDKdRu82bKms8680oduOxw3fBpcEm2nU5olSU4xQYh?= =?us-ascii?Q?KPfd25fREnPUi8KF/L36+CeEv6u5mUTiPnKA7MAQZGt7IQuGC4tD7yqnVFLo?= =?us-ascii?Q?n3jdfNu6MsNxev8E9jVzBFnYJ44zeIttud9vzAbPriOvBxSo0a2sN+ad6oJ7?= =?us-ascii?Q?dirig+L93hWqK05Pj+JFLoUtoI4dEgRHPfK+XnEMxj+mFh2o+VM+bsaf5f7D?= =?us-ascii?Q?JBBcc0rvpJ5aFmZiX0+dAYsEFnPZC8RsB/ICAV7AJFcFpiZ9e7HyVLQ1ubvl?= =?us-ascii?Q?0Pbm0Gy6EoHZoBAin0xvfEXNCf1U0+i87yc8Pu0nAbZBSMXseCwdss7KDCEC?= =?us-ascii?Q?sqwHiuWGrxI8KcTKyWKPjeYxOpLM35I1KyjL2OdViYNQeWYWSDRgMbiyEiyY?= =?us-ascii?Q?1wcwzrAMusUWSE2STgHrfxjcZld0bjoVhk79gPDiXxfm3L55rH4PyKNVg7SP?= =?us-ascii?Q?KoqE8wwCSPaDSDe+ORmZW5uC2XjTLiHwS/HxbSoJgUpCmQcjCWDAO9JEviuZ?= =?us-ascii?Q?rGplPWJFlrCQm6qIULI4tK7qXlbFPZxhawPsW0evO3DefvuMmYPdukRz5QD4?= =?us-ascii?Q?vvV+kb9JnZfPE/uItXNQKqbya9pOAeG694BBMqAUmcQrvt39tiapCJMsXXgB?= =?us-ascii?Q?nE007CUO7Pq7CF3C/L2iCwn1q8fMhirAf3UrYuKb6l2+c7RebsRPq8MI9OTC?= =?us-ascii?Q?AofYsQw5CEGlyc02Xl2DkFM+8GjSygbtq5YJpdCH/JppI5OgIr2h6xoBuf0j?= =?us-ascii?Q?ToIZUNJK1X/HPMQIqrPf65cccmqPyIcPNblpNqTwD1DifOxmdadqBu05Pb8o?= =?us-ascii?Q?RwP9uwefWHMUzpJTj0TO/3VZhNmcZMbYw0sw3tIXs7YSCqLxQVsxoNzJ6NBs?= =?us-ascii?Q?pEZBtgJcuKYFM7WQe2fqZdHaer9Jb8TngiKVZ9evCsQKPcmkN5jtOB5PyxBQ?= =?us-ascii?Q?TGD/zan0ksDYDJUbAz/b4tmGc88vjI8njwfXE7rh2EiFJnCL3aHmLOjLBktL?= =?us-ascii?Q?uMID2C69Qwj1bZbSDvhMe0B3POjdqtp4/Fi3ft14tfhdaJ7Kv3pE6X3cWM5t?= =?us-ascii?Q?EN7+KsDYZ9/ADIrlHqZFjp/d2aNE56djsMkCzljqYBA9gb1mYQ+LaLg5Vxwc?= =?us-ascii?Q?zyUn2kG13B8ILG/4yV2QKgvjs+tuZI2mXoXasl8EP8TQRW5afbmX4cXjAw/c?= =?us-ascii?Q?cee8PCTGU90=3D?= X-Forefront-Antispam-Report: CIP:255.255.255.255;CTRY:;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:DS0PR12MB8044.namprd12.prod.outlook.com;PTR:;CAT:NONE;SFS:(13230040)(1800799024)(366016)(376014)(7416014);DIR:OUT;SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: =?us-ascii?Q?86oKCxGxwMjCAZ08TIKj4hA4tF0GMp+xwvKxR/k2lqKgyWqLTtbDWjJMYlQm?= =?us-ascii?Q?ZiRNd1mLW4RrXLQzZDr93rMQq/fcYH7opf2tjhWArnAznf1o4BndnnlFFLNR?= =?us-ascii?Q?UFDrDM8iVlv//a6dmMG75Xt6NP0hpYwf8Y2Dx/W8DIoEoHnoyy+1gbhDzEwz?= =?us-ascii?Q?FDutxZQ3VVNVIx+9FqNf2ALqWUKqRebzlkOAkcS/Q55FYo6DxIOmv4GGtReK?= =?us-ascii?Q?V9NhZl10wkjnQdqa0ICt1ekedvnZLbCChnCrvIQdDCcxV1uscogWvzCE3/Fz?= =?us-ascii?Q?p2vCZgQd8DP7JU4xdLaa1Jhtc01DqqzWBj52Yzh3j7NL6srEV+Rw0X+3Bza0?= =?us-ascii?Q?ENnwZIy779OD3SD5A23l8VOo22YGDE2vJc6RXvRzDLfl118tr5qgt6eAlrDV?= =?us-ascii?Q?LrDwxbZRYRKbAc/HIAurqTN/QoX0mj3XNDGb3QI21jnfWGCPixtjjz8SeDQ2?= =?us-ascii?Q?p69y6J5zKj2SxGe7cB9VlnkhctpUcqTSYoTo408ghaH9GHEXfHwdezMV5IF3?= =?us-ascii?Q?b/DJDfgeJ+WpqBZvxPtXXZZOF8sTo60j9Faj5EgHIa0o6S45besOFaP/ZSLd?= =?us-ascii?Q?DfVLkW9cyLTrqJ7414NUGcjMrHC+i95STaTNovD7rqfXd2DukEIlCLdlbCu0?= =?us-ascii?Q?poEWfDSJdb+oLvJcSPYlLM7neDQve3lhHUccK10AWWAOTiGQyMt5vFGYOL/O?= =?us-ascii?Q?D9tcTZ3mP4dm+J++OZy1yIdLWzGBZBckd7+wRL7PWmiqBdVEQFI8HCDqQmMR?= =?us-ascii?Q?qU8mY5esbJ1hQKWW1pq0jtOP5uLDSJQPIDyEWNounQRY/+rHPpxBSW/71iE3?= =?us-ascii?Q?U0m/7gz3lC1qGxlLYNjCNsW9mj13FxTt30gihGV5/bHL9OaaLIMDmO9WRkGd?= =?us-ascii?Q?xCkmWJAfhbmho4I2/NFof+E+7SuQOqSWIgvaUCa1/Z+MAxV9z8I9505PIxTo?= =?us-ascii?Q?qGY9RfL7byqBHjXaSqihtYeMtdWcQfIcN0vC1F+zpm2NDcbuswDY8HSISa8j?= =?us-ascii?Q?Bl2n6WKvymwiWJWVH1B5b4hLFl2UQJN63qtPmv09biykSvHQShA6yUgFIjh8?= =?us-ascii?Q?Hb3nEkb6VNRPdB/1VXj+fg5GH3DOr2Jr3Lz2nrzsqL8CTuU/tn8Hsv6Az67q?= =?us-ascii?Q?BgbYTFvsfuHg7Q6qa8agrtM6SD6tnep4j2wgswsLB17hXKw7FOPf0No6l7qo?= =?us-ascii?Q?nt9mlTCW4i4yoNxYIRMJBn5dyYBcYO/bhDUJuKPMYW9fvje6Q8yh/E9ARKHc?= =?us-ascii?Q?28wF6Gt54nThzXvIxetDdiAP82rDEkNew1834XbmoVqNWtB7RxczYnp+5+SA?= =?us-ascii?Q?qyTAfJBkIwJ3yHOlGqqPNY19UcL397mv8t15pN/fCxvPoLUP3efZLrDF/4wi?= =?us-ascii?Q?fZrAWwF9ng4MsNNPnNtGW48OVmx0yNPkTPqaAME7xpQY+oPtI7aYzONlOaQE?= =?us-ascii?Q?S7yioEF0NwrlMEuSReZ3uewxRM2ieOM4wycGHtCm9obhCWZaDTbkExPl96jq?= =?us-ascii?Q?vhy47SIRc4N9uwmOmDAXYLIPGpPgfE9xbg2OmIq/F8u5RoHdCPlYYPU1ks8/?= =?us-ascii?Q?iiLigwG1n7P9YaJfdy74M9JzfbpK1xbdpLbuHk8S?= X-OriginatorOrg: Nvidia.com X-MS-Exchange-CrossTenant-Network-Message-Id: 3c1a8fb1-3d5c-48ec-61d2-08ddefe6c0be X-MS-Exchange-CrossTenant-AuthSource: DS0PR12MB8044.namprd12.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 09 Sep 2025 21:20:51.3265 (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: OzHQNnOVfbn/pfALr+8JLPIwoIqXXBupF+XDc0+zzHwY1A7SukiiJeZLCtyegfujvjCHDEnQmgrkjeVTBbrUXA== X-MS-Exchange-Transport-CrossTenantHeadersStamped: MN0PR12MB6031 Content-Type: text/plain; charset="utf-8" The bitfield-specific into new macro. This will be used to define structs with bitfields, similar to C language. Reviewed-by: Elle Rhumsaa Signed-off-by: Joel Fernandes --- drivers/gpu/nova-core/bitfield.rs | 314 +++++++++++++++++++++++++++ drivers/gpu/nova-core/nova_core.rs | 3 + drivers/gpu/nova-core/regs/macros.rs | 259 +--------------------- 3 files changed, 327 insertions(+), 249 deletions(-) create mode 100644 drivers/gpu/nova-core/bitfield.rs diff --git a/drivers/gpu/nova-core/bitfield.rs b/drivers/gpu/nova-core/bitf= ield.rs new file mode 100644 index 000000000000..ba6b7caa05d9 --- /dev/null +++ b/drivers/gpu/nova-core/bitfield.rs @@ -0,0 +1,314 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! Bitfield library for Rust structures +//! +//! Support for defining bitfields in Rust structures. Also used by the [`= register!`] macro. +//! +//! # Syntax +//! +//! ```rust +//! #[derive(Debug, Clone, Copy)] +//! enum Mode { +//! Low =3D 0, +//! High =3D 1, +//! Auto =3D 2, +//! } +//! +//! impl TryFrom for Mode { +//! type Error =3D u8; +//! fn try_from(value: u8) -> Result { +//! match value { +//! 0 =3D> Ok(Mode::Low), +//! 1 =3D> Ok(Mode::High), +//! 2 =3D> Ok(Mode::Auto), +//! _ =3D> Err(value), +//! } +//! } +//! } +//! +//! impl From for u32 { +//! fn from(mode: Mode) -> u32 { +//! mode as u32 +//! } +//! } +//! +//! #[derive(Debug, Clone, Copy)] +//! enum State { +//! Inactive =3D 0, +//! Active =3D 1, +//! } +//! +//! impl From for State { +//! fn from(value: bool) -> Self { +//! if value { State::Active } else { State::Inactive } +//! } +//! } +//! +//! impl From for u32 { +//! fn from(state: State) -> u32 { +//! state as u32 +//! } +//! } +//! +//! bitfield! { +//! struct ControlReg { +//! 3:0 mode as u8 ?=3D> Mode; +//! 7 state as bool =3D> State; +//! } +//! } +//! ``` +//! +//! This generates a struct with: +//! - Field accessors: `mode()`, `state()`, etc. +//! - Field setters: `set_mode()`, `set_state()`, etc. (supports chaining = with builder pattern). +//! - Debug and Default implementations +//! +//! The field setters can be used with the builder pattern, example: +//! ControlReg::default().set_mode(mode).set_state(state); +//! +//! Fields are defined as follows: +//! +//! - `as ` simply returns the field value casted to , typical= ly `u32`, `u16`, `u8` or +//! `bool`. Note that `bool` fields must have a range of 1 bit. +//! - `as =3D> ` calls ``'s `From::<>` = implementation and returns +//! the result. +//! - `as ?=3D> ` calls ``'s `TryFrom= ::<>` implementation +//! and returns the result. This is useful with fields for which not all= values are valid. +//! +macro_rules! bitfield { + // Main entry point - defines the bitfield struct with fields + (struct $name:ident $(, $comment:literal)? { $($fields:tt)* }) =3D> { + bitfield!(@core $name $(, $comment)? { $($fields)* }); + }; + + // All rules below are helpers. + + // Defines the wrapper `$name` type, as well as its relevant implement= ations (`Debug`, + // `Default`, `BitOr`, and conversion to the value type) and field acc= essor methods. + (@core $name:ident $(, $comment:literal)? { $($fields:tt)* }) =3D> { + $( + #[doc=3D$comment] + )? + #[repr(transparent)] + #[derive(Clone, Copy)] + pub(crate) struct $name(u32); + + impl ::core::ops::BitOr for $name { + type Output =3D Self; + + fn bitor(self, rhs: Self) -> Self::Output { + Self(self.0 | rhs.0) + } + } + + impl ::core::convert::From<$name> for u32 { + fn from(val: $name) -> u32 { + val.0 + } + } + + bitfield!(@fields_dispatcher $name { $($fields)* }); + }; + + // Captures the fields and passes them to all the implementers that re= quire field information. + // + // Used to simplify the matching rules for implementers, so they don't= need to match the entire + // complex fields rule even though they only make use of part of it. + (@fields_dispatcher $name:ident { + $($hi:tt:$lo:tt $field:ident as $type:tt + $(?=3D> $try_into_type:ty)? + $(=3D> $into_type:ty)? + $(, $comment:literal)? + ; + )* + } + ) =3D> { + bitfield!(@field_accessors $name { + $( + $hi:$lo $field as $type + $(?=3D> $try_into_type)? + $(=3D> $into_type)? + $(, $comment)? + ; + )* + }); + bitfield!(@debug $name { $($field;)* }); + bitfield!(@default $name { $($field;)* }); + }; + + // Defines all the field getter/setter methods for `$name`. + ( + @field_accessors $name:ident { + $($hi:tt:$lo:tt $field:ident as $type:tt + $(?=3D> $try_into_type:ty)? + $(=3D> $into_type:ty)? + $(, $comment:literal)? + ; + )* + } + ) =3D> { + $( + bitfield!(@check_field_bounds $hi:$lo $field as $type); + )* + + #[allow(dead_code)] + impl $name { + $( + bitfield!(@field_accessor $name $hi:$lo $field as $type + $(?=3D> $try_into_type)? + $(=3D> $into_type)? + $(, $comment)? + ; + ); + )* + } + }; + + // Boolean fields must have `$hi =3D=3D $lo`. + (@check_field_bounds $hi:tt:$lo:tt $field:ident as bool) =3D> { + #[allow(clippy::eq_op)] + const _: () =3D { + ::kernel::build_assert!( + $hi =3D=3D $lo, + concat!("boolean field `", stringify!($field), "` covers m= ore than one bit") + ); + }; + }; + + // Non-boolean fields must have `$hi >=3D $lo`. + (@check_field_bounds $hi:tt:$lo:tt $field:ident as $type:tt) =3D> { + #[allow(clippy::eq_op)] + const _: () =3D { + ::kernel::build_assert!( + $hi >=3D $lo, + concat!("field `", stringify!($field), "`'s MSB is smaller= than its LSB") + ); + }; + }; + + // Catches fields defined as `bool` and convert them into a boolean va= lue. + ( + @field_accessor $name:ident $hi:tt:$lo:tt $field:ident as bool =3D= > $into_type:ty + $(, $comment:literal)?; + ) =3D> { + bitfield!( + @leaf_accessor $name $hi:$lo $field + { |f| <$into_type>::from(if f !=3D 0 { true } else { false }) } + $into_type =3D> $into_type $(, $comment)?; + ); + }; + + // Shortcut for fields defined as `bool` without the `=3D>` syntax. + ( + @field_accessor $name:ident $hi:tt:$lo:tt $field:ident as bool $(,= $comment:literal)?; + ) =3D> { + bitfield!(@field_accessor $name $hi:$lo $field as bool =3D> bool $= (, $comment)?;); + }; + + // Catches the `?=3D>` syntax for non-boolean fields. + ( + @field_accessor $name:ident $hi:tt:$lo:tt $field:ident as $type:tt= ?=3D> $try_into_type:ty + $(, $comment:literal)?; + ) =3D> { + bitfield!(@leaf_accessor $name $hi:$lo $field + { |f| <$try_into_type>::try_from(f as $type) } $try_into_type = =3D> + ::core::result::Result< + $try_into_type, + <$try_into_type as ::core::convert::TryFrom<$type>>::Error + > + $(, $comment)?;); + }; + + // Catches the `=3D>` syntax for non-boolean fields. + ( + @field_accessor $name:ident $hi:tt:$lo:tt $field:ident as $type:tt= =3D> $into_type:ty + $(, $comment:literal)?; + ) =3D> { + bitfield!(@leaf_accessor $name $hi:$lo $field + { |f| <$into_type>::from(f as $type) } $into_type =3D> $into_t= ype $(, $comment)?;); + }; + + // Shortcut for non-boolean fields defined without the `=3D>` or `?=3D= >` syntax. + ( + @field_accessor $name:ident $hi:tt:$lo:tt $field:ident as $type:tt + $(, $comment:literal)?; + ) =3D> { + bitfield!(@field_accessor $name $hi:$lo $field as $type =3D> $type= $(, $comment)?;); + }; + + // Generates the accessor methods for a single field. + ( + @leaf_accessor $name:ident $hi:tt:$lo:tt $field:ident + { $process:expr } $to_type:ty =3D> $res_type:ty $(, $comment:l= iteral)?; + ) =3D> { + ::kernel::macros::paste!( + const [<$field:upper _RANGE>]: ::core::ops::RangeInclusive =3D= $lo..=3D$hi; + const [<$field:upper _MASK>]: u32 =3D ((((1 << $hi) - 1) << 1) + 1= ) - ((1 << $lo) - 1); + const [<$field:upper _SHIFT>]: u32 =3D Self::[<$field:upper _MASK>= ].trailing_zeros(); + ); + + $( + #[doc=3D"Returns the value of this field:"] + #[doc=3D$comment] + )? + #[inline(always)] + pub(crate) fn $field(self) -> $res_type { + ::kernel::macros::paste!( + const MASK: u32 =3D $name::[<$field:upper _MASK>]; + const SHIFT: u32 =3D $name::[<$field:upper _SHIFT>]; + ); + let field =3D ((self.0 & MASK) >> SHIFT); + + $process(field) + } + + ::kernel::macros::paste!( + $( + #[doc=3D"Sets the value of this field:"] + #[doc=3D$comment] + )? + #[inline(always)] + pub(crate) fn [](mut self, value: $to_type) -> Self { + const MASK: u32 =3D $name::[<$field:upper _MASK>]; + const SHIFT: u32 =3D $name::[<$field:upper _SHIFT>]; + let value =3D (u32::from(value) << SHIFT) & MASK; + self.0 =3D (self.0 & !MASK) | value; + + self + } + ); + }; + + // Generates the `Debug` implementation for `$name`. + (@debug $name:ident { $($field:ident;)* }) =3D> { + impl ::core::fmt::Debug for $name { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::f= mt::Result { + f.debug_struct(stringify!($name)) + .field("", &format_args!("{:#x}", &self.0)) + $( + .field(stringify!($field), &self.$field()) + )* + .finish() + } + } + }; + + // Generates the `Default` implementation for `$name`. + (@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.[](Default::default()); + )* + ); + + value + } + } + }; +} diff --git a/drivers/gpu/nova-core/nova_core.rs b/drivers/gpu/nova-core/nov= a_core.rs index 4dbc7e5daae3..eaba6ad22f7a 100644 --- a/drivers/gpu/nova-core/nova_core.rs +++ b/drivers/gpu/nova-core/nova_core.rs @@ -2,6 +2,9 @@ =20 //! Nova Core GPU Driver =20 +#[macro_use] +mod bitfield; + mod dma; mod driver; mod falcon; diff --git a/drivers/gpu/nova-core/regs/macros.rs b/drivers/gpu/nova-core/r= egs/macros.rs index 754c14ee7f40..945d15a2c529 100644 --- a/drivers/gpu/nova-core/regs/macros.rs +++ b/drivers/gpu/nova-core/regs/macros.rs @@ -8,7 +8,8 @@ //! //! 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. +//! return an error if a field's value is invalid. Please look at the [`bi= tfield`] macro for the +//! complete syntax of fields definitions. =20 /// Trait providing a base address to be added to the offset of a relative= register to obtain /// its actual offset. @@ -54,15 +55,6 @@ pub(crate) trait RegisterBase { /// BOOT_0::alter(&bar, |r| r.set_major_revision(3).set_minor_revision(10)= ); /// ``` /// -/// Fields are defined as follows: -/// -/// - `as ` simply returns the field value casted to , typical= ly `u32`, `u16`, `u8` or -/// `bool`. Note that `bool` fields must have a range of 1 bit. -/// - `as =3D> ` calls ``'s `From::<>` = implementation and returns -/// the result. -/// - `as ?=3D> ` calls ``'s `TryFrom= ::<>` implementation -/// and returns the result. This is useful with fields for which not all= values are valid. -/// /// 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. /// @@ -284,25 +276,25 @@ pub(crate) trait RegisterBase { macro_rules! register { // Creates a register at a fixed offset of the MMIO space. ($name:ident @ $offset:literal $(, $comment:literal)? { $($fields:tt)*= } ) =3D> { - register!(@core $name $(, $comment)? { $($fields)* } ); + bitfield!(struct $name $(, $comment)? { $($fields)* } ); register!(@io_fixed $name @ $offset); }; =20 // Creates an alias register of fixed offset register `alias` with its= own fields. ($name:ident =3D> $alias:ident $(, $comment:literal)? { $($fields:tt)*= } ) =3D> { - register!(@core $name $(, $comment)? { $($fields)* } ); + bitfield!(struct $name $(, $comment)? { $($fields)* } ); register!(@io_fixed $name @ $alias::OFFSET); }; =20 // Creates a register at a relative offset from a base address provide= r. ($name:ident @ $base:ty [ $offset:literal ] $(, $comment:literal)? { $= ($fields:tt)* } ) =3D> { - register!(@core $name $(, $comment)? { $($fields)* } ); + bitfield!(struct $name $(, $comment)? { $($fields)* } ); register!(@io_relative $name @ $base [ $offset ]); }; =20 // 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> { - register!(@core $name $(, $comment)? { $($fields)* } ); + bitfield!(struct $name $(, $comment)? { $($fields)* } ); register!(@io_relative $name @ $base [ $alias::OFFSET ]); }; =20 @@ -313,7 +305,7 @@ macro_rules! register { } ) =3D> { static_assert!(::core::mem::size_of::() <=3D $stride); - register!(@core $name $(, $comment)? { $($fields)* } ); + bitfield!(struct $name $(, $comment)? { $($fields)* } ); register!(@io_array $name @ $offset [ $size ; $stride ]); }; =20 @@ -334,7 +326,7 @@ macro_rules! register { $(, $comment:literal)? { $($fields:tt)* } ) =3D> { static_assert!(::core::mem::size_of::() <=3D $stride); - register!(@core $name $(, $comment)? { $($fields)* } ); + bitfield!(struct $name $(, $comment)? { $($fields)* } ); register!(@io_relative_array $name @ $base [ $offset [ $size ; $st= ride ] ]); }; =20 @@ -356,7 +348,7 @@ macro_rules! register { } ) =3D> { static_assert!($idx < $alias::SIZE); - register!(@core $name $(, $comment)? { $($fields)* } ); + bitfield!(struct $name $(, $comment)? { $($fields)* } ); register!(@io_relative $name @ $base [ $alias::OFFSET + $idx * $al= ias::STRIDE ] ); }; =20 @@ -365,241 +357,10 @@ macro_rules! register { // 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); - register!(@core $name $(, $comment)? { $($fields)* } ); + bitfield!(struct $name $(, $comment)? { $($fields)* } ); register!(@io_fixed $name @ $alias::OFFSET + $idx * $alias::STRIDE= ); }; =20 - // All rules below are helpers. - - // Defines the wrapper `$name` type, as well as its relevant implement= ations (`Debug`, - // `Default`, `BitOr`, and conversion to the value type) and field acc= essor methods. - (@core $name:ident $(, $comment:literal)? { $($fields:tt)* }) =3D> { - $( - #[doc=3D$comment] - )? - #[repr(transparent)] - #[derive(Clone, Copy)] - pub(crate) struct $name(u32); - - impl ::core::ops::BitOr for $name { - type Output =3D Self; - - fn bitor(self, rhs: Self) -> Self::Output { - Self(self.0 | rhs.0) - } - } - - impl ::core::convert::From<$name> for u32 { - fn from(reg: $name) -> u32 { - reg.0 - } - } - - register!(@fields_dispatcher $name { $($fields)* }); - }; - - // Captures the fields and passes them to all the implementers that re= quire field information. - // - // Used to simplify the matching rules for implementers, so they don't= need to match the entire - // complex fields rule even though they only make use of part of it. - (@fields_dispatcher $name:ident { - $($hi:tt:$lo:tt $field:ident as $type:tt - $(?=3D> $try_into_type:ty)? - $(=3D> $into_type:ty)? - $(, $comment:literal)? - ; - )* - } - ) =3D> { - register!(@field_accessors $name { - $( - $hi:$lo $field as $type - $(?=3D> $try_into_type)? - $(=3D> $into_type)? - $(, $comment)? - ; - )* - }); - register!(@debug $name { $($field;)* }); - register!(@default $name { $($field;)* }); - }; - - // Defines all the field getter/methods methods for `$name`. - ( - @field_accessors $name:ident { - $($hi:tt:$lo:tt $field:ident as $type:tt - $(?=3D> $try_into_type:ty)? - $(=3D> $into_type:ty)? - $(, $comment:literal)? - ; - )* - } - ) =3D> { - $( - register!(@check_field_bounds $hi:$lo $field as $type); - )* - - #[allow(dead_code)] - impl $name { - $( - register!(@field_accessor $name $hi:$lo $field as $type - $(?=3D> $try_into_type)? - $(=3D> $into_type)? - $(, $comment)? - ; - ); - )* - } - }; - - // Boolean fields must have `$hi =3D=3D $lo`. - (@check_field_bounds $hi:tt:$lo:tt $field:ident as bool) =3D> { - #[allow(clippy::eq_op)] - const _: () =3D { - ::kernel::build_assert!( - $hi =3D=3D $lo, - concat!("boolean field `", stringify!($field), "` covers m= ore than one bit") - ); - }; - }; - - // Non-boolean fields must have `$hi >=3D $lo`. - (@check_field_bounds $hi:tt:$lo:tt $field:ident as $type:tt) =3D> { - #[allow(clippy::eq_op)] - const _: () =3D { - ::kernel::build_assert!( - $hi >=3D $lo, - concat!("field `", stringify!($field), "`'s MSB is smaller= than its LSB") - ); - }; - }; - - // Catches fields defined as `bool` and convert them into a boolean va= lue. - ( - @field_accessor $name:ident $hi:tt:$lo:tt $field:ident as bool =3D= > $into_type:ty - $(, $comment:literal)?; - ) =3D> { - register!( - @leaf_accessor $name $hi:$lo $field - { |f| <$into_type>::from(if f !=3D 0 { true } else { false }) } - $into_type =3D> $into_type $(, $comment)?; - ); - }; - - // Shortcut for fields defined as `bool` without the `=3D>` syntax. - ( - @field_accessor $name:ident $hi:tt:$lo:tt $field:ident as bool $(,= $comment:literal)?; - ) =3D> { - register!(@field_accessor $name $hi:$lo $field as bool =3D> bool $= (, $comment)?;); - }; - - // Catches the `?=3D>` syntax for non-boolean fields. - ( - @field_accessor $name:ident $hi:tt:$lo:tt $field:ident as $type:tt= ?=3D> $try_into_type:ty - $(, $comment:literal)?; - ) =3D> { - register!(@leaf_accessor $name $hi:$lo $field - { |f| <$try_into_type>::try_from(f as $type) } $try_into_type = =3D> - ::core::result::Result< - $try_into_type, - <$try_into_type as ::core::convert::TryFrom<$type>>::Error - > - $(, $comment)?;); - }; - - // Catches the `=3D>` syntax for non-boolean fields. - ( - @field_accessor $name:ident $hi:tt:$lo:tt $field:ident as $type:tt= =3D> $into_type:ty - $(, $comment:literal)?; - ) =3D> { - register!(@leaf_accessor $name $hi:$lo $field - { |f| <$into_type>::from(f as $type) } $into_type =3D> $into_t= ype $(, $comment)?;); - }; - - // Shortcut for non-boolean fields defined without the `=3D>` or `?=3D= >` syntax. - ( - @field_accessor $name:ident $hi:tt:$lo:tt $field:ident as $type:tt - $(, $comment:literal)?; - ) =3D> { - register!(@field_accessor $name $hi:$lo $field as $type =3D> $type= $(, $comment)?;); - }; - - // Generates the accessor methods for a single field. - ( - @leaf_accessor $name:ident $hi:tt:$lo:tt $field:ident - { $process:expr } $to_type:ty =3D> $res_type:ty $(, $comment:l= iteral)?; - ) =3D> { - ::kernel::macros::paste!( - const [<$field:upper _RANGE>]: ::core::ops::RangeInclusive =3D= $lo..=3D$hi; - const [<$field:upper _MASK>]: u32 =3D ((((1 << $hi) - 1) << 1) + 1= ) - ((1 << $lo) - 1); - const [<$field:upper _SHIFT>]: u32 =3D Self::[<$field:upper _MASK>= ].trailing_zeros(); - ); - - $( - #[doc=3D"Returns the value of this field:"] - #[doc=3D$comment] - )? - #[inline(always)] - pub(crate) fn $field(self) -> $res_type { - ::kernel::macros::paste!( - const MASK: u32 =3D $name::[<$field:upper _MASK>]; - const SHIFT: u32 =3D $name::[<$field:upper _SHIFT>]; - ); - let field =3D ((self.0 & MASK) >> SHIFT); - - $process(field) - } - - ::kernel::macros::paste!( - $( - #[doc=3D"Sets the value of this field:"] - #[doc=3D$comment] - )? - #[inline(always)] - pub(crate) fn [](mut self, value: $to_type) -> Self { - const MASK: u32 =3D $name::[<$field:upper _MASK>]; - const SHIFT: u32 =3D $name::[<$field:upper _SHIFT>]; - let value =3D (u32::from(value) << SHIFT) & MASK; - self.0 =3D (self.0 & !MASK) | value; - - self - } - ); - }; - - // Generates the `Debug` implementation for `$name`. - (@debug $name:ident { $($field:ident;)* }) =3D> { - impl ::core::fmt::Debug for $name { - fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::f= mt::Result { - f.debug_struct(stringify!($name)) - .field("", &format_args!("{:#x}", &self.0)) - $( - .field(stringify!($field), &self.$field()) - )* - .finish() - } - } - }; - - // Generates the `Default` implementation for `$name`. - (@default $name:ident { $($field:ident;)* }) =3D> { - /// Returns a value for the register 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.[](Default::default()); - )* - ); - - value - } - } - }; - // Generates the IO accessors for a fixed offset register. (@io_fixed $name:ident @ $offset:expr) =3D> { #[allow(dead_code)] --=20 2.34.1 From nobody Tue Dec 16 21:28:44 2025 Received: from NAM10-BN7-obe.outbound.protection.outlook.com (mail-bn7nam10on2048.outbound.protection.outlook.com [40.107.92.48]) (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 A615325785E for ; Tue, 9 Sep 2025 21:20:58 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=40.107.92.48 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1757452860; cv=fail; b=iYPZFtu5DY8ZFgIHzafgeP7QHhsryaSrHznrzkiQSYjaoZGSGb01FgpS3ID9k2YGwxkaobBlZkftRnzdFNoRYOhMFvDfdG9h0US9je3bmRK48Oa8/qK+Ws23rYVdfeDKUhjP4a06NzFHhUTkhDNcubhKjlvMfDfDJkoNPL27oCk= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1757452860; c=relaxed/simple; bh=hg+RFa4+fwqyMYbjDmgzKq/74MdLhY/1pfi0Cp7g9qU=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: Content-Type:MIME-Version; b=kgyiH2oQ4nFt3U0nGpuOfH6jN/cShzCPAbmhEge/3NIWCWKTQ+eQkuM40QtMGk6CKUev9rstk8mXwzZvonLdxGpcBdqnf9EkcAwBUyVj3Gegk5w3ICQtztmLfR5wIEoKZvji1OwHhks61SUGuyESsFs6m4L01skBo/QVk971E1I= 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=iJjHTIzo; arc=fail smtp.client-ip=40.107.92.48 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="iJjHTIzo" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=Z30EmzpnbljIEYAUNBtOv6MAGE/u0TkeFRAWozPEk2d9zWq3XQaPAaVpIIC+vdbzhP1jVCzv7dhYIYazIGSMjcaW6QMJNlhXrK5ype++DjnlwePwGja9+JVhqJGauvcHLCjcO/vweMgxeET1AHlp4f2Pnp9XDKN8Uh38Z2Uh5c67MrEdb5nRKgaUhyEg2XaaadxrGy0ffhfWlZHLzNQt8vbaucFOecYoh1CT+rtd4GOk9Raqc8gQPezyxqiI2nYRr9xrOmmBv4s+f4WkSnLQFgRSUB/wTs/gXWQU4MRljLBLjnpMEmQlTqbyjNy97osfHUCWHLQRMhLtoS+TfrYXZA== 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=qCAwEOu9v0pz1g8w1oJdXF52IpYLC3MyyXBRF0Iifqw=; b=Y/U2SNrOo/fkhbtkFifzDzKgiCyKxNHV/XyqjzRVDteM0ns0h8YTui0AVH9jRW7Lz9RyxUK4kFefE3PAQEd+ja8ggGxwO2TP/5wvF2Z9DhM/z7Wwe46J33RPWiJM+1P7WSSdTxjqwFkFyAJguUQjuNEexeLjsU/bcjkyeFPMl+zXX9+Oz+bdmwIVp97CA+B9fKbiA0DAqypXN8MEsL0R/HPcSYe0JwsmLnwrrEgZ9UJTJp7qZY5x4UDyDD3Mvb77Cz8nF4suD62H7rfWmj8olfdGCCuS2i3irIArQEY8l0M/uvA3lu4ZbVU+qvjVMIDLoE0Mtt61rGv0RgbLWs1TVA== 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=qCAwEOu9v0pz1g8w1oJdXF52IpYLC3MyyXBRF0Iifqw=; b=iJjHTIzoqCSzZzF/muPS1R6Yh6WxS8OEheGbTsvPoo5s7tngUrD/oBVGoIl9HnUg5qBl2iPsE+qy0jW+k8uTcJcOfWkUHh6lTo8g7RaidL9iieL71d1veJhiHhjFo3+UHEWLxMxtACgetBropJuTufpae43VcJs69S8HuGSpAlJ1WzgN4R6BuyzFXKJQWQ7TCWuD3WCpwaDtiRwV11x8GZxAco958fNoFP46TQgbWIGU5SsQi6ebBNWUYOGoF7LaQAt4YjRt7TccKOUjYiT/PGCLl6HCSILqESZkPZUItHXj3M98nekNTFdXoAWFu1RJCju+ToYi/8HvH/KZ0OlGiQ== Authentication-Results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=nvidia.com; Received: from DS0PR12MB8044.namprd12.prod.outlook.com (2603:10b6:8:148::14) by MN0PR12MB6031.namprd12.prod.outlook.com (2603:10b6:208:3cd::7) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.9094.22; Tue, 9 Sep 2025 21:20:54 +0000 Received: from DS0PR12MB8044.namprd12.prod.outlook.com ([fe80::49af:9ef0:2373:1515]) by DS0PR12MB8044.namprd12.prod.outlook.com ([fe80::49af:9ef0:2373:1515%6]) with mapi id 15.20.9094.021; Tue, 9 Sep 2025 21:20:53 +0000 From: Joel Fernandes To: linux-kernel@vger.kernel.org, dri-devel@lists.freedesktop.org, dakr@kernel.org, acourbot@nvidia.com Cc: Alistair Popple , Miguel Ojeda , Alex Gaynor , Boqun Feng , Gary Guo , bjorn3_gh@protonmail.com, Benno Lossin , Andreas Hindborg , Alice Ryhl , Trevor Gross , David Airlie , Simona Vetter , Maarten Lankhorst , Maxime Ripard , Thomas Zimmermann , John Hubbard , Joel Fernandes , Timur Tabi , joel@joelfernandes.org, Elle Rhumsaa , Yury Norov , Daniel Almeida , nouveau@lists.freedesktop.org Subject: [PATCH v3 2/5] nova-core: bitfield: Add support for different storage widths Date: Tue, 9 Sep 2025 17:20:36 -0400 Message-Id: <20250909212039.227221-3-joelagnelf@nvidia.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20250909212039.227221-1-joelagnelf@nvidia.com> References: <20250909212039.227221-1-joelagnelf@nvidia.com> Content-Transfer-Encoding: quoted-printable X-ClientProxiedBy: BL1PR13CA0162.namprd13.prod.outlook.com (2603:10b6:208:2bd::17) To DS0PR12MB8044.namprd12.prod.outlook.com (2603:10b6:8:148::14) 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: DS0PR12MB8044:EE_|MN0PR12MB6031:EE_ X-MS-Office365-Filtering-Correlation-Id: c276a733-deb8-4152-ef48-08ddefe6c1cc X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|1800799024|366016|376014|7416014; X-Microsoft-Antispam-Message-Info: =?us-ascii?Q?fMk0gLkht6i7lAzq39ZbM5lR7ICeFVYPMtWvodptu55Y1pkc81QFQdGZA+0D?= =?us-ascii?Q?XoqZL011RDbKbsnLYgJlNKRjyqd6i1umjxs576AHSRRSu6ANvqYhrpbzEirY?= =?us-ascii?Q?/lqc5qC+e5E2N7nKTAmYZe5CivkjGLIh265RodplggdyS0/Rbi2/IhHbRCnQ?= =?us-ascii?Q?YLqNFsWwBA5aNn2isixtPjwQbRvkLf+INGCtyv8lBdP1mYEAWEmIKfMcWtlT?= =?us-ascii?Q?REk/Vd1k4UqDNMAbIn44xYPXkcMZCaYTtEYDmNvOEkqOTnuP4VLqho58w3lT?= =?us-ascii?Q?ngwcpV9tLDzGm4IDHKUhnHXkr7V9dzeoLymLucBif9w7DVpxxdYAkutQcunB?= =?us-ascii?Q?lermLz2xyBFTGaykjRw+QFFi5hVHr0Mc5CljzzzN8DCfbersZO3TEmop1U19?= =?us-ascii?Q?2lA/E25z4X2UsZgV3kLoHJJrf/N9ory948o870+iYH3UvcQArUmPf5BPr1+w?= =?us-ascii?Q?Ljsh5sp52Xi0HdCXZPfhOfhSp01IfD868PbcksWq9zR2bl6iD7VDKEMoZxFc?= =?us-ascii?Q?p2deMa2RTU8rDHbzDRh3quuziB0LZ0naoNCHTdaEkIUuldb47zMzqzGP8+M9?= =?us-ascii?Q?QAMoSWrNl8Bgo2CuabNmcO5F6XFQqmZZuBS3lD2xgfU8TuxIHjpP2EexZulb?= =?us-ascii?Q?lywd4DAunXvMelL1FQgYlLmGdG89oFTWPqHs4wvbRp1cakU8BlmdnAJsVBQT?= =?us-ascii?Q?igqxeRf4UNRoZYd/qVUOp0/5pppt1tKo61zkL2PfThD9B1/aB6mHupKXXbU3?= =?us-ascii?Q?w2FHfTSZluU1qfSt/jaHCx+Yx1qQutdkpTKLi9LF/0tRxsELYnpMaVBlYTMF?= =?us-ascii?Q?eQNxK0xFLOQsD7TnwyvSzxDBtdprdFbEEKOd/eddCvYmigA/SdmAhcwMjsNf?= =?us-ascii?Q?v0hTIiF8PzBRrZZa2mcT8FCD6qqco9MfX7NRry4JNTOnuGqGa9cTd9733QaX?= =?us-ascii?Q?hDtBfO024x1+Itz/gK1uRVhca/Vcz+t5zzFyIxkpgad3vOmzU6RnDXvWHTQp?= =?us-ascii?Q?SpS4QXKtx+KeXd0OxS38/m47IScwp4rl6Rh+KWVvECNgseKqLLMHtGPi+JAu?= =?us-ascii?Q?0i8AUJMyiPB1lcXGXogD4dUZD4kVRXht4wTLyIK9dTJmtOSzldbvjdhmm2VQ?= =?us-ascii?Q?QIaRVjP/Q/cKyIktcXPLuSmDe1KtB1n9hDz7oTI794iwKypacwSFcrk6N+JV?= =?us-ascii?Q?L41TfiUXGuSCOhDaeo6gHjxmfFL5Mq9dksepFh7wDoieBp5nh7V1u8VSAhMa?= =?us-ascii?Q?SVky26rH4zTALyGMvlhvOkqDucabIw+PegJVTtSqk2lOqFVYQ9quxdQQK2zv?= =?us-ascii?Q?J9pBWDoNESdMVelADGqfi0HjMe/H6WBGdl7Qihm1qpYk8bFTSlrsHFNFDJrw?= =?us-ascii?Q?0im8RMMySyn1VQ+FwHgVX5cRDMK0jgiEQiuuwpJCKX3VBHvD+6piQV/lm36f?= =?us-ascii?Q?fBzwT1qoGgk=3D?= X-Forefront-Antispam-Report: CIP:255.255.255.255;CTRY:;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:DS0PR12MB8044.namprd12.prod.outlook.com;PTR:;CAT:NONE;SFS:(13230040)(1800799024)(366016)(376014)(7416014);DIR:OUT;SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: =?us-ascii?Q?Il1vHpV8dhiogM+9WFYNtNvBUsg3b4T11CHt/Tt/cw0oGzQmh9Owao663Wep?= =?us-ascii?Q?EOaCvvF3Dr+vVFFB3Gh/PjmNWDR7k2vUmBn1CirlVUu24Up2j+3ieWr/Tva2?= =?us-ascii?Q?PV+suXI2AxYtbffjoeCpSkWHAgJ+AqIjOJbZIkTiYhV5nBc/6rm0oQn+RQe8?= =?us-ascii?Q?wz5x66c2HG1o033/Pq1Itk9cqsHg3oEe0Wp34U0i9vknQ01eLA0cqYUZJJGs?= =?us-ascii?Q?lAmBui8S8a0nSVmA4/F2y51vyxGjZHtVFqmpPBs18gSoNUepOqXrK7cJovwe?= =?us-ascii?Q?Rf1SDFbCswsrMSqI+AEHzKcxX1b2hYTZeWbBsX1W3i9qsiA5WPHuNAJCpUh0?= =?us-ascii?Q?waj4Xkmd9roxbaflMz2TOQWdQjkipk8bUD28DQWBBGNP5v1OtDRq5rpM6M5C?= =?us-ascii?Q?ejVaEfICJZtpwran0C8WttJccZDCtIIVC9nxtqiIzFMZVV1Hj6crNrc8/9BU?= =?us-ascii?Q?MFkoJWRC//Pe9kCxayR1IF5kLrsM+T2AyyCKhunF+xDj0gG2ktEiTkcX1Iof?= =?us-ascii?Q?RP4RA2nLzwSBql2+K8H6DV1ONg6PjgTwWVpw1VEqgNE5WEUflGVtZYFMuAtq?= =?us-ascii?Q?rxqyjQKCIG/S1VbiTVvsxwFcG2Eo9R0R5dvm3kEDb+MWBHjkZN8mS8hm9sDt?= =?us-ascii?Q?a48llv9ncGSOwOjWGTQPydSIvDMD+225x8j5JlY4j2QaT20yOKlAp/WZRwkm?= =?us-ascii?Q?k0k+N7eBPKUTPUPWcw0hmsYdPhA+F82iu2gz9CehFvR6GNCxIgHzaF8TXBNs?= =?us-ascii?Q?rtg2AJeiOQgfE4q4Ae99ti93bjvMKAlGXaLd39yBW5pQZYUZAKp6HzTY1wDZ?= =?us-ascii?Q?zAF0o6lLYh9zd5AZRt5S/4xecJApZBYr3kdDknjpaqyHdSIfJvcgLLpGvxD9?= =?us-ascii?Q?gwsBcg09ZZLfUkaXFuL7g7+P5Evg+uREYsGtk5B0CRLjETPPUkIwJHksHjEi?= =?us-ascii?Q?Uv0pC+vVbTiCOK8Ha0j3722EIIZafCSwzgdccqyKw2eiSh4E9sTujjdxWyqa?= =?us-ascii?Q?ETPYFW4eqYHXT/cXKdkA+PwXSPnEQMQP4P/G+HKPGhMnqW+2lqhvMkuftJLd?= =?us-ascii?Q?BTtz2cFN1/vb7dHgBRhHoKjya08LDX1kNqYIH+ipVAvSpAgkZlezkPSmpFzI?= =?us-ascii?Q?NWJkahhpEkYlF+T9ocD/i36E+HN/IN3FpOR7NtPM3A/erz/NlzM44DEyMKOw?= =?us-ascii?Q?F0VHcY60LICAeAYqs9i77I7aGrkhq7ECgo22Ewo1uYF8K9CodjNNkJSeH3lL?= =?us-ascii?Q?s4BicNtF0ZBho1KDqK6Z/7BHZhk9ld/Y6fjWTIqp7hLzOOWBL+EhUqmcRyYK?= =?us-ascii?Q?kAuF21exTS8ll/mIydvZ/aBLKzdwNcCQOYxFfgxt17R2wr4bn7bH2Afq/lHq?= =?us-ascii?Q?WxGMDsVjdx6pJEfpOplQF6DDmouqRG3Lav5Bwyiikk2+sCnn9aLdHdsdUIyZ?= =?us-ascii?Q?RYr0y9z60YgL3d4kc172FZ9D6O1CuXR/oKnWWSZdjG7KbDOFhzprHjD/hEC4?= =?us-ascii?Q?8HO90LxyJXvsQ6JqOTD50K5A8LLz297Y5liPqpUedLAaTMwAuC6NMDnJQJsq?= =?us-ascii?Q?TjH2aQb20mjrrOZewGR+Q3vl39v4hqL+sQK7APT/?= X-OriginatorOrg: Nvidia.com X-MS-Exchange-CrossTenant-Network-Message-Id: c276a733-deb8-4152-ef48-08ddefe6c1cc X-MS-Exchange-CrossTenant-AuthSource: DS0PR12MB8044.namprd12.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 09 Sep 2025 21:20:53.0849 (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: LjXBuoRZJ3aHiKcidhuu0Jke5+IbqoSusorkHpEmuSMDjdZn+DgOmlOC+1ODiM36Atg+gQdcG7bc7n67DiRShw== X-MS-Exchange-Transport-CrossTenantHeadersStamped: MN0PR12MB6031 Content-Type: text/plain; charset="utf-8" Previously, bitfields were hardcoded to use u32 as the underlying storage type. Add support for different storage types (u8, u16, u32, u64) to the bitfield macro. New syntax is: struct Name: { ... } Reviewed-by: Elle Rhumsaa Signed-off-by: Joel Fernandes --- drivers/gpu/nova-core/bitfield.rs | 69 +++++++++++++++++----------- drivers/gpu/nova-core/regs/macros.rs | 16 +++---- 2 files changed, 50 insertions(+), 35 deletions(-) diff --git a/drivers/gpu/nova-core/bitfield.rs b/drivers/gpu/nova-core/bitf= ield.rs index ba6b7caa05d9..824559c3462b 100644 --- a/drivers/gpu/nova-core/bitfield.rs +++ b/drivers/gpu/nova-core/bitfield.rs @@ -51,7 +51,7 @@ //! } //! //! bitfield! { -//! struct ControlReg { +//! struct ControlReg: u32 { //! 3:0 mode as u8 ?=3D> Mode; //! 7 state as bool =3D> State; //! } @@ -77,21 +77,21 @@ //! macro_rules! bitfield { // Main entry point - defines the bitfield struct with fields - (struct $name:ident $(, $comment:literal)? { $($fields:tt)* }) =3D> { - bitfield!(@core $name $(, $comment)? { $($fields)* }); + (struct $name:ident : $storage:ty $(, $comment:literal)? { $($fields:t= t)* }) =3D> { + bitfield!(@core $name $storage $(, $comment)? { $($fields)* }); }; =20 // All rules below are helpers. =20 // Defines the wrapper `$name` type, as well as its relevant implement= ations (`Debug`, // `Default`, `BitOr`, and conversion to the value type) and field acc= essor methods. - (@core $name:ident $(, $comment:literal)? { $($fields:tt)* }) =3D> { + (@core $name:ident $storage:ty $(, $comment:literal)? { $($fields:tt)*= }) =3D> { $( #[doc=3D$comment] )? #[repr(transparent)] #[derive(Clone, Copy)] - pub(crate) struct $name(u32); + pub(crate) struct $name($storage); =20 impl ::core::ops::BitOr for $name { type Output =3D Self; @@ -101,20 +101,26 @@ fn bitor(self, rhs: Self) -> Self::Output { } } =20 - impl ::core::convert::From<$name> for u32 { - fn from(val: $name) -> u32 { + impl ::core::convert::From<$name> for $storage { + fn from(val: $name) -> $storage { val.0 } } =20 - bitfield!(@fields_dispatcher $name { $($fields)* }); + impl ::core::convert::From<$storage> for $name { + fn from(val: $storage) -> Self { + Self(val) + } + } + + bitfield!(@fields_dispatcher $name $storage { $($fields)* }); }; =20 // Captures the fields and passes them to all the implementers that re= quire field information. // // Used to simplify the matching rules for implementers, so they don't= need to match the entire // complex fields rule even though they only make use of part of it. - (@fields_dispatcher $name:ident { + (@fields_dispatcher $name:ident $storage:ty { $($hi:tt:$lo:tt $field:ident as $type:tt $(?=3D> $try_into_type:ty)? $(=3D> $into_type:ty)? @@ -123,7 +129,7 @@ fn from(val: $name) -> u32 { )* } ) =3D> { - bitfield!(@field_accessors $name { + bitfield!(@field_accessors $name $storage { $( $hi:$lo $field as $type $(?=3D> $try_into_type)? @@ -138,7 +144,7 @@ fn from(val: $name) -> u32 { =20 // Defines all the field getter/setter methods for `$name`. ( - @field_accessors $name:ident { + @field_accessors $name:ident $storage:ty { $($hi:tt:$lo:tt $field:ident as $type:tt $(?=3D> $try_into_type:ty)? $(=3D> $into_type:ty)? @@ -154,7 +160,7 @@ fn from(val: $name) -> u32 { #[allow(dead_code)] impl $name { $( - bitfield!(@field_accessor $name $hi:$lo $field as $type + bitfield!(@field_accessor $name $storage, $hi:$lo $field as $t= ype $(?=3D> $try_into_type)? $(=3D> $into_type)? $(, $comment)? @@ -188,11 +194,11 @@ impl $name { =20 // Catches fields defined as `bool` and convert them into a boolean va= lue. ( - @field_accessor $name:ident $hi:tt:$lo:tt $field:ident as bool =3D= > $into_type:ty + @field_accessor $name:ident $storage:ty, $hi:tt:$lo:tt $field:iden= t as bool =3D> $into_type:ty $(, $comment:literal)?; ) =3D> { bitfield!( - @leaf_accessor $name $hi:$lo $field + @leaf_accessor $name $storage, $hi:$lo $field { |f| <$into_type>::from(if f !=3D 0 { true } else { false }) } $into_type =3D> $into_type $(, $comment)?; ); @@ -200,17 +206,17 @@ impl $name { =20 // Shortcut for fields defined as `bool` without the `=3D>` syntax. ( - @field_accessor $name:ident $hi:tt:$lo:tt $field:ident as bool $(,= $comment:literal)?; + @field_accessor $name:ident $storage:ty, $hi:tt:$lo:tt $field:iden= t as bool $(, $comment:literal)?; ) =3D> { - bitfield!(@field_accessor $name $hi:$lo $field as bool =3D> bool $= (, $comment)?;); + bitfield!(@field_accessor $name $storage, $hi:$lo $field as bool = =3D> bool $(, $comment)?;); }; =20 // Catches the `?=3D>` syntax for non-boolean fields. ( - @field_accessor $name:ident $hi:tt:$lo:tt $field:ident as $type:tt= ?=3D> $try_into_type:ty + @field_accessor $name:ident $storage:ty, $hi:tt:$lo:tt $field:iden= t as $type:tt ?=3D> $try_into_type:ty $(, $comment:literal)?; ) =3D> { - bitfield!(@leaf_accessor $name $hi:$lo $field + bitfield!(@leaf_accessor $name $storage, $hi:$lo $field { |f| <$try_into_type>::try_from(f as $type) } $try_into_type = =3D> ::core::result::Result< $try_into_type, @@ -221,29 +227,38 @@ impl $name { =20 // Catches the `=3D>` syntax for non-boolean fields. ( - @field_accessor $name:ident $hi:tt:$lo:tt $field:ident as $type:tt= =3D> $into_type:ty + @field_accessor $name:ident $storage:ty, $hi:tt:$lo:tt $field:iden= t as $type:tt =3D> $into_type:ty $(, $comment:literal)?; ) =3D> { - bitfield!(@leaf_accessor $name $hi:$lo $field + bitfield!(@leaf_accessor $name $storage, $hi:$lo $field { |f| <$into_type>::from(f as $type) } $into_type =3D> $into_t= ype $(, $comment)?;); }; =20 // Shortcut for non-boolean fields defined without the `=3D>` or `?=3D= >` syntax. ( - @field_accessor $name:ident $hi:tt:$lo:tt $field:ident as $type:tt + @field_accessor $name:ident $storage:ty, $hi:tt:$lo:tt $field:iden= t as $type:tt $(, $comment:literal)?; ) =3D> { - bitfield!(@field_accessor $name $hi:$lo $field as $type =3D> $type= $(, $comment)?;); + bitfield!(@field_accessor $name $storage, $hi:$lo $field as $type = =3D> $type $(, $comment)?;); }; =20 // Generates the accessor methods for a single field. ( - @leaf_accessor $name:ident $hi:tt:$lo:tt $field:ident + @leaf_accessor $name:ident $storage:ty, $hi:tt:$lo:tt $field:ident { $process:expr } $to_type:ty =3D> $res_type:ty $(, $comment:l= iteral)?; ) =3D> { ::kernel::macros::paste!( const [<$field:upper _RANGE>]: ::core::ops::RangeInclusive =3D= $lo..=3D$hi; - const [<$field:upper _MASK>]: u32 =3D ((((1 << $hi) - 1) << 1) + 1= ) - ((1 << $lo) - 1); + const [<$field:upper _MASK>]: $storage =3D { + // Generate mask for shifting + match ::core::mem::size_of::<$storage>() { + 1 =3D> ::kernel::bits::genmask_u8($lo..=3D$hi) as $storage, + 2 =3D> ::kernel::bits::genmask_u16($lo..=3D$hi) as $storag= e, + 4 =3D> ::kernel::bits::genmask_u32($lo..=3D$hi) as $storag= e, + 8 =3D> ::kernel::bits::genmask_u64($lo..=3D$hi) as $storag= e, + _ =3D> ::kernel::build_error!("Unsupported storage type si= ze") + } + }; const [<$field:upper _SHIFT>]: u32 =3D Self::[<$field:upper _MASK>= ].trailing_zeros(); ); =20 @@ -254,7 +269,7 @@ impl $name { #[inline(always)] pub(crate) fn $field(self) -> $res_type { ::kernel::macros::paste!( - const MASK: u32 =3D $name::[<$field:upper _MASK>]; + const MASK: $storage =3D $name::[<$field:upper _MASK>]; const SHIFT: u32 =3D $name::[<$field:upper _SHIFT>]; ); let field =3D ((self.0 & MASK) >> SHIFT); @@ -269,9 +284,9 @@ pub(crate) fn $field(self) -> $res_type { )? #[inline(always)] pub(crate) fn [](mut self, value: $to_type) -> Self { - const MASK: u32 =3D $name::[<$field:upper _MASK>]; + const MASK: $storage =3D $name::[<$field:upper _MASK>]; const SHIFT: u32 =3D $name::[<$field:upper _SHIFT>]; - let value =3D (u32::from(value) << SHIFT) & MASK; + let value =3D (<$storage>::from(value) << SHIFT) & MASK; self.0 =3D (self.0 & !MASK) | value; =20 self diff --git a/drivers/gpu/nova-core/regs/macros.rs b/drivers/gpu/nova-core/r= egs/macros.rs index 945d15a2c529..d34c7f37fb93 100644 --- a/drivers/gpu/nova-core/regs/macros.rs +++ b/drivers/gpu/nova-core/regs/macros.rs @@ -276,25 +276,25 @@ pub(crate) trait RegisterBase { macro_rules! register { // Creates a register at a fixed offset of the MMIO space. ($name:ident @ $offset:literal $(, $comment:literal)? { $($fields:tt)*= } ) =3D> { - bitfield!(struct $name $(, $comment)? { $($fields)* } ); + bitfield!(struct $name: u32 $(, $comment)? { $($fields)* } ); register!(@io_fixed $name @ $offset); }; =20 // Creates an alias register of fixed offset register `alias` with its= own fields. ($name:ident =3D> $alias:ident $(, $comment:literal)? { $($fields:tt)*= } ) =3D> { - bitfield!(struct $name $(, $comment)? { $($fields)* } ); + bitfield!(struct $name: u32 $(, $comment)? { $($fields)* } ); register!(@io_fixed $name @ $alias::OFFSET); }; =20 // 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!(struct $name $(, $comment)? { $($fields)* } ); + bitfield!(struct $name: u32 $(, $comment)? { $($fields)* } ); register!(@io_relative $name @ $base [ $offset ]); }; =20 // 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!(struct $name $(, $comment)? { $($fields)* } ); + bitfield!(struct $name: u32 $(, $comment)? { $($fields)* } ); register!(@io_relative $name @ $base [ $alias::OFFSET ]); }; =20 @@ -305,7 +305,7 @@ macro_rules! register { } ) =3D> { static_assert!(::core::mem::size_of::() <=3D $stride); - bitfield!(struct $name $(, $comment)? { $($fields)* } ); + bitfield!(struct $name: u32 $(, $comment)? { $($fields)* } ); register!(@io_array $name @ $offset [ $size ; $stride ]); }; =20 @@ -326,7 +326,7 @@ macro_rules! register { $(, $comment:literal)? { $($fields:tt)* } ) =3D> { static_assert!(::core::mem::size_of::() <=3D $stride); - bitfield!(struct $name $(, $comment)? { $($fields)* } ); + bitfield!(struct $name: u32 $(, $comment)? { $($fields)* } ); register!(@io_relative_array $name @ $base [ $offset [ $size ; $st= ride ] ]); }; =20 @@ -348,7 +348,7 @@ macro_rules! register { } ) =3D> { static_assert!($idx < $alias::SIZE); - bitfield!(struct $name $(, $comment)? { $($fields)* } ); + bitfield!(struct $name: u32 $(, $comment)? { $($fields)* } ); register!(@io_relative $name @ $base [ $alias::OFFSET + $idx * $al= ias::STRIDE ] ); }; =20 @@ -357,7 +357,7 @@ macro_rules! register { // 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!(struct $name $(, $comment)? { $($fields)* } ); + bitfield!(struct $name: u32 $(, $comment)? { $($fields)* } ); register!(@io_fixed $name @ $alias::OFFSET + $idx * $alias::STRIDE= ); }; =20 --=20 2.34.1 From nobody Tue Dec 16 21:28:44 2025 Received: from NAM10-BN7-obe.outbound.protection.outlook.com (mail-bn7nam10on2048.outbound.protection.outlook.com [40.107.92.48]) (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 B06D2258ECC for ; Tue, 9 Sep 2025 21:21:00 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=40.107.92.48 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1757452864; cv=fail; b=aWz14i2w/COy5SLiPowu6daiuaXkEwoWKpVXHOJ8OqjIdRTU9sr35asWM4+gz4Vr/snd9eUGu0heFGDmisgBdqGhhgsLYJuVgiUyKdxuHK0vz8kJHsLFMlrKhQ69CZK2ve3Cu5z+XkiNdz6nTanij96yKtWOEO09ToN5NdnP8yg= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1757452864; c=relaxed/simple; bh=vqc8U2Dmf+/w8v5mCU3ZzThRUsOieIwN+FeHpBbmEMY=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: Content-Type:MIME-Version; b=bsPDghUipgtfHzaTPjd+UYlRgZ/vXQBvw9rDR0KG2+GlCypEezdLEKEbG+NRAGR13UE43lwrDinQpNogOdvL7jEBjLuhypO0gwtgNPadY9YMh173ZF9iY0MnXllIVzOQS9y6L4DvDAzZ1EACfhZZuy09ykrxtNytCNmWTZiRjyY= 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=Ott0RFdl; arc=fail smtp.client-ip=40.107.92.48 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="Ott0RFdl" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=yFEmEBQpMOUyFx4uCFYhzn/IN6WE+fL8GuJyY765grFkvmH42ApQ8as6tfZCi3sZogVd7KoaFQh4udq4WDTHmC7rqaelqEcrb7GdN6I2L7TSzZeUpNlyuC0oCU1s68r2gEZV2OZ43q9iCWpNI2z6+nkG3wNqoqAmg7aG0wiyaZ/wRuPJBjb/nFp9wSGsTXIJn02a8w+y69GFhUux+VNnQB1Fcq6CqmSLXLhgvabGov0oGdMYavJ3S7EMWxaGlDGBHWYlwBDPjbQiTas2S4v4KHUCz5+74GofaoTKnw3sdQsBkrAP1l2MaFMFGRQPKOmmjts4O+bmu2fRRKzD3O7D2Q== 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=VdpnCgv+SBOHwmyBE6fcjxGEWIEgynJoITa+s34jpB8=; b=KPNgY6rYXOVE9rjkXmUZuUOqy+UystPHdeNgZB40ZbrEvH2YXHxMpS3/RXgnBgCHEMYSv9kmOrTylLPfDG1C95Q5SdqETMZpUberDjH7P+fxlhMOhBe067UDZKhp67bhbuyRb4TzISdTPbj/5bJZO6RjktNi/9neyzRmIzFfkn5trJ2b0ELvFB7+UMHjKSXR4OgXH1d012+ZTzZXrZ/5kEICuRooM6Vrv4jGgYByaH5xmyiDc1S7FPx38mY2ThJBGDW45NaFw7wsWDlPDNgqI7rekKlB+e2LHSFivFccLQ92Sw6VKl+SlrJkfdbMJdpmq7h8KrlIl33KPZj0Jtmshg== 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=VdpnCgv+SBOHwmyBE6fcjxGEWIEgynJoITa+s34jpB8=; b=Ott0RFdlLYgJA07xEo7PyvCJea/AMo1LivpaM9OUTHQMSG2Dy7DhJKOl7/V4XPa21pmwamd1wD/PVRGdXmptXcSPRB/MF/xNxnis7mt9Idu8q0LQNGMldcHNeFtab+Hhk8gePrwS4Jkfu2XNyo+rHv1K2FJlI+LVwyfBzZ5A85MeftU7JODgRVZO0ijpoX2i7bi0Hq39G63K2VX0A2ONb0ixQZDj4IWRe5lvUW5I76Lg30dcAiueu/jGtaAvyOKpw3aNaaZ6Yw6MMcSlv8DvgZWAmtXUHxTZ53s7vu2UFgbPyejc9ALnIe3d9rqd99wmiD7XpHWorAK4GpkAnJMEkA== Authentication-Results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=nvidia.com; Received: from DS0PR12MB8044.namprd12.prod.outlook.com (2603:10b6:8:148::14) by MN0PR12MB6031.namprd12.prod.outlook.com (2603:10b6:208:3cd::7) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.9094.22; Tue, 9 Sep 2025 21:20:55 +0000 Received: from DS0PR12MB8044.namprd12.prod.outlook.com ([fe80::49af:9ef0:2373:1515]) by DS0PR12MB8044.namprd12.prod.outlook.com ([fe80::49af:9ef0:2373:1515%6]) with mapi id 15.20.9094.021; Tue, 9 Sep 2025 21:20:55 +0000 From: Joel Fernandes To: linux-kernel@vger.kernel.org, dri-devel@lists.freedesktop.org, dakr@kernel.org, acourbot@nvidia.com Cc: Alistair Popple , Miguel Ojeda , Alex Gaynor , Boqun Feng , Gary Guo , bjorn3_gh@protonmail.com, Benno Lossin , Andreas Hindborg , Alice Ryhl , Trevor Gross , David Airlie , Simona Vetter , Maarten Lankhorst , Maxime Ripard , Thomas Zimmermann , John Hubbard , Joel Fernandes , Timur Tabi , joel@joelfernandes.org, Elle Rhumsaa , Yury Norov , Daniel Almeida , nouveau@lists.freedesktop.org Subject: [PATCH v3 3/5] nova-core: bitfield: Add support for custom visiblity Date: Tue, 9 Sep 2025 17:20:37 -0400 Message-Id: <20250909212039.227221-4-joelagnelf@nvidia.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20250909212039.227221-1-joelagnelf@nvidia.com> References: <20250909212039.227221-1-joelagnelf@nvidia.com> Content-Transfer-Encoding: quoted-printable X-ClientProxiedBy: BN9PR03CA0452.namprd03.prod.outlook.com (2603:10b6:408:139::7) To DS0PR12MB8044.namprd12.prod.outlook.com (2603:10b6:8:148::14) 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: DS0PR12MB8044:EE_|MN0PR12MB6031:EE_ X-MS-Office365-Filtering-Correlation-Id: 43ddd319-092d-40e6-35c4-08ddefe6c2f3 X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|1800799024|366016|376014|7416014; X-Microsoft-Antispam-Message-Info: =?us-ascii?Q?1sgCMiEjsHkFw//NyTXZNU4n4EJdBiKufmsEP+nSLo2he1+2kgTFZxeMszDE?= =?us-ascii?Q?yXXqz+sLTgszpncsjuPw62E0CB8HYcXiwmz1IUi3RXgnV+A6o2M25yf8Fcwl?= =?us-ascii?Q?cDPP8gkRtJgim3eR3TAiKZq2KrsNnDCblDAwW4f1IM+GUepw0GIh+tpnUwF9?= =?us-ascii?Q?7bIFSwpLhA2Bb66Oi0j39kb7jAeT440UXapyty6EAie2S276FSO25S1u7/XE?= =?us-ascii?Q?SgMr1UaG0oWni8VxI46fqZvFeo88CB9azor0I6IVhH+K7NBo/0jsEWPXVAnl?= =?us-ascii?Q?S85DjXHzA75alhLAwuUnb2u9N7IMu45g1Z8bJiQpWQ78WivoIPNvop7K7Rr9?= =?us-ascii?Q?HL+slt1FFAV3HlCxKEWKe5anpNNNLiOKEmfsTXz2TGEuyGdL7pZeqpQqNge6?= =?us-ascii?Q?odz8i5r3hKAFBlKlzW+5gua5gdQYY7TCpVrujrDO7KVzzxVk6teKupnVKucY?= =?us-ascii?Q?3HGjuHmW/JWmpMCQ5jmU8UXLTBId6a0ERxReqlUGAMecogw/NQ1QfRMMlRPm?= =?us-ascii?Q?RVSDynrcQmFZmyc0zp0yRSvZIMOmWYHV52rVdzpV8Z6zFajtF5ooDmV8g2vu?= =?us-ascii?Q?qCSrUkWgvf1cxPKOKTLe9R0fpjyoi5Fv58L4DCTjfAOgeZhezn3f6Wt9yr+5?= =?us-ascii?Q?7mIhWOJt8GtQYStGDzJCv2MrWlWwmwu4sg8Bqk6c11EcdaZuSTbq0+2/09aQ?= =?us-ascii?Q?qscThcICj+ANpsXylzT1dhjKaFB/dBHcnuyLCmmPUfFKoibU2DgZkZUQs6wY?= =?us-ascii?Q?kv8XtLoeW92OcKmXUuuLZAYd377P6VqYV4obbdtCbjXrfhjLaX+RWYcJP7b4?= =?us-ascii?Q?0X3lSzbrydG0xiLx0FOw1D0WFzOfq69XHbtiPhtQz2itChfotK58bmsv11oN?= =?us-ascii?Q?KAb9qFrExvuUSn/jyD5NHA1qMO2tjx+BjS1kBSuGKwvog9MHUO26wxQ+dv2b?= =?us-ascii?Q?0ZUeK2NA+6Ht6txN39UU7Xg3qORI2j4Rk9kF+a+AQHDLumHuBt4pd0jDioXR?= =?us-ascii?Q?Ed40oV9jXFJxk0JTFDNbbBmGsJt4LwNefgaznrsWYw9ucM1d1tV87aSi+SFC?= =?us-ascii?Q?br2x02F3cJGclYt8akjqDOBOuQAO6s4FQsx/GKTw1nNWBKbmnTL5KQ9GLn5X?= =?us-ascii?Q?8NZmC2IHYr+f97B4LEDMmdUra42EzoT559egH0HXsO7V1WQzz6PMF8PoO9Hn?= =?us-ascii?Q?rlB6CcQ695k7kb2N2QQF+Tfmwm6wGfe1tJua3M43pfaEK57mk2QA/qJK/yxu?= =?us-ascii?Q?J4as3KMots3SWH83S8S8/TKTLCLzaOxsiVRz3KsMOo9LvNvwu8QjcvEM/5A2?= =?us-ascii?Q?S1NdbKuCW4YKGMNRL06G3LGJZTv/YyKDmPj0kU8Qbz5zr8nt0xBu9gwpJADy?= =?us-ascii?Q?8+VGBOVwC8khgUPcu+51AECspFvB/iv/+fCwv+1KQIELM14F0FFuKytrlFLW?= =?us-ascii?Q?QB98DwN+3IU=3D?= X-Forefront-Antispam-Report: CIP:255.255.255.255;CTRY:;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:DS0PR12MB8044.namprd12.prod.outlook.com;PTR:;CAT:NONE;SFS:(13230040)(1800799024)(366016)(376014)(7416014);DIR:OUT;SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: =?us-ascii?Q?xcCC39jVJZmM3ycImVLjeEeKRdA8n6bzzrrnZR6ElhBOU7q9tFEpCQIaXfmo?= =?us-ascii?Q?55Pf6XTInyTmRXr/R5zeikt9gvh6noUzIyWwTrn79z9muZJBAwSNsoahqguj?= =?us-ascii?Q?5iKXTx3CElxmpOywHyochrwBaSRM69FaV0Rg4DF6JmvQJ/ii4E4JGrqjYYYd?= =?us-ascii?Q?VRT1HTK4jRhFbb2m8LgoJ2Zo0XNCS3uqoc+6Qd2R1oobAkdrkhgoNipWxBQg?= =?us-ascii?Q?NKt88hP7Zn5agiCPLfiyX1QE3j+VmCAT9zUVu4b8ktpvpDSjjNqYK3YPmUuc?= =?us-ascii?Q?2whvgR+Aa/fsiFiopvPDOaD+tchaCJA0eLKjrcLQYZRFhVztN/S2eQbDpf0h?= =?us-ascii?Q?d8BAQ0FZ41yzzIJREi3B2tPGBW7fM3+REbmeH+2go65Gt+zJXoagHfQQita/?= =?us-ascii?Q?DZqlsYWJq1auLp/3+fiRwsRDe3Cii/iraWGC3RI4HNRQXPUnrT4Qhz1NW/XK?= =?us-ascii?Q?6C+2XsqGQyx62bxNMAj2cqNxVuBQU54KFY5MBzauk70VY/LOfF0dd4pdhf75?= =?us-ascii?Q?Wf5wzsktROG94abUdJ1KGKt0GPOo0YXDSQAbha9jt2utb3aru1VIEDZKRdvr?= =?us-ascii?Q?O9LPP/YngseHnf0nt48eESeMadTA9rlKgHKP5R5FM1LWx5gV7bA/Qefkw2s9?= =?us-ascii?Q?HDeVuP8E77Jpfbf2oobPHj0VfyX9iuobg1mP4HxwtuVQIi1uAmqkFPe/qLaI?= =?us-ascii?Q?EFuBvd3WWrg8oTI/StgtJ91EkmTCOKzKIx5QtKd7aF4v3kk06cOCeWGjXeXE?= =?us-ascii?Q?iTcjvUDoPEqcM3O4QNq2B3VewYPXutsl0wSmscY9M9dXy/owpalHzOeGug1H?= =?us-ascii?Q?XVJVV6lCgm6OufSrYXc/YQk53XOz/pCypLX+H4bl355wM+3l6xAccVI1LLd2?= =?us-ascii?Q?PszjTp8QzD7I77iOxgJFj8VBUzoVXru8s9Gm3HQk+/PkFJNaKnlE2Oa/dnBC?= =?us-ascii?Q?DZLWh+Ih2nGd6ypoqJlKxq4bJmaznDQgz7yv0nYtQhTP0u7ryfAk8lnRYt+O?= =?us-ascii?Q?ZHCAWKlvdtioseQtbUQVmiaWZ6PoUCv8KVTHU2Gr7PJgPeoe952LtRsK/JE0?= =?us-ascii?Q?khN5QKNjtcKDLuiOnUlUndjcIpHzkWxjMAX2OPBHY4JS+cUlFcFIcfCHNCdF?= =?us-ascii?Q?B+0K2Pd/Ww1w9Q+i8mK/KjBfBAzESk8pYpWhDCs++GPxFm2UmCaVdp1F1Rj2?= =?us-ascii?Q?6HPe1UUCRRNqomZ8LBpKO1Med909qDjOOJoAI6uJNitU3VKt4jPKoBu2m+Vx?= =?us-ascii?Q?Jw8jSRalT6Q18CO92MjEFl8Vcv2ClDaOsU0++XNQfBrd3njYZwPY/O82Fsxr?= =?us-ascii?Q?aCkmbfgB3tEmen5kfFaPgYQrsUmvl/mLx+9JbLIKDZa46ECIL6XQcTC6kChx?= =?us-ascii?Q?GXbWlbECHvTN4jedt5YhTZ4lJffniaNRRzEpzeUGPrXR9ijdoKP2MSDZFhPu?= =?us-ascii?Q?em9PsNq9bAG65Ps6dKDr2eccWIuNjbqO8Wp1JDPzZfbe5CyWyayuNeCM/f8a?= =?us-ascii?Q?ipwdT9YnXVI0X/BQmDA48OwVJS4mthVPZcPbuyoJip920gjm3yC0Fm8rfXdf?= =?us-ascii?Q?UpowRYO9TthDtRIYhW0tbnzytwMkznrPSMWW8jO3?= X-OriginatorOrg: Nvidia.com X-MS-Exchange-CrossTenant-Network-Message-Id: 43ddd319-092d-40e6-35c4-08ddefe6c2f3 X-MS-Exchange-CrossTenant-AuthSource: DS0PR12MB8044.namprd12.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 09 Sep 2025 21:20:55.0422 (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: 5a8cBAtLKa7E5uu17YUZg9fGPeGnGKEOwTFpWcYZvYNYwuke4AF9LYiVHOZ6eTTKvw/k9vWsl7or1Sy9M9ZBnQ== X-MS-Exchange-Transport-CrossTenantHeadersStamped: MN0PR12MB6031 Content-Type: text/plain; charset="utf-8" Add support for custom visiblity to allow for users to control visibility of the structure and helpers. Reviewed-by: Elle Rhumsaa Signed-off-by: Joel Fernandes --- drivers/gpu/nova-core/bitfield.rs | 55 ++++++++++++++++------------ drivers/gpu/nova-core/regs/macros.rs | 16 ++++---- 2 files changed, 40 insertions(+), 31 deletions(-) diff --git a/drivers/gpu/nova-core/bitfield.rs b/drivers/gpu/nova-core/bitf= ield.rs index 824559c3462b..39354e60360c 100644 --- a/drivers/gpu/nova-core/bitfield.rs +++ b/drivers/gpu/nova-core/bitfield.rs @@ -51,7 +51,7 @@ //! } //! //! bitfield! { -//! struct ControlReg: u32 { +//! pub struct ControlReg: u32 { //! 3:0 mode as u8 ?=3D> Mode; //! 7 state as bool =3D> State; //! } @@ -63,6 +63,9 @@ //! - Field setters: `set_mode()`, `set_state()`, etc. (supports chaining = with builder pattern). //! - Debug and Default implementations //! +//! Note: Field accessors and setters inherit the same visibility as the s= truct itself. +//! In the example above, both `mode()` and `set_mode()` methods will be `= pub`. +//! //! The field setters can be used with the builder pattern, example: //! ControlReg::default().set_mode(mode).set_state(state); //! @@ -77,21 +80,21 @@ //! macro_rules! bitfield { // Main entry point - defines the bitfield struct with fields - (struct $name:ident : $storage:ty $(, $comment:literal)? { $($fields:t= t)* }) =3D> { - bitfield!(@core $name $storage $(, $comment)? { $($fields)* }); + ($vis:vis struct $name:ident : $storage:ty $(, $comment:literal)? { $(= $fields:tt)* }) =3D> { + bitfield!(@core $vis $name $storage $(, $comment)? { $($fields)* }= ); }; =20 // All rules below are helpers. =20 // Defines the wrapper `$name` type, as well as its relevant implement= ations (`Debug`, // `Default`, `BitOr`, and conversion to the value type) and field acc= essor methods. - (@core $name:ident $storage:ty $(, $comment:literal)? { $($fields:tt)*= }) =3D> { + (@core $vis:vis $name:ident $storage:ty $(, $comment:literal)? { $($fi= elds:tt)* }) =3D> { $( #[doc=3D$comment] )? #[repr(transparent)] #[derive(Clone, Copy)] - pub(crate) struct $name($storage); + $vis struct $name($storage); =20 impl ::core::ops::BitOr for $name { type Output =3D Self; @@ -113,14 +116,14 @@ fn from(val: $storage) -> Self { } } =20 - bitfield!(@fields_dispatcher $name $storage { $($fields)* }); + bitfield!(@fields_dispatcher $vis $name $storage { $($fields)* }); }; =20 // Captures the fields and passes them to all the implementers that re= quire field information. // // Used to simplify the matching rules for implementers, so they don't= need to match the entire // complex fields rule even though they only make use of part of it. - (@fields_dispatcher $name:ident $storage:ty { + (@fields_dispatcher $vis:vis $name:ident $storage:ty { $($hi:tt:$lo:tt $field:ident as $type:tt $(?=3D> $try_into_type:ty)? $(=3D> $into_type:ty)? @@ -129,7 +132,7 @@ fn from(val: $storage) -> Self { )* } ) =3D> { - bitfield!(@field_accessors $name $storage { + bitfield!(@field_accessors $vis $name $storage { $( $hi:$lo $field as $type $(?=3D> $try_into_type)? @@ -144,7 +147,7 @@ fn from(val: $storage) -> Self { =20 // Defines all the field getter/setter methods for `$name`. ( - @field_accessors $name:ident $storage:ty { + @field_accessors $vis:vis $name:ident $storage:ty { $($hi:tt:$lo:tt $field:ident as $type:tt $(?=3D> $try_into_type:ty)? $(=3D> $into_type:ty)? @@ -159,8 +162,14 @@ fn from(val: $storage) -> Self { =20 #[allow(dead_code)] impl $name { + /// Returns the raw underlying value + #[inline(always)] + $vis fn raw(&self) -> $storage { + self.0 + } + $( - bitfield!(@field_accessor $name $storage, $hi:$lo $field as $t= ype + bitfield!(@field_accessor $vis $name $storage, $hi:$lo $field = as $type $(?=3D> $try_into_type)? $(=3D> $into_type)? $(, $comment)? @@ -194,11 +203,11 @@ impl $name { =20 // Catches fields defined as `bool` and convert them into a boolean va= lue. ( - @field_accessor $name:ident $storage:ty, $hi:tt:$lo:tt $field:iden= t as bool =3D> $into_type:ty + @field_accessor $vis:vis $name:ident $storage:ty, $hi:tt:$lo:tt $f= ield:ident as bool =3D> $into_type:ty $(, $comment:literal)?; ) =3D> { bitfield!( - @leaf_accessor $name $storage, $hi:$lo $field + @leaf_accessor $vis $name $storage, $hi:$lo $field { |f| <$into_type>::from(if f !=3D 0 { true } else { false }) } $into_type =3D> $into_type $(, $comment)?; ); @@ -206,17 +215,17 @@ impl $name { =20 // Shortcut for fields defined as `bool` without the `=3D>` syntax. ( - @field_accessor $name:ident $storage:ty, $hi:tt:$lo:tt $field:iden= t as bool $(, $comment:literal)?; + @field_accessor $vis:vis $name:ident $storage:ty, $hi:tt:$lo:tt $f= ield:ident as bool $(, $comment:literal)?; ) =3D> { - bitfield!(@field_accessor $name $storage, $hi:$lo $field as bool = =3D> bool $(, $comment)?;); + bitfield!(@field_accessor $vis $name $storage, $hi:$lo $field as b= ool =3D> bool $(, $comment)?;); }; =20 // Catches the `?=3D>` syntax for non-boolean fields. ( - @field_accessor $name:ident $storage:ty, $hi:tt:$lo:tt $field:iden= t as $type:tt ?=3D> $try_into_type:ty + @field_accessor $vis:vis $name:ident $storage:ty, $hi:tt:$lo:tt $f= ield:ident as $type:tt ?=3D> $try_into_type:ty $(, $comment:literal)?; ) =3D> { - bitfield!(@leaf_accessor $name $storage, $hi:$lo $field + bitfield!(@leaf_accessor $vis $name $storage, $hi:$lo $field { |f| <$try_into_type>::try_from(f as $type) } $try_into_type = =3D> ::core::result::Result< $try_into_type, @@ -227,24 +236,24 @@ impl $name { =20 // Catches the `=3D>` syntax for non-boolean fields. ( - @field_accessor $name:ident $storage:ty, $hi:tt:$lo:tt $field:iden= t as $type:tt =3D> $into_type:ty + @field_accessor $vis:vis $name:ident $storage:ty, $hi:tt:$lo:tt $f= ield:ident as $type:tt =3D> $into_type:ty $(, $comment:literal)?; ) =3D> { - bitfield!(@leaf_accessor $name $storage, $hi:$lo $field + bitfield!(@leaf_accessor $vis $name $storage, $hi:$lo $field { |f| <$into_type>::from(f as $type) } $into_type =3D> $into_t= ype $(, $comment)?;); }; =20 // Shortcut for non-boolean fields defined without the `=3D>` or `?=3D= >` syntax. ( - @field_accessor $name:ident $storage:ty, $hi:tt:$lo:tt $field:iden= t as $type:tt + @field_accessor $vis:vis $name:ident $storage:ty, $hi:tt:$lo:tt $f= ield:ident as $type:tt $(, $comment:literal)?; ) =3D> { - bitfield!(@field_accessor $name $storage, $hi:$lo $field as $type = =3D> $type $(, $comment)?;); + bitfield!(@field_accessor $vis $name $storage, $hi:$lo $field as $= type =3D> $type $(, $comment)?;); }; =20 // Generates the accessor methods for a single field. ( - @leaf_accessor $name:ident $storage:ty, $hi:tt:$lo:tt $field:ident + @leaf_accessor $vis:vis $name:ident $storage:ty, $hi:tt:$lo:tt $fi= eld:ident { $process:expr } $to_type:ty =3D> $res_type:ty $(, $comment:l= iteral)?; ) =3D> { ::kernel::macros::paste!( @@ -267,7 +276,7 @@ impl $name { #[doc=3D$comment] )? #[inline(always)] - pub(crate) fn $field(self) -> $res_type { + $vis fn $field(self) -> $res_type { ::kernel::macros::paste!( const MASK: $storage =3D $name::[<$field:upper _MASK>]; const SHIFT: u32 =3D $name::[<$field:upper _SHIFT>]; @@ -283,7 +292,7 @@ pub(crate) fn $field(self) -> $res_type { #[doc=3D$comment] )? #[inline(always)] - pub(crate) fn [](mut self, value: $to_type) -> Self { + $vis fn [](mut self, value: $to_type) -> Self { const MASK: $storage =3D $name::[<$field:upper _MASK>]; const SHIFT: u32 =3D $name::[<$field:upper _SHIFT>]; let value =3D (<$storage>::from(value) << SHIFT) & MASK; diff --git a/drivers/gpu/nova-core/regs/macros.rs b/drivers/gpu/nova-core/r= egs/macros.rs index d34c7f37fb93..6a4f3271beb3 100644 --- a/drivers/gpu/nova-core/regs/macros.rs +++ b/drivers/gpu/nova-core/regs/macros.rs @@ -276,25 +276,25 @@ pub(crate) trait RegisterBase { macro_rules! register { // Creates a register at a fixed offset of the MMIO space. ($name:ident @ $offset:literal $(, $comment:literal)? { $($fields:tt)*= } ) =3D> { - bitfield!(struct $name: u32 $(, $comment)? { $($fields)* } ); + bitfield!(pub(crate) struct $name: u32 $(, $comment)? { $($fields)= * } ); register!(@io_fixed $name @ $offset); }; =20 // Creates an alias register of fixed offset register `alias` with its= own fields. ($name:ident =3D> $alias:ident $(, $comment:literal)? { $($fields:tt)*= } ) =3D> { - bitfield!(struct $name: u32 $(, $comment)? { $($fields)* } ); + bitfield!(pub(crate) struct $name: u32 $(, $comment)? { $($fields)= * } ); register!(@io_fixed $name @ $alias::OFFSET); }; =20 // 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!(struct $name: u32 $(, $comment)? { $($fields)* } ); + bitfield!(pub(crate) struct $name: u32 $(, $comment)? { $($fields)= * } ); register!(@io_relative $name @ $base [ $offset ]); }; =20 // 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!(struct $name: u32 $(, $comment)? { $($fields)* } ); + bitfield!(pub(crate) struct $name: u32 $(, $comment)? { $($fields)= * } ); register!(@io_relative $name @ $base [ $alias::OFFSET ]); }; =20 @@ -305,7 +305,7 @@ macro_rules! register { } ) =3D> { static_assert!(::core::mem::size_of::() <=3D $stride); - bitfield!(struct $name: u32 $(, $comment)? { $($fields)* } ); + bitfield!(pub(crate) struct $name: u32 $(, $comment)? { $($fields)= * } ); register!(@io_array $name @ $offset [ $size ; $stride ]); }; =20 @@ -326,7 +326,7 @@ macro_rules! register { $(, $comment:literal)? { $($fields:tt)* } ) =3D> { static_assert!(::core::mem::size_of::() <=3D $stride); - bitfield!(struct $name: u32 $(, $comment)? { $($fields)* } ); + bitfield!(pub(crate) struct $name: u32 $(, $comment)? { $($fields)= * } ); register!(@io_relative_array $name @ $base [ $offset [ $size ; $st= ride ] ]); }; =20 @@ -348,7 +348,7 @@ macro_rules! register { } ) =3D> { static_assert!($idx < $alias::SIZE); - bitfield!(struct $name: u32 $(, $comment)? { $($fields)* } ); + bitfield!(pub(crate) struct $name: u32 $(, $comment)? { $($fields)= * } ); register!(@io_relative $name @ $base [ $alias::OFFSET + $idx * $al= ias::STRIDE ] ); }; =20 @@ -357,7 +357,7 @@ macro_rules! register { // 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!(struct $name: u32 $(, $comment)? { $($fields)* } ); + bitfield!(pub(crate) struct $name: u32 $(, $comment)? { $($fields)= * } ); register!(@io_fixed $name @ $alias::OFFSET + $idx * $alias::STRIDE= ); }; =20 --=20 2.34.1 From nobody Tue Dec 16 21:28:44 2025 Received: from NAM10-BN7-obe.outbound.protection.outlook.com (mail-bn7nam10on2048.outbound.protection.outlook.com [40.107.92.48]) (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 CFFE225B695 for ; Tue, 9 Sep 2025 21:21:06 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=40.107.92.48 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1757452869; cv=fail; b=lW1UbrCzd4ENwhEOWtJc3PqAn6FvD01FBA8btDrPSpxZw9B0GUFQdTTkYwKsLpyIkzGiCu+7EZnu+jnKwVpn8OLB01m5MNSx/4vuQ6mEhO9FaNDxLIVx+OOHnUFzJnADLKyYY0YELQsd19v7nlmfMFCAxboGA2uJSS3dZbVj1zM= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1757452869; c=relaxed/simple; bh=oe3AEfdKTNyGiya58S9E1UB0JCM7WdiTvC9/m3VPpAY=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: Content-Type:MIME-Version; b=KVeZQGg0rumKQFT2fSZ+DP3Z1FHex19sA7rtWNlsvHuQCOYKm8/vRXHHMDGzcFUUIm2ePpseop5ZOCNwB5g/mqotS6jpNIrOAZKGMrRxe1q3TonwoZoQ65YevNPJFn9zAS/SGV6JR5KapgNr5gpCRgPWFno5m0MIB7B3alLqcKI= 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=Mmd/1fFq; arc=fail smtp.client-ip=40.107.92.48 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="Mmd/1fFq" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=rh0OiA/Nsvru58TEIZjFiJw9ilGw2UXIpM7j1OVxsbvgRG/OjBipARLQOVQOVSLhL/Vbr2oVETifeVxu+Je/QHnHx+T0v7rv4iAzEcfjsGGeUPkAsN9Mx7F1pm11jG0rozByJcSdfDJPKCwYmlnKrIBgkvwHIusLQQo2sCmEBwgb51vqiKAkzK0g3pSfq5NzpeCCrr55k/j+QPuXoBFnM7ygSyQp3AUCGSRng/X8G9Aog0Mb3xS/aSPPc0Q2nKjTqMqhjlkYUs48+OWmVmfBTbtLe/VB4qCJoRpVodske5mrhnrLQnOqLgTDR48xhN9WcR9yHxfTGWiepCpMtXOp2g== 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=vB/0m+dC+kJDCLBn5gX+R4R0eoiOjIzPaz0uX11EHQw=; b=FHGauCtvBv2K8pIrqwBV97k4pstBFLzR+g/9SPj6gsOdb1xccoz7bNCxDcSIZP4SXyymKdZN9X90+NEBUbuD87u9j7Go4PtAUHzarQpM+PiALkdEMLJPArK5xVfTQOIauIKSuRXzWD1jcnhOqY8iSrs0M6cdKTsondFG2Ir3JFEUSMh8OQEtFdiYHtgiQP93T95GwIwRE3FK//gwRZ5ZuW56upHwL03dOtTXxmcSrcC6SOqTXwY29tlw8LtnkHL61JtqlIzXnNIy4ug3uBKypektqrE9A17exzs0Wt0UMAV7LWVvtCOvGbIpYjHSG/OJBRrr2lRez6MEngjgW8PBsw== 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=vB/0m+dC+kJDCLBn5gX+R4R0eoiOjIzPaz0uX11EHQw=; b=Mmd/1fFqp0QQ0+q8k+l/7s4iodikNmeeoASsCI53lovyOb1p+XUcBbhjqmyic3OhXvcxRcKMz5UaWFJyJPMowIu7zJ9E9H1K9aH5nUXoj9gwI4zkKIGa8W+FacHZrhipX1gpBErtjTcavmUl4CkpivILf3pu0lJOv/IDLm20XANSQYAPdQuuLJAEdeW/jnsYJ4m/mUMdLc795oVfdKHFXHzVYqD4pPOTRhOfjOAHFnZp5XdaJw5z8gwkz76EPM5PUu80+oAmogCiXkTw0AmtAiAaTPwoZzHmiAi1HL35cQzDSGGV3NHxWum3xdVFu0i5pLolJUJRe7wxc/Km6N/vog== Authentication-Results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=nvidia.com; Received: from DS0PR12MB8044.namprd12.prod.outlook.com (2603:10b6:8:148::14) by MN0PR12MB6031.namprd12.prod.outlook.com (2603:10b6:208:3cd::7) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.9094.22; Tue, 9 Sep 2025 21:20:57 +0000 Received: from DS0PR12MB8044.namprd12.prod.outlook.com ([fe80::49af:9ef0:2373:1515]) by DS0PR12MB8044.namprd12.prod.outlook.com ([fe80::49af:9ef0:2373:1515%6]) with mapi id 15.20.9094.021; Tue, 9 Sep 2025 21:20:56 +0000 From: Joel Fernandes To: linux-kernel@vger.kernel.org, dri-devel@lists.freedesktop.org, dakr@kernel.org, acourbot@nvidia.com Cc: Alistair Popple , Miguel Ojeda , Alex Gaynor , Boqun Feng , Gary Guo , bjorn3_gh@protonmail.com, Benno Lossin , Andreas Hindborg , Alice Ryhl , Trevor Gross , David Airlie , Simona Vetter , Maarten Lankhorst , Maxime Ripard , Thomas Zimmermann , John Hubbard , Joel Fernandes , Timur Tabi , joel@joelfernandes.org, Elle Rhumsaa , Yury Norov , Daniel Almeida , nouveau@lists.freedesktop.org Subject: [PATCH v3 4/5] rust: Move register and bitfield macros out of Nova Date: Tue, 9 Sep 2025 17:20:38 -0400 Message-Id: <20250909212039.227221-5-joelagnelf@nvidia.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20250909212039.227221-1-joelagnelf@nvidia.com> References: <20250909212039.227221-1-joelagnelf@nvidia.com> Content-Transfer-Encoding: quoted-printable X-ClientProxiedBy: MN0P221CA0011.NAMP221.PROD.OUTLOOK.COM (2603:10b6:208:52a::8) To DS0PR12MB8044.namprd12.prod.outlook.com (2603:10b6:8:148::14) 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: DS0PR12MB8044:EE_|MN0PR12MB6031:EE_ X-MS-Office365-Filtering-Correlation-Id: 95d36632-35f7-49a8-2c24-08ddefe6c3f1 X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|1800799024|366016|376014|7416014; X-Microsoft-Antispam-Message-Info: =?us-ascii?Q?atyHYDPmx5c0MsYYyreeRQ6HtWnJhIjGGWx7MZ4vXWnbrjD3UbRqh6PM9Xc+?= =?us-ascii?Q?PA6vGtxLjeJJ+rzn0HSnhutr+FIXj+Ey75+fytmdxLq/Ukj8WHwJye6W6UxS?= =?us-ascii?Q?Fa8f3mixOT2eput+Lrymiy2yzLLGJrz891Tv3Q1a+6T34N55MEc54uJMrnDJ?= =?us-ascii?Q?Rr6OhcXZSGM3WFICzdHH9gebRgMDQAHnDdA8fvpcUX+CAwaQ+m0mHb4tKRo9?= =?us-ascii?Q?8kILyMr2mysrVAO66k3CqajFXjvjyYHDESmGM2mZcsYpqTqD7NaK24zVIeXn?= =?us-ascii?Q?IqSb6H9ZXYqsV+ExWpdsFbQDdTYPVPfVc5UjXPuapPNToWICl82oCxETXbcj?= =?us-ascii?Q?oAp2rd9dl1JkfV9wV+zN85/IMAH16qUtjSQtH91oq/jhxYz/8l40BsJ5fwNE?= =?us-ascii?Q?WDAT5qNRaWvnOVAuNatyrBhKNzdR55CoZv2JYft1JFBZPrWjIGdTBo2Io3G7?= =?us-ascii?Q?FTsGryjplwG2Rb+Icnz+HFASKnTNqvHL1Q8JKriB8JaU377dvhzRC1jfgz/e?= =?us-ascii?Q?3EPzHTU44Knrv8SGXT3Ra5ZTPJmE8oyZrqXYZcS6NADcp2wdUMg1KbCQbsoM?= =?us-ascii?Q?srOXSMnW+gtw00io62yTUtUrDMuvqWnnhhVjsXphXZDXza6Ts3FdSPbdT3TF?= =?us-ascii?Q?EuiY6Dd6eKK4BLaAxunNd4ZBmQmREvmjzqKMLUhNj5g+ltUqK5bPItPx/9ta?= =?us-ascii?Q?Ohi3wixAcuDj3KETw0caMjxZ14MrEYqs70Mf+zsvF1JvHFNPwAhDlptPdJEE?= =?us-ascii?Q?H19nJfF+vNxbd8VP+N8fceuGVHGg2MOzQOd7MXB8OS8fkYrmYYK9KUqAxdv+?= =?us-ascii?Q?06qTrVJaiy4gzeq8bavbKijG7dv2e6BqiP/lZMaF8Jctlng8yi1UtCIgJijx?= =?us-ascii?Q?UDcT3o0Er8RVH1k656RBE3N0wggwJQutCvN3nwui95lejuKATMuEoNZisSID?= =?us-ascii?Q?mDxhvBPhY4gzucGI1VqRjnCxAOyiHXxYMlq7zxzHPlZBFipJs2Ys8XREl/1v?= =?us-ascii?Q?cTqsjCq1vgEmZy0JpAKKbkB2TSD92NN/1d7tpSIGcslgVrre930RDYaclbR8?= =?us-ascii?Q?Z5/i9CC+ym5o/9yUG7fV0cz3rrbi6lUPwBaxJLda+eL2DZsrAhBbfyfCHqyM?= =?us-ascii?Q?ZtNkHPbc34gl4PCWoLA6Il1WFd0vkpEMq4OOWejFml9jSqJzZE3zGowJg6as?= =?us-ascii?Q?W8J5YdKy2V/aknxhGoXjUoPOj47AJL5Agq8OVQF9HaTyDGx25pPXVGvKru9m?= =?us-ascii?Q?BBw/WLeL8hlbT0CXGi90KF2eknxovAxWBctPJF2JclA6D/evfboqMujGy+a5?= =?us-ascii?Q?73coDxp5cFF0oXA7BIRX2D4yBmzUx+Mn0/82l4f9iliRJI5s6m8x3fff7VEn?= =?us-ascii?Q?jrRXuxEELaHrE7eM77uCzmyAaLexkl4VYfMfGIz04UL+6ghYZmzupq/5jGDj?= =?us-ascii?Q?szb0LGuOxL0=3D?= X-Forefront-Antispam-Report: CIP:255.255.255.255;CTRY:;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:DS0PR12MB8044.namprd12.prod.outlook.com;PTR:;CAT:NONE;SFS:(13230040)(1800799024)(366016)(376014)(7416014);DIR:OUT;SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: =?us-ascii?Q?m432szmTzqhSuk3qfovH/OrFx3Wma81EDBYBYuW8QnbeOw0OfqgK2og6FxLm?= =?us-ascii?Q?TgwycRHgkXTWSdne047A1b5dMWno69y4SfYlPJ6ZDh0YabRhzCF0oh+hzM9D?= =?us-ascii?Q?L3I7O0v3eyIXdv1kgHTMkCFBjRyKSiIy1oFvL1EpUS2PpBJM3Fq6nBAROHRz?= =?us-ascii?Q?Bxy253/SQacJtaU8dJXV46OOupKd8sDWxzu+uYYjLX8lA954YwD8SmBb7YqV?= =?us-ascii?Q?3myNgXhvDC3aZlFfEr5/uE+lM5BcVEOdP41148dOg5al6oRLVyBTJGefurK6?= =?us-ascii?Q?J1ODg8nSkHJ4nuqJsVHsO12NhYyHGZ/TE/qZHpbMqrP9ANYE2cC37mZPfI/t?= =?us-ascii?Q?uTmHe5J7KD9Wek8fA7UXSv+yc2BjALYbEVs4NHB/3JpxoLg23qPLvnmNMRvH?= =?us-ascii?Q?sDwZIk1/C0N4waySY+3oVrz18MUrfGIZ4aEmkFQWy8sQuDAfuIRO0L52fDpT?= =?us-ascii?Q?lU2g7S+QOip875K1jr2mfvIazn900w6EMeXgpz7IZFODGsVzHBVfAlcF4zhF?= =?us-ascii?Q?5lA65daMtlbpmEhGK/d18Ov6LGIQBBbgpec7n1AOX3IFf3FdQNhulqJvzwDz?= =?us-ascii?Q?o8DucNJg4lp/sVKTXskCWeK303xNFgNpY26yGNaDxehe0Vd5iU33ALz3QIAx?= =?us-ascii?Q?kK/j4v8IbwEP6u05yDzi51jMWSvd6oBDIKGMEEirWgrjma4EPaQ2UTurblgx?= =?us-ascii?Q?HTkHYzRA5QKEdmv1hyKmyV5sOzjAMmoDaOchvQAZ1zkiG8F9nViRZJmE9l0G?= =?us-ascii?Q?pasKrqiBZpJ327D4Uju++mK681qWy2ye1wKbaemb9FlyehqZS7+qArohFGmZ?= =?us-ascii?Q?u0NDLxzGhb2X/bVAO3RtxpTXorg+ojAsn+2aYcwizlcK1iMAms69N4WScApQ?= =?us-ascii?Q?YrUuALV6V86huEHDVICsjifTgtreOg0aE5x2n9CAEEowWQJ9NprssDQL8VGL?= =?us-ascii?Q?M9CAdrVgEup0kT+5VTHHzXgFEeWxNnihgOXyEOE2qrNKnv2ZzQXsuMYKYLDO?= =?us-ascii?Q?pgieAp0oHRV5SHAE2DauQ96m0ONq5MIP2WP771cW23Qbv3CDQWynCmghSv6w?= =?us-ascii?Q?9j8K4O8NbnKxch3Dls4OaLTcFA8DeAOEIaKLBQHnyOAprT6qDWyu23kASdJR?= =?us-ascii?Q?2WFfzbOjp0FRebpHlOWec0DxsQklraRx2JCa8vg4xqIuMa04Ctx5Diqp9FKQ?= =?us-ascii?Q?cFGiH3N9ACNFTzQMh5jkcAtlSqmNAA4s1I4ffW728ewH+EjEgNylTOoZyOyf?= =?us-ascii?Q?DuUV8t1MdrcStQutro56lZyd1AhYn6rTLUxrOR5l8UPYzkgehnAFOZBEjy8B?= =?us-ascii?Q?JMURTBqRKOROvXlmANmMG9W8xMe3rhntTtzXajj+j1A5pE76xD0+7T1wBMyh?= =?us-ascii?Q?Z+BCr9XN9fn4ARl4bGNYIcZBPW4LHqV0jjd8+LcyPEEfpmBc8WQzQOIlVU72?= =?us-ascii?Q?Yt/C5SJo2fKYsHPy1OqA7J24Nl914Q0b/So6Rzg7sZvLlE1pS/ziNssWFeAR?= =?us-ascii?Q?sH+6tdAB9c+TKaA4SDAspQJ2EyiRaUxogDmYSJHcUmB+dppMYE92I3uE4L5b?= =?us-ascii?Q?Gz0Vi9aOeA9GLYs1gt+G455Q0MCEGivp7HsXSQFi?= X-OriginatorOrg: Nvidia.com X-MS-Exchange-CrossTenant-Network-Message-Id: 95d36632-35f7-49a8-2c24-08ddefe6c3f1 X-MS-Exchange-CrossTenant-AuthSource: DS0PR12MB8044.namprd12.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 09 Sep 2025 21:20:56.7733 (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: aulbIjhxZoI8Mu0rN/cf+qcMSgUpgjN82ROYbxfJXI4SD12rW1BSAIwldnUpPsN2B9Q4UJ6J5iUK5BWLIb+E5g== X-MS-Exchange-Transport-CrossTenantHeadersStamped: MN0PR12MB6031 Content-Type: text/plain; charset="utf-8" Out of broad need for these macros in Rust, move them out. Several folks have shown interest (Nova, Tyr GPU drivers). bitfield moved into bits modules - defines bitfields in Rust structs simila= r to C. register moved into io module - defines hardware registers and accessors. [Added F: record to MAINTAINERS file entry as suggested by Yury.] Reviewed-by: Elle Rhumsaa Signed-off-by: Joel Fernandes --- MAINTAINERS | 1 + drivers/gpu/nova-core/falcon.rs | 2 +- drivers/gpu/nova-core/falcon/gsp.rs | 3 +- drivers/gpu/nova-core/falcon/sec2.rs | 2 +- drivers/gpu/nova-core/nova_core.rs | 3 -- drivers/gpu/nova-core/regs.rs | 6 +-- rust/kernel/bits.rs | 2 + .../kernel/bits}/bitfield.rs | 27 ++++++----- rust/kernel/io.rs | 1 + .../macros.rs =3D> rust/kernel/io/register.rs | 46 ++++++++++--------- 10 files changed, 50 insertions(+), 43 deletions(-) rename {drivers/gpu/nova-core =3D> rust/kernel/bits}/bitfield.rs (91%) rename drivers/gpu/nova-core/regs/macros.rs =3D> rust/kernel/io/register.r= s (93%) diff --git a/MAINTAINERS b/MAINTAINERS index b97760467f09..ca9132fa4055 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -4313,6 +4313,7 @@ F: include/asm-generic/bitops.h F: include/linux/bitops.h F: lib/test_bitops.c F: tools/*/bitops* +F: rust/kernel/bits* =20 BLINKM RGB LED DRIVER M: Jan-Simon Moeller diff --git a/drivers/gpu/nova-core/falcon.rs b/drivers/gpu/nova-core/falcon= .rs index 938f25b556a8..55f03f435138 100644 --- a/drivers/gpu/nova-core/falcon.rs +++ b/drivers/gpu/nova-core/falcon.rs @@ -6,6 +6,7 @@ use hal::FalconHal; use kernel::device; use kernel::dma::DmaAddress; +use kernel::io::register::RegisterBase; use kernel::prelude::*; use kernel::sync::aref::ARef; use kernel::time::Delta; @@ -14,7 +15,6 @@ use crate::driver::Bar0; use crate::gpu::Chipset; use crate::regs; -use crate::regs::macros::RegisterBase; use crate::util; =20 pub(crate) mod gsp; diff --git a/drivers/gpu/nova-core/falcon/gsp.rs b/drivers/gpu/nova-core/fa= lcon/gsp.rs index c9ab375fd8a1..04920a619246 100644 --- a/drivers/gpu/nova-core/falcon/gsp.rs +++ b/drivers/gpu/nova-core/falcon/gsp.rs @@ -1,12 +1,13 @@ // SPDX-License-Identifier: GPL-2.0 =20 +use kernel::io::register::RegisterBase; use kernel::prelude::*; use kernel::time::Delta; =20 use crate::{ driver::Bar0, falcon::{Falcon, FalconEngine, PFalcon2Base, PFalconBase}, - regs::{self, macros::RegisterBase}, + regs, util::wait_on, }; =20 diff --git a/drivers/gpu/nova-core/falcon/sec2.rs b/drivers/gpu/nova-core/f= alcon/sec2.rs index 815786c8480d..81717868a8a8 100644 --- a/drivers/gpu/nova-core/falcon/sec2.rs +++ b/drivers/gpu/nova-core/falcon/sec2.rs @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 =20 use crate::falcon::{FalconEngine, PFalcon2Base, PFalconBase}; -use crate::regs::macros::RegisterBase; +use kernel::io::register::RegisterBase; =20 /// Type specifying the `Sec2` falcon engine. Cannot be instantiated. pub(crate) struct Sec2(()); diff --git a/drivers/gpu/nova-core/nova_core.rs b/drivers/gpu/nova-core/nov= a_core.rs index eaba6ad22f7a..4dbc7e5daae3 100644 --- a/drivers/gpu/nova-core/nova_core.rs +++ b/drivers/gpu/nova-core/nova_core.rs @@ -2,9 +2,6 @@ =20 //! Nova Core GPU Driver =20 -#[macro_use] -mod bitfield; - mod dma; mod driver; mod falcon; diff --git a/drivers/gpu/nova-core/regs.rs b/drivers/gpu/nova-core/regs.rs index c214f8056d6e..07533eb6f64e 100644 --- a/drivers/gpu/nova-core/regs.rs +++ b/drivers/gpu/nova-core/regs.rs @@ -4,15 +4,13 @@ // but are mapped to types. #![allow(non_camel_case_types)] =20 -#[macro_use] -pub(crate) mod macros; - use crate::falcon::{ DmaTrfCmdSize, FalconCoreRev, FalconCoreRevSubversion, FalconFbifMemTy= pe, FalconFbifTarget, FalconModSelAlgo, FalconSecurityModel, PFalcon2Base, PFalconBase, Pere= grineCoreSelect, }; use crate::gpu::{Architecture, Chipset}; use kernel::prelude::*; +use kernel::register; =20 // PMC =20 @@ -352,6 +350,7 @@ pub(crate) fn mem_scrubbing_done(self) -> bool { =20 pub(crate) mod gm107 { // FUSE + use kernel::register; =20 register!(NV_FUSE_STATUS_OPT_DISPLAY @ 0x00021c04 { 0:0 display_disabled as bool; @@ -360,6 +359,7 @@ pub(crate) mod gm107 { =20 pub(crate) mod ga100 { // FUSE + use kernel::register; =20 register!(NV_FUSE_STATUS_OPT_DISPLAY @ 0x00820c04 { 0:0 display_disabled as bool; diff --git a/rust/kernel/bits.rs b/rust/kernel/bits.rs index 553d50265883..590a77d99ad7 100644 --- a/rust/kernel/bits.rs +++ b/rust/kernel/bits.rs @@ -201,3 +201,5 @@ pub const fn [](range: RangeInclusive) -> $ty { /// assert_eq!(genmask_u8(0..=3D7), u8::MAX); /// ``` ); + +pub mod bitfield; diff --git a/drivers/gpu/nova-core/bitfield.rs b/rust/kernel/bits/bitfield.= rs similarity index 91% rename from drivers/gpu/nova-core/bitfield.rs rename to rust/kernel/bits/bitfield.rs index 39354e60360c..0837fefc270f 100644 --- a/drivers/gpu/nova-core/bitfield.rs +++ b/rust/kernel/bits/bitfield.rs @@ -78,10 +78,13 @@ //! - `as ?=3D> ` calls ``'s `TryFrom= ::<>` implementation //! and returns the result. This is useful with fields for which not all= values are valid. //! + +/// bitfield macro definition +#[macro_export] macro_rules! bitfield { // Main entry point - defines the bitfield struct with fields ($vis:vis struct $name:ident : $storage:ty $(, $comment:literal)? { $(= $fields:tt)* }) =3D> { - bitfield!(@core $vis $name $storage $(, $comment)? { $($fields)* }= ); + ::kernel::bitfield!(@core $vis $name $storage $(, $comment)? { $($= fields)* }); }; =20 // All rules below are helpers. @@ -116,7 +119,7 @@ fn from(val: $storage) -> Self { } } =20 - bitfield!(@fields_dispatcher $vis $name $storage { $($fields)* }); + ::kernel::bitfield!(@fields_dispatcher $vis $name $storage { $($fi= elds)* }); }; =20 // Captures the fields and passes them to all the implementers that re= quire field information. @@ -132,7 +135,7 @@ fn from(val: $storage) -> Self { )* } ) =3D> { - bitfield!(@field_accessors $vis $name $storage { + ::kernel::bitfield!(@field_accessors $vis $name $storage { $( $hi:$lo $field as $type $(?=3D> $try_into_type)? @@ -141,8 +144,8 @@ fn from(val: $storage) -> Self { ; )* }); - bitfield!(@debug $name { $($field;)* }); - bitfield!(@default $name { $($field;)* }); + ::kernel::bitfield!(@debug $name { $($field;)* }); + ::kernel::bitfield!(@default $name { $($field;)* }); }; =20 // Defines all the field getter/setter methods for `$name`. @@ -157,7 +160,7 @@ fn from(val: $storage) -> Self { } ) =3D> { $( - bitfield!(@check_field_bounds $hi:$lo $field as $type); + ::kernel::bitfield!(@check_field_bounds $hi:$lo $field as $typ= e); )* =20 #[allow(dead_code)] @@ -169,7 +172,7 @@ impl $name { } =20 $( - bitfield!(@field_accessor $vis $name $storage, $hi:$lo $field = as $type + ::kernel::bitfield!(@field_accessor $vis $name $storage, $hi:$= lo $field as $type $(?=3D> $try_into_type)? $(=3D> $into_type)? $(, $comment)? @@ -206,7 +209,7 @@ impl $name { @field_accessor $vis:vis $name:ident $storage:ty, $hi:tt:$lo:tt $f= ield:ident as bool =3D> $into_type:ty $(, $comment:literal)?; ) =3D> { - bitfield!( + ::kernel::bitfield!( @leaf_accessor $vis $name $storage, $hi:$lo $field { |f| <$into_type>::from(if f !=3D 0 { true } else { false }) } $into_type =3D> $into_type $(, $comment)?; @@ -217,7 +220,7 @@ impl $name { ( @field_accessor $vis:vis $name:ident $storage:ty, $hi:tt:$lo:tt $f= ield:ident as bool $(, $comment:literal)?; ) =3D> { - bitfield!(@field_accessor $vis $name $storage, $hi:$lo $field as b= ool =3D> bool $(, $comment)?;); + ::kernel::bitfield!(@field_accessor $vis $name $storage, $hi:$lo $= field as bool =3D> bool $(, $comment)?;); }; =20 // Catches the `?=3D>` syntax for non-boolean fields. @@ -225,7 +228,7 @@ impl $name { @field_accessor $vis:vis $name:ident $storage:ty, $hi:tt:$lo:tt $f= ield:ident as $type:tt ?=3D> $try_into_type:ty $(, $comment:literal)?; ) =3D> { - bitfield!(@leaf_accessor $vis $name $storage, $hi:$lo $field + ::kernel::bitfield!(@leaf_accessor $vis $name $storage, $hi:$lo $f= ield { |f| <$try_into_type>::try_from(f as $type) } $try_into_type = =3D> ::core::result::Result< $try_into_type, @@ -239,7 +242,7 @@ impl $name { @field_accessor $vis:vis $name:ident $storage:ty, $hi:tt:$lo:tt $f= ield:ident as $type:tt =3D> $into_type:ty $(, $comment:literal)?; ) =3D> { - bitfield!(@leaf_accessor $vis $name $storage, $hi:$lo $field + ::kernel::bitfield!(@leaf_accessor $vis $name $storage, $hi:$lo $f= ield { |f| <$into_type>::from(f as $type) } $into_type =3D> $into_t= ype $(, $comment)?;); }; =20 @@ -248,7 +251,7 @@ impl $name { @field_accessor $vis:vis $name:ident $storage:ty, $hi:tt:$lo:tt $f= ield:ident as $type:tt $(, $comment:literal)?; ) =3D> { - bitfield!(@field_accessor $vis $name $storage, $hi:$lo $field as $= type =3D> $type $(, $comment)?;); + ::kernel::bitfield!(@field_accessor $vis $name $storage, $hi:$lo $= field as $type =3D> $type $(, $comment)?;); }; =20 // Generates the accessor methods for a single field. diff --git a/rust/kernel/io.rs b/rust/kernel/io.rs index 03b467722b86..a79b603604b1 100644 --- a/rust/kernel/io.rs +++ b/rust/kernel/io.rs @@ -8,6 +8,7 @@ use crate::{bindings, build_assert, ffi::c_void}; =20 pub mod mem; +pub mod register; pub mod resource; =20 pub use resource::Resource; diff --git a/drivers/gpu/nova-core/regs/macros.rs b/rust/kernel/io/register= .rs similarity index 93% rename from drivers/gpu/nova-core/regs/macros.rs rename to rust/kernel/io/register.rs index 6a4f3271beb3..088a8590db92 100644 --- a/drivers/gpu/nova-core/regs/macros.rs +++ b/rust/kernel/io/register.rs @@ -17,7 +17,8 @@ /// 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 { +pub trait RegisterBase { + /// The base address for the register. const BASE: usize; } =20 @@ -273,28 +274,29 @@ pub(crate) trait RegisterBase { /// # Ok(()) /// # } /// ``` +#[macro_export] 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)= * } ); + ::kernel::bitfield!(pub(crate) struct $name: u32 $(, $comment)? { = $($fields)* } ); register!(@io_fixed $name @ $offset); }; =20 // 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)= * } ); + ::kernel::bitfield!(pub(crate) struct $name: u32 $(, $comment)? { = $($fields)* } ); register!(@io_fixed $name @ $alias::OFFSET); }; =20 // 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)= * } ); + ::kernel::bitfield!(pub(crate) struct $name: u32 $(, $comment)? { = $($fields)* } ); register!(@io_relative $name @ $base [ $offset ]); }; =20 // 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)= * } ); + ::kernel::bitfield!(pub(crate) struct $name: u32 $(, $comment)? { = $($fields)* } ); register!(@io_relative $name @ $base [ $alias::OFFSET ]); }; =20 @@ -305,7 +307,7 @@ macro_rules! register { } ) =3D> { static_assert!(::core::mem::size_of::() <=3D $stride); - bitfield!(pub(crate) struct $name: u32 $(, $comment)? { $($fields)= * } ); + ::kernel::bitfield!(pub(crate) struct $name: u32 $(, $comment)? { = $($fields)* } ); register!(@io_array $name @ $offset [ $size ; $stride ]); }; =20 @@ -326,7 +328,7 @@ macro_rules! register { $(, $comment:literal)? { $($fields:tt)* } ) =3D> { static_assert!(::core::mem::size_of::() <=3D $stride); - bitfield!(pub(crate) struct $name: u32 $(, $comment)? { $($fields)= * } ); + ::kernel::bitfield!(pub(crate) struct $name: u32 $(, $comment)? { = $($fields)* } ); register!(@io_relative_array $name @ $base [ $offset [ $size ; $st= ride ] ]); }; =20 @@ -348,7 +350,7 @@ macro_rules! register { } ) =3D> { static_assert!($idx < $alias::SIZE); - bitfield!(pub(crate) struct $name: u32 $(, $comment)? { $($fields)= * } ); + ::kernel::bitfield!(pub(crate) struct $name: u32 $(, $comment)? { = $($fields)* } ); register!(@io_relative $name @ $base [ $alias::OFFSET + $idx * $al= ias::STRIDE ] ); }; =20 @@ -357,7 +359,7 @@ macro_rules! register { // 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)= * } ); + ::kernel::bitfield!(pub(crate) struct $name: u32 $(, $comment)? { = $($fields)* } ); register!(@io_fixed $name @ $alias::OFFSET + $idx * $alias::STRIDE= ); }; =20 @@ -414,12 +416,12 @@ pub(crate) fn read( base: &B, ) -> Self where T: ::core::ops::Deref>, - B: crate::regs::macros::RegisterBase<$base>, + B: ::kernel::io::register::RegisterBase<$base>, { const OFFSET: usize =3D $name::OFFSET; =20 let value =3D io.read32( - >::BASE = + OFFSET + >::BA= SE + OFFSET ); =20 Self(value) @@ -435,13 +437,13 @@ pub(crate) fn write( base: &B, ) where T: ::core::ops::Deref>, - B: crate::regs::macros::RegisterBase<$base>, + B: ::kernel::io::register::RegisterBase<$base>, { const OFFSET: usize =3D $name::OFFSET; =20 io.write32( self.0, - >::BASE = + OFFSET + >::BA= SE + OFFSET ); } =20 @@ -455,7 +457,7 @@ pub(crate) fn alter( f: F, ) where T: ::core::ops::Deref>, - B: crate::regs::macros::RegisterBase<$base>, + B: ::kernel::io::register::RegisterBase<$base>, F: ::core::ops::FnOnce(Self) -> Self, { let reg =3D f(Self::read(io, base)); @@ -600,11 +602,11 @@ pub(crate) fn read( idx: usize, ) -> Self where T: ::core::ops::Deref>, - B: crate::regs::macros::RegisterBase<$base>, + B: ::kernel::io::register::RegisterBase<$base>, { build_assert!(idx < Self::SIZE); =20 - let offset =3D >::BASE + + let offset =3D >::BASE + Self::OFFSET + (idx * Self::STRIDE); let value =3D io.read32(offset); =20 @@ -622,11 +624,11 @@ pub(crate) fn write( idx: usize ) where T: ::core::ops::Deref>, - B: crate::regs::macros::RegisterBase<$base>, + B: ::kernel::io::register::RegisterBase<$base>, { build_assert!(idx < Self::SIZE); =20 - let offset =3D >::BASE + + let offset =3D >::BASE + Self::OFFSET + (idx * Self::STRIDE); =20 io.write32(self.0, offset); @@ -643,7 +645,7 @@ pub(crate) fn alter( f: F, ) where T: ::core::ops::Deref>, - B: crate::regs::macros::RegisterBase<$base>, + B: ::kernel::io::register::RegisterBase<$base>, F: ::core::ops::FnOnce(Self) -> Self, { let reg =3D f(Self::read(io, base, idx)); @@ -662,7 +664,7 @@ pub(crate) fn try_read( idx: usize, ) -> ::kernel::error::Result where T: ::core::ops::Deref>, - B: crate::regs::macros::RegisterBase<$base>, + B: ::kernel::io::register::RegisterBase<$base>, { if idx < Self::SIZE { Ok(Self::read(io, base, idx)) @@ -684,7 +686,7 @@ pub(crate) fn try_write( idx: usize, ) -> ::kernel::error::Result where T: ::core::ops::Deref>, - B: crate::regs::macros::RegisterBase<$base>, + B: ::kernel::io::register::RegisterBase<$base>, { if idx < Self::SIZE { Ok(self.write(io, base, idx)) @@ -707,7 +709,7 @@ pub(crate) fn try_alter( f: F, ) -> ::kernel::error::Result where T: ::core::ops::Deref>, - B: crate::regs::macros::RegisterBase<$base>, + B: ::kernel::io::register::RegisterBase<$base>, F: ::core::ops::FnOnce(Self) -> Self, { if idx < Self::SIZE { --=20 2.34.1 From nobody Tue Dec 16 21:28:44 2025 Received: from NAM10-BN7-obe.outbound.protection.outlook.com (mail-bn7nam10on2048.outbound.protection.outlook.com [40.107.92.48]) (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 BECB925D536 for ; Tue, 9 Sep 2025 21:21:09 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=40.107.92.48 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1757452871; cv=fail; b=sEK47RGowaEhpfZIvxQIH1wA9B/onUipSI340GRqQvezQwNcOWT8btWtcbPNsvzbKc4CGXzwc2V0tk0+Gm5dlUkVTXw8U7H0YwkhquHTsDy5Iefg3jzLqUEK0sxU4eAFo1xxk3hhIpeoQ29+SYqf6Yg/ySht4p44Gxd0w21gNfg= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1757452871; c=relaxed/simple; bh=cByVda2zcYdTjbLDBjGa8u9H84ktS5Ky+jdVgpbF9PU=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: Content-Type:MIME-Version; b=c32mmvcP7H3xkgj6Uirk8foZ9PHk5GREpBKo+maLy5GsAJ5eSAQfKvUSVaeZfDO0nEbEBKj8zZthV8N6j0tQiPKhHZcR5fFxVGIzpZhgLt1faM7nIAJebPuNCvoxYQF/OvmGTtgMX7RgdKXd8SGzVOb+Ly2Dz/Bde4nmvlT0Ov0= 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=CWL+mVCL; arc=fail smtp.client-ip=40.107.92.48 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="CWL+mVCL" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=y2UmbHt6SOE9UlRWdrcg/PYDMHPtWPSIITEEqdPTkGwfY8RHJUCfYUMO9I29o+oOxScxeccEnLAFKdAn/6g4w4fBIiCDjxj/x3YKevwVo6frBJJjwO0jLw3LivUcd+PJYNZ0KhfYphuYmiaZ3RI/8t873v7ZtXsxWULnTk40GHFFgSvGXB0tMVSIuHfIjpCrUGb560C2NudvvFI53Ogo0KuAzKIwWRkJ9mbxwLpdLs1Vwry+LPoBcHVpI+vbRkaj7oNP+hL0+rYcxt1pO94fnYjJ8XLMzkJi84plZ1qqtm0HlPn73tEpKSjb55UyiZfIG7XvgWUdOkxgHNPCOnM28w== 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=dygLGICj0TKOZ542+yk7yMFeePqPVbCHPBwzVmwQXWk=; b=G5gPT63DLf6amzW54DzwDRXj7Gri5N6ttD6k0BRCZ6jwDR6sA/BY7X9ivQkjfQNA1TwokM2UDd8J9BlpH3/zIG5xq1XgQzG6vJqIRHmQMuzkG4ECfPexQIqM+N3p/FsHTw19hE+JHWCgeCuNZSdCjrAVqgiS46YTXixIGBAftPeDQ61h1D766sfyHlat95HVUe1ww0jNL6aGFNIHIbukIRMsqHNIY6Rm0mWAhwESwmU9GLH6WMkX7b0aGXNyj4G14P5PK6Yc+Iz7mEUAT2dD7rUDAEl/v7saqGqPqpnlUvkfqrq9vhQ6z39mFdgVYuFZNoZ7kUtk/LUCf1Z3EiFqnA== 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=dygLGICj0TKOZ542+yk7yMFeePqPVbCHPBwzVmwQXWk=; b=CWL+mVCL5pqFdHycdiNNdCrPk9rYUIv38KrXJ0/HRYT4eRhuc53TVUA3H5TQj9IML7o9vMiHXMh2BM6gF+LRwoggtwQcK4XpPYAluyuHlV44a6251l95VmhXhEWMk3Kg8S/+gDNXsMjFKN6DR77CLVJBpm8Nis10CBZEiMYsSgUfy3YIe8RRN0zcbuUVl/dRzzyqgrGb9pJE+zRULQsAIwDrtbTGyVDqhskuzsWqfpK28AhOc5hB+5M3FkDjC0mesHNm58ZNTqBz8jKJGlqAass08eJYZwSUzCo+HBi17RKPtRznpmSz4QgnfD0TG+qh4T1TZ6ia1jT/52RyjAUL3Q== Authentication-Results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=nvidia.com; Received: from DS0PR12MB8044.namprd12.prod.outlook.com (2603:10b6:8:148::14) by MN0PR12MB6031.namprd12.prod.outlook.com (2603:10b6:208:3cd::7) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.9094.22; Tue, 9 Sep 2025 21:20:58 +0000 Received: from DS0PR12MB8044.namprd12.prod.outlook.com ([fe80::49af:9ef0:2373:1515]) by DS0PR12MB8044.namprd12.prod.outlook.com ([fe80::49af:9ef0:2373:1515%6]) with mapi id 15.20.9094.021; Tue, 9 Sep 2025 21:20:58 +0000 From: Joel Fernandes To: linux-kernel@vger.kernel.org, dri-devel@lists.freedesktop.org, dakr@kernel.org, acourbot@nvidia.com Cc: Alistair Popple , Miguel Ojeda , Alex Gaynor , Boqun Feng , Gary Guo , bjorn3_gh@protonmail.com, Benno Lossin , Andreas Hindborg , Alice Ryhl , Trevor Gross , David Airlie , Simona Vetter , Maarten Lankhorst , Maxime Ripard , Thomas Zimmermann , John Hubbard , Joel Fernandes , Timur Tabi , joel@joelfernandes.org, Elle Rhumsaa , Yury Norov , Daniel Almeida , nouveau@lists.freedesktop.org Subject: [PATCH v3 5/5] rust: Add KUNIT tests for bitfield Date: Tue, 9 Sep 2025 17:20:39 -0400 Message-Id: <20250909212039.227221-6-joelagnelf@nvidia.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20250909212039.227221-1-joelagnelf@nvidia.com> References: <20250909212039.227221-1-joelagnelf@nvidia.com> Content-Transfer-Encoding: quoted-printable X-ClientProxiedBy: BL1P223CA0033.NAMP223.PROD.OUTLOOK.COM (2603:10b6:208:5b6::8) To DS0PR12MB8044.namprd12.prod.outlook.com (2603:10b6:8:148::14) 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: DS0PR12MB8044:EE_|MN0PR12MB6031:EE_ X-MS-Office365-Filtering-Correlation-Id: 176406d9-7dc7-4ddd-d668-08ddefe6c4f9 X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|1800799024|366016|376014|7416014; X-Microsoft-Antispam-Message-Info: =?us-ascii?Q?QX7E39w62smhWHMkrEBfrl26fIcpxTJMeulQ2+NsjjWFjwNmgmk4n/j99qqs?= =?us-ascii?Q?p/iAuu8TVZN4RoHPrus1IAkrIxYTe2rTwZJfkUSqVqp0eKtfRulaCoryeZnC?= =?us-ascii?Q?MLyo8L9A6JDpfI4NidmFdUDga0cWg5bwTBNYFU8Dwq7KmULkNYBuSfV3UZ11?= =?us-ascii?Q?tCUsoWF4qOpqPSX0oShxhaqvAgmMqq98PSNAFL2eUK+JQP4dWiwBeHGIREp0?= =?us-ascii?Q?r6G/EfsjCrhSznwY1vMoEa8JckzfAyLZrRpsChL4NazgCAxXvGKbBHKEw6gq?= =?us-ascii?Q?feyZXEJOtX3nTKZdgQ8dCQt4F3TcrIsJo8uvjWa7nmSocoig7lnhnVZu2sNI?= =?us-ascii?Q?QPoZWRF8/q1KRrbI+AlkA5Xlnb4LiwYKyh617ohoxbgPCHElLU3EFJJ54PCa?= =?us-ascii?Q?1sO38YDfZJ/Hqrqfd6IQOb7AiX5mqiIIlMY6QDpOxRLlmckMKcDCm8sTEK6b?= =?us-ascii?Q?DnSKSZb2AEaLYk6mOYfnr8snT4f4oq+lJF/CbXlki+LJavGZbGDevpnhH6J6?= =?us-ascii?Q?tDmIIctbLIPetC5aHU9iEOcDfoJIPxKA01JD+7zJWEOea9IvamwsgN1ZyzBl?= =?us-ascii?Q?Nex0xmi+uFsJ3KOuciKnGyB9U05qJAs1HMaRZHItWcfhAqZJ2k1B1tBN4yF8?= =?us-ascii?Q?iAxov0RWuqqQoIhdtlyZ+ZtB7tCOcIw6FKR6s1OMLbSNcTjMrO/ugCq37p+y?= =?us-ascii?Q?umZj06iD5ZEZ05bUHh+Aci9otjNhZUR4HmhNIs3zegahB2wTMFiW4+1027Yu?= =?us-ascii?Q?6JZhgDo+T4kWErnyZJxZMqqhFeePIeBONVr69PtvA3BrlBU0s20AC4EHywB5?= =?us-ascii?Q?PggdCoztDFQGRoYg4isyU3D4VkOouxfhvkdnqAOZUNfzHkgIz8O2mTvLp1sK?= =?us-ascii?Q?XUdAirKn6tm4ITaZ/8ErC4HG1Cqnq6ex2eWPdj716DJ2V3I2EJzU6uhMVa7I?= =?us-ascii?Q?L1kg/gR+dmSHuF/2L0SFRoXO3M3rEolqBaKa+lzCiWmHQ+35cfhvJdq5riWy?= =?us-ascii?Q?Rn43zBribkEM5YZXBWvspG8VnJff5FB/fKHRJL7Qpu7psTr+DKpJmTrQSuvR?= =?us-ascii?Q?P2qWJMNbFkcu3SxcAFHRXeIMCcGH8W3pWNCEXrsa1ViFkOtFO6wM9w21T0fJ?= =?us-ascii?Q?3hbmGW8aO4fsiELUiOHVxwc8v1x1fFoZNGly7S6n3wJnAOTZTvZa2dQ/g24n?= =?us-ascii?Q?VOrBpCjgIXnxxyVUPCgQ5/1H57H2q3BI3V5SS9hbbWYwnb2CTfV69+cqpgCe?= =?us-ascii?Q?7QmwUAmntUSyM0Qn9auonzSPJ6C26asvRzJuw7xvz3tjmigmYSTAyjc+uWQN?= =?us-ascii?Q?RhOobbSXCtg3q99H27zU7bn1pVdABBHITR7IS66+ax9wifFwZpF/yWW6u1W0?= =?us-ascii?Q?qy5x2UTPPZSyhGzLl2Hq93C/08vFIXVEo/lh5mVvNk/w6UlVWMMIomnfx4rg?= =?us-ascii?Q?VSLArCiHhuw=3D?= X-Forefront-Antispam-Report: CIP:255.255.255.255;CTRY:;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:DS0PR12MB8044.namprd12.prod.outlook.com;PTR:;CAT:NONE;SFS:(13230040)(1800799024)(366016)(376014)(7416014);DIR:OUT;SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: =?us-ascii?Q?F2ZxOL9V5hOFbWFXTDvITpGcA1yF6sFFh/VikK9MkB3MmEPWzR+e7ld8qWFH?= =?us-ascii?Q?+QvzNEoOkOOHQaFbNB+BiAGEIl3OEVcSvfXSApZ3mWBpbWupiDbJubFcID33?= =?us-ascii?Q?vnDwGpAXtq1VBQVYqLC4aluHyYwDu8nchwsQ0AIL9OI6GwHgbfKX7Ab+0LET?= =?us-ascii?Q?POJ0+o9E6t/qVDsF6fhNpRxKDhIeJsrLmd6UOZoCReGluzq7EJ5XHfGuUmi6?= =?us-ascii?Q?cBSHwveuH6M9G84w51DzYTfFoW3ctISTen3PvhqR1vRjfM/6SwH2oXaO1bLE?= =?us-ascii?Q?WjY0qRF90pHkYTsuzs546hDQ1QbPuEPiwOR/8+6W1QnzmUbZJAPeA2oU7FLM?= =?us-ascii?Q?16m7hUHIdbRNSbx6ex3c4UwKJHiU1StJ3A0JXSW4U0inQ0HQqs55Ar7Qw/LA?= =?us-ascii?Q?15pXiBejmEZfQrc3cIgdfWhz9l8bULD7y8mONUpxJwJsBUD/GzHZZEy4Ho2e?= =?us-ascii?Q?P0rs4IEBxCJpdWJVB5+bgr3JQ6DZ2EZhiPVGDrZBNs9ydKKWzWtRQRL3Shhl?= =?us-ascii?Q?BmHkI6V3aNKkEV4SyRrtQ1WegU4mLN1kpDnyAt9iUXWnKoGmd1UX4gjkzhkm?= =?us-ascii?Q?SFie5nP9q+vGdjAQuihCr75qGcan+LLcpRRhWzf6d485FmXdE+te1xtQc0bF?= =?us-ascii?Q?a9iDQS+BhgzedEfvg2eIn5qHWMP2IRFiy6A6MegH8UU0ANuYgdyF6+a8Bv3G?= =?us-ascii?Q?Co/Qum6Vklmv6PRRZaBMDVTlHg7J9J5sc8e5UwBIAa3A0y0t6+1iGrYynOZB?= =?us-ascii?Q?GX8BNmmAjYtKCmRESwbK5xUOZc9f7Zy2KMGsInca84NYhdUILmUaeRNZ4FJP?= =?us-ascii?Q?7pcGKDXQU315jt3E/quOX42gZPqxiJNlpuuqUZRxVEsmZhPkJzHI8cB39XPk?= =?us-ascii?Q?ggMxCooSmPHmDlB3l6/ZXKeFS6bHHrASP8w/YUjHh739Jn574BgJ1fjBn4kY?= =?us-ascii?Q?9pWJA/LMQabGNW5nIbRvG0cN4bCQ14RpZRJ5IEmKaSvlrNRE8ke1A6wog4Xp?= =?us-ascii?Q?HpCz8R8JTQZ17vuRwrIHkhBuYMuWrB9/bzBIDDtfTtLF393Wwp0iFBEzm7iA?= =?us-ascii?Q?XvCuJPY0NwIqWwBPhArId5DLk0zF2FNpoZ9+QJvzfIq46pEC1QmFa50i5B4E?= =?us-ascii?Q?XNTsk2VW6+yIYSY2fZPv0hHpJ5ejwfce2mvq1/odOSaczaZdPjyDERwCEZ6F?= =?us-ascii?Q?U0LRbbax/Vhmgrv38BNJTg6d3wc07aNXbj2uFZHj5rUYM+skONskjUiX8CSs?= =?us-ascii?Q?yg2dwSBwIWjRmi3ZTW7fo+AsVndA3A2eDO1GOpo3YxliElbLHblshtLnOpje?= =?us-ascii?Q?KfyZlzcFwZrT7QYA3dbZ3HGESPbcwO0K5UkDN1bYMUKcMgfKt4Tsm7N5RxVs?= =?us-ascii?Q?NgA/3hQESyTnRUFTPBNhSdnCZq03jtMEYO8FkgsCIEIyhV19/9WaHYC/CT9L?= =?us-ascii?Q?4YUW+jlEIg2aoFOspBOJ/E2xcJwU2PzjQOnmHYz7nEHj7r1+rytdHKwo1ZQc?= =?us-ascii?Q?W9SGistzuSUBQSCgXTHfod77zPuY/irw7FW/s6O672eJThY3l9oZT/FWLjbr?= =?us-ascii?Q?CcLuSyafKKlAAU/iWdz/966JAWqFStbP8KucQy2j?= X-OriginatorOrg: Nvidia.com X-MS-Exchange-CrossTenant-Network-Message-Id: 176406d9-7dc7-4ddd-d668-08ddefe6c4f9 X-MS-Exchange-CrossTenant-AuthSource: DS0PR12MB8044.namprd12.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 09 Sep 2025 21:20:58.5896 (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: rAcXF2lErk39CVtN39WQjIWF/Zo/pLo+L8RYyxnNuH+bhXMcfap2SqsBok8UeJ7jrNMzujyLg7uy+5cPNjswwg== X-MS-Exchange-Transport-CrossTenantHeadersStamped: MN0PR12MB6031 Content-Type: text/plain; charset="utf-8" Add KUNIT tests to make sure the macro is working correctly. [Added range overlap tests suggested by Yury]. Signed-off-by: Joel Fernandes Suggested-by: Yury Norov (NVIDIA) # For overlapped t= ests --- rust/kernel/bits/bitfield.rs | 320 +++++++++++++++++++++++++++++++++++ 1 file changed, 320 insertions(+) diff --git a/rust/kernel/bits/bitfield.rs b/rust/kernel/bits/bitfield.rs index 0837fefc270f..f3134f2ffd08 100644 --- a/rust/kernel/bits/bitfield.rs +++ b/rust/kernel/bits/bitfield.rs @@ -339,3 +339,323 @@ fn default() -> Self { } }; } + +#[::kernel::macros::kunit_tests(kernel_bitfield)] +mod tests { + use core::convert::TryFrom; + + // Enum types for testing =3D> and ?=3D> conversions + #[derive(Debug, Clone, Copy, PartialEq)] + enum MemoryType { + Unmapped =3D 0, + Normal =3D 1, + Device =3D 2, + Reserved =3D 3, + } + + impl Default for MemoryType { + fn default() -> Self { + MemoryType::Unmapped + } + } + + impl TryFrom for MemoryType { + type Error =3D u8; + fn try_from(value: u8) -> Result { + match value { + 0 =3D> Ok(MemoryType::Unmapped), + 1 =3D> Ok(MemoryType::Normal), + 2 =3D> Ok(MemoryType::Device), + 3 =3D> Ok(MemoryType::Reserved), + _ =3D> Err(value), + } + } + } + + impl From for u64 { + fn from(mt: MemoryType) -> u64 { + mt as u64 + } + } + + #[derive(Debug, Clone, Copy, PartialEq)] + enum Priority { + Low =3D 0, + Medium =3D 1, + High =3D 2, + Critical =3D 3, + } + + impl Default for Priority { + fn default() -> Self { + Priority::Low + } + } + + impl From for Priority { + fn from(value: u8) -> Self { + match value & 0x3 { + 0 =3D> Priority::Low, + 1 =3D> Priority::Medium, + 2 =3D> Priority::High, + _ =3D> Priority::Critical, + } + } + } + + impl From for u16 { + fn from(p: Priority) -> u16 { + p as u16 + } + } + + bitfield! { + struct TestPageTableEntry: u64 { + 0:0 present as bool; + 1:1 writable as bool; + 11:9 available as u8; + 13:12 mem_type as u8 ?=3D> MemoryType; + 17:14 extended_type as u8 ?=3D> MemoryType; // 4-bit fiel= d for testing failures + 51:12 pfn as u64; + 51:12 pfn_overlap as u64; // Overlapping field + 61:52 available2 as u16; + } + } + + bitfield! { + struct TestControlRegister: u16 { + 0:0 enable as bool; + 3:1 mode as u8; + 5:4 priority as u8 =3D> Priority; + 7:4 priority_nibble as u8; // Overlapping field + 15:8 channel as u8; + } + } + + bitfield! { + struct TestStatusRegister: u8 { + 0:0 ready as bool; + 1:1 error as bool; + 3:2 state as u8; + 7:4 reserved as u8; + 7:0 full_byte as u8; // Overlapping field for entire = register + } + } + + #[test] + fn test_single_bits() { + let mut pte =3D TestPageTableEntry::default(); + + // Test bool field + assert!(!pte.present()); + assert!(!pte.writable()); + + pte =3D pte.set_present(true); + assert!(pte.present()); + + pte =3D pte.set_writable(true); + assert!(pte.writable()); + + pte =3D pte.set_writable(false); + assert!(!pte.writable()); + + assert_eq!(pte.available(), 0); + pte =3D pte.set_available(0x5); + assert_eq!(pte.available(), 0x5); + } + + #[test] + fn test_range_fields() { + let mut pte =3D TestPageTableEntry::default(); + + pte =3D pte.set_pfn(0x123456); + assert_eq!(pte.pfn(), 0x123456); + // Test overlapping field reads same value + assert_eq!(pte.pfn_overlap(), 0x123456); + + pte =3D pte.set_available(0x7); + assert_eq!(pte.available(), 0x7); + + pte =3D pte.set_available2(0x3FF); + assert_eq!(pte.available2(), 0x3FF); + + // Test TryFrom with ?=3D> for MemoryType + pte =3D pte.set_mem_type(MemoryType::Device); + assert_eq!(pte.mem_type(), Ok(MemoryType::Device)); + + pte =3D pte.set_mem_type(MemoryType::Normal); + assert_eq!(pte.mem_type(), Ok(MemoryType::Normal)); + + // Test all valid values for mem_type + pte =3D pte.set_mem_type(MemoryType::Reserved); // Valid value: 3 + assert_eq!(pte.mem_type(), Ok(MemoryType::Reserved)); + + // Test failure case using extended_type field which has 4 bits (0= -15) + // MemoryType only handles 0-3, so values 4-15 should return Err + let mut raw =3D pte.raw(); + raw =3D (raw & !(0xF << 14)) | (0x7 << 14); // Set bits 17:14 to 7= (invalid for MemoryType) + let invalid_pte =3D TestPageTableEntry::from(raw); + assert_eq!(invalid_pte.extended_type(), Err(0x7)); // Should retur= n Err with the invalid value + + // Test a valid value after testing invalid to ensure both cases w= ork + raw =3D (raw & !(0xF << 14)) | (0x2 << 14); // Set bits 17:14 to 2= (valid: Device) + let valid_pte =3D TestPageTableEntry::from(raw); + assert_eq!(valid_pte.extended_type(), Ok(MemoryType::Device)); // = Should return Ok with Device + + let max_pfn =3D (1u64 << 40) - 1; + pte =3D pte.set_pfn(max_pfn); + assert_eq!(pte.pfn(), max_pfn); + assert_eq!(pte.pfn_overlap(), max_pfn); + } + + #[test] + fn test_builder_pattern() { + let pte =3D TestPageTableEntry::default() + .set_present(true) + .set_writable(true) + .set_available(0x7) + .set_pfn(0xABCDEF) + .set_mem_type(MemoryType::Reserved) + .set_available2(0x3FF); + + assert!(pte.present()); + assert!(pte.writable()); + assert_eq!(pte.available(), 0x7); + assert_eq!(pte.pfn(), 0xABCDEF); + assert_eq!(pte.pfn_overlap(), 0xABCDEF); + assert_eq!(pte.mem_type(), Ok(MemoryType::Reserved)); + assert_eq!(pte.available2(), 0x3FF); + } + + #[test] + fn test_raw_operations() { + let raw_value =3D 0x3FF0000003123E03u64; + + // Test using ::from() syntax + let pte =3D TestPageTableEntry::from(raw_value); + assert_eq!(pte.raw(), raw_value); + + assert!(pte.present()); + assert!(pte.writable()); + assert_eq!(pte.available(), 0x7); + assert_eq!(pte.pfn(), 0x3123); + assert_eq!(pte.pfn_overlap(), 0x3123); + assert_eq!(pte.mem_type(), Ok(MemoryType::Reserved)); + assert_eq!(pte.available2(), 0x3FF); + + // Test using direct constructor syntax TestStruct(value) + let pte2 =3D TestPageTableEntry(raw_value); + assert_eq!(pte2.raw(), raw_value); + } + + #[test] + fn test_u16_bitfield() { + let mut ctrl =3D TestControlRegister::default(); + + assert!(!ctrl.enable()); + assert_eq!(ctrl.mode(), 0); + assert_eq!(ctrl.priority(), Priority::Low); + assert_eq!(ctrl.priority_nibble(), 0); + assert_eq!(ctrl.channel(), 0); + + ctrl =3D ctrl.set_enable(true); + assert!(ctrl.enable()); + + ctrl =3D ctrl.set_mode(0x5); + assert_eq!(ctrl.mode(), 0x5); + + // Test From conversion with =3D> + ctrl =3D ctrl.set_priority(Priority::High); + assert_eq!(ctrl.priority(), Priority::High); + assert_eq!(ctrl.priority_nibble(), 0x2); // High =3D 2 in bits 5:4 + + ctrl =3D ctrl.set_channel(0xAB); + assert_eq!(ctrl.channel(), 0xAB); + + // Test overlapping fields + ctrl =3D ctrl.set_priority_nibble(0xF); + assert_eq!(ctrl.priority_nibble(), 0xF); + assert_eq!(ctrl.priority(), Priority::Critical); // bits 5:4 =3D 0= x3 + + let ctrl2 =3D TestControlRegister::default() + .set_enable(true) + .set_mode(0x3) + .set_priority(Priority::Medium) + .set_channel(0x42); + + assert!(ctrl2.enable()); + assert_eq!(ctrl2.mode(), 0x3); + assert_eq!(ctrl2.priority(), Priority::Medium); + assert_eq!(ctrl2.channel(), 0x42); + + let raw_value: u16 =3D 0x4217; + let ctrl3 =3D TestControlRegister::from(raw_value); + assert_eq!(ctrl3.raw(), raw_value); + assert!(ctrl3.enable()); + assert_eq!(ctrl3.priority(), Priority::Medium); + assert_eq!(ctrl3.priority_nibble(), 0x1); + assert_eq!(ctrl3.channel(), 0x42); + } + + #[test] + fn test_u8_bitfield() { + let mut status =3D TestStatusRegister::default(); + + assert!(!status.ready()); + assert!(!status.error()); + assert_eq!(status.state(), 0); + assert_eq!(status.reserved(), 0); + assert_eq!(status.full_byte(), 0); + + status =3D status.set_ready(true); + assert!(status.ready()); + assert_eq!(status.full_byte(), 0x01); + + status =3D status.set_error(true); + assert!(status.error()); + assert_eq!(status.full_byte(), 0x03); + + status =3D status.set_state(0x3); + assert_eq!(status.state(), 0x3); + assert_eq!(status.full_byte(), 0x0F); + + status =3D status.set_reserved(0xA); + assert_eq!(status.reserved(), 0xA); + assert_eq!(status.full_byte(), 0xAF); + + // Test overlapping field + status =3D status.set_full_byte(0x55); + assert_eq!(status.full_byte(), 0x55); + assert!(status.ready()); + assert!(!status.error()); + assert_eq!(status.state(), 0x1); + assert_eq!(status.reserved(), 0x5); + + let status2 =3D TestStatusRegister::default() + .set_ready(true) + .set_state(0x2) + .set_reserved(0x5); + + assert!(status2.ready()); + assert!(!status2.error()); + assert_eq!(status2.state(), 0x2); + assert_eq!(status2.reserved(), 0x5); + assert_eq!(status2.full_byte(), 0x59); + + let raw_value: u8 =3D 0x59; + let status3 =3D TestStatusRegister::from(raw_value); + assert_eq!(status3.raw(), raw_value); + assert!(status3.ready()); + assert!(!status3.error()); + assert_eq!(status3.state(), 0x2); + assert_eq!(status3.reserved(), 0x5); + assert_eq!(status3.full_byte(), 0x59); + + let status4 =3D TestStatusRegister::from(0xFF); + assert!(status4.ready()); + assert!(status4.error()); + assert_eq!(status4.state(), 0x3); + assert_eq!(status4.reserved(), 0xF); + assert_eq!(status4.full_byte(), 0xFF); + } +} --=20 2.34.1