From nobody Thu Jun 25 00:35:31 2026 Received: from CWXP265CU008.outbound.protection.outlook.com (mail-ukwestazon11020099.outbound.protection.outlook.com [52.101.195.99]) (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 E01EB2E9729; Mon, 8 Jun 2026 19:59:11 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=52.101.195.99 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780948754; cv=fail; b=jYxAgwru7Gb4KMwDK2hyQL3KgIoecbrfTtnyWKzaepKVjK2PViDeNOhn6cgPhUf303TamuJW7Cu5ER9G9ZA0zoqxfhuzzPeHkVQZmtbfzHiv5+R42KPKxZy1k7h/lvSoaUBw24BZJ284QEZXf+8++VNdN0QIfhuRtAteB6T3ozw= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780948754; c=relaxed/simple; bh=9kc34t/fCVoNLZv+3VpTgeN7MieeNOygy8GCKlBxPz0=; h=From:Date:Subject:Content-Type:Message-Id:References:In-Reply-To: To:Cc:MIME-Version; b=UU6HEWXZ0ksPr9tl/rEy2jC68Rr+KMJKlYDQYZYfVsGHLgMbVcNTPKJxNYPPTQviLj3BIaQlmBFt4QoiMEgUVL79zGaGdYVC/u7jPP3WONNh8ncygHb1EjhkFJy9j7l7PR4648p1FTCALnziIjHqHkECI3WxOtWJlwkaczsI974= 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=IBFbL8s9; arc=fail smtp.client-ip=52.101.195.99 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="IBFbL8s9" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=iUuV2Zk+jJgXH0LsJWG6/r/xNogQUaX+Wty8J6yMPD4qCCsJtUyd7qIt8pkhA5Ejo2xmnbVMj6gGoPl33GVnloANON5q/Eu8qX4JDQXiVfXHTHChtbHQIYrmJPO3a0oLdsmFFTgYnZoF9yb2NOMwiQQMZ3J1pjQ+xyMgqpbcVDgQANcDIYjxAW4YzrvZFq/JAPYrb0MZTXHTJcdkK10jORXOAHPxMNVAFWC83Mu+aNU574UQ2PJShn6BlUsQWYpqG6/jw5/ku5GpOA2AzrfXmdFak+t2fHwiKiJzELRcHY2rBd34/fu6lASZwzqYxGoaVADbPAMMQ39KRXzMuyEzyg== 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=ND1fcK0zeZsQ7guq4wiThRCNimjDJvRCl85vTSMKHN4=; b=MGA/lvK5cYkHLdTdAhTCbbhpYHJbks/u1xi5ZlfUcjLIxZapCIC8ZiwyptDug8DCjQGp7L30iEOtZRY4yv7n4ZjWT6Gd23bp+BCOU/6aMfV4KMYAPBLZktqWNi+/wDboBwknumgigujBITldwjykEuxEyedHlhvMaRRpN6f3dbu7XMFtuC3xfeq93cgB/0q40C4LvWeJRO8IJStQWMIuKupr468qVbiwlwiAYOm6RBkObCZq/ja6fBVe1sYkN9dqnkt2G+tQGoli6YmzJ9MShzFtDPX4O4OyYXN7ZEFqEP46ezOdVi+Eqw9wHhsJEVK0uav7ppSykJxgHoR1P4ep8Q== 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=ND1fcK0zeZsQ7guq4wiThRCNimjDJvRCl85vTSMKHN4=; b=IBFbL8s9Ep5781uE75dIS/wXxSaimlc1sSRFqbVmIi816j4hGEWkC02x7DyxwqNH0mjol+L2ML0HROaLgXug7W0omWcEH7hIIdVV01WD6Mxrnthadga0XeYXOxKinU167TJ9XIKf1CeewjBW8YKBpE2rTRnLfOXfKiGWfgw+f/0= Authentication-Results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=garyguo.net; Received: from LOVP265MB8871.GBRP265.PROD.OUTLOOK.COM (2603:10a6:600:488::16) by LO8P265MB7398.GBRP265.PROD.OUTLOOK.COM (2603:10a6:600:3ca::5) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.21.92.12; Mon, 8 Jun 2026 19:59:08 +0000 Received: from LOVP265MB8871.GBRP265.PROD.OUTLOOK.COM ([fe80::1c3:ceba:21b4:9986]) by LOVP265MB8871.GBRP265.PROD.OUTLOOK.COM ([fe80::1c3:ceba:21b4:9986%4]) with mapi id 15.21.0092.011; Mon, 8 Jun 2026 19:59:08 +0000 From: Gary Guo Date: Mon, 08 Jun 2026 20:58:58 +0100 Subject: [PATCH v3 01/19] rust: io: add dynamically-sized `Region` type Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260608-io_projection-v3-1-c5cde13a5ec4@garyguo.net> References: <20260608-io_projection-v3-0-c5cde13a5ec4@garyguo.net> In-Reply-To: <20260608-io_projection-v3-0-c5cde13a5ec4@garyguo.net> To: Danilo Krummrich , Alice Ryhl , Daniel Almeida , Greg Kroah-Hartman , "Rafael J. Wysocki" , Miguel Ojeda , Boqun Feng , Gary Guo , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Andreas Hindborg , Trevor Gross , Bjorn Helgaas , =?utf-8?q?Krzysztof_Wilczy=C5=84ski?= , Abdiel Janulgue , Robin Murphy , Alexandre Courbot , David Airlie , Simona Vetter Cc: driver-core@lists.linux.dev, rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, linux-pci@vger.kernel.org, nova-gpu@lists.linux.dev, dri-devel@lists.freedesktop.org X-Mailer: b4 0.15.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1780948747; l=16706; i=gary@garyguo.net; s=20221204; h=from:subject:message-id; bh=9kc34t/fCVoNLZv+3VpTgeN7MieeNOygy8GCKlBxPz0=; b=xfv578LvEoFcXyAiBWryQxqVTeoaVPg5z6kp8QPP2Il82RhEZebxtMvfyWrPsd1LeM3cmC32n dJcHUMAtCBgBKf4knBWjSsrQbpk9Fog/xtL3o5z8EXsyJzYNauqYnUz X-Developer-Key: i=gary@garyguo.net; a=ed25519; pk=vB3uIX95SM4eVrIqo1DWNWKDKD2xzB+yLLLr0yOPYMo= X-ClientProxiedBy: LO4P123CA0344.GBRP123.PROD.OUTLOOK.COM (2603:10a6:600:18d::7) To LOVP265MB8871.GBRP265.PROD.OUTLOOK.COM (2603:10a6:600:488::16) 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: LOVP265MB8871:EE_|LO8P265MB7398:EE_ X-MS-Office365-Filtering-Correlation-Id: 0e1b7665-40e7-440d-c33c-08dec59866ce X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|1800799024|7416014|376014|366016|10070799003|6133799003|22082099003|18002099003|921020|56012099006|5023799004; X-Microsoft-Antispam-Message-Info: HWCMn8kbeo+lbB+m0RuTOZZOJ/tih7xHT1CgfKsVTR3NKpAT07XHJH0oLsOGnC33CnFUWUJjcYZmg3VPfhN3jYIfbez5WlZ8wLjuljhHqpx1ItDAjb0yJKqzFTQ10e9gIJiE6gKmEclwwRKUz8X4rJsTey1aSpl7lGjDqWH/f4H1jLf8i8ti+GeX9tZhY5X6t4iyfkKRsuBuW0Vk72WzEX60ODHqt0RblbukiB+HyFvBWwX6AWPKOW9vmxTYwuWa4ljykKAgVUcKlSHfgQI0Po6u/TybRCILpRGvO7HMn7Y5WnQVVexLQ5nZcssiafef+U62UlknBUDvjErmKCwyfwytWLf5kRGi9b0pWqhscTL0PDgNCydClUw/ikNtD/dP8yVnnD2Qnhrzr+yAs/wcTuZc31ny4efTyX8rzC638VfBrlP5jxUE6/TGOeLhRQSGHdupJgc2q1q9d8+oujXqelhzMfReZkxe9QInldbtdjmdcOJoPycQnxuoPme2K1E/DAr6JILy6cagr/vj8YzjbiQxq9CfnUDUrVp4nZn1lThrU0ttMmBLbIG2R8umXXI5aQ5KKjoK7xINjxw9z8Lqs9Ve3RoIQL+sC+VubDc/dT7uHL3VcZJLCVsj9W33rLrZ9/yI2Jyq+jrJ034DYBV5ssSNVtdqC0Xz58Wv7EhP2Mvg06aRxy+DS4U2uQfNZ5cyn3yv7+ZDhGY2Z9fOlEYc88ybENrWHjRDm7oym7XroMg= X-Forefront-Antispam-Report: CIP:255.255.255.255;CTRY:;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:LOVP265MB8871.GBRP265.PROD.OUTLOOK.COM;PTR:;CAT:NONE;SFS:(13230040)(1800799024)(7416014)(376014)(366016)(10070799003)(6133799003)(22082099003)(18002099003)(921020)(56012099006)(5023799004);DIR:OUT;SFP:1102; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: =?utf-8?B?ejg1NWNvZkI0SENITmQ5K2lmOHZqNVBHK3lxbGdCTFYzR2w0VDZHMjhUUjF5?= =?utf-8?B?UGhTdmJPSXRDcnpwZkVreGhickhRTmtWcEFxclkrWHZBQ3JuNHl6ajc1MUtK?= =?utf-8?B?RlpITXFoNVRVRTZHVExRd0l1cHFTNHpaYytGT2M0YklEbHFYMWpaS3dJZ1F2?= =?utf-8?B?WDk2aTFZa3lyeWtEWEt2cTRDT2NIbzBySzFFbjUvVDZYeUloeE83QXArVjRn?= =?utf-8?B?V01vc2Z5VlFTQkNuWU1nNDFtNE1jZnFYTmZ5TmVoT09UVzg1a2JqNjgrVlhF?= =?utf-8?B?OVkwbEFrTHl2blBSV2VhR1FYdWZvYjRyd2JpcDdzc1pQNjZiSXozbENULy9O?= =?utf-8?B?MGZONzRyR3lUZDBGVUo4NFFGVHdiL05KY1oyaGRlaHlQU2dYNHFtdU9sSmVG?= =?utf-8?B?MTJwRGF2bTlHTzc2TlhxNll1Z2dBL0pya1dpMzl0dXdoWlp6djlLMjNERC9E?= =?utf-8?B?eFRJY0JwcFhwT3hsemd1R1BLSjBPREJwVVBWRU1RZHR5T2FXamJZNFhtUDNa?= =?utf-8?B?QlNBUzBvaEtLMHlPQmVJUWY3M0lJa2NEbkpLdENJelVwVFRUVlpOcXg2Y2Zo?= =?utf-8?B?dW4zdGZFRmVWWXMzaG93bjFTMVoyOUlHZERicTdjQ0pDZnIvY0lISTVoSmsz?= =?utf-8?B?SzlGNytQUDJKdDgvb2NTTm9adVR6MnZtQUpCN21DL2ZmUnBYVFZPbTFYek5V?= =?utf-8?B?V3Z5M2QyVFRoRW9Sei9QRUFhdXhiWnAvVlZqODJLbCtSZ2lKNlYvT3FKTTdj?= =?utf-8?B?YmR5eUxlUEJQQWtBd2puclR3WkNISGNRZkttZTNzdTk0ck15SXV6YTI5Nmhu?= =?utf-8?B?aVZ4UldZNnJkVjhrS21wTGc0bkYxR1VxTDc1OVBNdXp0MjBhbmphYnc2MS9l?= =?utf-8?B?UjdtOVU0ejNtZjM1Q3R2dTRJWHdpSFZ6THhZRGxJeFRDNnZySFdDVFlOcXRa?= =?utf-8?B?UnNwbzY3YW1oMlZDTUp2M2J3YzRHOXZiTWhkQnp0U0cxN0drR3c3SXlpcUs2?= =?utf-8?B?bGxZUjBnZ1RQbVk2WkJTM2R2QnNBU24zNkpYT2VoQkNSMDJreDJXQTA0K0pX?= =?utf-8?B?ci9wWHZHeWlJQmozTVpFRlNudm9GQnVWY2hGQktKZDYzTis3STJ0Q2JqTjlM?= =?utf-8?B?dWMrRy82ZWJWRExVNVlEQnd6UkNQK2FSSzE3aVJxdDZUcHBVMHVPMUlyelVY?= =?utf-8?B?OXZoVzNIVUhlb0ZielZLMDIwUjRTek9GdDNrUDZRVTNCNmhLb0MwRXhCWERr?= =?utf-8?B?NUtFdDUzU3hoTkZqbnVZdms5TW9uQXRUQ016akdXQnRicXhzY2tPRXk5bTZO?= =?utf-8?B?cU5vVFBUcXZMb0tJQ3BiQVA2UVdjRXBEeGdrN0VPZzZqaGNLN1N3S1BlVWta?= =?utf-8?B?aTdMMGY1MStSWitkQncyR2pERVh5U3lmZ013V1BDSVJYUlRRdit1cS9jTDF0?= =?utf-8?B?OTlReVNpeGxPaDB1VVI2eEVLS2NFOUpVdEhuL3U4ZVY3S1RnUlFacjBJYnF0?= =?utf-8?B?SFh5Tm80eGtwaDFpd3I2dkt0aUVlTHYyMGhsTXJONWh4cFhMM3ZrR0V2UXlZ?= =?utf-8?B?bkNqcjVNMlZwWmNZZ2tzbEtUSVp6V0JXamdXY0o1RFFWZ1lTNUt3QWdhMjB2?= =?utf-8?B?cEdKNDZqbE9nZzBWMUcrWEpKamFDbXpRYkxBV0hpSjl5REp2VCs2dFBYSFdq?= =?utf-8?B?MXlhK1laelpiM3Y1M1RkaWROVjEybFVxWEhENzZlczVsV1FGdURBKzFrYm55?= =?utf-8?B?YmlYVUZIM25rZks2Tkg4b0FYWEdDMThYMWlCck1GTGxCdk9zbnlGTDduTlJk?= =?utf-8?B?Q04yVERqcWkyZTV6WC9VUzhpV3ZLRUljY1FQQlF2YnErUU1YOG4vY2NPQ1No?= =?utf-8?B?ZUhoYVlzUFpZelVLL1dVZGl3YzNYbXpXUVl3cVZmazhpTVNCV3lwQzFlTFdv?= =?utf-8?B?UVZxUnlnbFU5THA2OU9SWSticFhqYmNDWXAxL3owaG1HeUwyeDZlNTEvcmRm?= =?utf-8?B?WFQ2TDIwZGdFRXpCY2JNRXYxY2ExcHhaRmVNZ29qNUR3dEFMM2dOTDNjRS9F?= =?utf-8?B?SmVCbFBKcnVCRllFYTJrYXBuQWJoMzM1M3JOYUovaE92cit5U1p6U2V0VWh3?= =?utf-8?B?SlRDWldHdEdJeFpVSDVrRDZRY2dmVXVNUWIwSDJhakdXMFB3ZTJISDhWS0xr?= =?utf-8?B?UjcwRjhTRTJLbDRkQnBwRi8vTnRpLzJYRFVXRVB4VGJNUUM3cWxQYTBDamtR?= =?utf-8?B?bHdxZzZOU3Ewam5tbUhpTWFyNm9OdGJHUU1HSWNMd2gzVFV4ME5sMlpuMGI1?= =?utf-8?B?K3dDSC9rOFNVUjE0YVhuTDZncUhmT2UzdnB4clB2L1BxTG11NVdwQT09?= X-OriginatorOrg: garyguo.net X-MS-Exchange-CrossTenant-Network-Message-Id: 0e1b7665-40e7-440d-c33c-08dec59866ce X-MS-Exchange-CrossTenant-AuthSource: LOVP265MB8871.GBRP265.PROD.OUTLOOK.COM X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 08 Jun 2026 19:59:08.4453 (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: 6ub8IwFPwYKlJYr6IeCekFkhnHHelOxROJ1syIbHyqerV62SmJojvOBogkDolabw/YnSBmuaDNENWyiwNxVXAw== X-MS-Exchange-Transport-CrossTenantHeadersStamped: LO8P265MB7398 Currently many I/O related structs carry a `SIZE` parameter to denote the minimum size of the I/O region, while they also carry a field indicating the actual size. Proliferation of the pattern creates a lot of duplicated code, and makes it hard to create typed views of I/O. Introduce a `Region` type that carries the `SIZE` parameter. It is a wrapper of `[u8]`, which makes it dynamically sized with a metadata of `usize`. This way, pointers to `Region` naturally carry size information. This type is required to be naturally aligned. Expose the minimum size information via `MIN_SIZE` constant of the `KnownSize` trait. Similarly, expose the minimum alignment information via `KnownSize::MIN_ALIGN`. With these changes, it is possible to add an associated type to `Io` trait to represent the type of I/O region. For untyped regions, this is the newly added `Region` type. Remove `IoKnownSize` as it is no longer necessary. Use the same mechanism to indicate minimum size of PCI config spaces. Signed-off-by: Gary Guo Suggested-by: Danilo Krummrich --- rust/kernel/devres.rs | 6 +-- rust/kernel/io.rs | 131 +++++++++++++++++++++++++++++++++-------------= ---- rust/kernel/pci.rs | 1 - rust/kernel/pci/io.rs | 40 ++++++--------- rust/kernel/ptr.rs | 12 +++++ 5 files changed, 116 insertions(+), 74 deletions(-) diff --git a/rust/kernel/devres.rs b/rust/kernel/devres.rs index 11ce500e9b76..ed30ccc6e68e 100644 --- a/rust/kernel/devres.rs +++ b/rust/kernel/devres.rs @@ -68,7 +68,6 @@ struct Inner { /// devres::Devres, /// io::{ /// Io, -/// IoKnownSize, /// Mmio, /// MmioRaw, /// PhysAddr, // @@ -297,10 +296,7 @@ pub fn device(&self) -> &Device { /// use kernel::{ /// device::Core, /// devres::Devres, - /// io::{ - /// Io, - /// IoKnownSize, // - /// }, + /// io::Io, /// pci, // /// }; /// diff --git a/rust/kernel/io.rs b/rust/kernel/io.rs index fcc7678fd9e3..dcf3b40ffa48 100644 --- a/rust/kernel/io.rs +++ b/rust/kernel/io.rs @@ -6,7 +6,11 @@ =20 use crate::{ bindings, - prelude::*, // + prelude::*, + ptr::{ + Alignment, + KnownSize, // + }, // }; =20 pub mod mem; @@ -31,6 +35,59 @@ /// `CONFIG_PHYS_ADDR_T_64BIT`, and it can be a u64 even on 32-bit archite= ctures. pub type ResourceSize =3D bindings::resource_size_t; =20 +/// Untyped I/O region. +/// +/// This type can be used when an I/O region without known type informatio= n has a compile-time known +/// minimum size (and a runtime known actual size). +/// +/// This must be naturally aligned to `usize`. +/// +/// # Invariants +/// +/// Size of the region is at least as large as the `SIZE` generic paramete= r. +#[repr(C)] +#[cfg_attr(CONFIG_64BIT, repr(align(8)))] +#[cfg_attr(not(CONFIG_64BIT), repr(align(4)))] +pub struct Region { + inner: [u8], +} + +impl Region { + /// Create a raw mutable pointer from given base address and size. + /// + /// `size` should be at least as large as the minimum size `SIZE` to u= phold the type invariant. + /// + /// Just like other methods on raw pointers, it is not unsafe to creat= e a raw pointer + /// that does not uphold the type invariants. However such pointers ar= e not valid. + #[inline] + pub fn ptr_from_raw_parts_mut(base: *mut u8, size: usize) -> *mut Self= { + core::ptr::slice_from_raw_parts_mut(base, size) as *mut Region + } + + /// Create a raw mutable pointer from given base address and size. + /// + /// The alignment of `base` is checked, and `size` is checked against = the minimum size specified + /// via const generics. + #[inline] + pub fn ptr_try_from_raw_parts_mut(base: *mut u8, size: usize) -> Resul= t<*mut Self> { + if size < SIZE || base.align_offset(size_of::()) !=3D 0 { + return Err(EINVAL); + } + + Ok(Self::ptr_from_raw_parts_mut(base, size)) + } +} + +impl KnownSize for Region { + const MIN_SIZE: usize =3D SIZE; + const MIN_ALIGN: Alignment =3D Alignment::new::<{ size_of::() }= >(); + + #[inline(always)] + fn size(p: *const Self) -> usize { + (p as *const [u8]).len() + } +} + /// Raw representation of an MMIO region. /// /// By itself, the existence of an instance of this structure does not pro= vide any guarantees that @@ -85,7 +142,6 @@ pub fn maxsize(&self) -> usize { /// ffi::c_void, /// io::{ /// Io, -/// IoKnownSize, /// Mmio, /// MmioRaw, /// PhysAddr, @@ -241,12 +297,25 @@ fn offset(self) -> usize { /// For MMIO regions, all widths (u8, u16, u32, and u64 on 64-bit systems)= are typically /// supported. For PCI configuration space, u8, u16, and u32 are supported= but u64 is not. pub trait Io { + /// Type of this I/O region. For untyped regions, [`Region`] can be us= ed. + type Target: ?Sized + KnownSize; + /// Returns the base address of this mapping. fn addr(&self) -> usize; =20 /// Returns the maximum size of this mapping. fn maxsize(&self) -> usize; =20 + /// Returns the absolute I/O address for a given `offset`, + /// performing compile-time bound checks. + // Always inline to optimize out error path of `build_assert`. + #[inline(always)] + fn io_addr_assert(&self, offset: usize) -> usize { + build_assert!(offset_valid::(offset, Self::Target::MIN_SIZE)); + + self.addr() + offset + } + /// Returns the absolute I/O address for a given `offset`, /// performing runtime bound checks. #[inline] @@ -336,7 +405,7 @@ fn try_write64(&self, value: u64, offset: usize) -> Res= ult #[inline(always)] fn read8(&self, offset: usize) -> u8 where - Self: IoKnownSize + IoCapable, + Self: IoCapable, { self.read(offset) } @@ -345,7 +414,7 @@ fn read8(&self, offset: usize) -> u8 #[inline(always)] fn read16(&self, offset: usize) -> u16 where - Self: IoKnownSize + IoCapable, + Self: IoCapable, { self.read(offset) } @@ -354,7 +423,7 @@ fn read16(&self, offset: usize) -> u16 #[inline(always)] fn read32(&self, offset: usize) -> u32 where - Self: IoKnownSize + IoCapable, + Self: IoCapable, { self.read(offset) } @@ -363,7 +432,7 @@ fn read32(&self, offset: usize) -> u32 #[inline(always)] fn read64(&self, offset: usize) -> u64 where - Self: IoKnownSize + IoCapable, + Self: IoCapable, { self.read(offset) } @@ -372,7 +441,7 @@ fn read64(&self, offset: usize) -> u64 #[inline(always)] fn write8(&self, value: u8, offset: usize) where - Self: IoKnownSize + IoCapable, + Self: IoCapable, { self.write(offset, value) } @@ -381,7 +450,7 @@ fn write8(&self, value: u8, offset: usize) #[inline(always)] fn write16(&self, value: u16, offset: usize) where - Self: IoKnownSize + IoCapable, + Self: IoCapable, { self.write(offset, value) } @@ -390,7 +459,7 @@ fn write16(&self, value: u16, offset: usize) #[inline(always)] fn write32(&self, value: u32, offset: usize) where - Self: IoKnownSize + IoCapable, + Self: IoCapable, { self.write(offset, value) } @@ -399,7 +468,7 @@ fn write32(&self, value: u32, offset: usize) #[inline(always)] fn write64(&self, value: u64, offset: usize) where - Self: IoKnownSize + IoCapable, + Self: IoCapable, { self.write(offset, value) } @@ -582,7 +651,7 @@ fn try_update(&self, location: L, f: F) -> Res= ult fn read(&self, location: L) -> T where L: IoLoc, - Self: IoKnownSize + IoCapable, + Self: IoCapable, { let address =3D self.io_addr_assert::(location.offset()= ); =20 @@ -614,7 +683,7 @@ fn read(&self, location: L) -> T fn write(&self, location: L, value: T) where L: IoLoc, - Self: IoKnownSize + IoCapable, + Self: IoCapable, { let address =3D self.io_addr_assert::(location.offset()= ); let io_value =3D value.into(); @@ -658,7 +727,7 @@ fn write_reg(&self, value: V) where L: IoLoc, V: LocatedRegister, - Self: IoKnownSize + IoCapable, + Self: IoCapable, { let (location, value) =3D value.into_io_op(); =20 @@ -690,7 +759,7 @@ fn write_reg(&self, value: V) fn update(&self, location: L, f: F) where L: IoLoc, - Self: IoKnownSize + IoCapable + Sized, + Self: IoCapable + Sized, F: FnOnce(T) -> T, { let address =3D self.io_addr_assert::(location.offset()= ); @@ -704,28 +773,6 @@ fn update(&self, location: L, f: F) } } =20 -/// Trait for types with a known size at compile time. -/// -/// This trait is implemented by I/O backends that have a compile-time kno= wn size, -/// enabling the use of infallible I/O accessors with compile-time bounds = checking. -/// -/// Types implementing this trait can use the infallible methods in [`Io`]= trait -/// (e.g., `read8`, `write32`), which require `Self: IoKnownSize` bound. -pub trait IoKnownSize: Io { - /// Minimum usable size of this region. - const MIN_SIZE: usize; - - /// Returns the absolute I/O address for a given `offset`, - /// performing compile-time bound checks. - // Always inline to optimize out error path of `build_assert`. - #[inline(always)] - fn io_addr_assert(&self, offset: usize) -> usize { - build_assert!(offset_valid::(offset, Self::MIN_SIZE)); - - self.addr() + offset - } -} - /// Implements [`IoCapable`] on `$mmio` for `$ty` using `$read_fn` and `$w= rite_fn`. macro_rules! impl_mmio_io_capable { ($mmio:ident, $(#[$attr:meta])* $ty:ty, $read_fn:ident, $write_fn:iden= t) =3D> { @@ -758,6 +805,8 @@ unsafe fn io_write(&self, value: $ty, address: usize) { ); =20 impl Io for Mmio { + type Target =3D Region; + /// Returns the base address of this mapping. #[inline] fn addr(&self) -> usize { @@ -771,10 +820,6 @@ fn maxsize(&self) -> usize { } } =20 -impl IoKnownSize for Mmio { - const MIN_SIZE: usize =3D SIZE; -} - impl Mmio { /// Converts an `MmioRaw` into an `Mmio` instance, providing the acces= sors to the MMIO mapping. /// @@ -798,6 +843,8 @@ pub unsafe fn from_raw(raw: &MmioRaw) -> &Self { pub struct RelaxedMmio(Mmio); =20 impl Io for RelaxedMmio { + type Target =3D Region; + #[inline] fn addr(&self) -> usize { self.0.addr() @@ -809,10 +856,6 @@ fn maxsize(&self) -> usize { } } =20 -impl IoKnownSize for RelaxedMmio { - const MIN_SIZE: usize =3D SIZE; -} - impl Mmio { /// Returns a [`RelaxedMmio`] reference that performs relaxed I/O oper= ations. /// diff --git a/rust/kernel/pci.rs b/rust/kernel/pci.rs index 5071cae6543f..c6d6bd8f251d 100644 --- a/rust/kernel/pci.rs +++ b/rust/kernel/pci.rs @@ -43,7 +43,6 @@ pub use self::io::{ Bar, ConfigSpace, - ConfigSpaceKind, ConfigSpaceSize, Extended, Normal, // diff --git a/rust/kernel/pci/io.rs b/rust/kernel/pci/io.rs index 0461e01aaa20..b4996aa059d8 100644 --- a/rust/kernel/pci/io.rs +++ b/rust/kernel/pci/io.rs @@ -10,11 +10,12 @@ io::{ Io, IoCapable, - IoKnownSize, Mmio, - MmioRaw, // + MmioRaw, + Region, // }, - prelude::*, // + prelude::*, + ptr::KnownSize, // }; use core::{ marker::PhantomData, @@ -46,28 +47,21 @@ pub const fn into_raw(self) -> usize { } } =20 -/// Marker type for normal (256-byte) PCI configuration space. -pub struct Normal; +/// Alias for normal (256-byte) PCI configuration space. +pub type Normal =3D Region<256>; =20 -/// Marker type for extended (4096-byte) PCIe configuration space. -pub struct Extended; +/// Alias for extended (4096-byte) PCIe configuration space. +pub type Extended =3D Region<4096>; =20 /// Trait for PCI configuration space size markers. /// /// This trait is implemented by [`Normal`] and [`Extended`] to provide /// compile-time knowledge of the configuration space size. -pub trait ConfigSpaceKind { - /// The size of this configuration space in bytes. - const SIZE: usize; -} +pub trait ConfigSpaceKind: KnownSize {} =20 -impl ConfigSpaceKind for Normal { - const SIZE: usize =3D 256; -} +impl ConfigSpaceKind for Normal {} =20 -impl ConfigSpaceKind for Extended { - const SIZE: usize =3D 4096; -} +impl ConfigSpaceKind for Extended {} =20 /// The PCI configuration space of a device. /// @@ -77,7 +71,7 @@ impl ConfigSpaceKind for Extended { /// The generic parameter `S` indicates the maximum size of the configurat= ion space. /// Use [`Normal`] for 256-byte legacy configuration space or [`Extended`]= for /// 4096-byte PCIe extended configuration space (default). -pub struct ConfigSpace<'a, S: ConfigSpaceKind =3D Extended> { +pub struct ConfigSpace<'a, S: ?Sized + ConfigSpaceKind =3D Extended> { pub(crate) pdev: &'a Device, _marker: PhantomData, } @@ -85,7 +79,7 @@ pub struct ConfigSpace<'a, S: ConfigSpaceKind =3D Extende= d> { /// Implements [`IoCapable`] on [`ConfigSpace`] for `$ty` using `$read_fn`= and `$write_fn`. macro_rules! impl_config_space_io_capable { ($ty:ty, $read_fn:ident, $write_fn:ident) =3D> { - impl<'a, S: ConfigSpaceKind> IoCapable<$ty> for ConfigSpace<'a, S>= { + impl<'a, S: ?Sized + ConfigSpaceKind> IoCapable<$ty> for ConfigSpa= ce<'a, S> { unsafe fn io_read(&self, address: usize) -> $ty { let mut val: $ty =3D 0; =20 @@ -118,7 +112,9 @@ unsafe fn io_write(&self, value: $ty, address: usize) { impl_config_space_io_capable!(u16, pci_read_config_word, pci_write_config_= word); impl_config_space_io_capable!(u32, pci_read_config_dword, pci_write_config= _dword); =20 -impl<'a, S: ConfigSpaceKind> Io for ConfigSpace<'a, S> { +impl<'a, S: ?Sized + ConfigSpaceKind> Io for ConfigSpace<'a, S> { + type Target =3D S; + /// Returns the base address of the I/O region. It is always 0 for con= figuration space. #[inline] fn addr(&self) -> usize { @@ -132,10 +128,6 @@ fn maxsize(&self) -> usize { } } =20 -impl<'a, S: ConfigSpaceKind> IoKnownSize for ConfigSpace<'a, S> { - const MIN_SIZE: usize =3D S::SIZE; -} - /// A PCI BAR to perform I/O-Operations on. /// /// I/O backend assumes that the device is little-endian and will automati= cally diff --git a/rust/kernel/ptr.rs b/rust/kernel/ptr.rs index 3f3e529e9f58..82acb531b17b 100644 --- a/rust/kernel/ptr.rs +++ b/rust/kernel/ptr.rs @@ -235,11 +235,20 @@ fn align_up(self, alignment: Alignment) -> Option { /// /// This is a generalization of [`size_of`] that works for dynamically siz= ed types. pub trait KnownSize { + /// Minimum size of this type known at compile-time. + const MIN_SIZE: usize; + + /// Minimum alignment of this type known at compile-time. + const MIN_ALIGN: Alignment; + /// Get the size of an object of this type in bytes, with the metadata= of the given pointer. fn size(p: *const Self) -> usize; } =20 impl KnownSize for T { + const MIN_SIZE: usize =3D size_of::(); + const MIN_ALIGN: Alignment =3D Alignment::of::(); + #[inline(always)] fn size(_: *const Self) -> usize { size_of::() @@ -247,6 +256,9 @@ fn size(_: *const Self) -> usize { } =20 impl KnownSize for [T] { + const MIN_SIZE: usize =3D 0; + const MIN_ALIGN: Alignment =3D Alignment::of::(); + #[inline(always)] fn size(p: *const Self) -> usize { p.len() * size_of::() --=20 2.54.0 From nobody Thu Jun 25 00:35:31 2026 Received: from LO3P265CU004.outbound.protection.outlook.com (mail-uksouthazon11020097.outbound.protection.outlook.com [52.101.196.97]) (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 19E9F3EBF02; Mon, 8 Jun 2026 19:59:20 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=52.101.196.97 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780948762; cv=fail; b=ufyKn0Jz9lDC/2yyLP970RR/jXDVP/tw29J++IY+HXIW0293aFq9khLGLnGn7cT5N2+/pjYi1mBf55ztNQvTKJZldqy4/wu8RexaJTIeGhgaHf/17tb9b2W8fOy3XgWdo/VGql60/ilVDH2m58jyfCVz/7CFIymUGqgwSRc/WAE= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780948762; c=relaxed/simple; bh=1dBGnRtZtvrGIAto6rLiWeZm1SPdkIb+ZmTkOAo6zpo=; h=From:Date:Subject:Content-Type:Message-Id:References:In-Reply-To: To:Cc:MIME-Version; b=M3aPnuhd2XgHFi6M6hmRWsuTwwXyNVb9xhWblZ1/rojThfg7NCtKP2CJ82IEUx+Ws5n6FgcD0QX7fhEfFJFud/2i7cgU4aclGlalcfvuGQGRq0bx7PC2gIVMC2b8ojwWQhUUqXwvigO/M84sgHGTK+FRn4cVt2WDrrGy9Z6rtU4= 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=O8tEO63g; arc=fail smtp.client-ip=52.101.196.97 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="O8tEO63g" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=w0eVdod6vQoB0+cgzapRY2EKhAz+G6kdIrsJRlUXdLJmx5BoEoz/VKo8VN2+tk4hJGHQ2ZF6JtRh5nKhn3muxJXMo9ehoMTL9WhHryEVfpaQ7Dd4BmA2ry+lG9eQ6qwuDYgS8RkbhzXrSY9jsLTtIthsmgwrKh4OvmiaEtoFvvrSZoVOGfmSa+N4OFpL+96H8ml8it43Rq/CGeShqaHD8Uibzgs7J/PWnIiaZ4Fpb9gMVkfV91sW2ANk6a1ntwUkn0P5flwpdvBXZ+xuBSNLm3a40U11WnU2NBhIvYowBpbf0vfFxMpIknHY+JKtDOf6Y6syT1zpPyl8HX1Va69Bkg== 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=Rj8tPZ70X73pJLFJzHDL00y/CnyDaT2yCg0XffJ9Qg4=; b=scLBiNQvzH4kDV05/3Flb+dpsUexBhhBL7QvhQ8yj8UFKqWD/MCqXDTQSbHUMsdOW4nclM22p2UhQ0Cnohl1ci5eZwt9WX0joRcvQWrOyMuSRAfXzc5NohGLL+KTYhFV5vECMiWqBG/1tesAd3GA9Qu85F0igvz4vG1Vru0dgv+RrSXaAN1VeamG/Ljr/RxLQqzfxQ0d7AmCm3ioQ+W1+dMOHEeFu0nITonk5i5kQLx25RP5i/jghbYCo9MWvqzPnA3kNAbeQIaCWCMsLG6zxItpqINw5esSWP2R3O7j8iSitqoCE0LBAWbnHilx6lW/4cYoL9Pu5ajDei0vlqRfLw== 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=Rj8tPZ70X73pJLFJzHDL00y/CnyDaT2yCg0XffJ9Qg4=; b=O8tEO63gZ2m/jQgvSTHUe9DW6jknJxBDVgk6MMIcEIpsUHl9DLyMKpaxlFZzwnzNvYHnr74MlFwx/aeRAgXwiHecL+s4z8HdngQyHp0ps6W508PPqPgVhqImKYrk8ozcexPtLgy5Vu7W+b4GwAGUrQsIvF3ipfy5ZGGiIXhGMJs= Authentication-Results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=garyguo.net; Received: from LOVP265MB8871.GBRP265.PROD.OUTLOOK.COM (2603:10a6:600:488::16) by LO8P265MB7398.GBRP265.PROD.OUTLOOK.COM (2603:10a6:600:3ca::5) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.21.92.12; Mon, 8 Jun 2026 19:59:08 +0000 Received: from LOVP265MB8871.GBRP265.PROD.OUTLOOK.COM ([fe80::1c3:ceba:21b4:9986]) by LOVP265MB8871.GBRP265.PROD.OUTLOOK.COM ([fe80::1c3:ceba:21b4:9986%4]) with mapi id 15.21.0092.011; Mon, 8 Jun 2026 19:59:08 +0000 From: Gary Guo Date: Mon, 08 Jun 2026 20:58:59 +0100 Subject: [PATCH v3 02/19] rust: io: add missing safety requirement in `IoCapable` methods Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260608-io_projection-v3-2-c5cde13a5ec4@garyguo.net> References: <20260608-io_projection-v3-0-c5cde13a5ec4@garyguo.net> In-Reply-To: <20260608-io_projection-v3-0-c5cde13a5ec4@garyguo.net> To: Danilo Krummrich , Alice Ryhl , Daniel Almeida , Greg Kroah-Hartman , "Rafael J. Wysocki" , Miguel Ojeda , Boqun Feng , Gary Guo , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Andreas Hindborg , Trevor Gross , Bjorn Helgaas , =?utf-8?q?Krzysztof_Wilczy=C5=84ski?= , Abdiel Janulgue , Robin Murphy , Alexandre Courbot , David Airlie , Simona Vetter Cc: driver-core@lists.linux.dev, rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, linux-pci@vger.kernel.org, nova-gpu@lists.linux.dev, dri-devel@lists.freedesktop.org X-Mailer: b4 0.15.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1780948747; l=3404; i=gary@garyguo.net; s=20221204; h=from:subject:message-id; bh=1dBGnRtZtvrGIAto6rLiWeZm1SPdkIb+ZmTkOAo6zpo=; b=ZzASpkW5Y2YhBk/fsxqiSe5SkjhlvZA1L1Ofb/stCyYtoH6RHVDyLCPDQ6JcgMm+q/2XZ0ZCR h/QRvt3QJDWA3DqSFDDX4jRu7/ysmFujGmlkydsoQZH5qWY8JpRnmUg X-Developer-Key: i=gary@garyguo.net; a=ed25519; pk=vB3uIX95SM4eVrIqo1DWNWKDKD2xzB+yLLLr0yOPYMo= X-ClientProxiedBy: LO4P123CA0344.GBRP123.PROD.OUTLOOK.COM (2603:10a6:600:18d::7) To LOVP265MB8871.GBRP265.PROD.OUTLOOK.COM (2603:10a6:600:488::16) 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: LOVP265MB8871:EE_|LO8P265MB7398:EE_ X-MS-Office365-Filtering-Correlation-Id: 47598c69-a3b6-4933-587e-08dec5986709 X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|1800799024|7416014|376014|366016|10070799003|6133799003|22082099003|18002099003|921020|56012099006|5023799004; X-Microsoft-Antispam-Message-Info: k8lDbi1I0sXj3oSx+b5dU7peJ+z7C2x/j6cG9ZILEboxhAppE4PKbQ7wQYKgjGCSCDJVlOjIGtH6eNZH1425AL9IsMphi2vlCafGWEzlvJNtHXFaecO4IL3BUk5lqLPkYW6PV4dxL65+a+JK0q23K9cToXOm7qXi+8SCW4gyi92TyvsU8tPESOq3b0k7r+Scg7/5pO20bF4e5hYNIYXzvjFFF071bhON2UC/vX7TLjrOfK3MX70vR9cQaox49mLT7bPFyhg8/XFoYZ9l2FhEfSXT1Mtbn7afZ6w7ckoTG7FjQX3/vuDM6bmOT4fmemAmAwB5qRta60MMwIfnbxw56HZnaxFP9p1+6rjvVanp7xD+M4nhh6yYQJwJXAsSeEMk8tivNPveHscjMgHrGK92N88WrwAPU5fFb14B/i2a1kwYgfWNYx/mF5IzKw9amGedq/YTEzLGWPNQTkCFeF4v1ze98JxCrmf5z3HVTo3fpX/Z5JBf+HImshp5vVQsfr1kgkAOYZ3VE+ofH/jNg5rHkdADMSog6xIZI2Szgk0KWK7CKGPjA9jtbR8ja7evVe2US0OVPKogrYvRXi2RlD6plJpjut4tJ+wccOHnniOwaKOoUq4vTE9c5voeHMTOGzLFQknum5YKzE5bklV1k8SHsbwfCjc3Pn6MVjryBQaAi024ZTBKyGzuQjLReTz6rfMVjtXEUJ3xHUTNdmOPguGpiGSS4SP7NjcpTsxEK5l08Qo= X-Forefront-Antispam-Report: CIP:255.255.255.255;CTRY:;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:LOVP265MB8871.GBRP265.PROD.OUTLOOK.COM;PTR:;CAT:NONE;SFS:(13230040)(1800799024)(7416014)(376014)(366016)(10070799003)(6133799003)(22082099003)(18002099003)(921020)(56012099006)(5023799004);DIR:OUT;SFP:1102; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: =?utf-8?B?WFcrZ0RLUUpyYitMMUNlVG4xWFlWMDVTOWdWcXVVeElrSjFsTER1SU4rMUtF?= =?utf-8?B?c3VDbHVDTWZMN1p4aW5Yc1R2Uk5XQU5nOUk2WkkrSExDVmxuTWhLSTdyaW1u?= =?utf-8?B?MjJ3Y2NIK2NXcEtLc3VnNU1WWXZRSi9yYjdkQWFHbFVVZFRCL1h3UGZVZjZk?= =?utf-8?B?QzVMV3dGN3dpTWdWbng4Z2Y4ZXIrL2NQQzloQURhSlh3WkEzMHdlMlM1Tjk0?= =?utf-8?B?NEVUM25KUGFZTnR6d0FST1VhYmttby9pcWY1K0o5UmorQ01hSENHUVpBMWpr?= =?utf-8?B?ZSt6YmljazhiSUJOeEppK0J0cDJjQ3NhK1VkbWhQbjJuL1pUVkV1V05HcUk5?= =?utf-8?B?Unh6UzBUUGcyWUxpZngvdC9Ka2hRQlJobm1NQ3AvNHF2ZzhnbnZjRE1uNE5M?= =?utf-8?B?dlU1SFdHeTNzZzJYSlRqbjFyYkljM3JBWWRwSGhtWW10ejFBMWhBUDJTWGNY?= =?utf-8?B?Q1dvWGxidEdjUkIySGhJN1ZTTnJDQjN0eks3RDhFRXp4eXE2dlRRSEp0RTZk?= =?utf-8?B?WWg2ZjAweFFQSzJBOE5EbW5JMXRqLzZvWk8wSXBYYkkvelB2TXhPVHBZUDU1?= =?utf-8?B?NWZjYTYwNVZ6VkVDRjBSVWQ4TmRJVi8wOFFVNkZRZHBOWmovcTkwQ25OZzAz?= =?utf-8?B?b2kwM3Y4NUtmOHF1dEZObzVoME9mNnMwMjY1M1RJOUNBQjNOL2lHOEdLLzlw?= =?utf-8?B?VDFRbmR4TXNEa1ltUWtvRTkwalZJY0kvaGV4ZTF3V2c1cXRxOEpZeW95RnJw?= =?utf-8?B?by9GcGI3N1JncFAxc1U0bDdFZHJEdlh4WVdrMC9TNU9SRDdUNyt3TjFLWG1s?= =?utf-8?B?eXBKdGU5TFc5dXFjU0d2eEVQUDNqK0ZBSEZETDl5ZmNyRjRCVHQrT2tmaFFl?= =?utf-8?B?UE1CczlPYnJER0pCbTY0TTBQVVZNZlFtU3JVQnlCdGpsakRubHJzMWFOWTZ0?= =?utf-8?B?cC95eVV5cUNQdUdVcm9pUER3WmFNcDNaNWMxblo1Qmx4cHQrVUErSmFCeWhi?= =?utf-8?B?cTUyT1d4bzVZTmcrUi9iRUtKbWlha2Uwa1RaMStSWkxDRnJ6ZVJXQnpDa3g3?= =?utf-8?B?amUycjJZSE9pVUNwQlBybHRhWE83ckVsQ2ZEY0lKcDAxOU9MbUhmdS9xRWpG?= =?utf-8?B?UEZZQ3lhcUJ5aXhyaTJ4MjRvTXJyaEZScGlBbThKRlNqc3BhdCs5MlpteHJp?= =?utf-8?B?VDh3V0gxZTdBdmdBSmpnWDFsakdadzRQTXRXdUphU2ZKUzFXeEV6YmkxaG9R?= =?utf-8?B?QUhMRmpZMFY1N1R1cGF0YlhzSU5mUG44RWNRNFRNbnJYaWpqdC8yeEdiTUw1?= =?utf-8?B?RUo5cEpWdGpvZysyT01aSmh3NDNoQjFxSE5aYlF1YmpXMlJhUHN2ckFkcW9S?= =?utf-8?B?THFXNEdmeTBwcHJWSFJ5SWU4STBtYkR2YkE2WjAzeURyaXBTQnVuVzBJZ1da?= =?utf-8?B?US95dTRZTDUxS2JsOHdLM1lrdklaYzZmMHJzNThWUW1xZDVpN3hCdDRrOWFu?= =?utf-8?B?L1JWTC9RV2pCMDloSzgzbnJtVmVrWWE1WVF5SEJhaEJoZmxrUEVSTndnMU12?= =?utf-8?B?TjU1WE9LeHVJN2t6eXowc0YxaHJzRXRRTVhQUHhsU25pQXZjVG5Xc3hZeWtI?= =?utf-8?B?WHVIMFVjbzU1NmdtNG9iMWptUGFWVncwaE0zZ01NcnNWcW5DbFJ2SjVsdTN4?= =?utf-8?B?VFF3QzZVbkJNaHpRSllhTllCUWNOR25DTEV4bmc2eFFvVVpKSStpL0R0NDBE?= =?utf-8?B?NFVTbHlKbkM0VFZRUkc3THdBQTJwM1FpTjl0Y0hOazR0U3lyK0pQQjBZM1hl?= =?utf-8?B?VjFoc2VkSnFXREJrZmp4Ky9jVnMrZGN6OEFvck0vN25McGR3MVZ2djJzMFMr?= =?utf-8?B?KzErT0tjSGU1Ni9pVDVSdWlaVXo5dENoaXN6ODJseU51WWRWb1VOVnlOaElN?= =?utf-8?B?RWtjTHJEZDNtVFNwTmo0bnhQVnBRSm45N2tIOUVlSlNOS2RDQWpKa1l0VFhR?= =?utf-8?B?dHF2MWJzRmNCMzRMMS9WenNvdUZ3bnVlTUhPVEliWWhxNGpUc0FmYU5zb2o0?= =?utf-8?B?YnUyTXlLelVxaUwyQXozNEF1ZklYLzNYdkhMU0VTNVo5NEZrMXNWdFdaNk13?= =?utf-8?B?VXl4UFkyVkZ2eGhtb2FjaWVSSnV3bG1uZGlYSjdmZEdOSmx0VlY0UkFURDRy?= =?utf-8?B?ZjcvS25OTy9jSFNwY29RTGp1VkJVcVgrQU5CTGV1NWc4ZytEYXcyTTVxSlhU?= =?utf-8?B?M2I3UTdIeTJaYXRnSEFOR2k2M3psb0FsZjBqNldnZkdiSUcwQTZCYzJncTZQ?= =?utf-8?B?dVpBK0lPNE1DNnhoYmRXN0srekVhbUFrWWRnd0NtaG81bCtlZmxYUT09?= X-OriginatorOrg: garyguo.net X-MS-Exchange-CrossTenant-Network-Message-Id: 47598c69-a3b6-4933-587e-08dec5986709 X-MS-Exchange-CrossTenant-AuthSource: LOVP265MB8871.GBRP265.PROD.OUTLOOK.COM X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 08 Jun 2026 19:59:08.8208 (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: +cMpr8zKf+kvDAc3tyb7YLGUu3BvWnCkwbeFYmSYD0R1mzXBtS0undqpsmmGT/WmsUa5EuYUicd3mSM1CUYd1w== X-MS-Exchange-Transport-CrossTenantHeadersStamped: LO8P265MB7398 The current safety comment on `io_read`/`io_write` does not cover the topic about alignment. Add it so it can be relied on by implementor of `IoCapable`. Expand the check `Io` by taking `self.addr()` into consideration when checking if `offset` is aligned. For the compile-time `io_addr_assert` check, check using the known minimum alignment of `IO::Target` and the accessed type. Signed-off-by: Gary Guo Suggested-by: Danilo Krummrich --- rust/kernel/io.rs | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/rust/kernel/io.rs b/rust/kernel/io.rs index dcf3b40ffa48..a58fb9a21dca 100644 --- a/rust/kernel/io.rs +++ b/rust/kernel/io.rs @@ -197,13 +197,15 @@ pub fn maxsize(&self) -> usize { #[repr(transparent)] pub struct Mmio(MmioRaw); =20 -/// Checks whether an access of type `U` at the given `offset` +/// Checks whether an access of type `U` at the given `base` and the given= `offset` /// is valid within this region. +/// +/// The `base` is used for alignment checking only. This can be set to 0 t= o skip the check. #[inline] -const fn offset_valid(offset: usize, size: usize) -> bool { +const fn offset_valid(base: usize, offset: usize, size: usize) -> bool { let type_size =3D core::mem::size_of::(); if let Some(end) =3D offset.checked_add(type_size) { - end <=3D size && offset % type_size =3D=3D 0 + end <=3D size && (base.wrapping_add(offset) % type_size =3D=3D 0) } else { false } @@ -222,14 +224,16 @@ pub trait IoCapable { /// /// # Safety /// - /// The range `[address..address + size_of::()]` must be within the= bounds of `Self`. + /// - The range `[address..address + size_of::()]` must be within t= he bounds of `Self`. + /// - `address` must be aligned. unsafe fn io_read(&self, address: usize) -> T; =20 /// Performs an I/O write of `value` at `address`. /// /// # Safety /// - /// The range `[address..address + size_of::()]` must be within the= bounds of `Self`. + /// - The range `[address..address + size_of::()]` must be within t= he bounds of `Self`. + /// - `address` must be aligned. unsafe fn io_write(&self, value: T, address: usize); } =20 @@ -311,7 +315,11 @@ pub trait Io { // Always inline to optimize out error path of `build_assert`. #[inline(always)] fn io_addr_assert(&self, offset: usize) -> usize { - build_assert!(offset_valid::(offset, Self::Target::MIN_SIZE)); + // We cannot check alignment with `offset_valid` using `self.addr(= )`. So set 0 for it and + // ensure alignment by checking that the alignment of `U` is small= er or equal to the + // alignment of `Self::Target`. + const_assert!(Alignment::of::().as_usize() <=3D Self::Target::M= IN_ALIGN.as_usize()); + build_assert!(offset_valid::(0, offset, Self::Target::MIN_SIZE)= ); =20 self.addr() + offset } @@ -320,7 +328,7 @@ fn io_addr_assert(&self, offset: usize) -> usize { /// performing runtime bound checks. #[inline] fn io_addr(&self, offset: usize) -> Result { - if !offset_valid::(offset, self.maxsize()) { + if !offset_valid::(self.addr(), offset, self.maxsize()) { return Err(EINVAL); } =20 --=20 2.54.0 From nobody Thu Jun 25 00:35:31 2026 Received: from LO3P265CU004.outbound.protection.outlook.com (mail-uksouthazon11020097.outbound.protection.outlook.com [52.101.196.97]) (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 1B6DA3E95A3; Mon, 8 Jun 2026 19:59:16 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=52.101.196.97 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780948759; cv=fail; b=JyaJQTxK7bRn78VE5kFgCIGuDpQK9QFRjuvTZwjTizKVK7K+hQDZNyjx+x3NYdo1jjwImxdgqz7XmyFdP2i5rO/9+fwKiEvbA6KLrHUlpr/5KQXapBev7xg48156lsnzT83VS7VouU6GpAMSpOI4dFIJ+ml012lOxv5dNQZ5V8M= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780948759; c=relaxed/simple; bh=sODMu6MRVgP3YcejTtcK6aCyOtgfeoRVQ+EUOWCLFtA=; h=From:Date:Subject:Content-Type:Message-Id:References:In-Reply-To: To:Cc:MIME-Version; b=JHin5MGGiyhjAGwbxqQdtgIh9kDtZh4mwTE/qna/wDGPux7fGBOEVk+KEh3gutPbM8s8NwWlBLEV4/acMe/YObDal81ILil2BbRO0sXSv78O7uLTqGcQrbNor6TfR7RaDiT97UjNhPnNDJit6lIzHiPNPCbZbchqjygf8hCSbVc= 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=xKUXMb3l; arc=fail smtp.client-ip=52.101.196.97 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="xKUXMb3l" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=Zd34Uz3E1e+mBenqGQVDzKgjM8D0oq+8zKe8NEmgXbObjxzvCXlxX8q+PSQ4jQVpxVb24SsN4iHIbFlObn+RCCdP1a7eim6/vzGOZ27S3avRsP1PTlXDa9YcQ0q7hZUNZxipif5TZXk6wBKM0CNtRTZtB13ozvaS8YIslmv5Js7cIAQtrdqRV24CUfZET4XCHzdUFgvFPEQ3qSUI82Z0CmFrBXMQwJaDMr52EGR4lJ7nFB0cKgi6X2mwxkolnGwKn706K17r2ISxgXXlN1aUjAMsh4a66unSVL9OOob41Tq97GSgXMvdYmuZ4V4AlBzuFG3V/VzFJpn/ExrxAERdDA== 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=wU60pSIXUGtF45W9Ve4tE6xmWzaNVy3oYOJUKZViNd8=; b=Tz5K4zG4vXk3s2idAfcsZx2AIWcBFZAhiLsz8sV1pUDTJyM4G+igl+UJ15aEMZjUVT6ojXqWhA4S2UjdZHgQiHrjT206al0rUjs6p1DBx1Ku7eVmIYAhPQT1IBVMIlOJ2q19cACGsQun8DLPqO82TJunqfX94Mj31cOy0lsqaAu4KQyi2xNEbJwklW4G7vMumrQNGgcCYxzAR1uYXd7+9Ne3EhcRFdUPZn3b1xzhyQdIDajeGXRPwjPEobjWzOvTnTiUjhdvQtMiGB9Wf1oPTzLMDQHd3FJgyWelUtBsDPrSvwTXbPHouyf2YKlF47YfpQnA1vPpTuWyHW/mY8e9cg== 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=wU60pSIXUGtF45W9Ve4tE6xmWzaNVy3oYOJUKZViNd8=; b=xKUXMb3lPZqbNsZdpBQEIkyfUmeZQNKUopFt2+jGt66H1lhp42sY60lYwefwx9CjIL0zTCDHPAf5xhp340Pq25l1u9M/G135V7OmyrXTdrJw/O6hxsRKAI6EOdBgpzDAima+kj4yNYhE3Xp5OMqXBY8kIRBGbi0flP7QLtGW/jQ= Authentication-Results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=garyguo.net; Received: from LOVP265MB8871.GBRP265.PROD.OUTLOOK.COM (2603:10a6:600:488::16) by LO8P265MB7398.GBRP265.PROD.OUTLOOK.COM (2603:10a6:600:3ca::5) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.21.92.12; Mon, 8 Jun 2026 19:59:09 +0000 Received: from LOVP265MB8871.GBRP265.PROD.OUTLOOK.COM ([fe80::1c3:ceba:21b4:9986]) by LOVP265MB8871.GBRP265.PROD.OUTLOOK.COM ([fe80::1c3:ceba:21b4:9986%4]) with mapi id 15.21.0092.011; Mon, 8 Jun 2026 19:59:09 +0000 From: Gary Guo Date: Mon, 08 Jun 2026 20:59:00 +0100 Subject: [PATCH v3 03/19] rust: io: restrict untyped IO access and `register!` to `Region` Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260608-io_projection-v3-3-c5cde13a5ec4@garyguo.net> References: <20260608-io_projection-v3-0-c5cde13a5ec4@garyguo.net> In-Reply-To: <20260608-io_projection-v3-0-c5cde13a5ec4@garyguo.net> To: Danilo Krummrich , Alice Ryhl , Daniel Almeida , Greg Kroah-Hartman , "Rafael J. Wysocki" , Miguel Ojeda , Boqun Feng , Gary Guo , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Andreas Hindborg , Trevor Gross , Bjorn Helgaas , =?utf-8?q?Krzysztof_Wilczy=C5=84ski?= , Abdiel Janulgue , Robin Murphy , Alexandre Courbot , David Airlie , Simona Vetter Cc: driver-core@lists.linux.dev, rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, linux-pci@vger.kernel.org, nova-gpu@lists.linux.dev, dri-devel@lists.freedesktop.org X-Mailer: b4 0.15.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1780948747; l=13430; i=gary@garyguo.net; s=20221204; h=from:subject:message-id; bh=sODMu6MRVgP3YcejTtcK6aCyOtgfeoRVQ+EUOWCLFtA=; b=yVo1ZBL9Ao1tAkhmFfXt4CCOlinPtIy4qMQ8L1qHdMtrSKERI9IDCpcOsstZdxP5BgNdzJjUl lSm3QUTUNcsDWRBQNvG/4TBg666ys7LP5z6WyxIl3Um5CZHw8ryoet5 X-Developer-Key: i=gary@garyguo.net; a=ed25519; pk=vB3uIX95SM4eVrIqo1DWNWKDKD2xzB+yLLLr0yOPYMo= X-ClientProxiedBy: LO4P123CA0344.GBRP123.PROD.OUTLOOK.COM (2603:10a6:600:18d::7) To LOVP265MB8871.GBRP265.PROD.OUTLOOK.COM (2603:10a6:600:488::16) 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: LOVP265MB8871:EE_|LO8P265MB7398:EE_ X-MS-Office365-Filtering-Correlation-Id: 8be7e30c-c5bf-409d-a2ac-08dec5986750 X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|1800799024|7416014|376014|366016|10070799003|6133799003|22082099003|18002099003|921020|56012099006|5023799004; X-Microsoft-Antispam-Message-Info: OZ1/sTh8uZ7afQ78QXJqIAW4o8hc0i8oU//zR/foXJZm4VJRkAEituUh4w9c2AQeweg5B6Fx/Z/Oh5fQ4QCyqO+QrOwTu5iMUS+XZVgNH03W8e44OVuGcdhKf7JAEoe+JfiUh60blhdmMKDQ8Vm/bUpQkNb431dNG3yPkgClyWDIztOH/D+TDP751QK6JPs5HqECaM3pnZpSDKIuINPP+8DMYhF/5vVe0ZtfCO9WMp+3sndNZKIN1+zXVSu2Ca4j2Qyr7B/kQL9eQuh9O8gfLycCpf6IcAf5FgiLAn6wWn/Zl4jj3DED61p2FElD0W1rbkgknp1ZiEhmBrp5asrN07Lg8VYCZTujnnRIaO7odAzpA0kATqnMOnIWcMdWtRAdSLEutB7J4WYjbv0BLTh8Z6e7p1FI9BBeHY4bLzw1ibq/7LckJDTOzffhmvy9ysXdeUwwqBZ3xsOQ1RwIxF0zqrec4vdRM4zwXDFoCNs5ULdCWAiqvveWwdHy7xt1QuXvHXGwTx1nKEYR+iq/BdPY/2b/lzrxv7P8NfEaDp3U73IFulAiXm2dxq2IOZPPP6vJiSJr6tn+KvVvQXwOPVbGzG5aHKoxxgkg7/mnriVwZS0o5EFAcArAYPEyVi4kOGwF3VosBQ6BFiDA9SztuYesJdURQSkdXE1p+6NIRyhO+Bum30TDjmcbf8sP0C9wo3FMXpr8Dy43bkMxFpDIbRB1X1G+6r4wVht2qB0TDI1u2RweDLUdnmx95Bn1XGgo35kJ X-Forefront-Antispam-Report: CIP:255.255.255.255;CTRY:;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:LOVP265MB8871.GBRP265.PROD.OUTLOOK.COM;PTR:;CAT:NONE;SFS:(13230040)(1800799024)(7416014)(376014)(366016)(10070799003)(6133799003)(22082099003)(18002099003)(921020)(56012099006)(5023799004);DIR:OUT;SFP:1102; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: =?utf-8?B?ZytqOU53d0xOT1YzTGZxNTRYVDIwd3dZNTNuSldKSnhnUXRqeDlLWEx5SUpW?= =?utf-8?B?VW9LZzdxWGxjc3J3TzFDNFV3Q2NiV25PNnMzbjBhU1UvNTBNQmNmTGdtRFN5?= =?utf-8?B?aDI5amFrdW1OS3YzR3RjZHZUcGdxKzZsV1NSUk4ydHZSK2pHemcvMHN3dFRW?= =?utf-8?B?eHNlSzVwZHhjQmJmODB4eTM0YWNHZEhmaEdCbDdrUWNZS0JpbHUrMTlRTGoy?= =?utf-8?B?bFhURmFwMnY2cXp5cDFpMkk1UXJFWGd1UlJtRDhMeDcwclpjdkhHQWt0RndU?= =?utf-8?B?RTZwelcyNHIzUjB0M3R5MlFWMlgxTlIxcDZDaEI5MElCSVQ2SWcrMmpCZmM1?= =?utf-8?B?dDd2WUhWUVRDSXduckpZSHpqYWx0bDAwK0xtelV0NmJGZmNhQ0pWbkdmaUZu?= =?utf-8?B?cGhleTJMUS9xZmFncVMyVGhIaUx5SXpnRC9adDlXQkdrZ3pQMDJMOGh5bTBI?= =?utf-8?B?czhrdjF5R1BYZUt4TEJLZVU3N0Vobm1QM3BLWVIxNHcxNW5URjVSNVk5QXRS?= =?utf-8?B?ZEg1Vk54OVAxZnJ0cCtyNFA1aDBrOGx5VW5yWDVsRjF0NVNUbUdaeG9KeVh2?= =?utf-8?B?NmtpSDFiclFYYU45MGwrbXM2MkhURXl1b3c4Q3M1RWVWYU4wcUpuMnBDT2My?= =?utf-8?B?WjI3SWVoaGFIbndkNjlGdWpHMFJWMERwLzZ0SEFGYzBPZ1dGcU5ndHlXSlda?= =?utf-8?B?L1hkTitVYm1EZlM4bk4zTHFTNHF6R0FZMnZJUEVjclkvQlhJMXVSTjVCeVVU?= =?utf-8?B?azJvbmpGTkRnVTF1UlIyRnR1QjlNWUEyU0NrYTBIVWhORWhNVHJaQ1o0cXVJ?= =?utf-8?B?eEVTRTZDcnVZRmpPSDVXNytadW1oQkJ4SE96ZkhOTkFxdlhwZGNlbGVsaTlq?= =?utf-8?B?SUlpYTMvanlQNXpxRTloTURXcVZDU3pvVFVPNWlKWEppTGxNOEQ2LzFzZld6?= =?utf-8?B?MWRpZlo0bFhvcVZqWVVWWnhZMmlWalJwNTU0dTJIYm1XSURWMGc5a1FiZVdD?= =?utf-8?B?cmRibVB4UlNxaWdDUi9DWVF3TWEwSzdaazV5d3g2S21pZUs0cUtEWFJFeUpO?= =?utf-8?B?ZmJtS1d3RHFsZFFrampwN0ZhbmtsZnN1WDg2Qm5OL2dranlSSWJJOURmUVBv?= =?utf-8?B?UTU0THI2UUQ3SGZUTEc1eWlINU44MkxscXE4Y2xTNEdPZ2FKc0ZIN0pZOG5s?= =?utf-8?B?bFB1MkRNMTI3WWZCTTF4QnRiazNUOGhiS0l4MThxaEhvUGVNOXVpSlFndmJO?= =?utf-8?B?UDFFdTVqQUVxQ2JQRElCeWl2UHM0QVY1bUFWcWtpeGRvNk5LbnVlVFVPMHFO?= =?utf-8?B?YTJUTkw0T1hzVzdIdG5uT1o3Sm9PRTBoeEVaTlp0OTJUb0pzL1ZnWW8xaW9Y?= =?utf-8?B?SjlYYkZpYzBybm84b1I0VVRzU1pOVjlCd1YwY2wrWDZGRExjSXdqUWQ4VTcw?= =?utf-8?B?ME1ldTMrTk9HRFBrOEtyYkJVeXpnazRCS2tkak5EZmxyL0tjK2hkSTNWQ1dZ?= =?utf-8?B?SzRmdUE3eXZUUWRHWFdxUGwvWW5wWTJXOTBJUmovMHhvUnQxYjFKMG1oNDNC?= =?utf-8?B?c1ZoeHREZTRDblZCVkNoRW9pQmhqT3FLLzhxUHlXR3paZlA1TzhvLzVlc2NH?= =?utf-8?B?YTZtSXgwbkRWaUFJSGpNSm94ZU9DMGZLV1ozckRSODNVcWVTNm1qTVMvWDY0?= =?utf-8?B?djN2SUZ3VG1jL2ZPZzY1TlhjaWN2am1wRFBrZVlvT1hiUkl3OUdUQmlINTU0?= =?utf-8?B?Qmt6ZW8zcm10ZEFBVDhGWXoveVRiQStrYUVrRmIxYk51bWx2MUl6Tll2OWxj?= =?utf-8?B?bFdDalZJVkFZOGsza3lJZXI2TE5TTW85U3VEUHhuOEpqNVV1YStJVy9TQnNP?= =?utf-8?B?MG05Z1dGZmhOZk9WdHoyZSs4SDFEVURHY2hiYllmYkc2aE05ZlVsbE5vYXZF?= =?utf-8?B?VTdtWGdYaGNpbWFFVW1ETTluQTMrWmFzWk1WcFdFS3JwNGJjWDJHbTVpT1g0?= =?utf-8?B?c1I5S0FqWUErdDJ4dC9jaFVlQ0wvV21Bd1BJK1dmNTY5L2pWY0c1aHpCckV1?= =?utf-8?B?T2U3anVkNnQ1bEhFdnpNRU5mRm9Fd2l1a0pLSWxISDFPUGVzME0rWWpGQUpZ?= =?utf-8?B?aFlvck1lWHRiU1ZoVzFLRUlDVFZjVkNnVjNsblNXUFNVOGZDWUlsckNSazB5?= =?utf-8?B?bkt1OWROZ0JsNEJYVW0vRzkyeU55N2gzRnZhWWpSMW51WURGRFZ5TzMycHB6?= =?utf-8?B?VGZVaGdiUkhEUmppUmFPeHpCRXozSkI0eVB5SkdjQmpDVnArM1NKRThVNy9J?= =?utf-8?B?aDhoS1JoenBCeFJYaFlVL0x5L1MyVkpqejI0TjBSZXhlclpwVjdYQT09?= X-OriginatorOrg: garyguo.net X-MS-Exchange-CrossTenant-Network-Message-Id: 8be7e30c-c5bf-409d-a2ac-08dec5986750 X-MS-Exchange-CrossTenant-AuthSource: LOVP265MB8871.GBRP265.PROD.OUTLOOK.COM X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 08 Jun 2026 19:59:09.2871 (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: NRvjW97s8nhLYesbVxLy7lmv6CWNgPtJRMhCaNf50zLZ+GXC/pKr6CJW2A/xnPeK9NOw6lah8PcvqSUY5y8zlQ== X-MS-Exchange-Transport-CrossTenantHeadersStamped: LO8P265MB7398 Currently the `Io` trait exposes a bunch of untyped IO accesses, but if the `Io` region itself is typed, then it might be weird to have let io: Mmio =3D /* ... */; io.read8(1); while not unsound, it is surely strange. Thus, restrict the untyped methods and also the register macro to `Region` type only. Implement it by adding a generic type to `IoLoc` indicating allowed base types. This also paves the way to add typed register blocks in the future; for example, we could use this mechanism to block driver A's `register!()` generated macro from being used on driver B's MMIO. The same mechanism could be used for relative IO registers. These are future opportunities, and for now restrict everything to require `IoLoc, _>`. Suggested-by: Alexandre Courbot Link: https://lore.kernel.org/rust-for-linux/DHLB3RO3OSF5.2R7F27U99BKLN@nvi= dia.com/ Signed-off-by: Gary Guo Suggested-by: Danilo Krummrich --- rust/kernel/io.rs | 49 +++++++++++++++++++++++++++++++-----------= ---- rust/kernel/io/register.rs | 21 +++++++++++--------- 2 files changed, 45 insertions(+), 25 deletions(-) diff --git a/rust/kernel/io.rs b/rust/kernel/io.rs index a58fb9a21dca..5a657bb3da09 100644 --- a/rust/kernel/io.rs +++ b/rust/kernel/io.rs @@ -246,15 +246,16 @@ pub trait IoCapable { /// (for primitive types like [`u32`]) and typed ones (like those generate= d by the [`register!`] /// macro). /// -/// An `IoLoc` carries three pieces of information: +/// An `IoLoc` carries the following pieces of information: /// +/// - 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. /// /// `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`= ). -pub trait IoLoc { +pub trait IoLoc { /// Size ([`u8`], [`u16`], etc) of the I/O performed on the returned [= `offset`](IoLoc::offset). type IoType: Into + From; =20 @@ -262,12 +263,12 @@ pub trait IoLoc { fn offset(self) -> usize; } =20 -/// Implements [`IoLoc<$ty>`] for [`usize`], allowing [`usize`] to be used= as a parameter of -/// [`Io::read`] and [`Io::write`]. +/// Implements [`IoLoc, $ty>`] for [`usize`], allowing [`usiz= e`] to be used as a +/// parameter of [`Io::read`] and [`Io::write`]. macro_rules! impl_usize_ioloc { ($($ty:ty),*) =3D> { $( - impl IoLoc<$ty> for usize { + impl IoLoc, $ty> for usize { type IoType =3D $ty; =20 #[inline(always)] @@ -341,6 +342,7 @@ fn io_addr(&self, offset: usize) -> Result { #[inline(always)] fn try_read8(&self, offset: usize) -> Result where + usize: IoLoc, Self: IoCapable, { self.try_read(offset) @@ -350,6 +352,7 @@ fn try_read8(&self, offset: usize) -> Result #[inline(always)] fn try_read16(&self, offset: usize) -> Result where + usize: IoLoc, Self: IoCapable, { self.try_read(offset) @@ -359,6 +362,7 @@ fn try_read16(&self, offset: usize) -> Result #[inline(always)] fn try_read32(&self, offset: usize) -> Result where + usize: IoLoc, Self: IoCapable, { self.try_read(offset) @@ -368,6 +372,7 @@ fn try_read32(&self, offset: usize) -> Result #[inline(always)] fn try_read64(&self, offset: usize) -> Result where + usize: IoLoc, Self: IoCapable, { self.try_read(offset) @@ -377,6 +382,7 @@ fn try_read64(&self, offset: usize) -> Result #[inline(always)] fn try_write8(&self, value: u8, offset: usize) -> Result where + usize: IoLoc, Self: IoCapable, { self.try_write(offset, value) @@ -386,6 +392,7 @@ fn try_write8(&self, value: u8, offset: usize) -> Result #[inline(always)] fn try_write16(&self, value: u16, offset: usize) -> Result where + usize: IoLoc, Self: IoCapable, { self.try_write(offset, value) @@ -395,6 +402,7 @@ fn try_write16(&self, value: u16, offset: usize) -> Res= ult #[inline(always)] fn try_write32(&self, value: u32, offset: usize) -> Result where + usize: IoLoc, Self: IoCapable, { self.try_write(offset, value) @@ -404,6 +412,7 @@ fn try_write32(&self, value: u32, offset: usize) -> Res= ult #[inline(always)] fn try_write64(&self, value: u64, offset: usize) -> Result where + usize: IoLoc, Self: IoCapable, { self.try_write(offset, value) @@ -413,6 +422,7 @@ fn try_write64(&self, value: u64, offset: usize) -> Res= ult #[inline(always)] fn read8(&self, offset: usize) -> u8 where + usize: IoLoc, Self: IoCapable, { self.read(offset) @@ -422,6 +432,7 @@ fn read8(&self, offset: usize) -> u8 #[inline(always)] fn read16(&self, offset: usize) -> u16 where + usize: IoLoc, Self: IoCapable, { self.read(offset) @@ -431,6 +442,7 @@ fn read16(&self, offset: usize) -> u16 #[inline(always)] fn read32(&self, offset: usize) -> u32 where + usize: IoLoc, Self: IoCapable, { self.read(offset) @@ -440,6 +452,7 @@ fn read32(&self, offset: usize) -> u32 #[inline(always)] fn read64(&self, offset: usize) -> u64 where + usize: IoLoc, Self: IoCapable, { self.read(offset) @@ -449,6 +462,7 @@ fn read64(&self, offset: usize) -> u64 #[inline(always)] fn write8(&self, value: u8, offset: usize) where + usize: IoLoc, Self: IoCapable, { self.write(offset, value) @@ -458,6 +472,7 @@ fn write8(&self, value: u8, offset: usize) #[inline(always)] fn write16(&self, value: u16, offset: usize) where + usize: IoLoc, Self: IoCapable, { self.write(offset, value) @@ -467,6 +482,7 @@ fn write16(&self, value: u16, offset: usize) #[inline(always)] fn write32(&self, value: u32, offset: usize) where + usize: IoLoc, Self: IoCapable, { self.write(offset, value) @@ -476,6 +492,7 @@ fn write32(&self, value: u32, offset: usize) #[inline(always)] fn write64(&self, value: u64, offset: usize) where + usize: IoLoc, Self: IoCapable, { self.write(offset, value) @@ -506,7 +523,7 @@ fn write64(&self, value: u64, offset: usize) #[inline(always)] fn try_read(&self, location: L) -> Result where - L: IoLoc, + L: IoLoc, Self: IoCapable, { let address =3D self.io_addr::(location.offset())?; @@ -540,7 +557,7 @@ fn try_read(&self, location: L) -> Result #[inline(always)] fn try_write(&self, location: L, value: T) -> Result where - L: IoLoc, + L: IoLoc, Self: IoCapable, { let address =3D self.io_addr::(location.offset())?; @@ -586,8 +603,8 @@ fn try_write(&self, location: L, value: T) -> Res= ult #[inline(always)] fn try_write_reg(&self, value: V) -> Result where - L: IoLoc, - V: LocatedRegister, + L: IoLoc, + V: LocatedRegister, Self: IoCapable, { let (location, value) =3D value.into_io_op(); @@ -619,7 +636,7 @@ fn try_write_reg(&self, value: V) -> Result #[inline(always)] fn try_update(&self, location: L, f: F) -> Result where - L: IoLoc, + L: IoLoc, Self: IoCapable, F: FnOnce(T) -> T, { @@ -658,7 +675,7 @@ fn try_update(&self, location: L, f: F) -> Res= ult #[inline(always)] fn read(&self, location: L) -> T where - L: IoLoc, + L: IoLoc, Self: IoCapable, { let address =3D self.io_addr_assert::(location.offset()= ); @@ -690,7 +707,7 @@ fn read(&self, location: L) -> T #[inline(always)] fn write(&self, location: L, value: T) where - L: IoLoc, + L: IoLoc, Self: IoCapable, { let address =3D self.io_addr_assert::(location.offset()= ); @@ -733,8 +750,8 @@ fn write(&self, location: L, value: T) #[inline(always)] fn write_reg(&self, value: V) where - L: IoLoc, - V: LocatedRegister, + L: IoLoc, + V: LocatedRegister, Self: IoCapable, { let (location, value) =3D value.into_io_op(); @@ -766,8 +783,8 @@ fn write_reg(&self, value: V) #[inline(always)] fn update(&self, location: L, f: F) where - L: IoLoc, - Self: IoCapable + Sized, + L: IoLoc, + Self: IoCapable, F: FnOnce(T) -> T, { let address =3D self.io_addr_assert::(location.offset()= ); diff --git a/rust/kernel/io/register.rs b/rust/kernel/io/register.rs index 388647f28292..1e81de770b4f 100644 --- a/rust/kernel/io/register.rs +++ b/rust/kernel/io/register.rs @@ -112,6 +112,8 @@ =20 use kernel::build_assert; =20 +use super::Region; + /// Trait implemented by all registers. pub trait Register: Sized { /// Backing primitive type of the register. @@ -128,7 +130,7 @@ 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 for () +impl IoLoc, T> for () where T: FixedRegister, { @@ -142,7 +144,7 @@ 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 for T +impl IoLoc, T> for T where T: FixedRegister, { @@ -167,7 +169,7 @@ pub const fn new() -> Self { } } =20 -impl IoLoc for FixedRegisterLoc +impl IoLoc, T> for FixedRegisterLoc where T: FixedRegister, { @@ -238,7 +240,8 @@ const fn offset(self) -> usize { } } =20 -impl IoLoc for RelativeRegisterLoc +// FIXME: Make use of `Base` type parameter of `Region` directly. +impl IoLoc, T> for RelativeRegisterL= oc where T: RelativeRegister, B: RegisterBase + ?Sized, @@ -282,7 +285,7 @@ pub fn try_new(idx: usize) -> Option { } } =20 -impl IoLoc for RegisterArrayLoc +impl IoLoc, T> for RegisterArrayLoc where T: RegisterArray, { @@ -369,7 +372,7 @@ pub fn try_at(self, idx: usize) -> Option> { } } =20 -impl IoLoc for RelativeRegisterArrayLoc +impl IoLoc, T> for RelativeRegisterA= rrayLoc where T: RelativeRegisterArray, B: RegisterBase + ?Sized, @@ -386,18 +389,18 @@ fn offset(self) -> usize { /// which to write it. /// /// Implementors can be used with [`Io::write_reg`](super::Io::write_reg). -pub trait LocatedRegister { +pub trait LocatedRegister { /// Register value to write. type Value: Register; /// Full location information at which to write the value. - type Location: IoLoc; + type Location: IoLoc; =20 /// Consumes `self` and returns a `(location, value)` tuple describing= a valid I/O write /// operation. fn into_io_op(self) -> (Self::Location, Self::Value); } =20 -impl LocatedRegister for T +impl LocatedRegister> for T where T: FixedRegister, { --=20 2.54.0 From nobody Thu Jun 25 00:35:31 2026 Received: from CWXP265CU008.outbound.protection.outlook.com (mail-ukwestazon11020099.outbound.protection.outlook.com [52.101.195.99]) (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 1F38C3E95A4; Mon, 8 Jun 2026 19:59:17 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=52.101.195.99 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780948759; cv=fail; b=FYBsTGV1ZGNk9vPWSesCw8ugLJjJgaIzDKmGVg+ni+Z1x08HgqWZpewYQu+Xh6VWe5RI/bPSjXpyQYmG9Am3gAZ4HLBEmefR49zv2rh9VexzUVTZbWte3ZbtlIISt7hNLL1JQqbaw5PF+3QxxrEzk5ML1Zgy0NkYpi9lCnjy0uc= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780948759; c=relaxed/simple; bh=JrWvnoFu8en2jfBcWMs/D2BwWcGYO3qY0mO+16Fdi4Q=; h=From:Date:Subject:Content-Type:Message-Id:References:In-Reply-To: To:Cc:MIME-Version; b=M2IY8TBXH/GZzuS8TpVYYCjJ7wC0pw+BuYnJwyBX1PCQDidr6H67KFM0JwvHeJsG801qJRpIysFmuVFsS5NiPxkAYiVdkQRrppr4c42Xa5J4hmjpbW4meL4yox2rwD/1jRYEq2ttJhWRN2UAfKL8vquzrurg/YghE7xISHSv+JY= 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=dpFaWNu7; arc=fail smtp.client-ip=52.101.195.99 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="dpFaWNu7" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=b18aw5yrOY0AYTh4IMYglsP4gMQEzbZQ80RAxKt5Ce2YDhVInqYAXX0jbNIOrqtGJ7IGxJcrD2osIC6zzpeEODdsxhKgDce6CbXf/uONdY+tL2iNiOmBHaQKcVwdY/siuBIZFAdXA8fyalkyYMbMHjt+MAMaX1Lgc4DfYnYvYhYTBWzVUd940EgaNFZaZytsrGcTAFzhnri8rPLZ1cvht7zfQaa7lZ74xNfv6JKga1X8kkeZrIWQx8dUztWL+cnRpwnX++09lUbveWK/nVzV0mNlCG4gENBRITQf5+YL8LJX94OhE9DqOMhm0Oax9cuPQlYSuiz68BwHL2Es2cxzbQ== 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=+8D6u+DmuDvUSll1wCtj/pUENbrxckYN0a2P55ksnMA=; b=mCSiNDv44vt8GZg2C7j4Gp9iyRrT+LIo+XonEBxOcPBG6jTkMS7VwUGk715yInAY6tKY6G5TmqlXAQQMvm4qpmPgVb5cIhwRrDTYE2JWm75hqMcib4WP7jmHCuhrJwugXJE7EKA3KNbsK8RaQY6Nm2XLqx0Aalsk9rBEd+FDw9ZqEF5fE/R5HsRZt93qWshEFPgK08VtwbQ/Li+t/3l++wTm3y0uDltMEmF0P6BuPtERuw5WBGeX1zfkeXq8od1LR41KOhKbAn6ctWTRkMYivr/6/qGMsnb01hLa7u6mzRnBKlTIe3st2EQRKyD9HRnf/qO2Ng0bi6QmnSfXlEnAYg== 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=+8D6u+DmuDvUSll1wCtj/pUENbrxckYN0a2P55ksnMA=; b=dpFaWNu7RkJcNpQFog5e88wWSobJrWYHm4rtj2M8oshVv73SAOvj/qi2SZ2l1JYD4SyoxDmfV7/x5NKoWH0e4geFSeePPgB1te/RPtt/XB1VUajMfA6roPkJUK1eqow8Hdz5Am2dgK921lla1d4zgTXif4zE/k0bdLWymyXT7hM= Authentication-Results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=garyguo.net; Received: from LOVP265MB8871.GBRP265.PROD.OUTLOOK.COM (2603:10a6:600:488::16) by LO8P265MB7398.GBRP265.PROD.OUTLOOK.COM (2603:10a6:600:3ca::5) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.21.92.12; Mon, 8 Jun 2026 19:59:09 +0000 Received: from LOVP265MB8871.GBRP265.PROD.OUTLOOK.COM ([fe80::1c3:ceba:21b4:9986]) by LOVP265MB8871.GBRP265.PROD.OUTLOOK.COM ([fe80::1c3:ceba:21b4:9986%4]) with mapi id 15.21.0092.011; Mon, 8 Jun 2026 19:59:09 +0000 From: Gary Guo Date: Mon, 08 Jun 2026 20:59:01 +0100 Subject: [PATCH v3 04/19] rust: io: implement `Io` on reference types instead Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260608-io_projection-v3-4-c5cde13a5ec4@garyguo.net> References: <20260608-io_projection-v3-0-c5cde13a5ec4@garyguo.net> In-Reply-To: <20260608-io_projection-v3-0-c5cde13a5ec4@garyguo.net> To: Danilo Krummrich , Alice Ryhl , Daniel Almeida , Greg Kroah-Hartman , "Rafael J. Wysocki" , Miguel Ojeda , Boqun Feng , Gary Guo , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Andreas Hindborg , Trevor Gross , Bjorn Helgaas , =?utf-8?q?Krzysztof_Wilczy=C5=84ski?= , Abdiel Janulgue , Robin Murphy , Alexandre Courbot , David Airlie , Simona Vetter Cc: driver-core@lists.linux.dev, rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, linux-pci@vger.kernel.org, nova-gpu@lists.linux.dev, dri-devel@lists.freedesktop.org X-Mailer: b4 0.15.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1780948747; l=16076; i=gary@garyguo.net; s=20221204; h=from:subject:message-id; bh=JrWvnoFu8en2jfBcWMs/D2BwWcGYO3qY0mO+16Fdi4Q=; b=r6JRD3MpPrvsbhh528ALN733mKy5SpTUYz2mk4hAqaZSAYjWT1gYpIuxxd+3t2RYzqvhsVLTD 1DfwFYgnY6sC0zA3RyZ7p/5KXZBfqmpq8IDA6HxQGFERsQ5fOGJS6xq X-Developer-Key: i=gary@garyguo.net; a=ed25519; pk=vB3uIX95SM4eVrIqo1DWNWKDKD2xzB+yLLLr0yOPYMo= X-ClientProxiedBy: LO4P123CA0344.GBRP123.PROD.OUTLOOK.COM (2603:10a6:600:18d::7) To LOVP265MB8871.GBRP265.PROD.OUTLOOK.COM (2603:10a6:600:488::16) 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: LOVP265MB8871:EE_|LO8P265MB7398:EE_ X-MS-Office365-Filtering-Correlation-Id: 0acffe8c-07db-4d9c-5264-08dec5986788 X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|1800799024|7416014|376014|366016|10070799003|6133799003|22082099003|18002099003|921020|56012099006|5023799004; X-Microsoft-Antispam-Message-Info: IOniocswQkmrT9skFTcC7cIvGnlwceZWomeHPUN8TahvTOus7DYbArEF7uXp7nMpGXbXH1yKQEyvDQHOHSs5e0s3DzxKoQmAWkvLWf/noAn8oQGY11SUuPDZvv0JwkYgM2+Q6DUPOR27o1+uMA9XhjxIGSkoIXSg4lofe3ahdTcioLpH/EFynGuoTbJ9lpGbpyWn4Zxg41yP6d9Pfx6U3rCYLqi6GozukMyPWi/njWZEeQj0Rey38r2Xjnqk+lxrMi0XCH1JOgMqAwEcglxml3O4TNvuIyU72AK1RPlA4dzZ/gbojRuRN2rmenuPCC+Zxps92titcKz8lIeYC9ZL+r14x0SCKwH8FmR+01EcUYj3Xjnk1hbKDftpOyja2YL85DYygwFEcAV0L2ZshOsRv5AWDOSTPlrByOg2iDjdwY23zFBGX/52TiYJ5rzGcwU9WF+w+EnCKqd6mSV7Sa9FTVPMBS699uE4ntQOIH7lk7AQ6Tqnl9vN6ObVNV7eowkZAlsO6Dhhh3AntuP7/wQ6diBj3Um09GFYBARWP4520ICrHiK9WWqAMW31TeZ6M/EzZgQxiWqqKMQi5oiEfGVhlM3H5c9v5EOGfqQqWQmQY8TifgusY6D7N0gSeKb8zdRFyrG4578+/ncJwpusk8wp9cDmGNU3eiv/xpWMBQBZobeMtvaE5t/0vmfACBQIPCxN+i+huH590nxSfJbiDEPKuoj3qoz/NpbW+akFsXz8LvY= X-Forefront-Antispam-Report: CIP:255.255.255.255;CTRY:;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:LOVP265MB8871.GBRP265.PROD.OUTLOOK.COM;PTR:;CAT:NONE;SFS:(13230040)(1800799024)(7416014)(376014)(366016)(10070799003)(6133799003)(22082099003)(18002099003)(921020)(56012099006)(5023799004);DIR:OUT;SFP:1102; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: =?utf-8?B?dGhFWlBjWXJQcDlQenREU0dxUmtVS1ZkbEV3Q3FGNmhYRGZKRFNiWDBrMGVM?= =?utf-8?B?T3dKMmhZR0FBbHRCUkJ1R1Y2cm1WeE8xUHVvVXovaVlxNjh5UjA2N0dROFg5?= =?utf-8?B?d3YxUlErY2k4VzgzMGJaNUwyQkQ0Z3BSV0ozRnEzVC9vLzFsd3V0cm9XbVVu?= =?utf-8?B?czFzZVVFdFpmOFlvaEgrSmRwQmJKUzdzR3BkSFd1YXR3Y1dmTit2UHJpMlhK?= =?utf-8?B?a05jODVRQmN0dG5xWEtPbjVQS1VsSzdaOXN0dmtBNWp1QjdLMzk0bFAxWFhu?= =?utf-8?B?OEJ4Nk9CdXpBM2FvenBoTU11bzNCaUFIclZoOWx0MEFqdW8vb01Kckp2UDVB?= =?utf-8?B?MS83R2VPQWFPZUhSM0VDTXNUQ0hnbWtkSUZuak40RkFEcysvTVp0Ukg3anRO?= =?utf-8?B?QzhSODhtSFZPUDNYS0xVbnFTOXVnRFJ3QzRjSTN2Y1ZkWE82TkhEVjZYSVFG?= =?utf-8?B?K1FnR3dGTWJ6MGk5UTlGbU1DL3B4c0NWQnpKU3BkOGF4Qi8rYzJ0RHhTNGxz?= =?utf-8?B?Y1RSRUlBUUF1ME15Q0xqQUsrQjIrQi9weGlNeldQcEF6VkRqaUR6Ymg3UW54?= =?utf-8?B?QWNwUy83bTNHK0h2aDZQa0ROZjh4MlVyOVJJNVBmb1cyRnRPckora0Zkbzhj?= =?utf-8?B?YTVBYzFtNGZZMVJFaVZyeU9IK2NNY2g2MkJKQ3ZJT1RSZHRYOXFWbTVvSGYx?= =?utf-8?B?WFp1bWhQUE9WelJ2aTJtY0dLTHJBa1JZYVoyaXdINFlqYUgydUVhTTJ3MzQv?= =?utf-8?B?T1kxNmRnQTltUlBXbDRUL0UrRkNmMkx3ZWdscG13K0RQUDBpUi9Uc3lYR0hP?= =?utf-8?B?TWVNcFF3T0kzdFRRaXFKSjNpK0NiR1N4a2gxSG9iQndHYWJjdUU4clhieWhM?= =?utf-8?B?QmEwbm5udmNDM2o2cndJa2o4Njd2alE1WDNrTzZaZlJubGMxcGh6YXdqaHdh?= =?utf-8?B?RGplNm5CeVMrT1dFTzg0Wm1vQVI0Yjk5NDhEcjhVbkFlMVpPODZieFN4WUIy?= =?utf-8?B?T1AxUDAyMldHbUJ0VXpwd2pWV3ppTHJReDBJTUdoWGpXOUJsZWl0YkRLWXlL?= =?utf-8?B?L2RCeG5SVXd3ZisyVENZRGpJVFRhZ2J3L0JaZGdMUXJmQnZMZlRIYUNqSlBB?= =?utf-8?B?TkRpV0doRGsvVmJkQ2ROKzk3cXMrSnNBeWR1VFJPM1ltQjZheHQ2a3JLeTho?= =?utf-8?B?enJDV05kR2tJWlZLUVNTN29ZN05xZjU2dk5hNE55OGFsS2xlN2Z5bGRYQ1ZM?= =?utf-8?B?aFJhMTRlaC9Gb0ZHRmFFaHhURVNlSkxRQXZIUFNOWE10d0VvOUdZZCswT3RV?= =?utf-8?B?N1BMczh0YmozOW83cjF0OTlzSk1FNitHVnFzOWRydWh4VFl1RVFWTjJ2VjJt?= =?utf-8?B?U0grU2VSek54MXFqckJrcXM2SDQxUllrOERnamdOVDNSYUovTkNFUFZDMzdB?= =?utf-8?B?NVZqc3RxNTRrL0JKTzQyeWV0d2hnaWc0c0pFYUgwQmhBUHpITENzWXZWRkZi?= =?utf-8?B?MkF5ci9uRER5czFjbXk5bXRldFRaNkJxVHduUi9iWEZucDBHSGJxdWxHb01h?= =?utf-8?B?Um4wcWVUWUpKdHViTnhReTRVRmpHVENwQlRJTFdhQ3V5L0FBOXd4TVJMNXZz?= =?utf-8?B?T0VPbkEycDM2VGQ0VHFVNkkvWFFkemorWkxoSFI5NER5Qm5aWjk4U1BWVXIr?= =?utf-8?B?L2NqbDcvSzcxNjVjZjlRN2VBNktrWnhZa1ZEYi81NjlxdzU2aERGMUIzWjh6?= =?utf-8?B?SlNxVUpvMVZlRVpMUlY1YURDKzNOVUE0dUF4clowZ1UxN0JOMzB0bnh5djlL?= =?utf-8?B?Q1J4bEV1SU93aDdIVStUOUtCc2Nlcjc4QW9uUkZXTFdxVXJFSUZiRGpwQ1lJ?= =?utf-8?B?RmlVdGduQlBVeWVvNFdFVHlyRStmWVV4dE5xZjhZdmpFNG5pWjVvVDZ1M0NP?= =?utf-8?B?R1l2dUdRNkdhV3lhaDdsT1NEN0JuYWRsSCtKTHJqOWtOdXg5S2MydGo1Tk9n?= =?utf-8?B?bCtFVnJJbTFDelJ0VlN3cjIzazRVNE9LYTg0NGw4aHJwUTZUcjlWSm1yZUpj?= =?utf-8?B?SUxYbTV4RTVzejhpdytkUnpPYlhOelQ2ek1PY2QyL2R0dkhWTXdzL3p6Smoy?= =?utf-8?B?N0dMUW5ndUdNSXJBcDJ6elpuK05JSUtXRmpZMTFja0hwUFdVU0ZVWEVqS1Bi?= =?utf-8?B?QlU4RkIyRThrUzFNSEhXTTlhRGN3ZlRBckFSQnE2dE5lZW9hUnhKYXRDQSsv?= =?utf-8?B?U3U3UFMwVktuRDM1Zm4zbmRCK2g2cDAwSFRUaktoRERhWEtHOG01ei9QYzI4?= =?utf-8?B?aVloV1ZpSGVZREluSG03RG0xeTFoYmlCYTBvS0tHVTViRlhndkVvUT09?= X-OriginatorOrg: garyguo.net X-MS-Exchange-CrossTenant-Network-Message-Id: 0acffe8c-07db-4d9c-5264-08dec5986788 X-MS-Exchange-CrossTenant-AuthSource: LOVP265MB8871.GBRP265.PROD.OUTLOOK.COM X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 08 Jun 2026 19:59:09.6694 (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: hUqPCoKBL2lRGR1dOjJqGnEuJ75cyKs/MSDkIkHl82LxBzywd7hzn/W0C8/dBaJWAm6Y9xq1+btlQAOZ7fw0FA== X-MS-Exchange-Transport-CrossTenantHeadersStamped: LO8P265MB7398 Currently, `Io` is implemented on owned I/O objects (e.g. `Bar`). This is going to change with I/O projections, as then `Io` need to work both for owned objects and views of them. Views are themselves reference-like (however they obviously cannot be references, because they belong to a different address space). To faciliate the change, change `Io` to be implemented on reference types for the owned I/O objects, and make methods take `self` instead of `&self`. When I/O views are implemented, we can then naturally implement `Io` for these objects. Signed-off-by: Gary Guo Suggested-by: Danilo Krummrich --- rust/kernel/io.rs | 80 +++++++++++++++++++++++++----------------------= ---- rust/kernel/pci/io.rs | 12 ++++---- 2 files changed, 46 insertions(+), 46 deletions(-) diff --git a/rust/kernel/io.rs b/rust/kernel/io.rs index 5a657bb3da09..d57df2a072a0 100644 --- a/rust/kernel/io.rs +++ b/rust/kernel/io.rs @@ -226,7 +226,7 @@ pub trait IoCapable { /// /// - The range `[address..address + size_of::()]` must be within t= he bounds of `Self`. /// - `address` must be aligned. - unsafe fn io_read(&self, address: usize) -> T; + unsafe fn io_read(self, address: usize) -> T; =20 /// Performs an I/O write of `value` at `address`. /// @@ -234,7 +234,7 @@ pub trait IoCapable { /// /// - The range `[address..address + size_of::()]` must be within t= he bounds of `Self`. /// - `address` must be aligned. - unsafe fn io_write(&self, value: T, address: usize); + unsafe fn io_write(self, value: T, address: usize); } =20 /// Describes a given I/O location: its offset, width, and type to convert= the raw value from and @@ -301,21 +301,21 @@ fn offset(self) -> usize { /// /// For MMIO regions, all widths (u8, u16, u32, and u64 on 64-bit systems)= are typically /// supported. For PCI configuration space, u8, u16, and u32 are supported= but u64 is not. -pub trait Io { +pub trait Io: Copy { /// Type of this I/O region. For untyped regions, [`Region`] can be us= ed. type Target: ?Sized + KnownSize; =20 /// Returns the base address of this mapping. - fn addr(&self) -> usize; + fn addr(self) -> usize; =20 /// Returns the maximum size of this mapping. - fn maxsize(&self) -> usize; + fn maxsize(self) -> usize; =20 /// Returns the absolute I/O address for a given `offset`, /// performing compile-time bound checks. // Always inline to optimize out error path of `build_assert`. #[inline(always)] - fn io_addr_assert(&self, offset: usize) -> usize { + fn io_addr_assert(self, offset: usize) -> usize { // We cannot check alignment with `offset_valid` using `self.addr(= )`. So set 0 for it and // ensure alignment by checking that the alignment of `U` is small= er or equal to the // alignment of `Self::Target`. @@ -328,7 +328,7 @@ fn io_addr_assert(&self, offset: usize) -> usize { /// Returns the absolute I/O address for a given `offset`, /// performing runtime bound checks. #[inline] - fn io_addr(&self, offset: usize) -> Result { + fn io_addr(self, offset: usize) -> Result { if !offset_valid::(self.addr(), offset, self.maxsize()) { return Err(EINVAL); } @@ -340,7 +340,7 @@ fn io_addr(&self, offset: usize) -> Result { =20 /// Fallible 8-bit read with runtime bounds check. #[inline(always)] - fn try_read8(&self, offset: usize) -> Result + fn try_read8(self, offset: usize) -> Result where usize: IoLoc, Self: IoCapable, @@ -350,7 +350,7 @@ fn try_read8(&self, offset: usize) -> Result =20 /// Fallible 16-bit read with runtime bounds check. #[inline(always)] - fn try_read16(&self, offset: usize) -> Result + fn try_read16(self, offset: usize) -> Result where usize: IoLoc, Self: IoCapable, @@ -360,7 +360,7 @@ fn try_read16(&self, offset: usize) -> Result =20 /// Fallible 32-bit read with runtime bounds check. #[inline(always)] - fn try_read32(&self, offset: usize) -> Result + fn try_read32(self, offset: usize) -> Result where usize: IoLoc, Self: IoCapable, @@ -370,7 +370,7 @@ fn try_read32(&self, offset: usize) -> Result =20 /// Fallible 64-bit read with runtime bounds check. #[inline(always)] - fn try_read64(&self, offset: usize) -> Result + fn try_read64(self, offset: usize) -> Result where usize: IoLoc, Self: IoCapable, @@ -380,7 +380,7 @@ fn try_read64(&self, offset: usize) -> Result =20 /// Fallible 8-bit write with runtime bounds check. #[inline(always)] - fn try_write8(&self, value: u8, offset: usize) -> Result + fn try_write8(self, value: u8, offset: usize) -> Result where usize: IoLoc, Self: IoCapable, @@ -390,7 +390,7 @@ fn try_write8(&self, value: u8, offset: usize) -> Result =20 /// Fallible 16-bit write with runtime bounds check. #[inline(always)] - fn try_write16(&self, value: u16, offset: usize) -> Result + fn try_write16(self, value: u16, offset: usize) -> Result where usize: IoLoc, Self: IoCapable, @@ -400,7 +400,7 @@ fn try_write16(&self, value: u16, offset: usize) -> Res= ult =20 /// Fallible 32-bit write with runtime bounds check. #[inline(always)] - fn try_write32(&self, value: u32, offset: usize) -> Result + fn try_write32(self, value: u32, offset: usize) -> Result where usize: IoLoc, Self: IoCapable, @@ -410,7 +410,7 @@ fn try_write32(&self, value: u32, offset: usize) -> Res= ult =20 /// Fallible 64-bit write with runtime bounds check. #[inline(always)] - fn try_write64(&self, value: u64, offset: usize) -> Result + fn try_write64(self, value: u64, offset: usize) -> Result where usize: IoLoc, Self: IoCapable, @@ -420,7 +420,7 @@ fn try_write64(&self, value: u64, offset: usize) -> Res= ult =20 /// Infallible 8-bit read with compile-time bounds check. #[inline(always)] - fn read8(&self, offset: usize) -> u8 + fn read8(self, offset: usize) -> u8 where usize: IoLoc, Self: IoCapable, @@ -430,7 +430,7 @@ fn read8(&self, offset: usize) -> u8 =20 /// Infallible 16-bit read with compile-time bounds check. #[inline(always)] - fn read16(&self, offset: usize) -> u16 + fn read16(self, offset: usize) -> u16 where usize: IoLoc, Self: IoCapable, @@ -440,7 +440,7 @@ fn read16(&self, offset: usize) -> u16 =20 /// Infallible 32-bit read with compile-time bounds check. #[inline(always)] - fn read32(&self, offset: usize) -> u32 + fn read32(self, offset: usize) -> u32 where usize: IoLoc, Self: IoCapable, @@ -450,7 +450,7 @@ fn read32(&self, offset: usize) -> u32 =20 /// Infallible 64-bit read with compile-time bounds check. #[inline(always)] - fn read64(&self, offset: usize) -> u64 + fn read64(self, offset: usize) -> u64 where usize: IoLoc, Self: IoCapable, @@ -460,7 +460,7 @@ fn read64(&self, offset: usize) -> u64 =20 /// Infallible 8-bit write with compile-time bounds check. #[inline(always)] - fn write8(&self, value: u8, offset: usize) + fn write8(self, value: u8, offset: usize) where usize: IoLoc, Self: IoCapable, @@ -470,7 +470,7 @@ fn write8(&self, value: u8, offset: usize) =20 /// Infallible 16-bit write with compile-time bounds check. #[inline(always)] - fn write16(&self, value: u16, offset: usize) + fn write16(self, value: u16, offset: usize) where usize: IoLoc, Self: IoCapable, @@ -480,7 +480,7 @@ fn write16(&self, value: u16, offset: usize) =20 /// Infallible 32-bit write with compile-time bounds check. #[inline(always)] - fn write32(&self, value: u32, offset: usize) + fn write32(self, value: u32, offset: usize) where usize: IoLoc, Self: IoCapable, @@ -490,7 +490,7 @@ fn write32(&self, value: u32, offset: usize) =20 /// Infallible 64-bit write with compile-time bounds check. #[inline(always)] - fn write64(&self, value: u64, offset: usize) + fn write64(self, value: u64, offset: usize) where usize: IoLoc, Self: IoCapable, @@ -521,7 +521,7 @@ fn write64(&self, value: u64, offset: usize) /// } /// ``` #[inline(always)] - fn try_read(&self, location: L) -> Result + fn try_read(self, location: L) -> Result where L: IoLoc, Self: IoCapable, @@ -555,7 +555,7 @@ fn try_read(&self, location: L) -> Result /// } /// ``` #[inline(always)] - fn try_write(&self, location: L, value: T) -> Result + fn try_write(self, location: L, value: T) -> Result where L: IoLoc, Self: IoCapable, @@ -601,7 +601,7 @@ fn try_write(&self, location: L, value: T) -> Res= ult /// } /// ``` #[inline(always)] - fn try_write_reg(&self, value: V) -> Result + fn try_write_reg(self, value: V) -> Result where L: IoLoc, V: LocatedRegister, @@ -634,7 +634,7 @@ fn try_write_reg(&self, value: V) -> Result /// } /// ``` #[inline(always)] - fn try_update(&self, location: L, f: F) -> Result + fn try_update(self, location: L, f: F) -> Result where L: IoLoc, Self: IoCapable, @@ -673,7 +673,7 @@ fn try_update(&self, location: L, f: F) -> Res= ult /// } /// ``` #[inline(always)] - fn read(&self, location: L) -> T + fn read(self, location: L) -> T where L: IoLoc, Self: IoCapable, @@ -705,7 +705,7 @@ fn read(&self, location: L) -> T /// } /// ``` #[inline(always)] - fn write(&self, location: L, value: T) + fn write(self, location: L, value: T) where L: IoLoc, Self: IoCapable, @@ -748,7 +748,7 @@ fn write(&self, location: L, value: T) /// } /// ``` #[inline(always)] - fn write_reg(&self, value: V) + fn write_reg(self, value: V) where L: IoLoc, V: LocatedRegister, @@ -781,7 +781,7 @@ fn write_reg(&self, value: V) /// } /// ``` #[inline(always)] - fn update(&self, location: L, f: F) + fn update(self, location: L, f: F) where L: IoLoc, Self: IoCapable, @@ -802,13 +802,13 @@ fn update(&self, location: L, f: F) macro_rules! impl_mmio_io_capable { ($mmio:ident, $(#[$attr:meta])* $ty:ty, $read_fn:ident, $write_fn:iden= t) =3D> { $(#[$attr])* - impl IoCapable<$ty> for $mmio { - unsafe fn io_read(&self, address: usize) -> $ty { + impl IoCapable<$ty> for &$mmio { + unsafe fn io_read(self, address: usize) -> $ty { // SAFETY: By the trait invariant `address` is a valid add= ress for MMIO operations. unsafe { bindings::$read_fn(address as *const c_void) } } =20 - unsafe fn io_write(&self, value: $ty, address: usize) { + unsafe fn io_write(self, value: $ty, address: usize) { // SAFETY: By the trait invariant `address` is a valid add= ress for MMIO operations. unsafe { bindings::$write_fn(value, address as *mut c_void= ) } } @@ -829,18 +829,18 @@ unsafe fn io_write(&self, value: $ty, address: usize)= { writeq ); =20 -impl Io for Mmio { +impl<'a, const SIZE: usize> Io for &'a Mmio { type Target =3D Region; =20 /// Returns the base address of this mapping. #[inline] - fn addr(&self) -> usize { + fn addr(self) -> usize { self.0.addr() } =20 /// Returns the maximum size of this mapping. #[inline] - fn maxsize(&self) -> usize { + fn maxsize(self) -> usize { self.0.maxsize() } } @@ -867,16 +867,16 @@ pub unsafe fn from_raw(raw: &MmioRaw) -> &Self { #[repr(transparent)] pub struct RelaxedMmio(Mmio); =20 -impl Io for RelaxedMmio { +impl<'a, const SIZE: usize> Io for &'a RelaxedMmio { type Target =3D Region; =20 #[inline] - fn addr(&self) -> usize { + fn addr(self) -> usize { self.0.addr() } =20 #[inline] - fn maxsize(&self) -> usize { + fn maxsize(self) -> usize { self.0.maxsize() } } diff --git a/rust/kernel/pci/io.rs b/rust/kernel/pci/io.rs index b4996aa059d8..505305cd9b86 100644 --- a/rust/kernel/pci/io.rs +++ b/rust/kernel/pci/io.rs @@ -79,8 +79,8 @@ pub struct ConfigSpace<'a, S: ?Sized + ConfigSpaceKind = =3D Extended> { /// Implements [`IoCapable`] on [`ConfigSpace`] for `$ty` using `$read_fn`= and `$write_fn`. macro_rules! impl_config_space_io_capable { ($ty:ty, $read_fn:ident, $write_fn:ident) =3D> { - impl<'a, S: ?Sized + ConfigSpaceKind> IoCapable<$ty> for ConfigSpa= ce<'a, S> { - unsafe fn io_read(&self, address: usize) -> $ty { + impl<'a, S: ?Sized + ConfigSpaceKind> IoCapable<$ty> for &ConfigSp= ace<'a, S> { + unsafe fn io_read(self, address: usize) -> $ty { let mut val: $ty =3D 0; =20 // Return value from C function is ignored in infallible a= ccessors. @@ -94,7 +94,7 @@ unsafe fn io_read(&self, address: usize) -> $ty { val } =20 - unsafe fn io_write(&self, value: $ty, address: usize) { + unsafe fn io_write(self, value: $ty, address: usize) { // Return value from C function is ignored in infallible a= ccessors. let _ret =3D // SAFETY: By the type invariant `self.pdev` is a vali= d address. @@ -112,18 +112,18 @@ unsafe fn io_write(&self, value: $ty, address: usize)= { impl_config_space_io_capable!(u16, pci_read_config_word, pci_write_config_= word); impl_config_space_io_capable!(u32, pci_read_config_dword, pci_write_config= _dword); =20 -impl<'a, S: ?Sized + ConfigSpaceKind> Io for ConfigSpace<'a, S> { +impl<'a, S: ?Sized + ConfigSpaceKind> Io for &ConfigSpace<'a, S> { type Target =3D S; =20 /// Returns the base address of the I/O region. It is always 0 for con= figuration space. #[inline] - fn addr(&self) -> usize { + fn addr(self) -> usize { 0 } =20 /// Returns the maximum size of the configuration space. #[inline] - fn maxsize(&self) -> usize { + fn maxsize(self) -> usize { self.pdev.cfg_size().into_raw() } } --=20 2.54.0 From nobody Thu Jun 25 00:35:31 2026 Received: from CWXP265CU008.outbound.protection.outlook.com (mail-ukwestazon11020099.outbound.protection.outlook.com [52.101.195.99]) (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 0DC763E9284; Mon, 8 Jun 2026 19:59:20 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=52.101.195.99 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780948762; cv=fail; b=bx8LrM6BZZFgCU0tabod0PfKVB9eIVCSe74LwoceewEzC0LqWkPxP9zxXmDNBpLIaoGUxe+XJjWbSERGRlgQuOc9xtbD/2izbyhlwmp3AmlEHfp89QnXgiOvsahdBzGwnx7yuikLAgSi46aqI+opvY5w0ujtlQUYpX/kwfDCxAo= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780948762; c=relaxed/simple; bh=TQu251RbAEKJSp7O3be+Dv/1yXkBgl67+gFSH6eSmMo=; h=From:Date:Subject:Content-Type:Message-Id:References:In-Reply-To: To:Cc:MIME-Version; b=hdcA4WpxMkJlWsKswKH4RnwBjDK7+bERCCEtTA7Ad9ycq1dz5tjjvsbMc0Rs4v2enn7wrdMPwPQ6uyO00JxC1gj5Dw8ZZAdjFV36AaF3sWYhP67qaT1q/veD04kY0Nsumsb7Wp7cvoHmddfb/clKve3QhdO96XsEMKXJgRsQVSA= 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=h9bD4en0; arc=fail smtp.client-ip=52.101.195.99 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="h9bD4en0" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=cdKSrtLd8rBo0pAfHIgd8XetmcvvKn6HSgM1lS1JdRgc5O6KKW+xeKPl0WxustOTzvrWqxnSpiHho1tjhW4y8uzQtZcf5fOATYN4Qdlna1Ny2XbflNnRVeCgPYgJyEbaREguV1+ew0nVXVlN/rtLK+iYdtLA2FXQHCNoNl35vUXDQ6n91INn/ewJBf0da01Oxxaog5utqdha2XGFOmUX0GK+kkPrn0WhRueEVCP0Z/XyxJl42AYO49YuBXNTvDiK9lKc8a0fKc/c1NtL7YbYWg8tpa22dyioRiYwJfGTas7Mvm2R4q+EVFlVFDJEfUrN6pb2jTLyvPgbT+xKdS+GcQ== 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=La+iQi6/WOXuxcAaZxq6cKG9UrrA5hLsn3OenvkCCTU=; b=Wa2VffXUqvh1kqVZtszWIhx5jHal0nlneXNbi0DYmUNPyMhDDx2YU5fTrlocaxVsgKA05APjZuwQmKInPxlNLxS4iWSeDl6zZB3G2r8AJyyP3xBEx0FajfQbxqcXZ3fZRaLhXjgAiLXJIBhz+mrT1xbiXbCM73bM95E0O0N1w2foWztfDwN3DMxTdeIEqSdaoXOTshu9ind/JqbWP5Dk1ZTyUiVFgn2v5hSYKXjZe2dYK7dt4yjTvWQWN5uzCX2a7QAfaURH0WUkhMKcY6CDjD7WXFa3Xf7+lIJEUe80MLd/y+3ng3Av8FdArFA36Z7kIffIawnjPEjhh6/AxGz47w== 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=La+iQi6/WOXuxcAaZxq6cKG9UrrA5hLsn3OenvkCCTU=; b=h9bD4en0HTmDhmlU97pkKGpwne4Sfsq3fhPm6D74IpQXyLmp96D/kxt++6tW1Rb4+M3swXZDynfEYFKdt0tOpW40dJTfwiAPvdx57FYcxUARVmdw23wxM/23Azkm/3Fdq7izzVYH/p1WGGgMGs+MIzB2jiwcIS/lmrO2/84YHrQ= Authentication-Results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=garyguo.net; Received: from LOVP265MB8871.GBRP265.PROD.OUTLOOK.COM (2603:10a6:600:488::16) by LO8P265MB7398.GBRP265.PROD.OUTLOOK.COM (2603:10a6:600:3ca::5) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.21.92.12; Mon, 8 Jun 2026 19:59:10 +0000 Received: from LOVP265MB8871.GBRP265.PROD.OUTLOOK.COM ([fe80::1c3:ceba:21b4:9986]) by LOVP265MB8871.GBRP265.PROD.OUTLOOK.COM ([fe80::1c3:ceba:21b4:9986%4]) with mapi id 15.21.0092.011; Mon, 8 Jun 2026 19:59:10 +0000 From: Gary Guo Date: Mon, 08 Jun 2026 20:59:02 +0100 Subject: [PATCH v3 05/19] rust: io: generalize `MmioRaw` to pointer to arbitrary type Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260608-io_projection-v3-5-c5cde13a5ec4@garyguo.net> References: <20260608-io_projection-v3-0-c5cde13a5ec4@garyguo.net> In-Reply-To: <20260608-io_projection-v3-0-c5cde13a5ec4@garyguo.net> To: Danilo Krummrich , Alice Ryhl , Daniel Almeida , Greg Kroah-Hartman , "Rafael J. Wysocki" , Miguel Ojeda , Boqun Feng , Gary Guo , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Andreas Hindborg , Trevor Gross , Bjorn Helgaas , =?utf-8?q?Krzysztof_Wilczy=C5=84ski?= , Abdiel Janulgue , Robin Murphy , Alexandre Courbot , David Airlie , Simona Vetter Cc: driver-core@lists.linux.dev, rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, linux-pci@vger.kernel.org, nova-gpu@lists.linux.dev, dri-devel@lists.freedesktop.org X-Mailer: b4 0.15.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1780948747; l=7828; i=gary@garyguo.net; s=20221204; h=from:subject:message-id; bh=TQu251RbAEKJSp7O3be+Dv/1yXkBgl67+gFSH6eSmMo=; b=l/tiv7OG4YJWEJBx3pSIcmCFQ5jfxX47LHdJGCyo6yBYJwGL3rERpUw18yN7Fmb3Q1UbQiBuz V1Ht3uYxoUyD2R1qTc0CcG2dfIQzIkVvO+uwHF5oJboIAUeKeEyG1oq X-Developer-Key: i=gary@garyguo.net; a=ed25519; pk=vB3uIX95SM4eVrIqo1DWNWKDKD2xzB+yLLLr0yOPYMo= X-ClientProxiedBy: LO4P123CA0344.GBRP123.PROD.OUTLOOK.COM (2603:10a6:600:18d::7) To LOVP265MB8871.GBRP265.PROD.OUTLOOK.COM (2603:10a6:600:488::16) 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: LOVP265MB8871:EE_|LO8P265MB7398:EE_ X-MS-Office365-Filtering-Correlation-Id: d884709b-ef3c-4568-4564-08dec59867c5 X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|1800799024|7416014|376014|366016|10070799003|6133799003|22082099003|18002099003|921020|56012099006; X-Microsoft-Antispam-Message-Info: bjLXGSiwwjp4hyJbN7AfoXUaUwaXoepsHgs9bEsu0e/5qMXjVlOEEcBuiRCZulgG6B/uggH9nEF7C6HgnAi4I3fi24oQBa7MbPeYABjPYCmLADR5DiqpOAL0Xe8rs+JRyA7PQX+ksTdRznu/BL/czxZbbtdIlVMqibdbFAMK8/zR8xeah/dBZRyXvyTLhMu0HxNN0Jcdufc8qp11dNuM3sSyp7jCqtRSSXp4jMhEuyDFlF/m1tN9Qq5sZW3d1Y4cfVRpBB0XoLoPs7GIDmDNQRjL/KQfo4ABMdFdWiHW6mXauoF7tt9KxXAYyfnMRBEeB9WqepNFKlyjCfkWxizAql/PpA0uU6JeXj0gyLnC8FqyQl9X5d0d7q0LFEG+Pczi9oS5/gTL3CfZrZL8W49XSTQLNXyzL4P17VHJSBHDVizKrL/9rHUpHsOjjmBcc+vDGdCzKliOBLoLYBHmEy8Q7ZA9859tUbOeTBlN+3d/Gx2rUaHrBNdo9DWKNash8WEbF15N4pPJYBB3H384CH/d88Kww2ajZZ4xswivjz8vddQ5Q1lfmFfYVJTudI+sPD9an24rYYlpwt8jqELC2pPC63qib2MzjqChGEjkFvo6XkSAm57ZKfKhdPpnbZ8veE0B3rAFkzaMPGQMjVXXv6iaHcoPh2LJsRXT//j4+fXQZiJ+fI/e7svjORIvtcx5DFcuhMTD14CmJ2DwubqXEgvuOxmEoDKrmpYg8iw8Icx4Idg= X-Forefront-Antispam-Report: CIP:255.255.255.255;CTRY:;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:LOVP265MB8871.GBRP265.PROD.OUTLOOK.COM;PTR:;CAT:NONE;SFS:(13230040)(1800799024)(7416014)(376014)(366016)(10070799003)(6133799003)(22082099003)(18002099003)(921020)(56012099006);DIR:OUT;SFP:1102; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: =?utf-8?B?QlJhMHZ5ZVM4ZGs3d3FPdjN0L2tkQklCKzd0VHZYV1ZmdnJ0b2hLSVFOWk9N?= =?utf-8?B?bTYwdlFNeis4dk94VWVFNXdEVmpqamR2MUtteDhxNnl0WWVVcFQ1LzJuckRT?= =?utf-8?B?blJyWlFEUzd1d0Y1c29CQ2dlV3VJdjQ4T3ZUN1NIZnVLOVpGbnN1WXZVL0Z2?= =?utf-8?B?WTVyTXdVQW9EU2lBbmNxcmxPeUlML1RPc0dHMzBuaGozMjZRUVBmRHlVN1J2?= =?utf-8?B?WXk2ZTVRdnJRUnNoT1VraVdzUXpBb0FrSTkvSXp4R05BNVYxcUFhaElSRm1O?= =?utf-8?B?cGppSnUvK1N3R0trK2t6WCtUQTVLeUMyTjhVUnROaDdwcjVhUlo0SFVkbVZ0?= =?utf-8?B?bzBwMDlSd291TUF2Uy91aHZzRnZIbjhsaDFxclBGV1BERDhPNk1teGthcm52?= =?utf-8?B?a1J0ZkhTYk80NWx6OXpLNzVRZXpWQ1NOOWlPdVhvWEdEVjJkZEpPWlk5djZm?= =?utf-8?B?ZnVvbzJvZFBJT2VJK2dtVlFJTXZ5a0pEb3oxMEsvbytJRytwenc3UFozbjc2?= =?utf-8?B?S3pYMFNtL1dlc0UxWlVDY1QveTd2aGdBcjI0UGN2OGdBdEM0ZHhkN2kwUkp6?= =?utf-8?B?bnJxb0tIYjJFZTdrZmNLTHZXRHN5SUpqbWZ4RklmSTJZd015Q0lXKy9Gcmsy?= =?utf-8?B?ODRjVmllTHpJYVllSkhrUVlESGF2R2ZLTWxDYU5NTVNYYktWMnJDSk5nY0lT?= =?utf-8?B?ZjZrVERCUExHbUtJQUhqZExrVjA1d1B2dHM2ZzZ5dkNwb3ZlT1FrRjlvZjRl?= =?utf-8?B?ejA0MERlZzA0Q0FweDhWNHBSOXlaUVc5bjBtaXU2NW1vdlJjWURjcU1UK3g4?= =?utf-8?B?VEwwNGExQzhVWXdKY2p4RDhod0RjL0x0OGxFMHpwTDh2MFh0Yy9DTzBiUFFO?= =?utf-8?B?dndJMGlHTkpRMW5ld0MrL1hvUTA1dnJBdWUzcGh6Mlc4WGZNM1JkK2tkWlpl?= =?utf-8?B?c2VMa3hPc0ZuK3o5cmZjeWJHdC9uWi9FODJhWU0zZmc2THZtMms5cjJHTERO?= =?utf-8?B?a2d0bDcwekZQQ3ZMQVhQMGhxR3p4TjNXYjFqUy9qVk9pTUREQ2taMW5QeWUw?= =?utf-8?B?Q1BjNEJBZ21pbm5DUTA0VFhsZ2JtQVp2QVI1SUVmd3Rqc2gwa2h4a01sVmVy?= =?utf-8?B?anUwakdrYW1qeFI1cVAzN3RsWDJQdldtYXRiQzYrY2FkL1R3U3R0ME5PWGhS?= =?utf-8?B?bzEyOVhDMmViQStqZUpGSVFURjNlUm5wZ0JPbjA0bHBmTllSWGpJLzdLT3dW?= =?utf-8?B?ZTR1SXZ4WUltQzA0M3I2YlRGWWxJdjFCcGpHNW94UUdnYmN0eW9CU2dRY3VD?= =?utf-8?B?czNzR3ZhNEU0NTA4ZXdvYis1RVo3S1A1OVA0am5KcWlFWVZxTGZGTEZaa1ZV?= =?utf-8?B?NFI4N0pNRnNVMHQ5OGduWmZQS2VkVFI2VVZaai8wQU1JWVAranBqYXNyckNQ?= =?utf-8?B?MXVvL01NSmFTeFJIenJpUE14c2pmcWRjdi95ZzNiUjN3dzROcU13YnRyY3pl?= =?utf-8?B?YmdoZnZuZ0Y3NGlpczBtbEFYREwzbCtjM0FHZkVwNlN5a29JN3c1WWx3SGth?= =?utf-8?B?dmNOYTByUGVmeFNDTmlEV1A1TVNPSnJHN2hOZGJ5V2JQK0ZzN01aMGlNUUty?= =?utf-8?B?NWw3NFJwNE9KdUVEd3hGZFB6bkExRmRpb1VqcmVLOCtIQTE3V20vSXNUZFls?= =?utf-8?B?cXRSWDJWQjJUcUdnZkg1bGxZZzdTUk5kdkhPbDNkd3EvVm55UnByNVgzNmhI?= =?utf-8?B?NWc0eFFheEZUend4L1BDekJnZm1sUzA5NlQrTkFOZkppK01JbWVVZzBBQll1?= =?utf-8?B?Y3Q0eXN1Tzk1SkNnSW4xVkUybitVb1l1T1lhb1ZJUFRIQ1RnQzB1bjVzWjNL?= =?utf-8?B?dGM3SVBzVUlEQ0NaMGN4Q09RRDMxNVNkRDhFb3R2eFgwNjNnWkhqWENxMmwr?= =?utf-8?B?Ry9yTWoxeFY4d0JtdURrdm5NcVBWa3ZobGZ2RUVXNXgwUjJieXdRUGlidm56?= =?utf-8?B?VW1OYmdkejc4d2JmN0swV3lpTlk0UTFMYzl4T05tSUhseEdPYmdmZTNnaGZm?= =?utf-8?B?VUc2WVVEdE95QVZRNnJzSzA3dEVTMHNOK0pOTGFrSWMxZTFKSlFXZUs3V0ow?= =?utf-8?B?YlArUlpNQmE5YVRFZWNIejNrRmFFZ042dk1QUDZaSjY1dXp4YlVxTFlHWFo4?= =?utf-8?B?aDZ4OHhFNkhIcklMOVJLRGpXdWFCMm5kZXBhN2FRM0REZzJ6WWxXVlBpTWlI?= =?utf-8?B?ZWFSdjRqTUdFZk40TGI4Tlp4MEJyOUdSQXlic1BjdXlBREJ6bnJaVEQyeXNP?= =?utf-8?B?emh5eTVJS3JsTHREWmFPaFhLYWMvcitsQ1FjbTlYUFBZSHF4L0pNQT09?= X-OriginatorOrg: garyguo.net X-MS-Exchange-CrossTenant-Network-Message-Id: d884709b-ef3c-4568-4564-08dec59867c5 X-MS-Exchange-CrossTenant-AuthSource: LOVP265MB8871.GBRP265.PROD.OUTLOOK.COM X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 08 Jun 2026 19:59:10.0915 (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: euGSgUg7sjmoaVcqsJdS5aKZXGMESHK7ERgmj05A70MMsmTOol+6npZA7Jd6rWzVp7IAYpjOtW6j24Srg5Mq9g== X-MS-Exchange-Transport-CrossTenantHeadersStamped: LO8P265MB7398 Conceptually, `MmioRaw` is just `__iomem *`, so it should work for any types. Update the existing use case where it represents a region of compile-time known minimum size and run-time known actual size to use the dynamic-sized type `Region` instead. Rename `maxsize` method to reflect that it is the actual size (not a bound) of the region. Implement `Clone` and `Copy` manually, which cannot be derived due to the generic parameter. The use of raw pointers also cause the `Send` and `Sync` auto trait implementation to be lost, so add them back by manual implementation. Signed-off-by: Gary Guo Suggested-by: Danilo Krummrich --- rust/kernel/devres.rs | 7 +++--- rust/kernel/io.rs | 67 +++++++++++++++++++++++++++++++++++++----------= ---- rust/kernel/io/mem.rs | 5 ++-- rust/kernel/pci/io.rs | 4 +-- 4 files changed, 57 insertions(+), 26 deletions(-) diff --git a/rust/kernel/devres.rs b/rust/kernel/devres.rs index ed30ccc6e68e..d0c677fd7932 100644 --- a/rust/kernel/devres.rs +++ b/rust/kernel/devres.rs @@ -70,14 +70,15 @@ struct Inner { /// Io, /// Mmio, /// MmioRaw, -/// PhysAddr, // +/// PhysAddr, +/// Region, // /// }, /// prelude::*, /// }; /// use core::ops::Deref; /// /// // See also [`pci::Bar`] for a real example. -/// struct IoMem(MmioRaw); +/// struct IoMem(MmioRaw>); /// /// impl IoMem { /// /// # Safety @@ -92,7 +93,7 @@ struct Inner { /// return Err(ENOMEM); /// } /// -/// Ok(IoMem(MmioRaw::new(addr as usize, SIZE)?)) +/// Ok(IoMem(MmioRaw::new_region(addr as usize, SIZE)?)) /// } /// } /// diff --git a/rust/kernel/io.rs b/rust/kernel/io.rs index d57df2a072a0..c9533d3f003b 100644 --- a/rust/kernel/io.rs +++ b/rust/kernel/io.rs @@ -90,37 +90,67 @@ fn size(p: *const Self) -> usize { =20 /// Raw representation of an MMIO region. /// +/// `MmioRaw` is equivalent to `T __iomem *` in C. +/// /// By itself, the existence of an instance of this structure does not pro= vide any guarantees that /// the represented MMIO region does exist or is properly mapped. /// /// Instead, the bus specific MMIO implementation must convert this raw re= presentation into an /// `Mmio` instance providing the actual memory accessors. Only by the con= version into an `Mmio` /// structure any guarantees are given. -pub struct MmioRaw { - addr: usize, - maxsize: usize, +pub struct MmioRaw { + /// Pointer is in I/O address space. + /// + /// The provenance does not matter, only the address and metadata do. + ptr: *mut T, } =20 -impl MmioRaw { - /// Returns a new `MmioRaw` instance on success, an error otherwise. - pub fn new(addr: usize, maxsize: usize) -> Result { - if maxsize < SIZE { - return Err(EINVAL); +impl Copy for MmioRaw {} +impl Clone for MmioRaw { + #[inline] + fn clone(&self) -> Self { + *self + } +} + +// SAFETY: `MmioRaw` is just an address, so is thread-safe. +unsafe impl Send for MmioRaw {} +// SAFETY: `MmioRaw` is just an address, so is thread-safe. +unsafe impl Sync for MmioRaw {} + +impl MmioRaw { + /// Create a `MmioRaw` from address. + #[inline] + pub fn new(addr: usize) -> Self { + Self { + ptr: core::ptr::without_provenance_mut(addr), } + } +} =20 - Ok(Self { addr, maxsize }) +impl MmioRaw> { + /// Create a `MmioRaw` representing a I/O region with given size. + /// + /// The size is checked against the minimum size specified via const g= enerics. + #[inline] + pub fn new_region(addr: usize, size: usize) -> Result { + Ok(Self { + ptr: Region::ptr_try_from_raw_parts_mut(core::ptr::without_pro= venance_mut(addr), size)?, + }) } +} =20 +impl MmioRaw { /// Returns the base address of the MMIO region. #[inline] pub fn addr(&self) -> usize { - self.addr + self.ptr.addr() } =20 - /// Returns the maximum size of the MMIO region. + /// Returns the size of the MMIO region. #[inline] - pub fn maxsize(&self) -> usize { - self.maxsize + pub fn size(&self) -> usize { + KnownSize::size(self.ptr) } } =20 @@ -145,12 +175,13 @@ pub fn maxsize(&self) -> usize { /// Mmio, /// MmioRaw, /// PhysAddr, +/// Region, /// }, /// }; /// use core::ops::Deref; /// /// // See also `pci::Bar` for a real example. -/// struct IoMem(MmioRaw); +/// struct IoMem(MmioRaw>); /// /// impl IoMem { /// /// # Safety @@ -165,7 +196,7 @@ pub fn maxsize(&self) -> usize { /// return Err(ENOMEM); /// } /// -/// Ok(IoMem(MmioRaw::new(addr as usize, SIZE)?)) +/// Ok(IoMem(MmioRaw::new_region(addr as usize, SIZE)?)) /// } /// } /// @@ -195,7 +226,7 @@ pub fn maxsize(&self) -> usize { /// # } /// ``` #[repr(transparent)] -pub struct Mmio(MmioRaw); +pub struct Mmio(MmioRaw>); =20 /// Checks whether an access of type `U` at the given `base` and the given= `offset` /// is valid within this region. @@ -841,7 +872,7 @@ fn addr(self) -> usize { /// Returns the maximum size of this mapping. #[inline] fn maxsize(self) -> usize { - self.0.maxsize() + self.0.size() } } =20 @@ -852,7 +883,7 @@ impl Mmio { /// /// Callers must ensure that `addr` is the start of a valid I/O mapped= memory region of size /// `maxsize`. - pub unsafe fn from_raw(raw: &MmioRaw) -> &Self { + pub unsafe fn from_raw(raw: &MmioRaw>) -> &Self { // SAFETY: `Mmio` is a transparent wrapper around `MmioRaw`. unsafe { &*core::ptr::from_ref(raw).cast() } } diff --git a/rust/kernel/io/mem.rs b/rust/kernel/io/mem.rs index fc2a3e24f8d5..9e15bc8fde78 100644 --- a/rust/kernel/io/mem.rs +++ b/rust/kernel/io/mem.rs @@ -229,7 +229,7 @@ fn deref(&self) -> &Self::Target { /// start of the I/O memory mapped region. pub struct IoMem<'a, const SIZE: usize =3D 0> { dev: &'a Device, - io: MmioRaw, + io: MmioRaw>, } =20 impl<'a, const SIZE: usize> IoMem<'a, SIZE> { @@ -264,8 +264,7 @@ fn ioremap(dev: &'a Device, resource: &Resource)= -> Result { return Err(ENOMEM); } =20 - let io =3D MmioRaw::new(addr as usize, size)?; - + let io =3D MmioRaw::new_region(addr as usize, size)?; Ok(IoMem { dev, io }) } =20 diff --git a/rust/kernel/pci/io.rs b/rust/kernel/pci/io.rs index 505305cd9b86..42f840d64a6f 100644 --- a/rust/kernel/pci/io.rs +++ b/rust/kernel/pci/io.rs @@ -139,7 +139,7 @@ fn maxsize(self) -> usize { /// memory mapped PCI BAR and its size. pub struct Bar<'a, const SIZE: usize =3D 0> { pdev: &'a Device, - io: MmioRaw, + io: MmioRaw>, num: i32, } =20 @@ -179,7 +179,7 @@ pub(super) fn new( return Err(ENOMEM); } =20 - let io =3D match MmioRaw::new(ioptr, len as usize) { + let io =3D match MmioRaw::new_region(ioptr, len as usize) { Ok(io) =3D> io, Err(err) =3D> { // SAFETY: --=20 2.54.0 From nobody Thu Jun 25 00:35:31 2026 Received: from LO3P265CU004.outbound.protection.outlook.com (mail-uksouthazon11020080.outbound.protection.outlook.com [52.101.196.80]) (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 179213ED3C3; Mon, 8 Jun 2026 19:59:21 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=52.101.196.80 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780948766; cv=fail; b=qFu2N3hZaX7n/t8bqmsZmBIDf5OBu4/aIE2MU1tSAidnegzpt7RZF4+vgFWOuS047AB2DFyVW3WtLBMyHkQVX6dWRwMHVzj9pNrAuxglB7HNyISZULd4hhnX/59wCX44e7TBRBF5nRRCaS+MBghu23jLqY1U3i1RQTTvH9RfLoA= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780948766; c=relaxed/simple; bh=mreONJ+AHAEhaJglZOeJLMnPk4Q9LO40LchOeihcJSQ=; h=From:Date:Subject:Content-Type:Message-Id:References:In-Reply-To: To:Cc:MIME-Version; b=vEwMrnxhhZgOlS+jW8NoufOS1ivxhIWj6ZDjdth7jzELBdn0E6NQNKoicW6Fsx0UILvkistAy5ErE04aZSJcE16o0wOr60jAF9YzidlQ+IQ55HXez/Weu3TsreCw2sCYVf1XS46iZe+EIhPQGsz+oOs2u6jV7hPqnrQXGa0Ki18= 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=KEdTEqnj; arc=fail smtp.client-ip=52.101.196.80 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="KEdTEqnj" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=Vx4rK5OoogDBzvWU+2eXWfJV9zLBMGe4oUPjNQT4G6J0WOxZOcDeF1fCKkps/kE9WGiiH6iSZ0Q4/axeIhc8HJ9GAk1wNCbeLgeMNbmH9Ezq+v27bDVwZ9YykgBER0LobnF5TCO3RA3eQ/F0gLE7k9puLLiRokS0tAPGOHzSQQ+wK9Ssr7dbFymAEf3V1U6JIAGB/Y3T3gByJidzfHES+KbHVXxty9+OgFpSMX1NphB2Mz6QSsJXic1bHYYMmuBaJO5uWe3A7V0vo4d+yXVavDy3u9e6u0xWtkgqe04utOGUog9rLVx5kBo0p19UXtj2vyZbVFj2psYZbmAgkhIy5Q== 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=FkHARU1FufBVHwKsb1jGceHWa7BP9kZ+4tdcCjmNEhQ=; b=IZuelxFTuFbkzg/E1fmC9C8Yms/HBDkpo21sV8sP49xuBEPizdSAv+MjE7rUqMymXR6j8Ik84gc9uGWBd+MBwBNsehqb9D6KXqoeduiljOcLacWzwLRy6ieh0t9WrGwIq0m+//1Fch/DMlSnAYF4VXOhdWUK5m7lW1ijGH+wjTiIht/fdV/OB1pQoFIEqQtmDOd3WYbkuTxp/VTXIGHKtDXD7aak2TJdik+BUJrrYqRjO9BUQdRwrrTiLTx8SQYi/Fd/KhNWwpz18daxm6E79NxgOWQXQ1nvBQLQng48zbzp9+A9twZGJ84EBsV0i2aCIv6X4Ly/ddtjag7Pfaml9A== 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=FkHARU1FufBVHwKsb1jGceHWa7BP9kZ+4tdcCjmNEhQ=; b=KEdTEqnjnyjVhnhXR8LHmHccJ/Tn17DsOIyf1buUJbBg7CC+LExjjyn3wlex2Ozw3pQsTqNs1WYVOCLxz3An3sAe+s9Rer7kThcJIGjR0wThcI/3OfiZ2FnpWSX25U4/b+tOaP4H8Q9X0gSjsA2+aHgPEsUjGL0kbk9q5PehBt0= Authentication-Results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=garyguo.net; Received: from LOVP265MB8871.GBRP265.PROD.OUTLOOK.COM (2603:10a6:600:488::16) by LO8P265MB7398.GBRP265.PROD.OUTLOOK.COM (2603:10a6:600:3ca::5) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.21.92.12; Mon, 8 Jun 2026 19:59:10 +0000 Received: from LOVP265MB8871.GBRP265.PROD.OUTLOOK.COM ([fe80::1c3:ceba:21b4:9986]) by LOVP265MB8871.GBRP265.PROD.OUTLOOK.COM ([fe80::1c3:ceba:21b4:9986%4]) with mapi id 15.21.0092.011; Mon, 8 Jun 2026 19:59:10 +0000 From: Gary Guo Date: Mon, 08 Jun 2026 20:59:03 +0100 Subject: [PATCH v3 06/19] rust: io: rename `Mmio` to `MmioOwned` Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260608-io_projection-v3-6-c5cde13a5ec4@garyguo.net> References: <20260608-io_projection-v3-0-c5cde13a5ec4@garyguo.net> In-Reply-To: <20260608-io_projection-v3-0-c5cde13a5ec4@garyguo.net> To: Danilo Krummrich , Alice Ryhl , Daniel Almeida , Greg Kroah-Hartman , "Rafael J. Wysocki" , Miguel Ojeda , Boqun Feng , Gary Guo , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Andreas Hindborg , Trevor Gross , Bjorn Helgaas , =?utf-8?q?Krzysztof_Wilczy=C5=84ski?= , Abdiel Janulgue , Robin Murphy , Alexandre Courbot , David Airlie , Simona Vetter Cc: driver-core@lists.linux.dev, rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, linux-pci@vger.kernel.org, nova-gpu@lists.linux.dev, dri-devel@lists.freedesktop.org X-Mailer: b4 0.15.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1780948747; l=16838; i=gary@garyguo.net; s=20221204; h=from:subject:message-id; bh=mreONJ+AHAEhaJglZOeJLMnPk4Q9LO40LchOeihcJSQ=; b=3fQNSfZoaiIYvzkb90FtUo9hDj7LSRt3MDi+U41f1/37VzdGDqFhX9fGCFOIA/fKO6NPhO6zX JYU0dHQQoS9BPEZMt40lycJ2dPlLv/BQLkQMPXS7KST1W2F8CHjNdDk X-Developer-Key: i=gary@garyguo.net; a=ed25519; pk=vB3uIX95SM4eVrIqo1DWNWKDKD2xzB+yLLLr0yOPYMo= X-ClientProxiedBy: LO4P123CA0344.GBRP123.PROD.OUTLOOK.COM (2603:10a6:600:18d::7) To LOVP265MB8871.GBRP265.PROD.OUTLOOK.COM (2603:10a6:600:488::16) 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: LOVP265MB8871:EE_|LO8P265MB7398:EE_ X-MS-Office365-Filtering-Correlation-Id: 6abad7a6-0081-4c9a-0f5e-08dec598680a X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|1800799024|7416014|376014|366016|10070799003|6133799003|22082099003|18002099003|921020|56012099006|5023799004; X-Microsoft-Antispam-Message-Info: Azmi8fcck6bU9bVa27WA60hNruEMO03KvlgJdPudZ4JjYTfczEq6bTb3TrNfUvYHbTeBysfNr6rokVGiLOsvMhMwFLPo4168abKbZJ5wapp1PPfPg1V2xlr4zk0/gcy/fV6j1QlbErWfgP6vd+2993SV9lL+R2MMLfO/QfrQ/l4FBhYwFHBCq9fyIaYA220Snou7Gns9KgYFzzxrK0S/qd2lEEMcjZfm6ZNOuP8rIlgKRAuHMN24BdnvGAxMvEt6U/WyGrCEp9TvGzjCvJGjk5g66TuzDgtQlouVLVu98HQbCz8yYgkUVqXL2IHgDlv4djBMM8WoB270o1tSHvznVZYMd/GnjrlsxBLw5HTzzdEjv9PNxiOrxSARyWgM0IZxrJMKVq6t4pmrzVtLh5kJOE6wB+0y6K5XM7ZeyKdvX4SLraIUmhmeapcyrc0ahW6dg04aJafafEL9h5JXMY72bsQ3EvJELJdnrcraZn/gV5Mj83TyKXrPb4JUII5Q7WyuO8UWTsNF0whkf0pVhCI1ebQjxaXs46/Uf8Z1KIcUuih1gWJZUyiD7rhmP3GyFZLwUBabeSLtYFVSZbTHDPT0IqK1HsFoidcbPT3/ygrCH9kfboxSi88I/U2oX8D8LExh9p3hTuljBXpuL8VEeEV2xtXr0qj8nz+ACB3cOpWXOHx8kOrQ9a6Y538+Y3elUGsVpVoDmN7C3yniZLUGUscqArtK8RgC9Ln3a4MqVVij4zQ= X-Forefront-Antispam-Report: CIP:255.255.255.255;CTRY:;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:LOVP265MB8871.GBRP265.PROD.OUTLOOK.COM;PTR:;CAT:NONE;SFS:(13230040)(1800799024)(7416014)(376014)(366016)(10070799003)(6133799003)(22082099003)(18002099003)(921020)(56012099006)(5023799004);DIR:OUT;SFP:1102; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: =?utf-8?B?U0QvNVZ3V202RC90VjR2bVNCaVBuRGxicVYzV2dVYnBoUXN0SnNndVBNNlAy?= =?utf-8?B?R0pHRVNvVDlySDkwdUwxSmU4TjBGeTJmZjh1SlJWNXFKSzVvVTI5aEFBWHpC?= =?utf-8?B?dERYMlU1aFJieDZHWC9USlRIeFJ2WFZ1bTR4OTBnai9INlMxZWovK1p6Mk8y?= =?utf-8?B?aWZkMmRaZ1hBdjhTV0RONGpqSWQzakx6Q3M3MXFyRkNxTGx0SEJGY1JkT05o?= =?utf-8?B?MzAvcGN1TktYdU80eC9wRVQwUHJTeUNicGR1RUlBUjVreFVBeW1zd2o3bmwy?= =?utf-8?B?Ty9rR2t3a3VncXRyenhHUGlGMEhlQzgvMjB2K1QveTJiK1oxUWxQRmpKdk1y?= =?utf-8?B?a3liSWJCdDdhbkh6RFFpNVg2dVBFek5McUtSL2NnZ0ZxUVVLVjVSVE5sSE1Y?= =?utf-8?B?ZVdyeGdFNUp2dE9BdTBOYjJxRXBwY3QreEhwS015d3dHclVreGRLVjQzZW41?= =?utf-8?B?Uk1XQnJVZ1J1dlVpVWNTeUszak5JNU1QTTBjb0NuN1hOWDJ0Y2pJc3kzTnY4?= =?utf-8?B?Ym03UWZTNWZMelJPak5HMjZ3L1B2QXJUVHpiZkxqRmNFTStabWt2Q2pxS2lY?= =?utf-8?B?U1RIUnFSdkZXUnErTUdNM1hxd0xicTEzQnJvU2RJNktBenZXNVJBYmNRLzVo?= =?utf-8?B?TEc0cUFKUnNFK1h5ZmpOeWd2RjFwN3MxeTNZRExKYkZZV3hqTmdsUC9PWjRS?= =?utf-8?B?ZkJROCs5Ykk3NmNQQlNFcGF4SS9DcFMyT3VBVVdUeERuUHJlSlNOM2ptTm5O?= =?utf-8?B?NmdoZUJIMkxwQ01zYTdjWitDblFzclhOem00SE1mYjVQMG4yZ0pQVUE0TDF5?= =?utf-8?B?UXZkWjhOSCt1K2lPY2RtVVJueVNvK203VVZxcXF2M01rWW9tRnA3WHViemFL?= =?utf-8?B?enRHRk52SWNyNjlQRnhwMkdpTU1KSllFa3NKZS9WZ3ZzK3dYUjRNWWQ4MHlz?= =?utf-8?B?UUNTbWNDOUVHN3lMYlVnSXkrRUdodk0wRXAvaExIRDNDSzBNM3lIVUp0cGlr?= =?utf-8?B?bExlbW1ySVJuUjZtYlI4TWxnQjQ3eHNjZndKTHJqUkpIV3k3RGRxejh5RTAy?= =?utf-8?B?QXdBbzlTbnVObVc5elNET3FNTDhMUndwRXZlM1RvamNMMk50YXdnaVRuZnpv?= =?utf-8?B?N0ZreGhDWDFrZ1dEZU5FVjltUmN1U3kwQUgxc3d5MXdJbWdhcWFrYjZCYTZY?= =?utf-8?B?WDcwazlSNzcrcnhuWnhJcFZmQ0l4Qm9pS1FlNFpseDY4ZzZzZFdVRGlQR01Y?= =?utf-8?B?S0FZdzlKMEdjY2N2VkE2cWZBVkRsV1R5QURKMUtxbVNyWXZ5eXYrRjhIc2RX?= =?utf-8?B?aUVsbGJRTGJYVC9TczRIRGZOQ1EwaXVyamk4VUR4eW1kRzhuWUJSN3J1VkJQ?= =?utf-8?B?UHZTMWxkdGlGN0pEWnNBK3FTNWVGd2tiQTFUOXRqWVJoejRYMnBPenhHdndl?= =?utf-8?B?blVyQ3ptY1QyaG9Sdk1nemRycTZSY2QvRGdqR0NrdVg4VVJ0QXgvUjl2UTcw?= =?utf-8?B?Z1lTSlVITHhoeU54RFNUbkFaNlNTUjZMQWFBbWdCeEd4ZWVRKzVVOGRuUXkx?= =?utf-8?B?N0Z3NkkvUWEwN2x4azcxaHMwNkh2Q1U2TEZlUXVGcmE1VW00VEN2NjlpSUtU?= =?utf-8?B?N2F0eFZWTCtUTzQrUXlyWmtmRXcrVzFjV3ZhYktOa3dQOUxwWjJCUVNYb2Va?= =?utf-8?B?RzgwY1MyQ0dQVnltcHRlcHhXNlZkZ3VuRDc4azVQSThPM2QraEgwQm10NmJF?= =?utf-8?B?Mk4wOXk1UzhlbTZCUTEzQ1dsVWFEZnZ4WkRNWEQzTjY2ajVyZzg2bkNTWnFa?= =?utf-8?B?WSt6aC9WWE1XUG5hL0xmZ0EwN3RLY3UwVmNDbWc0akNaaTh4Z2lhUGlVcGtq?= =?utf-8?B?bHRhQzRQTEl2MTIyeWQ1bWtmRlIvWkhvWXpZY1RnN2VJVFVFSlkzSjYzOXE1?= =?utf-8?B?NkdxZS9ZTjVBdDBVMGEraXkwdXZrbFlCMnU3Rm5oNmR1STl4RE8xMXNCRGx0?= =?utf-8?B?akRIRmNTdDNSelB4M1htNDREWngvMEdvNFJOSHgyZExoWjhrcXVPNEx0eFpU?= =?utf-8?B?Tk5Cb0ZXZmZ6UWdUcEJ2aEhjMjEvRFFVUEM4L3dMR0dITC9mUVljVmdxc0V2?= =?utf-8?B?K3h4ejlya04vcUFtdHFBZGVmY2hJeHkvMkZVbkZBTDZMZHlWMHUwWEcxWWJo?= =?utf-8?B?YWFBZDl1bUFjZGNPbWltM2puUEQxOUtTMzk4Tk1TanRyckNOZjlESDNOSTE5?= =?utf-8?B?bk9kY0VyRmFPOTk3VGRGQlg4OHRkSEJVU1IwbXQ1UkM1Z2d1b0NzVFRMbHFB?= =?utf-8?B?ZUFKaUgrYWVpSXR2WDRpYVJuRlJFRTNtdkh1L3ZsWlNaRklZU0xmUT09?= X-OriginatorOrg: garyguo.net X-MS-Exchange-CrossTenant-Network-Message-Id: 6abad7a6-0081-4c9a-0f5e-08dec598680a X-MS-Exchange-CrossTenant-AuthSource: LOVP265MB8871.GBRP265.PROD.OUTLOOK.COM X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 08 Jun 2026 19:59:10.5121 (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: c1PQWMpoJakW5qTCsevm/EbUWJezFJ2YCZcMM6LzKUtbmcKnGiJL1k6GsykxVUthBdLPyBD5xhZ8UeETWGKvrA== X-MS-Exchange-Transport-CrossTenantHeadersStamped: LO8P265MB7398 Most users would more commonly reach out to a view of `Mmio` rather than an owned instance of `Mmio`. Only implementor of `Io` like `Bar` or `IoMem` would need the owned version. Thus, rename `Mmio` to `MmioOwned` so that the name `Mmio` can be used for the view type instead. Signed-off-by: Gary Guo Suggested-by: Danilo Krummrich --- rust/kernel/devres.rs | 6 ++-- rust/kernel/io.rs | 77 +++++++++++++++++++++++-------------------= ---- rust/kernel/io/mem.rs | 8 ++--- rust/kernel/io/poll.rs | 8 ++--- rust/kernel/io/register.rs | 24 +++++++-------- rust/kernel/pci/io.rs | 6 ++-- 6 files changed, 65 insertions(+), 64 deletions(-) diff --git a/rust/kernel/devres.rs b/rust/kernel/devres.rs index d0c677fd7932..aed0c994fd30 100644 --- a/rust/kernel/devres.rs +++ b/rust/kernel/devres.rs @@ -68,7 +68,7 @@ struct Inner { /// devres::Devres, /// io::{ /// Io, -/// Mmio, +/// MmioOwned, /// MmioRaw, /// PhysAddr, /// Region, // @@ -105,11 +105,11 @@ struct Inner { /// } /// /// impl Deref for IoMem { -/// type Target =3D Mmio; +/// type Target =3D MmioOwned; /// /// fn deref(&self) -> &Self::Target { /// // SAFETY: The memory range stored in `self` has been properly= mapped in `Self::new`. -/// unsafe { Mmio::from_raw(&self.0) } +/// unsafe { MmioOwned::from_raw(&self.0) } /// } /// } /// # fn no_run(dev: &Device) -> Result<(), Error> { diff --git a/rust/kernel/io.rs b/rust/kernel/io.rs index c9533d3f003b..d5c233a66846 100644 --- a/rust/kernel/io.rs +++ b/rust/kernel/io.rs @@ -96,8 +96,8 @@ fn size(p: *const Self) -> usize { /// the represented MMIO region does exist or is properly mapped. /// /// Instead, the bus specific MMIO implementation must convert this raw re= presentation into an -/// `Mmio` instance providing the actual memory accessors. Only by the con= version into an `Mmio` -/// structure any guarantees are given. +/// `MmioOwned` instance providing the actual memory accessors. Only by th= e conversion into an +/// `MmioOwned` structure any guarantees are given. pub struct MmioRaw { /// Pointer is in I/O address space. /// @@ -172,7 +172,7 @@ pub fn size(&self) -> usize { /// ffi::c_void, /// io::{ /// Io, -/// Mmio, +/// MmioOwned, /// MmioRaw, /// PhysAddr, /// Region, @@ -208,11 +208,11 @@ pub fn size(&self) -> usize { /// } /// /// impl Deref for IoMem { -/// type Target =3D Mmio; +/// type Target =3D MmioOwned; /// /// fn deref(&self) -> &Self::Target { /// // SAFETY: The memory range stored in `self` has been properly= mapped in `Self::new`. -/// unsafe { Mmio::from_raw(&self.0) } +/// unsafe { MmioOwned::from_raw(&self.0) } /// } /// } /// @@ -226,7 +226,7 @@ pub fn size(&self) -> usize { /// # } /// ``` #[repr(transparent)] -pub struct Mmio(MmioRaw>); +pub struct MmioOwned(MmioRaw>); =20 /// Checks whether an access of type `U` at the given `base` and the given= `offset` /// is valid within this region. @@ -538,10 +538,10 @@ fn write64(self, value: u64, offset: usize) /// ```no_run /// use kernel::io::{ /// Io, - /// Mmio, + /// MmioOwned, /// }; /// - /// fn do_reads(io: &Mmio) -> Result { + /// fn do_reads(io: &MmioOwned) -> Result { /// // 32-bit read from address `0x10`. /// let v: u32 =3D io.try_read(0x10)?; /// @@ -572,10 +572,10 @@ fn try_read(self, location: L) -> Result /// ```no_run /// use kernel::io::{ /// Io, - /// Mmio, + /// MmioOwned, /// }; /// - /// fn do_writes(io: &Mmio) -> Result { + /// fn do_writes(io: &MmioOwned) -> Result { /// // 32-bit write of value `1` at address `0x10`. /// io.try_write(0x10, 1u32)?; /// @@ -610,7 +610,7 @@ fn try_write(self, location: L, value: T) -> Resu= lt /// use kernel::io::{ /// register, /// Io, - /// Mmio, + /// MmioOwned, /// }; /// /// register! { @@ -626,7 +626,7 @@ fn try_write(self, location: L, value: T) -> Resu= lt /// } /// } /// - /// fn do_write_reg(io: &Mmio) -> Result { + /// fn do_write_reg(io: &MmioOwned) -> Result { /// /// io.try_write_reg(VERSION::new(1, 0)) /// } @@ -655,10 +655,10 @@ fn try_write_reg(self, value: V) -> Result /// ```no_run /// use kernel::io::{ /// Io, - /// Mmio, + /// MmioOwned, /// }; /// - /// fn do_update(io: &Mmio<0x1000>) -> Result { + /// fn do_update(io: &MmioOwned<0x1000>) -> Result { /// io.try_update(0x10, |v: u32| { /// v + 1 /// }) @@ -692,10 +692,10 @@ fn try_update(self, location: L, f: F) -> Re= sult /// ```no_run /// use kernel::io::{ /// Io, - /// Mmio, + /// MmioOwned, /// }; /// - /// fn do_reads(io: &Mmio<0x1000>) { + /// fn do_reads(io: &MmioOwned<0x1000>) { /// // 32-bit read from address `0x10`. /// let v: u32 =3D io.read(0x10); /// @@ -724,10 +724,10 @@ fn read(self, location: L) -> T /// ```no_run /// use kernel::io::{ /// Io, - /// Mmio, + /// MmioOwned, /// }; /// - /// fn do_writes(io: &Mmio<0x1000>) { + /// fn do_writes(io: &MmioOwned<0x1000>) { /// // 32-bit write of value `1` at address `0x10`. /// io.write(0x10, 1u32); /// @@ -758,7 +758,7 @@ fn write(self, location: L, value: T) /// use kernel::io::{ /// register, /// Io, - /// Mmio, + /// MmioOwned, /// }; /// /// register! { @@ -774,7 +774,7 @@ fn write(self, location: L, value: T) /// } /// } /// - /// fn do_write_reg(io: &Mmio<0x1000>) { + /// fn do_write_reg(io: &MmioOwned<0x1000>) { /// io.write_reg(VERSION::new(1, 0)); /// } /// ``` @@ -802,10 +802,10 @@ fn write_reg(self, value: V) /// ```no_run /// use kernel::io::{ /// Io, - /// Mmio, + /// MmioOwned, /// }; /// - /// fn do_update(io: &Mmio<0x1000>) { + /// fn do_update(io: &MmioOwned<0x1000>) { /// io.update(0x10, |v: u32| { /// v + 1 /// }) @@ -848,19 +848,19 @@ unsafe fn io_write(self, value: $ty, address: usize) { } =20 // MMIO regions support 8, 16, and 32-bit accesses. -impl_mmio_io_capable!(Mmio, u8, readb, writeb); -impl_mmio_io_capable!(Mmio, u16, readw, writew); -impl_mmio_io_capable!(Mmio, u32, readl, writel); +impl_mmio_io_capable!(MmioOwned, u8, readb, writeb); +impl_mmio_io_capable!(MmioOwned, u16, readw, writew); +impl_mmio_io_capable!(MmioOwned, u32, readl, writel); // MMIO regions on 64-bit systems also support 64-bit accesses. impl_mmio_io_capable!( - Mmio, + MmioOwned, #[cfg(CONFIG_64BIT)] u64, readq, writeq ); =20 -impl<'a, const SIZE: usize> Io for &'a Mmio { +impl<'a, const SIZE: usize> Io for &'a MmioOwned { type Target =3D Region; =20 /// Returns the base address of this mapping. @@ -876,27 +876,28 @@ fn maxsize(self) -> usize { } } =20 -impl Mmio { - /// Converts an `MmioRaw` into an `Mmio` instance, providing the acces= sors to the MMIO mapping. +impl MmioOwned { + /// Converts an `MmioRaw` into an `MmioOwned` instance, providing the = accessors to the MMIO + /// mapping. /// /// # Safety /// /// Callers must ensure that `addr` is the start of a valid I/O mapped= memory region of size /// `maxsize`. pub unsafe fn from_raw(raw: &MmioRaw>) -> &Self { - // SAFETY: `Mmio` is a transparent wrapper around `MmioRaw`. + // SAFETY: `MmioOwned` is a transparent wrapper around `MmioRaw`. unsafe { &*core::ptr::from_ref(raw).cast() } } } =20 -/// [`Mmio`] wrapper using relaxed accessors. +/// [`MmioOwned`] wrapper using relaxed accessors. /// /// This type provides an implementation of [`Io`] that uses relaxed I/O M= MIO operands instead of /// the regular ones. /// -/// See [`Mmio::relaxed`] for a usage example. +/// See [`MmioOwned::relaxed`] for a usage example. #[repr(transparent)] -pub struct RelaxedMmio(Mmio); +pub struct RelaxedMmio(MmioOwned); =20 impl<'a, const SIZE: usize> Io for &'a RelaxedMmio { type Target =3D Region; @@ -912,7 +913,7 @@ fn maxsize(self) -> usize { } } =20 -impl Mmio { +impl MmioOwned { /// Returns a [`RelaxedMmio`] reference that performs relaxed I/O oper= ations. /// /// Relaxed accessors do not provide ordering guarantees with respect = to DMA or memory accesses @@ -923,19 +924,19 @@ impl Mmio { /// ```no_run /// use kernel::io::{ /// Io, - /// Mmio, + /// MmioOwned, /// RelaxedMmio, /// }; /// - /// fn do_io(io: &Mmio<0x100>) { + /// fn do_io(io: &MmioOwned<0x100>) { /// // The access is performed using `readl_relaxed` instead of `r= eadl`. /// let v =3D io.relaxed().read32(0x10); /// } /// /// ``` pub fn relaxed(&self) -> &RelaxedMmio { - // SAFETY: `RelaxedMmio` is `#[repr(transparent)]` over `Mmio`, so= `Mmio` and - // `RelaxedMmio` have identical layout. + // SAFETY: `RelaxedMmio` is `#[repr(transparent)]` over `MmioOwned= `, so `MmioOwned` + // and `RelaxedMmio` have identical layout. unsafe { core::mem::transmute(self) } } } diff --git a/rust/kernel/io/mem.rs b/rust/kernel/io/mem.rs index 9e15bc8fde78..8f6c257c5b8e 100644 --- a/rust/kernel/io/mem.rs +++ b/rust/kernel/io/mem.rs @@ -16,7 +16,7 @@ Region, Resource, // }, - Mmio, + MmioOwned, MmioRaw, // }, prelude::*, @@ -211,7 +211,7 @@ pub fn into_devres(self) -> Result>> { } =20 impl Deref for ExclusiveIoMem<'_, SIZE> { - type Target =3D Mmio; + type Target =3D MmioOwned; =20 fn deref(&self) -> &Self::Target { &self.iomem @@ -291,10 +291,10 @@ fn drop(&mut self) { } =20 impl Deref for IoMem<'_, SIZE> { - type Target =3D Mmio; + type Target =3D MmioOwned; =20 fn deref(&self) -> &Self::Target { // SAFETY: Safe as by the invariant of `IoMem`. - unsafe { Mmio::from_raw(&self.io) } + unsafe { MmioOwned::from_raw(&self.io) } } } diff --git a/rust/kernel/io/poll.rs b/rust/kernel/io/poll.rs index 75d1b3e8596c..79828a8006b5 100644 --- a/rust/kernel/io/poll.rs +++ b/rust/kernel/io/poll.rs @@ -47,14 +47,14 @@ /// ```no_run /// use kernel::io::{ /// Io, -/// Mmio, +/// MmioOwned, /// poll::read_poll_timeout, // /// }; /// use kernel::time::Delta; /// /// const HW_READY: u16 =3D 0x01; /// -/// fn wait_for_hardware(io: &Mmio) -> Result { +/// fn wait_for_hardware(io: &MmioOwned) -> Resul= t { /// read_poll_timeout( /// // The `op` closure reads the value of a specific status regis= ter. /// || io.try_read16(0x1000), @@ -134,14 +134,14 @@ pub fn read_poll_timeout( /// ```no_run /// use kernel::io::{ /// Io, -/// Mmio, +/// MmioOwned, /// poll::read_poll_timeout_atomic, // /// }; /// use kernel::time::Delta; /// /// const HW_READY: u16 =3D 0x01; /// -/// fn wait_for_hardware(io: &Mmio) -> Result { +/// fn wait_for_hardware(io: &MmioOwned) -> Resul= t { /// read_poll_timeout_atomic( /// // The `op` closure reads the value of a specific status regis= ter. /// || io.try_read16(0x1000), diff --git a/rust/kernel/io/register.rs b/rust/kernel/io/register.rs index 1e81de770b4f..e375a1332f37 100644 --- a/rust/kernel/io/register.rs +++ b/rust/kernel/io/register.rs @@ -58,7 +58,7 @@ //! }, //! num::Bounded, //! }; -//! # use kernel::io::Mmio; +//! # use kernel::io::MmioOwned; //! # register! { //! # pub BOOT_0(u32) @ 0x00000100 { //! # 15:8 vendor_id; @@ -66,7 +66,7 @@ //! # 3:0 minor_revision; //! # } //! # } -//! # fn test(io: &Mmio<0x1000>) { +//! # fn test(io: &MmioOwned<0x1000>) { //! # fn obtain_vendor_id() -> u8 { 0xff } //! //! // Read from the register's defined offset (0x100). @@ -446,7 +446,7 @@ fn into_io_op(self) -> (FixedRegisterLoc, T) { /// Io, /// }, /// }; -/// # use kernel::io::Mmio; +/// # use kernel::io::MmioOwned; /// /// register! { /// FIXED_REG(u32) @ 0x100 { @@ -455,7 +455,7 @@ fn into_io_op(self) -> (FixedRegisterLoc, T) { /// } /// } /// -/// # fn test(io: &Mmio<0x1000>) { +/// # fn test(io: &MmioOwned<0x1000>) { /// let val =3D io.read(FIXED_REG); /// /// // Write from an already-existing value. @@ -559,7 +559,7 @@ fn into_io_op(self) -> (FixedRegisterLoc, T) { /// Io, /// }, /// }; -/// # use kernel::io::Mmio; +/// # use kernel::io::MmioOwned; /// /// // Type used to identify the base. /// pub struct CpuCtlBase; @@ -584,7 +584,7 @@ fn into_io_op(self) -> (FixedRegisterLoc, T) { /// } /// } /// -/// # fn test(io: Mmio<0x1000>) { +/// # fn test(io: MmioOwned<0x1000>) { /// // Read the status of `Cpu0`. /// let cpu0_started =3D io.read(CPU_CTL::of::()); /// @@ -601,7 +601,7 @@ fn into_io_op(self) -> (FixedRegisterLoc, T) { /// } /// } /// -/// # fn test2(io: Mmio<0x1000>) { +/// # fn test2(io: MmioOwned<0x1000>) { /// // Start the aliased `CPU0`, leaving its other fields untouched. /// io.update(CPU_CTL_ALIAS::of::(), |r| r.with_alias_start(true)); /// # } @@ -638,7 +638,7 @@ fn into_io_op(self) -> (FixedRegisterLoc, T) { /// Io, /// }, /// }; -/// # use kernel::io::Mmio; +/// # use kernel::io::MmioOwned; /// # fn get_scratch_idx() -> usize { /// # 0x15 /// # } @@ -651,7 +651,7 @@ fn into_io_op(self) -> (FixedRegisterLoc, T) { /// } /// } /// -/// # fn test(io: &Mmio<0x1000>) +/// # fn test(io: &MmioOwned<0x1000>) /// # -> Result<(), Error>{ /// // Read scratch register 0, i.e. I/O address `0x80`. /// let scratch_0 =3D io.read(SCRATCH::at(0)).value(); @@ -724,7 +724,7 @@ fn into_io_op(self) -> (FixedRegisterLoc, T) { /// Io, /// }, /// }; -/// # use kernel::io::Mmio; +/// # use kernel::io::MmioOwned; /// # fn get_scratch_idx() -> usize { /// # 0x15 /// # } @@ -752,7 +752,7 @@ fn into_io_op(self) -> (FixedRegisterLoc, T) { /// } /// } /// -/// # fn test(io: &Mmio<0x1000>) -> Result<(), Error> { +/// # fn test(io: &MmioOwned<0x1000>) -> Result<(), Error> { /// // Read scratch register 0 of CPU0. /// let scratch =3D io.read(CPU_SCRATCH::of::().at(0)); /// @@ -794,7 +794,7 @@ fn into_io_op(self) -> (FixedRegisterLoc, T) { /// } /// } /// -/// # fn test2(io: &Mmio<0x1000>) -> Result<(), Error> { +/// # fn test2(io: &MmioOwned<0x1000>) -> Result<(), Error> { /// let cpu0_status =3D io.read(CPU_FIRMWARE_STATUS::of::()).status(= ); /// # Ok(()) /// # } diff --git a/rust/kernel/pci/io.rs b/rust/kernel/pci/io.rs index 42f840d64a6f..e0acb62f58a2 100644 --- a/rust/kernel/pci/io.rs +++ b/rust/kernel/pci/io.rs @@ -10,7 +10,7 @@ io::{ Io, IoCapable, - Mmio, + MmioOwned, MmioRaw, Region, // }, @@ -242,11 +242,11 @@ fn drop(&mut self) { } =20 impl Deref for Bar<'_, SIZE> { - type Target =3D Mmio; + type Target =3D MmioOwned; =20 fn deref(&self) -> &Self::Target { // SAFETY: By the type invariant of `Self`, the MMIO range in `sel= f.io` is properly mapped. - unsafe { Mmio::from_raw(&self.io) } + unsafe { MmioOwned::from_raw(&self.io) } } } =20 --=20 2.54.0 From nobody Thu Jun 25 00:35:31 2026 Received: from LO3P265CU004.outbound.protection.outlook.com (mail-uksouthazon11020097.outbound.protection.outlook.com [52.101.196.97]) (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 99D713EDAB1; Mon, 8 Jun 2026 19:59:22 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=52.101.196.97 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780948765; cv=fail; b=Cy+upv4IlXusEQtVSaCwf6vqeEl8PEmhqToc1PUhF/Wa9yL36lP0WdJNlM8irivIZW7qqEaAB/N2ngL+nSndGnXh+XGgKqWg8+DAFCfsKl+ULPHsfC9m7AC/lDFahJlI4c28ywkvRPGc6tWoMIeJfa7WtDSG5xlgRR65JUfdU7o= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780948765; c=relaxed/simple; bh=r2q1qWfO5e8jFD2g6fm9zgAg3vp0e062rU1FIO/ucj8=; h=From:Date:Subject:Content-Type:Message-Id:References:In-Reply-To: To:Cc:MIME-Version; b=aSxwbVRCKCPlgNWgkguFkzWiL/ELCcsMPmvp2GfpQvqe6JJMXD/2P9VnvmNaypdefSwuHAi04SGSLdgEuIBnNrf0Wm9M/jFAfTx+bCLqjp1dGgxIby0FfhBL1YhZKfjAslxqh2nOIat3SIZTYG/yUURxHULOsHLaUGlpfECJCok= 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=YcC13fwe; arc=fail smtp.client-ip=52.101.196.97 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="YcC13fwe" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=ZhQNgHdsrDgVB3kNMCS+h3wz44g2hM4mYNQTFEDcJoydqXWM4kohho27QtrvXjCGYO0NVte3XhqCrRudBv4DFJHV5meXh+/v9kMhcFmPDCJ3VOrnDSwkc031Gotfmh8vQAcWX0p2U1fMzNvSzPTk0lZlM1NhJQXTxCNyxk29aF1aGevkUEfXMf0cEOU/6HMoe8QvyNQbA44uzXf9qhHsv/iZG/hFdYWjnR1UGZNVAt4/n9DFHp0D2l4jfBgPQ10OgbjIIhhl21L3MvdpaPymUifA7WyLRIHMSZGXDm+fJqcgYfyyA+PpWBJEe6/uzNCnCSaztaZOpfSg81NSQ+7+Dw== 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=nEfMySBA5gL3Uwz/ku/52pFwMwCdpQEsHoeUoShfEXs=; b=MD7MRlwfI2Nq6pDRJdY0nCqQ1kkiOynJJ+nyvF3FmJQwCA0WteaPGz3UWyAFRjjVtSmu0GAQLjXiHTlRLnxfJM/8Rpd91HOHKSTC6KVURP8NmhBoKXSwxFstvbbta34dZYoM19ZonUwrSqehd6qDXO6adwpQTcu1mddSpqJBUsVhSjETaZ0jihTipu2k/V8vsaQlk/gMracZm/PVP17I80cS1xM828yz+tdjSFcpTXNrsHkYfbD7/X4qWAUdd+7/dElh2FyLSOGeHpLkyXAjNtJbx6kNTacmkd0SXmr1WpGhsZ+cSF7xTAygGLCap2aoT7IucUuizGBCzDOwA3B+6A== 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=nEfMySBA5gL3Uwz/ku/52pFwMwCdpQEsHoeUoShfEXs=; b=YcC13fweLU/68YEEXHda3gTqWcO7KMiztvZt9B9WoaKtHgjimFCP97+bg/q+SvYMftvR8B9/kfEV6+ZqeaktDMsCOsQ5SMhtTiVgZmUZtghyqwT+BivfOiAdLa/t24++LQ94QvM+I8bVRBCgf1P/B6wGZ51lHE8ail/rG5h4Ui4= Authentication-Results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=garyguo.net; Received: from LOVP265MB8871.GBRP265.PROD.OUTLOOK.COM (2603:10a6:600:488::16) by LO8P265MB7398.GBRP265.PROD.OUTLOOK.COM (2603:10a6:600:3ca::5) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.21.92.12; Mon, 8 Jun 2026 19:59:10 +0000 Received: from LOVP265MB8871.GBRP265.PROD.OUTLOOK.COM ([fe80::1c3:ceba:21b4:9986]) by LOVP265MB8871.GBRP265.PROD.OUTLOOK.COM ([fe80::1c3:ceba:21b4:9986%4]) with mapi id 15.21.0092.011; Mon, 8 Jun 2026 19:59:10 +0000 From: Gary Guo Date: Mon, 08 Jun 2026 20:59:04 +0100 Subject: [PATCH v3 07/19] rust: io: implement `Mmio` as view type Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260608-io_projection-v3-7-c5cde13a5ec4@garyguo.net> References: <20260608-io_projection-v3-0-c5cde13a5ec4@garyguo.net> In-Reply-To: <20260608-io_projection-v3-0-c5cde13a5ec4@garyguo.net> To: Danilo Krummrich , Alice Ryhl , Daniel Almeida , Greg Kroah-Hartman , "Rafael J. Wysocki" , Miguel Ojeda , Boqun Feng , Gary Guo , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Andreas Hindborg , Trevor Gross , Bjorn Helgaas , =?utf-8?q?Krzysztof_Wilczy=C5=84ski?= , Abdiel Janulgue , Robin Murphy , Alexandre Courbot , David Airlie , Simona Vetter Cc: driver-core@lists.linux.dev, rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, linux-pci@vger.kernel.org, nova-gpu@lists.linux.dev, dri-devel@lists.freedesktop.org X-Mailer: b4 0.15.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1780948747; l=16544; i=gary@garyguo.net; s=20221204; h=from:subject:message-id; bh=r2q1qWfO5e8jFD2g6fm9zgAg3vp0e062rU1FIO/ucj8=; b=On/r4pfiW8c7U/YE1O08vKoFGA2NJRYIqz4l2MH8j1PQA+5rZxdfubFgSR99WtSB1G5R6NJw5 9an3oto88o7CzV8oAFPTCt3DkVOCRHu4puUY77gbaRHQTas5eUnindr X-Developer-Key: i=gary@garyguo.net; a=ed25519; pk=vB3uIX95SM4eVrIqo1DWNWKDKD2xzB+yLLLr0yOPYMo= X-ClientProxiedBy: LO4P123CA0344.GBRP123.PROD.OUTLOOK.COM (2603:10a6:600:18d::7) To LOVP265MB8871.GBRP265.PROD.OUTLOOK.COM (2603:10a6:600:488::16) 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: LOVP265MB8871:EE_|LO8P265MB7398:EE_ X-MS-Office365-Filtering-Correlation-Id: 015066b1-da44-4d36-788e-08dec5986844 X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|1800799024|7416014|376014|366016|10070799003|6133799003|22082099003|18002099003|921020|56012099006|5023799004; X-Microsoft-Antispam-Message-Info: Koopa51sFrQKFAOWL9jJ3EZ5VIpVvfR2NzwC8ee5S+YaA15Skf7i7C4giXqqc2QN9LKDtjO1VYtjS7SYWitpJleBNx7vY5h4GCzpMvfBLp/WYKtq91JiP0tBGzlFkd7GtF59PBYTHDcPxYSXl6PjHbgkMCVmrzrOZmUDcrq8PqnPk5cGcYcnbPAQQQZdOEPnSKAj38yACjQHkf8zeiH/SmUKZJMfQEZITzgTgFVkwoRWre68NeHYNq+WUmm8JWIZCiZJtqZZ9bHoRVybyfdm8xazxzLHADnlzSCAXoNTQtYVMXvLMDq6zZ6y0HERzTp2uGrjr9TnC3xtDx4eIUd94uyKt54K+yhC6w+VQ3M/FQPgQFga+pJAILzKFMzzdv6HnLUNV64w9GkKju/BSXVI3tgrLYOgxej6LArxohHbpq/SAC35hV5MF3gPf2RvkeFRYs94dxiPX+VXZE4dYqdt+lFkxtTLvu8fX1gjv7K5HmZLL9UF8t5RVCQ3d8gP2iwuR0HfdkdYQp2HQ0MdmTRRQD7KhtSwrK1jCrkR+S/xZGwbtibXGI0TNog5CmbfMiHJocO9cOa4UNcMGIuucdLdtTkzpprgkPkkzgRqcgtKCwtIililaOBGvnlXrr9WuaS7Qf0+5fDMiVwUkFFqgKjA7opqsP0uzBsShq2zf66Fd5+Qh3cIwGdchVpuCcAro1DkN11fMgxJfQVjwKaEZeEDQp/Ns9z21ooTNNTG5vW5ck8= X-Forefront-Antispam-Report: CIP:255.255.255.255;CTRY:;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:LOVP265MB8871.GBRP265.PROD.OUTLOOK.COM;PTR:;CAT:NONE;SFS:(13230040)(1800799024)(7416014)(376014)(366016)(10070799003)(6133799003)(22082099003)(18002099003)(921020)(56012099006)(5023799004);DIR:OUT;SFP:1102; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: =?utf-8?B?OXFld2tZa1YxV3lJdU1ocjYxZVZKWGpJaUNyQUpHelJ3aFQ0b3FyMnJWdlBI?= =?utf-8?B?dVRiVGRIMEFTem4wOGFMQm9GeUFMaVBuTHdoOTRQenFIN21sclFKem40cmt1?= =?utf-8?B?ZWhSeUpwcDJ2V0NKRllGWVIwcWhPTGZ6SU14eXE5THlwS2k0SmQyeGdML0Vv?= =?utf-8?B?TXpsdnErUVVvS21PSEs2R2RBMnkrUEhJOWI2NTNJdXdCZ3IrRjV5bmtSL1Mz?= =?utf-8?B?NU9tQ0Uvb1BLSE1LbjdXSnlsT0hXMCtjNENVMFhvSUFtcUJKNTAySTlWcG9W?= =?utf-8?B?QW10OXFaL2NWWTdlUjNDVjhoeW5lR0FqMnU2R3EwWFB3S1k2NE1Wd2wwWXFT?= =?utf-8?B?Ui9kWDkrdWE4TktHQmlWY0xxemlGcUhOMzZlN01vRG1mTDltZHVyUGgzelJC?= =?utf-8?B?Sncxa2JzLzJSYWVDK0FYSGZvZ3VJYWpsMStTYlFRWUZMK2NzTXRCNklSbFA1?= =?utf-8?B?aEsyNjIxY2Z4VGJOeTljVnhlQzZaNkV0eFVKVzB5dGFSV2QxUjFNRlZ5TTZm?= =?utf-8?B?NnVNNGJ3ZlNHTkNwN2JQUXhFa0JDMjMwUmMyWnRYb2l6NVZaVjNESm5NNTZ2?= =?utf-8?B?OURST0FUUm1oYUFMWVNXc2E0UTdvVVhPdEVLSVhLbDdCVGdEbTkzUHVzQ3dI?= =?utf-8?B?Y3g3VWRTR1YzQkpjVm1kZWtiWnM1SGZwZUt1WDhOakJWNUZQSjEwWk1QS3Fa?= =?utf-8?B?RktJYmQyNHJZd0YxZDg2aElBcmxnNElVMjJHR1dJQWpIaEo1Sk5YRnJGS2U2?= =?utf-8?B?cDJsSFJrYmJJZCtIVFBqS3AzQWM5OWdZci83QmQ5d04zZXdpSkdDQ21kbW9o?= =?utf-8?B?ODl2NU8vaThEVXFYSDd0WjdnNFVPY0tjSDRUUHRna0wzckZlR2ZJa2xjQUll?= =?utf-8?B?R2x4L3p3WlZWMm02NFBTTDczRTZ6cktadkNqdzVxVWRFMnZueGdmMVlmT3g5?= =?utf-8?B?SHpjMHFSSUswbHorZVBKdVBWMk8xMGJCZHl2UkdPdzQ1eUZVbTlUdEZhVGpk?= =?utf-8?B?bHpqWkh2a0NSeFhDLzdEQVpkeUpwUkRDY0lIa3F4TUwwV0Q4TVV2dlZrcnRL?= =?utf-8?B?TTRVRk82WWxUOG13cVlieTdVZDg1bFkvZXlOYWVqSnlWT0NQSTk4eUhYRlNL?= =?utf-8?B?OFRXQzZQeWIvTWRDclpNZ0xqRm50NnVPaVNsK3dCcURIdEZndndtN09UMDhW?= =?utf-8?B?WWJvaW5oTnozUHdOcTJ6dGJ6S3dyL1IwOVVDYzR4d0dKTzJjQ055UnVmbXVZ?= =?utf-8?B?R0hPbCtMTVRKTzROalVpVklDbnBITGVyTVBLRjVmaTFteHVkbUFSNHcrMGVY?= =?utf-8?B?MFhYTHFZMjUxYzY3UmtuemprN0dKdEhxRjBVQnBrMi8zTGVvT0tFczczenBt?= =?utf-8?B?cnMwRUJxQVg2bjFkZ0lEMEpaUGVldTlHNVZndmlMOEVFYUFMVzhhVHhKWmNj?= =?utf-8?B?TE5QNUYrcGNFVm9qcmFSWHFmY3Y1cTVvRURZd3pKa0FPK1BBQ3hOcnZPK2F4?= =?utf-8?B?c2lncU5La0N2VHpiR0YwMWxSRUp2WHBsempjTlBZdjBLMENmdytmamVtcnBs?= =?utf-8?B?aE5tYzkrQ3dPOGY1SERoMjljVmhuamhYRHlITzAxdEJBN2t2Q3IrWGJrcDFC?= =?utf-8?B?ZGZSUyt3YmhxdG9rNlZtRk5abU45QnhSQ3ErNHg1aWc4VzNKK1JvQWY0RUI2?= =?utf-8?B?UmhBVkJBM1dxd284WVVVRmVtYjhBNUdyS1A4K0RwelNtKzJLc1JkZTdibWox?= =?utf-8?B?OWdIZmFkNzF4R2ZmeW9hSmNqZmpienZpVVVUcXZ3OVlkZ2pJSjRRS0N6SEdK?= =?utf-8?B?djBKOTMvMHA2cEhsTk90Mzh4NElGV2hXRFhSMEJuTmVFN2RPcG1tV3R2UFhD?= =?utf-8?B?RGRLSnkzQnFxQXU1OTIwYVQyQXhOUHBRK2FYRFM4bHNQT0JZYTkvQ2lUSUVj?= =?utf-8?B?bElZSFc3bHFEL0JIamxtK0R1bVJTQnMyT2hpS1RmU2lBcFF5aXRoVjRkZHM0?= =?utf-8?B?R1R2dXg4bWN4YjhraGVaUXAzK3ZJelFVakx5MVZoQWJyclRzTW9HNGxhaFZ4?= =?utf-8?B?RFdkenhTaWFuRHZhVzBzTmhTTUNkc2hRYk1KZFdEdUIxQXdjLzNtSnRFZnFo?= =?utf-8?B?ekVIQlEzLzNmNUhHOTd1SVVwelZoT04rSVB6OWZkT1NnNnN3WHNVeXQyLzZU?= =?utf-8?B?ZE02N3RpRkxTRlB4WXA3VTBVV1JNT201dlA4NUtjZnMwMmd1ekw0K3pVOTNy?= =?utf-8?B?T3hCbHdZQ1BUaDFYelpsL0MwOE1iNkFVRFp2Ym5YQm13VDdzazRRWUtuc0dv?= =?utf-8?B?QTE3SlZKTzJzckhoTGhxQTErQm9QR1pNWk16Q3paeU9GQkhsTERzdz09?= X-OriginatorOrg: garyguo.net X-MS-Exchange-CrossTenant-Network-Message-Id: 015066b1-da44-4d36-788e-08dec5986844 X-MS-Exchange-CrossTenant-AuthSource: LOVP265MB8871.GBRP265.PROD.OUTLOOK.COM X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 08 Jun 2026 19:59:10.8893 (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: q8/RlTn3aaET7PLllG9T0fSzks0+rUlzsMj1AAx5V/7beJ8DZYuS5gmdg38AQrQAKwm0Sd08hci5RynUqrwFrw== X-MS-Exchange-Transport-CrossTenantHeadersStamped: LO8P265MB7398 Implement `Mmio` as view type and convert `RelaxedMmio` to view type as well. I/O implementations of `MmioOwned` are changed to delegate to the `Mmio` view type. All existing users of `MmioOwned` in the documentation which do not actually reflect the owning semantics is converted. Signed-off-by: Gary Guo Suggested-by: Danilo Krummrich --- rust/kernel/io.rs | 188 +++++++++++++++++++++++++++++++++++------= ---- rust/kernel/io/poll.rs | 10 ++- rust/kernel/io/register.rs | 24 +++--- 3 files changed, 164 insertions(+), 58 deletions(-) diff --git a/rust/kernel/io.rs b/rust/kernel/io.rs index d5c233a66846..771372a8aa36 100644 --- a/rust/kernel/io.rs +++ b/rust/kernel/io.rs @@ -4,6 +4,10 @@ //! //! C header: [`include/asm-generic/io.h`](srctree/include/asm-generic/io.= h) =20 +use core::{ + marker::PhantomData, // +}; + use crate::{ bindings, prelude::*, @@ -538,10 +542,11 @@ fn write64(self, value: u64, offset: usize) /// ```no_run /// use kernel::io::{ /// Io, - /// MmioOwned, + /// Mmio, + /// Region, /// }; /// - /// fn do_reads(io: &MmioOwned) -> Result { + /// fn do_reads(io: Mmio<'_, Region>) -> Result { /// // 32-bit read from address `0x10`. /// let v: u32 =3D io.try_read(0x10)?; /// @@ -572,10 +577,11 @@ fn try_read(self, location: L) -> Result /// ```no_run /// use kernel::io::{ /// Io, - /// MmioOwned, + /// Mmio, + /// Region, /// }; /// - /// fn do_writes(io: &MmioOwned) -> Result { + /// fn do_writes(io: Mmio<'_, Region>) -> Result { /// // 32-bit write of value `1` at address `0x10`. /// io.try_write(0x10, 1u32)?; /// @@ -610,7 +616,8 @@ fn try_write(self, location: L, value: T) -> Resu= lt /// use kernel::io::{ /// register, /// Io, - /// MmioOwned, + /// Mmio, + /// Region, /// }; /// /// register! { @@ -626,7 +633,7 @@ fn try_write(self, location: L, value: T) -> Resu= lt /// } /// } /// - /// fn do_write_reg(io: &MmioOwned) -> Result { + /// fn do_write_reg(io: Mmio<'_, Region>) -> Result { /// /// io.try_write_reg(VERSION::new(1, 0)) /// } @@ -655,10 +662,11 @@ fn try_write_reg(self, value: V) -> Result /// ```no_run /// use kernel::io::{ /// Io, - /// MmioOwned, + /// Mmio, + /// Region, /// }; /// - /// fn do_update(io: &MmioOwned<0x1000>) -> Result { + /// fn do_update(io: Mmio<'_, Region<0x1000>>) -> Result { /// io.try_update(0x10, |v: u32| { /// v + 1 /// }) @@ -692,10 +700,11 @@ fn try_update(self, location: L, f: F) -> Re= sult /// ```no_run /// use kernel::io::{ /// Io, - /// MmioOwned, + /// Mmio, + /// Region, /// }; /// - /// fn do_reads(io: &MmioOwned<0x1000>) { + /// fn do_reads(io: Mmio<'_, Region<0x1000>>) { /// // 32-bit read from address `0x10`. /// let v: u32 =3D io.read(0x10); /// @@ -724,10 +733,11 @@ fn read(self, location: L) -> T /// ```no_run /// use kernel::io::{ /// Io, - /// MmioOwned, + /// Mmio, + /// Region, /// }; /// - /// fn do_writes(io: &MmioOwned<0x1000>) { + /// fn do_writes(io: Mmio<'_, Region<0x1000>>) { /// // 32-bit write of value `1` at address `0x10`. /// io.write(0x10, 1u32); /// @@ -758,7 +768,8 @@ fn write(self, location: L, value: T) /// use kernel::io::{ /// register, /// Io, - /// MmioOwned, + /// Mmio, + /// Region, /// }; /// /// register! { @@ -774,7 +785,7 @@ fn write(self, location: L, value: T) /// } /// } /// - /// fn do_write_reg(io: &MmioOwned<0x1000>) { + /// fn do_write_reg(io: Mmio<'_, Region<0x1000>>) { /// io.write_reg(VERSION::new(1, 0)); /// } /// ``` @@ -802,10 +813,11 @@ fn write_reg(self, value: V) /// ```no_run /// use kernel::io::{ /// Io, - /// MmioOwned, + /// Mmio, + /// Region, /// }; /// - /// fn do_update(io: &MmioOwned<0x1000>) { + /// fn do_update(io: Mmio<'_, Region<0x1000>>) { /// io.update(0x10, |v: u32| { /// v + 1 /// }) @@ -829,16 +841,72 @@ fn update(self, location: L, f: F) } } =20 +/// A view of memory-mapped I/O region. +/// +/// # Invariant +/// +/// `ptr` points to a valid and aligned memory-mapped I/O region for the d= uration lifetime `'a`. +pub struct Mmio<'a, T: ?Sized> { + ptr: *mut T, + phantom: PhantomData<&'a ()>, +} + +impl Copy for Mmio<'_, T> {} +impl Clone for Mmio<'_, T> { + #[inline] + fn clone(&self) -> Self { + *self + } +} + +impl<'a, T: ?Sized> Mmio<'a, T> { + /// Create a `Mmio`, providing the accessors to the MMIO mapping. + /// + /// # Safety + /// + /// `raw` represents an valid and aligned memory-mapped I/O region whi= le `'a` is alive. + #[inline] + pub unsafe fn from_raw(raw: MmioRaw) -> Self { + // INVARIANT: Per safety requirement. + Self { + ptr: raw.ptr, + phantom: PhantomData, + } + } +} + +// SAFETY: `Mmio<'_, T>` is conceptually `&T` but in I/O memory. +unsafe impl Send for Mmio<'_, T> {} + +// SAFETY: `Mmio<'_, T>` is conceptually `&T` but in I/O memory. +unsafe impl Sync for Mmio<'_, T> {} + +impl Io for Mmio<'_, T> { + type Target =3D T; + + #[inline] + fn addr(self) -> usize { + self.ptr.addr() + } + + #[inline] + fn maxsize(self) -> usize { + KnownSize::size(self.ptr) + } +} + /// Implements [`IoCapable`] on `$mmio` for `$ty` using `$read_fn` and `$w= rite_fn`. macro_rules! impl_mmio_io_capable { ($mmio:ident, $(#[$attr:meta])* $ty:ty, $read_fn:ident, $write_fn:iden= t) =3D> { $(#[$attr])* - impl IoCapable<$ty> for &$mmio { + impl IoCapable<$ty> for $mmio<'_, T> { + #[inline] unsafe fn io_read(self, address: usize) -> $ty { // SAFETY: By the trait invariant `address` is a valid add= ress for MMIO operations. unsafe { bindings::$read_fn(address as *const c_void) } } =20 + #[inline] unsafe fn io_write(self, value: $ty, address: usize) { // SAFETY: By the trait invariant `address` is a valid add= ress for MMIO operations. unsafe { bindings::$write_fn(value, address as *mut c_void= ) } @@ -848,17 +916,12 @@ unsafe fn io_write(self, value: $ty, address: usize) { } =20 // MMIO regions support 8, 16, and 32-bit accesses. -impl_mmio_io_capable!(MmioOwned, u8, readb, writeb); -impl_mmio_io_capable!(MmioOwned, u16, readw, writew); -impl_mmio_io_capable!(MmioOwned, u32, readl, writel); +impl_mmio_io_capable!(Mmio, u8, readb, writeb); +impl_mmio_io_capable!(Mmio, u16, readw, writew); +impl_mmio_io_capable!(Mmio, u32, readl, writel); // MMIO regions on 64-bit systems also support 64-bit accesses. -impl_mmio_io_capable!( - MmioOwned, - #[cfg(CONFIG_64BIT)] - u64, - readq, - writeq -); +#[cfg(CONFIG_64BIT)] +impl_mmio_io_capable!(Mmio, u64, readq, writeq); =20 impl<'a, const SIZE: usize> Io for &'a MmioOwned { type Target =3D Region; @@ -876,6 +939,23 @@ fn maxsize(self) -> usize { } } =20 +impl<'a, const SIZE: usize, T> IoCapable for &'a MmioOwned +where + Mmio<'a, Region>: IoCapable, +{ + #[inline] + unsafe fn io_read(self, address: usize) -> T { + // SAFETY: Per safety requirement. + unsafe { self.as_view().io_read(address) } + } + + #[inline] + unsafe fn io_write(self, value: T, address: usize) { + // SAFETY: Per safety requirement. + unsafe { self.as_view().io_write(value, address) } + } +} + impl MmioOwned { /// Converts an `MmioRaw` into an `MmioOwned` instance, providing the = accessors to the MMIO /// mapping. @@ -888,32 +968,53 @@ pub unsafe fn from_raw(raw: &MmioRaw>) -= > &Self { // SAFETY: `MmioOwned` is a transparent wrapper around `MmioRaw`. unsafe { &*core::ptr::from_ref(raw).cast() } } + + /// Return a view that covers the full region. + #[inline] + pub fn as_view(&self) -> Mmio<'_, Region> { + // SAFETY: `Mmio` has same invariant as `MmioOwned`. + unsafe { Mmio::from_raw(self.0) } + } } =20 -/// [`MmioOwned`] wrapper using relaxed accessors. +/// [`Mmio`] but using relaxed accessors. /// /// This type provides an implementation of [`Io`] that uses relaxed I/O M= MIO operands instead of /// the regular ones. /// -/// See [`MmioOwned::relaxed`] for a usage example. -#[repr(transparent)] -pub struct RelaxedMmio(MmioOwned); +/// See [`Mmio::relaxed`] for a usage example. +/// +/// # Invariant +/// +/// `ptr` points to a valid and aligned memory-mapped I/O region for the d= uration lifetime `'a`. +pub struct RelaxedMmio<'a, T: ?Sized> { + ptr: *mut T, + phantom: PhantomData<&'a ()>, +} =20 -impl<'a, const SIZE: usize> Io for &'a RelaxedMmio { - type Target =3D Region; +impl Copy for RelaxedMmio<'_, T> {} +impl Clone for RelaxedMmio<'_, T> { + #[inline] + fn clone(&self) -> Self { + *self + } +} + +impl Io for RelaxedMmio<'_, T> { + type Target =3D T; =20 #[inline] fn addr(self) -> usize { - self.0.addr() + self.ptr.addr() } =20 #[inline] fn maxsize(self) -> usize { - self.0.maxsize() + KnownSize::size(self.ptr) } } =20 -impl MmioOwned { +impl<'a, T: ?Sized> Mmio<'a, T> { /// Returns a [`RelaxedMmio`] reference that performs relaxed I/O oper= ations. /// /// Relaxed accessors do not provide ordering guarantees with respect = to DMA or memory accesses @@ -924,20 +1025,23 @@ impl MmioOwned { /// ```no_run /// use kernel::io::{ /// Io, - /// MmioOwned, + /// Mmio, + /// Region, /// RelaxedMmio, /// }; /// - /// fn do_io(io: &MmioOwned<0x100>) { + /// fn do_io(io: Mmio<'_, Region<0x100>>) { /// // The access is performed using `readl_relaxed` instead of `r= eadl`. /// let v =3D io.relaxed().read32(0x10); /// } /// /// ``` - pub fn relaxed(&self) -> &RelaxedMmio { - // SAFETY: `RelaxedMmio` is `#[repr(transparent)]` over `MmioOwned= `, so `MmioOwned` - // and `RelaxedMmio` have identical layout. - unsafe { core::mem::transmute(self) } + pub fn relaxed(self) -> RelaxedMmio<'a, T> { + // INVARIANT: `RelaxedMmio` has the same invariant as `Mmio`. + RelaxedMmio { + ptr: self.ptr, + phantom: PhantomData, + } } } =20 diff --git a/rust/kernel/io/poll.rs b/rust/kernel/io/poll.rs index 79828a8006b5..d75f2fcf46f2 100644 --- a/rust/kernel/io/poll.rs +++ b/rust/kernel/io/poll.rs @@ -47,14 +47,15 @@ /// ```no_run /// use kernel::io::{ /// Io, -/// MmioOwned, +/// Mmio, +/// Region, /// poll::read_poll_timeout, // /// }; /// use kernel::time::Delta; /// /// const HW_READY: u16 =3D 0x01; /// -/// fn wait_for_hardware(io: &MmioOwned) -> Resul= t { +/// fn wait_for_hardware(io: Mmio<'_, Region>) ->= Result { /// read_poll_timeout( /// // The `op` closure reads the value of a specific status regis= ter. /// || io.try_read16(0x1000), @@ -134,14 +135,15 @@ pub fn read_poll_timeout( /// ```no_run /// use kernel::io::{ /// Io, -/// MmioOwned, +/// Mmio, +/// Region, /// poll::read_poll_timeout_atomic, // /// }; /// use kernel::time::Delta; /// /// const HW_READY: u16 =3D 0x01; /// -/// fn wait_for_hardware(io: &MmioOwned) -> Resul= t { +/// fn wait_for_hardware(io: Mmio<'_, Region>) ->= Result { /// read_poll_timeout_atomic( /// // The `op` closure reads the value of a specific status regis= ter. /// || io.try_read16(0x1000), diff --git a/rust/kernel/io/register.rs b/rust/kernel/io/register.rs index e375a1332f37..2fe7ba60a95f 100644 --- a/rust/kernel/io/register.rs +++ b/rust/kernel/io/register.rs @@ -58,7 +58,7 @@ //! }, //! num::Bounded, //! }; -//! # use kernel::io::MmioOwned; +//! # use kernel::io::{Mmio, Region}; //! # register! { //! # pub BOOT_0(u32) @ 0x00000100 { //! # 15:8 vendor_id; @@ -66,7 +66,7 @@ //! # 3:0 minor_revision; //! # } //! # } -//! # fn test(io: &MmioOwned<0x1000>) { +//! # fn test(io: Mmio<'_, Region<0x1000>>) { //! # fn obtain_vendor_id() -> u8 { 0xff } //! //! // Read from the register's defined offset (0x100). @@ -446,7 +446,7 @@ fn into_io_op(self) -> (FixedRegisterLoc, T) { /// Io, /// }, /// }; -/// # use kernel::io::MmioOwned; +/// # use kernel::io::{Mmio, Region}; /// /// register! { /// FIXED_REG(u32) @ 0x100 { @@ -455,7 +455,7 @@ fn into_io_op(self) -> (FixedRegisterLoc, T) { /// } /// } /// -/// # fn test(io: &MmioOwned<0x1000>) { +/// # fn test(io: Mmio<'_, Region<0x1000>>) { /// let val =3D io.read(FIXED_REG); /// /// // Write from an already-existing value. @@ -559,7 +559,7 @@ fn into_io_op(self) -> (FixedRegisterLoc, T) { /// Io, /// }, /// }; -/// # use kernel::io::MmioOwned; +/// # use kernel::io::{Mmio, Region}; /// /// // Type used to identify the base. /// pub struct CpuCtlBase; @@ -584,7 +584,7 @@ fn into_io_op(self) -> (FixedRegisterLoc, T) { /// } /// } /// -/// # fn test(io: MmioOwned<0x1000>) { +/// # fn test(io: Mmio<'_, Region<0x1000>>) { /// // Read the status of `Cpu0`. /// let cpu0_started =3D io.read(CPU_CTL::of::()); /// @@ -601,7 +601,7 @@ fn into_io_op(self) -> (FixedRegisterLoc, T) { /// } /// } /// -/// # fn test2(io: MmioOwned<0x1000>) { +/// # 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)); /// # } @@ -638,7 +638,7 @@ fn into_io_op(self) -> (FixedRegisterLoc, T) { /// Io, /// }, /// }; -/// # use kernel::io::MmioOwned; +/// # use kernel::io::{Mmio, Region}; /// # fn get_scratch_idx() -> usize { /// # 0x15 /// # } @@ -651,7 +651,7 @@ fn into_io_op(self) -> (FixedRegisterLoc, T) { /// } /// } /// -/// # fn test(io: &MmioOwned<0x1000>) +/// # fn test(io: Mmio<'_, Region<0x1000>>) /// # -> Result<(), Error>{ /// // Read scratch register 0, i.e. I/O address `0x80`. /// let scratch_0 =3D io.read(SCRATCH::at(0)).value(); @@ -724,7 +724,7 @@ fn into_io_op(self) -> (FixedRegisterLoc, T) { /// Io, /// }, /// }; -/// # use kernel::io::MmioOwned; +/// # use kernel::io::{Mmio, Region}; /// # fn get_scratch_idx() -> usize { /// # 0x15 /// # } @@ -752,7 +752,7 @@ fn into_io_op(self) -> (FixedRegisterLoc, T) { /// } /// } /// -/// # fn test(io: &MmioOwned<0x1000>) -> Result<(), Error> { +/// # fn test(io: Mmio<'_, Region<0x1000>>) -> Result<(), Error> { /// // Read scratch register 0 of CPU0. /// let scratch =3D io.read(CPU_SCRATCH::of::().at(0)); /// @@ -794,7 +794,7 @@ fn into_io_op(self) -> (FixedRegisterLoc, T) { /// } /// } /// -/// # fn test2(io: &MmioOwned<0x1000>) -> Result<(), Error> { +/// # fn test2(io: Mmio<'_, Region<0x1000>>) -> Result<(), Error> { /// let cpu0_status =3D io.read(CPU_FIRMWARE_STATUS::of::()).status(= ); /// # Ok(()) /// # } --=20 2.54.0 From nobody Thu Jun 25 00:35:31 2026 Received: from CWXP265CU008.outbound.protection.outlook.com (mail-ukwestazon11020099.outbound.protection.outlook.com [52.101.195.99]) (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 048EE3EDE53; Mon, 8 Jun 2026 19:59:23 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=52.101.195.99 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780948765; cv=fail; b=bfraPbeJBvh77wmSaGLBEGYZocU9olVyE8ABDEU7ngVBMUCGjQ15hzqPcZF6DpCqcTDYNIDU/JMe6VPwDYlb8aKR7k4m50vlIkaMOJ8Zhq95mzv9yOf5qV+NCj3XkFlrOwkwjweGmabpSuzJQkebhqZpLsWWF1dRhbys8D9HOvA= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780948765; c=relaxed/simple; bh=asZ8rlzSXV0U+EZg1Fe9smEUk3vFTSWP3reSKao5plc=; h=From:Date:Subject:Content-Type:Message-Id:References:In-Reply-To: To:Cc:MIME-Version; b=DkwwFxlPmfGXTR8KPY7gXGwT/3h5pidqM0/8k5eNEZfFAWYcYFCTo2tP8zC3EgLp3NROG4tvLjIP724vKn5/hurgeiwsHV28r7jCLr8E/6gh0I9Z93oZZxSJiKf0N7DYDczvCrKv3fX2/UPThaHB38HZvwoILTBd0xy5Yo33AZ8= 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=HMh5naKX; arc=fail smtp.client-ip=52.101.195.99 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="HMh5naKX" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=dZJ24nXNv+aHRu/Poz3ftMt+6zhHn7kFmbadyldLJdWb+xsMZaAtG3HgR0FKkTIfXDPri4d0i2wsThXzEWdr2hymEQUQUhm+gF7YooCmuowy+M8Y0Qfyf9LPLLogtjgAZlYuOZg47xIHKcpm8Ewz9uYm2MJSNnVxAm1OMlMgSSCggeq3G8z5A68DnQBYJrOAT2/ytHaO0i++Bh/mbrrNwUiH4lqURdK4AJf/rEGqD/osyLP3BS39xJYGuYoQFjNhcaMVT6j/CK/R84ZVJ+IsuVcdw7z5lh9LHkwpLHFNxGdmRQ8b9RpgGIGZUMu/3L/cl9s2vOwE9MqTYzU+XhhQ3A== 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=o0rnkgChXX3moDTT9hxo4eQ4gldoJ90V5SBu8bqZpg8=; b=xT0rnnfVEiPTP6yfAetSojd4klf3bG9+wCXu4wnRoUOgTOkGKyf/YXAZG3jw2L1ohFOkpvmaNvhot3RlG2dyMlVso2V1uj+uEZ8TmJiahw0PmQZJvgDk9YuXpiv8fLytjE5siC+1TBGQ7Ki8g/9SD95ickgOt29I1GKk2/HNxSEWw44m8UXrzymPDMS31RWkUyA9biitZzjZmMcpObHAN7pLUlMAzY9nepbEALxEH36Eu3cdBzxanLvKRlctX6cPwiWlpLTsJnN4CH9kZ8WCiZXG50t8FBopr2Uh+GjgTGtgUtdTG9B+lsOgqjNSm/Xr9WWCmCAV4B/uFTMuSeT+Sw== 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=o0rnkgChXX3moDTT9hxo4eQ4gldoJ90V5SBu8bqZpg8=; b=HMh5naKXEPCJqFNEh7/nfNcgHDIxVmZrE91a/uZYuj4LTfGsQ4u48Ri38el417VKuShGbUIUmQjaNqRU63QKxJOyLEu2JmbdRQX0EulmGJ9ERkff7d+ncK6WGynlBUt8QPv30KjbZ+gcgOfRFOLBtOB488Bx/I/M3Pil9VW4MKE= Authentication-Results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=garyguo.net; Received: from LOVP265MB8871.GBRP265.PROD.OUTLOOK.COM (2603:10a6:600:488::16) by LO8P265MB7398.GBRP265.PROD.OUTLOOK.COM (2603:10a6:600:3ca::5) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.21.92.12; Mon, 8 Jun 2026 19:59:11 +0000 Received: from LOVP265MB8871.GBRP265.PROD.OUTLOOK.COM ([fe80::1c3:ceba:21b4:9986]) by LOVP265MB8871.GBRP265.PROD.OUTLOOK.COM ([fe80::1c3:ceba:21b4:9986%4]) with mapi id 15.21.0092.011; Mon, 8 Jun 2026 19:59:11 +0000 From: Gary Guo Date: Mon, 08 Jun 2026 20:59:05 +0100 Subject: [PATCH v3 08/19] rust: pci: io: make `ConfigSpace` a view Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260608-io_projection-v3-8-c5cde13a5ec4@garyguo.net> References: <20260608-io_projection-v3-0-c5cde13a5ec4@garyguo.net> In-Reply-To: <20260608-io_projection-v3-0-c5cde13a5ec4@garyguo.net> To: Danilo Krummrich , Alice Ryhl , Daniel Almeida , Greg Kroah-Hartman , "Rafael J. Wysocki" , Miguel Ojeda , Boqun Feng , Gary Guo , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Andreas Hindborg , Trevor Gross , Bjorn Helgaas , =?utf-8?q?Krzysztof_Wilczy=C5=84ski?= , Abdiel Janulgue , Robin Murphy , Alexandre Courbot , David Airlie , Simona Vetter Cc: driver-core@lists.linux.dev, rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, linux-pci@vger.kernel.org, nova-gpu@lists.linux.dev, dri-devel@lists.freedesktop.org X-Mailer: b4 0.15.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1780948747; l=5574; i=gary@garyguo.net; s=20221204; h=from:subject:message-id; bh=asZ8rlzSXV0U+EZg1Fe9smEUk3vFTSWP3reSKao5plc=; b=1/TgU1LhqRQJCj67vYAJwPqRax/itwT+A8si9KDuxJOwW6on6fdLfKJ/YZAbOuDvYdFUxIySs HkYGcwWuuarCNqhiyXtap8Td+y/TSmEdgzp/eufTghzkRM5yVvw1uSI X-Developer-Key: i=gary@garyguo.net; a=ed25519; pk=vB3uIX95SM4eVrIqo1DWNWKDKD2xzB+yLLLr0yOPYMo= X-ClientProxiedBy: LO4P123CA0344.GBRP123.PROD.OUTLOOK.COM (2603:10a6:600:18d::7) To LOVP265MB8871.GBRP265.PROD.OUTLOOK.COM (2603:10a6:600:488::16) 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: LOVP265MB8871:EE_|LO8P265MB7398:EE_ X-MS-Office365-Filtering-Correlation-Id: 7cc7f9db-4039-4b05-0b23-08dec598687d X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|1800799024|7416014|376014|366016|10070799003|6133799003|22082099003|18002099003|921020|3023799007|56012099006|5023799004; X-Microsoft-Antispam-Message-Info: Aj8YNjYZUhQGP3QXu+PKA7N7MEdE/XwvhvaH3J91lbPVeRjtmvgLrGeNzWWNpQB6oygRFBSRRrdK5r4btM7ZA9ClBIVIwoAlQMXXGOK/O54OSoXWmIHw05IeH//xwa8toar0kyozSygi1aVzJR1wHRo2I6/8XYHCDsf/mkCRRV6gGlGsbdWxxWtLCDjQvTObvqXhzKaq4259oXxlxaKigXJBOKfUIVXS8dM9JBsHRI6+/vPytIBzVpCpIkLN08bpBpR7SeCNIhvxA3JfFsjdO1yhWkTEJDFVakVFon2KIyPVqV7JLvlSKnRBVz248f/t6VSwUBoN37ntSvqRx3L9OMQrN1vsBxxdTDoxsC4TDq72AxS7M8a95cULIDaP2lp0KjHVmKs/c+zagbbe35z5JQjDd6+7/JcIEU8tp8IzSzvjpieguk32tRUjS5b1u2EaxIpuQpmtVAq11mXCU2GKxQYHGbn48FK3VTkRpU7g/I7qVAVaZ/PabWmcPPu/aLo5Xi+FW5D16XVy5dluWMorU4M5ky8F6AZnvHxNk9JlmsPu7FrNaac/7Hn5O0UDgvc9CFfZqkYdKLz/HDKjmMpv2X+BcM39rz6qd16LNIj6REAtWl2ZuNqO/LDD4b8rMiaMbbHgZxQQa67fY6NLKWWrSK3ytqIHtreHaQKuGiioLcGI2DvXJhqB8TxFiuMQrflmkp9B8vRI3aYv1iDBKzS4EWu7cErrbUgZaplwiswfXW4= X-Forefront-Antispam-Report: CIP:255.255.255.255;CTRY:;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:LOVP265MB8871.GBRP265.PROD.OUTLOOK.COM;PTR:;CAT:NONE;SFS:(13230040)(1800799024)(7416014)(376014)(366016)(10070799003)(6133799003)(22082099003)(18002099003)(921020)(3023799007)(56012099006)(5023799004);DIR:OUT;SFP:1102; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: =?utf-8?B?ZUhJaDZmdzl0NmVWMXI4aXZ3UzYvekxheFpuU3BKK3ZiRFJaY1NpcVM5bk00?= =?utf-8?B?KzFwaXpsc3RMTWIxUWg0ZUxIU2hqdnhJejlkbW0vWHBvN3JSaCtlUGxSZTVu?= =?utf-8?B?Q1VZZEdKQUhPaERyUHhsZGdWR1BXbFF1T1dlVHV2eG5GdWZJSU1OTVpoejhi?= =?utf-8?B?SUhqNzRVSTB3cVdNc21McUgwUUplZ1FvNXhqdHFrWjNwQ1EvU3ZGL1ZxYUZo?= =?utf-8?B?TVNOMlN0cGNlNHpURy9tZ0VZa2p0TUlhR2l1Qis4aVpDeURuV3B2Q0U3TVlT?= =?utf-8?B?RkhWTGZLZEx5Y1pwQmNEWEZKRUdHeFlCWEVpbjB5KzBmNGRwYlR4OXRYM2li?= =?utf-8?B?ay9ZVVgyMUsvazRDTTZza1VLRXFtejZuc2syWE5lNENUTnBXSCtycjdnaTFs?= =?utf-8?B?VzBHZlFVQm9BdUFubzRxb3pOSU5GNWczalBOaDdaVEV6MWpodWI3SHFYdmp6?= =?utf-8?B?eGpXeEZObGlseFdFd1d2RGFoZGZ5VkZQcHhDV2V5Y3lGcGgweDJ1M2thNnFz?= =?utf-8?B?V2M2cHNpMU11OVAwaWhxemNuZDFTSnVnNkRvR1hBV05zUU9naUxQOVpsZUxN?= =?utf-8?B?czM1SzlHYzVpNFJYSGdua0ZMV0lTSDFoajc4SHdSTVVBUUZTVEpsNUl1UUd2?= =?utf-8?B?ZVBzcmlub3NTeUcyQ1Z6TGsvdGtKOStTd0hWZFc1dW5zamxtbDQyMGZlWU5J?= =?utf-8?B?SmVVNW0vUEZPaGpGTVVyY2xwWDMzUmNiMDM3eFMzY3dLZ1Y4UkloUjNUTk1J?= =?utf-8?B?bjZ2R1dkbWhOZUtsclZQZHh5WTFMdFh6MEJabEUvejdPeitzUTdhRnVuOGNo?= =?utf-8?B?RUo5bEk3ek5uVXA5ZVV1VitNYVBBUW5NVXVseExMVE1xWG9WZDErczVHVnhI?= =?utf-8?B?NFFpZnBqM2d3TW9Qa3JBMnpHUjV1VC9IdGdWYURqc3VzMFNKS1JWSytSeEJh?= =?utf-8?B?RkNzZndtU2x0Mk04VmhpQlBvUlpERGJlVDY4YnpXdnpSYnhPdkJNbHpvZjdV?= =?utf-8?B?VnJ1SmIzWVdiS3VQT3ZnVDljcFhCa0g5NUZIYW5ocFN3R1drU3JGY0JpM3Ns?= =?utf-8?B?VWNnT0sxcENOZ2FkVndRRUJuZi8wN2UyeG1paXBxdHNyRy8vd2tmL2xpdHhp?= =?utf-8?B?bEtYL3R5SkZrK0JROEF4dld0UnJLaDlTMlhqY0JMa3ZtSDY2ODR1QUJ0VDZQ?= =?utf-8?B?ZHJHZzFzOXR2a2YreWlZc0xwWVVMbjBGYmVwYTBHRitxVGIzV3ByZ1lQcnN4?= =?utf-8?B?RlZ5UDhGSWlrMXRYUGdrOU9jcUZlNm1vZjJoNjZsSHA0aURBRzNyWDh4NFV1?= =?utf-8?B?bm5rVGlqSCtLMmtjQUptQ3FleC91SXdIemlLYnhaYnlDeWFBWjZoZWs5WjJu?= =?utf-8?B?YmRRYWJYYXFWazFvTGpyT29LRjg4K1F3N0V0M3Q1ejdsRldzcmRYWGRMcmlj?= =?utf-8?B?YSsvL3JIZ1QyVnh2R0FneTMyZVhOdjZ4a3VLRVNMYnJPZ1VCQk8vTjlHUkFE?= =?utf-8?B?My9Nb3I3a1lOeDJpM2lpN0dwTDh3cmJSY3VDUUh4bTB4TWlUZ3IwVVdQdXdo?= =?utf-8?B?ak0vK2pyTTZWZ3RPek4vL0tJYVJ6aFRiaE1CbU5LS1ZyZElMc3Q0OTl0MGo5?= =?utf-8?B?U3krZ0FXVy9qdHUraWVHbE4yVkFOMks2M25JYXptcC9mMXdTNlBhQmZVV1JI?= =?utf-8?B?Q2VVVkNVTE9Qc2hjRUVEV29YQnFNWkMxcW04U013U0toN1FtWlFsdWhCMVho?= =?utf-8?B?cXg5djgyMG5mand5M29ZcUlBb3NuazFFQXArZkJzejA0eWx1OFc0cytuNVJE?= =?utf-8?B?czZzYWI2emNXTk12aTBWQVorWkVMRXVnOWhFdlAvbWdjb1RlS1VUVUE4aDM1?= =?utf-8?B?UmdLS01tVzJmVXA0c2tRV3lacWFScWhwK2t0c0ZVVS95RFVqRnlqanlVYTIr?= =?utf-8?B?dFo0RjJtdmh3R0QvQ3dFb3dQaTY1NFR5eEZERkxtNzM3OHVTcWlieVVJMWJj?= =?utf-8?B?c01ZY2t0SUxMdmFmYmpaRXZuL1RHRzJUdm5XRGhLNWRqUG13Zmd0Wmh3eHYx?= =?utf-8?B?SkRpemQ0cjNobG4zdFRsOVArZHdMZnFPaFFvWUZjNW8ydnRGNFR6U3VXdTIr?= =?utf-8?B?a242U3VGSk83NTZpRFZsMW9uOHVvOE0wVFV0WXh2S1BiQWNQMmhiQ3R5L0tQ?= =?utf-8?B?RTZaZHhaNTIzV3pia094OEJpeUhVL2RXRlBERE9rcFF2QkRtZklTamJIV2pT?= =?utf-8?B?VzJMSzA1eFphbUZvWUh2LzZUd0t5ZzlBR0dwYVZwMXBza05IOUNIUnpRMzlo?= =?utf-8?B?T1dMZ25Jck5kMHZqQkVtdHBsc0Z1NndtSldSNzZVNEtIYm4rZkZBZz09?= X-OriginatorOrg: garyguo.net X-MS-Exchange-CrossTenant-Network-Message-Id: 7cc7f9db-4039-4b05-0b23-08dec598687d X-MS-Exchange-CrossTenant-AuthSource: LOVP265MB8871.GBRP265.PROD.OUTLOOK.COM X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 08 Jun 2026 19:59:11.2743 (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: d/2N5O0d0TFB5auX2TzVSK7u+dwK4MCplA/VN2mSJwISGuqb29X+lDxqByhcFCeRWD/fYJ1shZ7OdCWHbznY/A== X-MS-Exchange-Transport-CrossTenantHeadersStamped: LO8P265MB7398 In order to support I/O projection, we are splitting I/O types into two categories: owned objects and views. Owned objects have a specific type that is related to setting up and tearing down, while views can have their type changed with I/O projection. Things like `IoMem` or `Bar` are owned objects, which requires setting up mapping and cleaning up on drop. On the other side, `ConfigSpace` is really just a view, as the resource is associated with the `pci::Device`. Remove the `ConfigSpaceKind` bound on `ConfigSpace` and make it a generic view. This means that `ConfigSpace` object now represents a subregion and therefore encodes offset (as address of pointers) and size (as metadata of pointers) itself. The full region case is still supported with offset 0 and size of `cfg_size`. Signed-off-by: Gary Guo Suggested-by: Danilo Krummrich --- rust/kernel/pci/io.rs | 58 ++++++++++++++++++++++++++---------------------= ---- 1 file changed, 30 insertions(+), 28 deletions(-) diff --git a/rust/kernel/pci/io.rs b/rust/kernel/pci/io.rs index e0acb62f58a2..a4cfa1ec6e62 100644 --- a/rust/kernel/pci/io.rs +++ b/rust/kernel/pci/io.rs @@ -18,7 +18,6 @@ ptr::KnownSize, // }; use core::{ - marker::PhantomData, ops::Deref, // }; =20 @@ -53,33 +52,36 @@ pub const fn into_raw(self) -> usize { /// Alias for extended (4096-byte) PCIe configuration space. pub type Extended =3D Region<4096>; =20 -/// Trait for PCI configuration space size markers. -/// -/// This trait is implemented by [`Normal`] and [`Extended`] to provide -/// compile-time knowledge of the configuration space size. -pub trait ConfigSpaceKind: KnownSize {} - -impl ConfigSpaceKind for Normal {} - -impl ConfigSpaceKind for Extended {} - -/// The PCI configuration space of a device. +/// A view of PCI configuration space of a device. /// /// Provides typed read and write accessors for configuration registers /// using the standard `pci_read_config_*` and `pci_write_config_*` helper= s. /// -/// The generic parameter `S` indicates the maximum size of the configurat= ion space. -/// Use [`Normal`] for 256-byte legacy configuration space or [`Extended`]= for -/// 4096-byte PCIe extended configuration space (default). -pub struct ConfigSpace<'a, S: ?Sized + ConfigSpaceKind =3D Extended> { +/// The generic parameter `T` is the type of the view. The full configurat= ion space is also a +/// special type of view; in such cases, `T` can be [`Normal`] for 256-byt= e legacy configuration +/// space or [`Extended`] for 4096-byte PCIe extended configuration space = (default). +/// +/// # Invariants +/// +/// `ptr` is aligned and range `ptr..ptr + KnownSize::size(ptr)` is within +/// `0..pdev.cfg_size().into_raw()`. +pub struct ConfigSpace<'a, T: ?Sized =3D Extended> { pub(crate) pdev: &'a Device, - _marker: PhantomData, + ptr: *mut T, +} + +impl Copy for ConfigSpace<'_, T> {} +impl Clone for ConfigSpace<'_, T> { + #[inline] + fn clone(&self) -> Self { + *self + } } =20 /// Implements [`IoCapable`] on [`ConfigSpace`] for `$ty` using `$read_fn`= and `$write_fn`. macro_rules! impl_config_space_io_capable { ($ty:ty, $read_fn:ident, $write_fn:ident) =3D> { - impl<'a, S: ?Sized + ConfigSpaceKind> IoCapable<$ty> for &ConfigSp= ace<'a, S> { + impl<'a, T: ?Sized> IoCapable<$ty> for ConfigSpace<'a, T> { unsafe fn io_read(self, address: usize) -> $ty { let mut val: $ty =3D 0; =20 @@ -112,19 +114,17 @@ unsafe fn io_write(self, value: $ty, address: usize) { impl_config_space_io_capable!(u16, pci_read_config_word, pci_write_config_= word); impl_config_space_io_capable!(u32, pci_read_config_dword, pci_write_config= _dword); =20 -impl<'a, S: ?Sized + ConfigSpaceKind> Io for &ConfigSpace<'a, S> { - type Target =3D S; +impl<'a, T: ?Sized + KnownSize> Io for ConfigSpace<'a, T> { + type Target =3D T; =20 - /// Returns the base address of the I/O region. It is always 0 for con= figuration space. #[inline] fn addr(self) -> usize { - 0 + self.ptr.addr() } =20 - /// Returns the maximum size of the configuration space. #[inline] fn maxsize(self) -> usize { - self.pdev.cfg_size().into_raw() + KnownSize::size(self.ptr) } } =20 @@ -281,23 +281,25 @@ pub fn cfg_size(&self) -> ConfigSpaceSize { } } =20 - /// Return an initialized normal (256-byte) config space object. + /// Return a view of the normal (256-byte) config space. pub fn config_space<'a>(&'a self) -> ConfigSpace<'a, Normal> { + // INVARIANT: null is aligned and the range is within config space. ConfigSpace { pdev: self, - _marker: PhantomData, + ptr: Normal::ptr_from_raw_parts_mut(core::ptr::null_mut(), sel= f.cfg_size().into_raw()), } } =20 - /// Return an initialized extended (4096-byte) config space object. + /// Return a view of the extended (4096-byte) config space. pub fn config_space_extended<'a>(&'a self) -> Result> { if self.cfg_size() !=3D ConfigSpaceSize::Extended { return Err(EINVAL); } =20 + // INVARIANT: null is aligned and we just checked the `cfg_size`. Ok(ConfigSpace { pdev: self, - _marker: PhantomData, + ptr: Extended::ptr_from_raw_parts_mut(core::ptr::null_mut(), 4= 096), }) } } --=20 2.54.0 From nobody Thu Jun 25 00:35:31 2026 Received: from CWXP265CU008.outbound.protection.outlook.com (mail-ukwestazon11020099.outbound.protection.outlook.com [52.101.195.99]) (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 828363EEAE7; Mon, 8 Jun 2026 19:59:25 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=52.101.195.99 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780948770; cv=fail; b=QOTyTUmnrerPFoM8wU/0fBl9BFcilfk6a8x/GQFSevm3voN9npaHcYzPOYivOC0RBfiGvNdKWVWD2jYKNEka8yI3sU/tt8rCZNovSL3Z3kxDG5KjZeqxkcYwM1nOGQTAbPEajO4CphE/thi2qPfUxqnX5JOHU7U+q7Ox6ouq8Zo= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780948770; c=relaxed/simple; bh=07xGwWcYVaICSsPU1QnBMdFkxeGvgCqQU55QX5zieH8=; h=From:Date:Subject:Content-Type:Message-Id:References:In-Reply-To: To:Cc:MIME-Version; b=dQ3tVIyWUXWwP4BkTgOjeaIMZ9c1kb8A/xPLO1+M7l7qpOQjUj3zG+kkmchj+1E8xvOycRqxQxT05edkmeST5zIO6tUa1d5ORq2YQZ+WtZNjOzpD/kmBBd3NvMVav5mjOAIV9cXu7SL6I0F8Dd1NlhecGcczX9Xxa7plGHblOeU= 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=Na4X4TC/; arc=fail smtp.client-ip=52.101.195.99 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="Na4X4TC/" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=oyVo032agHuHZLlt1oHNRmcMk18BmxE3RFSoHg0heTxXVW/YNSfBDVWet75yrUTKUQ2LCQ4VpqH93JMN7tYO7DmBibATVOg7uP3Ipkg3gS7pR0QqZZ/iBnRDF8BZ6qpL4ccZsaGpgMdIzEpzWHnSowaRxQCncZSnTtBekHc8/o4qX9i5HFCw5KpOnmhnq8GETyKRaXpQerP3KHBIu0pkhIPcsa85LQUp+Y4wfu7cP96oNND2el4EWrDSWfikB3X2kA6mATo0RnpqNLCCsEO9hILVwkkf2dFgZhPKsl6wJoTVlF8peDLdTjsWMMIpZH2uiMefwykOlS4CFFPf8JF/tw== 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=WpRY7YAg2M9rrd1G8XoLZfqEaOTd+0/YoDHU+HbjVIw=; b=ZEb4TXnZs1WtZQkF5pgK4RtsDzM4MaeRuf2NNSrCBxW2ewMsLIOWu2TvlP8ax5y+TI0JHaUpWAbR3Jv43Slc4ZGV+l6QyTG6Irz/q8UjNmmw4ddcxYqRahOIGMoaXuqRLifqS4RlKlix81ALMt31tsaGHdVY7ylA59xQACS6omM/7aAeUbvTuicr7yKMCjS3Jy8tjilePA6nyfw+8cEiQk571eLOJZehW4tXan5yv6DKfg7MRd7zYFNtHXQEooNQ7GRU8ulzr4fhjjnqEZA2orLzwrjGfqHem4joZ9FETvACR0faeUoxks78yvPV6uvHIeuk7N5nD4VmGKMU6UTgoQ== 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=WpRY7YAg2M9rrd1G8XoLZfqEaOTd+0/YoDHU+HbjVIw=; b=Na4X4TC/FQPSdjo9dJGmNtNZPYSb3pJKVtVsGOvzHVmu8t9pqR1gG6gAFgAtDGA/F0ZEpURPTQnWAat3E8Zd0ub0Mjiu4IgaPs1T34kP9EbDw8SrXeOrhanBGL8xcsL0BPKinWFBsZsnarYgmhMQHsKtv9WZa+nhrnM8cSnRtrI= Authentication-Results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=garyguo.net; Received: from LOVP265MB8871.GBRP265.PROD.OUTLOOK.COM (2603:10a6:600:488::16) by LO8P265MB7398.GBRP265.PROD.OUTLOOK.COM (2603:10a6:600:3ca::5) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.21.92.12; Mon, 8 Jun 2026 19:59:11 +0000 Received: from LOVP265MB8871.GBRP265.PROD.OUTLOOK.COM ([fe80::1c3:ceba:21b4:9986]) by LOVP265MB8871.GBRP265.PROD.OUTLOOK.COM ([fe80::1c3:ceba:21b4:9986%4]) with mapi id 15.21.0092.011; Mon, 8 Jun 2026 19:59:11 +0000 From: Gary Guo Date: Mon, 08 Jun 2026 20:59:06 +0100 Subject: [PATCH v3 09/19] rust: io: use view types instead of addresses for `Io` Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260608-io_projection-v3-9-c5cde13a5ec4@garyguo.net> References: <20260608-io_projection-v3-0-c5cde13a5ec4@garyguo.net> In-Reply-To: <20260608-io_projection-v3-0-c5cde13a5ec4@garyguo.net> To: Danilo Krummrich , Alice Ryhl , Daniel Almeida , Greg Kroah-Hartman , "Rafael J. Wysocki" , Miguel Ojeda , Boqun Feng , Gary Guo , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Andreas Hindborg , Trevor Gross , Bjorn Helgaas , =?utf-8?q?Krzysztof_Wilczy=C5=84ski?= , Abdiel Janulgue , Robin Murphy , Alexandre Courbot , David Airlie , Simona Vetter Cc: driver-core@lists.linux.dev, rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, linux-pci@vger.kernel.org, nova-gpu@lists.linux.dev, dri-devel@lists.freedesktop.org X-Mailer: b4 0.15.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1780948747; l=30401; i=gary@garyguo.net; s=20221204; h=from:subject:message-id; bh=07xGwWcYVaICSsPU1QnBMdFkxeGvgCqQU55QX5zieH8=; b=xIQoFtsLbh6JjQCaxxpd3arwHfXQ/6xl3BMYD0ckyKzCQ1/2jTJ/oFja4P0U0kAZ60HQO0Oyd 8RDSIdG4GcZD5p6tnWZWgzKL4VZEuOfNUwUqeCj8lY5uplF5GhCxw6B X-Developer-Key: i=gary@garyguo.net; a=ed25519; pk=vB3uIX95SM4eVrIqo1DWNWKDKD2xzB+yLLLr0yOPYMo= X-ClientProxiedBy: LO4P123CA0344.GBRP123.PROD.OUTLOOK.COM (2603:10a6:600:18d::7) To LOVP265MB8871.GBRP265.PROD.OUTLOOK.COM (2603:10a6:600:488::16) 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: LOVP265MB8871:EE_|LO8P265MB7398:EE_ X-MS-Office365-Filtering-Correlation-Id: 06586865-f43c-4669-1bd7-08dec59868ba X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|1800799024|7416014|376014|366016|10070799003|6133799003|22082099003|18002099003|921020|56012099006|5023799004; X-Microsoft-Antispam-Message-Info: zySko1HMfIzdKyW4H7tNTCgCjpcCjT3bMjzWA2SKxP4qKtYoSjBPrn2gPcLysyrrPwjynbcKi6e64c3osCVVpxHEuAQ7BXvcqSKIIORMEw+k16x4J+QzCDX8EHLqjFKPcR47c/rQA2tFjV3/ibxBrqFfY6G9B8QJgb0IT0FEmyPPKZJirLMxPycAZ36DVJf/u8R4knn9Ad8LAhXOHANCWXYMv9PCT6cvSEDVgtLDwEWF6+Nwim+H8TR5ENtrBOb4flK01lTevmJ0e3djTnD+TylvMLPpdg09An8KS4vmbqmi5QG3HtugscF2vWtGmW0S4pwvTUZgBKIH9L/m5A4DWz1nD7Qd12N5cWej4RlTDdua7pad+Tys4/z+o22jn8TN6nMNCpQy4zdBYW8sXvHIhNU4pZrFVBRhm6e+yfvMQ9k7tLwcU9VaGsp4M/71pbuROPSlsUTNnl+mp1HzmjGVnaz86ntL/nrAQhz5DbEsbVjVIjP2qjR0E0Hs/Fzri/gIDUxlH3coBJbz7Bd9Fhx6RPnfi7Qg3RZjzi1y+XzE+N+EnA2QK+d4pzwlzeWsXKDnqTrBGGiX1OPd+a78Yy+m+wAcpsovnqkmscWTYbHzwKje97JgkBEEr8lca5/KIHU9fDE6sHBqt68LL/o/fDI5hktiAiY373eOIxFzCqN8pCTaaaTTRvu42K1l94ypOCLmgShHZh5OiewYNQx/OywpNPPRBIRPHVBYhxy7ClHrKCM= X-Forefront-Antispam-Report: CIP:255.255.255.255;CTRY:;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:LOVP265MB8871.GBRP265.PROD.OUTLOOK.COM;PTR:;CAT:NONE;SFS:(13230040)(1800799024)(7416014)(376014)(366016)(10070799003)(6133799003)(22082099003)(18002099003)(921020)(56012099006)(5023799004);DIR:OUT;SFP:1102; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: =?utf-8?B?a2greWVweDZLSDNyTjNIcExJNjNNRVp6bldHU2d0RUlzMUdYbk5odmNrYkRo?= =?utf-8?B?cGFlVWpiSSt6MmRUN29KTHlqcmgyZTZZdUgyOWpaeTA1RitWdmFPNU5uMHdi?= =?utf-8?B?T0xDL0hmcHFCSGJqMVVnY0h4M1NLSjBPY01ST0RxTFlXVlpqRmljNlZUT3FC?= =?utf-8?B?NDhrMVFVd1dKRzRuWlQwLzU0UTNZUGtreERFa0wvOHNNN3doclFsR200N3di?= =?utf-8?B?ZmdSYWtGZzhBaVZYQ3FQT0h2bXBJbjNLUEdmbWJZUzdQNmVsUTFMVEhnaW4r?= =?utf-8?B?cW5qd2xIazRxSFloVXdwRkd0cVF2SnRhcS8wWU5RUmdiK3BaT3U1UVU1T2lR?= =?utf-8?B?ak4wS3hJUHlRQmV5QWRId01XS2JjdGZFNUtzZVNOVy9GUCtZZnJZZGlPWDhX?= =?utf-8?B?MVJUT3JoT1ZxNTVCMEljZ0lGOGFlZEEvbEFnTlgvem1lb3NzcndJL0FSbEs0?= =?utf-8?B?V3ZtZWVWT0dEZ2I5RnNqY1IxS244MW9BVFdnSHprRSs3by8wZnNCTkhCb2V2?= =?utf-8?B?eDNoMlJlcTdsR3Z5UkxvV2dRQytpZm5lUS9jNFo0OFJRd1h6dXpJVFVCOWtw?= =?utf-8?B?dVdQT2pxeVUvZmd0SzRHZXNzTERNeEQ2Q1hMSS9KVzRpOTdPdW9peVJ0bitm?= =?utf-8?B?K2JXUTJNZGM3WWNTSjdHWXJvaFE1MW5BdGZ6aU9mZDdZUW5iV2t4SGtpVDFW?= =?utf-8?B?c1Awa1duYnNsRE9yUkVpMkVFci82b0NhcXlKVkR0a3dvR3NOU3NkSC9hRmVK?= =?utf-8?B?SEJSKzVYaFV0VjJwR0EzUXovTUxPRVczQ3RFc3NpNjdvWjFXTVhOSU5HWkpa?= =?utf-8?B?Z2JWYnp5YjdFZE9CV3RYY3FKNVN4VnJiMDU3QURRMDFQYXhSSHI4SXF1OVpT?= =?utf-8?B?b1hSV3ozbTAwQkRRcDdWRWZtQmdEUUhjOWd3WHI1V1N3Rno2UGN5aDJmTDNr?= =?utf-8?B?eDFBZWZneVhyT2ozbDc3eWRrbnp1MHE3SzNGSDJKYjRpeHdGVUUxT3RkUU8r?= =?utf-8?B?aUEwc1dCcU9YOU5sVHA0a2F1N041MWtvaHhRSFpudjdTYU5JVjNkejE0a3VH?= =?utf-8?B?ejlmbGgxajkzVVhMNVYyQW9HODcyK2F0RXNvVlpSbmdUMHZJSnFNdnF5QXVF?= =?utf-8?B?eTJwTDZ5QjVLNFZlcmp2Q3BJV3NuS2dFaHdNa1pKdHN1OEx4YW1Oem1IUmFa?= =?utf-8?B?ODVhRVFCODZFYnhoelJRcnVoRW9UU1VIQnF5cyt5RzRjRCtPOWVQQlpzbWta?= =?utf-8?B?VjIyVmE1N0FUb0ZweTh5UjFWNFd0UHJ2YjgwWkJ3WFA2QVU1YktWUmh4NDg0?= =?utf-8?B?bEFJWVUvK01lL1hnWnAwUTZRVmI5VzBEV0JsNWhVYnBlSmV0U0lFeHoyNFp1?= =?utf-8?B?YUxBanlTR04rN1hzS1daMy9iU0pWS1pxVTRqUjR3QWNVZWlDK0NPVXhveG9u?= =?utf-8?B?a0xKMTFnSDlqNGxVT0tPSWxlRGlxUVlaTkhTQ2ZtekE4VFJSYXJZaWdDMXVp?= =?utf-8?B?cU1obGhGb0FLNUlxYnU5eHlFMEl2dGpnSm5tbHNvek44TzU1WXVpR25WcWJE?= =?utf-8?B?MG1RY1Q3VU9RNkozVjRselNQK0lOSmVCOHRKT2NNVzg4Q2tIdHA1b1MzTHpz?= =?utf-8?B?Y0x1Ujh1c0s3ekhvU2c3MWFVVkhaTDVoNkpiRkx0amVBcC9qN25qZmVLZFNv?= =?utf-8?B?UUdEVU5uekl0SHoyWk5IYkVYZHpWWFpHeVRLME03NTM3V1gydFVLd2lKekxU?= =?utf-8?B?ZDA0ejR2aElWM0R4cUNlQ1hXc0FsN2hZUWExeUptUGl1bXQ5bFpsTzNTK2Zv?= =?utf-8?B?cnNGVTdyLzZQeGFDdEk1bWpGSDdhWG81UFJpTTZ0UGlPQUFtRkFiU0tobkRp?= =?utf-8?B?NkdmTkJDcUxrSVpvZFY3dGh1eTlKU3lBVFZvcENYWFNVZjVaTFN0OUdNZUYv?= =?utf-8?B?M0FySTZxaWY1dkhqalRZVHRqQ2I5TWo2aEJENnphWUVQekNMQ3lLcHM2OWpN?= =?utf-8?B?cDlrTkdtTEFhbyt1enVocVNzbmdkMzZZQnBQR0RuUm9uaHJHS2d5dFB1ZmhY?= =?utf-8?B?blk1RHI1cTh0SEptK3RjNW5CbGJGN0w4QjREWTZMRnExMXowUDVnVFRMRXAw?= =?utf-8?B?NjBpbmhxR0lNTzBXazNPSVEwQkZMamo0Q1l2KzExR1dSMUxkZndjY3NPTklo?= =?utf-8?B?cmhSQUlsVksrOG44dFVRZml4OFdBVC9HK25UVDZmTW45dzZ4TGdDL2VSWWF6?= =?utf-8?B?TEJsbmw2VFV1L3ZzZ0RoSkwwSjVtYThZcVUzSnhaTStqODh4Q1RESUhIbk81?= =?utf-8?B?bnNKSjhDOGs2RXM3MW5zZk81MmlaOFJPK21aUFZtZ2M3OU9PQW1yQT09?= X-OriginatorOrg: garyguo.net X-MS-Exchange-CrossTenant-Network-Message-Id: 06586865-f43c-4669-1bd7-08dec59868ba X-MS-Exchange-CrossTenant-AuthSource: LOVP265MB8871.GBRP265.PROD.OUTLOOK.COM X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 08 Jun 2026 19:59:11.6689 (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: Ey2F5QoxYUhmpI7ZPGvSARnBaaaDlhEvOPek3fdqpBb8BZG13EG336yK99eHPsa6kiOEPuynxKzbRdNj+HMafQ== X-MS-Exchange-Transport-CrossTenantHeadersStamped: LO8P265MB7398 Currently, `io_read` and `io_write` methods require the exact type of `Io` plus an address. This means that they need to be monomorphized for each different `Io` instance. This also means that multiple I/O implementors for the same I/O kind needs to duplicate implementation (e.g. `Mmio` and `MmioOwned`). Create a new `IoBackend` trait and define these operations on it instead. The operations are just going to receive a view type and operate on them. This has the additional advantage that the invariants can be moved from the trait (and guaranteed via `unsafe`) to type invariants on the canonical view types of the backends, so `io_read` and `io_write` can be safe. Note that view type is needed; addresses are insufficient in this designk, as they do not carry sufficient information. For example, `ConfigSpace` needs `&pci::Device` in addition to the address. Signed-off-by: Gary Guo Suggested-by: Danilo Krummrich --- rust/kernel/io.rs | 345 ++++++++++++++++++++++++++--------------------= ---- rust/kernel/pci/io.rs | 70 ++++++---- 2 files changed, 224 insertions(+), 191 deletions(-) diff --git a/rust/kernel/io.rs b/rust/kernel/io.rs index 771372a8aa36..d09d9864858d 100644 --- a/rust/kernel/io.rs +++ b/rust/kernel/io.rs @@ -246,6 +246,38 @@ const fn offset_valid(base: usize, offset: usize, s= ize: usize) -> bool { } } =20 +/// I/O backends. +/// +/// This is an abstract representation to be implemented by arbitrary I/O +/// backends (e.g. MMIO, PCI config space, etc.). +/// +/// The base trait only defines the projection operations; which I/O metho= ds are available depends +/// on which [`IoCapable`] traits are implemented for the type. For exa= mple, for MMIO regions, +/// all widths (u8, u16, u32, and u64 on 64-bit systems) are typically sup= ported. For PCI +/// configuration space, u8, u16, and u32 are supported but u64 is not. +/// +/// This trait is separate from the `Io` trait as multiple different I/O t= ypes may share the same +/// operation. +pub trait IoBackend { + /// View type for this I/O backend. + type View<'a, T: ?Sized + KnownSize>: Io<'a, Backend =3D Self, Target = =3D T>; + + /// Convert a `view` to a raw pointer for projection. + fn as_ptr<'a, T: ?Sized + KnownSize>(view: Self::View<'a, T>) -> *mut = T; + + /// Project `view` to its subregion indicated by `ptr`. + /// + /// If input `view` is valid, returned view must also be valid. + /// + /// # Safety + /// + /// `ptr` must be a projection of `Self::as_ptr(view)`. + unsafe fn project_view<'a, T: ?Sized + KnownSize, U: ?Sized + KnownSiz= e>( + view: Self::View<'a, T>, + ptr: *mut U, + ) -> Self::View<'a, U>; +} + /// Trait indicating that an I/O backend supports operations of a certain = type and providing an /// implementation for these operations. /// @@ -254,22 +286,12 @@ const fn offset_valid(base: usize, offset: usize, = size: usize) -> bool { /// For example, a PCI configuration space may implement `IoCapable`, = `IoCapable`, /// and `IoCapable`, but not `IoCapable`, while an MMIO region o= n a 64-bit /// system might implement all four. -pub trait IoCapable { - /// Performs an I/O read of type `T` at `address` and returns the resu= lt. - /// - /// # Safety - /// - /// - The range `[address..address + size_of::()]` must be within t= he bounds of `Self`. - /// - `address` must be aligned. - unsafe fn io_read(self, address: usize) -> T; +pub trait IoCapable: IoBackend { + /// Performs an I/O read of type `T` at `view` and returns the result. + fn io_read<'a>(view: Self::View<'a, T>) -> T; =20 - /// Performs an I/O write of `value` at `address`. - /// - /// # Safety - /// - /// - The range `[address..address + size_of::()]` must be within t= he bounds of `Self`. - /// - `address` must be aligned. - unsafe fn io_write(self, value: T, address: usize); + /// Performs an I/O write of `value` at `view`. + fn io_write<'a>(view: Self::View<'a, T>, value: T); } =20 /// Describes a given I/O location: its offset, width, and type to convert= the raw value from and @@ -321,56 +343,54 @@ fn offset(self) -> usize { /// Types implementing this trait (e.g. MMIO BARs or PCI config regions) /// can perform I/O operations on regions of memory. /// -/// This is an abstract representation to be implemented by arbitrary I/O -/// backends (e.g. MMIO, PCI config space, etc.). -/// /// The [`Io`] trait provides: -/// - Base address and size information +/// - Method to convert into [`IoBackend::View`]. /// - Helper methods for offset validation and address calculation /// - Fallible (runtime checked) accessors for different data widths /// -/// Which I/O methods are available depends on which [`IoCapable`] trai= ts -/// are implemented for the type. -/// -/// # Examples -/// -/// For MMIO regions, all widths (u8, u16, u32, and u64 on 64-bit systems)= are typically -/// supported. For PCI configuration space, u8, u16, and u32 are supported= but u64 is not. -pub trait Io: Copy { +/// Which I/O methods are available depends on the associated [`IoBackend`= ] implementation. +pub trait Io<'a>: Copy { + /// Type that defines all I/O operations. + type Backend: IoBackend; + /// Type of this I/O region. For untyped regions, [`Region`] can be us= ed. type Target: ?Sized + KnownSize; =20 - /// Returns the base address of this mapping. - fn addr(self) -> usize; - - /// Returns the maximum size of this mapping. - fn maxsize(self) -> usize; + /// Return a view that covers the full region. + fn as_view(self) -> ::View<'a, Self::Targe= t>; =20 - /// Returns the absolute I/O address for a given `offset`, - /// performing compile-time bound checks. + /// Returns a view for a given `offset`, performing compile-time bound= checks. // Always inline to optimize out error path of `build_assert`. #[inline(always)] - fn io_addr_assert(self, offset: usize) -> usize { - // We cannot check alignment with `offset_valid` using `self.addr(= )`. So set 0 for it and + fn io_addr_assert(self, offset: usize) -> ::View<'a, U> { + // We cannot check alignment with `offset_valid` using `ptr.addr()= `. So set 0 for it and // ensure alignment by checking that the alignment of `U` is small= er or equal to the // alignment of `Self::Target`. const_assert!(Alignment::of::().as_usize() <=3D Self::Target::M= IN_ALIGN.as_usize()); build_assert!(offset_valid::(0, offset, Self::Target::MIN_SIZE)= ); =20 - self.addr() + offset + let view =3D self.as_view(); + let ptr =3D Self::Backend::as_ptr(view); + let projected_ptr =3D ptr.cast::().wrapping_byte_add(offset); + // SAFETY: `offset_valid` checks for size and alignment and theref= ore `projected_ptr` is a + // valid projection. + unsafe { Self::Backend::project_view(view, projected_ptr) } } =20 - /// Returns the absolute I/O address for a given `offset`, - /// performing runtime bound checks. + /// Returns a view for a given `offset`, performing runtime bound chec= ks. #[inline] - fn io_addr(self, offset: usize) -> Result { - if !offset_valid::(self.addr(), offset, self.maxsize()) { + fn io_addr(self, offset: usize) -> Result<::View<'a, U>> { + let view =3D self.as_view(); + let ptr =3D Self::Backend::as_ptr(view); + + if !offset_valid::(ptr.addr(), offset, KnownSize::size(ptr)) { return Err(EINVAL); } =20 - // Probably no need to check, since the safety requirements of `Se= lf::new` guarantee that - // this can't overflow. - self.addr().checked_add(offset).ok_or(EINVAL) + let projected_ptr =3D ptr.cast::().wrapping_byte_add(offset); + // SAFETY: `offset_valid` checks for size and alignment and theref= ore `projected_ptr` is a + // valid projection. + Ok(unsafe { Self::Backend::project_view(view, projected_ptr) }) } =20 /// Fallible 8-bit read with runtime bounds check. @@ -378,7 +398,7 @@ fn io_addr(self, offset: usize) -> Result { fn try_read8(self, offset: usize) -> Result where usize: IoLoc, - Self: IoCapable, + Self::Backend: IoCapable, { self.try_read(offset) } @@ -388,7 +408,7 @@ fn try_read8(self, offset: usize) -> Result fn try_read16(self, offset: usize) -> Result where usize: IoLoc, - Self: IoCapable, + Self::Backend: IoCapable, { self.try_read(offset) } @@ -398,7 +418,7 @@ fn try_read16(self, offset: usize) -> Result fn try_read32(self, offset: usize) -> Result where usize: IoLoc, - Self: IoCapable, + Self::Backend: IoCapable, { self.try_read(offset) } @@ -408,7 +428,7 @@ fn try_read32(self, offset: usize) -> Result fn try_read64(self, offset: usize) -> Result where usize: IoLoc, - Self: IoCapable, + Self::Backend: IoCapable, { self.try_read(offset) } @@ -418,7 +438,7 @@ fn try_read64(self, offset: usize) -> Result fn try_write8(self, value: u8, offset: usize) -> Result where usize: IoLoc, - Self: IoCapable, + Self::Backend: IoCapable, { self.try_write(offset, value) } @@ -428,7 +448,7 @@ fn try_write8(self, value: u8, offset: usize) -> Result fn try_write16(self, value: u16, offset: usize) -> Result where usize: IoLoc, - Self: IoCapable, + Self::Backend: IoCapable, { self.try_write(offset, value) } @@ -438,7 +458,7 @@ fn try_write16(self, value: u16, offset: usize) -> Resu= lt fn try_write32(self, value: u32, offset: usize) -> Result where usize: IoLoc, - Self: IoCapable, + Self::Backend: IoCapable, { self.try_write(offset, value) } @@ -448,7 +468,7 @@ fn try_write32(self, value: u32, offset: usize) -> Resu= lt fn try_write64(self, value: u64, offset: usize) -> Result where usize: IoLoc, - Self: IoCapable, + Self::Backend: IoCapable, { self.try_write(offset, value) } @@ -458,7 +478,7 @@ fn try_write64(self, value: u64, offset: usize) -> Resu= lt fn read8(self, offset: usize) -> u8 where usize: IoLoc, - Self: IoCapable, + Self::Backend: IoCapable, { self.read(offset) } @@ -468,7 +488,7 @@ fn read8(self, offset: usize) -> u8 fn read16(self, offset: usize) -> u16 where usize: IoLoc, - Self: IoCapable, + Self::Backend: IoCapable, { self.read(offset) } @@ -478,7 +498,7 @@ fn read16(self, offset: usize) -> u16 fn read32(self, offset: usize) -> u32 where usize: IoLoc, - Self: IoCapable, + Self::Backend: IoCapable, { self.read(offset) } @@ -488,7 +508,7 @@ fn read32(self, offset: usize) -> u32 fn read64(self, offset: usize) -> u64 where usize: IoLoc, - Self: IoCapable, + Self::Backend: IoCapable, { self.read(offset) } @@ -498,7 +518,7 @@ fn read64(self, offset: usize) -> u64 fn write8(self, value: u8, offset: usize) where usize: IoLoc, - Self: IoCapable, + Self::Backend: IoCapable, { self.write(offset, value) } @@ -508,7 +528,7 @@ fn write8(self, value: u8, offset: usize) fn write16(self, value: u16, offset: usize) where usize: IoLoc, - Self: IoCapable, + Self::Backend: IoCapable, { self.write(offset, value) } @@ -518,7 +538,7 @@ fn write16(self, value: u16, offset: usize) fn write32(self, value: u32, offset: usize) where usize: IoLoc, - Self: IoCapable, + Self::Backend: IoCapable, { self.write(offset, value) } @@ -528,7 +548,7 @@ fn write32(self, value: u32, offset: usize) fn write64(self, value: u64, offset: usize) where usize: IoLoc, - Self: IoCapable, + Self::Backend: IoCapable, { self.write(offset, value) } @@ -560,12 +580,10 @@ fn write64(self, value: u64, offset: usize) fn try_read(self, location: L) -> Result where L: IoLoc, - Self: IoCapable, + Self::Backend: IoCapable, { - let address =3D self.io_addr::(location.offset())?; - - // SAFETY: `address` has been validated by `io_addr`. - Ok(unsafe { self.io_read(address) }.into()) + let view =3D self.io_addr::(location.offset())?; + Ok(Self::Backend::io_read(view).into()) } =20 /// Generic fallible write with runtime bounds check. @@ -595,14 +613,11 @@ fn try_read(self, location: L) -> Result fn try_write(self, location: L, value: T) -> Result where L: IoLoc, - Self: IoCapable, + Self::Backend: IoCapable, { - let address =3D self.io_addr::(location.offset())?; + let view =3D self.io_addr::(location.offset())?; let io_value =3D value.into(); - - // SAFETY: `address` has been validated by `io_addr`. - unsafe { self.io_write(io_value, address) } - + Self::Backend::io_write(view, io_value); Ok(()) } =20 @@ -643,7 +658,7 @@ fn try_write_reg(self, value: V) -> Result where L: IoLoc, V: LocatedRegister, - Self: IoCapable, + Self::Backend: IoCapable, { let (location, value) =3D value.into_io_op(); =20 @@ -676,17 +691,14 @@ fn try_write_reg(self, value: V) -> Result fn try_update(self, location: L, f: F) -> Result where L: IoLoc, - Self: IoCapable, + Self::Backend: IoCapable, F: FnOnce(T) -> T, { - let address =3D self.io_addr::(location.offset())?; + let view =3D self.io_addr::(location.offset())?; =20 - // SAFETY: `address` has been validated by `io_addr`. - let value: T =3D unsafe { self.io_read(address) }.into(); + let value: T =3D Self::Backend::io_read(view).into(); let io_value =3D f(value).into(); - - // SAFETY: `address` has been validated by `io_addr`. - unsafe { self.io_write(io_value, address) } + Self::Backend::io_write(view, io_value); =20 Ok(()) } @@ -716,12 +728,10 @@ fn try_update(self, location: L, f: F) -> Re= sult fn read(self, location: L) -> T where L: IoLoc, - Self: IoCapable, + Self::Backend: IoCapable, { - let address =3D self.io_addr_assert::(location.offset()= ); - - // SAFETY: `address` has been validated by `io_addr_assert`. - unsafe { self.io_read(address) }.into() + let view =3D self.io_addr_assert::(location.offset()); + Self::Backend::io_read(view).into() } =20 /// Generic infallible write with compile-time bounds check. @@ -749,13 +759,11 @@ fn read(self, location: L) -> T fn write(self, location: L, value: T) where L: IoLoc, - Self: IoCapable, + Self::Backend: IoCapable, { - let address =3D self.io_addr_assert::(location.offset()= ); + let view =3D self.io_addr_assert::(location.offset()); let io_value =3D value.into(); - - // SAFETY: `address` has been validated by `io_addr_assert`. - unsafe { self.io_write(io_value, address) } + Self::Backend::io_write(view, io_value); } =20 /// Generic infallible write of a fully-located register value. @@ -794,7 +802,7 @@ fn write_reg(self, value: V) where L: IoLoc, V: LocatedRegister, - Self: IoCapable, + Self::Backend: IoCapable, { let (location, value) =3D value.into_io_op(); =20 @@ -827,17 +835,13 @@ fn write_reg(self, value: V) fn update(self, location: L, f: F) where L: IoLoc, - Self: IoCapable, + Self::Backend: IoCapable, F: FnOnce(T) -> T, { - let address =3D self.io_addr_assert::(location.offset()= ); - - // SAFETY: `address` has been validated by `io_addr_assert`. - let value: T =3D unsafe { self.io_read(address) }.into(); + let view =3D self.io_addr_assert::(location.offset()); + let value: T =3D Self::Backend::io_read(view).into(); let io_value =3D f(value).into(); - - // SAFETY: `address` has been validated by `io_addr_assert`. - unsafe { self.io_write(io_value, address) } + Self::Backend::io_write(view, io_value); } } =20 @@ -881,78 +885,76 @@ unsafe impl Send for Mmio<'_, T> {} // SAFETY: `Mmio<'_, T>` is conceptually `&T` but in I/O memory. unsafe impl Sync for Mmio<'_, T> {} =20 -impl Io for Mmio<'_, T> { +impl<'a, T: ?Sized + KnownSize> Io<'a> for Mmio<'a, T> { + type Backend =3D MmioBackend; type Target =3D T; =20 #[inline] - fn addr(self) -> usize { - self.ptr.addr() + fn as_view(self) -> Mmio<'a, T> { + self } +} + +/// I/O Backend for memory-mapped I/O. +pub struct MmioBackend; + +impl IoBackend for MmioBackend { + type View<'a, T: ?Sized + KnownSize> =3D Mmio<'a, T>; =20 #[inline] - fn maxsize(self) -> usize { - KnownSize::size(self.ptr) + fn as_ptr<'a, T: ?Sized + KnownSize>(view: Self::View<'a, T>) -> *mut = T { + view.ptr + } + + #[inline] + unsafe fn project_view<'a, T: ?Sized + KnownSize, U: ?Sized + KnownSiz= e>( + _view: Self::View<'a, T>, + ptr: *mut U, + ) -> Self::View<'a, U> { + // INVARIANT: Per safety requirement, `ptr` is projection from `vi= ew`, so it is also a valid + // memory-mapped I/O region. + Mmio { + ptr, + phantom: PhantomData, + } } } =20 -/// Implements [`IoCapable`] on `$mmio` for `$ty` using `$read_fn` and `$w= rite_fn`. +/// Implements [`IoCapable`] on `$backend` for `$ty` using `$read_fn` and = `$write_fn`. macro_rules! impl_mmio_io_capable { - ($mmio:ident, $(#[$attr:meta])* $ty:ty, $read_fn:ident, $write_fn:iden= t) =3D> { - $(#[$attr])* - impl IoCapable<$ty> for $mmio<'_, T> { + ($backend: ident, $ty:ty, $read_fn:ident, $write_fn:ident) =3D> { + impl IoCapable<$ty> for $backend { #[inline] - unsafe fn io_read(self, address: usize) -> $ty { - // SAFETY: By the trait invariant `address` is a valid add= ress for MMIO operations. - unsafe { bindings::$read_fn(address as *const c_void) } + fn io_read(view: <$backend as IoBackend>::View<'_, $ty>) -> $t= y { + // SAFETY: By the type invariant, `view.ptr` is a valid ad= dress for MMIO operations. + unsafe { bindings::$read_fn(view.ptr.cast_const().cast()) } } =20 #[inline] - unsafe fn io_write(self, value: $ty, address: usize) { - // SAFETY: By the trait invariant `address` is a valid add= ress for MMIO operations. - unsafe { bindings::$write_fn(value, address as *mut c_void= ) } + fn io_write(view: <$backend as IoBackend>::View<'_, $ty>, valu= e: $ty) { + // SAFETY: By the type invariant, `view.ptr` is a valid ad= dress for MMIO operations. + unsafe { bindings::$write_fn(value, view.ptr.cast()) } } } }; } =20 // MMIO regions support 8, 16, and 32-bit accesses. -impl_mmio_io_capable!(Mmio, u8, readb, writeb); -impl_mmio_io_capable!(Mmio, u16, readw, writew); -impl_mmio_io_capable!(Mmio, u32, readl, writel); +impl_mmio_io_capable!(MmioBackend, u8, readb, writeb); +impl_mmio_io_capable!(MmioBackend, u16, readw, writew); +impl_mmio_io_capable!(MmioBackend, u32, readl, writel); // MMIO regions on 64-bit systems also support 64-bit accesses. #[cfg(CONFIG_64BIT)] -impl_mmio_io_capable!(Mmio, u64, readq, writeq); +impl_mmio_io_capable!(MmioBackend, u64, readq, writeq); =20 -impl<'a, const SIZE: usize> Io for &'a MmioOwned { +impl<'a, const SIZE: usize> Io<'a> for &'a MmioOwned { + type Backend =3D MmioBackend; type Target =3D Region; =20 - /// Returns the base address of this mapping. #[inline] - fn addr(self) -> usize { - self.0.addr() - } - - /// Returns the maximum size of this mapping. - #[inline] - fn maxsize(self) -> usize { - self.0.size() - } -} - -impl<'a, const SIZE: usize, T> IoCapable for &'a MmioOwned -where - Mmio<'a, Region>: IoCapable, -{ - #[inline] - unsafe fn io_read(self, address: usize) -> T { - // SAFETY: Per safety requirement. - unsafe { self.as_view().io_read(address) } - } - - #[inline] - unsafe fn io_write(self, value: T, address: usize) { - // SAFETY: Per safety requirement. - unsafe { self.as_view().io_write(value, address) } + fn as_view(self) -> Mmio<'a, Self::Target> { + // SAFETY: `Mmio` has same invariant as `MmioOwned` + unsafe { Mmio::from_raw(self.0) } } } =20 @@ -968,13 +970,6 @@ pub unsafe fn from_raw(raw: &MmioRaw>) ->= &Self { // SAFETY: `MmioOwned` is a transparent wrapper around `MmioRaw`. unsafe { &*core::ptr::from_ref(raw).cast() } } - - /// Return a view that covers the full region. - #[inline] - pub fn as_view(&self) -> Mmio<'_, Region> { - // SAFETY: `Mmio` has same invariant as `MmioOwned`. - unsafe { Mmio::from_raw(self.0) } - } } =20 /// [`Mmio`] but using relaxed accessors. @@ -1000,17 +995,38 @@ fn clone(&self) -> Self { } } =20 -impl Io for RelaxedMmio<'_, T> { - type Target =3D T; +/// I/O Backend for memory-mapped I/O, with relaxed access semantics. +pub struct RelaxedMmioBackend; + +impl IoBackend for RelaxedMmioBackend { + type View<'a, T: ?Sized + KnownSize> =3D RelaxedMmio<'a, T>; =20 #[inline] - fn addr(self) -> usize { - self.ptr.addr() + fn as_ptr<'a, T: ?Sized + KnownSize>(view: Self::View<'a, T>) -> *mut = T { + view.ptr } =20 #[inline] - fn maxsize(self) -> usize { - KnownSize::size(self.ptr) + unsafe fn project_view<'a, T: ?Sized + KnownSize, U: ?Sized + KnownSiz= e>( + _view: Self::View<'a, T>, + ptr: *mut U, + ) -> Self::View<'a, U> { + // INVARIANT: Per safety requirement, `ptr` is projection from `vi= ew`, so it is also a valid + // memory-mapped I/O region. + RelaxedMmio { + ptr, + phantom: PhantomData, + } + } +} + +impl<'a, T: ?Sized + KnownSize> Io<'a> for RelaxedMmio<'a, T> { + type Backend =3D RelaxedMmioBackend; + type Target =3D T; + + #[inline] + fn as_view(self) -> RelaxedMmio<'a, T> { + self } } =20 @@ -1046,14 +1062,9 @@ pub fn relaxed(self) -> RelaxedMmio<'a, T> { } =20 // MMIO regions support 8, 16, and 32-bit accesses. -impl_mmio_io_capable!(RelaxedMmio, u8, readb_relaxed, writeb_relaxed); -impl_mmio_io_capable!(RelaxedMmio, u16, readw_relaxed, writew_relaxed); -impl_mmio_io_capable!(RelaxedMmio, u32, readl_relaxed, writel_relaxed); +impl_mmio_io_capable!(RelaxedMmioBackend, u8, readb_relaxed, writeb_relaxe= d); +impl_mmio_io_capable!(RelaxedMmioBackend, u16, readw_relaxed, writew_relax= ed); +impl_mmio_io_capable!(RelaxedMmioBackend, u32, readl_relaxed, writel_relax= ed); // MMIO regions on 64-bit systems also support 64-bit accesses. -impl_mmio_io_capable!( - RelaxedMmio, - #[cfg(CONFIG_64BIT)] - u64, - readq_relaxed, - writeq_relaxed -); +#[cfg(CONFIG_64BIT)] +impl_mmio_io_capable!(RelaxedMmioBackend, u64, readq_relaxed, writeq_relax= ed); diff --git a/rust/kernel/pci/io.rs b/rust/kernel/pci/io.rs index a4cfa1ec6e62..9286b2e419f9 100644 --- a/rust/kernel/pci/io.rs +++ b/rust/kernel/pci/io.rs @@ -9,6 +9,7 @@ devres::Devres, io::{ Io, + IoBackend, IoCapable, MmioOwned, MmioRaw, @@ -78,32 +79,57 @@ fn clone(&self) -> Self { } } =20 +/// I/O Backend for PCI configuration space. +pub struct ConfigSpaceBackend; + +impl IoBackend for ConfigSpaceBackend { + type View<'a, T: ?Sized + KnownSize> =3D ConfigSpace<'a, T>; + + #[inline] + fn as_ptr<'a, T: ?Sized + KnownSize>(view: ConfigSpace<'a, T>) -> *mut= T { + view.ptr + } + + #[inline] + unsafe fn project_view<'a, T: ?Sized + KnownSize, U: ?Sized + KnownSiz= e>( + view: Self::View<'a, T>, + ptr: *mut U, + ) -> Self::View<'a, U> { + // INVARIANT: Per safety requirement. + ConfigSpace { + pdev: view.pdev, + ptr, + } + } +} + /// Implements [`IoCapable`] on [`ConfigSpace`] for `$ty` using `$read_fn`= and `$write_fn`. macro_rules! impl_config_space_io_capable { ($ty:ty, $read_fn:ident, $write_fn:ident) =3D> { - impl<'a, T: ?Sized> IoCapable<$ty> for ConfigSpace<'a, T> { - unsafe fn io_read(self, address: usize) -> $ty { + impl IoCapable<$ty> for ConfigSpaceBackend { + fn io_read(view: ConfigSpace<'_, $ty>) -> $ty { + // CAST: The offset is cast to `i32` because the C functio= ns expect a 32-bit + // signed offset parameter. PCI configuration space size i= s at most 4096 bytes, + // so the value always fits within `i32` without truncatio= n or sign change. + let addr =3D view.ptr.addr() as i32; + let mut val: $ty =3D 0; =20 // Return value from C function is ignored in infallible a= ccessors. - let _ret =3D - // SAFETY: By the type invariant `self.pdev` is a vali= d address. - // CAST: The offset is cast to `i32` because the C fun= ctions expect a 32-bit - // signed offset parameter. PCI configuration space si= ze is at most 4096 bytes, - // so the value always fits within `i32` without trunc= ation or sign change. - unsafe { bindings::$read_fn(self.pdev.as_raw(), addres= s as i32, &mut val) }; - + // SAFETY: By the type invariant `pdev` is a valid address. + let _ =3D unsafe { bindings::$read_fn(view.pdev.as_raw(), = addr, &mut val) }; val } =20 - unsafe fn io_write(self, value: $ty, address: usize) { + fn io_write(view: ConfigSpace<'_, $ty>, value: $ty) { + // CAST: The offset is cast to `i32` because the C functio= ns expect a 32-bit + // signed offset parameter. PCI configuration space size i= s at most 4096 bytes, + // so the value always fits within `i32` without truncatio= n or sign change. + let addr =3D view.ptr.addr() as i32; + // Return value from C function is ignored in infallible a= ccessors. - let _ret =3D - // SAFETY: By the type invariant `self.pdev` is a vali= d address. - // CAST: The offset is cast to `i32` because the C fun= ctions expect a 32-bit - // signed offset parameter. PCI configuration space si= ze is at most 4096 bytes, - // so the value always fits within `i32` without trunc= ation or sign change. - unsafe { bindings::$write_fn(self.pdev.as_raw(), addre= ss as i32, value) }; + // SAFETY: By the type invariant `pdev` is a valid address. + let _ =3D unsafe { bindings::$write_fn(view.pdev.as_raw(),= addr, value) }; } } }; @@ -114,17 +140,13 @@ unsafe fn io_write(self, value: $ty, address: usize) { impl_config_space_io_capable!(u16, pci_read_config_word, pci_write_config_= word); impl_config_space_io_capable!(u32, pci_read_config_dword, pci_write_config= _dword); =20 -impl<'a, T: ?Sized + KnownSize> Io for ConfigSpace<'a, T> { +impl<'a, T: ?Sized + KnownSize> Io<'a> for ConfigSpace<'a, T> { + type Backend =3D ConfigSpaceBackend; type Target =3D T; =20 #[inline] - fn addr(self) -> usize { - self.ptr.addr() - } - - #[inline] - fn maxsize(self) -> usize { - KnownSize::size(self.ptr) + fn as_view(self) -> ConfigSpace<'a, T> { + self } } =20 --=20 2.54.0 From nobody Thu Jun 25 00:35:31 2026 Received: from LO3P265CU004.outbound.protection.outlook.com (mail-uksouthazon11020097.outbound.protection.outlook.com [52.101.196.97]) (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 CFA153EF64F; Mon, 8 Jun 2026 19:59:25 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=52.101.196.97 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780948770; cv=fail; b=ezHCeoD8utKhoPJuIIEaMBOOd8dtjVB4SHNRcj3UeqR/L5PCduYN7C03v/X/l6fhCVSWkp5ac67WWJORr6WAOOb/EUPMg7RbHfQ04Gc0vP8qMIanF/TPExUs2ym1+Qzko4r8YSo3eZQ8miXA/JLX0Xn83tiyQzfwB5bFXpmEgb4= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780948770; c=relaxed/simple; bh=FMyTpgv39QpY3xO13drGr70SK+wnFr/pLzsyeQ+ApzI=; h=From:Date:Subject:Content-Type:Message-Id:References:In-Reply-To: To:Cc:MIME-Version; b=l2kajv0Dh06UG6XfV25A6i/4imbkypl2Esv/zvpyqn55YtK7zh3TAzPK02gWzrOa5o56GQyZMDyWx5PMuJ/7obGY5OOdllufa1e+VZzX7TtlXbpY2EfnWFlU63b1hJMCJRml/hDorFORoVZJYwXMCtH3KaLuPXBh7S1IUC2rhMc= 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=k8yrD0jn; arc=fail smtp.client-ip=52.101.196.97 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="k8yrD0jn" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=VL3Py8p3N+N2c6n5r2s3R1LoT6IbZHLPedZXHrdvG0uJCAnn4uNjvQAxWR//tf9xPWtgMSvpMsuy9LNiJhn5e9STKszYkdk9hNTzIcMelTDJu2I5IqNjkdvxzRfkwqxNnHGnEPW5eklXAYq8k9nrf67b1ei5887GeNzW4Mc/u3cwpbtGmV/Si0zCiIQI4PKaisylze34CIE5hHLFsZKP5Z7rxwXjYuD8LXmsn5l7Y1YFngJhLSfBbim4PITwBPjtsLR4Whw8/OGxe1UQOk5eAcEOe47Pccwh/8f+xSqVzBcx1yf4VI4JVz0ERBr69D2oIBvU5QthTW1YT+vm65NoZQ== 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=J+OMAN0Kqzu9SQSmzuZuYXQ0t7v4gw4PfJyG0uT4dgE=; b=aj+pOLVidIt35qu0KtY2KTQ1/RqjMPCv9Gk28VosmyvCAHZgqAIVpTecuCU9t7PPh8ODUx0+gSoQAW6G82L8+UAZsk9y0G+HJPFsISIjA+NVEO43RwAgKY6n2cXlo0iNXzNWaUNUa/+7Y3FRRZxkMZmSPmoez4G1wk8CTh8RR0YTxstFSdqZ02bgflTqYqidm/HjHqEaCj+zA/SUaPa1s7dAUbpOOkTuFvAfDU01CZ6koYW9Tin21y8udyCKs029heyYDi0miqLj0jURIot+nrT14zlfY4nkWIorAgx7vCAM+7mrQ+BbqY0k/ZjYkRQrP3S5Stxgf47NuXCLSwTV9Q== 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=J+OMAN0Kqzu9SQSmzuZuYXQ0t7v4gw4PfJyG0uT4dgE=; b=k8yrD0jnYLBIMjJoSJxsLdXWh07QrtDm7Y5xUTB9H39slWMILHTlQroFoVi0KdOIp6PZymm5z2ZpdvtLad2+4tE6uyOz96CO9Yu20aKE+o6AQ6Ek7qHAAinfgvVR3S6bJm6vkVr+O1EdYDvfk6bZGd5Fgexllj9bym2jhG6OIQQ= Authentication-Results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=garyguo.net; Received: from LOVP265MB8871.GBRP265.PROD.OUTLOOK.COM (2603:10a6:600:488::16) by LO8P265MB7398.GBRP265.PROD.OUTLOOK.COM (2603:10a6:600:3ca::5) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.21.92.12; Mon, 8 Jun 2026 19:59:12 +0000 Received: from LOVP265MB8871.GBRP265.PROD.OUTLOOK.COM ([fe80::1c3:ceba:21b4:9986]) by LOVP265MB8871.GBRP265.PROD.OUTLOOK.COM ([fe80::1c3:ceba:21b4:9986%4]) with mapi id 15.21.0092.011; Mon, 8 Jun 2026 19:59:12 +0000 From: Gary Guo Date: Mon, 08 Jun 2026 20:59:07 +0100 Subject: [PATCH v3 10/19] rust: io: remove `MmioOwned` Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260608-io_projection-v3-10-c5cde13a5ec4@garyguo.net> References: <20260608-io_projection-v3-0-c5cde13a5ec4@garyguo.net> In-Reply-To: <20260608-io_projection-v3-0-c5cde13a5ec4@garyguo.net> To: Danilo Krummrich , Alice Ryhl , Daniel Almeida , Greg Kroah-Hartman , "Rafael J. Wysocki" , Miguel Ojeda , Boqun Feng , Gary Guo , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Andreas Hindborg , Trevor Gross , Bjorn Helgaas , =?utf-8?q?Krzysztof_Wilczy=C5=84ski?= , Abdiel Janulgue , Robin Murphy , Alexandre Courbot , David Airlie , Simona Vetter Cc: driver-core@lists.linux.dev, rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, linux-pci@vger.kernel.org, nova-gpu@lists.linux.dev, dri-devel@lists.freedesktop.org X-Mailer: b4 0.15.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1780948747; l=8855; i=gary@garyguo.net; s=20221204; h=from:subject:message-id; bh=FMyTpgv39QpY3xO13drGr70SK+wnFr/pLzsyeQ+ApzI=; b=ugJnNl4GjZ7pynKJmlGu12J8Op2MEH05EjuIG8uxhfi1pU24pHxpt/1c1VYgJByxtlU8eIQlm ovQMgwCOrtCDC/Cb5RJDMOuiubQOe+BH/KJDAUNdwjK97bL3y7/lvzt X-Developer-Key: i=gary@garyguo.net; a=ed25519; pk=vB3uIX95SM4eVrIqo1DWNWKDKD2xzB+yLLLr0yOPYMo= X-ClientProxiedBy: LO4P123CA0344.GBRP123.PROD.OUTLOOK.COM (2603:10a6:600:18d::7) To LOVP265MB8871.GBRP265.PROD.OUTLOOK.COM (2603:10a6:600:488::16) 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: LOVP265MB8871:EE_|LO8P265MB7398:EE_ X-MS-Office365-Filtering-Correlation-Id: 0dc34bd8-57bd-4a72-4fa7-08dec59868f8 X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|1800799024|7416014|376014|366016|10070799003|6133799003|22082099003|18002099003|921020|56012099006|5023799004; X-Microsoft-Antispam-Message-Info: W/92YoR827Mo32o8PM3jGNVwHs4rdQpCa6srq3G8mYW/5XqDWuxUBKBtzq90zzA+PCV5nUUkGMO4wChYE2sRmohi+EaGyjqTscUE1QCf6PNWmRxEmWfM9GVw8DLDnyKJsvK5wxQYWLAK/kIBsgU09RrirHC3hecHnwGH/RLXvCRDN0UASW4XNJ56uWEJ6SIBjn2yaQ6Lvgu6BU44kuD1+yKPgUCiG3cu4OCYjlG8JhAkMgbMRKlyvyhOx8yH/FfykwV6I2QowA36fMoRvsvLBOXLR7zLnooRJkWy3u/tDkBKvqVHorS8uucP2QtRsI5gwGWDmmEaUtoK6FmqXe48UFl0s1LIwXfm4ixFDM/3T+y9dh2IysfjUak1T+ft1ET55hArdb/Ztf2pGNe2loYcCNKeolVBVGSa9qLDAW5X6rZ2tIpAb1EXWOi3Gkq3Iq7xfzPLfa/6K7xck9AuWo9XwNkIywJ54layP3F+g1/tGalhWsKEMovbH0kkzNWqT0PxC6bEFpKeR8CKD5843chyjQkEXI3DcbzMw7m7e9P+HaxguIiLEQneqX42I0Zntv0B+pLUbpMY/yUPLB4YXONN3sTW8+HLqJ7MkJ2yFWU6obZRMIoZzRxpx69mxjKmHYwm0WPEWkG6YGxZhdD9aCK0WeiO1+p6SZ4ahLseGEV5O+AvpT1ypj4WPi2LeeRo3otSuzBZiyvTVTuzdbO32FwYIYvSkJhVlDS05fp0WKzwXjk= X-Forefront-Antispam-Report: CIP:255.255.255.255;CTRY:;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:LOVP265MB8871.GBRP265.PROD.OUTLOOK.COM;PTR:;CAT:NONE;SFS:(13230040)(1800799024)(7416014)(376014)(366016)(10070799003)(6133799003)(22082099003)(18002099003)(921020)(56012099006)(5023799004);DIR:OUT;SFP:1102; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: =?utf-8?B?RWNMMFRFV1dTNGg0bUpKTHdSb2dwY1FDZGZWYXlQV0ZQZGoxQ090ZXRSeHlC?= =?utf-8?B?ck4rZjJkaWZLODZvMVgyOC9zQmlpZGJpbUxZUlVodk5paGNaV2Q1djJXeEx3?= =?utf-8?B?Tm5QWDludXJhck53L3pHam5EdEpxRDkyT2M4Vm8yNTNuN091ZWlsNWMwMVMr?= =?utf-8?B?Y1hVeDh4SG0wRjNRZG9Hak9iMG0xS1pweDA0b29sVWVCUFV4S2YxeWlmYmZU?= =?utf-8?B?cHFITm1VNUl5cnBUejRhME1vbEpCSThtdkRoNFM2QVljZXpWdXJuVElieTJV?= =?utf-8?B?YlVTb1BTRXQ0azF6NEhuOEFUSEpPZ2tjcVB5NTArNThEVHpMYUpncFgyMTkr?= =?utf-8?B?YXFqWDhwN1hJc0dKQmRkUml1WXl1WWl2ek9tY2xYUkNYaGMvbm0xWDJrMk9m?= =?utf-8?B?N3dCazA0UE5xdW5rVGJQRzRQTlFCS3MrRDJqc3NwazVFaEZIaVZyekVCdEpj?= =?utf-8?B?MndRZkJJYVRpUGFWZENOQVZyYWg4Z1ovamVISVpVUkpqS3pDejZTZ0lVL1pl?= =?utf-8?B?ZzJ4NUtlUGFNdHA5MmtzN3h6RHlqZEpaOHNOWTF3c3pjeWlMVUV6bTNzaGNh?= =?utf-8?B?eGZEWGVLUEVaNkNHY044ZUtLK0tjTHdsQ2NJMHpWUGNjS0ViQSs2NUlQV2pN?= =?utf-8?B?VHNQeG12WUhZVUEvOERRR1hYbm5RWVMzY0k0Z1dGZHpFekJuTE1GMldtK2gz?= =?utf-8?B?cVJ4T2k1TEtzaWVaSmJiN3VzNlBTbGZJc1k3b0VLcDE1d2NEVkQwZUV1MjNQ?= =?utf-8?B?aW51dzJiQzhaQ1daSUtxN1lwcXpBZVpqWTRqeEpma2FpSjluVHZaRGJ1TXE4?= =?utf-8?B?R3N5YnpmWUJJSEtaY0lPMXNhOXBRcUJmSko3QStndGJFb0Rab1M5ZVhPS0FQ?= =?utf-8?B?cW4yb3hZNjI3aEFLbCtGSmMwOTlBQW5lb3EzL2xPaDQ2MGlhSG5abHk3ZjJr?= =?utf-8?B?NEV6TnplNzBMVnhwUTRTeDdFbXVKZHpXdDdSVGVVbHhtdHVkMzYzd3BscUFr?= =?utf-8?B?VGV5NXpRZlh5eWp4NEp1R2w5c2t1dy90WmFlYnAwVVNXK3ZvYmUvbElRdHll?= =?utf-8?B?akt1cFVzejVybVRtU29Wa1E1N1dVbWNMTmhMOWdBc2pCbEF3Y3RlU1VFbDh4?= =?utf-8?B?VDJQY0tuaC9CajZMcWphQlRKQTVMUjhpWjF5dTZyNXRYOEUzQnZVbWRYUHJn?= =?utf-8?B?VmFvTGJobkswK3hqWElKRldtcHJjSTJLNXdTV0o2djFrZHkvcDFseWdxZjlJ?= =?utf-8?B?ZlA0cjdsSm9zR2VaTndWeHhKemRyWTNIMGF1V1k0clJRbmNvYWkwNklvK0dj?= =?utf-8?B?bDl0eXUyVmMrL2tZOWlvOExNMG5wZE44eURvbHhiYUNQYjJEYitYVFJDOU8y?= =?utf-8?B?U3JkL2c3b0xjakJMSkJQRGJnMHIxQ1M2NW5lcExOZFpQNFd0eEMvZUxzSTA0?= =?utf-8?B?NnQzUlp1SllMcU1FM3dQbjN4MFBTZVdpeHptcXZKMTdvNStUdkVEYldRcGdK?= =?utf-8?B?TXcvcW1sSzJVTm5rK1lmRlg5VnFQS2dESWhISTFZSDNkSjZiR0lSUEFlL1hp?= =?utf-8?B?QTgwUTd1TXI4bmlxMHFmeDIwOWVFQ1JENll5Rk5Ea1dJS2laSWExeEhqQWFY?= =?utf-8?B?SWVDZFowLzdlNmxHNWJwckYxTFFiclVER09HY0pqVDBFOXN2a3lEZ0tLK054?= =?utf-8?B?WEg2OU5KYkUyT2Y0djVna3FqYnczaHEvQnNraVhldmhscytMa3N0RVh2b0Nn?= =?utf-8?B?aENkZE5CbERsR2ptSmZYcmdwRXRMWEFJdjZlL0xjVmxHTk9sQ3pCWHR3Ti9v?= =?utf-8?B?UDR4clNWb3dlOWMwV3FnOHZONVZnZStUeThkeTdZbjgxRWZsSTFFUldoR0lZ?= =?utf-8?B?RHhGdjVuSkM1S3BrMTd0TjRRVzVReW9VVGRXaWFIbnNqNmZVWUZHcDJFampi?= =?utf-8?B?bHBBaUFCbVVPNUpxQW5kQVFpVTlzTnQva3IwRmhxeENvUEc3Z1hHZlM5RXFC?= =?utf-8?B?d0JQYVcrRVl3bW5vSVlxWEZGZDdTZVZaL1FyTGMxQTMxK2Rud1dabjNONzBh?= =?utf-8?B?M1dGRlJyY2pQQTU3amtHNEc4UjhPTFprekxKV2RrbnBrODNja0wzcUNFMmRH?= =?utf-8?B?WlAyMXNJQXBZMzVnQmlEUTN1V3lUdklub2NIZERmVEEyVWVHbVVVZnZ3VEJE?= =?utf-8?B?UHNZSlVqbGpxcGI0S0JKRlBWbGQzOFRSSnlMR2ZPN3Q0Mkg1azNMT3M0eGl4?= =?utf-8?B?cWJ5aE5LMWFIK1AxN0tUZkYvR1EzT0Y1MzRjYXcrY0E2SUU4K3BZUzRja0U0?= =?utf-8?B?bFZxcHJWdFpmcnZOSkdTRkI3SUFSNjhVeGpDY0FLMk1pOUpSa29EQT09?= X-OriginatorOrg: garyguo.net X-MS-Exchange-CrossTenant-Network-Message-Id: 0dc34bd8-57bd-4a72-4fa7-08dec59868f8 X-MS-Exchange-CrossTenant-AuthSource: LOVP265MB8871.GBRP265.PROD.OUTLOOK.COM X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 08 Jun 2026 19:59:12.0684 (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: dqO4xQEuuEhAJVuT1cfoJndyVmrz8XhF9ZuZzRdzATChWPdxlQAfT47hIQGWKpAAt7Oagb8prZsG2eJimMXjrA== X-MS-Exchange-Transport-CrossTenantHeadersStamped: LO8P265MB7398 `Io` trait is now very easy to implement. Thus, implement it on `Bar` and `IoMem` directly and remove the `MmioOwned` struct. Signed-off-by: Gary Guo Suggested-by: Danilo Krummrich --- rust/kernel/devres.rs | 12 +++--- rust/kernel/io.rs | 103 +---------------------------------------------= ---- rust/kernel/io/mem.rs | 26 +++++++------ rust/kernel/pci/io.rs | 16 ++++---- 4 files changed, 32 insertions(+), 125 deletions(-) diff --git a/rust/kernel/devres.rs b/rust/kernel/devres.rs index aed0c994fd30..3545ffc5345d 100644 --- a/rust/kernel/devres.rs +++ b/rust/kernel/devres.rs @@ -68,8 +68,9 @@ struct Inner { /// devres::Devres, /// io::{ /// Io, -/// MmioOwned, +/// Mmio, /// MmioRaw, +/// MmioBackend, /// PhysAddr, /// Region, // /// }, @@ -104,12 +105,13 @@ struct Inner { /// } /// } /// -/// impl Deref for IoMem { -/// type Target =3D MmioOwned; +/// impl<'a, const SIZE: usize> Io<'a> for &'a IoMem { +/// type Backend =3D MmioBackend; +/// type Target =3D Region; /// -/// fn deref(&self) -> &Self::Target { +/// fn as_view(self) -> Mmio<'a, Region> { /// // SAFETY: The memory range stored in `self` has been properly= mapped in `Self::new`. -/// unsafe { MmioOwned::from_raw(&self.0) } +/// unsafe { Mmio::from_raw(self.0) } /// } /// } /// # fn no_run(dev: &Device) -> Result<(), Error> { diff --git a/rust/kernel/io.rs b/rust/kernel/io.rs index d09d9864858d..8b3a64188b48 100644 --- a/rust/kernel/io.rs +++ b/rust/kernel/io.rs @@ -100,8 +100,8 @@ fn size(p: *const Self) -> usize { /// the represented MMIO region does exist or is properly mapped. /// /// Instead, the bus specific MMIO implementation must convert this raw re= presentation into an -/// `MmioOwned` instance providing the actual memory accessors. Only by th= e conversion into an -/// `MmioOwned` structure any guarantees are given. +/// `Mmio` instance providing the actual memory accessors. Only by the con= version into an `Mmio` +/// structure any guarantees are given. pub struct MmioRaw { /// Pointer is in I/O address space. /// @@ -158,80 +158,6 @@ pub fn size(&self) -> usize { } } =20 -/// IO-mapped memory region. -/// -/// The creator (usually a subsystem / bus such as PCI) is responsible for= creating the -/// mapping, performing an additional region request etc. -/// -/// # Invariant -/// -/// `addr` is the start and `maxsize` the length of valid I/O mapped memor= y region of size -/// `maxsize`. -/// -/// # Examples -/// -/// ```no_run -/// use kernel::{ -/// bindings, -/// ffi::c_void, -/// io::{ -/// Io, -/// MmioOwned, -/// MmioRaw, -/// PhysAddr, -/// Region, -/// }, -/// }; -/// use core::ops::Deref; -/// -/// // See also `pci::Bar` for a real example. -/// struct IoMem(MmioRaw>); -/// -/// impl IoMem { -/// /// # Safety -/// /// -/// /// [`paddr`, `paddr` + `SIZE`) must be a valid MMIO region that i= s mappable into the CPUs -/// /// virtual address space. -/// unsafe fn new(paddr: usize) -> Result{ -/// // SAFETY: By the safety requirements of this function [`paddr= `, `paddr` + `SIZE`) is -/// // valid for `ioremap`. -/// let addr =3D unsafe { bindings::ioremap(paddr as PhysAddr, SIZ= E) }; -/// if addr.is_null() { -/// return Err(ENOMEM); -/// } -/// -/// Ok(IoMem(MmioRaw::new_region(addr as usize, SIZE)?)) -/// } -/// } -/// -/// impl Drop for IoMem { -/// fn drop(&mut self) { -/// // SAFETY: `self.0.addr()` is guaranteed to be properly mapped= by `Self::new`. -/// unsafe { bindings::iounmap(self.0.addr() as *mut c_void); }; -/// } -/// } -/// -/// impl Deref for IoMem { -/// type Target =3D MmioOwned; -/// -/// fn deref(&self) -> &Self::Target { -/// // SAFETY: The memory range stored in `self` has been properly= mapped in `Self::new`. -/// unsafe { MmioOwned::from_raw(&self.0) } -/// } -/// } -/// -///# fn no_run() -> Result<(), Error> { -/// // SAFETY: Invalid usage for example purposes. -/// let iomem =3D unsafe { IoMem::<{ core::mem::size_of::() }>::new(0= xBAAAAAAD)? }; -/// iomem.write32(0x42, 0x0); -/// assert!(iomem.try_write32(0x42, 0x0).is_ok()); -/// assert!(iomem.try_write32(0x42, 0x4).is_err()); -/// # Ok(()) -/// # } -/// ``` -#[repr(transparent)] -pub struct MmioOwned(MmioRaw>); - /// Checks whether an access of type `U` at the given `base` and the given= `offset` /// is valid within this region. /// @@ -947,31 +873,6 @@ fn io_write(view: <$backend as IoBackend>::View<'_, $t= y>, value: $ty) { #[cfg(CONFIG_64BIT)] impl_mmio_io_capable!(MmioBackend, u64, readq, writeq); =20 -impl<'a, const SIZE: usize> Io<'a> for &'a MmioOwned { - type Backend =3D MmioBackend; - type Target =3D Region; - - #[inline] - fn as_view(self) -> Mmio<'a, Self::Target> { - // SAFETY: `Mmio` has same invariant as `MmioOwned` - unsafe { Mmio::from_raw(self.0) } - } -} - -impl MmioOwned { - /// Converts an `MmioRaw` into an `MmioOwned` instance, providing the = accessors to the MMIO - /// mapping. - /// - /// # Safety - /// - /// Callers must ensure that `addr` is the start of a valid I/O mapped= memory region of size - /// `maxsize`. - pub unsafe fn from_raw(raw: &MmioRaw>) -> &Self { - // SAFETY: `MmioOwned` is a transparent wrapper around `MmioRaw`. - unsafe { &*core::ptr::from_ref(raw).cast() } - } -} - /// [`Mmio`] but using relaxed accessors. /// /// This type provides an implementation of [`Io`] that uses relaxed I/O M= MIO operands instead of diff --git a/rust/kernel/io/mem.rs b/rust/kernel/io/mem.rs index 8f6c257c5b8e..d9b3189d09b4 100644 --- a/rust/kernel/io/mem.rs +++ b/rust/kernel/io/mem.rs @@ -2,8 +2,6 @@ =20 //! Generic memory-mapped IO. =20 -use core::ops::Deref; - use crate::{ device::{ Bound, @@ -16,7 +14,9 @@ Region, Resource, // }, - MmioOwned, + Io, + Mmio, + MmioBackend, MmioRaw, // }, prelude::*, @@ -210,11 +210,13 @@ pub fn into_devres(self) -> Result>> { } } =20 -impl Deref for ExclusiveIoMem<'_, SIZE> { - type Target =3D MmioOwned; +impl<'a, const SIZE: usize> Io<'a> for &'a ExclusiveIoMem<'_, SIZE> { + type Backend =3D MmioBackend; + type Target =3D super::Region; =20 - fn deref(&self) -> &Self::Target { - &self.iomem + #[inline] + fn as_view(self) -> Mmio<'a, Self::Target> { + self.iomem.as_view() } } =20 @@ -290,11 +292,13 @@ fn drop(&mut self) { } } =20 -impl Deref for IoMem<'_, SIZE> { - type Target =3D MmioOwned; +impl<'a, const SIZE: usize> Io<'a> for &'a IoMem<'_, SIZE> { + type Backend =3D MmioBackend; + type Target =3D super::Region; =20 - fn deref(&self) -> &Self::Target { + #[inline] + fn as_view(self) -> Mmio<'a, Self::Target> { // SAFETY: Safe as by the invariant of `IoMem`. - unsafe { MmioOwned::from_raw(&self.io) } + unsafe { Mmio::from_raw(self.io) } } } diff --git a/rust/kernel/pci/io.rs b/rust/kernel/pci/io.rs index 9286b2e419f9..cd921cbba164 100644 --- a/rust/kernel/pci/io.rs +++ b/rust/kernel/pci/io.rs @@ -11,16 +11,14 @@ Io, IoBackend, IoCapable, - MmioOwned, + Mmio, + MmioBackend, MmioRaw, Region, // }, prelude::*, ptr::KnownSize, // }; -use core::{ - ops::Deref, // -}; =20 /// Represents the size of a PCI configuration space. /// @@ -263,12 +261,14 @@ fn drop(&mut self) { } } =20 -impl Deref for Bar<'_, SIZE> { - type Target =3D MmioOwned; +impl<'a, const SIZE: usize> Io<'a> for &'a Bar<'_, SIZE> { + type Backend =3D MmioBackend; + type Target =3D crate::io::Region; =20 - fn deref(&self) -> &Self::Target { + #[inline] + fn as_view(self) -> Mmio<'a, Self::Target> { // SAFETY: By the type invariant of `Self`, the MMIO range in `sel= f.io` is properly mapped. - unsafe { MmioOwned::from_raw(&self.io) } + unsafe { Mmio::from_raw(self.io) } } } =20 --=20 2.54.0 From nobody Thu Jun 25 00:35:31 2026 Received: from LO3P265CU004.outbound.protection.outlook.com (mail-uksouthazon11020080.outbound.protection.outlook.com [52.101.196.80]) (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 B54523EE1EA; Mon, 8 Jun 2026 19:59:26 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=52.101.196.80 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780948769; cv=fail; b=r0+RYNSf+0Kao2G8Q4nwINenlTDVtUTyWMMej1Ow9WY6gQM8EFYMjIAW111cBNN0YnA8kmcR9CEdRvUwjx3Kzy0VeVIgF7icjlaKHTPWZixojyQhQ8v+I2hdA35NU/y7/NLk4OuDWPuxFochRO44nCftogK8E6vFp9t6q2Riqu8= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780948769; c=relaxed/simple; bh=hARIKO1AiUcO0j1zhfrY2ipk+iqXCaOtanAULqEAdIo=; h=From:Date:Subject:Content-Type:Message-Id:References:In-Reply-To: To:Cc:MIME-Version; b=AIhfATARuKIxgrr2RXxBKrIblWNxYJmltevlRHBi+JnZVi+TXECuMFcpGWjJW/1ASSmNYyKgTn3IzkDD8cnIX3YWW37u6SecyiRHHjsr8sneQMnNHjWO67kObG9eEDgg45INfRpjRm/BAQmWfd8JkpI/q+ONnOz1L/TICMgCc3c= 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=jf3Xp6gI; arc=fail smtp.client-ip=52.101.196.80 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="jf3Xp6gI" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=qQhRKivhAUd7ddTE09QfS+BJvMOS3n3Kv7fjM5Q5sfrShorE0fv/e6qFFPrmkgCob13d1v2uokpzvk9JGBeAO1U6if/OiUZv2oRXZ/BM5x9wnrPZ5w9rC+etF+GcjX4KawenCJUxTFuqqojhNFlye4JFcAWo681E16fXtuCzyWia+XgBq+cZqfOO0zTxZ0EuvqN9B5BZFXuoql1Ttb2BvG2FrIf1mwlAbwM2xysBBcfJUH4PX8Pb5n+L79uj9atxscv2zG16hSokwi44JZtTI4Q/sTinI/lWdlLIKbiG9ef1E0yTkVs5y/zMnZGOjGhucmMrp9McbVGLLCHPKLy9yg== 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=Xdy54JqDYQWz55PhzLjgqZ55JFsFWnLcTa5MtnbU6pY=; b=q2XEpbqWd+TIuTTF+3aadL/xsGGeUluKymr1+cRWDgsAzrJpj21UjgRRU6ZfEl04KbHkouM9Gkk0UJMOkT5iFJe2iAvGTVBLinWBRpVBbsTqA654NMXQ0femadmlwUnLquVeZgGBkDMWZ+aTsNjK2XzkxKA1KmLxwt9/E+C7cCxIEZk4T8PLtqpW63at2iRP2Cjeh9RJRZ8XJzg8qsU1iHWiZzAhDffJxo4fJyry/5HC0aRY8Sx4uyIpwGsfunQsYg+oSYeNLTO+j0VupfdzbQyQSeToit7lId2mfr/ZLLa+p37RLYayfoJ3zDbdxwanA0KIhTqoyeO9Ce/Tw3WCIw== 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=Xdy54JqDYQWz55PhzLjgqZ55JFsFWnLcTa5MtnbU6pY=; b=jf3Xp6gINQbstspxFN6S2hjtyyH18K1RdrZ9EG+/lyxXkGFOYpElSxD8lCZLcvhhYNMH3Kd0q30P2yJUYCgRHCVGtuiYWUChymDI3z2ISqo2bEtItbpgw4FKyhmwihPWR53Jbofoo54I17cV8Fwb4bBjzmZvCPwl0bz1spkCKLU= Authentication-Results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=garyguo.net; Received: from LOVP265MB8871.GBRP265.PROD.OUTLOOK.COM (2603:10a6:600:488::16) by LO8P265MB7398.GBRP265.PROD.OUTLOOK.COM (2603:10a6:600:3ca::5) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.21.92.12; Mon, 8 Jun 2026 19:59:12 +0000 Received: from LOVP265MB8871.GBRP265.PROD.OUTLOOK.COM ([fe80::1c3:ceba:21b4:9986]) by LOVP265MB8871.GBRP265.PROD.OUTLOOK.COM ([fe80::1c3:ceba:21b4:9986%4]) with mapi id 15.21.0092.011; Mon, 8 Jun 2026 19:59:12 +0000 From: Gary Guo Date: Mon, 08 Jun 2026 20:59:08 +0100 Subject: [PATCH v3 11/19] rust: io: move `Io` methods to extension trait Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260608-io_projection-v3-11-c5cde13a5ec4@garyguo.net> References: <20260608-io_projection-v3-0-c5cde13a5ec4@garyguo.net> In-Reply-To: <20260608-io_projection-v3-0-c5cde13a5ec4@garyguo.net> To: Danilo Krummrich , Alice Ryhl , Daniel Almeida , Greg Kroah-Hartman , "Rafael J. Wysocki" , Miguel Ojeda , Boqun Feng , Gary Guo , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Andreas Hindborg , Trevor Gross , Bjorn Helgaas , =?utf-8?q?Krzysztof_Wilczy=C5=84ski?= , Abdiel Janulgue , Robin Murphy , Alexandre Courbot , David Airlie , Simona Vetter Cc: driver-core@lists.linux.dev, rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, linux-pci@vger.kernel.org, nova-gpu@lists.linux.dev, dri-devel@lists.freedesktop.org X-Mailer: b4 0.15.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1780948747; l=6959; i=gary@garyguo.net; s=20221204; h=from:subject:message-id; bh=hARIKO1AiUcO0j1zhfrY2ipk+iqXCaOtanAULqEAdIo=; b=OcPp8gUvCf9PF7NlPCry5f6mmsS507ZX0+ylQJbTn2JErCZVCZ8oeWZjfe/TmiRmHan2+uLdO Se/chvYAIsQB4g2yGVtCKorZ5HIXwmgR6WMzuZYdnq13uifapOg3jl3 X-Developer-Key: i=gary@garyguo.net; a=ed25519; pk=vB3uIX95SM4eVrIqo1DWNWKDKD2xzB+yLLLr0yOPYMo= X-ClientProxiedBy: LO4P123CA0344.GBRP123.PROD.OUTLOOK.COM (2603:10a6:600:18d::7) To LOVP265MB8871.GBRP265.PROD.OUTLOOK.COM (2603:10a6:600:488::16) 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: LOVP265MB8871:EE_|LO8P265MB7398:EE_ X-MS-Office365-Filtering-Correlation-Id: 1fb4bdbf-e59b-41d6-0203-08dec5986932 X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|1800799024|7416014|376014|366016|10070799003|6133799003|22082099003|18002099003|921020|3023799007|56012099006|5023799004; X-Microsoft-Antispam-Message-Info: jwNZMwA45tjWqLGNtWAs//JAjjpTYudr0M0Ic61keXoHzPsqg3A6hbtbge46LY5oaoh5SpTqYDwK+PbGyN0KfuI8KZb4mqGhC+1vGporj5B7GqIa3GCFbmzeeXgsPlsHdsfhZ2DZnhpPXnIHYhoZEwa48MYGE9mILWKoAscoshEG+S/dcdKj3OXv9pkUgjyUyv02psc+6un6FVk/c82g+wxtZvCU0KYKahpJ1fTTESGZD+EzceijsV1d8Vc7pLB9Mww6L1+3ss+WW7j6622tXneV2ErRw0ci++OTFKJjPSVlZLY9hUPTidzYM5r3ynJLudaiiUrGmSMB6cEFQwIel2XKh9o6WB89iYEinG6uZEi7Iw68dfeBwxXMPtjv6C+v7hJ+ujafd8Pd7dIEckIsql3Z5lOJN7LBH9p8sR2amhi9LwaNjMA6/X/1A+lPDEYbHXNrnqoSiga3nwDzftSN7p03ovel/fh2Xni8ImAhvu1eaSdx6rJEtupyP4a+wThu5OzVEQnemqrz5PU/CuknGys5SRqFyXC76vNFlr2xot0y/+E2TPkN5QOBoQpiypDjmQD9O3lcQwoOkmm4ESFXEHERdQBZccAAZBEDgRLBT889+bjNC9hy6uspyau5Kmjm1T1AGAtDKWJd/PqE4RmUGvqly0Cnx+Qf3Ke9lrkbmTuQ6vSYGfehLZ1SZhQhLlQ/dTRUnOKSDj4B0ieUYoxiGO4PU/FkeGMaJVUEwoSnXks= X-Forefront-Antispam-Report: CIP:255.255.255.255;CTRY:;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:LOVP265MB8871.GBRP265.PROD.OUTLOOK.COM;PTR:;CAT:NONE;SFS:(13230040)(1800799024)(7416014)(376014)(366016)(10070799003)(6133799003)(22082099003)(18002099003)(921020)(3023799007)(56012099006)(5023799004);DIR:OUT;SFP:1102; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: =?utf-8?B?VGZ3UGRvVzlkNkovT1E4WlZSeTFDc1I2SUgvakdFMkFheWJVSUdlbXJvU0JE?= =?utf-8?B?eTByajM3WWFGb2FEblp4eW93YSs1SFl0cEZEcjNZM0ZnaFBMdWN4QXRPalR0?= =?utf-8?B?dGFOSGYvL0d0Nis1TFJTRkFtYnFtd29DUkpHbGlyR1R1bzBJT3JTOUQ1NExB?= =?utf-8?B?SjN0ajVGRjdkbXJ6SGo5UmJTaUhBNCtIYm9KVnRGcnBCSFJPbVFpU0RXWmVU?= =?utf-8?B?aHl6eTI1VG5XMkdZWHhGYnFreng1UFZSNEpqYURFdlFKL1JUMUN1ZW1Qb0E4?= =?utf-8?B?VmFCRDE1UjBXTnVFcWgrU1Q4RDJKZ1V1R2lyQlMwUXVGamJkMEM4TG1Fcm5k?= =?utf-8?B?VWtJN0JkTFVRdEV5YVVEV0x0ZkZSdW1zNTRnQlVzN0UvcTArcXM3MHJTM3BG?= =?utf-8?B?dlJYZEYzRGgxcFVYbzQzbDRrdVYranRBUlREQVp0RVMxVC9BT0o5ZEoweExU?= =?utf-8?B?SXF3OGREcWxMbE0zS2pDS2NoWCs3RG9oZUcxQVJkeTRjL3NJbXZiNVhpa2F6?= =?utf-8?B?UVZtUGh6dW1DZ2xwRHBiaVBPMFBPWU5XaGNIampzWHVWWDBTZGQyWm1rUXU3?= =?utf-8?B?SkRpb0pmVGtNa1lrUkhzaGdsOExSZjhwSXNWenlqQVJvdFo5OXJUZ3EyMWdN?= =?utf-8?B?Z05NSFhERkI3QnZvUUdDS2FBd2JNT2hxajh4MGJrUTJGY3E2U2U0WXBYTXlU?= =?utf-8?B?WlB0d3hFdHJxOW1TQVd6aFlsdW5HOGd1aGZ1T2pobTVMSVM1TzZPV0hKNG82?= =?utf-8?B?MlBJSjhxeFFISFM0d1ltVDdvS0p3KzFrT2NkK0xUU1hLSzJmc1VHTjhHVk43?= =?utf-8?B?M21PcTA4QnVoOGl2czQxUWtpMXNOR0swSUI0YmUyejg4QzNyRDhRYXVsL3JU?= =?utf-8?B?MjVVNG9wL0VSNjhTT1R0dlRQU2IxZDdqY1p3UXBLOTRBa2NGSFBaaTVxb3l5?= =?utf-8?B?cVUzZkxzZFZSZXdCcVRSd3QyenIwdklYcVozbnpUNENjQVJGSmNqZEZNeTd6?= =?utf-8?B?ajViSUxYQVRIZERFVmZJRUZxWjFEOWEzc2h4cTIxaUxwVDN3R2U1N0FtWE1E?= =?utf-8?B?NDJ1aWd5OHV3N0x4b1MzRmJLbkZuN0lVT1N4dFoyWVkxQURrSUVCL1B5VFJE?= =?utf-8?B?bWV5aWN0UTFSRU9JaStJNjNkN2o4TFlpeFFDU3VqakpjUlhncVpFbENFYUU1?= =?utf-8?B?ODcxMVlVYlFFMGxZOHNSaFFYMWVEL2liWFFndGFjNUhmTGFVdmNJVzRIU2pQ?= =?utf-8?B?TE0xeDVRRDRseWdGWDAyVXVWd0FCOEFvSnhadWV4V2I5T21UbVljR2tRREla?= =?utf-8?B?UFZFanQyNG1Zbms1QVBtdTNRa0NTNStoUjREVGRmbFRtKzRFS0hBME1TTFow?= =?utf-8?B?UVdBNlBpY3NZOWUzZWN4bWpmR3ZDQWVQd3Q3QWw2QnhkRHVXOUNqblZlL2ZK?= =?utf-8?B?dUV5bnhpV0pnbHkrNDlpWUQyUVo5OHpqL2VxNEd2cDE4SzR6WUJyTzQ5V004?= =?utf-8?B?cTZKZHpGVkFadTRjdjZvWmVTTHcvRlppUVVudTc0Tmh3cGVpQUJjYjV3VzEz?= =?utf-8?B?MGU1M2xDVDBjdFlBb2JCMDVzUUtocHpsWm1pTTJjOWw4MlhTazRrSmlkUVhH?= =?utf-8?B?VWR5ZGZJQ1FJbVNEQ1U5TEFucXpkV2EwU3A3LzRxOE9ESGZyTlRQS0lIazFF?= =?utf-8?B?dEJGcGpqY29DREhIem1OL0hjdm9HUDU0U1NsOHNmUzFxNTlqcEVvL216Ylpo?= =?utf-8?B?Y2pIdVkvV2JFWVRkVHJQTE1OUkV3Nzc0amhGZTVqYlZvaWY3QnVXUUc1ZlZL?= =?utf-8?B?V2JRWXJ6R1FSRWU1aWdLdlFSK3M5QzdsWW4rVklmdk9zVlhVYm94NVBoZUYx?= =?utf-8?B?b1hNMW02Sm16cEo3d0tpU1R4VHE1dGZuZWFjR3hJME5QSWFvNm55ZkdjZ0I2?= =?utf-8?B?aVBmTXVtOWk4TjNUdHZxZHRmTXVpQnd0bnBWK1N3cDFaYXgycVlKUHlHL2FD?= =?utf-8?B?QTlHYUsrZUd6OTcvTVRFeVAvMVZIdjliL2hEbllNTnFCR3hLNEZQbUQxbmhP?= =?utf-8?B?NVRWcitXSlBZK0ZNUmxYRkN3amNFN1pyd2Q5eUd2djM2R25leGRwdGRhWnho?= =?utf-8?B?cUprUlkyTSt4TnpnU1VTS0xlTENuNkRHeXFZMHBGd1JnZ1JTMDNNU2JiWCtj?= =?utf-8?B?MDBjczZkSmdPR1ByMmJ2Nzd6SEJiMHJydlo0OXE5bnpPZjB0ZzRQZGFWS2VG?= =?utf-8?B?WkhtZ3dWd2dWZ0tQVDBSbjhtR3lNS01oem4ydHVlQm1ocWZDMC9sU3d5Mmdp?= =?utf-8?B?TFlMSHEybVJicGRzU0hEYkZYUXFhZUUxeDFEdy9nNFNkMWY4dDVkQT09?= X-OriginatorOrg: garyguo.net X-MS-Exchange-CrossTenant-Network-Message-Id: 1fb4bdbf-e59b-41d6-0203-08dec5986932 X-MS-Exchange-CrossTenant-AuthSource: LOVP265MB8871.GBRP265.PROD.OUTLOOK.COM X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 08 Jun 2026 19:59:12.4458 (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: E98Po6IOkGFUB7V+UUnQO1IjaiGuTydB+hXgcDTF+gqCvekwq59u+s9pTRvi0/cVqd/i0oV0v01dOKiDsOt+Eg== X-MS-Exchange-Transport-CrossTenantHeadersStamped: LO8P265MB7398 `Io` trait now has a single required methods with many more provided methods. Provided methods may want to rely on their implementations to not be arbitrarily overridden by implementers for correctness or soundness. Thus, extract these methods to a new trait and provide a blanket implementation. This pattern is used extensively in userspace Rust libraries e.g. `tokio` where `AsyncRead` has minimum methods and `AsyncReadExt` is what users mostly interact with. To avoid changing all user imports, the base trait is renamed to `IoBase` and the newly added trait takes the existing `Io` name. A `size` method is added as an example of methods that users should not override. Suggested-by: Danilo Krummrich Signed-off-by: Gary Guo --- rust/kernel/devres.rs | 3 ++- rust/kernel/io.rs | 34 ++++++++++++++++++++++++---------- rust/kernel/io/mem.rs | 6 +++--- rust/kernel/pci/io.rs | 6 +++--- 4 files changed, 32 insertions(+), 17 deletions(-) diff --git a/rust/kernel/devres.rs b/rust/kernel/devres.rs index 3545ffc5345d..6e0b845b229b 100644 --- a/rust/kernel/devres.rs +++ b/rust/kernel/devres.rs @@ -68,6 +68,7 @@ struct Inner { /// devres::Devres, /// io::{ /// Io, +/// IoBase, /// Mmio, /// MmioRaw, /// MmioBackend, @@ -105,7 +106,7 @@ struct Inner { /// } /// } /// -/// impl<'a, const SIZE: usize> Io<'a> for &'a IoMem { +/// impl<'a, const SIZE: usize> IoBase<'a> for &'a IoMem { /// type Backend =3D MmioBackend; /// type Target =3D Region; /// diff --git a/rust/kernel/io.rs b/rust/kernel/io.rs index 8b3a64188b48..9c2ea17ca87b 100644 --- a/rust/kernel/io.rs +++ b/rust/kernel/io.rs @@ -186,7 +186,7 @@ const fn offset_valid(base: usize, offset: usize, si= ze: usize) -> bool { /// operation. pub trait IoBackend { /// View type for this I/O backend. - type View<'a, T: ?Sized + KnownSize>: Io<'a, Backend =3D Self, Target = =3D T>; + type View<'a, T: ?Sized + KnownSize>: IoBase<'a, Backend =3D Self, Tar= get =3D T>; =20 /// Convert a `view` to a raw pointer for projection. fn as_ptr<'a, T: ?Sized + KnownSize>(view: Self::View<'a, T>) -> *mut = T; @@ -269,13 +269,10 @@ fn offset(self) -> usize { /// Types implementing this trait (e.g. MMIO BARs or PCI config regions) /// can perform I/O operations on regions of memory. /// -/// The [`Io`] trait provides: -/// - Method to convert into [`IoBackend::View`]. -/// - Helper methods for offset validation and address calculation -/// - Fallible (runtime checked) accessors for different data widths -/// -/// Which I/O methods are available depends on the associated [`IoBackend`= ] implementation. -pub trait Io<'a>: Copy { +/// This trait defines which backend shall be used for I/O operations and = provides a method to +/// convert into [`IoBackend::View`]. Users should use the [`Io`] trait wh= ich provides the actual +/// methods to perform I/O operations. +pub trait IoBase<'a>: Copy { /// Type that defines all I/O operations. type Backend: IoBackend; =20 @@ -284,6 +281,21 @@ pub trait Io<'a>: Copy { =20 /// Return a view that covers the full region. fn as_view(self) -> ::View<'a, Self::Targe= t>; +} + +/// Extension trait to provide I/O operation methods to types that impleme= nt [`IoBase`]. +/// +/// This trait provides: +/// - Helper methods for offset validation and address calculation +/// - Fallible (runtime checked) accessors for different data widths +/// +/// Which I/O methods are available depends on the associated [`IoBackend`= ] implementation. +pub trait Io<'a>: IoBase<'a> { + /// Returns the size of this I/O region. + #[inline] + fn size(self) -> usize { + KnownSize::size(Self::Backend::as_ptr(self.as_view())) + } =20 /// Returns a view for a given `offset`, performing compile-time bound= checks. // Always inline to optimize out error path of `build_assert`. @@ -771,6 +783,8 @@ fn update(self, location: L, f: F) } } =20 +impl<'a, T: IoBase<'a>> Io<'a> for T {} + /// A view of memory-mapped I/O region. /// /// # Invariant @@ -811,7 +825,7 @@ unsafe impl Send for Mmio<'_, T> {} // SAFETY: `Mmio<'_, T>` is conceptually `&T` but in I/O memory. unsafe impl Sync for Mmio<'_, T> {} =20 -impl<'a, T: ?Sized + KnownSize> Io<'a> for Mmio<'a, T> { +impl<'a, T: ?Sized + KnownSize> IoBase<'a> for Mmio<'a, T> { type Backend =3D MmioBackend; type Target =3D T; =20 @@ -921,7 +935,7 @@ unsafe fn project_view<'a, T: ?Sized + KnownSize, U: ?S= ized + KnownSize>( } } =20 -impl<'a, T: ?Sized + KnownSize> Io<'a> for RelaxedMmio<'a, T> { +impl<'a, T: ?Sized + KnownSize> IoBase<'a> for RelaxedMmio<'a, T> { type Backend =3D RelaxedMmioBackend; type Target =3D T; =20 diff --git a/rust/kernel/io/mem.rs b/rust/kernel/io/mem.rs index d9b3189d09b4..e95b769ebe47 100644 --- a/rust/kernel/io/mem.rs +++ b/rust/kernel/io/mem.rs @@ -14,7 +14,7 @@ Region, Resource, // }, - Io, + IoBase, Mmio, MmioBackend, MmioRaw, // @@ -210,7 +210,7 @@ pub fn into_devres(self) -> Result>> { } } =20 -impl<'a, const SIZE: usize> Io<'a> for &'a ExclusiveIoMem<'_, SIZE> { +impl<'a, const SIZE: usize> IoBase<'a> for &'a ExclusiveIoMem<'_, SIZE> { type Backend =3D MmioBackend; type Target =3D super::Region; =20 @@ -292,7 +292,7 @@ fn drop(&mut self) { } } =20 -impl<'a, const SIZE: usize> Io<'a> for &'a IoMem<'_, SIZE> { +impl<'a, const SIZE: usize> IoBase<'a> for &'a IoMem<'_, SIZE> { type Backend =3D MmioBackend; type Target =3D super::Region; =20 diff --git a/rust/kernel/pci/io.rs b/rust/kernel/pci/io.rs index cd921cbba164..0d4e87b00b71 100644 --- a/rust/kernel/pci/io.rs +++ b/rust/kernel/pci/io.rs @@ -8,8 +8,8 @@ device, devres::Devres, io::{ - Io, IoBackend, + IoBase, IoCapable, Mmio, MmioBackend, @@ -138,7 +138,7 @@ fn io_write(view: ConfigSpace<'_, $ty>, value: $ty) { impl_config_space_io_capable!(u16, pci_read_config_word, pci_write_config_= word); impl_config_space_io_capable!(u32, pci_read_config_dword, pci_write_config= _dword); =20 -impl<'a, T: ?Sized + KnownSize> Io<'a> for ConfigSpace<'a, T> { +impl<'a, T: ?Sized + KnownSize> IoBase<'a> for ConfigSpace<'a, T> { type Backend =3D ConfigSpaceBackend; type Target =3D T; =20 @@ -261,7 +261,7 @@ fn drop(&mut self) { } } =20 -impl<'a, const SIZE: usize> Io<'a> for &'a Bar<'_, SIZE> { +impl<'a, const SIZE: usize> IoBase<'a> for &'a Bar<'_, SIZE> { type Backend =3D MmioBackend; type Target =3D crate::io::Region; =20 --=20 2.54.0 From nobody Thu Jun 25 00:35:31 2026 Received: from LO3P265CU004.outbound.protection.outlook.com (mail-uksouthazon11020080.outbound.protection.outlook.com [52.101.196.80]) (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 EECD73F1658; Mon, 8 Jun 2026 19:59:29 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=52.101.196.80 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780948774; cv=fail; b=puISLc23DD1GBQ/3jK4GC7ZVsTyS50adyXJGwciHAEHk1PCx5vVz2ha9sKefCi+N8vTGhsl/0aZcNVQZKjqfwAU82ChTRdK/rnVuyBGTJPpqYHqb3msARYOU/GsPpb+mVo4JmybeXzy5vWP5GmbWf6mnDha44mz8i1C+63C51i0= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780948774; c=relaxed/simple; bh=BBwKMm17IeGIaVGQr0hPKvwXhlHdIsUV/DwitqNy3e0=; h=From:Date:Subject:Content-Type:Message-Id:References:In-Reply-To: To:Cc:MIME-Version; b=g+VybHXC8Tsdbewg3wT7TBauVzP8Liowwv08LAOnhFK99q7cWigji842vTpIoK4uSaXvm7Y6K0pdyNj1oEFydlfyryAVckR81fKDKkMe5U4B4HkWO/naHopsJ/4pA8FBd06O6LQ9hOQqF6JMD8vYNpyMP6C5RAHvAZWJLBkrjuQ= 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=jtbD8i72; arc=fail smtp.client-ip=52.101.196.80 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="jtbD8i72" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=VJMDaR0KP3Sus9P6IX3+ZrHQsDduz+hm8Eni/CiNFi8go6HQXWLXViQobY4ajY1I3qZSfMAH5B65biDAQBe/BUm0/Su3Gh498K+Li0iwar7i46yQDphEnQxML8+rQUcU3nK1FHDiymrH5y7OpC0CIbCgwqFUxfE0DW7QhbM6EfHch+02hP17JkDHkjRPuJls4mAsPdFtDk62nCphVy484ljD3JRdDuO0g8ECc6Fx0WhI8R5gy2XcimOyxdswpI6NorPQyZhhCtT/9Nn793X6COUZ7lOICT0mvCD0Drg95/yGMCUaIjFP8DbTFFTV9iZVpg+MBBYrhPH9L8uQ3ZLBSg== 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=2SyRkf5bGgPUNu0KLGOX4k+Q9xt5K6NM7mKy99GC+5k=; b=eD8FvnQQFmiy71LF48AqHYe1lQIoN/ZvUxCIA2glQvFHjri7p31twu2W/rohrWCQZvlOImqXMBlTpsEKe//4baOZFJkU7Fu7ftUkdIWQTacay4z26esc9HyJsPvD5e+I/PHeOTMfzlH8Dp0IGSGWGvELm7nNJi43MlhxMAGKH0AMIR+/LltluppR8n+XpQEVNEmCABppXpi6IDGK2mw3Xy23LBEahwQuMl7NPrRKOBjf6ELR+GLCPKj4PgR0Bjqqj5ptjrRuokwpzISq7j1ICUDtYHGCe+5PX7uZOpsPkPUhi7q2wIavqdO2XFbCI93m3KBQb9Zak/LQGpeCJmzWHA== 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=2SyRkf5bGgPUNu0KLGOX4k+Q9xt5K6NM7mKy99GC+5k=; b=jtbD8i72AZ/ulmpvLY2BIIiw0Z40RxnsMipSvnwKZeN4lM4iOcPpT/qBwzF1zwnitA5ecDvXRqwOyMeKhsLQvNN1/WmP5CxaLiuAiHu9fWRctdIdgB5ZMb7Z50YtCoIPzqwUmUcb4+e7ny6rgfzZUxiRpTBwvo1DhzMSNklDnC4= Authentication-Results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=garyguo.net; Received: from LOVP265MB8871.GBRP265.PROD.OUTLOOK.COM (2603:10a6:600:488::16) by LO8P265MB7398.GBRP265.PROD.OUTLOOK.COM (2603:10a6:600:3ca::5) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.21.92.12; Mon, 8 Jun 2026 19:59:12 +0000 Received: from LOVP265MB8871.GBRP265.PROD.OUTLOOK.COM ([fe80::1c3:ceba:21b4:9986]) by LOVP265MB8871.GBRP265.PROD.OUTLOOK.COM ([fe80::1c3:ceba:21b4:9986%4]) with mapi id 15.21.0092.011; Mon, 8 Jun 2026 19:59:12 +0000 From: Gary Guo Date: Mon, 08 Jun 2026 20:59:09 +0100 Subject: [PATCH v3 12/19] rust: io: add projection macro and methods Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260608-io_projection-v3-12-c5cde13a5ec4@garyguo.net> References: <20260608-io_projection-v3-0-c5cde13a5ec4@garyguo.net> In-Reply-To: <20260608-io_projection-v3-0-c5cde13a5ec4@garyguo.net> To: Danilo Krummrich , Alice Ryhl , Daniel Almeida , Greg Kroah-Hartman , "Rafael J. Wysocki" , Miguel Ojeda , Boqun Feng , Gary Guo , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Andreas Hindborg , Trevor Gross , Bjorn Helgaas , =?utf-8?q?Krzysztof_Wilczy=C5=84ski?= , Abdiel Janulgue , Robin Murphy , Alexandre Courbot , David Airlie , Simona Vetter Cc: driver-core@lists.linux.dev, rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, linux-pci@vger.kernel.org, nova-gpu@lists.linux.dev, dri-devel@lists.freedesktop.org X-Mailer: b4 0.15.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1780948747; l=5924; i=gary@garyguo.net; s=20221204; h=from:subject:message-id; bh=BBwKMm17IeGIaVGQr0hPKvwXhlHdIsUV/DwitqNy3e0=; b=lCk+4unqi+baHmzzweBh/dNSAyE65Rz7YrGYT13/6/LSGKTvuDmrnVhTsAdVBa5VbdPV9pqee oB+aWEENS29Bbfa79/wXHQ2lzPJKpyo8lcvliW2rruTlN5Jkrmyp9vM X-Developer-Key: i=gary@garyguo.net; a=ed25519; pk=vB3uIX95SM4eVrIqo1DWNWKDKD2xzB+yLLLr0yOPYMo= X-ClientProxiedBy: LO4P123CA0344.GBRP123.PROD.OUTLOOK.COM (2603:10a6:600:18d::7) To LOVP265MB8871.GBRP265.PROD.OUTLOOK.COM (2603:10a6:600:488::16) 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: LOVP265MB8871:EE_|LO8P265MB7398:EE_ X-MS-Office365-Filtering-Correlation-Id: 8bca0864-c199-4a08-f363-08dec598696c X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|1800799024|7416014|376014|366016|10070799003|6133799003|22082099003|18002099003|921020|56012099006|5023799004; X-Microsoft-Antispam-Message-Info: 6+4ovOPyJWB//g8ERHMYceAI+AM9K/sZhP3KTUSAB9QE8zOJu5lC7H2SywPssOmb4xXCLgLKu9JKEB9Fwggxq4uodfUQH0o3o32nyhe11ITQ4dLOp88DHsl2ahrqRFxEp4L+Tj+QijaEVltKySDG3BK4qMadssdhe2wpbUH/qF4KwM/0oxCbPf18+/nyuFrX+kB5K7ZrUx41fHSL/E8chxMFD6cIL6gz4TKw+Zzw/JspBLRgAQbTHLgnJw/nL9dBS8RzNZEZC7N5t05YC92Y5vdFV3Cn4m7jcabo7otrKiBvaa/ZA1qSQbNCq5NfboucdhrjvyH82ctAGifLZF8ARmRI+i1GSDFhlXt9PFFNicFE8vpTACRan5KNED5prT6ezQuAzqBxmA+QKRC7OBCCtcLmUThcth8Q6EcO+78/jNIFcpLfTF7SBB0BdM0lvxbWQ1+TZ1B2RXhOrVBYLcFolAGG4yl2wilgVdXhbx3j4BMhH5zumNlW9kEwVGcDOu2QJfcPEoPdoo2YPmyZ9VIS8asg3YlyM44MtbVqXGEXNTxXr3c768363Q0RyB02tT5aQAq1+JLtNGZs5H7gt8mHdXv03smmbjZ3+FBtecElk96/uv5AAmMVJiQvjkNRnnB8gMJ7zk+HHNEeTynT0ozClxpA4rWoaU86BBW48jr1kEWoPszlqgRkz4sQvf+ZqcwR5X3d82/xpl2au82mpnwVqncJRMdOvxN69C7/pWNj3hc= X-Forefront-Antispam-Report: CIP:255.255.255.255;CTRY:;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:LOVP265MB8871.GBRP265.PROD.OUTLOOK.COM;PTR:;CAT:NONE;SFS:(13230040)(1800799024)(7416014)(376014)(366016)(10070799003)(6133799003)(22082099003)(18002099003)(921020)(56012099006)(5023799004);DIR:OUT;SFP:1102; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: =?utf-8?B?b0o4K1p4TU9BZ3VmVHk1b0JTcFdaeDlOamtKam1DdEdtUFZvM2xCMDJnUFp2?= =?utf-8?B?ODlhbkVYWEVvRUp6bVVhdm9hZCtNczlxRTIycnBwUjFYcXFEdVhwVE83QUtZ?= =?utf-8?B?RTEvazlJSjhQNzUwbC9OL083eTQ0UmIxT3JuRzYraXdFT1Rsc2ZSckk2cDdO?= =?utf-8?B?TXFqYi94dllsdEdGWkk0dVVEV2JxSWUwVE5EdVU2MjhVVTZ2dE1xeUQzYzMz?= =?utf-8?B?NWc0OEpYL1ZpTFdKdWw0bnJPZkZOMlNGMThsTU9LMFFLMFlNWFI5TmVtUG5Z?= =?utf-8?B?OWVGOVg2SCt6NGdnaG14VW5iSHJVd3VFOU1MMGVWT3VJYkdZNFlSVjlNeFFJ?= =?utf-8?B?dDJzUWxwRE5yeGJBS2pHbmRVSEtwenQwT3pUM0Q2T1RyODNGeEpVS0N6emFF?= =?utf-8?B?REJsbkhZZFd1VEVGdEhXeDRTQ0ZUSUgvUW9oYlVaYlBmVzZXS2d4Z3N2SHBy?= =?utf-8?B?aldzcWU0azUvdGhhNjZSdkRsckJqa1g2eHpnZS9XMWVIdUZ5WHA1NlgxT3dR?= =?utf-8?B?bE9EWXVldGZvY2tVaDdRZjlENlpEbnpXS29jemx3RGtzL01hV2MyTjJLQXZF?= =?utf-8?B?eVk3MllZQ0xhbE01L2trNm9NTW9QZFVWRllQVTJiQnoxMnRiSjBJclNReXVw?= =?utf-8?B?aklhRXliMWloODBCS2YrQUVNVWJHeUE0OEdvY29yNDh4Q2UwK0swT1ZJQmVq?= =?utf-8?B?ZUcvR0hCck93MHJiMVlsMTZWb0tZaGJQUldWOHJ6UXpPVnRRNkdyZllkVkRs?= =?utf-8?B?ZmZmY20rTGQzVVhTSm1OZW93YWx2ekVsbnBzRUd6KzNzRTlTRVRQMWZnK1dE?= =?utf-8?B?bzlPaHRPbDdmbjhRNTl5cU5IRFBvTGpSMStxRnd2MUh2bVlWK25wdGFldEZj?= =?utf-8?B?ZGhoNURvbGlzWVhOdllGSGJWRElpaWN1RWZocDBIZmpwSlR5SERmNFVLMzQr?= =?utf-8?B?WHdZbWkra3ZTQXhmSm03VWZRNTZ0b2sxTGR4MjJoS0FGd1RFR20xMmNhd2Zl?= =?utf-8?B?clVwRmdpQXU4d3BzL0k2d04raTZkTGdKUFhSNStFcFEyRHNOWk1HMU5Kck1n?= =?utf-8?B?WVBvVkdIQURqZXo4RDAvV2NQVEliWGRLbkZpL2xRQmdweTJIak1WZk10Sys1?= =?utf-8?B?UWM2KzE2THpuampCclAwMlZQSjZmMDhHTmZBVDFDcURkTkVTalZyUXJTb0dt?= =?utf-8?B?Uy9xNkkzSFpvZVFNUi9VQS9IajdKL1NPbVVjK093bXJJSGRxaW5NUjlZaTNW?= =?utf-8?B?TU4wM1lFWUROSGVLT1BtOXRRQXFzd3Rya21ualR4UDZlbmxSeTc5cHA5WmRi?= =?utf-8?B?U09keEpvNUtLRTBUSWp4R1hrbzFFNDNyWHMzSDZ1bkF4RTNXWElxdVkxNlk3?= =?utf-8?B?VERhTVE0WVpiTzVhN052MURQU0F3OGFZWWRQQjNiTFJkMHhmMGtOUTBXK2N5?= =?utf-8?B?QzNYWkVMbnZIQm1WMytpVEdod3pDVHlTdFJMSG1QZUVaSmxEcktVRjFtNFJ3?= =?utf-8?B?T3lNSzhwN1JyQ2MrSW1kNEc1T2hNbjdrTWErUlhTQ1FYRjhrRnBQa3BZdEd4?= =?utf-8?B?enVPYmlZRXU0WnUyeUpUT3psVlAzMjUzZGxYVzMyeUU3YUdrL0trbXVlQ0d1?= =?utf-8?B?Q2U2RFJ4OVdyRmJiTWNETXFwcTc1bENEQmZsRFpoNEpEaUxKVVNYZTdhcHFZ?= =?utf-8?B?aUFpWlptalRobFcyampWdjZQanlxL2dUUlJKbkRwMU5VTW9SV2U2UDhkc3Rk?= =?utf-8?B?NCt1WlhMcUwwYVNGTFd3SjFIZjdZNkl1ZWczYmxHVlJndDhhNWZ0SzFER2cx?= =?utf-8?B?UDNiSVpOUmVNQXR3YWQxTGF4bXJ5eUdKOWJYTXFwYnhDNGZoaWd5M2R4M3pv?= =?utf-8?B?Z3hzNVAxK0tyMzBiOWs3enQrOTdEMXBvL0dacWhvdkwzM1poaWlpYUQrN0xW?= =?utf-8?B?bGtvejRCMGRmd3RTNSs4anNpUXFvcUsxYnlvSVhKN1pIZldrYVErZE1jV1hF?= =?utf-8?B?TnA0aXJ1L3c4VGlEUitWNUJwR2Y4QWY1cjZTKzV3Tnp0c1d4T1RhNmY5MGNa?= =?utf-8?B?NnRHOGlzOFhIaVFXbW9MRFhmK3NSdjNESXpmL3VVMjdvYWI1NlBJZXVybndL?= =?utf-8?B?UG9jUHIzaVFUSk1lMnNqTEZnTUc2L1AvSzk3MjBsV1N0SHZucjlqL3c1SWRX?= =?utf-8?B?UjV5ZEFBSTZ4VHlCNFlOd2wrQjFqcUNoOFFWbEtxWjYxWVNpSlFQVjBwR25B?= =?utf-8?B?a2ZZWS9tZk5HbHlwWE41d3EvcmUvUlc0WFpIREtOTGdjRU5leEpXQWt0aTU3?= =?utf-8?B?c1lhcm5sdHhPYXI5R2pGNDlGVFhzQm5mMkduWkpqbmxHWEIyYmxhUT09?= X-OriginatorOrg: garyguo.net X-MS-Exchange-CrossTenant-Network-Message-Id: 8bca0864-c199-4a08-f363-08dec598696c X-MS-Exchange-CrossTenant-AuthSource: LOVP265MB8871.GBRP265.PROD.OUTLOOK.COM X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 08 Jun 2026 19:59:12.8292 (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: EeK4EOKfcT9ctFu+TbUV5BfHJmiKufCAzxGkgclJGsTLXFBGSHnC8E+AcGf6aiy+OsXClu02Tq3vCEnHnZcjFg== X-MS-Exchange-Transport-CrossTenantHeadersStamped: LO8P265MB7398 Add a `io_project!()` macro allows projection from `Io` to a subview of it, using the pointer projection mechanism to perform compile-time checks. For cases where type-casting is required, the `try_cast()` function may be used where the size and alignment checks are performed at runtime. Signed-off-by: Gary Guo Suggested-by: Danilo Krummrich --- rust/kernel/io.rs | 131 ++++++++++++++++++++++++++++++++++++++++++++++++++= ++++ 1 file changed, 131 insertions(+) diff --git a/rust/kernel/io.rs b/rust/kernel/io.rs index 9c2ea17ca87b..173f8c0ba2d6 100644 --- a/rust/kernel/io.rs +++ b/rust/kernel/io.rs @@ -14,6 +14,10 @@ ptr::{ Alignment, KnownSize, // + }, + transmute::{ + AsBytes, + FromBytes, // }, // }; =20 @@ -92,6 +96,11 @@ fn size(p: *const Self) -> usize { } } =20 +// SAFETY: I/O regions can compose of arbitrary bytes. +unsafe impl kernel::transmute::FromBytes for Region {} +// SAFETY: Values read from I/O are always treated as initialized. +unsafe impl kernel::transmute::AsBytes for Region= {} + /// Raw representation of an MMIO region. /// /// `MmioRaw` is equivalent to `T __iomem *` in C. @@ -297,6 +306,53 @@ fn size(self) -> usize { KnownSize::size(Self::Backend::as_ptr(self.as_view())) } =20 + /// Try to convert into a different typed I/O view. + /// + /// The target type must be of same or smaller size to current type, a= nd the current view must + /// be properly aligned for the target type. + /// + /// # Examples + /// + /// ```no_run + /// use kernel::io::{ + /// io_project, + /// Mmio, + /// Io, + /// Region, + /// }; + /// struct MyStruct { field: u32, } + /// + /// // SAFETY: All bit patterns are acceptable values for `MyStruct`. + /// unsafe impl kernel::transmute::FromBytes for MyStruct {}; + /// // SAFETY: Instances of `MyStruct` have no uninitialized portions. + /// unsafe impl kernel::transmute::AsBytes for MyStruct {}; + /// + /// # fn test(mmio: &Mmio<'_, Region>) -> Result { + /// // let mmio: Mmio; + /// let whole: Mmio<'_, MyStruct> =3D mmio.try_cast()?; + /// # Ok::<(), Error>(()) } + /// ``` + #[inline] + fn try_cast(self) -> Result<::View<'a, = U>> + where + Self::Target: FromBytes + AsBytes, + U: FromBytes + AsBytes, + { + let view =3D self.as_view(); + let ptr =3D Self::Backend::as_ptr(view); + + if size_of::() > KnownSize::size(ptr) { + return Err(EINVAL); + } + + if ptr.addr() % align_of::() !=3D 0 { + return Err(EINVAL); + } + + // SAFETY: We have checked bounds and alignment, so this is a vali= d projection. + Ok(unsafe { Self::Backend::project_view(view, ptr.cast()) }) + } + /// Returns a view for a given `offset`, performing compile-time bound= checks. // Always inline to optimize out error path of `build_assert`. #[inline(always)] @@ -983,3 +1039,78 @@ pub fn relaxed(self) -> RelaxedMmio<'a, T> { // MMIO regions on 64-bit systems also support 64-bit accesses. #[cfg(CONFIG_64BIT)] impl_mmio_io_capable!(RelaxedMmioBackend, u64, readq_relaxed, writeq_relax= ed); + +// This helper turns associated functions to methods so it can be invoked = in macro. +// Used by `io_project!()` only. +#[doc(hidden)] +#[derive(Clone, Copy)] +pub struct ProjectHelper(pub T); + +impl<'a, T> ProjectHelper +where + T: Io<'a, Backend: IoBackend =3D T>>, +{ + // These helper methods must not have symbols present in binary to avo= id confusion. + #[inline(always)] + pub fn as_ptr(self) -> *mut T::Target { + T::Backend::as_ptr(self.0) + } + + /// # Safety + /// + /// Same as `IoBackend::project_view` + #[inline(always)] + pub unsafe fn project_view( + self, + ptr: *mut U, + ) -> ::View<'a, U> { + // SAFETY: Per safety requirement. + unsafe { T::Backend::project_view::(self.0, ptr) } + } +} + +/// Project an I/O type to a subview of it. +/// +/// 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!). +/// +/// In addition to projecting from [`Io`], you may also project from a [`V= iew`] of an [`Io`]. +/// +/// # Examples +/// +/// ``` +/// use kernel::io::{ +/// io_project, +/// Mmio, +/// }; +/// struct MyStruct { field: u32, } +/// +/// // SAFETY: All bit patterns are acceptable values for `MyStruct`. +/// unsafe impl kernel::transmute::FromBytes for MyStruct {}; +/// // SAFETY: Instances of `MyStruct` have no uninitialized portions. +/// unsafe impl kernel::transmute::AsBytes for MyStruct {}; +/// +/// # 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); +/// # Ok::<(), Error>(()) } +/// ``` +#[macro_export] +#[doc(hidden)] +macro_rules! io_project { + ($io:expr, $($proj:tt)*) =3D> {{ + #[allow(unused)] + use $crate::io::IoBase as _; + let view =3D $crate::io::ProjectHelper($io.as_view()); + let ptr =3D $crate::ptr::project!( + mut view.as_ptr(), $($proj)* + ); + #[allow(unused_unsafe)] + // SAFETY: `ptr` is a projection. + unsafe { view.project_view(ptr) } + }}; +} +#[doc(inline)] +pub use crate::io_project; --=20 2.54.0 From nobody Thu Jun 25 00:35:31 2026 Received: from CWXP265CU008.outbound.protection.outlook.com (mail-ukwestazon11020099.outbound.protection.outlook.com [52.101.195.99]) (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 595FE3EE1D1; Mon, 8 Jun 2026 19:59:30 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=52.101.195.99 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780948774; cv=fail; b=TKhgzMrhgRlf9nFQgtix4q/WnSSG/e4UHcXfC8pxuQ45joKgMMT6neuVULQBew4FyocWVK1LSGpLvs9pOHKMZ9/ZknpcRoVTt9leJaWGB2ibnQo0LA+EtkwglZUcW3FNzPORHLUNODa7Q21MlFydGaZp2b/6Gl5GT7CWcuaDkcc= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780948774; c=relaxed/simple; bh=vcdMQc7L2X5q7MLzsjeBdjUYKsKn42hZ7KuZ3sc3al0=; h=From:Date:Subject:Content-Type:Message-Id:References:In-Reply-To: To:Cc:MIME-Version; b=GQ40QgIEiJlKR/oNTdQiS68VdO7YOwV6s6EuVunLAA+zLXH3mhu1onlmo2KEprs6YT2c4p16rgjSrxMHuyBZN7knCIrpAP4JdzgOqmu9xrt8Zo41yRhmuIMIOCzsRahK4FaAKxd4FmFhsLbPyY/Fwjc9D5MZywDXB+47PYJN3xs= 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=x3UsNviq; arc=fail smtp.client-ip=52.101.195.99 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="x3UsNviq" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=sNJtqD1/1/r0RMy2Xk1KVO2n99bQsYANthjNRPBnNE0k5wpCNLEPVdHerC9Sadk4NQpNGcqBMwS726mNxVObyyfqtk6Wzq6KMSxnUQgHSh2i1xhtKdjnJPf7B/McnCMJ+9p0Tt93qoKy4l4vLYXjL3dbrrzKQjBWl8QGdG54POxVWomgZyCueG9Rf7NqZUpbVYfzrFS2mTXIFgu+Wnylnk96VpsMlL+muLsRGdDF/Fyon02hGjf0yEIkbJcNEyplvt+UrPLL+TNZDEsIEUQPP0OGqjMTMm2wQEh7zVfnv2g296TvQsPCF4wzw7P/BOoxJiaTmxLVYaJhV97jCEF1xQ== 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=60pCk675gSeThQ+AfPYkQPgXU+UzSOf56AMAw7q5jX4=; b=U22NRLwjs+9fYjkynyVb4qQNiROGlLuWE982B05wjvAormyVn+Q1RzF93ZyMSkG/teCCO5U6OEUKQG45uuB1iRigr2OwB8c+nDa6x3juMKZp9qsKSTja/Zw8cx9MNCWJjt0u7h3dDyGXOZpUqG206SgcZUtv1qo0JBUfI9ZX86DN436B2R+Hbm0DhP/l5xsznmxKDtlajDb7thfqlN9xyJJK2Nlh+rmRtcsPVqNeCyEbDW/sGlOr48gT9l8vADOPN6BAnpY44xt9B5eQ77K26vCcHIFb/MttxYRbfmcy/v+IIeoyhOJMkRXAgPTtACozPRWnxbJRrpAG3cSCAPqYLQ== 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=60pCk675gSeThQ+AfPYkQPgXU+UzSOf56AMAw7q5jX4=; b=x3UsNviqzyTPkZw1VaL1tsESGOm2dWaochFGI3bmy69igCmULrNhURq74uK7sxsQN1yADa79jvnNEMWmW/f5v7qhz3NGkQNYH2u1BAaN0eP4xbMENAGesv5XFlb4VA151DDmtRiXpTD+c/8uqNYtE4HuMgQrMoD9oRAsE3aU++8= Authentication-Results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=garyguo.net; Received: from LOVP265MB8871.GBRP265.PROD.OUTLOOK.COM (2603:10a6:600:488::16) by LO8P265MB7398.GBRP265.PROD.OUTLOOK.COM (2603:10a6:600:3ca::5) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.21.92.12; Mon, 8 Jun 2026 19:59:13 +0000 Received: from LOVP265MB8871.GBRP265.PROD.OUTLOOK.COM ([fe80::1c3:ceba:21b4:9986]) by LOVP265MB8871.GBRP265.PROD.OUTLOOK.COM ([fe80::1c3:ceba:21b4:9986%4]) with mapi id 15.21.0092.011; Mon, 8 Jun 2026 19:59:13 +0000 From: Gary Guo Date: Mon, 08 Jun 2026 20:59:10 +0100 Subject: [PATCH v3 13/19] rust: io: add I/O backend for system memory with volatile access Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260608-io_projection-v3-13-c5cde13a5ec4@garyguo.net> References: <20260608-io_projection-v3-0-c5cde13a5ec4@garyguo.net> In-Reply-To: <20260608-io_projection-v3-0-c5cde13a5ec4@garyguo.net> To: Danilo Krummrich , Alice Ryhl , Daniel Almeida , Greg Kroah-Hartman , "Rafael J. Wysocki" , Miguel Ojeda , Boqun Feng , Gary Guo , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Andreas Hindborg , Trevor Gross , Bjorn Helgaas , =?utf-8?q?Krzysztof_Wilczy=C5=84ski?= , Abdiel Janulgue , Robin Murphy , Alexandre Courbot , David Airlie , Simona Vetter Cc: driver-core@lists.linux.dev, rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, linux-pci@vger.kernel.org, nova-gpu@lists.linux.dev, dri-devel@lists.freedesktop.org, Laura Nao X-Mailer: b4 0.15.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1780948747; l=4994; i=gary@garyguo.net; s=20221204; h=from:subject:message-id; bh=9tXIYsADs8wwgk9tZU6LAmTg0OnAqj70/WkBdSauC6E=; b=Pizf4d1BKQIL+ItdyguqRWkUG2+FpQ59YDsHmPTOqFM/j2agWf9CsR6VLP/ej+ClTBbYDdTY4 zJGMBft+ZLlAGpUWgkpLp5S9CfeaV+QP2s2h/WnLnt5ZXHkjEAjdJxX X-Developer-Key: i=gary@garyguo.net; a=ed25519; pk=vB3uIX95SM4eVrIqo1DWNWKDKD2xzB+yLLLr0yOPYMo= X-ClientProxiedBy: LO4P123CA0344.GBRP123.PROD.OUTLOOK.COM (2603:10a6:600:18d::7) To LOVP265MB8871.GBRP265.PROD.OUTLOOK.COM (2603:10a6:600:488::16) 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: LOVP265MB8871:EE_|LO8P265MB7398:EE_ X-MS-Office365-Filtering-Correlation-Id: af7b434e-9c57-42be-2ffa-08dec59869a8 X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|1800799024|7416014|376014|366016|10070799003|6133799003|22082099003|18002099003|921020|56012099006|5023799004; X-Microsoft-Antispam-Message-Info: Xq/2kDgZXFAZZm3TuyrnLAGCmfqwX5ntx7JUrER58klqv2ptczIz1pMREpF0bUegaaPxSJffWCBAcRGoHXiNAw4+LSDbZyYaUi79scrR2SwCMdmDodFyNj4m6bZZ9mlOu1Rp0FyNSO4KMJiYKzmmYl1LlzFRvOojCQZGTQSTrLUcSi0a6pLcRkJUcc9/b61HNDp3jKvkFZVdXnx1OZCTXaXDav98pE6qTd3OBo5Qhvn4VLgvML+vmfdInSrptZJlo9CpfAoz97JyZ6UWHqDn3A5hA31qAxw052dl1k/eK9JEwJ/i0/lTQNFuyQw9vcp+79SHtL61ojPHhfVqjq+Ps2GfyqcVbG9W+KlAfbnhzZV7nJfyit5YhVCWJn0bwi2JX0+I0OzWABrpS0ba0mOlhBCqsucIQNALJktuTL/mKrxCM4yXnwaPl1RQO4hsvbVfeY4z7oq+jDGvcBF4NxTdB0G2v/78LhdF6uAO59aOsaXJO+fG23Bo70IRvxTcPpiJGi3plpdTKOMgHvO3FbQJ7VevYnrUGRB6wA3KYXQ3tBPn7HW5G9CQBRi99fL5T785kkbvd3ILq8xlsRiqygUYjieH4PtSdGsByg8SgatvaOBiZYkXSfYZo/sT0bWqbOGC/WTIcF1apt0zTbFOZyDuAMcrNrFFM6v25GgkfABrX9V3sHGljyAg4pRGOfBw2dGSN9aneH3f+7/9XlV7JnJFR8LAyskXz0SC5x7G49NaaAI= X-Forefront-Antispam-Report: CIP:255.255.255.255;CTRY:;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:LOVP265MB8871.GBRP265.PROD.OUTLOOK.COM;PTR:;CAT:NONE;SFS:(13230040)(1800799024)(7416014)(376014)(366016)(10070799003)(6133799003)(22082099003)(18002099003)(921020)(56012099006)(5023799004);DIR:OUT;SFP:1102; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: =?utf-8?B?VjBKMHN1dnMzN3NwVzY1TTU2dzBMMGlYQlFLMityVWRxYlB1a05nb001Uk5Y?= =?utf-8?B?cENINGUwL016cEw1Syt3Z0NoTXZ0VmxuMHlvenNyeTc4bG45eXZzN2NyWm40?= =?utf-8?B?NzA3VDZ3ZGZGOVNwUVJNWXk2WC9YSkhpeWlDbDN0bkNHV2JFWEZITXVpS2dX?= =?utf-8?B?dzQvZzVtYzE0dGViUFI2LzBpbTUrQnhpWVVma3hNNUhRMVZRR3pDRHBwVVBX?= =?utf-8?B?dDRJWGxJTjdKWVVUUnJUSGREekFLSVRiUzRBOFlRVDFOTTRuNXJEUGd2MGx1?= =?utf-8?B?dWxTMTVZQVJtb0RjTnZDSndLbmp1Vzhtd2F1RHNnRUkwSlpkbmNsSkh4L1I5?= =?utf-8?B?UnJySXBFbHc0cGF2NzVWK0FuYWRNaVNRZWFYcE5iL1JxU0gvYlUwTzMvejRY?= =?utf-8?B?S3k3Ny9JZWFZVE1XbEsrWWVBbWRGcTcxTCtSVHZ1cXdObzRiMjNhNFJ2OTlk?= =?utf-8?B?T2E2TGZBUGFiYVYzcHpXZEZ5SmgxTjZCYVlQMmdkMDF3eDNnUnQvNGgyeHc3?= =?utf-8?B?QUhCQUtzeDdXZnhFNEF2S05PUkZoL2tOWWt5UjJSdUh2bmNkb1kxRjBIemlE?= =?utf-8?B?ZUltVndWM2tqTTFYd3hvRnNhUlArVnFJdzE5WURQbUtOQW43UDZDWlJaNXB4?= =?utf-8?B?aXFpQ0szMWszQ1crWVI0YlFTblg1OFhCK2VLVWlMWW51cUFocWtiTEQzSU9U?= =?utf-8?B?ME5tTzlnN1VvQmdvMEFCbjNwdXU1ZFFaL0NXdnhEQWNMS2Y5YjRRVWdzTm93?= =?utf-8?B?TFlPemFVdko3bkprOEl6aWE3cDdkcGNRVnpxV0VvWWg0bk10QUhMZHJROU5q?= =?utf-8?B?b1BsN3I3L0tUNDR5YUY3Z0ZNckZZUURWQ2kzY2sycW9hTWljaisrTnZmQWNB?= =?utf-8?B?YzNvbW5WZWNDWmpCbitYa1JEaVdJZWxBMnpRM2FJMHpLQWdGS1lnbWpvMHhL?= =?utf-8?B?SWlnTmZLNmUzS0VWNG56NW1IZVlRK0FreHExQUdzZnorenc4OHZNd0RGUjZG?= =?utf-8?B?UGkzeUV2bmkrMWFmNVY0TWtiSHR3Z1lydGc2bU5TcnlFM2Fzd05NVkRaTDdL?= =?utf-8?B?Q3UySkdWbU83aFJBejdCcG1pajhyQmM4cmxsa2EzeGtJR0Y1WU1OWnc0SE5B?= =?utf-8?B?SUNlUWhiSndOOTk4eGRTaHl1cWhsYlBMMXJLaTlqOEc1MWRlcUQ3TlpFaHlX?= =?utf-8?B?d0g4ZUErNDhCZExCRDlzZjBjUHlsYjhadUJvQnE4MmN2M2ZadlFpNFpvY1dw?= =?utf-8?B?UTRqUm9GcDFCQTZLMlJkaHY4OUFYMTYrVkpwLzRScVVjY05ZQTJ4MUlkL3d6?= =?utf-8?B?bVF0SEpKYTA4eUVnVWsvY0VQT2lRUEpZVjBONmdMTE5RdmthTCtOOFhyYWdr?= =?utf-8?B?TUduVWdIblA0TVZRY09NTi9EbUU0SWF4L1ZocUxtdWxKSFBSbmM5d2xmMUxB?= =?utf-8?B?OXNZS3hUMnRQaFNsV3JaaTdLa09lMFRJQ3RSODluMSs0aWQ5ZGlBMW1ZRGRM?= =?utf-8?B?Y3U5UVhlL0JjYXdWTEw2UDJGY0lIUUdzNG1sZHRLVGxoaTg2SXppb1FtWXZ3?= =?utf-8?B?bzVYMnRraUNjNnJieVp0K2wwRmVGZm90cWpmamMvSGh2VG91aWYvK1RYTWxQ?= =?utf-8?B?MnhDVmFvelY2K0d6MEdaQjZ1NUp1T3JGL2dqUHdxVzVOcEtLYWVnajU3NHN3?= =?utf-8?B?ZEU1SklVOFZZQUFlV2ZsSjNNcndRV3NwMDZjQTR6dU01WTN4L0lsYmx2SjNZ?= =?utf-8?B?aWxTOW1BS1dudGFxMFZQc3ozNnZlbmQvSzdSdEhMM0QyQzNOSEhhclJ4UjhE?= =?utf-8?B?MmFNaFhqcUtXRVovMXJqWDdVenhWc0cxWjhjdjRPOU4xYy95WWhMYUd0SUtX?= =?utf-8?B?cW5wYnNEaXdTNFN5RUhGOUN5RGJDN3ovKzNDRThDWHZ5RHpnTUl2dklObzJv?= =?utf-8?B?elhOaXBBTE1MeGdBVmVMQ3B0UTBOZlFtbDNHMDJreGlFMmNlVmdpLy9CYUlu?= =?utf-8?B?OHh5bmsxSjFqUnFGejVjSmE2aXFjaWU3Mkt0VVBud3NhVmE5c1QxeHJtUDJi?= =?utf-8?B?UUc0WU5vaU1ZZmlwcjg5cTdIN1l6eVJyemhoUElQRi8xUys5ejExSGVYNlFw?= =?utf-8?B?UEo0QmVYcVlrb2tRalpQYXl3ZGswU252ZFUrZ3Y3S0NTOTAzcEFwL1FpWUNO?= =?utf-8?B?WEFrMXUxUmU1WVhqL1M2SGMrbi9rRmlYY2RLbTkxN1lnTE1KNHBIVWs2Wkhi?= =?utf-8?B?QlNPaGkyYWZEeUdpTGFqMHpkc0gxa3lsOWV2REtJcEE2RWhKZnNrNVdFTmhw?= =?utf-8?B?Um5XRUdDZzB2eCs5YnF0c1EvRDRKMlB0bFNid1Z5TERqcWtxU2FUdz09?= X-OriginatorOrg: garyguo.net X-MS-Exchange-CrossTenant-Network-Message-Id: af7b434e-9c57-42be-2ffa-08dec59869a8 X-MS-Exchange-CrossTenant-AuthSource: LOVP265MB8871.GBRP265.PROD.OUTLOOK.COM X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 08 Jun 2026 19:59:13.2260 (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: MuS172WAuEhuclXLj6hmXd+hh0Rty7oGu66m1SbeCbL6Gl8bk2pVr3UlHRTATSgTk4oa2MjVWwt+uH5t67qY+g== X-MS-Exchange-Transport-CrossTenantHeadersStamped: LO8P265MB7398 From: Laura Nao Add `SysMem`, an `Io` trait implementation for kernel virtual address ranges. It uses volatile accessors to provide safe access to shared memory that may be concurrently accessed by external hardware. Implement `IoCapable` for `u8`, `u16`, `u32`, and `u64` (for 64-bit system). This can be used for instead of `Coherent` for cases where a different layer takes care of mapping the system memory to the device (e.g. dma-buf or GPUVM). Signed-off-by: Laura Nao [ Rebased and adapted on top of I/O rework. - Gary ] Co-developed-by: Gary Guo Signed-off-by: Gary Guo Suggested-by: Danilo Krummrich --- rust/kernel/io.rs | 114 ++++++++++++++++++++++++++++++++++++++++++++++++++= ++++ 1 file changed, 114 insertions(+) diff --git a/rust/kernel/io.rs b/rust/kernel/io.rs index 173f8c0ba2d6..580ca88c46cc 100644 --- a/rust/kernel/io.rs +++ b/rust/kernel/io.rs @@ -1040,6 +1040,120 @@ pub fn relaxed(self) -> RelaxedMmio<'a, T> { #[cfg(CONFIG_64BIT)] impl_mmio_io_capable!(RelaxedMmioBackend, u64, readq_relaxed, writeq_relax= ed); =20 +/// I/O Backend for system memory. +pub struct SysMemBackend; + +impl IoBackend for SysMemBackend { + type View<'a, T: ?Sized + KnownSize> =3D SysMem<'a, T>; + + #[inline] + fn as_ptr<'a, T: ?Sized + KnownSize>(view: Self::View<'a, T>) -> *mut = T { + view.ptr + } + + #[inline] + unsafe fn project_view<'a, T: ?Sized + KnownSize, U: ?Sized + KnownSiz= e>( + _view: Self::View<'a, T>, + ptr: *mut U, + ) -> Self::View<'a, U> { + // INVARIANT: Per safety requirement, `ptr` is projection from `vi= ew`, so it is also a valid + // kernel accessible memory region. + SysMem { + ptr, + phantom: PhantomData, + } + } +} + +/// Implements [`IoCapable`] on `SysMemBackend` for `$ty` using `read_vola= tile` and +/// `write_volatile`. +macro_rules! impl_sysmem_io_capable { + ($ty:ty) =3D> { + impl IoCapable<$ty> for SysMemBackend { + fn io_read(view: SysMem<'_, $ty>) -> $ty { + // SAFETY: + // - Per type invariant, `ptr` is valid and aligned. + // - Using read_volatile() here so that race with hardware= is well-defined. + // - Using read_volatile() here is not sound if it races w= ith other CPU per Rust + // rules, but this is allowed per LKMM. + // - The macro is only used on primitives so all bit patte= rns are valid. + unsafe { view.ptr.read_volatile() } + } + + fn io_write(view: SysMem<'_, $ty>, value: $ty) { + // SAFETY: + // - Per type invariant, `ptr` is valid and aligned. + // - Using write_volatile() here so that race with hardwar= e is well-defined. + // - Using write_volatile() here is not sound if it races = with other CPU per Rust + // rules, but this is allowed per LKMM. + unsafe { view.ptr.write_volatile(value) } + } + } + }; +} + +impl_sysmem_io_capable!(u8); +impl_sysmem_io_capable!(u16); +impl_sysmem_io_capable!(u32); +#[cfg(CONFIG_64BIT)] +impl_sysmem_io_capable!(u64); + +/// System memory region. +/// +/// Provides `Io` trait implementation for kernel virtual address ranges, +/// using volatile read/write to safely access shared memory that may be +/// concurrently accessed by external hardware. +/// +/// # Invariants +/// +/// `self.ptr.addr() .. self.ptr.addr() + KnownSize::size(self.ptr)` is va= lid and aligned kernel +/// accessible memory region for the lifetime `'a`. +pub struct SysMem<'a, T: ?Sized> { + ptr: *mut T, + phantom: PhantomData<&'a ()>, +} + +impl Copy for SysMem<'_, T> {} +impl Clone for SysMem<'_, T> { + #[inline] + fn clone(&self) -> Self { + *self + } +} + +impl<'a, T: ?Sized> SysMem<'a, T> { + /// Create a `SysMem` from a raw pointer. + /// + /// # Safety + /// + /// `ptr.addr() .. ptr.addr() + KnownSize::size(ptr)` must be valid an= d aligned kernel + /// accessible memory region for the lifetime `'a`. + #[inline] + pub unsafe fn new(ptr: *mut T) -> Self { + // INVARIANT: Per safety requirement. + Self { + ptr, + phantom: PhantomData, + } + } + + /// Obtain the raw pointer to the memory. + #[inline] + pub fn as_ptr(self) -> *mut T { + self.ptr + } +} + +impl<'a, T: ?Sized + KnownSize> IoBase<'a> for SysMem<'a, T> { + type Backend =3D SysMemBackend; + type Target =3D T; + + #[inline] + fn as_view(self) -> ::View<'a, Self::Targe= t> { + self + } +} + // This helper turns associated functions to methods so it can be invoked = in macro. // Used by `io_project!()` only. #[doc(hidden)] --=20 2.54.0 From nobody Thu Jun 25 00:35:31 2026 Received: from LO3P265CU004.outbound.protection.outlook.com (mail-uksouthazon11020097.outbound.protection.outlook.com [52.101.196.97]) (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 D59A73F1ACC; Mon, 8 Jun 2026 19:59:30 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=52.101.196.97 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780948774; cv=fail; b=uhmL/TM9wuvf+PeFzv42yK/6bR5D1ByKrT3NsxupnG5ZuBNEUQxD1AKfdYzxSsjGmKjHyMGfSz51egtTwTogZkvrRH5hyYeWO4VaxpVNLRt4dkUlyXjFc2zzEEsMFYzWO53aV0eo2AvTVd74YoKWPkIi2XVfiteNLU83EvVrHLg= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780948774; c=relaxed/simple; bh=3nIiOE6FJXaI1YLRgnb53IPPaAbfEtvdGIHEVlnr5jY=; h=From:Date:Subject:Content-Type:Message-Id:References:In-Reply-To: To:Cc:MIME-Version; b=k1/F/lQQUnwYXGv6xTJr4iqbOHajAzSKj3WIVeZu9YsN5xWlrlBzFGTJY4AgwJlAKhYxfiHHlEmXVlavM3YRaFqI8VBlXq3y/+013m5pmT9NZDU2pdEqZxywViZ/8imPqVO2mEsua/qsZPgHnhuE3BZsYTgAD288tttzn0xCupQ= 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=ZXOPQjg5; arc=fail smtp.client-ip=52.101.196.97 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="ZXOPQjg5" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=h548KC/BjYlzziUt5OAqg8zepbYIendTWWhnUNBNLFee9SfTGt0babeEVF2NBAlKLAE0E9CCKfgTMT6SyLXA9VBGgb1FH+neUgYN+x9bZujWgPh4XJu4tPC6Yp97ORwMTDE+OxOLZqE+W4WR23Cp1p7bKhFde7bPTW8EMEWuGyEbuLuyM4dXDc1l8eRcfavfnDQdKgFIqxq3AhMTSmZWHFa5vcZGUsJl3C0raP+AFBl9yWi2CTuvJDGU+CrR+ZQRkMgN7HA0VV2go6AkXoYLE50rohZUw+21hL9M+nlaWabuUTihr74nxYkSu39rwhpyXDg2qjeJxAkBBfZX+QjPhA== 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=mo92A5YIhqAgyTJ5d5JrCMrcSLa0f1V1WI7G/2pctzw=; b=GtZS8di8eQZToxH2OXanWruPnLS5ACRqevJAYxI99IwLMIell0uWf0rJvyuZGYIBDmRBJ61yFIbe3Iv9gA4jk02ckdMwCho/xBMXIEstlzdIqAlCtaT8+wSCKKgFMp3bMHdq+ukC/sF/W0vaej61h1gzoLJUgrIPTI2Ykibs9N7DK2gw3cQxfbO5nheNHt6AhyV7gP4WrquSf9IHlDiUwPwV1q5CzzsAMyH0nWmsguA36CB+G2hkAhisnEIilcoYGQvzSlpatioIC8+vlmOZ8MWtyxSytG+sn5EaXNEcwXC4YCfNzQgC44RMzSGed7iu1c65S7lQnNWtoT6rWHF/hQ== 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=mo92A5YIhqAgyTJ5d5JrCMrcSLa0f1V1WI7G/2pctzw=; b=ZXOPQjg5NfzHIpzJgs2slIMOPlrLe2gKLzL7mCNq/zhZC4qYGOZYUdBzzoS2M3iOqDwZotdNFaOJxuqqg9t5DZxGHdfVtR9oAtDpB0P75rvfalBjL6KCDzASNAEkLa3/l/rwt4rgblFd7I25ytWbjTInb8byw8k/1b5Zbkfmui0= Authentication-Results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=garyguo.net; Received: from LOVP265MB8871.GBRP265.PROD.OUTLOOK.COM (2603:10a6:600:488::16) by LO8P265MB7398.GBRP265.PROD.OUTLOOK.COM (2603:10a6:600:3ca::5) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.21.92.12; Mon, 8 Jun 2026 19:59:13 +0000 Received: from LOVP265MB8871.GBRP265.PROD.OUTLOOK.COM ([fe80::1c3:ceba:21b4:9986]) by LOVP265MB8871.GBRP265.PROD.OUTLOOK.COM ([fe80::1c3:ceba:21b4:9986%4]) with mapi id 15.21.0092.011; Mon, 8 Jun 2026 19:59:13 +0000 From: Gary Guo Date: Mon, 08 Jun 2026 20:59:11 +0100 Subject: [PATCH v3 14/19] rust: io: implement a view type for `Coherent` Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260608-io_projection-v3-14-c5cde13a5ec4@garyguo.net> References: <20260608-io_projection-v3-0-c5cde13a5ec4@garyguo.net> In-Reply-To: <20260608-io_projection-v3-0-c5cde13a5ec4@garyguo.net> To: Danilo Krummrich , Alice Ryhl , Daniel Almeida , Greg Kroah-Hartman , "Rafael J. Wysocki" , Miguel Ojeda , Boqun Feng , Gary Guo , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Andreas Hindborg , Trevor Gross , Bjorn Helgaas , =?utf-8?q?Krzysztof_Wilczy=C5=84ski?= , Abdiel Janulgue , Robin Murphy , Alexandre Courbot , David Airlie , Simona Vetter Cc: driver-core@lists.linux.dev, rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, linux-pci@vger.kernel.org, nova-gpu@lists.linux.dev, dri-devel@lists.freedesktop.org X-Mailer: b4 0.15.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1780948747; l=5606; i=gary@garyguo.net; s=20221204; h=from:subject:message-id; bh=3nIiOE6FJXaI1YLRgnb53IPPaAbfEtvdGIHEVlnr5jY=; b=pw5VhRge3g2Qs5r/5Tt0J9dyAuuO9LLWqhMXEl1BNUTrDaLc96SDTXtpCErj9avRZ1wst3QA9 ldrZTGOwO1oAnrhooE6s4zfpaiLdo3Jik47Vw6da/JpNC6CN2fvjdh8 X-Developer-Key: i=gary@garyguo.net; a=ed25519; pk=vB3uIX95SM4eVrIqo1DWNWKDKD2xzB+yLLLr0yOPYMo= X-ClientProxiedBy: LO4P123CA0344.GBRP123.PROD.OUTLOOK.COM (2603:10a6:600:18d::7) To LOVP265MB8871.GBRP265.PROD.OUTLOOK.COM (2603:10a6:600:488::16) 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: LOVP265MB8871:EE_|LO8P265MB7398:EE_ X-MS-Office365-Filtering-Correlation-Id: f70c1e67-f3a0-4926-d6a2-08dec59869e3 X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|1800799024|7416014|376014|366016|10070799003|6133799003|22082099003|18002099003|921020|56012099006|5023799004; X-Microsoft-Antispam-Message-Info: +VPRFaLZKM8s+90I2erNzMkW0VE1yd3Wy7rFfRJHDBZo4Ec3xPZyxKASFujaa3bYwwkY9D35a8e82oGCTYcKECaGQLj0ZvmXgjRrBPUd2PE4gw/d4tsw3HAKa79toJOICVyCTxaWUCvLUf0b26Slc5YaGf/Duj2aJbdVF5naX+kEC749xHNwb7kqI5b/oWgKHOOnvlv746PkL1n0eH1hxvnt9sifQhm2KGK1z6W0LN4N1t30KfsKM7X8zBozwo7JutaZlreIYG6SVG326o6C1zyKTmertDKrdKafuz0c4IeqipG0Ix9J++Az5YSpUB72etibBIpWA9NIrKpeTbgyKoQ0Te9wdvw6OqfIvQkF+fZxRW2KD684pgWej1nQVQLPzBunwJvKXP68vczznwpTKMNR4XS8dWP+sI98GvrlVcJeGhooxjwqHNWZ47skDm0odidLtIJa1pIXSZeGREnNaLplGCzbbyjH90n1zNi7Qs9lM7E0f+2RxsQSpWBcEMHbEV43dzXJI0RVXvHNtokvEvjrY98xIPSKmljMn0oSlwxEkqqn4kXfMlIQMyeywVvYbDyIw0OOW3SmXlrHgaIX93o3CYK8W4i1DFAjcRHZYq26H5E8Ljot5o+LvDyceUnKj0taamyajtcKmWFv9liwRH/8EZbyNi3omJDzbjN9WZLC9VK0IHGZ6E+PZNsO/IYsn+7BWgrvNbFsngSIxr7fl998fSCY/cGj02FnZhiRq9I= X-Forefront-Antispam-Report: CIP:255.255.255.255;CTRY:;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:LOVP265MB8871.GBRP265.PROD.OUTLOOK.COM;PTR:;CAT:NONE;SFS:(13230040)(1800799024)(7416014)(376014)(366016)(10070799003)(6133799003)(22082099003)(18002099003)(921020)(56012099006)(5023799004);DIR:OUT;SFP:1102; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: =?utf-8?B?Z1ZDVnJVQ0xJV0U4SE9tQ3IzTVJpMVgxaG9ndy9HSXhlT1ZnSXhMSUxQb3Zh?= =?utf-8?B?ejVOYncwYWp3STNqZ1EyMnU5d25nbmUwaVJHaWRmcWpSTnR2bEJLbXF1emRD?= =?utf-8?B?Qm1vdm5pdFAxZFBCN2tDS1lzOStYMHczejlGaGJPSCs3ZGlENDBtdSttRnRN?= =?utf-8?B?cGlySUg5OVlyUU5zcmluVzVLWkYyOWZGK0FOMXdJbTBGbVJXQVU5VmV0SFF6?= =?utf-8?B?VkFjNEM4NkpOVVdmNjVrZ2lzNlN2NmF2Mm5IUG1PMXFqYkRSZE9LbDY0b3lD?= =?utf-8?B?QUlyNnVRd3did0ZBanpqT25ZeW0zTG1IMFZDMXVkSzYwcC9qTnpFc0NOWXMx?= =?utf-8?B?d0hxaHJXdWtpdjRyeU5ncjJyOTUrTUNpMUZ2RkRrVTE5S2RXOURaa3lLYWQz?= =?utf-8?B?dFBqdEdKRFREVjJkOEpuOEp5elo0Mnd0emV2NVd5enFKVjl5NnBmclBtYzV3?= =?utf-8?B?Q2d3Zkpyd1BJbXV2V0VOSGhycWtSMXFMYWYreWhycGZWK2liWDlGSmx1L1cx?= =?utf-8?B?bVBpQXZqZEd4VUdJeGhjWFEvVCtZUmN0Uk1GSEVBTHVwQkpjWDhzMXVndXRB?= =?utf-8?B?Yk5jOFBON2F5ZFBPaEw4aVNNcm9xTWhDR0tLZGYyalp6Vnc3Z3hxUHlOYmdk?= =?utf-8?B?R1hXaEF4V2FibG80dzUwakQ4SW82aVFML2pqMSsxN1RFNUN4ek16Q0JiaDlN?= =?utf-8?B?aHpyWHlnVEZoMjR0ajNtZEt4NTFGMm41NnNFamFJditCRG1NWTBja21rcndL?= =?utf-8?B?d1lxMGI3N1Z1NVZ0bzlxdzh3V1VXMi9oamtwdlRjNkg2Zng2dFc3bEM3djAr?= =?utf-8?B?NWFiaDA1MXovbXdXMm9XVk9oOFdxNkZ1ak8raVVMbkZZd0puUXJsTkZDS21D?= =?utf-8?B?cDRCN2h2RWxJYVJMamdJL2ZjWUNnMlUwaEJkVGt4QjBuZE5kUDgxQ3A0c2Jk?= =?utf-8?B?NVlEZG0yZ00yZUlEWnFhNnBMUmxDaW96Vm1hNElNWnlyTWk1VkhwVlZ2TWNx?= =?utf-8?B?bEdqWkZ2SDVDdFFrWWQvM2NNWDhtUlR2TW4xTUkwOHgrcXlZYkwvWUFjbzRp?= =?utf-8?B?bWxtQy9SZWRVTTMzTFpVSnUyOHBKb0pGbGhuNW9Jbk15d0ZzMDIvaGhpRmsy?= =?utf-8?B?aENZMTNvenVqNmN6TUZtdVpVdG5LRFlNbFRHYUFUVU5DY0hJVDJ3UXFmKy84?= =?utf-8?B?MTRrbmxoUWJBei9PMlNDcGdMZUNJUFhqcUsvSm1rdXB4TmorbXpLUEVQN1hx?= =?utf-8?B?WDNpMFA0ZmVhRmU4UG9nYTZtRUpSSU41S1hpU2V1WDJhcWM0WnNBMHo4eUF6?= =?utf-8?B?aHVUeDNsYlhGR0RvL2ZPTHBQWXoxNDdsUFdyMm1EdmZvTFRvSkVCQ0lvSi9w?= =?utf-8?B?d2x0dzZUZnhOS2Y2enpnNllmbmpTUXcrYkl6ak82TkNNSFE5THZHcTZSVzZU?= =?utf-8?B?U3NoVDdqVHNuRjcrc0lGZ1paUStXb0JXMEVybSszdUNxbU15ZXNvcjlvMlZV?= =?utf-8?B?YXQrVzZvazRESGY2TSthMzV2Tk9kWUF1VDlKc3BPVjlIc3pvSTlZbjNTcVhq?= =?utf-8?B?VGtGWDgramVQTEMybVBYbStBZ2crTjVNck9oRzBFK1hYZ201Y2VsbTNMa0lX?= =?utf-8?B?RXRob1p0bFBSUFJ5R2hKTEpqNktSUFE3VDFzTWt1YWhPSHNFUnlLWVdLS0JB?= =?utf-8?B?TkRuQkxkUzVDOXAxcmx4YkJyUjNuL1RoMzJ2QmZ4NU5MaS9TQ3pvT05Jdy80?= =?utf-8?B?ZGdwUVNLT0tjd1l3a1B5eHJia3c5QXhZbkV0SjJWSkYvWGJHdlc3eVlRSHRK?= =?utf-8?B?Z3dKaHlQYk1EQjRxK01uQ25TdVBNODVnTWdUN3F1RW54emRuYWh2OGNYL29R?= =?utf-8?B?TXdmc1VTWndVTDBBRS95UjZIVUxSdENtL1ZiNjJ4WVo0SDRUY2dxKzVMUk9J?= =?utf-8?B?UGJnTzA2dE11YTNBOEE1bm1qSjYwR0lqU0RuOHRLOFRTcFVoSWM0TThwQklo?= =?utf-8?B?Z1Y4a2tmamIveWFKbFg4eXVoZHNDc3MrOVY3SE14dlNVZHBiM1hwUkV3dmxL?= =?utf-8?B?N2FySVdhK3V6U0RpblpvNGt1YVZGNXpHYlFoTHZlWjVxSHFaeU5lZm9yUFA1?= =?utf-8?B?NWNUZWVYWVJTUFRUTVFlRUh0YnZrRjR1VjIvVk04a0pkVjU3dlhzUzJtanlI?= =?utf-8?B?bEVuczBLbmg2ajFiWkVHOFZxYkNLNTgrUWRlZGxtT3hrMllqczdWOWlnSTYv?= =?utf-8?B?U3J6bFNCU3ZXWkR4OEpZNFVTN0wwM1d5ZEY2UzJoeDJwMWh5ZFp2eFl2by9E?= =?utf-8?B?d1pvUGo2cG9GTHJKVVk5cVFxTlhtS25nRWRVUGU4YzNnR2ZhN3FOUT09?= X-OriginatorOrg: garyguo.net X-MS-Exchange-CrossTenant-Network-Message-Id: f70c1e67-f3a0-4926-d6a2-08dec59869e3 X-MS-Exchange-CrossTenant-AuthSource: LOVP265MB8871.GBRP265.PROD.OUTLOOK.COM X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 08 Jun 2026 19:59:13.6320 (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: A8spEXmmXGnSn2rRIPQMRET8m2JC3tbSz9ikzOnA3TQgqyLOq5Qz0Z5pAyMPQAPAopP9ExS3YaNKAYp9b6/ytg== X-MS-Exchange-Transport-CrossTenantHeadersStamped: LO8P265MB7398 Implement a `CoherentView` type which is a view of `Coherent`. To be able to give out DMA handles, the view type contains both CPU and DMA pointers, and the projection method projects both at once. Delegate most of the `Io` implementation to `SysMemBackend`. Provide a method to erase the DMA handle and give out a `SysMem` view, if the user does not need the `dma_handle`. Signed-off-by: Gary Guo Suggested-by: Danilo Krummrich --- rust/kernel/dma.rs | 137 +++++++++++++++++++++++++++++++++++++++++++++++++= +++- 1 file changed, 135 insertions(+), 2 deletions(-) diff --git a/rust/kernel/dma.rs b/rust/kernel/dma.rs index 200def84fb69..970a667b9be2 100644 --- a/rust/kernel/dma.rs +++ b/rust/kernel/dma.rs @@ -14,14 +14,21 @@ }, error::to_result, fs::file, + io::{ + IoBackend, + IoBase, + IoCapable, + SysMem, + SysMemBackend, // + }, prelude::*, ptr::KnownSize, sync::aref::ARef, transmute::{ AsBytes, FromBytes, // - }, // - uaccess::UserSliceWriter, + }, + uaccess::UserSliceWriter, // }; use core::{ ops::{ @@ -1133,6 +1140,132 @@ unsafe impl Send for CoherentHandle {} // plain `Copy` values. unsafe impl Sync for CoherentHandle {} =20 +/// View type for `Coherent`. +/// +/// This is same as [`SysMem`] but with additional information that allows= handing out a DMA handle. +pub struct CoherentView<'a, T: ?Sized> { + cpu_addr: SysMem<'a, T>, + dma_handle: DmaAddress, +} + +impl Copy for CoherentView<'_, T> {} +impl Clone for CoherentView<'_, T> { + #[inline] + fn clone(&self) -> Self { + *self + } +} + +impl<'a, T> CoherentView<'a, T> { + /// Erase the DMA handle information and obtain a [`SysMem`] view of t= he same memory region. + #[inline] + pub fn as_sys_mem(self) -> SysMem<'a, T> { + self.cpu_addr + } + + /// Returns a DMA handle which may be given to the device as the DMA a= ddress base of the region. + #[inline] + pub fn dma_handle(self) -> DmaAddress { + self.dma_handle + } + + /// Returns a reference to the data in the region. + /// + /// # Safety + /// + /// * Callers must ensure that the device does not read/write to/from = memory while the returned + /// slice is live. + /// * Callers must ensure that this call does not race with a write to= the same region while + /// the returned slice is live. + #[inline] + pub unsafe fn as_ref(self) -> &'a T { + // SAFETY: pointer is aligned and valid per type invariant. Aliasi= ng rule is satisfied per + // safety requirement. + unsafe { &*self.cpu_addr.as_ptr() } + } + + /// Returns a mutable reference to the data in the region. + /// + /// # Safety + /// + /// * Callers must ensure that the device does not read/write to/from = memory while the returned + /// slice is live. + /// * Callers must ensure that this call does not race with a read or = write to the same region + /// while the returned slice is live. + #[inline] + pub unsafe fn as_mut(self) -> &'a mut T { + // SAFETY: pointer is aligned and valid per type invariant. Aliasi= ng rule is satisfied per + // safety requirement. + unsafe { &mut *self.cpu_addr.as_ptr() } + } +} + +/// `IoBackend` implementation for `Coherent`. +pub struct CoherentBackend; + +impl IoBackend for CoherentBackend { + type View<'a, T: ?Sized + KnownSize> =3D CoherentView<'a, T>; + + #[inline] + fn as_ptr<'a, T: ?Sized + KnownSize>(view: Self::View<'a, T>) -> *mut = T { + SysMemBackend::as_ptr(view.cpu_addr) + } + + #[inline] + unsafe fn project_view<'a, T: ?Sized + KnownSize, U: ?Sized + KnownSiz= e>( + view: Self::View<'a, T>, + ptr: *mut U, + ) -> Self::View<'a, U> { + let offset =3D ptr.addr() - view.cpu_addr.as_ptr().addr(); + // CAST: The offset DMA address can never overflow. + let dma_handle =3D view.dma_handle + offset as DmaAddress; + CoherentView { + dma_handle, + // SAFETY: Per safety requirement. + cpu_addr: unsafe { SysMemBackend::project_view(view.cpu_addr, = ptr) }, + } + } +} + +impl IoCapable for CoherentBackend +where + SysMemBackend: IoCapable, +{ + #[inline] + fn io_read<'a>(view: Self::View<'a, T>) -> T { + SysMemBackend::io_read(view.cpu_addr) + } + + #[inline] + fn io_write<'a>(view: Self::View<'a, T>, value: T) { + SysMemBackend::io_write(view.cpu_addr, value) + } +} + +impl<'a, T: ?Sized + KnownSize> IoBase<'a> for CoherentView<'a, T> { + type Backend =3D CoherentBackend; + type Target =3D T; + + #[inline] + fn as_view(self) -> CoherentView<'a, Self::Target> { + self + } +} + +impl<'a, T: ?Sized + KnownSize> IoBase<'a> for &'a Coherent { + type Backend =3D CoherentBackend; + type Target =3D T; + + #[inline] + fn as_view(self) -> CoherentView<'a, Self::Target> { + CoherentView { + // SAFETY: `cpu_addr` is valid and aligned kernel accessible m= emory. + cpu_addr: unsafe { SysMem::new(self.cpu_addr.as_ptr()) }, + dma_handle: self.dma_handle, + } + } +} + /// Reads a field of an item from an allocated region of structs. /// /// The syntax is of the form `kernel::dma_read!(dma, proj)` where `dma` i= s an expression evaluating --=20 2.54.0 From nobody Thu Jun 25 00:35:31 2026 Received: from LO3P265CU004.outbound.protection.outlook.com (mail-uksouthazon11020080.outbound.protection.outlook.com [52.101.196.80]) (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 840B13F39E5; Mon, 8 Jun 2026 19:59:34 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=52.101.196.80 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780948777; cv=fail; b=PhpOjItHILSh3XNU/5IQ0TWEe0fQ4xX95/gC3A4QkgrCNESifeXMFWoouISFEZkk/BEnD4QXLP/cx8Nvfy5YpsJzs7KbcHHt1SBJ0tEqkWv0KV8Xyj5k9erw/TPdME2R0fp6JtTUqqelafjjir7i0g/Yw4qGOmQg6qxKl+uutks= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780948777; c=relaxed/simple; bh=2reHlWNqXZ1I2nXvOoGdiIWe017bHX3+8mpgOeI2sVI=; h=From:Date:Subject:Content-Type:Message-Id:References:In-Reply-To: To:Cc:MIME-Version; b=ZqxoytYhWewydn2hjuCOufm/7K8RhKXrTxS1xX0OljKjsUZWoPA39JD8UeItdi6Q7rjqxp8bUxhBIEY5sElhAiHKZO3hiTxCbmAoijCzPb5Rb+dGB6INCStVVmPeybEPuh2bNojq6zs8UrqmOGZhSliye6w5SltVCECsZKDUsiY= 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=J/NGqaBd; arc=fail smtp.client-ip=52.101.196.80 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="J/NGqaBd" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=F6ZCN+2sqKzu7fbbeyJn3SUW7myku3V4LP8WLGBSL55Nx0njCt5RayFoQ2KEsVfayDzzXwZLPIRgXLKFs9SEXF7arGDA/viri8L5jlKrqg/GfFmqp1IQrCjNgPGRNSJWpeovRQ4Ro7OieUulhOr1aMmBxgKrOS2YiarjoWhqAZRrc3u2An8WSuGh4oDw9vQ5XGAl1o4VAoXVjZvVaPFd+wY+kkZGcMXkIw+yXm/wC00OgYVhqcnSIJNXOCBLuWLy8OWOA9mB7yV4+htF748ekIUkee+L7njdU9Aa21DVKtyoUieRxpAqxZoQTYtNSkgpwgY60U9Z6vJ93kWNBQ2CWQ== 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=PhjW1NSoebyE/bs8Vx2O/rQlrwNytPj9LNyoNRD++Us=; b=DymYWiUHyJnLQRALJaE15FNGEMIo5nnwDy4Z8z5RiWQzKaOK7VihOaIPp4TPH4XGayg2/BINYf6YqUFhEaNfPu/B03q+89so/M1t2GQwxsey0H1ug8wB81XHgUBHPvHsiohQiNbxS4f2X7MFEZgkloklb+RGY77TqD8bR3LTL27i1JvLzDDEIhrRNOvY00dOECB+DUDSpB/Ek3XVOXWxRSbievYXa84OwRwNIgWRheIkIBC7DhxnCFNH4weGN7yI1YlpW1LGxTHb6p3gF+rEp3hBY5pONid7isG4HAutZMQAIIqj5HAUuS8EA/Lj7b9swhap8f8MRnIWjMjpN9yMIQ== 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=PhjW1NSoebyE/bs8Vx2O/rQlrwNytPj9LNyoNRD++Us=; b=J/NGqaBdC49+hT0CaN/yzuUTTwQJMl2YPaGk48afRW27/20K0or9XVpCRHH4kuWT3r7D8M5lv0tIXmO19HsKqZrpu5QYjYAnqYIlmcc4LDV0a1sxUjSSiV2ut2YWAtn7zxnyuJTfhc9PyY4/OAfFxNRShtbB+Snmv8g9yoTbOUs= Authentication-Results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=garyguo.net; Received: from LOVP265MB8871.GBRP265.PROD.OUTLOOK.COM (2603:10a6:600:488::16) by LO8P265MB7398.GBRP265.PROD.OUTLOOK.COM (2603:10a6:600:3ca::5) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.21.92.12; Mon, 8 Jun 2026 19:59:14 +0000 Received: from LOVP265MB8871.GBRP265.PROD.OUTLOOK.COM ([fe80::1c3:ceba:21b4:9986]) by LOVP265MB8871.GBRP265.PROD.OUTLOOK.COM ([fe80::1c3:ceba:21b4:9986%4]) with mapi id 15.21.0092.011; Mon, 8 Jun 2026 19:59:14 +0000 From: Gary Guo Date: Mon, 08 Jun 2026 20:59:12 +0100 Subject: [PATCH v3 15/19] rust: io: add `read_val` and `write_val` function on `Io` Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260608-io_projection-v3-15-c5cde13a5ec4@garyguo.net> References: <20260608-io_projection-v3-0-c5cde13a5ec4@garyguo.net> In-Reply-To: <20260608-io_projection-v3-0-c5cde13a5ec4@garyguo.net> To: Danilo Krummrich , Alice Ryhl , Daniel Almeida , Greg Kroah-Hartman , "Rafael J. Wysocki" , Miguel Ojeda , Boqun Feng , Gary Guo , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Andreas Hindborg , Trevor Gross , Bjorn Helgaas , =?utf-8?q?Krzysztof_Wilczy=C5=84ski?= , Abdiel Janulgue , Robin Murphy , Alexandre Courbot , David Airlie , Simona Vetter Cc: driver-core@lists.linux.dev, rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, linux-pci@vger.kernel.org, nova-gpu@lists.linux.dev, dri-devel@lists.freedesktop.org X-Mailer: b4 0.15.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1780948747; l=5545; i=gary@garyguo.net; s=20221204; h=from:subject:message-id; bh=2reHlWNqXZ1I2nXvOoGdiIWe017bHX3+8mpgOeI2sVI=; b=INSbpiXpPLvYgD6Cr3IvrSQ/PGjB6wnXUjSsZmnlk0Xm8Zh31rwxhlh9F+G/OoUpipGbtsK+H ye4tyUyxqxxCfqlwNq1K+TP9S7SVq8+63iXsE9D16UJtScAHKFfQMNO X-Developer-Key: i=gary@garyguo.net; a=ed25519; pk=vB3uIX95SM4eVrIqo1DWNWKDKD2xzB+yLLLr0yOPYMo= X-ClientProxiedBy: LO4P123CA0344.GBRP123.PROD.OUTLOOK.COM (2603:10a6:600:18d::7) To LOVP265MB8871.GBRP265.PROD.OUTLOOK.COM (2603:10a6:600:488::16) 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: LOVP265MB8871:EE_|LO8P265MB7398:EE_ X-MS-Office365-Filtering-Correlation-Id: c592f6f6-7e5d-471b-3fcf-08dec5986a21 X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|1800799024|7416014|376014|366016|10070799003|6133799003|22082099003|18002099003|921020|3023799007|56012099006|5023799004; X-Microsoft-Antispam-Message-Info: P5eEBJ4Dlk0R3SxIZLzQz0dx2JejvPaxOnPIYR++AmmJoVgwPNb6/PjxoG6JBYbbOOMvCz/BRoSUJkkKvLgFomShQlPKtR8EwCvfkzh6di5mdD1+B6i+aAGnSTMOY+JKEWZyFKIJDuuuuoTdfARDUg4TiO2k11V4f/0ZjQq3vfYXSNX8ic5WH2j4bG/aqpokO0RNXubd7J+8Vh2Zh3Sof8rm788WChSe7tQSPHx3k42/PriZwcH/rb9/aZIoyBJPngTiNWjGVFerPJw/DQjb9+TtPQdFInXnrLbLcul3Apslemu7peIZ8wUBKV2goDVwQHMmLDrGZJcoSj5k7R6K72ELvvRYV/pC390vv9Xr1WVNqxsQ8QtyzxdSNZoPX47QLTDUjFqQhm5B2SAdpN/OWIX/be54ODfn9CtxLqFhx/tTHH39CMqUwMX5QlKS6G1BZL+f162lEsgOUn8x37WN56qym6MuoxJ03inDDNPRZaXfzG2AImtiXcmYq00kw3EGEE3OfAwNRXHE6DvbO4d3MFdmLpMtPz51uzog813ZlF9fKG9p7Le3xAJknigDRYBy6MFGFpJMPPV6KMohTpiFl0TW53f/Y8xh5xCYdY2CHt/m6uzRSxE4Hme2zP/pvRUK0c4NyjnUf3xWNwyxo9GKSEIWYgsvBbKb26aHnmLuo836Sr/Uenrh9FWtzZILk53O8sUCk69YERyeutAwNjELtObbqgvZmCR4FzGIN9oSB44= X-Forefront-Antispam-Report: CIP:255.255.255.255;CTRY:;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:LOVP265MB8871.GBRP265.PROD.OUTLOOK.COM;PTR:;CAT:NONE;SFS:(13230040)(1800799024)(7416014)(376014)(366016)(10070799003)(6133799003)(22082099003)(18002099003)(921020)(3023799007)(56012099006)(5023799004);DIR:OUT;SFP:1102; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: =?utf-8?B?UUJ1QW5kMTRQcEN3UFF4L1lTb2gwSXFpYlkydEpQRXdEalRrbm1YRnlYbkNj?= =?utf-8?B?ZHJyNDRGbFAyQnJUa2VNOWdMOFNrbDB0V3czd09XcCt2VEd3T2Jzdi9pWmQw?= =?utf-8?B?L3VEbTF1QnY2RjZOZUNGSTlYeHpaVy9XNTBXdzV1TnhFRFdIZ0hnWEhLQjB5?= =?utf-8?B?eEdZdUd3cEphbXpjclJkalNYOCtCaC9VK0xJZThGRXUrZ3hlZnpERnUvNUFN?= =?utf-8?B?TlM2MmVMUWVPK0VLK2syNmFUdEVoRW9sRHJnbUpPaURZODROWUIxb3Q1TUNr?= =?utf-8?B?U2loSGJzTUJ0d0Q4c1NRbTFvZDlXVHNadW84L3kzK1ZKSFh3L2hKalQ3bU9V?= =?utf-8?B?QkhQaHM2azNhWW9MemFYNlA2TUNMQkxLdnBKWFFpOElaekxBV2xILzlmK3NC?= =?utf-8?B?VTZxL1RVazRlVXZSaEtRakF2Q2NpeDFnUjlSVHpaWFc4NVo5c3kyRjNydUZU?= =?utf-8?B?ZG1jOW55TWQvR3J4OVJEMkpKdVF5TEc4T0ZYTDM2OWdWSE9LSkdjL0Zlc1cx?= =?utf-8?B?N0JBWDJJQmtCZFA0dnc4ZkVIcHZGNDJpT0lzdUZaSmI5cVozTGdLbmxOeXdy?= =?utf-8?B?UWs5eS9uYzlHV0Y3TjhYR2J4OXNJRVNIcjZDaGE2ajNmWjlpM3BiREdxS09D?= =?utf-8?B?NC9lRlJYZzZpOWlkaHVGY2hMcTJkZXVHQWVaemxEV05JcUFMVmJ2OGg4cnBh?= =?utf-8?B?SEI4OTVXcCtOODBWNlFHNEhIK2NmODBybnl2ejJWRmt4Y0l0UGRrZkVLYWRL?= =?utf-8?B?RW40YThoRm1UcnlQVXBncXBrTk5xaWVJVGl6R3pGYWgxYkhsWFE2WmtuTEM5?= =?utf-8?B?a1B4c0NaSmowdWhIWDJ6aUt4NHZ1M3VGV1ltUFdVZ2JybStaVmZ5NTdtOFc4?= =?utf-8?B?cXBnbHJlU0hzVVlJaUt4VkFxNm4wbWo5RVRsOHR2OHVsb3piVUNBekRlL0ZB?= =?utf-8?B?MVFWQ3NyOG9FTGhiaFVSaEplYmZOUnNoMC95QUk1VC9jWEMwU0UydmhySUUz?= =?utf-8?B?WnEzc1FCMEJ0eTJreksyQ3BuUTdRbG96V1FzbVZMZjJESjlnSUpCUWtKTFQr?= =?utf-8?B?eG9QUjFCOU9heWxLU2xyYnlpMzFsNmZyWnR1YjNTRU0xVzg2WXN2VHZmdFly?= =?utf-8?B?eUNZZ0FKdEI1cDNybUJ0TjhKYjBaQ09TTmhLZWt3MHZBSHdqRWJFSjlVOU80?= =?utf-8?B?TFVLWmI1UGprbGJnUDB0K1RsT2Y0cnpqQm0rVTNBS1BmeStSWmpnOVkwYm4x?= =?utf-8?B?STBxcC9JSXkxQzY2Wkhxamd6NUNtSGVxWERmVEJtWGxwaGVrK3hyd0c0QzRL?= =?utf-8?B?elZjN2Z4Y1FXYS9JaDR1bFE0Z05sK0ZLNWpIcVRhV3pSaTd4R2VieXd6TVY5?= =?utf-8?B?QTdlR1VmTVEvdWJKdVZSUDFpazIvNG9PMkl0amVuREt4dk5FM2NLdUo3VG8w?= =?utf-8?B?MjRXOTIwa3IyZVFOcEZTWFhPVndFeTBzaHROT2FoOUJhYmNnMWZiWDhZdXgv?= =?utf-8?B?RFgybkNBZENuaEJwYmR2NXRFUWhQbWZxNitGR0RQWWxYbTEvRHpFV0ZIbVE5?= =?utf-8?B?OGlSbEZaa3l0RHJQYTBMbG5kajVoK1ArR0NEQjVTaVVzSlBZNmJhdUVnZTQz?= =?utf-8?B?WUlQci9HRENjZnNFWjc0bkMzSW5tQXRRYUJocERGWW5PbWVmTVFKdTBqV0Q5?= =?utf-8?B?Rm9pMjdkK250YlgzQjV1a2swNExBZHF1akVVMXZWMWRmRG9UZzE4bUpRbGR2?= =?utf-8?B?eFhrYTRmMkVGVGVINTdKbEg1SnViNEIvRlMvQ0trVjNvS0JHQ2dKVS9DVTVa?= =?utf-8?B?SkFqQ1l1MmFPRWh2T0Z2ZmhGcEtEYzM0Y05iNE5zUVZ2d3FvVk5vcG13K0FX?= =?utf-8?B?U3dnMzhjZjRoOFBvaitGaERTd0JRZjJiZ1FQVm5WeVUvYXIyTjJyZmVNVDly?= =?utf-8?B?TEoyWCt2VEhiVGZ2QVBmQlpFMzZBUVNPYVQ1VkVEYnNLZlVZa0pDcVA0SC9k?= =?utf-8?B?d3ZrUEd3S0ZWKy9wRlZXUzc5VFpFV3hwcWtZUitzQmJFcXVKdVJldE9ydFNv?= =?utf-8?B?MERLNDdZdnlaVmQxQ2RacU43MkIvbXh2TTB3WkIxdzVIdFRRVFBSZzVnYzlG?= =?utf-8?B?UU1hTkpYTDA3ZGxXWkpQWDR1TnN1QWkwYW1TTWx2bkUyNUpoVC9WVW4yWmV3?= =?utf-8?B?V0dxQ3hYZXhLSmE5cE1OSDV1dHhoZURWbFFNZ00wci84ZWxLWVN4Y0s5anV5?= =?utf-8?B?N1BpSGdRdXZuTm9ER2lQZUNhU2ZienlMS1dEVldTMG5DVE1HZ3EwSTJXbFYx?= =?utf-8?B?bXNzajFXcklZZ09jTU9EUGxlTXllRFR1VzhXb2huYnphZS8rNWM4UT09?= X-OriginatorOrg: garyguo.net X-MS-Exchange-CrossTenant-Network-Message-Id: c592f6f6-7e5d-471b-3fcf-08dec5986a21 X-MS-Exchange-CrossTenant-AuthSource: LOVP265MB8871.GBRP265.PROD.OUTLOOK.COM X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 08 Jun 2026 19:59:14.0240 (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: pqiNg15VhO2BeAXApMPBJ1c1VEnTwPdFmWFVnWqb5GRe9Yl7nyufDx6T4QGnPwdI2rW1OaIRoVr7RkgypsmbWQ== X-MS-Exchange-Transport-CrossTenantHeadersStamped: LO8P265MB7398 Provide `read_val` and `write_val` that allow I/O views to be accessed when they're narrowed down to just views of primitives. This is used to provide `io_read!` and `io_write!` macros, which are generalized version of current `dma_read!` and `dma_write!` macro that work for all types that implement `Io`. Note though `io_read!` and `io_write!` only works if backend implements `IoCapable` for the type; which is typically only implemented for atomically accessible primitives. `dma_read!` and `dma_write!` currently supports them via `read_volatile` and `write_volatile`; this can be undesirable for aggregates as LLVM may turn them to multiple instructions to access parts and re-assemble, even if they could be combined to a single instruction. Thus, `io_read!()` and `io_write!()` does not fully replace `dma_read!()` and `dma_write!()` in this scenario. The ability to read/write aggregates (when atomicity is of no concern) is better served with copying primitives (e.g. memcpy_{from,to}io). Signed-off-by: Gary Guo Suggested-by: Danilo Krummrich --- rust/kernel/io.rs | 114 ++++++++++++++++++++++++++++++++++++++++++++++++++= ++++ 1 file changed, 114 insertions(+) diff --git a/rust/kernel/io.rs b/rust/kernel/io.rs index 580ca88c46cc..72f3acc0f50d 100644 --- a/rust/kernel/io.rs +++ b/rust/kernel/io.rs @@ -353,6 +353,50 @@ fn try_cast(self) -> Result<::View<'a, U>> Ok(unsafe { Self::Backend::project_view(view, ptr.cast()) }) } =20 + /// Read a value from I/O. + /// + /// This only works for primitives supported by the I/O backend. + /// + /// # Examples + /// + /// ```no_run + /// # use kernel::io::*; + /// # fn test_read_val(mmio: Mmio<'_, u32>) { + /// // let mmio: Mmio<'_, u32>; + /// let val: u32 =3D mmio.read_val(); + /// # } + /// ``` + #[inline] + fn read_val(self) -> Self::Target + where + Self::Backend: IoCapable, + Self::Target: Sized, + { + Self::Backend::io_read(self.as_view()) + } + + /// Write a value to I/O. + /// + /// This only works for primitives supported by the I/O backend. + /// + /// # Examples + /// + /// ```no_run + /// # use kernel::io::*; + /// # fn test_write_val(mmio: Mmio<'_, u32>) { + /// // let mmio: Mmio<'_, u32>; + /// mmio.write_val(1u32); + /// # } + /// ``` + #[inline] + fn write_val(self, value: Self::Target) + where + Self::Backend: IoCapable, + Self::Target: Sized, + { + Self::Backend::io_write(self.as_view(), value) + } + /// Returns a view for a given `offset`, performing compile-time bound= checks. // Always inline to optimize out error path of `build_assert`. #[inline(always)] @@ -1228,3 +1272,73 @@ macro_rules! io_project { } #[doc(inline)] pub use crate::io_project; + +/// Read from I/O memory. +/// +/// The syntax is of form `io_read!(io, proj)` where `io` is an expression= to a type that +/// implements [`Io`] and `proj` is a [projection specification](kernel::p= tr::project!). +/// +/// # Examples +/// +/// ``` +/// struct MyStruct { field: u32, } +/// +/// // SAFETY: All bit patterns are acceptable values for `MyStruct`. +/// unsafe impl kernel::transmute::FromBytes for MyStruct{}; +/// // SAFETY: Instances of `MyStruct` have no uninitialized portions. +/// unsafe impl kernel::transmute::AsBytes for MyStruct{}; +/// +/// # fn test(mmio: kernel::io::Mmio<'_, [MyStruct]>) -> Result { +/// // let mmio: Mmio<'_, [MyStruct]>; +/// let field: u32 =3D kernel::io::io_read!(mmio, [try: 2].field); +/// # Ok::<(), Error>(()) } +/// ``` +#[macro_export] +#[doc(hidden)] +macro_rules! io_read { + ($io:expr, $($proj:tt)*) =3D> { + $crate::io::Io::read_val($crate::io_project!($io, $($proj)*)) + }; +} +#[doc(inline)] +pub use crate::io_read; + +/// Writes to I/O memory. +/// +/// The syntax is of form `io_write!(io, proj, val)` where `io` is an expr= ession to a type that +/// implements [`Io`] and `proj` is a [projection specification](kernel::p= tr::project!), +/// and `val` is the value to be written to the projected location. +/// +/// # Examples +/// +/// ``` +/// struct MyStruct { field: u32, } +/// +/// // SAFETY: All bit patterns are acceptable values for `MyStruct`. +/// unsafe impl kernel::transmute::FromBytes for MyStruct{}; +/// // SAFETY: Instances of `MyStruct` have no uninitialized portions. +/// unsafe impl kernel::transmute::AsBytes for MyStruct{}; +/// +/// # fn test(mmio: kernel::io::Mmio<'_, [MyStruct]>) -> Result { +/// // let mmio: Mmio<'_, [MyStruct]>; +/// kernel::io::io_write!(mmio, [try: 2].field, 10); +/// # Ok::<(), Error>(()) } +/// ``` +#[macro_export] +#[doc(hidden)] +macro_rules! io_write { + (@parse [$io:expr] [$($proj:tt)*] [, $val:expr]) =3D> { + $crate::io::Io::write_val($crate::io_project!($io, $($proj)*), $va= l) + }; + (@parse [$io:expr] [$($proj:tt)*] [.$field:tt $($rest:tt)*]) =3D> { + $crate::io_write!(@parse [$io] [$($proj)* .$field] [$($rest)*]) + }; + (@parse [$io:expr] [$($proj:tt)*] [[$flavor:ident: $index:expr] $($res= t:tt)*]) =3D> { + $crate::io_write!(@parse [$io] [$($proj)* [$flavor: $index]] [$($r= est)*]) + }; + ($io:expr, $($rest:tt)*) =3D> { + $crate::io_write!(@parse [$io] [] [$($rest)*]) + }; +} +#[doc(inline)] +pub use crate::io_write; --=20 2.54.0 From nobody Thu Jun 25 00:35:31 2026 Received: from CWXP265CU008.outbound.protection.outlook.com (mail-ukwestazon11020099.outbound.protection.outlook.com [52.101.195.99]) (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 9E2F53F39F9; Mon, 8 Jun 2026 19:59:34 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=52.101.195.99 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780948777; cv=fail; b=INOrPOTAtwirQYhDTCD9Z9OSXuNS4YuqIM9+M9DXGh4qHahy+nQBqyPcQwMi01lLhXcyZ9AXeyQQc1BJbtqtpF94rcJJ6GCqho4IJotYYUaH3Q712QOlc2mbzJINB4A7P4B6wuNpvcn4b7rtpwyrI0mQhjESe6GjlAKK65D6j24= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780948777; c=relaxed/simple; bh=l4oA9OL4IRd+F2126WqfQn4rOSqui3zNcK3p0I1bTBc=; h=From:Date:Subject:Content-Type:Message-Id:References:In-Reply-To: To:Cc:MIME-Version; b=os20/TCs7Ea21U1nU0Av3lg3Q2Vn8cPU22P1KzfQ6bpm34hvJR//gdX9MTphUGZJCLfXVMTNwmXO6YY/0MHE4EB/VCg4K13NzOWg5JDL4hgsLptYITHRMxoQtARHAhJ++Sa0aD8Mgb/Idh4fUE0nsCW1+n40F6Pf1Y3NjJ6ojoI= 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=VEXJ71o9; arc=fail smtp.client-ip=52.101.195.99 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="VEXJ71o9" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=SMKHYTLMlQrMSMKEamhJV0kQ77BQpX1+ZlyQh4KlBpeMAGPhnh0VJ/XnetkYxwe5XCmMWqM6qTQBh92pK26+sh5LCUsTgbwZc7hlGG4rvNeGWW8F2DAGawCMpsRlgjNcFlVD9bPtPh6DKmJr4HX2lOujITkaNC5uE0KS1zZtv+jInzknILbEX3MHzqnhwCGKXOb6pwMTE0G/NxlEIMPZALWu4KYu56H2o3cMWa95OXNIf2s0WrukUDGDfLbczcO45q5lthOZTsI41Y+akUlH+vmXZvkIZPpKCX+51SyDtB7yRLt5tTcKqD6ARNmb5rPQ9xxkpa+jfmxCyXcYKOcxAg== 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=H5SpviNfIjUUozXT+xdEge2MyrYHZmt8nPbL/SBu4N8=; b=o+sOcD+oKEpV+cwBcv7NUP7s07inETySj9VJgMkR8mOsEvu4PzlWrNU0ipZQRQnwyZ7eb9ytptyqeqG/AjxHklf3QN/aUSULgwlAQNopMg7NEl1LkdSsd0yzYxLK8iVNo0y3y623Kb9VvPybuHYN6ZM1TMdmmdOmzy/xmg1wv4BsfSG5786cAR8s8iFACNWE3RVJvPHdNdZA3U0YPR4u/s7gkUnELrLkX1bDbdI2fZ6Pza5k5m03QRA585mrq6Ez2SCqHV3bLl2dRqy+s9zUdU8c5mNWVbjB7HSewZdjn4WC5/ZTkw3zS6azSCWUghgqMRgiJCcvhUODy1iKmpPCIw== 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=H5SpviNfIjUUozXT+xdEge2MyrYHZmt8nPbL/SBu4N8=; b=VEXJ71o9tqYYT6lV9XBxNn1V5X0Fho+hoFM7Uo5qyuuYe5XOXc5vLkia+j2o7U1AsOeTbAE+6IZqKrJK7WRpKJKTyZuhhSTPGb0vQGyicoMKZNNT79KX2DrLvtBtMlmEWm4Hho4tTnpoHOOfxuIXeyxnMZTS9ANt4yNPFV/H9TY= Authentication-Results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=garyguo.net; Received: from LOVP265MB8871.GBRP265.PROD.OUTLOOK.COM (2603:10a6:600:488::16) by LO8P265MB7398.GBRP265.PROD.OUTLOOK.COM (2603:10a6:600:3ca::5) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.21.92.12; Mon, 8 Jun 2026 19:59:14 +0000 Received: from LOVP265MB8871.GBRP265.PROD.OUTLOOK.COM ([fe80::1c3:ceba:21b4:9986]) by LOVP265MB8871.GBRP265.PROD.OUTLOOK.COM ([fe80::1c3:ceba:21b4:9986%4]) with mapi id 15.21.0092.011; Mon, 8 Jun 2026 19:59:14 +0000 From: Gary Guo Date: Mon, 08 Jun 2026 20:59:13 +0100 Subject: [PATCH v3 16/19] gpu: nova-core: use I/O projection for cleaner encapsulation Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260608-io_projection-v3-16-c5cde13a5ec4@garyguo.net> References: <20260608-io_projection-v3-0-c5cde13a5ec4@garyguo.net> In-Reply-To: <20260608-io_projection-v3-0-c5cde13a5ec4@garyguo.net> To: Danilo Krummrich , Alice Ryhl , Daniel Almeida , Greg Kroah-Hartman , "Rafael J. Wysocki" , Miguel Ojeda , Boqun Feng , Gary Guo , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Andreas Hindborg , Trevor Gross , Bjorn Helgaas , =?utf-8?q?Krzysztof_Wilczy=C5=84ski?= , Abdiel Janulgue , Robin Murphy , Alexandre Courbot , David Airlie , Simona Vetter Cc: driver-core@lists.linux.dev, rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, linux-pci@vger.kernel.org, nova-gpu@lists.linux.dev, dri-devel@lists.freedesktop.org X-Mailer: b4 0.15.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1780948747; l=12615; i=gary@garyguo.net; s=20221204; h=from:subject:message-id; bh=l4oA9OL4IRd+F2126WqfQn4rOSqui3zNcK3p0I1bTBc=; b=Mf8jiS6DUTnAi0qFE2GOzUTaR1xm+AfT4V04lcohKcMbAe6H5g1BW+grcp+qzuC6BnCSamcoE GFAgYahvn6JAIw4gArEB9Ar0F4GD09+tbmb+ljIyg01skYcM27PSAZH X-Developer-Key: i=gary@garyguo.net; a=ed25519; pk=vB3uIX95SM4eVrIqo1DWNWKDKD2xzB+yLLLr0yOPYMo= X-ClientProxiedBy: LO4P123CA0344.GBRP123.PROD.OUTLOOK.COM (2603:10a6:600:18d::7) To LOVP265MB8871.GBRP265.PROD.OUTLOOK.COM (2603:10a6:600:488::16) 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: LOVP265MB8871:EE_|LO8P265MB7398:EE_ X-MS-Office365-Filtering-Correlation-Id: 1d851fff-a528-410d-4742-08dec5986a61 X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|1800799024|7416014|376014|366016|10070799003|6133799003|22082099003|18002099003|921020|3023799007|56012099006; X-Microsoft-Antispam-Message-Info: O89piWUkqBADUbeUroNQsw82WrmVG1mlDdcSJGE9df3C76VRmIIKxRVrUMA/nYrYPcFSLiv+RClRcdZQ126Zc4pcvtEphQNbmhe/8CIiL1sY3JtD2QrxiWuNeqGR5X70KpTpSZ5c8Im3U0gnHDPbelAfgTVTLGJKySNAgk9UBtoZ488lggmP5ehdNtLhEoGT9BPV4UM7xwjs6eYzfbNjpX1LNZWu3dkxEUtoPpRWprb8G6vsr/8OtYGsdxcfnN74PsSIJUqGqaQwB11ZhY5znVR7qJ1lr1xfoxfvR64PAfatoJUl6TVnp3rjNUDSX9vkiok62nSP+rzmdVUIESKdQvKZq27iWDRTCjtrgLGZoLTWvHxoyDhyklOP8mGBHkBnPBlRxRSFohg9CiGgYM1NmlLBtYTe3qGBKmgrr/eZUryVtrvP1gaNrseMqtz5LdBejN0kL3a2NB/XjWkwSJe3oR1lAXUzPHsSs5f4KMhtA0dojVxfSyCBr/AKyBbtgdRIGu9XLxU3Ozr8vhBlS8goTsOZBmC//i8SvDolh1Q01+C4R+Qqro77AQGG9D+kJTe8yvbxhG3iXDJSTSwwDj/XDsJFH5fjAsm7PFx9aAtQR1hs/7NenyRBQSnW/jKt5k8ccfJjH8t5ZDXRYnqpz/6xYGwaMdPQcSEYbkRDQ/zFuCjCwHvyc0lK3SoS/T6/aA/BkgnM7ofo26SteN13EC20F3aqO+GcQhEivFHFNXrKKbU= X-Forefront-Antispam-Report: CIP:255.255.255.255;CTRY:;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:LOVP265MB8871.GBRP265.PROD.OUTLOOK.COM;PTR:;CAT:NONE;SFS:(13230040)(1800799024)(7416014)(376014)(366016)(10070799003)(6133799003)(22082099003)(18002099003)(921020)(3023799007)(56012099006);DIR:OUT;SFP:1102; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: =?utf-8?B?ZG9MV0ZnK083NEtJNTlydHFmakhYSjYwS3RqZXA3TnROQUFZMXBjOC9WZ3Vo?= =?utf-8?B?TmQ1Zjh6MUoweWJxVGtGcnluZDVYUnZSK2tpN2JUVitVWXdMNlJIT0UzV2JF?= =?utf-8?B?NGhPclZnSXh2ZTZnWUdBM2tVRG9USzBMTzczOXFPN2VlRFBrVzI3aHJpSUxM?= =?utf-8?B?RFNoR2I4VUVXeTZZVWpvU1NZYjM2dHVSSlFMV2t1K2trMXZnVVNMdGxsUUpu?= =?utf-8?B?RXExYnlyaXIwa1dwY2szNTMvZEFRQmRMa21EakZZY2xiNy81c3dLZWJrMHJr?= =?utf-8?B?bmVMRWtkTWxCVHdaVjFRR0dWL1owSmRTd25raVJDc3I1ZkpSM05DV0VRbFM0?= =?utf-8?B?by9FbXZ2Y2FuSEg2VFBBdkMrQ3JtUVREQjVlV2E2Q1lPN3dZK3FhYStyTDhj?= =?utf-8?B?bmQ0WDlyM203YkhFVUloa0FhaDVaNlltZlVuZm40UnZQdVQ0cTV0c0Myb1Bm?= =?utf-8?B?MGFFcWdSRWJPSXovSVk2bUo2em4xbVhQRjR6cm1oK3ozYTJVbWlmbTR6VnZ5?= =?utf-8?B?LzM5V2hSU1NzMTc2Q25BbjhUL21rKy9EckhML3B6N2M1TWl0NGtGdk13YWM4?= =?utf-8?B?UitmZjNVdlBjTXlBcGZyeWppV2xaL0dDVTFpWWY4emwvVTZzZW12UHY3ODRr?= =?utf-8?B?R1BjOGIzSGRnZlhJZUw4TVJJTWxhVWNmbzltbEs5dllOeElCNmFOU0tNejFk?= =?utf-8?B?MGpSdlNmblZFOWRvR2F4a25WWURBOFY5d1VHc09MQ3YySUxmazlvdjVXN0s1?= =?utf-8?B?bk5Ya1lnakM0WjJzTWE2MzZ0VE0yNE1ybnBxUVRoeFVFU3J4MHlCWXUwb0hz?= =?utf-8?B?dXhLK0kzQWNQTGlaRll5ampGNUFsZkNzdDREdXFyaUtTcTFBbkdZOHNXTDNE?= =?utf-8?B?Vmg1QkkyMWNkdjBqdWhGUWxGVDFmUXNuaHloNERoWVN0aEE3d3JFRjIvS3Nv?= =?utf-8?B?dzN0bVAyaXBhVXArQVZiNUJkK1NKSFlPUU95SWhYRFpzSCtZK21oL0NUdHNj?= =?utf-8?B?RGJ3Sm8vOXpFMlNIT2RYU3RndUp0RWZZR0RuNGpmY1F6SElaRUtldCtkSVJS?= =?utf-8?B?c1N4cXdIZDFNMFN2L0NRNmJBQmNlbTRzbjBHaFBTalZOMjFtMXN3NmJCZC96?= =?utf-8?B?U3ZVUzAwZk1tUXhPUWVIUXdEYWJQaVk2Sy9ISXF6L3IxaW5jbHQrd04vTWJh?= =?utf-8?B?czIyeWpGRG9QV25MVldGWmdQd2phSEhYUEJDaHQ4RElXMHNOQjhjV1RVb2t5?= =?utf-8?B?TUY4aWRRK052RUJobGR0T3ZNRDRXWlkwVHpjdzJYUGFlOXByTmJoUHV5djJm?= =?utf-8?B?VzB0ZUlZNHhqMzZnN0x2dEVQYXQ0R3RVVGFWSjFaU2lGbHZvS1k5eGs4dS92?= =?utf-8?B?MFl2dkczb0p0VmFUKzczejVYckFmWGxaTi9WUTJlOFRqeDUybUh5L2U4TVJl?= =?utf-8?B?MUplOUkvUko1NjdVUG00MlpHVHBKZ29sU0RsaDRlNlRIdlBiVVZjNXR5YzI5?= =?utf-8?B?MUQyNk1UTnRWeEh3V29pZHlReHovZGlXb0U4TG1mcDQvTkpCWExwMzFYYnZ1?= =?utf-8?B?b0FPSXVYZWtwMDNCVmFqSU9xUmRhMFcySTlRYktBS0E0Z09ITisyaVQyTHRS?= =?utf-8?B?MlhVSE1rV3dOTkxsUmpnT2xaVVZGMFFrcDZIckdvK1BqYlMzQS9UZFhEbVFG?= =?utf-8?B?QVJnRU5rQlZGa0RJczdldVFsc2hVTU11K0wxcERXOWVKSDhaRWQ1d2gvN1o4?= =?utf-8?B?UVhKY043UTJPbU1TTGVmZ2RnT0VNOEY4TzlSdXhDOWhtSDIxaWdVTkNZZDF6?= =?utf-8?B?ZU9DdGkzbnUvR251aGticW13eERKR0dPWXpXVnI1cUlQRmFFNXgrY3lwZ2pi?= =?utf-8?B?MVhxTjI3OXlsTWJubG5pVWkzeGhMOWVrVXJXT2F0b0VCaXg1M3dTdEZrbVVF?= =?utf-8?B?UXhBVlVscWNiVWpBVHpad2NZTmVhckpWbU1DWlgranNxVWlkeW1ZWDZsZlZR?= =?utf-8?B?cjI3d0VEVlZMc2VHRUFsNk5jczRzc25lRjB0Ykh2SXRQa3VXZE44M2JlVEVw?= =?utf-8?B?bys1cHJwTlErR0pybDRGK0ZWeWhJdytOR0dpQVlCcGpJVEJiUWZUcXg5bk85?= =?utf-8?B?V1JOdmhpRDNpQ0xpQzJtUHp4VjZKV3hSeGYzbWZTMEJuVlNORGZOc2tvQmxs?= =?utf-8?B?ODMxOUVmZndsZm96SUc0WXNGU1F0Wkl2eE1VaHRHTUFRV2tLVHY1NFMzdFdT?= =?utf-8?B?dnRLdzJ5M0FNV0pjZ1F0bmJZdHYxTGM3aHh2UVd6Wkh2V0U0R25VRnVsdXh4?= =?utf-8?B?d252M2lYVlJrdUwvSkFjK0FneW5iajJyZnU5S0lLYVdCQkFQTFhjZz09?= X-OriginatorOrg: garyguo.net X-MS-Exchange-CrossTenant-Network-Message-Id: 1d851fff-a528-410d-4742-08dec5986a61 X-MS-Exchange-CrossTenant-AuthSource: LOVP265MB8871.GBRP265.PROD.OUTLOOK.COM X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 08 Jun 2026 19:59:14.4372 (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: HoAKzEoV6CqfqMbiTnHLsIrI7B6pDA4Y+kfbjud+HCIg/OrdYqFy3XKum633yXcBfr3tBlbMhtjID/iDAPf7bg== X-MS-Exchange-Transport-CrossTenantHeadersStamped: LO8P265MB7398 Use `io_project!` for PTE array and message queues to restore the proper encapsulation. The remaining `dma_read!` and `dma_write!` is now only acting on primitives; thus replace by `io_read!` and `io_write!`. Signed-off-by: Gary Guo Suggested-by: Danilo Krummrich --- drivers/gpu/nova-core/gsp.rs | 40 +++++++++++-------- drivers/gpu/nova-core/gsp/cmdq.rs | 66 +++++++++++++++++-------------- drivers/gpu/nova-core/gsp/fw.rs | 82 +++++++++++++----------------------= ---- 3 files changed, 88 insertions(+), 100 deletions(-) diff --git a/drivers/gpu/nova-core/gsp.rs b/drivers/gpu/nova-core/gsp.rs index 69175ca3315c..d18942dee61e 100644 --- a/drivers/gpu/nova-core/gsp.rs +++ b/drivers/gpu/nova-core/gsp.rs @@ -9,8 +9,14 @@ dma::{ Coherent, CoherentBox, + CoherentView, DmaAddress, // }, + io::{ + io_project, + io_write, + Io, // + }, pci, prelude::*, transmute::{ @@ -57,12 +63,17 @@ unsafe impl FromBytes for Pte= Array {} unsafe impl AsBytes for PteArray {} =20 impl PteArray { - /// Returns the page table entry for `index`, for a mapping starting a= t `start`. - // TODO: Replace with `IoView` projection once available. - fn entry(start: DmaAddress, index: usize) -> Result { - start - .checked_add(num::usize_as_u64(index) << GSP_PAGE_SHIFT) - .ok_or(EOVERFLOW) + /// Initialize a new page table array mapping `NUM_PAGES` GSP pages st= arting at address `start`. + fn init(view: CoherentView<'_, Self>, start: DmaAddress) -> Result<()>= { + for i in 0..NUM_PAGES { + io_write!(view, .0[build: i], + start + .checked_add(num::usize_as_u64(i) << GSP_PAGE_SHIFT) + .ok_or(EOVERFLOW)? + ); + } + + Ok(()) } } =20 @@ -89,17 +100,12 @@ fn new(dev: &device::Device) -> Result<= Self> { =20 let start_addr =3D obj.0.dma_handle(); =20 - // SAFETY: `obj` has just been created and we are its sole user. - let pte_region =3D unsafe { - &mut obj.0.as_mut()[size_of::()..][..RM_LOG_BUFFER_NUM_PA= GES * size_of::()] - }; - - // Write values one by one to avoid an on-stack instance of `PteAr= ray`. - for (i, chunk) in pte_region.chunks_exact_mut(size_of::()).en= umerate() { - let pte_value =3D PteArray::<0>::entry(start_addr, i)?; - - chunk.copy_from_slice(&pte_value.to_ne_bytes()); - } + let pte_view =3D io_project!( + obj.0, + [build: size_of::()..][build: ..RM_LOG_BUFFER_NUM_PAGES *= size_of::()] + ) + .try_cast::>()?; + PteArray::init(pte_view, start_addr)?; =20 Ok(obj) } diff --git a/drivers/gpu/nova-core/gsp/cmdq.rs b/drivers/gpu/nova-core/gsp/= cmdq.rs index 070de0731e95..c34b48961496 100644 --- a/drivers/gpu/nova-core/gsp/cmdq.rs +++ b/drivers/gpu/nova-core/gsp/cmdq.rs @@ -2,16 +2,23 @@ =20 mod continuation; =20 -use core::mem; +use core::{ + mem, + sync::atomic::{ + fence, + Ordering, // + }, +}; =20 use kernel::{ device, dma::{ Coherent, + CoherentBox, DmaAddress, // }, - dma_write, io::{ + io_project, poll::read_poll_timeout, Io, // }, @@ -171,20 +178,18 @@ struct MsgqData { #[repr(C)] // There is no struct defined for this in the open-gpu-kernel-source heade= rs. // Instead it is defined by code in `GspMsgQueuesInit()`. -// TODO: Revert to private once `IoView` projections replace the `gsp_mem`= module. -pub(super) struct Msgq { +struct Msgq { /// Header for sending messages, including the write pointer. - pub(super) tx: MsgqTxHeader, + tx: MsgqTxHeader, /// Header for receiving messages, including the read pointer. - pub(super) rx: MsgqRxHeader, + rx: MsgqRxHeader, /// The message queue proper. msgq: MsgqData, } =20 /// Structure shared between the driver and the GSP and containing the com= mand and message queues. #[repr(C)] -// TODO: Revert to private once `IoView` projections replace the `gsp_mem`= module. -pub(super) struct GspMem { +struct GspMem { /// Self-mapping page table entries. ptes: PteArray<{ Self::PTE_ARRAY_SIZE }>, /// CPU queue: the driver writes commands here, and the GSP reads them= . It also contains the @@ -192,13 +197,13 @@ pub(super) struct GspMem { /// index into the GSP queue. /// /// This member is read-only for the GSP. - pub(super) cpuq: Msgq, + cpuq: Msgq, /// GSP queue: the GSP writes messages here, and the driver reads them= . It also contains the /// write and read pointers that the GSP updates. This means that the = read pointer here is an /// index into the CPU queue. /// /// This member is read-only for the driver. - pub(super) gspq: Msgq, + gspq: Msgq, } =20 impl GspMem { @@ -232,20 +237,12 @@ fn new(dev: &device::Device) -> Result= { const MSGQ_SIZE: u32 =3D num::usize_into_u32::<{ size_of::()= }>(); const RX_HDR_OFF: u32 =3D num::usize_into_u32::<{ mem::offset_of!(= Msgq, rx) }>(); =20 - let gsp_mem =3D Coherent::::zeroed(dev, GFP_KERNEL)?; - - let start =3D gsp_mem.dma_handle(); - // Write values one by one to avoid an on-stack instance of `PteAr= ray`. - for i in 0..GspMem::PTE_ARRAY_SIZE { - dma_write!(gsp_mem, .ptes.0[build: i], PteArray::<0>::entry(st= art, i)?); - } + let mut gsp_mem =3D CoherentBox::::zeroed(dev, GFP_KERNEL)= ?; + gsp_mem.cpuq.tx =3D MsgqTxHeader::new(MSGQ_SIZE, RX_HDR_OFF, MSGQ_= NUM_PAGES); + gsp_mem.cpuq.rx =3D MsgqRxHeader::new(); =20 - dma_write!( - gsp_mem, - .cpuq.tx, - MsgqTxHeader::new(MSGQ_SIZE, RX_HDR_OFF, MSGQ_NUM_PAGES) - ); - dma_write!(gsp_mem, .cpuq.rx, MsgqRxHeader::new()); + let gsp_mem: Coherent<_> =3D gsp_mem.into(); + PteArray::init(io_project!(gsp_mem, .ptes), gsp_mem.dma_handle())?; =20 Ok(Self(gsp_mem)) } @@ -406,7 +403,7 @@ fn allocate_command(&mut self, size: usize, timeout: De= lta) -> Result u32 { - super::fw::gsp_mem::gsp_write_ptr(&self.0) + MsgqTxHeader::write_ptr(io_project!(self.0, .gspq.tx)) % MSGQ_NUM_= PAGES } =20 // Returns the index of the memory page the GSP will read the next com= mand from. @@ -415,7 +412,7 @@ fn gsp_write_ptr(&self) -> u32 { // // - The returned value is within `0..MSGQ_NUM_PAGES`. fn gsp_read_ptr(&self) -> u32 { - super::fw::gsp_mem::gsp_read_ptr(&self.0) + MsgqRxHeader::read_ptr(io_project!(self.0, .gspq.rx)) % MSGQ_NUM_P= AGES } =20 // Returns the index of the memory page the CPU can read the next mess= age from. @@ -424,12 +421,18 @@ fn gsp_read_ptr(&self) -> u32 { // // - The returned value is within `0..MSGQ_NUM_PAGES`. fn cpu_read_ptr(&self) -> u32 { - super::fw::gsp_mem::cpu_read_ptr(&self.0) + MsgqRxHeader::read_ptr(io_project!(self.0, .cpuq.rx)) % MSGQ_NUM_P= AGES } =20 // Informs the GSP that it can send `elem_count` new pages into the me= ssage queue. fn advance_cpu_read_ptr(&mut self, elem_count: u32) { - super::fw::gsp_mem::advance_cpu_read_ptr(&self.0, elem_count) + let rx =3D io_project!(self.0, .cpuq.rx); + let rptr =3D MsgqRxHeader::read_ptr(rx).wrapping_add(elem_count) %= MSGQ_NUM_PAGES; + + // Ensure read pointer is properly ordered. + fence(Ordering::SeqCst); + + MsgqRxHeader::set_read_ptr(rx, rptr) } =20 // Returns the index of the memory page the CPU can write the next com= mand to. @@ -438,12 +441,17 @@ fn advance_cpu_read_ptr(&mut self, elem_count: u32) { // // - The returned value is within `0..MSGQ_NUM_PAGES`. fn cpu_write_ptr(&self) -> u32 { - super::fw::gsp_mem::cpu_write_ptr(&self.0) + MsgqTxHeader::write_ptr(io_project!(self.0, .cpuq.tx)) % MSGQ_NUM_= PAGES } =20 // Informs the GSP that it can process `elem_count` new pages from the= command queue. fn advance_cpu_write_ptr(&mut self, elem_count: u32) { - super::fw::gsp_mem::advance_cpu_write_ptr(&self.0, elem_count) + let tx =3D io_project!(self.0, .cpuq.tx); + let wptr =3D MsgqTxHeader::write_ptr(tx).wrapping_add(elem_count) = % MSGQ_NUM_PAGES; + MsgqTxHeader::set_write_ptr(tx, wptr); + + // Ensure all command data is visible before triggering the GSP re= ad. + fence(Ordering::SeqCst); } } =20 diff --git a/drivers/gpu/nova-core/gsp/fw.rs b/drivers/gpu/nova-core/gsp/fw= .rs index 4db0cfa4dc4d..b0e7de328eaf 100644 --- a/drivers/gpu/nova-core/gsp/fw.rs +++ b/drivers/gpu/nova-core/gsp/fw.rs @@ -10,7 +10,14 @@ use core::ops::Range; =20 use kernel::{ - dma::Coherent, + dma::{ + Coherent, + CoherentView, // + }, + io::{ + io_read, + io_write, // + }, prelude::*, ptr::{ Alignable, @@ -44,59 +51,6 @@ }, }; =20 -// TODO: Replace with `IoView` projections once available. -pub(super) mod gsp_mem { - use core::sync::atomic::{ - fence, - Ordering, // - }; - - use kernel::{ - dma::Coherent, - dma_read, - dma_write, // - }; - - use crate::gsp::cmdq::{ - GspMem, - MSGQ_NUM_PAGES, // - }; - - pub(in crate::gsp) fn gsp_write_ptr(qs: &Coherent) -> u32 { - dma_read!(qs, .gspq.tx.0.writePtr) % MSGQ_NUM_PAGES - } - - pub(in crate::gsp) fn gsp_read_ptr(qs: &Coherent) -> u32 { - dma_read!(qs, .gspq.rx.0.readPtr) % MSGQ_NUM_PAGES - } - - pub(in crate::gsp) fn cpu_read_ptr(qs: &Coherent) -> u32 { - dma_read!(qs, .cpuq.rx.0.readPtr) % MSGQ_NUM_PAGES - } - - pub(in crate::gsp) fn advance_cpu_read_ptr(qs: &Coherent, coun= t: u32) { - let rptr =3D cpu_read_ptr(qs).wrapping_add(count) % MSGQ_NUM_PAGES; - - // Ensure read pointer is properly ordered. - fence(Ordering::SeqCst); - - dma_write!(qs, .cpuq.rx.0.readPtr, rptr); - } - - pub(in crate::gsp) fn cpu_write_ptr(qs: &Coherent) -> u32 { - dma_read!(qs, .cpuq.tx.0.writePtr) % MSGQ_NUM_PAGES - } - - pub(in crate::gsp) fn advance_cpu_write_ptr(qs: &Coherent, cou= nt: u32) { - let wptr =3D cpu_write_ptr(qs).wrapping_add(count) % MSGQ_NUM_PAGE= S; - - dma_write!(qs, .cpuq.tx.0.writePtr, wptr); - - // Ensure all command data is visible before triggering the GSP re= ad. - fence(Ordering::SeqCst); - } -} - /// Maximum size of a single GSP message queue element in bytes. pub(crate) const GSP_MSG_QUEUE_ELEMENT_SIZE_MAX: usize =3D num::u32_as_usize(bindings::GSP_MSG_QUEUE_ELEMENT_SIZE_MAX); @@ -720,6 +674,16 @@ pub(crate) fn new(msgq_size: u32, rx_hdr_offset: u32, = msg_count: u32) -> Self { entryOff: num::usize_into_u32::(), }) } + + /// Returns the value of the write pointer for this queue. + pub(crate) fn write_ptr(this: CoherentView<'_, Self>) -> u32 { + io_read!(this, .0.writePtr) + } + + /// Sets the value of the write pointer for this queue. + pub(crate) fn set_write_ptr(this: CoherentView<'_, Self>, val: u32) { + io_write!(this, .0.writePtr, val) + } } =20 // SAFETY: Padding is explicit and does not contain uninitialized data. @@ -735,6 +699,16 @@ impl MsgqRxHeader { pub(crate) fn new() -> Self { Self(Default::default()) } + + /// Returns the value of the read pointer for this queue. + pub(crate) fn read_ptr(this: CoherentView<'_, Self>) -> u32 { + io_read!(this, .0.readPtr) + } + + /// Sets the value of the read pointer for this queue. + pub(crate) fn set_read_ptr(this: CoherentView<'_, Self>, val: u32) { + io_write!(this, .0.readPtr, val) + } } =20 // SAFETY: Padding is explicit and does not contain uninitialized data. --=20 2.54.0 From nobody Thu Jun 25 00:35:31 2026 Received: from LO3P265CU004.outbound.protection.outlook.com (mail-uksouthazon11020097.outbound.protection.outlook.com [52.101.196.97]) (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 0B5693F0AA2; Mon, 8 Jun 2026 19:59:35 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=52.101.196.97 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780948778; cv=fail; b=exCXz4Uw0So+IQZufdawzT+RZo/wqYTYB0+1bKwf1UrrCAGLniWxJzLPL8XB0sokGTt2U5yN+jWh5uLj0uDzylX8+05NGKnhUFry5V247XOF6/qMqHKXxNtDJy1He7k0XV9b6I8HGD68RJmwnmxQ7iqsVlghXdHjPlgUljPoHwU= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780948778; c=relaxed/simple; bh=U4sgtg+PsZydA75oyiPMnCQI7oPllCK0F9P8o45F4bU=; h=From:Date:Subject:Content-Type:Message-Id:References:In-Reply-To: To:Cc:MIME-Version; b=CnpaKox9N+ZpZLp3e2ihM2oCOc2vp5a/uZEDniIsFjInChDjgbd51Ap+0iKfqIQQKXcx6hBf/ugr6cOOE0ceW9Er27Gat5hBvHaiwNqMrqxOqpnRn1XWuZlPdL9PtdkrjBY3/iuipc3EmLBMx48tUUebYc8nklCiZU/7sEDewZA= 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=pJ15MoaS; arc=fail smtp.client-ip=52.101.196.97 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="pJ15MoaS" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=B05WzdrPnftNMMblVFWP2ZpfsQytPFqSmm6cabY1a6PQFEG514vmInfTfAm3HHIXiTF+zbu+EUS0kxrXQBwhHLn07M0CocdEfU67ZWw2r1hvh/m81x2RuNqrByPvRSuDzleoEk/qe3YjyburAyljRet4/XqU0ny2NLdgQgDyuDMwaknkqu0bOqX8Rp62ZijS3IG7DffFez2rVjQtjV5Ogmjyz8/UeWXPAivYKY9XRzmx5fLUERnW5syiAm4yunVkW6V927ZxJahpoHGzDK/1dl3pDxON+3ZrGNZ3w2Pc5qd+lRIrNbDTxjGcoapbZLiNBFdnQctXYSp4G2g4arX/wQ== 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=m6s55GE3t+EaTIWGewrRvkHNiIicUa9eIXKL7E2bCF8=; b=bka7w/5w+TRXjZBDi28bW5Vv2QO7GbBsfKVV5Jahxjrtt/IksYQaI6ZIIjOdYw4Tskz/ro0134ptM2YyIcaOKWGd9AaJCslO5euTZPVWRUoQbvR5Cn1YEM4zf4lZkR+tebJ06kSY0/gMC/nEng9XePD2XMKcgnoRsHgJrqJlktsHdk66/2qcjVLMwKRXoF3YVAJXuCj1wjLcEEXE9x7zISAsY7Jf5V2gDDHgBqXVRSJp3CkqzlUPsx/G65uFn49UpxL32S4o2Dh5Cx2grY6Rg9MWw7eQO21RtGnoZDZV/Ith+ZCxsvgESNB8T02fYIfuhQ4Fl+t7Rhz0GWa9BbHTtQ== 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=m6s55GE3t+EaTIWGewrRvkHNiIicUa9eIXKL7E2bCF8=; b=pJ15MoaS+CuY4ivroL7bt39o+qNebBC+PizjnV46Es87UlycTY5sSnS43LkHCfcPx1GtLeIvyDS0v6XukdvjnAIQkmeg/2loUhffpHjYJ9gNwuPJG7dbmhO2EHvERYWLKhbqS9uHQ5E89MVVyc1Df3E1goWbaDcPEw7ErG4cokc= Authentication-Results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=garyguo.net; Received: from LOVP265MB8871.GBRP265.PROD.OUTLOOK.COM (2603:10a6:600:488::16) by LO8P265MB7398.GBRP265.PROD.OUTLOOK.COM (2603:10a6:600:3ca::5) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.21.92.12; Mon, 8 Jun 2026 19:59:14 +0000 Received: from LOVP265MB8871.GBRP265.PROD.OUTLOOK.COM ([fe80::1c3:ceba:21b4:9986]) by LOVP265MB8871.GBRP265.PROD.OUTLOOK.COM ([fe80::1c3:ceba:21b4:9986%4]) with mapi id 15.21.0092.011; Mon, 8 Jun 2026 19:59:14 +0000 From: Gary Guo Date: Mon, 08 Jun 2026 20:59:14 +0100 Subject: [PATCH v3 17/19] rust: dma: drop `dma_read!` and `dma_write!` API Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260608-io_projection-v3-17-c5cde13a5ec4@garyguo.net> References: <20260608-io_projection-v3-0-c5cde13a5ec4@garyguo.net> In-Reply-To: <20260608-io_projection-v3-0-c5cde13a5ec4@garyguo.net> To: Danilo Krummrich , Alice Ryhl , Daniel Almeida , Greg Kroah-Hartman , "Rafael J. Wysocki" , Miguel Ojeda , Boqun Feng , Gary Guo , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Andreas Hindborg , Trevor Gross , Bjorn Helgaas , =?utf-8?q?Krzysztof_Wilczy=C5=84ski?= , Abdiel Janulgue , Robin Murphy , Alexandre Courbot , David Airlie , Simona Vetter Cc: driver-core@lists.linux.dev, rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, linux-pci@vger.kernel.org, nova-gpu@lists.linux.dev, dri-devel@lists.freedesktop.org X-Mailer: b4 0.15.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1780948747; l=8864; i=gary@garyguo.net; s=20221204; h=from:subject:message-id; bh=U4sgtg+PsZydA75oyiPMnCQI7oPllCK0F9P8o45F4bU=; b=mFuP8PQ2/l5oFJKw/nExr6QOfHGRroas+dN2Pz1rGYirQdOwehSLTajFut8g3GSf6f9dhEWdB vndkhp2ppF0AFbuK6jNACZFBBNPZ9DChDPgGs4V6cqM0c9Sui0hBgL1 X-Developer-Key: i=gary@garyguo.net; a=ed25519; pk=vB3uIX95SM4eVrIqo1DWNWKDKD2xzB+yLLLr0yOPYMo= X-ClientProxiedBy: LO4P123CA0344.GBRP123.PROD.OUTLOOK.COM (2603:10a6:600:18d::7) To LOVP265MB8871.GBRP265.PROD.OUTLOOK.COM (2603:10a6:600:488::16) 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: LOVP265MB8871:EE_|LO8P265MB7398:EE_ X-MS-Office365-Filtering-Correlation-Id: 0fb4bd58-b4b3-407f-4ede-08dec5986aa0 X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|1800799024|7416014|376014|366016|10070799003|6133799003|22082099003|18002099003|921020|3023799007|56012099006|5023799004; X-Microsoft-Antispam-Message-Info: tRbjzXP68waXnVxUmBSPTFyTQhOdlKJ1yH2f2Y4fXbCo4uo8KaS+xl4gPYwa6Jgx4IjNOGPWBWzQiH8XaLzfyi5LE7y/TeTfS4F9Ah2s90UNO1slcC+HjvLKtU5PukhvqezM+SJ6hgUP9pByxWlLHYtPhAUgLteQlamqxTW/SfRbKiQU6s9iEB6h5vheF69MGxQ1LdkVjsdtPWRy2oAne5UthLUPxiN5uOVB9FxVvQOE6HFk3jh56jaST7cvyVLHjbLDVQHMdmAY5Y39llmRMWQav1sHBd69Sk68JgmY23cvuHBjSnA2AdZoLBmdMQWA7vhhYR1P/9LfZVMQxd5ngb4GBhXh7UJoumP62sV0Yigv+NPjp5EAhmCOZvj5gF29R/U/61WxXZ6Zv0aHurQsNyWVgiTCGRKqLPkQXZFhEFLA4ymcS+vc9UYCU8upCybjNFaPIcMCwnfMY+iZxCkPHmk3KLsW6+aAzCGubqZZCJL+VX7Ou0cTFFMvpnH5RT/8HPQGVNRHAV90i2h0X4beW3zxuC09XM6ojurRHm3PlBUOF6wj/m5mmQee3jEbkJ5/GDHiUTUrRyp1K0+6Bv4QWuyzimvaJ7+GxBzF/2krEsCEqOvUxU9xDxRTHokAyT7T6lK5NM41SxluSOVsdnYywPKkXx1V0eX31fiMeXwPI3LJE2xSdMECMJFJExyvVDE7WngGSicHYTEG1O4WaPqrpBbRm3rfltAh9jWb5iAzGhM= X-Forefront-Antispam-Report: CIP:255.255.255.255;CTRY:;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:LOVP265MB8871.GBRP265.PROD.OUTLOOK.COM;PTR:;CAT:NONE;SFS:(13230040)(1800799024)(7416014)(376014)(366016)(10070799003)(6133799003)(22082099003)(18002099003)(921020)(3023799007)(56012099006)(5023799004);DIR:OUT;SFP:1102; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: =?utf-8?B?d0J6bjB3amRzRXJzbVNvYktqMmhOWmpTOGYxMEZWOStwYlBvWlQ2ZVQrVlNj?= =?utf-8?B?UjVsQ0JGWnFqZnIzYVRqMXVoMWltaHl3VHllQ3VkQnRTTnVmdy9VdEtYRWlr?= =?utf-8?B?WjRnWWdtc2xoVVNzUWJlL043ZDdSWjAxY0NnUHZmWXIxZ1grZHRUVkRmaWF2?= =?utf-8?B?NTRSS1VTK2tROVltYjJtNHpPS2ozaW1XemxmTnRKdWtJRFgreERkNjNaVytv?= =?utf-8?B?bWU4ZzhVeXY3N1ZqVThDS2dCYm43b0JwYjRoVDloWEw0SW1wZ1hraDJuRzZn?= =?utf-8?B?S3psUGdWUGxxaVJQd0FOcjBIMjBURGtneXhSem12OFBGNFQyVU0vY0VaYnFP?= =?utf-8?B?WlBHSWt0bEh5WFN0Z1QwbmxQNUpINzJhREFKYzZrRkppanptaHNsYS9tUGNN?= =?utf-8?B?cEdKMUlINUlGdFAzV25kVmZ5alBkNzg5MkNqL1kzenFNY2pTTWdtN3dRcEdi?= =?utf-8?B?SjNFUUNwbXJSbFYwelNBTDltQ3A0NDRKYlFISHBWbm9sN0VFZVFTZlI5cVBH?= =?utf-8?B?RGw5dkhPSUlmUzB3QnhjeSttMTB0Q3MrT016OVhleXRqUEx4dS9DRmxQYmxy?= =?utf-8?B?VkhlL29BUEdhQ2ZlSUZRMHBSa3JEWW0xUTVJVFVkU3J4OFNyNFdFUUFMUzhj?= =?utf-8?B?cFZrUm9KbVMyVlo4SGptYURkYVNxUENOV3l2djNoN090L0RtK2hpcCtiTitL?= =?utf-8?B?ODk2cStRNE5CN1owbkVVdkljS3FoN2hRWUJnaGpkNFlqYzg5ZGtDMWhSeldh?= =?utf-8?B?d2xJR1BLZDN2d0l6SXQ0aTJJMFV3bUllTVN3ZjR4cmJZdDdmQ3ZtNit3eUpP?= =?utf-8?B?NlRlbVNGd2tLd2NBYWtHYlhnSzF3TXc0RzVZa2hmdXd4ZURUU1A2dnk0U0VT?= =?utf-8?B?US8ySVJySnBkTXErU1V0aEwybnRwcjJPc2lHZWg5OG5qcitreHNkUGZ5UC9y?= =?utf-8?B?QThyQ3RjbTlZekErN2tjNFYvYlc0WU41eFFLNjE1bG1ubHM1VnNGQVhwNzht?= =?utf-8?B?eU1EV1UwL1VTZFJUTWJqWWV4ZUM3OElTa0lWc29QVGxnUk1YVmVDb0RBYk0w?= =?utf-8?B?WkVLVUNUUitvdnNEbkZ5Wm1JRkY4NE5YZGdOdHhYVVlvRWI1NVhKMlhjMHp4?= =?utf-8?B?c3lERi9iekJFWk9HZDBJKzFFTnI0eTUwRE1hdHlPWHdvWUxCMkdFNVlFUTll?= =?utf-8?B?azgvbVBwQzVGcUlXRkorZWJZZTcwMzFSYkJjWkFxaGx3VFd2cVZHdnIzQkVO?= =?utf-8?B?anlZNDVRUlQzakFJa1ZzbjQyUndGMzdsZndMbk11S1BDTTl1RkJ3eXphbksy?= =?utf-8?B?WlNwNkExM09NNjRCUFNVUGpMNHQzWGFJbDltNTg2d3NwejBOTGI1aitRWjZW?= =?utf-8?B?YUJDNjBnNkZGdEtUekdZQXJMTFRMVmVOWjU5N1Z0cVNtaXErUGFMT011VEVF?= =?utf-8?B?ZFNRdHVmSno3WUV4NXpIbm95aWxrbjhHaGZ1bmlVQVlYM3BBRWNORWE1V3Vu?= =?utf-8?B?VEVXYlFpbDNNS1B4NE82YzBVald3amloaGFmN3VmVEZOaENFNlJhSWJFUEFx?= =?utf-8?B?ZkRCRkhCTlF4bzJPaHpUaThMY04wK3ZBMm1ndG5ESmUyWFFhbDkyeFRCTjdP?= =?utf-8?B?ZHA0Z2RpTzh0TndEQWM5ZUdlay8yazF2VzErNlVEKytrRTFUbjIzdTI3WktX?= =?utf-8?B?d2tTdTNERGxVRDRDN2FQVXRNb2tENDNDT1dGLzMzYld0MytnM0huMHB0VjRW?= =?utf-8?B?UUVhOUpiUDdER1dvN0E1NDdiNWxiUFlGcUloQ3lCT1BEd3hoN29oWnZkWjR0?= =?utf-8?B?YTZQVzhCbHVEL29LcnpjZlRoUW5jOFJaT2dUVUhVQmFrSUJhQk5LNUw5WE5w?= =?utf-8?B?OGZDaEFXdjF6dmlhby9NVGM0dWdjeVdpOTNmQnpETnhoeTkvczRuRXJwS1d6?= =?utf-8?B?RVFsNFhNTG5vUis5elhyMlluTm9UR3F4Qmt6OTZNVmNtR1BoQjhVZUo2aW9x?= =?utf-8?B?eTNOOXRZcHRteHhTMlU0T3dCdlVMa1FlT3BHVXRBa0hmTkJrQkJRak82cEc1?= =?utf-8?B?cjIvQ3Q3UStzZS9rQU51QXF1TmlhTEN2SE40K1FHVUR1akZ0dnkwTWtyU2h4?= =?utf-8?B?S3QzVUhzS3RheWtBbnBHc2JuSmU5L3dmS1hZaEM4SzVFOXg1OTRTcFdLN0do?= =?utf-8?B?a3dhdFJOcW9IMko3MlpOYXR5L3plRWFXNzZ0NjlMaEZpci9lejBaY21nZE5B?= =?utf-8?B?NmxTQU9wM0RicnpjemJ1Mm9qZ0NvYlg1QXB5eHJJQ0IwMlpieHk1QktvL1BZ?= =?utf-8?B?WGF1MTRuU3RyL2kzQVBqUFhGL1lUTGVaZVliVXJyeU5aYlM5UUllQT09?= X-OriginatorOrg: garyguo.net X-MS-Exchange-CrossTenant-Network-Message-Id: 0fb4bd58-b4b3-407f-4ede-08dec5986aa0 X-MS-Exchange-CrossTenant-AuthSource: LOVP265MB8871.GBRP265.PROD.OUTLOOK.COM X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 08 Jun 2026 19:59:14.8460 (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: JS1iwd/qHimgLXQQdyu9xG6Jy4lo66Mp2B17SqTvV1HMVDaqnA8qlvq5vrM6SThf7985gE0yaQtZBvpwZr2gHw== X-MS-Exchange-Transport-CrossTenantHeadersStamped: LO8P265MB7398 The primitive read/write use case is covered by the `io_read!` and `io_write!` macro. The non-primitive use case was finicky; they should either be achieved using `CoherentBox` or `as_ref()/as_mut()` to assert the lack of concurrent access, or should be using memcpy-like APIs to express the non-atomic and tearable nature. Reviewed-by: Andreas Hindborg Signed-off-by: Gary Guo Suggested-by: Danilo Krummrich --- rust/kernel/dma.rs | 128 -------------------------------------------= ---- samples/rust/rust_dma.rs | 13 ++--- 2 files changed, 7 insertions(+), 134 deletions(-) diff --git a/rust/kernel/dma.rs b/rust/kernel/dma.rs index 970a667b9be2..68015a2ab43b 100644 --- a/rust/kernel/dma.rs +++ b/rust/kernel/dma.rs @@ -661,52 +661,6 @@ pub unsafe fn as_mut(&self) -> &mut T { // SAFETY: per safety requirement. unsafe { &mut *self.as_mut_ptr() } } - - /// Reads the value of `field` and ensures that its type is [`FromByte= s`]. - /// - /// # Safety - /// - /// This must be called from the [`dma_read`] macro which ensures that= the `field` pointer is - /// validated beforehand. - /// - /// Public but hidden since it should only be used from [`dma_read`] m= acro. - #[doc(hidden)] - pub unsafe fn field_read(&self, field: *const F) -> F { - // SAFETY: - // - By the safety requirements field is valid. - // - Using read_volatile() here is not sound as per the usual rule= s, the usage here is - // a special exception with the following notes in place. When dea= ling with a potential - // race from a hardware or code outside kernel (e.g. user-space pr= ogram), we need that - // read on a valid memory is not UB. Currently read_volatile() is = used for this, and the - // rationale behind is that it should generate the same code as RE= AD_ONCE() which the - // kernel already relies on to avoid UB on data races. Note that t= he usage of - // read_volatile() is limited to this particular case, it cannot b= e used to prevent - // the UB caused by racing between two kernel functions nor do the= y provide atomicity. - unsafe { field.read_volatile() } - } - - /// Writes a value to `field` and ensures that its type is [`AsBytes`]. - /// - /// # Safety - /// - /// This must be called from the [`dma_write`] macro which ensures tha= t the `field` pointer is - /// validated beforehand. - /// - /// Public but hidden since it should only be used from [`dma_write`] = macro. - #[doc(hidden)] - pub unsafe fn field_write(&self, field: *mut F, val: F) { - // SAFETY: - // - By the safety requirements field is valid. - // - Using write_volatile() here is not sound as per the usual rul= es, the usage here is - // a special exception with the following notes in place. When dea= ling with a potential - // race from a hardware or code outside kernel (e.g. user-space pr= ogram), we need that - // write on a valid memory is not UB. Currently write_volatile() i= s used for this, and the - // rationale behind is that it should generate the same code as WR= ITE_ONCE() which the - // kernel already relies on to avoid UB on data races. Note that t= he usage of - // write_volatile() is limited to this particular case, it cannot = be used to prevent - // the UB caused by racing between two kernel functions nor do the= y provide atomicity. - unsafe { field.write_volatile(val) } - } } =20 impl Coherent { @@ -1265,85 +1219,3 @@ fn as_view(self) -> CoherentView<'a, Self::Target> { } } } - -/// Reads a field of an item from an allocated region of structs. -/// -/// The syntax is of the form `kernel::dma_read!(dma, proj)` where `dma` i= s an expression evaluating -/// to a [`Coherent`] and `proj` is a [projection specification](kernel::p= tr::project!). -/// -/// # Examples -/// -/// ``` -/// use kernel::device::Device; -/// use kernel::dma::{attrs::*, Coherent}; -/// -/// struct MyStruct { field: u32, } -/// -/// // SAFETY: All bit patterns are acceptable values for `MyStruct`. -/// unsafe impl kernel::transmute::FromBytes for MyStruct{}; -/// // SAFETY: Instances of `MyStruct` have no uninitialized portions. -/// unsafe impl kernel::transmute::AsBytes for MyStruct{}; -/// -/// # fn test(alloc: &kernel::dma::Coherent<[MyStruct]>) -> Result { -/// let whole =3D kernel::dma_read!(alloc, [try: 2]); -/// let field =3D kernel::dma_read!(alloc, [panic: 1].field); -/// # Ok::<(), Error>(()) } -/// ``` -#[macro_export] -macro_rules! dma_read { - ($dma:expr, $($proj:tt)*) =3D> {{ - let dma =3D &$dma; - let ptr =3D $crate::ptr::project!( - $crate::dma::Coherent::as_ptr(dma), $($proj)* - ); - // SAFETY: The pointer created by the projection is within the DMA= region. - unsafe { $crate::dma::Coherent::field_read(dma, ptr) } - }}; -} - -/// Writes to a field of an item from an allocated region of structs. -/// -/// The syntax is of the form `kernel::dma_write!(dma, proj, val)` where `= dma` is an expression -/// evaluating to a [`Coherent`], `proj` is a -/// [projection specification](kernel::ptr::project!), and `val` is the va= lue to be written to the -/// projected location. -/// -/// # Examples -/// -/// ``` -/// use kernel::device::Device; -/// use kernel::dma::{attrs::*, Coherent}; -/// -/// struct MyStruct { member: u32, } -/// -/// // SAFETY: All bit patterns are acceptable values for `MyStruct`. -/// unsafe impl kernel::transmute::FromBytes for MyStruct{}; -/// // SAFETY: Instances of `MyStruct` have no uninitialized portions. -/// unsafe impl kernel::transmute::AsBytes for MyStruct{}; -/// -/// # fn test(alloc: &kernel::dma::Coherent<[MyStruct]>) -> Result { -/// kernel::dma_write!(alloc, [try: 2].member, 0xf); -/// kernel::dma_write!(alloc, [panic: 1], MyStruct { member: 0xf }); -/// # Ok::<(), Error>(()) } -/// ``` -#[macro_export] -macro_rules! dma_write { - (@parse [$dma:expr] [$($proj:tt)*] [, $val:expr]) =3D> {{ - let dma =3D &$dma; - let ptr =3D $crate::ptr::project!( - mut $crate::dma::Coherent::as_mut_ptr(dma), $($proj)* - ); - let val =3D $val; - // SAFETY: The pointer created by the projection is within the DMA= region. - unsafe { $crate::dma::Coherent::field_write(dma, ptr, val) } - }}; - (@parse [$dma:expr] [$($proj:tt)*] [.$field:tt $($rest:tt)*]) =3D> { - $crate::dma_write!(@parse [$dma] [$($proj)* .$field] [$($rest)*]) - }; - (@parse [$dma:expr] [$($proj:tt)*] [[$flavor:ident: $index:expr] $($re= st:tt)*]) =3D> { - $crate::dma_write!(@parse [$dma] [$($proj)* [$flavor: $index]] [$(= $rest)*]) - }; - ($dma:expr, $($rest:tt)*) =3D> { - $crate::dma_write!(@parse [$dma] [] [$($rest)*]) - }; -} diff --git a/samples/rust/rust_dma.rs b/samples/rust/rust_dma.rs index 5046b4628d0e..6727c441658a 100644 --- a/samples/rust/rust_dma.rs +++ b/samples/rust/rust_dma.rs @@ -12,6 +12,7 @@ Device, DmaMask, // }, + io::io_read, page, pci, prelude::*, scatterlist::{Owned, SGTable}, @@ -73,11 +74,11 @@ fn probe<'bound>( // SAFETY: There are no concurrent calls to DMA allocation and= mapping primitives. unsafe { pdev.dma_set_mask_and_coherent(mask)? }; =20 - let ca: Coherent<[MyStruct]> =3D - Coherent::zeroed_slice(pdev.as_ref(), TEST_VALUES.len(), G= FP_KERNEL)?; + let mut ca: CoherentBox<[MyStruct]> =3D + CoherentBox::zeroed_slice(pdev.as_ref(), TEST_VALUES.len()= , GFP_KERNEL)?; =20 for (i, value) in TEST_VALUES.into_iter().enumerate() { - kernel::dma_write!(ca, [try: i], MyStruct::new(value.0, va= lue.1)); + ca.init_at(i, MyStruct::new(value.0, value.1))?; } =20 let size =3D 4 * page::PAGE_SIZE; @@ -87,7 +88,7 @@ fn probe<'bound>( =20 Ok(try_pin_init!(Self { pdev: pdev.into(), - ca, + ca: ca.into(), sgt <- sgt, })) }) @@ -97,8 +98,8 @@ fn probe<'bound>( impl DmaSampleDriver { fn check_dma(&self) { for (i, value) in TEST_VALUES.into_iter().enumerate() { - let val0 =3D kernel::dma_read!(self.ca, [panic: i].h); - let val1 =3D kernel::dma_read!(self.ca, [panic: i].b); + let val0 =3D io_read!(self.ca, [panic: i].h); + let val1 =3D io_read!(self.ca, [panic: i].b); =20 assert_eq!(val0, value.0); assert_eq!(val1, value.1); --=20 2.54.0 From nobody Thu Jun 25 00:35:31 2026 Received: from LO3P265CU004.outbound.protection.outlook.com (mail-uksouthazon11020080.outbound.protection.outlook.com [52.101.196.80]) (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 6F9DB3F4DEF; Mon, 8 Jun 2026 19:59:37 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=52.101.196.80 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780948781; cv=fail; b=DB5DXJRvVg1YsYecjYb1+Mt84fHo6awfXOcyurGuZ7URVIJlAFD90a8FXmyoSSHWghxgmFp6/bFuf1iVk2gIaUgWl0tpJQRFm87uwxTR2LoYp05bnFuguoZQ2sOqepekf2ChlpEE2KLnan7/rCvZ2y3IYBW01ju/kFvGm6xGGgM= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780948781; c=relaxed/simple; bh=c8KGbabCBL6sAYhen1qcmvo3+fDJott3INnsajYTRfw=; h=From:Date:Subject:Content-Type:Message-Id:References:In-Reply-To: To:Cc:MIME-Version; b=lTysVpg2qe2/BcPY6svM89bapvYMOa1/Lte5g5RWleZ3Ie+H7xv21BwTjkC/WaUxnfGDIY5QpvZxmPQOlt3JAHW06/a/vWWKYMftOsF5dtLbQMtpEd17fepqgpVTgqasulkNWyRG8mGdnJ7pYdtoc/8+UNmyRBsPN4d32uilOtE= 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=CDGgfbBD; arc=fail smtp.client-ip=52.101.196.80 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="CDGgfbBD" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=BWaUddGdCZco4ZH2PE9524tBoRaSEvYHNXSi1NfwQd/6/1W/SgFcdH6ytlg9Kq6w4//P6/yQ+ncioO7zbRooI0uAvDyB0TKafuLQpcO8bvW4/nR6VkiV7o6NvXwa7FQrF+S5LzUIvKrxnUZtHtii3zUCmJ+Tc7kGnH5P7N52WVSS1YPO0OlRtaU8IlQ7z4D+PeTLqhQcKc9yE20fHrsaf0CMoOLsV/SRQ038QDvxfW4B5QfMd3vs//oQmvAc+6qGUpEk2LjDGQHUmtwECgWMoVShu6hGW3CWrnw08lYVNjo/neMnMn5mysq0djrNZjtboY3bih1Qxfz5mMPc70DwAg== 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=gLY78DnMjTBxpAlQ4zjOKgVSGoGLmiVXpyredJYtrDQ=; b=vqqppThUhgnF4j+JLPC1OG7jGS5F5/UzxYS0SoD8q5jUikZiJdP++VW8Ip/n80dyv7C7KQ9Zb6ikVob5yWfjZY+c+87aOTTBmxd1X2TaO53RXX/ppica2eVrd+XSL89xJ+Bst73S6jhuqxe2rqYplbnn+vFstW8ku6jChodBbM2nB7djliMzOLg7GjtpMsxSGkjyUgFjROzhXT2KVOti6R/xDR1C9uwMv/BfTkXSnMTSVymWO4LWnS6cNWyZhnXSzPKvxaK4tvQNc7oI3UoXnjZiFkRzl/XVa54yvh+/u+UiApCmP98noaW67KpecDl+Fys6NFUcN0ddcnqruLaP2w== 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=gLY78DnMjTBxpAlQ4zjOKgVSGoGLmiVXpyredJYtrDQ=; b=CDGgfbBDNg4SL4HWgBHDhKaAu3dKJQrW9VlesMtVMsTjVn6JSR+LCVmM5DCyAuJemHKBXxQmK5VYbmridpD2lBFxD8xYeUTXvh3dA2gXkdPnX8eZkTAkbYoEtDxwg46AVC2Z6rSipo1tI1yY3DL4tC5h35T4oqYvlUHjLB2CYS4= Authentication-Results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=garyguo.net; Received: from LOVP265MB8871.GBRP265.PROD.OUTLOOK.COM (2603:10a6:600:488::16) by LO8P265MB7398.GBRP265.PROD.OUTLOOK.COM (2603:10a6:600:3ca::5) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.21.92.12; Mon, 8 Jun 2026 19:59:15 +0000 Received: from LOVP265MB8871.GBRP265.PROD.OUTLOOK.COM ([fe80::1c3:ceba:21b4:9986]) by LOVP265MB8871.GBRP265.PROD.OUTLOOK.COM ([fe80::1c3:ceba:21b4:9986%4]) with mapi id 15.21.0092.011; Mon, 8 Jun 2026 19:59:15 +0000 From: Gary Guo Date: Mon, 08 Jun 2026 20:59:15 +0100 Subject: [PATCH v3 18/19] rust: io: add copying methods Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260608-io_projection-v3-18-c5cde13a5ec4@garyguo.net> References: <20260608-io_projection-v3-0-c5cde13a5ec4@garyguo.net> In-Reply-To: <20260608-io_projection-v3-0-c5cde13a5ec4@garyguo.net> To: Danilo Krummrich , Alice Ryhl , Daniel Almeida , Greg Kroah-Hartman , "Rafael J. Wysocki" , Miguel Ojeda , Boqun Feng , Gary Guo , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Andreas Hindborg , Trevor Gross , Bjorn Helgaas , =?utf-8?q?Krzysztof_Wilczy=C5=84ski?= , Abdiel Janulgue , Robin Murphy , Alexandre Courbot , David Airlie , Simona Vetter Cc: driver-core@lists.linux.dev, rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, linux-pci@vger.kernel.org, nova-gpu@lists.linux.dev, dri-devel@lists.freedesktop.org X-Mailer: b4 0.15.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1780948747; l=18950; i=gary@garyguo.net; s=20221204; h=from:subject:message-id; bh=c8KGbabCBL6sAYhen1qcmvo3+fDJott3INnsajYTRfw=; b=lpEhKXaXkbrh4egeITFgbW01gTEkqLExTrk6euk8iWHZNjifc9sAFLT3GQCSdZ4xfZWvxMYZF Fo963E4z8YIDfpLAYRdMc6xq/FZ1QOf1YMxLCcFGB6Dj2xZNkv+Xo2H X-Developer-Key: i=gary@garyguo.net; a=ed25519; pk=vB3uIX95SM4eVrIqo1DWNWKDKD2xzB+yLLLr0yOPYMo= X-ClientProxiedBy: LO4P123CA0344.GBRP123.PROD.OUTLOOK.COM (2603:10a6:600:18d::7) To LOVP265MB8871.GBRP265.PROD.OUTLOOK.COM (2603:10a6:600:488::16) 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: LOVP265MB8871:EE_|LO8P265MB7398:EE_ X-MS-Office365-Filtering-Correlation-Id: 1fe4b607-4aca-4373-b52a-08dec5986ada X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|1800799024|7416014|376014|366016|10070799003|6133799003|22082099003|18002099003|921020|3023799007|56012099006|5023799004; X-Microsoft-Antispam-Message-Info: /2vDcwhhWZvEFXw7lniYHKxoVIftRbve+wTA6dtGDONlyOZzgWaO+iKcaQjdEu0l9exQGUdL5NR4eTiagLLAXgQ26VgC+xmFpk2/zvnFhxFreZwdAfXeTHYjc0SJhFI8tcWfo7vUS0+/1zawoI2lYaxSFYQpsmgdNz2rFk2eGq/N2v18F0pb5KP1iYOsDkyU7LHDQHV9MLlNEsZoZNBYWVfAutGDiaWhJwiCzzfJiWTEqFGLtDjXnJuWffhsarzDcOwDBzRjl4PPlpWyapw0BoAYbBZoT5fwG67M0xwhesjyyza0cia5FWGYx1cDzaWixGT4HxfCypBRLgGgHm0oMyZEUAAI5UEUkHh/Scy0/dvwgzzvSIKoUd6B1pdt/0t0aAx961k/u3i269fJf5ULJEc//jS8pD+5FNeVmSjTDYvnbSe1lGpgbiYNwXFv2z8gZ2u9wJPaxXWH1xNW7lOauoXejzdjsTLY2e3tpbTtd5VGK7dXgY7Mz0iPDLhyab7EAcyXIJ9Xp1tw8/CQhn/9v8Mbj9Hxy1Yl3q7ProkeOrS6TuHam7S5afDMhm/FxjAYxRyIpGbxdhdPLlKVhXI6IYTSyCxvs+LVY29VzDFTyZS/LDE83Mr1MCqCMHREw0Gz0N8FUlQ3cARbUAgEmIG1A40QpxR3fAUgrwSeborcYNYOICIrXfTl97H6eb/qqFB0e7QAYuvJbe4PPyYJHvGjGBVVZbWL8MOYaHwu/negN/E= X-Forefront-Antispam-Report: CIP:255.255.255.255;CTRY:;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:LOVP265MB8871.GBRP265.PROD.OUTLOOK.COM;PTR:;CAT:NONE;SFS:(13230040)(1800799024)(7416014)(376014)(366016)(10070799003)(6133799003)(22082099003)(18002099003)(921020)(3023799007)(56012099006)(5023799004);DIR:OUT;SFP:1102; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: =?utf-8?B?aUV2Tkl1aTg1YzRkbzZNMHdZK3AyYVZ5WDJFMmhRUzNmdlFHYklHZ3hrQXdF?= =?utf-8?B?YkNsOXNjdnR4ZkVnYzVheW5hNmViS2VmUUFNNFM1dFZrZktqdk1MMGJMaEJo?= =?utf-8?B?L1RKTHU3NW9HQzEwUzNwR1QvN3ppNkZWRjBtSnhRaElaZUp5NG5QMEF0cmdu?= =?utf-8?B?UTg0d2E3RkJFMVRrYXM3QXNEUUhrM1QzZEVEbU04MUFrNXB3SWIrRUVPMHhQ?= =?utf-8?B?VHE4MFRYQ2JjS0FFdXl2US9DSHJTK3NNT3pJM0h4OG90bVFmZnd6YTJzMU5R?= =?utf-8?B?OTN5WUZzeGhBS01FUmFVNk8xY2NnUGtvdTdrRDRuQVJsL200WWdocno2NlEv?= =?utf-8?B?OUw3WCs5M2MzTDFnd1c0bSsvVXc4Z3NTZ1gvVEYwaWpmbDNRQWFpVkVVaEx6?= =?utf-8?B?MFNzc1FXZHVwNmdPNkF6QWFCdzZSUWs5REI5dkNOTk9DYnlQbU5Cbm1Za0Jx?= =?utf-8?B?cFVsdldDZlA4MlZmYVJRSlRkWXNuVzk4VWxPY2FhMzZoK3JWdy9lZXlFUDBG?= =?utf-8?B?TEhyLzFpaDIzVTFwNlNGZEdFemhybXNpc3h5ZjBhLy82K2lTN1ZaZ29pcFpP?= =?utf-8?B?c2xtWEpieGtwcVN2aGc0ZExvbEVjWEZhcFMrTExPQUc1bW52Uy80K3d2bzVl?= =?utf-8?B?S1RxNGttMVJXZmpQZ25pVk1CRlVWWkJkM1JiN3FuRVk2Ym5nd2JIVE1UU2x6?= =?utf-8?B?SnYvUVB4ZzJkQm13dlQ3bFhwQVhkWVc3TndNUU9BR3o4RlRseWErdjBDRFIz?= =?utf-8?B?bkJaS0RjcDlpVnBpTEo2QVFFVk9JWFJPZHZDd1FiOHdzY0E5R3dFc2VINmx6?= =?utf-8?B?NnNkMHdWdE9YT05zUlV5WUZGTFUrVGl0UnRmMytBNjMrcEdkQU5mcFBmNlV0?= =?utf-8?B?ZVZ3QWtETGRwOEZmdUVHSXJaSytNQzN1eE45UDFXb29xU0NhL0t5emRhUDZh?= =?utf-8?B?UHpZeEtlR1BaemtKeDA4bmcveVk0NDZtWVU5YVRWakMxRUJrVitYSnNkNlcw?= =?utf-8?B?NDFWd0NST0NqUWNXRHBlMktwWWtaMEpUbWlPaTRueDZpSVFEVE5qTW5KNlJN?= =?utf-8?B?OVA5UTZXc1ZEMEJnZ1VFakRwOVJac1N0S2J3NmwvcWVIUEF0b1dqMDJLMTU4?= =?utf-8?B?SUpJZjd3MUVkbFpZR0VQWDZqTFVzTTZpNk0ybEhrZU5EN2poUVZNMzhFZ1Jw?= =?utf-8?B?RURkZkwrOTBaTnZoVFNFUndmdVdDYlFJTDFQMzExY0F6L3hxNUd4UXFUM0tq?= =?utf-8?B?WWF3NVhyanRhZlhzNHRURS9WT25MRWl2OUk2ZFo4ZVN0TWNRb2xuTGg0YXF6?= =?utf-8?B?RGdLa0FRL0pZRWJpSk1aSzFxQkllWWJ5c3FQTDFHQXpCVlFXTEV6bURQVFo0?= =?utf-8?B?UlhPNjZ6a2NmWHRnazlGeXc2Q1hWNEFVbU1ZcXBaOThBaThFU1FZSm56WXpN?= =?utf-8?B?b1RCVDFzV3J6QjdQZnc3Und4bkRRSm52TFlPTkI3M3hDa0dtdkJkZHpTbmRH?= =?utf-8?B?THdGSEdVSTVXMjltOHZOaHZNNFRrd0E0QVBBSW9xdk95K3drYVp3bHNoanBE?= =?utf-8?B?dlMrM29tMytwRUZreGd5NStPZUxXSjN3LzA3TUZrZ01RUi9NeDVTUWxBaEs0?= =?utf-8?B?ZVhud1pNTjZBbFE1akQ2cjFLUWkzU1JVdXY0LzJTQ1R2QVZoY1lvQld5djF4?= =?utf-8?B?cFJVS1BBNFNGR3cxRS9ud0JZYjA5WkcwZ1Y2YVpVZFVKdXhFa2c2MDE5V3ZP?= =?utf-8?B?LzNicXlLUXQ3R1ZEVndmV3FFekhadEZRQ2VNMVcrTlFIUUpsVE1PSktDaDJO?= =?utf-8?B?WFFpWWxsTjVsYURnNTQyeEc1WFJmeU5mNEw3U3MyZ0pKUEFDc0lUVVQrLzJE?= =?utf-8?B?d2ZlNXQ5MkJFTi9nS2N5K0Y5SnRGdzdKYURwSG8yaTI2RVNSMmNGYURYbndS?= =?utf-8?B?YjJrL3oxT3czczFZbVl4ZHdpU0FCMmFFdGpDeXJtQ0dpVFBWR0FmcDhxL00z?= =?utf-8?B?TnlSdDVQbFo1WStBMmhuVit2MFpHZ1JBbHpTYW5sOCt6bFl3T0Z2YWpXeWpt?= =?utf-8?B?UVo5WUhucThJQmlLMlZOcHMrY1lBSHB3YmRNRkFKTlJqclVqZnNncm1CVnho?= =?utf-8?B?S0duYi9Jck9FTWFHVUt4a0JmeEJhYzE1M05xdDFTZ3JNYklHNUI2eUo3c2lX?= =?utf-8?B?U3o2VldCY2JSR01rak9JOThlRUVoV1pJUlE5bXlHMTFIVzNzSUQwTEFqWFVn?= =?utf-8?B?eGs4aFl0TVVqRjF3ajRaWUpSM2pGUjNKVStRQnY4ZFdEbWN6QmJ2aUplOVV3?= =?utf-8?B?VzE5TGY5VG03WlkwN2ZkYzM3Q0g0UndiRStobmxmTkxrSGdwSlUwQT09?= X-OriginatorOrg: garyguo.net X-MS-Exchange-CrossTenant-Network-Message-Id: 1fe4b607-4aca-4373-b52a-08dec5986ada X-MS-Exchange-CrossTenant-AuthSource: LOVP265MB8871.GBRP265.PROD.OUTLOOK.COM X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 08 Jun 2026 19:59:15.2505 (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: EZZ866gM6eSjnx1ilpUs2mxwIK5hFKS+yK83RRJhgGkytpS+u+SsvnJgvJSQp0s3Msy1hHrJbMJLx6LsaP7kZg== X-MS-Exchange-Transport-CrossTenantHeadersStamped: LO8P265MB7398 One feature that was lost from the old `dma_read!` and `dma_write!` when moving to `io_read!` and `io_write!` was the ability to read/write a large structs. However, the semantics was unclear to begin with, as there was no guarantee about their atomicity even for structs that were small enough to fit in u32. Re-introduce the capability in the form of copying methods. dma_read!(foo, bar) -> io_project!(foo, bar).copy_read() dma_write!(foo, bar, baz) -> io_project!(foo, bar).copy_write(baz) Model these semantics after memcpy so user has clear expectation of lack of atomicity. As an additional benefit of this change, this now works for MMIO as well by mapping them to `memcpy_{from,to}io`. For slices which is DST so the `copy_read` and `copy_write` API above can't work, add `copy_from_slice` and `copy_to_slice` to copy from/to normal memory, and `copy_from_io_slice` and `copy_to_io_slice` to copy from/to other `Io` regions. They're optimized if at least one end is mapped to system memory; if none are, the copy occurs with an intermediate stack buffer. Signed-off-by: Gary Guo Suggested-by: Danilo Krummrich --- rust/helpers/io.c | 13 ++ rust/kernel/dma.rs | 9 ++ rust/kernel/io.rs | 367 +++++++++++++++++++++++++++++++++++++++++++= +++- samples/rust/rust_dma.rs | 14 +- 4 files changed, 397 insertions(+), 6 deletions(-) diff --git a/rust/helpers/io.c b/rust/helpers/io.c index 397810864a24..7ed9a4f77f1b 100644 --- a/rust/helpers/io.c +++ b/rust/helpers/io.c @@ -19,6 +19,19 @@ __rust_helper void rust_helper_iounmap(void __iomem *add= r) iounmap(addr); } =20 +__rust_helper void rust_helper_memcpy_fromio(void *dst, + const volatile void __iomem *src, + size_t count) +{ + memcpy_fromio(dst, src, count); +} + +__rust_helper void rust_helper_memcpy_toio(volatile void __iomem *dst, + const void *src, size_t count) +{ + memcpy_toio(dst, src, count); +} + __rust_helper u8 rust_helper_readb(const void __iomem *addr) { return readb(addr); diff --git a/rust/kernel/dma.rs b/rust/kernel/dma.rs index 68015a2ab43b..71d495a2e3a8 100644 --- a/rust/kernel/dma.rs +++ b/rust/kernel/dma.rs @@ -18,6 +18,7 @@ IoBackend, IoBase, IoCapable, + IoCopyable, SysMem, SysMemBackend, // }, @@ -1196,6 +1197,14 @@ fn io_write<'a>(view: Self::View<'a, T>, value: T) { } } =20 +// SAFETY: `CoherentView::as_ptr` is mapped to CPU address space. +unsafe impl IoCopyable for CoherentBackend { + #[inline(always)] + fn is_mapped(_view: Self::View<'_, T>) -> bool { + true + } +} + impl<'a, T: ?Sized + KnownSize> IoBase<'a> for CoherentView<'a, T> { type Backend =3D CoherentBackend; type Target =3D T; diff --git a/rust/kernel/io.rs b/rust/kernel/io.rs index 72f3acc0f50d..2b238b625672 100644 --- a/rust/kernel/io.rs +++ b/rust/kernel/io.rs @@ -5,7 +5,8 @@ //! C header: [`include/asm-generic/io.h`](srctree/include/asm-generic/io.= h) =20 use core::{ - marker::PhantomData, // + marker::PhantomData, + mem::MaybeUninit, // }; =20 use crate::{ @@ -229,6 +230,63 @@ pub trait IoCapable: IoBackend { fn io_write<'a>(view: Self::View<'a, T>, value: T); } =20 +/// Trait indicating that an I/O backend supports memory copy operations. +/// +/// # Safety +/// +/// If [`Self::is_mapped`] is overridden, it must be correct per documenta= tion. +pub unsafe trait IoCopyable: IoBackend { + /// Whether the pointers for this I/O backend are in the CPU address s= pace, and are coherently + /// mapped. + /// + /// When this returns true, `Self::as_ptr(view)` must return a valid a= nd aligned pointer. The + /// pointer may be accessed with byte-wise atomic memory copy or volat= ile read/write. + /// + /// This is not an associated constants to support backends where the = view may be conditionally + /// mapped. This method should be marked as `#[inline(always)]` if it = always returns true, so + /// `build_assert!()` in `copy_{from,to}io` can see it. + #[inline] + fn is_mapped(_view: Self::View<'_, T>) -> bool { + false + } + + /// Copy contents of `view` to `buffer`. + /// + /// # Safety + /// + /// - `buffer` is valid for volatile write for `view.size()` bytes. + #[inline] + unsafe fn copy_from_io(view: Self::View<'_, [u8]>, buffer: *mut u8) { + build_assert!(Self::is_mapped(view)); + + let ptr =3D Self::as_ptr(view); + + // Use `bindings::memcpy` instead of copy_nonoverlapping for volat= ile. + // SAFETY: + // - `is_mapped` guarantees `ptr` is in CPU address space and vali= d for read. + // - `buffer` is valid for write for `view.size()` bytes which is = equal to `ptr.len()`. + unsafe { bindings::memcpy(buffer.cast(), ptr.cast(), ptr.len()) }; + } + + /// Copy `size` bytes from `buffer` to `address`. + /// + /// # Safety + /// + /// - `buffer` is valid for volatile read for `view.size()` bytes. + #[inline] + unsafe fn copy_to_io(view: Self::View<'_, [u8]>, buffer: *const u8) { + build_assert!(Self::is_mapped(view)); + + let ptr =3D Self::as_ptr(view); + + // Use `bindings::memcpy` instead of copy_nonoverlapping for volat= ile. + // SAFETY: + // - `is_mapped` guarantees `ptr` is in CPU address space and vali= d for write. + // - `buffer` is valid for read for `view.size()` bytes which is e= qual to `ptr.len()`. + unsafe { bindings::memcpy(ptr.cast(), buffer.cast(), ptr.len()) }; + } +} + /// Describes a given I/O location: its offset, width, and type to convert= the raw value from and /// into. /// @@ -306,6 +364,24 @@ fn size(self) -> usize { KnownSize::size(Self::Backend::as_ptr(self.as_view())) } =20 + /// Returns the length of the slice in number of elements. + #[inline] + fn len(self) -> usize + where + Self: Io<'a, Target =3D [T]>, + { + Self::Backend::as_ptr(self.as_view()).len() + } + + /// Returns `true` if the slice has a length of 0. + #[inline] + fn is_empty(self) -> bool + where + Self: Io<'a, Target =3D [T]>, + { + self.len() =3D=3D 0 + } + /// Try to convert into a different typed I/O view. /// /// The target type must be of same or smaller size to current type, a= nd the current view must @@ -397,6 +473,264 @@ fn write_val(self, value: Self::Target) Self::Backend::io_write(self.as_view(), value) } =20 + /// Copy-read from I/O memory. + /// + /// There is no atomicity guarantee. + /// + /// # Examples + /// + /// ```no_run + /// # use kernel::io::*; + /// # fn test_copy_read(mmio: Mmio<'_, [u8; 6]>) { + /// // let mmio: Mmio<'_, [u8; 6]>; + /// let val: [u8; 6] =3D mmio.copy_read(); + /// # } + /// ``` + #[inline] + fn copy_read(self) -> Self::Target + where + Self::Backend: IoCopyable, + Self::Target: Sized + FromBytes, + { + let view =3D self.as_view(); + + // Optimized path if I/O backend is CPU mapped. + if Self::Backend::is_mapped(view) { + let ptr =3D Self::Backend::as_ptr(view); + // SAFETY: + // - `is_mapped` guarantees `ptr` is valid for read in CPU add= ress space. + // - Using read_volatile() here so that race with hardware is = well-defined. + // - Using read_volatile() here is not sound if it races with = other CPU per Rust + // rules, but this is allowed per LKMM. + return unsafe { ptr.read_volatile() }; + } + + // Project `self` to `[u8]`. + let ptr =3D Self::Backend::as_ptr(view); + // SAFETY: This is a identity projection. + let slice_view =3D unsafe { + Self::Backend::project_view( + view, + core::ptr::slice_from_raw_parts_mut::(ptr.cast(), size= _of::()), + ) + }; + + let mut buf =3D MaybeUninit::::uninit(); + // SAFETY: `buf.as_mut_ptr()` is valid for write for `size_of::= ()` bytes. + unsafe { Self::Backend::copy_from_io(slice_view, buf.as_mut_ptr().= cast()) }; + // SAFETY: T: FromBytes` guarantee that all bit patterns are valid. + unsafe { buf.assume_init() } + } + + /// Copy-write to I/O memory. + /// + /// There is no atomicity guarantee. + /// + /// # Examples + /// + /// ```no_run + /// # use kernel::io::*; + /// # fn test_copy_write(mmio: Mmio<'_, [u8; 6]>) { + /// // let mmio: Mmio<'_, [u8; 6]>; + /// mmio.copy_write([0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF]); + /// # } + /// ``` + #[inline] + fn copy_write(self, value: Self::Target) + where + Self::Backend: IoCopyable, + Self::Target: Sized + AsBytes, + { + let view =3D self.as_view(); + + // Optimized path if I/O backend is CPU mapped. + if Self::Backend::is_mapped(view) { + let ptr =3D Self::Backend::as_ptr(view); + // SAFETY: + // - `is_mapped` guarantees `ptr` is valid for write in CPU ad= dress space. + // - Using write_volatile() here so that race with hardware is= well-defined. + // - Using write_volatile() here is not sound if it races with= other CPU per Rust + // rules, but this is allowed per LKMM. + unsafe { ptr.write_volatile(value) }; + return; + } + + // Project `self` to `[u8]`. + let ptr =3D Self::Backend::as_ptr(view); + // SAFETY: This is a identity projection. + let slice_view =3D unsafe { + Self::Backend::project_view( + view, + core::ptr::slice_from_raw_parts_mut::(ptr.cast(), size= _of::()), + ) + }; + + // SAFETY: `&raw const value` is valid for read for `size_of::(= )` bytes. + unsafe { Self::Backend::copy_to_io(slice_view, (&raw const value).= cast()) }; + core::mem::forget(value); + } + + /// Copy bytes from slice to I/O memory. + /// + /// The length of `self` must be the same as `data`, similar to [`[u8]= ::copy_from_slice`]. + /// + /// # Examples + /// + /// ```no_run + /// # use kernel::io::*; + /// # fn test_copy_write(mmio: Mmio<'_, [u8]>) { + /// // let mmio: Mmio<'_, [u8]>; + /// mmio.copy_from_slice(&[0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF]); + /// # } + /// ``` + #[inline] + fn copy_from_slice(self, data: &[u8]) + where + Self::Backend: IoCopyable, + Self: Io<'a, Target =3D [u8]>, + { + assert_eq!(self.len(), data.len()); + + // SAFETY: `data.as_ptr()` is valid for read for `self.size()` byt= es. + unsafe { + Self::Backend::copy_to_io(self.as_view(), data.as_ptr()); + } + } + + /// Copy bytes from I/O memory to slice. + /// + /// The length of `self` must be the same as `data`, similar to [`[u8]= ::copy_from_slice`]. + /// + /// # Examples + /// + /// ```no_run + /// # use kernel::io::*; + /// # fn test_copy_write(mmio: Mmio<'_, [u8]>) { + /// // let mmio: Mmio<'_, [u8]>; + /// let mut buf =3D [0; 6]; + /// mmio.copy_to_slice(&mut buf); + /// # } + /// ``` + #[inline] + fn copy_to_slice(self, data: &mut [u8]) + where + Self::Backend: IoCopyable, + Self: Io<'a, Target =3D [u8]>, + { + assert_eq!(self.len(), data.len()); + + // SAFETY: `data.as_ptr()` is valid for write for `self.size()` by= tes. + unsafe { + Self::Backend::copy_from_io(self.as_view(), data.as_mut_ptr()); + } + } + + /// Copy bytes from `data` I/O slice to the `self`. + /// + /// The length of `self` must be the same as `data`, similar to [`[u8]= ::copy_from_slice`]. + /// + /// # Examples + /// + /// ```no_run + /// # use kernel::io::*; + /// # fn test_copy_write(dst: Mmio<'_, [u8]>, src: Mmio<'_, [u8]>) { + /// // let dst: Mmio<'_, [u8]>; + /// // let src: Mmio<'_, [u8]>; + /// dst.copy_from_io_slice(src); + /// # } + /// ``` + fn copy_from_io_slice<'b, T>(self, data: T) + where + Self::Backend: IoCopyable, + Self: Io<'a, Target =3D [u8]>, + T: Io<'b, Target =3D [u8], Backend: IoCopyable>, + { + fn copy_from_io_slice_via_buffer< + 'a, + 'b, + T: Io<'a, Target =3D [u8], Backend: IoCopyable>, + U: Io<'b, Target =3D [u8], Backend: IoCopyable>, + >( + dest: T, + src: U, + ) { + let mut buf =3D MaybeUninit::<[u8; 256]>::uninit(); + + let mut offset =3D 0; + let mut len =3D dest.len(); + + while len !=3D 0 { + let copy_len =3D core::cmp::min(len, 256); + + // SAFETY: `buf.as_mut_ptr()` is valid for write for `copy= _len` bytes as `copy_len + // <=3D 256`. + unsafe { + U::Backend::copy_from_io( + io_project!(src, [panic: offset..][panic: ..copy_l= en]), + buf.as_mut_ptr().cast(), + ) + }; + + // SAFETY: `buf.as_ptr()` is valid for read for `copy_len`= bytes as `copy_len <=3D + // 256`. + unsafe { + T::Backend::copy_to_io( + io_project!(dest, [panic: offset..][panic: ..copy_= len]), + buf.as_ptr().cast(), + ) + }; + + offset +=3D copy_len; + len -=3D copy_len; + } + } + + assert_eq!(self.len(), data.len()); + + let dst_view =3D self.as_view(); + let src_view =3D data.as_view(); + + if T::Backend::is_mapped(src_view) { + // SAFETY: `T::Backend::as_ptr(src_view)` is valid for read fo= r `data.len()` + // bytes. + unsafe { + Self::Backend::copy_to_io(self.as_view(), T::Backend::as_p= tr(src_view).cast()) + } + } else if Self::Backend::is_mapped(dst_view) { + // SAFETY: `Self::Backend::as_ptr(dst_view)` is valid for writ= e for `data.len()` + // bytes. + unsafe { + T::Backend::copy_from_io(data.as_view(), Self::Backend::as= _ptr(dst_view).cast()) + } + } else { + copy_from_io_slice_via_buffer(dst_view, src_view) + } + } + + /// Copy bytes from `self` to the `data` I/O slice. + /// + /// The length of `self` must be the same as `data`, similar to [`[u8]= ::copy_from_slice`]. + /// + /// # Examples + /// + /// ```no_run + /// # use kernel::io::*; + /// # fn test_copy_write(dst: Mmio<'_, [u8]>, src: Mmio<'_, [u8]>) { + /// // let dst: Mmio<'_, [u8]>; + /// // let src: Mmio<'_, [u8]>; + /// src.copy_to_io_slice(dst); + /// # } + /// ``` + #[inline] + fn copy_to_io_slice<'b, T>(self, data: T) + where + Self::Backend: IoCopyable, + Self: Io<'a, Target =3D [u8]>, + T: Io<'b, Target =3D [u8], Backend: IoCopyable>, + { + data.copy_from_io_slice(self) + } + /// Returns a view for a given `offset`, performing compile-time bound= checks. // Always inline to optimize out error path of `build_assert`. #[inline(always)] @@ -987,6 +1321,29 @@ fn io_write(view: <$backend as IoBackend>::View<'_, $= ty>, value: $ty) { #[cfg(CONFIG_64BIT)] impl_mmio_io_capable!(MmioBackend, u64, readq, writeq); =20 +// SAFETY: `is_mapped` is not overridden. +unsafe impl IoCopyable for MmioBackend { + #[inline] + unsafe fn copy_from_io(view: Self::View<'_, [u8]>, buffer: *mut u8) { + // SAFETY: + // - `view.ptr` is valid MMIO memory for `view.size()` bytes. + // - `buffer` is valid for write for `view.size()` bytes. + unsafe { + bindings::memcpy_fromio(buffer.cast(), view.ptr.cast(), view.s= ize()); + } + } + + #[inline] + unsafe fn copy_to_io(view: Self::View<'_, [u8]>, buffer: *const u8) { + // SAFETY: + // - `view.ptr` is valid MMIO memory for `view.size()` bytes. + // - `buffer` is valid for read for `view.size()` bytes. + unsafe { + bindings::memcpy_toio(view.ptr.cast(), buffer.cast(), view.siz= e()); + } + } +} + /// [`Mmio`] but using relaxed accessors. /// /// This type provides an implementation of [`Io`] that uses relaxed I/O M= MIO operands instead of @@ -1142,6 +1499,14 @@ fn io_write(view: SysMem<'_, $ty>, value: $ty) { #[cfg(CONFIG_64BIT)] impl_sysmem_io_capable!(u64); =20 +// SAFETY: `SysMem::as_ptr` is mapped to the CPU address space. +unsafe impl IoCopyable for SysMemBackend { + #[inline(always)] + fn is_mapped(_view: Self::View<'_, T>) -> bool { + true + } +} + /// System memory region. /// /// Provides `Io` trait implementation for kernel virtual address ranges, diff --git a/samples/rust/rust_dma.rs b/samples/rust/rust_dma.rs index 6727c441658a..0f2597798ff5 100644 --- a/samples/rust/rust_dma.rs +++ b/samples/rust/rust_dma.rs @@ -12,7 +12,11 @@ Device, DmaMask, // }, - io::io_read, + io::{ + io_project, + io_read, + Io, // + }, page, pci, prelude::*, scatterlist::{Owned, SGTable}, @@ -74,11 +78,11 @@ fn probe<'bound>( // SAFETY: There are no concurrent calls to DMA allocation and= mapping primitives. unsafe { pdev.dma_set_mask_and_coherent(mask)? }; =20 - let mut ca: CoherentBox<[MyStruct]> =3D - CoherentBox::zeroed_slice(pdev.as_ref(), TEST_VALUES.len()= , GFP_KERNEL)?; + let ca: Coherent<[MyStruct]> =3D + Coherent::zeroed_slice(pdev.as_ref(), TEST_VALUES.len(), G= FP_KERNEL)?; =20 for (i, value) in TEST_VALUES.into_iter().enumerate() { - ca.init_at(i, MyStruct::new(value.0, value.1))?; + io_project!(ca, [panic: i]).copy_write(MyStruct::new(value= .0, value.1)); } =20 let size =3D 4 * page::PAGE_SIZE; @@ -88,7 +92,7 @@ fn probe<'bound>( =20 Ok(try_pin_init!(Self { pdev: pdev.into(), - ca: ca.into(), + ca, sgt <- sgt, })) }) --=20 2.54.0 From nobody Thu Jun 25 00:35:31 2026 Received: from LO2P265CU024.outbound.protection.outlook.com (mail-uksouthazon11021080.outbound.protection.outlook.com [52.101.95.80]) (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 E7A0F3EA967; Mon, 8 Jun 2026 19:59:18 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=52.101.95.80 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780948761; cv=fail; b=mhY3a5fRBjordMT65mj8dTfk3g1ce3t+AQXxYdl7X93o3hxkuPW290u1P+mcNoBb5hxG8HvUJblCJLV6dTSbZlONlyJstZT7+B8F8yqrk8T1mVx34UUVRiq30w0XUHycFQGd1E/+FfwFyroa4CybBystjUDXR30Wrun1S0Rz7Y0= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780948761; c=relaxed/simple; bh=wmxzPu0c0OKYEprY/AcsW+0RzmA2WFWu+K+BzicwFZQ=; h=From:Date:Subject:Content-Type:Message-Id:References:In-Reply-To: To:Cc:MIME-Version; b=uXMKgRlhw80aW02NCchPEiNffLWkdbt2ID/SJZs8NRM0TB7nPvVCwTlpNwHWwZbrA98P3YGZMzzCXC+bg/cMbjHlpHL72mAXJhaEd0Y+0ErqRIODgBJErjhaNgQzD5zm67HeR/Zw+KRxtoMqE5vcNzMkznzOoqHNAaDRzX+cquo= 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=Yj7ycDa4; arc=fail smtp.client-ip=52.101.95.80 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="Yj7ycDa4" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=AkhyIZcxSzOTy0AvMNAvGa7plgmBc2laB88sh78XIY83BvJtfyRhyfhW0QjhqFIeGF/oKQSUF8F5ccczXGRKE5qhlM8MwM1Ata7AQd3f93R/V4LUplBBblvVmn7i6466h0biCaW3aWSxvPhIFP8+3m67obzXQ4HzBekPkE9JOevuI47PNwGhm0ATgCjgYBiRp202jxV16QDNs/w2912J3vkn2QXCw3dwJyr6lCXDGoBGYvapqKnjzrpQz2AHnROw3FeaaDjhxkGSXCaPXdt+5104e/eFZ99T6azoYhbN1l2q6KJ93igl4qqoSpUDJXifdM3nocUKI7E13X/HKSwuNw== 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=VcmDl9qJ/oGwD4XoEgLcnZxea+19bOZMP/ZNt8FC8NM=; b=IIkj1N1kguDFoipqElgIL1iJcP+MgGSjuNmqmrLcOoBUYOet7Xs0HH53jH1jr5Fyc+H6tDyfhlvr0cQWbVtX7Kp97maoQxpIRZ6ohpjGEtDmo3MMrZ5n+OiBgwLYhCOye9R8VFMdv/uUN0fMYy4V9nY6C7LMAIjZ4QeQ6NRrHlkJZtF9c/Op9q/fwjNu0ZXouhlne5jJUrqj4GP/HQSthwRLiuLIwNzIFp54eJWksm4aohWhthi1jd/NbKcSqQOWhtpNBIVAFAB1XXSBFj/jH4npckPzNrk3VnDl6b43G2IpmYDvoRNhMRMFzWHzef5+xtAOfpG7kGuB/5ohTqJVdg== 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=VcmDl9qJ/oGwD4XoEgLcnZxea+19bOZMP/ZNt8FC8NM=; b=Yj7ycDa4VQGR41Y+SB2iLHJ3C6nW8nGafwSUuhyVyqn4wGeEPNfUmheKFloxSHQmVOcStfWy3UDHcW58Wk2fu7zMbUTy1r+28pVaQsY6/GVBgM9aHiXv8u+Rb/7/rySe3tG6mM3+A8Jy+yfHMbE9i5FZsPTH2cA7xcEu0CuGJZY= Authentication-Results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=garyguo.net; Received: from LOVP265MB8871.GBRP265.PROD.OUTLOOK.COM (2603:10a6:600:488::16) by LOAP265MB9032.GBRP265.PROD.OUTLOOK.COM (2603:10a6:600:492::22) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.21.92.13; Mon, 8 Jun 2026 19:59:15 +0000 Received: from LOVP265MB8871.GBRP265.PROD.OUTLOOK.COM ([fe80::1c3:ceba:21b4:9986]) by LOVP265MB8871.GBRP265.PROD.OUTLOOK.COM ([fe80::1c3:ceba:21b4:9986%4]) with mapi id 15.21.0092.011; Mon, 8 Jun 2026 19:59:15 +0000 From: Gary Guo Date: Mon, 08 Jun 2026 20:59:16 +0100 Subject: [PATCH v3 19/19] rust: io: implement `Io` for `Either` Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260608-io_projection-v3-19-c5cde13a5ec4@garyguo.net> References: <20260608-io_projection-v3-0-c5cde13a5ec4@garyguo.net> In-Reply-To: <20260608-io_projection-v3-0-c5cde13a5ec4@garyguo.net> To: Danilo Krummrich , Alice Ryhl , Daniel Almeida , Greg Kroah-Hartman , "Rafael J. Wysocki" , Miguel Ojeda , Boqun Feng , Gary Guo , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Andreas Hindborg , Trevor Gross , Bjorn Helgaas , =?utf-8?q?Krzysztof_Wilczy=C5=84ski?= , Abdiel Janulgue , Robin Murphy , Alexandre Courbot , David Airlie , Simona Vetter Cc: driver-core@lists.linux.dev, rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, linux-pci@vger.kernel.org, nova-gpu@lists.linux.dev, dri-devel@lists.freedesktop.org X-Mailer: b4 0.15.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1780948747; l=4706; i=gary@garyguo.net; s=20221204; h=from:subject:message-id; bh=wmxzPu0c0OKYEprY/AcsW+0RzmA2WFWu+K+BzicwFZQ=; b=q1S2929VJWPMdafMXT0r61VsJALLzS6xmkHO2r2431POzQGCniIaRMRjvZAWHtCGEENbfp0lV F25in8X1LmmA2NiXEmn591SaicdYqn7JQQNjqnDbdWu7J1pCTkmhr/L X-Developer-Key: i=gary@garyguo.net; a=ed25519; pk=vB3uIX95SM4eVrIqo1DWNWKDKD2xzB+yLLLr0yOPYMo= X-ClientProxiedBy: LO4P123CA0344.GBRP123.PROD.OUTLOOK.COM (2603:10a6:600:18d::7) To LOVP265MB8871.GBRP265.PROD.OUTLOOK.COM (2603:10a6:600:488::16) 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: LOVP265MB8871:EE_|LOAP265MB9032:EE_ X-MS-Office365-Filtering-Correlation-Id: 48e25a22-f420-4ca1-6395-08dec5986b19 X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|366016|10070799003|1800799024|7416014|376014|921020|5023799004|56012099006|6133799003|22082099003|18002099003; X-Microsoft-Antispam-Message-Info: e5ZMd35SaF5Y0/HDn4fLyu+hqeIEgGnOTX2GlwwVs+HxBU4I+K8EqxySv9+SZZpITEMtXmj7FP6C1rVGsdKpCOABQp9sqp/8B6pwiCu+YhITPBx4SWC3AxqzS4fVCxOsG2OmVZEu/Ew1MfE71/DQreFlInUW4bkU6S9GC1WNhgEqU9FasXYSE9vbb2mCEebK5tFrHUqcReeg8e5pgUjCU4XVGs793oAVQyjE3oe4rQZLyoghqIY5O+cN6ZFv4sa+gw8/Jt20uwrNZt+NdyOfRspxVIiNO2u1CdXTZwR9mahK67XPi7idiEztQGJhvj2WUodb506/j1MYWSxLA3WWgIEhTZbu3JeWZRbdG/R4ReopEl4LpFQebp37Vj1m4kEAvTa5wbpyvkl58Y0Z6uvOGEwX79EKxilA7GVsqYeXFQ1EGOO+RAV0k75JhIaG1aCccqw2Ou2wAyTVPmV4wjO/HYNIAZYbVFvf/K50wmtTcRqeUZqbqnvT/N7ihufVjwPSLP1+nb4ywLvpkvcfY0WX3TjWc/KEhu9tytX/6t7VJ3mjo9cUGgcuK5gNHgiaurEDlhWhA5vHkNDyi8IQk/Que+gYBTToA2botCpb90GRhnMaseTRUShVL1XyzXkwc7jHqD5ARcDvCGnAg/jPrD9RM7oIpzGcMD5cI1l3BW0+7qSLpng1lJBTQsZhpCaOVFMSRYiQItsGVwUpOUDdZtPBJUxYHdlRmnCpcKmGkP9mfBI= X-Forefront-Antispam-Report: CIP:255.255.255.255;CTRY:;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:LOVP265MB8871.GBRP265.PROD.OUTLOOK.COM;PTR:;CAT:NONE;SFS:(13230040)(366016)(10070799003)(1800799024)(7416014)(376014)(921020)(5023799004)(56012099006)(6133799003)(22082099003)(18002099003);DIR:OUT;SFP:1102; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: =?utf-8?B?NjNnQkQvMnB2eVd4dzdZeFN3d2FrWkhaa0hXSUMwUlpWbm1iQU5zTmtSWWVj?= =?utf-8?B?ekgrK09ZVktzc3lIODRpTnY4N0FPc1FpRHloZ0E5YVNHem43eFd4Q0FxL0hK?= =?utf-8?B?SWs0bVFTbi9ISmN3L09sTFAvTVpLWGdsUGJqRUQrdllrNFZaVkhCOExtSEgr?= =?utf-8?B?WjIwVFpIajhpNXJOQTRUbU5kV0x4TXZqTkZEMlltMHg1MnFVd2ZzTEhmUnpw?= =?utf-8?B?MkZSMDI2SFUvL3pjc0tXUWM1RXBKcURISnhOM3hlWHBhbWZvM1hiMGhadVh6?= =?utf-8?B?ZjJjd3NKamU3MytPenJKWWU1RnRXbmk1REt3dnhzSFBvRlZ2ZDJtK3hOUzJh?= =?utf-8?B?dDN3bStURnlja0V0QzlVWXZLR2pKRjhKN1pVd1NLckEvc2RhbFZOdlQ5WkhX?= =?utf-8?B?aW9EYlB0VmQwdWt6ZTFVRWhaL1cwUzUrSDBEQ2JyeGdyQnlMVmVCWHZLYkVt?= =?utf-8?B?bTN6NnE4TjN2d01ORkE1UjVlN3QrRVhVT2luenN4c1pvK05sNnl5NHFJTTFz?= =?utf-8?B?bFpXSlRKWlhGNlNrK0NRVGNnWUpkTVFwc3B6Z2dpWmp0QzZJMk9WN3pWaHpC?= =?utf-8?B?ZW91Zk1Kams3QytITERZVkwwQ0F3KzcxYUtKT3R0ZXpVK1FCdHBGZTFnZFZH?= =?utf-8?B?aUxQbmNxNEZPVEQ5RkVwSTVBMmxxZVNKcEpid2VMdTZyN3RNZGZnd0dlRHBm?= =?utf-8?B?dlNwTmtzejFBaWJqU1dRVGZuZEJ5YWdHUEJDMkJnZktjTHNWL0YzVk0xeFox?= =?utf-8?B?ZFBPTnd3bmxxQy9vUW9kV1NWT1QxZFVRZmRxNmJEMit1bHRIdm1aalk2TDlZ?= =?utf-8?B?MzJzNmxoamg5dWdOT2EreVJ6c1lqaWNGcTBKTWZBNWdkSUNGVzBKN1AvM2tU?= =?utf-8?B?akY1K3Bma3lNa0Zvb3BwWU5raTZNcGZhZk9NTXUyVDJLdEhrQ05SMStuYndi?= =?utf-8?B?eWI4R1FqMlQ5RHNkNFFSOStpSmpBcVJob0wzdEtsNjdnVXozaDFERkU1NG5r?= =?utf-8?B?Wjd3d0d3aDJaT0RuNXdjZEFlQnNiRmNrdlErTUZmSHhDVFBEOStHbHJuZW1K?= =?utf-8?B?ZTZBclBwdWdCdGwwL0VnejY2VWhhazZzSFpMM3NSL0NHWHl6d21YN3pzYmF4?= =?utf-8?B?dW9YM0YwdnhWb2JUb01xOWx6NEdxQlJHbXoxRldLWVU0SXMyMHJQU1MyZUpF?= =?utf-8?B?SVI3d0ZVZi9jdk1ESVVCMUZPVjYxOUhxMHlYSjJ0eTRTV29ZcDlnblR1dHFs?= =?utf-8?B?R3VYN0xtc0xuUWNBMjRDVnZsMEI1Z3pnb05WUnFNL0FQYlhIRkpNRTBBd2Va?= =?utf-8?B?eHdac3pNSUM5RXh1Ky91ZEx6NnYralJ6WW53dWkvN25LUkdmQ2xnallWQWhq?= =?utf-8?B?NVBlOEVBa2E1VlJHNmMrWDZHMGpXejBKTUoxYXd0Z28yMFNkRU0zemNQR3hy?= =?utf-8?B?aFBDc2U3QjZSdVhzKzI1TUlYbXNueWtZcWd1c3dmTXIrUTdoQXpDckVQWlQz?= =?utf-8?B?bTVXUVN4RFRtY1l3WFJpSnRCVjAzYmJ1MUo4RVN1T2FJdklWTHIraWQrdkxw?= =?utf-8?B?dDVibURoQWZuVEZxaUhSYzRDWkZUdXZRNWNnd0UwMUIwejErQWpFby9oSWxy?= =?utf-8?B?ZUwzcnhrelhLUldpS01aZTZQUUVkTFc0bTM2eEJtVk9IclJYWFVaaWs1ZjBQ?= =?utf-8?B?dlFENjJnWVEvWGxSdTRUWWlwUGt1cFRGaUFiYnlQRDZoK2x6d0c5bzA1dzhG?= =?utf-8?B?NXF5cFA3VjJQNXhGcXRJb09UUk5aemZzcjA3K2lacmhhQkx6bW1LRHVONnhm?= =?utf-8?B?R0YySDNrWkwrQ3pMY0ZTckcrN3pmVnpORW9icjFPeGpTN0hwNVI1ZmxqemFs?= =?utf-8?B?ckltd2VkZ1VXeWM2NkRGRmxjTUlYK2ZHZ2hzbzNuWXdpcllXU3NZcE9JNS9l?= =?utf-8?B?ZWpWUzQ3b1ZVenpoZFBYcmhFd0p3c0J3elRpUXFmME51ZDRqcTBNRWdZbWRZ?= =?utf-8?B?N3dxVUxRRWl2MTY2L0FyM0hDWGhJa01qVUlJNGJWcU9lUmd0VTgwMWRxdGp5?= =?utf-8?B?Y0cwaGo2M2VuVUhsSHd1bm1nQXFxSnJ2Tkk2SzZkREkxMFppYzM3Q0lvRWNC?= =?utf-8?B?T0swbUFxbm5CeUdhMWhpMXFTcnM2RFYrV2RldWYzZjN2V0hOR2dwL1d0VEQ0?= =?utf-8?B?TkV2K0NkaWVrU1liVnk1SWU1ai9qcFpzVUxiVXN0dC8yVzlaQmNOcUgzWWpy?= =?utf-8?B?NERzQXI0QWV3b2QxWUdVUzdsaXpYTFJuNDRmNGZoOWt6NGM5TDVFRUZRaEpQ?= =?utf-8?B?b29LekFZYllOd2xBYjM1RXZqT3orTHBscVltUTJXeFdoS2h2elEyQT09?= X-OriginatorOrg: garyguo.net X-MS-Exchange-CrossTenant-Network-Message-Id: 48e25a22-f420-4ca1-6395-08dec5986b19 X-MS-Exchange-CrossTenant-AuthSource: LOVP265MB8871.GBRP265.PROD.OUTLOOK.COM X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 08 Jun 2026 19:59:15.6360 (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: PXwH3itv3xPM2uxvNO5zH3yA6LBmRpC7nnMGWJi7zP2HripPdAmOmjSCnB8O7scn65JArHSCxMFl8zaOFzu+JQ== X-MS-Exchange-Transport-CrossTenantHeadersStamped: LOAP265MB9032 Add a general purpose sum type `Either` (with no preference on either side, unlike `Result`) and implement `Io` for it. This is generic version of what C `iosys_map` provides, which can be just implemented like this: type IoSysMap<'a, T> =3D Either, SysMem<'a, T>>; Signed-off-by: Gary Guo Suggested-by: Danilo Krummrich --- rust/kernel/io.rs | 93 ++++++++++++++++++++++++++++++++++++++++++++++++= +++- rust/kernel/types.rs | 9 +++++ 2 files changed, 101 insertions(+), 1 deletion(-) diff --git a/rust/kernel/io.rs b/rust/kernel/io.rs index 2b238b625672..28d713eaddda 100644 --- a/rust/kernel/io.rs +++ b/rust/kernel/io.rs @@ -19,7 +19,8 @@ transmute::{ AsBytes, FromBytes, // - }, // + }, + types::Either, // }; =20 pub mod mem; @@ -1592,6 +1593,96 @@ pub unsafe fn project_view( } } =20 +impl<'a, T: ?Sized + KnownSize, L: IoBase<'a, Target =3D T>, R: IoBase<'a,= Target =3D T>> IoBase<'a> + for Either +{ + type Backend =3D Either; + type Target =3D T; + + #[inline] + fn as_view(self) -> ::View<'a, Self::Targe= t> { + match self { + Either::Left(l) =3D> Either::Left(l.as_view()), + Either::Right(r) =3D> Either::Right(r.as_view()), + } + } +} + +impl IoBackend for Either { + type View<'a, T: ?Sized + KnownSize> =3D Either, R::Vie= w<'a, T>>; + + #[inline] + fn as_ptr<'a, T: ?Sized + KnownSize>(view: Self::View<'a, T>) -> *mut = T { + match view { + Either::Left(l) =3D> L::as_ptr(l), + Either::Right(r) =3D> R::as_ptr(r), + } + } + + #[inline] + unsafe fn project_view<'a, T: ?Sized + KnownSize, U: ?Sized + KnownSiz= e>( + view: Self::View<'a, T>, + ptr: *mut U, + ) -> Self::View<'a, U> { + match view { + // SAFETY: Per safety requirement. + Either::Left(l) =3D> Either::Left(unsafe { L::project_view(l, = ptr) }), + // SAFETY: Per safety requirement. + Either::Right(r) =3D> Either::Right(unsafe { R::project_view(r= , ptr) }), + } + } +} + +impl, R: IoCapable> IoCapable for Either { + #[inline] + fn io_read(view: Self::View<'_, T>) -> T { + match view { + Either::Left(l) =3D> L::io_read(l), + Either::Right(r) =3D> R::io_read(r), + } + } + + #[inline] + fn io_write<'a>(view: Self::View<'a, T>, value: T) { + match view { + Either::Left(l) =3D> L::io_write(l, value), + Either::Right(r) =3D> R::io_write(r, value), + } + } +} + +// SAFETY: Per safety guarantee of `L` and `R`'s `IoCopyable` impl, `is_ma= pped` is correctly +// implemented. +unsafe impl IoCopyable for Either { + #[inline] + fn is_mapped(view: Self::View<'_, T>) -> bool { + match view { + Either::Left(l) =3D> L::is_mapped(l), + Either::Right(r) =3D> R::is_mapped(r), + } + } + + #[inline] + unsafe fn copy_from_io(view: Self::View<'_, [u8]>, buffer: *mut u8) { + match view { + // SAFETY: Per safety requirement. + Either::Left(l) =3D> unsafe { L::copy_from_io(l, buffer) }, + // SAFETY: Per safety requirement. + Either::Right(r) =3D> unsafe { R::copy_from_io(r, buffer) }, + } + } + + #[inline] + unsafe fn copy_to_io(view: Self::View<'_, [u8]>, buffer: *const u8) { + match view { + // SAFETY: Per safety requirement. + Either::Left(l) =3D> unsafe { L::copy_to_io(l, buffer) }, + // SAFETY: Per safety requirement. + Either::Right(r) =3D> unsafe { R::copy_to_io(r, buffer) }, + } + } +} + /// Project an I/O type to a subview of it. /// /// The syntax is of form `io_project!(io, proj)` where `io` is an express= ion to a type that diff --git a/rust/kernel/types.rs b/rust/kernel/types.rs index ac316fd7b538..12546c312dd2 100644 --- a/rust/kernel/types.rs +++ b/rust/kernel/types.rs @@ -448,3 +448,12 @@ fn pin_init(slot: impl PinInit) -> impl PinIn= it { /// [`NotThreadSafe`]: type@NotThreadSafe #[allow(non_upper_case_globals)] pub const NotThreadSafe: NotThreadSafe =3D PhantomData; + +/// General purpose sum type with two cases. +#[derive(Clone, Copy)] +pub enum Either { + /// A value of type `L`. + Left(L), + /// A value of type `R`. + Right(R), +} --=20 2.54.0