From nobody Sat Sep 26 12:29:11 2026 Received: from LO3P265CU004.outbound.protection.outlook.com (mail-uksouthazon11020089.outbound.protection.outlook.com [52.101.196.89]) (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 C160B483825; Tue, 1 Sep 2026 16:50:39 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=52.101.196.89 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788281442; cv=fail; b=K9kBDCjUTPMFQuqOa7lU0vw7FhXnzV1z2YvWZniCbvYBpuU5fsNDapF8sb8VFKZmCh/mHa+VuyoRrzpLuhRiBdBleaiQqq5p/qF6Rajqf886rFWg6tiUycaOoBGh8VygZjJ2KETkcPdBOz/AfXbuS29M8zUwQ14Xv+roDIQu/sQ= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788281442; c=relaxed/simple; bh=Zx7heSsk8DCn4lZE4dws+jTnWJOl/ZnhN4v8+izAFmw=; h=From:Date:Subject:Content-Type:Message-Id:References:In-Reply-To: To:Cc:MIME-Version; b=cSuqsoWExgDw6PWFfAq9+/IMX2sTpZF/AZOp1RNWnqiQFH3tn06g1dOT//freAJb5fpTc+6CKOt6epOGOPEXFyHs6j0AP+6DXTr5Sej5LVXCgLrDgsJq0T4RtUXtWe4ZxXaMNZGWvFbEv8a3jD2ed0bgvmFal2hnP+t+6NMisLg= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=garyguo.net; spf=pass smtp.mailfrom=garyguo.net; dkim=pass (1024-bit key) header.d=garyguo.net header.i=@garyguo.net header.b=e5SnFC16; arc=fail smtp.client-ip=52.101.196.89 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=garyguo.net Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=garyguo.net Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=garyguo.net header.i=@garyguo.net header.b="e5SnFC16" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=PQLedsB1gkJDYx7NZv+wXCAqCgaF0wPYiQostUud/6Yljgwc4QCnCuwN4e93/1MUX7N/2ANm8G+Aau6RZQrOA1XH8AbpUuygQb+iRwAe54pSrD4ZuvvSGXrnKZZx8hc2ZXvV9CxMJKfJWTXc47zOzmcJs4VGAheDhoeSdOSp7e87jNN1fXYiQa0ogcXBCF+m06A/vxxIsEKjZu4VFJr538pPcjCo3onKmoX5iytp1r9FlzMWUCArPUu86zsz322KM/i4VMWiPAc91iEsyULNGB5apBzJgkrLhIilYPEtFHHG7CzmWVhgIVzqD/QX5qXicTITp1a1Vji9Vs2XguxUCQ== 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=l61BiUTycE5b/rJHGCJOA270/LuiPPdk9n7KTr72HlM=; b=aC0jTHLb5LIpbX2xb63Yr7c9wsXaJKPux2zjRUEU7ajx4QOCGjTmmebmjSH4qL2CaziwK/M16p+euwtsiLC6N0AKF/ERlND+PmVyZ+yZgK4wB7bE5pPNFYJQG9mwAY/v5c/2bztxY7z9ASNFD/c5XUE72YhBRwPrM6eEmqYpLulowGhGVNEYgu4Wm/4ZuSAH81UsMeti6U8eiabVk9vYMVhWXzyzl7xfWr/o0ebdlKWdrn1fQyFPMX41XCPsPnONmWrssEhNIFTFke1Qi7zTl6Eont3VgQawxJ1udir4kyNejvpbd9TVa0xEWKTYJyRnElnmN4XhIcqoMFew2O8Rnw== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=garyguo.net; dmarc=pass action=none header.from=garyguo.net; dkim=pass header.d=garyguo.net; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=garyguo.net; s=selector1; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=l61BiUTycE5b/rJHGCJOA270/LuiPPdk9n7KTr72HlM=; b=e5SnFC169tqNYMYezOJ/eSihjA3p31BM5c/g1VKLgNwc/+0ytt7lfvVSAPhAB8hQ9xTopNIOfWIFqDgQ3Q3F9uFPwLRy+7bWo58HuwupyS4dnMuc2kYUD2vh+zUj2MlVdbp9/Qln1XRZOfkxG3YWtDm8ZuHPYNMvedlA+uXrUEs= Authentication-Results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=garyguo.net; Received: from LOAP265MB8560.GBRP265.PROD.OUTLOOK.COM (2603:10a6:600:4ab::19) by LO0P265MB7316.GBRP265.PROD.OUTLOOK.COM (2603:10a6:600:2ef::11) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.21.360.13; Tue, 1 Sep 2026 16:50:33 +0000 Received: from LOAP265MB8560.GBRP265.PROD.OUTLOOK.COM ([fe80::f60b:1537:68d7:4fc1]) by LOAP265MB8560.GBRP265.PROD.OUTLOOK.COM ([fe80::f60b:1537:68d7:4fc1%4]) with mapi id 15.21.0360.008; Tue, 1 Sep 2026 16:50:33 +0000 From: Gary Guo Date: Tue, 01 Sep 2026 17:50:25 +0100 Subject: [PATCH v4 01/16] rust: io: register: reimplement as proc macro Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260901-typed_register-v4-1-5552b1d59525@garyguo.net> References: <20260901-typed_register-v4-0-5552b1d59525@garyguo.net> In-Reply-To: <20260901-typed_register-v4-0-5552b1d59525@garyguo.net> To: Danilo Krummrich , Alice Ryhl , Daniel Almeida , Miguel Ojeda , Boqun Feng , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Andreas Hindborg , Trevor Gross , Tamir Duberstein , Alexandre Courbot , =?utf-8?q?Onur_=C3=96zkan?= , David Airlie , Simona Vetter , Bjorn Helgaas , =?utf-8?q?Krzysztof_Wilczy=C5=84ski?= Cc: driver-core@lists.linux.dev, rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, nova-gpu@lists.linux.dev, dri-devel@lists.freedesktop.org, linux-pci@vger.kernel.org, Gary Guo X-Mailer: b4 0.15.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1788281431; l=21718; i=gary@garyguo.net; s=20221204; h=from:subject:message-id; bh=Zx7heSsk8DCn4lZE4dws+jTnWJOl/ZnhN4v8+izAFmw=; b=AJXGj8Aysc3ywlPvPtWMYTRL655UGTuKSuxb58gJg2uGREdKt+wlxII41ZD9YlMp7UovD6ojW Ct0a1v0IHbRDvsB4HHxW8FI86KFCaZBHq4O7Y6z+Cq4cvutms+RqMie X-Developer-Key: i=gary@garyguo.net; a=ed25519; pk=vB3uIX95SM4eVrIqo1DWNWKDKD2xzB+yLLLr0yOPYMo= X-ClientProxiedBy: PAZP264CA0173.FRAP264.PROD.OUTLOOK.COM (2603:10a6:102:236::16) To LOAP265MB8560.GBRP265.PROD.OUTLOOK.COM (2603:10a6:600:4ab::19) 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: LOAP265MB8560:EE_|LO0P265MB7316:EE_ X-MS-Office365-Filtering-Correlation-Id: 9358661a-65f9-48db-debc-08df0849235c X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|366016|1800799024|23010399003|10070799003|376014|7416014|10067099003|3023799007|22082099003|56012099006|5023799004|18002099003|921020; X-Microsoft-Antispam-Message-Info: czpw+6aGODEBR/yNlIEJLG7gXruWkrEJwOsjoUAM4W8pwveDEHiHAX8y2Qp0bkjq2yyvn/xY6yeEkAneJ8IVHuh6V14dqpgcbk/87wR9wuSRU9vj1RIAkl9Prh9TwLX6JcUJaH3sySCyrSTX/mbFdzLk+IP+krEUvzGTOzi9Y6O2HdBcznVy0KkSo/N7Mo+10a8TYK0ELvye294/qv0pqlxtHfjZ1m/6OEe7LkZKB11jH7u9ifTEOZUxyf8UhSWrYQ/Np4jEPXNEMfYgZzGZDU18F495wWVf5I5Ba+xhUt5XC2+Mq6FJr3PnyQzdfPVbO0RAcG2AhoDpw2vUSpoIPsul14tTDxti7ASZkzUdencbTdWbAEE0lvMU26xAKhT8q3ZkF9b0fcdorrCdaEiPioFn4F/wUeveO1JNHcQODWHD+CJ6SFFlBYLSgCtz7z49yA3hes3CPZt8jBEl1gfMOm4CVHbFX1GCURjSdCfUsZdBwUupoKw0N8rNr3nHx0nE58uhpYuovC5HC3mF8l8J8T3IMnK1pci4HkbILxYUFx6cXmMXA+vhf518gFD+1MQBW7MiWQlkqwGzglzohObDqyfINartBfJr3Uf+m+4ZVDOKUfc9LX1g1qoKyzoYMEwW2uIBp3NcMUtWu/37crB7xOg9JXNh/byPa/s0ZTOQ0oUnp10THftSfM+zFf1VURoAa8WzUAQK+5wOEdh6OwxJ8g== X-Forefront-Antispam-Report: CIP:255.255.255.255;CTRY:;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:LOAP265MB8560.GBRP265.PROD.OUTLOOK.COM;PTR:;CAT:NONE;SFS:(13230040)(366016)(1800799024)(23010399003)(10070799003)(376014)(7416014)(10067099003)(3023799007)(22082099003)(56012099006)(5023799004)(18002099003)(921020);DIR:OUT;SFP:1102; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: =?utf-8?B?RUVQN3dKVkRxRGJ1THlHVEVqNG1NZHNzYk10R010Ynd2VU5GdDExZ1J3dmZY?= =?utf-8?B?Z2lUTmh4dDdGVklzcHVIajdEWjlta0RRTjduQjYxNXdCTGkvZkw3SCtEOWdi?= =?utf-8?B?U1hZVU93MEoyS0VmbW94R1kzOEFwMHl1aW4zS21iSGc3NC9MNUVWWTA3NkFT?= =?utf-8?B?WW5JaTBGVW9NTVZzTm5pTEprL1FtRzFWS0pRUnUzUXlyZDlXVGNhazdkSnNy?= =?utf-8?B?N3hZOW9BNDVvK056SElHTEJMZUtlVm05cklMVWxOYXB1MjBZdTQ3SzJENFhM?= =?utf-8?B?STQzN0JCbzFvWmZOaWVsUGRvMnZaUW51YUxMSWllcWR6eG5uRWgyYjlBbXlM?= =?utf-8?B?a0tra2Ryd0x0N2poR1dOVU5LVUJ5Y254Smg5QlZQMUpPNVdTekhYUFc2SHZy?= =?utf-8?B?UkJjN3dGYXI2N1djTGoxYTRJQTAzZ3VncUU5a1l6bU9hTnpNWWNxTkJXZTly?= =?utf-8?B?SlF3L21UUURFblpGTkdlajBVRlBUVjhEUXo2SDJ0TEt1bXlHVXlDbWF5Nndz?= =?utf-8?B?UzdhcTB3b2w5SmxvbEdIRS8vb25aVUlNMlB3Sms1MGRtUFlTWVIxejd2aXVu?= =?utf-8?B?RW43UEtXQW9mUUV1VGFlMUk5Z0tOclpiZnRTZGhMSXA5aXljV0N4NVdBTnU2?= =?utf-8?B?Ynpza3EySUU0dENMazZJUHZJc3p4aU1SRUs1NnBjU2hsbGlJTUVxTkF2R0RI?= =?utf-8?B?Yjd5OTBYQnRQcE9XU2lSZUh3UDYvN1JQOGQ3QmxtR3JyUGFPMUsrMjE4WEZS?= =?utf-8?B?UzdlYmk4Qk1BbVp5eVREcDdmTlV4aSs2ZXJkTkxiOHJJREwzTDgyWElHQ3E1?= =?utf-8?B?R0M2SEdJZHA2NG0yRitWRFA4OHNWNHFhWHJTZHZoU3JiRU5LSkJzem1TSVZV?= =?utf-8?B?bnMvc2pBVjFEWGUzWDlidDRHWXFnamRUVXNGdUpMcko5QWlkM1hqcEZXZVJF?= =?utf-8?B?eC9aYU1jUFRwOGgwQUJhSTZ2TzRibjM5SGV2VGh5RkU1OEE3VmxQZ29makZB?= =?utf-8?B?T3p5YkViL04rQzFGc1crRzMyQ0gzOU9FRkFsWW11N0M0SkQ2WHNxd2RYZndX?= =?utf-8?B?YzRSQ25pVUlaQm9CbVRnemlPaE1aUjFHUStCTzBLbytqUkdrNEtFc2sybi93?= =?utf-8?B?Ukh5NDZnVituamRmZDhRQk8yVU1FbmkrYTRQR0dXVUJhYnJJT3lqRjdFWTZW?= =?utf-8?B?YXhTSWhtZWpGdml1aDFsaVEwOEdNZzZnY3VwN0JDNnJGZE9PY0dXVm5BU2lh?= =?utf-8?B?ZnY3K2crVXRHL3VNclBwNE5tTmYrUzA3ZUJRNmdWMHlSdk5ucUhBTWMrK1pL?= =?utf-8?B?TE5XUVNSdElxUVRzWDN2VFZZZFZxRkM5eFBZaEpXNWxoTFo4eVJZQkczZ0xO?= =?utf-8?B?blZJa1BYbXZCVVBWQ2Y2MHlGUkpiK3lLalNnSlV0VW0rcGJndXRRakFoUldM?= =?utf-8?B?bVJBVEh2a3V4Z28yOFRsc25uZjZTelA5ZTQzY1dJamJQM3VCZkpwbGF4YnFS?= =?utf-8?B?Wmd3dnlYVDgxWlZKV0ZqcXVob1BMTVRKRGYrcHJCWkhnU3RSL0xTSVkvb0tr?= =?utf-8?B?ampmeTNhYVQyZ2ZMVm11SlUxa1MzQklXdmFVSngxRGZ4SUhoQmEwSHQ0clBw?= =?utf-8?B?YkQvWlY4c1RWaUtwZytWQUNJNWFCR2tJNHhPZm5YcEhuZmJvd0x4cDRiVUhl?= =?utf-8?B?M2lQUTh3QVlIWDY0L1RlQU8wU3FjdUVRaXhUTlRXODFmb3k1cFpMMUtZekZr?= =?utf-8?B?Wk01cnVzOWIzOG1vRGhjbnZuWGtCbU1EOWFiRjRkdFN6MUFuZW9DWkVtVUdD?= =?utf-8?B?V2VuYUJFVkRZZVQ2T2hSbGVyVnR6d2xLNkh6RDhPWGkzTllzMDFxQWp1VzRx?= =?utf-8?B?NEF3ZHVBdVQ1UzQyYkpGTHUyam5VbDA0Wk5qM2NDS0p6TXBPZVFhMjZOeENK?= =?utf-8?B?bE1lSVZXV3hsd2h4U0E2YnpxY1JLRzlVWUk4enNlclNSVjR2SThVbEVFVTVl?= =?utf-8?B?VU5sRzFkR3RzODQ4R3VxMnRvUnZ1K3A4Y3kxckU4NGhOMHRNM0orcWlpZWVx?= =?utf-8?B?Qmx0ZTRTMklxdEdQL3Z0RExnYm9LaVJtMFhXZFNaaS8wZ25sdzhwR3dvR1Bz?= =?utf-8?B?emZuQXlNUi9MQm9NS0xGM0tmYWtMUGp2Q1ZSTXByN3cyVW9OSVV6ZUFFWmxp?= =?utf-8?B?Z1BtUGVpVXluVW9DLzRqVlZSTVgzWDBtbkZzQ04wT3hUNzVvQkdiR29zaDdE?= =?utf-8?B?ZEYrM0s0dDJnQ3BPdlo5UWE5WmxkcEhiT0JUSTdoTDdyck41QWtkRU80OUZM?= =?utf-8?B?RzhiekVYaDQ1Z3ZLUlNwNE4yWjlsU2FRbnA1YjlrQXFQdWRqMDJrdz09?= X-OriginatorOrg: garyguo.net X-MS-Exchange-CrossTenant-Network-Message-Id: 9358661a-65f9-48db-debc-08df0849235c X-MS-Exchange-CrossTenant-AuthSource: LOAP265MB8560.GBRP265.PROD.OUTLOOK.COM X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 01 Sep 2026 16:50:32.9752 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: bbc898ad-b10f-4e10-8552-d9377b823d45 X-MS-Exchange-CrossTenant-MailboxType: HOSTED X-MS-Exchange-CrossTenant-UserPrincipalName: tnn9+mRSOkes6ewPJpb/z/5tmiyVv6KwnQoWyHPVAx+qOKVSVwLssq0sfrPdIbPbW+slEVJ8TjekwBjVSnlZOQ== X-MS-Exchange-Transport-CrossTenantHeadersStamped: LO0P265MB7316 The existing `register!` macro is implemented as a declarative macro. Reimplement it as proc macro instead, with no functional changes intended. The old implementation produces unhelpful diagnostics when things go wrong. For example, for code like register! { pub(crate) TESTREG(u32) { 31:0 data; } } which misses out the "@ offset" part of the specification, and the following error is produced: error: no rules expected `{` --> test.rs:42:5 | 42 | / register! { 43 | | pub(crate) TESTREG(u32) { 44 | | 31:0 data; ... | 100 | | } | |_____^ no rules expected this token in macro call which isn't very helpful. With the proc macro implementation, the following error is produced: error: expected `@` or `=3D>` --> tests.rs:43:33 | 43 | pub(crate) TESTREG(u32) { | ^ which is much more helpful. Apart from diagnostics, proc macro also has a benefit of not having follow-set restrictions, which makes syntax like register!(name: ty @ offset); possible; declarative macro will reject this as `@` is not in the follow-set of "ty" metavariable kind. Signed-off-by: Gary Guo Acked-by: Miguel Ojeda Reviewed-by: Alexandre Courbot Tested-by: Alexandre Courbot --- MAINTAINERS | 1 + rust/kernel/io/register.rs | 224 +----------------------------------- rust/macros/io/mod.rs | 3 + rust/macros/io/register.rs | 276 +++++++++++++++++++++++++++++++++++++++++= ++++ rust/macros/lib.rs | 9 ++ 5 files changed, 291 insertions(+), 222 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index 3a19da74d00c..d92c7d834693 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -7494,6 +7494,7 @@ F: rust/kernel/io.rs F: rust/kernel/io/ F: rust/kernel/irq.rs F: rust/kernel/irq/ +F: rust/macros/io/ =20 DEVICE RESOURCE MANAGEMENT HELPERS M: Hans de Goede diff --git a/rust/kernel/io/register.rs b/rust/kernel/io/register.rs index 03dfd2ff48c7..6a19552ffb95 100644 --- a/rust/kernel/io/register.rs +++ b/rust/kernel/io/register.rs @@ -801,227 +801,7 @@ fn into_io_op(self) -> (FixedRegisterLoc, T) { /// ``` #[macro_export] macro_rules! register { - // Entry point for the macro, allowing multiple registers to be define= d in one call. - // It matches all possible register declaration patterns to dispatch t= hem to corresponding - // `@reg` rule that defines a single register. - // - // TODO: change `alias:ident` to `alias:path` once relative registers = are replaced by I/O - // projections. - ( - $( - $(#[$attr:meta])* $vis:vis $name:ident ($storage:ty) - $([ $size:expr $(, stride =3D $stride:expr)? ])? - $(@ $($base:ident +)? $offset:literal)? - $(=3D> $alias:ident $(+ $alias_offset:ident)? $([$alias_id= x:expr])? )? - { $($fields:tt)* } - )* - ) =3D> { - $( - $crate::register!( - @reg $(#[$attr])* $vis $name ($storage) $([$size $(, stride = =3D $stride)?])? - $(@ $($base +)? $offset)? - $(=3D> $alias $(+ $alias_offset)? $([$alias_idx])? )? - { $($fields)* } - ); - )* - }; - - // All the rules below are private helpers. - - // Creates a register at a fixed offset of the MMIO space. - ( - @reg $(#[$attr:meta])* $vis:vis $name:ident ($storage:ty) @ $offse= t:literal - { $($fields:tt)* } - ) =3D> { - $crate::register!(@bitfield $(#[$attr])* $vis struct $name($storag= e) { $($fields)* }); - $crate::register!(@io_base $name($storage) @ $offset); - $crate::register!(@io_fixed $(#[$attr])* $vis $name); - }; - - // Creates an alias register of fixed offset register `alias` with its= own fields. - ( - @reg $(#[$attr:meta])* $vis:vis $name:ident ($storage:ty) =3D> $al= ias:path - { $($fields:tt)* } - ) =3D> { - $crate::register!(@bitfield $(#[$attr])* $vis struct $name($storag= e) { $($fields)* }); - $crate::register!( - @io_base $name($storage) @ - <$alias as $crate::io::register::Register>::OFFSET - ); - $crate::register!(@io_fixed $(#[$attr])* $vis $name); - }; - - // Creates a register at a relative offset from a base address provide= r. - ( - @reg $(#[$attr:meta])* $vis:vis $name:ident ($storage:ty) @ $base:= ident + $offset:literal - { $($fields:tt)* } - ) =3D> { - $crate::register!(@bitfield $(#[$attr])* $vis struct $name($storag= e) { $($fields)* }); - $crate::register!(@io_base $name($storage) @ $offset); - $crate::register!(@io_relative $name @ $base); - }; - - // Creates an alias register of relative offset register `alias` with = its own fields. - ( - @reg $(#[$attr:meta])* $vis:vis $name:ident ($storage:ty) =3D> $ba= se:ident + $alias:ident - { $($fields:tt)* } - ) =3D> { - $crate::register!(@bitfield $(#[$attr])* $vis struct $name($storag= e) { $($fields)* }); - $crate::register!( - @io_base $name($storage) @ <$alias as $crate::io::register::Re= gister>::OFFSET - ); - $crate::register!(@io_relative $name @ $base); - }; - - // Creates an array of registers at a fixed offset of the MMIO space. - ( - @reg $(#[$attr:meta])* $vis:vis $name:ident ($storage:ty) - [ $size:expr, stride =3D $stride:expr ] @ $offset:literal { $(= $fields:tt)* } - ) =3D> { - $crate::build_assert::static_assert!(::core::mem::size_of::<$stora= ge>() <=3D $stride); - - $crate::register!(@bitfield $(#[$attr])* $vis struct $name($storag= e) { $($fields)* }); - $crate::register!(@io_base $name($storage) @ $offset); - $crate::register!(@io_array $name [ $size, stride =3D $stride ]); - }; - - // Shortcut for contiguous array of registers (stride =3D=3D size of e= lement). - ( - @reg $(#[$attr:meta])* $vis:vis $name:ident ($storage:ty) [ $size:= expr ] @ $offset:literal - { $($fields:tt)* } - ) =3D> { - $crate::register!( - @reg $(#[$attr])* $vis $name($storage) - [ $size, stride =3D ::core::mem::size_of::<$storage>() ] - @ $offset { $($fields)* } - ); - }; - - // Creates an alias of register `idx` of array of registers `alias` wi= th its own fields. - ( - @reg $(#[$attr:meta])* $vis:vis $name:ident ($storage:ty) =3D> $al= ias:path [ $idx:expr ] - { $($fields:tt)* } - ) =3D> { - $crate::build_assert::static_assert!( - $idx < <$alias as $crate::io::register::RegisterArray>::SIZE - ); - - $crate::register!(@bitfield $(#[$attr])* $vis struct $name($storag= e) { $($fields)* }); - $crate::register!( - @io_base $name($storage) @ - <$alias as $crate::io::register::Register>::OFFSET - + $idx * <$alias as $crate::io::register::RegisterArray>::= STRIDE - ); - $crate::register!(@io_fixed $(#[$attr])* $vis $name); - }; - - // Creates an array of registers at a relative offset from a base addr= ess provider. - ( - @reg $(#[$attr:meta])* $vis:vis $name:ident ($storage:ty) - [ $size:expr, stride =3D $stride:expr ] - @ $base:ident + $offset:literal { $($fields:tt)* } - ) =3D> { - $crate::build_assert::static_assert!(::core::mem::size_of::<$stora= ge>() <=3D $stride); - - $crate::register!(@bitfield $(#[$attr])* $vis struct $name($storag= e) { $($fields)* }); - $crate::register!(@io_base $name($storage) @ $offset); - $crate::register!(@io_relative_array $name [ $size, stride =3D $st= ride ] @ $base); - }; - - // Shortcut for contiguous array of relative registers (stride =3D=3D = size of element). - ( - @reg $(#[$attr:meta])* $vis:vis $name:ident ($storage:ty) [ $size:= expr ] - @ $base:ident + $offset:literal { $($fields:tt)* } - ) =3D> { - $crate::register!( - @reg $(#[$attr])* $vis $name($storage) - [ $size, stride =3D ::core::mem::size_of::<$storage>() ] - @ $base + $offset { $($fields)* } - ); - }; - - // Creates an alias of register `idx` of relative array of registers `= alias` with its own - // fields. - ( - @reg $(#[$attr:meta])* $vis:vis $name:ident ($storage:ty) - =3D> $base:ident + $alias:ident [ $idx:expr ] { $($fields:tt)*= } - ) =3D> { - $crate::build_assert::static_assert!( - $idx < <$alias as $crate::io::register::RegisterArray>::SIZE - ); - - $crate::register!(@bitfield $(#[$attr])* $vis struct $name($storag= e) { $($fields)* }); - $crate::register!( - @io_base $name($storage) @ - <$alias as $crate::io::register::Register>::OFFSET + - $idx * <$alias as $crate::io::register::RegisterArray>::ST= RIDE - ); - $crate::register!(@io_relative $name @ $base); - }; - - // Generates the bitfield for the register. - // - // `#[allow(non_camel_case_types)]` is added since register names typi= cally use - // `SCREAMING_CASE`. - ( - @bitfield $(#[$attr:meta])* $vis:vis struct $name:ident($storage:t= y) { $($fields:tt)* } - ) =3D> { - $crate::bitfield!( - #[allow(non_camel_case_types)] - $(#[$attr])* $vis struct $name($storage) { $($fields)* } - ); - }; - - // Implementations shared by all registers types. - (@io_base $name:ident($storage:ty) @ $offset:expr) =3D> { - impl $crate::io::register::Register for $name { - type Storage =3D $storage; - - const OFFSET: usize =3D $offset; - } - }; - - // Implementations of fixed registers. - (@io_fixed $(#[$attr:meta])* $vis:vis $name:ident) =3D> { - impl $crate::io::register::FixedRegister for $name {} - - $(#[$attr])* - $vis const $name: $crate::io::register::FixedRegisterLoc<$name> = =3D - $crate::io::register::FixedRegisterLoc::<$name>::new(); - }; - - // Implementations of relative registers. - (@io_relative $name:ident @ $base:ident) =3D> { - impl $crate::io::register::WithBase for $name { - type BaseFamily =3D $base; - } - - impl $crate::io::register::RelativeRegister for $name {} - }; - - // Implementations of register arrays. - (@io_array $name:ident [ $size:expr, stride =3D $stride:expr ]) =3D> { - impl $crate::io::register::Array for $name {} - - impl $crate::io::register::RegisterArray for $name { - const SIZE: usize =3D $size; - const STRIDE: usize =3D $stride; - } - }; - - // Implementations of relative array registers. - ( - @io_relative_array $name:ident [ $size:expr, stride =3D $stride:ex= pr ] @ $base:ident - ) =3D> { - impl $crate::io::register::WithBase for $name { - type BaseFamily =3D $base; - } - - impl $crate::io::register::RegisterArray for $name { - const SIZE: usize =3D $size; - const STRIDE: usize =3D $stride; - } - - impl $crate::io::register::RelativeRegisterArray for $name {} + ($($tt:tt)*) =3D> { + $crate::macros::register!($($tt)*); }; } diff --git a/rust/macros/io/mod.rs b/rust/macros/io/mod.rs new file mode 100644 index 000000000000..87f7742f4619 --- /dev/null +++ b/rust/macros/io/mod.rs @@ -0,0 +1,3 @@ +// SPDX-License-Identifier: GPL-2.0 + +pub(crate) mod register; diff --git a/rust/macros/io/register.rs b/rust/macros/io/register.rs new file mode 100644 index 000000000000..83ba4dd75ab3 --- /dev/null +++ b/rust/macros/io/register.rs @@ -0,0 +1,276 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! Documention and usage example of the macro can be found at `rust/kerne= l/io/register.rs`. + +use proc_macro2::{ + Group, + Literal, + Span, + TokenStream, // +}; +use quote::{ + quote, + quote_spanned, // +}; +use syn::{ + bracketed, + parenthesized, + parse::Parse, + spanned::Spanned, + token, + Attribute, + Expr, + Ident, + Path, + Result, + Token, + Type, + Visibility, // +}; + +mod kw { + syn::custom_keyword!(stride); +} + +/// Definition of a register array. +/// +/// Specify a size, and optionally a stride. Syntax is of form `[size: EXP= R, $(stride =3D EXPR)?]`. +struct RegArrayDef { + size: Expr, + stride: Option, +} + +/// Offset of a register. +/// +/// Can be either of form +/// * `@ offset` for fixed offset +/// * `=3D> alias` for alias of register `alias`. +/// * `=3D> alias[idx]` for alias of register array `alias`'s `idx`-th ele= ment. +enum RegOffset { + /// Register is located at fixed address. + Fixed { offset: Literal }, + /// Register is an alias of a fixed register. + Alias { alias: Path }, + /// Register is an alias of an element of a register array. + ElementAlias { alias: Path, idx: Expr }, +} + +/// Definition of a single register. +struct Reg { + attrs: Vec, + vis: Visibility, + name: Ident, + storage: Type, + array: Option, + relative_base: Option, + offset: RegOffset, + bitfield_args: Group, +} + +impl Parse for Reg { + fn parse(input: syn::parse::ParseStream<'_>) -> Result { + let attrs =3D input.call(Attribute::parse_outer)?; + let vis =3D input.parse()?; + let name =3D input.parse()?; + let storage =3D { + let content; + parenthesized!(content in input); + content.parse()? + }; + let array =3D if input.peek(token::Bracket) { + let content; + bracketed!(content in input); + let size =3D content.parse()?; + let stride =3D if content.peek(Token![,]) { + let _: Token![,] =3D content.parse()?; + let _: kw::stride =3D content.parse()?; + let _: Token![=3D] =3D content.parse()?; + Some(content.parse()?) + } else { + None + }; + Some(RegArrayDef { size, stride }) + } else { + None + }; + + // Parse offset and the base it's relative to. + let lh =3D input.lookahead1(); + let mut relative_base =3D None; + let offset =3D if lh.peek(Token![@]) { + let _: Token![@] =3D input.parse()?; + + if input.peek(Ident) { + relative_base =3D Some(input.parse()?); + let _: Token![+] =3D input.parse()?; + } + + RegOffset::Fixed { + offset: input.parse()?, + } + } else if lh.peek(Token![=3D>]) { + let _: Token![=3D>] =3D input.parse()?; + let mut alias: Path =3D input.parse()?; + if input.peek(Token![+]) { + let _: Token![+] =3D input.parse()?; + relative_base =3D Some(alias); + alias =3D input.parse()?; + } + + if input.peek(token::Bracket) { + let content; + bracketed!(content in input); + RegOffset::ElementAlias { + alias, + idx: content.parse()?, + } + } else { + RegOffset::Alias { alias } + } + } else { + Err(lh.error())? + }; + + let lh =3D input.lookahead1(); + let bitfield_args =3D if lh.peek(token::Brace) { + input.parse()? + } else { + Err(lh.error())? + }; + + Ok(Self { + attrs, + vis, + name, + storage, + array, + relative_base, + offset, + bitfield_args, + }) + } +} + +pub(crate) struct RegDef { + regs: Vec, +} + +impl Parse for RegDef { + fn parse(input: syn::parse::ParseStream<'_>) -> Result { + let mut regs =3D Vec::new(); + while !input.is_empty() { + regs.push(input.parse()?); + } + Ok(RegDef { regs }) + } +} + +pub(crate) fn register(def: RegDef) -> Result { + let mut outputs =3D TokenStream::new(); + + for reg in def.regs { + let Reg { + attrs, + vis, + name, + storage, + array, + relative_base, + offset, + bitfield_args, + } =3D reg; + + // Use register name's span for generated code, so error messages = (if any) can point to it + // instead of the entire register allocation. + let span =3D name.span().resolved_at(Span::mixed_site()); + + let offset =3D match offset { + RegOffset::Fixed { offset } =3D> quote!(#offset), + RegOffset::Alias { alias } =3D> { + quote_spanned!(alias.span().resolved_at(span) =3D> + <#alias as ::kernel::io::register::Register>::OFFSET + ) + } + RegOffset::ElementAlias { alias, idx } =3D> { + outputs.extend(quote_spanned!(idx.span().resolved_at(span)= =3D> + ::kernel::build_assert::static_assert!( + (#idx) < <#alias as ::kernel::io::register::Regist= erArray>::SIZE + ); + )); + quote_spanned!(alias.span().resolved_at(span) =3D> + <#alias as ::kernel::io::register::Register>::OFFSET + + (#idx) * <#alias as ::kernel::io::register::Regi= sterArray>::STRIDE + ) + } + }; + + outputs.extend(quote_spanned!(span =3D> + ::kernel::bitfield!( + // `#[allow(non_camel_case_types)]` is added since registe= r names typically use + // `SCREAMING_CASE`. + #[allow(non_camel_case_types)] + #(#attrs)* #vis struct #name(#storage) #bitfield_args + ); + + impl ::kernel::io::register::Register for #name { + type Storage =3D #storage; + + const OFFSET: usize =3D #offset; + } + )); + + match array { + None =3D> match relative_base { + None =3D> outputs.extend(quote_spanned!(span =3D> + impl ::kernel::io::register::FixedRegister for #name {} + + #(#attrs)* #vis const #name: ::kernel::io::register::F= ixedRegisterLoc<#name> =3D + ::kernel::io::register::FixedRegisterLoc::<#name>:= :new(); + )), + Some(relative_base) =3D> outputs.extend(quote_spanned!(spa= n =3D> + impl ::kernel::io::register::WithBase for #name { + type BaseFamily =3D #relative_base; + } + + impl ::kernel::io::register::RelativeRegister for #nam= e {} + )), + }, + + Some(def) =3D> { + let size =3D &def.size; + let stride =3D if let Some(stride) =3D &def.stride { + outputs.extend(quote_spanned!(stride.span().resolved_a= t(span) =3D> + ::kernel::build_assert::static_assert!( + ::core::mem::size_of::<#storage>() <=3D #stride + ); + )); + quote!(#stride) + } else { + quote_spanned!(span =3D> ::core::mem::size_of::<#stora= ge>()) + }; + + outputs.extend(quote_spanned!(span =3D> + impl ::kernel::io::register::RegisterArray for #name { + const SIZE: usize =3D #size; + const STRIDE: usize =3D #stride; + } + )); + + match relative_base { + None =3D> outputs.extend(quote_spanned!(span =3D> + impl ::kernel::io::register::Array for #name {} + )), + Some(relative_base) =3D> outputs.extend(quote_spanned!= (span =3D> + impl ::kernel::io::register::WithBase for #name { + type BaseFamily =3D #relative_base; + } + + impl ::kernel::io::register::RelativeRegisterArray= for #name {} + )), + } + } + }; + } + + Ok(outputs) +} diff --git a/rust/macros/lib.rs b/rust/macros/lib.rs index 24f96feaeb34..9b76efe1476f 100644 --- a/rust/macros/lib.rs +++ b/rust/macros/lib.rs @@ -19,6 +19,7 @@ mod fmt; mod for_lt; mod helpers; +mod io; mod kunit; mod module; mod paste; @@ -481,6 +482,14 @@ pub fn paste(input: TokenStream) -> TokenStream { .into() } =20 +#[doc(hidden)] // Documented in `kernel` crate. +#[proc_macro] +pub fn register(input: TokenStream) -> TokenStream { + io::register::register(parse_macro_input!(input)) + .unwrap_or_else(|e| e.into_compile_error()) + .into() +} + /// Registers a KUnit test suite and its test cases using a user-space lik= e syntax. /// /// This macro should be used on modules. If `CONFIG_KUNIT` (in `.config`)= is `n`, the target module --=20 2.54.0 From nobody Sat Sep 26 12:29:11 2026 Received: from LO0P265CU003.outbound.protection.outlook.com (mail-uksouthazon11022089.outbound.protection.outlook.com [52.101.96.89]) (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 51928483BEE; Tue, 1 Sep 2026 16:50:43 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=52.101.96.89 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788281445; cv=fail; b=mL0IU74CqsGs+4Fa1bzOli9y9HZM7PfSwnQSW0DjR7+mTnkAGM4hwjPS/NdQaEx8e9VuaXUBYDMFGoLtMNQ20N+822nXCqBHnhoma7eSrGW4k9+Yy0oDhoe9D9wm3hZy8+B42KhI5axoa8gewpt6mwX8QoBWi2t+d1iCr9OY43Y= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788281445; c=relaxed/simple; bh=NeZrH9hBHB4zTmEF8ZFX2YA8HrTA9PebDOQbzpjmQYI=; h=From:Date:Subject:Content-Type:Message-Id:References:In-Reply-To: To:Cc:MIME-Version; b=Hdr5qdW9fQD0RYU1AiGs63KHF0offZRjV/tvc/T6eEGhLugi9/Ro8w3923aZAleVijQRnXsCQ6qbL8ROEAdixRDHriQB81ncQbUimCU+ksi3OA1u/oE993xonbxaRflXZA2YGad7SUJqi0rbaxwxGlmiFb/CQgmWJ4neB4gctzI= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=garyguo.net; spf=pass smtp.mailfrom=garyguo.net; dkim=pass (1024-bit key) header.d=garyguo.net header.i=@garyguo.net header.b=C1Su3NhW; arc=fail smtp.client-ip=52.101.96.89 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=garyguo.net Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=garyguo.net Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=garyguo.net header.i=@garyguo.net header.b="C1Su3NhW" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=mvBRYlj9+UnNLp7MN92pEmYbVNJ4DyQHXYBOU80QSXWSfc/T/Vp1NowW4GVztK1NJ7muzibfGFZVb6JUwO8FwBa/bWcQxZIO536kvNoW6BOIftUsvg+SjMIBIJ7mmpKWGUNneXajlhR7edYNaU+HV6vwUUY/wG1nvB9NOCtDISVg37DOqXIEAasZ6M/Fxtg76eYjWAY/hMWzeY4GGYxSZE9P1S7ZwOnB9zxnRavRwqGlELh6wUdWAyuahIeK5Aq9X8asGzfoaKU6yaWjHdzsKLX0f01c+f8zb97YW/lA5CIopH/n9RrRie3FiUZ5l0qbZ0UCSPeROSOztLmrxP9IZQ== 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=xMMf2NaTFafdLzX6/WyXaRTQYT3NlqItnQqMVq4Dwvg=; b=VXTEOua/tBAS/YX6993XaizAxvvgjRHkXPgl8MpCWFSo2Qpj1AdO42ADcv7CKYLzqbaUDVIiH+Nkn3AkfDNHqwiqYjtSzxYEePPhZhJ8O63jNgYQpRn/KZk5oQxxS6lDuAMWbe7TuwSHM+TFSp7/KoROiNfF8nJ0jzB73SPTOxfiSq5l/0ysAkcogSLcvuXoDmMBM1vSIR0GK9VHkqWv+dZfvGyA0hkpiX0GiSGp10dkldILgWyNCbLaFChy+6Hh4d21E0qONhzXCOEUF8OM5SolYFCbU5aa7VrzVipda9Ur2o+YDd5E9F6d+OyyFDZjFcURhPXWvaGrkjSGa4srmA== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=garyguo.net; dmarc=pass action=none header.from=garyguo.net; dkim=pass header.d=garyguo.net; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=garyguo.net; s=selector1; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=xMMf2NaTFafdLzX6/WyXaRTQYT3NlqItnQqMVq4Dwvg=; b=C1Su3NhWls1cgGfiCswyLszrAwzeA/CcddbszuJoQGnMX3gJFuWXmOLQ5E+fI5HvBxXBZoN1HV52fJivTVODCIKuKmwS7Kda/c6Uv+TiYtmJjMjBTRNVQV0II2JnAYPRPq0kD5eS5mVPPJ3aM8zaKu4A2/GyRFCPgxgfrs/yNMg= Authentication-Results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=garyguo.net; Received: from LOAP265MB8560.GBRP265.PROD.OUTLOOK.COM (2603:10a6:600:4ab::19) by LO0P265MB7316.GBRP265.PROD.OUTLOOK.COM (2603:10a6:600:2ef::11) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.21.360.13; Tue, 1 Sep 2026 16:50:34 +0000 Received: from LOAP265MB8560.GBRP265.PROD.OUTLOOK.COM ([fe80::f60b:1537:68d7:4fc1]) by LOAP265MB8560.GBRP265.PROD.OUTLOOK.COM ([fe80::f60b:1537:68d7:4fc1%4]) with mapi id 15.21.0360.008; Tue, 1 Sep 2026 16:50:34 +0000 From: Gary Guo Date: Tue, 01 Sep 2026 17:50:26 +0100 Subject: [PATCH v4 02/16] rust: mem: add `transmute` with deferred size check Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260901-typed_register-v4-2-5552b1d59525@garyguo.net> References: <20260901-typed_register-v4-0-5552b1d59525@garyguo.net> In-Reply-To: <20260901-typed_register-v4-0-5552b1d59525@garyguo.net> To: Danilo Krummrich , Alice Ryhl , Daniel Almeida , Miguel Ojeda , Boqun Feng , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Andreas Hindborg , Trevor Gross , Tamir Duberstein , Alexandre Courbot , =?utf-8?q?Onur_=C3=96zkan?= , David Airlie , Simona Vetter , Bjorn Helgaas , =?utf-8?q?Krzysztof_Wilczy=C5=84ski?= Cc: driver-core@lists.linux.dev, rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, nova-gpu@lists.linux.dev, dri-devel@lists.freedesktop.org, linux-pci@vger.kernel.org, Gary Guo X-Mailer: b4 0.15.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1788281431; l=6609; i=gary@garyguo.net; s=20221204; h=from:subject:message-id; bh=NeZrH9hBHB4zTmEF8ZFX2YA8HrTA9PebDOQbzpjmQYI=; b=j/l/DCuKl7OcUMWnABSd13Ln6Fy+sgUce64a4JM/Fv1++hzQ/scyRJ3WUVFZzh30cwCxzsxp/ PBML7zc8eWiAqx0Ok9yR6YV5SMTEWp86+A/0E56M3l62qTqP+wHTIit X-Developer-Key: i=gary@garyguo.net; a=ed25519; pk=vB3uIX95SM4eVrIqo1DWNWKDKD2xzB+yLLLr0yOPYMo= X-ClientProxiedBy: PAZP264CA0173.FRAP264.PROD.OUTLOOK.COM (2603:10a6:102:236::16) To LOAP265MB8560.GBRP265.PROD.OUTLOOK.COM (2603:10a6:600:4ab::19) 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: LOAP265MB8560:EE_|LO0P265MB7316:EE_ X-MS-Office365-Filtering-Correlation-Id: 4df27b02-bd79-4c24-ec51-08df084923d7 X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|366016|1800799024|23010399003|10070799003|376014|7416014|10067099003|6133799003|22082099003|56012099006|5023799004|18002099003|921020; X-Microsoft-Antispam-Message-Info: wdeW5+VFB3fEIr5zcZjfsAtrjANdTlIT9ykQVoW/pdfzlddMezmLHFmGv4F8vk9vbC4GI8C8w5m++kkTpncHDomh0pUG1hkMCxZYRcFHU8wYFzjhUA/t5svLcAUoXDFkNUjcOOloMBg/Nq1Pkm7hGtkB71ZGaYWcymf9uf5hDLtREL4LsL78uZGZzKQBESfgB7DwvcVDGF9uakzPu+qx7WkYuFkokhOUDj0vFVpydRH45SbIfmq4cIm1Zb5gMj81JqdkCcvit5RVKTto6wbGrW862bQT9tBDgqXUxbtzIL6K/DA8s99httLyj+3hhVR8KxDcXshHjrVN8PdnW11dk2K6R0/BRwTsq7xoLTGi5F4kNscGb3ummVuTudESjePcZW4U6zZHDJHs+OtAyv6UjzCD4g5/DHGIxiJ/c2BGxklojNdUz8OaqFBMtG4tKg66kWT7btBsvOUQgHq88iOyFjnB78wSXyNveDNxZINW6eo2eA+YdQKcn5lU8DUxOkTIiI+JoaHyDSYOkLZUVyktJJhsnVSmpmA2+WKLMW+XUa3v+NobWdTCh7JOW+W+mKKgOJKxUtwudzDsNzaL7L+R8rmddTkj1Z3Oy+bSM6QPfEQfXXLNBzP1BzB0qEQ2DRYUw5AUD7/94zpQ0H4AWZWqTNZP5lTErAwCoPPcGBh3OEuSEDCT4ZM8qIrcfZJx+J3FjJHP8hn9Lne2PidQoThmYA== X-Forefront-Antispam-Report: CIP:255.255.255.255;CTRY:;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:LOAP265MB8560.GBRP265.PROD.OUTLOOK.COM;PTR:;CAT:NONE;SFS:(13230040)(366016)(1800799024)(23010399003)(10070799003)(376014)(7416014)(10067099003)(6133799003)(22082099003)(56012099006)(5023799004)(18002099003)(921020);DIR:OUT;SFP:1102; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: =?utf-8?B?ZHhlYVJ4K0FmZFFtOEROb256Ym9SUEVkU25FdXIwVWR6M3JaQkRReFZpd1lM?= =?utf-8?B?RVJ4TU9DazNIdFdjSittOG5aVnV2YkxVSXBWU1FzUUE2b1BBbXJrSnErWGRv?= =?utf-8?B?RjZoM2FDcGx3eUYrYXBOZUtFUjFBQXBHV0p0V3d3eFdjQ1lZeEkrMHUvYndL?= =?utf-8?B?bXRHVW5mWW9uaTJJRU9qbnFoQ09GemcyaGZXZVp3MWo5VGpFY2NNNDI3U0I0?= =?utf-8?B?Z1FYb2pxNzYvV0hQZ0J2SkhLaDdTaWhmdHJWYnNoY3BQYy93b05oTTdsclIw?= =?utf-8?B?V1dXT1FONExYRFZNZ0N2TkpkTTZqUGt1REM1Z1NUM3RoWHVodlB6UWp3Vi9y?= =?utf-8?B?SjhmTWdlZHFmdzRkcCt3aElaQzFndkxUOGJmVjVYb2RxMmI2WXh5REV1TEdp?= =?utf-8?B?alptb1JwaWtnbEZjS0M0TGQ4akc1Q2JlUGtGOGFIWFR3ZUQxZ3ozb2xmUmpo?= =?utf-8?B?VmNUbCs5TkRkY2dkUlBoNXhMazNCRXo1MWJUdjVFMDhTaUthbHErM3FZZVpS?= =?utf-8?B?a3VRdHdGbVBjV0RGZXd0QnE0K29EWk94QmJoY002TUx5L3g1QmFieGFrNGxT?= =?utf-8?B?TU84REx2NUJjS2hDMzBZcUg0UG9CL1IwV2RvNXBLS1hwM0hFKy95K0d2dEtW?= =?utf-8?B?S1JwRnpYejU1dFduV1NuK09PV0htTzFZZktmaURGUHBXSW5kTTdpRUdLRHg3?= =?utf-8?B?MWFBVmpwaE00T1luRG1JdmVDZEoybFRZU0dqa2tiampUeERrM1I1ZWRHcHdY?= =?utf-8?B?MTdNTVROZnpJT0lrclVtaS9FYXg5b0xJeGZRb1BoWWRneHo5R09jaHd3MXdS?= =?utf-8?B?eUlpWDhWelRZNlB6NTVKbWdhL1k5UEQxWTh5dUFBcWY5SXNodTR1U1JlNkRm?= =?utf-8?B?a21jb2FuM0N4NFFibS82eG41ci9zMlovZmxsNG5CcFR6QUtXV3habStwZVpJ?= =?utf-8?B?NUtXaERUZmlqMUhWUHlFWXNPak9JSWgrNnkyZCtYNkNXbXAvMUJXVHNDN0ZC?= =?utf-8?B?ZUUrMG1lWmgvWFdZNzQ1TFlwTGthRzdTa3Zqa1ZtV25NV2xJWG1BSVVuaXpP?= =?utf-8?B?UzJSdFd5Q1RTQ21aOWhXYW1tYTdMSnhaQmVyWVBoMkRTb2JXZVJpa2lWVzZ5?= =?utf-8?B?elJFSnVkdTMwdlRqOXVTN0taYm1FS25Ncmt1eEVNTGI3ejdpRHhMUytjdVFz?= =?utf-8?B?anBEa3A0N3R3Vmk2Rnk5Rm9rNmhoNGFKYlcvRjFLL0dsMHJiN25YRG5qTmli?= =?utf-8?B?Y2YyU1VQeDd0bFdYVWxNZTMvSld3UUJwVTVvelNnL1ZTYTBlY21SNS8rdS8r?= =?utf-8?B?MGdGSlcxdDNTb3dyeTNxYXY2Mi9hQ09JNVQ4TlpjUjlRVUlKd1lnekRwVWpq?= =?utf-8?B?RVByVjJxQURQd0JZMTAxM1JiT3Zsd1RFa2tTa05NRXZOaHJpRUdHdkxTeUs3?= =?utf-8?B?WUwzbmh3c050b3YzeTFJS25vQ3J2RFR2amlZeDJtU1BSSEZoS0l3eVpHUUx1?= =?utf-8?B?dHdjbnZiQy9oelloOVh0ZE83MTFoU0N2bS96K1RUOG5VamN2SnErK2k1WEFr?= =?utf-8?B?ai82TDNHb3JjZGMyb2dMQkowNnZTb3dkSzlUZlRlYVR5RmN1WmFzWU9VK3Yz?= =?utf-8?B?UjIzbW83K05vd0VLR0FmQzBYZWhCbUozeWpqQ0lNQWhkbHFGVFk2NXZvQlhp?= =?utf-8?B?eldxWTVXTWgyVm5CSHVpdkFqdEJIMnp1VUdLREVUNmlFeGtQWkc4UjR1a3V5?= =?utf-8?B?RzJ4cTZoQnNweG4vR244aU9lR1ZUQlFOWS9jaHM2MXI3RVE3czAzTlYxcndm?= =?utf-8?B?ZVQ3OTJCNFBiL0NONmQvWDJ0cXZpSGlzVUY1c0dOL2pCbEIrTzBiYmc0UXgy?= =?utf-8?B?TnM4ZDJkQXBVa1NuVU1zTmh5L2x2eXhMSkI5clhjRzlLMElwQ1lKSytRMVpJ?= =?utf-8?B?UGtRSUEwS1JQNGhRM1lGYWdqN3ZtbFRlYnE5dW0wYmdaVFM1T0V1cTd0NE5q?= =?utf-8?B?Rzl5OXp5ekZLMmxmTGlpZFV1UmYxc0NsOUpxOXBLY21xTnBxUFpTUW9hVUxK?= =?utf-8?B?M1IzS0NjY0dTdG5TYUdvWTRha0NydVRLZzVNZ0hXdllMZXp2NEhhdFIzbHpr?= =?utf-8?B?emMrdlNhUWIyWTlGb0NMaWQ1c3I0R3VUWFVYelQxbUEwU0dIaGM0cXAwVGhJ?= =?utf-8?B?cnFaNkpia3Q5cXFpM1ljU1UzR3I3Q0NMTnZvVkUwcURiSEovcGVlQW1nQTlj?= =?utf-8?B?c01naHFsUGdKcFhIc2VYVVRMWUVDcDBqTjlqbEZsSVIyVjNUb3hCZWpXcVRC?= =?utf-8?B?azV1QzVSWXB6OUlkNkpia2xsQnMxTHU3bVowL1Vjb1ZRZ29QeTd4dz09?= X-OriginatorOrg: garyguo.net X-MS-Exchange-CrossTenant-Network-Message-Id: 4df27b02-bd79-4c24-ec51-08df084923d7 X-MS-Exchange-CrossTenant-AuthSource: LOAP265MB8560.GBRP265.PROD.OUTLOOK.COM X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 01 Sep 2026 16:50:33.9775 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: bbc898ad-b10f-4e10-8552-d9377b823d45 X-MS-Exchange-CrossTenant-MailboxType: HOSTED X-MS-Exchange-CrossTenant-UserPrincipalName: vbOqz92+XyPONSHxNyvYRGl/7acWbGhSNq1BlHY/8GrGj5wx+Lc2gpTv6U3qxuIXaRaxxfkKr25WzOEFerEK4g== X-MS-Exchange-Transport-CrossTenantHeadersStamped: LO0P265MB7316 Implement a `transmute/safe_transmute` that checks size at monomorphization time instead of type-checking time. This allows more cases where we know that the size matches but this is not generically checkable. The signature is equivalent to the unstable `transmute_neo` function in the standard library. A safe variant is provided to use with types implementing `FromBytes` and `IntoBytes`. Existing users of `transmute_copy` to bypass size checks are converted. Signed-off-by: Gary Guo Acked-by: Miguel Ojeda Reviewed-by: Alexandre Courbot Tested-by: Alexandre Courbot --- Changes since v3: - Renamed the methods to `transmute` and `safe_transmute`, so the name `transmute_unchecked` is for the completely unchecked variant instead, matching that of Rust intrinsics. --- rust/kernel/device_id.rs | 3 +- rust/kernel/lib.rs | 1 + rust/kernel/mem.rs | 99 ++++++++++++++++++++++++++++++++++++++++++= ++++ rust/kernel/sync/atomic.rs | 4 +- 4 files changed, 103 insertions(+), 4 deletions(-) diff --git a/rust/kernel/device_id.rs b/rust/kernel/device_id.rs index c81fca5b4986..f0b9cb84e58e 100644 --- a/rust/kernel/device_id.rs +++ b/rust/kernel/device_id.rs @@ -146,8 +146,7 @@ impl IdArray { /// If the device implements [`RawDeviceIdIndex`], consider using [`Id= Array::new`] instead. pub const fn new_without_index(ids: [T; N]) -> Self { // SAFETY: `T` is layout-wise compatible with `T::RawType`, so is = the array of them. - let raw_ids: [MaybeUninit; N] =3D unsafe { core::mem::= transmute_copy(&ids) }; - core::mem::forget(ids); + let raw_ids: [MaybeUninit; N] =3D unsafe { crate::mem:= :transmute(ids) }; =20 Self { ids: raw_ids, diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs index 4d5c96ddc49c..7225abc64084 100644 --- a/rust/kernel/lib.rs +++ b/rust/kernel/lib.rs @@ -98,6 +98,7 @@ pub mod kunit; pub mod list; pub mod maple_tree; +pub mod mem; pub mod miscdevice; pub mod mm; pub mod module; diff --git a/rust/kernel/mem.rs b/rust/kernel/mem.rs new file mode 100644 index 000000000000..958e43bbcc3a --- /dev/null +++ b/rust/kernel/mem.rs @@ -0,0 +1,99 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! Basic utilities for dealing with memory, values, and types. + +use crate::prelude::*; + +/// Transmute between two types. +/// +/// Use this instead of [`core::mem::transmute`] when it is known that siz= es are identical but this +/// cannot be proven by the compiler. +/// +/// This is equivalent to Rust's `transmute_unchecked` intrinsics. +/// +/// # Safety +/// +/// All safety requirements of [`core::mem::transmute`] apply, plus that t= he size `Src` and `Dst` +/// must match. +/// +/// # Example +/// +/// This can be used when types are known to have the same size, but only = at runtime. +/// ```no_run +/// # use core::any::TypeId; +/// fn to_u32(v: T) -> Option { +/// if TypeId::of::() !=3D TypeId::of::() { +/// return None; +/// } +/// +/// // `core::mem::transmute` won't work here. +/// // SAFETY: We've checked that `T` is u32! +/// Some(unsafe { kernel::mem::transmute_unchecked(v) }) +/// } +/// +/// to_u32(1u32); +#[inline(always)] +pub const unsafe fn transmute_unchecked(val: Src) -> Dst { + // SAFETY: This is identical to `transmute` except that we bypassed th= e size check; which is + // true per safety requirement. + unsafe { core::mem::transmute_copy(&core::mem::ManuallyDrop::new(val))= } +} + +/// Version of `transmute` that performs size check at monomorphization-ti= me. +/// +/// Use this instead of [`core::mem::transmute`] when it is known that siz= es are identical but this +/// cannot be proven by the compiler during type checking and can be prove= n during monomorphization. +/// +/// The signature is equivalent to Rust standard library's unstable `trans= mute_neo` and that of +/// [RFC 3844](https://github.com/rust-lang/rfcs/pull/3844). +/// +/// # Safety +/// +/// Same as [`core::mem::transmute`]. +/// +/// # Examples +/// +/// This is typically used in generic code where it's known that type will= have the same size, but +/// the compiler cannot prove it generically. +/// ```no_run +/// trait IsU32 {} +/// impl IsU32 for u32 {} +/// +/// fn to_u32(v: T) -> u32 { +/// // `core::mem::transmute` won't work here. +/// // SAFETY: We know that `v` is u32! +/// unsafe { kernel::mem::transmute(v) } +/// } +/// +/// to_u32(1u32); +/// ``` +#[inline(always)] +pub const unsafe fn transmute(val: Src) -> Dst { + const_assert!(size_of::() =3D=3D size_of::()); + + // SAFETY: Size is checked above. Other safety requirements follow tho= se of the function. + unsafe { transmute_unchecked(val) } +} + +/// Safely transmutes a value of one type to a value of another type of th= e same size. +/// +/// The sizes are checked during monomorphization. +/// +/// This can be considered as generic version of [`zerocopy::transmute!`] = macro that defers the size +/// check and thus can be used in more cases. +/// +/// # Examples +/// +/// ```no_run +/// fn to_u32(v: T) -> u32 { +/// // `zerocopy::transmute!` won't work here. +/// kernel::mem::safe_transmute(v) +/// } +/// +/// to_u32(1i32); +/// ``` +#[inline(always)] +pub const fn safe_transmute(val: Src) -> D= st { + // SAFETY: transmute is safe with `IntoBytes` and `FromBytes` bounds. + unsafe { transmute(val) } +} diff --git a/rust/kernel/sync/atomic.rs b/rust/kernel/sync/atomic.rs index 9cd009d57e35..6d27898add42 100644 --- a/rust/kernel/sync/atomic.rs +++ b/rust/kernel/sync/atomic.rs @@ -140,7 +140,7 @@ pub unsafe trait AtomicAdd: AtomicType { const fn into_repr(v: T) -> T::Repr { // SAFETY: Per the safety requirement of `AtomicType`, `T` is round-tr= ip transmutable to // `T::Repr`, therefore the transmute operation is sound. - unsafe { core::mem::transmute_copy(&v) } + unsafe { crate::mem::transmute(v) } } =20 /// # Safety @@ -149,7 +149,7 @@ const fn into_repr(v: T) -> T::Repr { #[inline(always)] const unsafe fn from_repr(r: T::Repr) -> T { // SAFETY: Per the safety requirement of the function, the transmute o= peration is sound. - unsafe { core::mem::transmute_copy(&r) } + unsafe { crate::mem::transmute(r) } } =20 impl Atomic { --=20 2.54.0 From nobody Sat Sep 26 12:29:11 2026 Received: from LO3P265CU004.outbound.protection.outlook.com (mail-uksouthazon11020089.outbound.protection.outlook.com [52.101.196.89]) (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 41A19483BF2; Tue, 1 Sep 2026 16:50:42 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=52.101.196.89 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788281444; cv=fail; b=Y5Ams3kvbZIjEi7/igOedcJDwuXswqb8pcoR/oZQLveJtNjiQv4y0cE+X6PMKzyJ5cJfcJlClbfooX1ZB8UdW3LvAzXS77qJe9RSRMkzZjLAyyz9Zn1b+kpewAyZdGHE8AU5aFiJpTM9CP2h2JPgvgA/e8CiVvfktEWhen5ROGg= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788281444; c=relaxed/simple; bh=aqM1m8hQVBQcfuLUtUp2YErCndlB9UHKXD3Qyyki3X0=; h=From:Date:Subject:Content-Type:Message-Id:References:In-Reply-To: To:Cc:MIME-Version; b=WX/VVh5OnbjEZIKe3DOjCp5M9sY40y6PB8CZb/kEXa8vIPF+MoXLVN85NyHBnFN5k4Bx14DMhE3yZpVEY2o4HLEGExtUFwg+9UdAphQHEOnUNAHxI2azFwtyp/8k4mcgH852/oz7W45JLAczvedhmmn96RMsQTAqdlPYe6/DEfg= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=garyguo.net; spf=pass smtp.mailfrom=garyguo.net; dkim=pass (1024-bit key) header.d=garyguo.net header.i=@garyguo.net header.b=SOHoEwq8; arc=fail smtp.client-ip=52.101.196.89 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=garyguo.net Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=garyguo.net Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=garyguo.net header.i=@garyguo.net header.b="SOHoEwq8" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=CKIsAk9ZbaU/7G2lApYykoq+BCVINm1rMpOsI7ZJDusqWkVGUlmL/sLSpnlNOcTM6uPqH5IpX4OU9X1qKNL13se4CfLuNK8pe2o81gDJmo0rEuB537OL5Fa7bhYoQ0UxN4ln9OdAO/1KvIHPAOflEIE5sRL/MTCUYKIfuE/fmag1MENl76Z72gRoAi36VmaEp3cqxJYj8gxFiut97H206Kq4WISEnibbdMZS4GXDr3hvH/dAgSRFilkS4GFi5BzqVZTQdxy3C6RW8pQ7TCoSw9lYCY6lwk0e0Tlz3J6Yav77HYG898NdbDzRphowMQuYGOEcPqshGxSIpKNuv9WYzw== 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=/LIgUQ0Lq8xjNZ53P0UEI58qk7Zc3xSvgVWc9JA3104=; b=rdRvGCagnZmzO82qSasZMQwn+pWawA1tLow81rAxzZDwHUk+UW2IGgqHII7pKKKZsPRfV7wi+Fj6Bpq4KZ5RqqgL6Z4IY4MoVC5rx+QrQbI9lOM31qKwo9auZbLAgLv/T0XCV2QeKNvOcdUjXXtFJUAeIBkVMMj5LwulZQHxGLL7y6jag3LI4hQYU4UFA+ll79+WRMVKBBDSdPPuRfvUjaKb0bt2vFZSApgSWNwqNy4eABCPNdMCUmlFwO4i2QsBoS/3eNIN0JWDHq8ytSM+WqVsiunsX9DISHnMyU1KWuLFTi0K4Pbw4b5CrzDeY47e3BacknXb0jAgv0Oc5xInKw== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=garyguo.net; dmarc=pass action=none header.from=garyguo.net; dkim=pass header.d=garyguo.net; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=garyguo.net; s=selector1; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=/LIgUQ0Lq8xjNZ53P0UEI58qk7Zc3xSvgVWc9JA3104=; b=SOHoEwq8wTzcO0q+2kl61gVgKzaME7WAm0U0ocdel/CmP84P6Rol4h/4mEB7S7Qj42u8fnPCSfuZbrFT/gqcvjGInEpTgzytogz9CjspFR70CetKOVP+6GHocO0eQIyzdcfQAnmXG+hNsqP4fYWq42i2yRU48me1fhwajO7lTHg= Authentication-Results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=garyguo.net; Received: from LOAP265MB8560.GBRP265.PROD.OUTLOOK.COM (2603:10a6:600:4ab::19) by LO0P265MB7316.GBRP265.PROD.OUTLOOK.COM (2603:10a6:600:2ef::11) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.21.360.13; Tue, 1 Sep 2026 16:50:35 +0000 Received: from LOAP265MB8560.GBRP265.PROD.OUTLOOK.COM ([fe80::f60b:1537:68d7:4fc1]) by LOAP265MB8560.GBRP265.PROD.OUTLOOK.COM ([fe80::f60b:1537:68d7:4fc1%4]) with mapi id 15.21.0360.008; Tue, 1 Sep 2026 16:50:35 +0000 From: Gary Guo Date: Tue, 01 Sep 2026 17:50:27 +0100 Subject: [PATCH v4 03/16] rust: mem: add `AsRepr` and `AsReprMut` Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260901-typed_register-v4-3-5552b1d59525@garyguo.net> References: <20260901-typed_register-v4-0-5552b1d59525@garyguo.net> In-Reply-To: <20260901-typed_register-v4-0-5552b1d59525@garyguo.net> To: Danilo Krummrich , Alice Ryhl , Daniel Almeida , Miguel Ojeda , Boqun Feng , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Andreas Hindborg , Trevor Gross , Tamir Duberstein , Alexandre Courbot , =?utf-8?q?Onur_=C3=96zkan?= , David Airlie , Simona Vetter , Bjorn Helgaas , =?utf-8?q?Krzysztof_Wilczy=C5=84ski?= Cc: driver-core@lists.linux.dev, rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, nova-gpu@lists.linux.dev, dri-devel@lists.freedesktop.org, linux-pci@vger.kernel.org, Gary Guo X-Mailer: b4 0.15.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1788281431; l=6839; i=gary@garyguo.net; s=20221204; h=from:subject:message-id; bh=aqM1m8hQVBQcfuLUtUp2YErCndlB9UHKXD3Qyyki3X0=; b=enlmFjuj+HDXPvXRhhJv3ET7jkW9NEJzhAbRX6Kuy55iCm4ZJ6qZ+7W/khraQMtw/YboG3onn dN22aHbn6dEBaecVUk3QbZ6s62Z+Vx8zuUTzZhWR1AqeLsmfTbKM7DV X-Developer-Key: i=gary@garyguo.net; a=ed25519; pk=vB3uIX95SM4eVrIqo1DWNWKDKD2xzB+yLLLr0yOPYMo= X-ClientProxiedBy: PAZP264CA0173.FRAP264.PROD.OUTLOOK.COM (2603:10a6:102:236::16) To LOAP265MB8560.GBRP265.PROD.OUTLOOK.COM (2603:10a6:600:4ab::19) 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: LOAP265MB8560:EE_|LO0P265MB7316:EE_ X-MS-Office365-Filtering-Correlation-Id: f3b5ef96-960c-439d-df8f-08df08492495 X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|366016|1800799024|23010399003|10070799003|376014|7416014|10067099003|6133799003|22082099003|56012099006|18002099003|921020; X-Microsoft-Antispam-Message-Info: ApGvS0sXhGTZNZI29jPsMFXuEpurZ3CNR3qp8UHrTXYHyaIVArZ4Sg8tMqVL195V6WqsHrCkBvP9kH3R67T4ybjJsaWUVqbnsiJ85d81OZ04TFfMQFTl4GUbbaxpTrbNCA/6daDFmUpXdfGDKAeaTyfjGmVm9+EjvwYEoRt+aNpjPYMO7v5kstKUqMqD1d4GoQCciDH6Pr6Qwx5JWIvJElFyEvmp0Q14qnockQqreR2rjOCYA+uTSDAs6teTlT8qvZhqPw8QjwgQiOK5tXt/GjpiraiHdnfxVFD5udtgRZTjARg/arwliEDmgxYWcdnHn0gsDnGtlFFEmSOPVXp0C6W1FPE0ACf+6aflhyjxuirxvEr+OeZNeiQnCCL1VEWQWXo1AsKMj6fuIK9nd7WSxo9ClcRmn67BXocLY0OgsigIWTUxO7ZniSgEyVHtR6RZ16/o0PX4EyOiwe9OkAWibxrFMVL6BL6/uSG3XT++6gtLeQjQ9Ca67WrlpkV5NqfRMDDKwdNlmczLvCTu7vtEef6PPtIdsT7iskOcA7Wl9TiMQU39YFZnxx1PyYcIpvlCH0mA6maNHCaOEmkxUQUP3RdX3UFphfzjuRjWrGRargdyywJcZzwAdpHiuJK7NC6tqdn/QVlZ5ZnnGRgUnuniAx9Q31zrZJg8LqCm9hTAi0a6nRISsC3jUbU/8SKbWwHEnvpVBQ1Lj8fdWCanSrNOyw== X-Forefront-Antispam-Report: CIP:255.255.255.255;CTRY:;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:LOAP265MB8560.GBRP265.PROD.OUTLOOK.COM;PTR:;CAT:NONE;SFS:(13230040)(366016)(1800799024)(23010399003)(10070799003)(376014)(7416014)(10067099003)(6133799003)(22082099003)(56012099006)(18002099003)(921020);DIR:OUT;SFP:1102; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: =?utf-8?B?a290RmdYSTNISnRGMmpITTcwNysveFM2TVNnUHRkR1RyNlNnclkvVHNidGh0?= =?utf-8?B?aFovMW5FaU4xVDllYjZ1Q2ExUVg1WGdVVldRZkduTlVHWkEvajBPRFdMTkIr?= =?utf-8?B?cUJtRnVxOWVLcnlJYkE5QStYaXpmOW1oTnpxSVFRSnoxOFpPQlE5L2NhS01X?= =?utf-8?B?ZjVQSTJGVzFQRkxtUi8yYnRwMWI4UG9GcDhQWjhtWnZWcTV0dEFZcG5TRExn?= =?utf-8?B?WDNIVDNDU2dkWTZUL3VkVFFtZFg3cHR0OVV0NC94TW5ZRmJ5SjJ5OVJ5VDRW?= =?utf-8?B?dUZHVkI4dnU5YlQ3czdmM2tpU2xXaEIxdlVuNXM2djlmcXk5ZnhWL2xGTHln?= =?utf-8?B?L1hVaFZVWm5rTURjWVA2aS8rUlFSY2F0bEZNcnhuRzZod3l2ODV1a3pHdFE3?= =?utf-8?B?Y1hOWStPYXErVW1tWUd5QTQ4K1dCNmJwZlU0UGlqczhNd0I4b3l1WUdtc1g3?= =?utf-8?B?eWo5WU9zQ0ZrN095a2laY2lvQzU3VldEcDFqeWxkOE9xclllc2hnd21wMG0y?= =?utf-8?B?KzFkamFXLzliQUdzVmJKNjFsREYwdzRnck5ibXhqOFhMMXNWZVpQejBCazdX?= =?utf-8?B?b2U0M1M5WDJiUW5MTlpXRC9PR1dUS3pSQVdIWkJYYmlPY0wxNWgzWVpUdkVm?= =?utf-8?B?SW12SDNnUVV4OUNUSVhKNEtNTFgwVnI5ckF4aW51WmduYWJDam90eFJWV2dy?= =?utf-8?B?VllrUHBQL1dXRHRTZit2RUFiSnBIYWUxcGxOdUQ1TVNDZytuK2p6MUNUYzRw?= =?utf-8?B?WkowbnFFeGJ1STdNMmtSRE55UkNST2FwU2orN3lKTEhzVmRyc1NiVFkrdWhK?= =?utf-8?B?bTNONGxSV0xaR0lVSGJzSkwrTVZFVVo0aGRGNHR4NTN3NG1jT0ErVmwwaW9N?= =?utf-8?B?UVRLSjB4bG12ZC9GT25YR3h4cUJyaCtTT0YwbEU1cnJQbnlaWGxURFdNOXY1?= =?utf-8?B?SWVieWc1V2dDRDAvcWdxN0VoMmJUNlM5Y3BtSWViWVZMUms5eFVsMlA3RnE3?= =?utf-8?B?MEprRzcrOGM0QkYvcHY1V2h4d1hGVThGTmdVUVVVK1NrazlrK3d5dUU2V1lV?= =?utf-8?B?ZmN5NzlkSzkwYUNBT2p4dmZaMDcyWkdzZW5lWmtWN2V5Z2cvTXJQYzIzWmhS?= =?utf-8?B?MnA3SzMvL0l1ODl0RDZBTjJvMElxUU8xZE5HMGFzZ2RLQkhLNjZEbWRZUnhD?= =?utf-8?B?bEUrYnB2K0dOVEhzYWxDV0RuMnFHaStUekNWMWdoSHVnbDRxWHp1N1VSUTVp?= =?utf-8?B?dFY4WDZaeFJUdm5OZU1nekdnUUlwdjlhL1lVMEpCanlTQ2xZbmtYbnQ1Nmpk?= =?utf-8?B?NEFQamZBRnBjMHRwTDgvNTdLOFZnd05zRzhWMEdRTWJxVXkrNktLNXhRd1Er?= =?utf-8?B?bnNxLzhwd01RZWxJNklHVkc2N1ZCb2VsdjU0Si9WVjRxeFFpdHQrQk95VE8x?= =?utf-8?B?RmRxaXpiUXpCTjJDUmh3dTdNVml5M3J6dm1Ma0lXTUNqUS9JRS92YXdiK0pl?= =?utf-8?B?c0dUbzlKZ0NnclkzdjVoa0VCNkhHZkFjNjhwcW5tVzNmKzUyMzJ3TVdvYkVp?= =?utf-8?B?Z0Z5cnRpWngzeFhBaUhHZm1ZZ1pWanZRa2p2WC9NSjJlSEVBU25Tc1VHaHhk?= =?utf-8?B?ckZreTNjS2YwNlJIV3hFdmI0eEN6OU1oSms3RTV6OVRsVG5zUGZ3MVJ6aWJP?= =?utf-8?B?djNBT05IUmQ3MWg3dGxrMy9JMUk5OVl2NXoxYVJNQWpXakl0Njhoc3NIM1NP?= =?utf-8?B?UHgzRDFVRW5XNXlWWmpVenlyL1VpMlFwTmtFbEFpY1VMc2JVSVZjUGVZdmdF?= =?utf-8?B?dzNJb3BTZ1VMM2lNZEZGelkwTko5bEJkOHIzL1ArWEJVMlVsM2FaQms5aFZy?= =?utf-8?B?OE1oam94Wi9PWnh2N3FyMGhNek5VeWttWjRRaEhWczBIamtMaGJvaHUvOTJt?= =?utf-8?B?dGo4enlzSHNMVWZqTEVsNVFjK0lqdlQzbnhYWTF4bHNNMWRHK0tTQi9YbTJ4?= =?utf-8?B?dy83OC96N1ltZHRnU2tkN0FQMGF0K1pyc3huZXhNamxVaFErNWRFUzZFUzZM?= =?utf-8?B?dUFIOUZQamxnbHNFWEJQYlQ2c000c1lTdHhHZHlZa2ZidzdxaCs1YlMxSGFr?= =?utf-8?B?Y3MxY2lNSFhNUUZqK0t2OEJwR2dLRVkwdHNtVkR1b1JnUDdDK2hHb0gyaWdI?= =?utf-8?B?UEdwTEp1R3lzM2RmbWpDUWhFVXhtZmR6Yno4TWE5OGFFc0FORlE3MFNkWEpJ?= =?utf-8?B?QjhYSkpHM3FIdTlKVmc4OThBQzFhRlg5YjFOYnNkdkdkV3kyVEVpMnBsNERH?= =?utf-8?B?SUVZL1ArY0VITFpLYU5HZWdPSHl3enNTYzI2dkVRSHZWV3Z5bWVMZz09?= X-OriginatorOrg: garyguo.net X-MS-Exchange-CrossTenant-Network-Message-Id: f3b5ef96-960c-439d-df8f-08df08492495 X-MS-Exchange-CrossTenant-AuthSource: LOAP265MB8560.GBRP265.PROD.OUTLOOK.COM X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 01 Sep 2026 16:50:34.9904 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: bbc898ad-b10f-4e10-8552-d9377b823d45 X-MS-Exchange-CrossTenant-MailboxType: HOSTED X-MS-Exchange-CrossTenant-UserPrincipalName: LbR3wIuREzRA1bxNhtdNCuSc+pw981etpsR8CeUmlaOSVyzqBRLbApVngmem/uPWISMYle0oU3lq4n0zEJZ6yA== X-MS-Exchange-Transport-CrossTenantHeadersStamped: LO0P265MB7316 Some API like atomics and I/O operate on primitives only; therefore other types would need to converted to these primitive first. Add two traits `AsRepr` and `AsReprMut` to indicate that the type can be turned into a primitive for these operations. `T: AsRepr` means that `&T` can be viewed as `&T::Repr` and thus it needs to support transmutability in one direction. `T: AsReprMut` means that `&mut T` can be viewed as `&mut T::Repr` and thus it needs to support bi-directional transmutability. To avoid duplicating implementations, all repr types are normalized to unsigned integers. Signed-off-by: Gary Guo Acked-by: Miguel Ojeda Reviewed-by: Alexandre Courbot Tested-by: Alexandre Courbot --- Changes since v3: - Added `as_repr` and `as_repr_mut` so the name makes sense (Alex). I did not add `Copy` bound because it is not necessary (adding it won't simplify the implementation without also requring `Self: Copy`, which I don't want to add). - Dropped round-trip transmutability as a concept, as it can be proved correct because `from_repr_unchecked(into_repr(v))` is basically just `move v`. Even for the `AtomicType`'s use case where copies are made, it can still be proven by observing that `from_repr_unchecked(copy into_repr(v))` is not distinguishable from `from_repr_unchecked(into_repr(copy v))`. --- rust/kernel/mem.rs | 132 +++++++++++++++++++++++++++++++++++++++++++++++++= ++++ 1 file changed, 132 insertions(+) diff --git a/rust/kernel/mem.rs b/rust/kernel/mem.rs index 958e43bbcc3a..0bfd6929ae45 100644 --- a/rust/kernel/mem.rs +++ b/rust/kernel/mem.rs @@ -97,3 +97,135 @@ pub const fn safe_transmute(val: Src) -> Dst { // SAFETY: transmute is safe with `IntoBytes` and `FromBytes` bounds. unsafe { transmute(val) } } + +/// Type that is layout-compatible with a primitive representation. +/// +/// # Safety +/// +/// - `Self` must have the same size and alignment as [`Self::Repr`]. +/// - `Self` can be [transmutable] to [`Self::Repr`]. +/// - Neither `Self` nor [`Self::Repr`] contains interior mutability. +/// +/// The above basically says that `&Self` can be transmuted to `&Self::Rep= r`. +/// +/// [transmutable]: core::mem::transmute +pub unsafe trait AsRepr: Sized { + /// Primitive representation of this type. + type Repr; + + /// Convert from `&Self` to [`&Self::Repr`](AsRepr::Repr). + #[inline(always)] + fn as_repr(this: &Self) -> &Self::Repr { + // SAFETY: Per safety requirement of the trait. + unsafe { core::mem::transmute(this) } + } + + /// Convert from `Self` to [`Self::Repr`]. + #[inline(always)] + fn into_repr(this: Self) -> Self::Repr { + // SAFETY: Per safety requirement of the trait. + unsafe { transmute(this) } + } + + /// Convert from [`Self::Repr`] to `Self`. + /// + /// # Safety + /// + /// `repr` must be a valid bit pattern of `Self` and satisfy type-spec= ific invariants of it. + /// + /// Alternatively, if `repr` is previously obtained using [`Self::into= _repr`], and each + /// `from_repr_unchecked` should corresponds to a unique `into_repr` c= all, then it is safe to + /// call as well (this means that we're undoing a `into_repr` call get= ting the exact bytes + /// back). + /// + /// This method makes no guarantee if a `into_repr` corresponds to mul= tiple + /// `from_repr_unchecked` (i.e. copies are made), to allow for cases w= here `Repr` is a pointer + /// and the user of the API wants ownership transfer. Users that want = the ability to call + /// `from_repr_unchecked` after copying can require `Copy` bound expli= citly. + #[inline(always)] + unsafe fn from_repr_unchecked(repr: Self::Repr) -> Self { + // SAFETY: Per safety requirement, `repr` is valid repr of `Self`,= or it is previously from + // `into_repr`, in which case we're undoing the transmute so it is= also safe. + unsafe { transmute(repr) } + } +} + +/// Type that is bi-directionally transmutable with a primitive representa= tion. +/// +/// # Safety +/// +/// - [`Self`] must be [transmutable] from [`Self::Repr`]. +/// +/// [transmutable]: core::mem::transmute +/// [`Self::Repr`]: AsRepr::Repr +pub unsafe trait AsReprMut: AsRepr { + /// Convert from `&mut Self` to [`&mut Self::Repr`](AsRepr::Repr). + #[inline(always)] + fn as_repr_mut(this: &mut Self) -> &mut Self::Repr { + // SAFETY: Per safety requirement of the trait. + unsafe { core::mem::transmute(this) } + } + + /// Convert from [`Self::Repr`](AsRepr::Repr) to `Self`. + #[inline(always)] + fn from_repr(repr: Self::Repr) -> Self { + // SAFETY: Per safety requirement of the trait. + unsafe { transmute(repr) } + } +} + +// SAFETY: `bool` has the same size and alignment as `u8`, and Rust guaran= tees that `bool` has +// only two valid bit patterns: 0 (false) and 1 (true). Thus `bool` can be= transmuted to `u8`. +// Neither types contain interior mutability. +unsafe impl AsRepr for bool { + type Repr =3D u8; +} + +// SAFETY: `*mut T` has the same size and alignment with `*const c_void`, = and thus `*mut T` is +// transmutable to `*const c_void`. Neither types contain interior mutabil= ity. +unsafe impl AsRepr for *mut T { + type Repr =3D *const c_void; +} + +// SAFETY: `*mut T` is transmutable from `*const c_void`. +unsafe impl AsReprMut for *mut T {} + +// SAFETY: `*const T` has the same size and alignment with `*const c_void`= , and is transmutable to +// `*const c_void`. Neither types contain interior mutability. +unsafe impl AsRepr for *const T { + type Repr =3D *const c_void; +} + +// SAFETY: `*const T` is transmutable from `*const c_void`. +unsafe impl AsReprMut for *const T {} + +macro_rules! int_impl { + ($($unsigned:ident $signed:ident ,)*) =3D> {$( + // SAFETY: $unsigned has the same size and alignment with itself, = and is transmutable to + // itself. It does not contain interior mutability. + unsafe impl AsRepr for $unsigned { + type Repr =3D $unsigned; + } + + // SAFETY: $unsigned is transmutable from itself. + unsafe impl AsReprMut for $unsigned {} + + // SAFETY: $signed has the same size and alignment with $unsigned,= and is transmutable to it + // Neither types contain interior mutability. + unsafe impl AsRepr for $signed { + type Repr =3D $unsigned; + } + + // SAFETY: $signed is transmutable from $unsigned. + unsafe impl AsReprMut for $signed {} + )*}; +} + +int_impl! { + u8 i8, + u16 i16, + u32 i32, + u64 i64, + // `usize` is not normalized to particular integer for portability. + usize isize, +} --=20 2.54.0 From nobody Sat Sep 26 12:29:11 2026 Received: from LO3P265CU004.outbound.protection.outlook.com (mail-uksouthazon11020089.outbound.protection.outlook.com [52.101.196.89]) (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 46CDF484255; Tue, 1 Sep 2026 16:50:44 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=52.101.196.89 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788281447; cv=fail; b=V7f2shaUUPq35fmDDFsuJsWVbB8h2uGyzGuAnV2Ohp7any9bZKzV7wv4efkj1AtI0LV8T3rlWnA71pYeTfuvwokWNq/sP27OiqqR/JLxI/uw98ZNZtsday4DKhIxBlHCc0cW6Hqn27C3ivfgLGmcqL5VGtCTIuwHhHusW8mJuNE= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788281447; c=relaxed/simple; bh=a4e0IW7uOdgVQTyEzPyQL8e411BYAWC48EB6qOIO1d8=; h=From:Date:Subject:Content-Type:Message-Id:References:In-Reply-To: To:Cc:MIME-Version; b=mgGM1Mx2F1/Np6SL0FIIgzwyBATBGYicls9DkHKL7o1yIUjuq9RoWK8/v56E7Em8RgueKL9LORklmA+BsLTakLqMatTEgH9fie29bYwsPme4OCyNPqZUfOWomQiHdSbgcRZdRIpXj+IxvRttROdCGbXlbuQ4Q+JarebhKKgzD44= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=garyguo.net; spf=pass smtp.mailfrom=garyguo.net; dkim=pass (1024-bit key) header.d=garyguo.net header.i=@garyguo.net header.b=TEr9m4EL; arc=fail smtp.client-ip=52.101.196.89 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=garyguo.net Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=garyguo.net Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=garyguo.net header.i=@garyguo.net header.b="TEr9m4EL" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=fQ4ofD/ecyR+qtWKjVxAPyO4DKorOeZKCs9638HX3EZBRX9cQLnI5h95VIW2MpooS4F3JhOUMCFCuULCbmIQdGj/F3U82t6vaMNivwsYj1geRO1GZDV2nyuZQ8aJHBSuOc4mr/5GAb0RJaOVkHnQ0RA1gU3c40c4sujkPfm14Zjb+1BbMkJ4Zg2tOqkyQp498ZbR5HZXBkYJEbs2ynASC8m46VyTOkbQHs7ZzFZEiPiqrqagQUlRAke9NJidr0a1IceFs/TRgDMXIwvaSvMqwGtCoU/xz/Iw3uq/9p7ktRPTtqxzfETnQL8SQnV9EVZqCXXKTXFms9yDv92hbbxNaA== 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=+DEKIwi5XRlMtlt/hNGKxVbZBbR6FHV50Rhc592Fzww=; b=cmo77OThY5Pav47wpF+TgeTtRCgi2UV8Sb9clQG+3HY61JerDMtETb83U/3t5kiZIdSqGxqlRzPeL8BUhUNUIiub83KLapGEGRfn1QZFCZyI8ybXxrpREBxLB4aV3PbFxPKiG5wOKsPgVl1W/MUbgNo5A6hk56IRd882q/KtFXprvvb7lpXNXZNAW7bK8Hj5gdkRW4ALFV98wpiQf/HU0Vxhnxe2iWgwn0jkQ4ySEQ19Z/7aL0XBKAPXnZbYg77tcb8ghEfQiRgF1V0PmvDeiRWnol8GNtuR09bbVHyG7DgDwTG518aQtMFs0S66PMUTTx34puvbk/UGf+lGDah3mQ== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=garyguo.net; dmarc=pass action=none header.from=garyguo.net; dkim=pass header.d=garyguo.net; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=garyguo.net; s=selector1; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=+DEKIwi5XRlMtlt/hNGKxVbZBbR6FHV50Rhc592Fzww=; b=TEr9m4ELenwK36xlSKUYV5QS3LW2YU1C/eK1SXdbzglnkfgoWyFVChI5Ugh6W7T33owIDtqkPI4fh/sdLkUoYLrhF6nlH7GGrgaOsN5qYq1Kie4nyXEPN3wc/eUQVRGBU57fCI6rUDacp/rnEDvqSsuDNqjQYsQ21CBAJsbZUlg= Authentication-Results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=garyguo.net; Received: from LOAP265MB8560.GBRP265.PROD.OUTLOOK.COM (2603:10a6:600:4ab::19) by LO0P265MB7316.GBRP265.PROD.OUTLOOK.COM (2603:10a6:600:2ef::11) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.21.360.13; Tue, 1 Sep 2026 16:50:36 +0000 Received: from LOAP265MB8560.GBRP265.PROD.OUTLOOK.COM ([fe80::f60b:1537:68d7:4fc1]) by LOAP265MB8560.GBRP265.PROD.OUTLOOK.COM ([fe80::f60b:1537:68d7:4fc1%4]) with mapi id 15.21.0360.008; Tue, 1 Sep 2026 16:50:36 +0000 From: Gary Guo Date: Tue, 01 Sep 2026 17:50:28 +0100 Subject: [PATCH v4 04/16] rust: io: perform conversions using `AsRepr` Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260901-typed_register-v4-4-5552b1d59525@garyguo.net> References: <20260901-typed_register-v4-0-5552b1d59525@garyguo.net> In-Reply-To: <20260901-typed_register-v4-0-5552b1d59525@garyguo.net> To: Danilo Krummrich , Alice Ryhl , Daniel Almeida , Miguel Ojeda , Boqun Feng , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Andreas Hindborg , Trevor Gross , Tamir Duberstein , Alexandre Courbot , =?utf-8?q?Onur_=C3=96zkan?= , David Airlie , Simona Vetter , Bjorn Helgaas , =?utf-8?q?Krzysztof_Wilczy=C5=84ski?= Cc: driver-core@lists.linux.dev, rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, nova-gpu@lists.linux.dev, dri-devel@lists.freedesktop.org, linux-pci@vger.kernel.org, Gary Guo X-Mailer: b4 0.15.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1788281431; l=18332; i=gary@garyguo.net; s=20221204; h=from:subject:message-id; bh=a4e0IW7uOdgVQTyEzPyQL8e411BYAWC48EB6qOIO1d8=; b=wFxuX2Fy0md6c2KfGcum6OOQ/wuh4+GStOBNPLd7ztoe4Vr7TkLJ9gIQNz+nqVESmIwHHe/lD xt0HOgwRKxIB7kbwIwCrZ062pjVFPLu2W0TExbdcx50iFxHy57Ha/KY X-Developer-Key: i=gary@garyguo.net; a=ed25519; pk=vB3uIX95SM4eVrIqo1DWNWKDKD2xzB+yLLLr0yOPYMo= X-ClientProxiedBy: PAZP264CA0173.FRAP264.PROD.OUTLOOK.COM (2603:10a6:102:236::16) To LOAP265MB8560.GBRP265.PROD.OUTLOOK.COM (2603:10a6:600:4ab::19) 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: LOAP265MB8560:EE_|LO0P265MB7316:EE_ X-MS-Office365-Filtering-Correlation-Id: e2558477-487b-49ab-94ff-08df0849253e X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|366016|1800799024|23010399003|10070799003|376014|7416014|10067099003|6133799003|22082099003|56012099006|5023799004|18002099003|921020; X-Microsoft-Antispam-Message-Info: 80FzFT4d9/i93bE/YA12pc6NYrS/+WzKhZzetusG5/PD+UTCGwn0BuSYLxaq19x0M7fjiCaw270kFzBFH5n2EHPiV7Ulia9cUy5YZbpTxbi0SaYIPOJGjoK9LeUMWzFWMVG5/+OZ7QZf7Ix+50SoK8KfSKVNq78wmf6tSFNYhXsVIene5csO0YkgERBh5ZzuP7+72ujUTPk8gJmPfwc6rnzAlwSO1aHONYQ9d6khXFOONncg3626ezjgxN+Y+WhaVoxxJTfazy/BRoa8ag0N22U8NHzOL1HQFLw6ArrwK2GvlFPBGe3vkYltwvnh3X+7vqXvcfjVdMZKyaqUFYDhFCahVyhx9qy8BkVDWjU1XF9Xobv91zaMFu2lCw3ab+wWTig7aiOtcOeGMPYpm/yuEIiVWftrIIaGInEZc7sTcn47NNh/+0pGEhthpedhbZ6N/R/Sz4P6whW0QMuWU0xNjlPKXHIFF7OKxrrlm4V1hzJZsVmW9sAU7l256YJAVnUZc34VwrDmC66pLehcYlWZAoh/49a14WYhoo5yygsC8a9AwYiZLKQWfIoUQxPW+pj+bduCm0nUQwuYYJqOKHF8mOu+0sGErohnPo8Yv2t8pvavNgd3GnGXOnv0bvGim1If0FKZ0ruDgOyPL2dJjTEQ6iorGxBuyvpXVvfAqoh2fO2DWyPkvZKGA8qg60GWu1GumiM2CiEY2VesL69iHRimmg== X-Forefront-Antispam-Report: CIP:255.255.255.255;CTRY:;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:LOAP265MB8560.GBRP265.PROD.OUTLOOK.COM;PTR:;CAT:NONE;SFS:(13230040)(366016)(1800799024)(23010399003)(10070799003)(376014)(7416014)(10067099003)(6133799003)(22082099003)(56012099006)(5023799004)(18002099003)(921020);DIR:OUT;SFP:1102; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: =?utf-8?B?YkExa0hNRGVoWlBNeGMzS3l2Q0V3LzdGRTg1T2YxQXJZZFNFN1lLVmtHWjBJ?= =?utf-8?B?Vkl0cVM5RVYyQW9HbE5vSC9uTGZ2RXg3T1NsU1h0Z0ZGd3lNV0dlejhGelhw?= =?utf-8?B?eVBPeGNvT2kyN0ZtcmlNUmp2ZDlFZU91a2lLdjcxQnI4c1h1VDY4QzEyV3Ns?= =?utf-8?B?Z3dvRkZPSnRWblRPMlA0UGZBSk9OaWZWLyswZ0NKT3lZQXJkSmdNVHlLLyt0?= =?utf-8?B?Nm0rTVZxWS9IeUhjWG14YXZjdDEraVpPYlFzcE5OYSs5UW5NU2FZdi9RWGli?= =?utf-8?B?OEVaSzFyMmtoZzNlUDUrVWt1SHVrSCtxMTYvNHVZYXI4NDdQeGlXRFNxMmhp?= =?utf-8?B?bXI1RVNXV1ZKOHFQdDdkUEI1cUlMMVVKdzVVMGhKT084M20wUWpRL3IwWlI5?= =?utf-8?B?emFnUUxVWmZuS3FndHNFemIvcWFFcVhUVnZ3Yk9RUFFPM1FaNXU1d0hSNys3?= =?utf-8?B?Qk1RaUJQdGZySGpWUVR6OS9VTGpKT1V6eFlCVk9lUDZOOEl0OWJYOVlTRE5h?= =?utf-8?B?QjRVZjRUQ1RlWEVFbUtuWUxLUE04UTlIek8wa0xFbUFlY2dFSThZS1VGMTN3?= =?utf-8?B?TVBMUWVFOGFrdlZ1RlBXb2EyejIzK0hWaVBBcDhFUXFRUTJzd0JSbVpxYm5i?= =?utf-8?B?K3oyaTVXYjNUUzJVdTJ0YXlReVdwSk83bStVeUdKUXJZWFlTcDZhdG1ObUFM?= =?utf-8?B?bXNmNGtwN3BWNTBIU0VFRFZ2aldyR3dTekFHWC9zTTA1RFdOKzR2VFFlR3pU?= =?utf-8?B?M0hwN3ovSHR5eHF6a0Ztd3hEZjh2Qm1uMzZaaGVoWFU2NVlHd0dnSjRVQjg0?= =?utf-8?B?alhzZGQ4TkkvNy9JRndoV3RISlNZd0VtenY5ZlUyNWFCVkNLUEwvYituTis4?= =?utf-8?B?VWZzQit2U0pVdytmaDY2MFU1MVRZVEhIVk95NTBlQjNEeG8yZ0xrZGIxVE5m?= =?utf-8?B?eHk4RDl5YjlLVmhzZGNLVUtzUjZzS0FEMlNkcVRzYjIzWlp1RURMV3lPaGpI?= =?utf-8?B?ZFlXRmt3c2F1V0RIYURWOUJoQVJWNE1aYW4xWjBuK3lVZGNUa0dOVk9uYi9N?= =?utf-8?B?cDJqa2VZMWVmWmtCQVJWZS9LTXZUWFEyR2hnbkdsbkw5QlNCK0NIWVRQayts?= =?utf-8?B?SFNnblZ1eDZEYVhDVlc2bTlBWDNZUE9EcTZUZGVTQTV0RnNWcVQ0Z2lmOURM?= =?utf-8?B?Uzh1ZldtRDNwZ2xlZ3JyTXNqdE5BOEU0cmx2R1lSajdGNGd3VUVLQkNNWVBs?= =?utf-8?B?ZlFDT0pjYWRIYjFsaUdpOHdXU210N2pTREZ0d1NiOTlQdHFGTkJta2YxNVIy?= =?utf-8?B?U1NIT3IrSmZBRXU0dnE5NUNaUTAxc253UmNoMElDTVVEeFZYdjVwSVFFcTR4?= =?utf-8?B?blNBWmRFa2FLM0RSZUZIVGlMSDM5WHROQTJRZUQ0VFRsMDZJb3dDK2JJRHo2?= =?utf-8?B?d0hNRzRNdTAzT0c3K3RYc0p1OXhEcUJmM2txMzVMNDA2RWlkdG5ocUJGVFJX?= =?utf-8?B?ZnlzQ0xkYTl6ZVJ3cUI5U2FicFU4OHhPc3FOVFZEL0FOeFpmY0ozdW4zazd4?= =?utf-8?B?bWFsQVZiSXRnMktrZEt1aXlnUmkrc1FQZ1ZGQ1JqYTFvU2pZRk00ak1hanp4?= =?utf-8?B?MHVQbUNDaDNlSGNobHgzVFYvM0hXMkE1R1F2dUVqYUZ5L0hhRHl6V01FT256?= =?utf-8?B?WGV3NkhzcC9Cc0FCeDZTUUEwalRCenpoQk5vNkZZT2RqckJPM1I3YXpZQ0Rp?= =?utf-8?B?M0pOVzk0RUFYTmlTeVlwWWlXRHo0S3FVcXpHbGVnazc1aHNlUWREMmZKblpn?= =?utf-8?B?NTRwOXRUSW1oL21FOFdidjVtREVRY29LREtIWTBycVh6TUdHb2V6dTlZeVdM?= =?utf-8?B?VDRBR2JJV2xvQWZ0czVuZ3JtU3FCNUVwZjRsOHlNODlKQUp2WTE3UjFaMnJ2?= =?utf-8?B?Y0YxMHh0MnlMNVVwV2F2K29jYks2MVJLeFdTZENiV1ZmaHhsRXJPRGlHb2c5?= =?utf-8?B?K1NsRkw0QlB3ZXorZVZoWitYelhETGhGM1lBdndjZ09vNWRiT2p3U0ZtbFc0?= =?utf-8?B?L1F3dlg2SklWSWNobm9mNjhNMGdURmpQb2RNSTh1WGFWN0pHMGhoUVVxRHZ3?= =?utf-8?B?cUs0S2RuRjVBRnV6aWQ4N3ZQUUtCd29qQXFuanRBNmQrWHlTZFNoclpsMjh5?= =?utf-8?B?OFNiVVNUMU9BbW9uN1JHOXM3U2hKb1BsczBUWUxMV3h4RHpwWXpIalZjY3lK?= =?utf-8?B?N3NYSnFjaUhUM2o3SUs1UVFhbDNEektLdjBNZUlpbHJscGpZMXVCVWxCSlpi?= =?utf-8?B?V085ZjJMc1hwaVRQdlFMYWlmdkJubUM3dERObzUzQ3hOcExBdHo2Zz09?= X-OriginatorOrg: garyguo.net X-MS-Exchange-CrossTenant-Network-Message-Id: e2558477-487b-49ab-94ff-08df0849253e X-MS-Exchange-CrossTenant-AuthSource: LOAP265MB8560.GBRP265.PROD.OUTLOOK.COM X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 01 Sep 2026 16:50:36.1403 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: bbc898ad-b10f-4e10-8552-d9377b823d45 X-MS-Exchange-CrossTenant-MailboxType: HOSTED X-MS-Exchange-CrossTenant-UserPrincipalName: Yp1b+7tQKBbeJ9o+FybnDV4pYfjgIq8m567VNh6xtp21VLULfGxBSNoWBG35hT2NiXK5R5bHIgBGuFo4Bjcu0w== X-MS-Exchange-Transport-CrossTenantHeadersStamped: LO0P265MB7316 For types that are layout-compatible with an I/O capable type, we would want the ability to use them directly for I/O operations. E.g. bitfield! { pub struct Foo(u32) { ... } } #[repr(C)] struct Bar { foo: Foo, } let mmio: Mmio<'_, Bar> =3D ...; io_read!(mmio, .foo) Currently this feature is available from `register!()` macro but not otherwise available with `io_read!`, `io_write!`. Support this by performing conversions to I/O primitives via the `AsRepr`/`AsReprMut` trait. This makes the `IoLoc::IoType` and `Register::Storage` redundant; thus remove them; also convert register methods to use the `read_val` and `write_val` instead. Reviewed-by: Alexandre Courbot Signed-off-by: Gary Guo Acked-by: Miguel Ojeda Tested-by: Alexandre Courbot --- rust/kernel/bitfield.rs | 9 ++++ rust/kernel/io.rs | 128 ++++++++++++++++++++++++-----------------= ---- rust/kernel/io/register.rs | 15 ------ rust/macros/io/register.rs | 2 - 4 files changed, 78 insertions(+), 76 deletions(-) diff --git a/rust/kernel/bitfield.rs b/rust/kernel/bitfield.rs index a0d089423f21..15c78790e151 100644 --- a/rust/kernel/bitfield.rs +++ b/rust/kernel/bitfield.rs @@ -346,6 +346,15 @@ fn from(val: $storage) -> $name { Self::from_raw(val) } } + + // SAFETY: `$name` is transparent over `$storage` and `$storage` h= as no interior mutability. + unsafe impl $crate::mem::AsRepr for $name { + // Normalize `$storage` to the canonical repr type in case it = is signed. + type Repr =3D <$storage as $crate::mem::AsRepr>::Repr; + } + + // SAFETY: `$name` is transparent over `$storage`. + unsafe impl $crate::mem::AsReprMut for $name {} }; =20 // Definitions requiring knowledge of individual fields: private and p= ublic field accessors, diff --git a/rust/kernel/io.rs b/rust/kernel/io.rs index 5ce9fd129068..18c71bd765b2 100644 --- a/rust/kernel/io.rs +++ b/rust/kernel/io.rs @@ -11,6 +11,10 @@ =20 use crate::{ bindings, + mem::{ + AsRepr, + AsReprMut, // + }, prelude::*, ptr::{ Alignment, @@ -226,6 +230,17 @@ fn io_view<'a, IO: Io<'a>, U>( Ok(unsafe { IO::Backend::project_view(view, projected_ptr) }) } =20 +/// Returns the primitive view of a I/O view. +#[inline] +fn io_view_as_repr<'a, IO: Io<'a, Target =3D T>, T: AsRepr>( + this: IO, +) -> ::View<'a, T::Repr> { + let view =3D this.as_view(); + + // SAFETY: `AsRepr` guarantees layout compatibility. + unsafe { IO::Backend::project_view(view, IO::Backend::as_ptr(view).cas= t::()) } +} + /// I/O backends. /// /// This is an abstract representation to be implemented by arbitrary I/O @@ -353,15 +368,12 @@ fn copy_write(view: Self::View<'_, T>, = value: T) { /// /// - The valid `Base` to operate on. For most registers, this should be [= `Region`]. /// - The offset to access (returned by [`IoLoc::offset`]), -/// - The width of the access (determined by [`IoLoc::IoType`]), -/// - The type `T` in which the raw data is returned or provided. +/// - The type `T` in which the data is returned or provided. /// -/// `T` and `IoLoc::IoType` may differ: for instance, a typed register has= `T` =3D the register type -/// with its bitfields, and `IoType` =3D its backing primitive (e.g. `u32`= ). +/// `T` is not necessarily the type for underlying I/O operation. Methods = that take `IoLoc` have `T: +/// AsRepr` bound and the `::Repr` type would be used to perf= orm I/O and converted to +/// `T` instead. pub trait IoLoc { - /// Size ([`u8`], [`u16`], etc) of the I/O performed on the returned [= `offset`](IoLoc::offset). - type IoType: Into + From; - /// Consumes `self` and returns the offset of this location. fn offset(self) -> usize; } @@ -372,8 +384,6 @@ macro_rules! impl_usize_ioloc { ($($ty:ty),*) =3D> { $( impl IoLoc, $ty> for usize { - type IoType =3D $ty; - #[inline(always)] fn offset(self) -> usize { self @@ -498,10 +508,10 @@ fn try_cast(self) -> Result<::View<'a, U>> #[inline] fn read_val(self) -> Self::Target where - Self::Backend: IoCapable, - Self::Target: Sized, + Self::Target: AsReprMut, + Self::Backend: IoCapable<::Repr>, { - Self::Backend::io_read(self.as_view()) + Self::Target::from_repr(Self::Backend::io_read(io_view_as_repr(sel= f))) } =20 /// Write a value to I/O. @@ -520,10 +530,10 @@ fn read_val(self) -> Self::Target #[inline] fn write_val(self, value: Self::Target) where - Self::Backend: IoCapable, - Self::Target: Sized, + Self::Target: AsRepr, + Self::Backend: IoCapable<::Repr>, { - Self::Backend::io_write(self.as_view(), value) + Self::Backend::io_write(io_view_as_repr(self), Self::Target::into_= repr(value)) } =20 /// Copy-read from I/O memory. @@ -645,7 +655,7 @@ fn copy_to_slice(self, data: &mut [u8]) #[inline(always)] fn try_read8(self, offset: usize) -> Result where - usize: IoLoc, + usize: IoLoc, Self::Backend: IoCapable, { self.try_read(offset) @@ -655,7 +665,7 @@ fn try_read8(self, offset: usize) -> Result #[inline(always)] fn try_read16(self, offset: usize) -> Result where - usize: IoLoc, + usize: IoLoc, Self::Backend: IoCapable, { self.try_read(offset) @@ -665,7 +675,7 @@ fn try_read16(self, offset: usize) -> Result #[inline(always)] fn try_read32(self, offset: usize) -> Result where - usize: IoLoc, + usize: IoLoc, Self::Backend: IoCapable, { self.try_read(offset) @@ -675,7 +685,7 @@ fn try_read32(self, offset: usize) -> Result #[inline(always)] fn try_read64(self, offset: usize) -> Result where - usize: IoLoc, + usize: IoLoc, Self::Backend: IoCapable, { self.try_read(offset) @@ -685,7 +695,7 @@ fn try_read64(self, offset: usize) -> Result #[inline(always)] fn try_write8(self, value: u8, offset: usize) -> Result where - usize: IoLoc, + usize: IoLoc, Self::Backend: IoCapable, { self.try_write(offset, value) @@ -695,7 +705,7 @@ fn try_write8(self, value: u8, offset: usize) -> Result #[inline(always)] fn try_write16(self, value: u16, offset: usize) -> Result where - usize: IoLoc, + usize: IoLoc, Self::Backend: IoCapable, { self.try_write(offset, value) @@ -705,7 +715,7 @@ fn try_write16(self, value: u16, offset: usize) -> Resu= lt #[inline(always)] fn try_write32(self, value: u32, offset: usize) -> Result where - usize: IoLoc, + usize: IoLoc, Self::Backend: IoCapable, { self.try_write(offset, value) @@ -715,7 +725,7 @@ fn try_write32(self, value: u32, offset: usize) -> Resu= lt #[inline(always)] fn try_write64(self, value: u64, offset: usize) -> Result where - usize: IoLoc, + usize: IoLoc, Self::Backend: IoCapable, { self.try_write(offset, value) @@ -727,7 +737,7 @@ fn try_write64(self, value: u64, offset: usize) -> Resu= lt #[inline(always)] fn read8(self, offset: usize) -> u8 where - usize: IoLoc, + usize: IoLoc, Self::Backend: IoCapable, { self.read(offset) @@ -739,7 +749,7 @@ fn read8(self, offset: usize) -> u8 #[inline(always)] fn read16(self, offset: usize) -> u16 where - usize: IoLoc, + usize: IoLoc, Self::Backend: IoCapable, { self.read(offset) @@ -751,7 +761,7 @@ fn read16(self, offset: usize) -> u16 #[inline(always)] fn read32(self, offset: usize) -> u32 where - usize: IoLoc, + usize: IoLoc, Self::Backend: IoCapable, { self.read(offset) @@ -763,7 +773,7 @@ fn read32(self, offset: usize) -> u32 #[inline(always)] fn read64(self, offset: usize) -> u64 where - usize: IoLoc, + usize: IoLoc, Self::Backend: IoCapable, { self.read(offset) @@ -775,7 +785,7 @@ fn read64(self, offset: usize) -> u64 #[inline(always)] fn write8(self, value: u8, offset: usize) where - usize: IoLoc, + usize: IoLoc, Self::Backend: IoCapable, { self.write(offset, value) @@ -787,7 +797,7 @@ fn write8(self, value: u8, offset: usize) #[inline(always)] fn write16(self, value: u16, offset: usize) where - usize: IoLoc, + usize: IoLoc, Self::Backend: IoCapable, { self.write(offset, value) @@ -799,7 +809,7 @@ fn write16(self, value: u16, offset: usize) #[inline(always)] fn write32(self, value: u32, offset: usize) where - usize: IoLoc, + usize: IoLoc, Self::Backend: IoCapable, { self.write(offset, value) @@ -811,7 +821,7 @@ fn write32(self, value: u32, offset: usize) #[inline(always)] fn write64(self, value: u64, offset: usize) where - usize: IoLoc, + usize: IoLoc, Self::Backend: IoCapable, { self.write(offset, value) @@ -843,11 +853,12 @@ fn write64(self, value: u64, offset: usize) #[inline(always)] fn try_read(self, location: L) -> Result where + T: AsReprMut, L: IoLoc, - Self::Backend: IoCapable, + Self::Backend: IoCapable<::Repr>, { - let view =3D io_view::(self, location.offset())?; - Ok(Self::Backend::io_read(view).into()) + let view =3D io_view::(self, location.offset())?; + Ok(view.read_val()) } =20 /// Generic fallible write with runtime bounds check. @@ -876,12 +887,12 @@ fn try_read(self, location: L) -> Result #[inline(always)] fn try_write(self, location: L, value: T) -> Result where + T: AsRepr, L: IoLoc, - Self::Backend: IoCapable, + Self::Backend: IoCapable<::Repr>, { - let view =3D io_view::(self, location.offset())?; - let io_value =3D value.into(); - Self::Backend::io_write(view, io_value); + let view =3D io_view::(self, location.offset())?; + view.write_val(value); Ok(()) } =20 @@ -920,9 +931,10 @@ fn try_write(self, location: L, value: T) -> Res= ult #[inline(always)] fn try_write_reg(self, value: V) -> Result where + T: AsRepr, L: IoLoc, V: LocatedRegister, - Self::Backend: IoCapable, + Self::Backend: IoCapable<::Repr>, { let (location, value) =3D value.into_io_op(); =20 @@ -954,16 +966,13 @@ fn try_write_reg(self, value: V) -> Result #[inline(always)] fn try_update(self, location: L, f: F) -> Result where + T: AsReprMut, L: IoLoc, - Self::Backend: IoCapable, + Self::Backend: IoCapable<::Repr>, F: FnOnce(T) -> T, { - let view =3D io_view::(self, location.offset())?; - - let value: T =3D Self::Backend::io_read(view).into(); - let io_value =3D f(value).into(); - Self::Backend::io_write(view, io_value); - + let view =3D io_view::(self, location.offset())?; + view.write_val(f(view.read_val())); Ok(()) } =20 @@ -991,11 +1000,12 @@ fn try_update(self, location: L, f: F) -> R= esult #[inline(always)] fn read(self, location: L) -> T where + T: AsReprMut, L: IoLoc, - Self::Backend: IoCapable, + Self::Backend: IoCapable<::Repr>, { - let view =3D io_view_assert::(self, location.offs= et()); - Self::Backend::io_read(view).into() + let view =3D io_view_assert::(self, location.offset()); + view.read_val() } =20 /// Generic infallible write with compile-time bounds check. @@ -1022,12 +1032,12 @@ fn read(self, location: L) -> T #[inline(always)] fn write(self, location: L, value: T) where + T: AsRepr, L: IoLoc, - Self::Backend: IoCapable, + Self::Backend: IoCapable<::Repr>, { - let view =3D io_view_assert::(self, location.offs= et()); - let io_value =3D value.into(); - Self::Backend::io_write(view, io_value); + let view =3D io_view_assert::(self, location.offset()); + view.write_val(value) } =20 /// Generic infallible write of a fully-located register value. @@ -1064,9 +1074,10 @@ fn write(self, location: L, value: T) #[inline(always)] fn write_reg(self, value: V) where + T: AsRepr, L: IoLoc, V: LocatedRegister, - Self::Backend: IoCapable, + Self::Backend: IoCapable<::Repr>, { let (location, value) =3D value.into_io_op(); =20 @@ -1098,14 +1109,13 @@ fn write_reg(self, value: V) #[inline(always)] fn update(self, location: L, f: F) where + T: AsReprMut, L: IoLoc, - Self::Backend: IoCapable, + Self::Backend: IoCapable<::Repr>, F: FnOnce(T) -> T, { - let view =3D io_view_assert::(self, location.offs= et()); - let value: T =3D Self::Backend::io_read(view).into(); - let io_value =3D f(value).into(); - Self::Backend::io_write(view, io_value); + let view =3D io_view_assert::(self, location.offset()); + view.write_val(f(view.read_val())); } } =20 diff --git a/rust/kernel/io/register.rs b/rust/kernel/io/register.rs index 6a19552ffb95..45d2e73a92e7 100644 --- a/rust/kernel/io/register.rs +++ b/rust/kernel/io/register.rs @@ -117,9 +117,6 @@ =20 /// Trait implemented by all registers. pub trait Register: Sized { - /// Backing primitive type of the register. - type Storage: Into + From; - /// Start offset of the register. /// /// The interpretation of this offset depends on the type of the regis= ter. @@ -135,8 +132,6 @@ impl IoLoc, T> for () where T: FixedRegister, { - type IoType =3D T::Storage; - #[inline(always)] fn offset(self) -> usize { T::OFFSET @@ -149,8 +144,6 @@ impl IoLoc, T> for T where T: FixedRegister, { - type IoType =3D T::Storage; - #[inline(always)] fn offset(self) -> usize { T::OFFSET @@ -174,8 +167,6 @@ impl IoLoc, T> for F= ixedRegisterLoc where T: FixedRegister, { - type IoType =3D T::Storage; - #[inline(always)] fn offset(self) -> usize { T::OFFSET @@ -246,8 +237,6 @@ impl IoLoc, T> fo= r RelativeRegisterLoc + ?Sized, { - type IoType =3D T::Storage; - #[inline(always)] fn offset(self) -> usize { RelativeRegisterLoc::offset(self) @@ -289,8 +278,6 @@ impl IoLoc, T> for R= egisterArrayLoc where T: RegisterArray, { - type IoType =3D T::Storage; - #[inline(always)] fn offset(self) -> usize { T::OFFSET + self.0 * T::STRIDE @@ -377,8 +364,6 @@ impl IoLoc, T> fo= r RelativeRegisterArrayLo T: RelativeRegisterArray, B: RegisterBase + ?Sized, { - type IoType =3D T::Storage; - #[inline(always)] fn offset(self) -> usize { self.0.offset() + self.1 * T::STRIDE diff --git a/rust/macros/io/register.rs b/rust/macros/io/register.rs index 83ba4dd75ab3..9b92c8099edd 100644 --- a/rust/macros/io/register.rs +++ b/rust/macros/io/register.rs @@ -213,8 +213,6 @@ pub(crate) fn register(def: RegDef) -> Result { ); =20 impl ::kernel::io::register::Register for #name { - type Storage =3D #storage; - const OFFSET: usize =3D #offset; } )); --=20 2.54.0 From nobody Sat Sep 26 12:29:11 2026 Received: from LO0P265CU003.outbound.protection.outlook.com (mail-uksouthazon11022089.outbound.protection.outlook.com [52.101.96.89]) (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 0A733485CC3; Tue, 1 Sep 2026 16:50:46 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=52.101.96.89 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788281448; cv=fail; b=oD29XmS4j9SLPqTcKe/d4506va/0ekEe/nfqMETW1Y8XaiwK3oP7rp52MBC7txOlZ9IULxhtoPboYyEui4U9qhBJyROEtp4IsxIcCzXU0QgdgOXtGDuQerjd3pcueBKSPHeUihpb7ttSpL4BR8WgBExVnebhDKCaYg5gLtiNW5w= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788281448; c=relaxed/simple; bh=sEaFmQA041Nq96pwerlQKqsj6hyKGBvL0oWCm+haOJM=; h=From:Date:Subject:Content-Type:Message-Id:References:In-Reply-To: To:Cc:MIME-Version; b=Ac9KCxEuPIiy/YU3+6Ks5DZhx6wcjv0wFgw5TbyVQlQ3IoRUFILPIfQGTQZn0bwZ9nOwQwkRCO7BTaWXpfQZ2N8GeQrfu9k0HcJxa2aPlzHPqwRrEtIomR7O0lY71BUlHHFZoB3YulaiED81P7bZUIxMx5cuF8uw25gmiMRtsac= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=garyguo.net; spf=pass smtp.mailfrom=garyguo.net; dkim=pass (1024-bit key) header.d=garyguo.net header.i=@garyguo.net header.b=M3eWj+G5; arc=fail smtp.client-ip=52.101.96.89 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=garyguo.net Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=garyguo.net Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=garyguo.net header.i=@garyguo.net header.b="M3eWj+G5" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=j4zkMPrjuey+ZfQu/Bkj7p7SyB8M2DJTC5Fu/2yFbR8es8YJ4oCFUVZvSKCzEbidCACTphZalcQznCxZ+JA0w3GMJ9T+lNkZcXn7dzD/7Yh1MZihr7VDIPD2h+FFHbiIjJOVRiGmGJCWQEzD+/HoTilLCOMGCKZTs7nPNDyr6qfb6ym0U7wJIvepUNqp34idYykcuhZUMCUpJRO9y2mwhxT8DexxGflkWjP9lE0tFhQ+6sKDUCgNPOcrt7GK0XuE0WPndz0DFvlwFetU0Bwgdwbwnd/UDKGLKQRFRlW/EETgq+4GtB/QErIF08icU7T4HhJejKzGSg6W2PkCSzgrvA== 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=9jE0bJqKT5LFNVhvgPBihMUBaSnMK8oMzqaN6Q0oGnU=; b=EMdC81vgqsr00Da1fZ8BNgc4nkYrvm+VyTLZPvT5FW1SEeucVXXaS7p05uLrAEXAy0RWbjf4V45ibvQ5jCdlUPqQ+JnT68PXvj0xzmuMSESPMEiXaQSYqCioEDoM8Jz73QxNI37MMgGWAkJRwLrmB4N6KzYlCMTR6bLeaEOZJdWnWFUdzQyxiSxsiJ5xA3LFBZDylkD2rjGihp/8UlpKVxeYDIs2LxP+FCNEW1B5GbwHWvpfx+ZPY5xLC7dxjixpIzxBqxLBT2sLJklhEMiEmOFEqrAbTPNnJIFz/HWaGB80gqodbWD/W+5JGG+nmKg6HSU/GEYc0N0jBzT55esUUg== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=garyguo.net; dmarc=pass action=none header.from=garyguo.net; dkim=pass header.d=garyguo.net; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=garyguo.net; s=selector1; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=9jE0bJqKT5LFNVhvgPBihMUBaSnMK8oMzqaN6Q0oGnU=; b=M3eWj+G5AS1A6TQCG82LH0gKWxJyQdmO2F/tOmBcSR7D9R111pf3RLndpd1+HDSLxvAgY7YMwB9TUsUg1EliOp5CKkiRnq6hQ5fIP54JnKwve870EBxdAw3VxZYXIpzptSRI2co/WOS59EHPOkw+h3Nf8vme++WnFTDzkt1DYQs= Authentication-Results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=garyguo.net; Received: from LOAP265MB8560.GBRP265.PROD.OUTLOOK.COM (2603:10a6:600:4ab::19) by LO0P265MB7316.GBRP265.PROD.OUTLOOK.COM (2603:10a6:600:2ef::11) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.21.360.13; Tue, 1 Sep 2026 16:50:36 +0000 Received: from LOAP265MB8560.GBRP265.PROD.OUTLOOK.COM ([fe80::f60b:1537:68d7:4fc1]) by LOAP265MB8560.GBRP265.PROD.OUTLOOK.COM ([fe80::f60b:1537:68d7:4fc1%4]) with mapi id 15.21.0360.008; Tue, 1 Sep 2026 16:50:36 +0000 From: Gary Guo Date: Tue, 01 Sep 2026 17:50:29 +0100 Subject: [PATCH v4 05/16] rust: io: support register projections Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260901-typed_register-v4-5-5552b1d59525@garyguo.net> References: <20260901-typed_register-v4-0-5552b1d59525@garyguo.net> In-Reply-To: <20260901-typed_register-v4-0-5552b1d59525@garyguo.net> To: Danilo Krummrich , Alice Ryhl , Daniel Almeida , Miguel Ojeda , Boqun Feng , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Andreas Hindborg , Trevor Gross , Tamir Duberstein , Alexandre Courbot , =?utf-8?q?Onur_=C3=96zkan?= , David Airlie , Simona Vetter , Bjorn Helgaas , =?utf-8?q?Krzysztof_Wilczy=C5=84ski?= Cc: driver-core@lists.linux.dev, rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, nova-gpu@lists.linux.dev, dri-devel@lists.freedesktop.org, linux-pci@vger.kernel.org, Gary Guo X-Mailer: b4 0.15.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1788281431; l=5324; i=gary@garyguo.net; s=20221204; h=from:subject:message-id; bh=sEaFmQA041Nq96pwerlQKqsj6hyKGBvL0oWCm+haOJM=; b=+RrGLvf1Dqe6r0gsQGkEJe7Ww8LtICPzAt3VproILBj7bwADcqY5823VaFX1II30nH93j26c/ 4VJXSGrf18rDHjQmwFqq0CSlJy1dBWbIg84C0+GiIgtzcKCQ0quKsE4 X-Developer-Key: i=gary@garyguo.net; a=ed25519; pk=vB3uIX95SM4eVrIqo1DWNWKDKD2xzB+yLLLr0yOPYMo= X-ClientProxiedBy: PAZP264CA0173.FRAP264.PROD.OUTLOOK.COM (2603:10a6:102:236::16) To LOAP265MB8560.GBRP265.PROD.OUTLOOK.COM (2603:10a6:600:4ab::19) 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: LOAP265MB8560:EE_|LO0P265MB7316:EE_ X-MS-Office365-Filtering-Correlation-Id: 8ba7699a-28a7-4e61-7341-08df084925b5 X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|366016|1800799024|23010399003|10070799003|376014|7416014|10067099003|6133799003|22082099003|56012099006|5023799004|18002099003|921020; X-Microsoft-Antispam-Message-Info: xCKkgCkGEuGr+SmYmeUByt9xmkDa9L7kzJxYKzaym9ZsZxcAk7IEDemKOHHk5U19U3IWghAsig6sN7ZLch+ze62ncAF8ptkwulFXF4Rqfbv4QPIwetFMV0zM/g4FhXsjxwOa7kffOD0k/9js1JAq+ggfO/GipjjhHWB6Q3z4L7FWRW+8N6gXH1yzZhgskdCBVZgpRB+VFQl2hE+6Igg09vrzRA9qNEY+wOPI2GOj/TceR7CsviXxqfJhkcdH48o75BV3CgxwIlBhVY0yAmgOOwDNR3oNOzvJbFEljGu4UViGi/VlYd+5XvwX2reaARH+dzFDl0MEV2yHDYRyLDkxnEFcQd/ZjFyF5yPyZv88S2JDmbe9Yu6PlrMhBvNQ1VbCAeOasBRlPRmS/DvFV2Sr1m8iwl+fhx5nJYLINBai6xcjGxYQ2Ou65ciANONd2uxpz+iSce9tQ6p0PBGEh19SobLfPQw23v4cl6mmL80UV6RTQJ4VS/jkajNeQcd9/6jIZJsuqhadivnYLIkgkjcsm61Yz5sAbtD6HbXFyDiKTNAstvzdAvVZRS0YOKXB+LrwKhJyBxTEPrFp/PvuxLFyNVwydTAk/jEq1Etpogw6zZ2/zQDZ5hglk9orJcowtaL0jrJON0SOHZFAWZKEUUvqRV/Xwtmt1Xk0MWUpkUlbsLTcy7iF2glgdUAwZD9DHB34jptC/XphPfrc9p0bMP2d/A== X-Forefront-Antispam-Report: CIP:255.255.255.255;CTRY:;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:LOAP265MB8560.GBRP265.PROD.OUTLOOK.COM;PTR:;CAT:NONE;SFS:(13230040)(366016)(1800799024)(23010399003)(10070799003)(376014)(7416014)(10067099003)(6133799003)(22082099003)(56012099006)(5023799004)(18002099003)(921020);DIR:OUT;SFP:1102; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: =?utf-8?B?eFJzTjRlQTZ6Nzlvd1JvUVROa04wQnI0TElYOUpXN2RUd0JpZWRaR25NRUVS?= =?utf-8?B?cGV0R09TL3k0d0wrSFhwV2l6YzkzU1JPcjdjTzd2YzNPRk0zUm45SzdyL08z?= =?utf-8?B?dXVvUjVFTzBnQm9zTGk3MmlpUzNHcExGSG53b0hoU3lVUmYrVnRwcVo2bGd6?= =?utf-8?B?MzI3WXBQMXcyQlhJV2FTQk8zRVRpVy9ESVZjR2o5YjZmck50aG5NbDBZNmUw?= =?utf-8?B?Nk1pSldQMUVpVFpmZjB2REhCb2krVlUwM3lmbG5UZGNvaXNrQnhUZFNVMndj?= =?utf-8?B?Y3ROVnl1bDhac2ppZFdCTWNnUEhla0I3djF1SW5ydURDTTBhTjlsaTFnVm1J?= =?utf-8?B?SlhaWFA1ZFJqZ3d5RFJzNy90MktVeW9idVpFdHcrNk40TVVDbnNQSklSU2Mr?= =?utf-8?B?YTBKd3FiMHhVY2NXOTQ4L2w3MkpIMmlZbG05V1pvVHdXZ21JcktNSkVPd0Fq?= =?utf-8?B?UzlVaC9kWTNlK20yak9JMm93QnQxVExkYTlIMXJhbThkRFRMTzBySEc2VURl?= =?utf-8?B?dFloYTVFZ1I5ajVYSThhUy9LN2h5NmdVZjFZdmxlWTIzZ2tTZUd5ZjNJOEFk?= =?utf-8?B?N0pUSEo2UVRhZy9KcUYvNi9pS3p4K0pvUGsvR3RBSGtwa2tjWjBFYXo3WDVY?= =?utf-8?B?elpibUo1S2hVMTFsWVdTejA3d25rK2ZUTVc0RTk4QjNMcTVmTGkzKzEvUWJS?= =?utf-8?B?NmkvL3Z1NGhDWCtmdHhIaHZJbm1UcjB4TlhibFZobDJsY3V3THNLSlRIcVhT?= =?utf-8?B?bmgzSHZmekZCRlZWdFE2SGdmdmdVemhBRUQ3OE9uQVZJamNPOVBrSVhTSUFh?= =?utf-8?B?akZ4anBKMU4xYTJ2YVFuNFZadTB4a1JrWGdoSUk4Q0tDYVNuQ2N2eVVOQ3Ay?= =?utf-8?B?RlNBNUJscDQvWjJCLzRzcDYyNFNvZDR0SmZ1ZE96eFRmdm8yVWl5VCt5Sis5?= =?utf-8?B?czJyck9lTXhSV051N2JWeDVsdGhHbUNVU3JNVVVNZS9YZEkyWXhlN0VQRXBO?= =?utf-8?B?cUxHU3lCZVFYb0U2TG41dWZwTXJwK1Q1N1JrcjBPSmhuRU5QL3JEaTdoMjhM?= =?utf-8?B?cURzRHIxTmRuMHVyNjFtSnh0SzQrN0g2UVRHUWZtME9SQmYrbm9WaXQ0NVZD?= =?utf-8?B?MGVIV3BCdEFLbjE3bE90ZTU2NUp2bVZYYXIrTmk1Z3lrTzViNjBUdkZCVXFi?= =?utf-8?B?Z2xweHp5MFNySjZTZ2h1czR1eVpGNk1uVlh6dUtQY2czb3lQRTFIeXJPRTEy?= =?utf-8?B?MWg5bHdldWRISVBRNy9GeUxpaFpJYUFvRnBkTWUvR2JubHFRRlQ3aUdKd09o?= =?utf-8?B?bzVPK2hVbkdiWFRNNm0wQVprQkUvZEZkR3dUT01Va0ZrZ2ROSVVPM2Y1N3JJ?= =?utf-8?B?amhIN0FiR0hkSDgzbjVmbUJTaTJFWWhFMFBBcWdHMWxhU2JNdXg3RkZRZDBm?= =?utf-8?B?VURSRjdEV0pMblFJY1JuR0o2aVo0TStjQnRrNnhUMEx2STJCWCsyQ3VjSmZM?= =?utf-8?B?Uy96SVJxbFhoY244YUVlYnJlcUx5YzVHd1Z6Q1hkM3pCVm5xOFBEeXJDTTNF?= =?utf-8?B?MnlxYjdDdVQ0OXVTdStVSFRubFpHbzRyUFhGNk9XZ1NyQzJzMGZTQ01OTHVa?= =?utf-8?B?T01qS0NYTFJ2eUFIMG9wSUpBTktjM2JCamVtYUxFOEQvQnpJeWFxRklaM1U4?= =?utf-8?B?YWxEbHBQM0RmQzlJamI0VHQ3K1dpcXFnd1ZGQzkvMnFDVXZJcDRGLzJJbytP?= =?utf-8?B?K1Fnd25uRGloWjMxTGRjQVpHeDFUbGRzTlhrc2lDOVg4S3RWWGp1Um0vcWlj?= =?utf-8?B?QzlxZlUwN0gwbFZxOUhHWjk1Y2NzZEJjMnNORmxnNSt2cHB0aXQxMXd5Ri94?= =?utf-8?B?REZ6cXFOM3gxcklmbGwwdlQzSUtBZmUrRmoxQjFvQUZFUTBCNjk5TEY2MHB5?= =?utf-8?B?N2RCVUhaVnZpcmRrU25IVzdmUmpWZEVmQnFkMXNWVlVrTVFVUk96UmcyN0xX?= =?utf-8?B?dFdNU3V6aTVlRXdHd21DTjc2d3pldXdoT0Yxd2dEbHhYM1NiUW9EeUxKZmhX?= =?utf-8?B?Z0YyaHBIUmtiSldZV2lnYU50WitHTDJ3aVVIRDVKOENLSzVDYjZoTHJCVVpG?= =?utf-8?B?eFZGL0JCYUNZSVNXRzNxUTNhaVNYNEt3cUR3VzhNTEZFczdaTkgwNnlBM2ZH?= =?utf-8?B?a2x3Q2FERUtPOExXV0lFQWxBSUw2QVh2NUltNVpFU2NOSmVOT3BEQmtyM3Bx?= =?utf-8?B?VGJ3WDhNSVBFZE5SekpDbzlYVzA4MVh5b2NFckJyTzFMcHkvY1VZaVl2Rk1v?= =?utf-8?B?VUQxNmpuMlFKYStaR0UrSHR2L1g1QXhEeUpOcU83YUV6OFVDQmQxQT09?= X-OriginatorOrg: garyguo.net X-MS-Exchange-CrossTenant-Network-Message-Id: 8ba7699a-28a7-4e61-7341-08df084925b5 X-MS-Exchange-CrossTenant-AuthSource: LOAP265MB8560.GBRP265.PROD.OUTLOOK.COM X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 01 Sep 2026 16:50:36.8868 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: bbc898ad-b10f-4e10-8552-d9377b823d45 X-MS-Exchange-CrossTenant-MailboxType: HOSTED X-MS-Exchange-CrossTenant-UserPrincipalName: tXkMD6MZVafbjsHI3Z02Esm3UE4hZP+eEirLN3edNk1wP8UOXrv16HIgnRh3J4pIeGJTL8HFB1eDIXtLuBY1EA== X-MS-Exchange-Transport-CrossTenantHeadersStamped: LO0P265MB7316 `IoLoc`s themselves just describe a projection from a region to a concrete register. Thus, support it in `io_project` macro too. Also, update methods that operate on `IoLoc` to use I/O projection. Documentation of `io_project!` is not expanded yet as the example works better when `register!` type can specify base type. `io_read!` and `io_write!` gains the ability to operate on registers as corollary of the capability of `io_project!`. Examples are not added because `read` and `write` is still preferrably used instead. Reviewed-by: Alexandre Courbot Signed-off-by: Gary Guo Acked-by: Miguel Ojeda Tested-by: Alexandre Courbot --- rust/kernel/io.rs | 56 +++++++++++++++++++++++++++++++++++++++++++++------= ---- 1 file changed, 46 insertions(+), 10 deletions(-) diff --git a/rust/kernel/io.rs b/rust/kernel/io.rs index 18c71bd765b2..8df268969566 100644 --- a/rust/kernel/io.rs +++ b/rust/kernel/io.rs @@ -857,8 +857,7 @@ fn try_read(self, location: L) -> Result L: IoLoc, Self::Backend: IoCapable<::Repr>, { - let view =3D io_view::(self, location.offset())?; - Ok(view.read_val()) + Ok(io_read!(self, try: location)) } =20 /// Generic fallible write with runtime bounds check. @@ -891,8 +890,7 @@ fn try_write(self, location: L, value: T) -> Resu= lt L: IoLoc, Self::Backend: IoCapable<::Repr>, { - let view =3D io_view::(self, location.offset())?; - view.write_val(value); + io_write!(self, try: location, value); Ok(()) } =20 @@ -971,7 +969,7 @@ fn try_update(self, location: L, f: F) -> Resu= lt Self::Backend: IoCapable<::Repr>, F: FnOnce(T) -> T, { - let view =3D io_view::(self, location.offset())?; + let view =3D io_project!(self, try: location); view.write_val(f(view.read_val())); Ok(()) } @@ -1004,8 +1002,7 @@ fn read(self, location: L) -> T L: IoLoc, Self::Backend: IoCapable<::Repr>, { - let view =3D io_view_assert::(self, location.offset()); - view.read_val() + io_read!(self, build: location) } =20 /// Generic infallible write with compile-time bounds check. @@ -1036,8 +1033,7 @@ fn write(self, location: L, value: T) L: IoLoc, Self::Backend: IoCapable<::Repr>, { - let view =3D io_view_assert::(self, location.offset()); - view.write_val(value) + io_write!(self, build: location, value); } =20 /// Generic infallible write of a fully-located register value. @@ -1114,7 +1110,7 @@ fn update(self, location: L, f: F) Self::Backend: IoCapable<::Repr>, F: FnOnce(T) -> T, { - let view =3D io_view_assert::(self, location.offset()); + let view =3D io_project!(self, build: location); view.write_val(f(view.read_val())); } } @@ -1659,6 +1655,25 @@ pub unsafe fn project_view( // SAFETY: Per safety requirement. unsafe { T::Backend::project_view::(self.0, ptr) } } + + #[inline(always)] + pub fn try_project_loc( + self, + location: L, + ) -> Result<::View<'a, U>> + where + L: IoLoc, + { + io_view::<_, U>(self.0, location.offset()) + } + + #[inline(always)] + pub fn project_loc(self, location: L) -> ::View<'a, U> + where + L: IoLoc, + { + io_view_assert::<_, U>(self.0, location.offset()) + } } =20 /// Project an I/O type to a subview of it. @@ -1686,6 +1701,21 @@ pub unsafe fn project_view( #[macro_export] #[doc(hidden)] macro_rules! io_project { + // Register projection + ($io:expr, try: $ioloc:expr) =3D> {{ + #[allow(unused)] + use $crate::io::IoBase as _; + let view =3D $crate::io::ProjectHelper($io.as_view()); + view.try_project_loc($ioloc)? + }}; + ($io:expr, build: $ioloc:expr) =3D> {{ + #[allow(unused)] + use $crate::io::IoBase as _; + let view =3D $crate::io::ProjectHelper($io.as_view()); + view.project_loc($ioloc) + }}; + + // Field or index projection ($io:expr, $($proj:tt)*) =3D> {{ #[allow(unused)] use $crate::io::IoBase as _; @@ -1756,6 +1786,12 @@ macro_rules! io_write { (@parse [$io:expr] [$($proj:tt)*] [[$flavor:ident: $index:expr] $($res= t:tt)*]) =3D> { $crate::io_write!(@parse [$io] [$($proj)* [$flavor: $index]] [$($r= est)*]) }; + (@parse [$io:expr] [] [try: $ioloc:expr, $($rest:tt)*]) =3D> { + $crate::io_write!(@parse [$io] [try: $ioloc] [, $($rest)*]) + }; + (@parse [$io:expr] [] [build: $ioloc:expr, $($rest:tt)*]) =3D> { + $crate::io_write!(@parse [$io] [build: $ioloc] [, $($rest)*]) + }; ($io:expr, $($rest:tt)*) =3D> { $crate::io_write!(@parse [$io] [] [$($rest)*]) }; --=20 2.54.0 From nobody Sat Sep 26 12:29:11 2026 Received: from LO3P265CU004.outbound.protection.outlook.com (mail-uksouthazon11020089.outbound.protection.outlook.com [52.101.196.89]) (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 54DBE48665F; Tue, 1 Sep 2026 16:50:47 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=52.101.196.89 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788281451; cv=fail; b=FAqHGd1YfgEK6WaVdVYqNA4wlws+8vJeSJpRrxKqrZJhrs+xUQmygOR80iTvbtOOlQYKslPd7GWZfLIcfBFpCEggXvcnZyOkwDU/8U5zt20pj3bveozjOuEQD3JcyuMzLr+82kykfUFC2YHwGWNV03Ea1Tx2GJ6DRQ0HcBCAYic= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788281451; c=relaxed/simple; bh=xnfbjRqvJKgOcZ12SKC5n17bNMX2qwQHPgAuyVtchgA=; h=From:Date:Subject:Content-Type:Message-Id:References:In-Reply-To: To:Cc:MIME-Version; b=oqmvoNozG/0Bmw44HG3tECumq0PqHMWo8gP9c2EG3NvguNhSy6NzN+C472uHVWll76ix6fWMTCQ3hThoeDJwtgf7eYBJIGnj0xr55vXLEdVDx/2jqoyJe27OrFl+mHsGpGO3UsyWMuD6bDYVu189J82L0Bh4cRA7PyQW5y82rBE= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=garyguo.net; spf=pass smtp.mailfrom=garyguo.net; dkim=pass (1024-bit key) header.d=garyguo.net header.i=@garyguo.net header.b=k0pmHjfm; arc=fail smtp.client-ip=52.101.196.89 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=garyguo.net Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=garyguo.net Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=garyguo.net header.i=@garyguo.net header.b="k0pmHjfm" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=Gt+nb1pa+gzs2k3vzbOIBuSO2dSGcpTpVzA09O7/cVsvMmwaQ8oY4MlYnHqnTU1BvDu4U3KtAEx5PIeZgRWBhAg3Whc/qEULcE2mtjl9qWfx3vwN0dXy7Vw8+U1u/vOT+cDT8BmEY6HnjGB150RsgSkBRkvYllANvU/PHXJ/4+WP+Z09c0FJ1oFA3kN/6GAmer2exQE/MNLToFDNxchCG8tAWfNiU1haGM3WBYroLErVFjBB5svXx/Sszggs9S0Vy+Iv3daL5Ew3rm6RoWNPnSqcPvHcSbmy+IlOkGzTb8+nJ7q7ZBj9ZVSVI4g1JoQky2qkROoJqcb3aXpP7UASfg== 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=c8POvxbCn0EDxKQV16ymx8mJMnN25n6i4oyPMxZhVbo=; b=l/UdC4YmurtQa50J1YzWlqgKPEnRPV3TqGPspK/xNwjK0EFMQkfuFhRGJMGlt2D8/SklxvV0W2sx+zDjuPvIjBDqn6wH+OCgDN80IliMopsaT/jY94EdRBtU3jZFM6JV7SkkAerhiaSMgsRvUBz77YbEsVVc186kJiFi+io44fk5OkyXQNTHPkh2pEkZ4BNl2RqZpPiweAncAAHfRaCaEnZQdlpl0GzvKRd6BFDgInzJPd23K9mBAgeLLPxQSC16bEmwbMsxNMRm5buvWCfi1icxex3puPjJyG6CFc+ME2uwMGdoDaNA72AfDSccaBUdlv+rUzFUvOX9h553HhTQSQ== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=garyguo.net; dmarc=pass action=none header.from=garyguo.net; dkim=pass header.d=garyguo.net; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=garyguo.net; s=selector1; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=c8POvxbCn0EDxKQV16ymx8mJMnN25n6i4oyPMxZhVbo=; b=k0pmHjfmxs0+fZXKnNdSnd4hgdm51TayHCfM8ivQ+T4DO/LL2smjNmXN03zhUxotMVTGNHdPzG75iSJ9Y8wSeAtCcSG0Svz+uKs2lkXlbU/7iWQh/y0u4M8XbWmfyTE1dZcEmraT7bbf9kskddtnHIyHZ77ucJfbpcB1/Pz0+2w= Authentication-Results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=garyguo.net; Received: from LOAP265MB8560.GBRP265.PROD.OUTLOOK.COM (2603:10a6:600:4ab::19) by LO0P265MB7316.GBRP265.PROD.OUTLOOK.COM (2603:10a6:600:2ef::11) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.21.360.13; Tue, 1 Sep 2026 16:50:37 +0000 Received: from LOAP265MB8560.GBRP265.PROD.OUTLOOK.COM ([fe80::f60b:1537:68d7:4fc1]) by LOAP265MB8560.GBRP265.PROD.OUTLOOK.COM ([fe80::f60b:1537:68d7:4fc1%4]) with mapi id 15.21.0360.008; Tue, 1 Sep 2026 16:50:37 +0000 From: Gary Guo Date: Tue, 01 Sep 2026 17:50:30 +0100 Subject: [PATCH v4 06/16] rust: io: register: allow explicit base type specification Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260901-typed_register-v4-6-5552b1d59525@garyguo.net> References: <20260901-typed_register-v4-0-5552b1d59525@garyguo.net> In-Reply-To: <20260901-typed_register-v4-0-5552b1d59525@garyguo.net> To: Danilo Krummrich , Alice Ryhl , Daniel Almeida , Miguel Ojeda , Boqun Feng , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Andreas Hindborg , Trevor Gross , Tamir Duberstein , Alexandre Courbot , =?utf-8?q?Onur_=C3=96zkan?= , David Airlie , Simona Vetter , Bjorn Helgaas , =?utf-8?q?Krzysztof_Wilczy=C5=84ski?= Cc: driver-core@lists.linux.dev, rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, nova-gpu@lists.linux.dev, dri-devel@lists.freedesktop.org, linux-pci@vger.kernel.org, Gary Guo X-Mailer: b4 0.15.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1788281431; l=9090; i=gary@garyguo.net; s=20221204; h=from:subject:message-id; bh=xnfbjRqvJKgOcZ12SKC5n17bNMX2qwQHPgAuyVtchgA=; b=7gW4WluEWaD83+/nNVoqBjkftphtAebq/fQHGP1DyaBlOvTWdwqQ8mzxEBgqU/hFz/xw7VVIZ SO1g3LR0jBsDDUITDrQltbGGrWCLjXkIVshYbF2HdmeSpeXTmdvW3HZ X-Developer-Key: i=gary@garyguo.net; a=ed25519; pk=vB3uIX95SM4eVrIqo1DWNWKDKD2xzB+yLLLr0yOPYMo= X-ClientProxiedBy: PAZP264CA0173.FRAP264.PROD.OUTLOOK.COM (2603:10a6:102:236::16) To LOAP265MB8560.GBRP265.PROD.OUTLOOK.COM (2603:10a6:600:4ab::19) 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: LOAP265MB8560:EE_|LO0P265MB7316:EE_ X-MS-Office365-Filtering-Correlation-Id: 728ac541-dcd4-4fb9-1a7e-08df08492628 X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|366016|1800799024|23010399003|10070799003|376014|7416014|10067099003|3023799007|22082099003|56012099006|5023799004|18002099003|921020; X-Microsoft-Antispam-Message-Info: YMg+HJ1J1pNFvqXzjcZUNDypAHwEmmcJEGwMB+Av6yskpX+KJ/LLghDL1BL8CNUHejk1IkvMFNis5Ny7hIaTlzJmBGP4qv8qOiVt65z9Et6ufIlCEtrflpd3OLdxSMjXB4dpAy3GTlbSOVlqvR4qPO9pk9CPSK2nzbOlTfsLo6tG7FIhpqjdH8FuOOpb02bJjVakO6e0wrUVh+LjtZMejpMbyH/an0e65Eur7zxESpbSg+uCVlqC7RotiPjQRR90A3ZDBS0bBvSl1OJun9Ub8RsbZsvGPkG33LhJO3ZWsLji2xw+QPu3CHXD2DPCmln+IhPkLElCKEyKFvm822RnYMMmehd+exn1iI+7pMtYU4ispM+83vXFCYU3tf2TqE4RzSCIwkztSe2ZmdLRpYgI5wz5JGBR1VLSEIxDvTH4+vwI5FkdrQIhSIES1v1WXVdlQVZKpcKTTriMulkENhKaSJkJnWcKf8BXOrvhBUsZ8M6FzI9DHgqgGVyc/Id0qH1wUtYhXYK4BTTYIoSNy5sROtsvTqflbLFH4zDHaIB7e0Ac31a54T7u75VVtScLrj4NvFj5r0CDL3kL8I6f6t3t3YQCJr19A12VdYaK3/vKNiLbegQ43ChuwW7/fz1W7CUnEDeUaUSHGWVMW0A4pvHKwWKiy8w/crFbJOBJxjz8C5fu97qEBacr9BDIRAe5Ztc0lV8tu3C61XJXDZOCJw2euA== X-Forefront-Antispam-Report: CIP:255.255.255.255;CTRY:;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:LOAP265MB8560.GBRP265.PROD.OUTLOOK.COM;PTR:;CAT:NONE;SFS:(13230040)(366016)(1800799024)(23010399003)(10070799003)(376014)(7416014)(10067099003)(3023799007)(22082099003)(56012099006)(5023799004)(18002099003)(921020);DIR:OUT;SFP:1102; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: =?utf-8?B?bmNnMDd0NXJ0VzVUVUZjdWRpbG5VUVhzc0JZS01COGVUaXNncW8rREZJK0hX?= =?utf-8?B?UENTZGMybnVqemIvZ0I0TXE2OXZ2ZWY0N0h3NWNURDhzRk1sQXVhWWJ5RjFZ?= =?utf-8?B?ZktoMFFrT2hrZFJIeHN6d0dPZTR1c3U1emJ1c2dualRRa21TVytkTHJKNFlv?= =?utf-8?B?WHprWFRIVTRBOURsRHVRMUVuOWZBNCs3UUhkWkJGNnhOcGVpa3lQanRScWNV?= =?utf-8?B?bW1Ja2ZYdXp0b2tkSGROU3Z2cG5acTRCZFhVUFY4eHRCdnFRSWZaSDNnUTk2?= =?utf-8?B?TmRuSG9TRGFpT0RoUE5IL21kN1QwZklYM3h5bnJyejBGMGlCRjB6YytNazg0?= =?utf-8?B?UFQ1ZVg3ZmVrb0FKRTAzRE9CUDNHdVpxOG5vOXVYckttMHlMZzVzU2svcUxu?= =?utf-8?B?Tk5TUXNIbVU4R2YxZFJnSVEzTWxJMjYrYnovMFROTlphSXh2eGoyNDRzd0N6?= =?utf-8?B?MXBRVnNnMHhMaDVEN3FkNkxtdTVxK1NrcUt1UExjeE9lQ3Z4Z2FobUFFM1Z3?= =?utf-8?B?alpEK2E2SENCSHI2aGV4MW9pUVd5WGRXcUdFc1NSQWthKzBkaWQwbUs4NkRI?= =?utf-8?B?TDBYQk8wWjBtS1pZTFFjU21jTC8ycW9sU0NCeFRBV1A1enJWbU16STg4SEZM?= =?utf-8?B?aitWRGdLa0VSM29ackpKUXlmamxzK1RjeXA0TlBkMGFPdTIvc1IrNk5kbXZZ?= =?utf-8?B?UnhrZi82SW4rN2hlREdOQ05YZ213QmxEWDkzanZuOFp6MlAxa1ZuRDRZT0hV?= =?utf-8?B?UHpQR0JuaEdxbkZmTGZZVDQ1MlhiM2k3QllsaUd2eE5zV1NiTXNpZ0dqNHJo?= =?utf-8?B?cUNtSVhEVXZGcS83RkwzaUppRGN6YmthLzRXaHF0bU9kbUU5akZ0NkJ5QTVn?= =?utf-8?B?RmVaVUNRRWQwOGV0U0VLNHBmeHY5angwSGU1R1lPRFpzS2N3SHBZNFhBY1or?= =?utf-8?B?RFRlaTJnSWovWFA1NEJ4RmxLeVdTQlFkTG1EWi8rZGZ2eTBleS94QndXTkFP?= =?utf-8?B?T0xOK1lsVFhBQUVKS1ViVElRS0FaT3lxQU5Xb1JadjdUN3VSaU95SzdhVzlv?= =?utf-8?B?dmlleVA5S2JuVzRhK0tLUElId0hyL1hvdTI1bnJPTitSU0puZ1dxcDF5NCtw?= =?utf-8?B?UFh4TVRDbVRaaElJaHd2WFFlUjdwdW05NW55cmhScUZNOU1VNXQ5dTNJMktV?= =?utf-8?B?akdGTjdqQjRueWFIRlkrTTU0dGR2SnhMNkR5dm9BUnFOSnY3aExtcXlNS0Iv?= =?utf-8?B?SFdkS0JjU1J5Q1pyeG90RzNRK2ZvMzB5bWZvd2Y5c0xFRUdSMXRZRG1yYzJq?= =?utf-8?B?ZGMvNlBrdDFEbmg2RzVLY044NTl0UUdnRkhzeVo3QzVLRmNkOTREMUM1RWtQ?= =?utf-8?B?eUt6RWpPbHduVXlxdWZsdGlhb2xCcUw4b21zK2UxWGpwbGx0R0dmTVdVVlhC?= =?utf-8?B?T3VyYzkwNUxkVTBKWnFrU0I3VSszUEp0UkZMS3E1UFUyUUt5Yjlob0t5WC82?= =?utf-8?B?WXZTcEZYVldrWTkwaG1UeDhVRWJMc1RoOXpPUk9zT253djBDN3ZrOUtDK3BB?= =?utf-8?B?QkEraktmdDU0bkdwdmxNTGh1cU5URUNkelFucXdXaXRHanR4L0NxVkRndGJ5?= =?utf-8?B?UGMraFBmbUd6MlVldEZoMVFIRk1lTlZDeFhoYjZ5bTViaXQ5VW54b3hGd1Za?= =?utf-8?B?dGtvamxuQXVKdmxHbTlLb2d0eWIyeTB1a1IwNEpiK0dCKzg2UlZTaG42ellR?= =?utf-8?B?WUtvYXFPVjI1a1JHUHBVWVphbmxEVHNwZGNWWUFGNmx1YnJkNEtCSmkwdlRU?= =?utf-8?B?WEJ6RmE5NWxBU1ZsWGpxam1kY2o2djdNcTY0UEI5Sjc0dFBvMkt1RXp2K2xD?= =?utf-8?B?QXo2VFRQL0xHZ2NrUis2MXIwVVpNb3cxcVNrNlZXczRjSk9JS0ZqTEFQMm44?= =?utf-8?B?OUtGK24zRWl5UmhGZFpoWXZYejA1YnFyOUV3Z3Jmd1Z5Z0hJRHQ4TjhTQjIr?= =?utf-8?B?Sy9wUVgzdldoWldsM2l2RnpjMndvaTJ5WnFSSnNKQkZKbjlQUWVRVzgwKytX?= =?utf-8?B?WWJmREZPc0xaTjdUdnM1NlhrdG1YZXpLK3U2Wi9KNkFpTnBaS1NSc1ZlWGYr?= =?utf-8?B?Y0JtaTdGc0M1cjNXdDYzcWMzRGdQR0VtYVU4TEZoTSt5S1YvWjRnNllWWWRR?= =?utf-8?B?a0hXdGN2dGZNSlE2NFBINlJyTTJ3cmo1K08wcHlxNjM3YmgrYnZHTE84V3VU?= =?utf-8?B?N0lmWTlTdkZsNm5QOWo5d2xURnJIdlBTV2tyWHdJOVgvNVVpb092YWJBNGJw?= =?utf-8?B?S0dzUzIwUEszNGFJV3BYcUpUa1YxVGc5YzRwQmFPdmdhNG1xK2tmdz09?= X-OriginatorOrg: garyguo.net X-MS-Exchange-CrossTenant-Network-Message-Id: 728ac541-dcd4-4fb9-1a7e-08df08492628 X-MS-Exchange-CrossTenant-AuthSource: LOAP265MB8560.GBRP265.PROD.OUTLOOK.COM X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 01 Sep 2026 16:50:37.6336 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: bbc898ad-b10f-4e10-8552-d9377b823d45 X-MS-Exchange-CrossTenant-MailboxType: HOSTED X-MS-Exchange-CrossTenant-UserPrincipalName: ZVRXViJcsS48dGjKUi+vZIqK8rAAmzUkHAxYzJvdQVaFjYGqEduQhRKckcJ5Ttc7lB19KCKvrWdd9pUE3RtxmA== X-MS-Exchange-Transport-CrossTenantHeadersStamped: LO0P265MB7316 Currently registers work for all untyped I/O regions, which is not ideal. It allows registers defined for device A to work for another device B and there is no safeguarding at all. All users of the `register!` macro know what type it will be operating on, and that type is consistent across the driver. Therefore, add a `base` parameter to `register!`. Currently this parameter is unused in the generated code; it will be used when all users of `register!` is converted to gain the parameter. Signed-off-by: Gary Guo Acked-by: Miguel Ojeda Reviewed-by: Alexandre Courbot Tested-by: Alexandre Courbot --- Changes since v3: - Add a dummy user of `base` to prevent warning on user side (this is present in v2 but I forgot to add it in v3's proc macro rewrite). --- rust/kernel/io.rs | 4 ++++ rust/kernel/io/register.rs | 51 +++++++++++++++++++++++++++++++++++++++---= ---- rust/macros/io/register.rs | 23 ++++++++++++++++++++- 3 files changed, 70 insertions(+), 8 deletions(-) diff --git a/rust/kernel/io.rs b/rust/kernel/io.rs index 8df268969566..05c7fa12fdbe 100644 --- a/rust/kernel/io.rs +++ b/rust/kernel/io.rs @@ -909,6 +909,8 @@ fn try_write(self, location: L, value: T) -> Resu= lt /// }; /// /// register! { + /// base: Region; + /// /// VERSION(u32) @ 0x100 { /// 15:8 major; /// 7:0 minor; @@ -1051,6 +1053,8 @@ fn write(self, location: L, value: T) /// }; /// /// register! { + /// base: Region<0x1000>; + /// /// VERSION(u32) @ 0x100 { /// 15:8 major; /// 7:0 minor; diff --git a/rust/kernel/io/register.rs b/rust/kernel/io/register.rs index 45d2e73a92e7..49a5fe069e47 100644 --- a/rust/kernel/io/register.rs +++ b/rust/kernel/io/register.rs @@ -13,9 +13,14 @@ //! # Simple example //! //! ```no_run -//! use kernel::io::register; +//! use kernel::io::{ +//! register, +//! Region, +//! }; //! //! register! { +//! base: Region<0x1000>; +//! //! /// Basic information about the chip. //! pub BOOT_0(u32) @ 0x00000100 { //! /// Vendor ID. @@ -55,11 +60,14 @@ //! register, //! Io, //! IoLoc, +//! Region, //! }, //! num::Bounded, //! }; -//! # use kernel::io::{Mmio, Region}; +//! # use kernel::io::Mmio; //! # register! { +//! # base: Region<0x1000>; +//! # //! # pub BOOT_0(u32) @ 0x00000100 { //! # 15:8 vendor_id; //! # 7:4 major_revision; @@ -429,11 +437,14 @@ fn into_io_op(self) -> (FixedRegisterLoc, T) { /// io::{ /// register, /// Io, +/// Region, /// }, /// }; -/// # use kernel::io::{Mmio, Region}; +/// # use kernel::io::Mmio; /// /// register! { +/// base: Region<0x1000>; +/// /// FIXED_REG(u32) @ 0x100 { /// 15:8 high_byte; /// 7:0 low_byte; @@ -464,9 +475,14 @@ fn into_io_op(self) -> (FixedRegisterLoc, T) { /// the context: /// /// ```no_run -/// use kernel::io::register; +/// use kernel::io::{ +/// register, +/// Region, +/// }; /// /// register! { +/// base: Region<0x1000>; +/// /// /// Scratch register. /// pub SCRATCH(u32) @ 0x00000200 { /// 31:0 value; @@ -516,6 +532,7 @@ fn into_io_op(self) -> (FixedRegisterLoc, T) { /// /// ```ignore /// register! { +/// ... /// pub RELATIVE_REG(u32) @ Base + 0x80 { /// ... /// } @@ -542,9 +559,10 @@ fn into_io_op(self) -> (FixedRegisterLoc, T) { /// WithBase, /// }, /// Io, +/// Region, /// }, /// }; -/// # use kernel::io::{Mmio, Region}; +/// # use kernel::io::Mmio; /// /// // Type used to identify the base. /// pub struct CpuCtlBase; @@ -563,6 +581,8 @@ fn into_io_op(self) -> (FixedRegisterLoc, T) { /// /// // This makes `CPU_CTL` accessible from all implementors of `RegisterB= ase`. /// register! { +/// base: Region<0x1000>; +/// /// /// CPU core control. /// pub CPU_CTL(u32) @ CpuCtlBase + 0x10 { /// 0:0 start; @@ -579,6 +599,8 @@ fn into_io_op(self) -> (FixedRegisterLoc, T) { /// /// // Aliases can also be defined for relative register. /// register! { +/// base: Region<0x1000>; +/// /// /// Alias to CPU core control. /// pub CPU_CTL_ALIAS(u32) =3D> CpuCtlBase + CPU_CTL { /// /// Start the aliased CPU core. @@ -621,15 +643,18 @@ fn into_io_op(self) -> (FixedRegisterLoc, T) { /// register, /// register::Array, /// Io, +/// Region, /// }, /// }; -/// # use kernel::io::{Mmio, Region}; +/// # use kernel::io::Mmio; /// # fn get_scratch_idx() -> usize { /// # 0x15 /// # } /// /// // Array of 64 consecutive registers with the same layout starting at = offset `0x80`. /// register! { +/// base: Region<0x1000>; +/// /// /// Scratch registers. /// pub SCRATCH(u32)[64] @ 0x00000080 { /// 31:0 value; @@ -655,6 +680,8 @@ fn into_io_op(self) -> (FixedRegisterLoc, T) { /// // Alias to a specific register in an array. /// // Here `SCRATCH[8]` is used to convey the firmware exit code. /// register! { +/// base: Region<0x1000>; +/// /// /// Firmware exit status code. /// pub FIRMWARE_STATUS(u32) =3D> SCRATCH[8] { /// 7:0 status; @@ -667,6 +694,8 @@ fn into_io_op(self) -> (FixedRegisterLoc, T) { /// // Here, each of the 16 registers of the array is separated by 8 bytes= , meaning that the /// // registers of the two declarations below are interleaved. /// register! { +/// base: Region<0x1000>; +/// /// /// Scratch registers bank 0. /// pub SCRATCH_INTERLEAVED_0(u32)[16, stride =3D 8] @ 0x000000c0 { /// 31:0 value; @@ -688,6 +717,7 @@ fn into_io_op(self) -> (FixedRegisterLoc, T) { /// /// ```ignore /// register! { +/// ... /// pub RELATIVE_REGISTER_ARRAY(u8)[10, stride =3D 4] @ Base + 0x100 { /// ... /// } @@ -707,9 +737,10 @@ fn into_io_op(self) -> (FixedRegisterLoc, T) { /// WithBase, /// }, /// Io, +/// Region, /// }, /// }; -/// # use kernel::io::{Mmio, Region}; +/// # use kernel::io::Mmio; /// # fn get_scratch_idx() -> usize { /// # 0x15 /// # } @@ -731,6 +762,8 @@ fn into_io_op(self) -> (FixedRegisterLoc, T) { /// /// // 64 per-cpu scratch registers, arranged as a contiguous array. /// register! { +/// base: Region<0x1000>; +/// /// /// Per-CPU scratch registers. /// pub CPU_SCRATCH(u32)[64] @ CpuCtlBase + 0x00000080 { /// 31:0 value; @@ -758,6 +791,8 @@ fn into_io_op(self) -> (FixedRegisterLoc, T) { /// /// // Alias to `SCRATCH[8]` used to convey the firmware exit code. /// register! { +/// base: Region<0x1000>; +/// /// /// Per-CPU firmware exit status code. /// pub CPU_FIRMWARE_STATUS(u32) =3D> CpuCtlBase + CPU_SCRATCH[8] { /// 7:0 status; @@ -768,6 +803,8 @@ fn into_io_op(self) -> (FixedRegisterLoc, T) { /// // Here, each of the 16 registers of the array is separated by 8 bytes= , meaning that the /// // registers of the two declarations below are interleaved. /// register! { +/// base: Region<0x1000>; +/// /// /// Scratch registers bank 0. /// pub CPU_SCRATCH_INTERLEAVED_0(u32)[16, stride =3D 8] @ CpuCtlBase = + 0x00000d00 { /// 31:0 value; diff --git a/rust/macros/io/register.rs b/rust/macros/io/register.rs index 9b92c8099edd..851335792a46 100644 --- a/rust/macros/io/register.rs +++ b/rust/macros/io/register.rs @@ -29,6 +29,7 @@ }; =20 mod kw { + syn::custom_keyword!(base); syn::custom_keyword!(stride); } =20 @@ -152,22 +153,42 @@ fn parse(input: syn::parse::ParseStream<'_>) -> Resul= t { } =20 pub(crate) struct RegDef { + #[allow(unused)] + base: Option, regs: Vec, } =20 impl Parse for RegDef { fn parse(input: syn::parse::ParseStream<'_>) -> Result { + let base =3D if input.peek(kw::base) { + let _: kw::base =3D input.parse()?; + let _: Token![:] =3D input.parse()?; + let base =3D input.parse()?; + let _: Token![;] =3D input.parse()?; + Some(base) + } else { + None + }; let mut regs =3D Vec::new(); while !input.is_empty() { regs.push(input.parse()?); } - Ok(RegDef { regs }) + Ok(RegDef { base, regs }) } } =20 pub(crate) fn register(def: RegDef) -> Result { let mut outputs =3D TokenStream::new(); =20 + if let Some(base) =3D &def.base { + outputs.extend(quote_spanned!(base.span() =3D> + const _: () =3D { + #[allow(unused)] + type Base =3D #base; + }; + )); + } + for reg in def.regs { let Reg { attrs, --=20 2.54.0 From nobody Sat Sep 26 12:29:11 2026 Received: from CWXP265CU008.outbound.protection.outlook.com (mail-ukwestazon11020139.outbound.protection.outlook.com [52.101.195.139]) (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 1877B4854FB; Tue, 1 Sep 2026 16:50:44 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=52.101.195.139 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788281447; cv=fail; b=aU0E4w8uysohT/vzhma8J8hhqQqyD9+XDdw4jsx0PDnckF/QCB41RKMC2qCInaQgSokwpX9B/LYal8XHxiQONQhqEu+ge31ALVp0RM4ei5JYb2mTv7gG1s7hlzB+cF3QYnyjH70VwcFmXD4bB0auDNciWoT2USi9bdp/yzHYss0= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788281447; c=relaxed/simple; bh=2uNTtWhdTI1vj/BfIrNYGSr2FLG/bFe6Zrz19DCl530=; h=From:Date:Subject:Content-Type:Message-Id:References:In-Reply-To: To:Cc:MIME-Version; b=adNiNdV+B+nTKV6rYwq4UxTBngQF1+LsgPCcSEtPaNreI6b9hya8PrdImmZUnVzHZRIOE5DdqcLJoDoguybxHVsbpF3N9h2akOe4NXmjVJt4Wc33y0W+Qp15/i4fo/86oX0cLD9gQYISnYfC2errMTZx4weI8Vih5vNlioILQRQ= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=garyguo.net; spf=pass smtp.mailfrom=garyguo.net; dkim=pass (1024-bit key) header.d=garyguo.net header.i=@garyguo.net header.b=GWRc4kGe; arc=fail smtp.client-ip=52.101.195.139 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=garyguo.net Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=garyguo.net Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=garyguo.net header.i=@garyguo.net header.b="GWRc4kGe" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=CwyicxT5DpR34upuzC7mFLC6kVkK4oP6y+IrvkGTatMH6Ko4XMWsC/y2ZoqmUbLS0CA1ACQJm/ZiHEh3rb8UHd9AKKxOdHdxqfKsaniyw6MP9HIuO9LAdpOJu13JLI2gfrbw7oc0lE1+wO3wYKcm7oEK5u9HG/243fodYilWAq3mwn7OP0tfg1kX72zLkZxPOIsRllnfnJebmC/1d7Lt9Fgor429EuxHotmc+l1Jxx9G33YQkJiN85DVKH5qeJoZsH6DgTZqCrUeVO/46aYkrC9mTp9A/dwl8V7ckLUnkQQoJRBTm6ll3ylD2cIW1Rmf5uJ/0BbLx3d+Uqt7K6Jmhw== 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=FnKPXDwl84fJXnvofr18yY6Cs8bP0OUEpUgDn761ty4=; b=eKVKBdAV8w206UXcBbFbzVT0hLxAMmoaUMx/MfkiW5PAe2eWWdNFiiEfn3vVTo/dpHEswWafvSSCfflzmB3YAy2G8P7cvYiq0BOBHrud8XHCvae0h+Vyp6y1TEREbMZ712rZrnY9e2YJOWZIIHPDa88MJqRgtCVYgT/f+pOJt5yO1yQrErGUoahiOs0pkOKUcl3gPvXDJCs+dCtK56pPyUD35gLOvTrBrQr5XqH+25NpBdQLUrSH6U85/mbiWjaDT4q10KFjps8zLAvRnyfKOwEi2GuxY2H2+YzPhFTsNPkxErkbSD5QxB5wgdnDNRMMXhOUxQrT1Hz0TohjXSlDDg== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=garyguo.net; dmarc=pass action=none header.from=garyguo.net; dkim=pass header.d=garyguo.net; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=garyguo.net; s=selector1; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=FnKPXDwl84fJXnvofr18yY6Cs8bP0OUEpUgDn761ty4=; b=GWRc4kGeQld95s2gfCwpQC/6V3lg/me+bRxCRxm4YI3sye6HLLkikheZFr1145gvBPnvdMQKcojiULZJbx0pZ7l8kvgr+yqBpxh1+hzUE7yVeCL45gVIteUN7jVfcrWfgWv78Pc/m7HL7omVdDrHYXoBhUDFCzxPhHbrp0WU4Ps= Authentication-Results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=garyguo.net; Received: from LOAP265MB8560.GBRP265.PROD.OUTLOOK.COM (2603:10a6:600:4ab::19) by LO6P265MB6954.GBRP265.PROD.OUTLOOK.COM (2603:10a6:600:322::14) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.21.360.13; Tue, 1 Sep 2026 16:50:38 +0000 Received: from LOAP265MB8560.GBRP265.PROD.OUTLOOK.COM ([fe80::f60b:1537:68d7:4fc1]) by LOAP265MB8560.GBRP265.PROD.OUTLOOK.COM ([fe80::f60b:1537:68d7:4fc1%4]) with mapi id 15.21.0360.008; Tue, 1 Sep 2026 16:50:38 +0000 From: Gary Guo Date: Tue, 01 Sep 2026 17:50:31 +0100 Subject: [PATCH v4 07/16] gpu: nova-core: specify base type for registers Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260901-typed_register-v4-7-5552b1d59525@garyguo.net> References: <20260901-typed_register-v4-0-5552b1d59525@garyguo.net> In-Reply-To: <20260901-typed_register-v4-0-5552b1d59525@garyguo.net> To: Danilo Krummrich , Alice Ryhl , Daniel Almeida , Miguel Ojeda , Boqun Feng , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Andreas Hindborg , Trevor Gross , Tamir Duberstein , Alexandre Courbot , =?utf-8?q?Onur_=C3=96zkan?= , David Airlie , Simona Vetter , Bjorn Helgaas , =?utf-8?q?Krzysztof_Wilczy=C5=84ski?= Cc: driver-core@lists.linux.dev, rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, nova-gpu@lists.linux.dev, dri-devel@lists.freedesktop.org, linux-pci@vger.kernel.org, Gary Guo X-Mailer: b4 0.15.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1788281431; l=8979; i=gary@garyguo.net; s=20221204; h=from:subject:message-id; bh=2uNTtWhdTI1vj/BfIrNYGSr2FLG/bFe6Zrz19DCl530=; b=Kkekqypd+3vwr0X9v02kkDU4PlqTPgMe3QPqkP+xHv96CbfQT+Fdnhwtp96UPrXvZu4WGeAx9 qINL2aqdCITA9qTqBN8oYrMvEBIUvDVrmM1Qp/rjTXYanjaZVUKjwVn X-Developer-Key: i=gary@garyguo.net; a=ed25519; pk=vB3uIX95SM4eVrIqo1DWNWKDKD2xzB+yLLLr0yOPYMo= X-ClientProxiedBy: PAZP264CA0173.FRAP264.PROD.OUTLOOK.COM (2603:10a6:102:236::16) To LOAP265MB8560.GBRP265.PROD.OUTLOOK.COM (2603:10a6:600:4ab::19) 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: LOAP265MB8560:EE_|LO6P265MB6954:EE_ X-MS-Office365-Filtering-Correlation-Id: ac3c05d9-64f3-4a76-82d3-08df0849269b X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|366016|1800799024|23010399003|7416014|376014|10070799003|10067099003|56012099006|22082099003|18002099003|921020; X-Microsoft-Antispam-Message-Info: buazC7D4XnVgA11scuI99f9v3QhBMP638C+952BG54WyeROoAKjvxp2OtFSqrTgpGS6+Q6wrL9LO4ghsdjIa2d2x4VgDGGuNb/DP2cLsgp6juMG7RgOCmrrahiBN/JxVueJojIiyCj4ZDlpL1DHYJggndrMWnFmiFpL11Bmdo+ApI1tS93dx0AXrPrtolzST3Hv3G1dmlhTeC4ABtVMgNhuku9VZqj7jkAILRn1M9n47F6kAf3tTXwi+MMaAsC0n8dV0PW3pO90MiPuvDT4dqyZHBCqGKUE70W7lIb6sIQxlVrpeUUIsQg4AW5YW8/qpM3aL+JGKn8D7yeYHGu8hVCItLyNMII82EY3gIVO4IldNr0spuxxh1yIZ68UTD6WG5+1fzhZxRr3m8YP+z2bX1mN1IXhUlTzO4R4At6k+42iwqstpRr/XDaGLOP3ax0FKDDAj6J+agpskGFeNeZGjvgE6/k0kyqtKGPYLmzcIhgkQ841p0tmgLON9KPoxWXYuPWbyDQSvSJVubXxISGPbvcxkET1HOTxkufbIN0dahhb/QVaj9o9uNtjMzeVB5KYFT+HpHE8VTQRwCh8eGgyUSVO/eezYAaFjmHGdS92GAHH3kTMrHET+dcUWmJ1+mza7P4OY3OelqfrmK1pfsOH58X/roVBo/t5+zT2f9SWQ8EoAp32oEG0Hqe7DN7kFCKHw87SU029+vIql8z3f24N6Xw== X-Forefront-Antispam-Report: CIP:255.255.255.255;CTRY:;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:LOAP265MB8560.GBRP265.PROD.OUTLOOK.COM;PTR:;CAT:NONE;SFS:(13230040)(366016)(1800799024)(23010399003)(7416014)(376014)(10070799003)(10067099003)(56012099006)(22082099003)(18002099003)(921020);DIR:OUT;SFP:1102; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: =?utf-8?B?dzdiVHl2ejIvZXpJKzE3WUluR1FDT01OREQ1OXVUVE02eTQ5YzRqZkRQbnhh?= =?utf-8?B?R2xoSlNyTEVqLy9lejR0dFE4WVlLTlljcGVPdFVSUnFaK0hWZnowbDlkbzl3?= =?utf-8?B?SjJSaGNoN3pPUjExcklZZi9odnpEdTlQeExYaWQxN21nNXNGemRuWG8wbFpr?= =?utf-8?B?S0g0cS8yQitkS2l6bGRaSVdCYWNGeGQ2VXZzL2daZnpXQXl0OVFWRkxEbWU2?= =?utf-8?B?cGR0Zk5vQkhRUFkxMUFjNWhTb0I5eUlZeDRaaVEvOUEyTWJCRE1aaHZKc0Vz?= =?utf-8?B?Y3FwUE1tbVUyWEk3OWpscUlUdWM4VnNjUTByalBnNnJJd21OVElvVHZPd2pJ?= =?utf-8?B?SHA2TEl4WGJDT25IOFM2ZzJZQTF4Zm1RSHRoM1czVGxsVXZTVVgvMHZuZXJN?= =?utf-8?B?NWFDV09JUlU5V2JwdTF0eWJsY002OVNmZFJncjg3WEVXMzNwYk4relduUHRJ?= =?utf-8?B?ZzlpaHdtQTBKdG53bUlQS25tK3MxaWxyM3VQbUJhVnlrQ0IyNlBMNjZRMGN2?= =?utf-8?B?WlBkNEgway9wYW5NRGRrSDRpbGxMMStwaTJRMFRjeFpMTFk5UGJKQzBoMXlz?= =?utf-8?B?bXZ3TnNzY05ETWU2Z3FORlBabTFaaVRobk1HSVJyQlViRDZjdlhUdmhKMHUx?= =?utf-8?B?a0JOaXpuOEdjdHF3WC92VlZoTy9FYktXQTB6ZEY3K2ZrWG41ekp4MkJXV2U4?= =?utf-8?B?cDJGZjIzWTZnUUt5UkdnYjdzN2lPaytzMGJnSGY4ZWR4K0RpTThkdndSNmMx?= =?utf-8?B?S2xPUXRoV25BcUNuTVI1ZUNHQUM2c0dpeCsvQjZydHpxWkFwQ0NkNGlvdGNK?= =?utf-8?B?OWgvaUpyNXphbHppWEJWS0VPYWVlWSthQllySlVJajJCZTkwTklCNXBHN0ha?= =?utf-8?B?RStqbmtDK2d3ZGIxT0pod0FlbmN2TUJXRzdXSHZnSzVPdlJlMnVHQzN5L3NC?= =?utf-8?B?bHlySHgxTklQNC9QNTlZNHIrR09PRDFqMGhxcElNcDM2OGVRa05mbmMvNGhP?= =?utf-8?B?QUUrSXNEVzBYVE5rYXhYNnBwY2YzK3lPenFJdWpCdjRDa0tNOHdMNVFGVFB1?= =?utf-8?B?eGlQWHVDNTNUVkdyZ05TelJoRzI2YUFoU3N3QzdBSDNQNFR5VTJyQmVOaEx6?= =?utf-8?B?b3V3bU12VDJkenFqSWw3UHBjNC9CV1p0VTRuUjNtMXVtL3E4SzRLamFVdTZh?= =?utf-8?B?VXNNekhMTzR3WEFCa0c2b0dIMWw0YUxqenN2MWxiMG1JMlBaWG1ONEpsMERi?= =?utf-8?B?YXArdUx4a0k3ei9oa3M0bTIxelBmYTdrdXVCVndaaTdkbkh5QVQ4bm4vZTBz?= =?utf-8?B?ZUJoVDJTb3pjMUNGM25OcCtiSXFnNERZODhLekM4SUtXSkV2YzZsOTYrUzI5?= =?utf-8?B?TnpxbGYvS1FiTmZEN091R2d2ZFdDTGFTSHlleWY1cVVSKzJ5Qkw5M2pMdzZM?= =?utf-8?B?VHZnNUw2TUppekRtODNUa2lsUllsRVlUQzM0NjNJUXl2aGlPUXBxdGJhNUZl?= =?utf-8?B?UE1wTGVMd0F3eGZZSG9MbTIxWllYZXZOZi9MUk0wVXQ4UXJGZzZ0UTljTGFj?= =?utf-8?B?TnlUVmJVNDFnNFBIMHRUTGp1N3FIQlUxbDRnM3F2V2J0UlZaOFROZmhBSlM0?= =?utf-8?B?cXM4K25udXduRHgra2ZubkVWcUV0SU1HbHk0Q21ESmtCU0E2RlNrM0VPbEtE?= =?utf-8?B?R3VaeHVsTVhTK0JiZTl2WGNTMlF4L0dJZTMrWUlPTVFsTWs3ZkUrZGk0enRK?= =?utf-8?B?ZnoxRnZWSENISTAxcUVBbG5PZ2tiV01sblQ1dWRmYlJvUTRxWUx5ajRhVHFX?= =?utf-8?B?TlNpNkZFT2FmWFIxZ1FjL2lhLzlwa01DdmNBMFZGQ2grYkNoQU9Qb09CcHVs?= =?utf-8?B?bGw1N0hGTlpEbnM5aVV5b1oyeUkyZXlrQmhwNklwZk9DQlU5NzVacmUvWHlx?= =?utf-8?B?K3Y1Wkw3U1c3cGsxZWc5Wk82UXNnS3drZzZTSzRSdlo0eEdDTUxmWnpTL2Yx?= =?utf-8?B?eGpianFqOHNZSFViZTRqWkVrRmNaVE1UbmVUMDhJNzZjWFJCeVlNdGRHVXVF?= =?utf-8?B?SllKaGdaTmxWMGVVSGcvQkRrRisva09TTGJucmQ5V2lTa2tQZndEcEREL2Ez?= =?utf-8?B?cjgvemJFYi9pSHVFdW8rMFFzYlowYXNlQ29xNnU1Ynp6akVjRjlmekFnKzB5?= =?utf-8?B?dlRFQzRIVW5Tdzkzb2cxYnk3clM2YmhvM3Q3Zys0VnltU3ZNQ1JNSjdWVHl1?= =?utf-8?B?blU5NEtVZjhmU3JyQmI3bGRzbTRMMmxZUlhNZDFpMmZkLzZTNmJuV1d1RElX?= =?utf-8?B?VC9Pd3lLSDllU3RicVpuSXpXNjhQY3d5eStZRGkyaE40QVVTUGdjQT09?= X-OriginatorOrg: garyguo.net X-MS-Exchange-CrossTenant-Network-Message-Id: ac3c05d9-64f3-4a76-82d3-08df0849269b X-MS-Exchange-CrossTenant-AuthSource: LOAP265MB8560.GBRP265.PROD.OUTLOOK.COM X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 01 Sep 2026 16:50:38.8096 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: bbc898ad-b10f-4e10-8552-d9377b823d45 X-MS-Exchange-CrossTenant-MailboxType: HOSTED X-MS-Exchange-CrossTenant-UserPrincipalName: zQw1yPspY3IK3otruYiAlYuFr6w113i8hqEMcCFSsd7InAguJyvw8gmO5snEXEyuqzR2iPEtJK59eHnya6iUNA== X-MS-Exchange-Transport-CrossTenantHeadersStamped: LO6P265MB6954 All registers use the same base type, which is `::Target`. Thus add the base parameter to `register!` invocation. Reviewed-by: Alexandre Courbot Signed-off-by: Gary Guo Acked-by: Miguel Ojeda Tested-by: Alexandre Courbot --- drivers/gpu/nova-core/driver.rs | 1 + drivers/gpu/nova-core/fb/regs.rs | 12 ++++++++++++ drivers/gpu/nova-core/gsp/regs.rs | 9 ++++++++- drivers/gpu/nova-core/regs.rs | 37 +++++++++++++++++++++++++++++++++++= +- drivers/gpu/nova-core/vbios.rs | 11 ++++++++++- 5 files changed, 67 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/nova-core/driver.rs b/drivers/gpu/nova-core/driver= .rs index bbd93959e0b2..cf3534dd47d4 100644 --- a/drivers/gpu/nova-core/driver.rs +++ b/drivers/gpu/nova-core/driver.rs @@ -37,6 +37,7 @@ pub(crate) struct NovaCore<'bound> { const BAR0_SIZE: usize =3D SZ_16M; =20 pub(crate) type Bar0<'a> =3D &'a pci::Bar<'a, BAR0_SIZE>; +pub(crate) type NovaRegisters =3D kernel::io::Region; =20 kernel::pci_device_table!( PCI_TABLE, diff --git a/drivers/gpu/nova-core/fb/regs.rs b/drivers/gpu/nova-core/fb/re= gs.rs index 95adbe124a30..c27582e376e2 100644 --- a/drivers/gpu/nova-core/fb/regs.rs +++ b/drivers/gpu/nova-core/fb/regs.rs @@ -5,9 +5,13 @@ sizes::SizeConstants, // }; =20 +use crate::driver::NovaRegisters; + // PDISP =20 register! { + base: NovaRegisters; + pub(super) NV_PDISP_VGA_WORKSPACE_BASE(u32) @ 0x00625f04 { /// VGA workspace base address divided by 0x10000. 31:8 addr; @@ -30,6 +34,8 @@ pub(super) fn vga_workspace_addr(self) -> Option { // PFB =20 register! { + base: NovaRegisters; + /// Low bits of the physical system memory address used by the GPU to = perform sysmembar /// operations (see [`crate::fb::SysmemFlush`]). pub(super) NV_PFB_NISO_FLUSH_SYSMEM_ADDR(u32) @ 0x00100c10 { @@ -65,6 +71,8 @@ pub(super) fn vga_workspace_addr(self) -> Option { pub(super) struct Hshub0Base(()); =20 register! { + base: NovaRegisters; + // GB10x sysmem flush registers, relative to the HSHUB0 base. GB10x ro= utes sysmembar // through a primary and an EG (egress) pair that must both be program= med to the same // address. Hardware ignores bits 7:0 of each LO register. The boot pa= th uses a fixed @@ -87,6 +95,8 @@ pub(super) fn vga_workspace_addr(self) -> Option { } =20 register! { + base: NovaRegisters; + // GB20x FBHUB0 sysmem flush registers. Unlike the older // NV_PFB_NISO_FLUSH_SYSMEM_ADDR registers, which encode the address w= ith an // 8-bit right-shift, these take the raw address split into lower and = upper @@ -101,6 +111,8 @@ pub(super) fn vga_workspace_addr(self) -> Option { } =20 register! { + base: NovaRegisters; + /// Low bits of the physical system memory address used by the GPU to = perform /// sysmembar operations on Hopper. /// diff --git a/drivers/gpu/nova-core/gsp/regs.rs b/drivers/gpu/nova-core/gsp/= regs.rs index 9a48aa87e7fb..3c410d65e8e4 100644 --- a/drivers/gpu/nova-core/gsp/regs.rs +++ b/drivers/gpu/nova-core/gsp/regs.rs @@ -2,11 +2,16 @@ =20 use kernel::io::register; =20 -use crate::regs::NV_PBUS_SW_SCRATCH; +use crate::{ + driver::NovaRegisters, + regs::NV_PBUS_SW_SCRATCH, // +}; =20 // PGSP =20 register! { + base: NovaRegisters; + pub(super) NV_PGSP_QUEUE_HEAD(u32) @ 0x00110c00 { 31:0 address; } @@ -15,6 +20,8 @@ // PBUS =20 register! { + base: NovaRegisters; + /// Scratch register 0xe used as FRTS firmware error code. pub(super) NV_PBUS_SW_SCRATCH_0E_FRTS_ERR(u32) =3D> NV_PBUS_SW_SCRATCH= [0xe] { 31:16 frts_err_code; diff --git a/drivers/gpu/nova-core/regs.rs b/drivers/gpu/nova-core/regs.rs index caeef4d85874..1af073f3861f 100644 --- a/drivers/gpu/nova-core/regs.rs +++ b/drivers/gpu/nova-core/regs.rs @@ -13,7 +13,10 @@ }; =20 use crate::{ - driver::Bar0, + driver::{ + Bar0, + NovaRegisters, // + }, falcon::{ DmaTrfCmdSize, FalconCoreRev, @@ -37,6 +40,8 @@ // PMC =20 register! { + base: NovaRegisters; + /// Basic revision information about the GPU. pub(crate) NV_PMC_BOOT_0(u32) @ 0x00000000 { /// Lower bits of the architecture. @@ -108,6 +113,8 @@ fn fmt(&self, f: &mut kernel::fmt::Formatter<'_>) -> ke= rnel::fmt::Result { // PBUS =20 register! { + base: NovaRegisters; + pub(crate) NV_PBUS_SW_SCRATCH(u32)[64] @ 0x00001400 {} } =20 @@ -121,6 +128,8 @@ fn fmt(&self, f: &mut kernel::fmt::Formatter<'_>) -> ke= rnel::fmt::Result { // number. =20 register! { + base: NovaRegisters; + /// Boot Sequence Interface (BSI) register used to determine /// if GSP reload/resume has completed during the boot process. pub(crate) NV_PGC6_BSI_SECURE_SCRATCH_14(u32) @ 0x001180f8 { @@ -175,6 +184,8 @@ pub(crate) fn usable_fb_size(self) -> u64 { pub(crate) const NV_FUSE_OPT_FPF_SIZE: usize =3D 16; =20 register! { + base: NovaRegisters; + pub(crate) NV_FUSE_OPT_FPF_NVDEC_UCODE1_VERSION(u32)[NV_FUSE_OPT_FPF_S= IZE] @ 0x00824100 { 15:0 data =3D> u16; } @@ -191,6 +202,8 @@ pub(crate) fn usable_fb_size(self) -> u64 { // PFALCON =20 register! { + base: NovaRegisters; + pub(crate) NV_PFALCON_FALCON_IRQSCLR(u32) @ PFalconBase + 0x00000004 { 6:6 swgen0 =3D> bool; 4:4 halt =3D> bool; @@ -392,6 +405,8 @@ pub(crate) fn mem_scrubbing_done(self) -> bool { /* PFALCON2 */ =20 register! { + base: NovaRegisters; + pub(crate) NV_PFALCON2_FALCON_MOD_SEL(u32) @ PFalcon2Base + 0x00000180= { 7:0 algo ?=3D> FalconModSelAlgo; } @@ -414,6 +429,8 @@ pub(crate) fn mem_scrubbing_done(self) -> bool { // PRISCV =20 register! { + base: NovaRegisters; + /// RISC-V status register for debug (Turing and GA100 only). /// Reflects current RISC-V core status. pub(crate) NV_PRISCV_RISCV_CORE_SWITCH_RISCV_STATUS(u32) @ PFalcon2Bas= e + 0x00000240 { @@ -439,6 +456,8 @@ pub(crate) fn mem_scrubbing_done(self) -> bool { // These registers manage falcon EMEM communication queues. =20 register! { + base: NovaRegisters; + pub(crate) NV_PFSP_QUEUE_HEAD(u32)[8] @ 0x008f2c00 { 31:0 address =3D> u32; } @@ -462,9 +481,13 @@ pub(crate) fn mem_scrubbing_done(self) -> bool { pub(crate) mod gm107 { use kernel::io::register; =20 + use crate::driver::NovaRegisters; + // FUSE =20 register! { + base: NovaRegisters; + pub(crate) NV_FUSE_STATUS_OPT_DISPLAY(u32) @ 0x00021c04 { 0:0 display_disabled =3D> bool; } @@ -474,9 +497,13 @@ pub(crate) mod gm107 { pub(crate) mod ga100 { use kernel::io::register; =20 + use crate::driver::NovaRegisters; + // FUSE =20 register! { + base: NovaRegisters; + pub(crate) NV_FUSE_STATUS_OPT_DISPLAY(u32) @ 0x00820c04 { 0:0 display_disabled =3D> bool; } @@ -488,9 +515,13 @@ pub(crate) mod ga100 { pub(crate) mod gh100 { use kernel::io::register; =20 + use crate::driver::NovaRegisters; + // PTHERM =20 register! { + base: NovaRegisters; + pub(crate) NV_THERM_I2CS_SCRATCH(u32) @ 0x000200bc { 31:0 data; } @@ -505,9 +536,13 @@ pub(crate) mod gh100 { pub(crate) mod gb202 { use kernel::io::register; =20 + use crate::driver::NovaRegisters; + // PTHERM =20 register! { + base: NovaRegisters; + pub(crate) NV_THERM_I2CS_SCRATCH(u32) @ 0x00ad00bc { 31:0 data; } diff --git a/drivers/gpu/nova-core/vbios.rs b/drivers/gpu/nova-core/vbios.rs index c03650ee5226..9c214b9f4dd9 100644 --- a/drivers/gpu/nova-core/vbios.rs +++ b/drivers/gpu/nova-core/vbios.rs @@ -16,7 +16,10 @@ }; =20 use crate::{ - driver::Bar0, + driver::{ + Bar0, + NovaRegisters, // + }, firmware::{ fwsec::Bcrt30Rsa3kSignature, FalconUCodeDesc, @@ -92,12 +95,16 @@ impl<'a> VbiosIterator<'a> { fn rom_offset(dev: &device::Device, bar0: Bar0<'_>) -> Result { // IFR Header in VBIOS. register! { + base: NovaRegisters; + NV_PBUS_IFR_FMT_FIXED0(u32) @ 0x300000 { 31:0 signature; } } =20 register! { + base: NovaRegisters; + NV_PBUS_IFR_FMT_FIXED1(u32) @ 0x300004 { 30:16 fixed_data_size; 15:8 version =3D> u8; @@ -105,6 +112,8 @@ fn rom_offset(dev: &device::Device, bar0: Bar0<'_>) -> = Result { } =20 register! { + base: NovaRegisters; + NV_PBUS_IFR_FMT_FIXED2(u32) @ 0x300008 { 19:0 total_data_size; } --=20 2.54.0 From nobody Sat Sep 26 12:29:11 2026 Received: from CWXP265CU009.outbound.protection.outlook.com (mail-ukwestazon11021101.outbound.protection.outlook.com [52.101.100.101]) (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 E089A48551B; Tue, 1 Sep 2026 16:50:45 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=52.101.100.101 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788281448; cv=fail; b=jpolBUaLQIi0wtaBNp3DW67WJ2CIM93g/KCJq7pYxuebUizrLtL/aE5BpnmChbJxgVOutFimgUdJQSprTxGPS7Fzlt9Ss1CCQPF/zQKtmGT8LK5889jp68m4WcDCvfLgAI7vdCR3dFmun1nnk5mKv4XOslcrfZS2+DAnNOg1/uc= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788281448; c=relaxed/simple; bh=nTJ7wZSeeUArV1c5w8DwZwK2ut/RdnBTX0czYVxRigA=; h=From:Date:Subject:Content-Type:Message-Id:References:In-Reply-To: To:Cc:MIME-Version; b=az9LIR28nWHznZsp4QxGDkpfKPUZQDkTedV/Tbh4ne1kLhnugkeLeyqd0nL08LjgZ30/f/YEujEouoxqdKI6xBUx/jK2PEGlhkyD+DCwqSKRUT1VqkNK0I8MexyoipeylXIrlYHaAeIvFGtIhQr6N4owGXqVfcHXj37KIa61su0= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=garyguo.net; spf=pass smtp.mailfrom=garyguo.net; dkim=pass (1024-bit key) header.d=garyguo.net header.i=@garyguo.net header.b=pGbWEPpD; arc=fail smtp.client-ip=52.101.100.101 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=garyguo.net Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=garyguo.net Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=garyguo.net header.i=@garyguo.net header.b="pGbWEPpD" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=HEj81LyXE8o44GHfyhH0frbWpEFZWka5GxhHIM1llm3np9J2DKiUZT+GDajN0f+u+jWPLmZdXjWy6ncNmxVb3YVYHs8N4/p/oN0Tg7hg3m1lBK+3WsJ0bxIUaCU+3JWpFgi8xG4mjpPLoKqAmWpGDQXskp/KJ0MXTnYLJ/IXfkXg9JRhUxF9np0OeyHzW1A/AkWzGQeIR8a/nGBv1n1dQ0/ozIJ/CsY5LARDFIOxjdrejX5Lx3TgdQLh5BzqR2WajVNTJ5ClCT4X6c7Yp7xxShZgq5Tm6g03GHgRfTO2r++K52f2CuK+FQndHsttQPE7zU1JhKbO/AGCQo/YI4oxaA== 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=NvWLye6q3T6iJdVLSyDKt2fXUAcrrEInZPcP41AR6Mo=; b=tc0QNDZPcJiRPb7uFP0O+4dSHiC0zskWuX8zfSI27lXZe+Vwuv+BPwcJMmQCjV1YLr7GrPpGNby6GX9E4/hj2emSLV0Pi2X+eVTd9i9HDWMe6zEVmidt3B5bqSmAmmXUTdEYpkxVQhffz1UGSIgAzixZiFdb1vgOgA7plbwx+VxBM3spN6KBxqCJImXOPrnPzdts19GT21oyAiOhaXRuO7ctg3S+b5ydOJknxoT+6OZgrEU2uJUkMi+MnYlk4YXQt9KF/vSyXjUbHBLOTDhrs7LVaMD+Tuy+LCyubOxHpE2rBfXz6i56/0CrkdExWUXXQgiwIqf7tVKJHInL1ksCYg== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=garyguo.net; dmarc=pass action=none header.from=garyguo.net; dkim=pass header.d=garyguo.net; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=garyguo.net; s=selector1; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=NvWLye6q3T6iJdVLSyDKt2fXUAcrrEInZPcP41AR6Mo=; b=pGbWEPpD58kDZLpBL7AR09S5fQDJx/XIkYg3NjRHu9DQF2sHwsYfX6dNNGGzod/Ad/duZ0/xwIGdoY0fl9su9b83RdgKx9xHytagf3wqptCtmR6n4oIu7z4UDkrYAb4tQNuri8Q3EDWzR1QxJEMFM8XX9ZGKRhQvgFBDz1eGvJc= Authentication-Results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=garyguo.net; Received: from LOAP265MB8560.GBRP265.PROD.OUTLOOK.COM (2603:10a6:600:4ab::19) by CW1P265MB9199.GBRP265.PROD.OUTLOOK.COM (2603:10a6:400:272::22) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.21.360.13; Tue, 1 Sep 2026 16:50:39 +0000 Received: from LOAP265MB8560.GBRP265.PROD.OUTLOOK.COM ([fe80::f60b:1537:68d7:4fc1]) by LOAP265MB8560.GBRP265.PROD.OUTLOOK.COM ([fe80::f60b:1537:68d7:4fc1%4]) with mapi id 15.21.0360.008; Tue, 1 Sep 2026 16:50:39 +0000 From: Gary Guo Date: Tue, 01 Sep 2026 17:50:32 +0100 Subject: [PATCH v4 08/16] drm/tyr: specify base type for registers Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260901-typed_register-v4-8-5552b1d59525@garyguo.net> References: <20260901-typed_register-v4-0-5552b1d59525@garyguo.net> In-Reply-To: <20260901-typed_register-v4-0-5552b1d59525@garyguo.net> To: Danilo Krummrich , Alice Ryhl , Daniel Almeida , Miguel Ojeda , Boqun Feng , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Andreas Hindborg , Trevor Gross , Tamir Duberstein , Alexandre Courbot , =?utf-8?q?Onur_=C3=96zkan?= , David Airlie , Simona Vetter , Bjorn Helgaas , =?utf-8?q?Krzysztof_Wilczy=C5=84ski?= Cc: driver-core@lists.linux.dev, rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, nova-gpu@lists.linux.dev, dri-devel@lists.freedesktop.org, linux-pci@vger.kernel.org, Gary Guo X-Mailer: b4 0.15.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1788281431; l=7409; i=gary@garyguo.net; s=20221204; h=from:subject:message-id; bh=nTJ7wZSeeUArV1c5w8DwZwK2ut/RdnBTX0czYVxRigA=; b=hwh470+H6ghU6gJ8+uNBfwNSKLi57prsGhGKA92YknymqxtJWpT3qb85Ljqc875s7yHLWqFsn bDqz8D0Gh1/BCGll2fOGh8VdoUWwBg3hI2G5jefFO6CTzg6QV8l4Io+ X-Developer-Key: i=gary@garyguo.net; a=ed25519; pk=vB3uIX95SM4eVrIqo1DWNWKDKD2xzB+yLLLr0yOPYMo= X-ClientProxiedBy: PAZP264CA0173.FRAP264.PROD.OUTLOOK.COM (2603:10a6:102:236::16) To LOAP265MB8560.GBRP265.PROD.OUTLOOK.COM (2603:10a6:600:4ab::19) 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: LOAP265MB8560:EE_|CW1P265MB9199:EE_ X-MS-Office365-Filtering-Correlation-Id: b5645085-ad1c-4f39-d928-08df0849274c X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|1800799024|7416014|10070799003|376014|23010399003|366016|921020|6133799003|3023799007|10067099003|56012099006|22082099003|18002099003; X-Microsoft-Antispam-Message-Info: ldHPAB4UBRCPQKaSAK43PhZCNO9g8cg1w/Qp180l+gxQoPAFd2bMHaL+OfYLJAlpCgjN+ZP6OLo9ZSK4yAjqkkf+5PTDLbOmN6UOvCgvga/8svHgSunRtl4rkwfgTQ9qrzBYmzZZdUdA6vxLj4ewM21IkqezMQ+xdm3xnMVm9DMG6XX5txanzCP1k4C7t9jQrva+q89zbH7Isk+5lMqU8VtwLGz7ADYfV60yYn25QjiaNP2frJMrAQVw6Sc03fqtATkX6c8liCoZAWMgUs+/WhOdh2nJOO5PUclggA31bYdUrRTNWt5W0O6dXnrbaJVblsJU7arIgSjz/koGJmvhgWQ6DuuGLPuWa4gAkWawCVSJ9TvxeBBJEk9HEXGaEbD/aPzJQeM3gZmBzz4WQT3jyrwds4CEkkAiWc8YhZ5ADsv9OjRUaVvWFKKOZHrUF8OZdrM8N34LEmCnqEc+7+q6/pWhqzjYXk1CoQ8u3g6tgUsB970mCJlLwCNSyqll0iPxiCsJaa87urbTFoBFCACyGBBkUsZe2nczye740vp0GoXQAYbFICOugviMA2ljYuWNQnJPGO32yyt4qQUEkCIhwnAOjtlL1H2in18tLxNGlalkO7BkDGJtsyQugKof23MDLCnlOCxaG7/q+zxCwFC7KBkmojiVIOYaxI6PTzneMHCmx2cL8uidas2d92jvp1cKdqxcoJk7Cn6W+fvVJh6mkA== X-Forefront-Antispam-Report: CIP:255.255.255.255;CTRY:;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:LOAP265MB8560.GBRP265.PROD.OUTLOOK.COM;PTR:;CAT:NONE;SFS:(13230040)(1800799024)(7416014)(10070799003)(376014)(23010399003)(366016)(921020)(6133799003)(3023799007)(10067099003)(56012099006)(22082099003)(18002099003);DIR:OUT;SFP:1102; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: =?utf-8?B?TmNhVDFNaGwxWGpxUytwQW1ZemVJbUF1aUw0My9qUHhudG05MWoyeU12aGN6?= =?utf-8?B?alRmSFpPTktrRmxtcFpCU0MrZEJ3eTlNTkk0OWVRRTdabnE3c0UxL2pvOFIy?= =?utf-8?B?dmY4N2o0WW5EQVg3aUhZa3VpS0k5eUFUYzBOMHNTTEsvTVZ4UHNRMnZ6MUtj?= =?utf-8?B?cXBmZmUwZEVhRnBYK1FDdHViU0p0YnkweUNTOFp0SEVCZlJyOXFBOTdiRW04?= =?utf-8?B?V1VLeHVYNjVLQnQ0YVBrQm55K1pkREMxYitxL0duN1B4TDVZTWVob1Y1UXhj?= =?utf-8?B?UmtmNUNBZEFZUGE4aGhOMnEvSWtnOTYvcnQ1UWN4NlIvbzg4R2lud1QvTDNk?= =?utf-8?B?ZGZaZzVRaGIyUVhQMC9HaGU3dGJlN3lVZERERldPUGlFNWF3bnRsZUozcEZt?= =?utf-8?B?NVRZWHp6YmxGeFg5L2dhTDVXa1Q2VXFGdXBWdm15cDFFOUVQNXFzWHdPMW9F?= =?utf-8?B?cGZGVVJNSk10dTlhd1VWSjZ6eVRDMmN1ZEl2cWtOMmZXbm9RNDltMWpCL2c5?= =?utf-8?B?djNrbkFaZTI1b1h1bHZmaVZvMmpLTDJTRm0wdVlsckllZHgvOWZFME93SVNC?= =?utf-8?B?RWhtcFUxV2lMMSs4QUdxcnhHOXZCNWRremhDeTRFSHBucUFON3RSV0pkU1Br?= =?utf-8?B?SUh3THQ2Q1ZPMHhZOG5hVE93cXpZM1pqSDhnWjFnUTZjUWZwaDhWc2VQUkZm?= =?utf-8?B?bm5Rd09mZFJ0WGExZWFlVkoyUG9saVJLRUl4ZTh4clVxZ0FaVDRuUC9RYlBs?= =?utf-8?B?Q1F3VldYRG9GbnRlaUdvSlpiOHlTS0l6aHhwdDVPTlkwZEdCK1h0bWNVb3Y5?= =?utf-8?B?UzJzenJoN2s2UFNwZTJCS2hRUXdwdytqQVdsNy92SDNXRmpRaGxvZG1VWnVa?= =?utf-8?B?L0l3amVnaExaMnl3aFYzLzFaVzdCeUVJM2M2MFpDZXpPVFc5cTFMcVJ1YzZ5?= =?utf-8?B?dklnN2xNcFFOcFlmMWxianFoNHZkNENPVGhUZStRQ1JzUGFqMkZmaW1CUGkx?= =?utf-8?B?MGxtNUM0NzlwTXZOTkh4UDh0clRQc2N0TFJ2dzdEVElTMm9CWGZQYllLMWxD?= =?utf-8?B?bnREQnRaNExGMFRWVDBuZ0xNWHpwVFdxV0ZkWEVuL281d1FDVTZaa2taUHp4?= =?utf-8?B?UlFXNjhHMWo1Y2tLVGlqSXk3TkJHS1Fwejl4ZTVSNE1tTTNFM2IrTjJGZ2Fh?= =?utf-8?B?QkxEL3hOSzVORUFFR0tzS2h1ai9vSm5TSFNLeDE3VUFYTUNSZHRxY045Vjc5?= =?utf-8?B?NVE4WEQ2Z0ZZWml1MktJMFNucWdYTWxvblg5QVJqSCs0Vm4rOHU0a2RBd0M3?= =?utf-8?B?NWdSZHptTWFMc2hqOUhORnA4aDBYa0ZETE1WUFR5djExYW1MTlVWWDFLY2ky?= =?utf-8?B?SlI3Q3NwVEpFZ0JBR09EbDRYWVJJaVArMXFJckE1R1Fuc2hCbURkTTY3ek5T?= =?utf-8?B?NGlRbEQ3MjRxemZiODR3SHBYYjhiZExoQ2dOekJ6U2twMG5RUmcvanZJZmVO?= =?utf-8?B?ZXpRTW1MSlNHN05xZXhMS1dEYTd2YjdNelpUUlBMOUV2L3hJR3JWb3JzdGli?= =?utf-8?B?TjhpcXNYYVdOYk15bVVHbkJWN3FTRVFCVjJMTHMrTDhkUFhWdDNLK0hzRDlK?= =?utf-8?B?OGp1Q2EwbzhUbVdXOU0xbmRrTkJkd21QOHAwdEJLRlUwbXBYMmRBMWN3TTJy?= =?utf-8?B?L0lMNnBYbkt4QVU2cENITXdmeGkzS2NlM2pzRXpEdk1JWHdUb0Q3bnNPNFpJ?= =?utf-8?B?S1ZpL1EzS00rMmdNSmNNeVBSb2dpeWZ4UE9YNjlWTVc2L2ZaTVZadlg2V2Fv?= =?utf-8?B?bE1DY1lzQ09NK3BxZDFmZ3lHWSs0cmtBaG9lbEU5VXYrVVRxWEw5Z0NuZVl6?= =?utf-8?B?cnNMQ0FZbmw5dmN6NzJqQmRLZTZlUjRrYTllS2lVcmJ0MzgzeE9KZVpUd1Ez?= =?utf-8?B?THN5WndsbThmMnhLbkhscGhMWWxXR3AzRGUyMENBQ01hR2Q3UWgzNjMvYzVK?= =?utf-8?B?YVNiREhWRXFIdi9WNExrWGtBZDVrbExMbWRzSHBzUW5pcTZveTZoT0ZhWlg2?= =?utf-8?B?dVJsUDVsWndqYklvMytES0ZZUll6RmpzRzRxTm95QzhVMnJPUG5CZTczNzBF?= =?utf-8?B?SXlzVHNEVW9lZ3NrNWZzL3JXRXdxQ3diK1c0OW0ydGJwOW1IbTV4OXdoa0N5?= =?utf-8?B?UEk3NEl6cURXSDNSaFpGc3B0Z2JOMmN5WkgrQ3Fxc1kyK3hGVkh4Q1QvaGc4?= =?utf-8?B?QU01dEN1aDdzMzA2QzhzcjJPaHZuWGs4c0pwSTBQdk8zQzFXcFllMnlwVU93?= =?utf-8?B?THZHSGo0enl0eitGSTJJbUNGblRMVXdSNUZPRXJzN3JZNkxwZmxwQT09?= X-OriginatorOrg: garyguo.net X-MS-Exchange-CrossTenant-Network-Message-Id: b5645085-ad1c-4f39-d928-08df0849274c X-MS-Exchange-CrossTenant-AuthSource: LOAP265MB8560.GBRP265.PROD.OUTLOOK.COM X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 01 Sep 2026 16:50:39.5628 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: bbc898ad-b10f-4e10-8552-d9377b823d45 X-MS-Exchange-CrossTenant-MailboxType: HOSTED X-MS-Exchange-CrossTenant-UserPrincipalName: /dAq2Hu39N3KsEhJM6o7T6cfJYxihwT22leb1W42nQVsiED7w5wc+/ReeF8cE2q9zNzQne8C/gelR+HVIbB7Ug== X-MS-Exchange-Transport-CrossTenantHeadersStamped: CW1P265MB9199 All registers use the same base type, which is `::Target`. Thus add the base parameter to `register!` invocation. Signed-off-by: Gary Guo Acked-by: Miguel Ojeda Tested-by: Alexandre Courbot --- drivers/gpu/drm/tyr/driver.rs | 1 + drivers/gpu/drm/tyr/fw.rs | 5 ++++- drivers/gpu/drm/tyr/regs.rs | 45 +++++++++++++++++++++++++++++++++++++++= +++- 3 files changed, 49 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/tyr/driver.rs b/drivers/gpu/drm/tyr/driver.rs index bfb0ba19caff..730b84e37a54 100644 --- a/drivers/gpu/drm/tyr/driver.rs +++ b/drivers/gpu/drm/tyr/driver.rs @@ -46,6 +46,7 @@ }; =20 pub(crate) type IoMem<'a> =3D kernel::io::mem::IoMem<'a, SZ_2M>; +pub(crate) type TyrRegisters =3D kernel::io::Region; =20 pub(crate) struct TyrDrmDriver; =20 diff --git a/drivers/gpu/drm/tyr/fw.rs b/drivers/gpu/drm/tyr/fw.rs index 47d25c901bd0..7edb5eff1707 100644 --- a/drivers/gpu/drm/tyr/fw.rs +++ b/drivers/gpu/drm/tyr/fw.rs @@ -39,7 +39,8 @@ use crate::{ driver::{ IoMem, - TyrDrmDevice, // + TyrDrmDevice, + TyrRegisters, // }, fw::parser::{ FwParser, @@ -101,6 +102,8 @@ fn from(value: CacheMode) -> Self { } =20 register! { + base: TyrRegisters; + #[allow(non_upper_case_globals)] pub(super) SectionFlags(u32) @ 0x0 { 0:0 read =3D> bool; diff --git a/drivers/gpu/drm/tyr/regs.rs b/drivers/gpu/drm/tyr/regs.rs index a62724378ced..0c419c4e1186 100644 --- a/drivers/gpu/drm/tyr/regs.rs +++ b/drivers/gpu/drm/tyr/regs.rs @@ -57,7 +57,11 @@ pub(crate) mod gpu_control { uapi, // }; =20 + use crate::driver::TyrRegisters; + register! { + base: TyrRegisters; + /// GPU identification register. pub(crate) GPU_ID(u32) @ 0x0 { /// Status of the GPU release. @@ -315,6 +319,8 @@ fn from(mode: FlushMode) -> Self { } =20 register! { + base: TyrRegisters; + /// GPU command register. /// /// Use the constructor methods to create commands: @@ -380,6 +386,8 @@ pub(crate) fn clear_fault() -> Self { } =20 register! { + base: TyrRegisters; + /// GPU status register. Read only. pub(crate) GPU_STATUS(u32) @ 0x34 { /// GPU active, a 1-bit boolean flag. @@ -463,6 +471,8 @@ fn from(access: AccessType) -> Self { } =20 register! { + base: TyrRegisters; + /// GPU fault status register. Read only. pub(crate) GPU_FAULTSTATUS(u32) @ 0x3c { /// Exception type. @@ -768,6 +778,8 @@ fn from(mode: CoherencyMode) -> Self { } =20 register! { + base: TyrRegisters; + /// Coherency enable. An index of which coherency protocols should= be used. /// This register only selects the protocol for coherency messages= on the /// interconnect. This is not to enable or disable coherency contr= olled by MMU. @@ -808,6 +820,8 @@ fn from(mode: McuControlMode) -> Self { } =20 register! { + base: TyrRegisters; + /// MCU control. pub(crate) MCU_CONTROL(u32) @ 0x700 { /// Request MCU state change. @@ -849,6 +863,8 @@ fn from(status: McuStatus) -> Self { } =20 register! { + base: TyrRegisters; + /// MCU status. Read only. pub(crate) MCU_STATUS(u32) @ 0x704 { /// Read current state of MCU. @@ -862,7 +878,11 @@ fn from(status: McuStatus) -> Self { pub(crate) mod job_control { use kernel::register; =20 + use crate::driver::TyrRegisters; + register! { + base: TyrRegisters; + /// Raw status of job interrupts. /// /// Write to this register to trigger these interrupts. @@ -912,7 +932,11 @@ pub(crate) mod job_control { pub(crate) mod mmu_control { use kernel::register; =20 + use crate::driver::TyrRegisters; + register! { + base: TyrRegisters; + /// IRQ sources raw status. /// /// This register contains the raw unmasked interrupt sources for = MMU status and exception @@ -966,9 +990,10 @@ pub(crate) mod mmu_as_control { prelude::*, register, // }; - use pin_init::Zeroable; =20 + use crate::driver::TyrRegisters; + /// Maximum number of hardware address space slots. /// The actual number of slots available is usually lower. pub(crate) const MAX_AS: usize =3D 16; @@ -977,6 +1002,8 @@ pub(crate) mod mmu_as_control { const STRIDE: usize =3D 0x40; =20 register! { + base: TyrRegisters; + /// Translation table base address. A 64-bit pointer. /// /// This field contains the address of the top level of a tran= slation table structure. @@ -1104,6 +1131,8 @@ fn from(val: MemoryType) -> Self { } =20 register! { + base: TyrRegisters; + /// Stage 1 memory attributes (8-bit bitfield). /// /// This is not an actual register, but a bitfield definition = used by the MEMATTR @@ -1137,6 +1166,8 @@ fn from(val: MMU_MEMATTR_STAGE1) -> Self { } =20 register! { + base: TyrRegisters; + /// Memory attributes. /// /// Each address space can configure up to 8 different memory = attribute profiles. @@ -1292,6 +1323,8 @@ pub(crate) fn from_mair(mair: u64) -> Self { } =20 register! { + base: TyrRegisters; + /// Lock region address for each address space. pub(crate) LOCKADDR(u64)[MAX_AS, stride =3D STRIDE] @ 0x2410 { /// Lock region size. @@ -1353,6 +1386,8 @@ fn from(cmd: MmuCommand) -> Self { } =20 register! { + base: TyrRegisters; + /// MMU command register for each address space. Write only. pub(crate) COMMAND(u32)[MAX_AS, stride =3D STRIDE] @ 0x2418 { 7:0 command ?=3D> MmuCommand; @@ -1480,6 +1515,8 @@ fn from(access: MmuAccessType) -> Self { } =20 register! { + base: TyrRegisters; + /// Fault status register for each address space. Read only. pub(crate) FAULTSTATUS(u32)[MAX_AS, stride =3D STRIDE] @ 0x241= c { /// Exception type. @@ -1705,6 +1742,8 @@ fn from(sh: PtwShareability) -> Self { } =20 register! { + base: TyrRegisters; + /// Translation configuration and control. pub(crate) TRANSCFG(u64)[MAX_AS, stride =3D STRIDE] @ 0x2430 { /// Address space mode. @@ -1760,6 +1799,8 @@ fn from(sh: PtwShareability) -> Self { pub(crate) mod doorbell_block { use kernel::register; =20 + use crate::driver::TyrRegisters; + /// Number of doorbells available. pub(crate) const NUM_DOORBELLS: usize =3D 64; =20 @@ -1770,6 +1811,8 @@ pub(crate) mod doorbell_block { const STRIDE: usize =3D 0x10000; =20 register! { + base: TyrRegisters; + /// Doorbell request register. Write-only. pub(crate) DOORBELL(u32)[NUM_DOORBELLS, stride =3D STRIDE] @ 0x800= 00 { /// Doorbell set. Writing 1 triggers the doorbell. --=20 2.54.0 From nobody Sat Sep 26 12:29:11 2026 Received: from CWXP265CU009.outbound.protection.outlook.com (mail-ukwestazon11021101.outbound.protection.outlook.com [52.101.100.101]) (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 801A3481669; Tue, 1 Sep 2026 16:50:43 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=52.101.100.101 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788281445; cv=fail; b=cbU/YCZz0q3W7fYNScW2/iOXsgRWXTFXkEOHeLV0F/pQ16e9dM42p/S8sH11zr5wqSkAbaRzGGWsnQbMmIWRS0MIj+i+Ccyi8KcUWwBeOVY+e+2xtFbRlgpmu8GJuso0t0aKZfMFQjnCDcZkBEiIuyW+O84NPTPPDGY6OhxwfLQ= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788281445; c=relaxed/simple; bh=sSdw1Dv5hlsSyV6K0T7adkobqSvSgIeuYjKeEZiTdAE=; h=From:Date:Subject:Content-Type:Message-Id:References:In-Reply-To: To:Cc:MIME-Version; b=aDspcRBU6jEbIgjkGQGDVeIjro7CI4gIHXPltKq+Ow5Rcrtyh/UCaK05SfG+ZPQgxU1PVyLlYH1BNrjPuczZR3SePn12DaTQBrruyYnReIZbERrjf1yPhnE92RaxLyVAWuxff5nHv8y7IyU1gkDteC/Ejgm9xiK87LlCIypGSqk= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=garyguo.net; spf=pass smtp.mailfrom=garyguo.net; dkim=pass (1024-bit key) header.d=garyguo.net header.i=@garyguo.net header.b=Es/yGJVh; arc=fail smtp.client-ip=52.101.100.101 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=garyguo.net Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=garyguo.net Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=garyguo.net header.i=@garyguo.net header.b="Es/yGJVh" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=mGlhk9cuh8+VK/dEMT9I9u1tap+fMMBQCMVQRMcdKKOPkgZHh75HP5R80TZsL9p+Twz1EyvAtcCkSXWeP4VzjtShvmH/614UQGLBrY92v+AOT/4ooLM5aDB6rnfG17AKG9JZfo804IcZOtotJTC2EAIGTbPD8aYTfCZTNhJdHMPd5HSsis/bamVxMpdWFiKQ0Sl/1GIEB+JlPEpGadVMuF15AOoJ//pWvHFvUDQCMJsBXf1L6mYmfwU5c7FK76c0l4hua64cJo7FsvrTaLoELTyK1Qk1gpuJR0S+kGgAzEOJIHzVV8yXqXRC+CJ2XLDuCLuFd6uJrLLknsjIWFs0LA== 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=uDHJXJ/+khNEoOPvYRZ9OmruChe2fAgBcIw89OaS+4c=; b=AGzlv9SpwAxqbcfdXVL1EJf7kIePfrtcVzieJObdEcGvSPWZRKU4ivYf0iB/IfMBSjVQaRfCEkILsEAvY6GCUPFN+W/B+rMxREySyLBHCyyoSqyGul3IwDrCfJV5ruk5kgoN5g55ZWZLjEeom78PxmAjel/LBnkXSdz1xDBH3L+tdjFdLjMPx/c9IDcZ5P/V6+SNxS56FY6lChLsVEfaVElBcLfh2Fy/OD7zqukIlG76yaz0j+qoN3VkbjjDpB3vdXz6KmEBOdgMoosCqq2AQYJxYQP6odz2G90uWVSnPNfMqtrY0eWp+vFeP/gQ2voLe9YQGhIwvYF9TarZS8uiCw== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=garyguo.net; dmarc=pass action=none header.from=garyguo.net; dkim=pass header.d=garyguo.net; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=garyguo.net; s=selector1; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=uDHJXJ/+khNEoOPvYRZ9OmruChe2fAgBcIw89OaS+4c=; b=Es/yGJVhu/Q75rUdASuW1gfu387vGTpC2fNgglRy3qsEHPjxjYTgbRs5qYYP0HekAplxR/a4YguSt/lkPizEyI5tLHB2KxuyRV854NDfBp7siEyrBNxm8I9wF1rQFHLT/OYJdJAV+UW4bFxKEdilBYBbzOte8VDm4xHryfGRKVE= Authentication-Results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=garyguo.net; Received: from LOAP265MB8560.GBRP265.PROD.OUTLOOK.COM (2603:10a6:600:4ab::19) by CW1P265MB9199.GBRP265.PROD.OUTLOOK.COM (2603:10a6:400:272::22) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.21.360.13; Tue, 1 Sep 2026 16:50:40 +0000 Received: from LOAP265MB8560.GBRP265.PROD.OUTLOOK.COM ([fe80::f60b:1537:68d7:4fc1]) by LOAP265MB8560.GBRP265.PROD.OUTLOOK.COM ([fe80::f60b:1537:68d7:4fc1%4]) with mapi id 15.21.0360.008; Tue, 1 Sep 2026 16:50:40 +0000 From: Gary Guo Date: Tue, 01 Sep 2026 17:50:33 +0100 Subject: [PATCH v4 09/16] samples: rust: pci: specify base type for registers Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260901-typed_register-v4-9-5552b1d59525@garyguo.net> References: <20260901-typed_register-v4-0-5552b1d59525@garyguo.net> In-Reply-To: <20260901-typed_register-v4-0-5552b1d59525@garyguo.net> To: Danilo Krummrich , Alice Ryhl , Daniel Almeida , Miguel Ojeda , Boqun Feng , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Andreas Hindborg , Trevor Gross , Tamir Duberstein , Alexandre Courbot , =?utf-8?q?Onur_=C3=96zkan?= , David Airlie , Simona Vetter , Bjorn Helgaas , =?utf-8?q?Krzysztof_Wilczy=C5=84ski?= Cc: driver-core@lists.linux.dev, rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, nova-gpu@lists.linux.dev, dri-devel@lists.freedesktop.org, linux-pci@vger.kernel.org, Gary Guo X-Mailer: b4 0.15.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1788281431; l=993; i=gary@garyguo.net; s=20221204; h=from:subject:message-id; bh=sSdw1Dv5hlsSyV6K0T7adkobqSvSgIeuYjKeEZiTdAE=; b=BGW+bCFaAxx/XFZbYYhjY7dh4ectiA84l9SMk5lqC3cPQikq0d/Mi3DbEgjozYq7FEKL6J6Wy 4BX8BbZpb/bBFSR3JlV3AkHEb+iWiDTCdjWz7sktrgDU/BQD1+j/2ih X-Developer-Key: i=gary@garyguo.net; a=ed25519; pk=vB3uIX95SM4eVrIqo1DWNWKDKD2xzB+yLLLr0yOPYMo= X-ClientProxiedBy: PAZP264CA0173.FRAP264.PROD.OUTLOOK.COM (2603:10a6:102:236::16) To LOAP265MB8560.GBRP265.PROD.OUTLOOK.COM (2603:10a6:600:4ab::19) 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: LOAP265MB8560:EE_|CW1P265MB9199:EE_ X-MS-Office365-Filtering-Correlation-Id: 036a5c3e-54f4-4da7-363a-08df084927c2 X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|1800799024|7416014|10070799003|376014|23010399003|366016|921020|6133799003|10067099003|56012099006|22082099003|18002099003; X-Microsoft-Antispam-Message-Info: 7M6RLwvUXy2nk9IPTarJOEQQ4u3exZ8sIDX5uKFtw39Vbg3RBJrMPKc7sZo6DR3v7ufRRUtI6n78UewWppK1S9MGaghJuiKaWJ7XSBH0zADOhom9RBTnWq8sFk9g4GdvxWAvHT10iVHWC0vUi6vNi9YidpG3dcBLTitqDx4oTY4UjfDvbQJFYr1VkpNbMm8qpIlgwrrPFC1xUmimK4vIv1SAhg5tyUwQxNYH+qkJ2KL8TH/ry8+sFFTFPftthhz/OOeUGFMZnuhvYcGbCPRsEQWbirp4wgvVq9lgLJ18YYtj36783gySLXlSPe7lr1+7KscbGyA/SBlG02IPuEbt5ZB8zG6lPxUOLYW7IhUsQ+CA4elnAqi3kEVtWq+x+adbdKivq8dZGEB+vzToA0ZXLo22svhEtxRT7vnaotbEMbcmw280DqOx/SdvwkgWLPwXxiOphlmm8HRBQpKZ74sgx0iPwrQe/U+8dtcMlHKRKBJpEOB8Az6r6Jmb45m8HvzbQn22E/6HYVH4IWpOUWg95lWIKrQR47/1f/x6iWL5fV1mH77MRNYOKlWltlw2l/lfCdKac+ukYlzDIyIe3gpzF+3C+xD8h5SHZPxzYxoaaOr1/Vl3ExvRBs8124yFzBZUaKkRuTNPFhAsX8y3VdseQPURN2A4foxaBd2PP+4AafvTVltO2OuSpq/6x6cz4UFwrD6YxGI+b1ukRVA+CSYLBw== X-Forefront-Antispam-Report: CIP:255.255.255.255;CTRY:;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:LOAP265MB8560.GBRP265.PROD.OUTLOOK.COM;PTR:;CAT:NONE;SFS:(13230040)(1800799024)(7416014)(10070799003)(376014)(23010399003)(366016)(921020)(6133799003)(10067099003)(56012099006)(22082099003)(18002099003);DIR:OUT;SFP:1102; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: =?utf-8?B?dzlSMnB4MGl2SDRIY2FaVmRpaDNkNHdKekU2MzdDNXRUaEdhZGs4a0JXaU5T?= =?utf-8?B?VDNqbkIxdHVYank0SS9EMEFFdXdrTDJEbjRadm9lR25zVE0rbVMxTE9KMlhm?= =?utf-8?B?Qml3b0pKc3FubVZZLzIveWE1QVIreGxZaWh2aVVzbitlWFdOdWVBVW5DdUxi?= =?utf-8?B?MU9VWHRUKytQUlNFTDZOVDJ2U0U4YkxiUmpYaWMxRlZ6TGxraFB4SVZUamJJ?= =?utf-8?B?eXFHdkswL3k4USt5TzF5QjhOMmkzaDJzcFlKOHZ5azRGR3JPK2hTeWRHeXJQ?= =?utf-8?B?Rkw5QVpscTBnK1crRXJLQmtTQ1JIYVB3KzFucUMrdVJlWHJmam14OHErVTVU?= =?utf-8?B?MEhkY2hLRDFlRWYzOEx3VzlkM2kvckNuQzJMcDhJTm52SEFoUWtpOUdwMWMv?= =?utf-8?B?aFVUN2ZLOVQzSVRQdDFDYngyWWpkL1pwK1hDcFc2eENIdDJlMVFUejVENnph?= =?utf-8?B?b21MU3BzVFF2RTV6V2NBVTdmd21aMFJ0RjQyREp0OFFaaFFTbzFWdmMxQSs4?= =?utf-8?B?WkZ1VXo0ZEZoYzdETm1BY1VRM0NiY2JaeVR3amZtZFJyZWFjUWx1aXY0MENI?= =?utf-8?B?RFdtNXlsQVBreXQ2a0lsazJaMnphL0hBM0tzR2ViMm9naWdHb005VUFZbXI0?= =?utf-8?B?M0NzamFZZ3BnamxvbzN6L3h2ODhzUWw4c0xHLzh4ajU4SjMyYW1Sa0lxRlpa?= =?utf-8?B?bEZQL00yQlFwQ01uUnFoUGE5amhpT051RFFIemZYa01HYjNnc081QmhXR09H?= =?utf-8?B?QnVUZGxZQ1c5emNOem9hdmd3VEF0QWw0U1NVNTBUM3BuZ0FYSFhIZEdVeXd1?= =?utf-8?B?VkR5TEJlVi9NcXhzM1l3MzlRR3RQMmczcmxFVVRhZ0ZyUmtkelR3RjRMVXcr?= =?utf-8?B?Z2o4eG50S1lhcUlyckxuc1ZRT2FUK3p4R2FWazN5SzAzcjlweVFlSTkzVGht?= =?utf-8?B?djFuVFBUTzd4bkZrTTVvQmd1dWFkWFViT1BlUS9DWEhpTTZ4Q2hZdGtST0Jk?= =?utf-8?B?RmFacitZMGRWMlU2YW1DcDRrclEwSVUxVTlLRlBNais3c0E1TGpTQkd1L1dF?= =?utf-8?B?SExnMWl2bis0ZS9ZSVp4TXpzOHVRN0x1ODdMSkZ3YitlYWRVTHpiZmY3cGxE?= =?utf-8?B?Q0VZWi9DaXFMN1hnTU44TTZTUjRDZW1MdzVkTFR5V1JWT1lDU3hETEQ4VGs0?= =?utf-8?B?Zm5RcEp6TmFlWC9ZTms0bStpNmxkMEh6SDJ0WWdKaWR3WGZrbDBPOEhQanhh?= =?utf-8?B?V1pwK2hxV2o4aGdpeHJrb2Zpb1Jmd0pwY1dsQ1NTU2tudnhVMktjRk8weTdW?= =?utf-8?B?TnJtYnROa2xXQ3dNcmFpbzlqQlcrUG5pMy9zRW15emtvdERRVU9aZTVyQUFN?= =?utf-8?B?ZGJtTlNQZzlmWUhmMCt4QnNEVzdvQVFOeTdxK21PVzVJV0hXVm1BcUQ1Qm9D?= =?utf-8?B?TFZrTzRLZHpGSmFCWC9wcHhwelFXMmpNNmNienU1OHdTbW9wdit5TEQwVWVO?= =?utf-8?B?bDhnazF4QWNjTmZ4NDZZU056OTlRUCtWUXhpenhvdnp5T1FrdURUSWJoTEdU?= =?utf-8?B?RDF5QnFqSi8wYmNDbU9WbDZRcUVRM2VzMlhjQUlHMnRqTDM3SDNOWktMaTRV?= =?utf-8?B?S1VvejRXOVZEWW5RbTFkT3I1NndCVUxidlEzQmp6M0hQMm5KYU9yeU54SmRx?= =?utf-8?B?VTVrbXVFeFZOUlI4T3ZTQS9KVmVXNDN3Ymt2M1J5RktyN0VndkNOU056NjBm?= =?utf-8?B?RHZhODVzaE5Na1RGaG9HODhGOGt5Yy8rUlcxMVRuTUl4cy9FRCsxcDJNWC95?= =?utf-8?B?dnJiNnM1WFl6Y3hCQ1JWaGg0aGZNcDlxcEhvQktmUlVna1F0dEs1YTlkMEVn?= =?utf-8?B?NzdNTDhJNS9xWXVRb1g0cTRQT0lGb0RrUUNRVEM2QWlJZGpIOFlMUGg5Q2JI?= =?utf-8?B?WjJjQko0NXpRWnlmTW1kNmtNc1RrUFF1ZWI1WVY2cVZnVzRjT0l2aE1SY0t2?= =?utf-8?B?WDBBajQ4L0ZtYk1JeDN6YmhPMnQ4S1hldGJtSDdLUk1VRnlXMnRmSFhubEpW?= =?utf-8?B?djBZSkNGdXRhSzE2Vk9YbHdiZXF0NHpXQjZwNVkrV1gwdmEzaHp4aFExclBw?= =?utf-8?B?U09keXo5Tk00Z2tZRVNNZVRCNzlCanRxTHFhQ25PWjBuZTJRZzJYb1Q0MG85?= =?utf-8?B?cWllZ0JqZndnUE5XQWF2UjB0SkUzK3JYc2tUMlFrMjZ3MnFWZFZnNGNNcWVJ?= =?utf-8?B?c2Y3SUdtU3lsaWVPeVplM09UVFZzRFpSeTZSaFhZaEd5UXFZeFg1S3IxTU1T?= =?utf-8?B?b0p1MUN6M0ZLbmp1TmgvVDNhcG5tWHJueHlQdlAwamNyWEpqL2dRQT09?= X-OriginatorOrg: garyguo.net X-MS-Exchange-CrossTenant-Network-Message-Id: 036a5c3e-54f4-4da7-363a-08df084927c2 X-MS-Exchange-CrossTenant-AuthSource: LOAP265MB8560.GBRP265.PROD.OUTLOOK.COM X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 01 Sep 2026 16:50:40.3329 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: bbc898ad-b10f-4e10-8552-d9377b823d45 X-MS-Exchange-CrossTenant-MailboxType: HOSTED X-MS-Exchange-CrossTenant-UserPrincipalName: rJGX04a9YxfUpmwQwwih7lDO/UHsYrC21rbgfrTnjSXpMl8l64uZlfYCCn8LFvNNYlzUXAitoyGzvPpfJs9c9Q== X-MS-Exchange-Transport-CrossTenantHeadersStamped: CW1P265MB9199 The `register!` macro is going to require explicit base type, specify it for both `register!` usages in PCI sample driver. Reviewed-by: Alexandre Courbot Signed-off-by: Gary Guo Acked-by: Miguel Ojeda Tested-by: Alexandre Courbot --- samples/rust/rust_driver_pci.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/samples/rust/rust_driver_pci.rs b/samples/rust/rust_driver_pci= .rs index 2282191e6292..13b035a95756 100644 --- a/samples/rust/rust_driver_pci.rs +++ b/samples/rust/rust_driver_pci.rs @@ -23,6 +23,8 @@ mod regs { use super::*; =20 register! { + base: kernel::io::Region; + pub(super) TEST(u8) @ 0x0 { 7:0 index =3D> TestIndex; } @@ -102,6 +104,8 @@ fn config_space(pdev: &pci::Device) { =20 // Some PCI configuration space registers. register! { + base: pci::Normal; + VENDOR_ID(u16) @ 0x0 { 15:0 vendor_id; } --=20 2.54.0 From nobody Sat Sep 26 12:29:11 2026 Received: from CWXP265CU008.outbound.protection.outlook.com (mail-ukwestazon11020105.outbound.protection.outlook.com [52.101.195.105]) (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 E84C8488DAD; Tue, 1 Sep 2026 16:50:49 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=52.101.195.105 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788281452; cv=fail; b=dCN2IGt7bUOMWv/Leqe8ejJLF16ZLn02o5gh9XHZzG9aTjHCRuOoiKrwsmlhZV4M/Ke+bvaCZzew+53MbDvaRaJ8uMAo+05qJAt+2OMKPgReDDx32Xq6LtBQR14+U7oR4bHN3Sipch7ppJI4IcRk6it0QkZhQRJbCXz16PPGwwE= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788281452; c=relaxed/simple; bh=LRCzTRbElfNXpnbN07JbS4qKUWYbLxu7w8UpJPZal0Q=; h=From:Date:Subject:Content-Type:Message-Id:References:In-Reply-To: To:Cc:MIME-Version; b=jhDdc7yP+wtsBPIX/Q5tmII2p17owkeroGWwxxgL07wkM5enXbI1cCyhepsHlvqZY3K5bFx5hPCbC3e1z7XORXFJy/5OgIFqHertvTpkXafrCihO5r9GqgZP0+RtG8taHS5arpNoFu5QgHpUu8LTVYfFahAnknLUQ/Pn4/sdRBQ= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=garyguo.net; spf=pass smtp.mailfrom=garyguo.net; dkim=pass (1024-bit key) header.d=garyguo.net header.i=@garyguo.net header.b=CaoG77Z1; arc=fail smtp.client-ip=52.101.195.105 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=garyguo.net Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=garyguo.net Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=garyguo.net header.i=@garyguo.net header.b="CaoG77Z1" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=tOcu4EsESSMwRqqlrl5VvIDCKhWnhPrMKacCA4ScrgzVWiBLqI7gIhtGX6nghQxxQ+OK2QL/e/T6bNM0o3G8rBeUtJISOP3xUJNmldbLQOidEkRk7YetGrB8Euse7m3ebU4k3JUe//CNvnbuLxCpVDVQ7KcUdfEOUqjCB4II+i133mvUi63Xj4d79rUhgyU+KbYTZNGjgenbSD62W8wM6flyGQcI9zCmxdCnHrD7VwTM2iGnpvdWeKk/CA5kxnTg36QTj6ie8BZ/ZAKfWMJVoKvihry1o/aC6E5x2Xzqpn64JD+1kRERlXAiU4cE8oliw53mfcyT4MOz1X8Ff01nUg== 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=Otepd9WSVL3uV6K+l1r6wDSj3LCIZLja4n6PbCqf+f4=; b=ToLMSgEPU45odr7si0zpW5V+1v8sKxJLj4ESbYwUtp9P+4UzOYj8M224mLkLHKd9SagZahBI+p7W+/5xyvkcDXrDNSHPEZXAOFIKSoFEUNjlzbFBWN/kE//7sRnL0Y70KNP2ak0NdnRhqO/gHe3N5oyuc0yQqbKVlM6S4pMj7qhdwVQCqge9E50ryVBHNlEuUZeWtU40CRCiAEBxGp2Cf+5ljLMzwR5ZtGeVCRzi7aYk30633rkf05X2bNU4Rdc4lgsoddR2PqtJblpfdcR/sKo48TcxrQ962sy5K/BK5OXO31J58HnKdWkScpU09RzzF1HzsG81jOXL1LBGiN22Mw== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=garyguo.net; dmarc=pass action=none header.from=garyguo.net; dkim=pass header.d=garyguo.net; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=garyguo.net; s=selector1; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=Otepd9WSVL3uV6K+l1r6wDSj3LCIZLja4n6PbCqf+f4=; b=CaoG77Z1kJsTRuakOZrjK9yVsjCePgSe/DzzGdPUg68qQxSjo002G8bDIyfn4OpBOh2XIJxE4JxPGZmWGlspgaZiPpxLo8HfS6ZZI4TuGeQ39wsPKogvNZkJFj4Sr5OTDaFM3zVcpGwmCmqghc6j4Y5IgEMS7WwS+w6R66wyUfo= Authentication-Results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=garyguo.net; Received: from LOAP265MB8560.GBRP265.PROD.OUTLOOK.COM (2603:10a6:600:4ab::19) by CW1P265MB9199.GBRP265.PROD.OUTLOOK.COM (2603:10a6:400:272::22) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.21.360.13; Tue, 1 Sep 2026 16:50:41 +0000 Received: from LOAP265MB8560.GBRP265.PROD.OUTLOOK.COM ([fe80::f60b:1537:68d7:4fc1]) by LOAP265MB8560.GBRP265.PROD.OUTLOOK.COM ([fe80::f60b:1537:68d7:4fc1%4]) with mapi id 15.21.0360.008; Tue, 1 Sep 2026 16:50:41 +0000 From: Gary Guo Date: Tue, 01 Sep 2026 17:50:34 +0100 Subject: [PATCH v4 10/16] rust: io: register: make register have a typed base Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260901-typed_register-v4-10-5552b1d59525@garyguo.net> References: <20260901-typed_register-v4-0-5552b1d59525@garyguo.net> In-Reply-To: <20260901-typed_register-v4-0-5552b1d59525@garyguo.net> To: Danilo Krummrich , Alice Ryhl , Daniel Almeida , Miguel Ojeda , Boqun Feng , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Andreas Hindborg , Trevor Gross , Tamir Duberstein , Alexandre Courbot , =?utf-8?q?Onur_=C3=96zkan?= , David Airlie , Simona Vetter , Bjorn Helgaas , =?utf-8?q?Krzysztof_Wilczy=C5=84ski?= Cc: driver-core@lists.linux.dev, rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, nova-gpu@lists.linux.dev, dri-devel@lists.freedesktop.org, linux-pci@vger.kernel.org, Gary Guo X-Mailer: b4 0.15.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1788281431; l=9843; i=gary@garyguo.net; s=20221204; h=from:subject:message-id; bh=LRCzTRbElfNXpnbN07JbS4qKUWYbLxu7w8UpJPZal0Q=; b=xJyvWtgl0OkNJs1eY0dYkJVr690tyL9fuZI5Gug5T+oBAFqHKj8gYSB0l9kEq6oHXr1r69LTN /xhWEdsgz15Aoh7dClWo/TuPMzrEKqZiHUSJVFxKjIK56BneZ0aGzxl X-Developer-Key: i=gary@garyguo.net; a=ed25519; pk=vB3uIX95SM4eVrIqo1DWNWKDKD2xzB+yLLLr0yOPYMo= X-ClientProxiedBy: PAZP264CA0173.FRAP264.PROD.OUTLOOK.COM (2603:10a6:102:236::16) To LOAP265MB8560.GBRP265.PROD.OUTLOOK.COM (2603:10a6:600:4ab::19) 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: LOAP265MB8560:EE_|CW1P265MB9199:EE_ X-MS-Office365-Filtering-Correlation-Id: 2c34f4a6-f2dc-41a9-bcb1-08df0849285d X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|1800799024|7416014|10070799003|376014|23010399003|366016|921020|3023799007|10067099003|56012099006|5023799004|22082099003|18002099003; X-Microsoft-Antispam-Message-Info: 4Vs4oaYBWCmXcOZn012tq7eVQOUvG8VbkGTV/IB0yRBKJ1+LheJS+MEoBqJTjAQiQ0cGRR3ds9n56bgp25O98XjLoIji7z1pqf4txeiPZ1c06SHz34IXDPAmvc45+YtDrxHbk6LhIPOClA15pzXnXGUw3Zy8tMjf6vW3MbtloYRlsp8f3ddBG6t6ezWU+T68ZjtkLQHESt1AIVaRVJXOI7iLbDo88a6jOeRi6Qir5lJ8FMSQPgOfB1/mycT1dcvhJ6zOD5zokGCY/J07mI7g/RjZKUARCdNKnlGMpEr1WILX0koabkaWqgXHbzP6dHaX08Mo1Eqdv8aF8cP5kkZW7Jl59y4GjeBJDeMzRa1ctfrbnZxhxcDwEWrgyfiOohjxvuI9k/H9rNNpBUbu99oWASQwAwsnA24LgnvykD+1qJX+0WdyZVzkD/K3InqUfd0zBWu5qYItVxWVp1pl458ZjtmMndrBoiZpEWv1uEbws7EOX9toLJQnUtK/hZu/VVb2SQisCcp6lQoN5bA+nI95qQW6Oy+1wHZWFylkaFqpWSkNXXW57mO2/vSfFmnJJOExZIWFCALVVUZjQflrCKu7Oq2BMhKo3taK8bi4BheakdEvO/TYBMvGBFtErW1K2WrdpHO0jpD2YE5Kf8ZQwwrH++iYtjzxJ64wvZfzyukd6u2ILenmXckEiI9TZiapueDD49VOLdobs3gdDvxqq+UxcQ== X-Forefront-Antispam-Report: CIP:255.255.255.255;CTRY:;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:LOAP265MB8560.GBRP265.PROD.OUTLOOK.COM;PTR:;CAT:NONE;SFS:(13230040)(1800799024)(7416014)(10070799003)(376014)(23010399003)(366016)(921020)(3023799007)(10067099003)(56012099006)(5023799004)(22082099003)(18002099003);DIR:OUT;SFP:1102; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: =?utf-8?B?Tm0ybHA0WXNkeEFnSHZuNkxtVGdzalROaGxpSlhQQXJ1V0RWTVVaT0xURnBp?= =?utf-8?B?SFpyK3l0amtyaHRoYU9WbzNFYWdZckgyN1l4elJlNU1hZlFMNUJUS200aUdM?= =?utf-8?B?ZFFFUGg2UmZoY3YzNm5UaC9zU3VqUVF1YStmaHV2T2hGa0p6R0FVQUU0LzlZ?= =?utf-8?B?cTFlQlBhazNUUldkeHR0U1dheFhUME83dG94UTltZFpST1ljYjdnZ3UydHRS?= =?utf-8?B?WXNNTDRuTU1YYjd5SlZQaG9KS0xQQnlRU2V4Y2lHQVBzREN6eUQ0bytsdzZQ?= =?utf-8?B?SGdwT1haWVBTK2VJVUxVT0pVQjhCMlVNdmNWRis4c0Z6ZytYbkVWOXM2NmUx?= =?utf-8?B?T252WloxZUgyUGM0UnlpSEFucU8rRENsRVJHaVNwdFlsWDl1a0JqSkFWdFAr?= =?utf-8?B?U1RBOE1MTC95TFFad0JHaVM5NEdFY0ZmUWQwNWM4VVNROGtUajlhWVc4VEZE?= =?utf-8?B?ZUIvek9rYVNXTUdRUkh1aU9nNGNRRHJVY1NjUUpQeEQ3MG9HbUxhSGNZQmZH?= =?utf-8?B?M1hybVJ6YUtPTXJKaFJaZCtUL2xTMnpoQVBRaTR3dzI5WEg0Y3JNM0x3REtv?= =?utf-8?B?S2ZGcVJ5MzAzZW5ucmNPc3VvMTZEcUNpb0FHWFVZVVViZWtTcFl2NXJ3eWlD?= =?utf-8?B?dlVSY2RnZlVhVkRlQmdyZUQ5dUUzRDFIdGdwc0xlZ0NOZ29STWMxbG5WYVRK?= =?utf-8?B?THZHM0JKRTFJd3E5SG0yQXFsRC84ZVMyMXdNUWkybHdocUd6OWV6cndRNkNu?= =?utf-8?B?cVJJRzNTU2hPZUh0VTBRb3ZUcHQ4cDZNLzFYV3NyOTVvNWFhM0FoYmQwSnN1?= =?utf-8?B?L2ZyZDBaTFhLNTczblpXLy9nMG5XM3JyQzJ5R1pNRitzU0pRYXBHSFd5NXQw?= =?utf-8?B?SkZob3QwdVBWdXh4MVdydFdPR0xhV2NENytrcUtiTjdjeUIySUttb0RjNUR0?= =?utf-8?B?ajN2UlRMSkdrYXpsTnc4UEdxS08raVpHVkpyaFA2ZXRtNGUyT0tjdkxqVHov?= =?utf-8?B?N0VvSFA0cEgyZXN5S3JjTHFOYzNKNUtkL2VCTHd6bno5S2psREZYaDlhcE1S?= =?utf-8?B?T01GRFJmbENuN1c2WnpxS0plUE1VOTRDbkRlMkx0NWg0c2pZcEZTQ2tYUnhM?= =?utf-8?B?eUxpbnY2WDdiTms5TUFkUzdVcnI0Y2dCR2JSQ2hFWGtzKzZ6amorQU5aKzJV?= =?utf-8?B?NE1UeStwNzA1V1N3N1VFcHVnRDlFVnVuV2RNZGhmVTEzSjJFWkc4eVFWS1Nx?= =?utf-8?B?clpXOURkSG83bmRJbGpiQmtDRXVXcGN0WmF1QUlKcFl5b0ZQazRVcnRJYTdK?= =?utf-8?B?bERlcWFwQ3A1NXNnUnZhU3RSMHV0NzdIdmhzaEdiVmZOc050K1FMa0FGZ0ZW?= =?utf-8?B?UDlTOGZhaEh6Z3BPSUczUWNpUzNaT0VhVnhYbjBSMDZZU0RxN1lMMW1WOUZJ?= =?utf-8?B?T3QxSTl4eDdNTXQvZmtpVkdscHIrb3hNTXk5UUw0TEtva3lXTnZqZlhQcUVE?= =?utf-8?B?OENrMzJnVkh4LzNFeUcxMU5yNTRYUFRzWFpDT0NNdWx4cFBNZ2kxTHBBeVlE?= =?utf-8?B?ZmpTVGVZRFdrcHJkU01WUk4ySGdCa0VkeDJrWHB4a05HVCs2RGpQeU5PKzBI?= =?utf-8?B?ZTN6cVlWRkZYVjY5cFhBSXYzcTEzaVgwc0ZyMW9INkMybElLL08vQVNOUmJS?= =?utf-8?B?QzExZnFMMFFYQ0VSdXczT2kwbDFWelNFMzZibkJWVGhxcjZ5NzdiZkFKb3BL?= =?utf-8?B?K0FjUGN0SVdaZWdJZy9md0VvbklLS1drd0lmcGhhRUwwbmFFS1owbTNNL25I?= =?utf-8?B?cDhaNTJYQ3hZQkpKYnVWd1YzUUxiZGlUTGZoNU1IbDdUR2xtMS9WNmRpYWI2?= =?utf-8?B?WWZkWng2TTdWMnBKVm9EcXJ6cEFxV1EzWENIRjE0QmRoT0hzcnBab1dGbkFT?= =?utf-8?B?Z0NkVlBmZUNoRzVtSk9iM0xtNC9seWJRakRqR25zYXRmbjN6NFl5c0UxZEJW?= =?utf-8?B?QTFmKzIzS1VOc3JyYmhpa3AxQ0s0SUZkRzYvR3hsSU5TYUdEdXdoY1IrSm41?= =?utf-8?B?ampJMzF3Y05uMzZKc0RwM216OHNPQXM5c0Q0THRMbmtuTmxBWklKUHAydy9t?= =?utf-8?B?S2padENFL1paalF2Y21wWm5LN0gyaXlPcnFzRitHaWpxbzdaMUtDMU5vOXlP?= =?utf-8?B?Y09pSXhqTmZKTGVKWDJsdDAvQk5KcmdQN0NJNFJBd2JJU1hZajFxNlpjVlhX?= =?utf-8?B?cXp4TEt0SVp1RUM3VkNQMHVtNFEvQzVLcW9mcm9DZERwWFdSYmtCMCtjSElE?= =?utf-8?B?RlZab0hyeFBjYzhYbUJzU2lhNFlpNDUzVXhQMFphUHdHZHM3TmpCdz09?= X-OriginatorOrg: garyguo.net X-MS-Exchange-CrossTenant-Network-Message-Id: 2c34f4a6-f2dc-41a9-bcb1-08df0849285d X-MS-Exchange-CrossTenant-AuthSource: LOAP265MB8560.GBRP265.PROD.OUTLOOK.COM X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 01 Sep 2026 16:50:41.3716 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: bbc898ad-b10f-4e10-8552-d9377b823d45 X-MS-Exchange-CrossTenant-MailboxType: HOSTED X-MS-Exchange-CrossTenant-UserPrincipalName: zSxIoHEEoG/seG4APmdoMyw71A2W7fMNy8I97pxHajSGBJgfVSofH9Pnd9hcVhjSK37QtFgewGnOs06Wh8MEeg== X-MS-Exchange-Transport-CrossTenantHeadersStamped: CW1P265MB9199 Previously `register!` defined registers can be used on any untyped I/O regions. With all users specifying their desired register type now, propagate the specified type and restrict I/O access only when type matches. Also, add an `io_project!` example which is enabled by this change. Signed-off-by: Gary Guo Acked-by: Miguel Ojeda Reviewed-by: Alexandre Courbot Tested-by: Alexandre Courbot --- Changes since v3: - Adopted Alex's map_err suggestion - Moved the "const eval only" comment slightly down and updated the build_assert to just a plain assert. --- rust/kernel/io.rs | 13 +++++++++++ rust/kernel/io/register.rs | 54 ++++++++++++++++++++++++++++++++----------= ---- rust/macros/io/register.rs | 45 +++++++++++++++----------------------- 3 files changed, 68 insertions(+), 44 deletions(-) diff --git a/rust/kernel/io.rs b/rust/kernel/io.rs index 05c7fa12fdbe..7a0e0ebc6c85 100644 --- a/rust/kernel/io.rs +++ b/rust/kernel/io.rs @@ -1685,21 +1685,34 @@ pub fn project_loc(self, location: L) -> ::View<' /// The syntax is of form `io_project!(io, proj)` where `io` is an express= ion to a type that /// implements [`Io`] and `proj` is a [projection specification](kernel::p= tr::project!). /// +/// `io_project!` can also project to a subview of registers defined with = [`register!`] macro. +/// Register projection has syntax `io_project!(io, try: REGISTER)` for fa= llible projection and +/// `io_project!(io, build: REGISTER)` for infallible projection. +/// /// # Examples /// /// ``` /// use kernel::io::{ /// io_project, +/// register, /// Mmio, /// }; /// #[repr(C)] /// struct MyStruct { field: u32, } /// +/// register! { +/// base: MyStruct; +/// FIELD(u32) @ 0 { +/// 31:0 val; +/// } +/// } +/// /// # fn test(mmio: Mmio<'_, [MyStruct]>) -> Result { /// // let mmio: Mmio<[MyStruct]>; /// let field: Mmio<'_, u32> =3D io_project!(mmio, [try: 1].field); /// let whole: Mmio<'_, MyStruct> =3D io_project!(mmio, [try: 2]); /// let nested: Mmio<'_, u32> =3D io_project!(whole, .field); +/// let reg: Mmio<'_, FIELD> =3D io_project!(whole, build: FIELD); /// # Ok::<(), Error>(()) } /// ``` #[macro_export] diff --git a/rust/kernel/io/register.rs b/rust/kernel/io/register.rs index 49a5fe069e47..58dcf651dfd0 100644 --- a/rust/kernel/io/register.rs +++ b/rust/kernel/io/register.rs @@ -121,10 +121,11 @@ io::IoLoc, // }; =20 -use super::Region; - /// Trait implemented by all registers. pub trait Register: Sized { + /// Base type for this register. + type Base: ?Sized; + /// Start offset of the register. /// /// The interpretation of this offset depends on the type of the regis= ter. @@ -136,9 +137,9 @@ pub trait FixedRegister: Register {} =20 /// Allows `()` to be used as the `location` parameter of [`Io::write`](su= per::Io::write) when /// passing a [`FixedRegister`] value. -impl IoLoc, T> for () +impl IoLoc for () where - T: FixedRegister, + T: FixedRegister, { #[inline(always)] fn offset(self) -> usize { @@ -148,9 +149,9 @@ fn offset(self) -> usize { =20 /// A [`FixedRegister`] carries its location in its type. Thus `FixedRegis= ter` values can be used /// as an [`IoLoc`]. -impl IoLoc, T> for T +impl IoLoc for T where - T: FixedRegister, + T: FixedRegister, { #[inline(always)] fn offset(self) -> usize { @@ -171,9 +172,9 @@ pub const fn new() -> Self { } } =20 -impl IoLoc, T> for FixedRegisterLoc +impl IoLoc for FixedRegisterLoc where - T: FixedRegister, + T: FixedRegister, { #[inline(always)] fn offset(self) -> usize { @@ -240,9 +241,9 @@ const fn offset(self) -> usize { } } =20 -impl IoLoc, T> for RelativeRegisterL= oc +impl IoLoc for RelativeRegisterLoc<= T, B> where - T: RelativeRegister, + T: RelativeRegister, B: RegisterBase + ?Sized, { #[inline(always)] @@ -282,9 +283,9 @@ pub fn try_new(idx: usize) -> Option { } } =20 -impl IoLoc, T> for RegisterArrayLoc +impl IoLoc for RegisterArrayLoc where - T: RegisterArray, + T: RegisterArray, { #[inline(always)] fn offset(self) -> usize { @@ -367,9 +368,9 @@ pub fn try_at(self, idx: usize) -> Option> { } } =20 -impl IoLoc, T> for RelativeRegisterA= rrayLoc +impl IoLoc for RelativeRegisterArra= yLoc where - T: RelativeRegisterArray, + T: RelativeRegisterArray, B: RegisterBase + ?Sized, { #[inline(always)] @@ -393,9 +394,9 @@ pub trait LocatedRegister { fn into_io_op(self) -> (Self::Location, Self::Value); } =20 -impl LocatedRegister> for T +impl LocatedRegister for T where - T: FixedRegister, + T: FixedRegister, { type Location =3D FixedRegisterLoc; type Value =3D T; @@ -406,6 +407,27 @@ fn into_io_op(self) -> (FixedRegisterLoc, T) { } } =20 +/// Helper function for register alias implementation. +/// +/// This is used to enforce base matching. +#[doc(hidden)] +#[inline(always)] // for const eval only +pub const fn alias_offset>() = -> usize { + Alias::OFFSET +} + +/// Helper function for register element alias implementation. +/// +/// This is used to enforce base matching and provide bounds checking. +#[doc(hidden)] +#[inline(always)] // for const eval only +pub const fn element_alias_offset>( + idx: usize, +) -> usize { + assert!(idx < Alias::SIZE); + Alias::OFFSET + idx * Alias::STRIDE +} + /// Defines a dedicated type for a register, including getter and setter m= ethods for its fields and /// methods to read and write it from an [`Io`](kernel::io::Io) region. /// diff --git a/rust/macros/io/register.rs b/rust/macros/io/register.rs index 851335792a46..f603f4e45565 100644 --- a/rust/macros/io/register.rs +++ b/rust/macros/io/register.rs @@ -19,6 +19,7 @@ spanned::Spanned, token, Attribute, + Error, Expr, Ident, Path, @@ -153,22 +154,23 @@ fn parse(input: syn::parse::ParseStream<'_>) -> Resul= t { } =20 pub(crate) struct RegDef { - #[allow(unused)] - base: Option, + base: Type, regs: Vec, } =20 impl Parse for RegDef { fn parse(input: syn::parse::ParseStream<'_>) -> Result { - let base =3D if input.peek(kw::base) { - let _: kw::base =3D input.parse()?; - let _: Token![:] =3D input.parse()?; - let base =3D input.parse()?; - let _: Token![;] =3D input.parse()?; - Some(base) - } else { - None - }; + let _: kw::base =3D input.parse().map_err(|e| { + Error::new( + e.span(), + "a base type needs to be specified for `register!` invocat= ion with `base: ty;`", + ) + })?; + + let _: Token![:] =3D input.parse()?; + let base =3D input.parse()?; + let _: Token![;] =3D input.parse()?; + let mut regs =3D Vec::new(); while !input.is_empty() { regs.push(input.parse()?); @@ -180,15 +182,7 @@ fn parse(input: syn::parse::ParseStream<'_>) -> Result= { pub(crate) fn register(def: RegDef) -> Result { let mut outputs =3D TokenStream::new(); =20 - if let Some(base) =3D &def.base { - outputs.extend(quote_spanned!(base.span() =3D> - const _: () =3D { - #[allow(unused)] - type Base =3D #base; - }; - )); - } - + let base =3D &def.base; for reg in def.regs { let Reg { attrs, @@ -209,18 +203,12 @@ pub(crate) fn register(def: RegDef) -> Result { RegOffset::Fixed { offset } =3D> quote!(#offset), RegOffset::Alias { alias } =3D> { quote_spanned!(alias.span().resolved_at(span) =3D> - <#alias as ::kernel::io::register::Register>::OFFSET + ::kernel::io::register::alias_offset::<#base, #alias>() ) } RegOffset::ElementAlias { alias, idx } =3D> { - outputs.extend(quote_spanned!(idx.span().resolved_at(span)= =3D> - ::kernel::build_assert::static_assert!( - (#idx) < <#alias as ::kernel::io::register::Regist= erArray>::SIZE - ); - )); quote_spanned!(alias.span().resolved_at(span) =3D> - <#alias as ::kernel::io::register::Register>::OFFSET - + (#idx) * <#alias as ::kernel::io::register::Regi= sterArray>::STRIDE + ::kernel::io::register::element_alias_offset::<#base, = #alias>(#idx) ) } }; @@ -234,6 +222,7 @@ pub(crate) fn register(def: RegDef) -> Result { ); =20 impl ::kernel::io::register::Register for #name { + type Base =3D #base; const OFFSET: usize =3D #offset; } )); --=20 2.54.0 From nobody Sat Sep 26 12:29:12 2026 Received: from CWXP265CU009.outbound.protection.outlook.com (mail-ukwestazon11021101.outbound.protection.outlook.com [52.101.100.101]) (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 EB2CF488224; Tue, 1 Sep 2026 16:50:48 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=52.101.100.101 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788281451; cv=fail; b=jGzITqLz4Sc9EsYoujvVJ5MG9uBIdjPhVBUadNf9K1GQb3dJNtn0jld8Hwrye8ybcnf4Qb3mLRPVnV49qVizK6ey6RiXW3qDFMDIPcAbRMh6LZr8Ju7r9oPlFFihfXrfoFQwCXwJCUwpMimzorizyS7NrdgpoFsMU7DK5tNjPL4= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788281451; c=relaxed/simple; bh=zEIOeiPp4a1yDOdPM6mIKhxZQ8hMqxFVFnTtfY+7bqI=; h=From:Date:Subject:Content-Type:Message-Id:References:In-Reply-To: To:Cc:MIME-Version; b=nxziap3aB0OpgxrN5G3rsakvJ+Kw+3dmmVnR9iiFi/uYeyuFqY+nuSzoutQ48uOSbskvbllg2eKPSEhgLa68vaXAA+1jF1HRwGE1wY6DRcpZSv04gxvogncPk2s4Ebvw1jtJPqBm5+jLybsKVifWMoKvLMgyl5leRJ1MeDr6fZY= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=garyguo.net; spf=pass smtp.mailfrom=garyguo.net; dkim=pass (1024-bit key) header.d=garyguo.net header.i=@garyguo.net header.b=ZalMD0Dq; arc=fail smtp.client-ip=52.101.100.101 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=garyguo.net Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=garyguo.net Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=garyguo.net header.i=@garyguo.net header.b="ZalMD0Dq" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=Jg+ax6NPjXwNxLu4bmgqPTYJGxBQXG3t4wx23+WDeuM6qdCeJcBbvKekZiDMjjR91CpmQUiOk51ECL75PmUK4KVOII8C++qaszc4xojAJEai8IqQOTARPOClX/qbpSx8mpTBZFjnOv1uCBx/7Gdofpep5ezxkaSjvFeRWFSBFOGUJPS9DTGsCJRgtgXMb1BgQMg3upotZlVMr6SnrNnyN/801ovB59+pcMuHWeVhQE/nK4CCU9K8VStr1gEI7uFuaTw+nOfQikMXx0kUpyV49P0YMqMOQtkrRkNY+eL6k9IopBq06TX3H97jtgXWPG8VczFYinbMKtvmbFlRvL18Cw== 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=rCqwbtdaqZ+QP3nT+UsxF/pKPsWOYcZlWfV5Q0XGCkc=; b=RtNs3M+oQVXXCtZ41mamdaNYWoA67XrzwAx2PSeGZ1yoblhX5jBHG76VOKW5Pzxv1NGc/2ztGnz6lqE0JrUA3T+dFi33SkYJ3v7eh0R2nCOIhRq/g/DtblmNoj6CqOAANFCiUJUN5VVyohFDw1rdcYVPwhWfg0oR6qLwjpqA717tA5B3nkcwQuPLlBLz7juvsluwA4cR7n+q9cWeb7g7XeHmf+DsPyOR7KhDFNkYA+FhMXvjFxilDTTbT7jSkWRXU5QAOrV6Ar0aGvFaNYzLQ2rxgDOAH+0UPwXxED2MAnMKrd3lXnGd4FLAUK2i3CzD8Y+dS4oEjatcnozYtHnoBg== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=garyguo.net; dmarc=pass action=none header.from=garyguo.net; dkim=pass header.d=garyguo.net; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=garyguo.net; s=selector1; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=rCqwbtdaqZ+QP3nT+UsxF/pKPsWOYcZlWfV5Q0XGCkc=; b=ZalMD0Dq+eAEsLvAlIIkQjFDu1Luznw/yQQgiuKpvYfHsMijVZSyajIaCHbFXaGLQBhhDBf9I46l+9+2Kr4777S2Z1TmGxMfRuarv18urp61RYlxLKWbmCBxDw/W/oatebHSXsnPVPc/29lhm1Vu80mGhD2MqIasUDz0bCqj4AQ= Authentication-Results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=garyguo.net; Received: from LOAP265MB8560.GBRP265.PROD.OUTLOOK.COM (2603:10a6:600:4ab::19) by CW1P265MB9199.GBRP265.PROD.OUTLOOK.COM (2603:10a6:400:272::22) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.21.360.13; Tue, 1 Sep 2026 16:50:42 +0000 Received: from LOAP265MB8560.GBRP265.PROD.OUTLOOK.COM ([fe80::f60b:1537:68d7:4fc1]) by LOAP265MB8560.GBRP265.PROD.OUTLOOK.COM ([fe80::f60b:1537:68d7:4fc1%4]) with mapi id 15.21.0360.008; Tue, 1 Sep 2026 16:50:42 +0000 From: Gary Guo Date: Tue, 01 Sep 2026 17:50:35 +0100 Subject: [PATCH v4 11/16] rust: io: register: support fixed offset register without bitfield Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260901-typed_register-v4-11-5552b1d59525@garyguo.net> References: <20260901-typed_register-v4-0-5552b1d59525@garyguo.net> In-Reply-To: <20260901-typed_register-v4-0-5552b1d59525@garyguo.net> To: Danilo Krummrich , Alice Ryhl , Daniel Almeida , Miguel Ojeda , Boqun Feng , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Andreas Hindborg , Trevor Gross , Tamir Duberstein , Alexandre Courbot , =?utf-8?q?Onur_=C3=96zkan?= , David Airlie , Simona Vetter , Bjorn Helgaas , =?utf-8?q?Krzysztof_Wilczy=C5=84ski?= Cc: driver-core@lists.linux.dev, rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, nova-gpu@lists.linux.dev, dri-devel@lists.freedesktop.org, linux-pci@vger.kernel.org, Gary Guo X-Mailer: b4 0.15.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1788281431; l=8003; i=gary@garyguo.net; s=20221204; h=from:subject:message-id; bh=zEIOeiPp4a1yDOdPM6mIKhxZQ8hMqxFVFnTtfY+7bqI=; b=SFk/cHLNnbV2FfHDTmt3JssIWyqe/UeG42qFroyd6eKi5q6hp5TxIGAabf8eZbXi8LRcPPQrq ibjYkIH9Jz6BxJp3x1A7vA5zdy5KtfbLFrbNHKWRGmxdpUJd7q/bLVK X-Developer-Key: i=gary@garyguo.net; a=ed25519; pk=vB3uIX95SM4eVrIqo1DWNWKDKD2xzB+yLLLr0yOPYMo= X-ClientProxiedBy: PAZP264CA0173.FRAP264.PROD.OUTLOOK.COM (2603:10a6:102:236::16) To LOAP265MB8560.GBRP265.PROD.OUTLOOK.COM (2603:10a6:600:4ab::19) 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: LOAP265MB8560:EE_|CW1P265MB9199:EE_ X-MS-Office365-Filtering-Correlation-Id: 33f4f20f-9fbe-4673-4f79-08df084928da X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|1800799024|7416014|10070799003|376014|23010399003|366016|921020|3023799007|10067099003|56012099006|5023799004|22082099003|18002099003; X-Microsoft-Antispam-Message-Info: xthVSC91G8LM21dfbm30fQuH9SeylS5RHqvXkAe4/9OvlgDCoZPWfb87euIY6xUuA4gWhwU+/fdVmtH6L6wksmwjolOh2v0Ef6OG+GP0jrsIDojG9hEfDzg4MoZiR+xfbtZYEkVjUaQtWO697BQKRWC8LE8iSNEqy42flkzRCAhm4jXEoA9yLcVjAO2Hb3U81rHOj6ywWS0qCmhOgA9kJEKwF1Xck8s/BQ8/vkkQnrPWjKyKjxypMdRSq6HDQq3hr1hYEFkGFdkBKZQqwhdNi/3BeoZTNNqtwFmwT51z0lQjCsWApXeHyEuk38ko0unoocENdd2XR4BHM1+KXCt+dyuOSigT3pw++9j7yMywkW9XXP0JqjlQeVF+cLWEcZHKOtPYpOoN2wWO695cDaIu373ZtUu2MpPGqhZ/HodIgqU3BiqHqBL9/w6c3p+48l9nvELrOpBaotRagoDIwpexQ42a/zdfwh+JLjqBSRQ6gwoMGpz+Zlxe7u2GpxYSm3t0k4ZY67Ic+g4zMJ3kENXoOsbH6kj1blG8EYxiOVLRt7cqjK6QMO1GY9hQJ7+cWzqApo77Dma8mbHarGUStLCDFPoROBBKXBJGgQ3nwC0vVoVZyTgfXT4/X0XlC8F6sFe6T2vb05xAsFVziZJm4q/IvOdMk0G/C/2g/pir/SgjnOK895ch6G2t+Lo2H5iYvFGGMw07wHLmlsOPYAZD9P5W1w== X-Forefront-Antispam-Report: CIP:255.255.255.255;CTRY:;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:LOAP265MB8560.GBRP265.PROD.OUTLOOK.COM;PTR:;CAT:NONE;SFS:(13230040)(1800799024)(7416014)(10070799003)(376014)(23010399003)(366016)(921020)(3023799007)(10067099003)(56012099006)(5023799004)(22082099003)(18002099003);DIR:OUT;SFP:1102; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: =?utf-8?B?SmJ1NmgxZTRzc1pmazE3WC9GOW8wcFlFNjRxN3VsMi9ZZXlFdlU4SlM3SVlZ?= =?utf-8?B?VVV3dFB5S1FTQ3U2ajlHZTgrWU04SkRLZktQbmlnSFZ0Y2ZFM0E5LzB3UzBt?= =?utf-8?B?T1NLUWEwN3E3Zk4vZjNDdStObnhsVFR3eEtYcHJCSHlkSCthMXUyQUtud0dl?= =?utf-8?B?cFZrc3N5QmNtUDVMbmlwVFZFNkQxMTFDYkZpUFY5c2d0WFJtdGcyK1BTS3ov?= =?utf-8?B?NytHMVJvRkh4UmNNTnNoUUUzMDNoeWhSVnBrRDJMV3o1MmNqZ001R1Z0c1I1?= =?utf-8?B?bGtILzZuRFZ2RFhUa2Y2M1NPb3dQbFljT21USnZmMmtVYVptVUlleGdZYTB0?= =?utf-8?B?UUpmenNKMXV3T2hOdUFDYUpJek5pQTgzNjJhQWZ5WGYvaTRDTkFLdmNLRjh1?= =?utf-8?B?YmFCRU44a2FuVWE0YVc5Y3ZpM3BrSjZGZkYrSlB3dHcwL0NVMy9IRFljNzRN?= =?utf-8?B?S3JrNE9EenUwc0lHakNPZDQ4Y05tajhzQndlQTFuTDBJZ2VGenZWcGZHemJa?= =?utf-8?B?T09TaHR4RHlPUzZ3Mld6NlJaZG5FcmZDcmtRRjA0YWJFRVBHWVRnd29keUUv?= =?utf-8?B?SlVVSENGQndqdWlodUgwTGp5MStGNXNCemVFSng1SXdnTGxlaENnZG9STW9L?= =?utf-8?B?Znc2UUVwbC95Um9TRnhEZ2NBaEJISFl0RG9WVXZGelFYbW5rLzVidzUxWEVF?= =?utf-8?B?THNyWjY0RENIR2wvWDNBU1RURnlUSlNPMlQ0UmVRNXRzRG5uZy92NnNpQVdq?= =?utf-8?B?NUtvS1YyVDRYWGZBS1d1ZExNdURsWnVEMkhXQ1ZXK1dodlJGeDNuMmFnSjQw?= =?utf-8?B?M1pteDlXYkxlelZ6UzJidGpQSFZXME1oMWN6LzlmUWJLVU5BcnloeVpXejhj?= =?utf-8?B?NGV4SVU4bXhyMDBiMUx4QXBmUjVjWTNaRTAzeDdnY2h0TGMrQmw4aUJ6RDV5?= =?utf-8?B?eXFodm5TWkxwc1VmVEIxc2lnSGo0YkZJazM3UVU0T3ZneXYwVHBkemlONDJk?= =?utf-8?B?VGxyU0RMZVgzQll4TTA2RUF4RXRpUk54VlRQdlJaL3Y1eHJYejRFS09YamN5?= =?utf-8?B?dTlRYzdheVpSKzJoSUpxd0VjMDJnOUtqbzR0aVNYc1hKWDlwQUZTTS9qdzk1?= =?utf-8?B?WThpNmE0R2xwakVwWXM3UU5FdTMycllHQ2UzZHJmMnByMzRjV0FpZUZvb09v?= =?utf-8?B?Q2M4eXhEOVhGNU5yMlgwZStJVkVkV2VsbHBCTnpoVzdYV2JwZ2JGY05oa0li?= =?utf-8?B?L2wvVHNIdlZCSkcvbFc5RVk5cE5zR1ZlOWkvK2pDd1kwcjBvYXFKZ2dJTHFw?= =?utf-8?B?eEhKNWFTUWV6alVyT3NUTXByVlFYd0dXSnhhbEJBdHB5RThLT0F1N1kyaUFT?= =?utf-8?B?QzVjQ1R4L2lPQWE5VUgzUUgzcWhTazlFRnIrMVNkdjdzQkEwQjQ5MThxYitq?= =?utf-8?B?WTA3ODJIWmJYUkNuV2JrQWR5R3RSU0RiWUNJU01kdGVqS1RmYmdmeVJrbXd4?= =?utf-8?B?c3p3Mkt2VmNhYUVGM2gzWVRXTlAxdStVRi9XdzVYZVVHcUdWakJvMWZUTU9F?= =?utf-8?B?UnM3L015dFgyVnNMa1pCb29SVkMwcWhRUWRESE5QY08yNzEzelRzVG14YnJQ?= =?utf-8?B?M1dIb3FKVU1SVTgzTmQ4S2FHd0ZSQU1Vb1Y0ZHVvUWY3VXF5OXUyWkh2cnk0?= =?utf-8?B?VURpQzRHRlZvSDlkOGNuMkpJaUJBVzkrU014NHdGNWFSdHVCWER6SGxYaFJo?= =?utf-8?B?ODkxTThIMWtwclZ3Z2RlMDViL24yaDAxbkVpZ1h5ZVIwbTN3dHVhOWdhSDBG?= =?utf-8?B?RVYxZldyUlJ6VWEza1Vybm1IMEovdG15S0d4aUlnNklPeTF5WjRrSDlXVE9z?= =?utf-8?B?d3pRandiMjJUVDFsSGJFWmRaZU9QMHhlczQ3SUdyR3htNEQ3Ylp1dUNja0R3?= =?utf-8?B?WWlzbEFDMExrSTNFUWc3dHJmRXkyWVFmcXl5SzNwZ2IvSU50L1VCQnF0Wnls?= =?utf-8?B?MFd6SWpnU1VhKys4NUYraDBuUXo5MUlRMmhiMTB3VnB5OHA3UXNGelJiTURX?= =?utf-8?B?VlNucVFQNHRSdXY2bWhSeW9vcHZlRGFoUWE3RTFtZ1BqYjFYbytNMVdVT0Uy?= =?utf-8?B?U1VTU0RsN2YzbHd0RWlsOWszQmhCSkdVYVVnbEs4Ui81VGNTbkI4aWd2andL?= =?utf-8?B?bEIrT1NaUnZiV1oySDRDaHlUMVJ3dVdjdThZTjdac0lYTlZWUDlHMnhPNFNj?= =?utf-8?B?R1duUS9JajBFYld4R3NQNzd2ZmQ5U0RUMWdROE9lcDI4T1dUSThYQ21YOStF?= =?utf-8?B?SWVFR2hmN1I0cGI0ZVBnanJ5WENyQnE4MkxhbVRPbHVxSVFnVWp4dz09?= X-OriginatorOrg: garyguo.net X-MS-Exchange-CrossTenant-Network-Message-Id: 33f4f20f-9fbe-4673-4f79-08df084928da X-MS-Exchange-CrossTenant-AuthSource: LOAP265MB8560.GBRP265.PROD.OUTLOOK.COM X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 01 Sep 2026 16:50:42.1747 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: bbc898ad-b10f-4e10-8552-d9377b823d45 X-MS-Exchange-CrossTenant-MailboxType: HOSTED X-MS-Exchange-CrossTenant-UserPrincipalName: mziR4W098qt9DAa70DRtPMO+1cWyFonp1m8yRu0h/c5pxnKoh/eHKVOx+MIr/qijwqeRSi0kaMJI5M5hnocclA== X-MS-Exchange-Transport-CrossTenantHeadersStamped: CW1P265MB9199 Add a rule to allow creating `IoLoc` in `register!()` using an existing type and not create a bitfield. Add an example to demonstrate this for FIFO registers. This rule is also going to be used to create subregions for registers; the example of doing so will be added later when relative registers are removed. Reviewed-by: Alexandre Courbot Signed-off-by: Gary Guo Acked-by: Miguel Ojeda Tested-by: Alexandre Courbot --- rust/kernel/io/register.rs | 31 +++++++++++++++++ rust/macros/io/register.rs | 84 +++++++++++++++++++++++++++++++-----------= ---- 2 files changed, 88 insertions(+), 27 deletions(-) diff --git a/rust/kernel/io/register.rs b/rust/kernel/io/register.rs index 58dcf651dfd0..b9cb4fce8628 100644 --- a/rust/kernel/io/register.rs +++ b/rust/kernel/io/register.rs @@ -182,6 +182,24 @@ fn offset(self) -> usize { } } =20 +// Provides a `IoLoc` impl that for a fixed offset. +#[doc(hidden)] +pub struct OffsetLoc(usize, PhantomData<(T, Base)>); + +impl OffsetLoc { + #[inline] + pub const fn new(offset: usize) -> Self { + Self(offset, PhantomData) + } +} + +impl IoLoc for OffsetLoc { + #[inline(always)] + fn offset(self) -> usize { + self.0 + } +} + /// Trait providing a base address to be added to the offset of a relative= register to obtain /// its actual offset. /// @@ -520,6 +538,19 @@ pub const fn element_alias_offset; +/// +/// /// UART RX register. +/// pub UART_RX: u8 @ 0x100; +/// } +/// ``` +/// /// ## Relative registers /// /// Relative registers can be instantiated several times at a relative off= set of a group of bases. diff --git a/rust/macros/io/register.rs b/rust/macros/io/register.rs index f603f4e45565..b3262e9c06a1 100644 --- a/rust/macros/io/register.rs +++ b/rust/macros/io/register.rs @@ -16,6 +16,7 @@ bracketed, parenthesized, parse::Parse, + parse_quote, spanned::Spanned, token, Attribute, @@ -62,11 +63,11 @@ struct Reg { attrs: Vec, vis: Visibility, name: Ident, - storage: Type, + ty: Type, array: Option, relative_base: Option, offset: RegOffset, - bitfield_args: Group, + bitfield: Option<(Type, Group)>, } =20 impl Parse for Reg { @@ -74,11 +75,22 @@ fn parse(input: syn::parse::ParseStream<'_>) -> Result<= Self> { let attrs =3D input.call(Attribute::parse_outer)?; let vis =3D input.parse()?; let name =3D input.parse()?; - let storage =3D { + + let lh =3D input.lookahead1(); + let (ty, bitfield_storage) =3D if lh.peek(Token![:]) { + let _: Token![:] =3D input.parse()?; + (input.parse()?, None) + } else if lh.peek(token::Paren) { let content; parenthesized!(content in input); - content.parse()? + let bitfield_storage =3D Some(content.parse()?); + + // For bitfields, bitfield macro will generate a type with the= same name as `name`. + (parse_quote!(#name), bitfield_storage) + } else { + Err(lh.error())? }; + let array =3D if input.peek(token::Bracket) { let content; bracketed!(content in input); @@ -133,22 +145,28 @@ fn parse(input: syn::parse::ParseStream<'_>) -> Resul= t { Err(lh.error())? }; =20 - let lh =3D input.lookahead1(); - let bitfield_args =3D if lh.peek(token::Brace) { - input.parse()? + let bitfield =3D if let Some(storage) =3D bitfield_storage { + let lh =3D input.lookahead1(); + let args =3D if lh.peek(token::Brace) { + input.parse()? + } else { + Err(lh.error())? + }; + Some((storage, args)) } else { - Err(lh.error())? + let _: Token![;] =3D input.parse()?; + None }; =20 Ok(Self { attrs, vis, name, - storage, + ty, array, relative_base, offset, - bitfield_args, + bitfield, }) } } @@ -188,11 +206,11 @@ pub(crate) fn register(def: RegDef) -> Result { attrs, vis, name, - storage, + ty, array, relative_base, offset, - bitfield_args, + bitfield, } =3D reg; =20 // Use register name's span for generated code, so error messages = (if any) can point to it @@ -213,21 +231,33 @@ pub(crate) fn register(def: RegDef) -> Result { } }; =20 - outputs.extend(quote_spanned!(span =3D> - ::kernel::bitfield!( - // `#[allow(non_camel_case_types)]` is added since registe= r names typically use - // `SCREAMING_CASE`. - #[allow(non_camel_case_types)] - #(#attrs)* #vis struct #name(#storage) #bitfield_args - ); - - impl ::kernel::io::register::Register for #name { - type Base =3D #base; - const OFFSET: usize =3D #offset; - } - )); + if let Some((storage, args)) =3D &bitfield { + outputs.extend(quote_spanned!(span =3D> + ::kernel::bitfield!( + // `#[allow(non_camel_case_types)]` is added since reg= ister names typically use + // `SCREAMING_CASE`. + #[allow(non_camel_case_types)] + #(#attrs)* #vis struct #name(#storage) #args + ); + + impl ::kernel::io::register::Register for #name { + type Base =3D #base; + const OFFSET: usize =3D #offset; + } + )); + } =20 match array { + None if bitfield.is_none() && relative_base.is_none() =3D> out= puts.extend(quote!( + #(#attrs)* #vis const #name: ::kernel::io::register::Offse= tLoc<#base, #ty> =3D + ::kernel::io::register::OffsetLoc::new(#offset); + )), + + _ if bitfield.is_none() =3D> Err(Error::new_spanned( + ty, + "defining without bitfield is not yet supported for this t= ype of register", + ))?, + None =3D> match relative_base { None =3D> outputs.extend(quote_spanned!(span =3D> impl ::kernel::io::register::FixedRegister for #name {} @@ -249,12 +279,12 @@ impl ::kernel::io::register::RelativeRegister for #na= me {} let stride =3D if let Some(stride) =3D &def.stride { outputs.extend(quote_spanned!(stride.span().resolved_a= t(span) =3D> ::kernel::build_assert::static_assert!( - ::core::mem::size_of::<#storage>() <=3D #stride + ::core::mem::size_of::<#ty>() <=3D #stride ); )); quote!(#stride) } else { - quote_spanned!(span =3D> ::core::mem::size_of::<#stora= ge>()) + quote_spanned!(span =3D> ::core::mem::size_of::<#ty>()) }; =20 outputs.extend(quote_spanned!(span =3D> --=20 2.54.0 From nobody Sat Sep 26 12:29:12 2026 Received: from CWXP265CU009.outbound.protection.outlook.com (mail-ukwestazon11021101.outbound.protection.outlook.com [52.101.100.101]) (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 E301D48A8A4; Tue, 1 Sep 2026 16:50:51 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=52.101.100.101 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788281455; cv=fail; b=hvtzjH9uYGnSZizEuFqnf+ctl8HDRsuaWGiejiR4H62uj+4qjYWv6Fk5o4fgBvkbCvYKM69PDHg6KIN1ESif8SelDHFvmt2C0ZjXiu+bL5j23BPr0TD6H3kpw/U5hub5nlrnMOBfMrqGA19Ey6lg8j5VtzkA60BbkVAJlKytz1E= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788281455; c=relaxed/simple; bh=16xLc/mUOzaQreTnJHGn33Nj9qxTDTA1r7zM5uFYy/o=; h=From:Date:Subject:Content-Type:Message-Id:References:In-Reply-To: To:Cc:MIME-Version; b=CKK6pGh9AuY/HHHtkHUHFA/OZGNZBXNYQhjSmHQwoXv9gDYZXAF4+6CmFpwqqYqj0zJSQKtt3mFNegKcyvMMo3YPaPO9s2CNKL75soz5LJR4naP/WyHhcD37HMMKVrFO2609TN/atmGrpGnfK6Q0plYKT3ppjDStfvi77YIBxWg= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=garyguo.net; spf=pass smtp.mailfrom=garyguo.net; dkim=pass (1024-bit key) header.d=garyguo.net header.i=@garyguo.net header.b=L9Rbley9; arc=fail smtp.client-ip=52.101.100.101 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=garyguo.net Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=garyguo.net Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=garyguo.net header.i=@garyguo.net header.b="L9Rbley9" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=P9qVBGlg8+QZDluzhx+mueNhP7RJG6c3yZ9U/ZnmqPeBMLmL2J6nladcxkDqS9CqEg1UAKkv0a3n0xADSu3Kz3ac4k512RbuCgZoLUIo6g8izd/Ga4xDh0SQM+D8M/kXelyRTEb7loOdmDAqYKlIlaS2ATo0agy0i1FxG8Rf8lkCBDIGVm5yptYv9A80s3A3Pl85BAlzrf89xoVsH0xfAWVXFB0KOoYsfWiGXe/76lv4hetYzQ9Ypuk3VqGiygJ8zaW49xfXiqw+l5B0SGzy5CYlho/aFEAMrbycb0wZ7fz5NB/4h40VqAWYLDS8rB+W+PXBGx+HMEWC4PdhwEltew== 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=ZTUtJEFv5VcrEXgxXLcxho/So8UFIvCOQMAgnhyhiso=; b=FEI0tgtuiSRA2/tn7p/2vAEddcsy7fM3w58gkXW46dDqD29+LO/cL70jlakXKgrfXXBIeE2U4Gv0FqU3yj3ip2JohEe7v8YntwzJwbLLKFw7L4WbX/Wts68Rzmj2c8ZczDKvWkDY5/hVZyIqBHJTq1X18QLYvqvjB0ofnnbUMDipaNsWrX5UNFPK4igTA8IdkQW7QNAAqUMNziubynfdib49IhBKyBVC1mk9QB/PWLe0elUW/ZrL6BcrD+BAvsVbVgSDfeb6jPBW2HYVqGElJEENhQeO7d4WYBqkjuLq1IP+Q93UNm0m/pv2OwqSnub6WUIXzEAmGzoC9r/QUsg7oQ== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=garyguo.net; dmarc=pass action=none header.from=garyguo.net; dkim=pass header.d=garyguo.net; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=garyguo.net; s=selector1; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=ZTUtJEFv5VcrEXgxXLcxho/So8UFIvCOQMAgnhyhiso=; b=L9Rbley9eR9e3su5FeoNr2Q5+lae5IeDiDEvyT8fR8XF16wH/dSuVKDB/aueLbwiJhG8bgSe3my9x+S375uWABUbOST6+eujrc1EDUQ7gxW/LEwKw3NxLqDOFDWQZLGBcCvv5+YmhVSjYMRIIxPWVTKgMLjcd9DMSSioeEtMjqI= Authentication-Results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=garyguo.net; Received: from LOAP265MB8560.GBRP265.PROD.OUTLOOK.COM (2603:10a6:600:4ab::19) by CW1P265MB9199.GBRP265.PROD.OUTLOOK.COM (2603:10a6:400:272::22) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.21.360.13; Tue, 1 Sep 2026 16:50:43 +0000 Received: from LOAP265MB8560.GBRP265.PROD.OUTLOOK.COM ([fe80::f60b:1537:68d7:4fc1]) by LOAP265MB8560.GBRP265.PROD.OUTLOOK.COM ([fe80::f60b:1537:68d7:4fc1%4]) with mapi id 15.21.0360.008; Tue, 1 Sep 2026 16:50:43 +0000 From: Gary Guo Date: Tue, 01 Sep 2026 17:50:36 +0100 Subject: [PATCH v4 12/16] gpu: nova-core: use projection for PFALCON and PFALCON2 registers Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260901-typed_register-v4-12-5552b1d59525@garyguo.net> References: <20260901-typed_register-v4-0-5552b1d59525@garyguo.net> In-Reply-To: <20260901-typed_register-v4-0-5552b1d59525@garyguo.net> To: Danilo Krummrich , Alice Ryhl , Daniel Almeida , Miguel Ojeda , Boqun Feng , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Andreas Hindborg , Trevor Gross , Tamir Duberstein , Alexandre Courbot , =?utf-8?q?Onur_=C3=96zkan?= , David Airlie , Simona Vetter , Bjorn Helgaas , =?utf-8?q?Krzysztof_Wilczy=C5=84ski?= Cc: driver-core@lists.linux.dev, rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, nova-gpu@lists.linux.dev, dri-devel@lists.freedesktop.org, linux-pci@vger.kernel.org, Gary Guo X-Mailer: b4 0.15.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1788281431; l=44858; i=gary@garyguo.net; s=20221204; h=from:subject:message-id; bh=16xLc/mUOzaQreTnJHGn33Nj9qxTDTA1r7zM5uFYy/o=; b=0ayO6V4OirGtfBsNM26WIhduvQGZjEtX2Ct6/EBN+LQkDzOK+F8bvst+Go5sz290efqgDjvzI +JvmLSkhgqTCny5nSFDAaywwVCglS2LpkIN/QXImXs98UBxzxIzKQjd X-Developer-Key: i=gary@garyguo.net; a=ed25519; pk=vB3uIX95SM4eVrIqo1DWNWKDKD2xzB+yLLLr0yOPYMo= X-ClientProxiedBy: PAZP264CA0173.FRAP264.PROD.OUTLOOK.COM (2603:10a6:102:236::16) To LOAP265MB8560.GBRP265.PROD.OUTLOOK.COM (2603:10a6:600:4ab::19) 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: LOAP265MB8560:EE_|CW1P265MB9199:EE_ X-MS-Office365-Filtering-Correlation-Id: cb3cf142-b3ab-49f6-eada-08df08492959 X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|1800799024|7416014|10070799003|376014|23010399003|366016|921020|6133799003|3023799007|10067099003|56012099006|22082099003|18002099003; X-Microsoft-Antispam-Message-Info: uzP0erWwwM7Qo2u3S1RAYy2PzA5tLc44wwAq4jZYZvH5rxy2NPqAoPLBiVh62t04FiXZzJNc3IwiT1P00UmuG0rIIvwNqN/b82uJlUi5Z//Lynn3FK8+igIrRQP8NhCMK8YEO9h2o2csWxCF7nk4kdr/UrsaYGIKrfcWjw5ZUR71NvPj1NejyA0GHAhXC91aZASdkyr2L/GhU5WZ0YoDlMT8EfyFtOOb0eOzyHI1Z+AZRLNmjB9Z4XKtUMTQB1OJ9wKrCvWsZ/OcVQKK09D1y1axdmVFwnLZGs7TPlqxpec1EyfTKKGm0T2NDPyagrR8EXs1qyRI0o48n2u122f/M5u4zmDVaolOVCgYbbvfhfI8UVl9fAk+mjtiUKAdfiuNEDsmH3vFte0MUE0TmoIC72ApAZD5DoiX79J5AMYQdwhigjIBW84A8sgafAg77S7DEGrkdy8hoGOxsvc1v31ECBQ8HZUip/Y1XVEGg/6cybSNy8fEfj++eNZ0hgS//J4oZfwd5aw8jItxloN/zx1E44FxXCA6xmf5y5NmyrmR+LoiuPzZ4bnZR5WkLUdDNBVj3AZYQiKAatA8h9LLtYhn4JEPqcUkefbiyW37Ea2O4bLfK3zQlI3KtueR++XWaU8BsrZSmxTGOEkq5sD+T7AskE53182+Yl8wtPnjLUIMh8fv/LRrSK1236EP7TkJ2TbTj3JAe1Jw4ah4Cp3jJScBHA== X-Forefront-Antispam-Report: CIP:255.255.255.255;CTRY:;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:LOAP265MB8560.GBRP265.PROD.OUTLOOK.COM;PTR:;CAT:NONE;SFS:(13230040)(1800799024)(7416014)(10070799003)(376014)(23010399003)(366016)(921020)(6133799003)(3023799007)(10067099003)(56012099006)(22082099003)(18002099003);DIR:OUT;SFP:1102; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: =?utf-8?B?UW16aVB1bFJXakhDamdaem5mK2NTZVFSTCtLZmVOWkhtOHhGYTlNcFVmaWNU?= =?utf-8?B?VStjb3lUNksySFUzeVVTS0tZSVA5YTJLbVBBcHdTOVdKcnBUclZYQWpXeGs3?= =?utf-8?B?Z0hWOEdvNnRweFdFTnVqak14bU9BdGRiTEE5VGxKb282aXBGcGM0T2hOWmd0?= =?utf-8?B?NWpVOXQ1OUhQcWRPOFZXRU9oeE5vTk8vL2ZlYXpNNWc5MzlpMTFDVSswQmV6?= =?utf-8?B?eGNodWQzNjFCa0I5ZnZHZUQra3pRd3pXWjN3QXE4TWN5S3JhRlNDdkJmSHR4?= =?utf-8?B?UHk3VklZNUNzV0tQN0M4aDlDTHJIVkJkL29LbHhHdkdWSU9vK2gwZ3RVVUJl?= =?utf-8?B?WjZ4MjFHVTgyeUNWVzJVbDZ5anVPSVZHcWJyUHZTZmpIKzYxcnRDUXJlVllh?= =?utf-8?B?eWtERk1tYkdPQjJ4ZThGWWdPOHJacFNGQ0tPcFZ2c0Z5S2Jib0txRlJXQW1v?= =?utf-8?B?TXV0YVl4eCtoWGNSRG9oMittVG5mb0tlanZMaHc2bmUxYTJjTnJPbjhsRlJ3?= =?utf-8?B?TkVhR0xMSnRHcmZUd1c3M3ZsdWhOdFNOVGg5L2hDRmgxdmVCQ3o3Z2FwWUo0?= =?utf-8?B?WDFibDhsRnRBSk1wQm5SSkdMZ0loemtSdi8zV1Y4SnpOZStlZXBQNjQ1VFI0?= =?utf-8?B?UThhb0NHVFNFU01rU20wdVFxYkR6bnB2d2NMSVJkbXFJdWF5aDI5Z3NidG9n?= =?utf-8?B?NDhhNE4yUVJEVDM1SERWSmFTeDRTVERSa1YvNTgwTTdIZ1k1eFpLOFlXV2M3?= =?utf-8?B?bDFoWTlGdGhQdVpack83M08xdVpDcU5xK0JBTUpTem1MSXRza0V0RUtEdUxD?= =?utf-8?B?SWJvZE1uVSs3L3I1ZlNEMTV3eWliQ0Erc0pjbXk4cXRzMWQrdU9PVy9vdmJY?= =?utf-8?B?TWpKb3MveW5kLzhMTVVuWHJjUE4zUTRNNkpxVmtGc2FXakVURDBpWmNaV2Nm?= =?utf-8?B?aDc4b2sxeWtESmVVRG41eGg4d2l1UGtWdlFkQ2JweHpWR0t0TzBURTJZK1R4?= =?utf-8?B?Skp0SnJEc1FrOUZ3eXZueURsd1BaU1lhMU05bDZuY2s5OVFHYVFiaTJ3TVFq?= =?utf-8?B?WStxVFpiNW4zR2d6VGg4dzBTWGJkOFlsVVVLNzBMcmc1MTVISkFnd0tuMkdQ?= =?utf-8?B?YndvcE9jdWIrT0dvd01PN2VFejVNbzhYVEdtWGJldHhoOCtpVDVVZVQxSnVr?= =?utf-8?B?RUVqMUl6Qmp6V3JCMEpFVGdlLzRHTU5keWhGUXFBSkVmeURRZzlOMDVHeXlS?= =?utf-8?B?ZURkeENhYXNwMXFlQjdQaDZ2dU9hbEh6MHNDMERCSndhVlV1QVN1b2tPL01Y?= =?utf-8?B?cnl2bzZXSXJ6enJQNmJUUHdhUnRQcTZpMGUyTkRwTTFqL2VoVzBBb2VEWTAz?= =?utf-8?B?cVJRZ0FaYmpVMGt2c3phOEpNZVAyVzl4ZDJZanZXVXpoaHp6ZS9wL0lkUS9S?= =?utf-8?B?RUpyWWhveEpMZXlDYzFJdmtCa25GRVVOV3VZZ2ZISGExNjZlVjBEdzdFUW81?= =?utf-8?B?S1VkVCtuS0swemdSbFFHNW1abFJPTUVNMXVkci9Tdm45U1cvUmVub2hqV3kw?= =?utf-8?B?U0diTnc3RnVaZ3pyRUs4dit1OHZUQWFleXcrTVREdFpoRkprUnJTTlVLOVNa?= =?utf-8?B?enhTNFRZR0FoY3FRSzExQi9ZU0lyQVI3dUJxVERGSFAzUXRwK0oyU2Z3eEx6?= =?utf-8?B?bE9RYWxwUDZyYjVCenV2YjZFUEx0MC8yRkR0d3NjSUxxOHJ3enIya00vZ1l6?= =?utf-8?B?dWwxZEFyVzk4ZndqMkIwdDRndGdpWUJmbGdDREcxdXpWNnduVUE4UDNLWjhM?= =?utf-8?B?dFY3K0RHT0xoZjk0V1VWeWREY0lSYTlvRzk4SnpBTTBkZU96MmpBSGlhTWVm?= =?utf-8?B?Q3dVdW5NUmRWUlpTQ0ZWMWZqeUtnSWdqWWVlWmtoU1pmTzVJb1pmZTBQem4w?= =?utf-8?B?RjZWZEdUZ1JsZ0taK3p0MGZVQzd2WmlVZUpGRENGaGYxT21TZFRTV3krQ3M5?= =?utf-8?B?KysxMHVrajNmOXo3SDRRRkJGSWdmWStqVlZTT3hvWWpVNDJ6MFYrbzBqWXMy?= =?utf-8?B?SWFIZWZmV2NNQWNCeDltdEh0TzVKQU9HL1RVM0xvQWc3V3crdzFMd2RKaEJ1?= =?utf-8?B?WXFXTDdsTEExa3dwZ0pzampmNmZoWWw1YWRNM1ZFbGc2TldJakd0SEFqNXZm?= =?utf-8?B?NnNZS0o1SUxtUmg4REFObHdwMWRrRGdUam5FWUJXeGJQOEdaaDU2ZmY0cFVy?= =?utf-8?B?bHE4UFFVS0QybHFYR0o5azFYUVZFcE1tbW50QVBqcmM4K1VVOE5ZTzhnZ1Vt?= =?utf-8?B?MXhkVlkzeGw1aDh2ZG5XcnhpQ2ZzTy9JTUpibVg5aVhqTzd2ZXVtQT09?= X-OriginatorOrg: garyguo.net X-MS-Exchange-CrossTenant-Network-Message-Id: cb3cf142-b3ab-49f6-eada-08df08492959 X-MS-Exchange-CrossTenant-AuthSource: LOAP265MB8560.GBRP265.PROD.OUTLOOK.COM X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 01 Sep 2026 16:50:43.0703 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: bbc898ad-b10f-4e10-8552-d9377b823d45 X-MS-Exchange-CrossTenant-MailboxType: HOSTED X-MS-Exchange-CrossTenant-UserPrincipalName: X6ncPYatvFM9ANkGXMcC6kUnxhpkxf8wiBwIjVUzVuzQx8hOJ3GVo1Coz7z4nBFc/le+hty2HfTXjBOH5Y522g== X-MS-Exchange-Transport-CrossTenantHeadersStamped: CW1P265MB9199 Add fixed size region types `PFalconRegisters` and `PFalcon2Registers` and update PFALCON and PFALCON2 registers to be fixed register on them and not relative registers on `NovaRegisters`. Update `Falcon` struct to store projected views when constructing and access with `self.pfalcon` and `self.pfalcon2`. Signed-off-by: Gary Guo Acked-by: Miguel Ojeda Reviewed-by: Alexandre Courbot Tested-by: Alexandre Courbot --- Changes since v3: - Add PFALCON_REGION_SIZE and PFALCON2_REGION_SIZE constants (Alex). - Add TODO comment to remove `pub(crate)` of pfalcon --- drivers/gpu/nova-core/falcon.rs | 161 +++++++++--------= ---- drivers/gpu/nova-core/falcon/fsp.rs | 63 ++++---- drivers/gpu/nova-core/falcon/gsp.rs | 51 ++++--- drivers/gpu/nova-core/falcon/hal/ga102.rs | 59 +++----- drivers/gpu/nova-core/falcon/hal/tu102.rs | 9 +- drivers/gpu/nova-core/falcon/sec2.rs | 37 +++-- drivers/gpu/nova-core/firmware/fwsec/bootloader.rs | 18 +-- drivers/gpu/nova-core/gsp/hal/tu102.rs | 7 +- drivers/gpu/nova-core/regs.rs | 92 ++++++------ 9 files changed, 239 insertions(+), 258 deletions(-) diff --git a/drivers/gpu/nova-core/falcon.rs b/drivers/gpu/nova-core/falcon= .rs index 65cb12d26e2b..e3af59fd57e3 100644 --- a/drivers/gpu/nova-core/falcon.rs +++ b/drivers/gpu/nova-core/falcon.rs @@ -14,13 +14,12 @@ io::{ io_project, poll::read_poll_timeout, - register::{ - RegisterBase, - WithBase, // - }, + register::Array, Io, + Mmio, // }, prelude::*, + sizes::SZ_4K, time::Delta, }; =20 @@ -165,18 +164,25 @@ pub(crate) enum FalconFbifMemType with From> { } } =20 -/// Type used to represent the `PFALCON` registers address base for a give= n falcon engine. -pub(crate) struct PFalconBase(()); +const PFALCON_REGION_SIZE: usize =3D SZ_4K; +const PFALCON2_REGION_SIZE: usize =3D SZ_4K; =20 -/// Type used to represent the `PFALCON2` registers address base for a giv= en falcon engine. -pub(crate) struct PFalcon2Base(()); +/// Type used to represent the `PFALCON` registers. +#[repr(align(4))] +#[derive(FromBytes, IntoBytes)] +pub(crate) struct PFalconRegisters([u8; PFALCON_REGION_SIZE]); + +/// Type used to represent the `PFALCON2` registers. +#[repr(align(4))] +#[derive(FromBytes, IntoBytes)] +pub(crate) struct PFalcon2Registers([u8; PFALCON2_REGION_SIZE]); =20 /// Trait defining the parameters of a given Falcon engine. /// /// Each engine provides one base for `PFALCON` and `PFALCON2` registers. -pub(crate) trait FalconEngine: - Send + Sync + RegisterBase + RegisterBase += Sized -{ +pub(crate) trait FalconEngine: Send + Sync + Sized { + fn pfalcon(io: Bar0<'_>) -> Mmio<'_, PFalconRegisters>; + fn pfalcon2(io: Bar0<'_>) -> Mmio<'_, PFalcon2Registers>; } =20 /// Represents a portion of the firmware to be loaded into a particular me= mory (e.g. IMEM or DMEM) @@ -358,6 +364,9 @@ pub(crate) struct Falcon<'a, E: FalconEngine> { hal: KBox>, dev: &'a device::Device, bar: Bar0<'a>, + // TODO: make private + pub(crate) pfalcon: Mmio<'a, PFalconRegisters>, + pfalcon2: Mmio<'a, PFalcon2Registers>, } =20 impl<'a, E: FalconEngine + 'static> Falcon<'a, E> { @@ -371,19 +380,19 @@ pub(crate) fn new( hal: hal::falcon_hal(chipset)?, dev, bar, + pfalcon: E::pfalcon(bar), + pfalcon2: E::pfalcon2(bar), }) } =20 /// Resets DMA-related registers. pub(crate) fn dma_reset(&self) { - self.bar.update(regs::NV_PFALCON_FBIF_CTL::of::(), |v| { + self.pfalcon.update(regs::NV_PFALCON_FBIF_CTL, |v| { v.with_allow_phys_no_ctx(true) }); =20 - self.bar.write( - WithBase::of::(), - regs::NV_PFALCON_FALCON_DMACTL::zeroed(), - ); + self.pfalcon + .write_reg(regs::NV_PFALCON_FALCON_DMACTL::zeroed()); } =20 /// Reset the controller, select the falcon core, and wait for memory = scrubbing to complete. @@ -392,10 +401,9 @@ pub(crate) fn reset(&self) -> Result { self.hal.select_core(self)?; self.hal.reset_wait_mem_scrubbing(self)?; =20 - self.bar.write( - WithBase::of::(), - regs::NV_PFALCON_FALCON_RM::from(self.bar.read(regs::NV_PMC_BO= OT_0).into_raw()), - ); + self.pfalcon.write_reg(regs::NV_PFALCON_FALCON_RM::from( + self.bar.read(regs::NV_PMC_BOOT_0).into_raw(), + )); =20 Ok(()) } @@ -413,8 +421,8 @@ fn pio_wr_imem_slice(&self, load_offsets: FalconPioImem= LoadTarget<'_>) -> Result return Err(EINVAL); } =20 - self.bar.write( - WithBase::of::().at(Self::PIO_PORT), + self.pfalcon.write( + Array::at(Self::PIO_PORT), regs::NV_PFALCON_FALCON_IMEMC::zeroed() .with_secure(load_offsets.secure) .with_aincw(true) @@ -424,14 +432,14 @@ fn pio_wr_imem_slice(&self, load_offsets: FalconPioIm= emLoadTarget<'_>) -> Result for (n, block) in load_offsets.data.chunks(MEM_BLOCK_ALIGNMENT).en= umerate() { let n =3D u16::try_from(n)?; let tag: u16 =3D load_offsets.start_tag.checked_add(n).ok_or(E= RANGE)?; - self.bar.write( - WithBase::of::().at(Self::PIO_PORT), + self.pfalcon.write( + Array::at(Self::PIO_PORT), regs::NV_PFALCON_FALCON_IMEMT::zeroed().with_tag(tag), ); for word in block.chunks_exact(4) { let w =3D [word[0], word[1], word[2], word[3]]; - self.bar.write( - WithBase::of::().at(Self::PIO_PORT), + self.pfalcon.write( + Array::at(Self::PIO_PORT), regs::NV_PFALCON_FALCON_IMEMD::zeroed().with_data(u32:= :from_le_bytes(w)), ); } @@ -450,8 +458,8 @@ fn pio_wr_dmem_slice(&self, load_offsets: FalconPioDmem= LoadTarget<'_>) -> Result return Err(EINVAL); } =20 - self.bar.write( - WithBase::of::().at(Self::PIO_PORT), + self.pfalcon.write( + Array::at(Self::PIO_PORT), regs::NV_PFALCON_FALCON_DMEMC::zeroed() .with_aincw(true) .with_offs(load_offsets.dst_start), @@ -459,8 +467,8 @@ fn pio_wr_dmem_slice(&self, load_offsets: FalconPioDmem= LoadTarget<'_>) -> Result =20 for word in load_offsets.data.chunks_exact(4) { let w =3D [word[0], word[1], word[2], word[3]]; - self.bar.write( - WithBase::of::().at(Self::PIO_PORT), + self.pfalcon.write( + Array::at(Self::PIO_PORT), regs::NV_PFALCON_FALCON_DMEMD::zeroed().with_data(u32::fro= m_le_bytes(w)), ); } @@ -473,14 +481,12 @@ pub(crate) fn pio_load + FalconPioLoadable>( &self, fw: &F, ) -> Result { - self.bar.update(regs::NV_PFALCON_FBIF_CTL::of::(), |v| { + self.pfalcon.update(regs::NV_PFALCON_FBIF_CTL, |v| { v.with_allow_phys_no_ctx(true) }); =20 - self.bar.write( - WithBase::of::(), - regs::NV_PFALCON_FALCON_DMACTL::zeroed(), - ); + self.pfalcon + .write_reg(regs::NV_PFALCON_FALCON_DMACTL::zeroed()); =20 if let Some(imem_ns) =3D fw.imem_ns_load_params() { self.pio_wr_imem_slice(imem_ns)?; @@ -492,10 +498,8 @@ pub(crate) fn pio_load= + FalconPioLoadable>( =20 self.hal.program_brom(self, &fw.brom_params()); =20 - self.bar.write( - WithBase::of::(), - regs::NV_PFALCON_FALCON_BOOTVEC::zeroed().with_value(fw.boot_a= ddr()), - ); + self.pfalcon + .write_reg(regs::NV_PFALCON_FALCON_BOOTVEC::zeroed().with_valu= e(fw.boot_addr())); =20 Ok(()) } @@ -547,16 +551,13 @@ fn dma_wr( =20 // Set up the base source DMA address. =20 - self.bar.write( - WithBase::of::(), - regs::NV_PFALCON_FALCON_DMATRFBASE::zeroed().with_base( + self.pfalcon + .write_reg(regs::NV_PFALCON_FALCON_DMATRFBASE::zeroed().with_b= ase( // CAST: `as u32` is used on purpose since we do want to s= trip the upper bits, // which will be written to `NV_PFALCON_FALCON_DMATRFBASE1= `. (dma_address >> 8) as u32, - ), - ); - self.bar.write( - WithBase::of::(), + )); + self.pfalcon.write_reg( regs::NV_PFALCON_FALCON_DMATRFBASE1::zeroed().try_with_base(dm= a_address >> 40)?, ); =20 @@ -566,23 +567,21 @@ fn dma_wr( =20 for pos in (0..num_transfers).map(|i| i * DMA_LEN) { // Perform a transfer of size `DMA_LEN`. - self.bar.write( - WithBase::of::(), + self.pfalcon.write_reg( regs::NV_PFALCON_FALCON_DMATRFMOFFS::zeroed() .try_with_offs(load_offsets.dst_start + pos)?, ); - self.bar.write( - WithBase::of::(), + self.pfalcon.write_reg( regs::NV_PFALCON_FALCON_DMATRFFBOFFS::zeroed().with_offs(s= rc_start + pos), ); =20 - self.bar.write(WithBase::of::(), cmd); + self.pfalcon.write_reg(cmd); =20 // Wait for the transfer to complete. // TIMEOUT: arbitrarily large value, no DMA transfer to the fa= lcon's small memories // should ever take that long. read_poll_timeout( - || Ok(self.bar.read(regs::NV_PFALCON_FALCON_DMATRFCMD::of:= :())), + || Ok(self.pfalcon.read(regs::NV_PFALCON_FALCON_DMATRFCMD)= ), |r| r.idle(), Delta::ZERO, Delta::from_secs(2), @@ -614,8 +613,8 @@ fn dma_load + FalconDma= Loadable>(&self, fw: &F) -> }; =20 self.dma_reset(); - self.bar - .update(regs::NV_PFALCON_FBIF_TRANSCFG::of::().at(0), |v| { + self.pfalcon + .update(regs::NV_PFALCON_FBIF_TRANSCFG::at(0), |v| { v.with_target(FalconFbifTarget::CoherentSysmem) .with_mem_type(FalconFbifMemType::Physical) }); @@ -626,10 +625,8 @@ fn dma_load + FalconDm= aLoadable>(&self, fw: &F) -> self.hal.program_brom(self, &fw.brom_params()); =20 // Set `BootVec` to start of non-secure code. - self.bar.write( - WithBase::of::(), - regs::NV_PFALCON_FALCON_BOOTVEC::zeroed().with_value(fw.boot_a= ddr()), - ); + self.pfalcon + .write_reg(regs::NV_PFALCON_FALCON_BOOTVEC::zeroed().with_valu= e(fw.boot_addr())); =20 Ok(()) } @@ -638,7 +635,7 @@ fn dma_load + FalconDma= Loadable>(&self, fw: &F) -> pub(crate) fn wait_till_halted(&self) -> Result<()> { // TIMEOUT: arbitrarily large value, firmwares should complete in = less than 2 seconds. read_poll_timeout( - || Ok(self.bar.read(regs::NV_PFALCON_FALCON_CPUCTL::of::())= ), + || Ok(self.pfalcon.read(regs::NV_PFALCON_FALCON_CPUCTL)), |r| r.halted(), Delta::ZERO, Delta::from_secs(2), @@ -649,19 +646,13 @@ pub(crate) fn wait_till_halted(&self) -> Result<()> { =20 /// Start the falcon CPU. pub(crate) fn start(&self) -> Result<()> { - match self - .bar - .read(regs::NV_PFALCON_FALCON_CPUCTL::of::()) - .alias_en() - { - true =3D> self.bar.write( - WithBase::of::(), - regs::NV_PFALCON_FALCON_CPUCTL_ALIAS::zeroed().with_startc= pu(true), - ), - false =3D> self.bar.write( - WithBase::of::(), - regs::NV_PFALCON_FALCON_CPUCTL::zeroed().with_startcpu(tru= e), - ), + match self.pfalcon.read(regs::NV_PFALCON_FALCON_CPUCTL).alias_en()= { + true =3D> self + .pfalcon + .write_reg(regs::NV_PFALCON_FALCON_CPUCTL_ALIAS::zeroed().= with_startcpu(true)), + false =3D> self + .pfalcon + .write_reg(regs::NV_PFALCON_FALCON_CPUCTL::zeroed().with_s= tartcpu(true)), } =20 Ok(()) @@ -670,32 +661,24 @@ pub(crate) fn start(&self) -> Result<()> { /// Writes values to the mailbox registers if provided. pub(crate) fn write_mailboxes(&self, mbox0: Option, mbox1: Option= ) { if let Some(mbox0) =3D mbox0 { - self.bar.write( - WithBase::of::(), - regs::NV_PFALCON_FALCON_MAILBOX0::zeroed().with_value(mbox= 0), - ); + self.pfalcon + .write_reg(regs::NV_PFALCON_FALCON_MAILBOX0::zeroed().with= _value(mbox0)); } =20 if let Some(mbox1) =3D mbox1 { - self.bar.write( - WithBase::of::(), - regs::NV_PFALCON_FALCON_MAILBOX1::zeroed().with_value(mbox= 1), - ); + self.pfalcon + .write_reg(regs::NV_PFALCON_FALCON_MAILBOX1::zeroed().with= _value(mbox1)); } } =20 /// Reads the value from `mbox0` register. pub(crate) fn read_mailbox0(&self) -> u32 { - self.bar - .read(regs::NV_PFALCON_FALCON_MAILBOX0::of::()) - .value() + self.pfalcon.read(regs::NV_PFALCON_FALCON_MAILBOX0).value() } =20 /// Reads the value from `mbox1` register. pub(crate) fn read_mailbox1(&self) -> u32 { - self.bar - .read(regs::NV_PFALCON_FALCON_MAILBOX1::of::()) - .value() + self.pfalcon.read(regs::NV_PFALCON_FALCON_MAILBOX1).value() } =20 /// Reads values from both mailbox registers. @@ -760,9 +743,7 @@ pub(crate) fn load + Fa= lconDmaLoadable>(&self, fw: =20 /// Write the application version to the OS register. pub(crate) fn write_os_version(&self, app_version: u32) { - self.bar.write( - WithBase::of::(), - regs::NV_PFALCON_FALCON_OS::zeroed().with_value(app_version), - ); + self.pfalcon + .write_reg(regs::NV_PFALCON_FALCON_OS::zeroed().with_value(app= _version)); } } diff --git a/drivers/gpu/nova-core/falcon/fsp.rs b/drivers/gpu/nova-core/fa= lcon/fsp.rs index 0437180b8829..85f9c8c5d60e 100644 --- a/drivers/gpu/nova-core/falcon/fsp.rs +++ b/drivers/gpu/nova-core/falcon/fsp.rs @@ -8,13 +8,12 @@ =20 use kernel::{ io::{ + io_project, poll::read_poll_timeout, - register::{ - Array, - RegisterBase, - WithBase, // - }, - Io, // + register, + register::Array, + Io, + Mmio, // }, prelude::*, sizes::SZ_1K, @@ -22,11 +21,13 @@ }; =20 use crate::{ + driver::{ + Bar0, + NovaRegisters, // + }, falcon::{ Falcon, - FalconEngine, - PFalcon2Base, - PFalconBase, // + FalconEngine, // }, num, regs, // @@ -41,15 +42,24 @@ /// Type specifying the `Fsp` falcon engine. Cannot be instantiated. pub(crate) struct Fsp(()); =20 -impl RegisterBase for Fsp { - const BASE: usize =3D 0x8f2000; -} +register! { + base: NovaRegisters; =20 -impl RegisterBase for Fsp { - const BASE: usize =3D 0x8f3000; + PFALCON: super::PFalconRegisters @ 0x8f2000; + PFALCON2: super::PFalcon2Registers @ 0x8f3000; } =20 -impl FalconEngine for Fsp {} +impl FalconEngine for Fsp { + #[inline] + fn pfalcon(io: Bar0<'_>) -> Mmio<'_, super::PFalconRegisters> { + io_project!(io, build: PFALCON) + } + + #[inline] + fn pfalcon2(io: Bar0<'_>) -> Mmio<'_, super::PFalcon2Registers> { + io_project!(io, build: PFALCON2) + } +} =20 impl<'a> Falcon<'a, Fsp> { /// Writes `data` to FSP external memory at offset `0`. @@ -62,19 +72,15 @@ fn write_emem(&mut self, data: &[u8]) -> Result { } =20 // Begin a write burst at offset `0`, auto-incrementing on each wr= ite. - self.bar.write( - WithBase::of::(), - regs::NV_PFALCON_FALCON_EMEMC::zeroed().with_aincw(true), - ); + self.pfalcon + .write_reg(regs::NV_PFALCON_FALCON_EMEMC::zeroed().with_aincw(= true)); =20 for chunk in data.chunks_exact(4) { let value =3D u32::from_le_bytes([chunk[0], chunk[1], chunk[2]= , chunk[3]]); =20 // Write the next 32-bit `value`; hardware advances the offset. - self.bar.write( - WithBase::of::(), - regs::NV_PFALCON_FALCON_EMEMD::zeroed().with_data(value), - ); + self.pfalcon + .write_reg(regs::NV_PFALCON_FALCON_EMEMD::zeroed().with_da= ta(value)); } =20 Ok(()) @@ -90,17 +96,12 @@ fn read_emem(&mut self, data: &mut [u8]) -> Result { } =20 // Begin a read burst at offset `0`, auto-incrementing on each rea= d. - self.bar.write( - WithBase::of::(), - regs::NV_PFALCON_FALCON_EMEMC::zeroed().with_aincr(true), - ); + self.pfalcon + .write_reg(regs::NV_PFALCON_FALCON_EMEMC::zeroed().with_aincr(= true)); =20 for chunk in data.chunks_exact_mut(4) { // Read the next 32-bit word; hardware advances the offset. - let value =3D self - .bar - .read(regs::NV_PFALCON_FALCON_EMEMD::of::()) - .data(); + let value =3D self.pfalcon.read(regs::NV_PFALCON_FALCON_EMEMD)= .data(); chunk.copy_from_slice(&value.to_le_bytes()); } =20 diff --git a/drivers/gpu/nova-core/falcon/gsp.rs b/drivers/gpu/nova-core/fa= lcon/gsp.rs index ae32f401aeb0..4c96ae325fda 100644 --- a/drivers/gpu/nova-core/falcon/gsp.rs +++ b/drivers/gpu/nova-core/falcon/gsp.rs @@ -2,23 +2,24 @@ =20 use kernel::{ io::{ + io_project, poll::read_poll_timeout, - register::{ - RegisterBase, - WithBase, // - }, + register, Io, + Mmio, // }, prelude::*, time::Delta, // }; =20 use crate::{ + driver::{ + Bar0, + NovaRegisters, // + }, falcon::{ Falcon, - FalconEngine, - PFalcon2Base, - PFalconBase, // + FalconEngine, // }, regs, }; @@ -26,24 +27,31 @@ /// Type specifying the `Gsp` falcon engine. Cannot be instantiated. pub(crate) struct Gsp(()); =20 -impl RegisterBase for Gsp { - const BASE: usize =3D 0x00110000; -} +register! { + base: NovaRegisters; =20 -impl RegisterBase for Gsp { - const BASE: usize =3D 0x00111000; + PFALCON: super::PFalconRegisters @ 0x00110000; + PFALCON2: super::PFalcon2Registers @ 0x00111000; } =20 -impl FalconEngine for Gsp {} +impl FalconEngine for Gsp { + #[inline] + fn pfalcon(io: Bar0<'_>) -> Mmio<'_, super::PFalconRegisters> { + io_project!(io, build: PFALCON) + } + + #[inline] + fn pfalcon2(io: Bar0<'_>) -> Mmio<'_, super::PFalcon2Registers> { + io_project!(io, build: PFALCON2) + } +} =20 impl<'a> Falcon<'a, Gsp> { /// Clears the SWGEN0 bit in the Falcon's IRQ status clear register to /// allow GSP to signal CPU for processing new messages in message que= ue. pub(crate) fn clear_swgen0_intr(&self) { - self.bar.write( - WithBase::of::(), - regs::NV_PFALCON_FALCON_IRQSCLR::zeroed().with_swgen0(true), - ); + self.pfalcon + .write_reg(regs::NV_PFALCON_FALCON_IRQSCLR::zeroed().with_swge= n0(true)); } =20 /// Checks if GSP reload/resume has completed during the boot process. @@ -59,8 +67,8 @@ pub(crate) fn check_reload_completed(&self, timeout: Delt= a) -> Result { =20 /// Returns whether the RISC-V branch privilege lockdown bit is set. pub(crate) fn riscv_branch_privilege_lockdown(&self) -> bool { - self.bar - .read(regs::NV_PFALCON_FALCON_HWCFG2::of::()) + self.pfalcon + .read(regs::NV_PFALCON_FALCON_HWCFG2) .riscv_br_priv_lockdown() } =20 @@ -71,10 +79,7 @@ pub(crate) fn priv_target_mask_released(&self) -> bool { const LOCKED_PATTERN: u32 =3D 0xbadf_4100; const LOCKED_MASK: u32 =3D 0xffff_ff00; =20 - let hwcfg2 =3D self - .bar - .read(regs::NV_PFALCON_FALCON_HWCFG2::of::()) - .into_raw(); + let hwcfg2 =3D self.pfalcon.read(regs::NV_PFALCON_FALCON_HWCFG2).i= nto_raw(); =20 hwcfg2 !=3D 0 && (hwcfg2 & LOCKED_MASK) !=3D LOCKED_PATTERN } diff --git a/drivers/gpu/nova-core/falcon/hal/ga102.rs b/drivers/gpu/nova-c= ore/falcon/hal/ga102.rs index 7600ee07ca2e..f9a8444cf840 100644 --- a/drivers/gpu/nova-core/falcon/hal/ga102.rs +++ b/drivers/gpu/nova-core/falcon/hal/ga102.rs @@ -6,11 +6,9 @@ device, io::{ poll::read_poll_timeout, - register::{ - Array, - WithBase, // - }, - Io, // + register::Array, + Io, + Mmio, // }, prelude::*, time::Delta, // @@ -24,6 +22,7 @@ FalconBromParams, FalconEngine, FalconModSelAlgo, + PFalcon2Registers, PeregrineCoreSelect, // }, regs, @@ -31,17 +30,16 @@ =20 use super::FalconHal; =20 -fn select_core_ga102(bar: Bar0<'_>) -> Result { - let bcr_ctrl =3D bar.read(regs::NV_PRISCV_RISCV_BCR_CTRL::of::()); +fn select_core_ga102(pfalcon2: Mmio<'_, PFalcon2Registers>) -> Result { + let bcr_ctrl =3D pfalcon2.read(regs::NV_PRISCV_RISCV_BCR_CTRL); if bcr_ctrl.core_select() !=3D PeregrineCoreSelect::Falcon { - bar.write( - WithBase::of::(), + pfalcon2.write_reg( regs::NV_PRISCV_RISCV_BCR_CTRL::zeroed().with_core_select(Pere= grineCoreSelect::Falcon), ); =20 // TIMEOUT: falcon core should take less than 10ms to report being= enabled. read_poll_timeout( - || Ok(bar.read(regs::NV_PRISCV_RISCV_BCR_CTRL::of::())), + || Ok(pfalcon2.read(regs::NV_PRISCV_RISCV_BCR_CTRL)), |r| r.valid(), Delta::ZERO, Delta::from_millis(10), @@ -86,24 +84,20 @@ fn signature_reg_fuse_version_ga102( Ok(u16::BITS - reg_fuse_version.leading_zeros()) } =20 -fn program_brom_ga102(bar: Bar0<'_>, params: &FalconBromP= arams) { - bar.write( - WithBase::of::().at(0), +fn program_brom_ga102(pfalcon2: Mmio<'_, PFalcon2Registers>, params: &Falc= onBromParams) { + pfalcon2.write( + Array::at(0), regs::NV_PFALCON2_FALCON_BROM_PARAADDR::zeroed().with_value(params= .pkc_data_offset), ); - bar.write( - WithBase::of::(), + pfalcon2.write_reg( regs::NV_PFALCON2_FALCON_BROM_ENGIDMASK::zeroed() .with_value(u32::from(params.engine_id_mask)), ); - bar.write( - WithBase::of::(), + pfalcon2.write_reg( regs::NV_PFALCON2_FALCON_BROM_CURR_UCODE_ID::zeroed().with_ucode_i= d(params.ucode_id), ); - bar.write( - WithBase::of::(), - regs::NV_PFALCON2_FALCON_MOD_SEL::zeroed().with_algo(FalconModSelA= lgo::Rsa3k), - ); + pfalcon2 + .write_reg(regs::NV_PFALCON2_FALCON_MOD_SEL::zeroed().with_algo(Fa= lconModSelAlgo::Rsa3k)); } =20 pub(super) struct Ga102(PhantomData); @@ -116,7 +110,7 @@ pub(super) fn new() -> Self { =20 impl FalconHal for Ga102 { fn select_core(&self, falcon: &Falcon<'_, E>) -> Result { - select_core_ga102::(falcon.bar) + select_core_ga102(falcon.pfalcon2) } =20 fn signature_reg_fuse_version( @@ -129,27 +123,24 @@ fn signature_reg_fuse_version( } =20 fn program_brom(&self, falcon: &Falcon<'_, E>, params: &FalconBromPara= ms) { - program_brom_ga102::(falcon.bar, params); + program_brom_ga102(falcon.pfalcon2, params); } =20 fn is_riscv_active(&self, falcon: &Falcon<'_, E>) -> bool { falcon - .bar - .read(regs::NV_PRISCV_RISCV_CPUCTL::of::()) + .pfalcon2 + .read(regs::NV_PRISCV_RISCV_CPUCTL) .active_stat() } =20 fn is_riscv_halted(&self, falcon: &Falcon<'_, E>) -> Result { - Ok(falcon - .bar - .read(regs::NV_PRISCV_RISCV_CPUCTL::of::()) - .halted()) + Ok(falcon.pfalcon2.read(regs::NV_PRISCV_RISCV_CPUCTL).halted()) } =20 fn reset_wait_mem_scrubbing(&self, falcon: &Falcon<'_, E>) -> Result { // TIMEOUT: memory scrubbing should complete in less than 20ms. read_poll_timeout( - || Ok(falcon.bar.read(regs::NV_PFALCON_FALCON_HWCFG2::of::(= ))), + || Ok(falcon.pfalcon.read(regs::NV_PFALCON_FALCON_HWCFG2)), |r| r.mem_scrubbing_done(), Delta::ZERO, Delta::from_millis(20), @@ -158,20 +149,18 @@ fn reset_wait_mem_scrubbing(&self, falcon: &Falcon<'_= , E>) -> Result { } =20 fn reset_eng(&self, falcon: &Falcon<'_, E>) -> Result { - let bar =3D falcon.bar; - - let _ =3D bar.read(regs::NV_PFALCON_FALCON_HWCFG2::of::()); + let _ =3D falcon.pfalcon.read(regs::NV_PFALCON_FALCON_HWCFG2); =20 // According to OpenRM's `kflcnPreResetWait_GA102` documentation, = HW sometimes does not set // RESET_READY so a non-failing timeout is used. let _ =3D read_poll_timeout( - || Ok(bar.read(regs::NV_PFALCON_FALCON_HWCFG2::of::())), + || Ok(falcon.pfalcon.read(regs::NV_PFALCON_FALCON_HWCFG2)), |r| r.reset_ready(), Delta::ZERO, Delta::from_micros(150), ); =20 - regs::NV_PFALCON_FALCON_ENGINE::reset_engine::(bar); + regs::NV_PFALCON_FALCON_ENGINE::reset_engine(falcon.pfalcon); self.reset_wait_mem_scrubbing(falcon)?; =20 Ok(()) diff --git a/drivers/gpu/nova-core/falcon/hal/tu102.rs b/drivers/gpu/nova-c= ore/falcon/hal/tu102.rs index 5291598fedf7..7fc6e83c2566 100644 --- a/drivers/gpu/nova-core/falcon/hal/tu102.rs +++ b/drivers/gpu/nova-core/falcon/hal/tu102.rs @@ -5,7 +5,6 @@ use kernel::{ io::{ poll::read_poll_timeout, - register::WithBase, Io, // }, prelude::*, @@ -50,8 +49,8 @@ fn program_brom(&self, _falcon: &Falcon<'_, E>, _params: = &FalconBromParams) {} =20 fn is_riscv_active(&self, falcon: &Falcon<'_, E>) -> bool { falcon - .bar - .read(regs::NV_PRISCV_RISCV_CORE_SWITCH_RISCV_STATUS::of::(= )) + .pfalcon2 + .read(regs::NV_PRISCV_RISCV_CORE_SWITCH_RISCV_STATUS) .active_stat() } =20 @@ -62,7 +61,7 @@ fn is_riscv_halted(&self, _falcon: &Falcon<'_, E>) -> Res= ult { fn reset_wait_mem_scrubbing(&self, falcon: &Falcon<'_, E>) -> Result { // TIMEOUT: memory scrubbing should complete in less than 10ms. read_poll_timeout( - || Ok(falcon.bar.read(regs::NV_PFALCON_FALCON_DMACTL::of::(= ))), + || Ok(falcon.pfalcon.read(regs::NV_PFALCON_FALCON_DMACTL)), |r| r.mem_scrubbing_done(), Delta::ZERO, Delta::from_millis(10), @@ -71,7 +70,7 @@ fn reset_wait_mem_scrubbing(&self, falcon: &Falcon<'_, E>= ) -> Result { } =20 fn reset_eng(&self, falcon: &Falcon<'_, E>) -> Result { - regs::NV_PFALCON_FALCON_ENGINE::reset_engine::(falcon.bar); + regs::NV_PFALCON_FALCON_ENGINE::reset_engine(falcon.pfalcon); self.reset_wait_mem_scrubbing(falcon)?; =20 Ok(()) diff --git a/drivers/gpu/nova-core/falcon/sec2.rs b/drivers/gpu/nova-core/f= alcon/sec2.rs index 91ec7d49c1f5..6648a397d38a 100644 --- a/drivers/gpu/nova-core/falcon/sec2.rs +++ b/drivers/gpu/nova-core/falcon/sec2.rs @@ -1,22 +1,37 @@ // SPDX-License-Identifier: GPL-2.0 =20 -use kernel::io::register::RegisterBase; +use kernel::io::{ + io_project, + register, + Mmio, // +}; =20 -use crate::falcon::{ - FalconEngine, - PFalcon2Base, - PFalconBase, // +use crate::{ + driver::{ + Bar0, + NovaRegisters, // + }, + falcon::FalconEngine, // }; =20 /// Type specifying the `Sec2` falcon engine. Cannot be instantiated. pub(crate) struct Sec2(()); =20 -impl RegisterBase for Sec2 { - const BASE: usize =3D 0x00840000; -} +register! { + base: NovaRegisters; =20 -impl RegisterBase for Sec2 { - const BASE: usize =3D 0x00841000; + PFALCON: super::PFalconRegisters @ 0x00840000; + PFALCON2: super::PFalcon2Registers @ 0x00841000; } =20 -impl FalconEngine for Sec2 {} +impl FalconEngine for Sec2 { + #[inline] + fn pfalcon(io: Bar0<'_>) -> Mmio<'_, super::PFalconRegisters> { + io_project!(io, build: PFALCON) + } + + #[inline] + fn pfalcon2(io: Bar0<'_>) -> Mmio<'_, super::PFalcon2Registers> { + io_project!(io, build: PFALCON2) + } +} diff --git a/drivers/gpu/nova-core/firmware/fwsec/bootloader.rs b/drivers/g= pu/nova-core/firmware/fwsec/bootloader.rs index ec4d92317a93..02a36fd59902 100644 --- a/drivers/gpu/nova-core/firmware/fwsec/bootloader.rs +++ b/drivers/gpu/nova-core/firmware/fwsec/bootloader.rs @@ -12,7 +12,10 @@ Device, // }, dma::Coherent, - io::{register::WithBase, Io}, + io::{ + register::Array, + Io, // + }, prelude::*, ptr::{ Alignable, @@ -23,7 +26,6 @@ }; =20 use crate::{ - driver::Bar0, falcon::{ self, gsp::Gsp, @@ -235,12 +237,7 @@ pub(crate) fn new( /// /// The bootloader will load the FWSEC firmware and then execute it. T= his function returns /// after FWSEC has reached completion. - pub(crate) fn run( - &self, - dev: &Device, - falcon: &Falcon<'_, Gsp>, - bar: Bar0<'_>, - ) -> Result<()> { + pub(crate) fn run(&self, dev: &Device, falcon: &Falcon<= '_, Gsp>) -> Result<()> { // Reset falcon, load the firmware, and run it. falcon .reset() @@ -250,9 +247,8 @@ pub(crate) fn run( .inspect_err(|e| dev_err!(dev, "Failed to load FWSEC firmware:= {:?}\n", e))?; =20 // Configure DMA index for the bootloader to fetch the FWSEC firmw= are from system memory. - bar.update( - regs::NV_PFALCON_FBIF_TRANSCFG::of::() - .try_at(usize::from_safe_cast(self.dmem_desc.ctx_dma)) + falcon.pfalcon.update( + regs::NV_PFALCON_FBIF_TRANSCFG::try_at(usize::from_safe_cast(s= elf.dmem_desc.ctx_dma)) .ok_or(EINVAL)?, |v| { v.with_target(FalconFbifTarget::CoherentSysmem) diff --git a/drivers/gpu/nova-core/gsp/hal/tu102.rs b/drivers/gpu/nova-core= /gsp/hal/tu102.rs index a5c0ca355493..d2ef35080689 100644 --- a/drivers/gpu/nova-core/gsp/hal/tu102.rs +++ b/drivers/gpu/nova-core/gsp/hal/tu102.rs @@ -62,12 +62,11 @@ impl FwsecUnloadFirmware { fn run( &self, dev: &device::Device, - bar: Bar0<'_>, gsp_falcon: &Falcon<'_, GspEngine>, ) -> Result { match self { Self::WithoutBl(fw) =3D> fw.run(dev, gsp_falcon), - Self::WithBl(fw) =3D> fw.run(dev, gsp_falcon, bar), + Self::WithBl(fw) =3D> fw.run(dev, gsp_falcon), } } } @@ -88,7 +87,7 @@ fn run(&self, ctx: &mut GspBootContext<'_, '_>) -> Result= { // Log errors but keep going if it fails. let fwsec_sb_res =3D self .fwsec_sb - .run(dev, bar, ctx.gsp_falcon) + .run(dev, ctx.gsp_falcon) .inspect_err(|e| dev_err!(dev, "FWSEC-SB failed to run: {:?}\n= ", e)); =20 // Remove WPR2 region if set. @@ -168,7 +167,7 @@ fn run_fwsec_frts( if self.needs_fwsec_bootloader { let fwsec_frts_bl =3D FwsecFirmwareWithBl::new(fwsec_frts, dev= , chipset)?; // Load and run the bootloader, which will load FWSEC-FRTS and= run it. - fwsec_frts_bl.run(dev, falcon, bar)?; + fwsec_frts_bl.run(dev, falcon)?; } else { // Load and run FWSEC-FRTS directly. fwsec_frts.run(dev, falcon)?; diff --git a/drivers/gpu/nova-core/regs.rs b/drivers/gpu/nova-core/regs.rs index 1af073f3861f..90ac8dac5349 100644 --- a/drivers/gpu/nova-core/regs.rs +++ b/drivers/gpu/nova-core/regs.rs @@ -4,8 +4,8 @@ use kernel::{ io::{ register, - register::WithBase, - Io, // + Io, + Mmio, // }, prelude::*, sizes::SizeConstants, @@ -13,22 +13,18 @@ }; =20 use crate::{ - driver::{ - Bar0, - NovaRegisters, // - }, + driver::NovaRegisters, falcon::{ DmaTrfCmdSize, FalconCoreRev, FalconCoreRevSubversion, - FalconEngine, FalconFbifMemType, FalconFbifTarget, FalconMem, FalconModSelAlgo, FalconSecurityModel, - PFalcon2Base, - PFalconBase, + PFalcon2Registers, + PFalconRegisters, PeregrineCoreSelect, // }, gpu::{ @@ -202,32 +198,32 @@ pub(crate) fn usable_fb_size(self) -> u64 { // PFALCON =20 register! { - base: NovaRegisters; + base: PFalconRegisters; =20 - pub(crate) NV_PFALCON_FALCON_IRQSCLR(u32) @ PFalconBase + 0x00000004 { + pub(crate) NV_PFALCON_FALCON_IRQSCLR(u32) @ 0x00000004 { 6:6 swgen0 =3D> bool; 4:4 halt =3D> bool; } =20 - pub(crate) NV_PFALCON_FALCON_MAILBOX0(u32) @ PFalconBase + 0x00000040 { + pub(crate) NV_PFALCON_FALCON_MAILBOX0(u32) @ 0x00000040 { 31:0 value =3D> u32; } =20 - pub(crate) NV_PFALCON_FALCON_MAILBOX1(u32) @ PFalconBase + 0x00000044 { + pub(crate) NV_PFALCON_FALCON_MAILBOX1(u32) @ 0x00000044 { 31:0 value =3D> u32; } =20 /// Used to store version information about the firmware running /// on the Falcon processor. - pub(crate) NV_PFALCON_FALCON_OS(u32) @ PFalconBase + 0x00000080 { + pub(crate) NV_PFALCON_FALCON_OS(u32) @ 0x00000080 { 31:0 value =3D> u32; } =20 - pub(crate) NV_PFALCON_FALCON_RM(u32) @ PFalconBase + 0x00000084 { + pub(crate) NV_PFALCON_FALCON_RM(u32) @ 0x00000084 { 31:0 value =3D> u32; } =20 - pub(crate) NV_PFALCON_FALCON_HWCFG2(u32) @ PFalconBase + 0x000000f4 { + pub(crate) NV_PFALCON_FALCON_HWCFG2(u32) @ 0x000000f4 { /// Signal indicating that reset is completed (GA102+). 31:31 reset_ready =3D> bool; /// RISC-V branch privilege lockdown bit. @@ -237,17 +233,17 @@ pub(crate) fn usable_fb_size(self) -> u64 { 10:10 riscv =3D> bool; } =20 - pub(crate) NV_PFALCON_FALCON_CPUCTL(u32) @ PFalconBase + 0x00000100 { + pub(crate) NV_PFALCON_FALCON_CPUCTL(u32) @ 0x00000100 { 6:6 alias_en =3D> bool; 4:4 halted =3D> bool; 1:1 startcpu =3D> bool; } =20 - pub(crate) NV_PFALCON_FALCON_BOOTVEC(u32) @ PFalconBase + 0x00000104 { + pub(crate) NV_PFALCON_FALCON_BOOTVEC(u32) @ 0x00000104 { 31:0 value =3D> u32; } =20 - pub(crate) NV_PFALCON_FALCON_DMACTL(u32) @ PFalconBase + 0x0000010c { + pub(crate) NV_PFALCON_FALCON_DMACTL(u32) @ 0x0000010c { 7:7 secure_stat =3D> bool; 6:3 dmaq_num; 2:2 imem_scrubbing =3D> bool; @@ -255,15 +251,15 @@ pub(crate) fn usable_fb_size(self) -> u64 { 0:0 require_ctx =3D> bool; } =20 - pub(crate) NV_PFALCON_FALCON_DMATRFBASE(u32) @ PFalconBase + 0x0000011= 0 { + pub(crate) NV_PFALCON_FALCON_DMATRFBASE(u32) @ 0x00000110 { 31:0 base =3D> u32; } =20 - pub(crate) NV_PFALCON_FALCON_DMATRFMOFFS(u32) @ PFalconBase + 0x000001= 14 { + pub(crate) NV_PFALCON_FALCON_DMATRFMOFFS(u32) @ 0x00000114 { 23:0 offs; } =20 - pub(crate) NV_PFALCON_FALCON_DMATRFCMD(u32) @ PFalconBase + 0x00000118= { + pub(crate) NV_PFALCON_FALCON_DMATRFCMD(u32) @ 0x00000118 { 16:16 set_dmtag; 14:12 ctxdma; 10:8 size ?=3D> DmaTrfCmdSize; @@ -274,15 +270,15 @@ pub(crate) fn usable_fb_size(self) -> u64 { 0:0 full =3D> bool; } =20 - pub(crate) NV_PFALCON_FALCON_DMATRFFBOFFS(u32) @ PFalconBase + 0x00000= 11c { + pub(crate) NV_PFALCON_FALCON_DMATRFFBOFFS(u32) @ 0x0000011c { 31:0 offs =3D> u32; } =20 - pub(crate) NV_PFALCON_FALCON_DMATRFBASE1(u32) @ PFalconBase + 0x000001= 28 { + pub(crate) NV_PFALCON_FALCON_DMATRFBASE1(u32) @ 0x00000128 { 8:0 base; } =20 - pub(crate) NV_PFALCON_FALCON_HWCFG1(u32) @ PFalconBase + 0x0000012c { + pub(crate) NV_PFALCON_FALCON_HWCFG1(u32) @ 0x0000012c { /// Core revision subversion. 7:6 core_rev_subversion =3D> FalconCoreRevSubversion; /// Security model. @@ -291,12 +287,12 @@ pub(crate) fn usable_fb_size(self) -> u64 { 3:0 core_rev ?=3D> FalconCoreRev; } =20 - pub(crate) NV_PFALCON_FALCON_CPUCTL_ALIAS(u32) @ PFalconBase + 0x00000= 130 { + pub(crate) NV_PFALCON_FALCON_CPUCTL_ALIAS(u32) @ 0x00000130 { 1:1 startcpu =3D> bool; } =20 /// IMEM access control register. Up to 4 ports are available for IMEM= access. - pub(crate) NV_PFALCON_FALCON_IMEMC(u32)[4, stride =3D 16] @ PFalconBas= e + 0x00000180 { + pub(crate) NV_PFALCON_FALCON_IMEMC(u32)[4, stride =3D 16] @ 0x00000180= { /// Access secure IMEM. 28:28 secure =3D> bool; /// Auto-increment on write. @@ -307,17 +303,17 @@ pub(crate) fn usable_fb_size(self) -> u64 { =20 /// IMEM data register. Reading/writing this register accesses IMEM at= the address /// specified by the corresponding IMEMC register. - pub(crate) NV_PFALCON_FALCON_IMEMD(u32)[4, stride =3D 16] @ PFalconBas= e + 0x00000184 { + pub(crate) NV_PFALCON_FALCON_IMEMD(u32)[4, stride =3D 16] @ 0x00000184= { 31:0 data; } =20 /// IMEM tag register. Used to set the tag for the current IMEM block. - pub(crate) NV_PFALCON_FALCON_IMEMT(u32)[4, stride =3D 16] @ PFalconBas= e + 0x00000188 { + pub(crate) NV_PFALCON_FALCON_IMEMT(u32)[4, stride =3D 16] @ 0x00000188= { 15:0 tag; } =20 /// DMEM access control register. Up to 8 ports are available for DMEM= access. - pub(crate) NV_PFALCON_FALCON_DMEMC(u32)[8, stride =3D 8] @ PFalconBase= + 0x000001c0 { + pub(crate) NV_PFALCON_FALCON_DMEMC(u32)[8, stride =3D 8] @ 0x000001c0 { /// Auto-increment on write. 24:24 aincw =3D> bool; /// DMEM block and word offset. @@ -326,29 +322,29 @@ pub(crate) fn usable_fb_size(self) -> u64 { =20 /// DMEM data register. Reading/writing this register accesses DMEM at= the address /// specified by the corresponding DMEMC register. - pub(crate) NV_PFALCON_FALCON_DMEMD(u32)[8, stride =3D 8] @ PFalconBase= + 0x000001c4 { + pub(crate) NV_PFALCON_FALCON_DMEMD(u32)[8, stride =3D 8] @ 0x000001c4 { 31:0 data; } =20 /// Actually known as `NV_PSEC_FALCON_ENGINE` and `NV_PGSP_FALCON_ENGI= NE` depending on the /// falcon instance. - pub(crate) NV_PFALCON_FALCON_ENGINE(u32) @ PFalconBase + 0x000003c0 { + pub(crate) NV_PFALCON_FALCON_ENGINE(u32) @ 0x000003c0 { 0:0 reset =3D> bool; } =20 - pub(crate) NV_PFALCON_FBIF_TRANSCFG(u32)[8] @ PFalconBase + 0x00000600= { + pub(crate) NV_PFALCON_FBIF_TRANSCFG(u32)[8] @ 0x00000600 { 2:2 mem_type =3D> FalconFbifMemType; 1:0 target ?=3D> FalconFbifTarget; } =20 - pub(crate) NV_PFALCON_FBIF_CTL(u32) @ PFalconBase + 0x00000624 { + pub(crate) NV_PFALCON_FBIF_CTL(u32) @ 0x00000624 { 7:7 allow_phys_no_ctx =3D> bool; } =20 // Falcon EMEM PIO registers (used by FSP on Hopper/Blackwell). // These provide the falcon external memory communication interface. =20 - pub(crate) NV_PFALCON_FALCON_EMEMC(u32) @ PFalconBase + 0x00000ac0 { + pub(crate) NV_PFALCON_FALCON_EMEMC(u32) @ 0x00000ac0 { /// EMEM byte offset (4-byte aligned) within the block. 7:2 offs; /// EMEM block to access. @@ -359,7 +355,7 @@ pub(crate) fn usable_fb_size(self) -> u64 { 25:25 aincr =3D> bool; } =20 - pub(crate) NV_PFALCON_FALCON_EMEMD(u32) @ PFalconBase + 0x00000ac4 { + pub(crate) NV_PFALCON_FALCON_EMEMD(u32) @ 0x00000ac4 { 31:0 data =3D> u32; } } @@ -385,13 +381,13 @@ pub(crate) fn with_falcon_mem(self, mem: FalconMem) -= > Self { =20 impl NV_PFALCON_FALCON_ENGINE { /// Resets the falcon - pub(crate) fn reset_engine(bar: Bar0<'_>) { - bar.update(Self::of::(), |r| r.with_reset(true)); + pub(crate) fn reset_engine(pfalcon: Mmio<'_, PFalconRegisters>) { + pfalcon.update(NV_PFALCON_FALCON_ENGINE, |r| r.with_reset(true)); =20 // TIMEOUT: falcon engine should not take more than 10us to reset. time::delay::fsleep(time::Delta::from_micros(10)); =20 - bar.update(Self::of::(), |r| r.with_reset(false)); + pfalcon.update(NV_PFALCON_FALCON_ENGINE, |r| r.with_reset(false)); } } =20 @@ -405,23 +401,23 @@ pub(crate) fn mem_scrubbing_done(self) -> bool { /* PFALCON2 */ =20 register! { - base: NovaRegisters; + base: PFalcon2Registers; =20 - pub(crate) NV_PFALCON2_FALCON_MOD_SEL(u32) @ PFalcon2Base + 0x00000180= { + pub(crate) NV_PFALCON2_FALCON_MOD_SEL(u32) @ 0x00000180 { 7:0 algo ?=3D> FalconModSelAlgo; } =20 - pub(crate) NV_PFALCON2_FALCON_BROM_CURR_UCODE_ID(u32) @ PFalcon2Base += 0x00000198 { + pub(crate) NV_PFALCON2_FALCON_BROM_CURR_UCODE_ID(u32) @ 0x00000198 { 7:0 ucode_id =3D> u8; } =20 - pub(crate) NV_PFALCON2_FALCON_BROM_ENGIDMASK(u32) @ PFalcon2Base + 0x0= 000019c { + pub(crate) NV_PFALCON2_FALCON_BROM_ENGIDMASK(u32) @ 0x0000019c { 31:0 value =3D> u32; } =20 /// OpenRM defines this as a register array, but doesn't specify its s= ize and only uses its /// first element. Be conservative until we know the actual size or ne= ed to use more registers. - pub(crate) NV_PFALCON2_FALCON_BROM_PARAADDR(u32)[1] @ PFalcon2Base + 0= x00000210 { + pub(crate) NV_PFALCON2_FALCON_BROM_PARAADDR(u32)[1] @ 0x00000210 { 31:0 value =3D> u32; } } @@ -429,23 +425,23 @@ pub(crate) fn mem_scrubbing_done(self) -> bool { // PRISCV =20 register! { - base: NovaRegisters; + base: PFalcon2Registers; =20 /// RISC-V status register for debug (Turing and GA100 only). /// Reflects current RISC-V core status. - pub(crate) NV_PRISCV_RISCV_CORE_SWITCH_RISCV_STATUS(u32) @ PFalcon2Bas= e + 0x00000240 { + pub(crate) NV_PRISCV_RISCV_CORE_SWITCH_RISCV_STATUS(u32) @ 0x00000240 { /// RISC-V core active/inactive status. 0:0 active_stat =3D> bool; } =20 /// GA102 and later. - pub(crate) NV_PRISCV_RISCV_CPUCTL(u32) @ PFalcon2Base + 0x00000388 { + pub(crate) NV_PRISCV_RISCV_CPUCTL(u32) @ 0x00000388 { 7:7 active_stat =3D> bool; 4:4 halted =3D> bool; } =20 /// GA102 and later. - pub(crate) NV_PRISCV_RISCV_BCR_CTRL(u32) @ PFalcon2Base + 0x00000668 { + pub(crate) NV_PRISCV_RISCV_BCR_CTRL(u32) @ 0x00000668 { 8:8 br_fetch =3D> bool; 4:4 core_select =3D> PeregrineCoreSelect; 0:0 valid =3D> bool; --=20 2.54.0 From nobody Sat Sep 26 12:29:12 2026 Received: from CWXP265CU008.outbound.protection.outlook.com (mail-ukwestazon11020105.outbound.protection.outlook.com [52.101.195.105]) (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 ADAC348BD42; Tue, 1 Sep 2026 16:50:53 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=52.101.195.105 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788281456; cv=fail; b=qVWRrq3GTsmYT0A+cGWn4n5dEvjI7jlXc8tbUgMrTFfG8n5JCg2M31mpAqhNbXa94zgfbOYZXzWCA0l6ctAwp3Y+AnyD3b2MxPm5DQszkAZGObV59cmB7skae0WOIZc+zo4NRyH2EKO/l0DTiPAhEH9z56CTzOFr9Op9zuAjGZg= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788281456; c=relaxed/simple; bh=jxmNg7xPw7da42o5I5lxrJuHBh4clo2hgfjUDn1kqRg=; h=From:Date:Subject:Content-Type:Message-Id:References:In-Reply-To: To:Cc:MIME-Version; b=ZuGldEw5CEQcBg5xQ/SKPwHDjgjmOSpDL2IQniUdjeIZtwCdQt3JZy4qVhxfSzO+/zB7LV2PYmCm11sFR1nlZVjnHDhuJh20Ina2+uXTPDfxkQZob41uXYfiI/hTWK75qde6+1bN4gdN4o+xsXY4vP0zGoQD9oXK5YuE5gqA9VM= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=garyguo.net; spf=pass smtp.mailfrom=garyguo.net; dkim=pass (1024-bit key) header.d=garyguo.net header.i=@garyguo.net header.b=uC1IWFqg; arc=fail smtp.client-ip=52.101.195.105 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=garyguo.net Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=garyguo.net Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=garyguo.net header.i=@garyguo.net header.b="uC1IWFqg" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=I+Y5Ycet/PjB2ZHkp+8hlE0yUnN9OTjTq3PdOTh5HkBBXmqW/oN/dMBgPx7TCd1iP4vDRBM36P4d7c+JBPFkGX1TOhtJ5s9rJ+W1uC6iLBS9jRfr5wteMQe++ARl/Aeq/WkdSWU2zt1eP+Bf1Jete8gv9qk8WUTnheOjbvOaTskEc8IZpiKtA9XBhTDAYAMvSsZSEjvHqpCRVlpjG2vyRCyEe2fi+rbkWR7ot5g+BiQJiTp1gPT/lO1dyuPKMMJxR6z1XHCjR9F61HckjbyqNLWg8KSfb6bKZRx5XqEGQaAx7tidgz4tCth+UWIIxPmhxi1BwCJjlJXGaEOpaSvjuA== 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=ToENILkQJrEJR14hMqLdQy9VnyEgDH8Lxe1vho9utvw=; b=Pp0OJ6GsYJJLymQhhIr4wugg9RjTeZ8VrGUzcql3fenXwM/WmCJfbD1Lkn+HwmAiCdck10rl82ACQExCn1CCcrpRY/wXfjsvLl1ESv1HxTIb3sXNMk6c2y1E3ldZTA0fs8g7LsyIAk5yAUbR5DSdAK68BYecjAwWZPQJGk1L7d+5cGi13oYGSBNEoLGAu6lCm0VMbfNeR9qAFSyqw7sg5TKTFfou2b5W07T822V6vCVYkYkV0FXajbuaZUZgRa9y7ocVn5duVMQKl2RBjeUBwS4bXK/JFUrZ+7Po9JSVZ3TGzKrSVHvQjQXgWKGOuMlUJWwkaCGCCaVQTgXy50SvnQ== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=garyguo.net; dmarc=pass action=none header.from=garyguo.net; dkim=pass header.d=garyguo.net; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=garyguo.net; s=selector1; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=ToENILkQJrEJR14hMqLdQy9VnyEgDH8Lxe1vho9utvw=; b=uC1IWFqgKT95KXNhfubaUP9G5Q0W1hSq82ulJrpW0hIKUcAXJeKXx60m5HTkFUpU+q2cjj0n8trPfc0zsuzvmbd15gt4s+CGBkEcr5qarWRLXDf6PSpc1sb2+kHo5/czIfTpjDnmMBM28B/ePmoZyftrjaDy5yqjpvt2rO7b62o= Authentication-Results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=garyguo.net; Received: from LOAP265MB8560.GBRP265.PROD.OUTLOOK.COM (2603:10a6:600:4ab::19) by CW1P265MB9199.GBRP265.PROD.OUTLOOK.COM (2603:10a6:400:272::22) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.21.360.13; Tue, 1 Sep 2026 16:50:44 +0000 Received: from LOAP265MB8560.GBRP265.PROD.OUTLOOK.COM ([fe80::f60b:1537:68d7:4fc1]) by LOAP265MB8560.GBRP265.PROD.OUTLOOK.COM ([fe80::f60b:1537:68d7:4fc1%4]) with mapi id 15.21.0360.008; Tue, 1 Sep 2026 16:50:44 +0000 From: Gary Guo Date: Tue, 01 Sep 2026 17:50:37 +0100 Subject: [PATCH v4 13/16] gpu: nova-core: convert hshub0 from relative register to projection Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260901-typed_register-v4-13-5552b1d59525@garyguo.net> References: <20260901-typed_register-v4-0-5552b1d59525@garyguo.net> In-Reply-To: <20260901-typed_register-v4-0-5552b1d59525@garyguo.net> To: Danilo Krummrich , Alice Ryhl , Daniel Almeida , Miguel Ojeda , Boqun Feng , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Andreas Hindborg , Trevor Gross , Tamir Duberstein , Alexandre Courbot , =?utf-8?q?Onur_=C3=96zkan?= , David Airlie , Simona Vetter , Bjorn Helgaas , =?utf-8?q?Krzysztof_Wilczy=C5=84ski?= Cc: driver-core@lists.linux.dev, rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, nova-gpu@lists.linux.dev, dri-devel@lists.freedesktop.org, linux-pci@vger.kernel.org, Gary Guo X-Mailer: b4 0.15.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1788281431; l=6817; i=gary@garyguo.net; s=20221204; h=from:subject:message-id; bh=jxmNg7xPw7da42o5I5lxrJuHBh4clo2hgfjUDn1kqRg=; b=JadxgMXLjjnnZrm+DOQbhiD40wM/k7aZulIxsp2o2YwTWXGUCw3jVBsWC/hmEVFCqRmAb+OK7 44uIbImgxzpDg/v0tySKH986Gt7QNKr8+/ich2YhSTf0o14cmW5E2Hg X-Developer-Key: i=gary@garyguo.net; a=ed25519; pk=vB3uIX95SM4eVrIqo1DWNWKDKD2xzB+yLLLr0yOPYMo= X-ClientProxiedBy: PAZP264CA0173.FRAP264.PROD.OUTLOOK.COM (2603:10a6:102:236::16) To LOAP265MB8560.GBRP265.PROD.OUTLOOK.COM (2603:10a6:600:4ab::19) 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: LOAP265MB8560:EE_|CW1P265MB9199:EE_ X-MS-Office365-Filtering-Correlation-Id: 9ed1013e-ec49-43de-4765-08df08492a02 X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|1800799024|7416014|10070799003|376014|23010399003|366016|921020|6133799003|10067099003|56012099006|22082099003|18002099003; X-Microsoft-Antispam-Message-Info: RR7EsED61qSUlhjA39HXGgkISiWbtcARH0atp88wOGEet3jKSlUMDnt9y+MfL002yB/Llhhh93U2+8p4NNtQLv+chSKqyWOUYCsl9SiQK8hhJtbsqzpHGlh9oqEyq7ahKuhgWRsxqOlHQlKNnNBYvMXTG5XURKoD1Sp6Ey5c/x2Vfj5OMvCswB5rtSAM5oEt1dfc3RIm1+pnl4m25vI6n4jLUKEtxUygyyBcHOio14lziRNqKu1Lr9Ui7hVv1fzDWVsh/sECTOI3nto5xMMwNvsvqKEeSYnX2TWRijfuPF3DS3yTg/wthbjVFv0gwuQelLcQ4QYoRYwu/llvYWwA1F3UdAsZDyCDY6OkUrKZpw7Vba/sK7uCuqeQNtuF6nayYLP454a8LhmxkXA/PspWtqo7A2keXmt9N4NAIXmTZn2moWs6QsyV/dm/2hp7e5a09ODowsAZv1yUnthAC6Ta2AiABkiz2tCnV6u+2dmPeo0MCCBTBmDO/4z1eWJjAffsbMec/OUfLoJ9GfZ1gM6gM1CYwpeo9LaJZ02rN2pbOnOoYdd108MLmYMudSxdyoGVBYEKUQe4gLY/Bk7IPueq0jvLm7ai7DgDtCQAXfXSD6gb7TF9yB0E6Oxah0PB7eqAVWi8UUFKKod8ENrmmkw7MlqYdxpOZyVF0Kw6Uh3kJpG6ZYlhl1M7i6UUU2r2jm09R+pTVN7+lrnrkv9AJ1Ppfg== X-Forefront-Antispam-Report: CIP:255.255.255.255;CTRY:;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:LOAP265MB8560.GBRP265.PROD.OUTLOOK.COM;PTR:;CAT:NONE;SFS:(13230040)(1800799024)(7416014)(10070799003)(376014)(23010399003)(366016)(921020)(6133799003)(10067099003)(56012099006)(22082099003)(18002099003);DIR:OUT;SFP:1102; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: =?utf-8?B?dmluR1lBeksvNElnZWtoNlExZlVrc2Q5L0p2cDVXWUpMcUhQaVN6SUJOcmk0?= =?utf-8?B?Z3BqeUZnaDBpRlBHcWJhMnI2NzRkQ1cwa2RwTTg1YTk3TGxsYlZEMjloK3Np?= =?utf-8?B?eEhSZmp0REdRZWErbDhTbFVWS2VjdCtCQXAvWG85dVBlNUZGdTl6WWZBRFFU?= =?utf-8?B?eng4SFNOdnFqK01SRjNjaUd1Y0RQMEdzVVBXTVpJazIxaVBIWUNGKzNweTJi?= =?utf-8?B?aW9MSU82NW5VYzZ2c0E3OWMxU1BnYkF2enhQbVprS2VxaDNkS2xoUTl2WWw1?= =?utf-8?B?N1I2Vm9TeWRLYjE2eFg1Tmg5ODZaNHpRSVNnWlFtZWdXcmdJY1g2eC9ZUDdP?= =?utf-8?B?M05vY0twQjh6M1RNUCs0T2F6c3NLTkMzZXk4RVNaK29ZZFNpZWNGNUNpTnpw?= =?utf-8?B?RG1vbDY3QldoMUw3UFZkdkd6LzVBYVgvTHhJY0psV3FSZXpvcjhaQldrSmZC?= =?utf-8?B?TkpyRXVaSmJoOE9YRDlBaW5xZFNCVUpRcnpQWVIrWG40UE9GMnNSVnVYNHhs?= =?utf-8?B?TzlkU1FMNGptR0JIbStFcmdHS2FvSS9WUVVWQUhYTXF0dnhVeGJnVTFlYncr?= =?utf-8?B?dUVtS0lkRnhNTUJvNW9IemJtMFBJbWRZcjJiNml4TzZldWFFUlZtSzVqbU1z?= =?utf-8?B?dGZsYWVYSVVPWFUwRS8xZ0FrQWZmMnlpNHIxZERGaFJmS1k1S3dVbEVHTHlm?= =?utf-8?B?b21YMWk4QXJleCt0cllpTExubHFXTlpNMWlrSEZqbEo3OUhFYllLa1JiZk9x?= =?utf-8?B?KzF6YWRXOWE2QWhvL3gwZmxrTVhUWGVqSG5ORmRwem9yQjJpYkRaRyszREhl?= =?utf-8?B?M1djQm4rSEFEcHBDbmFmSUZrQjhPUDh3SWY2RmhBQmpIMXlWZ3p1QS9jTnQz?= =?utf-8?B?UFZ5RzlscXkwdjFycGM4M0VldjFBUVJrZnpTUUthVnZoTWUvaGs1TklzTllv?= =?utf-8?B?bCswL1JVYkc4SDZ6YUJsQitlWisyb3Y2Wm4yWElUTGdpdjJiNkpVakdIaUt2?= =?utf-8?B?aks4NW5xY0gvWE5BRmRKaEU1SCt2UWwwZnQ3NWVQbUlXS29WU05mR25yK3lt?= =?utf-8?B?cXg0NkFPYWxOY2JnOGhCRE51b0h3STl2cFJRSE9ScEpNbVpNZVBLQ3lsVzE3?= =?utf-8?B?cnEyT2Rhd3pmOVVEemdYbFBNVGZwbE1YM0pvUjdZOWJKN2xVMjNzYTM2TzdO?= =?utf-8?B?TWR4andhOHA3K1o1QUdKc3dhT3N2cGtsbi9xN0ZBVFNrT0o1NVdLREpVZkJl?= =?utf-8?B?SFBRck9yNjRsUXRTaDFJakkzMDVzWWkwZFNldDNwYWltMS9wWk1YdjBmd1lk?= =?utf-8?B?QjAyZzNOTmhBSzZ2NHBxQzVMVFVBd0J2djFvOWVFWHpVckJham1JdTFHREQ3?= =?utf-8?B?U25VL1BMSXE3Y3hhR1VUQ0hON2UyNTB0eTNpRi8yOGlJTW5oY25UeEhIYVNt?= =?utf-8?B?Z1Rsc282bWdQYXpUT1R4ckYrSmRPVVlnc2paYjJnaXRMM0RjRGY4S1ljVENa?= =?utf-8?B?endLQTZxR1BBYWd4NTFQZ2ZFMjEvcGdIbVZlV1lWaGtleUdEOGVjMEJqaUdt?= =?utf-8?B?Ky8rVVZPeUpSa3BJOTNEeWIrbWVYTFowUVhWV3cyV0RpS2NjMzZLaWpIT0JL?= =?utf-8?B?cGxWOWYzdTNjd29pc1daVXpiQnh3MEhaWCt1WHJKTVdqU1RpLzVvVU5wK3dp?= =?utf-8?B?VmlRditkM21PRTRWanplMjFLOTdYcjB0VjJuRWdyU0RuM1FrZTdLQ3k2NVlI?= =?utf-8?B?d0lnMXRyWHlMSm1CdDJLb2FsU0RvRDV0WVRRRXdQaWVWdno5aHFKbS9sTy9s?= =?utf-8?B?T01IRHkzbjFhZWUwMW90V1J3eloyTTB3SzVJR29GUURyamMxcURsdm9MVnpx?= =?utf-8?B?NnJFL3pUL2xadEJkd005ckZ3K1F5SjNJNkhFTVVGVGprOU1RamJRS0xxT1Fn?= =?utf-8?B?Y2QrVzRNK3g0UU1QZ05jdVVUSEEvZGJ5a1BrZkhwNWQvM2IyaVFmUGpHL2ZH?= =?utf-8?B?NVA1Y2dUSEdPTTJaR1pVRkJxRnJyem9hR29nWkVGbmNqYXEzZ2NTb2ZZZ3l6?= =?utf-8?B?dXYzL2VxdzBsSHdZWFMvWVZIV21QdWpNZUtFRVk5K3U5dXNGZ29jdXlhSUpT?= =?utf-8?B?UlM2a1E4UEdwN1N4dHJBTG5OUGZKUUZFSEdxYTdNcW85ZGJhQ21CS2c4Rmln?= =?utf-8?B?OFpHNTFyQ0VUVGxaeExacVdHeFNYWlZUZk9wd1V3WmRnaXZqTmpDdzNWNEpR?= =?utf-8?B?QjZQbTZiZWlnOUFqa2lxREFqMlp2dThzRE45WjAwdnhqMVVUdERDeFQ5VUVH?= =?utf-8?B?aWRXWFdMTkUveUtVZVd3THNuY3ptcll5QUtBQ0crSzZuUjYyM2Uvdz09?= X-OriginatorOrg: garyguo.net X-MS-Exchange-CrossTenant-Network-Message-Id: 9ed1013e-ec49-43de-4765-08df08492a02 X-MS-Exchange-CrossTenant-AuthSource: LOAP265MB8560.GBRP265.PROD.OUTLOOK.COM X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 01 Sep 2026 16:50:44.0989 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: bbc898ad-b10f-4e10-8552-d9377b823d45 X-MS-Exchange-CrossTenant-MailboxType: HOSTED X-MS-Exchange-CrossTenant-UserPrincipalName: l/KxF7kf4L/YFM1+dqCQtd1co+U917+zpg8WstUuuAP78MheVoFuY/1TP4OQDem74D4pMD+bBJQgSK0IH+GLCg== X-MS-Exchange-Transport-CrossTenantHeadersStamped: CW1P265MB9199 Similar to the PFALCON and PFALCON2 conversion, the hshub0 relative access can also be achieved cleanly with projection and a new base. Reviewed-by: Alexandre Courbot Signed-off-by: Gary Guo Acked-by: Miguel Ojeda Tested-by: Alexandre Courbot --- drivers/gpu/nova-core/fb/hal/gb100.rs | 59 +++++++++++++++++--------------= ---- drivers/gpu/nova-core/fb/regs.rs | 21 ++++++++----- 2 files changed, 42 insertions(+), 38 deletions(-) diff --git a/drivers/gpu/nova-core/fb/hal/gb100.rs b/drivers/gpu/nova-core/= fb/hal/gb100.rs index d9e4d62ae632..9fa094939600 100644 --- a/drivers/gpu/nova-core/fb/hal/gb100.rs +++ b/drivers/gpu/nova-core/fb/hal/gb100.rs @@ -5,11 +5,10 @@ =20 use kernel::{ io::{ - register::{ - RegisterBase, - WithBase, // - }, - Io, // + io_project, + register, + Io, + Mmio, // }, num::Bounded, prelude::*, @@ -21,7 +20,10 @@ }; =20 use crate::{ - driver::Bar0, + driver::{ + Bar0, + NovaRegisters, // + }, fb::{ hal::FbHal, regs, // @@ -31,17 +33,26 @@ =20 struct Gb100; =20 -impl RegisterBase for Gb100 { - const BASE: usize =3D 0x0087_0000; +register! { + base: NovaRegisters; + + HSHUB0: regs::Hshub0Registers @ 0x0087_0000; +} + +#[inline] +fn hshub0(bar: Bar0<'_>) -> Mmio<'_, regs::Hshub0Registers> { + io_project!(bar, build: HSHUB0) } =20 -fn read_sysmem_flush_page_gb100(bar: Bar0<'_>) -> u64 { +fn read_sysmem_flush_page_gb100(hshub0: Mmio<'_, regs::Hshub0Registers>) -= > u64 { let lo =3D u64::from( - bar.read(regs::NV_PFB_HSHUB_PCIE_FLUSH_SYSMEM_ADDR_LO::of::= ()) + hshub0 + .read(regs::NV_PFB_HSHUB_PCIE_FLUSH_SYSMEM_ADDR_LO) .adr(), ); let hi =3D u64::from( - bar.read(regs::NV_PFB_HSHUB_PCIE_FLUSH_SYSMEM_ADDR_HI::of::= ()) + hshub0 + .read(regs::NV_PFB_HSHUB_PCIE_FLUSH_SYSMEM_ADDR_HI) .adr(), ); =20 @@ -52,7 +63,7 @@ fn read_sysmem_flush_page_gb100(bar: Bar0<'_>) -> u64 { /// /// Both the primary and EG (egress) register pairs must be programmed to = the same address, /// as required by hardware. -fn write_sysmem_flush_page_gb100(bar: Bar0<'_>, addr: Bounded) { +fn write_sysmem_flush_page_gb100(hshub0: Mmio<'_, regs::Hshub0Registers>, = addr: Bounded) { // CAST: lower 32 bits. Hardware ignores bits 7:0. let addr_lo =3D *addr as u32; let addr_hi =3D addr.shr::<32, 20>().cast::(); @@ -60,24 +71,12 @@ fn write_sysmem_flush_page_gb100(bar: Bar0<'_>, addr: B= ounded) { // Write HI first. The hardware will trigger the flush on the LO write. =20 // Primary HSHUB pair. - bar.write( - regs::NV_PFB_HSHUB_PCIE_FLUSH_SYSMEM_ADDR_HI::of::(), - regs::NV_PFB_HSHUB_PCIE_FLUSH_SYSMEM_ADDR_HI::zeroed().with_adr(ad= dr_hi), - ); - bar.write( - regs::NV_PFB_HSHUB_PCIE_FLUSH_SYSMEM_ADDR_LO::of::(), - regs::NV_PFB_HSHUB_PCIE_FLUSH_SYSMEM_ADDR_LO::zeroed().with_adr(ad= dr_lo), - ); + hshub0.write_reg(regs::NV_PFB_HSHUB_PCIE_FLUSH_SYSMEM_ADDR_HI::zeroed(= ).with_adr(addr_hi)); + hshub0.write_reg(regs::NV_PFB_HSHUB_PCIE_FLUSH_SYSMEM_ADDR_LO::zeroed(= ).with_adr(addr_lo)); =20 // EG (egress) pair -- must match the primary pair. - bar.write( - regs::NV_PFB_HSHUB_EG_PCIE_FLUSH_SYSMEM_ADDR_HI::of::(), - regs::NV_PFB_HSHUB_EG_PCIE_FLUSH_SYSMEM_ADDR_HI::zeroed().with_adr= (addr_hi), - ); - bar.write( - regs::NV_PFB_HSHUB_EG_PCIE_FLUSH_SYSMEM_ADDR_LO::of::(), - regs::NV_PFB_HSHUB_EG_PCIE_FLUSH_SYSMEM_ADDR_LO::zeroed().with_adr= (addr_lo), - ); + hshub0.write_reg(regs::NV_PFB_HSHUB_EG_PCIE_FLUSH_SYSMEM_ADDR_HI::zero= ed().with_adr(addr_hi)); + hshub0.write_reg(regs::NV_PFB_HSHUB_EG_PCIE_FLUSH_SYSMEM_ADDR_LO::zero= ed().with_adr(addr_lo)); } =20 // This PMU reservation size is r570-specific. @@ -88,13 +87,13 @@ pub(super) const fn pmu_reserved_size_gb100() -> u32 { =20 impl FbHal for Gb100 { fn read_sysmem_flush_page(&self, bar: Bar0<'_>) -> u64 { - read_sysmem_flush_page_gb100(bar) + read_sysmem_flush_page_gb100(hshub0(bar)) } =20 fn write_sysmem_flush_page(&self, bar: Bar0<'_>, addr: u64) -> Result { let addr =3D Bounded::::try_new(addr).ok_or(EINVAL)?; =20 - write_sysmem_flush_page_gb100(bar, addr); + write_sysmem_flush_page_gb100(hshub0(bar), addr); =20 Ok(()) } diff --git a/drivers/gpu/nova-core/fb/regs.rs b/drivers/gpu/nova-core/fb/re= gs.rs index c27582e376e2..abb48b0955a9 100644 --- a/drivers/gpu/nova-core/fb/regs.rs +++ b/drivers/gpu/nova-core/fb/regs.rs @@ -2,7 +2,8 @@ =20 use kernel::{ io::register, - sizes::SizeConstants, // + prelude::*, + sizes::{SizeConstants, SZ_4K}, // }; =20 use crate::driver::NovaRegisters; @@ -65,31 +66,35 @@ pub(super) fn vga_workspace_addr(self) -> Option { } } =20 -/// Base of the GB10x HSHUB0 register window (`NV_HSHUB0_PRIV_BASE` in Ope= n RM). +const HSHUB0_REGION_SIZE: usize =3D SZ_4K; + +/// The GB10x HSHUB0 register window (Base defined as `NV_HSHUB0_PRIV_BASE= ` in Open RM). /// /// The base is provided by the GB10x framebuffer HAL. -pub(super) struct Hshub0Base(()); +#[repr(align(4))] +#[derive(FromBytes, IntoBytes)] +pub(super) struct Hshub0Registers([u8; HSHUB0_REGION_SIZE]); =20 register! { - base: NovaRegisters; + base: Hshub0Registers; =20 // GB10x sysmem flush registers, relative to the HSHUB0 base. GB10x ro= utes sysmembar // through a primary and an EG (egress) pair that must both be program= med to the same // address. Hardware ignores bits 7:0 of each LO register. The boot pa= th uses a fixed // HSHUB0 base, so the multiple runtime-discovered HSHUB bases are not= needed here. - pub(super) NV_PFB_HSHUB_PCIE_FLUSH_SYSMEM_ADDR_LO(u32) @ Hshub0Base + = 0x00000e50 { + pub(super) NV_PFB_HSHUB_PCIE_FLUSH_SYSMEM_ADDR_LO(u32) @ 0x00000e50 { 31:0 adr =3D> u32; } =20 - pub(super) NV_PFB_HSHUB_PCIE_FLUSH_SYSMEM_ADDR_HI(u32) @ Hshub0Base + = 0x00000e54 { + pub(super) NV_PFB_HSHUB_PCIE_FLUSH_SYSMEM_ADDR_HI(u32) @ 0x00000e54 { 19:0 adr; } =20 - pub(super) NV_PFB_HSHUB_EG_PCIE_FLUSH_SYSMEM_ADDR_LO(u32) @ Hshub0Base= + 0x000006c0 { + pub(super) NV_PFB_HSHUB_EG_PCIE_FLUSH_SYSMEM_ADDR_LO(u32) @ 0x000006c0= { 31:0 adr =3D> u32; } =20 - pub(super) NV_PFB_HSHUB_EG_PCIE_FLUSH_SYSMEM_ADDR_HI(u32) @ Hshub0Base= + 0x000006c4 { + pub(super) NV_PFB_HSHUB_EG_PCIE_FLUSH_SYSMEM_ADDR_HI(u32) @ 0x000006c4= { 19:0 adr; } } --=20 2.54.0 From nobody Sat Sep 26 12:29:12 2026 Received: from CWXP265CU009.outbound.protection.outlook.com (mail-ukwestazon11021101.outbound.protection.outlook.com [52.101.100.101]) (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 5190B48423C; Tue, 1 Sep 2026 16:50:56 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=52.101.100.101 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788281459; cv=fail; b=AJ+1Qc2ICrJiwcnvIMcG9ncEvA2/9blhRWAkCE0khm10KOy9KWYBGe+6kFSkfd5OrKx+gA+oSsqTVgfLFY/NeyTQCcSJmCfTsmTZg7yZVHz5zf6mD4Oi+exxC4+A2M574LG5T8hGDcA01AYojiWAmv+Ex9sJKhrLsJ/uFgG853Y= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788281459; c=relaxed/simple; bh=EgmvhMdvQOw5JTbtU7xFkmoqrywfFFVDzYf7+beRyFo=; h=From:Date:Subject:Content-Type:Message-Id:References:In-Reply-To: To:Cc:MIME-Version; b=pZgYuQLCtHqa/8OH/vQZAg5JIm5i5ATFLcP+AQiNyrr2wwSGYBG0qaXOciYiHzAkjWDU3f3RG8oE6I55JwsvNYKlNOMVFgRb8e1Hend2SeL6JVT/wiE1v5jryjkb0sIEhtkyPES8z0kq9BUCyRfjYoVBKv0aQBt6vGCfzjZyR5I= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=garyguo.net; spf=pass smtp.mailfrom=garyguo.net; dkim=pass (1024-bit key) header.d=garyguo.net header.i=@garyguo.net header.b=Asfp7F7u; arc=fail smtp.client-ip=52.101.100.101 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=garyguo.net Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=garyguo.net Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=garyguo.net header.i=@garyguo.net header.b="Asfp7F7u" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=gc46ajvOXY8clyEx7FmZUVn4bkOIt7ioMzLx2Qdq4PvxoHTd7tMhxiNT1gzgDnbAK7ih9UYvXNmPqIn7/opU69hvvHxUnPokjpc+qsxVjgOYrbYYvlUZ8XUcaXPdbrTCG5OFR4T3+0ZlD7xuSnGxlp7Tl4hh5hNjSOIer81S3vcNlLAs00gAxyQhmn48dTUCv6zwNium8mfltOukNV+Ukmeg/2Sc7lfigX02LV0+hdpa3AahhkcCBKVD4ApSvXcRXnG/3kOQmXrsIsG3IUgQd4x5ZdcuO01LcFl7gQpRaOtSS7NEWpmSXUtiT5YjJhiHfvc2/h4SA5gNr3usEXOe8Q== 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=EIYwGqR1b0tULxUdtc2vkU39s7/3YxvyPT/2aJFyp9Y=; b=V4vTS5BvH8lxS1rPmCpAPe7kLDoz3H6B/GdX01r3OiVWROI5I7+BVIApzpirpDCPRpNfYomfXJArswhSccqzEKhdy5Ddx+l4ozXnQmnG76adUGJPPW4j2nQiZ+8u6+SSdii8NPXTleDs/A3FbJV4NSB4RzN0DZ+pUWmUAJu6HUkDrxCKsHGyjsGn0OS/OBiEUMAcOEeK+KmXwjWk+lx621DP+cEd9UaJJKGudCFTd2iBKd0Vh82J3JTIZ0frYNYYcc+6WN+FgN3IOLNF802uUEE8sOXTNrsdg8pdTmtS/VuEc8XjQjDzq8wymTwF3D01QGxdTcAwjrpctxDYAsSaJQ== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=garyguo.net; dmarc=pass action=none header.from=garyguo.net; dkim=pass header.d=garyguo.net; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=garyguo.net; s=selector1; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=EIYwGqR1b0tULxUdtc2vkU39s7/3YxvyPT/2aJFyp9Y=; b=Asfp7F7ux0ozx6wnwVm3Icm14dQHYeUaHa+M1USKjMdPkw0AQOoPjdDXRoxUTC07NijJiSrvFCUiLB/BlloLeqfkR2VYHG2CTVa3jN3zXJFrI1/8ZAueEuPKmvKtmbs35AMuNAQE0SwJcvrCw0YgVZzEjHxA1+y1H5PwYni8WAI= Authentication-Results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=garyguo.net; Received: from LOAP265MB8560.GBRP265.PROD.OUTLOOK.COM (2603:10a6:600:4ab::19) by CW1P265MB9199.GBRP265.PROD.OUTLOOK.COM (2603:10a6:400:272::22) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.21.360.13; Tue, 1 Sep 2026 16:50:44 +0000 Received: from LOAP265MB8560.GBRP265.PROD.OUTLOOK.COM ([fe80::f60b:1537:68d7:4fc1]) by LOAP265MB8560.GBRP265.PROD.OUTLOOK.COM ([fe80::f60b:1537:68d7:4fc1%4]) with mapi id 15.21.0360.008; Tue, 1 Sep 2026 16:50:44 +0000 From: Gary Guo Date: Tue, 01 Sep 2026 17:50:38 +0100 Subject: [PATCH v4 14/16] rust: io: register: remove relative registers Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260901-typed_register-v4-14-5552b1d59525@garyguo.net> References: <20260901-typed_register-v4-0-5552b1d59525@garyguo.net> In-Reply-To: <20260901-typed_register-v4-0-5552b1d59525@garyguo.net> To: Danilo Krummrich , Alice Ryhl , Daniel Almeida , Miguel Ojeda , Boqun Feng , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Andreas Hindborg , Trevor Gross , Tamir Duberstein , Alexandre Courbot , =?utf-8?q?Onur_=C3=96zkan?= , David Airlie , Simona Vetter , Bjorn Helgaas , =?utf-8?q?Krzysztof_Wilczy=C5=84ski?= Cc: driver-core@lists.linux.dev, rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, nova-gpu@lists.linux.dev, dri-devel@lists.freedesktop.org, linux-pci@vger.kernel.org, Gary Guo X-Mailer: b4 0.15.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1788281431; l=22008; i=gary@garyguo.net; s=20221204; h=from:subject:message-id; bh=EgmvhMdvQOw5JTbtU7xFkmoqrywfFFVDzYf7+beRyFo=; b=oZxsc2PWzVVx9pCCFadGps1/t08LqzVAqCK9I2bq4QIy0bzHKRfu9ebIC/XmK2fU/lH1NXlTg 2ZvXlZLbSOWDWITRxiefMHBmlImZKDfs94s4//FwExFkTutBM4xF3Ja X-Developer-Key: i=gary@garyguo.net; a=ed25519; pk=vB3uIX95SM4eVrIqo1DWNWKDKD2xzB+yLLLr0yOPYMo= X-ClientProxiedBy: PAZP264CA0173.FRAP264.PROD.OUTLOOK.COM (2603:10a6:102:236::16) To LOAP265MB8560.GBRP265.PROD.OUTLOOK.COM (2603:10a6:600:4ab::19) 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: LOAP265MB8560:EE_|CW1P265MB9199:EE_ X-MS-Office365-Filtering-Correlation-Id: 8995a286-29e5-459f-60c2-08df08492a79 X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|1800799024|7416014|10070799003|376014|23010399003|366016|921020|3023799007|10067099003|56012099006|5023799004|22082099003|18002099003; X-Microsoft-Antispam-Message-Info: bIPnIc2b83OS1CsQwXDknFBAf4AooJD07kt/oSW+aTqvoxKlxL1kWblBU5StgLPyfv5QgpMv7KSmHAfEnqNreMLikY+WtgpaWw31uBfhLqu4mAOPmGetwqx9jKM6bd6Gg9zdxyX+42E2yW+9ZBXcqIEgoryx/yenq1I27TtH+zQnXQqzP1nAJRSCtpEfrn4XLsnS1aVR1Sn1Q5IfQpEsmYaMOUPdxYkbKP1xrsmUOS5D/ecb0J//pyqYj6Yksw0vbZ/wHQMDZhg2XWoG0X4QdMJVQ+3l0TdJOdll4+MrC0PKXowuScgv8DpbviFBrPw2NlumBVXsUPlSmwroCKFcMoYbQZZhYZtQQqSCz6MnLT0AfUDf++M4OB5swVGGFJ00RCTK+8KZNwyngWQYvDsMAkvPrneQLOiMs65RrQV9ffKzBW6+DBXZlYY8B6glwv+EOtn8GwFjQArpDe60wug7GtDHU2XKmRuq2qLM9joRQEOQy6R94To7mp3uB9SWAIpqektyOMRT4mgW/DyeiXJQ++II7vz7ErUk4wdPm9T+ympqVxZGNIMzKyjlZs7fven6PvlEUzBQZ94AgIAI299eEjIIOPDu3qBzTyj+EuG7mNtsHRrlKgaByoHrxm3hRc1Z4iLVXliJs5x4d3qq76ZDY4mph1d2DfwW9CL1vrJEX29mzpzaYCrkx+t3VfH9sq6H7xUJOOUFiGv0DVnNe0nRyw== X-Forefront-Antispam-Report: CIP:255.255.255.255;CTRY:;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:LOAP265MB8560.GBRP265.PROD.OUTLOOK.COM;PTR:;CAT:NONE;SFS:(13230040)(1800799024)(7416014)(10070799003)(376014)(23010399003)(366016)(921020)(3023799007)(10067099003)(56012099006)(5023799004)(22082099003)(18002099003);DIR:OUT;SFP:1102; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: =?utf-8?B?RkpLcEFoODNiUVZJQTN2UVBhbDdkSGhsQ0E1YkNKbFlhWUJ3UnZaYmRjYlJn?= =?utf-8?B?UkRVY1Zuc0NnaG5ReWZUV25YUmxma0RCZktWKzVNdFJwZGk0ZGVoVktVckRS?= =?utf-8?B?b2pyWmIxenVsKzJMbEFWY3U2WXZGa0NJZi9TeThZYWladk5lbHJqSFk5SU9t?= =?utf-8?B?cHlpSm9naFYvenZnTE1xU0FFK29BcG5sekM0NWxjNjdoV24xNEpzcHJPU2Vh?= =?utf-8?B?eTVERFRsT015TGxQd05DTG54djcyRU5xRm9wQUN0RWowL2RpaVJqTWJ2OXAx?= =?utf-8?B?K012WnJUd2s2Z2VzUm1PREJ1Mkxlc0xRK05GMldrNVNXZCt0Z2RBd0hCVi9h?= =?utf-8?B?TTZSSkNud2V5MUsxMU4ybnVYbU9kR29DeFJjYVhqQjlUc0JlSWxmMEZDZ1Vq?= =?utf-8?B?aTJVNVNuNmVCcEYzK2ZMcGszL1RySk13NGN6S3pFamp4TGQyU2pEOWpqbnJx?= =?utf-8?B?c3RheGpvZnZCNlkyblltR3dpdDA3VWx3OUJXU3l2cFIvWHZaMUxIc1VhRzlx?= =?utf-8?B?a3BwWm01N2loLy8wbHliQmlyanRGMWVEZGROZytKaVdvNmhsb2N5OWRuRXpH?= =?utf-8?B?eHNNY2RLdUtiSUs5blJXNWx6THdmZFprbHp2UXJZRDlvMENySlNOQ1haUGlK?= =?utf-8?B?TFZQTU5DWTAxV0lMc2FBVG84MWpBL3ZQUkpGeGpkcHZKZ2o5MXVHSi9EODNq?= =?utf-8?B?K2dmbzh0TzRzRzJjMmpNUnAySzVaT2NVVTR5VjhteldDQnV0SjJSL0N4bVdt?= =?utf-8?B?amU3L1lNclBxcXprNGpDYnlySFBDSzFsU2o1c0kxL1ppeGhzQkgzZ3I5THdr?= =?utf-8?B?T252dXQzVzd2VDVYeUFxdmJBVWpNR0FuZnppa3JWK1NZNnk5VWprVmtuaXRi?= =?utf-8?B?Z0RZSjFpY3BZdWxPWjVpVHJlWnEvNTJMNlRsYllwU1FpTlFpVUpueSt0ZjN2?= =?utf-8?B?OGhMeEllQ2RIekxJa1hiaW9LbUZ6ZzU2ZlBndXRabEpTN2pwZEtQNE1aNG9H?= =?utf-8?B?LzdGVVMwVVQzYjR4bDZ2VG9OQ2FQRkV0cDRyZGhVeklTTWpQcWJXQVByaVRh?= =?utf-8?B?alp6ZFRhMTVJdHhINUtFYW9ENDhjMDJLdDZPdi9zeG0wV0M5UlcxeHBWT2FZ?= =?utf-8?B?TFZRT1ZIQWhLNUVEV1BCc2R5emk0bTNOWXdUNTZRNGpiMmlYNDJGWHF1V2NT?= =?utf-8?B?ZzI2M0VZQkgvWEE2T0RlMjIyME1oM2N2STBNWFhsc1h5clVNKytxRDVSSDVP?= =?utf-8?B?V0VsTXBoUGJSRHlvenlIam4zeG44Q2dNRzBPcDNoWDBDUnhlSjRJVzVhMkIw?= =?utf-8?B?NWdIWmZDVVlHVkpoeEl3c1dBZ3F4VVVxK0ZkcFZsRDBiZHlCMUxQR3BZS1dl?= =?utf-8?B?UFlSU3ZvTHlvRENOR1FXbCtYRWZTZE1NRjNYMTBTS1pMNldvNVNiMHRHTE5x?= =?utf-8?B?RGNZMWUzSDgzTTQrcHplZVhLdnZwRytmVHVmRnc2a3J4eGdBck9YSzhSZVNp?= =?utf-8?B?NWUrU1ozbGtwZXpWaVVGRXZIM1ovb0QxeDZ3R285bS9CN2VGQ3RHUm94d0hF?= =?utf-8?B?VVpGb1o4emkrdnlvTGU0VzlsWDk1VE0xUlJPRDVqVU5GZnpyVEpmU3BnaVA0?= =?utf-8?B?dmRJNGIwUXRxbCt3UWlHNWdBcDcxQThrMENPMFhkRWhxZTZ3YzVsRTgxTDhW?= =?utf-8?B?M003Zm5Sc2JhVHJwYUNMQW5PYjVxdEFLdDFWLzBJTVZGSW5XakNCY2w2SkVy?= =?utf-8?B?aWx3ZXdUTElLWTV5ZWY4ejNOTXpiTjdoeVI5NHFwcnU0djU2SzRrTmxZSVN6?= =?utf-8?B?bnlyd3IyVGF3OVhKTzhpU1VXMjZtcXN3M2ZMQ0FmZEFrTGE4RG03L1ZWT2w4?= =?utf-8?B?ZG1BTGpmRDZYdkM1UW1mbjJZV2hlc1hzSTlHQ3ZaVi9WMXpsU0RBVEdKL05T?= =?utf-8?B?b1JOTk10ZkFPQVdMZ1RGdFVJODlsZGx5OWlISTJBWXVsVEFsU2RzL1YwckZS?= =?utf-8?B?VUdIcHZJZnhTTmYvMU1rZldSbEJGbUd6MllFUW5RdHJmcWZ1MEJxZlpKUDg5?= =?utf-8?B?SzZmenpVc2U3UnJCMW9VQ0N3TlNhT3JId28zTS9TamRhMVZRNDJvLzhCVnhr?= =?utf-8?B?OWloZ29LaHZsY1F3UkNNS3U3UUsyaGpGMlBxVSt5R3JJMFVHeFBjVkZhbGpJ?= =?utf-8?B?ZFZjNFdCUzQ4aHczMnZaZUN3OHNiY3A0WHBuU1lsbndpVGNTTkpvMGhMMThs?= =?utf-8?B?T29zM2RCUzVIWjNqVk1sb1NZclE0L01NTEFKZ0NZdWozM2lrLysvTlBhZ3o0?= =?utf-8?B?emc0Zmw3OG1xT1NSeW5FZzlZRkZJL0cxdzBGc2dGZStBSFp5VWhsQT09?= X-OriginatorOrg: garyguo.net X-MS-Exchange-CrossTenant-Network-Message-Id: 8995a286-29e5-459f-60c2-08df08492a79 X-MS-Exchange-CrossTenant-AuthSource: LOAP265MB8560.GBRP265.PROD.OUTLOOK.COM X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 01 Sep 2026 16:50:44.9043 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: bbc898ad-b10f-4e10-8552-d9377b823d45 X-MS-Exchange-CrossTenant-MailboxType: HOSTED X-MS-Exchange-CrossTenant-UserPrincipalName: q4peWSYrwooq2kmUV1tQFBdp65pLnusQxSTWzlw/Oq3kmL/o7RRROE7lpA0NTy7fnfdazT/YcG6DgaGdtifBQA== X-MS-Exchange-Transport-CrossTenantHeadersStamped: CW1P265MB9199 Relative registers can be better served by projection to subregion instead of ad-hoc handling in register macro. Projection composes better (e.g. it natively allows relative registers of relative registers without needing additional support). Remove relative register support, and update the documentation to demonstrate how projection and subregions can be used to achieve this instead. Reviewed-by: Alexandre Courbot Signed-off-by: Gary Guo Acked-by: Miguel Ojeda Tested-by: Alexandre Courbot --- rust/kernel/io/register.rs | 388 ++++++-----------------------------------= ---- rust/macros/io/register.rs | 52 ++---- 2 files changed, 61 insertions(+), 379 deletions(-) diff --git a/rust/kernel/io/register.rs b/rust/kernel/io/register.rs index b9cb4fce8628..187f28f16614 100644 --- a/rust/kernel/io/register.rs +++ b/rust/kernel/io/register.rs @@ -8,7 +8,7 @@ //! //! Note: most of the items in this module are public so they can be refer= enced by the macro, but //! most are not to be used directly by users. Outside of the `register!` = macro itself, the only -//! items you might want to import from this module are [`WithBase`] and [= `Array`]. +//! item you might want to import from this module is [`Array`]. //! //! # Simple example //! @@ -200,76 +200,6 @@ fn offset(self) -> usize { } } =20 -/// Trait providing a base address to be added to the offset of a relative= register to obtain -/// its actual offset. -/// -/// The `T` generic argument is used to distinguish which base to use, in = case a type provides -/// several bases. It is given to the `register!` macro to restrict the us= e of the register to -/// implementors of this particular variant. -pub trait RegisterBase { - /// Base address to which register offsets are added. - const BASE: usize; -} - -/// Trait implemented by all registers that are relative to a base. -pub trait WithBase { - /// Family of bases applicable to this register. - type BaseFamily; - - /// Returns the absolute location of this type when using `B` as its b= ase. - #[inline(always)] - fn of>() -> RelativeRegisterLoc - where - Self: Register, - { - RelativeRegisterLoc::new() - } -} - -/// Trait implemented by relative registers. -pub trait RelativeRegister: Register + WithBase {} - -/// Location of a relative register. -/// -/// This can either be an immediately accessible regular [`RelativeRegiste= r`], or a -/// [`RelativeRegisterArray`] that needs one additional resolution through -/// [`RelativeRegisterLoc::at`]. -pub struct RelativeRegisterLoc(PhantomData, Pha= ntomData); - -impl RelativeRegisterLoc -where - T: Register + WithBase, - B: RegisterBase + ?Sized, -{ - /// Returns the location of a relative register or register array. - #[inline(always)] - // We do not implement `Default` so we can be const. - #[expect(clippy::new_without_default)] - pub const fn new() -> Self { - Self(PhantomData, PhantomData) - } - - // Returns the absolute offset of the relative register using base `B`. - // - // This is implemented as a private const method so it can be reused b= y the [`IoLoc`] - // implementations of both [`RelativeRegisterLoc`] and [`RelativeRegis= terArrayLoc`]. - #[inline] - const fn offset(self) -> usize { - B::BASE + T::OFFSET - } -} - -impl IoLoc for RelativeRegisterLoc<= T, B> -where - T: RelativeRegister, - B: RegisterBase + ?Sized, -{ - #[inline(always)] - fn offset(self) -> usize { - RelativeRegisterLoc::offset(self) - } -} - /// Trait implemented by arrays of registers. pub trait RegisterArray: Register { /// Number of elements in the registers array. @@ -332,71 +262,6 @@ fn try_at(idx: usize) -> Option> } } =20 -/// Trait implemented by arrays of relative registers. -pub trait RelativeRegisterArray: RegisterArray + WithBase {} - -/// Location of a relative array register. -pub struct RelativeRegisterArrayLoc< - T: RelativeRegisterArray, - B: RegisterBase + ?Sized, ->(RelativeRegisterLoc, usize); - -impl RelativeRegisterArrayLoc -where - T: RelativeRegisterArray, - B: RegisterBase + ?Sized, -{ - /// Returns the location of register `T` from the base `B` at index `i= dx`, with build-time - /// validation. - #[inline(always)] - pub fn new(idx: usize) -> Self { - build_assert!(idx < T::SIZE); - - Self(RelativeRegisterLoc::new(), idx) - } - - /// Attempts to return the location of register `T` from the base `B` = at index `idx`, with - /// runtime validation. - #[inline(always)] - pub fn try_new(idx: usize) -> Option { - if idx < T::SIZE { - Some(Self(RelativeRegisterLoc::new(), idx)) - } else { - None - } - } -} - -/// Methods exclusive to [`RelativeRegisterLoc`]s created with a [`Relativ= eRegisterArray`]. -impl RelativeRegisterLoc -where - T: RelativeRegisterArray, - B: RegisterBase + ?Sized, -{ - /// Returns the location of the register at position `idx`, with build= -time validation. - #[inline(always)] - pub fn at(self, idx: usize) -> RelativeRegisterArrayLoc { - RelativeRegisterArrayLoc::new(idx) - } - - /// Returns the location of the register at position `idx`, with runti= me validation. - #[inline(always)] - pub fn try_at(self, idx: usize) -> Option> { - RelativeRegisterArrayLoc::try_new(idx) - } -} - -impl IoLoc for RelativeRegisterArra= yLoc -where - T: RelativeRegisterArray, - B: RegisterBase + ?Sized, -{ - #[inline(always)] - fn offset(self) -> usize { - self.0.offset() + self.1 * T::STRIDE - } -} - /// Trait implemented by items that contain both a register value and the = absolute I/O location at /// which to write it. /// @@ -452,8 +317,7 @@ pub const fn element_alias_offset+------------CPU0-------------+ -/// | | -/// 0x110--->+-----------------------------+ -/// | CPU_CTL | -/// +-----------------------------+ -/// | ... | -/// | | -/// | | -/// 0x200--->+------------CPU1-------------+ -/// | | -/// 0x210--->+-----------------------------+ -/// | CPU_CTL | -/// +-----------------------------+ -/// | ... | -/// +-----------------------------+ -/// ``` -/// -/// `CPU0` and `CPU1` both have a `CPU_CTL` register that starts at offset= `0x10` of their I/O -/// space segment. Since both instances of `CPU_CTL` share the same layout= , we don't want to define -/// them twice and would prefer a way to select which one to use from a si= ngle definition. -/// -/// This can be done using the `Base + Offset` syntax when specifying the = register's address: -/// -/// ```ignore -/// register! { -/// ... -/// pub RELATIVE_REG(u32) @ Base + 0x80 { -/// ... -/// } -/// } -/// ``` -/// -/// This creates a register with an offset of `0x80` from a given base. -/// -/// `Base` is an arbitrary type (typically a ZST) to be used as a generic = parameter of the -/// [`RegisterBase`] trait to provide the base as a constant, i.e. each ty= pe providing a base for -/// this register needs to implement `RegisterBase`. -/// -/// The location of relative registers can be built using the [`WithBase::= of`] method to specify -/// its base. All relative registers implement [`WithBase`]. -/// -/// Here is the above layout translated into code: -/// -/// ```no_run -/// use kernel::{ -/// io::{ -/// register, -/// register::{ -/// RegisterBase, -/// WithBase, -/// }, -/// Io, -/// Region, -/// }, -/// }; -/// # use kernel::io::Mmio; -/// -/// // Type used to identify the base. -/// pub struct CpuCtlBase; -/// -/// // ZST describing `CPU0`. -/// struct Cpu0; -/// impl RegisterBase for Cpu0 { -/// const BASE: usize =3D 0x100; -/// } -/// -/// // ZST describing `CPU1`. -/// struct Cpu1; -/// impl RegisterBase for Cpu1 { -/// const BASE: usize =3D 0x200; -/// } -/// -/// // This makes `CPU_CTL` accessible from all implementors of `RegisterB= ase`. -/// register! { -/// base: Region<0x1000>; -/// -/// /// CPU core control. -/// pub CPU_CTL(u32) @ CpuCtlBase + 0x10 { -/// 0:0 start; -/// } -/// } -/// -/// # fn test(io: Mmio<'_, Region<0x1000>>) { -/// // Read the status of `Cpu0`. -/// let cpu0_started =3D io.read(CPU_CTL::of::()); -/// -/// // Stop `Cpu0`. -/// io.write(WithBase::of::(), CPU_CTL::zeroed()); -/// # } -/// -/// // Aliases can also be defined for relative register. -/// register! { -/// base: Region<0x1000>; -/// -/// /// Alias to CPU core control. -/// pub CPU_CTL_ALIAS(u32) =3D> CpuCtlBase + CPU_CTL { -/// /// Start the aliased CPU core. -/// 1:1 alias_start; -/// } -/// } -/// -/// # fn test2(io: Mmio<'_, Region<0x1000>>) { -/// // Start the aliased `CPU0`, leaving its other fields untouched. -/// io.update(CPU_CTL_ALIAS::of::(), |r| r.with_alias_start(true)); -/// # } -/// ``` -/// /// ## Arrays of registers /// /// Some I/O areas contain consecutive registers that share the same field= layout. These areas can @@ -763,115 +511,83 @@ pub const fn element_alias_offset+------------CPU0-------------+ +/// | | +/// 0x110--->+-----------------------------+ +/// | CPU_CTL | +/// +-----------------------------+ +/// | ... | +/// | | +/// | | +/// 0x200--->+------------CPU1-------------+ +/// | | +/// 0x210--->+-----------------------------+ +/// | CPU_CTL | +/// +-----------------------------+ +/// | ... | +/// +-----------------------------+ /// ``` /// -/// Like relative registers, they implement the [`WithBase`] trait. Howeve= r the return value of -/// [`WithBase::of`] cannot be used directly as a location and must be fur= ther specified using the -/// [`at`](RelativeRegisterLoc::at) method. +/// `CPU0` and `CPU1` both have a `CPU_CTL` register that starts at offset= `0x10` of their I/O +/// space segment. Since both instances of `CPU_CTL` share the same layout= , we don't want to define +/// them twice and would prefer a way to select which one to use from a si= ngle definition. +/// +/// This can be done by defining a new type for the subregion, and then de= fining registers that use +/// the new type as the base: /// /// ```no_run /// use kernel::{ /// io::{ +/// io_project, /// register, -/// register::{ -/// RegisterBase, -/// WithBase, -/// }, /// Io, /// Region, /// }, /// }; /// # use kernel::io::Mmio; -/// # fn get_scratch_idx() -> usize { -/// # 0x15 -/// # } -/// -/// // Type used as parameter of `RegisterBase` to specify the base. -/// pub struct CpuCtlBase; /// -/// // ZST describing `CPU0`. -/// struct Cpu0; -/// impl RegisterBase for Cpu0 { -/// const BASE: usize =3D 0x100; -/// } +/// // Subregion type. Make sure it has adequate size and alignment. +/// #[repr(align(4))] +/// #[derive(FromBytes, IntoBytes)] +/// pub struct CpuCtl([u8; 0x100]); /// -/// // ZST describing `CPU1`. -/// struct Cpu1; -/// impl RegisterBase for Cpu1 { -/// const BASE: usize =3D 0x200; -/// } -/// -/// // 64 per-cpu scratch registers, arranged as a contiguous array. /// register! { /// base: Region<0x1000>; /// -/// /// Per-CPU scratch registers. -/// pub CPU_SCRATCH(u32)[64] @ CpuCtlBase + 0x00000080 { -/// 31:0 value; -/// } +/// // Subregions can just be defined like normal registers. +/// CPU0: CpuCtl @ 0x100; +/// CPU1: CpuCtl @ 0x200; /// } /// -/// # fn test(io: Mmio<'_, Region<0x1000>>) -> Result<(), Error> { -/// // Read scratch register 0 of CPU0. -/// let scratch =3D io.read(CPU_SCRATCH::of::().at(0)); -/// -/// // Write the retrieved value into scratch register 15 of CPU1. -/// io.write(WithBase::of::().at(15), scratch); -/// -/// // This won't build. -/// // let cpu0_scratch_128 =3D io.read(CPU_SCRATCH::of::().at(128))= .value(); -/// -/// // Runtime-obtained array index. -/// let scratch_idx =3D get_scratch_idx(); -/// // Access on a runtime index returns an error if it is out-of-bounds. -/// let cpu0_scratch =3D io.read( -/// CPU_SCRATCH::of::().try_at(scratch_idx).ok_or(EINVAL)? -/// ).value(); -/// # Ok(()) -/// # } -/// -/// // Alias to `SCRATCH[8]` used to convey the firmware exit code. +/// // Then you can define new registers on the subregion. /// register! { -/// base: Region<0x1000>; +/// base: CpuCtl; /// -/// /// Per-CPU firmware exit status code. -/// pub CPU_FIRMWARE_STATUS(u32) =3D> CpuCtlBase + CPU_SCRATCH[8] { -/// 7:0 status; +/// /// CPU core control. +/// pub CPU_CTL(u32) @ 0x10 { +/// 0:0 start; /// } /// } /// -/// // Non-contiguous relative register arrays can be defined by adding a = stride parameter. -/// // Here, each of the 16 registers of the array is separated by 8 bytes= , meaning that the -/// // registers of the two declarations below are interleaved. -/// register! { -/// base: Region<0x1000>; -/// -/// /// Scratch registers bank 0. -/// pub CPU_SCRATCH_INTERLEAVED_0(u32)[16, stride =3D 8] @ CpuCtlBase = + 0x00000d00 { -/// 31:0 value; -/// } -/// -/// /// Scratch registers bank 1. -/// pub CPU_SCRATCH_INTERLEAVED_1(u32)[16, stride =3D 8] @ CpuCtlBase = + 0x00000d04 { -/// 31:0 value; -/// } -/// } +/// # fn test(io: Mmio<'_, Region<0x1000>>) { +/// // Read the status of `Cpu0`. +/// let cpu0_started =3D io_project!(io, build: CPU0).read(CPU_CTL); /// -/// # fn test2(io: Mmio<'_, Region<0x1000>>) -> Result<(), Error> { -/// let cpu0_status =3D io.read(CPU_FIRMWARE_STATUS::of::()).status(= ); -/// # Ok(()) +/// // Stop `Cpu0`. +/// io_project!(io, build: CPU0).write_reg(CPU_CTL::zeroed()); /// # } /// ``` #[macro_export] diff --git a/rust/macros/io/register.rs b/rust/macros/io/register.rs index b3262e9c06a1..6da8ba760ab3 100644 --- a/rust/macros/io/register.rs +++ b/rust/macros/io/register.rs @@ -65,7 +65,6 @@ struct Reg { name: Ident, ty: Type, array: Option, - relative_base: Option, offset: RegOffset, bitfield: Option<(Type, Group)>, } @@ -110,26 +109,15 @@ fn parse(input: syn::parse::ParseStream<'_>) -> Resul= t { =20 // Parse offset and the base it's relative to. let lh =3D input.lookahead1(); - let mut relative_base =3D None; let offset =3D if lh.peek(Token![@]) { let _: Token![@] =3D input.parse()?; =20 - if input.peek(Ident) { - relative_base =3D Some(input.parse()?); - let _: Token![+] =3D input.parse()?; - } - RegOffset::Fixed { offset: input.parse()?, } } else if lh.peek(Token![=3D>]) { let _: Token![=3D>] =3D input.parse()?; - let mut alias: Path =3D input.parse()?; - if input.peek(Token![+]) { - let _: Token![+] =3D input.parse()?; - relative_base =3D Some(alias); - alias =3D input.parse()?; - } + let alias: Path =3D input.parse()?; =20 if input.peek(token::Bracket) { let content; @@ -164,7 +152,6 @@ fn parse(input: syn::parse::ParseStream<'_>) -> Result<= Self> { name, ty, array, - relative_base, offset, bitfield, }) @@ -208,7 +195,6 @@ pub(crate) fn register(def: RegDef) -> Result { name, ty, array, - relative_base, offset, bitfield, } =3D reg; @@ -248,7 +234,7 @@ impl ::kernel::io::register::Register for #name { } =20 match array { - None if bitfield.is_none() && relative_base.is_none() =3D> out= puts.extend(quote!( + None if bitfield.is_none() =3D> outputs.extend(quote!( #(#attrs)* #vis const #name: ::kernel::io::register::Offse= tLoc<#base, #ty> =3D ::kernel::io::register::OffsetLoc::new(#offset); )), @@ -258,21 +244,12 @@ impl ::kernel::io::register::Register for #name { "defining without bitfield is not yet supported for this t= ype of register", ))?, =20 - None =3D> match relative_base { - None =3D> outputs.extend(quote_spanned!(span =3D> - impl ::kernel::io::register::FixedRegister for #name {} - - #(#attrs)* #vis const #name: ::kernel::io::register::F= ixedRegisterLoc<#name> =3D - ::kernel::io::register::FixedRegisterLoc::<#name>:= :new(); - )), - Some(relative_base) =3D> outputs.extend(quote_spanned!(spa= n =3D> - impl ::kernel::io::register::WithBase for #name { - type BaseFamily =3D #relative_base; - } + None =3D> outputs.extend(quote_spanned!(span =3D> + impl ::kernel::io::register::FixedRegister for #name {} =20 - impl ::kernel::io::register::RelativeRegister for #nam= e {} - )), - }, + #(#attrs)* #vis const #name: ::kernel::io::register::Fixed= RegisterLoc<#name> =3D + ::kernel::io::register::FixedRegisterLoc::<#name>::new= (); + )), =20 Some(def) =3D> { let size =3D &def.size; @@ -288,24 +265,13 @@ impl ::kernel::io::register::RelativeRegister for #na= me {} }; =20 outputs.extend(quote_spanned!(span =3D> + impl ::kernel::io::register::Array for #name {} + impl ::kernel::io::register::RegisterArray for #name { const SIZE: usize =3D #size; const STRIDE: usize =3D #stride; } )); - - match relative_base { - None =3D> outputs.extend(quote_spanned!(span =3D> - impl ::kernel::io::register::Array for #name {} - )), - Some(relative_base) =3D> outputs.extend(quote_spanned!= (span =3D> - impl ::kernel::io::register::WithBase for #name { - type BaseFamily =3D #relative_base; - } - - impl ::kernel::io::register::RelativeRegisterArray= for #name {} - )), - } } }; } --=20 2.54.0 From nobody Sat Sep 26 12:29:12 2026 Received: from CWXP265CU008.outbound.protection.outlook.com (mail-ukwestazon11020105.outbound.protection.outlook.com [52.101.195.105]) (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 9934848CD57; Tue, 1 Sep 2026 16:50:56 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=52.101.195.105 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788281459; cv=fail; b=dO+z4VbjGPXnVrennIcJ/2QqdIFA0m1jkxEn/XmZqj1Ycs3RP8kTnxKEfl8Qr0kMCUXaUAN34CnBQl3Kp7/nasQ+ttdelusIogVfHcu2OSosoMak1JPKxwX1KVyD/DbR6BzlYujzpmF9ilMHgsVad0EpHG2EgYrYkOt1uPciqBM= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788281459; c=relaxed/simple; bh=WYaIyKcKO7QIC+sRD6g+xJ/UsiWjwb+9Ba3XtN9t9SA=; h=From:Date:Subject:Content-Type:Message-Id:References:In-Reply-To: To:Cc:MIME-Version; b=qJDGP95YEecJDfSx99S1S3ntpA25rjCtagVl0JhBtxzANKOcLcENP5SULHwTnCxK6Kx/dx5mB038Padxbw//37ynTSQ6EjBAQLT5swM8aDkhQl7CeVBt1HqLbgzGdi9ZV7Ze8xXTh7jA1AZcOXXt36p2xak+uHrj1p4SjY1z1HM= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=garyguo.net; spf=pass smtp.mailfrom=garyguo.net; dkim=pass (1024-bit key) header.d=garyguo.net header.i=@garyguo.net header.b=DDSRe6hF; arc=fail smtp.client-ip=52.101.195.105 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=garyguo.net Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=garyguo.net Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=garyguo.net header.i=@garyguo.net header.b="DDSRe6hF" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=Ci+4wYXnK7YWsGF+WFBeF2HrzlkTxy/XoncFzOX0saPdS+jXm7+/+W6W6lj8WMxotO+z7pm+zuAZkOpxlc/8Otgg4+2H0QUF9RV8qXejhdnYJwHufxuRN29Wj9R1Jf0EgIwZGsoL/8bld2/efxImoE4AzaWYevc6uw/B7XQkQJekOY0IVpo/Cp0jpIYlfXtEr7sdCl+ys7FyEJuami1oH/c4rZO5engBD8jqPChqu++m02V0SWu9ErN1s9TDLuvUQ7xJvmjy5ztyiQMWBvj2QN7lQAkBBJK0WzliIgDscGlCMRS4zJL/EhtHAwZqB1o/TUz5OIR7wk4h+vi41DZpJw== 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=Y5e3CEs1asxsaI1dtRmvhvQTfPV88eNjosHxKRSKS2c=; b=U1asrZq19OxchenynooGAXKnlhdBN/7tLlXTBWuYg6MictZ8e0GZpeq2SGeAEMNb35N098wwLz/faMy924F0ByjgJiB3HRm1wbGGYObZPKhR9qhrvZ3n98F3/qDm+nXmXloDIQzy5ntUVnDTEZNsSLFMsPhVqeUcp5YjqxQicXcUZ5j61dT1rHk//lI2x091CL/ytIprjIDbn+DqOZAreoXOFfY9RqcBD1mtlJaWYNWmn7ED+YSMlk/n3w49W3BM9NahxzoUxWyF6vqblNPzMq3S4RIub7Sp9fnP1sdlobFhF1cDZrqERQaNGmY8zLdjQtocSZY+xXPfbtltnk5tJA== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=garyguo.net; dmarc=pass action=none header.from=garyguo.net; dkim=pass header.d=garyguo.net; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=garyguo.net; s=selector1; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=Y5e3CEs1asxsaI1dtRmvhvQTfPV88eNjosHxKRSKS2c=; b=DDSRe6hFyY6gnulNm4+fLrDuaVTLrXfyi9ZGm98sYhOM2MJncZiy9zcieVcQCVTV5QI0CH41uYJx4HRS8+VEP64IMzu3Bve1eBpYuQFdw9kclU4acnw2J/eqUp0mTLmElwdEXLXF5fXgKSFTocNfJ3ya+HOzcRFbGRPWI4keUrs= Authentication-Results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=garyguo.net; Received: from LOAP265MB8560.GBRP265.PROD.OUTLOOK.COM (2603:10a6:600:4ab::19) by CW1P265MB9199.GBRP265.PROD.OUTLOOK.COM (2603:10a6:400:272::22) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.21.360.13; Tue, 1 Sep 2026 16:50:45 +0000 Received: from LOAP265MB8560.GBRP265.PROD.OUTLOOK.COM ([fe80::f60b:1537:68d7:4fc1]) by LOAP265MB8560.GBRP265.PROD.OUTLOOK.COM ([fe80::f60b:1537:68d7:4fc1%4]) with mapi id 15.21.0360.008; Tue, 1 Sep 2026 16:50:45 +0000 From: Gary Guo Date: Tue, 01 Sep 2026 17:50:39 +0100 Subject: [PATCH v4 15/16] rust: io: register: remove `Register` trait and cleanup macro Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260901-typed_register-v4-15-5552b1d59525@garyguo.net> References: <20260901-typed_register-v4-0-5552b1d59525@garyguo.net> In-Reply-To: <20260901-typed_register-v4-0-5552b1d59525@garyguo.net> To: Danilo Krummrich , Alice Ryhl , Daniel Almeida , Miguel Ojeda , Boqun Feng , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Andreas Hindborg , Trevor Gross , Tamir Duberstein , Alexandre Courbot , =?utf-8?q?Onur_=C3=96zkan?= , David Airlie , Simona Vetter , Bjorn Helgaas , =?utf-8?q?Krzysztof_Wilczy=C5=84ski?= Cc: driver-core@lists.linux.dev, rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, nova-gpu@lists.linux.dev, dri-devel@lists.freedesktop.org, linux-pci@vger.kernel.org, Gary Guo X-Mailer: b4 0.15.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1788281431; l=4357; i=gary@garyguo.net; s=20221204; h=from:subject:message-id; bh=WYaIyKcKO7QIC+sRD6g+xJ/UsiWjwb+9Ba3XtN9t9SA=; b=kQ1Ppeib3fjkA+kvY3Yh93wcYlMXX6Hu6J3xokdF8eyxYx1xvwXCaMpVBCG69W4fKhKNCnAbB 3Cl66orN8enD1SnFWXqtWzXdSGlwshOGyT2CtHd1NiYEoc8f/mBJs/1 X-Developer-Key: i=gary@garyguo.net; a=ed25519; pk=vB3uIX95SM4eVrIqo1DWNWKDKD2xzB+yLLLr0yOPYMo= X-ClientProxiedBy: PAZP264CA0173.FRAP264.PROD.OUTLOOK.COM (2603:10a6:102:236::16) To LOAP265MB8560.GBRP265.PROD.OUTLOOK.COM (2603:10a6:600:4ab::19) 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: LOAP265MB8560:EE_|CW1P265MB9199:EE_ X-MS-Office365-Filtering-Correlation-Id: 5708527c-148e-4ece-12a3-08df08492af6 X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|1800799024|7416014|10070799003|376014|23010399003|366016|921020|3023799007|10067099003|56012099006|5023799004|22082099003|18002099003; X-Microsoft-Antispam-Message-Info: bzcs8I6o8nzyCxAzCCYJwrYnpTncf/gYht+PPdfN9a0lBWTqaNJYq423zyu2yr0KdnrF7pupQdBESvCxjhaHO7zHoDUncjkzNLIFdmLSpbZKRMToFIfcOo3OdwCS7wP4Z0Jr0wlFXKgLlp+nghey5u7DFfP6sWVS50X6XIXyLptev9jgbdAlQOwOhXHCUUtPSMcIVX9glMiCPTuKDiFmzssfmPSpcuZ+BnHChA5JKBXcjV9M/2VXgD0IqvapUqWnR6wi9EsJx0HaHBHzovNtHBTdeyVkfmNBjj9ZVE/cAjArwXGF/YzCeqdIxeKjEuqgYORi+Y9Diq11hSB0uWWOcli+m6ZJ2kyfK5DDEdCGJQR17ZcPb/RAVcgEnNH9A/fcOAicacO+/Y2F+q6jmt2lGB9x9p7V1nl7IgmSd8dyggA5449cKMXOuKi5+14uNtDm8pC+fjUJxXWpPlCxPiaeCZqa81fwHBYTZLPX1caH7DBFq7fnBlJMGgwhFpDMCFC9uJ1rZZOnVJn5/VF377BF3XUwLeuQwPui5TedmSXltGPE83S+npmD/iUb5MpruVC6/UOmnAz0FxHhbzWlepdIUGQLqeuXsjj4Ffe9eAgb+oSUTCu37VXhuI0Aa1v95+7wVI1FuIndq95I/jZlb3wWu+H94qrpcWdCG8OfRGx4dkUBeF0u1hkK8OeYe/skUsedKI/WPry1JbCZpQV731fKzQ== X-Forefront-Antispam-Report: CIP:255.255.255.255;CTRY:;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:LOAP265MB8560.GBRP265.PROD.OUTLOOK.COM;PTR:;CAT:NONE;SFS:(13230040)(1800799024)(7416014)(10070799003)(376014)(23010399003)(366016)(921020)(3023799007)(10067099003)(56012099006)(5023799004)(22082099003)(18002099003);DIR:OUT;SFP:1102; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: =?utf-8?B?amx6YVBPWWp6SmFjUjNTT1FaTlV2Uit1dnVZNlpjTnBvMlNvZENOcG95aUxk?= =?utf-8?B?YkpwUytHS0RSeGR6U0Q3anhOZDZRV1Vjd0ZOaWhrZXNZOXlJMDFVTURpcEZJ?= =?utf-8?B?cGpEWllTYzM4SmJmNWVBT2M0d01vNExneXQzZXB3QUFSc0p2RG51WGVOR0Ft?= =?utf-8?B?WU8vaFp1VVpzUExjTitXZzY5elBRYmJqOTNkbzU2Wk5FTXBaRFBPdmZuTHhs?= =?utf-8?B?cE1jWkVJeTg1SjAyaURGSDQ2WldJUEUwT005dVBDTmFLUytFdUd6aU1QQ0dD?= =?utf-8?B?bER2S2lIbStYeDZhTm1VOWUxYmlqR21mUG0xY2RCUkJVQ0N5MXpqN1IzWkJ4?= =?utf-8?B?MFh0Vmdpd2hSQjB0UzdXOVM3Qzlpa29hQUttZzZzRWRVWEFUaWgyWDUxUnpP?= =?utf-8?B?V1Y1dFpPYktrUHg1NlE5RmFWOWhxU3czbEpFUDN2dW12Tldoa2tBNzVhYTVo?= =?utf-8?B?SWFhc1EydFRSQlpZVUt6c0dtVXNwc1ZLSmdkaFZUUkliOHBUVGFiOXZTUGFU?= =?utf-8?B?WkJxc08yM3hUR1N6VEEzVGZxQVJBSXpnempvTHBYd3orYjNUQWVTdlBnakhs?= =?utf-8?B?MDhXV0cwOGpySm5zQktTZXZ2K2ZaUVVXekhjMGxINFhBemovRTJRTlZWdEJa?= =?utf-8?B?M1Z1S1lTQlQydzgzdEdTVHpPbk5BbS9ZU1gvb1IxRDlPaFNUSUVRZlBiYlpn?= =?utf-8?B?c1c0bVB4eVFIbGlwSWxPZDNMQWtzOUdybUpYQ0JjRi9FU3kyaTNRMVpNbzFm?= =?utf-8?B?Sm5QQW1vSkVib2dWWGdXMnJuWUlpYmp5UW5iN3FwKzdIU2RoN1dyOHhvQys2?= =?utf-8?B?MjVMT1gwN0tqSU9NV3ZwSVg1S281aERBcXA2NkQrWUErYmtuY09EUTZSamVk?= =?utf-8?B?SlJ1MjMwMjJSenpGdVhNQlR3U3JURlRrdGo1SDBkY3hzTGNRT000aTNtalgr?= =?utf-8?B?VlVTb1BGUDVwZEJkc2hpbDdKUnV2YUxsYmF1d0pDNzI1b3JpR3lrTHcxT0Vi?= =?utf-8?B?dVUwVStZOWFTNmQxb1ladlBQZXQydGQxUFBvSjhiaEVVb0ZOYkcxeFUwYXFE?= =?utf-8?B?bE01K3F3VnMxRnpkT25yR1hMQm12YUZicTJ2Y3Y0SWlnR1BVN3pnS0ljL1Zk?= =?utf-8?B?clAyTUZWK3ZURTZWZ3RQdm83Q21EeWJrUlhXNTNiN0hmT3N3bldLcUVNcWJJ?= =?utf-8?B?SzNOZndndlg5RjdTL0F4dVhTVVBZQ1NpaHptOGVJcGNTZTJUYURyRjVyU3RZ?= =?utf-8?B?enV2emdjMXZRVnk4Q3JVOEVzQkNkdkgrUFM0NnhNZ2Q4QkN6YU9iVkdBdHly?= =?utf-8?B?S0FtRW9MSlljR0YycmNyRGZ2c3d6RWVrUzF4MGxubUx4T0RHNVZPT0k0SU1F?= =?utf-8?B?UUVwSzJ0QmJnaCtTZnl2WFNRK1dxZWpsY0FGUGtUcHhDL1dSK2pvb2JBdDVy?= =?utf-8?B?YStESEFWNWtJckZXa1ZDaHhGRkhicVo2Z1A1RUw3alZncHU3aEhiSkFvbklt?= =?utf-8?B?cFN4TUpmRUJ2TitUY0NPR2lodGRtRWJRSFF6dWptMTJGQVdneE9xUzhEc21L?= =?utf-8?B?Slp6cnlyMy9IYkhvd1lJWVZ3eXByZXdxa3VBWkhvbjZwRlExODNIcEJzOUV6?= =?utf-8?B?TzVrWmp3QzVTMVZYcGFIRnRLaU9TeS9EM05xbzMrdm5KcUJoVlcyTHB6NFpt?= =?utf-8?B?SWJrSVVkRkdScm9RRGE2eEttZEp4enFPVzc5MEF5TmpRSzhNd05CYkZQSW54?= =?utf-8?B?TmcvMG5Mc3BVeVJ0QzRUN3ZheDNhUnl4YUxyN2NxM0ZEd3RUazVrYkJrdDRa?= =?utf-8?B?YzRlWHA2ZEFoVGxOQ0t1aXBKVktCYWlPOENzVWplNko0M2lTMC93THNKeFJz?= =?utf-8?B?TVZYWjE1a2k4UHhaLzhVbElEL2VjakhJL3VrM2FMNmdobHMzaEovcnc4MUhr?= =?utf-8?B?bHlNQzU5c3lVSHBEa3BhMVprMW85Zkg2NEN0bFo0NTJlRFpMMXpQU0cvdlNT?= =?utf-8?B?R3hrQnF6REhwUlVEMmNkL082WmlUNnEvRGlYRllQNXBXWnQzNVduc0xJeDhp?= =?utf-8?B?ZFZCTE0vWGJ5S1ZVNStTN1NKakxjSlZnODI0Wk5EN25OMEtySzAzWnJYamI5?= =?utf-8?B?OTdoNEkrUEZZUzZmeVlpUVFLeDBkNDJBQ2lOT1NkcTJiWk1QNThCa1dlaHl1?= =?utf-8?B?d0NSdjdLbUJWSWtRU2pGb2szM05iUkpXZk1MemxBVTBFbzE0aWNvTlExLzJr?= =?utf-8?B?K0h0RnFwQzRrZi8wWW5uV0JUNlVoeGQ3czg5N1I2OG94NEFNYU9LZmI5emtS?= =?utf-8?B?bVZVeVkzby9VWXZYbzlmTGVBY05XL1p1NTVDNDlPNDNaYWtZZE9PZz09?= X-OriginatorOrg: garyguo.net X-MS-Exchange-CrossTenant-Network-Message-Id: 5708527c-148e-4ece-12a3-08df08492af6 X-MS-Exchange-CrossTenant-AuthSource: LOAP265MB8560.GBRP265.PROD.OUTLOOK.COM X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 01 Sep 2026 16:50:45.7172 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: bbc898ad-b10f-4e10-8552-d9377b823d45 X-MS-Exchange-CrossTenant-MailboxType: HOSTED X-MS-Exchange-CrossTenant-UserPrincipalName: q0UMo1RlVeCLesUeR7NTmlPwbDPOKHn/e6O2bwvmiCUvkhMQqZYOBdKF9W1Hof32UPZA8FDUETbY6Gcgt9BPaQ== X-MS-Exchange-Transport-CrossTenantHeadersStamped: CW1P265MB9199 With the removal of relative registers, there are only two type of registers left, fixed register and register arrays. There is not much benefit in having a common super trait for them anymore, thus remove it, and cleanup the macro rules associated with it. Signed-off-by: Gary Guo Acked-by: Miguel Ojeda Reviewed-by: Alexandre Courbot Tested-by: Alexandre Courbot --- rust/kernel/io/register.rs | 22 +++++++++++++--------- rust/macros/io/register.rs | 12 ++++++------ 2 files changed, 19 insertions(+), 15 deletions(-) diff --git a/rust/kernel/io/register.rs b/rust/kernel/io/register.rs index 187f28f16614..9df7572aee9d 100644 --- a/rust/kernel/io/register.rs +++ b/rust/kernel/io/register.rs @@ -121,8 +121,8 @@ io::IoLoc, // }; =20 -/// Trait implemented by all registers. -pub trait Register: Sized { +/// Trait implemented by registers with a fixed offset. +pub trait FixedRegister: Sized { /// Base type for this register. type Base: ?Sized; =20 @@ -132,9 +132,6 @@ pub trait Register: Sized { const OFFSET: usize; } =20 -/// Trait implemented by registers with a fixed offset. -pub trait FixedRegister: Register {} - /// Allows `()` to be used as the `location` parameter of [`Io::write`](su= per::Io::write) when /// passing a [`FixedRegister`] value. impl IoLoc for () @@ -201,7 +198,14 @@ fn offset(self) -> usize { } =20 /// Trait implemented by arrays of registers. -pub trait RegisterArray: Register { +pub trait RegisterArray: Sized { + /// Base type for this register. + type Base: ?Sized; + + /// Start offset of the register. + /// + /// The interpretation of this offset depends on the type of the regis= ter. + const OFFSET: usize; /// Number of elements in the registers array. const SIZE: usize; /// Number of bytes between the start of elements in the registers arr= ay. @@ -267,8 +271,8 @@ fn try_at(idx: usize) -> Option> /// /// Implementors can be used with [`Io::write_reg`](super::Io::write_reg). pub trait LocatedRegister { - /// Register value to write. - type Value: Register; + /// Value to write. + type Value; /// Full location information at which to write the value. type Location: IoLoc; =20 @@ -295,7 +299,7 @@ fn into_io_op(self) -> (FixedRegisterLoc, T) { /// This is used to enforce base matching. #[doc(hidden)] #[inline(always)] // for const eval only -pub const fn alias_offset>() = -> usize { +pub const fn alias_offset>() -> usize { Alias::OFFSET } =20 diff --git a/rust/macros/io/register.rs b/rust/macros/io/register.rs index 6da8ba760ab3..7d3160c4873a 100644 --- a/rust/macros/io/register.rs +++ b/rust/macros/io/register.rs @@ -225,11 +225,6 @@ pub(crate) fn register(def: RegDef) -> Result { #[allow(non_camel_case_types)] #(#attrs)* #vis struct #name(#storage) #args ); - - impl ::kernel::io::register::Register for #name { - type Base =3D #base; - const OFFSET: usize =3D #offset; - } )); } =20 @@ -245,7 +240,10 @@ impl ::kernel::io::register::Register for #name { ))?, =20 None =3D> outputs.extend(quote_spanned!(span =3D> - impl ::kernel::io::register::FixedRegister for #name {} + impl ::kernel::io::register::FixedRegister for #name { + type Base =3D #base; + const OFFSET: usize =3D #offset; + } =20 #(#attrs)* #vis const #name: ::kernel::io::register::Fixed= RegisterLoc<#name> =3D ::kernel::io::register::FixedRegisterLoc::<#name>::new= (); @@ -268,6 +266,8 @@ impl ::kernel::io::register::FixedRegister for #name {} impl ::kernel::io::register::Array for #name {} =20 impl ::kernel::io::register::RegisterArray for #name { + type Base =3D #base; + const OFFSET: usize =3D #offset; const SIZE: usize =3D #size; const STRIDE: usize =3D #stride; } --=20 2.54.0 From nobody Sat Sep 26 12:29:12 2026 Received: from CWXP265CU008.outbound.protection.outlook.com (mail-ukwestazon11020105.outbound.protection.outlook.com [52.101.195.105]) (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 A03F448F831; Tue, 1 Sep 2026 16:50:59 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=52.101.195.105 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788281461; cv=fail; b=SRHqJlVGfC4VVvHv6yAyJB/6sfhTY3EDeXYKNTm1tcWP7N93LzqHIOw7GrKantm//LpQ7Yet2+Nwye9dmV9nvOCy6OwBM2i4TWuKyMf1Qa7CuRkYZ01cK1JvllmOcq62Lte3uL7c5gHgAWL/two8Avt0231A0HLEIEl5Xo/G+SA= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788281461; c=relaxed/simple; bh=Xb4DD4uN8tS4xE64OPyY1srq63t2yRPPUCby23Jigzo=; h=From:Date:Subject:Content-Type:Message-Id:References:In-Reply-To: To:Cc:MIME-Version; b=H7mnuDVm5/kw79dTI/sB1e9x9bA9qDm8q540a0ZybHEIqqhUSB1Lp1OctDyZh7tQE1uBofRR99DVzLhHNiBllhHmafB8Nxx1Rt7ors3Y3bXCnlY64S9LwRFy4wApqn6loa8GTilgV2UAkTOaWoxU0deLchIWDDGTUY1zKAcvWcM= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=garyguo.net; spf=pass smtp.mailfrom=garyguo.net; dkim=pass (1024-bit key) header.d=garyguo.net header.i=@garyguo.net header.b=m4dTYEfR; arc=fail smtp.client-ip=52.101.195.105 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=garyguo.net Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=garyguo.net Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=garyguo.net header.i=@garyguo.net header.b="m4dTYEfR" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=BWBp2sWdRPYZgKbR8lf1gaRiP8ioxOR9ay/JNkbPSSA3FZ0aHvJMuFKj2zSLBZ39akVVI7MaVkETKOdxhGKha7NUO2atNtZqhAT5MpX+SKRQuEwFeHMPlJWU35gP1YNbmQg2X/x0XHbPrxuMcmvu0mDYQ0O8/E5N2RDpDDII/VZ7np9Rgit3kO+J+mvAnLSS2Mj96lgrkLAMQzpgW1XuSuioMg/oDf29cxNNpP1VUB/sC3u2q4bhnXJibAH7iiH/iZq7NLKijOq6he3gtS3fEmDKyN4x6ThlASygmcOSlwZERLsuzqF2JcxNuof2Ok6+ARhnzX+9MSUyB4rDMXy+gQ== 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=QgNTWozGwZ/yHO7i+BJQmmZm1y8Oef8BDGqKEaOWIno=; b=k5EWXvDzi0pOeVlEOYb3V6hNSC5spPNS4cOW5ajh9TArParwE7WyH2FATW7jRtxpYuuU9lOpg2lWX74gHwQx9wYwtSrWQeEnMug/5kBIn/k26DbPn/GJICUC/KVx7fgbzepS3tiBb745ZiW5zzFRc4lGlSvOFq4v3hSwM8qiu6+TAp8h25plCNssOXJpgBkid2zxbFssMeDXWkwGuOS+J3zjq+fX0I4OsFbOXt8g8bWWf715BjDr3dgoo9HsxxrRg4StX6A7AUbuqca1Vj4pFs6Tp+6Txzpcz+uEpjRrnxxkmcpuAwsMBBaDAZA4mU5iGK8yycKRCATp9uO7uw4Fng== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=garyguo.net; dmarc=pass action=none header.from=garyguo.net; dkim=pass header.d=garyguo.net; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=garyguo.net; s=selector1; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=QgNTWozGwZ/yHO7i+BJQmmZm1y8Oef8BDGqKEaOWIno=; b=m4dTYEfRUVq28QfQdgRucZuvoLlpJLrVLMODuhvzViSFRuGFvi0ev//4AP0lAm7KP753yNaFYyPZ32CgGkzXzH4ra0DqnTWwOEK27WWvmVMULKWLFQxj+choAouAKg4+ivPn2dqMedxg6Uq5dN8Oyk/BFT8nPkY1HkAvqkFAcsU= Authentication-Results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=garyguo.net; Received: from LOAP265MB8560.GBRP265.PROD.OUTLOOK.COM (2603:10a6:600:4ab::19) by CW1P265MB9199.GBRP265.PROD.OUTLOOK.COM (2603:10a6:400:272::22) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.21.360.13; Tue, 1 Sep 2026 16:50:46 +0000 Received: from LOAP265MB8560.GBRP265.PROD.OUTLOOK.COM ([fe80::f60b:1537:68d7:4fc1]) by LOAP265MB8560.GBRP265.PROD.OUTLOOK.COM ([fe80::f60b:1537:68d7:4fc1%4]) with mapi id 15.21.0360.008; Tue, 1 Sep 2026 16:50:46 +0000 From: Gary Guo Date: Tue, 01 Sep 2026 17:50:40 +0100 Subject: [PATCH v4 16/16] rust: io: register: unify handling of register with/without bitfields Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260901-typed_register-v4-16-5552b1d59525@garyguo.net> References: <20260901-typed_register-v4-0-5552b1d59525@garyguo.net> In-Reply-To: <20260901-typed_register-v4-0-5552b1d59525@garyguo.net> To: Danilo Krummrich , Alice Ryhl , Daniel Almeida , Miguel Ojeda , Boqun Feng , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Andreas Hindborg , Trevor Gross , Tamir Duberstein , Alexandre Courbot , =?utf-8?q?Onur_=C3=96zkan?= , David Airlie , Simona Vetter , Bjorn Helgaas , =?utf-8?q?Krzysztof_Wilczy=C5=84ski?= Cc: driver-core@lists.linux.dev, rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, nova-gpu@lists.linux.dev, dri-devel@lists.freedesktop.org, linux-pci@vger.kernel.org, Gary Guo X-Mailer: b4 0.15.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1788281431; l=10728; i=gary@garyguo.net; s=20221204; h=from:subject:message-id; bh=Xb4DD4uN8tS4xE64OPyY1srq63t2yRPPUCby23Jigzo=; b=NLIFSh0h4XvoG2uzJTeMnm/v6lFM4wgLIaHXPmrNyj/y3WHl8uaqEmxaRDsHLEyVImrkEB4g3 wonaBr4v2CqD9iQ6NPZ4NiMT6f4QEpvR+f4WB06er8Df7PD417rg8bj X-Developer-Key: i=gary@garyguo.net; a=ed25519; pk=vB3uIX95SM4eVrIqo1DWNWKDKD2xzB+yLLLr0yOPYMo= X-ClientProxiedBy: PAZP264CA0173.FRAP264.PROD.OUTLOOK.COM (2603:10a6:102:236::16) To LOAP265MB8560.GBRP265.PROD.OUTLOOK.COM (2603:10a6:600:4ab::19) 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: LOAP265MB8560:EE_|CW1P265MB9199:EE_ X-MS-Office365-Filtering-Correlation-Id: 3530b8f8-7158-4fe2-0024-08df08492b78 X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|1800799024|7416014|10070799003|376014|23010399003|366016|921020|6133799003|3023799007|10067099003|56012099006|5023799004|22082099003|18002099003; X-Microsoft-Antispam-Message-Info: mWpfFP5PWkUzzSvgGbqUt155oTNY6yjCA6HphaUAMDsy1DTfV1re5zU5FJowo5tJtMFRng903OwUSOUhlyyAwUID0BLBhG5V3fKPQa1V8ZrI9jvycbWrW38g7rJQ0506z8qDbPuU83vvY/V4Ue9mlYmV3P2VS1D3ceukHLTGif86rCRcTtPjTf5Nxh+D8DgnMP8XH0ItgAQmDwlXocOb0veo93czoQz32RO5lBl6GxjM51N8GmfxCmmdqtgW8l0xZQjOYz2ywcMNVNqI+IVn6kFtzJ638Wz253GKVggiiKVdxRQHlkTVqBC8D709kKZP6GFhvDn41pF0hcesgNIqmtsVZADM9SoMrXP8s9BCRwyERJ48AzcPCGFvZef+rcy945udVXrPjH76wtrHk09/6RmvsLx8pVStYwC4Q1cecLyOsAr1Yat0SweWOaxUPlDF9zmezKCb1JXSyYmgFiG6wHVgw7kGsB2LH+zXMKmlMaWVN778E+ED2RPa1Os4psvGoKe2W7ySFVHClfhd3/OAf1DTAU6JNsiOfF1jdCAti40CrZYAwQcxudYYGSgJzB6sf0w1d6Fku9o9xfGTAqNM8yLMRWtgPvUDyTrkmACmQkdX2LMr7LUgqPdD4ro30Kr1rHSEieJwFvK9kEfFtR6BITy6X9B4qvkuO7ufe4PqEmViWgKXXxjUh9INsEqt1uDST8rwR3A7JDPaqF5XbXnwLg== X-Forefront-Antispam-Report: CIP:255.255.255.255;CTRY:;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:LOAP265MB8560.GBRP265.PROD.OUTLOOK.COM;PTR:;CAT:NONE;SFS:(13230040)(1800799024)(7416014)(10070799003)(376014)(23010399003)(366016)(921020)(6133799003)(3023799007)(10067099003)(56012099006)(5023799004)(22082099003)(18002099003);DIR:OUT;SFP:1102; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: =?utf-8?B?dVJMb0drQVRaNVd1cW1xRkdHWitqY3R3Q1k5MHNoTU9sSmpsczQ1LzRRMzY1?= =?utf-8?B?RjJEVWxHc0hTYTFmaGlEUzFFdWNiSUxtZzlIajI1YzBqV1pabk9YWlB5UXlD?= =?utf-8?B?b3FTZTIvdW42Wmh2UHJSa0Y2UlBtRjR0QjRxUXMxR1Erak5QcXhSMllhTm56?= =?utf-8?B?cGtzRHFQcjRrcElZR1NrNitwY2orMVkreDZHbGIyQ1hiaXY5bjJqOVZDUjhI?= =?utf-8?B?YjIyN2UwMExqNk42QXhaeTNLUm5ZTlUzQUpwQWV0a2UrTVdsZ2ZiMW1SVVI5?= =?utf-8?B?Q016M1kwQkZxaFZaNW5tdm94TTZNZ3VhRi9JUW54eE4waG9ndjhXOW4xTkhm?= =?utf-8?B?ZDhHVWdnOXcwUFVtamZKQStMaVc2OVdVUjFnYS9ySG12QUNhZWJ6S2lsT1FN?= =?utf-8?B?M09xRXIzUkIvU1FLY2FTck93ZTRtN00vUm5hUEJVa2duNXhPTE04NWs3M1R3?= =?utf-8?B?RjJwajhlV3NXUm1nalF6T2ZvQzhtc3VCeXdraHgyMk9hUDNWK0g4Wkh5UlJo?= =?utf-8?B?SEkxL1lFblFGSkJKeWJtdS9DUXRaazlUcXlSRVZuYjF6U3g2MkpocDFya2R3?= =?utf-8?B?bndyaENWN2Q4ZVNSZ1hESmQwbFRwb1FKczVLU0ZRK2VqUUkvRDN2V2FpV1lV?= =?utf-8?B?Rlh2SHppMFIzWnVUa1BERzRtVHpQNXdUNkFLRjg3TFdmRkRweStzbWZ0SnVi?= =?utf-8?B?ZTVGN3VUUm9QNnI0K3lUNWMydS9sYys5SnhZOElTNWtrcEdWT3VuSlRuSm02?= =?utf-8?B?aW9HRDVNWjQ2NmQ4V2xjMlRmcW9yMUM3MFlNMFJ4N2RTOUdnemFRSjJiYVdT?= =?utf-8?B?TFhFaEpYS045bHQyL0l3N3FEbUt1MjFaVm9UQ3lGS05KMU8xTkQxSUJFeUtx?= =?utf-8?B?eWtSV2ttdER1bW8rS052dnFMeHU3RXorMTJzemQzYVhWQnd5M0pkQVVZZVJW?= =?utf-8?B?VGhZbG9tNGdoV3VSbGE3K0R5TkVpWWFDTyt5cjF4a0toSnp5Sy93b1RxeFN1?= =?utf-8?B?UDEvd0grRjJTR1pRWnVaSTBVaHppSHRSb3B3c2lkbmhtZTRYcStRRDNVcTV6?= =?utf-8?B?NGFDT2c4bGUrMGNETXVHdzNYeHdpWlAwenRNQTlGOW15WXB5b05aVDV0WlJK?= =?utf-8?B?TStHb29GbzdCeHZTSHFTamw4Vys4Y1FrQ1NoNDFwbER2c0ZyVUJIaE9CaWk0?= =?utf-8?B?cEE0bU0wQTQ2Q0liYmwzbUNlSnFXNkdyQ3hZYlFiTGkrSDl1emkxeHdjSjZh?= =?utf-8?B?MWpTbm8xM2dUWlFLZXZPZG9QU3llVEh0cWNqd3ZRUzIzU2YwanpsNGlKamE4?= =?utf-8?B?SXljZitIdERiNkhIVG9IcnFnbDR2L1R0cnViMVA1elVnOENCbzJDNHYxOER4?= =?utf-8?B?aUdxRXhkUi9nejI4dGs1amFBVStxRXFyQ29qK2IyTmpVSjBTd2RDNGpRdW9i?= =?utf-8?B?OGhKdUtyTkowYzROTDNpNlEvMTNzeTRNc3NWb3RRRWZkaUdZVVVJOWhyWlJW?= =?utf-8?B?TS9ZakpGM0MzT3dram5VS1pEalVjRVpXSVZoVldEZWN0Y3hjU05qeUxYV1hW?= =?utf-8?B?VmN1U1NwNTVRYVJEQTVuc1lxVitha1FiSnZaZDgrWTMvcFQyL3VPbXYwN2Mw?= =?utf-8?B?V3pPUDdGVVN6SmVsVk5LWkF0OGZRWmt0VXhRVWdycmplVlJDQWxYSVNaZ0xS?= =?utf-8?B?SVpPVXJXSldvcUN4cEhBRmxsRExmdEw4dGplZittZ0dHeXJXR0pvNkxJVE96?= =?utf-8?B?bDRXb24wc1dvNjBjTUZaSnlmeGlzcVU3Qjc0d2xLZVQyTFdSaDRUZFdsLzJO?= =?utf-8?B?dVI3YTZub3pLYkxxNlZkaWJ6alZ4YThhRXJOVjRFbUdKSkdGTjVBYTVpQnhz?= =?utf-8?B?VlNkU2ZLTWJTY2doSkdkcmI0QzJ0MU40QzV4T0N6WWs1TnA2MktaRk91S3ZJ?= =?utf-8?B?SGlid1F6Mmdtc0V0aXVRL0cvcWJLN3htS0I1L25LUFBkblkxR3dTL1BWd2w4?= =?utf-8?B?VVNIVkF5elZhb1lDTXlwQnNFdHo3RExma2t1TEJqOVkycDFLSlRLZlFIZGRQ?= =?utf-8?B?MFhMcDNqOStWc2ZsajZkRmZJQWw4YXJzRCtaTHBreFYxbEc3Znl6N01BYjhT?= =?utf-8?B?YWtlN1V0LzBqNStOci91SGEyeGlDUm9Ic1JWR3MyMDErTSsyOWNFcmxPOWhG?= =?utf-8?B?ZFdZaEhxYy80OTYzZENYZDBEY2V4c0hxdUVMM0VpWTg4bGZxQ1J1eUZCUUZp?= =?utf-8?B?d1pGNUVNOHNqdTV3TFczWFd3Y09LeVIzODFQUjFoQkl2dWh1Zk95OUxsL2cr?= =?utf-8?B?eUpRNGt5SGMyZkhXV3RqTkJGVHBCbVJpSjQ2TlE2dTdPWm9rc3paQT09?= X-OriginatorOrg: garyguo.net X-MS-Exchange-CrossTenant-Network-Message-Id: 3530b8f8-7158-4fe2-0024-08df08492b78 X-MS-Exchange-CrossTenant-AuthSource: LOAP265MB8560.GBRP265.PROD.OUTLOOK.COM X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 01 Sep 2026 16:50:46.5532 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: bbc898ad-b10f-4e10-8552-d9377b823d45 X-MS-Exchange-CrossTenant-MailboxType: HOSTED X-MS-Exchange-CrossTenant-UserPrincipalName: YEFY7iXfzIF53/I+w2/yUEcnSn71Jvqc8/nm3VTLG1vmx3dItL9780/ZDdwZoKKgEiUQC5tOJIzCyDh2ymlm1w== X-MS-Exchange-Transport-CrossTenantHeadersStamped: CW1P265MB9199 Move the `FixedRegister` from a property of register to become a property of type. Name the new trait `FixedIoLoc` indicating if I/O location of a type is unique for a specific base. Thus, bitfields become just a special case of this (where type is unique because we're generating it in the register macro), and expose feature to registers without inline bitfield definition with the `#[unique]` attribute. Reviewed-by: Alexandre Courbot Signed-off-by: Gary Guo Acked-by: Miguel Ojeda Tested-by: Alexandre Courbot --- Changes since v3: - Add a note that discourage `#[unique]` on primitives (Sashiko). - Fix array's bitfield check to check `bitfield.is_none()` instead of `!unique` (Sashiko). --- rust/kernel/io/register.rs | 114 +++++++++++++++++++++--------------------= ---- rust/macros/io/register.rs | 58 ++++++++++++++--------- 2 files changed, 89 insertions(+), 83 deletions(-) diff --git a/rust/kernel/io/register.rs b/rust/kernel/io/register.rs index 9df7572aee9d..b6513fa0f412 100644 --- a/rust/kernel/io/register.rs +++ b/rust/kernel/io/register.rs @@ -121,61 +121,15 @@ io::IoLoc, // }; =20 -/// Trait implemented by registers with a fixed offset. -pub trait FixedRegister: Sized { - /// Base type for this register. - type Base: ?Sized; - - /// Start offset of the register. - /// - /// The interpretation of this offset depends on the type of the regis= ter. - const OFFSET: usize; -} - /// Allows `()` to be used as the `location` parameter of [`Io::write`](su= per::Io::write) when -/// passing a [`FixedRegister`] value. +/// passing a [`FixedIoLoc`] value. impl IoLoc for () where - T: FixedRegister, + T: FixedIoLoc, { #[inline(always)] fn offset(self) -> usize { - T::OFFSET - } -} - -/// A [`FixedRegister`] carries its location in its type. Thus `FixedRegis= ter` values can be used -/// as an [`IoLoc`]. -impl IoLoc for T -where - T: FixedRegister, -{ - #[inline(always)] - fn offset(self) -> usize { - T::OFFSET - } -} - -/// Location of a fixed register. -pub struct FixedRegisterLoc(PhantomData); - -impl FixedRegisterLoc { - /// Returns the location of `T`. - #[inline(always)] - // We do not implement `Default` so we can be const. - #[expect(clippy::new_without_default)] - pub const fn new() -> Self { - Self(PhantomData) - } -} - -impl IoLoc for FixedRegisterLoc -where - T: FixedRegister, -{ - #[inline(always)] - fn offset(self) -> usize { - T::OFFSET + T::LOCATION.offset() } } =20 @@ -188,6 +142,11 @@ impl OffsetLoc { pub const fn new(offset: usize) -> Self { Self(offset, PhantomData) } + + #[inline] + pub const fn const_offset(self) -> usize { + self.0 + } } =20 impl IoLoc for OffsetLoc { @@ -266,6 +225,17 @@ fn try_at(idx: usize) -> Option> } } =20 +/// Trait implemented by types that indicate there is a fixed I/O location= for this given type. +/// +/// Implementors can be used with [`Io::write_reg`](super::Io::write_reg). +pub trait FixedIoLoc: Sized { + /// Type of [`FixedIoLoc::LOCATION`]. + type Location: IoLoc; + + /// Location of this type within given base. + const LOCATION: Self::Location; +} + /// Trait implemented by items that contain both a register value and the = absolute I/O location at /// which to write it. /// @@ -283,26 +253,17 @@ pub trait LocatedRegister { =20 impl LocatedRegister for T where - T: FixedRegister, + T: FixedIoLoc, { - type Location =3D FixedRegisterLoc; + type Location =3D T::Location; type Value =3D T; =20 #[inline(always)] - fn into_io_op(self) -> (FixedRegisterLoc, T) { - (FixedRegisterLoc::new(), self) + fn into_io_op(self) -> (T::Location, T) { + (T::LOCATION, self) } } =20 -/// Helper function for register alias implementation. -/// -/// This is used to enforce base matching. -#[doc(hidden)] -#[inline(always)] // for const eval only -pub const fn alias_offset>() -> usize { - Alias::OFFSET -} - /// Helper function for register element alias implementation. /// /// This is used to enforce base matching and provide bounds checking. @@ -419,6 +380,35 @@ pub const fn element_alias_offset; +/// +/// pub RESET: #[unique] Reset @ 0x100; +/// } +/// +/// # fn test(mmio: Mmio<'_, Region<0x1000>>) { +/// // let mmio: Mmio<'_, Region<0x1000>>; +/// mmio.write_reg(Reset::zeroed().with_const_reset::<1>()); +/// # } +/// ``` +/// /// ## Arrays of registers /// /// Some I/O areas contain consecutive registers that share the same field= layout. These areas can diff --git a/rust/macros/io/register.rs b/rust/macros/io/register.rs index 7d3160c4873a..6a89e4b60735 100644 --- a/rust/macros/io/register.rs +++ b/rust/macros/io/register.rs @@ -63,6 +63,7 @@ struct Reg { attrs: Vec, vis: Visibility, name: Ident, + unique: bool, ty: Type, array: Option, offset: RegOffset, @@ -76,16 +77,26 @@ fn parse(input: syn::parse::ParseStream<'_>) -> Result<= Self> { let name =3D input.parse()?; =20 let lh =3D input.lookahead1(); - let (ty, bitfield_storage) =3D if lh.peek(Token![:]) { + let (unique, ty, bitfield_storage) =3D if lh.peek(Token![:]) { let _: Token![:] =3D input.parse()?; - (input.parse()?, None) + + let mut attrs =3D input.call(Attribute::parse_outer)?; + let unique =3D attrs + .extract_if(.., |attr| attr.path().is_ident("unique")) + .count() + !=3D 0; + if !attrs.is_empty() { + Err(Error::new_spanned(&attrs[0], "unexpected attributes")= )? + } + + (unique, input.parse()?, None) } else if lh.peek(token::Paren) { let content; parenthesized!(content in input); let bitfield_storage =3D Some(content.parse()?); =20 // For bitfields, bitfield macro will generate a type with the= same name as `name`. - (parse_quote!(#name), bitfield_storage) + (true, parse_quote!(#name), bitfield_storage) } else { Err(lh.error())? }; @@ -150,6 +161,7 @@ fn parse(input: syn::parse::ParseStream<'_>) -> Result<= Self> { attrs, vis, name, + unique, ty, array, offset, @@ -193,6 +205,7 @@ pub(crate) fn register(def: RegDef) -> Result { attrs, vis, name, + unique, ty, array, offset, @@ -207,7 +220,7 @@ pub(crate) fn register(def: RegDef) -> Result { RegOffset::Fixed { offset } =3D> quote!(#offset), RegOffset::Alias { alias } =3D> { quote_spanned!(alias.span().resolved_at(span) =3D> - ::kernel::io::register::alias_offset::<#base, #alias>() + ::kernel::io::register::OffsetLoc::<#base, _>::const_o= ffset(#alias) ) } RegOffset::ElementAlias { alias, idx } =3D> { @@ -229,27 +242,30 @@ pub(crate) fn register(def: RegDef) -> Result { } =20 match array { - None if bitfield.is_none() =3D> outputs.extend(quote!( - #(#attrs)* #vis const #name: ::kernel::io::register::Offse= tLoc<#base, #ty> =3D - ::kernel::io::register::OffsetLoc::new(#offset); - )), - - _ if bitfield.is_none() =3D> Err(Error::new_spanned( - ty, - "defining without bitfield is not yet supported for this t= ype of register", - ))?, - - None =3D> outputs.extend(quote_spanned!(span =3D> - impl ::kernel::io::register::FixedRegister for #name { - type Base =3D #base; - const OFFSET: usize =3D #offset; + None =3D> { + if unique { + outputs.extend(quote!( + impl ::kernel::io::register::FixedIoLoc<#base> for= #ty { + type Location =3D ::kernel::io::register::Offs= etLoc<#base, #ty>; + const LOCATION: Self::Location =3D #name; + } + )) } =20 - #(#attrs)* #vis const #name: ::kernel::io::register::Fixed= RegisterLoc<#name> =3D - ::kernel::io::register::FixedRegisterLoc::<#name>::new= (); - )), + outputs.extend(quote_spanned!(span =3D> + #(#attrs)* #vis const #name: ::kernel::io::register::O= ffsetLoc<#base, #ty> =3D + ::kernel::io::register::OffsetLoc::new(#offset); + )); + } =20 Some(def) =3D> { + if bitfield.is_none() { + Err(Error::new_spanned( + &ty, + "defining without bitfield is not yet supported fo= r this type of register", + ))? + } + let size =3D &def.size; let stride =3D if let Some(stride) =3D &def.stride { outputs.extend(quote_spanned!(stride.span().resolved_a= t(span) =3D> --=20 2.54.0